venti/copy: synchronize with Plan 9; indent in verbose mode

http://codereview.appspot.com/110062
This commit is contained in:
Venkatesh Srinivas 2009-08-21 15:55:56 -04:00
parent c0cc7cc4da
commit da0a205ed6
2 changed files with 146 additions and 14 deletions

View file

@ -28,7 +28,7 @@ read, write, copy \- simple Venti clients
.br .br
.B venti/copy .B venti/copy
[ [
.B -fir .B -fimrVv
] ]
[ [
.B -t .B -t
@ -99,14 +99,35 @@ the root block from the server
to the server to the server
.IR dsthost . .IR dsthost .
.PP .PP
Venti's blocks are arranged in a directed acyclic graph (see venti(6));
there may be multiple paths from a root score to an
interior block (for example, if the same file contents are stored
under multiple names in an archive).
.I Copy
runs more efficiently if it does not copy blocks
(and all their children) multiple times.
The The
.B -f .B -f
option causes option causes
.I copy .I copy
to run in `fast' mode, to assume that if a block already exists on the destination
assuming that if a block already exists on the Venti server, all its children also exist and need not be considered.
destination Venti server, all its children also The
exist and need not be checked. .B -m
option causes
.I copy
to maintain an in-memory list of blocks it has copied
and avoid considering the same block multiple times.
The
.B -f
option is only useful if the destination Venti server is
known not to have lost any blocks due to disk corruption
or other failures.
The
.B -m
option is only useful if enough memory is available to
hold the block list, which typically requires about 1%
of the total number of bytes being copied.
.PP .PP
The The
.B -i .B -i
@ -135,6 +156,14 @@ option is given,
replaces pointers to unreadable blocks with replaces pointers to unreadable blocks with
pointers to the zero block. pointers to the zero block.
It writes the new root score to standard output. It writes the new root score to standard output.
The
.B -v
option prints scores as it copies them, total writes, and other
debugging information.
The
.B -V
option prints debugging information about the Venti protocol
messages send/received.
.SH SOURCE .SH SOURCE
.B \*9/src/cmd/venti .B \*9/src/cmd/venti
.SH SEE ALSO .SH SEE ALSO

View file

@ -3,6 +3,8 @@
#include <venti.h> #include <venti.h>
#include <libsec.h> #include <libsec.h>
#include <thread.h> #include <thread.h>
#include <avl.h>
#include <bin.h>
enum enum
{ {
@ -15,25 +17,93 @@ int rewrite;
int ignoreerrors; int ignoreerrors;
int fast; int fast;
int verbose; int verbose;
int nskip;
int nwrite;
VtConn *zsrc, *zdst; VtConn *zsrc, *zdst;
uchar zeroscore[VtScoreSize]; /* all zeros */
typedef struct ScoreTree ScoreTree;
struct ScoreTree
{
Avl avl;
uchar score[VtScoreSize];
int type;
};
Avltree *scoretree;
Bin *scorebin;
static int
scoretreecmp(Avl *va, Avl *vb)
{
ScoreTree *a, *b;
int i;
a = (ScoreTree*)va;
b = (ScoreTree*)vb;
i = memcmp(a->score, b->score, VtScoreSize);
if(i != 0)
return i;
return a->type - b->type;
}
static int
havevisited(uchar score[VtScoreSize], int type)
{
ScoreTree a;
if(scoretree == nil)
return 0;
memmove(a.score, score, VtScoreSize);
a.type = type;
return lookupavl(scoretree, &a.avl) != nil;
}
static void
markvisited(uchar score[VtScoreSize], int type)
{
ScoreTree *a;
Avl *old;
if(scoretree == nil)
return;
a = binalloc(&scorebin, sizeof *a, 1);
memmove(a->score, score, VtScoreSize);
a->type = type;
insertavl(scoretree, &a->avl, &old);
}
void void
usage(void) usage(void)
{ {
fprint(2, "usage: copy [-fir] [-t type] srchost dsthost score\n"); fprint(2, "usage: copy [-fimrVv] [-t type] srchost dsthost score\n");
threadexitsall("usage"); threadexitsall("usage");
} }
void void
walk(uchar score[VtScoreSize], uint type, int base) walk(uchar score[VtScoreSize], uint type, int base, int depth)
{ {
int i, n; int i, n;
uchar *buf; uchar *buf;
uchar nscore[VtScoreSize];
VtEntry e; VtEntry e;
VtRoot root; VtRoot root;
if(memcmp(score, vtzeroscore, VtScoreSize) == 0) if(verbose){
for(i = 0; i < depth; i++)
fprint(2, " ");
fprint(2, "-> %d %d %d %V\n", depth, type, base, score);
}
if(memcmp(score, vtzeroscore, VtScoreSize) == 0 || memcmp(score, zeroscore, VtScoreSize) == 0)
return; return;
if(havevisited(score, type)){
nskip++;
return;
}
buf = vtmallocz(VtMaxLumpSize); buf = vtmallocz(VtMaxLumpSize);
if(fast && vtread(zdst, score, type, buf, VtMaxLumpSize) >= 0){ if(fast && vtread(zdst, score, type, buf, VtMaxLumpSize) >= 0){
@ -59,8 +129,8 @@ walk(uchar score[VtScoreSize], uint type, int base)
fprint(2, "warning: could not unpack root in %V %d\n", score, type); fprint(2, "warning: could not unpack root in %V %d\n", score, type);
break; break;
} }
walk(root.score, VtDirType, 0); walk(root.prev, VtRootType, 0, depth+1);
walk(root.prev, VtRootType, 0); walk(root.score, VtDirType, 0, depth+1);
if(rewrite) if(rewrite)
vtrootpack(&root, buf); /* walk might have changed score */ vtrootpack(&root, buf); /* walk might have changed score */
break; break;
@ -73,7 +143,14 @@ walk(uchar score[VtScoreSize], uint type, int base)
} }
if(!(e.flags & VtEntryActive)) if(!(e.flags & VtEntryActive))
continue; continue;
walk(e.score, e.type, e.type&VtTypeBaseMask); walk(e.score, e.type, e.type&VtTypeBaseMask, depth+1);
/*
* Don't repack unless we're rewriting -- some old
* vac files have psize==0 and dsize==0, and these
* get rewritten by vtentryunpack to have less strange
* block sizes. So vtentryunpack; vtentrypack does not
* guarantee to preserve the exact bytes in buf.
*/
if(rewrite) if(rewrite)
vtentrypack(&e, buf, i); vtentrypack(&e, buf, i);
} }
@ -85,17 +162,31 @@ walk(uchar score[VtScoreSize], uint type, int base)
default: /* pointers */ default: /* pointers */
for(i=0; i<n; i+=VtScoreSize) for(i=0; i<n; i+=VtScoreSize)
if(memcmp(buf+i, vtzeroscore, VtScoreSize) != 0) if(memcmp(buf+i, vtzeroscore, VtScoreSize) != 0)
walk(buf+i, type-1, base); walk(buf+i, type-1, base, depth+1);
break; break;
} }
if(vtwrite(zdst, score, type, buf, n) < 0){ nwrite++;
if(vtwrite(zdst, nscore, type, buf, n) < 0){
/* figure out score for better error message */ /* figure out score for better error message */
/* can't use input argument - might have changed contents */ /* can't use input argument - might have changed contents */
n = vtzerotruncate(type, buf, n); n = vtzerotruncate(type, buf, n);
sha1(buf, n, score, nil); sha1(buf, n, score, nil);
sysfatal("writing block %V (type %d): %r", score, type); sysfatal("writing block %V (type %d): %r", score, type);
} }
if(!rewrite && memcmp(score, nscore, VtScoreSize) != 0)
sysfatal("not rewriting: wrote %V got %V", score, nscore);
if((type !=0 || base !=0) && verbose){
n = vtzerotruncate(type, buf, n);
sha1(buf, n, score, nil);
for(i = 0; i < depth; i++)
fprint(2, " ");
fprint(2, "<- %V\n", score);
}
markvisited(score, type);
free(buf); free(buf);
} }
@ -112,6 +203,9 @@ threadmain(int argc, char *argv[])
type = -1; type = -1;
ARGBEGIN{ ARGBEGIN{
case 'V':
chattyventi++;
break;
case 'f': case 'f':
fast = 1; fast = 1;
break; break;
@ -120,6 +214,9 @@ threadmain(int argc, char *argv[])
usage(); usage();
ignoreerrors = 1; ignoreerrors = 1;
break; break;
case 'm':
scoretree = mkavltree(scoretreecmp);
break;
case 'r': case 'r':
if(ignoreerrors) if(ignoreerrors)
usage(); usage();
@ -128,6 +225,9 @@ threadmain(int argc, char *argv[])
case 't': case 't':
type = atoi(EARGF(usage())); type = atoi(EARGF(usage()));
break; break;
case 'v':
verbose = 1;
break;
default: default:
usage(); usage();
break; break;
@ -167,10 +267,13 @@ threadmain(int argc, char *argv[])
sysfatal("could not find block %V of any type", score); sysfatal("could not find block %V of any type", score);
} }
walk(score, type, VtDirType); walk(score, type, VtDirType, 0);
if(changes) if(changes)
print("%s:%V (%d pointers rewritten)\n", prefix, score, changes); print("%s:%V (%d pointers rewritten)\n", prefix, score, changes);
if(verbose)
print("%d skipped, %d written\n", nskip, nwrite);
if(vtsync(zdst) < 0) if(vtsync(zdst) < 0)
sysfatal("could not sync dst server: %r"); sysfatal("could not sync dst server: %r");