ref: ce708f49bf5ec6c6b3fe1bb29d401c42b841b649
dir: /reconcile.c/
#include <u.h> #include <libc.h> #include "dat.h" #include "extents.h" #include <bio.h> /* read block numbers in 2 streams and flag the common and missing blocks. test the reconcile.c cd /mnt/term/home/j/local/plan9/custom/mafs/tests watch -e '6\.reconcile' 'date; ./6.reconcile -D -u <{seq 1 1 3; seq 5 1 6} -F <{seq 3 1 5} 7 ' ./6.reconcile -D -u <{seq 1 1 3; seq 5 1 6} -F <{seq 3 1 5} 7 collect used +1 +2 +3 +5 +6 collect free +3 +4 +5 show used 1 .. 3 5 .. 6 show free 3 .. 5 common: 3 5 missing: 0 test extents with duplicates - below should panic ./6.reconcile -D -u <{seq 1 1 3; seq 2 1 6} -F <{seq 3 1 5} 7 */ enum { FileNameLen = KiB, }; int debug = 0; int chatty9p = 0; struct Stream { struct Extents *es; Biobufhdr bp; int fd; s8 *buf; char *file; s8 name[32]; }; typedef struct Stream Stream; void collect(Stream * s); void common(u64 nblocks, Stream *u, Stream *f); void *emalloc(u32); s8 find(Extents *es, u64 bno); static void init(Stream *s); void missing(u64 nblocks, Stream *u, Stream *f); void panic(char *fmt, ...); void show(Stream * s); static void usage(void) { fprint(2, "usage: reconcile [-D ] -u list_of_used_blocks_file" " -F list_of_free_blocks_file nblocks\n"); exits("usage"); } void main(int argc, char *argv[]) { Stream u, f; /* u = used, f = free */ u64 nblocks; Errenv env = {0}; envpp = privalloc(); *envpp = &env; if(waserror()){ panic(0, "err stack %d: %lux %lux %lux %lux %lux %lux", env.nlabel, env.label[0][JMPBUFPC], env.label[1][JMPBUFPC], env.label[2][JMPBUFPC], env.label[3][JMPBUFPC], env.label[4][JMPBUFPC], env.label[5][JMPBUFPC]); } memset(&u, 0, sizeof(Stream)); memset(&f, 0, sizeof(Stream)); ARGBEGIN{ default: usage(); case 'D': chatty9p = ++debug; break; case 'u': u.file = strdup(EARGF(usage())); break; case 'F': f.file = strdup(EARGF(usage())); break; }ARGEND if(argc != 1) usage(); nblocks = atoll(argv[0]); if(u.file == nil || f.file == nil) sysfatal("no used or free file"); if(nblocks == 0) sysfatal("nblocks == 0"); strncpy(u.name, "used", 5); strncpy(f.name, "free", 5); init(&u); init(&f); collect(&u); collect(&f); if(debug){ show(&u); show(&f); } /* identify common blocks */ common(nblocks, &u, &f); /* identify missing blocks */ // missing(nblocks, &u, &f); /* why bother? just exits(nil) as cinap suggests */ Bterm(&u.bp); Bterm(&f.bp); free(u.buf); free(f.buf); close(u.fd); close(f.fd); exits(nil); } void missing(u64 nblocks, Stream *u, Stream *f) { u64 i; u8 header = 0; Extent *ue, *fe; ue = u->es->lowest; fe = f->es->lowest; for(i = 0; i < nblocks; i++){ if(ue != nil && ue->start <= i && i < ue->start+ue->len){ if(i == ue->start+ue->len-1) ue = ue->high; continue; } if(fe != nil && fe->start <= i && i < fe->start+fe->len){ if(i == fe->start+fe->len-1) fe = fe->high; continue; } if(header == 0){ header++; print("missing: "); } print(" %llud", i); } if(header) print("\n"); } void common(u64 nblocks, Stream *u, Stream *f) { u64 i; u8 header = 0; Extent *ue, *fe; ue = u->es->lowest; fe = f->es->lowest; if(fe == nil) /* disk is full */ return; for(i = 0; i < nblocks; i++){ if(ue->start <= i && i < ue->start+ue->len && fe->start <= i && i < fe->start+fe->len){ if(header == 0){ header++; print("common: "); } print(" %llud", i); } if(i == ue->start+ue->len-1) ue = ue->high; if(i == fe->start+fe->len-1) fe = fe->high; if(ue == nil || fe == nil) break; } if(header) print("\n"); } static void init(Stream *s) { s->buf = emalloc(MiB); s->fd = open(s->file, OREAD); if(Binits(&s->bp, s->fd, OREAD, (u8*)s->buf, MiB) == Beof) sysfatal ("%s: Binits on msin failed: status code: Beof, errstr: %r", argv0); Blethal(&s->bp, nil); } void collect(Stream * s) { s8 *p, *ep; u64 start, end, nblocks; if(debug) print("collect %s ", s->name); s->es = emalloc(sizeof(Extents)); initextents(s->es, s->name, 0, 0, 2, nil, fprint, panic, emalloc); while((s->buf = Brdstr(&s->bp, '\n', 1)) != nil) { p = s->buf; start = strtoull(p, &ep, 10); if(p == ep) panic("could not read"); p = ep; p += 1; /* skip over the space */ end = strtoull(p, &ep, 10); if(p == ep) panic("could not read"); p = ep; p += 1; /* skip over the space */ nblocks = strtoull(p, &ep, 10); if(p == ep) panic("could not read"); if(end-start+1 != nblocks) panic("loadextents does not match up: start %llud end %llud nblocks %llud", start, end, nblocks); ufree(s->es, start, nblocks); // show(s); } if(debug) print("\n"); } void show(Stream * s) { print("show %s\n", s->name); if(s == nil || s->es == nil){ print("nil\n"); return; } showextents(1, "show stream: ", s->es); }