summaryrefslogtreecommitdiffstats
path: root/src/cmd/smugfs/cache.c
diff options
context:
space:
mode:
authorRuss Cox <rsc@swtch.com>2008-08-03 07:42:27 -0700
committerRuss Cox <rsc@swtch.com>2008-08-03 07:42:27 -0700
commit18824b586835525594cde126fbc90b8281d5af8b (patch)
treee8b69c05eda4543b6d2f3d30777abe6109b48b7f /src/cmd/smugfs/cache.c
parent3d36f4437348227c5bad62587dc12b5fd4a3e95e (diff)
downloadplan9port-18824b586835525594cde126fbc90b8281d5af8b.tar.gz
plan9port-18824b586835525594cde126fbc90b8281d5af8b.zip
smugfs(4): new program
Diffstat (limited to 'src/cmd/smugfs/cache.c')
-rw-r--r--src/cmd/smugfs/cache.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/cmd/smugfs/cache.c b/src/cmd/smugfs/cache.c
new file mode 100644
index 00000000..2adf8b9b
--- /dev/null
+++ b/src/cmd/smugfs/cache.c
@@ -0,0 +1,149 @@
+#include "a.h"
+
+struct Cache
+{
+ CEntry **hash;
+ int nhash;
+ CEntry *head;
+ CEntry *tail;
+ int nentry;
+ int maxentry;
+ int sizeofentry;
+ void (*cefree)(CEntry*);
+};
+
+static void
+nop(CEntry *ce)
+{
+}
+
+static uint
+hash(const char *s)
+{
+ uint h;
+ uchar *p;
+
+ h = 0;
+ for(p=(uchar*)s; *p; p++)
+ h = h*37 + *p;
+ return h;
+}
+
+Cache*
+newcache(int sizeofentry, int maxentry, void (*cefree)(CEntry*))
+{
+ Cache *c;
+ int i;
+
+ assert(sizeofentry >= sizeof(CEntry));
+ c = emalloc(sizeof *c);
+ c->sizeofentry = sizeofentry;
+ c->maxentry = maxentry;
+ c->nentry = 0;
+ for(i=1; i<maxentry; i<<=1)
+ ;
+ c->nhash = i;
+ c->hash = emalloc(c->nhash * sizeof c->hash[0]);
+ if(cefree == nil)
+ cefree = nop;
+ c->cefree = cefree;
+ return c;
+}
+
+static void
+popout(Cache *c, CEntry *e)
+{
+ if(e->list.prev)
+ e->list.prev->list.next = e->list.next;
+ else
+ c->head = e->list.next;
+ if(e->list.next)
+ e->list.next->list.prev = e->list.prev;
+ else
+ c->tail = e->list.prev;
+}
+
+static void
+insertfront(Cache *c, CEntry *e)
+{
+ e->list.next = c->head;
+ c->head = e;
+ if(e->list.next)
+ e->list.next->list.prev = e;
+ else
+ c->tail = e;
+}
+
+static void
+movetofront(Cache *c, CEntry *e)
+{
+ popout(c, e);
+ insertfront(c, e);
+}
+
+static CEntry*
+evict(Cache *c)
+{
+ CEntry *e;
+
+ e = c->tail;
+ popout(c, e);
+ c->cefree(e);
+ free(e->name);
+ e->name = nil;
+ memset(e, 0, c->sizeofentry);
+ insertfront(c, e);
+ return e;
+}
+
+CEntry*
+cachelookup(Cache *c, char *name, int create)
+{
+ int h;
+ CEntry *e;
+
+ h = hash(name) % c->nhash;
+ for(e=c->hash[h]; e; e=e->hash.next){
+ if(strcmp(name, e->name) == 0){
+ movetofront(c, e);
+ return e;
+ }
+ }
+
+ if(!create)
+ return nil;
+
+ if(c->nentry >= c->maxentry)
+ e = evict(c);
+ else{
+ e = emalloc(c->sizeofentry);
+ insertfront(c, e);
+ c->nentry++;
+ }
+ e->name = estrdup(name);
+ h = hash(name) % c->nhash;
+ e->hash.next = c->hash[h];
+ c->hash[h] = e;
+ return e;
+}
+
+void
+cacheflush(Cache *c, char *substr)
+{
+ CEntry **l, *e;
+ int i;
+
+ for(i=0; i<c->nhash; i++){
+ for(l=&c->hash[i]; (e=*l); ){
+ if(substr == nil || strstr(e->name, substr)){
+ *l = e->hash.next;
+ c->nentry--;
+ popout(c, e);
+ c->cefree(e);
+ free(e->name);
+ free(e);
+ }else
+ l = &e->hash.next;
+ }
+ }
+}