[entropy.misc] add FlockFile class

The purpose of this class is to implement a file-based lock,
abstracting away from fcntl.
This commit is contained in:
Fabio Erculiani
2012-02-15 17:23:32 +01:00
parent 6cdede57ab
commit 7c2c9437bb
2 changed files with 98 additions and 1 deletions
+79
View File
@@ -15,6 +15,8 @@
import os
import sys
import time
import fcntl
import errno
import codecs
if sys.hexversion >= 0x3000000:
import urllib.request, urllib.error, urllib.parse
@@ -26,8 +28,10 @@ else:
import logging
import threading
from collections import deque
from entropy.const import etpConst, const_isunicode, \
const_isfileobj, const_convert_log_level, const_setup_file
from entropy.exceptions import EntropyException
import entropy.tools
@@ -540,6 +544,81 @@ class MasterSlaveLock(object):
self.__master_locked = False
class FlockFile(object):
"""
Of flock() operations on a file.
"""
class FlockFileInitFailure(EntropyException):
"""
FlockFile initialization failure exception.
Can be raised either because file path does
not exist (missing directory) or permissions
are not sufficient.
"""
def __init__(self, file_path, fd = None):
self._path = file_path
if fd is None:
try:
self._f = open(self._path, "a+")
except IOError as err:
if err.errno in (errno.ENOENT, errno.EACCES):
raise FlockFileInitFailure(err)
raise
else:
self._f = os.fdopen(fd)
def acquire_shared(self):
"""
Acquire the lock in shared mode.
"""
flags = fcntl.LOCK_SH
try:
fcntl.flock(self._f.fileno(), flags)
except IOError as err:
self.close()
raise
def acquire_exclusive(self):
"""
Acquire the lock in exclusive mode.
"""
flags = fcntl.LOCK_EX
try:
fcntl.flock(self._f.fileno(), flags)
except IOError as err:
self.close()
raise
def promote(self):
"""
Promote a lock acquired in shared mode to exclusive mode.
"""
self.acquire_shared()
self.acquire_exclusive()
def demote(self):
"""
Demote a lock acquired in exclusive mode to shared mode.
"""
self.release()
self.acquire_shared()
def release(self):
"""
Release the lock previously acquired.
"""
fcntl.flock(self._f.fileno(), fcntl.LOCK_UN)
def close(self):
"""
Close the underlying file object.
"""
self._f.close()
class EmailSender:
"""
+19 -1
View File
@@ -8,7 +8,7 @@ import tempfile
import json
from entropy.const import const_convert_to_unicode
from entropy.misc import Lifo, TimeScheduled, ParallelTask, EmailSender, \
FastRSS
FastRSS, FlockFile
class MiscTest(unittest.TestCase):
@@ -104,6 +104,24 @@ class MiscTest(unittest.TestCase):
#print "joined"
self.assertTrue(self.t_sched_run)
def test_flock_file(self):
tmp_fd, tmp_path = None, None
try:
tmp_fd, tmp_path = tempfile.mkstemp(prefix="entropy.misc.test")
mf = FlockFile(tmp_path, fd = tmp_fd)
mf.acquire_exclusive()
mf.demote()
mf.promote()
mf.release()
mf.acquire_shared()
mf.release()
mf.close()
finally:
if tmp_fd is not None:
self.assertRaises(OSError, os.close, tmp_fd)
if tmp_path is not None:
os.remove(tmp_path)
def test_email_sender(self):
mail_sender = 'test@test.com'