git: 9front

Download patch

ref: aaf53fb23552873a01baf346f3ada736e8518fd8
parent: ca6e995952dfdafeb7ca908e27ee93526015d0b9
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Wed Nov 21 14:22:46 EST 2012

hgfs: various improvements

lazily close revlog files and keep up to 8
revlogs arround. also cache the latest extracted
file descriptor of a revision in the revlog.
this avoids the quite expensive reextracting/patching
when we reopen the same file revision.

dont use the racy mktemp()/create, instead create
a uniqueue name and create with OEXCL. this also
avoids a bunch of access() calls.

fix eof case and use pread() in fcopy() to avoid the
seeks.

dont modify changelog temp file but simulate trailing
newline instead.

--- a/sys/src/cmd/hgfs/dat.h
+++ b/sys/src/cmd/hgfs/dat.h
@@ -46,6 +46,9 @@
 
 	int	nmap;
 	Revmap	*map;
+
+	int	tfd;
+	int	tid;
 };
 
 struct Revnode
--- a/sys/src/cmd/hgfs/fns.h
+++ b/sys/src/cmd/hgfs/fns.h
@@ -6,6 +6,7 @@
 int readhash(char *path, char *name, uchar hash[]);
 
 /* patch */
+int fcopy(int dfd, int sfd, vlong off, vlong len);
 int fpatchmark(int pfd, char *mark);
 int fpatch(int ofd, int bfd, int pfd);
 
--- a/sys/src/cmd/hgfs/fs.c
+++ b/sys/src/cmd/hgfs/fs.c
@@ -43,6 +43,7 @@
 static Revlog changelog;
 static Revlog manifest;
 static Revlog *revlogs;
+static int nfreerevlogs = 0;
 
 static char workdir[MAXPATH];
 static int mangle = 0;
@@ -51,7 +52,7 @@
 getrevlog(Revnode *nd)
 {
 	char buf[MAXPATH];
-	Revlog *rl;
+	Revlog *rl, **link;
 	int mang;
 
 	mang = mangle;
@@ -58,9 +59,21 @@
 Again:
 	nodepath(seprint(buf, buf+sizeof(buf), "%s/.hg/store/data", workdir),
 		buf+sizeof(buf), nd, mang);
-	for(rl = revlogs; rl; rl = rl->next)
-		if(strcmp(buf, rl->path) == 0)
+	link = &revlogs;
+	while(rl = *link){
+		if(strcmp(buf, rl->path) == 0){
+			if(rl->ref == 0) nfreerevlogs--;
 			break;
+		}
+		if(nfreerevlogs > 8 && rl->ref == 0){
+			*link = rl->next;
+			nfreerevlogs--;
+			revlogclose(rl);
+			free(rl);
+			continue;
+		}
+		link = &rl->next;
+	}
 	if(rl == nil){
 		rl = emalloc9p(sizeof(*rl));
 		memset(rl, 0, sizeof(*rl));
@@ -83,18 +96,8 @@
 static void
 closerevlog(Revlog *rl)
 {
-	Revlog **pp;
-
-	if(rl == nil || decref(rl))
-		return;
-	for(pp = &revlogs; *pp; pp = &((*pp)->next)){
-		if(*pp == rl){
-			*pp = rl->next;
-			break;
-		}
-	}
-	revlogclose(rl);
-	free(rl);
+	if(rl != nil && decref(rl) == 0)
+		nfreerevlogs++;
 }
 
 static Revinfo*
--- a/sys/src/cmd/hgfs/info.c
+++ b/sys/src/cmd/hgfs/info.c
@@ -8,7 +8,7 @@
 loadrevinfo(Revlog *changelog, int rev)
 {
 	char buf[BUFSZ], *p, *e;
-	int fd, line, inmsg, n;
+	int fd, line, eof, inmsg, n;
 	Revinfo *ri;
 	vlong off;
 
@@ -15,9 +15,6 @@
 	if((fd = revlogopentemp(changelog, rev)) < 0)
 		return nil;
 
-	seek(fd, 0, 2);
-	write(fd, "\n", 1);
-
 	off = fmetaheader(fd);
 	seek(fd, off, 0);
 
@@ -26,11 +23,19 @@
 
 	memmove(ri->chash, changelog->map[rev].hash, HASHSZ);
 
+	eof = 0;
 	line = 0;
 	inmsg = 0;
 	p = buf;
 	e = buf + BUFSZ;
-	while((n = read(fd, p, e - p)) > 0){
+	while(eof == 0){
+		if((n = read(fd, p, e - p)) < 0)
+			break;
+		if(n == 0){
+			eof = 1;
+			*p = '\n';
+			n++;
+		}
 		p += n;
 		while((p > buf) && (e = memchr(buf, '\n', p - buf))){
 			*e++ = 0;
--- a/sys/src/cmd/hgfs/patch.c
+++ b/sys/src/cmd/hgfs/patch.c
@@ -5,19 +5,25 @@
 #include "fns.h"
 
 int
-fcopy(int dfd, int sfd, vlong len)
+fcopy(int dfd, int sfd, vlong off, vlong len)
 {
 	uchar buf[BUFSZ];
 	int n;
 
-	while(len > 0){
-		if((n = BUFSZ) > len)
+	while(len != 0){
+		n = BUFSZ;
+		if(len > 0 && n > len)
 			n = len;
-		if((n = read(sfd, buf, n)) < 0)
+		if((n = pread(sfd, buf, n, off)) < 0)
 			return -1;
+		if(n == 0)
+			return len > 0 ? -1 : 0;
 		if(write(dfd, buf, n) != n)
 			return -1;
-		len -= n;
+		if(off >= 0)
+			off += n;
+		if(len > 0)
+			len -= n;
 	}
 	return 0;
 }
@@ -58,6 +64,8 @@
 
 	if(bfd >= 0){
 		h = malloc(sizeof(Frag));
+		if(h == nil)
+			goto errout;
 		h->next = nil;
 		h->off = 0;
 		h->fd = bfd;
@@ -101,6 +109,8 @@
 			back = end < fend;
 			if(front && back){
 				p = malloc(sizeof(Frag));
+				if(p == nil)
+					goto errout;
 				*p = *f;
 				f->next = p;
 				f->len = start - fstart;
@@ -123,6 +133,8 @@
 			fstart += f->len;
 
 		f = malloc(sizeof(Frag));
+		if(f == nil)
+			goto errout;
 		f->fd = pfd;
 		f->len = len;
 		f->off = seek(f->fd, 0, 1);
@@ -141,12 +153,9 @@
 			goto errout;
 	}
 
-	for(f = h; f; f = f->next){
-		if(seek(f->fd, f->off, 0) < 0)
+	for(f = h; f; f = f->next)
+		if(fcopy(ofd, f->fd, f->off, f->len) < 0)
 			goto errout;
-		if(fcopy(ofd, f->fd, f->len) < 0)
-			goto errout;
-	}
 	err = 0;
 
 errout:
--- a/sys/src/cmd/hgfs/revlog.c
+++ b/sys/src/cmd/hgfs/revlog.c
@@ -7,10 +7,10 @@
 int
 fmktemp(void)
 {
-	char temp[MAXPATH];
-
-	snprint(temp, sizeof(temp), "/tmp/hgXXXXXXXXXXX");
-	return create(mktemp(temp), OTRUNC|ORCLOSE|ORDWR, 0666);
+	static ulong id = 1;
+	char path[MAXPATH];
+	snprint(path, sizeof(path), "/tmp/hg%.12d%.8lux", getpid(), id++);
+	return create(path, OEXCL|OTRUNC|ORDWR|ORCLOSE, 0600);
 }
 
 void
@@ -65,6 +65,8 @@
 {
 	r->ifd = -1;
 	r->dfd = -1;
+	r->tfd = -1;
+	r->tid = -1;
 	path = smprint("%s.i", path);
 	if((r->ifd = open(path, mode)) < 0){
 		free(path);
@@ -94,6 +96,11 @@
 		close(r->dfd);
 		r->dfd = -1;
 	}
+	if(r->tfd >= 0){
+		close(r->tfd);
+		r->tfd = -1;
+	}
+	r->tid = -1;
 	free(r->map);
 	r->map = nil;
 	r->nmap = 0;
@@ -269,12 +276,19 @@
 {
 	int fd;
 
-	if((fd = fmktemp()) < 0)
-		return -1;
-	if(revlogextract(r, rev, fd) < 0){
-		close(fd);
-		return -1;
+	if(r->tfd < 0 || rev != r->tid){
+		if((fd = fmktemp()) < 0)
+			return -1;
+		if(revlogextract(r, rev, fd) < 0){
+			close(fd);
+			return -1;
+		}
+		if(r->tfd >= 0)
+			close(r->tfd);
+		r->tfd = fd;
+		r->tid = rev;
 	}
+	fd = dup(r->tfd, -1);
 	if(seek(fd, 0, 0) < 0){
 		close(fd);
 		return -1;
--