1*86d7f5d3SJohn Marino /*- 2*86d7f5d3SJohn Marino * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 3*86d7f5d3SJohn Marino * All rights reserved. 4*86d7f5d3SJohn Marino * 5*86d7f5d3SJohn Marino * Redistribution and use in source and binary forms, with or without 6*86d7f5d3SJohn Marino * modification, are permitted provided that the following conditions 7*86d7f5d3SJohn Marino * are met: 8*86d7f5d3SJohn Marino * 1. Redistributions of source code must retain the above copyright 9*86d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer. 10*86d7f5d3SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright 11*86d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer in the 12*86d7f5d3SJohn Marino * documentation and/or other materials provided with the distribution. 13*86d7f5d3SJohn Marino * 14*86d7f5d3SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*86d7f5d3SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*86d7f5d3SJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*86d7f5d3SJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*86d7f5d3SJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*86d7f5d3SJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*86d7f5d3SJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*86d7f5d3SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*86d7f5d3SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*86d7f5d3SJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*86d7f5d3SJohn Marino * SUCH DAMAGE. 25*86d7f5d3SJohn Marino * 26*86d7f5d3SJohn Marino * $FreeBSD: src/usr.sbin/nscd/cachelib.h,v 1.3 2007/09/27 12:30:11 bushman Exp $ 27*86d7f5d3SJohn Marino */ 28*86d7f5d3SJohn Marino 29*86d7f5d3SJohn Marino #ifndef __NSCD_CACHELIB_H__ 30*86d7f5d3SJohn Marino #define __NSCD_CACHELIB_H__ 31*86d7f5d3SJohn Marino 32*86d7f5d3SJohn Marino #include <sys/queue.h> 33*86d7f5d3SJohn Marino #include <sys/time.h> 34*86d7f5d3SJohn Marino #include <stdlib.h> 35*86d7f5d3SJohn Marino #include "hashtable.h" 36*86d7f5d3SJohn Marino #include "cacheplcs.h" 37*86d7f5d3SJohn Marino 38*86d7f5d3SJohn Marino enum cache_entry_t { 39*86d7f5d3SJohn Marino CET_COMMON = 0, /* cache item is atomic */ 40*86d7f5d3SJohn Marino CET_MULTIPART /* cache item is formed part by part */ 41*86d7f5d3SJohn Marino }; 42*86d7f5d3SJohn Marino 43*86d7f5d3SJohn Marino enum cache_transformation_t { 44*86d7f5d3SJohn Marino CTT_FLUSH = 0, /* flush the cache - delete all obsolete items */ 45*86d7f5d3SJohn Marino CTT_CLEAR = 1 /* delete all items in the cache */ 46*86d7f5d3SJohn Marino }; 47*86d7f5d3SJohn Marino 48*86d7f5d3SJohn Marino /* cache deletion policy type enum */ 49*86d7f5d3SJohn Marino enum cache_policy_t { 50*86d7f5d3SJohn Marino CPT_FIFO = 0, /* first-in first-out */ 51*86d7f5d3SJohn Marino CPT_LRU = 1, /* least recently used */ 52*86d7f5d3SJohn Marino CPT_LFU = 2 /* least frequently used */ 53*86d7f5d3SJohn Marino }; 54*86d7f5d3SJohn Marino 55*86d7f5d3SJohn Marino /* multipart sessions can be used for reading and writing */ 56*86d7f5d3SJohn Marino enum cache_mp_session_t { 57*86d7f5d3SJohn Marino CMPT_READ_SESSION, 58*86d7f5d3SJohn Marino CMPT_WRITE_SESSION 59*86d7f5d3SJohn Marino }; 60*86d7f5d3SJohn Marino 61*86d7f5d3SJohn Marino /* 62*86d7f5d3SJohn Marino * When doing partial transformations of entries (which are applied for 63*86d7f5d3SJohn Marino * elements with keys, that contain specified buffer in its left or 64*86d7f5d3SJohn Marino * right part), this enum will show the needed position of the key part. 65*86d7f5d3SJohn Marino */ 66*86d7f5d3SJohn Marino enum part_position_t { 67*86d7f5d3SJohn Marino KPPT_LEFT, 68*86d7f5d3SJohn Marino KPPT_RIGHT 69*86d7f5d3SJohn Marino }; 70*86d7f5d3SJohn Marino 71*86d7f5d3SJohn Marino /* num_levels attribute is obsolete, i think - user can always emulate it 72*86d7f5d3SJohn Marino * by using one entry. 73*86d7f5d3SJohn Marino * get_time_func is needed to have the clocks-independent counter 74*86d7f5d3SJohn Marino */ 75*86d7f5d3SJohn Marino struct cache_params 76*86d7f5d3SJohn Marino { 77*86d7f5d3SJohn Marino void (*get_time_func)(struct timeval *); 78*86d7f5d3SJohn Marino }; 79*86d7f5d3SJohn Marino 80*86d7f5d3SJohn Marino /* 81*86d7f5d3SJohn Marino * base structure - normal_cache_entry_params and multipart_cache_entry_params 82*86d7f5d3SJohn Marino * are "inherited" from it 83*86d7f5d3SJohn Marino */ 84*86d7f5d3SJohn Marino struct cache_entry_params 85*86d7f5d3SJohn Marino { 86*86d7f5d3SJohn Marino enum cache_entry_t entry_type; 87*86d7f5d3SJohn Marino char *entry_name; 88*86d7f5d3SJohn Marino }; 89*86d7f5d3SJohn Marino 90*86d7f5d3SJohn Marino /* params, used for most entries */ 91*86d7f5d3SJohn Marino struct common_cache_entry_params 92*86d7f5d3SJohn Marino { 93*86d7f5d3SJohn Marino /* inherited fields */ 94*86d7f5d3SJohn Marino enum cache_entry_t entry_type; 95*86d7f5d3SJohn Marino 96*86d7f5d3SJohn Marino /* unique fields */ 97*86d7f5d3SJohn Marino char *entry_name; 98*86d7f5d3SJohn Marino size_t cache_entries_size; 99*86d7f5d3SJohn Marino 100*86d7f5d3SJohn Marino size_t max_elemsize; /* if 0 then no check is made */ 101*86d7f5d3SJohn Marino size_t satisf_elemsize; /* if entry size is exceeded, 102*86d7f5d3SJohn Marino * this number of elements will be left, 103*86d7f5d3SJohn Marino * others will be deleted */ 104*86d7f5d3SJohn Marino struct timeval max_lifetime; /* if 0 then no check is made */ 105*86d7f5d3SJohn Marino enum cache_policy_t policy; /* policy used for transformations */ 106*86d7f5d3SJohn Marino }; 107*86d7f5d3SJohn Marino 108*86d7f5d3SJohn Marino /* params, used for multipart entries */ 109*86d7f5d3SJohn Marino struct mp_cache_entry_params 110*86d7f5d3SJohn Marino { 111*86d7f5d3SJohn Marino /* inherited fields */ 112*86d7f5d3SJohn Marino enum cache_entry_t entry_type; 113*86d7f5d3SJohn Marino char *entry_name; 114*86d7f5d3SJohn Marino 115*86d7f5d3SJohn Marino /* unique fields */ 116*86d7f5d3SJohn Marino size_t max_elemsize; /* if 0 then no check is made */ 117*86d7f5d3SJohn Marino size_t max_sessions; /* maximum number of active sessions */ 118*86d7f5d3SJohn Marino 119*86d7f5d3SJohn Marino struct timeval max_lifetime; /* maximum elements lifetime */ 120*86d7f5d3SJohn Marino }; 121*86d7f5d3SJohn Marino 122*86d7f5d3SJohn Marino struct cache_ht_item_data_ 123*86d7f5d3SJohn Marino { 124*86d7f5d3SJohn Marino /* key is the bytes sequence only - not the null-terminated string */ 125*86d7f5d3SJohn Marino char *key; 126*86d7f5d3SJohn Marino size_t key_size; 127*86d7f5d3SJohn Marino 128*86d7f5d3SJohn Marino char *value; 129*86d7f5d3SJohn Marino size_t value_size; 130*86d7f5d3SJohn Marino 131*86d7f5d3SJohn Marino struct cache_policy_item_ *fifo_policy_item; 132*86d7f5d3SJohn Marino }; 133*86d7f5d3SJohn Marino 134*86d7f5d3SJohn Marino struct cache_ht_item_ 135*86d7f5d3SJohn Marino { 136*86d7f5d3SJohn Marino HASHTABLE_ENTRY_HEAD(ht_item_, struct cache_ht_item_data_) data; 137*86d7f5d3SJohn Marino }; 138*86d7f5d3SJohn Marino 139*86d7f5d3SJohn Marino struct cache_entry_ 140*86d7f5d3SJohn Marino { 141*86d7f5d3SJohn Marino char *name; 142*86d7f5d3SJohn Marino struct cache_entry_params *params; 143*86d7f5d3SJohn Marino }; 144*86d7f5d3SJohn Marino 145*86d7f5d3SJohn Marino struct cache_common_entry_ 146*86d7f5d3SJohn Marino { 147*86d7f5d3SJohn Marino char *name; 148*86d7f5d3SJohn Marino struct cache_entry_params *params; 149*86d7f5d3SJohn Marino 150*86d7f5d3SJohn Marino struct common_cache_entry_params common_params; 151*86d7f5d3SJohn Marino 152*86d7f5d3SJohn Marino HASHTABLE_HEAD(cache_ht_, cache_ht_item_) items; 153*86d7f5d3SJohn Marino size_t items_size; 154*86d7f5d3SJohn Marino 155*86d7f5d3SJohn Marino /* 156*86d7f5d3SJohn Marino * Entry always has the FIFO policy, that is used to eliminate old 157*86d7f5d3SJohn Marino * elements (the ones, with lifetime more than max_lifetime). Besides, 158*86d7f5d3SJohn Marino * user can specify another policy to be applied, when there are too 159*86d7f5d3SJohn Marino * many elements in the entry. So policies_size can be 1 or 2. 160*86d7f5d3SJohn Marino */ 161*86d7f5d3SJohn Marino struct cache_policy_ **policies; 162*86d7f5d3SJohn Marino size_t policies_size; 163*86d7f5d3SJohn Marino 164*86d7f5d3SJohn Marino void (*get_time_func)(struct timeval *); 165*86d7f5d3SJohn Marino }; 166*86d7f5d3SJohn Marino 167*86d7f5d3SJohn Marino struct cache_mp_data_item_ { 168*86d7f5d3SJohn Marino char *value; 169*86d7f5d3SJohn Marino size_t value_size; 170*86d7f5d3SJohn Marino 171*86d7f5d3SJohn Marino TAILQ_ENTRY(cache_mp_data_item_) entries; 172*86d7f5d3SJohn Marino }; 173*86d7f5d3SJohn Marino 174*86d7f5d3SJohn Marino struct cache_mp_write_session_ 175*86d7f5d3SJohn Marino { 176*86d7f5d3SJohn Marino struct cache_mp_entry_ *parent_entry; 177*86d7f5d3SJohn Marino 178*86d7f5d3SJohn Marino /* 179*86d7f5d3SJohn Marino * All items are accumulated in this queue. When the session is 180*86d7f5d3SJohn Marino * committed, they all will be copied to the multipart entry. 181*86d7f5d3SJohn Marino */ 182*86d7f5d3SJohn Marino TAILQ_HEAD(cache_mp_data_item_head, cache_mp_data_item_) items; 183*86d7f5d3SJohn Marino size_t items_size; 184*86d7f5d3SJohn Marino 185*86d7f5d3SJohn Marino TAILQ_ENTRY(cache_mp_write_session_) entries; 186*86d7f5d3SJohn Marino }; 187*86d7f5d3SJohn Marino 188*86d7f5d3SJohn Marino struct cache_mp_read_session_ 189*86d7f5d3SJohn Marino { 190*86d7f5d3SJohn Marino struct cache_mp_entry_ *parent_entry; 191*86d7f5d3SJohn Marino struct cache_mp_data_item_ *current_item; 192*86d7f5d3SJohn Marino 193*86d7f5d3SJohn Marino TAILQ_ENTRY(cache_mp_read_session_) entries; 194*86d7f5d3SJohn Marino }; 195*86d7f5d3SJohn Marino 196*86d7f5d3SJohn Marino struct cache_mp_entry_ 197*86d7f5d3SJohn Marino { 198*86d7f5d3SJohn Marino char *name; 199*86d7f5d3SJohn Marino struct cache_entry_params *params; 200*86d7f5d3SJohn Marino 201*86d7f5d3SJohn Marino struct mp_cache_entry_params mp_params; 202*86d7f5d3SJohn Marino 203*86d7f5d3SJohn Marino /* All opened write sessions */ 204*86d7f5d3SJohn Marino TAILQ_HEAD(write_sessions_head, cache_mp_write_session_) ws_head; 205*86d7f5d3SJohn Marino size_t ws_size; 206*86d7f5d3SJohn Marino 207*86d7f5d3SJohn Marino /* All opened read sessions */ 208*86d7f5d3SJohn Marino TAILQ_HEAD(read_sessions_head, cache_mp_read_session_) rs_head; 209*86d7f5d3SJohn Marino size_t rs_size; 210*86d7f5d3SJohn Marino 211*86d7f5d3SJohn Marino /* 212*86d7f5d3SJohn Marino * completed_write_session is the committed write sessions. All read 213*86d7f5d3SJohn Marino * sessions use data from it. If the completed_write_session is out of 214*86d7f5d3SJohn Marino * date, but still in use by some of the read sessions, the newly 215*86d7f5d3SJohn Marino * committed write session is stored in the pending_write_session. 216*86d7f5d3SJohn Marino * In such a case, completed_write_session will be substituted with 217*86d7f5d3SJohn Marino * pending_write_session as soon as it won't be used by any of 218*86d7f5d3SJohn Marino * the read sessions. 219*86d7f5d3SJohn Marino */ 220*86d7f5d3SJohn Marino struct cache_mp_write_session_ *completed_write_session; 221*86d7f5d3SJohn Marino struct cache_mp_write_session_ *pending_write_session; 222*86d7f5d3SJohn Marino struct timeval creation_time; 223*86d7f5d3SJohn Marino struct timeval last_request_time; 224*86d7f5d3SJohn Marino 225*86d7f5d3SJohn Marino void (*get_time_func)(struct timeval *); 226*86d7f5d3SJohn Marino }; 227*86d7f5d3SJohn Marino 228*86d7f5d3SJohn Marino struct cache_ 229*86d7f5d3SJohn Marino { 230*86d7f5d3SJohn Marino struct cache_params params; 231*86d7f5d3SJohn Marino 232*86d7f5d3SJohn Marino struct cache_entry_ **entries; 233*86d7f5d3SJohn Marino size_t entries_capacity; 234*86d7f5d3SJohn Marino size_t entries_size; 235*86d7f5d3SJohn Marino }; 236*86d7f5d3SJohn Marino 237*86d7f5d3SJohn Marino /* simple abstractions - for not to write "struct" every time */ 238*86d7f5d3SJohn Marino typedef struct cache_ *cache; 239*86d7f5d3SJohn Marino typedef struct cache_entry_ *cache_entry; 240*86d7f5d3SJohn Marino typedef struct cache_mp_write_session_ *cache_mp_write_session; 241*86d7f5d3SJohn Marino typedef struct cache_mp_read_session_ *cache_mp_read_session; 242*86d7f5d3SJohn Marino 243*86d7f5d3SJohn Marino #define INVALID_CACHE (NULL) 244*86d7f5d3SJohn Marino #define INVALID_CACHE_ENTRY (NULL) 245*86d7f5d3SJohn Marino #define INVALID_CACHE_MP_WRITE_SESSION (NULL) 246*86d7f5d3SJohn Marino #define INVALID_CACHE_MP_READ_SESSION (NULL) 247*86d7f5d3SJohn Marino 248*86d7f5d3SJohn Marino /* 249*86d7f5d3SJohn Marino * NOTE: all cache operations are thread-unsafe. You must ensure thread-safety 250*86d7f5d3SJohn Marino * externally, by yourself. 251*86d7f5d3SJohn Marino */ 252*86d7f5d3SJohn Marino 253*86d7f5d3SJohn Marino /* cache initialization/destruction routines */ 254*86d7f5d3SJohn Marino extern cache init_cache(struct cache_params const *); 255*86d7f5d3SJohn Marino extern void destroy_cache(cache); 256*86d7f5d3SJohn Marino 257*86d7f5d3SJohn Marino /* cache entries manipulation routines */ 258*86d7f5d3SJohn Marino extern int register_cache_entry(cache, struct cache_entry_params const *); 259*86d7f5d3SJohn Marino extern int unregister_cache_entry(cache, const char *); 260*86d7f5d3SJohn Marino extern cache_entry find_cache_entry(cache, const char *); 261*86d7f5d3SJohn Marino 262*86d7f5d3SJohn Marino /* read/write operations used on common entries */ 263*86d7f5d3SJohn Marino extern int cache_read(cache_entry, const char *, size_t, char *, size_t *); 264*86d7f5d3SJohn Marino extern int cache_write(cache_entry, const char *, size_t, char const *, size_t); 265*86d7f5d3SJohn Marino 266*86d7f5d3SJohn Marino /* read/write operations used on multipart entries */ 267*86d7f5d3SJohn Marino extern cache_mp_write_session open_cache_mp_write_session(cache_entry); 268*86d7f5d3SJohn Marino extern int cache_mp_write(cache_mp_write_session, char *, size_t); 269*86d7f5d3SJohn Marino extern void abandon_cache_mp_write_session(cache_mp_write_session); 270*86d7f5d3SJohn Marino extern void close_cache_mp_write_session(cache_mp_write_session); 271*86d7f5d3SJohn Marino 272*86d7f5d3SJohn Marino extern cache_mp_read_session open_cache_mp_read_session(cache_entry); 273*86d7f5d3SJohn Marino extern int cache_mp_read(cache_mp_read_session, char *, size_t *); 274*86d7f5d3SJohn Marino extern void close_cache_mp_read_session(cache_mp_read_session); 275*86d7f5d3SJohn Marino 276*86d7f5d3SJohn Marino /* transformation routines */ 277*86d7f5d3SJohn Marino extern int transform_cache_entry(cache_entry, enum cache_transformation_t); 278*86d7f5d3SJohn Marino extern int transform_cache_entry_part(cache_entry, enum cache_transformation_t, 279*86d7f5d3SJohn Marino const char *, size_t, enum part_position_t); 280*86d7f5d3SJohn Marino 281*86d7f5d3SJohn Marino #endif 282