[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] Preliminary locking solution

From: Stein Roger Skafløtten <srsmail_at_hotmail.com>
Date: 2004-07-31 13:41:23 CEST

Hi all,

The attached patch implements a preliminary solution for locking files
exclusively in Subversion. So this implementation does not pretend to
be the final locking solution, but rather a simple patch for those who
need locking right now.

A main goal was to change as little as possible and be non-intrusive:
No schema changes, no api changes and no server changes (except for
hook scripts.) So what is basically required is a rebuild of the
client and changing a few hook scripts on the server.

It would be nice to have this functionality in the API, but I realize
such a change requires a well-pondered design (but I sure would
like this stuff in my TSVN client ASAP too...)

[My first attempt on the client was to create a cute little python script,
but unfortunately the RA layer lacked bindings. But then again, having
this functionality in the standard command line client is nicer.]

To start with:
- Directory locks are not supported
- The 'lock' and 'unlock' sub commands require authentication.

lock: Locks the file(s).
usage: lock [--force] [PATH]
  Locks the file(s) exclusively. If the file is already locked by
  another user, an error message will be shown.

  Use the --force option to aquire the lock even if the file is locked
  by another user.

  With -v, also print lock tokens.

Valid options:
  --force : force operation to run
  -v [--verbose] : print extra information
  --targets arg : pass contents of file ARG as additional args
  --username arg : specify a username ARG
  --password arg : specify a password ARG
  --no-auth-cache : do not cache authentication tokens
  --non-interactive : do no interactive prompting
  --config-dir arg : read user configuration files from directory

Sample output: "svn lock --username=gorilla *.*"

        Successfully locked design.tiff
        Successfully locked tribute2revision0.doc
        Could not lock branch.xml: Already locked by 'chimp'
        Could not lock productlist.pdf: Not a versioned resource

Sample, verbose output: "svn lock --force -verbose project.prj"

  Successfully locked project.prj (lock-c3JzL3Rlt3QxLnR4dA---)

[You can see that this is in fact the lock token by doing a
'svn propget lock-c3JzL3Rlc3QxLnR4dA--- --revprop -r 0'
which also prints the current lock owner.]

unlock: Unlocks the file(s).
usage: unlock [PATH]
  Unlocks the file(s). If a file is locked by another user, an
  error message will be shown.
Valid options:
  --targets arg            : pass contents of file ARG as additional args
  --username arg           : specify a username ARG
  --password arg           : specify a password ARG
  --no-auth-cache          : do not cache authentication tokens
  --non-interactive        : do no interactive prompting
  --config-dir arg         : read user configuration files from directory 
Sample output: "svn unlock *.*"
	Successfully unlocked subversion.gif
	Could not unlock air.ogg: The file is locked by 'mozart'
	Could not unlock productlist.pdf:  Not a versioned resource
	Successfully unlocked design.tiff
	Successfully unlocked project.xls
	Successfully unlocked banjo-budget.xls
Attempting to commit changes a file locked by someone else
(the lock-related message is at the end of the entire commit
error message):
$svn ci -m="changed some stuff" test.doc
Sending        test.doc
Transmitting file data .svn: Commit failed (details follow):
svn: MERGE request failed on '/myrepos/gorilla'
'pre-commit' hook failed with error output:
pete has exclusively locked gorilla/test.doc
OK, so it would be nice if the "Commit failed" message was customizable...
Applying the patch
1. Rebuild the client
The patch adds locking capabilities to the command line client by
introducing two sub commands (changed main.c / cl.h and added
lock-cmd.c and unlock-cmd.c)
2. Install server hooks
a) Make sure "lock-commit.py" and "lock-revprop-change.py" are
b) Change pre-revprop-change and post-revprop-change to call
c) Change pre-commit to call "lock-commit.py"
I've included sample hooks at the end of this mail.
Called from pre-commit to check if any of the CRUD'ed files are locked
by another user. If so, the commit fails. Locks on moved/deleted files
are removed; see script comments for details.
Called from the pre-revprop-change and post-revprop-change hooks. When
called from pre, the script checks whether or not the user can lock the
file. In post, the script patches the lock token (removes FLAG - see
below) and sets the locktoken revprop = username.
Internals... how files get locked
The exclusive lock implementation features creative use of the revprops
on revision 0. When a file is locked, a new revprop is created on rev 0
(called the lock tocken), and the value of that revprop is the user who
locks the file. When the file is unlocked, the revprop is removed. Also,
if the file is deleted/moved, any "dangling" locks will be removed upon
The revprop naming scheme is as follows:
   locktoken ::= FLAG "lock-" base64(path-in-repos)
   lockvalue ::= username
   FLAG      ::= R | F | N
  R means remove lock
  F means forced lock
  N means non-forced lock
The flags are actually removed on the server side as they are just there
to tell the hook scripts what to do. Initially I actually tried to use the
propvalue for this, but a bug in pre-1.1 prevents pre-revprop-change hooks
from reading the value (I wanted this patch to work with older servers.)
Someone might want to add WebDAV LOCK support which requires (IIRC) a
universally unique lock identifier. In that case, just add the repos-uuid
to the lock token.
The path is base64 encoded except that [\n,=,+] are all replaced with '-'
in order to form valid revprop names.
Sample hook scripts
1. pre-commit
# check if any of the changed files are locked by another user
/.../hook-scripts/lock-commit.py "$REPOS" "$TXN"  || exit 1
exit 0
2. pre-revprop-change
# we only allow lock and log prop's to be changed (change as you see fit)
if [ "$PROPNAME" =  "svn:log" ]; then exit 0; fi
if [ "${PROPNAME:1:5}" != "lock-" ]; then exit 1; fi
# check whether or not the file can be locked
/.../hook-scripts/lock-revprop-change.py pre "$REPOS" "$PROPNAME" "$USER" || 
exit 1
exit 0
3. post-revprop-change
# patches propval to contain username -or- removes the revprop if the FLAG 
is 'R'
/.../hook-scripts/lock-revprop-change.py post "$REPOS" "$PROPNAME" "$USER" 
|| exit 1
exit 0
Future enhancements (?)
a) Make svn up/svn lock set non-mergable files read-only and have
   'svn lock' make them readable.
b) 'svn st' could perhaps show lock status... or is that mixing unrelated
c) 'svnadmin' should be able to list and remove all locks in a repository
d) Implement all the clever ideas discussed on the dev list and
e) Fix bugs?
Well... happy locking.
/Stein Roger
MSN Messenger http://www.msn.no/messenger Den korteste veien mellom deg og 
dine venner

To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

  • text/plain attachment: cl.h
  • text/plain attachment: main.c
Received on Sat Jul 31 13:42:37 2004

This is an archived mail posted to the Subversion Dev mailing list.