shithub: git9

Download patch

ref: 3261c06c0233588e24887f1bbfc1b8dfd4c647f9
parent: 828f943ad4fff1cdf4aa5b7c7a0b795c51b1d4ef
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Aug 14 23:09:02 EDT 2020

Work towards deltification.

--- a/git.h
+++ b/git.h
@@ -6,6 +6,7 @@
 
 typedef struct Conn	Conn;
 typedef struct Hash	Hash;
+typedef struct Delta	Delta;
 typedef struct Cinfo	Cinfo;
 typedef struct Tinfo	Tinfo;
 typedef struct Object	Object;
@@ -99,6 +100,12 @@
 	char islink;
 };
 
+struct Delta {
+	int	cpy;
+	int	off;
+	int	len;
+};
+
 struct Object {
 	/* Git data */
 	Hash	hash;
@@ -122,6 +129,7 @@
 	/* size excludes header */
 	vlong	size;
 
+	/* Significant win on memory use */
 	union {
 		Cinfo *commit;
 		Tinfo *tree;
@@ -221,8 +229,10 @@
 /* object io */
 int	resolverefs(Hash **, char *);
 int	resolveref(Hash *, char *);
+int	listrefs(Hash **);
 Object	*ancestor(Object *, Object *);
 Object	*readobject(Hash);
+Object	*clearedobject(Hash, int);
 void	parseobject(Object *);
 int	indexpack(char *, char *, Hash);
 int	hasheq(Hash *, Hash *);
@@ -234,7 +244,7 @@
 /* object sets */
 void	osinit(Objset *);
 void	osadd(Objset *, Object *);
-int	oshas(Objset *, Object *);
+int	oshas(Objset *, Hash);
 Object	*osfind(Objset *, Hash);
 
 /* object listing */
@@ -251,6 +261,9 @@
 int	hassuffix(char *, char *);
 int	swapsuffix(char *, int, char *, char *, char *);
 char	*strip(char *);
+
+/* packing */
+Delta*	deltify(void*, int, void *, int, int *, int *);
 
 /* proto handling */
 int	readpkt(Conn*, char*, int);
--- a/objset.c
+++ b/objset.c
@@ -60,7 +60,7 @@
 }
 
 int
-oshas(Objset *s, Object *o)
+oshas(Objset *s, Hash h)
 {
-	return osfind(s, o->hash) != nil;
+	return osfind(s, h) != nil;
 }
--- a/pack.c
+++ b/pack.c
@@ -887,6 +887,9 @@
 	return nil;
 }
 
+/*
+ * Loads and returns a cached object.
+ */
 Object*
 readobject(Hash h)
 {
@@ -895,6 +898,30 @@
 	o = readidxobject(nil, h, 0);
 	if(o)
 		ref(o);
+	return o;
+}
+
+/*
+ * Creates and returns a cached, cleared object
+ * that will get loaded some other time. Useful
+ * for performance if need to mark that a blob
+ * exists, but we don't care about its contents.
+ *
+ * The refcount of the returned object is 0, so
+ * it doesn't need to be unrefed.
+ */
+Object*
+clearedobject(Hash h, int type)
+{
+	Object *o;
+
+	if((o = osfind(&objcache, h)) != nil)
+		return o;
+
+	o = emalloc(sizeof(Object));
+	o->hash = h;
+	o->type = type;
+	osadd(&objcache, o);
 	return o;
 }
 
--- a/ref.c
+++ b/ref.c
@@ -238,7 +238,7 @@
 
 	for(i = nobj; i >= 0; i--){
 		idx[i]++;
-		if(keep && !oshas(set, obj[i])){
+		if(keep && !oshas(set, obj[i]->hash)){
 			push(ev, obj[i]);
 			osadd(set, obj[i]);
 		}else{
@@ -284,10 +284,10 @@
 		else if(p->commit->nparent == 0)
 			if((nall = unwind(ev, all, idx, nall, &p, &skip, 0)) == -1)
 				break;
-		else if(oshas(&keep, p))
+		else if(oshas(&keep, p->hash))
 			if((nall = unwind(ev, all, idx, nall, &p, &keep, 1)) == -1)
 				break;
-		else if(oshas(&skip, p))
+		else if(oshas(&skip, p->hash))
 			if((nall = unwind(ev, all, idx, nall, &p, &skip, 0)) == -1)
 				break;
 		if(p->commit->nparent == 0)
@@ -444,4 +444,47 @@
 	}
 	*r = ev.stk[0]->hash;
 	return 0;
+}
+
+int
+readrefdir(Hash **refs, int *nrefs, char *dpath, char *dname)
+{
+	Dir *d, *e, *dir;
+	char *path, *name;
+	int ndir;
+
+	if((ndir = slurpdir(dpath, &dir)) == -1)
+		return -1;
+	e = dir + ndir;
+	for(d = dir; d != e; d++){
+		path = smprint("%s/%s", dpath, d->name);
+		name = smprint("%s/%s", dname, d->name);
+		if(d->mode & DMDIR) {
+			if(readrefdir(refs, nrefs, path, name) == -1)
+				goto nextiter;
+		}else{
+			*refs = erealloc(*refs, (*nrefs + 1)*sizeof(Hash));
+			if(resolveref(*refs + *nrefs, name) == -1)
+				goto nextiter;
+			*nrefs += 1;
+		}
+nextiter:		
+		free(name);
+		free(path);
+	}
+	return 0;
+}
+
+int
+listrefs(Hash **refs)
+{
+	int nrefs;
+
+	*refs = nil;
+	nrefs = 0;
+	if(readrefdir(refs, &nrefs, ".git/refs", "") == -1){
+		free(*refs);
+		return -1;
+	}
+	return nrefs;
 }
--- a/send.c
+++ b/send.c
@@ -56,7 +56,7 @@
 	Object *s;
 	int i;
 
-	if(oshas(send, o) || oshas(skip, o))
+	if(oshas(send, o->hash) || oshas(skip, o->hash))
 		return;
 	osadd(send, o);
 	switch(o->type){
@@ -203,7 +203,7 @@
 		e = n;
 	for(; q; q = n){
 		o = q->obj;
-		if(oshas(&skip, o) || oshas(&send, o))
+		if(oshas(&skip, o->hash) || oshas(&send, o->hash))
 			goto iter;
 		pack(&send, &skip, o);
 		for(i = 0; i < o->commit->nparent; i++){