schfs: cache the last inode and the last extent
Every read descended the B-tree twice per block -- once for the inode and once for the extent -- so an 834 KB file cost 418 descents, each a tree walk plus a 4 KB copy out of the buffer cache per node visited. A sequential read asks for the same inode every time and usually stays inside one extent, so both answers were already known and thrown away. One entry each, not a table: the pattern being optimised is a single file read straight through, and one entry catches all of it without needing an eviction policy. A second reader simply misses. Correctness rests entirely on invalidation, so it is blunt: all five write entry points in objw.c call schfs_cache_invalidate() before touching anything. A cache that is merely usually right would hand back another file's data. The volume pointer is part of the key because the host tools can hold two images open at once. Measured in the guest, bracketed inside one command line, TCG: read 834 KB 1.73s -> 0.31s (5.6x, together with the BOUNCE fix) ls /bin cold 2.80s -> 1.40s (2x) ls /bin warm 0.70s -> 0.70s (unchanged) Warm ls is untouched on purpose-by-consequence: it is 241 separate inodes, so a one-entry cache never hits. That cost is the per-entry lookup path -- dirlookup plus iload, each its own descent -- and it is where the next order of magnitude is, not here. schfs-check passes, including the round-trip; bootcheck 108 [ok]. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
08e7878d8c
commit
ddf1e41177
3 changed files with 80 additions and 3 deletions
|
|
@ -45,6 +45,7 @@ schfs_alloc_objectid(struct schfs_vol *v)
|
|||
int
|
||||
schfs_inode_put(struct schfs_vol *v, uint64_t ino, const struct schfs_inode *in)
|
||||
{
|
||||
schfs_cache_invalidate(); /* any write can stale the read caches in obj.c */
|
||||
struct schfs_key k;
|
||||
schfs_mkkey(&k, ino, SCHFS_KEY_INODE, 0);
|
||||
return schfs_btree_insert(&v->tree, &v->ctx, &k, in, sizeof(*in));
|
||||
|
|
@ -110,6 +111,7 @@ int
|
|||
schfs_dir_add(struct schfs_vol *v, uint64_t dir, const char *name,
|
||||
unsigned namelen, uint64_t child, uint16_t type)
|
||||
{
|
||||
schfs_cache_invalidate(); /* any write can stale the read caches in obj.c */
|
||||
if (namelen == 0 || namelen > SCHFS_NAME_MAX)
|
||||
return -1;
|
||||
|
||||
|
|
@ -145,6 +147,7 @@ int
|
|||
schfs_dir_del(struct schfs_vol *v, uint64_t dir, const char *name,
|
||||
unsigned namelen)
|
||||
{
|
||||
schfs_cache_invalidate(); /* any write can stale the read caches in obj.c */
|
||||
if (namelen == 0 || namelen > SCHFS_NAME_MAX)
|
||||
return -1;
|
||||
|
||||
|
|
@ -559,6 +562,7 @@ long
|
|||
schfs_file_write(struct schfs_vol *v, uint64_t ino, uint64_t off,
|
||||
const void *buf, unsigned n, void *dblk)
|
||||
{
|
||||
schfs_cache_invalidate(); /* any write can stale the read caches in obj.c */
|
||||
struct schfs_inode in;
|
||||
int r = inode_load(v, ino, &in);
|
||||
if (r != 0)
|
||||
|
|
@ -635,6 +639,7 @@ int
|
|||
schfs_file_truncate(struct schfs_vol *v, uint64_t ino, uint64_t size,
|
||||
void *dblk)
|
||||
{
|
||||
schfs_cache_invalidate(); /* any write can stale the read caches in obj.c */
|
||||
struct schfs_inode in;
|
||||
int r = inode_load(v, ino, &in);
|
||||
if (r != 0)
|
||||
|
|
|
|||
Loading…
Reference in a new issue