ref: 71313e391acdd31721f9c67f83717eecafb7ed0c
parent: 36f18c50a8d8b01ca698af36b20b816293ae0df8
author: 9ferno <[email protected]>
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);
}
}