|  | #include "stdinc.h" | 
|  | #include <bio.h> | 
|  | #include "dat.h" | 
|  | #include "fns.h" | 
|  | #include "error.h" | 
|  |  | 
|  | int num = 100; | 
|  | int length = 20*1024; | 
|  | int block= 1024; | 
|  | int bush = 4; | 
|  | int iter = 100; | 
|  | Biobuf *bout; | 
|  | int maxdepth; | 
|  |  | 
|  | Source *mkroot(Cache*); | 
|  | void new(Source*, int trace, int); | 
|  | int delete(Source*); | 
|  | int count(Source *s, int); | 
|  | void stats(Source *s); | 
|  | void dump(Source *s, int ident, ulong entry); | 
|  | static void bench(Source *r); | 
|  |  | 
|  | void | 
|  | main(int argc, char *argv[]) | 
|  | { | 
|  | int i; | 
|  | Fs *fs; | 
|  | int csize = 1000; | 
|  | ulong t; | 
|  | Source *r; | 
|  |  | 
|  | ARGBEGIN{ | 
|  | case 'i': | 
|  | iter = atoi(ARGF()); | 
|  | break; | 
|  | case 'n': | 
|  | num = atoi(ARGF()); | 
|  | break; | 
|  | case 'l': | 
|  | length = atoi(ARGF()); | 
|  | break; | 
|  | case 'b': | 
|  | block = atoi(ARGF()); | 
|  | break; | 
|  | case 'u': | 
|  | bush = atoi(ARGF()); | 
|  | break; | 
|  | case 'c': | 
|  | csize = atoi(ARGF()); | 
|  | break; | 
|  | }ARGEND; | 
|  |  | 
|  | vtAttach(); | 
|  |  | 
|  | bout = vtMemAllocZ(sizeof(Biobuf)); | 
|  | Binit(bout, 1, OWRITE); | 
|  |  | 
|  | fmtinstall('V', vtScoreFmt); | 
|  | fmtinstall('R', vtErrFmt); | 
|  |  | 
|  | fs = fsOpen(argv[0], nil, csize, OReadWrite); | 
|  | if(fs == nil) | 
|  | sysfatal("could not open fs: %r"); | 
|  |  | 
|  | t = time(0); | 
|  |  | 
|  | srand(0); | 
|  |  | 
|  | r = fs->source; | 
|  | dump(r, 0, 0); | 
|  |  | 
|  | fprint(2, "count = %d\n", count(r, 1)); | 
|  | for(i=0; i<num; i++) | 
|  | new(r, 0, 0); | 
|  |  | 
|  | for(i=0; i<iter; i++){ | 
|  | if(i % 10000 == 0) | 
|  | stats(r); | 
|  | new(r, 0, 0); | 
|  | delete(r); | 
|  | } | 
|  |  | 
|  | //	dump(r, 0, 0); | 
|  |  | 
|  | fprint(2, "count = %d\n", count(r, 1)); | 
|  | //	cacheCheck(c); | 
|  |  | 
|  | fprint(2, "deleting\n"); | 
|  | for(i=0; i<num; i++) | 
|  | delete(r); | 
|  | //	dump(r, 0, 0); | 
|  |  | 
|  | fprint(2, "count = %d\n", count(r, 1)); | 
|  | fprint(2, "total time = %ld\n", time(0)-t); | 
|  |  | 
|  | fsClose(fs); | 
|  | vtDetach(); | 
|  | exits(0); | 
|  | } | 
|  |  | 
|  | static void | 
|  | bench(Source *r) | 
|  | { | 
|  | vlong t; | 
|  | Entry e; | 
|  | int i; | 
|  |  | 
|  | t = nsec(); | 
|  |  | 
|  | for(i=0; i<1000000; i++) | 
|  | sourceGetEntry(r, &e); | 
|  |  | 
|  | fprint(2, "%f\n", 1e-9*(nsec() - t)); | 
|  | } | 
|  |  | 
|  | void | 
|  | new(Source *s, int trace, int depth) | 
|  | { | 
|  | int i, n; | 
|  | Source *ss; | 
|  | Entry e; | 
|  |  | 
|  | if(depth > maxdepth) | 
|  | maxdepth = depth; | 
|  |  | 
|  | Bflush(bout); | 
|  |  | 
|  | n = sourceGetDirSize(s); | 
|  | for(i=0; i<n; i++){ | 
|  | ss = sourceOpen(s, nrand(n), OReadWrite); | 
|  | if(ss == nil || !sourceGetEntry(ss, &e)) | 
|  | continue; | 
|  | if((e.flags & VtEntryDir) && frand() < 1./bush){ | 
|  | if(trace){ | 
|  | int j; | 
|  | for(j=0; j<trace; j++) | 
|  | Bprint(bout, " "); | 
|  | Bprint(bout, "decend %d\n", i); | 
|  | } | 
|  | new(ss, trace?trace+1:0, depth+1); | 
|  | sourceClose(ss); | 
|  | return; | 
|  | } | 
|  | sourceClose(ss); | 
|  | } | 
|  | ss = sourceCreate(s, s->dsize, 1+frand()>.5, 0); | 
|  | if(ss == nil){ | 
|  | Bprint(bout, "could not create directory: %R\n"); | 
|  | return; | 
|  | } | 
|  | if(trace){ | 
|  | int j; | 
|  | for(j=1; j<trace; j++) | 
|  | Bprint(bout, " "); | 
|  | Bprint(bout, "create %d\n", ss->offset); | 
|  | } | 
|  | sourceClose(ss); | 
|  | } | 
|  |  | 
|  | int | 
|  | delete(Source *s) | 
|  | { | 
|  | int i, n; | 
|  | Source *ss; | 
|  |  | 
|  | n = sourceGetDirSize(s); | 
|  | /* check if empty */ | 
|  | for(i=0; i<n; i++){ | 
|  | ss = sourceOpen(s, i, OReadWrite); | 
|  | if(ss != nil){ | 
|  | sourceClose(ss); | 
|  | break; | 
|  | } | 
|  | } | 
|  | if(i == n) | 
|  | return 0; | 
|  |  | 
|  | for(;;){ | 
|  | ss = sourceOpen(s, nrand(n), OReadWrite); | 
|  | if(ss == nil) | 
|  | continue; | 
|  | if(s->dir && delete(ss)){ | 
|  | sourceClose(ss); | 
|  | return 1; | 
|  | } | 
|  | if(1) | 
|  | break; | 
|  | sourceClose(ss); | 
|  | } | 
|  |  | 
|  |  | 
|  | sourceRemove(ss); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | void | 
|  | dump(Source *s, int ident, ulong entry) | 
|  | { | 
|  | ulong i, n; | 
|  | Source *ss; | 
|  | Entry e; | 
|  |  | 
|  | for(i=0; i<ident; i++) | 
|  | Bprint(bout, " "); | 
|  |  | 
|  | if(!sourceGetEntry(s, &e)){ | 
|  | fprint(2, "sourceGetEntry failed: %r\n"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | Bprint(bout, "%4lud: gen %4ud depth %d tag=%x score=%V", | 
|  | entry, e.gen, e.depth, e.tag, e.score); | 
|  | if(!s->dir){ | 
|  | Bprint(bout, " data size: %llud\n", e.size); | 
|  | return; | 
|  | } | 
|  | n = sourceGetDirSize(s); | 
|  | Bprint(bout, " dir size: %lud\n", n); | 
|  | for(i=0; i<n; i++){ | 
|  | ss = sourceOpen(s, i, 1); | 
|  | if(ss == nil) | 
|  | continue; | 
|  | dump(ss, ident+1, i); | 
|  | sourceClose(ss); | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  | int | 
|  | count(Source *s, int rec) | 
|  | { | 
|  | ulong i, n; | 
|  | int c; | 
|  | Source *ss; | 
|  |  | 
|  | n = sourceGetDirSize(s); | 
|  | c = 0; | 
|  | for(i=0; i<n; i++){ | 
|  | ss = sourceOpen(s, i, OReadOnly); | 
|  | if(ss == nil) | 
|  | continue; | 
|  | if(rec) | 
|  | c += count(ss, rec); | 
|  | c++; | 
|  | sourceClose(ss); | 
|  | } | 
|  | return c; | 
|  | } | 
|  |  | 
|  | void | 
|  | stats(Source *s) | 
|  | { | 
|  | int n, i, c, cc, max; | 
|  | Source *ss; | 
|  |  | 
|  | cc = 0; | 
|  | max = 0; | 
|  | n = sourceGetDirSize(s); | 
|  | for(i=0; i<n; i++){ | 
|  | ss = sourceOpen(s, i, 1); | 
|  | if(ss == nil) | 
|  | continue; | 
|  | cc++; | 
|  | c = count(ss, 1); | 
|  | if(c > max) | 
|  | max = c; | 
|  | sourceClose(ss); | 
|  | } | 
|  | fprint(2, "count = %d top = %d depth=%d maxcount %d\n", cc, n, maxdepth, max); | 
|  | } |