Generalize ef_extend() to non-file-backed tables
ef_extend() extended the file bypassing the cache, which screws up the cache if it's EFF_MEM. It fixed that by closing and reopening the table. Cheesy, and worked only for file-backed tables. Rewrite ef_extend() to remap the cache properly for EFF_MEM. While there, simplify the !EFF_MEM case: steal a cache slot instead of allocating a buffer. Factor cache mapping out of ef_open() and ef_extend() into new ef_remap_cache().
This commit is contained in:
parent
642c11eb64
commit
d4ac7d94b2
1 changed files with 76 additions and 35 deletions
|
@ -46,8 +46,10 @@
|
||||||
#include "nsc.h"
|
#include "nsc.h"
|
||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
|
|
||||||
|
static int ef_remap_cache(struct empfile *, int);
|
||||||
static int fillcache(struct empfile *, int);
|
static int fillcache(struct empfile *, int);
|
||||||
static int do_write(struct empfile *, void *, int, int);
|
static int do_write(struct empfile *, void *, int, int);
|
||||||
|
static void ef_blank(struct empfile *, void *, int, int);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open the file-backed table TYPE (EF_SECTOR, ...).
|
* Open the file-backed table TYPE (EF_SECTOR, ...).
|
||||||
|
@ -61,7 +63,7 @@ ef_open(int type, int how)
|
||||||
{
|
{
|
||||||
struct empfile *ep;
|
struct empfile *ep;
|
||||||
struct flock lock;
|
struct flock lock;
|
||||||
int oflags, fd, fsiz, size;
|
int oflags, fd, fsiz, nslots;
|
||||||
|
|
||||||
if (ef_check(type) < 0)
|
if (ef_check(type) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -116,18 +118,13 @@ ef_open(int type, int how)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (how & EFF_MEM)
|
|
||||||
ep->csize = ep->fids;
|
|
||||||
else
|
|
||||||
ep->csize = blksize(fd) / ep->size;
|
|
||||||
/* 0 could lead to null cache, which confuses assertions */
|
|
||||||
if (!ep->csize)
|
|
||||||
ep->csize++;
|
|
||||||
size = ep->csize * ep->size;
|
|
||||||
if (CANT_HAPPEN(ep->cache))
|
if (CANT_HAPPEN(ep->cache))
|
||||||
free(ep->cache);
|
free(ep->cache);
|
||||||
ep->cache = malloc(size);
|
if (how & EFF_MEM)
|
||||||
if (ep->cache == NULL) {
|
nslots = ep->fids;
|
||||||
|
else
|
||||||
|
nslots = blksize(fd) / ep->size;
|
||||||
|
if (!ef_remap_cache(ep, nslots)) {
|
||||||
logerror("Can't open %s: out of memory", ep->file);
|
logerror("Can't open %s: out of memory", ep->file);
|
||||||
close(fd);
|
close(fd);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -151,6 +148,31 @@ ef_open(int type, int how)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ef_remap_cache(struct empfile *ep, int nslots)
|
||||||
|
{
|
||||||
|
void *cache;
|
||||||
|
|
||||||
|
if (CANT_HAPPEN(ep->flags & EFF_STATIC))
|
||||||
|
return 0;
|
||||||
|
if (CANT_HAPPEN(nslots < 0))
|
||||||
|
nslots = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Avoid zero slots, because that can lead to null cache, which
|
||||||
|
* would be interpreted as unmapped cache.
|
||||||
|
*/
|
||||||
|
if (nslots == 0)
|
||||||
|
nslots++;
|
||||||
|
cache = realloc(ep->cache, nslots * ep->size);
|
||||||
|
if (!cache)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ep->cache = cache;
|
||||||
|
ep->csize = nslots;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close the file-backed table TYPE (EF_SECTOR, ...).
|
* Close the file-backed table TYPE (EF_SECTOR, ...).
|
||||||
* Return non-zero on success, zero on failure.
|
* Return non-zero on success, zero on failure.
|
||||||
|
@ -384,47 +406,66 @@ ef_write(int type, int id, void *from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extend the file-backed table TYPE by COUNT elements.
|
* Extend table TYPE by COUNT elements.
|
||||||
* Can't extend privately mapped tables.
|
* Any pointers obtained from ef_ptr() become invalid.
|
||||||
* Return non-zero on success, zero on failure.
|
* Return non-zero on success, zero on failure.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ef_extend(int type, int count)
|
ef_extend(int type, int count)
|
||||||
{
|
{
|
||||||
struct empfile *ep;
|
struct empfile *ep;
|
||||||
void *tmpobj;
|
char *p;
|
||||||
int id, i, how;
|
int i, id;
|
||||||
|
|
||||||
if (ef_check(type) < 0)
|
if (ef_check(type) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
ep = &empfile[type];
|
ep = &empfile[type];
|
||||||
if (CANT_HAPPEN(ep->fd < 0 || count < 0))
|
if (CANT_HAPPEN(count < 0))
|
||||||
return 0;
|
return 0;
|
||||||
if (CANT_HAPPEN(ep->flags & EFF_PRIVATE))
|
|
||||||
return 0; /* not implemented */
|
|
||||||
|
|
||||||
tmpobj = calloc(1, ep->size);
|
|
||||||
id = ep->fids;
|
id = ep->fids;
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
if (ep->init)
|
|
||||||
ep->init(id + i, tmpobj);
|
|
||||||
if (do_write(ep, tmpobj, id + i, 1) < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
free(tmpobj);
|
|
||||||
|
|
||||||
if (ep->flags & EFF_MEM) {
|
if (ep->flags & EFF_MEM) {
|
||||||
/* FIXME lazy bastards... do this right */
|
if (id + count > ep->csize) {
|
||||||
/* XXX this will cause problems if there are ef_ptrs (to the
|
if (ep->flags & EFF_STATIC)
|
||||||
* old allocated structure) active when we do the re-open */
|
return 0;
|
||||||
how = ep->flags & ~EFF_IMMUTABLE;
|
if (!ef_remap_cache(ep, id + count))
|
||||||
ef_close(type);
|
return 0;
|
||||||
ef_open(type, how);
|
}
|
||||||
|
p = ep->cache + id * ep->size;
|
||||||
|
ef_blank(ep, p, id, count);
|
||||||
|
if (!(ep->flags & EFF_PRIVATE)) {
|
||||||
|
if (do_write(ep, p, id, count) < 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ep->cids += count;
|
||||||
} else {
|
} else {
|
||||||
ep->fids += i;
|
/* need a buffer, steal last cache slot */
|
||||||
|
if (ep->cids == ep->csize)
|
||||||
|
ep->cids--;
|
||||||
|
p = ep->cache + ep->cids * ep->size;
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
ef_blank(ep, p, id + i, 1);
|
||||||
|
if (do_write(ep, p, id + i, 1) < 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ep->fids += count;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return i == count;
|
/*
|
||||||
|
* Initialize COUNT elements of EP in BUF, starting with element ID.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ef_blank(struct empfile *ep, void *buf, int id, int count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(buf, 0, count * ep->size);
|
||||||
|
if (ep->init) {
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
ep->init(id + i, (char *)buf + i * ep->size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct castr *
|
struct castr *
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue