[PATCH 2 of 3] lock: add ability to store additional metadata on filesytem

Phil Cohen phillco at fb.com
Mon Mar 20 03:49:06 EDT 2017


# HG changeset patch
# User Phil Cohen <phillco at fb.com>
# Date 1489995201 25200
#      Mon Mar 20 00:33:21 2017 -0700
# Node ID 1ca023fb02cbe4747e2b5b625866cfa538cbebd3
# Parent  2c1d5a02ec533055f182b0cc1280107fbfb76206
lock: add ability to store additional metadata on filesytem

The metadata is written to <lock>.info while the lock is held. It can be
inspected by outside processes to better understand what the lock-holding
process is doing in cases when the PID alone is not enough.

Some examples might include:

- Getting the original command line `hg` is running when the lockholding process
  was a originally `chg` process.
- Finding out what command an `hg` process is running without having to parse
  its command line yourself.

diff --git a/mercurial/lock.py b/mercurial/lock.py
--- a/mercurial/lock.py
+++ b/mercurial/lock.py
@@ -59,8 +59,10 @@
 
     _host = None
 
+    # `metadata` is written to a <lockname>.info file while the lock is held
     def __init__(self, vfs, file, timeout=-1, releasefn=None, acquirefn=None,
-                 desc=None, inheritchecker=None, parentlock=None):
+                 desc=None, inheritchecker=None, parentlock=None,
+                 metadata=None):
         self.vfs = vfs
         self.f = file
         self.held = 0
@@ -70,6 +72,7 @@
         self.desc = desc
         self._inheritchecker = inheritchecker
         self.parentlock = parentlock
+        self.metadata = metadata
         self._parentheld = False
         self._inherited = False
         self.postrelease  = []
@@ -128,6 +131,8 @@
             try:
                 self.vfs.makelock(lockname, self.f)
                 self.held = 1
+                if self.metadata is not None:
+                    self.vfs.write(self.f + '.info', self.metadata)
             except (OSError, IOError) as why:
                 if why.errno == errno.EEXIST:
                     locker = self._readlock()
@@ -248,6 +253,7 @@
                 if not self._parentheld:
                     try:
                         self.vfs.unlink(self.f)
+                        self.vfs.unlink(self.f + '.info')
                     except OSError:
                         pass
             # The postrelease functions typically assume the lock is not held
diff --git a/tests/test-lock-meta.t b/tests/test-lock-meta.t
new file mode 100644
--- /dev/null
+++ b/tests/test-lock-meta.t
@@ -0,0 +1,36 @@
+Make a repo
+
+  $ hg init test
+  $ cd test
+  $ echo file > file
+  $ hg commit -Aqm initial
+
+Make an extension
+
+  $ cat << EOT > lockinfo.py
+  > from contextlib import nested
+  > from mercurial import (cmdutil, extensions, lock)
+  > cmdtable = {}
+  > command = cmdutil.command(cmdtable)
+  > @command('locktest')
+  > def locktest(ui, repo, *args, **opts):
+  >   def readf(path):
+  >      try:
+  >        with open(path, "r") as f:
+  >           return f.read()
+  >      except IOError as e:
+  >         return "<not found>"
+  >   def status(str):
+  >     print(str, readf(".hg/customlock.info"))
+  >   with lock.lock(repo.vfs, "customlock"):
+  >       status("No metadata passed; file should not exist")
+  >   with lock.lock(repo.vfs, "customlock", metadata="/arbitrary/data"):
+  >       status("Should have an info file.")
+  >   status("Should be deleted.")
+  > EOT
+
+Test store and write lock
+  $ hg locktest --config extensions.x=lockinfo.py
+  ('No metadata passed; file should not exist', '<not found>')
+  ('Should have an info file.', '/arbitrary/data')
+  ('Should be deleted.', '<not found>')


More information about the Mercurial-devel mailing list