code: mafs

Download patch

ref: 71313e391acdd31721f9c67f83717eecafb7ed0c
parent: 36f18c50a8d8b01ca698af36b20b816293ae0df8
author: 9ferno <gophone2015@gmail.com>
date: Fri Nov 25 15:05:11 EST 2022

flush old buffers

--- a/all.h
+++ b/all.h
@@ -38,6 +38,7 @@
 {
 	Iobuf*	link;	/* least recently used of the circular list */
 	QLock;		/* controls access to this hash bucket */
+	u64	n;		/* count of Iobuf's in the circular list */
 };
 
 /*
@@ -90,6 +91,7 @@
 	u8 *append;		/* appended data added not yet written to disk */
 	u64 appendsize;
 	u8 freshalloc;	/* uninitialized blocks on the disk */
+	u64 atime;		/* to find old buffers to flush to the disk */
 };
 
 extern	u64	nbuckets;		/* n hash buckets for i/o */
--- a/ctl.c
+++ b/ctl.c
@@ -2,6 +2,7 @@
 
 enum { MAXARGS = 16 };
 
+extern Extents memunits;
 static int echo;
 
 enum
@@ -99,7 +100,10 @@
 	used = config.nblocks - free;
 
 /*	n = snprint(buf, 1024, "pending writes %llud blocks\n", pendingwrites());*/
-	n = 0;
+	n = snprint(buf, 1024, "memunits extents:\n");
+	n += saveextents(&memunits, buf+n, 1024-n);
+	n += snprint(buf+n, 1024-n, "frees extents:\n");
+	n += saveextents(&frees, buf+n, 1024-n);
 	if(config.size > TiB)
 	n += snprint(buf+n, 1024-n, "(blocks) free %ulld, used %ulld, total %ulld\n"
 						"(MiB) free %ulld, used %ulld, total %ulld\n"
--- a/dat.h
+++ b/dat.h
@@ -37,6 +37,7 @@
 	Usec	= 1000ULL*1000,
 	Msec	= 1000ULL,
 	Nbkp	= 1,
+	Nrefresh = 10*Nsec,
 };
 
 /*
--- a/iobuf.c
+++ b/iobuf.c
@@ -13,6 +13,8 @@
 Extents memunits = {0};
 u8 *memunitpool = nil;
 u8 *memunitstart = nil;
+static lastflushtime = 0;
+static RWLock flushlck;
 
 /* using nunits + 1 for alignment */
 void
@@ -57,6 +59,47 @@
 }
 
 u64
+flushold(void)
+{
+	Iobuf *p;
+	Hiob *hp;
+	u64 nchecked, i;
+
+Again:
+	for(i = 0; i < nbuckets; i++){
+		hp=&hiob[i];
+		qlock(hp);
+		if((p = hp->link) != nil){
+			for(p = hp->link->back; p != hp->link; p = p->back){
+				if(p->ref == 0 &&
+					p->atime < nsec()-Nrefresh){
+					if(canwlock(p)){
+						/* p->ref cannot change without a lock on the hash bucket */
+						if(p->atime > nsec()-Nrefresh){
+							wunlock(p);
+							continue;
+						}
+						incref(p); /* not needed */
+						/* remove p from its current position in the lru circular buffer */
+						p->back->fore = p->fore;
+						p->fore->back = p->back;
+						hp->n--;
+						qunlock(hp);
+						flush(p);
+						freememunits(p->xiobuf, p->len);
+						free(p);
+						goto Again;
+					}
+				}
+			}
+		}
+		nchecked++;
+		qunlock(hp);
+	}
+	return i==nbuckets;
+}
+
+u64
 sync(void)
 {
 	Iobuf *p, *s;
@@ -83,7 +126,7 @@
 							nlocked++;
 						}
 				}
-				p = p->fore;
+				p = p->back;
 			}while(p != s);
 		}
 		qunlock(hp);
@@ -92,34 +135,6 @@
 }
 
 /*
-   add an Iobuf to the collisions lru linked list
-   hp must be locked
- */
-Iobuf *
-newbuf(Hiob *hp, u16 len)
-{
-	Iobuf *p, *q;
-
-	p = emalloc9p(sizeof(Iobuf));
-
-	q = hp->link;
-	if(q != nil){
-		p->fore = q;
-		p->back = q->back;
-		q->back = p;
-		p->back->fore = p;
-	}else{
-		hp->link = p;
-		p->fore = p;
-		p->back = p;
-	}
-	p->blkno = 0;
-	p->len   = len;
-	p->xiobuf = allocmemunits(len);
-	return p;
-}
-
-/*
 	Get the Iobuf of the disk block at addr from the buffer cache
 	for my use.
 
@@ -140,7 +155,6 @@
 {
 	Hiob *hp;
 	Iobuf *s, *p;
-	u64 ncollisions;
 
 	hp = &hiob[blkno%nbuckets];
 
@@ -153,8 +167,7 @@
 	s = hp->link;
 	if(s == nil)
 		goto new;
-	for(p=s, ncollisions = 0;;){
-		ncollisions++;
+	for(p=s;;){
 		if(p->blkno == blkno){
 			if(p != s){
 				/* remove p from its current position in the lru circular buffer */
@@ -174,28 +187,22 @@
 				dprint("	in cache, after qunlock(hp) hp 0x%p blkno %llud\n",
 						hp, blkno);
 			if(p->len != len){
-				if(chatty9p > 4)
-				dprint("getbuf refresh used blkno %llud, size in memory is %d"
-						" and not %d, caller %#p\n",
-						blkno, p->len, len, getcallerpc(&blkno));
-				if(p->len == 0 || len == 0)
-					panic("getbuf: p->len == 0 || len == 0 p->len %d len %d",
-							p->len, len);
 				wlock(p);
-				if(chatty9p > 4)
-					dprint("	after wlock() blkno %llud\n", blkno);
-				freememunits(p->xiobuf, p->len);
-				p->xiobuf = allocmemunits(len);
-				p->len = len;
-				p->freshalloc = freshalloc;
-				if(freshalloc == 0)
-					devread(blkno, p->xiobuf, len);
-				if(readonly){
-					if(chkwunlock(p) == 0){
-						showbuf(p);
-						panic("getbuf chkwunlock(p) == 0 called by %#p\n", getcallerpc(&blkno));
+				/* has someone done this change already? */
+				if(p->len != len){
+					freememunits(p->xiobuf, p->len);
+					p->xiobuf = allocmemunits(len);
+					p->len = len;
+					p->freshalloc = freshalloc;
+					if(freshalloc == 0)
+						devread(blkno, p->xiobuf, len);
+					if(readonly){
+						if(chkwunlock(p) == 0){
+							showbuf(p);
+							panic("getbuf chkwunlock(p) == 0 called by %#p\n", getcallerpc(&blkno));
+						}
+						rlock(p);
 					}
-					rlock(p);
 				}
 			}else if(readonly){
 				if(chatty9p > 4)
@@ -223,36 +230,22 @@
 		much either way. If it does, there is a changelru() function to do so in the
 		git history that can be reused.
 
-		dirties is decremented without a wlock() on the buffer in dowrite().
-		Using a wlock() in dowrite() deadlocks with putwrite().
-		getbuf() guarantees that even a free'ed block cannot be
-		stolen until the dirties == 0. This avoids dirty blocks
-		being stolen by other block numbers.
-		incref(dirties) only happens with a wlock() in putwrite().
+		incref(Iobuf) only happens with a qlock(hash bucket).
 	 */
-	if(ncollisions >= Ncollisions){
-Another:
-		do{
-			p = s->back;
-			if(p->ref == 0 && p->append != nil && canwlock(p)){
-				if(p->ref > 0 || p->append != nil){
-					wunlock(p);
-					goto Another;
+	if(hp->n >= Ncollisions){
+		for(p = hp->link->back; p != hp->link; p = p->back){
+			if(p->ref == 0 && p->append != nil){
+				if(canwlock(p)){
+					/* p->ref cannot change without a lock on the hash bucket */
+					if(p->append != nil){
+						wunlock(p);
+						continue;
+					}
+					incref(p);
+					goto found;	/* p is wlock() */
 				}
-				if(p->len != len){
-					freememunits(p->xiobuf, p->len);
-					p->xiobuf = allocmemunits(len);
-					p->len = len;
-				}else
-					memset(p->xiobuf, 0, p->len*Blocksize);
-				hp->link = p;
-				if(chatty9p > 4)
-					dprint("	stealing iobuf 0x%p for blkno %llud len %llud\n",
-							p, p->len, blkno);
-				goto found;	/* p is wlock() */
 			}
-			s = p;
-		}while(p != hp->link);
+		}
 	}
 
 	/* no unlocked blocks available; add a new one */
@@ -259,24 +252,46 @@
 new:
 	if(chatty9p > 4)
 		dprint("	adding new Iobuf for blkno %llud\n", blkno);
-	p = newbuf(hp, len);
-	if(chatty9p > 4)
-		dprint(" .. wlock() blkno %llud\n", blkno);
+	p = emalloc9p(sizeof(Iobuf));
 	wlock(p);
+	incref(p);
+	hp->n++;
 
 found:
 	p->blkno = blkno;
+	s = hp->link;
+	if(s != nil){
+		/* for stolen Iobuf */
+		if(p->fore != nil && p->back != nil){
+			/* remove p from its current position in the lru circular buffer */
+			p->back->fore = p->fore;
+			p->fore->back = p->back;
+		}
+		/* make p the hb->link and put it at the back of existing link */
+		p->fore = s;
+		p->back = s->back;
+		s->back = p;
+		p->back->fore = p;
+	}else{
+		p->fore = p;
+		p->back = p;
+	}
+	hp->link = p;
 	qunlock(hp);
 	if(chatty9p > 4)
 		dprint("	after qunlock(hp) hp 0x%p blkno %llud\n",
 				hp, blkno);
+	if(p->len != len){
+		if(p->len > 0)
+			freememunits(p->xiobuf, p->len);
+		p->xiobuf = allocmemunits(len);
+		p->len = len;
+	}else
+		memset(p->xiobuf, 0, p->len*Blocksize);
 	p->freshalloc = freshalloc;
 	if(freshalloc == 0)
 		devread(blkno, p->xiobuf, len);
 	if(readonly){
-		if(chatty9p > 4)
-		dprint("new buffer: switching from wlock() to rlock() blkno %llud\n", blkno);
-		incref(p);
 		wunlock(p);
 		rlock(p);
 		decref(p);
@@ -390,7 +405,7 @@
 	
 	if(chatty9p > 4)
 		dprint("putbuf p->blkno %llud\n", p->blkno);
-
+	p->atime = nsec();
 	if(p->readers){
 		chkrunlock(p);
 		if(chatty9p > 4)
@@ -431,6 +446,13 @@
 				bkp(srcbno, buf, config.root.dest[0], Qproot0);
 			}
 		}
+	}
+	if(canwlock(&flushlck)){
+		if(lastflushtime < nsec()-Nrefresh){
+			flushold();
+			lastflushtime = nsec();
+		}else
+			wunlock(&flushlck);
 	}
 }