mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-08-14 02:26:58 -07:00
Add zc.lockfile-2.0
This commit is contained in:
parent
bc81f19715
commit
a68e5f6519
4 changed files with 397 additions and 0 deletions
125
lib/zc/lockfile/__init__.py
Normal file
125
lib/zc/lockfile/__init__.py
Normal file
|
@ -0,0 +1,125 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# This software is subject to the provisions of the Zope Public License,
|
||||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import os
|
||||
import errno
|
||||
import logging
|
||||
logger = logging.getLogger("zc.lockfile")
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
class LockError(Exception):
|
||||
"""Couldn't get a lock
|
||||
"""
|
||||
|
||||
try:
|
||||
import fcntl
|
||||
except ImportError:
|
||||
try:
|
||||
import msvcrt
|
||||
except ImportError:
|
||||
def _lock_file(file):
|
||||
raise TypeError('No file-locking support on this platform')
|
||||
def _unlock_file(file):
|
||||
raise TypeError('No file-locking support on this platform')
|
||||
|
||||
else:
|
||||
# Windows
|
||||
def _lock_file(file):
|
||||
# Lock just the first byte
|
||||
try:
|
||||
msvcrt.locking(file.fileno(), msvcrt.LK_NBLCK, 1)
|
||||
except IOError:
|
||||
raise LockError("Couldn't lock %r" % file.name)
|
||||
|
||||
def _unlock_file(file):
|
||||
try:
|
||||
file.seek(0)
|
||||
msvcrt.locking(file.fileno(), msvcrt.LK_UNLCK, 1)
|
||||
except IOError:
|
||||
raise LockError("Couldn't unlock %r" % file.name)
|
||||
|
||||
else:
|
||||
# Unix
|
||||
_flags = fcntl.LOCK_EX | fcntl.LOCK_NB
|
||||
|
||||
def _lock_file(file):
|
||||
try:
|
||||
fcntl.flock(file.fileno(), _flags)
|
||||
except IOError:
|
||||
raise LockError("Couldn't lock %r" % file.name)
|
||||
|
||||
def _unlock_file(file):
|
||||
fcntl.flock(file.fileno(), fcntl.LOCK_UN)
|
||||
|
||||
class LazyHostName:
|
||||
"""Avoid importing socket and calling gethostname() unnecessarily"""
|
||||
def __str__(self):
|
||||
import socket
|
||||
return socket.gethostname()
|
||||
|
||||
|
||||
class SimpleLockFile:
|
||||
|
||||
_fp = None
|
||||
|
||||
def __init__(self, path):
|
||||
self._path = path
|
||||
try:
|
||||
# Try to open for writing without truncation:
|
||||
fp = open(path, 'r+')
|
||||
except IOError:
|
||||
# If the file doesn't exist, we'll get an IO error, try a+
|
||||
# Note that there may be a race here. Multiple processes
|
||||
# could fail on the r+ open and open the file a+, but only
|
||||
# one will get the the lock and write a pid.
|
||||
fp = open(path, 'a+')
|
||||
|
||||
try:
|
||||
_lock_file(fp)
|
||||
self._fp = fp
|
||||
except:
|
||||
fp.close()
|
||||
raise
|
||||
|
||||
# Lock acquired
|
||||
self._on_lock()
|
||||
fp.flush()
|
||||
|
||||
def close(self):
|
||||
if self._fp is not None:
|
||||
_unlock_file(self._fp)
|
||||
self._fp.close()
|
||||
self._fp = None
|
||||
|
||||
def _on_lock(self):
|
||||
"""
|
||||
Allow subclasses to supply behavior to occur following
|
||||
lock acquisition.
|
||||
"""
|
||||
|
||||
|
||||
class LockFile(SimpleLockFile):
|
||||
|
||||
def __init__(self, path, content_template='{pid}'):
|
||||
self._content_template = content_template
|
||||
super(LockFile, self).__init__(path)
|
||||
|
||||
def _on_lock(self):
|
||||
content = self._content_template.format(
|
||||
pid=os.getpid(),
|
||||
hostname=LazyHostName(),
|
||||
)
|
||||
self._fp.write(" %s\n" % content)
|
||||
self._fp.truncate()
|
Loading…
Add table
Add a link
Reference in a new issue