--- /n/sources/plan9/sys/src/cmd/fossil/cache.c Fri Apr 14 16:55:36 2023 +++ /sys/src/cmd/fossil/cache.c Tue Jun 16 10:39:51 2026 @@ -609,6 +609,51 @@ return b; } +void +cachePrefetch(Cache *c, u32int addr) +{ + Block *b; + ulong h; + + if(!diskCanPrefetch(c->disk)) + return; + + h = addr % c->hashSize; + qlock(&c->lk); + for(b = c->heads[h]; b != nil; b = b->next) + if(b->part == PartData && b->addr == addr) + break; + if(b != nil){ + qunlock(&c->lk); + return; + } + b = cacheBumpBlock(c); + b->part = PartData; + b->addr = addr; + localToGlobal(addr, b->score); + b->next = c->heads[h]; + c->heads[h] = b; + if(b->next != nil) + b->next->prev = &b->next; + b->prev = &c->heads[h]; + qunlock(&c->lk); + + bwatchLock(b); + qlock(&b->lk); + b->nlock = 1; + + if(b->iostate == BioEmpty){ + if(!readLabel(c, &b->l, addr)){ + blockPut(b); + return; + } + blockSetIOState(b, BioLabel); + } + if(b->iostate == BioEmpty || b->iostate == BioLabel) + diskRead(c->disk, b); + blockPut(b); +} + /* * fetch a global (Venti) block from the memory cache. * if it's not there, load it, bumping some other block. --- /n/sources/plan9/sys/src/cmd/fossil/disk.c Mon Nov 14 16:09:31 2016 +++ /sys/src/cmd/fossil/disk.c Tue Jun 16 10:39:51 2026 @@ -215,6 +215,17 @@ diskQueue(disk, b); } +int +diskCanPrefetch(Disk *disk) +{ + int ok; + + qlock(&disk->lk); + ok = disk->nqueue < QueueSize - 16; + qunlock(&disk->lk); + return ok; +} + void diskWrite(Disk *disk, Block *b) { --- /n/sources/plan9/sys/src/cmd/fossil/source.c Mon Nov 14 16:09:31 2016 +++ /sys/src/cmd/fossil/source.c Tue Jun 16 10:39:51 2026 @@ -822,6 +822,32 @@ } void +sourceReadAhead(Source *r, ulong bn, int n) +{ + Entry e; + Block *pb; + u32int addr; + int np, i0, k; + + assert(sourceIsLocked(r)); + if(!sourceGetEntry(r, &e)) + return; + if(e.depth == 0) + return; + np = e.psize/VtScoreSize; + i0 = bn % np; + pb = _sourceBlock(r, bn, OReadOnly, 1, 0); + if(pb == nil) + return; + for(k = 0; k < n && i0+k < np; k++){ + addr = globalToLocal(pb->data + (i0+k)*VtScoreSize); + if(addr != NilBlock) + cachePrefetch(r->fs->cache, addr); + } + blockPut(pb); +} + +void sourceClose(Source *r) { if(r == nil) --- /n/sources/plan9/sys/src/cmd/fossil/file.c Wed Apr 7 19:24:25 2021 +++ /sys/src/cmd/fossil/file.c Tue Jun 16 10:39:51 2026 @@ -46,6 +46,10 @@ static void fileRAccess(File*); static void fileWAccess(File*, char*); +enum { + RAWINDOW = 16, +}; + static File * fileAlloc(Fs *fs) { @@ -589,6 +593,40 @@ return -1; } +void +fileReadAhead(File *f, vlong offset, int n, u32int *raexpect, u32int *ramax) +{ + Source *s; + int dsize; + u32int bn0, last, start, frontier; + + if(fileIsDir(f)) + return; + if(!fileRLock(f)) + return; + if(!sourceLock(f->source, OReadOnly)){ + fileRUnlock(f); + return; + } + s = f->source; + dsize = s->dsize; + bn0 = offset/dsize; + last = (offset+n-1)/dsize; + if(offset == 0 || bn0 == *raexpect){ + frontier = last+RAWINDOW; + start = *ramax; + if(start < last+1) + start = last+1; + if(start <= frontier) + sourceReadAhead(s, start, frontier-start+1); + *ramax = frontier+1; + }else + *ramax = last+1; + *raexpect = last+1; + sourceUnlock(s); + fileRUnlock(f); +} + /* * Changes the file block bn to be the given block score. * Very sneaky. Only used by flfmt. --- /n/sources/plan9/sys/src/cmd/fossil/9p.c Sat Nov 12 00:09:03 2016 +++ /sys/src/cmd/fossil/9p.c Tue Jun 16 10:39:51 2026 @@ -556,8 +556,12 @@ n = dirRead(fid, data, count, m->t.offset); else if(fid->qid.type & QTAUTH) n = authRead(fid, data, count); - else + else{ n = fileRead(fid->file, data, count, m->t.offset); + if(n > 0) + fileReadAhead(fid->file, m->t.offset, n, + &fid->raexpect, &fid->ramax); + } if(n < 0) goto error; --- /n/sources/plan9/sys/src/cmd/fossil/9fid.c Mon Nov 14 16:09:31 2016 +++ /sys/src/cmd/fossil/9fid.c Tue Jun 16 10:39:51 2026 @@ -75,6 +75,8 @@ fid->ref = 0; fid->flags = 0; fid->open = FidOCreate; + fid->raexpect = 0; + fid->ramax = 0; assert(fid->fsys == nil); assert(fid->file == nil); fid->qid = (Qid){0, 0, 0}; --- /n/sources/plan9/sys/src/cmd/fossil/9.h Mon Nov 14 16:09:31 2016 +++ /sys/src/cmd/fossil/9.h Tue Jun 16 10:39:51 2026 @@ -107,6 +107,8 @@ int open; Fsys* fsys; File* file; + u32int raexpect; + u32int ramax; Qid qid; char* uid; char* uname; --- /n/sources/plan9/sys/src/cmd/fossil/fns.h Mon Nov 14 16:09:31 2016 +++ /sys/src/cmd/fossil/fns.h Tue Jun 16 10:39:51 2026 @@ -9,6 +9,7 @@ int sourceLock(Source*, int); char *sourceName(Source *s); Source* sourceOpen(Source*, ulong, int, int); +void sourceReadAhead(Source*, ulong, int); int sourceRemove(Source*); Source* sourceRoot(Fs*, u32int, int); int sourceSetDirSize(Source*, ulong); @@ -27,6 +28,7 @@ Block* cacheLocal(Cache*, int, u32int, int); Block* cacheLocalData(Cache*, u32int, int, u32int, int, u32int); u32int cacheLocalSize(Cache*, int); +void cachePrefetch(Cache*, u32int); int readLabel(Cache*, Label*, u32int addr); Block* blockCopy(Block*, u32int, u32int, u32int); @@ -43,6 +45,7 @@ Disk* diskAlloc(int); int diskBlockSize(Disk*); +int diskCanPrefetch(Disk*); int diskFlush(Disk*); void diskFree(Disk*); void diskRead(Disk*, Block*); --- /n/sources/plan9/sys/src/cmd/fossil/fs.h Mon Nov 14 16:09:31 2016 +++ /sys/src/cmd/fossil/fs.h Tue Jun 16 10:39:51 2026 @@ -60,6 +60,7 @@ char *fileName(File *f); File *fileOpen(Fs*, char*); int fileRead(File*, void *, int, vlong); +void fileReadAhead(File*, vlong, int, u32int*, u32int*); int fileRemove(File*, char*); int fileSetDir(File*, DirEntry*, char*); int fileSetQidSpace(File*, u64int, u64int);