ref: 664d2643077f8a6fe4218d71baa79fac30bb7fde
parent: 879f1b0d5c88e46e62aea5e965e8d198c28ddbd3
author: kvik <kvik@a-b.xyz>
date: Thu May 16 14:43:47 EDT 2019
implement hash table based directory reads makes listing huge directories remotely feasible; it is still very slow, but much, much faster than before.
--- a/unionfs.c
+++ b/unionfs.c
@@ -6,7 +6,7 @@
typedef struct Union Union;
typedef struct Fil Fil;
-typedef struct List List;
+typedef struct Ftab Ftab;
typedef struct Fstate Fstate;
typedef struct Qidmap Qidmap;
@@ -19,6 +19,8 @@
enum {
Nqidbits = 5,
Nqidmap = 1 << Nqidbits,
+ Nftab = 32,
+ Nftlist = 32,
};
struct Qidmap {
@@ -38,7 +40,7 @@
char *fspath; /* internal path */
};
-struct List {
+struct Ftab {
long n, sz;
Fil **l;
};
@@ -46,7 +48,7 @@
struct Fstate {
int fd;
Fil *file;
- List *flist;
+ Ftab *ftab;
};
Union u0 = {.next = &u0, .prev = &u0};
@@ -242,52 +244,90 @@
free(f);
}
-List*
-lnew(void)
+uint
+fthash(char *s)
{
- List *l;
-
- l = emalloc(sizeof *l);
- l->n = 0;
- l->sz = 256;
- l->l = emalloc(l->sz*sizeof(*l->l));
-
- return l;
+ uint h;
+ for(h = 0; *s; s++)
+ h = *s + 31*h;
+ return h % Nftab;
}
-void
-lfree(List *l)
+Ftab*
+ftnew(void)
{
int i;
+ Ftab *ft, *p;
- for(i = 0; i < l->n; i++)
- filefree(l->l[i]);
- free(l);
+ ft = emalloc(Nftab*sizeof(Ftab));
+ for(i = 0; i < Nftab; i++){
+ p = &ft[i];
+ p->sz = Nftlist;
+ p->l = emalloc(p->sz*sizeof(*p->l));
+ }
+ return ft;
}
-int
-ladd(List *l, Fil *f)
+void
+ftfree(Ftab *ft)
{
- if(l->n == l->sz){
- l->sz *= 2;
- l->l = erealloc(l->l, l->sz*sizeof(*l->l));
+ int i, j;
+ Ftab *p;
+
+ for(i = 0; i < Nftab; i++){
+ p = &ft[i];
+ for(j = 0; j < p->n; j++)
+ filefree(p->l[j]);
+ free(p->l);
}
- l->l[l->n++] = f;
+ free(ft);
+}
- return l->n;
+void
+ftadd(Ftab *ft, Fil *f)
+{
+ Ftab *p;
+
+ p = &ft[fthash(f->name)];
+ if(p->n == p->sz){
+ p->sz *= 2;
+ p->l = erealloc(p->l, p->sz*sizeof(*p->l));
+ }
+ p->l[p->n++] = f;
}
int
-lhas(List *l, char *name)
+fthas(Ftab *ft, char *name)
{
int i;
+ Ftab *p;
- for(i = 0; i < l->n; i++)
- if(strcmp(l->l[i]->name, name) == 0)
+ p = &ft[fthash(name)];
+ for(i = 0; i < p->n; i++)
+ if(strcmp(p->l[i]->name, name) == 0)
return 1;
return 0;
}
+Fil*
+ftidx(Ftab *ft, long i)
+{
+ long y;
+ Ftab *p;
+
+ for(y = 0; y < Nftab; y++){
+ p = &ft[y];
+ if(p->n == 0)
+ continue;
+ if(i >= p->n){
+ i -= p->n;
+ continue;
+ }
+ return p->l[i];
+ }
+ return nil;
+}
+
Fstate*
fstatenew(Fil *f)
{
@@ -304,8 +344,8 @@
{
if(st->file)
filefree(st->file);
- if(st->flist)
- lfree(st->flist);
+ if(st->ftab)
+ ftfree(st->ftab);
close(st->fd);
free(st);
}
@@ -420,7 +460,7 @@
walkandclone(r, walk1, clone, nil);
}
-List*
+Ftab*
filereaddir(Fil *p)
{
int fd;
@@ -429,9 +469,9 @@
char *path;
Union *u;
Fil *f;
- List *list;
+ Ftab *ft;
- list = lnew();
+ ft = ftnew();
for(u = unionlist->next; u != unionlist; u = u->next){
path = mkpath(u->root, p->fspath, nil);
if((d = dirstat(path)) == nil){
@@ -448,14 +488,15 @@
if(n < 0)
continue;
for(i = 0; i < n; i++){
- if(lhas(list, dir[i].name))
+ if(fthas(ft, dir[i].name))
continue;
f = filenew(&dir[i]);
- ladd(list, f);
+ ftadd(ft, f);
}
free(dir);
}
- return list;
+// ftprint(ft);
+ return ft;
}
void
@@ -471,7 +512,7 @@
f = st->file;
if(f->mode&DMDIR)
- st->flist = filereaddir(f);
+ st->ftab = filereaddir(f);
else{
if((st->fd = open(f->path, i->mode)) < 0){
responderror(r);
@@ -592,13 +633,13 @@
dirgen(int i, Dir *dir, void *aux)
{
Fstate *fs;
- List *l;
+ Fil *f;
fs = aux;
- l = fs->flist;
- if(i == l->n)
+ f = ftidx(fs->ftab, i);
+ if(f == nil)
return -1;
- dirfill(dir, l->l[i]);
+ dirfill(dir, f);
return 0;
}