1#include "memcached/types.h" 2 3#include <atomic> 4#include <cstddef> 5#include <cstring> 6 7#include "default_engine_internal.h" 8 9#ifndef ITEMS_H 10#define ITEMS_H 11 12/* 13 * You should not try to aquire any of the item locks before calling these 14 * functions. 15 */ 16typedef struct _hash_item { 17 struct _hash_item* next; 18 struct _hash_item* prev; 19 struct _hash_item* h_next; /* hash chain next */ 20 /** 21 * The unique identifier for this item (it is guaranteed to be unique 22 * per key, which means that a two different version of a document 23 * cannot have the same CAS value (This is not true after a server 24 * restart given that default_bucket is an in-memory bucket). 25 */ 26 uint64_t cas; 27 28 /** least recent access */ 29 rel_time_t time; 30 31 /** When the item will expire (relative to process startup) */ 32 rel_time_t exptime; 33 34 /** 35 * When the current lock for the object expire. If locktime < "current 36 * time" the item isn't locked anymore (timed out). If locktime >= 37 * "current time" the object is locked. 38 */ 39 rel_time_t locktime; 40 41 /** The total size of the data (in bytes) */ 42 uint32_t nbytes; 43 44 /** Flags associated with the item (in network byte order) */ 45 uint32_t flags; 46 47 /** 48 * The number of entities holding a reference to this item object (we 49 * operate in a copy'n'write context so it is always safe for all of 50 * our clients to share an existing object, but we need the refcount 51 * so that we know when we can release the object. 52 */ 53 uint16_t refcount; 54 55 /** Intermal flags used by the engine.*/ 56 std::atomic<uint8_t> iflag; 57 58 /** which slab class we're in */ 59 uint8_t slabs_clsid; 60 61 /** to identify the type of the data */ 62 uint8_t datatype; 63 64 // There is 3 spare bytes due to alignment 65} hash_item; 66 67/* 68 The structure of the key we hash with. 69 70 This is a combination of the bucket index and the client's key. 71 72 To respect the memcached protocol we support keys > 250, even 73 though the current frontend doesn't. 74 75 Keys upto 128 bytes long will be carried wholly on the stack, 76 larger keys go on the heap. 77*/ 78typedef struct _hash_key_sized { 79 bucket_id_t bucket_index; 80 uint8_t client_key[128]; 81} hash_key_sized; 82 83typedef struct _hash_key_data { 84 bucket_id_t bucket_index; 85 uint8_t client_key[1]; 86} hash_key_data; 87 88typedef struct _hash_key_header { 89 uint16_t len; /* length of the hash key (bucket_index+client) */ 90 hash_key_data* full_key; /* points to hash_key::key_storage or a malloc blob*/ 91} hash_key_header; 92 93typedef struct _hash_key { 94 hash_key_header header; 95 hash_key_sized key_storage; 96} hash_key; 97 98static inline uint8_t* hash_key_get_key(const hash_key* key) { 99 return (uint8_t*)key->header.full_key; 100} 101 102static inline bucket_id_t hash_key_get_bucket_index(const hash_key* key) { 103 return key->header.full_key->bucket_index; 104} 105 106static inline void hash_key_set_bucket_index(hash_key* key, 107 bucket_id_t bucket_index) { 108 key->header.full_key->bucket_index = bucket_index; 109} 110 111static inline uint16_t hash_key_get_key_len(const hash_key* key) { 112 return key->header.len; 113} 114 115static inline void hash_key_set_len(hash_key* key, uint16_t len) { 116 key->header.len = len; 117} 118 119static inline uint8_t* hash_key_get_client_key(const hash_key* key) { 120 return key->header.full_key->client_key; 121} 122 123static inline uint16_t hash_key_get_client_key_len(const hash_key* key) { 124 return hash_key_get_key_len(key) - 125 gsl::narrow<uint16_t>(sizeof(key->header.full_key->bucket_index)); 126} 127 128static inline void hash_key_set_client_key(hash_key* key, 129 const void* client_key, 130 const size_t client_key_len) { 131 memcpy(key->header.full_key->client_key, client_key, client_key_len); 132} 133 134/* 135 * return the bytes needed to store the hash_key structure 136 * in a single contiguous allocation. 137 */ 138static inline size_t hash_key_get_alloc_size(const hash_key* key) { 139 return offsetof(hash_key, key_storage) + hash_key_get_key_len(key); 140} 141 142typedef struct { 143 unsigned int evicted; 144 unsigned int evicted_nonzero; 145 rel_time_t evicted_time; 146 unsigned int outofmemory; 147 unsigned int tailrepairs; 148 unsigned int reclaimed; 149} itemstats_t; 150 151struct items { 152 hash_item *heads[POWER_LARGEST]; 153 hash_item *tails[POWER_LARGEST]; 154 itemstats_t itemstats[POWER_LARGEST]; 155 unsigned int sizes[POWER_LARGEST]; 156 /* 157 * serialise access to the items data 158 */ 159 cb_mutex_t lock; 160}; 161 162 163/** 164 * Allocate and initialize a new item structure 165 * @param engine handle to the storage engine 166 * @param key the key for the new item 167 * @param nkey the number of bytes in the key 168 * @param flags the flags in the new item 169 * @param exptime when the object should expire 170 * @param nbytes the number of bytes in the body for the item 171 * @return a pointer to an item on success NULL otherwise 172 */ 173hash_item *item_alloc(struct default_engine *engine, 174 const void *key, const size_t nkey, int flags, 175 rel_time_t exptime, int nbytes, const void *cookie, 176 uint8_t datatype); 177 178/** 179 * Get an item from the cache 180 * 181 * @param engine handle to the storage engine 182 * @param cookie connection cookie 183 * @param key the key for the item to get 184 * @param nkey the number of bytes in the key 185 * @param state Only return documents in this state 186 * @return pointer to the item if it exists or NULL otherwise 187 */ 188hash_item* item_get(struct default_engine* engine, 189 const void* cookie, 190 const void* key, 191 const size_t nkey, 192 const DocStateFilter state); 193 194/** 195 * Get an item from the cache using a hash_key 196 * 197 * @param engine handle to the storage engine 198 * @param cookie connection cookie 199 * @param key to lookup 200 * @param state Only return documents in this state 201 * @return pointer to the item if it exists or NULL otherwise 202 */ 203hash_item* item_get(struct default_engine* engine, 204 const void* cookie, 205 const hash_key& key, 206 const DocStateFilter state); 207 208/** 209 * Get an item from the cache and acquire the lock. 210 * 211 * @param engine handle to the storage engine 212 * @param cookie connection cookie 213 * @param where to return the item (if found) 214 * @param key the key for the item to get 215 * @param nkey the number of bytes in the key 216 * @param locktime when the item expire 217 * @return ENGINE_SUCCESS for success 218 */ 219ENGINE_ERROR_CODE item_get_locked(struct default_engine* engine, 220 const void* cookie, 221 hash_item** it, 222 const void* key, 223 const size_t nkey, 224 rel_time_t locktime); 225 226/** 227 * Get and touch an item 228 * 229 * @param engine handle to the storage engine 230 * @param cookie connection cookie 231 * @param where to return the item (if found) 232 * @param key the key for the item to get 233 * @param nkey the number of bytes in the key 234 * @param exptime The new expiry time 235 * @return ENGINE_SUCCESS for success 236 */ 237ENGINE_ERROR_CODE item_get_and_touch(struct default_engine* engine, 238 const void* cookie, 239 hash_item** it, 240 const void* key, 241 const size_t nkey, 242 rel_time_t exptime); 243 244 245/** 246 * Unlock an item in the cache 247 * 248 * @param engine handle to the storage engine 249 * @param cookie connection cookie 250 * @param key the key for the item to unlock 251 * @param nkey the number of bytes in the key 252 * @param cas value for the locked value 253 * @return ENGINE_SUCCESS for success 254 */ 255ENGINE_ERROR_CODE item_unlock(struct default_engine* engine, 256 const void* cookie, 257 const void* key, 258 const size_t nkey, 259 uint64_t cas); 260 261/** 262 * Reset the item statistics 263 * @param engine handle to the storage engine 264 */ 265void item_stats_reset(struct default_engine *engine); 266 267/** 268 * Get item statitistics 269 * @param engine handle to the storage engine 270 * @param add_stat callback provided by the core used to 271 * push statistics into the response 272 * @param cookie cookie provided by the core to identify the client 273 */ 274void item_stats(struct default_engine *engine, 275 ADD_STAT add_stat, 276 const void *cookie); 277 278/** 279 * Get detaild item statitistics 280 * @param engine handle to the storage engine 281 * @param add_stat callback provided by the core used to 282 * push statistics into the response 283 * @param cookie cookie provided by the core to identify the client 284 */ 285void item_stats_sizes(struct default_engine *engine, 286 ADD_STAT add_stat, const void *cookie); 287 288/** 289 * Flush expired items from the cache 290 * @param engine handle to the storage engine 291 */ 292void item_flush_expired(struct default_engine *engine); 293 294/** 295 * Release our reference to the current item 296 * @param engine handle to the storage engine 297 * @param it the item to release 298 */ 299void item_release(struct default_engine *engine, hash_item *it); 300 301/** 302 * Unlink the item from the hash table (make it inaccessible) 303 * @param engine handle to the storage engine 304 * @param it the item to unlink 305 */ 306void item_unlink(struct default_engine *engine, hash_item *it); 307 308/** 309 * Unlink the item from the hash table (make it inaccessible), 310 * but only if the CAS value in the item is the same as the 311 * one in the hash table (two different connections may operate 312 * on the same objects, so the cas value for the value in the 313 * hashtable may be different than the items value. We need 314 * to have exclusive access to the hashtable to do the actual 315 * unlink) 316 * 317 * @param engine handle to the storage engine 318 * @param it the item to unlink 319 */ 320ENGINE_ERROR_CODE safe_item_unlink(struct default_engine *engine, 321 hash_item *it); 322 323/** 324 * Store an item in the cache 325 * @param engine handle to the storage engine 326 * @param item the item to store 327 * @param cas the cas value (OUT) 328 * @param operation what kind of store operation is this (ADD/SET etc) 329 * @param document_state the state of the document to store 330 * @return ENGINE_SUCCESS on success 331 * 332 * @todo should we refactor this into hash_item ** and remove the cas 333 * there so that we can get it from the item instead? 334 */ 335ENGINE_ERROR_CODE store_item(struct default_engine *engine, 336 hash_item *item, 337 uint64_t *cas, 338 ENGINE_STORE_OPERATION operation, 339 const void *cookie, 340 const DocumentState document_state); 341 342/** 343 * Run a single scrub loop for the engine. 344 * @param engine handle to the storage engine 345 */ 346void item_scrubber_main(struct default_engine *engine); 347 348/** 349 * Start the item scrubber for the engine 350 * @param engine handle to the storage engine 351 * @return true if the scrubber has been invoked 352 */ 353bool item_start_scrub(struct default_engine *engine); 354 355#endif 356