shithub: git9

Download patch

ref: 46d4f3f4c75928f7b8af26cbf27452b317a1aac7
parent: 926e838a32a4c46d38a767e8970987e31c6b5864
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Oct 18 22:44:28 EDT 2019

Generate unique QIDs for files in git repo.

--- a/fs.c
+++ b/fs.c
@@ -35,6 +35,8 @@
 
 typedef struct Gitaux Gitaux;
 typedef struct Crumb Crumb;
+typedef struct Cache Cache;
+typedef struct Uqid Uqid;
 
 struct Crumb {
 	char	*name;
@@ -55,6 +57,21 @@
 	Object	*olslast;
 };
 
+struct Uqid {
+	vlong	uqid;
+
+	vlong	ppath;
+	vlong	oid;
+	int	t;
+	int	idx;
+};
+
+struct Cache {
+	Uqid *cache;
+	int n;
+	int max;
+};
+
 char *qroot[] = {
 	"HEAD",
 	"branch",
@@ -62,18 +79,48 @@
 	"ctl",
 };
 
-char *username;
-char *mtpt = "/mnt/git";
-char **branches = nil;
+char	*username;
+char	*mtpt = "/mnt/git";
+char	**branches = nil;
+Cache	uqidcache[512];
+vlong	nextqid = Qmax;
 
+vlong
+qpath(Crumb *p, int idx, vlong id, vlong t)
+{
+	int h, i;
+	vlong pp;
+	Cache *c;
+	Uqid *u;
+
+	pp = p ? p->qid.path : 0;
+	h = (pp*333 + id*7 + t) & (nelem(uqidcache) - 1);
+	c = &uqidcache[h];
+	u = c->cache;
+	for(i=0; i <c->n ; i++){
+		if(u->ppath == pp && u->oid == id && u->t == t && u->idx == idx)
+			return (u->uqid << 8) | t;
+		u++;
+	}
+	if(c->n == c->max){
+		c->max += c->max/2 + 1;
+		c->cache = erealloc(c->cache, c->max*sizeof(Uqid));
+	}
+	nextqid++;
+	c->cache[c->n++] = (Uqid){nextqid, pp, id, t, idx};
+	return (nextqid << 8) | t;
+}
+
 static Crumb*
-curcrumb(Gitaux *aux)
+crumb(Gitaux *aux, int n)
 {
-	return &aux->crumb[aux->ncrumb - 1];
+	if(n < aux->ncrumb)
+		return &aux->crumb[aux->ncrumb - n - 1];
+	return nil;
 }
 
 static vlong
-findbranch(Gitaux *aux, char *path)
+branchid(Gitaux *aux, char *path)
 {
 	int i;
 
@@ -85,16 +132,18 @@
 	branches[i + 1] = nil;
 
 found:
-	if(aux)
+	if(aux){
+		if(aux->refpath)
+			free(aux->refpath);
 		aux->refpath = estrdup(branches[i]);
-	return QPATH(i, Qbranch|Internal);
+	}
+	return i;
 }
 
 static void
-obj2dir(Dir *d, Object *o, Crumb *c, char *name, long qdir)
+obj2dir(Dir *d, Crumb *c, Object *o, char *name)
 {
-	d->qid.type = QTDIR;
-	d->qid.path = QPATH(o->id, qdir);
+	d->qid = c->qid;
 	d->atime = c->mtime;
 	d->mtime = c->mtime;
 	d->mode = c->mode;
@@ -115,7 +164,7 @@
 {
 	Crumb *c;
 
-	c = curcrumb(p);
+	c = crumb(p, 0);
 	if (i >= nelem(qroot))
 		return -1;
 	d->mode = 0555 | DMDIR;
@@ -122,7 +171,7 @@
 	d->name = estrdup9p(qroot[i]);
 	d->qid.vers = 0;
 	d->qid.type = strcmp(qroot[i], "ctl") == 0 ? 0 : QTDIR;
-	d->qid.path = QPATH(i, Qroot);
+	d->qid.path = qpath(nil, i, i, Qroot);
 	d->uid = estrdup9p(username);
 	d->gid = estrdup9p(username);
 	d->muid = estrdup9p(username);
@@ -139,11 +188,11 @@
 	int n;
 
 	aux = p;
-	c = curcrumb(aux);
+	c = crumb(aux, 0);
 	refs = nil;
 	d->qid.vers = 0;
 	d->qid.type = QTDIR;
-	d->qid.path = findbranch(nil, aux->refpath);
+	d->qid.path = qpath(c, i, branchid(aux, aux->refpath), Qbranch | Internal);
 	d->mode = 0555 | DMDIR;
 	d->uid = estrdup9p(username);
 	d->gid = estrdup9p(username);
@@ -189,7 +238,7 @@
 	Crumb *c;
 
 	aux = p;
-	c = curcrumb(aux);
+	c = crumb(aux, 0);
 	e = c->obj;
 	if(i >= e->tree->nent)
 		return -1;
@@ -200,7 +249,7 @@
 			die("could not read object %H: %r", e->tree->ent[i].h, e->hash);
 	d->qid.vers = 0;
 	d->qid.type = o->type == GTree ? QTDIR : 0;
-	d->qid.path = QPATH(o->id, aux->qdir);
+	d->qid.path = qpath(c, i, o->id, aux->qdir);
 	d->mode = e->tree->ent[i].mode;
 	d->atime = c->mtime;
 	d->mtime = c->mtime;
@@ -216,8 +265,10 @@
 gcommitgen(int i, Dir *d, void *p)
 {
 	Object *o;
+	Crumb *c;
 
-	o = curcrumb(p)->obj;
+	c = crumb(p, 0);
+	o = c->obj;
 	d->uid = estrdup9p(username);
 	d->gid = estrdup9p(username);
 	d->muid = estrdup9p(username);
@@ -232,23 +283,23 @@
 		d->mode = 0555 | DMDIR;
 		d->name = estrdup9p("tree");
 		d->qid.type = QTDIR;
-		d->qid.path = QPATH(o->id, Qcommittree);
+		d->qid.path = qpath(c, i, o->id, Qcommittree);
 		break;
 	case 1:
 		d->name = estrdup9p("parent");
-		d->qid.path = QPATH(o->id, Qcommitparent);
+		d->qid.path = qpath(c, i, o->id, Qcommitparent);
 		break;
 	case 2:
 		d->name = estrdup9p("msg");
-		d->qid.path = QPATH(o->id, Qcommitmsg);
+		d->qid.path = qpath(c, i, o->id, Qcommitmsg);
 		break;
 	case 3:
 		d->name = estrdup9p("hash");
-		d->qid.path = QPATH(o->id, Qcommithash);
+		d->qid.path = qpath(c, i, o->id, Qcommithash);
 		break;
 	case 4:
 		d->name = estrdup9p("author");
-		d->qid.path = QPATH(o->id, Qcommitauthor);
+		d->qid.path = qpath(c, i, o->id, Qcommitauthor);
 		break;
 	default:
 		return -1;
@@ -268,7 +319,7 @@
 	Hash h;
 
 	aux = p;
-	c = curcrumb(aux);
+	c = crumb(aux, 0);
 	if(!aux->ols)
 		aux->ols = mkols();
 	ols = aux->ols;
@@ -276,7 +327,7 @@
 	/* We tried to sent it, but it didn't fit */
 	if(aux->olslast && ols->idx == i + 1){
 		snprint(name, sizeof(name), "%H", aux->olslast->hash);
-		obj2dir(d, aux->olslast, c, name, Qobject);
+		obj2dir(d, c, aux->olslast, name);
 		return 0;
 	}
 	while(ols->idx <= i){
@@ -287,7 +338,7 @@
 	}
 	if(o != nil){
 		snprint(name, sizeof(name), "%H", o->hash);
-		obj2dir(d, o, c, name, Qobject);
+		obj2dir(d, c, o, name);
 		unref(aux->olslast);
 		aux->olslast = ref(o);
 		return 0;
@@ -300,7 +351,7 @@
 {
 	Object *o;
 
-	o = curcrumb(aux)->obj;
+	o = crumb(aux, 0)->obj;
 	switch(o->type){
 	case GBlob:
 		readbuf(r, o->data, o->size);
@@ -358,7 +409,7 @@
 }
 
 static char *
-objwalk1(Qid *q, Object *o, Crumb *c, char *name, vlong qdir)
+objwalk1(Qid *q, Object *o, Crumb *p, Crumb *c, char *name, vlong qdir)
 {
 	Object *w;
 	char *e;
@@ -379,7 +430,7 @@
 			if(!w)
 				die("could not read object for %s", name);
 			q->type = (w->type == GTree) ? QTDIR : 0;
-			q->path = QPATH(w->id, qdir);
+			q->path = qpath(c, i, w->id, qdir);
 			c->mode = o->tree->ent[i].mode;
 			c->obj = w;
 		}
@@ -391,16 +442,16 @@
 		c->mode = 0444;
 		assert(qdir == Qcommit || qdir == Qobject || qdir == Qcommittree || qdir == Qhead);
 		if(strcmp(name, "msg") == 0)
-			q->path = QPATH(o->id, Qcommitmsg);
+			q->path = qpath(p, 0, o->id, Qcommitmsg);
 		else if(strcmp(name, "parent") == 0 && o->commit->nparent != 0)
-			q->path = QPATH(o->id, Qcommitparent);
+			q->path = qpath(p, 1, o->id, Qcommitparent);
 		else if(strcmp(name, "hash") == 0)
-			q->path = QPATH(o->id, Qcommithash);
+			q->path = qpath(p, 2, o->id, Qcommithash);
 		else if(strcmp(name, "author") == 0)
-			q->path = QPATH(o->id, Qcommitauthor);
+			q->path = qpath(p, 3, o->id, Qcommitauthor);
 		else if(strcmp(name, "tree") == 0){
 			q->type = QTDIR;
-			q->path = QPATH(o->id, Qcommittree);
+			q->path = qpath(p, 4, o->id, Qcommittree);
 			unref(c->obj);
 			c->obj = readobject(o->commit->tree);
 			c->mode = DMDIR | 0555;
@@ -513,9 +564,9 @@
 		q->type = QTDIR;
 		d = dirstat(path);
 		if(d && d->qid.type == QTDIR)
-			q->path = QPATH(findbranch(aux, path), Qbranch);
+			q->path = qpath(o, Qbranch, branchid(aux, path), Qbranch);
 		else if(d && (c->obj = readref(path)) != nil)
-			q->path = QPATH(c->obj->id, Qcommit);
+			q->path = qpath(o, Qbranch, c->obj->id, Qcommit);
 		else
 			e = Eexist;
 		free(d);
@@ -522,7 +573,7 @@
 		break;
 	case Qobject:
 		if(c->obj){
-			e = objwalk1(q, o->obj, c, name, Qobject);
+			e = objwalk1(q, o->obj, o, c, name, Qobject);
 		}else{
 			if(hparse(&h, name) == -1)
 				return "invalid object name";
@@ -529,19 +580,19 @@
 			if((c->obj = readobject(h)) == nil)
 				return "could not read object";
 			c->mode = (c->obj->type == GBlob) ? 0444 : QTDIR | 0555;
-			q->path = QPATH(c->obj->id, Qobject);
+			q->path = qpath(o, Qobject, c->obj->id, Qobject);
 			q->type = (c->obj->type == GBlob) ? 0 : QTDIR;
 			q->vers = 0;
 		}
 		break;
 	case Qhead:
-		e = objwalk1(q, o->obj, c, name, Qhead);
+		e = objwalk1(q, o->obj, o, c, name, Qhead);
 		break;
 	case Qcommit:
-		e = objwalk1(q, o->obj, c, name, Qcommit);
+		e = objwalk1(q, o->obj, o, c, name, Qcommit);
 		break;
 	case Qcommittree:
-		e = objwalk1(q, o->obj, c, name, Qcommittree);
+		e = objwalk1(q, o->obj, o, c, name, Qcommittree);
 		break;
 	case Qcommitparent:
 	case Qcommitmsg:
@@ -634,7 +685,7 @@
 
 	aux = r->fid->aux;
 	q = &r->fid->qid;
-	o = curcrumb(aux)->obj;
+	o = crumb(aux, 0)->obj;
 	e = nil;
 
 	switch(QDIR(q)){
@@ -692,12 +743,11 @@
 gitstat(Req *r)
 {
 	Gitaux *aux;
-	Crumb *c;
-	Qid *q;
+	Crumb *c, *p;
 
 	aux = r->fid->aux;
-	q = &r->fid->qid;
-	c = curcrumb(aux);
+	c = crumb(aux, 0);
+	p = crumb(aux, 1);
 	r->d.uid = estrdup9p(username);
 	r->d.gid = estrdup9p(username);
 	r->d.muid = estrdup9p(username);
@@ -706,7 +756,7 @@
 	r->d.atime = c->mtime;
 	r->d.mode = c->mode;
 	if(c->obj)
-		obj2dir(&r->d, c->obj, c, c->name, QDIR(q));
+		obj2dir(&r->d, p, c->obj, c->name);
 	else
 		r->d.name = estrdup9p(c->name);
 	respond(r, nil);