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

svn obliterate: Keeping it real (or: What has already been implemented?)

From: Magnus Torfason <zulutime.net_at_gmail.com>
Date: Thu, 26 Feb 2009 13:18:59 -0500

While working on the obliteration functional specification, I have
been interested in examining a) what obliteration functionality has
already been implemented and b) how exising clients would deal with
all of a sudden seeing a repository that has changed through an
obliteration operation.

Attached are the logs of two such test runs. The first log shows how
svnsync can be used (through a little-documented feature allowing the
specification of subdirectories) to "obliterate" completely some parts
of the repository, and then tests how clients deal with those files
disappearing from the repository. The second log manually simulates
the obliteration of a single commit of a single file (nothing is
available to implement this yet), and tests how clients deal with the
repository file contents changing.

The summary of the results is as follows:

1: svnsync complies with the definition of OBLITERATION, including in
    the case where a file is copied from an obliterated path.

    1.a: Currently, he form of the obliteration set that can be
         specified through svnsync is *extremely* limited.

    1.b: When copying from an obliterated path, the history of the
         file is completely erased, *even if parts of the history are
         not in the obliteration set*.

2: When confronted with a changed repository, the current client
    (1.5.5) fails, not catastrophically, but not very gracefully
    either.

    2.a: I have not found any use-cases that corrupt the repository in
         a meaningful way (putting it in an unworkable state, or
         getting data into it that does not correspond to the working
         copy the user sees).

    2.b: However, it is very hard for a client user to get rid of
         files_at_rev that are not identical to the corresponding file_at_rev
         in the post-obliteration repository.

    2.c: In particular, a user who tries to solve the problem by
         deleting a file (that no longer exists in the repository), can
         commit the change, which results in an empty revision in the
         repository.

The first set of comments are useful in thinking generally about what
is the simplest way to implement obliterate. The second set of
comments have to do with ONLINE obliteration specifically (as defined
in a previous mail). In particular, one would want to make it easy for
users to run a "svn repair" or like to fix their working copy when
changes to the repository leave it in an inconsistent state.

Best,
Magnus

------------------------------------------------------
http://subversion.tigris.org/ds/viewMessage.do?dsForumId=462&dsMessageId=1234159

$ #!/bin/sh
$ PS1="$ "
$
$ ##
$ ## SVN OBLITERATE 1 - KEEPING IT REAL ...
$ ##
$ ## This script tests the obliteration functionality that is
$ ## already present in svn, through svnsync, and examines
$ ## the effect of ONLINE obliteration on existing working copies
$ ##
$
$ WD="`pwd`"
$
$ # Creating original repository ...
$ mkdir obl-repo
$ svnadmin create obl-repo
$
$ svn co "file://$WD/obl-repo" obl-wc > /dev/null
$
$ mkdir obl-wc/A > /dev/null
$ mkdir obl-wc/B > /dev/null
$ echo "Revision 1 contents" > obl-wc/A/file-rev1.txt
$ svn add obl-wc/* > /dev/null
$ svn commit obl-wc --message "Revision 1 log message" > /dev/null
$
$ svn cp obl-wc/A/file-rev1.txt obl-wc/B/file-rev2.txt > /dev/null
$ echo "Revision 2 contents" >> obl-wc/B/file-rev2.txt
$ svn commit obl-wc --message "Revision 2 log message" > /dev/null
$
$ svn cp obl-wc/B/file-rev2.txt obl-wc/A/file-rev3.txt > /dev/null
$ echo "Revision 3 contents" >> obl-wc/A/file-rev3.txt
$ svn commit obl-wc --message "Revision 3 log message" > /dev/null
$
$ rm -rf obl-wc
$
$
$ # Checking out a working copy that will become stale ...
$ svn co "file://$WD/obl-repo" obl-wc-stale > /dev/null
$ svn log -v obl-wc-stale/A/file-rev3.txt
------------------------------------------------------------------------
r3 | mtt2108 | 2009-02-23 10:52:41 -0500 (Mon, 23 Feb 2009) | 1 line
Changed paths:
   A /A/file-rev3.txt (from /B/file-rev2.txt:2)

Revision 3 log message
------------------------------------------------------------------------
r2 | mtt2108 | 2009-02-23 10:52:39 -0500 (Mon, 23 Feb 2009) | 1 line
Changed paths:
   A /B/file-rev2.txt (from /A/file-rev1.txt:1)

Revision 2 log message
------------------------------------------------------------------------
r1 | mtt2108 | 2009-02-23 10:52:36 -0500 (Mon, 23 Feb 2009) | 1 line
Changed paths:
   A /A
   A /A/file-rev1.txt
   A /B

Revision 1 log message
------------------------------------------------------------------------
$ # Note that the file-rev3.txt does have a history
$
$
$ # Obliterating B from repository (using svnsync) ...
$ mkdir obl-repo-tmp
$ svnadmin create obl-repo-tmp > /dev/null
$ echo '#!/bin/sh' > obl-repo-tmp/hooks/pre-revprop-change
$ echo 'exit 0' >> obl-repo-tmp/hooks/pre-revprop-change
$ echo 'exit 0' >> obl-repo-tmp/hooks/pre-revprop-change.bat
$ chmod 755 obl-repo-tmp/hooks/pre-revprop-change
$ svnsync init "file://$WD/obl-repo-tmp" "file://$WD/obl-repo/A" > /dev/null
$ svnsync sync "file://$WD/obl-repo-tmp" > /dev/null
$ mv obl-repo obl-repo-old
$ mv obl-repo-tmp obl-repo
$ rm -f obl-repo/db/uuid
$ cp obl-repo-old/db/uuid obl-repo/db/uuid
$
$
$ ##
$ ## NOW FOR SOME DIAGNOSTICS
$ ##
$
$ # Checking out a fresh copy from the post-obliterate repository ...
$ svn co "file://$WD/obl-repo" obl-wc-fresh
A obl-wc-fresh\A
A obl-wc-fresh\A\file-rev1.txt
A obl-wc-fresh\A\file-rev3.txt
Checked out revision 3.
$ svn log obl-wc-fresh/A/file-rev3.txt
------------------------------------------------------------------------
r3 | mtt2108 | 2009-02-23 10:52:41 -0500 (Mon, 23 Feb 2009) | 1 line

Revision 3 log message
------------------------------------------------------------------------
$ # Now the file has lost all of its history, even if an
$ # ancestor of the file (/A/file-rev1.txt_at_1) exists in the repo
$
$ # What happens when we try to use the stale working copy ?
$ cat obl-wc-stale/B/file-rev2.txt
Revision 1 contents
Revision 2 contents
$ svn status obl-wc-stale/B/file-rev2.txt
$ svn up obl-wc-stale/B/file-rev2.txt
At revision 3.
$ echo 'Change to stale file' >> obl-wc-stale/B/file-rev2.txt
$ svn status obl-wc-stale/B/file-rev2.txt
M obl-wc-stale\B\file-rev2.txt
$ svn up obl-wc-stale/B/file-rev2.txt
At revision 3.
$ svn commit --message "Trying to commit stale file" obl-wc-stale
Sending obl-wc-stale\B\file-rev2.txt
svn: Commit failed (details follow):
svn: File not found: transaction '3-3', path '/B/file-rev2.txt'
$ svn rm --force obl-wc-stale/B/file-rev2.txt
D obl-wc-stale\B\file-rev2.txt
$ svn commit --message "Trying to commit stale file" obl-wc-stale
Deleting obl-wc-stale\B\file-rev2.txt

Committed revision 4.
$ # Note that this created an empty revision in the repository
$
$ # We update the stale working copy after the commit
$ svn up obl-wc-stale
svn: Working copy path 'B' does not exist in repository
$
$ # Now we edit the fresh copy
$ svn up obl-wc-fresh
At revision 4.
$ echo "More changes to the rev3 file" >> obl-wc-fresh/A/file-rev3.txt
$ svn commit obl-wc-fresh --message "Committing in the fresh copy"
Sending obl-wc-fresh\A\file-rev3.txt
Transmitting file data .
Committed revision 5.
$
$ # Back to the stale one. Every update option errors out.
$ # (But the operations nevertheless impact the WC)
$ svn up obl-wc-stale
U obl-wc-stale\A\file-rev3.txt
svn: Working copy path 'B' does not exist in repository
$ svn co "file://$WD/obl-repo" obl-wc-stale
svn: Working copy path 'B' does not exist in repository
$ svn co --force "file://$WD/obl-repo" obl-wc-stale
svn: Working copy path 'B' does not exist in repository
$
$ # Change the UUID of the repository
$ svnadmin setuuid obl-repo
$
$ # Repeat the previous commands with a fresh uuid
$ svn up obl-wc-stale
svn: Repository UUID '9ef1a082-f420-f348-b313-5c74081b0e0e' doesn't match expected UUID 'ad62a6cf-fe1c-3048-bd30-e3a0988dccfa'
$ svn co "file://$WD/obl-repo" obl-wc-stale
svn: Repository UUID '9ef1a082-f420-f348-b313-5c74081b0e0e' doesn't match expected UUID 'ad62a6cf-fe1c-3048-bd30-e3a0988dccfa'
$ svn co --force "file://$WD/obl-repo" obl-wc-stale
svn: Repository UUID '9ef1a082-f420-f348-b313-5c74081b0e0e' doesn't match expected UUID 'ad62a6cf-fe1c-3048-bd30-e3a0988dccfa'
$
$ # Still no luck. We remove the .svn folders and try again
$ find obl-wc-stale -name ".svn" -type d -exec rm -rf {} \;
find: `obl-wc-stale/.svn': No such file or directory
find: `obl-wc-stale/A/.svn': No such file or directory
find: `obl-wc-stale/B/.svn': No such file or directory
$ svn up obl-wc-stale
Skipped 'obl-wc-stale'
$ svn co "file://$WD/obl-repo" obl-wc-stale
svn: Failed to add directory 'obl-wc-stale\A': an unversioned directory of the same name already exists
$ svn co --force "file://$WD/obl-repo" obl-wc-stale
E obl-wc-stale\A
E obl-wc-stale\A\file-rev1.txt
E obl-wc-stale\A\file-rev3.txt
Checked out revision 5.
$ svn up obl-wc-stale
At revision 5.
$
$ # Finally. We are back in business. Of course, removing
$ # the .svn copies would have resolved the issue regardless
$ # of the value of the UUID.
$
$ # Clean up after the test
$ rm -rf obl-*
$

$ #!/bin/sh
$ PS1="$ "
$
$ ##
$ ## SVN OBLITERATE 2 - INCOMPATIBLE DATA
$ ##
$ ## This script tests the effect of a simulated obliteration operation
$ ## on an existing working copy. The code simulates the obliteration of
$ ## a single revision for a single file, resulting in different data
$ ## in the ORIGINAL repository and in the MODIFIED repository (since
$ ## obliteration is not actually implemented, we use a REFERENCE
$ ## repository instead of the MODIFIED repository).
$ ##
$
$ WD="`pwd`"
$
$
$ # Creating original repository ...
$ mkdir obl-repo-org
$ svnadmin create obl-repo-org
$ svn co "file://$WD/obl-repo-org" obl-wc-org > /dev/null
$
$ echo "File 1, Revision 1: Contents" > obl-wc-org/file1.txt
$ echo "File 2, Revision 1: Contents" > obl-wc-org/file2.txt
$ svn add obl-wc-org/* > /dev/null
$ svn commit obl-wc-org --message "Revision 1 log message" > /dev/null
$
$ echo "File 1, Revision 2: Contents" >> obl-wc-org/file1.txt
$ echo "File 2, Revision 2: Contents" >> obl-wc-org/file2.txt
$ svn commit obl-wc-org --message "Revision 2 log message" > /dev/null
$
$ echo "File 1, Revision 3: Contents" >> obl-wc-org/file1.txt
$ echo "File 2, Revision 3: Contents" >> obl-wc-org/file2.txt
$ svn commit obl-wc-org --message "Revision 3 log message" > /dev/null
$
$ rm -rf obl-wc-org
$
$
$ # Creating reference repository ...
$ # File 2, revision 2, gets obliterated ...
$ mkdir obl-repo-ref
$ svnadmin create obl-repo-ref
$ svn co "file://$WD/obl-repo-ref" obl-wc-ref > /dev/null
$
$ echo "File 1, Revision 1: Contents" > obl-wc-ref/file1.txt
$ echo "File 2, Revision 1: Contents" > obl-wc-ref/file2.txt
$ svn add obl-wc-ref/* > /dev/null
$ svn commit obl-wc-ref --message "Revision 1 log message" > /dev/null
$
$ # This reordering of statements is equivalent to obliteration
$ echo "File 1, Revision 2: Contents" >> obl-wc-ref/file1.txt
$ svn commit obl-wc-ref --message "Revision 2 log message" > /dev/null
$ echo "File 2, Revision 2: Contents" >> obl-wc-ref/file2.txt
$
$ echo "File 1, Revision 3: Contents" >> obl-wc-ref/file1.txt
$ echo "File 2, Revision 3: Contents" >> obl-wc-ref/file2.txt
$ svn commit obl-wc-ref --message "Revision 3 log message" > /dev/null
$
$ rm -rf obl-wc-ref
$
$
$ ##
$ ## NOW FOR SOME DIAGNOSTICS
$ ##
$
$ # Check out to a fresh repository
$ svn co "file://$WD/obl-repo-org" obl-wc-test-head > /dev/null
$
$ # Check out to a fresh repository, and update to the version
$ # that will be obliterated
$ svn co "file://$WD/obl-repo-org" obl-wc-test-r2 > /dev/null
$ svn up -r2 obl-wc-test-r2
U obl-wc-test-r2\file2.txt
U obl-wc-test-r2\file1.txt
Updated to revision 2.
$
$ # Perform the ONLINE (simulated) obliteration
$ mv obl-repo-org obl-repo-org-old
$ mv obl-repo-ref obl-repo-org
$ rm -f obl-repo-org/db/uuid
$ cp obl-repo-org-old/db/uuid obl-repo-org/db/uuid
$
$ # Updating the head wc. No problems here.
$ svn up obl-wc-test-head
At revision 3.
$
$ # Updating the wc containing obsolete files.
$ # Failure, but not catastrophic
$ svn up obl-wc-test-r2
svn: Checksum mismatch for 'obl-wc-test-r2\.svn\text-base\file2.txt.svn-base';
expected: '44a64e5adb9077c8efb9c847537ff1bd',
actual: 'd5e4710e3392f970e21143c5f61583a9'
$
$ # Cleanup exits without errors, but does not fix things
$ svn cleanup obl-wc-test-r2
$ svn up obl-wc-test-r2
svn: Checksum mismatch for 'obl-wc-test-r2\.svn\text-base\file2.txt.svn-base';
expected: '44a64e5adb9077c8efb9c847537ff1bd',
actual: 'd5e4710e3392f970e21143c5f61583a9'
$
$ # Committing would fail of course, since the file is out of
$ # date, but the behavior when obliterations result in modified
$ # HEAD revision contents has not been checked.
$
$
$ # Clean up after the test
$ rm -rf obl-*
$
Received on 2009-02-26 21:28:00 CET

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