
HOW-TO:  svn repository upgrade procedure
=========================================
 $LastChangedDate: 2003-01-13 17:43:13 -0500 (Mon, 13 Jan 2003) $


PROBLEM:

In revision 2093 [June 5, 2002], the underlying schema for subversion
repositories (libsvn_fs) was changed.  The schema was changed again in
revision 2491.  This means you can see many different errors when
accessing a repository:

  1. if your client is newer that the repository, you might see:

         Berkeley DB error while opening `copies' table
         
            or

         Berkeley DB error while opening `changes' table


  2. if your client is older than the repository, you might see:

         Malformed revision skeleton



SOLUTION:

Here's the procedure for upgrading your old repository to a new one.

If your repository is very large, it may have quite a bit of
"deltified" data in it; you might notice very slow checkout times on
old revisions, and if so, you're probably a victim of inefficient
undeltification.  In these cases, we recommend running 'svnadmin
undeltify' on every Nth revision... it will drastically speed up the
repository export/import later on.  If you plan to do this, we labeled
relevant steps below as [OPTIONAL].


1. Depending on how old your repository is, obtain a working copy of
   either the r2092 or r2490 branches.  These branches exist so that
   you can compile a static binary of 'svnadmin' using the latest
   dumping/loading code, but with old fs schemas.

     svn co http://svn.collab.net/repos/svn/branches/fs-convert-2092

       or

     svn co http://svn.collab.net/repos/svn/branches/fs-convert-2490

   (If your repository is using libsvn_fs older than r2092, then use
   r2092.  If your libsvn_fs is between 2093 and 2490, then use the
   2490 branch.)

2. Build the branch statically (pass --disable-shared to ./configure),
   and then copy the large 'svnadmin' binary to a safe place.  Rename
   it to 'svnadmin-old'.

3. [OPTIONAL] Run 'svnadmin-old undeltify' on every Nth revision in
   your repository.  A perl script at the bottom of this document can
   help with that.

4. Build the HEAD revision of svn.  Find the latest svnadmin binary.

5. Create a brand new repository using the new fs schema:

       svnadmin create newrepos

6. Create a 'dump' of your repository using the *older* svnadmin binary
   like so:

       svnadmin-old dump oldrepos > dumpfile

   Then load the dumpfile into the new repository with the new
   svnadmin binary.  This effectively replays all of your commits:

       svnadmin load newrepos < dumpfile

   OR, if you're feeling saucy, you can do it all at once:

       svnadmin-old dump oldrepos | svnadmin load newrepos


Congratulations, you now have a newly upgraded repository.  For
starters, 'svn log' actually traces back through copy/rename history
now, and 'svn log -v' will quickly show you the changed paths in each
revision.


----------------------------------------------------------------------


Here's a perl script to undeltify every Nth revision in your repository.
Run it like so:  ./undeltify.pl REPOS-PATH [START-REV:END_REV] [INCREMENT]



#!/usr/bin/perl

use strict;

#############################################################################
#  SETUP 

my $svnadmin_cmd = '/home/cmpilato/bin/svnadmin-2092b';
my $svnlook_cmd = '/home/cmpilato/bin/svnlook-2092b';

#
#############################################################################

sub do_usage
{
    print "ERROR: usage: $0 REPOS [START-REV:END-REV] [INCREMENT]]\n\n";
    exit;
}

sub do_undeltify # ($repos, $start_rev, $end_rev, $increment)
{
    my $repos     = shift @_;
    my $start_rev = shift @_;
    my $end_rev   = shift @_;
    my $increment = shift @_;
    my $i = $start_rev;
    while (1)
    {
        print "--- Undeltifying revision $i...";
        `$svnadmin_cmd undeltify $repos $i /`;
        print "done.\n";
        if ($start_rev > $end_rev)
        {
            $i = $i - $increment;
            last if ($i < $end_rev);
        }
        else
        {
            $i = $i + $increment;
            last if ($i > $end_rev);
        }
    }
}

my $next_arg;
my $repos;
my $start_rev;
my $end_rev;
my $increment;
my $youngest;

# REPOS argument is required.
$next_arg = shift @ARGV;
if ($next_arg eq '')
{
    &do_usage();
}

# Use the REPOS argument to first figure out the youngest revision in
# the repository.
$repos = $next_arg;
$youngest = `$svnlook_cmd youngest $repos`;
chomp $youngest;

# Setup the default argument list, a backwards walk of all revisions
# in the repository.
$start_rev = $youngest - 1;
$end_rev = 1;
$increment = 1;

# Parse the remaining arguments.
$next_arg = shift @ARGV;
if ($next_arg ne '')
{
    if ($next_arg =~ /^(\d+)\:(\d+)$/)
    {
        $start_rev = $1;
        $end_rev = $2;
        $next_arg = shift @ARGV;
        if ($next_arg ne '')
        {
            if ($next_arg =~ /^\d+$/)
            {
                $increment = $next_arg;
            }
            else
            {
                &do_usage();
            }
        }
    }
    elsif ($next_arg =~ /^\d+$/)
    {
        $increment = $next_arg;
    }
    else
    {
        &do_usage();
    }
}

# Validate the input.
if (($start_rev > $youngest) 
    or ($end_rev > $youngest)
    or ($start_rev < 1)
    or ($end_rev < 1))
{
    print "ERROR: You've specified an invalid revision.\n";
    print "ERROR: Valid revisions are those between 1 and $youngest.\n\n";
    exit;
}

print "Undeltifying `$repos', revs $start_rev - $end_rev (by $increment).\n";
&do_undeltify ($repos, $start_rev, $end_rev, $increment);
print "Finished.  Happy computing!\n\n";
exit;
