1158115Sume/*- 2158115Sume * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 3158115Sume * All rights reserved. 4158115Sume * 5158115Sume * Redistribution and use in source and binary forms, with or without 6158115Sume * modification, are permitted provided that the following conditions 7158115Sume * are met: 8158115Sume * 1. Redistributions of source code must retain the above copyright 9158115Sume * notice, this list of conditions and the following disclaimer. 10158115Sume * 2. Redistributions in binary form must reproduce the above copyright 11158115Sume * notice, this list of conditions and the following disclaimer in the 12158115Sume * documentation and/or other materials provided with the distribution. 13158115Sume * 14158115Sume * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15158115Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16158115Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17158115Sume * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18158115Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19158115Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20158115Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21158115Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22158115Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23158115Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24158115Sume * SUCH DAMAGE. 25158115Sume * 26158115Sume */ 27158115Sume 28158115Sume#include <sys/cdefs.h> 29158115Sume__FBSDID("$FreeBSD$"); 30158115Sume 31158115Sume#include <sys/time.h> 32194093Sdes 33158115Sume#include <assert.h> 34158115Sume#include <stdlib.h> 35158115Sume#include <string.h> 36194093Sdes 37158115Sume#include "cachelib.h" 38158115Sume#include "debug.h" 39158115Sume 40158115Sume#define INITIAL_ENTRIES_CAPACITY 32 41158115Sume#define ENTRIES_CAPACITY_STEP 32 42158115Sume 43158115Sume#define STRING_SIMPLE_HASH_BODY(in_var, var, a, M) \ 44158115Sume for ((var) = 0; *(in_var) != '\0'; ++(in_var)) \ 45158115Sume (var) = ((a)*(var) + *(in_var)) % (M) 46158115Sume 47158115Sume#define STRING_SIMPLE_MP2_HASH_BODY(in_var, var, a, M) \ 48158115Sume for ((var) = 0; *(in_var) != 0; ++(in_var)) \ 49158115Sume (var) = ((a)*(var) + *(in_var)) & (M - 1) 50158115Sume 51158115Sumestatic int cache_elemsize_common_continue_func(struct cache_common_entry_ *, 52158115Sume struct cache_policy_item_ *); 53158115Sumestatic int cache_lifetime_common_continue_func(struct cache_common_entry_ *, 54158115Sume struct cache_policy_item_ *); 55158115Sumestatic void clear_cache_entry(struct cache_entry_ *); 56158115Sumestatic void destroy_cache_entry(struct cache_entry_ *); 57158115Sumestatic void destroy_cache_mp_read_session(struct cache_mp_read_session_ *); 58158115Sumestatic void destroy_cache_mp_write_session(struct cache_mp_write_session_ *); 59158115Sumestatic int entries_bsearch_cmp_func(const void *, const void *); 60158115Sumestatic int entries_qsort_cmp_func(const void *, const void *); 61158115Sumestatic struct cache_entry_ ** find_cache_entry_p(struct cache_ *, 62158115Sume const char *); 63158115Sumestatic void flush_cache_entry(struct cache_entry_ *); 64158115Sumestatic void flush_cache_policy(struct cache_common_entry_ *, 65158115Sume struct cache_policy_ *, struct cache_policy_ *, 66158115Sume int (*)(struct cache_common_entry_ *, 67158115Sume struct cache_policy_item_ *)); 68158115Sumestatic int ht_items_cmp_func(const void *, const void *); 69158115Sumestatic int ht_items_fixed_size_left_cmp_func(const void *, const void *); 70158115Sumestatic hashtable_index_t ht_item_hash_func(const void *, size_t); 71158115Sume 72158115Sume/* 73158115Sume * Hashing and comparing routines, that are used with the hash tables 74158115Sume */ 75158115Sumestatic int 76158115Sumeht_items_cmp_func(const void *p1, const void *p2) 77158115Sume{ 78158115Sume struct cache_ht_item_data_ *hp1, *hp2; 79158115Sume size_t min_size; 80158115Sume int result; 81158115Sume 82158115Sume hp1 = (struct cache_ht_item_data_ *)p1; 83158115Sume hp2 = (struct cache_ht_item_data_ *)p2; 84158115Sume 85158115Sume assert(hp1->key != NULL); 86158115Sume assert(hp2->key != NULL); 87158115Sume 88158115Sume if (hp1->key_size != hp2->key_size) { 89158115Sume min_size = (hp1->key_size < hp2->key_size) ? hp1->key_size : 90158115Sume hp2->key_size; 91158115Sume result = memcmp(hp1->key, hp2->key, min_size); 92158115Sume 93158115Sume if (result == 0) 94158115Sume return ((hp1->key_size < hp2->key_size) ? -1 : 1); 95158115Sume else 96158115Sume return (result); 97158115Sume } else 98158115Sume return (memcmp(hp1->key, hp2->key, hp1->key_size)); 99158115Sume} 100158115Sume 101158115Sumestatic int 102158115Sumeht_items_fixed_size_left_cmp_func(const void *p1, const void *p2) 103158115Sume{ 104158115Sume struct cache_ht_item_data_ *hp1, *hp2; 105158115Sume size_t min_size; 106158115Sume int result; 107158115Sume 108158115Sume hp1 = (struct cache_ht_item_data_ *)p1; 109158115Sume hp2 = (struct cache_ht_item_data_ *)p2; 110158115Sume 111158115Sume assert(hp1->key != NULL); 112158115Sume assert(hp2->key != NULL); 113158115Sume 114158115Sume if (hp1->key_size != hp2->key_size) { 115158115Sume min_size = (hp1->key_size < hp2->key_size) ? hp1->key_size : 116158115Sume hp2->key_size; 117158115Sume result = memcmp(hp1->key, hp2->key, min_size); 118158115Sume 119158115Sume if (result == 0) 120158115Sume if (min_size == hp1->key_size) 121158115Sume return (0); 122158115Sume else 123158115Sume return ((hp1->key_size < hp2->key_size) ? -1 : 1); 124158115Sume else 125158115Sume return (result); 126158115Sume } else 127158115Sume return (memcmp(hp1->key, hp2->key, hp1->key_size)); 128158115Sume} 129158115Sume 130158115Sumestatic hashtable_index_t 131158115Sumeht_item_hash_func(const void *p, size_t cache_entries_size) 132158115Sume{ 133158115Sume struct cache_ht_item_data_ *hp; 134158115Sume size_t i; 135158115Sume 136158115Sume hashtable_index_t retval; 137158115Sume 138158115Sume hp = (struct cache_ht_item_data_ *)p; 139158115Sume assert(hp->key != NULL); 140158115Sume 141158115Sume retval = 0; 142158115Sume for (i = 0; i < hp->key_size; ++i) 143158115Sume retval = (127 * retval + (unsigned char)hp->key[i]) % 144158115Sume cache_entries_size; 145158115Sume 146158115Sume return retval; 147158115Sume} 148158115Sume 149194095SdesHASHTABLE_PROTOTYPE(cache_ht_, cache_ht_item_, struct cache_ht_item_data_); 150158115SumeHASHTABLE_GENERATE(cache_ht_, cache_ht_item_, struct cache_ht_item_data_, data, 151158115Sume ht_item_hash_func, ht_items_cmp_func); 152158115Sume 153158115Sume/* 154158115Sume * Routines to sort and search the entries by name 155158115Sume */ 156158115Sumestatic int 157158115Sumeentries_bsearch_cmp_func(const void *key, const void *ent) 158158115Sume{ 159158115Sume 160158115Sume assert(key != NULL); 161158115Sume assert(ent != NULL); 162158115Sume 163158115Sume return (strcmp((char const *)key, 164158115Sume (*(struct cache_entry_ const **)ent)->name)); 165158115Sume} 166158115Sume 167158115Sumestatic int 168158115Sumeentries_qsort_cmp_func(const void *e1, const void *e2) 169158115Sume{ 170158115Sume 171158115Sume assert(e1 != NULL); 172158115Sume assert(e2 != NULL); 173158115Sume 174158115Sume return (strcmp((*(struct cache_entry_ const **)e1)->name, 175158115Sume (*(struct cache_entry_ const **)e2)->name)); 176158115Sume} 177158115Sume 178158115Sumestatic struct cache_entry_ ** 179158115Sumefind_cache_entry_p(struct cache_ *the_cache, const char *entry_name) 180158115Sume{ 181158115Sume 182158115Sume return ((struct cache_entry_ **)(bsearch(entry_name, the_cache->entries, 183158115Sume the_cache->entries_size, sizeof(struct cache_entry_ *), 184158115Sume entries_bsearch_cmp_func))); 185158115Sume} 186158115Sume 187158115Sumestatic void 188158115Sumedestroy_cache_mp_write_session(struct cache_mp_write_session_ *ws) 189158115Sume{ 190158115Sume 191158115Sume struct cache_mp_data_item_ *data_item; 192158115Sume 193158115Sume TRACE_IN(destroy_cache_mp_write_session); 194158115Sume assert(ws != NULL); 195158115Sume while (!TAILQ_EMPTY(&ws->items)) { 196158115Sume data_item = TAILQ_FIRST(&ws->items); 197158115Sume TAILQ_REMOVE(&ws->items, data_item, entries); 198158115Sume free(data_item->value); 199158115Sume free(data_item); 200158115Sume } 201158115Sume 202158115Sume free(ws); 203158115Sume TRACE_OUT(destroy_cache_mp_write_session); 204158115Sume} 205158115Sume 206158115Sumestatic void 207158115Sumedestroy_cache_mp_read_session(struct cache_mp_read_session_ *rs) 208158115Sume{ 209158115Sume 210158115Sume TRACE_IN(destroy_cache_mp_read_session); 211158115Sume assert(rs != NULL); 212158115Sume free(rs); 213158115Sume TRACE_OUT(destroy_cache_mp_read_session); 214158115Sume} 215158115Sume 216158115Sumestatic void 217158115Sumedestroy_cache_entry(struct cache_entry_ *entry) 218158115Sume{ 219158115Sume struct cache_common_entry_ *common_entry; 220158115Sume struct cache_mp_entry_ *mp_entry; 221158115Sume struct cache_mp_read_session_ *rs; 222158115Sume struct cache_mp_write_session_ *ws; 223158115Sume struct cache_ht_item_ *ht_item; 224158115Sume struct cache_ht_item_data_ *ht_item_data; 225158115Sume 226158115Sume TRACE_IN(destroy_cache_entry); 227158115Sume assert(entry != NULL); 228158115Sume 229158115Sume if (entry->params->entry_type == CET_COMMON) { 230158115Sume common_entry = (struct cache_common_entry_ *)entry; 231158115Sume 232158115Sume HASHTABLE_FOREACH(&(common_entry->items), ht_item) { 233158115Sume HASHTABLE_ENTRY_FOREACH(ht_item, data, ht_item_data) 234158115Sume { 235158115Sume free(ht_item_data->key); 236158115Sume free(ht_item_data->value); 237158115Sume } 238158115Sume HASHTABLE_ENTRY_CLEAR(ht_item, data); 239158115Sume } 240158115Sume 241158115Sume HASHTABLE_DESTROY(&(common_entry->items), data); 242158115Sume 243158115Sume /* FIFO policy is always first */ 244158115Sume destroy_cache_fifo_policy(common_entry->policies[0]); 245158115Sume switch (common_entry->common_params.policy) { 246158115Sume case CPT_LRU: 247158115Sume destroy_cache_lru_policy(common_entry->policies[1]); 248158115Sume break; 249158115Sume case CPT_LFU: 250158115Sume destroy_cache_lfu_policy(common_entry->policies[1]); 251158115Sume break; 252158115Sume default: 253158115Sume break; 254158115Sume } 255158115Sume free(common_entry->policies); 256158115Sume } else { 257158115Sume mp_entry = (struct cache_mp_entry_ *)entry; 258158115Sume 259158115Sume while (!TAILQ_EMPTY(&mp_entry->ws_head)) { 260158115Sume ws = TAILQ_FIRST(&mp_entry->ws_head); 261158115Sume TAILQ_REMOVE(&mp_entry->ws_head, ws, entries); 262158115Sume destroy_cache_mp_write_session(ws); 263158115Sume } 264158115Sume 265158115Sume while (!TAILQ_EMPTY(&mp_entry->rs_head)) { 266158115Sume rs = TAILQ_FIRST(&mp_entry->rs_head); 267158115Sume TAILQ_REMOVE(&mp_entry->rs_head, rs, entries); 268158115Sume destroy_cache_mp_read_session(rs); 269158115Sume } 270158115Sume 271158115Sume if (mp_entry->completed_write_session != NULL) 272158115Sume destroy_cache_mp_write_session( 273158115Sume mp_entry->completed_write_session); 274158115Sume 275158115Sume if (mp_entry->pending_write_session != NULL) 276158115Sume destroy_cache_mp_write_session( 277158115Sume mp_entry->pending_write_session); 278158115Sume } 279158115Sume 280158115Sume free(entry->name); 281158115Sume free(entry); 282158115Sume TRACE_OUT(destroy_cache_entry); 283158115Sume} 284158115Sume 285158115Sumestatic void 286158115Sumeclear_cache_entry(struct cache_entry_ *entry) 287158115Sume{ 288158115Sume struct cache_mp_entry_ *mp_entry; 289158115Sume struct cache_common_entry_ *common_entry; 290158115Sume struct cache_ht_item_ *ht_item; 291158115Sume struct cache_ht_item_data_ *ht_item_data; 292158115Sume struct cache_policy_ *policy; 293158115Sume struct cache_policy_item_ *item, *next_item; 294158115Sume size_t entry_size; 295194095Sdes unsigned int i; 296158115Sume 297158115Sume if (entry->params->entry_type == CET_COMMON) { 298158115Sume common_entry = (struct cache_common_entry_ *)entry; 299158115Sume 300158115Sume entry_size = 0; 301158115Sume HASHTABLE_FOREACH(&(common_entry->items), ht_item) { 302158115Sume HASHTABLE_ENTRY_FOREACH(ht_item, data, ht_item_data) 303158115Sume { 304158115Sume free(ht_item_data->key); 305158115Sume free(ht_item_data->value); 306158115Sume } 307158115Sume entry_size += HASHTABLE_ENTRY_SIZE(ht_item, data); 308158115Sume HASHTABLE_ENTRY_CLEAR(ht_item, data); 309158115Sume } 310158115Sume 311158115Sume common_entry->items_size -= entry_size; 312158115Sume for (i = 0; i < common_entry->policies_size; ++i) { 313158115Sume policy = common_entry->policies[i]; 314158115Sume 315158115Sume next_item = NULL; 316158115Sume item = policy->get_first_item_func(policy); 317158115Sume while (item != NULL) { 318158115Sume next_item = policy->get_next_item_func(policy, 319158115Sume item); 320158115Sume policy->remove_item_func(policy, item); 321158115Sume policy->destroy_item_func(item); 322158115Sume item = next_item; 323158115Sume } 324158115Sume } 325158115Sume } else { 326158115Sume mp_entry = (struct cache_mp_entry_ *)entry; 327158115Sume 328158115Sume if (mp_entry->rs_size == 0) { 329158115Sume if (mp_entry->completed_write_session != NULL) { 330158115Sume destroy_cache_mp_write_session( 331158115Sume mp_entry->completed_write_session); 332158115Sume mp_entry->completed_write_session = NULL; 333158115Sume } 334158115Sume 335158115Sume memset(&mp_entry->creation_time, 0, 336158115Sume sizeof(struct timeval)); 337158115Sume memset(&mp_entry->last_request_time, 0, 338158115Sume sizeof(struct timeval)); 339158115Sume } 340158115Sume } 341158115Sume} 342158115Sume 343158115Sume/* 344158115Sume * When passed to the flush_cache_policy, ensures that all old elements are 345158115Sume * deleted. 346158115Sume */ 347158115Sumestatic int 348158115Sumecache_lifetime_common_continue_func(struct cache_common_entry_ *entry, 349158115Sume struct cache_policy_item_ *item) 350158115Sume{ 351158115Sume 352158115Sume return ((item->last_request_time.tv_sec - item->creation_time.tv_sec > 353158115Sume entry->common_params.max_lifetime.tv_sec) ? 1: 0); 354158115Sume} 355158115Sume 356158115Sume/* 357158115Sume * When passed to the flush_cache_policy, ensures that all elements, that 358158115Sume * exceed the size limit, are deleted. 359158115Sume */ 360158115Sumestatic int 361158115Sumecache_elemsize_common_continue_func(struct cache_common_entry_ *entry, 362158115Sume struct cache_policy_item_ *item) 363158115Sume{ 364158115Sume 365158115Sume return ((entry->items_size > entry->common_params.satisf_elemsize) ? 1 366158115Sume : 0); 367158115Sume} 368158115Sume 369158115Sume/* 370158115Sume * Removes the elements from the cache entry, while the continue_func returns 1. 371158115Sume */ 372158115Sumestatic void 373158115Sumeflush_cache_policy(struct cache_common_entry_ *entry, 374158115Sume struct cache_policy_ *policy, 375158115Sume struct cache_policy_ *connected_policy, 376158115Sume int (*continue_func)(struct cache_common_entry_ *, 377158115Sume struct cache_policy_item_ *)) 378158115Sume{ 379158115Sume struct cache_policy_item_ *item, *next_item, *connected_item; 380158115Sume struct cache_ht_item_ *ht_item; 381158115Sume struct cache_ht_item_data_ *ht_item_data, ht_key; 382158115Sume hashtable_index_t hash; 383158115Sume 384158115Sume assert(policy != NULL); 385158115Sume 386158115Sume next_item = NULL; 387158115Sume item = policy->get_first_item_func(policy); 388158115Sume while ((item != NULL) && (continue_func(entry, item) == 1)) { 389158115Sume next_item = policy->get_next_item_func(policy, item); 390158115Sume 391158115Sume connected_item = item->connected_item; 392158115Sume policy->remove_item_func(policy, item); 393158115Sume 394158115Sume memset(&ht_key, 0, sizeof(struct cache_ht_item_data_)); 395158115Sume ht_key.key = item->key; 396158115Sume ht_key.key_size = item->key_size; 397158115Sume 398158115Sume hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &entry->items, 399158115Sume &ht_key); 400158115Sume assert(hash < HASHTABLE_ENTRIES_COUNT(&entry->items)); 401158115Sume 402158115Sume ht_item = HASHTABLE_GET_ENTRY(&(entry->items), hash); 403158115Sume ht_item_data = HASHTABLE_ENTRY_FIND(cache_ht_, ht_item, 404158115Sume &ht_key); 405158115Sume assert(ht_item_data != NULL); 406158115Sume free(ht_item_data->key); 407158115Sume free(ht_item_data->value); 408158115Sume HASHTABLE_ENTRY_REMOVE(cache_ht_, ht_item, ht_item_data); 409158115Sume --entry->items_size; 410158115Sume 411158115Sume policy->destroy_item_func(item); 412158115Sume 413158115Sume if (connected_item != NULL) { 414158115Sume connected_policy->remove_item_func(connected_policy, 415158115Sume connected_item); 416158115Sume connected_policy->destroy_item_func(connected_item); 417158115Sume } 418158115Sume 419158115Sume item = next_item; 420158115Sume } 421158115Sume} 422158115Sume 423158115Sumestatic void 424158115Sumeflush_cache_entry(struct cache_entry_ *entry) 425158115Sume{ 426158115Sume struct cache_mp_entry_ *mp_entry; 427158115Sume struct cache_common_entry_ *common_entry; 428158115Sume struct cache_policy_ *policy, *connected_policy; 429158115Sume 430158115Sume connected_policy = NULL; 431158115Sume if (entry->params->entry_type == CET_COMMON) { 432158115Sume common_entry = (struct cache_common_entry_ *)entry; 433158115Sume if ((common_entry->common_params.max_lifetime.tv_sec != 0) || 434158115Sume (common_entry->common_params.max_lifetime.tv_usec != 0)) { 435158115Sume 436158115Sume policy = common_entry->policies[0]; 437158115Sume if (common_entry->policies_size > 1) 438158115Sume connected_policy = common_entry->policies[1]; 439158115Sume 440158115Sume flush_cache_policy(common_entry, policy, 441158115Sume connected_policy, 442158115Sume cache_lifetime_common_continue_func); 443158115Sume } 444158115Sume 445158115Sume 446158115Sume if ((common_entry->common_params.max_elemsize != 0) && 447158115Sume common_entry->items_size > 448158115Sume common_entry->common_params.max_elemsize) { 449158115Sume 450158115Sume if (common_entry->policies_size > 1) { 451158115Sume policy = common_entry->policies[1]; 452158115Sume connected_policy = common_entry->policies[0]; 453158115Sume } else { 454158115Sume policy = common_entry->policies[0]; 455158115Sume connected_policy = NULL; 456158115Sume } 457158115Sume 458158115Sume flush_cache_policy(common_entry, policy, 459158115Sume connected_policy, 460158115Sume cache_elemsize_common_continue_func); 461158115Sume } 462158115Sume } else { 463158115Sume mp_entry = (struct cache_mp_entry_ *)entry; 464158115Sume 465158115Sume if ((mp_entry->mp_params.max_lifetime.tv_sec != 0) 466158115Sume || (mp_entry->mp_params.max_lifetime.tv_usec != 0)) { 467158115Sume 468158115Sume if (mp_entry->last_request_time.tv_sec - 469158115Sume mp_entry->last_request_time.tv_sec > 470158115Sume mp_entry->mp_params.max_lifetime.tv_sec) 471158115Sume clear_cache_entry(entry); 472158115Sume } 473158115Sume } 474158115Sume} 475158115Sume 476158115Sumestruct cache_ * 477158115Sumeinit_cache(struct cache_params const *params) 478158115Sume{ 479158115Sume struct cache_ *retval; 480158115Sume 481158115Sume TRACE_IN(init_cache); 482158115Sume assert(params != NULL); 483158115Sume 484194104Sdes retval = calloc(1, sizeof(*retval)); 485158115Sume assert(retval != NULL); 486158115Sume 487158115Sume assert(params != NULL); 488158115Sume memcpy(&retval->params, params, sizeof(struct cache_params)); 489158115Sume 490194104Sdes retval->entries = calloc(1, 491194104Sdes sizeof(*retval->entries) * INITIAL_ENTRIES_CAPACITY); 492158115Sume assert(retval->entries != NULL); 493158115Sume 494158115Sume retval->entries_capacity = INITIAL_ENTRIES_CAPACITY; 495158115Sume retval->entries_size = 0; 496158115Sume 497158115Sume TRACE_OUT(init_cache); 498158115Sume return (retval); 499158115Sume} 500158115Sume 501158115Sumevoid 502158115Sumedestroy_cache(struct cache_ *the_cache) 503158115Sume{ 504158115Sume 505158115Sume TRACE_IN(destroy_cache); 506158115Sume assert(the_cache != NULL); 507158115Sume 508158115Sume if (the_cache->entries != NULL) { 509158115Sume size_t i; 510158115Sume for (i = 0; i < the_cache->entries_size; ++i) 511158115Sume destroy_cache_entry(the_cache->entries[i]); 512158115Sume 513158115Sume free(the_cache->entries); 514158115Sume } 515158115Sume 516158115Sume free(the_cache); 517158115Sume TRACE_OUT(destroy_cache); 518158115Sume} 519158115Sume 520158115Sumeint 521158115Sumeregister_cache_entry(struct cache_ *the_cache, 522158115Sume struct cache_entry_params const *params) 523158115Sume{ 524158115Sume int policies_size; 525158115Sume size_t entry_name_size; 526158115Sume struct cache_common_entry_ *new_common_entry; 527158115Sume struct cache_mp_entry_ *new_mp_entry; 528158115Sume 529158115Sume TRACE_IN(register_cache_entry); 530158115Sume assert(the_cache != NULL); 531158115Sume 532158115Sume if (find_cache_entry(the_cache, params->entry_name) != NULL) { 533158115Sume TRACE_OUT(register_cache_entry); 534158115Sume return (-1); 535158115Sume } 536158115Sume 537158115Sume if (the_cache->entries_size == the_cache->entries_capacity) { 538158115Sume struct cache_entry_ **new_entries; 539158115Sume size_t new_capacity; 540158115Sume 541158115Sume new_capacity = the_cache->entries_capacity + 542158115Sume ENTRIES_CAPACITY_STEP; 543194104Sdes new_entries = calloc(1, 544194104Sdes sizeof(*new_entries) * new_capacity); 545158115Sume assert(new_entries != NULL); 546158115Sume 547158115Sume memcpy(new_entries, the_cache->entries, 548158115Sume sizeof(struct cache_entry_ *) 549158115Sume * the_cache->entries_size); 550158115Sume 551158115Sume free(the_cache->entries); 552158115Sume the_cache->entries = new_entries; 553158115Sume } 554158115Sume 555184189Sdelphij entry_name_size = strlen(params->entry_name) + 1; 556158115Sume switch (params->entry_type) 557158115Sume { 558158115Sume case CET_COMMON: 559194104Sdes new_common_entry = calloc(1, 560194104Sdes sizeof(*new_common_entry)); 561158115Sume assert(new_common_entry != NULL); 562158115Sume 563158115Sume memcpy(&new_common_entry->common_params, params, 564158115Sume sizeof(struct common_cache_entry_params)); 565158115Sume new_common_entry->params = 566158115Sume (struct cache_entry_params *)&new_common_entry->common_params; 567158115Sume 568194104Sdes new_common_entry->common_params.cep.entry_name = calloc(1, 569184189Sdelphij entry_name_size); 570194097Sdes assert(new_common_entry->common_params.cep.entry_name != NULL); 571194097Sdes strlcpy(new_common_entry->common_params.cep.entry_name, 572158115Sume params->entry_name, entry_name_size); 573158115Sume new_common_entry->name = 574194097Sdes new_common_entry->common_params.cep.entry_name; 575158115Sume 576158115Sume HASHTABLE_INIT(&(new_common_entry->items), 577158115Sume struct cache_ht_item_data_, data, 578158115Sume new_common_entry->common_params.cache_entries_size); 579158115Sume 580158115Sume if (new_common_entry->common_params.policy == CPT_FIFO) 581158115Sume policies_size = 1; 582158115Sume else 583158115Sume policies_size = 2; 584158115Sume 585194104Sdes new_common_entry->policies = calloc(1, 586194104Sdes sizeof(*new_common_entry->policies) * policies_size); 587158115Sume assert(new_common_entry->policies != NULL); 588158115Sume 589158115Sume new_common_entry->policies_size = policies_size; 590158115Sume new_common_entry->policies[0] = init_cache_fifo_policy(); 591158115Sume 592158115Sume if (policies_size > 1) { 593158115Sume switch (new_common_entry->common_params.policy) { 594158115Sume case CPT_LRU: 595158115Sume new_common_entry->policies[1] = 596158115Sume init_cache_lru_policy(); 597158115Sume break; 598158115Sume case CPT_LFU: 599158115Sume new_common_entry->policies[1] = 600158115Sume init_cache_lfu_policy(); 601158115Sume break; 602158115Sume default: 603158115Sume break; 604158115Sume } 605158115Sume } 606158115Sume 607158115Sume new_common_entry->get_time_func = 608158115Sume the_cache->params.get_time_func; 609158115Sume the_cache->entries[the_cache->entries_size++] = 610158115Sume (struct cache_entry_ *)new_common_entry; 611158115Sume break; 612158115Sume case CET_MULTIPART: 613194104Sdes new_mp_entry = calloc(1, 614194104Sdes sizeof(*new_mp_entry)); 615158115Sume assert(new_mp_entry != NULL); 616158115Sume 617158115Sume memcpy(&new_mp_entry->mp_params, params, 618158115Sume sizeof(struct mp_cache_entry_params)); 619158115Sume new_mp_entry->params = 620158115Sume (struct cache_entry_params *)&new_mp_entry->mp_params; 621158115Sume 622194104Sdes new_mp_entry->mp_params.cep.entry_name = calloc(1, 623184189Sdelphij entry_name_size); 624194097Sdes assert(new_mp_entry->mp_params.cep.entry_name != NULL); 625194097Sdes strlcpy(new_mp_entry->mp_params.cep.entry_name, params->entry_name, 626158115Sume entry_name_size); 627194097Sdes new_mp_entry->name = new_mp_entry->mp_params.cep.entry_name; 628158115Sume 629158115Sume TAILQ_INIT(&new_mp_entry->ws_head); 630158115Sume TAILQ_INIT(&new_mp_entry->rs_head); 631158115Sume 632158115Sume new_mp_entry->get_time_func = the_cache->params.get_time_func; 633158115Sume the_cache->entries[the_cache->entries_size++] = 634158115Sume (struct cache_entry_ *)new_mp_entry; 635158115Sume break; 636158115Sume } 637158115Sume 638158115Sume 639158115Sume qsort(the_cache->entries, the_cache->entries_size, 640158115Sume sizeof(struct cache_entry_ *), entries_qsort_cmp_func); 641158115Sume 642158115Sume TRACE_OUT(register_cache_entry); 643158115Sume return (0); 644158115Sume} 645158115Sume 646158115Sumeint 647158115Sumeunregister_cache_entry(struct cache_ *the_cache, const char *entry_name) 648158115Sume{ 649158115Sume struct cache_entry_ **del_ent; 650158115Sume 651158115Sume TRACE_IN(unregister_cache_entry); 652158115Sume assert(the_cache != NULL); 653158115Sume 654158115Sume del_ent = find_cache_entry_p(the_cache, entry_name); 655158115Sume if (del_ent != NULL) { 656158115Sume destroy_cache_entry(*del_ent); 657158115Sume --the_cache->entries_size; 658158115Sume 659158115Sume memmove(del_ent, del_ent + 1, 660158115Sume (&(the_cache->entries[--the_cache->entries_size]) - 661158115Sume del_ent) * sizeof(struct cache_entry_ *)); 662158115Sume 663158115Sume TRACE_OUT(unregister_cache_entry); 664158115Sume return (0); 665158115Sume } else { 666158115Sume TRACE_OUT(unregister_cache_entry); 667158115Sume return (-1); 668158115Sume } 669158115Sume} 670158115Sume 671158115Sumestruct cache_entry_ * 672158115Sumefind_cache_entry(struct cache_ *the_cache, const char *entry_name) 673158115Sume{ 674158115Sume struct cache_entry_ **result; 675158115Sume 676158115Sume TRACE_IN(find_cache_entry); 677158115Sume result = find_cache_entry_p(the_cache, entry_name); 678158115Sume 679158115Sume if (result == NULL) { 680158115Sume TRACE_OUT(find_cache_entry); 681158115Sume return (NULL); 682158115Sume } else { 683158115Sume TRACE_OUT(find_cache_entry); 684158115Sume return (*result); 685158115Sume } 686158115Sume} 687158115Sume 688158115Sume/* 689158115Sume * Tries to read the element with the specified key from the cache. If the 690158115Sume * value_size is too small, it will be filled with the proper number, and 691158115Sume * the user will need to call cache_read again with the value buffer, that 692158115Sume * is large enough. 693158115Sume * Function returns 0 on success, -1 on error, and -2 if the value_size is too 694158115Sume * small. 695158115Sume */ 696158115Sumeint 697158115Sumecache_read(struct cache_entry_ *entry, const char *key, size_t key_size, 698158115Sume char *value, size_t *value_size) 699158115Sume{ 700158115Sume struct cache_common_entry_ *common_entry; 701158115Sume struct cache_ht_item_data_ item_data, *find_res; 702158115Sume struct cache_ht_item_ *item; 703158115Sume hashtable_index_t hash; 704158115Sume struct cache_policy_item_ *connected_item; 705158115Sume 706158115Sume TRACE_IN(cache_read); 707158115Sume assert(entry != NULL); 708158115Sume assert(key != NULL); 709158115Sume assert(value_size != NULL); 710158115Sume assert(entry->params->entry_type == CET_COMMON); 711158115Sume 712158115Sume common_entry = (struct cache_common_entry_ *)entry; 713158115Sume 714158115Sume memset(&item_data, 0, sizeof(struct cache_ht_item_data_)); 715158115Sume /* can't avoid the cast here */ 716158115Sume item_data.key = (char *)key; 717158115Sume item_data.key_size = key_size; 718158115Sume 719158115Sume hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &common_entry->items, 720158115Sume &item_data); 721158115Sume assert(hash < HASHTABLE_ENTRIES_COUNT(&common_entry->items)); 722158115Sume 723158115Sume item = HASHTABLE_GET_ENTRY(&(common_entry->items), hash); 724158115Sume find_res = HASHTABLE_ENTRY_FIND(cache_ht_, item, &item_data); 725158115Sume if (find_res == NULL) { 726158115Sume TRACE_OUT(cache_read); 727158115Sume return (-1); 728158115Sume } 729238094Sse /* pretend that entry was not found if confidence is below threshold*/ 730238094Sse if (find_res->confidence < 731238094Sse common_entry->common_params.confidence_threshold) { 732238094Sse TRACE_OUT(cache_read); 733238094Sse return (-1); 734238094Sse } 735158115Sume 736158115Sume if ((common_entry->common_params.max_lifetime.tv_sec != 0) || 737158115Sume (common_entry->common_params.max_lifetime.tv_usec != 0)) { 738158115Sume 739158115Sume if (find_res->fifo_policy_item->last_request_time.tv_sec - 740158115Sume find_res->fifo_policy_item->creation_time.tv_sec > 741158115Sume common_entry->common_params.max_lifetime.tv_sec) { 742158115Sume 743158115Sume free(find_res->key); 744158115Sume free(find_res->value); 745158115Sume 746158115Sume connected_item = 747158115Sume find_res->fifo_policy_item->connected_item; 748158115Sume if (connected_item != NULL) { 749158115Sume common_entry->policies[1]->remove_item_func( 750158115Sume common_entry->policies[1], 751158115Sume connected_item); 752158115Sume common_entry->policies[1]->destroy_item_func( 753158115Sume connected_item); 754158115Sume } 755158115Sume 756158115Sume common_entry->policies[0]->remove_item_func( 757158115Sume common_entry->policies[0], 758158115Sume find_res->fifo_policy_item); 759158115Sume common_entry->policies[0]->destroy_item_func( 760158115Sume find_res->fifo_policy_item); 761158115Sume 762158115Sume HASHTABLE_ENTRY_REMOVE(cache_ht_, item, find_res); 763158115Sume --common_entry->items_size; 764158115Sume } 765158115Sume } 766158115Sume 767158115Sume if ((*value_size < find_res->value_size) || (value == NULL)) { 768158115Sume *value_size = find_res->value_size; 769158115Sume TRACE_OUT(cache_read); 770158115Sume return (-2); 771158115Sume } 772158115Sume 773158115Sume *value_size = find_res->value_size; 774158115Sume memcpy(value, find_res->value, find_res->value_size); 775158115Sume 776158115Sume ++find_res->fifo_policy_item->request_count; 777158115Sume common_entry->get_time_func( 778158115Sume &find_res->fifo_policy_item->last_request_time); 779158115Sume common_entry->policies[0]->update_item_func(common_entry->policies[0], 780158115Sume find_res->fifo_policy_item); 781158115Sume 782158115Sume if (find_res->fifo_policy_item->connected_item != NULL) { 783158115Sume connected_item = find_res->fifo_policy_item->connected_item; 784158115Sume memcpy(&connected_item->last_request_time, 785158115Sume &find_res->fifo_policy_item->last_request_time, 786158115Sume sizeof(struct timeval)); 787158115Sume connected_item->request_count = 788158115Sume find_res->fifo_policy_item->request_count; 789158115Sume 790158115Sume common_entry->policies[1]->update_item_func( 791158115Sume common_entry->policies[1], connected_item); 792158115Sume } 793158115Sume 794158115Sume TRACE_OUT(cache_read); 795158115Sume return (0); 796158115Sume} 797158115Sume 798158115Sume/* 799158115Sume * Writes the value with the specified key into the cache entry. 800158115Sume * Functions returns 0 on success, and -1 on error. 801158115Sume */ 802158115Sumeint 803158115Sumecache_write(struct cache_entry_ *entry, const char *key, size_t key_size, 804158115Sume char const *value, size_t value_size) 805158115Sume{ 806158115Sume struct cache_common_entry_ *common_entry; 807158115Sume struct cache_ht_item_data_ item_data, *find_res; 808158115Sume struct cache_ht_item_ *item; 809158115Sume hashtable_index_t hash; 810158115Sume 811158115Sume struct cache_policy_ *policy, *connected_policy; 812158115Sume struct cache_policy_item_ *policy_item; 813158115Sume struct cache_policy_item_ *connected_policy_item; 814158115Sume 815158115Sume TRACE_IN(cache_write); 816158115Sume assert(entry != NULL); 817158115Sume assert(key != NULL); 818158115Sume assert(value != NULL); 819158115Sume assert(entry->params->entry_type == CET_COMMON); 820158115Sume 821158115Sume common_entry = (struct cache_common_entry_ *)entry; 822158115Sume 823158115Sume memset(&item_data, 0, sizeof(struct cache_ht_item_data_)); 824158115Sume /* can't avoid the cast here */ 825158115Sume item_data.key = (char *)key; 826158115Sume item_data.key_size = key_size; 827158115Sume 828158115Sume hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &common_entry->items, 829158115Sume &item_data); 830158115Sume assert(hash < HASHTABLE_ENTRIES_COUNT(&common_entry->items)); 831158115Sume 832158115Sume item = HASHTABLE_GET_ENTRY(&(common_entry->items), hash); 833158115Sume find_res = HASHTABLE_ENTRY_FIND(cache_ht_, item, &item_data); 834158115Sume if (find_res != NULL) { 835238094Sse if (find_res->confidence < common_entry->common_params.confidence_threshold) { 836238094Sse /* duplicate entry is no error, if confidence is low */ 837238094Sse if ((find_res->value_size == value_size) && 838238094Sse (memcmp(find_res->value, value, value_size) == 0)) { 839238094Sse /* increase confidence on exact match (key and values) */ 840238094Sse find_res->confidence++; 841238094Sse } else { 842238094Sse /* create new entry with low confidence, if value changed */ 843238094Sse free(item_data.value); 844238094Sse item_data.value = malloc(value_size); 845238094Sse assert(item_data.value != NULL); 846238094Sse memcpy(item_data.value, value, value_size); 847238094Sse item_data.value_size = value_size; 848238094Sse find_res->confidence = 1; 849238094Sse } 850238094Sse TRACE_OUT(cache_write); 851238094Sse return (0); 852238094Sse } 853158115Sume TRACE_OUT(cache_write); 854158115Sume return (-1); 855158115Sume } 856158115Sume 857194104Sdes item_data.key = malloc(key_size); 858158115Sume memcpy(item_data.key, key, key_size); 859158115Sume 860194104Sdes item_data.value = malloc(value_size); 861158115Sume assert(item_data.value != NULL); 862158115Sume 863158115Sume memcpy(item_data.value, value, value_size); 864158115Sume item_data.value_size = value_size; 865158115Sume 866238094Sse item_data.confidence = 1; 867238094Sse 868158115Sume policy_item = common_entry->policies[0]->create_item_func(); 869158115Sume policy_item->key = item_data.key; 870158115Sume policy_item->key_size = item_data.key_size; 871158115Sume common_entry->get_time_func(&policy_item->creation_time); 872158115Sume 873158115Sume if (common_entry->policies_size > 1) { 874158115Sume connected_policy_item = 875158115Sume common_entry->policies[1]->create_item_func(); 876158115Sume memcpy(&connected_policy_item->creation_time, 877158115Sume &policy_item->creation_time, 878158115Sume sizeof(struct timeval)); 879158115Sume connected_policy_item->key = policy_item->key; 880158115Sume connected_policy_item->key_size = policy_item->key_size; 881158115Sume 882158115Sume connected_policy_item->connected_item = policy_item; 883158115Sume policy_item->connected_item = connected_policy_item; 884158115Sume } 885158115Sume 886158115Sume item_data.fifo_policy_item = policy_item; 887158115Sume 888158115Sume common_entry->policies[0]->add_item_func(common_entry->policies[0], 889158115Sume policy_item); 890158115Sume if (common_entry->policies_size > 1) 891158115Sume common_entry->policies[1]->add_item_func( 892158115Sume common_entry->policies[1], connected_policy_item); 893158115Sume 894158115Sume HASHTABLE_ENTRY_STORE(cache_ht_, item, &item_data); 895158115Sume ++common_entry->items_size; 896158115Sume 897158115Sume if ((common_entry->common_params.max_elemsize != 0) && 898158115Sume (common_entry->items_size > 899158115Sume common_entry->common_params.max_elemsize)) { 900158115Sume if (common_entry->policies_size > 1) { 901158115Sume policy = common_entry->policies[1]; 902158115Sume connected_policy = common_entry->policies[0]; 903158115Sume } else { 904158115Sume policy = common_entry->policies[0]; 905158115Sume connected_policy = NULL; 906158115Sume } 907158115Sume 908158115Sume flush_cache_policy(common_entry, policy, connected_policy, 909158115Sume cache_elemsize_common_continue_func); 910158115Sume } 911158115Sume 912158115Sume TRACE_OUT(cache_write); 913158115Sume return (0); 914158115Sume} 915158115Sume 916158115Sume/* 917158115Sume * Initializes the write session for the specified multipart entry. This 918158115Sume * session then should be filled with data either committed or abandoned by 919158115Sume * using close_cache_mp_write_session or abandon_cache_mp_write_session 920158115Sume * respectively. 921158115Sume * Returns NULL on errors (when there are too many opened write sessions for 922158115Sume * the entry). 923158115Sume */ 924158115Sumestruct cache_mp_write_session_ * 925158115Sumeopen_cache_mp_write_session(struct cache_entry_ *entry) 926158115Sume{ 927158115Sume struct cache_mp_entry_ *mp_entry; 928158115Sume struct cache_mp_write_session_ *retval; 929158115Sume 930158115Sume TRACE_IN(open_cache_mp_write_session); 931158115Sume assert(entry != NULL); 932158115Sume assert(entry->params->entry_type == CET_MULTIPART); 933158115Sume mp_entry = (struct cache_mp_entry_ *)entry; 934158115Sume 935158115Sume if ((mp_entry->mp_params.max_sessions > 0) && 936158115Sume (mp_entry->ws_size == mp_entry->mp_params.max_sessions)) { 937158115Sume TRACE_OUT(open_cache_mp_write_session); 938158115Sume return (NULL); 939158115Sume } 940158115Sume 941194104Sdes retval = calloc(1, 942194104Sdes sizeof(*retval)); 943158115Sume assert(retval != NULL); 944158115Sume 945158115Sume TAILQ_INIT(&retval->items); 946158115Sume retval->parent_entry = mp_entry; 947158115Sume 948158115Sume TAILQ_INSERT_HEAD(&mp_entry->ws_head, retval, entries); 949158115Sume ++mp_entry->ws_size; 950158115Sume 951158115Sume TRACE_OUT(open_cache_mp_write_session); 952158115Sume return (retval); 953158115Sume} 954158115Sume 955158115Sume/* 956158115Sume * Writes data to the specified session. Return 0 on success and -1 on errors 957158115Sume * (when write session size limit is exceeded). 958158115Sume */ 959158115Sumeint 960158115Sumecache_mp_write(struct cache_mp_write_session_ *ws, char *data, 961158115Sume size_t data_size) 962158115Sume{ 963158115Sume struct cache_mp_data_item_ *new_item; 964158115Sume 965158115Sume TRACE_IN(cache_mp_write); 966158115Sume assert(ws != NULL); 967158115Sume assert(ws->parent_entry != NULL); 968158115Sume assert(ws->parent_entry->params->entry_type == CET_MULTIPART); 969158115Sume 970158115Sume if ((ws->parent_entry->mp_params.max_elemsize > 0) && 971158115Sume (ws->parent_entry->mp_params.max_elemsize == ws->items_size)) { 972158115Sume TRACE_OUT(cache_mp_write); 973158115Sume return (-1); 974158115Sume } 975158115Sume 976194104Sdes new_item = calloc(1, 977194104Sdes sizeof(*new_item)); 978158115Sume assert(new_item != NULL); 979158115Sume 980194104Sdes new_item->value = malloc(data_size); 981158115Sume assert(new_item->value != NULL); 982158115Sume memcpy(new_item->value, data, data_size); 983158115Sume new_item->value_size = data_size; 984158115Sume 985158115Sume TAILQ_INSERT_TAIL(&ws->items, new_item, entries); 986158115Sume ++ws->items_size; 987158115Sume 988158115Sume TRACE_OUT(cache_mp_write); 989158115Sume return (0); 990158115Sume} 991158115Sume 992158115Sume/* 993158115Sume * Abandons the write session and frees all the connected resources. 994158115Sume */ 995158115Sumevoid 996158115Sumeabandon_cache_mp_write_session(struct cache_mp_write_session_ *ws) 997158115Sume{ 998158115Sume 999158115Sume TRACE_IN(abandon_cache_mp_write_session); 1000158115Sume assert(ws != NULL); 1001158115Sume assert(ws->parent_entry != NULL); 1002158115Sume assert(ws->parent_entry->params->entry_type == CET_MULTIPART); 1003158115Sume 1004158115Sume TAILQ_REMOVE(&ws->parent_entry->ws_head, ws, entries); 1005158115Sume --ws->parent_entry->ws_size; 1006158115Sume 1007158115Sume destroy_cache_mp_write_session(ws); 1008158115Sume TRACE_OUT(abandon_cache_mp_write_session); 1009158115Sume} 1010158115Sume 1011158115Sume/* 1012158115Sume * Commits the session to the entry, for which it was created. 1013158115Sume */ 1014158115Sumevoid 1015158115Sumeclose_cache_mp_write_session(struct cache_mp_write_session_ *ws) 1016158115Sume{ 1017158115Sume 1018158115Sume TRACE_IN(close_cache_mp_write_session); 1019158115Sume assert(ws != NULL); 1020158115Sume assert(ws->parent_entry != NULL); 1021158115Sume assert(ws->parent_entry->params->entry_type == CET_MULTIPART); 1022158115Sume 1023158115Sume TAILQ_REMOVE(&ws->parent_entry->ws_head, ws, entries); 1024158115Sume --ws->parent_entry->ws_size; 1025158115Sume 1026158115Sume if (ws->parent_entry->completed_write_session == NULL) { 1027158115Sume /* 1028158115Sume * If there is no completed session yet, this will be the one 1029158115Sume */ 1030158115Sume ws->parent_entry->get_time_func( 1031158115Sume &ws->parent_entry->creation_time); 1032158115Sume ws->parent_entry->completed_write_session = ws; 1033158115Sume } else { 1034158115Sume /* 1035158115Sume * If there is a completed session, then we'll save our session 1036158115Sume * as a pending session. If there is already a pending session, 1037158115Sume * it would be destroyed. 1038158115Sume */ 1039158115Sume if (ws->parent_entry->pending_write_session != NULL) 1040158115Sume destroy_cache_mp_write_session( 1041158115Sume ws->parent_entry->pending_write_session); 1042158115Sume 1043158115Sume ws->parent_entry->pending_write_session = ws; 1044158115Sume } 1045158115Sume TRACE_OUT(close_cache_mp_write_session); 1046158115Sume} 1047158115Sume 1048158115Sume/* 1049158115Sume * Opens read session for the specified entry. Returns NULL on errors (when 1050158115Sume * there are no data in the entry, or the data are obsolete). 1051158115Sume */ 1052158115Sumestruct cache_mp_read_session_ * 1053158115Sumeopen_cache_mp_read_session(struct cache_entry_ *entry) 1054158115Sume{ 1055158115Sume struct cache_mp_entry_ *mp_entry; 1056158115Sume struct cache_mp_read_session_ *retval; 1057158115Sume 1058158115Sume TRACE_IN(open_cache_mp_read_session); 1059158115Sume assert(entry != NULL); 1060158115Sume assert(entry->params->entry_type == CET_MULTIPART); 1061158115Sume mp_entry = (struct cache_mp_entry_ *)entry; 1062158115Sume 1063158115Sume if (mp_entry->completed_write_session == NULL) { 1064158115Sume TRACE_OUT(open_cache_mp_read_session); 1065158115Sume return (NULL); 1066158115Sume } 1067158115Sume 1068158115Sume if ((mp_entry->mp_params.max_lifetime.tv_sec != 0) 1069158115Sume || (mp_entry->mp_params.max_lifetime.tv_usec != 0)) { 1070158115Sume if (mp_entry->last_request_time.tv_sec - 1071158115Sume mp_entry->last_request_time.tv_sec > 1072158115Sume mp_entry->mp_params.max_lifetime.tv_sec) { 1073158115Sume flush_cache_entry(entry); 1074158115Sume TRACE_OUT(open_cache_mp_read_session); 1075158115Sume return (NULL); 1076158115Sume } 1077158115Sume } 1078158115Sume 1079194104Sdes retval = calloc(1, 1080194104Sdes sizeof(*retval)); 1081158115Sume assert(retval != NULL); 1082158115Sume 1083158115Sume retval->parent_entry = mp_entry; 1084158115Sume retval->current_item = TAILQ_FIRST( 1085158115Sume &mp_entry->completed_write_session->items); 1086158115Sume 1087158115Sume TAILQ_INSERT_HEAD(&mp_entry->rs_head, retval, entries); 1088158115Sume ++mp_entry->rs_size; 1089158115Sume 1090158115Sume mp_entry->get_time_func(&mp_entry->last_request_time); 1091158115Sume TRACE_OUT(open_cache_mp_read_session); 1092158115Sume return (retval); 1093158115Sume} 1094158115Sume 1095158115Sume/* 1096158115Sume * Reads the data from the read session - step by step. 1097158115Sume * Returns 0 on success, -1 on error (when there are no more data), and -2 if 1098158115Sume * the data_size is too small. In the last case, data_size would be filled 1099158115Sume * the proper value. 1100158115Sume */ 1101158115Sumeint 1102158115Sumecache_mp_read(struct cache_mp_read_session_ *rs, char *data, size_t *data_size) 1103158115Sume{ 1104158115Sume 1105158115Sume TRACE_IN(cache_mp_read); 1106158115Sume assert(rs != NULL); 1107158115Sume 1108158115Sume if (rs->current_item == NULL) { 1109158115Sume TRACE_OUT(cache_mp_read); 1110158115Sume return (-1); 1111158115Sume } 1112158115Sume 1113158115Sume if (rs->current_item->value_size > *data_size) { 1114158115Sume *data_size = rs->current_item->value_size; 1115158115Sume if (data == NULL) { 1116158115Sume TRACE_OUT(cache_mp_read); 1117158115Sume return (0); 1118158115Sume } 1119158115Sume 1120158115Sume TRACE_OUT(cache_mp_read); 1121158115Sume return (-2); 1122158115Sume } 1123158115Sume 1124158115Sume *data_size = rs->current_item->value_size; 1125158115Sume memcpy(data, rs->current_item->value, rs->current_item->value_size); 1126158115Sume rs->current_item = TAILQ_NEXT(rs->current_item, entries); 1127158115Sume 1128158115Sume TRACE_OUT(cache_mp_read); 1129158115Sume return (0); 1130158115Sume} 1131158115Sume 1132158115Sume/* 1133158115Sume * Closes the read session. If there are no more read sessions and there is 1134158115Sume * a pending write session, it will be committed and old 1135158115Sume * completed_write_session will be destroyed. 1136158115Sume */ 1137158115Sumevoid 1138158115Sumeclose_cache_mp_read_session(struct cache_mp_read_session_ *rs) 1139158115Sume{ 1140158115Sume 1141158115Sume TRACE_IN(close_cache_mp_read_session); 1142158115Sume assert(rs != NULL); 1143158115Sume assert(rs->parent_entry != NULL); 1144158115Sume 1145158115Sume TAILQ_REMOVE(&rs->parent_entry->rs_head, rs, entries); 1146158115Sume --rs->parent_entry->rs_size; 1147158115Sume 1148158115Sume if ((rs->parent_entry->rs_size == 0) && 1149158115Sume (rs->parent_entry->pending_write_session != NULL)) { 1150158115Sume destroy_cache_mp_write_session( 1151158115Sume rs->parent_entry->completed_write_session); 1152158115Sume rs->parent_entry->completed_write_session = 1153158115Sume rs->parent_entry->pending_write_session; 1154158115Sume rs->parent_entry->pending_write_session = NULL; 1155158115Sume } 1156158115Sume 1157158115Sume destroy_cache_mp_read_session(rs); 1158158115Sume TRACE_OUT(close_cache_mp_read_session); 1159158115Sume} 1160158115Sume 1161158115Sumeint 1162158115Sumetransform_cache_entry(struct cache_entry_ *entry, 1163158115Sume enum cache_transformation_t transformation) 1164158115Sume{ 1165158115Sume 1166158115Sume TRACE_IN(transform_cache_entry); 1167158115Sume switch (transformation) { 1168158115Sume case CTT_CLEAR: 1169158115Sume clear_cache_entry(entry); 1170158115Sume TRACE_OUT(transform_cache_entry); 1171158115Sume return (0); 1172158115Sume case CTT_FLUSH: 1173158115Sume flush_cache_entry(entry); 1174158115Sume TRACE_OUT(transform_cache_entry); 1175158115Sume return (0); 1176158115Sume default: 1177158115Sume TRACE_OUT(transform_cache_entry); 1178158115Sume return (-1); 1179158115Sume } 1180158115Sume} 1181158115Sume 1182158115Sumeint 1183158115Sumetransform_cache_entry_part(struct cache_entry_ *entry, 1184158115Sume enum cache_transformation_t transformation, const char *key_part, 1185158115Sume size_t key_part_size, enum part_position_t part_position) 1186158115Sume{ 1187158115Sume struct cache_common_entry_ *common_entry; 1188158115Sume struct cache_ht_item_ *ht_item; 1189158115Sume struct cache_ht_item_data_ *ht_item_data, ht_key; 1190158115Sume 1191158115Sume struct cache_policy_item_ *item, *connected_item; 1192158115Sume 1193158115Sume TRACE_IN(transform_cache_entry_part); 1194158115Sume if (entry->params->entry_type != CET_COMMON) { 1195158115Sume TRACE_OUT(transform_cache_entry_part); 1196158115Sume return (-1); 1197158115Sume } 1198158115Sume 1199158115Sume if (transformation != CTT_CLEAR) { 1200158115Sume TRACE_OUT(transform_cache_entry_part); 1201158115Sume return (-1); 1202158115Sume } 1203158115Sume 1204158115Sume memset(&ht_key, 0, sizeof(struct cache_ht_item_data_)); 1205158115Sume ht_key.key = (char *)key_part; /* can't avoid casting here */ 1206158115Sume ht_key.key_size = key_part_size; 1207158115Sume 1208158115Sume common_entry = (struct cache_common_entry_ *)entry; 1209158115Sume HASHTABLE_FOREACH(&(common_entry->items), ht_item) { 1210158115Sume do { 1211158115Sume ht_item_data = HASHTABLE_ENTRY_FIND_SPECIAL(cache_ht_, 1212158115Sume ht_item, &ht_key, 1213158115Sume ht_items_fixed_size_left_cmp_func); 1214158115Sume 1215158115Sume if (ht_item_data != NULL) { 1216158115Sume item = ht_item_data->fifo_policy_item; 1217158115Sume connected_item = item->connected_item; 1218158115Sume 1219158115Sume common_entry->policies[0]->remove_item_func( 1220158115Sume common_entry->policies[0], 1221158115Sume item); 1222158115Sume 1223158115Sume free(ht_item_data->key); 1224158115Sume free(ht_item_data->value); 1225158115Sume HASHTABLE_ENTRY_REMOVE(cache_ht_, ht_item, 1226158115Sume ht_item_data); 1227158115Sume --common_entry->items_size; 1228158115Sume 1229158115Sume common_entry->policies[0]->destroy_item_func( 1230158115Sume item); 1231158115Sume if (common_entry->policies_size == 2) { 1232158115Sume common_entry->policies[1]->remove_item_func( 1233158115Sume common_entry->policies[1], 1234158115Sume connected_item); 1235158115Sume common_entry->policies[1]->destroy_item_func( 1236158115Sume connected_item); 1237158115Sume } 1238158115Sume } 1239158115Sume } while (ht_item_data != NULL); 1240158115Sume } 1241158115Sume 1242158115Sume TRACE_OUT(transform_cache_entry_part); 1243158115Sume return (0); 1244158115Sume} 1245