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 } 729158115Sume 730158115Sume if ((common_entry->common_params.max_lifetime.tv_sec != 0) || 731158115Sume (common_entry->common_params.max_lifetime.tv_usec != 0)) { 732158115Sume 733158115Sume if (find_res->fifo_policy_item->last_request_time.tv_sec - 734158115Sume find_res->fifo_policy_item->creation_time.tv_sec > 735158115Sume common_entry->common_params.max_lifetime.tv_sec) { 736158115Sume 737158115Sume free(find_res->key); 738158115Sume free(find_res->value); 739158115Sume 740158115Sume connected_item = 741158115Sume find_res->fifo_policy_item->connected_item; 742158115Sume if (connected_item != NULL) { 743158115Sume common_entry->policies[1]->remove_item_func( 744158115Sume common_entry->policies[1], 745158115Sume connected_item); 746158115Sume common_entry->policies[1]->destroy_item_func( 747158115Sume connected_item); 748158115Sume } 749158115Sume 750158115Sume common_entry->policies[0]->remove_item_func( 751158115Sume common_entry->policies[0], 752158115Sume find_res->fifo_policy_item); 753158115Sume common_entry->policies[0]->destroy_item_func( 754158115Sume find_res->fifo_policy_item); 755158115Sume 756158115Sume HASHTABLE_ENTRY_REMOVE(cache_ht_, item, find_res); 757158115Sume --common_entry->items_size; 758158115Sume } 759158115Sume } 760158115Sume 761158115Sume if ((*value_size < find_res->value_size) || (value == NULL)) { 762158115Sume *value_size = find_res->value_size; 763158115Sume TRACE_OUT(cache_read); 764158115Sume return (-2); 765158115Sume } 766158115Sume 767158115Sume *value_size = find_res->value_size; 768158115Sume memcpy(value, find_res->value, find_res->value_size); 769158115Sume 770158115Sume ++find_res->fifo_policy_item->request_count; 771158115Sume common_entry->get_time_func( 772158115Sume &find_res->fifo_policy_item->last_request_time); 773158115Sume common_entry->policies[0]->update_item_func(common_entry->policies[0], 774158115Sume find_res->fifo_policy_item); 775158115Sume 776158115Sume if (find_res->fifo_policy_item->connected_item != NULL) { 777158115Sume connected_item = find_res->fifo_policy_item->connected_item; 778158115Sume memcpy(&connected_item->last_request_time, 779158115Sume &find_res->fifo_policy_item->last_request_time, 780158115Sume sizeof(struct timeval)); 781158115Sume connected_item->request_count = 782158115Sume find_res->fifo_policy_item->request_count; 783158115Sume 784158115Sume common_entry->policies[1]->update_item_func( 785158115Sume common_entry->policies[1], connected_item); 786158115Sume } 787158115Sume 788158115Sume TRACE_OUT(cache_read); 789158115Sume return (0); 790158115Sume} 791158115Sume 792158115Sume/* 793158115Sume * Writes the value with the specified key into the cache entry. 794158115Sume * Functions returns 0 on success, and -1 on error. 795158115Sume */ 796158115Sumeint 797158115Sumecache_write(struct cache_entry_ *entry, const char *key, size_t key_size, 798158115Sume char const *value, size_t value_size) 799158115Sume{ 800158115Sume struct cache_common_entry_ *common_entry; 801158115Sume struct cache_ht_item_data_ item_data, *find_res; 802158115Sume struct cache_ht_item_ *item; 803158115Sume hashtable_index_t hash; 804158115Sume 805158115Sume struct cache_policy_ *policy, *connected_policy; 806158115Sume struct cache_policy_item_ *policy_item; 807158115Sume struct cache_policy_item_ *connected_policy_item; 808158115Sume 809158115Sume TRACE_IN(cache_write); 810158115Sume assert(entry != NULL); 811158115Sume assert(key != NULL); 812158115Sume assert(value != NULL); 813158115Sume assert(entry->params->entry_type == CET_COMMON); 814158115Sume 815158115Sume common_entry = (struct cache_common_entry_ *)entry; 816158115Sume 817158115Sume memset(&item_data, 0, sizeof(struct cache_ht_item_data_)); 818158115Sume /* can't avoid the cast here */ 819158115Sume item_data.key = (char *)key; 820158115Sume item_data.key_size = key_size; 821158115Sume 822158115Sume hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &common_entry->items, 823158115Sume &item_data); 824158115Sume assert(hash < HASHTABLE_ENTRIES_COUNT(&common_entry->items)); 825158115Sume 826158115Sume item = HASHTABLE_GET_ENTRY(&(common_entry->items), hash); 827158115Sume find_res = HASHTABLE_ENTRY_FIND(cache_ht_, item, &item_data); 828158115Sume if (find_res != NULL) { 829158115Sume TRACE_OUT(cache_write); 830158115Sume return (-1); 831158115Sume } 832158115Sume 833194104Sdes item_data.key = malloc(key_size); 834158115Sume memcpy(item_data.key, key, key_size); 835158115Sume 836194104Sdes item_data.value = malloc(value_size); 837158115Sume assert(item_data.value != NULL); 838158115Sume 839158115Sume memcpy(item_data.value, value, value_size); 840158115Sume item_data.value_size = value_size; 841158115Sume 842158115Sume policy_item = common_entry->policies[0]->create_item_func(); 843158115Sume policy_item->key = item_data.key; 844158115Sume policy_item->key_size = item_data.key_size; 845158115Sume common_entry->get_time_func(&policy_item->creation_time); 846158115Sume 847158115Sume if (common_entry->policies_size > 1) { 848158115Sume connected_policy_item = 849158115Sume common_entry->policies[1]->create_item_func(); 850158115Sume memcpy(&connected_policy_item->creation_time, 851158115Sume &policy_item->creation_time, 852158115Sume sizeof(struct timeval)); 853158115Sume connected_policy_item->key = policy_item->key; 854158115Sume connected_policy_item->key_size = policy_item->key_size; 855158115Sume 856158115Sume connected_policy_item->connected_item = policy_item; 857158115Sume policy_item->connected_item = connected_policy_item; 858158115Sume } 859158115Sume 860158115Sume item_data.fifo_policy_item = policy_item; 861158115Sume 862158115Sume common_entry->policies[0]->add_item_func(common_entry->policies[0], 863158115Sume policy_item); 864158115Sume if (common_entry->policies_size > 1) 865158115Sume common_entry->policies[1]->add_item_func( 866158115Sume common_entry->policies[1], connected_policy_item); 867158115Sume 868158115Sume HASHTABLE_ENTRY_STORE(cache_ht_, item, &item_data); 869158115Sume ++common_entry->items_size; 870158115Sume 871158115Sume if ((common_entry->common_params.max_elemsize != 0) && 872158115Sume (common_entry->items_size > 873158115Sume common_entry->common_params.max_elemsize)) { 874158115Sume if (common_entry->policies_size > 1) { 875158115Sume policy = common_entry->policies[1]; 876158115Sume connected_policy = common_entry->policies[0]; 877158115Sume } else { 878158115Sume policy = common_entry->policies[0]; 879158115Sume connected_policy = NULL; 880158115Sume } 881158115Sume 882158115Sume flush_cache_policy(common_entry, policy, connected_policy, 883158115Sume cache_elemsize_common_continue_func); 884158115Sume } 885158115Sume 886158115Sume TRACE_OUT(cache_write); 887158115Sume return (0); 888158115Sume} 889158115Sume 890158115Sume/* 891158115Sume * Initializes the write session for the specified multipart entry. This 892158115Sume * session then should be filled with data either committed or abandoned by 893158115Sume * using close_cache_mp_write_session or abandon_cache_mp_write_session 894158115Sume * respectively. 895158115Sume * Returns NULL on errors (when there are too many opened write sessions for 896158115Sume * the entry). 897158115Sume */ 898158115Sumestruct cache_mp_write_session_ * 899158115Sumeopen_cache_mp_write_session(struct cache_entry_ *entry) 900158115Sume{ 901158115Sume struct cache_mp_entry_ *mp_entry; 902158115Sume struct cache_mp_write_session_ *retval; 903158115Sume 904158115Sume TRACE_IN(open_cache_mp_write_session); 905158115Sume assert(entry != NULL); 906158115Sume assert(entry->params->entry_type == CET_MULTIPART); 907158115Sume mp_entry = (struct cache_mp_entry_ *)entry; 908158115Sume 909158115Sume if ((mp_entry->mp_params.max_sessions > 0) && 910158115Sume (mp_entry->ws_size == mp_entry->mp_params.max_sessions)) { 911158115Sume TRACE_OUT(open_cache_mp_write_session); 912158115Sume return (NULL); 913158115Sume } 914158115Sume 915194104Sdes retval = calloc(1, 916194104Sdes sizeof(*retval)); 917158115Sume assert(retval != NULL); 918158115Sume 919158115Sume TAILQ_INIT(&retval->items); 920158115Sume retval->parent_entry = mp_entry; 921158115Sume 922158115Sume TAILQ_INSERT_HEAD(&mp_entry->ws_head, retval, entries); 923158115Sume ++mp_entry->ws_size; 924158115Sume 925158115Sume TRACE_OUT(open_cache_mp_write_session); 926158115Sume return (retval); 927158115Sume} 928158115Sume 929158115Sume/* 930158115Sume * Writes data to the specified session. Return 0 on success and -1 on errors 931158115Sume * (when write session size limit is exceeded). 932158115Sume */ 933158115Sumeint 934158115Sumecache_mp_write(struct cache_mp_write_session_ *ws, char *data, 935158115Sume size_t data_size) 936158115Sume{ 937158115Sume struct cache_mp_data_item_ *new_item; 938158115Sume 939158115Sume TRACE_IN(cache_mp_write); 940158115Sume assert(ws != NULL); 941158115Sume assert(ws->parent_entry != NULL); 942158115Sume assert(ws->parent_entry->params->entry_type == CET_MULTIPART); 943158115Sume 944158115Sume if ((ws->parent_entry->mp_params.max_elemsize > 0) && 945158115Sume (ws->parent_entry->mp_params.max_elemsize == ws->items_size)) { 946158115Sume TRACE_OUT(cache_mp_write); 947158115Sume return (-1); 948158115Sume } 949158115Sume 950194104Sdes new_item = calloc(1, 951194104Sdes sizeof(*new_item)); 952158115Sume assert(new_item != NULL); 953158115Sume 954194104Sdes new_item->value = malloc(data_size); 955158115Sume assert(new_item->value != NULL); 956158115Sume memcpy(new_item->value, data, data_size); 957158115Sume new_item->value_size = data_size; 958158115Sume 959158115Sume TAILQ_INSERT_TAIL(&ws->items, new_item, entries); 960158115Sume ++ws->items_size; 961158115Sume 962158115Sume TRACE_OUT(cache_mp_write); 963158115Sume return (0); 964158115Sume} 965158115Sume 966158115Sume/* 967158115Sume * Abandons the write session and frees all the connected resources. 968158115Sume */ 969158115Sumevoid 970158115Sumeabandon_cache_mp_write_session(struct cache_mp_write_session_ *ws) 971158115Sume{ 972158115Sume 973158115Sume TRACE_IN(abandon_cache_mp_write_session); 974158115Sume assert(ws != NULL); 975158115Sume assert(ws->parent_entry != NULL); 976158115Sume assert(ws->parent_entry->params->entry_type == CET_MULTIPART); 977158115Sume 978158115Sume TAILQ_REMOVE(&ws->parent_entry->ws_head, ws, entries); 979158115Sume --ws->parent_entry->ws_size; 980158115Sume 981158115Sume destroy_cache_mp_write_session(ws); 982158115Sume TRACE_OUT(abandon_cache_mp_write_session); 983158115Sume} 984158115Sume 985158115Sume/* 986158115Sume * Commits the session to the entry, for which it was created. 987158115Sume */ 988158115Sumevoid 989158115Sumeclose_cache_mp_write_session(struct cache_mp_write_session_ *ws) 990158115Sume{ 991158115Sume 992158115Sume TRACE_IN(close_cache_mp_write_session); 993158115Sume assert(ws != NULL); 994158115Sume assert(ws->parent_entry != NULL); 995158115Sume assert(ws->parent_entry->params->entry_type == CET_MULTIPART); 996158115Sume 997158115Sume TAILQ_REMOVE(&ws->parent_entry->ws_head, ws, entries); 998158115Sume --ws->parent_entry->ws_size; 999158115Sume 1000158115Sume if (ws->parent_entry->completed_write_session == NULL) { 1001158115Sume /* 1002158115Sume * If there is no completed session yet, this will be the one 1003158115Sume */ 1004158115Sume ws->parent_entry->get_time_func( 1005158115Sume &ws->parent_entry->creation_time); 1006158115Sume ws->parent_entry->completed_write_session = ws; 1007158115Sume } else { 1008158115Sume /* 1009158115Sume * If there is a completed session, then we'll save our session 1010158115Sume * as a pending session. If there is already a pending session, 1011158115Sume * it would be destroyed. 1012158115Sume */ 1013158115Sume if (ws->parent_entry->pending_write_session != NULL) 1014158115Sume destroy_cache_mp_write_session( 1015158115Sume ws->parent_entry->pending_write_session); 1016158115Sume 1017158115Sume ws->parent_entry->pending_write_session = ws; 1018158115Sume } 1019158115Sume TRACE_OUT(close_cache_mp_write_session); 1020158115Sume} 1021158115Sume 1022158115Sume/* 1023158115Sume * Opens read session for the specified entry. Returns NULL on errors (when 1024158115Sume * there are no data in the entry, or the data are obsolete). 1025158115Sume */ 1026158115Sumestruct cache_mp_read_session_ * 1027158115Sumeopen_cache_mp_read_session(struct cache_entry_ *entry) 1028158115Sume{ 1029158115Sume struct cache_mp_entry_ *mp_entry; 1030158115Sume struct cache_mp_read_session_ *retval; 1031158115Sume 1032158115Sume TRACE_IN(open_cache_mp_read_session); 1033158115Sume assert(entry != NULL); 1034158115Sume assert(entry->params->entry_type == CET_MULTIPART); 1035158115Sume mp_entry = (struct cache_mp_entry_ *)entry; 1036158115Sume 1037158115Sume if (mp_entry->completed_write_session == NULL) { 1038158115Sume TRACE_OUT(open_cache_mp_read_session); 1039158115Sume return (NULL); 1040158115Sume } 1041158115Sume 1042158115Sume if ((mp_entry->mp_params.max_lifetime.tv_sec != 0) 1043158115Sume || (mp_entry->mp_params.max_lifetime.tv_usec != 0)) { 1044158115Sume if (mp_entry->last_request_time.tv_sec - 1045158115Sume mp_entry->last_request_time.tv_sec > 1046158115Sume mp_entry->mp_params.max_lifetime.tv_sec) { 1047158115Sume flush_cache_entry(entry); 1048158115Sume TRACE_OUT(open_cache_mp_read_session); 1049158115Sume return (NULL); 1050158115Sume } 1051158115Sume } 1052158115Sume 1053194104Sdes retval = calloc(1, 1054194104Sdes sizeof(*retval)); 1055158115Sume assert(retval != NULL); 1056158115Sume 1057158115Sume retval->parent_entry = mp_entry; 1058158115Sume retval->current_item = TAILQ_FIRST( 1059158115Sume &mp_entry->completed_write_session->items); 1060158115Sume 1061158115Sume TAILQ_INSERT_HEAD(&mp_entry->rs_head, retval, entries); 1062158115Sume ++mp_entry->rs_size; 1063158115Sume 1064158115Sume mp_entry->get_time_func(&mp_entry->last_request_time); 1065158115Sume TRACE_OUT(open_cache_mp_read_session); 1066158115Sume return (retval); 1067158115Sume} 1068158115Sume 1069158115Sume/* 1070158115Sume * Reads the data from the read session - step by step. 1071158115Sume * Returns 0 on success, -1 on error (when there are no more data), and -2 if 1072158115Sume * the data_size is too small. In the last case, data_size would be filled 1073158115Sume * the proper value. 1074158115Sume */ 1075158115Sumeint 1076158115Sumecache_mp_read(struct cache_mp_read_session_ *rs, char *data, size_t *data_size) 1077158115Sume{ 1078158115Sume 1079158115Sume TRACE_IN(cache_mp_read); 1080158115Sume assert(rs != NULL); 1081158115Sume 1082158115Sume if (rs->current_item == NULL) { 1083158115Sume TRACE_OUT(cache_mp_read); 1084158115Sume return (-1); 1085158115Sume } 1086158115Sume 1087158115Sume if (rs->current_item->value_size > *data_size) { 1088158115Sume *data_size = rs->current_item->value_size; 1089158115Sume if (data == NULL) { 1090158115Sume TRACE_OUT(cache_mp_read); 1091158115Sume return (0); 1092158115Sume } 1093158115Sume 1094158115Sume TRACE_OUT(cache_mp_read); 1095158115Sume return (-2); 1096158115Sume } 1097158115Sume 1098158115Sume *data_size = rs->current_item->value_size; 1099158115Sume memcpy(data, rs->current_item->value, rs->current_item->value_size); 1100158115Sume rs->current_item = TAILQ_NEXT(rs->current_item, entries); 1101158115Sume 1102158115Sume TRACE_OUT(cache_mp_read); 1103158115Sume return (0); 1104158115Sume} 1105158115Sume 1106158115Sume/* 1107158115Sume * Closes the read session. If there are no more read sessions and there is 1108158115Sume * a pending write session, it will be committed and old 1109158115Sume * completed_write_session will be destroyed. 1110158115Sume */ 1111158115Sumevoid 1112158115Sumeclose_cache_mp_read_session(struct cache_mp_read_session_ *rs) 1113158115Sume{ 1114158115Sume 1115158115Sume TRACE_IN(close_cache_mp_read_session); 1116158115Sume assert(rs != NULL); 1117158115Sume assert(rs->parent_entry != NULL); 1118158115Sume 1119158115Sume TAILQ_REMOVE(&rs->parent_entry->rs_head, rs, entries); 1120158115Sume --rs->parent_entry->rs_size; 1121158115Sume 1122158115Sume if ((rs->parent_entry->rs_size == 0) && 1123158115Sume (rs->parent_entry->pending_write_session != NULL)) { 1124158115Sume destroy_cache_mp_write_session( 1125158115Sume rs->parent_entry->completed_write_session); 1126158115Sume rs->parent_entry->completed_write_session = 1127158115Sume rs->parent_entry->pending_write_session; 1128158115Sume rs->parent_entry->pending_write_session = NULL; 1129158115Sume } 1130158115Sume 1131158115Sume destroy_cache_mp_read_session(rs); 1132158115Sume TRACE_OUT(close_cache_mp_read_session); 1133158115Sume} 1134158115Sume 1135158115Sumeint 1136158115Sumetransform_cache_entry(struct cache_entry_ *entry, 1137158115Sume enum cache_transformation_t transformation) 1138158115Sume{ 1139158115Sume 1140158115Sume TRACE_IN(transform_cache_entry); 1141158115Sume switch (transformation) { 1142158115Sume case CTT_CLEAR: 1143158115Sume clear_cache_entry(entry); 1144158115Sume TRACE_OUT(transform_cache_entry); 1145158115Sume return (0); 1146158115Sume case CTT_FLUSH: 1147158115Sume flush_cache_entry(entry); 1148158115Sume TRACE_OUT(transform_cache_entry); 1149158115Sume return (0); 1150158115Sume default: 1151158115Sume TRACE_OUT(transform_cache_entry); 1152158115Sume return (-1); 1153158115Sume } 1154158115Sume} 1155158115Sume 1156158115Sumeint 1157158115Sumetransform_cache_entry_part(struct cache_entry_ *entry, 1158158115Sume enum cache_transformation_t transformation, const char *key_part, 1159158115Sume size_t key_part_size, enum part_position_t part_position) 1160158115Sume{ 1161158115Sume struct cache_common_entry_ *common_entry; 1162158115Sume struct cache_ht_item_ *ht_item; 1163158115Sume struct cache_ht_item_data_ *ht_item_data, ht_key; 1164158115Sume 1165158115Sume struct cache_policy_item_ *item, *connected_item; 1166158115Sume 1167158115Sume TRACE_IN(transform_cache_entry_part); 1168158115Sume if (entry->params->entry_type != CET_COMMON) { 1169158115Sume TRACE_OUT(transform_cache_entry_part); 1170158115Sume return (-1); 1171158115Sume } 1172158115Sume 1173158115Sume if (transformation != CTT_CLEAR) { 1174158115Sume TRACE_OUT(transform_cache_entry_part); 1175158115Sume return (-1); 1176158115Sume } 1177158115Sume 1178158115Sume memset(&ht_key, 0, sizeof(struct cache_ht_item_data_)); 1179158115Sume ht_key.key = (char *)key_part; /* can't avoid casting here */ 1180158115Sume ht_key.key_size = key_part_size; 1181158115Sume 1182158115Sume common_entry = (struct cache_common_entry_ *)entry; 1183158115Sume HASHTABLE_FOREACH(&(common_entry->items), ht_item) { 1184158115Sume do { 1185158115Sume ht_item_data = HASHTABLE_ENTRY_FIND_SPECIAL(cache_ht_, 1186158115Sume ht_item, &ht_key, 1187158115Sume ht_items_fixed_size_left_cmp_func); 1188158115Sume 1189158115Sume if (ht_item_data != NULL) { 1190158115Sume item = ht_item_data->fifo_policy_item; 1191158115Sume connected_item = item->connected_item; 1192158115Sume 1193158115Sume common_entry->policies[0]->remove_item_func( 1194158115Sume common_entry->policies[0], 1195158115Sume item); 1196158115Sume 1197158115Sume free(ht_item_data->key); 1198158115Sume free(ht_item_data->value); 1199158115Sume HASHTABLE_ENTRY_REMOVE(cache_ht_, ht_item, 1200158115Sume ht_item_data); 1201158115Sume --common_entry->items_size; 1202158115Sume 1203158115Sume common_entry->policies[0]->destroy_item_func( 1204158115Sume item); 1205158115Sume if (common_entry->policies_size == 2) { 1206158115Sume common_entry->policies[1]->remove_item_func( 1207158115Sume common_entry->policies[1], 1208158115Sume connected_item); 1209158115Sume common_entry->policies[1]->destroy_item_func( 1210158115Sume connected_item); 1211158115Sume } 1212158115Sume } 1213158115Sume } while (ht_item_data != NULL); 1214158115Sume } 1215158115Sume 1216158115Sume TRACE_OUT(transform_cache_entry_part); 1217158115Sume return (0); 1218158115Sume} 1219