shithub: gefs

ref: cc6e4b6231bb28fe268feea3bfb50f7e0ee59166
dir: /snap.c/

View raw version
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <avl.h>

#include "dat.h"
#include "fns.h"

uvlong
inc64(uvlong *v, uvlong dv)
{
	vlong ov, nv;

	while(1){
		ov = *v;
		nv = ov + dv;
		if(cas64((u64int*)v, ov, nv))
			return ov;
	}
}

int
syncblk(Blk *b)
{
	assert(b->flag & Bfinal);
	lock(b);
	b->flag &= ~(Bqueued|Bdirty);
	unlock(b);
	return pwrite(fs->fd, b->buf, Blksz, b->bp.addr);
}

void
enqueue(Blk *b)
{
	assert(b->flag&Bdirty);
	finalize(b);
	if(syncblk(b) == -1){
		ainc(&fs->broken);
		fprint(2, "write: %r");
		abort();
	}
}

Tree*
openlabel(char *name)
{
	char dbuf[Keymax], buf[Kvmax];
	char *p, *e;
	vlong id;
	Tree *t;
	int n;
	Key k;
	Kvp kv;

	qlock(&fs->snaplk);
	n = strlen(name);
	p = dbuf;
	p[0] = Klabel;			p += 1;
	memcpy(p, name, n);		p += n;
	k.k = dbuf;
	k.nk = p - dbuf;
	if((e = btlookup(&fs->snap, &k, &kv, buf, sizeof(buf))) != nil)
		goto Error;
	if(kv.nv != Snapsz)
		goto Error;

	id = GBIT64(kv.v + 1);
	for(t = fs->osnap; t != nil; t = t->snext){
		if(t->gen == id){
			ainc(&t->memref);
			qunlock(&fs->snaplk);
			return t;
		}
	}
	if((t = mallocz(sizeof(Tree), 1)) == nil){
		fprint(2, "open %s: %s\n", name, e);
		goto Error;
	}
	memset(&t->lk, 0, sizeof(t->lk));

	memmove(dbuf, kv.v, kv.nv);
	k.k = dbuf;
	k.nk = kv.nv;
	if((e = btlookup(&fs->snap, &k, &kv, buf, sizeof(buf))) != nil){
		fprint(2, "open %s: %s\n", name, e);
		goto Error;
	}
	if(unpacktree(t, kv.v, kv.nv) == nil)
		goto Error;
	t->memref = 1;
	t->snext = fs->osnap;
	fs->osnap = t;
	qunlock(&fs->snaplk);
	return t;

Error:
	qunlock(&fs->snaplk);
	return nil;
}

void
closesnap(Tree *t)
{
	Tree *te, **p;
	int i;

	if(adec(&t->memref) != 0)
		return;

	for(i = Ndead-1; i >= 0; i--){
		if(t->dead[i].tail == nil)
			continue;
		syncblk(t->dead[i].tail);
//FIXME		putblk(t->dead[i].tail);
	}

	p = &fs->osnap;
	for(te = fs->osnap; te != nil; te = te->snext){
		if(te == t)
			break;
		p = &te->snext;
	}
	assert(te != nil);
	*p = te->snext;
	free(te);
}

static char*
modifysnap(char *name, vlong gen, vlong next, int del)
{
	char dbuf[Keymax], sbuf[Snapsz], nbuf[Snapsz];
	char *p, *e;
	int n, nm;
	Msg m[2];

	nm = 0;

	p = sbuf;
	p[0] = Ksnap;		p += 1;
	PBIT64(p, gen);		p += 8;
	m[nm].op = del ? Ounrefsnap : Orefsnap;
	m[nm].k = sbuf;
	m[nm].nk = p - sbuf;
	p = nbuf;
	p[0] = Ksnap;		p += 1;
	PBIT64(p, next);	p += 8;
	m[nm].v = nbuf;
	m[nm].nv = p - nbuf;
	nm++;

	if(name != nil){
		p = dbuf;
		n = strlen(name);
		m[nm].op = del ? Odelete : Oinsert;
		p[0] = Klabel;		p += 1;
		memcpy(p, name, n);	p += n;
		m[nm].k = dbuf;
		m[nm].nk = p - dbuf;
		m[nm].v = m[nm-1].k;
		m[nm].nv = m[nm-1].nk;
		nm++;
	}
	if((e = btupsert(&fs->snap, m, nm)) != nil)
		return e;
	return nil;
}

char*
deletesnap(Tree *snap, Tree *from)
{
fprint(2, "deleting snap at %B from %B\n", snap->bp, from->bp);
	return nil;
}

char*
labelsnap(char *name, vlong gen)
{
	return modifysnap(name, gen, -1, 0);
}

char*
unlabelsnap(vlong gen, char *name)
{
	return modifysnap(name, gen, -1, 1);
}

char*
refsnap(vlong gen)
{
	return modifysnap(nil, gen, -1, 0);
}

char*
unrefsnap(vlong gen, vlong next)
{
	return modifysnap(nil, gen, next, 1);
}

void
freedead(Bptr bp, void *)
{
	fprint(2, "reclaimed deadlist: %B\n", bp);
	reclaimblk(bp);
}

char*
freesnap(Tree *snap, Tree *next)
{
	Oplog dl;
	int i;

	assert(snap->gen != next->gen);
	assert(next->prev[0] == snap->gen);

//fprint(2, "next tree\n");
//showtreeroot(2, next);
//fprint(2, "snap tree\n");
//showtreeroot(2, snap);
	scandead(&next->dead[0], freedead, nil);
	for(i = 0; i < Ndead-1; i++){
		next->prev[i] = snap->prev[i];
		dl = snap->dead[i];
		if(i < Ndead-1)
			if(graft(&dl, &next->dead[i+1]) == -1)
				return Efs;
		next->dead[i] = dl;
	}
//fprint(2, "transferred\n");
//showtreeroot(2, next);
	return nil;
}

Tree*
newsnap(Tree *t)
{
	char kbuf[Snapsz], vbuf[Treesz];
	vlong gen;
	char *p, *e;
	Tree *r;
	Msg m;
	int i;

	gen = inc64(&fs->nextgen, 1);
	for(i = 0; i < Ndead; i++){
		if(t->dead[i].tail != nil){
			finalize(t->dead[i].tail);
			syncblk(t->dead[i].tail);
		}
	}
	p = kbuf;
	p[0] = Ksnap;		p += 1;
	PBIT64(p, t->gen);	p += 8;
	m.op = Oinsert;
	m.k = kbuf;
	m.nk = p - kbuf;
	p = packtree(vbuf, sizeof(vbuf), t);
	m.v = vbuf;
	m.nv = p - vbuf;
	if((e = btupsert(&fs->snap, &m, 1)) != nil){
		fprint(2, "error snapshotting: %s\n", e);
		qunlock(&fs->snaplk);
		return nil;
	}

	if((r = malloc(sizeof(Tree))) == nil)
		return nil;

	memset(&r->lk, 0, sizeof(r->lk));
	r->snext = fs->osnap;
	r->memref = 1;
	r->ref = 0;
	r->ht = t->ht;
	r->bp = t->bp;
	r->gen = gen;
	/* shift deadlist down */
	for(i = Ndead-1; i >= 0; i--){
		r->prev[i] = i == 0 ? t->gen : t->prev[i-1];
		r->dead[i].head.addr = -1;
		r->dead[i].head.hash = -1;
		r->dead[i].head.gen = -1;
		r->dead[i].tail = nil;
	}
	fs->osnap = r;

	return r;
}