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