code: mafs

ref: 16f09290e03ec4fba68b6587dc01c13299c2a6f6
dir: /reconcile.c/

View raw version
#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);
	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);
}