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 "hashtable.h" 33 #include "cacheplcs.h" 34 35 enum cache_entry_t { 36 CET_COMMON = 0, /* cache item is atomic */ 37 CET_MULTIPART /* cache item is formed part by part */ 38 }; 39 40 enum cache_transformation_t { 41 CTT_FLUSH = 0, /* flush the cache - delete all obsolete items */ 42 CTT_CLEAR = 1 /* delete all items in the cache */ 43 }; 44 45 /* cache deletion policy type enum */ 46 enum cache_policy_t { 47 CPT_FIFO = 0, /* first-in first-out */ 48 CPT_LRU = 1, /* least recently used */ 49 CPT_LFU = 2 /* least frequently used */ 50 }; 51 52 /* multipart sessions can be used for reading and writing */ 53 enum cache_mp_session_t { 54 CMPT_READ_SESSION, 55 CMPT_WRITE_SESSION 56 }; 57 58 /* 59 * When doing partial transformations of entries (which are applied for 60 * elements with keys, that contain specified buffer in its left or 61 * right part), this enum will show the needed position of the key part. 62 */ 63 enum part_position_t { 64 KPPT_LEFT, 65 KPPT_RIGHT 66 }; 67 68 /* num_levels attribute is obsolete, i think - user can always emulate it 69 * by using one entry. 70 * get_time_func is needed to have the clocks-independent counter 71 */ 72 struct cache_params { 73 void (*get_time_func)(struct timeval *); 74 }; 75 76 /* 77 * base structure - normal_cache_entry_params and multipart_cache_entry_params 78 * are "inherited" from it 79 */ 80 struct cache_entry_params { 81 enum cache_entry_t entry_type; 82 char *entry_name; 83 }; 84 85 /* params, used for most entries */ 86 struct common_cache_entry_params { 87 struct cache_entry_params cep; 88 89 size_t cache_entries_size; 90 91 size_t max_elemsize; /* if 0 then no check is made */ 92 size_t satisf_elemsize; /* if entry size is exceeded, 93 * this number of elements will be left, 94 * others will be deleted */ 95 struct timeval max_lifetime; /* if 0 then no check is made */ 96 enum cache_policy_t policy; /* policy used for transformations */ 97 }; 98 99 /* params, used for multipart entries */ 100 struct mp_cache_entry_params { 101 struct cache_entry_params cep; 102 103 /* unique fields */ 104 size_t max_elemsize; /* if 0 then no check is made */ 105 size_t max_sessions; /* maximum number of active sessions */ 106 107 struct timeval max_lifetime; /* maximum elements lifetime */ 108 }; 109 110 struct cache_ht_item_data_ { 111 /* key is the bytes sequence only - not the null-terminated string */ 112 char *key; 113 size_t key_size; 114 115 char *value; 116 size_t value_size; 117 118 struct cache_policy_item_ *fifo_policy_item; 119 }; 120 121 struct cache_ht_item_ { 122 HASHTABLE_ENTRY_HEAD(ht_item_, struct cache_ht_item_data_) data; 123 }; 124 125 struct cache_entry_ { 126 char *name; 127 struct cache_entry_params *params; 128 }; 129 130 struct cache_common_entry_ { 131 char *name; 132 struct cache_entry_params *params; 133 134 struct common_cache_entry_params common_params; 135 136 HASHTABLE_HEAD(cache_ht_, cache_ht_item_) items; 137 size_t items_size; 138 139 /* 140 * Entry always has the FIFO policy, that is used to eliminate old 141 * elements (the ones, with lifetime more than max_lifetime). Besides, 142 * user can specify another policy to be applied, when there are too 143 * many elements in the entry. So policies_size can be 1 or 2. 144 */ 145 struct cache_policy_ **policies; 146 size_t policies_size; 147 148 void (*get_time_func)(struct timeval *); 149 }; 150 151 struct cache_mp_data_item_ { 152 char *value; 153 size_t value_size; 154 155 TAILQ_ENTRY(cache_mp_data_item_) entries; 156 }; 157 158 struct cache_mp_write_session_ { 159 struct cache_mp_entry_ *parent_entry; 160 161 /* 162 * All items are accumulated in this queue. When the session is 163 * committed, they all will be copied to the multipart entry. 164 */ 165 TAILQ_HEAD(cache_mp_data_item_head, cache_mp_data_item_) items; 166 size_t items_size; 167 168 TAILQ_ENTRY(cache_mp_write_session_) entries; 169 }; 170 171 struct cache_mp_read_session_ { 172 struct cache_mp_entry_ *parent_entry; 173 struct cache_mp_data_item_ *current_item; 174 175 TAILQ_ENTRY(cache_mp_read_session_) entries; 176 }; 177 178 struct cache_mp_entry_ { 179 char *name; 180 struct cache_entry_params *params; 181 182 struct mp_cache_entry_params mp_params; 183 184 /* All opened write sessions */ 185 TAILQ_HEAD(write_sessions_head, cache_mp_write_session_) ws_head; 186 size_t ws_size; 187 188 /* All opened read sessions */ 189 TAILQ_HEAD(read_sessions_head, cache_mp_read_session_) rs_head; 190 size_t rs_size; 191 192 /* 193 * completed_write_session is the committed write sessions. All read 194 * sessions use data from it. If the completed_write_session is out of 195 * date, but still in use by some of the read sessions, the newly 196 * committed write session is stored in the pending_write_session. 197 * In such a case, completed_write_session will be substituted with 198 * pending_write_session as soon as it won't be used by any of 199 * the read sessions. 200 */ 201 struct cache_mp_write_session_ *completed_write_session; 202 struct cache_mp_write_session_ *pending_write_session; 203 struct timeval creation_time; 204 struct timeval last_request_time; 205 206 void (*get_time_func)(struct timeval *); 207 }; 208 209 struct cache_ { 210 struct cache_params params; 211 212 struct cache_entry_ **entries; 213 size_t entries_capacity; 214 size_t entries_size; 215 }; 216 217 /* simple abstractions - for not to write "struct" every time */ 218 typedef struct cache_ *cache; 219 typedef struct cache_entry_ *cache_entry; 220 typedef struct cache_mp_write_session_ *cache_mp_write_session; 221 typedef struct cache_mp_read_session_ *cache_mp_read_session; 222 223 #define INVALID_CACHE (NULL) 224 #define INVALID_CACHE_ENTRY (NULL) 225 #define INVALID_CACHE_MP_WRITE_SESSION (NULL) 226 #define INVALID_CACHE_MP_READ_SESSION (NULL) 227 228 /* 229 * NOTE: all cache operations are thread-unsafe. You must ensure thread-safety 230 * externally, by yourself. 231 */ 232 233 /* cache initialization/destruction routines */ 234 cache init_cache(struct cache_params const *); 235 void destroy_cache(cache); 236 237 /* cache entries manipulation routines */ 238 int register_cache_entry(cache, struct cache_entry_params const *); 239 int unregister_cache_entry(cache, const char *); 240 cache_entry find_cache_entry(cache, const char *); 241 242 /* read/write operations used on common entries */ 243 int cache_read(cache_entry, const char *, size_t, char *, size_t *); 244 int cache_write(cache_entry, const char *, size_t, char const *, size_t); 245 246 /* read/write operations used on multipart entries */ 247 cache_mp_write_session open_cache_mp_write_session(cache_entry); 248 int cache_mp_write(cache_mp_write_session, char *, size_t); 249 void abandon_cache_mp_write_session(cache_mp_write_session); 250 void close_cache_mp_write_session(cache_mp_write_session); 251 252 cache_mp_read_session open_cache_mp_read_session(cache_entry); 253 int cache_mp_read(cache_mp_read_session, char *, size_t *); 254 void close_cache_mp_read_session(cache_mp_read_session); 255 256 /* transformation routines */ 257 int transform_cache_entry(cache_entry, enum cache_transformation_t); 258 int transform_cache_entry_part(cache_entry, enum cache_transformation_t, 259 const char *, size_t, enum part_position_t); 260 261 #endif 262