From: ori@eigenstate.org
To: 9front@9front.org
Subject: Re: [9front] git/query: improve LCA results
Date: Sat, 28 Aug 2021 22:33:15 -0400 [thread overview]
Message-ID: <77A01EE7FDB6C6E09DFECCDC61185541@eigenstate.org> (raw)
In-Reply-To: <FA21959D15655F42CFCC493082E2A3FE@eigenstate.org>
Quoth ori@eigenstate.org:
> Since bugs here can lead to issues sysupdating, I'd
> like some extra eyeballs, testing, and review on this
> before I commit.
A slightly improved version. The `haskeep()` optimization
to break out early could cause us to leave before we'd
found the best node.
diff e6f0abc25e4e237fff97ef9bdd1dc98ee519def8 uncommitted
--- a/sys/src/cmd/git/ref.c
+++ b/sys/src/cmd/git/ref.c
@@ -22,19 +22,19 @@
int stksz;
};
-struct XObject {
- Object *obj;
- Object *mark;
- XObject *queue;
- XObject *next;
-};
-
struct Objq {
Objq *next;
Object *o;
int color;
+ int dist;
};
+static char *colors[] = {
+[Keep] "keep",
+[Drop] "drop",
+[Blank] "blank",
+};
+
static Object zcommit = {
.type=GCommit
};
@@ -128,110 +128,6 @@
return 1;
}
-XObject*
-hnode(XObject *ht[], Object *o)
-{
- XObject *h;
- int hh;
-
- hh = o->hash.h[0] & 0xff;
- for(h = ht[hh]; h; h = h->next)
- if(hasheq(&o->hash, &h->obj->hash))
- return h;
-
- h = emalloc(sizeof(*h));
- h->obj = o;
- h->mark = nil;
- h->queue = nil;
- h->next = ht[hh];
- ht[hh] = h;
- return h;
-}
-
-Object*
-ancestor(Object *a, Object *b)
-{
- Object *o, *p, *r;
- XObject *ht[256];
- XObject *h, *q, *q1, *q2;
- int i;
-
- if(a == b)
- return a;
- if(a == nil || b == nil)
- return nil;
- r = nil;
- memset(ht, 0, sizeof(ht));
- q1 = nil;
-
- h = hnode(ht, a);
- h->mark = a;
- h->queue = q1;
- q1 = h;
-
- h = hnode(ht, b);
- h->mark = b;
- h->queue = q1;
- q1 = h;
-
- while(1){
- q2 = nil;
- while(q = q1){
- q1 = q->queue;
- q->queue = nil;
- o = q->obj;
- for(i = 0; i < o->commit->nparent; i++){
- p = readobject(o->commit->parent[i]);
- if(p == nil)
- goto err;
- h = hnode(ht, p);
- if(h->mark != nil){
- if(h->mark != q->mark){
- r = h->obj;
- goto done;
- }
- } else {
- h->mark = q->mark;
- h->queue = q2;
- q2 = h;
- }
- }
- }
- if(q2 == nil){
-err:
- werrstr("no common ancestor");
- break;
- }
- q1 = q2;
- }
-done:
- for(i=0; i<nelem(ht); i++){
- while(h = ht[i]){
- ht[i] = h->next;
- free(h);
- }
- }
- return r;
-}
-
-int
-lca(Eval *ev)
-{
- Object *a, *b, *o;
-
- if(ev->nstk < 2){
- werrstr("ancestor needs 2 objects");
- return -1;
- }
- a = pop(ev);
- b = pop(ev);
- o = ancestor(a, b);
- if(o == nil)
- return -1;
- push(ev, o);
- return 0;
-}
-
static int
repaint(Objset *keep, Objset *drop, Object *o)
{
@@ -249,29 +145,48 @@
for(i = 0; i < o->commit->nparent; i++){
if((p = readobject(o->commit->parent[i])) == nil)
return -1;
+ if(oshas(drop, p->hash))
+ goto next;
if(repaint(keep, drop, p) == -1)
return -1;
+next:
unref(p);
}
return 0;
}
-int
-findtwixt(Hash *head, int nhead, Hash *tail, int ntail, Object ***res, int *nres)
+static int
+bestpick(Hash *head, int nhead, Hash *tail, int ntail, Objq *q, int dist)
{
+ int i;
+
+ if(q->dist < dist)
+ return 1;
+ for(i = 0; i < nhead; i++)
+ if(hasheq(&head[i], &q->o->hash))
+ return 1;
+ for(i = 0; i < ntail; i++)
+ if(hasheq(&tail[i], &q->o->hash))
+ return 1;
+ return 0;
+}
+
+static int
+paint(Hash *head, int nhead, Hash *tail, int ntail, Object ***res, int *nres, int ancestor)
+{
Objq *q, *e, *n, **p;
Objset keep, drop;
- Object *o, *c;
- int i, ncolor;
+ Object *o, *c, *best;
+ int i, dist, ncolor;
e = nil;
q = nil;
p = &q;
+ best = nil;
+ dist = 1<<30;
osinit(&keep);
osinit(&drop);
for(i = 0; i < nhead; i++){
- if(hasheq(&head[i], &Zhash))
- continue;
if((o = readobject(head[i])) == nil){
fprint(2, "warning: %H does not point at commit\n", o->hash);
werrstr("read head %H: %r", head[i]);
@@ -282,17 +197,16 @@
unref(o);
continue;
}
- dprint(1, "twixt init: keep %H\n", o->hash);
+ dprint(1, "init: keep %H\n", o->hash);
e = emalloc(sizeof(Objq));
e->o = o;
e->color = Keep;
+ e->dist = 0;
*p = e;
p = &e->next;
unref(o);
}
for(i = 0; i < ntail; i++){
- if(hasheq(&tail[i], &Zhash))
- continue;
if((o = readobject(tail[i])) == nil){
werrstr("read tail %H: %r", tail[i]);
return -1;
@@ -306,6 +220,7 @@
e = emalloc(sizeof(Objq));
e->o = o;
e->color = Drop;
+ e->dist = 0;
*p = e;
p = &e->next;
unref(o);
@@ -319,18 +234,37 @@
ncolor = Keep;
else
ncolor = Blank;
- if(ncolor == Drop || ncolor == Keep && q->color == Keep)
+ dprint(2, "visit: ncolor=%s, qcolor=%s %H\n",
+ colors[ncolor], colors[q->color], q->o->hash);
+ if(ncolor == Keep && q->color == Keep){
goto next;
- if(ncolor == Keep && q->color == Drop){
+ }else if(ncolor == Drop){
+ dprint(2, "consider: best %H => %H (dist: %d => %d)\n",
+ best ? best->hash : Zhash, q->o->hash,
+ dist, q->dist);
+ if(q->color == Keep && bestpick(head, nhead, tail, ntail, q, dist)){
+ dprint(2, "ancestor: best %H => %H (dist: %d => %d)\n",
+ best ? best->hash : Zhash, q->o->hash,
+ dist, q->dist);
+ best = q->o;
+ dist = q->dist;
+ }
+ }else if(ncolor == Keep && q->color == Drop){
+ dprint(2, "consider: best %H => %H (dist: %d => %d)\n", best ? best->hash : Zhash, q->o->hash, dist, q->dist);
+ if(bestpick(head, nhead, tail, ntail, q, dist)){
+ dprint(2, "ancestor: best %H => %H (dist: %d => %d)\n", best ? best->hash : Zhash, q->o->hash, dist, q->dist);
+ best = q->o;
+ dist = q->dist;
+ }
if(repaint(&keep, &drop, q->o) == -1)
goto error;
}else if (ncolor == Blank) {
- dprint(2, "visit: %s %H\n", q->color == Keep ? "keep" : "drop", q->o->hash);
if(q->color == Keep)
osadd(&keep, q->o);
else
osadd(&drop, q->o);
- for(i = 0; i < q->o->commit->nparent; i++){
+ o = readobject(q->o->hash);
+ for(i = 0; i < o->commit->nparent; i++){
if((c = readobject(q->o->commit->parent[i])) == nil)
goto error;
if(c->type != GCommit){
@@ -338,9 +272,10 @@
unref(c);
continue;
}
- dprint(2, "enqueue: %s %H\n", q->color == Keep ? "keep" : "drop", c->hash);
+ dprint(2, "enqueue: %s %H\n", colors[q->color], c->hash);
n = emalloc(sizeof(Objq));
n->color = q->color;
+ n->dist = q->dist + 1;
n->next = nil;
n->o = c;
e->next = n;
@@ -347,8 +282,9 @@
e = n;
unref(c);
}
+ unref(o);
}else{
- sysfatal("oops");
+ sysfatal("oops: ncolor==%d && qcolor==%d", ncolor, q->color);
}
next:
n = q->next;
@@ -355,13 +291,24 @@
free(q);
q = n;
}
- *res = eamalloc(keep.nobj, sizeof(Object*));
- *nres = 0;
- for(i = 0; i < keep.sz; i++){
- if(keep.obj[i] != nil && !oshas(&drop, keep.obj[i]->hash)){
- (*res)[*nres] = keep.obj[i];
- (*nres)++;
+ if(ancestor){
+ if(best == nil){
+ *nres = 0;
+ *res = nil;
+ }else{
+ *nres = 1;
+ *res = eamalloc(1, sizeof(Object*));
+ (*res)[0] = best;
}
+ }else{
+ *res = eamalloc(keep.nobj, sizeof(Object*));
+ *nres = 0;
+ for(i = 0; i < keep.sz; i++){
+ if(keep.obj[i] != nil && !oshas(&drop, keep.obj[i]->hash)){
+ (*res)[*nres] = keep.obj[i];
+ (*nres)++;
+ }
+ }
}
osclear(&keep);
osclear(&drop);
@@ -372,6 +319,46 @@
free(q);
}
return -1;
+}
+
+int
+findtwixt(Hash *head, int nhead, Hash *tail, int ntail, Object ***res, int *nres)
+{
+ return paint(head, nhead, tail, ntail, res, nres, 0);
+}
+
+Object*
+ancestor(Object *a, Object *b)
+{
+ Object **o, *r;
+ int n;
+
+ if(paint(&a->hash, 1, &b->hash, 1, &o, &n, 1) == -1 || n == 0)
+ return nil;
+ r = o[0];
+ free(o);
+ return r;
+}
+
+int
+lca(Eval *ev)
+{
+ Object *a, *b, **o;
+ int n;
+
+ if(ev->nstk < 2){
+ werrstr("ancestor needs 2 objects");
+ return -1;
+ }
+ n = 0;
+ a = pop(ev);
+ b = pop(ev);
+ paint(&a->hash, 1, &b->hash, 1, &o, &n, 1);
+ if(n == 0)
+ return -1;
+ push(ev, *o);
+ free(o);
+ return 0;
}
static int
next prev parent reply other threads:[~2021-08-29 2:40 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-29 2:04 ori
2021-08-29 2:33 ` ori [this message]
2021-08-29 7:45 ` hiro
2021-08-29 15:28 ` ori
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=77A01EE7FDB6C6E09DFECCDC61185541@eigenstate.org \
--to=ori@eigenstate.org \
--cc=9front@9front.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).