symbian-qemu-0.9.1-12/python-2.6.1/Demo/pdist/cvslock.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """CVS locking algorithm.
       
     2 
       
     3 CVS locking strategy
       
     4 ====================
       
     5 
       
     6 As reverse engineered from the CVS 1.3 sources (file lock.c):
       
     7 
       
     8 - Locking is done on a per repository basis (but a process can hold
       
     9 write locks for multiple directories); all lock files are placed in
       
    10 the repository and have names beginning with "#cvs.".
       
    11 
       
    12 - Before even attempting to lock, a file "#cvs.tfl.<pid>" is created
       
    13 (and removed again), to test that we can write the repository.  [The
       
    14 algorithm can still be fooled (1) if the repository's mode is changed
       
    15 while attempting to lock; (2) if this file exists and is writable but
       
    16 the directory is not.]
       
    17 
       
    18 - While creating the actual read/write lock files (which may exist for
       
    19 a long time), a "meta-lock" is held.  The meta-lock is a directory
       
    20 named "#cvs.lock" in the repository.  The meta-lock is also held while
       
    21 a write lock is held.
       
    22 
       
    23 - To set a read lock:
       
    24 
       
    25         - acquire the meta-lock
       
    26         - create the file "#cvs.rfl.<pid>"
       
    27         - release the meta-lock
       
    28 
       
    29 - To set a write lock:
       
    30 
       
    31         - acquire the meta-lock
       
    32         - check that there are no files called "#cvs.rfl.*"
       
    33                 - if there are, release the meta-lock, sleep, try again
       
    34         - create the file "#cvs.wfl.<pid>"
       
    35 
       
    36 - To release a write lock:
       
    37 
       
    38         - remove the file "#cvs.wfl.<pid>"
       
    39         - rmdir the meta-lock
       
    40 
       
    41 - To release a read lock:
       
    42 
       
    43         - remove the file "#cvs.rfl.<pid>"
       
    44 
       
    45 
       
    46 Additional notes
       
    47 ----------------
       
    48 
       
    49 - A process should read-lock at most one repository at a time.
       
    50 
       
    51 - A process may write-lock as many repositories as it wishes (to avoid
       
    52 deadlocks, I presume it should always lock them top-down in the
       
    53 directory hierarchy).
       
    54 
       
    55 - A process should make sure it removes all its lock files and
       
    56 directories when it crashes.
       
    57 
       
    58 - Limitation: one user id should not be committing files into the same
       
    59 repository at the same time.
       
    60 
       
    61 
       
    62 Turn this into Python code
       
    63 --------------------------
       
    64 
       
    65 rl = ReadLock(repository, waittime)
       
    66 
       
    67 wl = WriteLock(repository, waittime)
       
    68 
       
    69 list = MultipleWriteLock([repository1, repository2, ...], waittime)
       
    70 
       
    71 """
       
    72 
       
    73 
       
    74 import os
       
    75 import time
       
    76 import stat
       
    77 import pwd
       
    78 
       
    79 
       
    80 # Default wait time
       
    81 DELAY = 10
       
    82 
       
    83 
       
    84 # XXX This should be the same on all Unix versions
       
    85 EEXIST = 17
       
    86 
       
    87 
       
    88 # Files used for locking (must match cvs.h in the CVS sources)
       
    89 CVSLCK = "#cvs.lck"
       
    90 CVSRFL = "#cvs.rfl."
       
    91 CVSWFL = "#cvs.wfl."
       
    92 
       
    93 
       
    94 class Error:
       
    95 
       
    96     def __init__(self, msg):
       
    97         self.msg = msg
       
    98 
       
    99     def __repr__(self):
       
   100         return repr(self.msg)
       
   101 
       
   102     def __str__(self):
       
   103         return str(self.msg)
       
   104 
       
   105 
       
   106 class Locked(Error):
       
   107     pass
       
   108 
       
   109 
       
   110 class Lock:
       
   111 
       
   112     def __init__(self, repository = ".", delay = DELAY):
       
   113         self.repository = repository
       
   114         self.delay = delay
       
   115         self.lockdir = None
       
   116         self.lockfile = None
       
   117         pid = repr(os.getpid())
       
   118         self.cvslck = self.join(CVSLCK)
       
   119         self.cvsrfl = self.join(CVSRFL + pid)
       
   120         self.cvswfl = self.join(CVSWFL + pid)
       
   121 
       
   122     def __del__(self):
       
   123         print "__del__"
       
   124         self.unlock()
       
   125 
       
   126     def setlockdir(self):
       
   127         while 1:
       
   128             try:
       
   129                 self.lockdir = self.cvslck
       
   130                 os.mkdir(self.cvslck, 0777)
       
   131                 return
       
   132             except os.error, msg:
       
   133                 self.lockdir = None
       
   134                 if msg[0] == EEXIST:
       
   135                     try:
       
   136                         st = os.stat(self.cvslck)
       
   137                     except os.error:
       
   138                         continue
       
   139                     self.sleep(st)
       
   140                     continue
       
   141                 raise Error("failed to lock %s: %s" % (
       
   142                         self.repository, msg))
       
   143 
       
   144     def unlock(self):
       
   145         self.unlockfile()
       
   146         self.unlockdir()
       
   147 
       
   148     def unlockfile(self):
       
   149         if self.lockfile:
       
   150             print "unlink", self.lockfile
       
   151             try:
       
   152                 os.unlink(self.lockfile)
       
   153             except os.error:
       
   154                 pass
       
   155             self.lockfile = None
       
   156 
       
   157     def unlockdir(self):
       
   158         if self.lockdir:
       
   159             print "rmdir", self.lockdir
       
   160             try:
       
   161                 os.rmdir(self.lockdir)
       
   162             except os.error:
       
   163                 pass
       
   164             self.lockdir = None
       
   165 
       
   166     def sleep(self, st):
       
   167         sleep(st, self.repository, self.delay)
       
   168 
       
   169     def join(self, name):
       
   170         return os.path.join(self.repository, name)
       
   171 
       
   172 
       
   173 def sleep(st, repository, delay):
       
   174     if delay <= 0:
       
   175         raise Locked(st)
       
   176     uid = st[stat.ST_UID]
       
   177     try:
       
   178         pwent = pwd.getpwuid(uid)
       
   179         user = pwent[0]
       
   180     except KeyError:
       
   181         user = "uid %d" % uid
       
   182     print "[%s]" % time.ctime(time.time())[11:19],
       
   183     print "Waiting for %s's lock in" % user, repository
       
   184     time.sleep(delay)
       
   185 
       
   186 
       
   187 class ReadLock(Lock):
       
   188 
       
   189     def __init__(self, repository, delay = DELAY):
       
   190         Lock.__init__(self, repository, delay)
       
   191         ok = 0
       
   192         try:
       
   193             self.setlockdir()
       
   194             self.lockfile = self.cvsrfl
       
   195             fp = open(self.lockfile, 'w')
       
   196             fp.close()
       
   197             ok = 1
       
   198         finally:
       
   199             if not ok:
       
   200                 self.unlockfile()
       
   201             self.unlockdir()
       
   202 
       
   203 
       
   204 class WriteLock(Lock):
       
   205 
       
   206     def __init__(self, repository, delay = DELAY):
       
   207         Lock.__init__(self, repository, delay)
       
   208         self.setlockdir()
       
   209         while 1:
       
   210             uid = self.readers_exist()
       
   211             if not uid:
       
   212                 break
       
   213             self.unlockdir()
       
   214             self.sleep(uid)
       
   215         self.lockfile = self.cvswfl
       
   216         fp = open(self.lockfile, 'w')
       
   217         fp.close()
       
   218 
       
   219     def readers_exist(self):
       
   220         n = len(CVSRFL)
       
   221         for name in os.listdir(self.repository):
       
   222             if name[:n] == CVSRFL:
       
   223                 try:
       
   224                     st = os.stat(self.join(name))
       
   225                 except os.error:
       
   226                     continue
       
   227                 return st
       
   228         return None
       
   229 
       
   230 
       
   231 def MultipleWriteLock(repositories, delay = DELAY):
       
   232     while 1:
       
   233         locks = []
       
   234         for r in repositories:
       
   235             try:
       
   236                 locks.append(WriteLock(r, 0))
       
   237             except Locked, instance:
       
   238                 del locks
       
   239                 break
       
   240         else:
       
   241             break
       
   242         sleep(instance.msg, r, delay)
       
   243     return list
       
   244 
       
   245 
       
   246 def test():
       
   247     import sys
       
   248     if sys.argv[1:]:
       
   249         repository = sys.argv[1]
       
   250     else:
       
   251         repository = "."
       
   252     rl = None
       
   253     wl = None
       
   254     try:
       
   255         print "attempting write lock ..."
       
   256         wl = WriteLock(repository)
       
   257         print "got it."
       
   258         wl.unlock()
       
   259         print "attempting read lock ..."
       
   260         rl = ReadLock(repository)
       
   261         print "got it."
       
   262         rl.unlock()
       
   263     finally:
       
   264         print [1]
       
   265         sys.exc_traceback = None
       
   266         print [2]
       
   267         if rl:
       
   268             rl.unlock()
       
   269         print [3]
       
   270         if wl:
       
   271             wl.unlock()
       
   272         print [4]
       
   273         rl = None
       
   274         print [5]
       
   275         wl = None
       
   276         print [6]
       
   277 
       
   278 
       
   279 if __name__ == '__main__':
       
   280     test()