#undef LOCAL_DEBUG
#include "lib/lib.h"
+#include "lib/bitops.h"
#include "lib/fastbuf.h"
+#include "lib/ff-binary.h"
#include "lib/qache.h"
-#include <stdlib.h>
+#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
+#include <sys/stat.h>
#include <sys/mman.h>
-#include <sys/user.h>
/*
* The cache lives in a mmapped file of the following format:
int fd;
byte *mmap_data;
uns file_size;
- byte *file_name;
+ char *file_name;
uns locked;
};
#define first_free_block entry_table[0].first_data_block
#define num_free_blocks entry_table[0].data_len
-static inline byte *
+static inline char *
format_key(qache_key_t *key)
{
- static byte keybuf[2*sizeof(qache_key_t)+1];
+ static char keybuf[2*sizeof(qache_key_t)+1];
for (uns i=0; i<sizeof(qache_key_t); i++)
sprintf(keybuf+2*i, "%02x", (*key)[i]);
return keybuf;
{
#ifndef CONFIG_LINUX
/* We don't need msyncing on Linux, since the mappings are guaranteed to be coherent */
- len += (start % PAGE_SIZE);
- start -= start % PAGE_SIZE;
- len = ALIGN(len, PAGE_SIZE);
+ len += (start % CPU_PAGE_SIZE);
+ start -= start % CPU_PAGE_SIZE;
+ len = ALIGN_TO(len, CPU_PAGE_SIZE);
if (msync(q->mmap_data + start, len, MS_ASYNC | MS_INVALIDATE) < 0)
- log(L_ERROR, "Cache %s: msync failed: %m", q->file_name);
+ msg(L_ERROR, "Cache %s: msync failed: %m", q->file_name);
#endif
}
ET_HASH = 4
};
-static byte *
+static char *
audit_entries(struct qache *q, byte *entrymap)
{
uns i, j;
BT_ALLOC = 2
};
-static byte *
+static char *
audit_blocks(struct qache *q, byte *entrymap, byte *blockmap)
{
uns i, j;
return NULL;
}
-static byte *
+static char *
do_audit(struct qache *q)
{
byte *entry_map = xmalloc_zero(q->hdr->max_entries);
return 0;
struct stat st;
- byte *err = "stat failed";
+ char *err = "stat failed";
if (fstat(q->fd, &st) < 0)
goto close_and_fail;
goto unlock_and_fail;
qache_unlock(q, 0);
- log(L_INFO, "Cache %s: using existing data", q->file_name);
+ msg(L_INFO, "Cache %s: using existing data", q->file_name);
return 1;
unlock_and_fail:
qache_unlock(q, 0);
munmap(q->mmap_data, q->file_size);
close_and_fail:
- log(L_INFO, "Cache %s: ignoring old contents (%s)", q->file_name, err);
+ msg(L_INFO, "Cache %s: ignoring old contents (%s)", q->file_name, err);
close(q->fd);
return 0;
}
bzero(&h, sizeof(h));
h.magic = QACHE_MAGIC;
h.block_size = par->block_size;
- h.block_shift = fls(h.block_size);
+ h.block_shift = bit_fls(h.block_size);
h.num_blocks = par->cache_size >> h.block_shift;
h.format_id = par->format_id;
h.entry_table_start = sizeof(h);
bwrite(fb, &h, sizeof(h));
/* Entry #0: heads of all lists */
- ASSERT(btell(fb) == h.entry_table_start);
+ ASSERT(btell(fb) == (sh_off_t)h.entry_table_start);
struct qache_entry ent;
bzero(&ent, sizeof(ent));
ent.first_data_block = h.first_data_block;
}
/* The hash table */
- ASSERT(btell(fb) == h.hash_table_start);
+ ASSERT(btell(fb) == (sh_off_t)h.hash_table_start);
for (uns i=0; i<h.hash_size; i++)
bputl(fb, 0);
/* The next pointers */
- ASSERT(btell(fb) == h.next_table_start);
+ ASSERT(btell(fb) == (sh_off_t)h.next_table_start);
for (uns i=0; i<h.num_blocks; i++)
bputl(fb, (i < h.first_data_block || i == h.num_blocks-1) ? 0 : i+1);
/* Padding */
- ASSERT(btell(fb) <= h.first_data_block << h.block_shift);
- while (btell(fb) < h.first_data_block << h.block_shift)
+ ASSERT(btell(fb) <= (sh_off_t)(h.first_data_block << h.block_shift));
+ while (btell(fb) < (sh_off_t)(h.first_data_block << h.block_shift))
bputc(fb, 0);
/* Data blocks */
for (uns j=0; j<h.block_size; j+=4)
bputl(fb, 0);
- ASSERT(btell(fb) == par->cache_size);
+ ASSERT(btell(fb) == (sh_off_t)par->cache_size);
bclose(fb);
- log(L_INFO, "Cache %s: created (%d bytes, %d slots, %d buckets)", q->file_name, par->cache_size, h.max_entries, h.hash_size);
+ msg(L_INFO, "Cache %s: created (%d bytes, %d slots, %d buckets)", q->file_name, par->cache_size, h.max_entries, h.hash_size);
if ((q->mmap_data = mmap(NULL, par->cache_size, PROT_READ | PROT_WRITE, MAP_SHARED, q->fd, 0)) == MAP_FAILED)
- die("Cache %s: mmap failed (%m)", par->cache_size);
+ die("Cache %s: mmap failed (%m)", par->file_name);
q->file_size = par->cache_size;
qache_setup_pointers(q);
}
q->file_name = xstrdup(par->file_name);
ASSERT(par->block_size >= 8 && !(par->block_size & (par->block_size-1)));
- par->cache_size = ALIGN(par->cache_size, par->block_size);
+ par->cache_size = ALIGN_TO(par->cache_size, par->block_size);
if (par->force_reset <= 0 && qache_open_existing(q, par))
;
else if (par->force_reset < 0)
- die("Cache %s: read-only access requested, but no data available");
+ die("Cache %s: read-only access requested, but no data available", q->file_name);
else
qache_create(q, par);
return q;
munmap(q->mmap_data, q->file_size);
close(q->fd);
if (!retain_data && unlink(q->file_name) < 0)
- log(L_ERROR, "Cache %s: unlink failed (%m)", q->file_name);
+ msg(L_ERROR, "Cache %s: unlink failed (%m)", q->file_name);
xfree(q->file_name);
xfree(q);
}
{
ASSERT(q->locked);
- if (pos_hint && pos_hint < q->hdr->max_entries && !memcmp(q->entry_table[pos_hint].key, key, sizeof(*key)))
+ if (pos_hint && pos_hint < q->hdr->max_entries && q->entry_table[pos_hint].data_len != ~0U && !memcmp(q->entry_table[pos_hint].key, key, sizeof(*key)))
return pos_hint;
uns h = qache_hash(q, key);
return e;
}
+static void
+copy_out(struct qache *q, struct qache_entry *entry, byte **datap, uns *sizep, uns start)
+{
+ if (sizep)
+ {
+ uns size = *sizep;
+ uns avail = (start > entry->data_len) ? 0 : entry->data_len - start;
+ uns xfer = MIN(size, avail);
+ *sizep = avail;
+ if (datap)
+ {
+ if (!*datap)
+ *datap = xmalloc(xfer);
+ uns blk = entry->first_data_block;
+ while (start >= q->hdr->block_size)
+ {
+ blk = q->next_table[blk];
+ start -= q->hdr->block_size;
+ }
+ byte *data = *datap;
+ while (xfer)
+ {
+ uns len = MIN(xfer, q->hdr->block_size - start);
+ memcpy(data, get_block_start(q, blk), len);
+ blk = q->next_table[blk];
+ data += len;
+ xfer -= len;
+ start = 0;
+ }
+ }
+ }
+ else
+ ASSERT(!datap);
+}
+
uns
qache_lookup(struct qache *q, qache_key_t *key, uns pos_hint, byte **datap, uns *sizep, uns start)
{
DBG("Lookup <%s>: found entry %d", format_key(key), e);
qache_lru_remove(q, e);
qache_lru_insert(q, e);
- if (sizep)
- {
- uns size = *sizep;
- uns avail = (start > entry->data_len) ? 0 : entry->data_len - start;
- uns xfer = MIN(size, avail);
- *sizep = avail;
- if (datap)
- {
- if (!*datap)
- *datap = xmalloc(xfer);
- uns blk = entry->first_data_block;
- while (start >= q->hdr->block_size)
- {
- blk = q->next_table[blk];
- start -= q->hdr->block_size;
- }
- byte *data = *datap;
- while (xfer)
- {
- uns len = MIN(xfer, q->hdr->block_size - start);
- memcpy(data, get_block_start(q, blk), len);
- blk = q->next_table[blk];
- data += len;
- xfer -= len;
- start = 0;
- }
- }
- }
- else
- ASSERT(!datap);
+ copy_out(q, entry, datap, sizep, start);
qache_unlock(q, 1); /* Yes, modified -- we update the LRU */
}
else
return e;
}
+uns
+qache_probe(struct qache *q, qache_key_t *key, uns pos, byte **datap, uns *sizep, uns start)
+{
+ if (!pos || pos >= q->hdr->max_entries)
+ {
+ DBG("Probe %d: Out of range", pos);
+ return ~0U;
+ }
+
+ qache_lock(q);
+ uns ret = 0;
+ struct qache_entry *entry = &q->entry_table[pos];
+ if (entry->data_len != ~0U)
+ {
+ DBG("Probe %d: Found key <%s>", format_key(entry->key));
+ if (key)
+ memcpy(key, entry->key, sizeof(qache_key_t));
+ copy_out(q, entry, datap, sizep, start);
+ ret = pos;
+ }
+ else
+ DBG("Probe %d: Empty", pos);
+ qache_unlock(q, 0);
+ return ret;
+}
+
uns
qache_delete(struct qache *q, qache_key_t *key, uns pos_hint)
{
void
qache_debug(struct qache *q)
{
- log(L_DEBUG, "Cache %s: block_size=%d (%d data), num_blocks=%d (%d first data), %d slots, %d hash buckets",
+ msg(L_DEBUG, "Cache %s: block_size=%d (%d data), num_blocks=%d (%d first data), %d slots, %d hash buckets",
q->file_name, q->hdr->block_size, q->hdr->block_size, q->hdr->num_blocks, q->hdr->first_data_block,
q->hdr->max_entries, q->hdr->hash_size);
- log(L_DEBUG, "Table of cache entries:");
- log(L_DEBUG, "\tEntry\tLruPrev\tLruNext\tDataLen\tDataBlk\tHashNxt\tKey");
+ msg(L_DEBUG, "Table of cache entries:");
+ msg(L_DEBUG, "\tEntry\tLruPrev\tLruNext\tDataLen\tDataBlk\tHashNxt\tKey");
for (uns e=0; e<q->hdr->max_entries; e++)
{
struct qache_entry *ent = &q->entry_table[e];
- log(L_DEBUG, "\t%d\t%d\t%d\t%d\t%d\t%d\t%s", e, ent->lru_prev, ent->lru_next, ent->data_len,
+ msg(L_DEBUG, "\t%d\t%d\t%d\t%d\t%d\t%d\t%s", e, ent->lru_prev, ent->lru_next, ent->data_len,
ent->first_data_block, ent->hash_next, format_key(&ent->key));
}
- log(L_DEBUG, "Hash table:");
+ msg(L_DEBUG, "Hash table:");
for (uns h=0; h<q->hdr->hash_size; h++)
- log(L_DEBUG, "\t%04x\t%d", h, q->hash_table[h]);
+ msg(L_DEBUG, "\t%04x\t%d", h, q->hash_table[h]);
- log(L_DEBUG, "Next pointers:");
+ msg(L_DEBUG, "Next pointers:");
for (uns blk=q->hdr->first_data_block; blk<q->hdr->num_blocks; blk++)
- log(L_DEBUG, "\t%d\t%d", blk, q->next_table[blk]);
+ msg(L_DEBUG, "\t%d\t%d", blk, q->next_table[blk]);
}
void
qache_audit(struct qache *q)
{
- byte *err;
+ char *err;
qache_lock(q);
if (err = do_audit(q))
die("Cache %s: %s", q->file_name, err);
found++;
}
}
- log(L_INFO, "Found %d of %d entries", found, N);
+ msg(L_INFO, "Found %d of %d entries", found, N);
qache_close(q, 1);
return 0;