Allow the acquired file to be closed manually

Instead of requiring library users to wait for a GC
pass to close the file descriptor, make it possible
for a explicit close() call to do the same.

This makes it possible for users of these locks to
avoid running out of file descriptors that they are
unable to close.

Change-Id: I3fabc57b2f0f6b1cef45553cac7e04732a9c2489
This commit is contained in:
Joshua Harlow 2015-04-08 11:58:55 -07:00
parent a0980f8a95
commit 15e659f2b2
4 changed files with 55 additions and 1 deletions

View File

@ -16,3 +16,4 @@ coverage>=3.6
psycopg2
PyMySQL>=0.6.2 # MIT License
sysv_ipc>=0.6.8 # BSD License
fixtures>=0.3.14

View File

@ -57,6 +57,10 @@ class FileLock(locking.Lock):
return _lock()
def close(self):
self.release()
self.lockfile.close()
def release(self):
self.unlock()
self.acquired = False

View File

@ -74,14 +74,22 @@ class SharedWeakLockHelper(Lock):
self._newlock = lambda: lockclass(
self.name, *args, **kwargs)
def acquire(self, blocking=True):
@property
def lock(self):
"""Access the underlying lock object.
For internal usage only.
"""
with self.LOCKS_LOCK:
try:
l = self.ACQUIRED_LOCKS[self._lock_key]
except KeyError:
l = self.RELEASED_LOCKS.setdefault(
self._lock_key, self._newlock())
return l
def acquire(self, blocking=True):
l = self.lock
if l.acquire(blocking):
with self.LOCKS_LOCK:
self.RELEASED_LOCKS.pop(self._lock_key, None)

41
tooz/tests/test_file.py Normal file
View File

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2015 Yahoo! Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import uuid
import fixtures
from testtools import testcase
from tooz import coordination
class TestFileClosing(testcase.TestCase):
@staticmethod
def _get_random_uuid():
return str(uuid.uuid4()).encode('ascii')
def setUp(self):
super(TestFileClosing, self).setUp()
self.tempd = self.useFixture(fixtures.TempDir())
self.url = 'file:///%s' % self.tempd.path
self.member_id = self._get_random_uuid()
def test_lock_closing(self):
driver = coordination.get_coordinator(self.url, self.member_id)
lk = driver.get_lock(b'test').lock
self.assertFalse(lk.lockfile.closed)
lk.close()
self.assertTrue(lk.lockfile.closed)