cvslock.py :  » Language-Interface » ChinesePython » chinesepython2.1.3-0.4 » Demo » pdist » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Language Interface » ChinesePython 
ChinesePython » chinesepython2.1.3 0.4 » Demo » pdist » cvslock.py
"""CVS locking algorithm.

CVS locking strategy
====================

As reverse engineered from the CVS 1.3 sources (file lock.c):

- Locking is done on a per repository basis (but a process can hold
write locks for multiple directories); all lock files are placed in
the repository and have names beginning with "#cvs.".

- Before even attempting to lock, a file "#cvs.tfl.<pid>" is created
(and removed again), to test that we can write the repository.  [The
algorithm can still be fooled (1) if the repository's mode is changed
while attempting to lock; (2) if this file exists and is writable but
the directory is not.]

- While creating the actual read/write lock files (which may exist for
a long time), a "meta-lock" is held.  The meta-lock is a directory
named "#cvs.lock" in the repository.  The meta-lock is also held while
a write lock is held.

- To set a read lock:

  - acquire the meta-lock
  - create the file "#cvs.rfl.<pid>"
  - release the meta-lock

- To set a write lock:

  - acquire the meta-lock
  - check that there are no files called "#cvs.rfl.*"
    - if there are, release the meta-lock, sleep, try again
  - create the file "#cvs.wfl.<pid>"

- To release a write lock:

  - remove the file "#cvs.wfl.<pid>"
  - rmdir the meta-lock

- To release a read lock:

  - remove the file "#cvs.rfl.<pid>"


Additional notes
----------------

- A process should read-lock at most one repository at a time.

- A process may write-lock as many repositories as it wishes (to avoid
deadlocks, I presume it should always lock them top-down in the
directory hierarchy).

- A process should make sure it removes all its lock files and
directories when it crashes.

- Limitation: one user id should not be committing files into the same
repository at the same time.


Turn this into Python code
--------------------------

rl = ReadLock(repository, waittime)

wl = WriteLock(repository, waittime)

list = MultipleWriteLock([repository1, repository2, ...], waittime)

"""


import os
import time
import stat
import pwd


# Default wait time
DELAY = 10


# XXX This should be the same on all Unix versions
EEXIST = 17


# Files used for locking (must match cvs.h in the CVS sources)
CVSLCK = "#cvs.lck"
CVSRFL = "#cvs.rfl."
CVSWFL = "#cvs.wfl."


class Error:

  def __init__(self, msg):
    self.msg = msg

  def __repr__(self):
    return repr(self.msg)

  def __str__(self):
    return str(self.msg)


class Locked(Error):
  pass


class Lock:

  def __init__(self, repository = ".", delay = DELAY):
    self.repository = repository
    self.delay = delay
    self.lockdir = None
    self.lockfile = None
    pid = `os.getpid()`
    self.cvslck = self.join(CVSLCK)
    self.cvsrfl = self.join(CVSRFL + pid)
    self.cvswfl = self.join(CVSWFL + pid)

  def __del__(self):
    print "__del__"
    self.unlock()

  def setlockdir(self):
    while 1:
      try:
        self.lockdir = self.cvslck
        os.mkdir(self.cvslck, 0777)
        return
      except os.error, msg:
        self.lockdir = None
        if msg[0] == EEXIST:
          try:
            st = os.stat(self.cvslck)
          except os.error:
            continue
          self.sleep(st)
          continue
        raise Error("failed to lock %s: %s" % (
          self.repository, msg))

  def unlock(self):
    self.unlockfile()
    self.unlockdir()

  def unlockfile(self):
    if self.lockfile:
      print "unlink", self.lockfile
      try:
        os.unlink(self.lockfile)
      except os.error:
        pass
      self.lockfile = None

  def unlockdir(self):
    if self.lockdir:
      print "rmdir", self.lockdir
      try:
        os.rmdir(self.lockdir)
      except os.error:
        pass
      self.lockdir = None

  def sleep(self, st):
    sleep(st, self.repository, self.delay)

  def join(self, name):
    return os.path.join(self.repository, name)


def sleep(st, repository, delay):
  if delay <= 0:
    raise Locked(st)
  uid = st[stat.ST_UID]
  try:
    pwent = pwd.getpwuid(uid)
    user = pwent[0]
  except KeyError:
    user = "uid %d" % uid
  print "[%s]" % time.ctime(time.time())[11:19],
  print "Waiting for %s's lock in" % user, repository
  time.sleep(delay)


class ReadLock(Lock):

  def __init__(self, repository, delay = DELAY):
    Lock.__init__(self, repository, delay)
    ok = 0
    try:
      self.setlockdir()
      self.lockfile = self.cvsrfl
      fp = open(self.lockfile, 'w')
      fp.close()
      ok = 1
    finally:
      if not ok:
        self.unlockfile()
      self.unlockdir()


class WriteLock(Lock):

  def __init__(self, repository, delay = DELAY):
    Lock.__init__(self, repository, delay)
    self.setlockdir()
    while 1:
      uid = self.readers_exist()
      if not uid:
        break
      self.unlockdir()
      self.sleep(uid)
    self.lockfile = self.cvswfl
    fp = open(self.lockfile, 'w')
    fp.close()

  def readers_exist(self):
    n = len(CVSRFL)
    for name in os.listdir(self.repository):
      if name[:n] == CVSRFL:
        try:
          st = os.stat(self.join(name))
        except os.error:
          continue
        return st
    return None


def MultipleWriteLock(repositories, delay = DELAY):
  while 1:
    locks = []
    for r in repositories:
      try:
        locks.append(WriteLock(r, 0))
      except Locked, instance:
        del locks
        break
    else:
      break
    sleep(instance.msg, r, delay)
  return list


def test():
  import sys
  if sys.argv[1:]:
    repository = sys.argv[1]
  else:
    repository = "."
  rl = None
  wl = None
  try:
    print "attempting write lock ..."
    wl = WriteLock(repository)
    print "got it."
    wl.unlock()
    print "attempting read lock ..."
    rl = ReadLock(repository)
    print "got it."
    rl.unlock()
  finally:
    print [1]
    sys.exc_traceback = None
    print [2]
    if rl:
      rl.unlock()
    print [3]
    if wl:
      wl.unlock()
    print [4]
    rl = None
    print [5]
    wl = None
    print [6]


if __name__ == '__main__':
  test()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.