00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 #include "P_Cache.h"
00025 
00026 struct RamCacheLRUEntry {
00027   INK_MD5 key;
00028   uint32_t auxkey1;
00029   uint32_t auxkey2;
00030   LINK(RamCacheLRUEntry, lru_link);
00031   LINK(RamCacheLRUEntry, hash_link);
00032   Ptr<IOBufferData> data;
00033 };
00034 
00035 struct RamCacheLRU: public RamCache {
00036   int64_t max_bytes;
00037   int64_t bytes;
00038   int64_t objects;
00039 
00040   
00041   int get(INK_MD5 *key, Ptr<IOBufferData> *ret_data, uint32_t auxkey1 = 0, uint32_t auxkey2 = 0);
00042   int put(INK_MD5 *key, IOBufferData *data, uint32_t len, bool copy = false, uint32_t auxkey1 = 0, uint32_t auxkey2 = 0);
00043   int fixup(INK_MD5 *key, uint32_t old_auxkey1, uint32_t old_auxkey2, uint32_t new_auxkey1, uint32_t new_auxkey2);
00044 
00045   void init(int64_t max_bytes, Vol *vol);
00046 
00047   
00048   uint16_t *seen;
00049   Que(RamCacheLRUEntry, lru_link) lru;
00050   DList(RamCacheLRUEntry, hash_link) *bucket;
00051   int nbuckets;
00052   int ibuckets;
00053   Vol *vol;
00054 
00055   void resize_hashtable();
00056   RamCacheLRUEntry *remove(RamCacheLRUEntry *e);
00057 
00058   RamCacheLRU():bytes(0), objects(0), seen(0), bucket(0), nbuckets(0), ibuckets(0), vol(NULL) {}
00059 };
00060 
00061 ClassAllocator<RamCacheLRUEntry> ramCacheLRUEntryAllocator("RamCacheLRUEntry");
00062 
00063 static const int bucket_sizes[] = {
00064   127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
00065   524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859,
00066   134217689, 268435399, 536870909
00067 };
00068 
00069 void RamCacheLRU::resize_hashtable() {
00070   int anbuckets = bucket_sizes[ibuckets];
00071   DDebug("ram_cache", "resize hashtable %d", anbuckets);
00072   int64_t s = anbuckets * sizeof(DList(RamCacheLRUEntry, hash_link));
00073   DList(RamCacheLRUEntry, hash_link) *new_bucket = (DList(RamCacheLRUEntry, hash_link) *)ats_malloc(s);
00074   memset(new_bucket, 0, s);
00075   if (bucket) {
00076     for (int64_t i = 0; i < nbuckets; i++) {
00077       RamCacheLRUEntry *e = 0;
00078       while ((e = bucket[i].pop()))
00079         new_bucket[e->key.slice32(3) % anbuckets].push(e);
00080     }
00081     ats_free(bucket);
00082   }
00083   bucket = new_bucket;
00084   nbuckets = anbuckets;
00085   ats_free(seen);
00086   int size = bucket_sizes[ibuckets] * sizeof(uint16_t);
00087   if (cache_config_ram_cache_use_seen_filter) {
00088     seen = (uint16_t*)ats_malloc(size);
00089     memset(seen, 0, size);
00090   }
00091 }
00092 
00093 void
00094 RamCacheLRU::init(int64_t abytes, Vol *avol) {
00095   vol = avol;
00096   max_bytes = abytes;
00097   DDebug("ram_cache", "initializing ram_cache %" PRId64 " bytes", abytes);
00098   if (!max_bytes)
00099     return;
00100   resize_hashtable();
00101 }
00102 
00103 int
00104 RamCacheLRU::get(INK_MD5 * key, Ptr<IOBufferData> *ret_data, uint32_t auxkey1, uint32_t auxkey2) {
00105   if (!max_bytes)
00106     return 0;
00107   uint32_t i = key->slice32(3) % nbuckets;
00108   RamCacheLRUEntry *e = bucket[i].head;
00109   while (e) {
00110     if (e->key == *key && e->auxkey1 == auxkey1 && e->auxkey2 == auxkey2) {
00111       lru.remove(e);
00112       lru.enqueue(e);
00113       (*ret_data) = e->data;
00114       DDebug("ram_cache", "get %X %d %d HIT", key->slice32(3), auxkey1, auxkey2);
00115       CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_hits_stat, 1);
00116       return 1;
00117     }
00118     e = e->hash_link.next;
00119   }
00120   DDebug("ram_cache", "get %X %d %d MISS", key->slice32(3), auxkey1, auxkey2);
00121   CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_misses_stat, 1);
00122   return 0;
00123 }
00124 
00125 RamCacheLRUEntry * RamCacheLRU::remove(RamCacheLRUEntry *e) {
00126   RamCacheLRUEntry *ret = e->hash_link.next;
00127   uint32_t b = e->key.slice32(3) % nbuckets;
00128   bucket[b].remove(e);
00129   lru.remove(e);
00130   bytes -= e->data->block_size();
00131   CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, -e->data->block_size());
00132   DDebug("ram_cache", "put %X %d %d FREED", e->key.slice32(3), e->auxkey1, e->auxkey2);
00133   e->data = NULL;
00134   THREAD_FREE(e, ramCacheLRUEntryAllocator, this_thread());
00135   objects--;
00136   return ret;
00137 }
00138 
00139 
00140 int RamCacheLRU::put(INK_MD5 *key, IOBufferData *data, uint32_t len, bool, uint32_t auxkey1, uint32_t auxkey2) {
00141   if (!max_bytes)
00142     return 0;
00143   uint32_t i = key->slice32(3) % nbuckets;
00144   if (cache_config_ram_cache_use_seen_filter) {
00145     uint16_t k = key->slice32(3) >> 16;
00146     uint16_t kk = seen[i];
00147     seen[i] = k;
00148     if ((kk != (uint16_t)k)) {
00149       DDebug("ram_cache", "put %X %d %d len %d UNSEEN", key->slice32(3), auxkey1, auxkey2, len);
00150       return 0;
00151     }
00152   }
00153   RamCacheLRUEntry *e = bucket[i].head;
00154   while (e) {
00155     if (e->key == *key) {
00156       if (e->auxkey1 == auxkey1 && e->auxkey2 == auxkey2) {
00157         lru.remove(e);
00158         lru.enqueue(e);
00159         return 1;
00160       } else { 
00161         e = remove(e);
00162         continue;
00163       }
00164     }
00165     e = e->hash_link.next;
00166   }
00167   e = THREAD_ALLOC(ramCacheLRUEntryAllocator, this_ethread());
00168   e->key = *key;
00169   e->auxkey1 = auxkey1;
00170   e->auxkey2 = auxkey2;
00171   e->data = data;
00172   bucket[i].push(e);
00173   lru.enqueue(e);
00174   bytes += data->block_size();
00175   objects++;
00176   CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, data->block_size());
00177   while (bytes > max_bytes) {
00178     RamCacheLRUEntry *ee = lru.dequeue();
00179     if (ee)
00180       remove(ee);
00181     else
00182       break;
00183   }
00184   DDebug("ram_cache", "put %X %d %d INSERTED", key->slice32(3), auxkey1, auxkey2);
00185   if (objects > nbuckets) {
00186     ++ibuckets;
00187     resize_hashtable();
00188   }
00189   return 1;
00190 }
00191 
00192 int RamCacheLRU::fixup(INK_MD5 * key, uint32_t old_auxkey1, uint32_t old_auxkey2, uint32_t new_auxkey1, uint32_t new_auxkey2) {
00193   if (!max_bytes)
00194     return 0;
00195   uint32_t i = key->slice32(3) % nbuckets;
00196   RamCacheLRUEntry *e = bucket[i].head;
00197   while (e) {
00198     if (e->key == *key && e->auxkey1 == old_auxkey1 && e->auxkey2 == old_auxkey2) {
00199       e->auxkey1 = new_auxkey1;
00200       e->auxkey2 = new_auxkey2;
00201       return 1;
00202     }
00203     e = e->hash_link.next;
00204   }
00205   return 0;
00206 }
00207 
00208 RamCache *new_RamCacheLRU() {
00209   return new RamCacheLRU;
00210 }