ref: 9b76881a8e11c44aae5dfd447e1cd1bc074ec9f3
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; static void init(Stream *s); void collect(Stream * s); void *emalloc(u32); s8 *estrdup(s8 *); void show(Stream * s); s8 find(Extents *es, u64 bno); void common(Stream *u, Stream *f); void missing(u64 nblocks, Stream *u, Stream *f); 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; ARGBEGIN{ default: usage(); case 'D': chatty9p = ++debug; break; case 'u': u.file = estrdup(EARGF(usage())); break; case 'F': f.file = estrdup(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", 32); strncpy(f.name, "free", 32); init(&u); init(&f); collect(&u); collect(&f); if(debug){ show(&u); show(&f); } /* identify common blocks */ common(&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; for(i = 0; i < nblocks; i++){ if(find(u->es, i) == 0 && find(f->es, i) == 0){ if(header++ == 0) print("missing: "); print(" %llud", i); } } if(header) print("\n"); } void common(Stream *u, Stream *f) { Extent *e; u64 bno; u8 header = 0; if(u == nil || u->es == nil){ print("common: no used extents\n"); return; } for(e = lowest(u->es); e != nil; e=e->high){ for(bno = e->start; bno<e->start+e->len; bno++){ if(find(f->es, bno) == 1){ if(header++ == 0) print("common: "); print(" %llud", bno); } } } 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, nil); 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); add(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); }