Revision a87b4824
b/lib/utils.py | ||
---|---|---|
1192 | 1192 |
raise |
1193 | 1193 |
|
1194 | 1194 |
|
1195 |
class FileLock(object): |
|
1196 |
"""Utility class for file locks. |
|
1197 |
|
|
1198 |
""" |
|
1199 |
def __init__(self, filename): |
|
1200 |
self.filename = filename |
|
1201 |
self.fd = open(self.filename, "w") |
|
1202 |
|
|
1203 |
def __del__(self): |
|
1204 |
self.Close() |
|
1205 |
|
|
1206 |
def Close(self): |
|
1207 |
if self.fd: |
|
1208 |
self.fd.close() |
|
1209 |
self.fd = None |
|
1210 |
|
|
1211 |
def _flock(self, flag, blocking, errmsg): |
|
1212 |
assert self.fd, "Lock was closed" |
|
1213 |
|
|
1214 |
if not blocking: |
|
1215 |
flag |= fcntl.LOCK_NB |
|
1216 |
|
|
1217 |
try: |
|
1218 |
fcntl.flock(self.fd, flag) |
|
1219 |
except IOError, err: |
|
1220 |
logging.exception("fcntl.flock failed") |
|
1221 |
if err.errno in (errno.EAGAIN, ): |
|
1222 |
raise errors.LockError(errmsg) |
|
1223 |
raise |
|
1224 |
|
|
1225 |
def Exclusive(self, blocking=False): |
|
1226 |
"""Locks the file in exclusive mode. |
|
1227 |
|
|
1228 |
""" |
|
1229 |
self._flock(fcntl.LOCK_EX, blocking, |
|
1230 |
"Failed to lock %s in exclusive mode" % self.filename) |
|
1231 |
|
|
1232 |
def Shared(self, blocking=False): |
|
1233 |
"""Locks the file in shared mode. |
|
1234 |
|
|
1235 |
""" |
|
1236 |
self._flock(fcntl.LOCK_SH, blocking, |
|
1237 |
"Failed to lock %s in shared mode" % self.filename) |
|
1238 |
|
|
1239 |
def Unlock(self, blocking=True): |
|
1240 |
"""Unlocks the file. |
|
1241 |
|
|
1242 |
According to "man flock", unlocking can also be a nonblocking operation: |
|
1243 |
"To make a non-blocking request, include LOCK_NB with any of the above |
|
1244 |
operations" |
|
1245 |
|
|
1246 |
""" |
|
1247 |
self._flock(fcntl.LOCK_UN, blocking, |
|
1248 |
"Failed to unlock %s" % self.filename) |
|
1249 |
|
|
1250 |
|
|
1195 | 1251 |
class SignalHandler(object): |
1196 | 1252 |
"""Generic signal handler class. |
1197 | 1253 |
|
b/test/ganeti.utils_unittest.py | ||
---|---|---|
32 | 32 |
import socket |
33 | 33 |
import shutil |
34 | 34 |
import re |
35 |
import tempfile |
|
36 | 35 |
|
37 | 36 |
import ganeti |
38 | 37 |
import testutils |
... | ... | |
710 | 709 |
self._test(["a", "b"], ["a", "b"]) |
711 | 710 |
self._test(["a", "b", "a"], ["a", "b"]) |
712 | 711 |
|
712 |
|
|
713 | 713 |
class TestFirstFree(unittest.TestCase): |
714 | 714 |
"""Test case for the FirstFree function""" |
715 | 715 |
|
... | ... | |
721 | 721 |
self.failUnlessEqual(FirstFree([3, 4, 6], base=3), 5) |
722 | 722 |
self.failUnlessRaises(AssertionError, FirstFree, [0, 3, 4, 6], base=3) |
723 | 723 |
|
724 |
|
|
725 |
class TestFileLock(unittest.TestCase): |
|
726 |
"""Test case for the FileLock class""" |
|
727 |
|
|
728 |
def setUp(self): |
|
729 |
self.tmpfile = tempfile.NamedTemporaryFile() |
|
730 |
self.lock = utils.FileLock(self.tmpfile.name) |
|
731 |
|
|
732 |
def testSharedNonblocking(self): |
|
733 |
self.lock.Shared(blocking=False) |
|
734 |
self.lock.Close() |
|
735 |
|
|
736 |
def testExclusiveNonblocking(self): |
|
737 |
self.lock.Exclusive(blocking=False) |
|
738 |
self.lock.Close() |
|
739 |
|
|
740 |
def testUnlockNonblocking(self): |
|
741 |
self.lock.Unlock(blocking=False) |
|
742 |
self.lock.Close() |
|
743 |
|
|
744 |
def testSharedBlocking(self): |
|
745 |
self.lock.Shared(blocking=True) |
|
746 |
self.lock.Close() |
|
747 |
|
|
748 |
def testExclusiveBlocking(self): |
|
749 |
self.lock.Exclusive(blocking=True) |
|
750 |
self.lock.Close() |
|
751 |
|
|
752 |
def testUnlockBlocking(self): |
|
753 |
self.lock.Unlock(blocking=True) |
|
754 |
self.lock.Close() |
|
755 |
|
|
756 |
def testSharedExclusiveUnlock(self): |
|
757 |
self.lock.Shared(blocking=False) |
|
758 |
self.lock.Exclusive(blocking=False) |
|
759 |
self.lock.Unlock(blocking=False) |
|
760 |
self.lock.Close() |
|
761 |
|
|
762 |
def testExclusiveSharedUnlock(self): |
|
763 |
self.lock.Exclusive(blocking=False) |
|
764 |
self.lock.Shared(blocking=False) |
|
765 |
self.lock.Unlock(blocking=False) |
|
766 |
self.lock.Close() |
|
767 |
|
|
768 |
def testCloseShared(self): |
|
769 |
self.lock.Close() |
|
770 |
self.assertRaises(AssertionError, self.lock.Shared, blocking=False) |
|
771 |
|
|
772 |
def testCloseExclusive(self): |
|
773 |
self.lock.Close() |
|
774 |
self.assertRaises(AssertionError, self.lock.Exclusive, blocking=False) |
|
775 |
|
|
776 |
def testCloseUnlock(self): |
|
777 |
self.lock.Close() |
|
778 |
self.assertRaises(AssertionError, self.lock.Unlock, blocking=False) |
|
779 |
|
|
780 |
|
|
724 | 781 |
if __name__ == '__main__': |
725 | 782 |
unittest.main() |
Also available in: Unified diff