]> mj.ucw.cz Git - libucw.git/blobdiff - lib/qache.c
Added a simple threading helper module.
[libucw.git] / lib / qache.c
index e965e47721a10b9ca55681c9980c15e6d4a6e193..3c4be273ab1c1bd0b24d100cc4439781da75a61c 100644 (file)
@@ -7,12 +7,13 @@
 #undef LOCAL_DEBUG
 
 #include "lib/lib.h"
+#include "lib/bitops.h"
 #include "lib/fastbuf.h"
 #include "lib/qache.h"
 
-#include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <sys/stat.h>
 #include <sys/mman.h>
 #include <sys/user.h>
 
@@ -82,7 +83,7 @@ qache_msync(struct qache *q UNUSED, uns start UNUSED, uns len UNUSED)
   /* 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 = ALIGN_TO(len, 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);
 #endif
@@ -313,7 +314,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);
@@ -371,7 +372,7 @@ qache_create(struct qache *q, struct qache_params *par)
   log(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 +384,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;
@@ -417,7 +418,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 +599,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 +645,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 +656,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)
 {