• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

RamCacheLRU.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
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   // returns 1 on found/stored, 0 on not found/stored, if provided auxkey1 and auxkey2 must match
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   // private
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 // ignore 'copy' since we don't touch the data
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 { // discard when aux keys conflict
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 }

Generated by  doxygen 1.7.1