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 }