From: Martin Mares Date: Tue, 9 Nov 1999 23:24:10 +0000 (+0000) Subject: Allow locked dirty pages. Better debugging. Simplified and cleaned up X-Git-Tag: holmes-import~1654 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=05d39c073356d120fec08689dfe1c43c78ed5ed4;p=libucw.git Allow locked dirty pages. Better debugging. Simplified and cleaned up handling of offset masking. Fixed 64-bit cast problems. --- diff --git a/lib/pagecache.c b/lib/pagecache.c index 2d8c1dbb..f9d1df2c 100644 --- a/lib/pagecache.c +++ b/lib/pagecache.c @@ -15,18 +15,25 @@ #include "lfs.h" struct page_cache { - list free_pages; /* LRU queue of free pages */ - list locked_pages; /* List of locked pages */ - list dirty_pages; /* List of dirty pages */ + list free_pages; /* LRU queue of free non-dirty pages */ + list locked_pages; /* List of locked pages (starts with dirty ones) */ + list dirty_pages; /* List of free dirty pages */ uns page_size; /* Bytes per page (must be a power of two) */ uns free_count; /* Number of free / dirty pages */ uns total_count; /* Total number of pages */ uns max_pages; /* Maximum number of free pages */ uns hash_size; /* Hash table size */ + uns stat_hit; /* Number of cache hits */ + uns stat_miss; /* Number of cache misses */ + uns stat_write; /* Number of writes */ list *hash_table; /* List heads corresponding to hash buckets */ }; -/* FIXME: Negations -> cast to sh_off_t */ +#define PAGE_NUMBER(pos) ((pos) & ~(sh_off_t)(c->page_size - 1)) +#define PAGE_OFFSET(pos) ((pos) & (c->page_size - 1)) + +#define KEY_PAGE(key) PAGE_NUMBER(key) +#define KEY_FD(key) PAGE_OFFSET(key) struct page_cache * pgc_open(uns page_size, uns max_pages) @@ -65,30 +72,34 @@ pgc_debug_page(struct page *p) } void -pgc_debug(struct page_cache *c) +pgc_debug(struct page_cache *c, int mode) { struct page *p; printf(">> Page cache dump: pgsize=%d, pages=%d, freepages=%d of %d, hash=%d\n", c->page_size, c->total_count, c->free_count, c->max_pages, c->hash_size); - puts("LRU list:"); - WALK_LIST(p, c->free_pages) - pgc_debug_page(p); - puts("Locked list:"); - WALK_LIST(p, c->locked_pages) - pgc_debug_page(p); - puts("Dirty list:"); - WALK_LIST(p, c->dirty_pages) - pgc_debug_page(p); + printf(">> stats: %d hits, %d misses, %d writes\n", c->stat_hit, c->stat_miss, c->stat_write); + if (mode) + { + puts("LRU list:"); + WALK_LIST(p, c->free_pages) + pgc_debug_page(p); + puts("Locked list:"); + WALK_LIST(p, c->locked_pages) + pgc_debug_page(p); + puts("Dirty list:"); + WALK_LIST(p, c->dirty_pages) + pgc_debug_page(p); + } } static void flush_page(struct page_cache *c, struct page *p) { - int fd = p->key & (c->page_size - 1); - sh_off_t pos = p->key & ~(c->page_size - 1); + int fd = KEY_FD(p->key); + sh_off_t pos = KEY_PAGE(p->key); int s; - ASSERT((p->flags & PG_FLAG_DIRTY) && !p->lock_count); + ASSERT(p->flags & PG_FLAG_DIRTY); /* FIXME: Use pwrite() */ sh_seek(fd, pos, SEEK_SET); s = write(fd, p->data, c->page_size); @@ -97,6 +108,7 @@ flush_page(struct page_cache *c, struct page *p) if (s != (int) c->page_size) die("pgc_write(%d): incomplete page (only %d of %d)", s, c->page_size); p->flags &= ~PG_FLAG_DIRTY; + c->stat_write++; } static inline uns @@ -168,6 +180,11 @@ pgc_flush(struct page_cache *c) rem_node(&p->n); add_tail(&c->free_pages, &p->n); } + WALK_LIST(p, c->locked_pages) + if (p->flags & PG_FLAG_DIRTY) + flush_page(c, p); + else + break; } void @@ -205,12 +222,15 @@ pgc_read(struct page_cache *c, int fd, sh_off_t pos) struct page *p; int s; - ASSERT(!(pos & (c->page_size - 1))); - ASSERT(!(fd & ~(c->page_size - 1))); + ASSERT(!PAGE_OFFSET(pos)); + ASSERT(!PAGE_NUMBER(fd)); key = pos | fd; p = get_and_lock_page(c, key); - if (!(p->flags & PG_FLAG_VALID)) + if (p->flags & PG_FLAG_VALID) + c->stat_hit++; + else { + c->stat_miss++; /* FIXME: Use pread() */ sh_seek(fd, pos, SEEK_SET); s = read(fd, p->data, c->page_size); @@ -229,8 +249,8 @@ pgc_get(struct page_cache *c, int fd, sh_off_t pos) sh_off_t key; struct page *p; - ASSERT(!(pos & (c->page_size - 1))); - ASSERT(!(fd & ~(c->page_size - 1))); + ASSERT(!PAGE_OFFSET(pos)); + ASSERT(!PAGE_NUMBER(fd)); key = pos | fd; p = get_and_lock_page(c, key); p->flags |= PG_FLAG_VALID | PG_FLAG_DIRTY; @@ -262,18 +282,23 @@ pgc_put(struct page_cache *c, struct page *p) } void -pgc_put_dirty(struct page_cache *c, struct page *p) +pgc_mark_dirty(struct page_cache *c, struct page *p) { - p->flags |= PG_FLAG_DIRTY; - pgc_put(c, p); + ASSERT(p->lock_count); + if (!(p->flags & PG_FLAG_DIRTY)) + { + p->flags |= PG_FLAG_DIRTY; + rem_node(&p->n); + add_head(&c->locked_pages, &p->n); + } } byte * pgc_read_data(struct page_cache *c, int fd, sh_off_t pos, uns *len) { struct page *p; - sh_off_t page = pos & ~(c->page_size - 1); - uns offset = pos & (c->page_size - 1); + sh_off_t page = PAGE_NUMBER(pos); + uns offset = PAGE_OFFSET(pos); p = pgc_read(c, fd, page); pgc_put(c, p); @@ -290,40 +315,45 @@ int main(int argc, char **argv) int fd = open("test", O_RDWR | O_CREAT | O_TRUNC, 0666); if (fd < 0) die("open: %m"); - pgc_debug(c); + pgc_debug(c, 1); p = pgc_get(c, fd, 0); - pgc_debug(c); + pgc_debug(c, 1); strcpy(p->data, "one"); - pgc_put_dirty(c, p); - pgc_debug(c); + pgc_put(c, p); + pgc_debug(c, 1); p = pgc_get(c, fd, 1024); - pgc_debug(c); + pgc_debug(c, 1); strcpy(p->data, "two"); - pgc_put_dirty(c, p); - pgc_debug(c); + pgc_put(c, p); + pgc_debug(c, 1); p = pgc_get(c, fd, 2048); - pgc_debug(c); + pgc_debug(c, 1); strcpy(p->data, "three"); - pgc_put_dirty(c, p); - pgc_debug(c); + pgc_put(c, p); + pgc_debug(c, 1); pgc_flush(c); - pgc_debug(c); + pgc_debug(c, 1); p = pgc_read(c, fd, 0); - pgc_debug(c); + pgc_debug(c, 1); + strcpy(p->data, "odin"); + pgc_mark_dirty(c, p); + pgc_debug(c, 1); + pgc_flush(c); + pgc_debug(c, 1); q = pgc_read(c, fd, 1024); - pgc_debug(c); + pgc_debug(c, 1); r = pgc_read(c, fd, 2048); - pgc_debug(c); + pgc_debug(c, 1); pgc_put(c, p); pgc_put(c, q); pgc_put(c, r); - pgc_debug(c); + pgc_debug(c, 1); p = pgc_get(c, fd, 3072); - pgc_debug(c); + pgc_debug(c, 1); pgc_put(c, p); - pgc_debug(c); + pgc_debug(c, 1); pgc_cleanup(c); - pgc_debug(c); + pgc_debug(c, 1); pgc_close(c); return 0; } diff --git a/lib/pagecache.h b/lib/pagecache.h index 67450e79..5c2661a0 100644 --- a/lib/pagecache.h +++ b/lib/pagecache.h @@ -25,13 +25,13 @@ struct page { struct page_cache *pgc_open(uns page_size, uns max_pages); void pgc_close(struct page_cache *); -void pgc_debug(struct page_cache *); +void pgc_debug(struct page_cache *, int mode); void pgc_flush(struct page_cache *); /* Write all unwritten pages */ void pgc_cleanup(struct page_cache *); /* Deallocate all unused buffers */ struct page *pgc_read(struct page_cache *, int fd, sh_off_t); /* Read page and lock it */ struct page *pgc_get(struct page_cache *, int fd, sh_off_t); /* Get page for writing */ void pgc_put(struct page_cache *, struct page *); /* Release page */ -void pgc_put_dirty(struct page_cache *, struct page *); /* Mark page as dirty and release it */ +void pgc_mark_dirty(struct page_cache *, struct page *); /* Mark locked page as dirty */ byte *pgc_read_data(struct page_cache *, int fd, sh_off_t, uns *); /* Partial reading */ #endif