Revert "lockfile improvements"

This commit is contained in:
Benoit Chesneau 2016-05-20 15:55:55 +02:00
parent 3186473e42
commit b4dc48dc02
6 changed files with 51 additions and 67 deletions

View File

@ -138,7 +138,16 @@ class Arbiter(object):
self.LISTENERS, need_lock = create_sockets(self.cfg, self.log) self.LISTENERS, need_lock = create_sockets(self.cfg, self.log)
if need_lock: if need_lock:
self.acquire_lockfile() if not self.LOCK_FILE:
# reuse the lockfile if already set
if 'GUNICORN_LOCK' in os.environ:
lock_path = os.environ.get('GUNICORN_LOCK')
else:
lock_path = self.cfg.lockfile
self.LOCK_FILE = LockFile(lock_path)
# add us to the shared lock
self.LOCK_FILE.lock()
listeners_str = ",".join([str(l) for l in self.LISTENERS]) listeners_str = ",".join([str(l) for l in self.LISTENERS])
self.log.debug("Arbiter booted") self.log.debug("Arbiter booted")
@ -341,13 +350,17 @@ class Arbiter(object):
:attr graceful: boolean, If True (the default) workers will be :attr graceful: boolean, If True (the default) workers will be
killed gracefully (ie. trying to wait for the current connection) killed gracefully (ie. trying to wait for the current connection)
""" """
released = self.try_release_lockfile() locked = False
if self.LOCK_FILE:
self.LOCK_FILE.unlock()
locked = self.LOCK_FILE.locked()
# delete the lock file if needed
if not locked and 'GUNICORN_LOCK' in os.environ:
del os.environ['GUNICORN_LOCK']
for l in self.LISTENERS: for l in self.LISTENERS:
l.close() l.close(locked)
if released:
l.destroy()
self.LISTENERS = [] self.LISTENERS = []
sig = signal.SIGTERM sig = signal.SIGTERM
if not graceful: if not graceful:
@ -440,36 +453,6 @@ class Arbiter(object):
# manage workers # manage workers
self.manage_workers() self.manage_workers()
def acquire_lockfile(self):
"""\
Acquire the lock file
"""
if not self.LOCK_FILE:
# reuse the lockfile if already set
if 'GUNICORN_LOCK' in os.environ:
lock_path = os.environ.get('GUNICORN_LOCK')
else:
lock_path = self.cfg.lockfile
self.LOCK_FILE = LockFile(lock_path)
# add us to the shared lock
self.LOCK_FILE.acquire()
def try_release_lockfile(self):
"""\
Try to release the lock file
"""
released = False
if self.LOCK_FILE:
released = self.LOCK_FILE.release()
# delete the lock file if needed
if released and 'GUNICORN_LOCK' in os.environ:
del os.environ['GUNICORN_LOCK']
return released
def murder_workers(self): def murder_workers(self):
"""\ """\
Kill unused/idle workers Kill unused/idle workers

View File

@ -49,27 +49,24 @@ class LockFile(object):
self._lockfile = open(self.fname, 'w+b') self._lockfile = open(self.fname, 'w+b')
# set permissions to -rw-r--r-- # set permissions to -rw-r--r--
os.chmod(self.fname, 420) os.chmod(self.fname, 420)
self._released = True self._locked = False
def acquire(self): def lock(self):
_lock(self._lockfile.fileno()) _lock(self._lockfile.fileno())
self._released = False self._locked = True
def release(self): def unlock(self):
if self.released(): if not self.locked():
return True return
if _unlock(self._lockfile.fileno()): if _unlock(self._lockfile.fileno()):
self._lockfile.close() self._lockfile.close()
util.unlink(self.fname) util.unlink(self.fname)
self._lockfile = None self._lockfile = None
self._released = True self._locked = False
return True
return False def locked(self):
return self._lockfile is not None and self._locked
def released(self):
return self._lockfile is None or self._released
def name(self): def name(self):
return self.fname return self.fname

View File

@ -53,7 +53,7 @@ class BaseSocket(object):
def bind(self, sock): def bind(self, sock):
sock.bind(self.cfg_addr) sock.bind(self.cfg_addr)
def close(self): def close(self, locked=False):
if self.sock is None: if self.sock is None:
return return
@ -64,9 +64,6 @@ class BaseSocket(object):
self.sock = None self.sock = None
def destroy(self):
pass
class TCPSocket(BaseSocket): class TCPSocket(BaseSocket):
@ -123,12 +120,10 @@ class UnixSocket(BaseSocket):
util.chown(self.cfg_addr, self.conf.uid, self.conf.gid) util.chown(self.cfg_addr, self.conf.uid, self.conf.gid)
os.umask(old_umask) os.umask(old_umask)
def close(self): def close(self, locked=False):
super(UnixSocket, self).close() if self.parent == os.getpid() and not locked:
def destroy(self):
if self.parent == os.getpid():
os.unlink(self.cfg_addr) os.unlink(self.cfg_addr)
super(UnixSocket, self).close()
def _sock_type(addr): def _sock_type(addr):

View File

@ -35,8 +35,8 @@ def test_arbiter_shutdown_closes_listeners():
listener2 = mock.Mock() listener2 = mock.Mock()
arbiter.LISTENERS = [listener1, listener2] arbiter.LISTENERS = [listener1, listener2]
arbiter.stop() arbiter.stop()
listener1.close.assert_called_with() listener1.close.assert_called_with(False)
listener2.close.assert_called_with() listener2.close.assert_called_with(False)
class PreloadedAppWithEnvSettings(DummyApplication): class PreloadedAppWithEnvSettings(DummyApplication):

View File

@ -6,10 +6,10 @@ from gunicorn.util import tmpfile
def test_lockfile(): def test_lockfile():
lockname = tmpfile(prefix="gunicorn-tests", suffix=".lock") lockname = tmpfile(prefix="gunicorn-tests", suffix=".lock")
lock_file = LockFile(lockname) lock_file = LockFile(lockname)
assert lock_file.released() == True assert lock_file.locked() == False
assert os.path.exists(lockname) assert os.path.exists(lockname)
lock_file.acquire() lock_file.lock()
assert lock_file.released() == False assert lock_file.locked() == True
lock_file.release() lock_file.unlock()
assert lock_file.released() == True assert lock_file.locked() == False
assert os.path.exists(lockname) == False assert os.path.exists(lockname) == False

View File

@ -11,10 +11,19 @@ from gunicorn import sock
@mock.patch('socket.fromfd') @mock.patch('socket.fromfd')
def test_unix_socket_close_delete_if_exlock(fromfd, unlink, getpid): def test_unix_socket_close_delete_if_exlock(fromfd, unlink, getpid):
gsock = sock.UnixSocket('test.sock', mock.Mock(), mock.Mock(), mock.Mock()) gsock = sock.UnixSocket('test.sock', mock.Mock(), mock.Mock(), mock.Mock())
gsock.destroy() gsock.close(False)
unlink.assert_called_with('test.sock') unlink.assert_called_with('test.sock')
@mock.patch('os.getpid')
@mock.patch('os.unlink')
@mock.patch('socket.fromfd')
def test_unix_socket_close_keep_if_no_exlock(fromfd, unlink, getpid):
gsock = sock.UnixSocket('test.sock', mock.Mock(), mock.Mock(), mock.Mock())
gsock.close(True)
unlink.assert_not_called()
@mock.patch('os.getpid') @mock.patch('os.getpid')
@mock.patch('os.unlink') @mock.patch('os.unlink')
@mock.patch('socket.fromfd') @mock.patch('socket.fromfd')
@ -23,5 +32,5 @@ def test_unix_socket_not_deleted_by_worker(fromfd, unlink, getpid):
gsock = sock.UnixSocket('test.sock', mock.Mock(), mock.Mock(), fd) gsock = sock.UnixSocket('test.sock', mock.Mock(), mock.Mock(), fd)
getpid.reset_mock() getpid.reset_mock()
getpid.return_value = "fake" # fake a pid change getpid.return_value = "fake" # fake a pid change
gsock.destroy() gsock.close(False)
unlink.assert_not_called() unlink.assert_not_called()