Simply repository locking
authormpm@selenic.com
Thu, 26 May 2005 08:53:04 -0800
changeset 161 0b4c5cb953d9
parent 160 5c331d941c7f
child 162 5dcbe4d9a30c
Simply repository locking This is a first pass at implementing repo locking. Next up, journal recovery and undo.
mercurial/hg.py
mercurial/lock.py
--- a/mercurial/hg.py	Wed May 25 16:40:22 2005 -0800
+++ b/mercurial/hg.py	Thu May 26 08:53:04 2005 -0800
@@ -7,7 +7,7 @@
 
 import sys, struct, sha, socket, os, time, re, urllib2
 import urllib
-from mercurial import byterange
+from mercurial import byterange, lock
 from mercurial.transaction import *
 from mercurial.revlog import *
 from difflib import SequenceMatcher
@@ -297,7 +297,17 @@
         return transaction(self.opener, self.join("journal"),
                            self.join("undo"))
 
+    def lock(self, wait = 1):
+        try:
+            return lock.lock(self.join("lock"), 0)
+        except lock.LockHeld, inst:
+            if wait:
+                self.ui.warn("waiting for lock held by %s\n" % inst.args[0])
+                return lock.lock(self.join("lock"), wait)
+            raise inst
+
     def commit(self, parent, update = None, text = ""):
+        self.lock()
         try:
             remove = [ l[:-1] for l in self.opener("to-remove") ]
             os.unlink(self.join("to-remove"))
@@ -612,6 +622,7 @@
             yield "".join([l, f, g])
 
     def addchangegroup(self, generator):
+        self.lock()
         class genread:
             def __init__(self, generator):
                 self.g = generator
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/lock.py	Thu May 26 08:53:04 2005 -0800
@@ -0,0 +1,46 @@
+# lock.py - simple locking scheme for mercurial
+#
+# Copyright 2005 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+import os, time
+
+class LockHeld(Exception):
+    pass
+
+class lock:
+    def __init__(self, file, wait = 1):
+        self.f = file
+        self.held = 0
+        self.wait = wait
+        self.lock()
+
+    def __del__(self):
+        self.release()
+
+    def lock(self):
+        while 1:
+            try:
+                self.trylock()
+                return 1
+            except LockHeld, inst:
+                if self.wait:
+                    time.sleep(1)
+                    continue
+                raise inst
+        
+    def trylock(self):
+        pid = os.getpid()
+        try:
+            os.symlink(str(pid), self.f)
+            self.held = 1
+        except:
+            raise LockHeld(os.readlink(self.f))
+
+    def release(self):
+        if self.held:
+            self.held = 0
+            os.unlink(self.f)
+