Patchwork [4,of,5,V2] censor: make censor acquire locks before processing

mail settings
Submitter Katsunori FUJIWARA
Date Dec. 9, 2015, 12:21 a.m.
Message ID <cec0b4d331b1fca867fc.1449620483@feefifofum>
Download mbox | patch
Permalink /patch/11944/
State Accepted
Headers show


Katsunori FUJIWARA - Dec. 9, 2015, 12:21 a.m.
# HG changeset patch
# User FUJIWARA Katsunori <>
# Date 1449617333 -32400
#      Wed Dec 09 08:28:53 2015 +0900
# Node ID cec0b4d331b1fca867fcf4b567c69e1718576fe9
# Parent  f67cce78a8dcd70a645267cfec27f45b713d6456
censor: make censor acquire locks before processing

Before this patch, "hg censor" executes below:

  - without acquisition of wlock, examine whether the working
    directory refers the revision of the file to be censored or not

  - without acquisition of store lock (slock), replace existing
    filelog of file to be censored with censored one,

    Replacement consists of steps below, and it is assumed that the
    destination filelog at (1) isn't changed before renaming at (3).

    1. read existing filelog in
    2. write filelog entries (both censored and not) into temporary file
    3. rename from temporary file to existing filelog to be censored

It may cause unintentional result, if another command runs parallelly
(see also issue4368).

This patch makes "hg censor" acquire wlock and slock before


diff --git a/hgext/ b/hgext/
--- a/hgext/
+++ b/hgext/
@@ -28,6 +28,7 @@  revisions if they are allowed by the "ce
 from mercurial.node import short
 from mercurial import cmdutil, error, filelog, revlog, scmutil, util
 from mercurial.i18n import _
+from mercurial import lock as lockmod
 cmdtable = {}
 command = cmdutil.command(cmdtable)
@@ -42,6 +43,15 @@  testedwith = 'internal'
      ('t', 'tombstone', '', _('replacement tombstone data'), _('TEXT'))],
     _('-r REV [-t TEXT] [FILE]'))
 def censor(ui, repo, path, rev='', tombstone='', **opts):
+    wlock = lock = None
+    try:
+        wlock = repo.wlock()
+        lock = repo.lock()
+        return _docensor(ui, repo, path, rev, tombstone, **opts)
+    finally:
+        lockmod.release(lock, wlock)
+def _docensor(ui, repo, path, rev='', tombstone='', **opts):
     if not path:
         raise error.Abort(_('must specify file path to censor'))
     if not rev: