]> mj.ucw.cz Git - libucw.git/commitdiff
Allow locked dirty pages. Better debugging. Simplified and cleaned up
authorMartin Mares <mj@ucw.cz>
Tue, 9 Nov 1999 23:24:10 +0000 (23:24 +0000)
committerMartin Mares <mj@ucw.cz>
Tue, 9 Nov 1999 23:24:10 +0000 (23:24 +0000)
handling of offset masking. Fixed 64-bit cast problems.

lib/pagecache.c
lib/pagecache.h

index 2d8c1dbb379f787ef35471cbcb9d09b157e128f4..f9d1df2c7863ae19c6a83cf240507090ddb69f69 100644 (file)
 #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;
 }
index 67450e796e850b4bcf27f1b19136597c81e92516..5c2661a0e04a6aedd31356d5cdd1187ffb90856c 100644 (file)
@@ -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