| 1 | /* |
|---|
| 2 | * (C) 2002 Clemson University and The University of Chicago |
|---|
| 3 | * |
|---|
| 4 | * See COPYING in top-level directory. |
|---|
| 5 | */ |
|---|
| 6 | |
|---|
| 7 | #include <stdlib.h> |
|---|
| 8 | #include <string.h> |
|---|
| 9 | #ifdef HAVE_MALLOC_H |
|---|
| 10 | #include <malloc.h> |
|---|
| 11 | #endif |
|---|
| 12 | |
|---|
| 13 | #include "dbpf-keyval-pcache.h" |
|---|
| 14 | #include "quickhash.h" |
|---|
| 15 | #include "gossip.h" |
|---|
| 16 | #include "pvfs2-internal.h" |
|---|
| 17 | |
|---|
| 18 | /* table size must be a multiple of 2 */ |
|---|
| 19 | #define DBPF_KEYVAL_PCACHE_TABLE_SIZE (1<<10) |
|---|
| 20 | #define DBPF_KEYVAL_PCACHE_HARD_LIMIT 51200 |
|---|
| 21 | |
|---|
| 22 | struct dbpf_keyval_pcache_key |
|---|
| 23 | { |
|---|
| 24 | TROVE_handle handle; |
|---|
| 25 | TROVE_kv_position pos; |
|---|
| 26 | }; |
|---|
| 27 | |
|---|
| 28 | struct dbpf_keyval_pcache_entry |
|---|
| 29 | { |
|---|
| 30 | TROVE_handle handle; |
|---|
| 31 | TROVE_kv_position pos; |
|---|
| 32 | char keyname[PVFS_NAME_MAX]; |
|---|
| 33 | int keylen; |
|---|
| 34 | }; |
|---|
| 35 | |
|---|
| 36 | static int dbpf_keyval_pcache_compare( |
|---|
| 37 | void * key, struct qhash_head * link); |
|---|
| 38 | static int dbpf_keyval_pcache_hash( |
|---|
| 39 | void * key, int size); |
|---|
| 40 | static int dbpf_keyval_pcache_entry_free( |
|---|
| 41 | void * entry); |
|---|
| 42 | |
|---|
| 43 | PINT_dbpf_keyval_pcache * PINT_dbpf_keyval_pcache_initialize(void) |
|---|
| 44 | { |
|---|
| 45 | PINT_dbpf_keyval_pcache * cache; |
|---|
| 46 | |
|---|
| 47 | cache = malloc(sizeof(PINT_dbpf_keyval_pcache)); |
|---|
| 48 | if(!cache) |
|---|
| 49 | { |
|---|
| 50 | return NULL; |
|---|
| 51 | } |
|---|
| 52 | |
|---|
| 53 | gen_mutex_init(&cache->mutex); |
|---|
| 54 | |
|---|
| 55 | cache->tcache = PINT_tcache_initialize( |
|---|
| 56 | dbpf_keyval_pcache_compare, |
|---|
| 57 | dbpf_keyval_pcache_hash, |
|---|
| 58 | dbpf_keyval_pcache_entry_free, |
|---|
| 59 | DBPF_KEYVAL_PCACHE_TABLE_SIZE); |
|---|
| 60 | if(!cache->tcache) |
|---|
| 61 | { |
|---|
| 62 | return NULL; |
|---|
| 63 | } |
|---|
| 64 | |
|---|
| 65 | PINT_tcache_set_info(cache->tcache, |
|---|
| 66 | TCACHE_ENABLE_EXPIRATION, |
|---|
| 67 | 0); |
|---|
| 68 | PINT_tcache_set_info(cache->tcache, |
|---|
| 69 | TCACHE_HARD_LIMIT, |
|---|
| 70 | DBPF_KEYVAL_PCACHE_HARD_LIMIT); |
|---|
| 71 | |
|---|
| 72 | |
|---|
| 73 | return cache; |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | void PINT_dbpf_keyval_pcache_finalize( |
|---|
| 77 | PINT_dbpf_keyval_pcache * cache) |
|---|
| 78 | { |
|---|
| 79 | PINT_tcache_finalize(cache->tcache); |
|---|
| 80 | gen_mutex_destroy(&cache->mutex); |
|---|
| 81 | free(cache); |
|---|
| 82 | } |
|---|
| 83 | |
|---|
| 84 | static int dbpf_keyval_pcache_compare( |
|---|
| 85 | void * key, struct qhash_head * link) |
|---|
| 86 | { |
|---|
| 87 | struct dbpf_keyval_pcache_key * key_entry = |
|---|
| 88 | (struct dbpf_keyval_pcache_key *)key; |
|---|
| 89 | struct dbpf_keyval_pcache_entry * link_entry = |
|---|
| 90 | (struct dbpf_keyval_pcache_entry *) |
|---|
| 91 | (qhash_entry(link, struct PINT_tcache_entry, hash_link))->payload; |
|---|
| 92 | |
|---|
| 93 | if(!(TROVE_handle_compare(key_entry->handle, link_entry->handle)) && |
|---|
| 94 | key_entry->pos.session == link_entry->pos.session && |
|---|
| 95 | key_entry->pos.count == link_entry->pos.count) |
|---|
| 96 | return 1; |
|---|
| 97 | return 0; |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | /* hash from http://burtleburtle.net/bob/hash/evahash.html |
|---|
| 101 | #define mix(a,b,c) \ |
|---|
| 102 | do { \ |
|---|
| 103 | a=a-b; a=a-c; a=a^(c>>13); \ |
|---|
| 104 | b=b-c; b=b-a; b=b^(a<<8); \ |
|---|
| 105 | c=c-a; c=c-b; c=c^(b>>13); \ |
|---|
| 106 | a=a-b; a=a-c; a=a^(c>>12); \ |
|---|
| 107 | b=b-c; b=b-a; b=b^(a<<16); \ |
|---|
| 108 | c=c-a; c=c-b; c=c^(b>>5); \ |
|---|
| 109 | a=a-b; a=a-c; a=a^(c>>3); \ |
|---|
| 110 | b=b-c; b=b-a; b=b^(a<<10); \ |
|---|
| 111 | c=c-a; c=c-b; c=c^(b>>15); \ |
|---|
| 112 | } while(0) */ |
|---|
| 113 | |
|---|
| 114 | /* 64 bit version */ |
|---|
| 115 | #define mix64(a,b,c) \ |
|---|
| 116 | { \ |
|---|
| 117 | a=a-b; a=a-c; a=a^(c>>43); \ |
|---|
| 118 | b=b-c; b=b-a; b=b^(a<<9); \ |
|---|
| 119 | c=c-a; c=c-b; c=c^(b>>8); \ |
|---|
| 120 | a=a-b; a=a-c; a=a^(c>>38); \ |
|---|
| 121 | b=b-c; b=b-a; b=b^(a<<23); \ |
|---|
| 122 | c=c-a; c=c-b; c=c^(b>>5); \ |
|---|
| 123 | a=a-b; a=a-c; a=a^(c>>35); \ |
|---|
| 124 | b=b-c; b=b-a; b=b^(a<<49); \ |
|---|
| 125 | c=c-a; c=c-b; c=c^(b>>11); \ |
|---|
| 126 | a=a-b; a=a-c; a=a^(c>>12); \ |
|---|
| 127 | b=b-c; b=b-a; b=b^(a<<18); \ |
|---|
| 128 | c=c-a; c=c-b; c=c^(b>>22); \ |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | |
|---|
| 132 | static int dbpf_keyval_pcache_hash( |
|---|
| 133 | void * key, int size) |
|---|
| 134 | { |
|---|
| 135 | struct dbpf_keyval_pcache_entry * key_entry = |
|---|
| 136 | (struct dbpf_keyval_pcache_entry *)key; |
|---|
| 137 | uint64_t a = 0, b = 0, c = 0; |
|---|
| 138 | |
|---|
| 139 | /* FIX: needs refactored for both handle and pos.session/pos.count */ |
|---|
| 140 | TROVE_handle_to_hash(key_entry->handle, &a); |
|---|
| 141 | b = key_entry->pos.session; |
|---|
| 142 | c = key_entry->pos.count; |
|---|
| 143 | |
|---|
| 144 | mix64(a,b,c); |
|---|
| 145 | return (int)(c & (DBPF_KEYVAL_PCACHE_TABLE_SIZE-1)); |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | static int dbpf_keyval_pcache_entry_free( |
|---|
| 149 | void * entry) |
|---|
| 150 | { |
|---|
| 151 | free(entry); |
|---|
| 152 | return 0; |
|---|
| 153 | } |
|---|
| 154 | |
|---|
| 155 | int PINT_dbpf_keyval_pcache_lookup( |
|---|
| 156 | PINT_dbpf_keyval_pcache *pcache, |
|---|
| 157 | TROVE_handle handle, |
|---|
| 158 | TROVE_kv_position pos, |
|---|
| 159 | const void ** keyname, |
|---|
| 160 | int * length) |
|---|
| 161 | { |
|---|
| 162 | struct PINT_tcache_entry *entry; |
|---|
| 163 | struct dbpf_keyval_pcache_key key; |
|---|
| 164 | int ret, status; |
|---|
| 165 | |
|---|
| 166 | TROVE_handle_copy(key.handle, handle); |
|---|
| 167 | |
|---|
| 168 | /* this used to be a 64 bit number where the top 32 bits were a |
|---|
| 169 | * session id and the bottom 32 were a count. that's replaced with |
|---|
| 170 | * struct that is the same, should provide the same data to tcache */ |
|---|
| 171 | memcpy(&key.pos, &pos, sizeof(TROVE_kv_position) ); |
|---|
| 172 | |
|---|
| 173 | gen_mutex_lock(&pcache->mutex); |
|---|
| 174 | ret = PINT_tcache_lookup(pcache->tcache, (void *)&key, &entry, &status); |
|---|
| 175 | if(ret != 0) |
|---|
| 176 | { |
|---|
| 177 | if(ret == -PVFS_ENOENT) |
|---|
| 178 | { |
|---|
| 179 | gossip_debug(GOSSIP_DBPF_KEYVAL_DEBUG, |
|---|
| 180 | "Trove KeyVal pcache NOTFOUND: " |
|---|
| 181 | "handle: %s, pos: session(%lluu), count(%lluu)\n", |
|---|
| 182 | PVFS_handle_to_str(handle), llu(pos.session), llu(pos.count)); |
|---|
| 183 | } |
|---|
| 184 | else |
|---|
| 185 | { |
|---|
| 186 | gossip_debug(GOSSIP_DBPF_KEYVAL_DEBUG, |
|---|
| 187 | "Trove KeyVal pcache failed: (error %d): " |
|---|
| 188 | "handle: %s, pos: session(%llu), count(%llu)\n", |
|---|
| 189 | ret, PVFS_handle_to_str(handle), llu(pos.session), llu(pos.count)); |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | gen_mutex_unlock(&pcache->mutex); |
|---|
| 193 | return ret; |
|---|
| 194 | } |
|---|
| 195 | gen_mutex_unlock(&pcache->mutex); |
|---|
| 196 | |
|---|
| 197 | *keyname = ((struct dbpf_keyval_pcache_entry *)entry->payload)->keyname; |
|---|
| 198 | *length = ((struct dbpf_keyval_pcache_entry *)entry->payload)->keylen; |
|---|
| 199 | |
|---|
| 200 | gossip_debug(GOSSIP_DBPF_KEYVAL_DEBUG, |
|---|
| 201 | "Trove KeyVal pcache lookup succeeded: " |
|---|
| 202 | "handle: %s, pos: session(%llu), count(%llu)\n", |
|---|
| 203 | PVFS_handle_to_str(handle), llu(pos.session), llu(pos.count)); |
|---|
| 204 | |
|---|
| 205 | return 0; |
|---|
| 206 | } |
|---|
| 207 | |
|---|
| 208 | int PINT_dbpf_keyval_pcache_insert( |
|---|
| 209 | PINT_dbpf_keyval_pcache *pcache, |
|---|
| 210 | TROVE_handle handle, |
|---|
| 211 | TROVE_kv_position pos, |
|---|
| 212 | const char * keyname, |
|---|
| 213 | int length) |
|---|
| 214 | { |
|---|
| 215 | struct dbpf_keyval_pcache_entry *entry; |
|---|
| 216 | struct dbpf_keyval_pcache_key key; |
|---|
| 217 | struct PINT_tcache_entry * tentry; |
|---|
| 218 | int lookup_status; |
|---|
| 219 | int ret; |
|---|
| 220 | int removed; |
|---|
| 221 | |
|---|
| 222 | entry = malloc(sizeof(struct dbpf_keyval_pcache_entry)); |
|---|
| 223 | if(!entry) |
|---|
| 224 | { |
|---|
| 225 | return -PVFS_ENOMEM; |
|---|
| 226 | } |
|---|
| 227 | |
|---|
| 228 | TROVE_handle_copy(key.handle, handle); |
|---|
| 229 | memcpy(&key.pos, &pos, sizeof(PVFS_kv_position)); |
|---|
| 230 | |
|---|
| 231 | gen_mutex_lock(&pcache->mutex); |
|---|
| 232 | if(PINT_tcache_lookup( |
|---|
| 233 | pcache->tcache, (void *)&key, &tentry, &lookup_status) == 0) |
|---|
| 234 | { |
|---|
| 235 | /* remove entry that already exists */ |
|---|
| 236 | PINT_tcache_delete(pcache->tcache, tentry); |
|---|
| 237 | } |
|---|
| 238 | |
|---|
| 239 | TROVE_handle_copy(entry->handle, handle); |
|---|
| 240 | memcpy(&entry->pos, &pos, sizeof(PVFS_kv_position)); |
|---|
| 241 | memcpy(entry->keyname, keyname, length); |
|---|
| 242 | entry->keylen = length; |
|---|
| 243 | |
|---|
| 244 | ret = PINT_tcache_insert_entry(pcache->tcache, |
|---|
| 245 | &key, |
|---|
| 246 | entry, |
|---|
| 247 | &removed); |
|---|
| 248 | if(ret != 0) |
|---|
| 249 | { |
|---|
| 250 | gossip_debug(GOSSIP_DBPF_KEYVAL_DEBUG, |
|---|
| 251 | "Trove KeyVal pcache insert failed: (error: %d) " |
|---|
| 252 | "handle: %s, pos: session(%llu), count(%llu)\n", |
|---|
| 253 | ret, PVFS_handle_to_str(handle), llu(pos.session), llu(pos.count)); |
|---|
| 254 | |
|---|
| 255 | gen_mutex_unlock(&pcache->mutex); |
|---|
| 256 | free(entry); |
|---|
| 257 | return ret; |
|---|
| 258 | } |
|---|
| 259 | gen_mutex_unlock(&pcache->mutex); |
|---|
| 260 | |
|---|
| 261 | gossip_debug(GOSSIP_DBPF_KEYVAL_DEBUG, |
|---|
| 262 | "Trove KeyVal pcache insert succeeded: " |
|---|
| 263 | "handle: %s, pos: session(%llu), count(%llu)\n", |
|---|
| 264 | PVFS_handle_to_str(handle), llu(pos.session), llu(pos.count)); |
|---|
| 265 | |
|---|
| 266 | return 0; |
|---|
| 267 | } |
|---|
| 268 | |
|---|
| 269 | /* |
|---|
| 270 | * Local variables: |
|---|
| 271 | * c-indent-level: 4 |
|---|
| 272 | * c-basic-offset: 4 |
|---|
| 273 | * End: |
|---|
| 274 | * |
|---|
| 275 | * vim: ts=8 sts=4 sw=4 expandtab |
|---|
| 276 | */ |
|---|