| OLD | NEW |
| (Empty) |
| 1 # -*- test-case-name: twisted.test.test_lockfile -*- | |
| 2 # Copyright (c) 2005 Divmod, Inc. | |
| 3 # See LICENSE for details. | |
| 4 | |
| 5 | |
| 6 """ | |
| 7 Lock files. | |
| 8 """ | |
| 9 | |
| 10 __metaclass__ = type | |
| 11 | |
| 12 import errno, os | |
| 13 | |
| 14 from time import time as _uniquefloat | |
| 15 | |
| 16 def unique(): | |
| 17 return str(long(_uniquefloat() * 1000)) | |
| 18 | |
| 19 try: | |
| 20 from os import symlink | |
| 21 from os import readlink | |
| 22 from os import remove as rmlink | |
| 23 from os import rename as mvlink | |
| 24 except: | |
| 25 # XXX Implement an atomic thingamajig for win32 | |
| 26 import shutil | |
| 27 def symlink(value, filename): | |
| 28 newlinkname = filename+"."+unique()+'.newlink' | |
| 29 newvalname = os.path.join(newlinkname,"symlink") | |
| 30 os.mkdir(newlinkname) | |
| 31 f = open(newvalname,'wb') | |
| 32 f.write(value) | |
| 33 f.flush() | |
| 34 f.close() | |
| 35 try: | |
| 36 os.rename(newlinkname, filename) | |
| 37 except: | |
| 38 os.remove(newvalname) | |
| 39 os.rmdir(newlinkname) | |
| 40 raise | |
| 41 | |
| 42 def readlink(filename): | |
| 43 return open(os.path.join(filename,'symlink'),'rb').read() | |
| 44 | |
| 45 def rmlink(filename): | |
| 46 shutil.rmtree(filename) | |
| 47 | |
| 48 def mvlink(src, dest): | |
| 49 try: | |
| 50 shutil.rmtree(dest) | |
| 51 except: | |
| 52 pass | |
| 53 os.rename(src,dest) | |
| 54 | |
| 55 | |
| 56 class FilesystemLock: | |
| 57 """A mutex. | |
| 58 | |
| 59 This relies on the filesystem property that creating | |
| 60 a symlink is an atomic operation and that it will | |
| 61 fail if the symlink already exists. Deleting the | |
| 62 symlink will release the lock. | |
| 63 | |
| 64 @ivar name: The name of the file associated with this lock. | |
| 65 @ivar clean: Indicates whether this lock was released cleanly by its | |
| 66 last owner. Only meaningful after C{lock} has been called and returns | |
| 67 True. | |
| 68 """ | |
| 69 | |
| 70 clean = None | |
| 71 locked = False | |
| 72 | |
| 73 def __init__(self, name): | |
| 74 self.name = name | |
| 75 | |
| 76 def lock(self): | |
| 77 """Acquire this lock. | |
| 78 | |
| 79 @rtype: C{bool} | |
| 80 @return: True if the lock is acquired, false otherwise. | |
| 81 | |
| 82 @raise: Any exception os.symlink() may raise, other than | |
| 83 EEXIST. | |
| 84 """ | |
| 85 try: | |
| 86 pid = readlink(self.name) | |
| 87 except (OSError, IOError), e: | |
| 88 if e.errno != errno.ENOENT: | |
| 89 raise | |
| 90 self.clean = True | |
| 91 else: | |
| 92 if not hasattr(os, 'kill'): | |
| 93 return False | |
| 94 try: | |
| 95 os.kill(int(pid), 0) | |
| 96 except (OSError, IOError), e: | |
| 97 if e.errno != errno.ESRCH: | |
| 98 raise | |
| 99 rmlink(self.name) | |
| 100 self.clean = False | |
| 101 else: | |
| 102 return False | |
| 103 | |
| 104 symlink(str(os.getpid()), self.name) | |
| 105 self.locked = True | |
| 106 return True | |
| 107 | |
| 108 def unlock(self): | |
| 109 """Release this lock. | |
| 110 | |
| 111 This deletes the directory with the given name. | |
| 112 | |
| 113 @raise: Any exception os.readlink() may raise, or | |
| 114 ValueError if the lock is not owned by this process. | |
| 115 """ | |
| 116 pid = readlink(self.name) | |
| 117 if int(pid) != os.getpid(): | |
| 118 raise ValueError("Lock %r not owned by this process" % (self.name,)) | |
| 119 rmlink(self.name) | |
| 120 self.locked = False | |
| 121 | |
| 122 | |
| 123 def isLocked(name): | |
| 124 """Determine if the lock of the given name is held or not. | |
| 125 | |
| 126 @type name: C{str} | |
| 127 @param name: The filesystem path to the lock to test | |
| 128 | |
| 129 @rtype: C{bool} | |
| 130 @return: True if the lock is held, False otherwise. | |
| 131 """ | |
| 132 l = FilesystemLock(name) | |
| 133 result = None | |
| 134 try: | |
| 135 result = l.lock() | |
| 136 finally: | |
| 137 if result: | |
| 138 l.unlock() | |
| 139 return not result | |
| 140 | |
| 141 | |
| 142 __all__ = ['FilesystemLock', 'isLocked'] | |
| 143 | |
| OLD | NEW |