1/*- 2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28#include <sys/cdefs.h>
|
29__FBSDID("$FreeBSD: head/usr.sbin/nscd/cachelib.c 194093 2009-06-13 00:43:56Z des $");
| 29__FBSDID("$FreeBSD: head/usr.sbin/nscd/cachelib.c 194095 2009-06-13 00:54:52Z des $");
|
30 31#include <sys/time.h> 32 33#include <assert.h> 34#include <stdlib.h> 35#include <string.h> 36 37#include "cachelib.h" 38#include "debug.h" 39 40#define INITIAL_ENTRIES_CAPACITY 32 41#define ENTRIES_CAPACITY_STEP 32 42 43#define STRING_SIMPLE_HASH_BODY(in_var, var, a, M) \ 44 for ((var) = 0; *(in_var) != '\0'; ++(in_var)) \ 45 (var) = ((a)*(var) + *(in_var)) % (M) 46 47#define STRING_SIMPLE_MP2_HASH_BODY(in_var, var, a, M) \ 48 for ((var) = 0; *(in_var) != 0; ++(in_var)) \ 49 (var) = ((a)*(var) + *(in_var)) & (M - 1) 50 51static int cache_elemsize_common_continue_func(struct cache_common_entry_ *, 52 struct cache_policy_item_ *); 53static int cache_lifetime_common_continue_func(struct cache_common_entry_ *, 54 struct cache_policy_item_ *); 55static void clear_cache_entry(struct cache_entry_ *); 56static void destroy_cache_entry(struct cache_entry_ *); 57static void destroy_cache_mp_read_session(struct cache_mp_read_session_ *); 58static void destroy_cache_mp_write_session(struct cache_mp_write_session_ *); 59static int entries_bsearch_cmp_func(const void *, const void *); 60static int entries_qsort_cmp_func(const void *, const void *); 61static struct cache_entry_ ** find_cache_entry_p(struct cache_ *, 62 const char *); 63static void flush_cache_entry(struct cache_entry_ *); 64static void flush_cache_policy(struct cache_common_entry_ *, 65 struct cache_policy_ *, struct cache_policy_ *, 66 int (*)(struct cache_common_entry_ *, 67 struct cache_policy_item_ *)); 68static int ht_items_cmp_func(const void *, const void *); 69static int ht_items_fixed_size_left_cmp_func(const void *, const void *); 70static hashtable_index_t ht_item_hash_func(const void *, size_t); 71 72/* 73 * Hashing and comparing routines, that are used with the hash tables 74 */ 75static int 76ht_items_cmp_func(const void *p1, const void *p2) 77{ 78 struct cache_ht_item_data_ *hp1, *hp2; 79 size_t min_size; 80 int result; 81 82 hp1 = (struct cache_ht_item_data_ *)p1; 83 hp2 = (struct cache_ht_item_data_ *)p2; 84 85 assert(hp1->key != NULL); 86 assert(hp2->key != NULL); 87 88 if (hp1->key_size != hp2->key_size) { 89 min_size = (hp1->key_size < hp2->key_size) ? hp1->key_size : 90 hp2->key_size; 91 result = memcmp(hp1->key, hp2->key, min_size); 92 93 if (result == 0) 94 return ((hp1->key_size < hp2->key_size) ? -1 : 1); 95 else 96 return (result); 97 } else 98 return (memcmp(hp1->key, hp2->key, hp1->key_size)); 99} 100 101static int 102ht_items_fixed_size_left_cmp_func(const void *p1, const void *p2) 103{ 104 struct cache_ht_item_data_ *hp1, *hp2; 105 size_t min_size; 106 int result; 107 108 hp1 = (struct cache_ht_item_data_ *)p1; 109 hp2 = (struct cache_ht_item_data_ *)p2; 110 111 assert(hp1->key != NULL); 112 assert(hp2->key != NULL); 113 114 if (hp1->key_size != hp2->key_size) { 115 min_size = (hp1->key_size < hp2->key_size) ? hp1->key_size : 116 hp2->key_size; 117 result = memcmp(hp1->key, hp2->key, min_size); 118 119 if (result == 0) 120 if (min_size == hp1->key_size) 121 return (0); 122 else 123 return ((hp1->key_size < hp2->key_size) ? -1 : 1); 124 else 125 return (result); 126 } else 127 return (memcmp(hp1->key, hp2->key, hp1->key_size)); 128} 129 130static hashtable_index_t 131ht_item_hash_func(const void *p, size_t cache_entries_size) 132{ 133 struct cache_ht_item_data_ *hp; 134 size_t i; 135 136 hashtable_index_t retval; 137 138 hp = (struct cache_ht_item_data_ *)p; 139 assert(hp->key != NULL); 140 141 retval = 0; 142 for (i = 0; i < hp->key_size; ++i) 143 retval = (127 * retval + (unsigned char)hp->key[i]) % 144 cache_entries_size; 145 146 return retval; 147} 148
| 30 31#include <sys/time.h> 32 33#include <assert.h> 34#include <stdlib.h> 35#include <string.h> 36 37#include "cachelib.h" 38#include "debug.h" 39 40#define INITIAL_ENTRIES_CAPACITY 32 41#define ENTRIES_CAPACITY_STEP 32 42 43#define STRING_SIMPLE_HASH_BODY(in_var, var, a, M) \ 44 for ((var) = 0; *(in_var) != '\0'; ++(in_var)) \ 45 (var) = ((a)*(var) + *(in_var)) % (M) 46 47#define STRING_SIMPLE_MP2_HASH_BODY(in_var, var, a, M) \ 48 for ((var) = 0; *(in_var) != 0; ++(in_var)) \ 49 (var) = ((a)*(var) + *(in_var)) & (M - 1) 50 51static int cache_elemsize_common_continue_func(struct cache_common_entry_ *, 52 struct cache_policy_item_ *); 53static int cache_lifetime_common_continue_func(struct cache_common_entry_ *, 54 struct cache_policy_item_ *); 55static void clear_cache_entry(struct cache_entry_ *); 56static void destroy_cache_entry(struct cache_entry_ *); 57static void destroy_cache_mp_read_session(struct cache_mp_read_session_ *); 58static void destroy_cache_mp_write_session(struct cache_mp_write_session_ *); 59static int entries_bsearch_cmp_func(const void *, const void *); 60static int entries_qsort_cmp_func(const void *, const void *); 61static struct cache_entry_ ** find_cache_entry_p(struct cache_ *, 62 const char *); 63static void flush_cache_entry(struct cache_entry_ *); 64static void flush_cache_policy(struct cache_common_entry_ *, 65 struct cache_policy_ *, struct cache_policy_ *, 66 int (*)(struct cache_common_entry_ *, 67 struct cache_policy_item_ *)); 68static int ht_items_cmp_func(const void *, const void *); 69static int ht_items_fixed_size_left_cmp_func(const void *, const void *); 70static hashtable_index_t ht_item_hash_func(const void *, size_t); 71 72/* 73 * Hashing and comparing routines, that are used with the hash tables 74 */ 75static int 76ht_items_cmp_func(const void *p1, const void *p2) 77{ 78 struct cache_ht_item_data_ *hp1, *hp2; 79 size_t min_size; 80 int result; 81 82 hp1 = (struct cache_ht_item_data_ *)p1; 83 hp2 = (struct cache_ht_item_data_ *)p2; 84 85 assert(hp1->key != NULL); 86 assert(hp2->key != NULL); 87 88 if (hp1->key_size != hp2->key_size) { 89 min_size = (hp1->key_size < hp2->key_size) ? hp1->key_size : 90 hp2->key_size; 91 result = memcmp(hp1->key, hp2->key, min_size); 92 93 if (result == 0) 94 return ((hp1->key_size < hp2->key_size) ? -1 : 1); 95 else 96 return (result); 97 } else 98 return (memcmp(hp1->key, hp2->key, hp1->key_size)); 99} 100 101static int 102ht_items_fixed_size_left_cmp_func(const void *p1, const void *p2) 103{ 104 struct cache_ht_item_data_ *hp1, *hp2; 105 size_t min_size; 106 int result; 107 108 hp1 = (struct cache_ht_item_data_ *)p1; 109 hp2 = (struct cache_ht_item_data_ *)p2; 110 111 assert(hp1->key != NULL); 112 assert(hp2->key != NULL); 113 114 if (hp1->key_size != hp2->key_size) { 115 min_size = (hp1->key_size < hp2->key_size) ? hp1->key_size : 116 hp2->key_size; 117 result = memcmp(hp1->key, hp2->key, min_size); 118 119 if (result == 0) 120 if (min_size == hp1->key_size) 121 return (0); 122 else 123 return ((hp1->key_size < hp2->key_size) ? -1 : 1); 124 else 125 return (result); 126 } else 127 return (memcmp(hp1->key, hp2->key, hp1->key_size)); 128} 129 130static hashtable_index_t 131ht_item_hash_func(const void *p, size_t cache_entries_size) 132{ 133 struct cache_ht_item_data_ *hp; 134 size_t i; 135 136 hashtable_index_t retval; 137 138 hp = (struct cache_ht_item_data_ *)p; 139 assert(hp->key != NULL); 140 141 retval = 0; 142 for (i = 0; i < hp->key_size; ++i) 143 retval = (127 * retval + (unsigned char)hp->key[i]) % 144 cache_entries_size; 145 146 return retval; 147} 148
|
| 149HASHTABLE_PROTOTYPE(cache_ht_, cache_ht_item_, struct cache_ht_item_data_);
|
149HASHTABLE_GENERATE(cache_ht_, cache_ht_item_, struct cache_ht_item_data_, data, 150 ht_item_hash_func, ht_items_cmp_func); 151 152/* 153 * Routines to sort and search the entries by name 154 */ 155static int 156entries_bsearch_cmp_func(const void *key, const void *ent) 157{ 158 159 assert(key != NULL); 160 assert(ent != NULL); 161 162 return (strcmp((char const *)key, 163 (*(struct cache_entry_ const **)ent)->name)); 164} 165 166static int 167entries_qsort_cmp_func(const void *e1, const void *e2) 168{ 169 170 assert(e1 != NULL); 171 assert(e2 != NULL); 172 173 return (strcmp((*(struct cache_entry_ const **)e1)->name, 174 (*(struct cache_entry_ const **)e2)->name)); 175} 176 177static struct cache_entry_ ** 178find_cache_entry_p(struct cache_ *the_cache, const char *entry_name) 179{ 180 181 return ((struct cache_entry_ **)(bsearch(entry_name, the_cache->entries, 182 the_cache->entries_size, sizeof(struct cache_entry_ *), 183 entries_bsearch_cmp_func))); 184} 185 186static void 187destroy_cache_mp_write_session(struct cache_mp_write_session_ *ws) 188{ 189 190 struct cache_mp_data_item_ *data_item; 191 192 TRACE_IN(destroy_cache_mp_write_session); 193 assert(ws != NULL); 194 while (!TAILQ_EMPTY(&ws->items)) { 195 data_item = TAILQ_FIRST(&ws->items); 196 TAILQ_REMOVE(&ws->items, data_item, entries); 197 free(data_item->value); 198 free(data_item); 199 } 200 201 free(ws); 202 TRACE_OUT(destroy_cache_mp_write_session); 203} 204 205static void 206destroy_cache_mp_read_session(struct cache_mp_read_session_ *rs) 207{ 208 209 TRACE_IN(destroy_cache_mp_read_session); 210 assert(rs != NULL); 211 free(rs); 212 TRACE_OUT(destroy_cache_mp_read_session); 213} 214 215static void 216destroy_cache_entry(struct cache_entry_ *entry) 217{ 218 struct cache_common_entry_ *common_entry; 219 struct cache_mp_entry_ *mp_entry; 220 struct cache_mp_read_session_ *rs; 221 struct cache_mp_write_session_ *ws; 222 struct cache_ht_item_ *ht_item; 223 struct cache_ht_item_data_ *ht_item_data; 224 225 TRACE_IN(destroy_cache_entry); 226 assert(entry != NULL); 227 228 if (entry->params->entry_type == CET_COMMON) { 229 common_entry = (struct cache_common_entry_ *)entry; 230 231 HASHTABLE_FOREACH(&(common_entry->items), ht_item) { 232 HASHTABLE_ENTRY_FOREACH(ht_item, data, ht_item_data) 233 { 234 free(ht_item_data->key); 235 free(ht_item_data->value); 236 } 237 HASHTABLE_ENTRY_CLEAR(ht_item, data); 238 } 239 240 HASHTABLE_DESTROY(&(common_entry->items), data); 241 242 /* FIFO policy is always first */ 243 destroy_cache_fifo_policy(common_entry->policies[0]); 244 switch (common_entry->common_params.policy) { 245 case CPT_LRU: 246 destroy_cache_lru_policy(common_entry->policies[1]); 247 break; 248 case CPT_LFU: 249 destroy_cache_lfu_policy(common_entry->policies[1]); 250 break; 251 default: 252 break; 253 } 254 free(common_entry->policies); 255 } else { 256 mp_entry = (struct cache_mp_entry_ *)entry; 257 258 while (!TAILQ_EMPTY(&mp_entry->ws_head)) { 259 ws = TAILQ_FIRST(&mp_entry->ws_head); 260 TAILQ_REMOVE(&mp_entry->ws_head, ws, entries); 261 destroy_cache_mp_write_session(ws); 262 } 263 264 while (!TAILQ_EMPTY(&mp_entry->rs_head)) { 265 rs = TAILQ_FIRST(&mp_entry->rs_head); 266 TAILQ_REMOVE(&mp_entry->rs_head, rs, entries); 267 destroy_cache_mp_read_session(rs); 268 } 269 270 if (mp_entry->completed_write_session != NULL) 271 destroy_cache_mp_write_session( 272 mp_entry->completed_write_session); 273 274 if (mp_entry->pending_write_session != NULL) 275 destroy_cache_mp_write_session( 276 mp_entry->pending_write_session); 277 } 278 279 free(entry->name); 280 free(entry); 281 TRACE_OUT(destroy_cache_entry); 282} 283 284static void 285clear_cache_entry(struct cache_entry_ *entry) 286{ 287 struct cache_mp_entry_ *mp_entry; 288 struct cache_common_entry_ *common_entry; 289 struct cache_ht_item_ *ht_item; 290 struct cache_ht_item_data_ *ht_item_data; 291 struct cache_policy_ *policy; 292 struct cache_policy_item_ *item, *next_item; 293 size_t entry_size;
| 150HASHTABLE_GENERATE(cache_ht_, cache_ht_item_, struct cache_ht_item_data_, data, 151 ht_item_hash_func, ht_items_cmp_func); 152 153/* 154 * Routines to sort and search the entries by name 155 */ 156static int 157entries_bsearch_cmp_func(const void *key, const void *ent) 158{ 159 160 assert(key != NULL); 161 assert(ent != NULL); 162 163 return (strcmp((char const *)key, 164 (*(struct cache_entry_ const **)ent)->name)); 165} 166 167static int 168entries_qsort_cmp_func(const void *e1, const void *e2) 169{ 170 171 assert(e1 != NULL); 172 assert(e2 != NULL); 173 174 return (strcmp((*(struct cache_entry_ const **)e1)->name, 175 (*(struct cache_entry_ const **)e2)->name)); 176} 177 178static struct cache_entry_ ** 179find_cache_entry_p(struct cache_ *the_cache, const char *entry_name) 180{ 181 182 return ((struct cache_entry_ **)(bsearch(entry_name, the_cache->entries, 183 the_cache->entries_size, sizeof(struct cache_entry_ *), 184 entries_bsearch_cmp_func))); 185} 186 187static void 188destroy_cache_mp_write_session(struct cache_mp_write_session_ *ws) 189{ 190 191 struct cache_mp_data_item_ *data_item; 192 193 TRACE_IN(destroy_cache_mp_write_session); 194 assert(ws != NULL); 195 while (!TAILQ_EMPTY(&ws->items)) { 196 data_item = TAILQ_FIRST(&ws->items); 197 TAILQ_REMOVE(&ws->items, data_item, entries); 198 free(data_item->value); 199 free(data_item); 200 } 201 202 free(ws); 203 TRACE_OUT(destroy_cache_mp_write_session); 204} 205 206static void 207destroy_cache_mp_read_session(struct cache_mp_read_session_ *rs) 208{ 209 210 TRACE_IN(destroy_cache_mp_read_session); 211 assert(rs != NULL); 212 free(rs); 213 TRACE_OUT(destroy_cache_mp_read_session); 214} 215 216static void 217destroy_cache_entry(struct cache_entry_ *entry) 218{ 219 struct cache_common_entry_ *common_entry; 220 struct cache_mp_entry_ *mp_entry; 221 struct cache_mp_read_session_ *rs; 222 struct cache_mp_write_session_ *ws; 223 struct cache_ht_item_ *ht_item; 224 struct cache_ht_item_data_ *ht_item_data; 225 226 TRACE_IN(destroy_cache_entry); 227 assert(entry != NULL); 228 229 if (entry->params->entry_type == CET_COMMON) { 230 common_entry = (struct cache_common_entry_ *)entry; 231 232 HASHTABLE_FOREACH(&(common_entry->items), ht_item) { 233 HASHTABLE_ENTRY_FOREACH(ht_item, data, ht_item_data) 234 { 235 free(ht_item_data->key); 236 free(ht_item_data->value); 237 } 238 HASHTABLE_ENTRY_CLEAR(ht_item, data); 239 } 240 241 HASHTABLE_DESTROY(&(common_entry->items), data); 242 243 /* FIFO policy is always first */ 244 destroy_cache_fifo_policy(common_entry->policies[0]); 245 switch (common_entry->common_params.policy) { 246 case CPT_LRU: 247 destroy_cache_lru_policy(common_entry->policies[1]); 248 break; 249 case CPT_LFU: 250 destroy_cache_lfu_policy(common_entry->policies[1]); 251 break; 252 default: 253 break; 254 } 255 free(common_entry->policies); 256 } else { 257 mp_entry = (struct cache_mp_entry_ *)entry; 258 259 while (!TAILQ_EMPTY(&mp_entry->ws_head)) { 260 ws = TAILQ_FIRST(&mp_entry->ws_head); 261 TAILQ_REMOVE(&mp_entry->ws_head, ws, entries); 262 destroy_cache_mp_write_session(ws); 263 } 264 265 while (!TAILQ_EMPTY(&mp_entry->rs_head)) { 266 rs = TAILQ_FIRST(&mp_entry->rs_head); 267 TAILQ_REMOVE(&mp_entry->rs_head, rs, entries); 268 destroy_cache_mp_read_session(rs); 269 } 270 271 if (mp_entry->completed_write_session != NULL) 272 destroy_cache_mp_write_session( 273 mp_entry->completed_write_session); 274 275 if (mp_entry->pending_write_session != NULL) 276 destroy_cache_mp_write_session( 277 mp_entry->pending_write_session); 278 } 279 280 free(entry->name); 281 free(entry); 282 TRACE_OUT(destroy_cache_entry); 283} 284 285static void 286clear_cache_entry(struct cache_entry_ *entry) 287{ 288 struct cache_mp_entry_ *mp_entry; 289 struct cache_common_entry_ *common_entry; 290 struct cache_ht_item_ *ht_item; 291 struct cache_ht_item_data_ *ht_item_data; 292 struct cache_policy_ *policy; 293 struct cache_policy_item_ *item, *next_item; 294 size_t entry_size;
|
294 int i;
| 295 unsigned int i;
|
295 296 if (entry->params->entry_type == CET_COMMON) { 297 common_entry = (struct cache_common_entry_ *)entry; 298 299 entry_size = 0; 300 HASHTABLE_FOREACH(&(common_entry->items), ht_item) { 301 HASHTABLE_ENTRY_FOREACH(ht_item, data, ht_item_data) 302 { 303 free(ht_item_data->key); 304 free(ht_item_data->value); 305 } 306 entry_size += HASHTABLE_ENTRY_SIZE(ht_item, data); 307 HASHTABLE_ENTRY_CLEAR(ht_item, data); 308 } 309 310 common_entry->items_size -= entry_size; 311 for (i = 0; i < common_entry->policies_size; ++i) { 312 policy = common_entry->policies[i]; 313 314 next_item = NULL; 315 item = policy->get_first_item_func(policy); 316 while (item != NULL) { 317 next_item = policy->get_next_item_func(policy, 318 item); 319 policy->remove_item_func(policy, item); 320 policy->destroy_item_func(item); 321 item = next_item; 322 } 323 } 324 } else { 325 mp_entry = (struct cache_mp_entry_ *)entry; 326 327 if (mp_entry->rs_size == 0) { 328 if (mp_entry->completed_write_session != NULL) { 329 destroy_cache_mp_write_session( 330 mp_entry->completed_write_session); 331 mp_entry->completed_write_session = NULL; 332 } 333 334 memset(&mp_entry->creation_time, 0, 335 sizeof(struct timeval)); 336 memset(&mp_entry->last_request_time, 0, 337 sizeof(struct timeval)); 338 } 339 } 340} 341 342/* 343 * When passed to the flush_cache_policy, ensures that all old elements are 344 * deleted. 345 */ 346static int 347cache_lifetime_common_continue_func(struct cache_common_entry_ *entry, 348 struct cache_policy_item_ *item) 349{ 350 351 return ((item->last_request_time.tv_sec - item->creation_time.tv_sec > 352 entry->common_params.max_lifetime.tv_sec) ? 1: 0); 353} 354 355/* 356 * When passed to the flush_cache_policy, ensures that all elements, that 357 * exceed the size limit, are deleted. 358 */ 359static int 360cache_elemsize_common_continue_func(struct cache_common_entry_ *entry, 361 struct cache_policy_item_ *item) 362{ 363 364 return ((entry->items_size > entry->common_params.satisf_elemsize) ? 1 365 : 0); 366} 367 368/* 369 * Removes the elements from the cache entry, while the continue_func returns 1. 370 */ 371static void 372flush_cache_policy(struct cache_common_entry_ *entry, 373 struct cache_policy_ *policy, 374 struct cache_policy_ *connected_policy, 375 int (*continue_func)(struct cache_common_entry_ *, 376 struct cache_policy_item_ *)) 377{ 378 struct cache_policy_item_ *item, *next_item, *connected_item; 379 struct cache_ht_item_ *ht_item; 380 struct cache_ht_item_data_ *ht_item_data, ht_key; 381 hashtable_index_t hash; 382 383 assert(policy != NULL); 384 385 next_item = NULL; 386 item = policy->get_first_item_func(policy); 387 while ((item != NULL) && (continue_func(entry, item) == 1)) { 388 next_item = policy->get_next_item_func(policy, item); 389 390 connected_item = item->connected_item; 391 policy->remove_item_func(policy, item); 392 393 memset(&ht_key, 0, sizeof(struct cache_ht_item_data_)); 394 ht_key.key = item->key; 395 ht_key.key_size = item->key_size; 396 397 hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &entry->items, 398 &ht_key);
| 296 297 if (entry->params->entry_type == CET_COMMON) { 298 common_entry = (struct cache_common_entry_ *)entry; 299 300 entry_size = 0; 301 HASHTABLE_FOREACH(&(common_entry->items), ht_item) { 302 HASHTABLE_ENTRY_FOREACH(ht_item, data, ht_item_data) 303 { 304 free(ht_item_data->key); 305 free(ht_item_data->value); 306 } 307 entry_size += HASHTABLE_ENTRY_SIZE(ht_item, data); 308 HASHTABLE_ENTRY_CLEAR(ht_item, data); 309 } 310 311 common_entry->items_size -= entry_size; 312 for (i = 0; i < common_entry->policies_size; ++i) { 313 policy = common_entry->policies[i]; 314 315 next_item = NULL; 316 item = policy->get_first_item_func(policy); 317 while (item != NULL) { 318 next_item = policy->get_next_item_func(policy, 319 item); 320 policy->remove_item_func(policy, item); 321 policy->destroy_item_func(item); 322 item = next_item; 323 } 324 } 325 } else { 326 mp_entry = (struct cache_mp_entry_ *)entry; 327 328 if (mp_entry->rs_size == 0) { 329 if (mp_entry->completed_write_session != NULL) { 330 destroy_cache_mp_write_session( 331 mp_entry->completed_write_session); 332 mp_entry->completed_write_session = NULL; 333 } 334 335 memset(&mp_entry->creation_time, 0, 336 sizeof(struct timeval)); 337 memset(&mp_entry->last_request_time, 0, 338 sizeof(struct timeval)); 339 } 340 } 341} 342 343/* 344 * When passed to the flush_cache_policy, ensures that all old elements are 345 * deleted. 346 */ 347static int 348cache_lifetime_common_continue_func(struct cache_common_entry_ *entry, 349 struct cache_policy_item_ *item) 350{ 351 352 return ((item->last_request_time.tv_sec - item->creation_time.tv_sec > 353 entry->common_params.max_lifetime.tv_sec) ? 1: 0); 354} 355 356/* 357 * When passed to the flush_cache_policy, ensures that all elements, that 358 * exceed the size limit, are deleted. 359 */ 360static int 361cache_elemsize_common_continue_func(struct cache_common_entry_ *entry, 362 struct cache_policy_item_ *item) 363{ 364 365 return ((entry->items_size > entry->common_params.satisf_elemsize) ? 1 366 : 0); 367} 368 369/* 370 * Removes the elements from the cache entry, while the continue_func returns 1. 371 */ 372static void 373flush_cache_policy(struct cache_common_entry_ *entry, 374 struct cache_policy_ *policy, 375 struct cache_policy_ *connected_policy, 376 int (*continue_func)(struct cache_common_entry_ *, 377 struct cache_policy_item_ *)) 378{ 379 struct cache_policy_item_ *item, *next_item, *connected_item; 380 struct cache_ht_item_ *ht_item; 381 struct cache_ht_item_data_ *ht_item_data, ht_key; 382 hashtable_index_t hash; 383 384 assert(policy != NULL); 385 386 next_item = NULL; 387 item = policy->get_first_item_func(policy); 388 while ((item != NULL) && (continue_func(entry, item) == 1)) { 389 next_item = policy->get_next_item_func(policy, item); 390 391 connected_item = item->connected_item; 392 policy->remove_item_func(policy, item); 393 394 memset(&ht_key, 0, sizeof(struct cache_ht_item_data_)); 395 ht_key.key = item->key; 396 ht_key.key_size = item->key_size; 397 398 hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &entry->items, 399 &ht_key);
|
399 assert(hash >= 0);
| |
400 assert(hash < HASHTABLE_ENTRIES_COUNT(&entry->items)); 401 402 ht_item = HASHTABLE_GET_ENTRY(&(entry->items), hash); 403 ht_item_data = HASHTABLE_ENTRY_FIND(cache_ht_, ht_item, 404 &ht_key); 405 assert(ht_item_data != NULL); 406 free(ht_item_data->key); 407 free(ht_item_data->value); 408 HASHTABLE_ENTRY_REMOVE(cache_ht_, ht_item, ht_item_data); 409 --entry->items_size; 410 411 policy->destroy_item_func(item); 412 413 if (connected_item != NULL) { 414 connected_policy->remove_item_func(connected_policy, 415 connected_item); 416 connected_policy->destroy_item_func(connected_item); 417 } 418 419 item = next_item; 420 } 421} 422 423static void 424flush_cache_entry(struct cache_entry_ *entry) 425{ 426 struct cache_mp_entry_ *mp_entry; 427 struct cache_common_entry_ *common_entry; 428 struct cache_policy_ *policy, *connected_policy; 429 430 connected_policy = NULL; 431 if (entry->params->entry_type == CET_COMMON) { 432 common_entry = (struct cache_common_entry_ *)entry; 433 if ((common_entry->common_params.max_lifetime.tv_sec != 0) || 434 (common_entry->common_params.max_lifetime.tv_usec != 0)) { 435 436 policy = common_entry->policies[0]; 437 if (common_entry->policies_size > 1) 438 connected_policy = common_entry->policies[1]; 439 440 flush_cache_policy(common_entry, policy, 441 connected_policy, 442 cache_lifetime_common_continue_func); 443 } 444 445 446 if ((common_entry->common_params.max_elemsize != 0) && 447 common_entry->items_size > 448 common_entry->common_params.max_elemsize) { 449 450 if (common_entry->policies_size > 1) { 451 policy = common_entry->policies[1]; 452 connected_policy = common_entry->policies[0]; 453 } else { 454 policy = common_entry->policies[0]; 455 connected_policy = NULL; 456 } 457 458 flush_cache_policy(common_entry, policy, 459 connected_policy, 460 cache_elemsize_common_continue_func); 461 } 462 } else { 463 mp_entry = (struct cache_mp_entry_ *)entry; 464 465 if ((mp_entry->mp_params.max_lifetime.tv_sec != 0) 466 || (mp_entry->mp_params.max_lifetime.tv_usec != 0)) { 467 468 if (mp_entry->last_request_time.tv_sec - 469 mp_entry->last_request_time.tv_sec > 470 mp_entry->mp_params.max_lifetime.tv_sec) 471 clear_cache_entry(entry); 472 } 473 } 474} 475 476struct cache_ * 477init_cache(struct cache_params const *params) 478{ 479 struct cache_ *retval; 480 481 TRACE_IN(init_cache); 482 assert(params != NULL); 483 484 retval = (struct cache_ *)calloc(1, sizeof(struct cache_)); 485 assert(retval != NULL); 486 487 assert(params != NULL); 488 memcpy(&retval->params, params, sizeof(struct cache_params)); 489 490 retval->entries = (struct cache_entry_ **)calloc(1, 491 sizeof(struct cache_entry_ *) * INITIAL_ENTRIES_CAPACITY); 492 assert(retval->entries != NULL); 493 494 retval->entries_capacity = INITIAL_ENTRIES_CAPACITY; 495 retval->entries_size = 0; 496 497 TRACE_OUT(init_cache); 498 return (retval); 499} 500 501void 502destroy_cache(struct cache_ *the_cache) 503{ 504 505 TRACE_IN(destroy_cache); 506 assert(the_cache != NULL); 507 508 if (the_cache->entries != NULL) { 509 size_t i; 510 for (i = 0; i < the_cache->entries_size; ++i) 511 destroy_cache_entry(the_cache->entries[i]); 512 513 free(the_cache->entries); 514 } 515 516 free(the_cache); 517 TRACE_OUT(destroy_cache); 518} 519 520int 521register_cache_entry(struct cache_ *the_cache, 522 struct cache_entry_params const *params) 523{ 524 int policies_size; 525 size_t entry_name_size; 526 struct cache_common_entry_ *new_common_entry; 527 struct cache_mp_entry_ *new_mp_entry; 528 529 TRACE_IN(register_cache_entry); 530 assert(the_cache != NULL); 531 532 if (find_cache_entry(the_cache, params->entry_name) != NULL) { 533 TRACE_OUT(register_cache_entry); 534 return (-1); 535 } 536 537 if (the_cache->entries_size == the_cache->entries_capacity) { 538 struct cache_entry_ **new_entries; 539 size_t new_capacity; 540 541 new_capacity = the_cache->entries_capacity + 542 ENTRIES_CAPACITY_STEP; 543 new_entries = (struct cache_entry_ **)calloc(1, 544 sizeof(struct cache_entry_ *) * new_capacity); 545 assert(new_entries != NULL); 546 547 memcpy(new_entries, the_cache->entries, 548 sizeof(struct cache_entry_ *) 549 * the_cache->entries_size); 550 551 free(the_cache->entries); 552 the_cache->entries = new_entries; 553 } 554 555 entry_name_size = strlen(params->entry_name) + 1; 556 switch (params->entry_type) 557 { 558 case CET_COMMON: 559 new_common_entry = (struct cache_common_entry_ *)calloc(1, 560 sizeof(struct cache_common_entry_)); 561 assert(new_common_entry != NULL); 562 563 memcpy(&new_common_entry->common_params, params, 564 sizeof(struct common_cache_entry_params)); 565 new_common_entry->params = 566 (struct cache_entry_params *)&new_common_entry->common_params; 567 568 new_common_entry->common_params.entry_name = (char *)calloc(1, 569 entry_name_size); 570 assert(new_common_entry->common_params.entry_name != NULL); 571 strlcpy(new_common_entry->common_params.entry_name, 572 params->entry_name, entry_name_size); 573 new_common_entry->name = 574 new_common_entry->common_params.entry_name; 575 576 HASHTABLE_INIT(&(new_common_entry->items), 577 struct cache_ht_item_data_, data, 578 new_common_entry->common_params.cache_entries_size); 579 580 if (new_common_entry->common_params.policy == CPT_FIFO) 581 policies_size = 1; 582 else 583 policies_size = 2; 584 585 new_common_entry->policies = (struct cache_policy_ **)calloc(1, 586 sizeof(struct cache_policy_ *) * policies_size); 587 assert(new_common_entry->policies != NULL); 588 589 new_common_entry->policies_size = policies_size; 590 new_common_entry->policies[0] = init_cache_fifo_policy(); 591 592 if (policies_size > 1) { 593 switch (new_common_entry->common_params.policy) { 594 case CPT_LRU: 595 new_common_entry->policies[1] = 596 init_cache_lru_policy(); 597 break; 598 case CPT_LFU: 599 new_common_entry->policies[1] = 600 init_cache_lfu_policy(); 601 break; 602 default: 603 break; 604 } 605 } 606 607 new_common_entry->get_time_func = 608 the_cache->params.get_time_func; 609 the_cache->entries[the_cache->entries_size++] = 610 (struct cache_entry_ *)new_common_entry; 611 break; 612 case CET_MULTIPART: 613 new_mp_entry = (struct cache_mp_entry_ *)calloc(1, 614 sizeof(struct cache_mp_entry_)); 615 assert(new_mp_entry != NULL); 616 617 memcpy(&new_mp_entry->mp_params, params, 618 sizeof(struct mp_cache_entry_params)); 619 new_mp_entry->params = 620 (struct cache_entry_params *)&new_mp_entry->mp_params; 621 622 new_mp_entry->mp_params.entry_name = (char *)calloc(1, 623 entry_name_size); 624 assert(new_mp_entry->mp_params.entry_name != NULL); 625 strlcpy(new_mp_entry->mp_params.entry_name, params->entry_name, 626 entry_name_size); 627 new_mp_entry->name = new_mp_entry->mp_params.entry_name; 628 629 TAILQ_INIT(&new_mp_entry->ws_head); 630 TAILQ_INIT(&new_mp_entry->rs_head); 631 632 new_mp_entry->get_time_func = the_cache->params.get_time_func; 633 the_cache->entries[the_cache->entries_size++] = 634 (struct cache_entry_ *)new_mp_entry; 635 break; 636 } 637 638 639 qsort(the_cache->entries, the_cache->entries_size, 640 sizeof(struct cache_entry_ *), entries_qsort_cmp_func); 641 642 TRACE_OUT(register_cache_entry); 643 return (0); 644} 645 646int 647unregister_cache_entry(struct cache_ *the_cache, const char *entry_name) 648{ 649 struct cache_entry_ **del_ent; 650 651 TRACE_IN(unregister_cache_entry); 652 assert(the_cache != NULL); 653 654 del_ent = find_cache_entry_p(the_cache, entry_name); 655 if (del_ent != NULL) { 656 destroy_cache_entry(*del_ent); 657 --the_cache->entries_size; 658 659 memmove(del_ent, del_ent + 1, 660 (&(the_cache->entries[--the_cache->entries_size]) - 661 del_ent) * sizeof(struct cache_entry_ *)); 662 663 TRACE_OUT(unregister_cache_entry); 664 return (0); 665 } else { 666 TRACE_OUT(unregister_cache_entry); 667 return (-1); 668 } 669} 670 671struct cache_entry_ * 672find_cache_entry(struct cache_ *the_cache, const char *entry_name) 673{ 674 struct cache_entry_ **result; 675 676 TRACE_IN(find_cache_entry); 677 result = find_cache_entry_p(the_cache, entry_name); 678 679 if (result == NULL) { 680 TRACE_OUT(find_cache_entry); 681 return (NULL); 682 } else { 683 TRACE_OUT(find_cache_entry); 684 return (*result); 685 } 686} 687 688/* 689 * Tries to read the element with the specified key from the cache. If the 690 * value_size is too small, it will be filled with the proper number, and 691 * the user will need to call cache_read again with the value buffer, that 692 * is large enough. 693 * Function returns 0 on success, -1 on error, and -2 if the value_size is too 694 * small. 695 */ 696int 697cache_read(struct cache_entry_ *entry, const char *key, size_t key_size, 698 char *value, size_t *value_size) 699{ 700 struct cache_common_entry_ *common_entry; 701 struct cache_ht_item_data_ item_data, *find_res; 702 struct cache_ht_item_ *item; 703 hashtable_index_t hash; 704 struct cache_policy_item_ *connected_item; 705 706 TRACE_IN(cache_read); 707 assert(entry != NULL); 708 assert(key != NULL); 709 assert(value_size != NULL); 710 assert(entry->params->entry_type == CET_COMMON); 711 712 common_entry = (struct cache_common_entry_ *)entry; 713 714 memset(&item_data, 0, sizeof(struct cache_ht_item_data_)); 715 /* can't avoid the cast here */ 716 item_data.key = (char *)key; 717 item_data.key_size = key_size; 718 719 hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &common_entry->items, 720 &item_data);
| 400 assert(hash < HASHTABLE_ENTRIES_COUNT(&entry->items)); 401 402 ht_item = HASHTABLE_GET_ENTRY(&(entry->items), hash); 403 ht_item_data = HASHTABLE_ENTRY_FIND(cache_ht_, ht_item, 404 &ht_key); 405 assert(ht_item_data != NULL); 406 free(ht_item_data->key); 407 free(ht_item_data->value); 408 HASHTABLE_ENTRY_REMOVE(cache_ht_, ht_item, ht_item_data); 409 --entry->items_size; 410 411 policy->destroy_item_func(item); 412 413 if (connected_item != NULL) { 414 connected_policy->remove_item_func(connected_policy, 415 connected_item); 416 connected_policy->destroy_item_func(connected_item); 417 } 418 419 item = next_item; 420 } 421} 422 423static void 424flush_cache_entry(struct cache_entry_ *entry) 425{ 426 struct cache_mp_entry_ *mp_entry; 427 struct cache_common_entry_ *common_entry; 428 struct cache_policy_ *policy, *connected_policy; 429 430 connected_policy = NULL; 431 if (entry->params->entry_type == CET_COMMON) { 432 common_entry = (struct cache_common_entry_ *)entry; 433 if ((common_entry->common_params.max_lifetime.tv_sec != 0) || 434 (common_entry->common_params.max_lifetime.tv_usec != 0)) { 435 436 policy = common_entry->policies[0]; 437 if (common_entry->policies_size > 1) 438 connected_policy = common_entry->policies[1]; 439 440 flush_cache_policy(common_entry, policy, 441 connected_policy, 442 cache_lifetime_common_continue_func); 443 } 444 445 446 if ((common_entry->common_params.max_elemsize != 0) && 447 common_entry->items_size > 448 common_entry->common_params.max_elemsize) { 449 450 if (common_entry->policies_size > 1) { 451 policy = common_entry->policies[1]; 452 connected_policy = common_entry->policies[0]; 453 } else { 454 policy = common_entry->policies[0]; 455 connected_policy = NULL; 456 } 457 458 flush_cache_policy(common_entry, policy, 459 connected_policy, 460 cache_elemsize_common_continue_func); 461 } 462 } else { 463 mp_entry = (struct cache_mp_entry_ *)entry; 464 465 if ((mp_entry->mp_params.max_lifetime.tv_sec != 0) 466 || (mp_entry->mp_params.max_lifetime.tv_usec != 0)) { 467 468 if (mp_entry->last_request_time.tv_sec - 469 mp_entry->last_request_time.tv_sec > 470 mp_entry->mp_params.max_lifetime.tv_sec) 471 clear_cache_entry(entry); 472 } 473 } 474} 475 476struct cache_ * 477init_cache(struct cache_params const *params) 478{ 479 struct cache_ *retval; 480 481 TRACE_IN(init_cache); 482 assert(params != NULL); 483 484 retval = (struct cache_ *)calloc(1, sizeof(struct cache_)); 485 assert(retval != NULL); 486 487 assert(params != NULL); 488 memcpy(&retval->params, params, sizeof(struct cache_params)); 489 490 retval->entries = (struct cache_entry_ **)calloc(1, 491 sizeof(struct cache_entry_ *) * INITIAL_ENTRIES_CAPACITY); 492 assert(retval->entries != NULL); 493 494 retval->entries_capacity = INITIAL_ENTRIES_CAPACITY; 495 retval->entries_size = 0; 496 497 TRACE_OUT(init_cache); 498 return (retval); 499} 500 501void 502destroy_cache(struct cache_ *the_cache) 503{ 504 505 TRACE_IN(destroy_cache); 506 assert(the_cache != NULL); 507 508 if (the_cache->entries != NULL) { 509 size_t i; 510 for (i = 0; i < the_cache->entries_size; ++i) 511 destroy_cache_entry(the_cache->entries[i]); 512 513 free(the_cache->entries); 514 } 515 516 free(the_cache); 517 TRACE_OUT(destroy_cache); 518} 519 520int 521register_cache_entry(struct cache_ *the_cache, 522 struct cache_entry_params const *params) 523{ 524 int policies_size; 525 size_t entry_name_size; 526 struct cache_common_entry_ *new_common_entry; 527 struct cache_mp_entry_ *new_mp_entry; 528 529 TRACE_IN(register_cache_entry); 530 assert(the_cache != NULL); 531 532 if (find_cache_entry(the_cache, params->entry_name) != NULL) { 533 TRACE_OUT(register_cache_entry); 534 return (-1); 535 } 536 537 if (the_cache->entries_size == the_cache->entries_capacity) { 538 struct cache_entry_ **new_entries; 539 size_t new_capacity; 540 541 new_capacity = the_cache->entries_capacity + 542 ENTRIES_CAPACITY_STEP; 543 new_entries = (struct cache_entry_ **)calloc(1, 544 sizeof(struct cache_entry_ *) * new_capacity); 545 assert(new_entries != NULL); 546 547 memcpy(new_entries, the_cache->entries, 548 sizeof(struct cache_entry_ *) 549 * the_cache->entries_size); 550 551 free(the_cache->entries); 552 the_cache->entries = new_entries; 553 } 554 555 entry_name_size = strlen(params->entry_name) + 1; 556 switch (params->entry_type) 557 { 558 case CET_COMMON: 559 new_common_entry = (struct cache_common_entry_ *)calloc(1, 560 sizeof(struct cache_common_entry_)); 561 assert(new_common_entry != NULL); 562 563 memcpy(&new_common_entry->common_params, params, 564 sizeof(struct common_cache_entry_params)); 565 new_common_entry->params = 566 (struct cache_entry_params *)&new_common_entry->common_params; 567 568 new_common_entry->common_params.entry_name = (char *)calloc(1, 569 entry_name_size); 570 assert(new_common_entry->common_params.entry_name != NULL); 571 strlcpy(new_common_entry->common_params.entry_name, 572 params->entry_name, entry_name_size); 573 new_common_entry->name = 574 new_common_entry->common_params.entry_name; 575 576 HASHTABLE_INIT(&(new_common_entry->items), 577 struct cache_ht_item_data_, data, 578 new_common_entry->common_params.cache_entries_size); 579 580 if (new_common_entry->common_params.policy == CPT_FIFO) 581 policies_size = 1; 582 else 583 policies_size = 2; 584 585 new_common_entry->policies = (struct cache_policy_ **)calloc(1, 586 sizeof(struct cache_policy_ *) * policies_size); 587 assert(new_common_entry->policies != NULL); 588 589 new_common_entry->policies_size = policies_size; 590 new_common_entry->policies[0] = init_cache_fifo_policy(); 591 592 if (policies_size > 1) { 593 switch (new_common_entry->common_params.policy) { 594 case CPT_LRU: 595 new_common_entry->policies[1] = 596 init_cache_lru_policy(); 597 break; 598 case CPT_LFU: 599 new_common_entry->policies[1] = 600 init_cache_lfu_policy(); 601 break; 602 default: 603 break; 604 } 605 } 606 607 new_common_entry->get_time_func = 608 the_cache->params.get_time_func; 609 the_cache->entries[the_cache->entries_size++] = 610 (struct cache_entry_ *)new_common_entry; 611 break; 612 case CET_MULTIPART: 613 new_mp_entry = (struct cache_mp_entry_ *)calloc(1, 614 sizeof(struct cache_mp_entry_)); 615 assert(new_mp_entry != NULL); 616 617 memcpy(&new_mp_entry->mp_params, params, 618 sizeof(struct mp_cache_entry_params)); 619 new_mp_entry->params = 620 (struct cache_entry_params *)&new_mp_entry->mp_params; 621 622 new_mp_entry->mp_params.entry_name = (char *)calloc(1, 623 entry_name_size); 624 assert(new_mp_entry->mp_params.entry_name != NULL); 625 strlcpy(new_mp_entry->mp_params.entry_name, params->entry_name, 626 entry_name_size); 627 new_mp_entry->name = new_mp_entry->mp_params.entry_name; 628 629 TAILQ_INIT(&new_mp_entry->ws_head); 630 TAILQ_INIT(&new_mp_entry->rs_head); 631 632 new_mp_entry->get_time_func = the_cache->params.get_time_func; 633 the_cache->entries[the_cache->entries_size++] = 634 (struct cache_entry_ *)new_mp_entry; 635 break; 636 } 637 638 639 qsort(the_cache->entries, the_cache->entries_size, 640 sizeof(struct cache_entry_ *), entries_qsort_cmp_func); 641 642 TRACE_OUT(register_cache_entry); 643 return (0); 644} 645 646int 647unregister_cache_entry(struct cache_ *the_cache, const char *entry_name) 648{ 649 struct cache_entry_ **del_ent; 650 651 TRACE_IN(unregister_cache_entry); 652 assert(the_cache != NULL); 653 654 del_ent = find_cache_entry_p(the_cache, entry_name); 655 if (del_ent != NULL) { 656 destroy_cache_entry(*del_ent); 657 --the_cache->entries_size; 658 659 memmove(del_ent, del_ent + 1, 660 (&(the_cache->entries[--the_cache->entries_size]) - 661 del_ent) * sizeof(struct cache_entry_ *)); 662 663 TRACE_OUT(unregister_cache_entry); 664 return (0); 665 } else { 666 TRACE_OUT(unregister_cache_entry); 667 return (-1); 668 } 669} 670 671struct cache_entry_ * 672find_cache_entry(struct cache_ *the_cache, const char *entry_name) 673{ 674 struct cache_entry_ **result; 675 676 TRACE_IN(find_cache_entry); 677 result = find_cache_entry_p(the_cache, entry_name); 678 679 if (result == NULL) { 680 TRACE_OUT(find_cache_entry); 681 return (NULL); 682 } else { 683 TRACE_OUT(find_cache_entry); 684 return (*result); 685 } 686} 687 688/* 689 * Tries to read the element with the specified key from the cache. If the 690 * value_size is too small, it will be filled with the proper number, and 691 * the user will need to call cache_read again with the value buffer, that 692 * is large enough. 693 * Function returns 0 on success, -1 on error, and -2 if the value_size is too 694 * small. 695 */ 696int 697cache_read(struct cache_entry_ *entry, const char *key, size_t key_size, 698 char *value, size_t *value_size) 699{ 700 struct cache_common_entry_ *common_entry; 701 struct cache_ht_item_data_ item_data, *find_res; 702 struct cache_ht_item_ *item; 703 hashtable_index_t hash; 704 struct cache_policy_item_ *connected_item; 705 706 TRACE_IN(cache_read); 707 assert(entry != NULL); 708 assert(key != NULL); 709 assert(value_size != NULL); 710 assert(entry->params->entry_type == CET_COMMON); 711 712 common_entry = (struct cache_common_entry_ *)entry; 713 714 memset(&item_data, 0, sizeof(struct cache_ht_item_data_)); 715 /* can't avoid the cast here */ 716 item_data.key = (char *)key; 717 item_data.key_size = key_size; 718 719 hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &common_entry->items, 720 &item_data);
|
721 assert(hash >= 0);
| |
722 assert(hash < HASHTABLE_ENTRIES_COUNT(&common_entry->items)); 723 724 item = HASHTABLE_GET_ENTRY(&(common_entry->items), hash); 725 find_res = HASHTABLE_ENTRY_FIND(cache_ht_, item, &item_data); 726 if (find_res == NULL) { 727 TRACE_OUT(cache_read); 728 return (-1); 729 } 730 731 if ((common_entry->common_params.max_lifetime.tv_sec != 0) || 732 (common_entry->common_params.max_lifetime.tv_usec != 0)) { 733 734 if (find_res->fifo_policy_item->last_request_time.tv_sec - 735 find_res->fifo_policy_item->creation_time.tv_sec > 736 common_entry->common_params.max_lifetime.tv_sec) { 737 738 free(find_res->key); 739 free(find_res->value); 740 741 connected_item = 742 find_res->fifo_policy_item->connected_item; 743 if (connected_item != NULL) { 744 common_entry->policies[1]->remove_item_func( 745 common_entry->policies[1], 746 connected_item); 747 common_entry->policies[1]->destroy_item_func( 748 connected_item); 749 } 750 751 common_entry->policies[0]->remove_item_func( 752 common_entry->policies[0], 753 find_res->fifo_policy_item); 754 common_entry->policies[0]->destroy_item_func( 755 find_res->fifo_policy_item); 756 757 HASHTABLE_ENTRY_REMOVE(cache_ht_, item, find_res); 758 --common_entry->items_size; 759 } 760 } 761 762 if ((*value_size < find_res->value_size) || (value == NULL)) { 763 *value_size = find_res->value_size; 764 TRACE_OUT(cache_read); 765 return (-2); 766 } 767 768 *value_size = find_res->value_size; 769 memcpy(value, find_res->value, find_res->value_size); 770 771 ++find_res->fifo_policy_item->request_count; 772 common_entry->get_time_func( 773 &find_res->fifo_policy_item->last_request_time); 774 common_entry->policies[0]->update_item_func(common_entry->policies[0], 775 find_res->fifo_policy_item); 776 777 if (find_res->fifo_policy_item->connected_item != NULL) { 778 connected_item = find_res->fifo_policy_item->connected_item; 779 memcpy(&connected_item->last_request_time, 780 &find_res->fifo_policy_item->last_request_time, 781 sizeof(struct timeval)); 782 connected_item->request_count = 783 find_res->fifo_policy_item->request_count; 784 785 common_entry->policies[1]->update_item_func( 786 common_entry->policies[1], connected_item); 787 } 788 789 TRACE_OUT(cache_read); 790 return (0); 791} 792 793/* 794 * Writes the value with the specified key into the cache entry. 795 * Functions returns 0 on success, and -1 on error. 796 */ 797int 798cache_write(struct cache_entry_ *entry, const char *key, size_t key_size, 799 char const *value, size_t value_size) 800{ 801 struct cache_common_entry_ *common_entry; 802 struct cache_ht_item_data_ item_data, *find_res; 803 struct cache_ht_item_ *item; 804 hashtable_index_t hash; 805 806 struct cache_policy_ *policy, *connected_policy; 807 struct cache_policy_item_ *policy_item; 808 struct cache_policy_item_ *connected_policy_item; 809 810 TRACE_IN(cache_write); 811 assert(entry != NULL); 812 assert(key != NULL); 813 assert(value != NULL); 814 assert(entry->params->entry_type == CET_COMMON); 815 816 common_entry = (struct cache_common_entry_ *)entry; 817 818 memset(&item_data, 0, sizeof(struct cache_ht_item_data_)); 819 /* can't avoid the cast here */ 820 item_data.key = (char *)key; 821 item_data.key_size = key_size; 822 823 hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &common_entry->items, 824 &item_data);
| 721 assert(hash < HASHTABLE_ENTRIES_COUNT(&common_entry->items)); 722 723 item = HASHTABLE_GET_ENTRY(&(common_entry->items), hash); 724 find_res = HASHTABLE_ENTRY_FIND(cache_ht_, item, &item_data); 725 if (find_res == NULL) { 726 TRACE_OUT(cache_read); 727 return (-1); 728 } 729 730 if ((common_entry->common_params.max_lifetime.tv_sec != 0) || 731 (common_entry->common_params.max_lifetime.tv_usec != 0)) { 732 733 if (find_res->fifo_policy_item->last_request_time.tv_sec - 734 find_res->fifo_policy_item->creation_time.tv_sec > 735 common_entry->common_params.max_lifetime.tv_sec) { 736 737 free(find_res->key); 738 free(find_res->value); 739 740 connected_item = 741 find_res->fifo_policy_item->connected_item; 742 if (connected_item != NULL) { 743 common_entry->policies[1]->remove_item_func( 744 common_entry->policies[1], 745 connected_item); 746 common_entry->policies[1]->destroy_item_func( 747 connected_item); 748 } 749 750 common_entry->policies[0]->remove_item_func( 751 common_entry->policies[0], 752 find_res->fifo_policy_item); 753 common_entry->policies[0]->destroy_item_func( 754 find_res->fifo_policy_item); 755 756 HASHTABLE_ENTRY_REMOVE(cache_ht_, item, find_res); 757 --common_entry->items_size; 758 } 759 } 760 761 if ((*value_size < find_res->value_size) || (value == NULL)) { 762 *value_size = find_res->value_size; 763 TRACE_OUT(cache_read); 764 return (-2); 765 } 766 767 *value_size = find_res->value_size; 768 memcpy(value, find_res->value, find_res->value_size); 769 770 ++find_res->fifo_policy_item->request_count; 771 common_entry->get_time_func( 772 &find_res->fifo_policy_item->last_request_time); 773 common_entry->policies[0]->update_item_func(common_entry->policies[0], 774 find_res->fifo_policy_item); 775 776 if (find_res->fifo_policy_item->connected_item != NULL) { 777 connected_item = find_res->fifo_policy_item->connected_item; 778 memcpy(&connected_item->last_request_time, 779 &find_res->fifo_policy_item->last_request_time, 780 sizeof(struct timeval)); 781 connected_item->request_count = 782 find_res->fifo_policy_item->request_count; 783 784 common_entry->policies[1]->update_item_func( 785 common_entry->policies[1], connected_item); 786 } 787 788 TRACE_OUT(cache_read); 789 return (0); 790} 791 792/* 793 * Writes the value with the specified key into the cache entry. 794 * Functions returns 0 on success, and -1 on error. 795 */ 796int 797cache_write(struct cache_entry_ *entry, const char *key, size_t key_size, 798 char const *value, size_t value_size) 799{ 800 struct cache_common_entry_ *common_entry; 801 struct cache_ht_item_data_ item_data, *find_res; 802 struct cache_ht_item_ *item; 803 hashtable_index_t hash; 804 805 struct cache_policy_ *policy, *connected_policy; 806 struct cache_policy_item_ *policy_item; 807 struct cache_policy_item_ *connected_policy_item; 808 809 TRACE_IN(cache_write); 810 assert(entry != NULL); 811 assert(key != NULL); 812 assert(value != NULL); 813 assert(entry->params->entry_type == CET_COMMON); 814 815 common_entry = (struct cache_common_entry_ *)entry; 816 817 memset(&item_data, 0, sizeof(struct cache_ht_item_data_)); 818 /* can't avoid the cast here */ 819 item_data.key = (char *)key; 820 item_data.key_size = key_size; 821 822 hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &common_entry->items, 823 &item_data);
|
825 assert(hash >= 0);
| |
826 assert(hash < HASHTABLE_ENTRIES_COUNT(&common_entry->items)); 827 828 item = HASHTABLE_GET_ENTRY(&(common_entry->items), hash); 829 find_res = HASHTABLE_ENTRY_FIND(cache_ht_, item, &item_data); 830 if (find_res != NULL) { 831 TRACE_OUT(cache_write); 832 return (-1); 833 } 834 835 item_data.key = (char *)malloc(key_size); 836 memcpy(item_data.key, key, key_size); 837 838 item_data.value = (char *)malloc(value_size); 839 assert(item_data.value != NULL); 840 841 memcpy(item_data.value, value, value_size); 842 item_data.value_size = value_size; 843 844 policy_item = common_entry->policies[0]->create_item_func(); 845 policy_item->key = item_data.key; 846 policy_item->key_size = item_data.key_size; 847 common_entry->get_time_func(&policy_item->creation_time); 848 849 if (common_entry->policies_size > 1) { 850 connected_policy_item = 851 common_entry->policies[1]->create_item_func(); 852 memcpy(&connected_policy_item->creation_time, 853 &policy_item->creation_time, 854 sizeof(struct timeval)); 855 connected_policy_item->key = policy_item->key; 856 connected_policy_item->key_size = policy_item->key_size; 857 858 connected_policy_item->connected_item = policy_item; 859 policy_item->connected_item = connected_policy_item; 860 } 861 862 item_data.fifo_policy_item = policy_item; 863 864 common_entry->policies[0]->add_item_func(common_entry->policies[0], 865 policy_item); 866 if (common_entry->policies_size > 1) 867 common_entry->policies[1]->add_item_func( 868 common_entry->policies[1], connected_policy_item); 869 870 HASHTABLE_ENTRY_STORE(cache_ht_, item, &item_data); 871 ++common_entry->items_size; 872 873 if ((common_entry->common_params.max_elemsize != 0) && 874 (common_entry->items_size > 875 common_entry->common_params.max_elemsize)) { 876 if (common_entry->policies_size > 1) { 877 policy = common_entry->policies[1]; 878 connected_policy = common_entry->policies[0]; 879 } else { 880 policy = common_entry->policies[0]; 881 connected_policy = NULL; 882 } 883 884 flush_cache_policy(common_entry, policy, connected_policy, 885 cache_elemsize_common_continue_func); 886 } 887 888 TRACE_OUT(cache_write); 889 return (0); 890} 891 892/* 893 * Initializes the write session for the specified multipart entry. This 894 * session then should be filled with data either committed or abandoned by 895 * using close_cache_mp_write_session or abandon_cache_mp_write_session 896 * respectively. 897 * Returns NULL on errors (when there are too many opened write sessions for 898 * the entry). 899 */ 900struct cache_mp_write_session_ * 901open_cache_mp_write_session(struct cache_entry_ *entry) 902{ 903 struct cache_mp_entry_ *mp_entry; 904 struct cache_mp_write_session_ *retval; 905 906 TRACE_IN(open_cache_mp_write_session); 907 assert(entry != NULL); 908 assert(entry->params->entry_type == CET_MULTIPART); 909 mp_entry = (struct cache_mp_entry_ *)entry; 910 911 if ((mp_entry->mp_params.max_sessions > 0) && 912 (mp_entry->ws_size == mp_entry->mp_params.max_sessions)) { 913 TRACE_OUT(open_cache_mp_write_session); 914 return (NULL); 915 } 916 917 retval = (struct cache_mp_write_session_ *)calloc(1, 918 sizeof(struct cache_mp_write_session_)); 919 assert(retval != NULL); 920 921 TAILQ_INIT(&retval->items); 922 retval->parent_entry = mp_entry; 923 924 TAILQ_INSERT_HEAD(&mp_entry->ws_head, retval, entries); 925 ++mp_entry->ws_size; 926 927 TRACE_OUT(open_cache_mp_write_session); 928 return (retval); 929} 930 931/* 932 * Writes data to the specified session. Return 0 on success and -1 on errors 933 * (when write session size limit is exceeded). 934 */ 935int 936cache_mp_write(struct cache_mp_write_session_ *ws, char *data, 937 size_t data_size) 938{ 939 struct cache_mp_data_item_ *new_item; 940 941 TRACE_IN(cache_mp_write); 942 assert(ws != NULL); 943 assert(ws->parent_entry != NULL); 944 assert(ws->parent_entry->params->entry_type == CET_MULTIPART); 945 946 if ((ws->parent_entry->mp_params.max_elemsize > 0) && 947 (ws->parent_entry->mp_params.max_elemsize == ws->items_size)) { 948 TRACE_OUT(cache_mp_write); 949 return (-1); 950 } 951 952 new_item = (struct cache_mp_data_item_ *)calloc(1, 953 sizeof(struct cache_mp_data_item_)); 954 assert(new_item != NULL); 955 956 new_item->value = (char *)malloc(data_size); 957 assert(new_item->value != NULL); 958 memcpy(new_item->value, data, data_size); 959 new_item->value_size = data_size; 960 961 TAILQ_INSERT_TAIL(&ws->items, new_item, entries); 962 ++ws->items_size; 963 964 TRACE_OUT(cache_mp_write); 965 return (0); 966} 967 968/* 969 * Abandons the write session and frees all the connected resources. 970 */ 971void 972abandon_cache_mp_write_session(struct cache_mp_write_session_ *ws) 973{ 974 975 TRACE_IN(abandon_cache_mp_write_session); 976 assert(ws != NULL); 977 assert(ws->parent_entry != NULL); 978 assert(ws->parent_entry->params->entry_type == CET_MULTIPART); 979 980 TAILQ_REMOVE(&ws->parent_entry->ws_head, ws, entries); 981 --ws->parent_entry->ws_size; 982 983 destroy_cache_mp_write_session(ws); 984 TRACE_OUT(abandon_cache_mp_write_session); 985} 986 987/* 988 * Commits the session to the entry, for which it was created. 989 */ 990void 991close_cache_mp_write_session(struct cache_mp_write_session_ *ws) 992{ 993 994 TRACE_IN(close_cache_mp_write_session); 995 assert(ws != NULL); 996 assert(ws->parent_entry != NULL); 997 assert(ws->parent_entry->params->entry_type == CET_MULTIPART); 998 999 TAILQ_REMOVE(&ws->parent_entry->ws_head, ws, entries); 1000 --ws->parent_entry->ws_size; 1001 1002 if (ws->parent_entry->completed_write_session == NULL) { 1003 /* 1004 * If there is no completed session yet, this will be the one 1005 */ 1006 ws->parent_entry->get_time_func( 1007 &ws->parent_entry->creation_time); 1008 ws->parent_entry->completed_write_session = ws; 1009 } else { 1010 /* 1011 * If there is a completed session, then we'll save our session 1012 * as a pending session. If there is already a pending session, 1013 * it would be destroyed. 1014 */ 1015 if (ws->parent_entry->pending_write_session != NULL) 1016 destroy_cache_mp_write_session( 1017 ws->parent_entry->pending_write_session); 1018 1019 ws->parent_entry->pending_write_session = ws; 1020 } 1021 TRACE_OUT(close_cache_mp_write_session); 1022} 1023 1024/* 1025 * Opens read session for the specified entry. Returns NULL on errors (when 1026 * there are no data in the entry, or the data are obsolete). 1027 */ 1028struct cache_mp_read_session_ * 1029open_cache_mp_read_session(struct cache_entry_ *entry) 1030{ 1031 struct cache_mp_entry_ *mp_entry; 1032 struct cache_mp_read_session_ *retval; 1033 1034 TRACE_IN(open_cache_mp_read_session); 1035 assert(entry != NULL); 1036 assert(entry->params->entry_type == CET_MULTIPART); 1037 mp_entry = (struct cache_mp_entry_ *)entry; 1038 1039 if (mp_entry->completed_write_session == NULL) { 1040 TRACE_OUT(open_cache_mp_read_session); 1041 return (NULL); 1042 } 1043 1044 if ((mp_entry->mp_params.max_lifetime.tv_sec != 0) 1045 || (mp_entry->mp_params.max_lifetime.tv_usec != 0)) { 1046 if (mp_entry->last_request_time.tv_sec - 1047 mp_entry->last_request_time.tv_sec > 1048 mp_entry->mp_params.max_lifetime.tv_sec) { 1049 flush_cache_entry(entry); 1050 TRACE_OUT(open_cache_mp_read_session); 1051 return (NULL); 1052 } 1053 } 1054 1055 retval = (struct cache_mp_read_session_ *)calloc(1, 1056 sizeof(struct cache_mp_read_session_)); 1057 assert(retval != NULL); 1058 1059 retval->parent_entry = mp_entry; 1060 retval->current_item = TAILQ_FIRST( 1061 &mp_entry->completed_write_session->items); 1062 1063 TAILQ_INSERT_HEAD(&mp_entry->rs_head, retval, entries); 1064 ++mp_entry->rs_size; 1065 1066 mp_entry->get_time_func(&mp_entry->last_request_time); 1067 TRACE_OUT(open_cache_mp_read_session); 1068 return (retval); 1069} 1070 1071/* 1072 * Reads the data from the read session - step by step. 1073 * Returns 0 on success, -1 on error (when there are no more data), and -2 if 1074 * the data_size is too small. In the last case, data_size would be filled 1075 * the proper value. 1076 */ 1077int 1078cache_mp_read(struct cache_mp_read_session_ *rs, char *data, size_t *data_size) 1079{ 1080 1081 TRACE_IN(cache_mp_read); 1082 assert(rs != NULL); 1083 1084 if (rs->current_item == NULL) { 1085 TRACE_OUT(cache_mp_read); 1086 return (-1); 1087 } 1088 1089 if (rs->current_item->value_size > *data_size) { 1090 *data_size = rs->current_item->value_size; 1091 if (data == NULL) { 1092 TRACE_OUT(cache_mp_read); 1093 return (0); 1094 } 1095 1096 TRACE_OUT(cache_mp_read); 1097 return (-2); 1098 } 1099 1100 *data_size = rs->current_item->value_size; 1101 memcpy(data, rs->current_item->value, rs->current_item->value_size); 1102 rs->current_item = TAILQ_NEXT(rs->current_item, entries); 1103 1104 TRACE_OUT(cache_mp_read); 1105 return (0); 1106} 1107 1108/* 1109 * Closes the read session. If there are no more read sessions and there is 1110 * a pending write session, it will be committed and old 1111 * completed_write_session will be destroyed. 1112 */ 1113void 1114close_cache_mp_read_session(struct cache_mp_read_session_ *rs) 1115{ 1116 1117 TRACE_IN(close_cache_mp_read_session); 1118 assert(rs != NULL); 1119 assert(rs->parent_entry != NULL); 1120 1121 TAILQ_REMOVE(&rs->parent_entry->rs_head, rs, entries); 1122 --rs->parent_entry->rs_size; 1123 1124 if ((rs->parent_entry->rs_size == 0) && 1125 (rs->parent_entry->pending_write_session != NULL)) { 1126 destroy_cache_mp_write_session( 1127 rs->parent_entry->completed_write_session); 1128 rs->parent_entry->completed_write_session = 1129 rs->parent_entry->pending_write_session; 1130 rs->parent_entry->pending_write_session = NULL; 1131 } 1132 1133 destroy_cache_mp_read_session(rs); 1134 TRACE_OUT(close_cache_mp_read_session); 1135} 1136 1137int 1138transform_cache_entry(struct cache_entry_ *entry, 1139 enum cache_transformation_t transformation) 1140{ 1141 1142 TRACE_IN(transform_cache_entry); 1143 switch (transformation) { 1144 case CTT_CLEAR: 1145 clear_cache_entry(entry); 1146 TRACE_OUT(transform_cache_entry); 1147 return (0); 1148 case CTT_FLUSH: 1149 flush_cache_entry(entry); 1150 TRACE_OUT(transform_cache_entry); 1151 return (0); 1152 default: 1153 TRACE_OUT(transform_cache_entry); 1154 return (-1); 1155 } 1156} 1157 1158int 1159transform_cache_entry_part(struct cache_entry_ *entry, 1160 enum cache_transformation_t transformation, const char *key_part, 1161 size_t key_part_size, enum part_position_t part_position) 1162{ 1163 struct cache_common_entry_ *common_entry; 1164 struct cache_ht_item_ *ht_item; 1165 struct cache_ht_item_data_ *ht_item_data, ht_key; 1166 1167 struct cache_policy_item_ *item, *connected_item; 1168 1169 TRACE_IN(transform_cache_entry_part); 1170 if (entry->params->entry_type != CET_COMMON) { 1171 TRACE_OUT(transform_cache_entry_part); 1172 return (-1); 1173 } 1174 1175 if (transformation != CTT_CLEAR) { 1176 TRACE_OUT(transform_cache_entry_part); 1177 return (-1); 1178 } 1179 1180 memset(&ht_key, 0, sizeof(struct cache_ht_item_data_)); 1181 ht_key.key = (char *)key_part; /* can't avoid casting here */ 1182 ht_key.key_size = key_part_size; 1183 1184 common_entry = (struct cache_common_entry_ *)entry; 1185 HASHTABLE_FOREACH(&(common_entry->items), ht_item) { 1186 do { 1187 ht_item_data = HASHTABLE_ENTRY_FIND_SPECIAL(cache_ht_, 1188 ht_item, &ht_key, 1189 ht_items_fixed_size_left_cmp_func); 1190 1191 if (ht_item_data != NULL) { 1192 item = ht_item_data->fifo_policy_item; 1193 connected_item = item->connected_item; 1194 1195 common_entry->policies[0]->remove_item_func( 1196 common_entry->policies[0], 1197 item); 1198 1199 free(ht_item_data->key); 1200 free(ht_item_data->value); 1201 HASHTABLE_ENTRY_REMOVE(cache_ht_, ht_item, 1202 ht_item_data); 1203 --common_entry->items_size; 1204 1205 common_entry->policies[0]->destroy_item_func( 1206 item); 1207 if (common_entry->policies_size == 2) { 1208 common_entry->policies[1]->remove_item_func( 1209 common_entry->policies[1], 1210 connected_item); 1211 common_entry->policies[1]->destroy_item_func( 1212 connected_item); 1213 } 1214 } 1215 } while (ht_item_data != NULL); 1216 } 1217 1218 TRACE_OUT(transform_cache_entry_part); 1219 return (0); 1220}
| 824 assert(hash < HASHTABLE_ENTRIES_COUNT(&common_entry->items)); 825 826 item = HASHTABLE_GET_ENTRY(&(common_entry->items), hash); 827 find_res = HASHTABLE_ENTRY_FIND(cache_ht_, item, &item_data); 828 if (find_res != NULL) { 829 TRACE_OUT(cache_write); 830 return (-1); 831 } 832 833 item_data.key = (char *)malloc(key_size); 834 memcpy(item_data.key, key, key_size); 835 836 item_data.value = (char *)malloc(value_size); 837 assert(item_data.value != NULL); 838 839 memcpy(item_data.value, value, value_size); 840 item_data.value_size = value_size; 841 842 policy_item = common_entry->policies[0]->create_item_func(); 843 policy_item->key = item_data.key; 844 policy_item->key_size = item_data.key_size; 845 common_entry->get_time_func(&policy_item->creation_time); 846 847 if (common_entry->policies_size > 1) { 848 connected_policy_item = 849 common_entry->policies[1]->create_item_func(); 850 memcpy(&connected_policy_item->creation_time, 851 &policy_item->creation_time, 852 sizeof(struct timeval)); 853 connected_policy_item->key = policy_item->key; 854 connected_policy_item->key_size = policy_item->key_size; 855 856 connected_policy_item->connected_item = policy_item; 857 policy_item->connected_item = connected_policy_item; 858 } 859 860 item_data.fifo_policy_item = policy_item; 861 862 common_entry->policies[0]->add_item_func(common_entry->policies[0], 863 policy_item); 864 if (common_entry->policies_size > 1) 865 common_entry->policies[1]->add_item_func( 866 common_entry->policies[1], connected_policy_item); 867 868 HASHTABLE_ENTRY_STORE(cache_ht_, item, &item_data); 869 ++common_entry->items_size; 870 871 if ((common_entry->common_params.max_elemsize != 0) && 872 (common_entry->items_size > 873 common_entry->common_params.max_elemsize)) { 874 if (common_entry->policies_size > 1) { 875 policy = common_entry->policies[1]; 876 connected_policy = common_entry->policies[0]; 877 } else { 878 policy = common_entry->policies[0]; 879 connected_policy = NULL; 880 } 881 882 flush_cache_policy(common_entry, policy, connected_policy, 883 cache_elemsize_common_continue_func); 884 } 885 886 TRACE_OUT(cache_write); 887 return (0); 888} 889 890/* 891 * Initializes the write session for the specified multipart entry. This 892 * session then should be filled with data either committed or abandoned by 893 * using close_cache_mp_write_session or abandon_cache_mp_write_session 894 * respectively. 895 * Returns NULL on errors (when there are too many opened write sessions for 896 * the entry). 897 */ 898struct cache_mp_write_session_ * 899open_cache_mp_write_session(struct cache_entry_ *entry) 900{ 901 struct cache_mp_entry_ *mp_entry; 902 struct cache_mp_write_session_ *retval; 903 904 TRACE_IN(open_cache_mp_write_session); 905 assert(entry != NULL); 906 assert(entry->params->entry_type == CET_MULTIPART); 907 mp_entry = (struct cache_mp_entry_ *)entry; 908 909 if ((mp_entry->mp_params.max_sessions > 0) && 910 (mp_entry->ws_size == mp_entry->mp_params.max_sessions)) { 911 TRACE_OUT(open_cache_mp_write_session); 912 return (NULL); 913 } 914 915 retval = (struct cache_mp_write_session_ *)calloc(1, 916 sizeof(struct cache_mp_write_session_)); 917 assert(retval != NULL); 918 919 TAILQ_INIT(&retval->items); 920 retval->parent_entry = mp_entry; 921 922 TAILQ_INSERT_HEAD(&mp_entry->ws_head, retval, entries); 923 ++mp_entry->ws_size; 924 925 TRACE_OUT(open_cache_mp_write_session); 926 return (retval); 927} 928 929/* 930 * Writes data to the specified session. Return 0 on success and -1 on errors 931 * (when write session size limit is exceeded). 932 */ 933int 934cache_mp_write(struct cache_mp_write_session_ *ws, char *data, 935 size_t data_size) 936{ 937 struct cache_mp_data_item_ *new_item; 938 939 TRACE_IN(cache_mp_write); 940 assert(ws != NULL); 941 assert(ws->parent_entry != NULL); 942 assert(ws->parent_entry->params->entry_type == CET_MULTIPART); 943 944 if ((ws->parent_entry->mp_params.max_elemsize > 0) && 945 (ws->parent_entry->mp_params.max_elemsize == ws->items_size)) { 946 TRACE_OUT(cache_mp_write); 947 return (-1); 948 } 949 950 new_item = (struct cache_mp_data_item_ *)calloc(1, 951 sizeof(struct cache_mp_data_item_)); 952 assert(new_item != NULL); 953 954 new_item->value = (char *)malloc(data_size); 955 assert(new_item->value != NULL); 956 memcpy(new_item->value, data, data_size); 957 new_item->value_size = data_size; 958 959 TAILQ_INSERT_TAIL(&ws->items, new_item, entries); 960 ++ws->items_size; 961 962 TRACE_OUT(cache_mp_write); 963 return (0); 964} 965 966/* 967 * Abandons the write session and frees all the connected resources. 968 */ 969void 970abandon_cache_mp_write_session(struct cache_mp_write_session_ *ws) 971{ 972 973 TRACE_IN(abandon_cache_mp_write_session); 974 assert(ws != NULL); 975 assert(ws->parent_entry != NULL); 976 assert(ws->parent_entry->params->entry_type == CET_MULTIPART); 977 978 TAILQ_REMOVE(&ws->parent_entry->ws_head, ws, entries); 979 --ws->parent_entry->ws_size; 980 981 destroy_cache_mp_write_session(ws); 982 TRACE_OUT(abandon_cache_mp_write_session); 983} 984 985/* 986 * Commits the session to the entry, for which it was created. 987 */ 988void 989close_cache_mp_write_session(struct cache_mp_write_session_ *ws) 990{ 991 992 TRACE_IN(close_cache_mp_write_session); 993 assert(ws != NULL); 994 assert(ws->parent_entry != NULL); 995 assert(ws->parent_entry->params->entry_type == CET_MULTIPART); 996 997 TAILQ_REMOVE(&ws->parent_entry->ws_head, ws, entries); 998 --ws->parent_entry->ws_size; 999 1000 if (ws->parent_entry->completed_write_session == NULL) { 1001 /* 1002 * If there is no completed session yet, this will be the one 1003 */ 1004 ws->parent_entry->get_time_func( 1005 &ws->parent_entry->creation_time); 1006 ws->parent_entry->completed_write_session = ws; 1007 } else { 1008 /* 1009 * If there is a completed session, then we'll save our session 1010 * as a pending session. If there is already a pending session, 1011 * it would be destroyed. 1012 */ 1013 if (ws->parent_entry->pending_write_session != NULL) 1014 destroy_cache_mp_write_session( 1015 ws->parent_entry->pending_write_session); 1016 1017 ws->parent_entry->pending_write_session = ws; 1018 } 1019 TRACE_OUT(close_cache_mp_write_session); 1020} 1021 1022/* 1023 * Opens read session for the specified entry. Returns NULL on errors (when 1024 * there are no data in the entry, or the data are obsolete). 1025 */ 1026struct cache_mp_read_session_ * 1027open_cache_mp_read_session(struct cache_entry_ *entry) 1028{ 1029 struct cache_mp_entry_ *mp_entry; 1030 struct cache_mp_read_session_ *retval; 1031 1032 TRACE_IN(open_cache_mp_read_session); 1033 assert(entry != NULL); 1034 assert(entry->params->entry_type == CET_MULTIPART); 1035 mp_entry = (struct cache_mp_entry_ *)entry; 1036 1037 if (mp_entry->completed_write_session == NULL) { 1038 TRACE_OUT(open_cache_mp_read_session); 1039 return (NULL); 1040 } 1041 1042 if ((mp_entry->mp_params.max_lifetime.tv_sec != 0) 1043 || (mp_entry->mp_params.max_lifetime.tv_usec != 0)) { 1044 if (mp_entry->last_request_time.tv_sec - 1045 mp_entry->last_request_time.tv_sec > 1046 mp_entry->mp_params.max_lifetime.tv_sec) { 1047 flush_cache_entry(entry); 1048 TRACE_OUT(open_cache_mp_read_session); 1049 return (NULL); 1050 } 1051 } 1052 1053 retval = (struct cache_mp_read_session_ *)calloc(1, 1054 sizeof(struct cache_mp_read_session_)); 1055 assert(retval != NULL); 1056 1057 retval->parent_entry = mp_entry; 1058 retval->current_item = TAILQ_FIRST( 1059 &mp_entry->completed_write_session->items); 1060 1061 TAILQ_INSERT_HEAD(&mp_entry->rs_head, retval, entries); 1062 ++mp_entry->rs_size; 1063 1064 mp_entry->get_time_func(&mp_entry->last_request_time); 1065 TRACE_OUT(open_cache_mp_read_session); 1066 return (retval); 1067} 1068 1069/* 1070 * Reads the data from the read session - step by step. 1071 * Returns 0 on success, -1 on error (when there are no more data), and -2 if 1072 * the data_size is too small. In the last case, data_size would be filled 1073 * the proper value. 1074 */ 1075int 1076cache_mp_read(struct cache_mp_read_session_ *rs, char *data, size_t *data_size) 1077{ 1078 1079 TRACE_IN(cache_mp_read); 1080 assert(rs != NULL); 1081 1082 if (rs->current_item == NULL) { 1083 TRACE_OUT(cache_mp_read); 1084 return (-1); 1085 } 1086 1087 if (rs->current_item->value_size > *data_size) { 1088 *data_size = rs->current_item->value_size; 1089 if (data == NULL) { 1090 TRACE_OUT(cache_mp_read); 1091 return (0); 1092 } 1093 1094 TRACE_OUT(cache_mp_read); 1095 return (-2); 1096 } 1097 1098 *data_size = rs->current_item->value_size; 1099 memcpy(data, rs->current_item->value, rs->current_item->value_size); 1100 rs->current_item = TAILQ_NEXT(rs->current_item, entries); 1101 1102 TRACE_OUT(cache_mp_read); 1103 return (0); 1104} 1105 1106/* 1107 * Closes the read session. If there are no more read sessions and there is 1108 * a pending write session, it will be committed and old 1109 * completed_write_session will be destroyed. 1110 */ 1111void 1112close_cache_mp_read_session(struct cache_mp_read_session_ *rs) 1113{ 1114 1115 TRACE_IN(close_cache_mp_read_session); 1116 assert(rs != NULL); 1117 assert(rs->parent_entry != NULL); 1118 1119 TAILQ_REMOVE(&rs->parent_entry->rs_head, rs, entries); 1120 --rs->parent_entry->rs_size; 1121 1122 if ((rs->parent_entry->rs_size == 0) && 1123 (rs->parent_entry->pending_write_session != NULL)) { 1124 destroy_cache_mp_write_session( 1125 rs->parent_entry->completed_write_session); 1126 rs->parent_entry->completed_write_session = 1127 rs->parent_entry->pending_write_session; 1128 rs->parent_entry->pending_write_session = NULL; 1129 } 1130 1131 destroy_cache_mp_read_session(rs); 1132 TRACE_OUT(close_cache_mp_read_session); 1133} 1134 1135int 1136transform_cache_entry(struct cache_entry_ *entry, 1137 enum cache_transformation_t transformation) 1138{ 1139 1140 TRACE_IN(transform_cache_entry); 1141 switch (transformation) { 1142 case CTT_CLEAR: 1143 clear_cache_entry(entry); 1144 TRACE_OUT(transform_cache_entry); 1145 return (0); 1146 case CTT_FLUSH: 1147 flush_cache_entry(entry); 1148 TRACE_OUT(transform_cache_entry); 1149 return (0); 1150 default: 1151 TRACE_OUT(transform_cache_entry); 1152 return (-1); 1153 } 1154} 1155 1156int 1157transform_cache_entry_part(struct cache_entry_ *entry, 1158 enum cache_transformation_t transformation, const char *key_part, 1159 size_t key_part_size, enum part_position_t part_position) 1160{ 1161 struct cache_common_entry_ *common_entry; 1162 struct cache_ht_item_ *ht_item; 1163 struct cache_ht_item_data_ *ht_item_data, ht_key; 1164 1165 struct cache_policy_item_ *item, *connected_item; 1166 1167 TRACE_IN(transform_cache_entry_part); 1168 if (entry->params->entry_type != CET_COMMON) { 1169 TRACE_OUT(transform_cache_entry_part); 1170 return (-1); 1171 } 1172 1173 if (transformation != CTT_CLEAR) { 1174 TRACE_OUT(transform_cache_entry_part); 1175 return (-1); 1176 } 1177 1178 memset(&ht_key, 0, sizeof(struct cache_ht_item_data_)); 1179 ht_key.key = (char *)key_part; /* can't avoid casting here */ 1180 ht_key.key_size = key_part_size; 1181 1182 common_entry = (struct cache_common_entry_ *)entry; 1183 HASHTABLE_FOREACH(&(common_entry->items), ht_item) { 1184 do { 1185 ht_item_data = HASHTABLE_ENTRY_FIND_SPECIAL(cache_ht_, 1186 ht_item, &ht_key, 1187 ht_items_fixed_size_left_cmp_func); 1188 1189 if (ht_item_data != NULL) { 1190 item = ht_item_data->fifo_policy_item; 1191 connected_item = item->connected_item; 1192 1193 common_entry->policies[0]->remove_item_func( 1194 common_entry->policies[0], 1195 item); 1196 1197 free(ht_item_data->key); 1198 free(ht_item_data->value); 1199 HASHTABLE_ENTRY_REMOVE(cache_ht_, ht_item, 1200 ht_item_data); 1201 --common_entry->items_size; 1202 1203 common_entry->policies[0]->destroy_item_func( 1204 item); 1205 if (common_entry->policies_size == 2) { 1206 common_entry->policies[1]->remove_item_func( 1207 common_entry->policies[1], 1208 connected_item); 1209 common_entry->policies[1]->destroy_item_func( 1210 connected_item); 1211 } 1212 } 1213 } while (ht_item_data != NULL); 1214 } 1215 1216 TRACE_OUT(transform_cache_entry_part); 1217 return (0); 1218}
|