#!/usr/bin/perl # $Id: //depot/r99.2/p4-tools/server/perfmerge.pl#1 $ # usage: perfmerge checkpoint.1 checkpoint.2 ... checkpoint.n > checkpoint.new # # WARNING: THIS SCRIPT IS PROVIDED AS IS. Please contact support@perforce.com # for more information if you are using this script for anything other than # experimentation. However, depots of version 2000.1 have been successfully # merged. # # Merge 2 or more checkpoint files into one checkpoint. Changes and jobs # are renumbered. The result is written to stdout - redirect this to a file! # Progress indicator is written to stderr! # # Requirements: # - no pathnames may overlap between checkpoints! # - checkpoints must both be from the same version of the server! %actions = ( "\@db.domain\@", 0x100, # take only first "\@db.view\@", 0x200, # same "\@db.integ\@", 0x509, # merged "\@db.rev\@", 0x505, # change (5) renumbered "\@db.revcx\@", 0x501, # change (1) renumbered "\@db.working\@", 0x509, # change (9) renumbered "\@db.change\@", 0x300, # change (1), key (2) renumbered "\@db.desc\@", 0x501, # change key (1) renumbered "\@db.job\@", 0x510, # job (1) renumbered "\@db.jobpend\@", 0x510, # job (1) renumbered "\@db.jobdesc\@", 0x510, # job (1) renumbered "\@db.fix\@", 0x512, # job (2), change (3) renumbered "\@db.fixrev\@", 0x512, # same "\@db.counters\@", 0x400, # elide -- we'll output new counters # any tables not mentioned here are just passed through (0x000) ) ; # # First, find job, change numbers $changes = 0; $jobs = 0; foreach $ck ( @ARGV ) { print STDERR "%%% Reading $ck ...\n"; open( CK, "$ck" ); while( <CK> ) { $y = split; # avoid infinite loop for descriptions which start with // if($_[2] ne "\@db.desc\@" && $_[2] ne "\@db.change\@") { for ($i = 1; $i < $y; $i++) { # look for @// at beginning of element, and no @ at end if ($_[$i] =~ /^\@\/\// && $_[$i] =~ /[^\@]$/) { splice(@_,$i,2,join (' ',$_[$i], $_[$i+1])); # decrement $i so that the new element is checked again $i = $i-1; } } } next if( $_[0] ne "\@pv\@" ); if( $_[2] eq "\@db.change\@" ) { print STDERR "%%% Reading change $_[3] ...\n"; # $_[3] is the real change # { $changes++; $changebydate{ "$_[7] $changes" } = "$ck/$_[3]"; } # $_[4] is the description #; different than $_[3] # if the change got renumbered. if( $_[3] != $_[4] ) { $changes++; $changebydate{ "$_[7] $changes" } = "$ck/$_[4]" } } if( $_[2] eq "\@db.jobs\@" ) { $jobs++; $jobsbydate{ "$_[5] $jobs" } = "$ck/$_[3]"; } } close( CK ); } # Now sort the job/change numbers and produce the mapping $changes = 0; $jobs = 0; foreach $i ( sort( keys( %changebydate ) ) ) { $changes{ $changebydate{ $i } } = ++$changes; } print STDERR "%%% Sorted $changes changes ...\n"; foreach $i ( sort( keys( %jobsbydate ) ) ) { $jobs{ $jobsbydate{ $i } } = ++$jobs; } print STDERR "%%% Sorted $jobs jobs ...\n"; # Write new counters print "\@pv\@ 0 \@db.counters\@ \@change\@ $changes\n"; print "\@pv\@ 0 \@db.counters\@ \@jobs\@ $jobs\n"; # Now read the checkpoint files, translating as we go foreach $ck ( @ARGV ) { open( CK, "$ck" ); local( $first, $action, $special, $change, $job ); $first = 1; while( <CK> ) { $y = split; # avoid infinite loop for descriptions which start with // if($_[2] ne "\@db.desc\@" && $_[2] ne "\@db.change\@") { for ($i = 1; $i < $y; $i++) { # look for @// at beginning of element, and no @ at end if ($_[$i] =~ /^\@\/\// && $_[$i] =~ /[^\@]$/) { splice(@_,$i,2,join (' ',$_[$i], $_[$i+1])); # decrement $i so that the new element is checked again $i = $i-1; } } } if( $first && $_[0] eq "\@pv\@" ) { $action = (defined ($actions{ $_[2] })) ? $actions{ $_[2] } : 0; $special = $action >> 8; if( $special == 1 ) { # For db.domain, skip duplicates if( $domained{ $_[3] } ) { #print "Skipping domain $_[3] already seen.\n"; } else { $domained{ $_[3] } = 1; } } elsif( $special == 2 ) { # For db.view, use only the first set we see. if( $viewed{ $_[3] } && $viewed{ $_[3] } ne $ck ) { #print "Skipping view $_[3] already seen.\n"; } else { $viewed{ $_[3] } = $ck; } } elsif( $special == 3 ) { # renumber change (1), key (2) $_[3] = $changes{ "$ck/$_[3]" }; $_[4] = $changes{ "$ck/$_[4]" }; } elsif( $special == 4 ) { # elide -- we'll output new counters next; } elsif( $special == 5 ) { $job = ( $action >> 4 ) & 0x0F; $change = ( $action ) & 0x0F; # Renumber changes if( $change ) { ++$change; ++$change; $_[$change] = $changes{ "$ck/$_[$change]" } if( $_[$change] ); } # Renumber jobs if( $job ) { ++$job; ++$job; #$_[$job] = $jobs{ "$ck/$_[$job]" }; } } print "@_\n"; } else { print; } # If this line has matching @@'s, we don't change first $first = 1 - $first if( ! ( split( /@/ ) % 2 ) ); } close( CK ); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#3 | 565 | Joerg Schaible | perfmerge.pl: Corrected output for STDERR | ||
#2 | 546 | Joerg Schaible |
Eliminated possible endless loop Added progress indicator |
||
#1 | 545 | Joerg Schaible | Latest original version as found at ftp.perforce.com in version 99.2 |