X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=lib%2Fqache.c;h=91536bf7a0df2d9d5a259df63680dcb03fafb0c6;hb=7462f9e27978542b37e1745b9a8fa80fb07dab3d;hp=e965e47721a10b9ca55681c9980c15e6d4a6e193;hpb=ff935b2de2eee5512798b44f0cb52e3e72398d68;p=libucw.git diff --git a/lib/qache.c b/lib/qache.c index e965e477..91536bf7 100644 --- a/lib/qache.c +++ b/lib/qache.c @@ -7,14 +7,16 @@ #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 +#include #include #include +#include #include -#include /* * The cache lives in a mmapped file of the following format: @@ -58,7 +60,7 @@ struct qache { int fd; byte *mmap_data; uns file_size; - byte *file_name; + char *file_name; uns locked; }; @@ -66,10 +68,10 @@ struct qache { #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; immap_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 } @@ -126,7 +128,7 @@ enum entry_audit_flags { ET_HASH = 4 }; -static byte * +static char * audit_entries(struct qache *q, byte *entrymap) { uns i, j; @@ -182,7 +184,7 @@ enum block_audit_flags { BT_ALLOC = 2 }; -static byte * +static char * audit_blocks(struct qache *q, byte *entrymap, byte *blockmap) { uns i, j; @@ -224,7 +226,7 @@ audit_blocks(struct qache *q, byte *entrymap, byte *blockmap) return NULL; } -static byte * +static char * do_audit(struct qache *q) { byte *entry_map = xmalloc_zero(q->hdr->max_entries); @@ -253,7 +255,7 @@ qache_open_existing(struct qache *q, struct qache_params *par) return 0; struct stat st; - byte *err = "stat failed"; + char *err = "stat failed"; if (fstat(q->fd, &st) < 0) goto close_and_fail; @@ -289,14 +291,14 @@ qache_open_existing(struct qache *q, struct qache_params *par) 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; } @@ -313,7 +315,7 @@ qache_create(struct qache *q, struct qache_params *par) 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); @@ -329,7 +331,7 @@ qache_create(struct qache *q, struct qache_params *par) 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; @@ -347,18 +349,18 @@ qache_create(struct qache *q, struct qache_params *par) } /* The hash table */ - ASSERT(btell(fb) == h.hash_table_start); + ASSERT(btell(fb) == (sh_off_t)h.hash_table_start); for (uns i=0; icache_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); } @@ -383,12 +385,12 @@ qache_open(struct qache_params *par) 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; @@ -400,7 +402,7 @@ qache_close(struct qache *q, uns retain_data) 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); } @@ -417,7 +419,7 @@ qache_hash_find(struct qache *q, qache_key_t *key, uns pos_hint) { 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); @@ -598,6 +600,41 @@ qache_insert(struct qache *q, qache_key_t *key, uns pos_hint, void *data, uns si 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) { @@ -609,36 +646,7 @@ qache_lookup(struct qache *q, qache_key_t *key, uns pos_hint, byte **datap, uns 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 @@ -649,6 +657,32 @@ qache_lookup(struct qache *q, qache_key_t *key, uns pos_hint, byte **datap, uns 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) { @@ -668,32 +702,32 @@ 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; ehdr->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; hhdr->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; blkhdr->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); @@ -743,7 +777,7 @@ int main(int argc UNUSED, char **argv UNUSED) 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;