code: mafs

ref: 390e726c64ee2aca967617ac7f7fd2a44f27646b
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;

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);
}