From d1aafff0fe133eb49770b78205bd183fe40c12bc Mon Sep 17 00:00:00 2001 From: Michal Vaner Date: Thu, 17 Jul 2008 11:23:16 +0200 Subject: [PATCH] Move pagecache from libucw to libsherlock --- ucw/Makefile | 4 +- ucw/pagecache.c | 429 ------------------------------------------------ ucw/pagecache.h | 42 ----- 3 files changed, 2 insertions(+), 473 deletions(-) delete mode 100644 ucw/pagecache.c delete mode 100644 ucw/pagecache.h diff --git a/ucw/Makefile b/ucw/Makefile index 39d69957..b803e7d4 100644 --- a/ucw/Makefile +++ b/ucw/Makefile @@ -8,7 +8,7 @@ PROGS+=$(o)/ucw/basecode LIBUCW_MODS= \ threads \ alloc alloc_str realloc bigalloc mempool mempool-str mempool-fmt eltpool \ - mmap pagecache partmap hashfunc \ + mmap partmap hashfunc \ lists slists simple-lists bitsig \ log log-file proctitle \ conf-alloc conf-dump conf-input conf-intr conf-journal conf-parse conf-section \ @@ -33,7 +33,7 @@ LIBUCW_MODS= \ LIBUCW_INCLUDES= \ lib.h config.h threads.h \ - mempool.h pagecache.h \ + mempool.h \ arraysort.h \ lists.h clists.h slists.h simple-lists.h \ string.h stkstring.h unicode.h chartype.h regex.h \ diff --git a/ucw/pagecache.c b/ucw/pagecache.c deleted file mode 100644 index 4f135a46..00000000 --- a/ucw/pagecache.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * UCW Library -- File Page Cache - * - * (c) 1999--2002 Martin Mares - * - * This software may be freely distributed and used according to the terms - * of the GNU Lesser General Public License. - */ - -#include "ucw/lib.h" -#include "ucw/pagecache.h" -#include "ucw/lfs.h" - -#include -#include -#include -#include -#include -#include - -struct page_cache { - 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 */ -#ifndef HAVE_PREAD - sh_off_t pos; /* Current position in the file */ - int pos_fd; /* FD the position corresponds to */ -#endif -}; - -#define PAGE_NUMBER(pos) ((pos) & ~(sh_off_t)(c->page_size - 1)) -#define PAGE_OFFSET(pos) ((pos) & (c->page_size - 1)) - -struct page_cache * -pgc_open(uns page_size, uns max_pages) -{ - struct page_cache *c = xmalloc_zero(sizeof(struct page_cache)); - uns i; - - init_list(&c->free_pages); - init_list(&c->locked_pages); - init_list(&c->dirty_pages); - c->page_size = page_size; - c->max_pages = max_pages; - c->hash_size = nextprime(c->max_pages); - c->hash_table = xmalloc(sizeof(list) * c->hash_size); - for(i=0; ihash_size; i++) - init_list(&c->hash_table[i]); -#ifndef HAVE_PREAD - c->pos_fd = -1; -#endif - return c; -} - -void -pgc_close(struct page_cache *c) -{ - pgc_cleanup(c); - ASSERT(EMPTY_LIST(c->locked_pages)); - ASSERT(EMPTY_LIST(c->dirty_pages)); - ASSERT(EMPTY_LIST(c->free_pages)); - xfree(c->hash_table); - xfree(c); -} - -static void -pgc_debug_page(struct page *p) -{ - printf("\tp=%08x d=%d f=%x c=%d\n", (uns) p->pos, p->fd, p->flags, p->lock_count); -} - -void -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); - 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 s; - - ASSERT(p->flags & PG_FLAG_DIRTY); -#ifdef HAVE_PREAD - s = sh_pwrite(p->fd, p->data, c->page_size, p->pos); -#else - if (c->pos != p->pos || c->pos_fd != (int) p->fd) - sh_seek(p->fd, p->pos, SEEK_SET); - s = write(p->fd, p->data, c->page_size); - c->pos = p->pos + s; - c->pos_fd = p->fd; -#endif - if (s < 0) - die("pgc_write(%d): %m", p->fd); - if (s != (int) c->page_size) - die("pgc_write(%d): incomplete page (only %d of %d)", p->fd, s, c->page_size); - p->flags &= ~PG_FLAG_DIRTY; - c->stat_write++; -} - -static int -flush_cmp(const void *X, const void *Y) -{ - struct page *x = *((struct page **)X); - struct page *y = *((struct page **)Y); - - if (x->fd < y->fd) - return -1; - if (x->fd > y->fd) - return 1; - if (x->pos < y->pos) - return -1; - if (x->pos > y->pos) - return 1; - return 0; -} - -static void -flush_pages(struct page_cache *c, uns force) -{ - uns cnt = 0; - uns max = force ? ~0U : c->free_count / 2; - uns i; - struct page *p, *q, **req, **rr; - - WALK_LIST(p, c->dirty_pages) - { - cnt++; - if (cnt >= max) - break; - } - req = rr = alloca(cnt * sizeof(struct page *)); - i = cnt; - p = HEAD(c->dirty_pages); - while ((q = (struct page *) p->n.next) && i--) - { - rem_node(&p->n); - add_tail(&c->free_pages, &p->n); - *rr++ = p; - p = q; - } - qsort(req, cnt, sizeof(struct page *), flush_cmp); - for(i=0; ihash_size; -} - -static struct page * -get_page(struct page_cache *c, sh_off_t pos, uns fd) -{ - node *n; - struct page *p; - uns hash = hash_page(c, pos, fd); - - /* - * Return locked buffer for given page. - */ - - WALK_LIST(n, c->hash_table[hash]) - { - p = SKIP_BACK(struct page, hn, n); - if (p->pos == pos && p->fd == fd) - { - /* Found in the cache */ - rem_node(&p->n); - if (!p->lock_count) - c->free_count--; - return p; - } - } - if (c->total_count < c->max_pages || !c->free_count) - { - /* Enough free space, expand the cache */ - p = xmalloc(sizeof(struct page) + c->page_size); - c->total_count++; - } - else - { - /* Discard the oldest unlocked page */ - p = HEAD(c->free_pages); - if (!p->n.next) - { - /* There are only dirty pages here */ - flush_pages(c, 0); - p = HEAD(c->free_pages); - ASSERT(p->n.next); - } - ASSERT(!p->lock_count); - rem_node(&p->n); - rem_node(&p->hn); - c->free_count--; - } - p->pos = pos; - p->fd = fd; - p->flags = 0; - p->lock_count = 0; - add_tail(&c->hash_table[hash], &p->hn); - return p; -} - -void -pgc_flush(struct page_cache *c) -{ - struct page *p; - - flush_pages(c, 1); - WALK_LIST(p, c->locked_pages) - if (p->flags & PG_FLAG_DIRTY) - flush_page(c, p); - else - break; -} - -void -pgc_cleanup(struct page_cache *c) -{ - struct page *p; - node *n; - - pgc_flush(c); - WALK_LIST_DELSAFE(p, n, c->free_pages) - { - ASSERT(!(p->flags & PG_FLAG_DIRTY) && !p->lock_count); - rem_node(&p->n); - rem_node(&p->hn); - c->free_count--; - c->total_count--; - xfree(p); - } - ASSERT(!c->free_count); -} - -static inline struct page * -get_and_lock_page(struct page_cache *c, sh_off_t pos, uns fd) -{ - struct page *p = get_page(c, pos, fd); - - add_tail(&c->locked_pages, &p->n); - p->lock_count++; - return p; -} - -struct page * -pgc_read(struct page_cache *c, int fd, sh_off_t pos) -{ - struct page *p; - int s; - - ASSERT(!PAGE_OFFSET(pos)); - p = get_and_lock_page(c, pos, fd); - if (p->flags & PG_FLAG_VALID) - c->stat_hit++; - else - { - c->stat_miss++; -#ifdef HAVE_PREAD - s = sh_pread(fd, p->data, c->page_size, pos); -#else - if (c->pos != pos || c->pos_fd != (int)fd) - sh_seek(fd, pos, SEEK_SET); - s = read(fd, p->data, c->page_size); - c->pos = pos + s; - c->pos_fd = fd; -#endif - if (s < 0) - die("pgc_read(%d): %m", fd); - if (s != (int) c->page_size) - die("pgc_read(%d): incomplete page (only %d of %d)", p->fd, s, c->page_size); - p->flags |= PG_FLAG_VALID; - } - return p; -} - -struct page * -pgc_get(struct page_cache *c, int fd, sh_off_t pos) -{ - struct page *p; - - ASSERT(!PAGE_OFFSET(pos)); - p = get_and_lock_page(c, pos, fd); - p->flags |= PG_FLAG_VALID | PG_FLAG_DIRTY; - return p; -} - -struct page * -pgc_get_zero(struct page_cache *c, int fd, sh_off_t pos) -{ - struct page *p; - - ASSERT(!PAGE_OFFSET(pos)); - p = get_and_lock_page(c, pos, fd); - bzero(p->data, c->page_size); - p->flags |= PG_FLAG_VALID | PG_FLAG_DIRTY; - return p; -} - -void -pgc_put(struct page_cache *c, struct page *p) -{ - ASSERT(p->lock_count); - if (--p->lock_count) - return; - rem_node(&p->n); - if (p->flags & PG_FLAG_DIRTY) - { - add_tail(&c->dirty_pages, &p->n); - c->free_count++; - } - else if (c->free_count < c->max_pages) - { - add_tail(&c->free_pages, &p->n); - c->free_count++; - } - else - { - rem_node(&p->hn); - xfree(p); - c->total_count--; - } -} - -void -pgc_mark_dirty(struct page_cache *c, struct page *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 = PAGE_NUMBER(pos); - uns offset = PAGE_OFFSET(pos); - - p = pgc_read(c, fd, page); - pgc_put(c, p); - *len = c->page_size - offset; - return p->data + offset; -} - -#ifdef TEST - -int main(int argc, char **argv) -{ - struct page_cache *c = pgc_open(1024, 2); - struct page *p, *q, *r; - int fd = open("test", O_RDWR | O_CREAT | O_TRUNC, 0666); - if (fd < 0) - die("open: %m"); - pgc_debug(c, 1); - p = pgc_get(c, fd, 0); - pgc_debug(c, 1); - strcpy(p->data, "one"); - pgc_put(c, p); - pgc_debug(c, 1); - p = pgc_get(c, fd, 1024); - pgc_debug(c, 1); - strcpy(p->data, "two"); - pgc_put(c, p); - pgc_debug(c, 1); - p = pgc_get(c, fd, 2048); - pgc_debug(c, 1); - strcpy(p->data, "three"); - pgc_put(c, p); - pgc_debug(c, 1); - pgc_flush(c); - pgc_debug(c, 1); - p = pgc_read(c, fd, 0); - 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, 1); - r = pgc_read(c, fd, 2048); - pgc_debug(c, 1); - pgc_put(c, p); - pgc_put(c, q); - pgc_put(c, r); - pgc_debug(c, 1); - p = pgc_get(c, fd, 3072); - pgc_debug(c, 1); - strcpy(p->data, "four"); - pgc_put(c, p); - pgc_debug(c, 1); - pgc_cleanup(c); - pgc_debug(c, 1); - pgc_close(c); - return 0; -} - -#endif diff --git a/ucw/pagecache.h b/ucw/pagecache.h deleted file mode 100644 index 36251a5c..00000000 --- a/ucw/pagecache.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * UCW Library -- File Page Cache - * - * (c) 1999--2002 Martin Mares - * - * This software may be freely distributed and used according to the terms - * of the GNU Lesser General Public License. - */ - -#ifndef _UCW_PAGECACHE_H -#define _UCW_PAGECACHE_H - -#include "ucw/lists.h" - -struct page_cache; - -struct page { - node n; /* Node in page list */ - node hn; /* Node in hash table */ - sh_off_t pos; - uns fd; - uns flags; - uns lock_count; - byte data[0]; -}; - -#define PG_FLAG_DIRTY 1 -#define PG_FLAG_VALID 2 - -struct page_cache *pgc_open(uns page_size, uns max_pages); -void pgc_close(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 */ -struct page *pgc_get_zero(struct page_cache *, int fd, sh_off_t); /* ... and clear it */ -void pgc_put(struct page_cache *, struct page *); /* Release page */ -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 -- 2.39.2