Patchwork [2,of,5,V3] commands.bookmarks: hold wlock for write operations

login
register
mail settings
Submitter Siddharth Agarwal
Date Dec. 20, 2013, 4:04 p.m.
Message ID <7d19e7757af44d1976cd.1387555442@sid0x220>
Download mbox | patch
Permalink /patch/3220/
State Accepted
Commit 5fe4c1a9dc34c4b4ef85366a32efae9bc7e8c1a1
Headers show

Comments

Siddharth Agarwal - Dec. 20, 2013, 4:04 p.m.
# HG changeset patch
# User Siddharth Agarwal <sid0@fb.com>
# Date 1384893194 28800
#      Tue Nov 19 12:33:14 2013 -0800
# Node ID 7d19e7757af44d1976cd06d08cf82358b85c2e22
# Parent  cc4fbea8fd8863d0e92868fccd9217c3152ae3e5
commands.bookmarks: hold wlock for write operations

Any invocations of bookmarks other than a plain 'hg bookmarks' will likely
cause a write to the bookmark store. These should be guarded by the wlock.

The repo._bookmarks read should be similarly guarded by the wlock if we're
going to be subsequently writing to it.

Patch

diff -r cc4fbea8fd8863d0e92868fccd9217c3152ae3e5 -r 7d19e7757af44d1976cd06d08cf82358b85c2e22 mercurial/commands.py
--- a/mercurial/commands.py	Tue Nov 19 11:47:30 2013 -0800
+++ b/mercurial/commands.py	Tue Nov 19 12:33:14 2013 -0800
@@ -808,7 +808,6 @@  def bookmark(ui, repo, *names, **opts):
     inactive = opts.get('inactive')
 
     hexfn = ui.debugflag and hex or short
-    marks = repo._bookmarks
     cur   = repo.changectx('.').node()
 
     def checkformat(mark):
@@ -862,59 +861,66 @@  def bookmark(ui, repo, *names, **opts):
     if not names and (delete or rev):
         raise util.Abort(_("bookmark name required"))
 
-    if delete:
-        for mark in names:
-            if mark not in marks:
-                raise util.Abort(_("bookmark '%s' does not exist") % mark)
-            if mark == repo._bookmarkcurrent:
-                bookmarks.unsetcurrent(repo)
-            del marks[mark]
-        marks.write()
-
-    elif rename:
-        if not names:
-            raise util.Abort(_("new bookmark name required"))
-        elif len(names) > 1:
-            raise util.Abort(_("only one new bookmark name allowed"))
-        mark = checkformat(names[0])
-        if rename not in marks:
-            raise util.Abort(_("bookmark '%s' does not exist") % rename)
-        checkconflict(repo, mark, force)
-        marks[mark] = marks[rename]
-        if repo._bookmarkcurrent == rename and not inactive:
-            bookmarks.setcurrent(repo, mark)
-        del marks[rename]
-        marks.write()
-
-    elif names:
-        newact = None
-        for mark in names:
-            mark = checkformat(mark)
-            if newact is None:
-                newact = mark
-            if inactive and mark == repo._bookmarkcurrent:
-                bookmarks.unsetcurrent(repo)
-                return
-            tgt = cur
-            if rev:
-                tgt = scmutil.revsingle(repo, rev).node()
-            checkconflict(repo, mark, force, tgt)
-            marks[mark] = tgt
-        if not inactive and cur == marks[newact] and not rev:
-            bookmarks.setcurrent(repo, newact)
-        elif cur != tgt and newact == repo._bookmarkcurrent:
-            bookmarks.unsetcurrent(repo)
-        marks.write()
-
-    elif inactive:
-        if len(marks) == 0:
-            ui.status(_("no bookmarks set\n"))
-        elif not repo._bookmarkcurrent:
-            ui.status(_("no active bookmark\n"))
-        else:
-            bookmarks.unsetcurrent(repo)
-
+    if delete or rename or names or inactive:
+        wlock = repo.wlock()
+        try:
+            marks = repo._bookmarks
+            if delete:
+                for mark in names:
+                    if mark not in marks:
+                        raise util.Abort(_("bookmark '%s' does not exist") %
+                                         mark)
+                    if mark == repo._bookmarkcurrent:
+                        bookmarks.unsetcurrent(repo)
+                    del marks[mark]
+                marks.write()
+
+            elif rename:
+                if not names:
+                    raise util.Abort(_("new bookmark name required"))
+                elif len(names) > 1:
+                    raise util.Abort(_("only one new bookmark name allowed"))
+                mark = checkformat(names[0])
+                if rename not in marks:
+                    raise util.Abort(_("bookmark '%s' does not exist") % rename)
+                checkconflict(repo, mark, force)
+                marks[mark] = marks[rename]
+                if repo._bookmarkcurrent == rename and not inactive:
+                    bookmarks.setcurrent(repo, mark)
+                del marks[rename]
+                marks.write()
+
+            elif names:
+                newact = None
+                for mark in names:
+                    mark = checkformat(mark)
+                    if newact is None:
+                        newact = mark
+                    if inactive and mark == repo._bookmarkcurrent:
+                        bookmarks.unsetcurrent(repo)
+                        return
+                    tgt = cur
+                    if rev:
+                        tgt = scmutil.revsingle(repo, rev).node()
+                    checkconflict(repo, mark, force, tgt)
+                    marks[mark] = tgt
+                if not inactive and cur == marks[newact] and not rev:
+                    bookmarks.setcurrent(repo, newact)
+                elif cur != tgt and newact == repo._bookmarkcurrent:
+                    bookmarks.unsetcurrent(repo)
+                marks.write()
+
+            elif inactive:
+                if len(marks) == 0:
+                    ui.status(_("no bookmarks set\n"))
+                elif not repo._bookmarkcurrent:
+                    ui.status(_("no active bookmark\n"))
+                else:
+                    bookmarks.unsetcurrent(repo)
+        finally:
+            wlock.release()
     else: # show bookmarks
+        marks = repo._bookmarks
         if len(marks) == 0:
             ui.status(_("no bookmarks set\n"))
         else: