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++){