16bbec722Sjim #include "memcached/types.h"
22c409887STrond Norbye 
32c409887STrond Norbye #include <atomic>
42c409887STrond Norbye #include <cstddef>
52c409887STrond Norbye #include <cstring>
62c409887STrond Norbye 
76bbec722Sjim #include "default_engine_internal.h"
86bbec722Sjim 
9b46427f0STrond Norbye #ifndef ITEMS_H
10b46427f0STrond Norbye #define ITEMS_H
11b46427f0STrond Norbye 
12b46427f0STrond Norbye /*
13b46427f0STrond Norbye  * You should not try to aquire any of the item locks before calling these
14b46427f0STrond Norbye  * functions.
15b46427f0STrond Norbye  */
16b46427f0STrond Norbye typedef struct _hash_item {
17b46427f0STrond Norbye     struct _hash_item* next;
18b46427f0STrond Norbye     struct _hash_item* prev;
19b46427f0STrond Norbye     struct _hash_item* h_next; /* hash chain next */
2098b69964STrond Norbye     /**
2198b69964STrond Norbye      * The unique identifier for this item (it is guaranteed to be unique
2298b69964STrond Norbye      * per key, which means that a two different version of a document
2398b69964STrond Norbye      * cannot have the same CAS value (This is not true after a server
2498b69964STrond Norbye      * restart given that default_bucket is an in-memory bucket).
2598b69964STrond Norbye      */
2622eb2257STrond Norbye     uint64_t cas;
2798b69964STrond Norbye 
2898b69964STrond Norbye     /** least recent access */
2998b69964STrond Norbye     rel_time_t time;
3098b69964STrond Norbye 
3198b69964STrond Norbye     /** When the item will expire (relative to process startup) */
3298b69964STrond Norbye     rel_time_t exptime;
33fb3b37a2STrond Norbye 
34fb3b37a2STrond Norbye     /**
35fb3b37a2STrond Norbye      * When the current lock for the object expire. If locktime < "current
36fb3b37a2STrond Norbye      * time" the item isn't locked anymore (timed out). If locktime >=
37fb3b37a2STrond Norbye      * "current time" the object is locked.
38fb3b37a2STrond Norbye      */
39fb3b37a2STrond Norbye     rel_time_t locktime;
4098b69964STrond Norbye 
4198b69964STrond Norbye     /** The total size of the data (in bytes) */
4298b69964STrond Norbye     uint32_t nbytes;
4398b69964STrond Norbye 
4498b69964STrond Norbye     /** Flags associated with the item (in network byte order) */
4598b69964STrond Norbye     uint32_t flags;
4698b69964STrond Norbye 
4798b69964STrond Norbye     /**
4898b69964STrond Norbye      * The number of entities holding a reference to this item object (we
4998b69964STrond Norbye      * operate in a copy'n'write context so it is always safe for all of
5098b69964STrond Norbye      * our clients to share an existing object, but we need the refcount
5198b69964STrond Norbye      * so that we know when we can release the object.
5298b69964STrond Norbye      */
5398b69964STrond Norbye     uint16_t refcount;
5498b69964STrond Norbye 
5598b69964STrond Norbye     /** Intermal flags used by the engine.*/
562c409887STrond Norbye     std::atomic<uint8_t> iflag;
5798b69964STrond Norbye 
5898b69964STrond Norbye     /** which slab class we're in */
5998b69964STrond Norbye     uint8_t slabs_clsid;
6098b69964STrond Norbye 
6198b69964STrond Norbye     /** to identify the type of the data */
6298b69964STrond Norbye     uint8_t datatype;
6398b69964STrond Norbye 
6498b69964STrond Norbye     // There is 3 spare bytes due to alignment
65b46427f0STrond Norbye } hash_item;
66b46427f0STrond Norbye 
676bbec722Sjim /*
686bbec722Sjim     The structure of the key we hash with.
696bbec722Sjim 
706bbec722Sjim     This is a combination of the bucket index and the client's key.
716bbec722Sjim 
726bbec722Sjim     To respect the memcached protocol we support keys > 250, even
736bbec722Sjim     though the current frontend doesn't.
746bbec722Sjim 
756bbec722Sjim     Keys upto 128 bytes long will be carried wholly on the stack,
766bbec722Sjim     larger keys go on the heap.
776bbec722Sjim */
786bbec722Sjim typedef struct _hash_key_sized {
796bbec722Sjim     bucket_id_t bucket_index;
806bbec722Sjim     uint8_t client_key[128];
816bbec722Sjim } hash_key_sized;
826bbec722Sjim 
836bbec722Sjim typedef struct _hash_key_data {
846bbec722Sjim     bucket_id_t bucket_index;
856bbec722Sjim     uint8_t client_key[1];
866bbec722Sjim } hash_key_data;
876bbec722Sjim 
886bbec722Sjim typedef struct _hash_key_header {
896bbec722Sjim     uint16_t len; /* length of the hash key (bucket_index+client) */
906bbec722Sjim     hash_key_data* full_key; /* points to hash_key::key_storage or a malloc blob*/
916bbec722Sjim } hash_key_header;
926bbec722Sjim 
936bbec722Sjim typedef struct _hash_key {
946bbec722Sjim     hash_key_header header;
956bbec722Sjim     hash_key_sized key_storage;
966bbec722Sjim } hash_key;
976bbec722Sjim 
hash_key_get_key(const hash_key * key)9819361e07STrond Norbye static inline uint8_t* hash_key_get_key(const hash_key* key) {
996bbec722Sjim     return (uint8_t*)key->header.full_key;
1006bbec722Sjim }
1016bbec722Sjim 
hash_key_get_bucket_index(const hash_key * key)10219361e07STrond Norbye static inline bucket_id_t hash_key_get_bucket_index(const hash_key* key) {
1036bbec722Sjim     return key->header.full_key->bucket_index;
1046bbec722Sjim }
1056bbec722Sjim 
hash_key_set_bucket_index(hash_key * key,bucket_id_t bucket_index)10619361e07STrond Norbye static inline void hash_key_set_bucket_index(hash_key* key,
1076bbec722Sjim                                              bucket_id_t bucket_index) {
1086bbec722Sjim     key->header.full_key->bucket_index = bucket_index;
1096bbec722Sjim }
1106bbec722Sjim 
hash_key_get_key_len(const hash_key * key)11119361e07STrond Norbye static inline uint16_t hash_key_get_key_len(const hash_key* key) {
1126bbec722Sjim     return key->header.len;
1136bbec722Sjim }
1146bbec722Sjim 
hash_key_set_len(hash_key * key,uint16_t len)11519361e07STrond Norbye static inline void hash_key_set_len(hash_key* key, uint16_t len) {
1166bbec722Sjim     key->header.len = len;
1176bbec722Sjim }
1186bbec722Sjim 
hash_key_get_client_key(const hash_key * key)11919361e07STrond Norbye static inline uint8_t* hash_key_get_client_key(const hash_key* key) {
1206bbec722Sjim     return key->header.full_key->client_key;
1216bbec722Sjim }
1226bbec722Sjim 
hash_key_get_client_key_len(const hash_key * key)12319361e07STrond Norbye static inline uint16_t hash_key_get_client_key_len(const hash_key* key) {
1246bbec722Sjim     return hash_key_get_key_len(key) -
125*ab711953STim Bradgate            gsl::narrow<uint16_t>(sizeof(key->header.full_key->bucket_index));
1266bbec722Sjim }
1276bbec722Sjim 
hash_key_set_client_key(hash_key * key,const void * client_key,const size_t client_key_len)12819361e07STrond Norbye static inline void hash_key_set_client_key(hash_key* key,
1296bbec722Sjim                                            const void* client_key,
130*ab711953STim Bradgate                                            const size_t client_key_len) {
1316bbec722Sjim     memcpy(key->header.full_key->client_key, client_key, client_key_len);
1326bbec722Sjim }
1336bbec722Sjim 
1346bbec722Sjim /*
1356bbec722Sjim  * return the bytes needed to store the hash_key structure
1366bbec722Sjim  * in a single contiguous allocation.
1376bbec722Sjim  */
hash_key_get_alloc_size(const hash_key * key)13819361e07STrond Norbye static inline size_t hash_key_get_alloc_size(const hash_key* key) {
1396bbec722Sjim     return offsetof(hash_key, key_storage) + hash_key_get_key_len(key);
1406bbec722Sjim }
1416bbec722Sjim 
142b46427f0STrond Norbye typedef struct {
143b46427f0STrond Norbye     unsigned int evicted;
144b46427f0STrond Norbye     unsigned int evicted_nonzero;
145b46427f0STrond Norbye     rel_time_t evicted_time;
146b46427f0STrond Norbye     unsigned int outofmemory;
147b46427f0STrond Norbye     unsigned int tailrepairs;
148b46427f0STrond Norbye     unsigned int reclaimed;
149b46427f0STrond Norbye } itemstats_t;
150b46427f0STrond Norbye 
151b46427f0STrond Norbye struct items {
152b46427f0STrond Norbye    hash_item *heads[POWER_LARGEST];
153b46427f0STrond Norbye    hash_item *tails[POWER_LARGEST];
154b46427f0STrond Norbye    itemstats_t itemstats[POWER_LARGEST];
155b46427f0STrond Norbye    unsigned int sizes[POWER_LARGEST];
1566bbec722Sjim    /*
1576bbec722Sjim     * serialise access to the items data
1586bbec722Sjim    */
1596bbec722Sjim    cb_mutex_t lock;
160b46427f0STrond Norbye };
161b46427f0STrond Norbye 
162b46427f0STrond Norbye 
163b46427f0STrond Norbye /**
164b46427f0STrond Norbye  * Allocate and initialize a new item structure
165b46427f0STrond Norbye  * @param engine handle to the storage engine
166b46427f0STrond Norbye  * @param key the key for the new item
167b46427f0STrond Norbye  * @param nkey the number of bytes in the key
168b46427f0STrond Norbye  * @param flags the flags in the new item
169b46427f0STrond Norbye  * @param exptime when the object should expire
170b46427f0STrond Norbye  * @param nbytes the number of bytes in the body for the item
171b46427f0STrond Norbye  * @return a pointer to an item on success NULL otherwise
172b46427f0STrond Norbye  */
173b46427f0STrond Norbye hash_item *item_alloc(struct default_engine *engine,
1746bbec722Sjim                       const void *key, const size_t nkey, int flags,
1751639b21aSabhinavdangeti                       rel_time_t exptime, int nbytes, const void *cookie,
1761639b21aSabhinavdangeti                       uint8_t datatype);
177b46427f0STrond Norbye 
178b46427f0STrond Norbye /**
179b46427f0STrond Norbye  * Get an item from the cache
180b46427f0STrond Norbye  *
181b46427f0STrond Norbye  * @param engine handle to the storage engine
1826bbec722Sjim  * @param cookie connection cookie
183b46427f0STrond Norbye  * @param key the key for the item to get
184b46427f0STrond Norbye  * @param nkey the number of bytes in the key
185374efa4bSTrond Norbye  * @param state Only return documents in this state
186b46427f0STrond Norbye  * @return pointer to the item if it exists or NULL otherwise
187b46427f0STrond Norbye  */
188b46427f0STrond Norbye hash_item* item_get(struct default_engine* engine,
1896bbec722Sjim                     const void* cookie,
1906bbec722Sjim                     const void* key,
191374efa4bSTrond Norbye                     const size_t nkey,
192f068119eSTrond Norbye                     const DocStateFilter state);
193fb3b37a2STrond Norbye 
194fb3b37a2STrond Norbye /**
1958f9005d0SJim Walker  * Get an item from the cache using a hash_key
1968f9005d0SJim Walker  *
1978f9005d0SJim Walker  * @param engine handle to the storage engine
1988f9005d0SJim Walker  * @param cookie connection cookie
1998f9005d0SJim Walker  * @param key to lookup
2008f9005d0SJim Walker  * @param state Only return documents in this state
2018f9005d0SJim Walker  * @return pointer to the item if it exists or NULL otherwise
2028f9005d0SJim Walker  */
2038f9005d0SJim Walker hash_item* item_get(struct default_engine* engine,
2048f9005d0SJim Walker                     const void* cookie,
2058f9005d0SJim Walker                     const hash_key& key,
2068f9005d0SJim Walker                     const DocStateFilter state);
2078f9005d0SJim Walker 
2088f9005d0SJim Walker /**
209fb3b37a2STrond Norbye  * Get an item from the cache and acquire the lock.
210fb3b37a2STrond Norbye  *
211fb3b37a2STrond Norbye  * @param engine handle to the storage engine
212fb3b37a2STrond Norbye  * @param cookie connection cookie
213fb3b37a2STrond Norbye  * @param where to return the item (if found)
214fb3b37a2STrond Norbye  * @param key the key for the item to get
215fb3b37a2STrond Norbye  * @param nkey the number of bytes in the key
216fb3b37a2STrond Norbye  * @param locktime when the item expire
217fb3b37a2STrond Norbye  * @return ENGINE_SUCCESS for success
218fb3b37a2STrond Norbye  */
219fb3b37a2STrond Norbye ENGINE_ERROR_CODE item_get_locked(struct default_engine* engine,
220fb3b37a2STrond Norbye                                   const void* cookie,
221fb3b37a2STrond Norbye                                   hash_item** it,
222fb3b37a2STrond Norbye                                   const void* key,
223fb3b37a2STrond Norbye                                   const size_t nkey,
224fb3b37a2STrond Norbye                                   rel_time_t locktime);
225fb3b37a2STrond Norbye 
226fb3b37a2STrond Norbye /**
227753d8721STrond Norbye  * Get and touch an item
228753d8721STrond Norbye  *
229753d8721STrond Norbye  * @param engine handle to the storage engine
230753d8721STrond Norbye  * @param cookie connection cookie
231753d8721STrond Norbye  * @param where to return the item (if found)
232753d8721STrond Norbye  * @param key the key for the item to get
233753d8721STrond Norbye  * @param nkey the number of bytes in the key
234753d8721STrond Norbye  * @param exptime The new expiry time
235753d8721STrond Norbye  * @return ENGINE_SUCCESS for success
236753d8721STrond Norbye  */
237753d8721STrond Norbye ENGINE_ERROR_CODE item_get_and_touch(struct default_engine* engine,
238753d8721STrond Norbye                                      const void* cookie,
239753d8721STrond Norbye                                      hash_item** it,
240753d8721STrond Norbye                                      const void* key,
241753d8721STrond Norbye                                      const size_t nkey,
242753d8721STrond Norbye                                      rel_time_t exptime);
243753d8721STrond Norbye 
244753d8721STrond Norbye 
245753d8721STrond Norbye /**
246fb3b37a2STrond Norbye  * Unlock an item in the cache
247fb3b37a2STrond Norbye  *
248fb3b37a2STrond Norbye  * @param engine handle to the storage engine
249fb3b37a2STrond Norbye  * @param cookie connection cookie
250fb3b37a2STrond Norbye  * @param key the key for the item to unlock
251fb3b37a2STrond Norbye  * @param nkey the number of bytes in the key
252fb3b37a2STrond Norbye  * @param cas value for the locked value
253fb3b37a2STrond Norbye  * @return ENGINE_SUCCESS for success
254fb3b37a2STrond Norbye  */
255fb3b37a2STrond Norbye ENGINE_ERROR_CODE item_unlock(struct default_engine* engine,
256fb3b37a2STrond Norbye                               const void* cookie,
257fb3b37a2STrond Norbye                               const void* key,
258fb3b37a2STrond Norbye                               const size_t nkey,
259fb3b37a2STrond Norbye                               uint64_t cas);
260fb3b37a2STrond Norbye 
261b46427f0STrond Norbye /**
262b46427f0STrond Norbye  * Reset the item statistics
263b46427f0STrond Norbye  * @param engine handle to the storage engine
264b46427f0STrond Norbye  */
265b46427f0STrond Norbye void item_stats_reset(struct default_engine *engine);
266b46427f0STrond Norbye 
267b46427f0STrond Norbye /**
268b46427f0STrond Norbye  * Get item statitistics
269b46427f0STrond Norbye  * @param engine handle to the storage engine
270b46427f0STrond Norbye  * @param add_stat callback provided by the core used to
271b46427f0STrond Norbye  *                 push statistics into the response
272b46427f0STrond Norbye  * @param cookie cookie provided by the core to identify the client
273b46427f0STrond Norbye  */
274b46427f0STrond Norbye void item_stats(struct default_engine *engine,
275b46427f0STrond Norbye                 ADD_STAT add_stat,
276b46427f0STrond Norbye                 const void *cookie);
277b46427f0STrond Norbye 
278b46427f0STrond Norbye /**
279b46427f0STrond Norbye  * Get detaild item statitistics
280b46427f0STrond Norbye  * @param engine handle to the storage engine
281b46427f0STrond Norbye  * @param add_stat callback provided by the core used to
282b46427f0STrond Norbye  *                 push statistics into the response
283b46427f0STrond Norbye  * @param cookie cookie provided by the core to identify the client
284b46427f0STrond Norbye  */
285b46427f0STrond Norbye void item_stats_sizes(struct default_engine *engine,
286b46427f0STrond Norbye                       ADD_STAT add_stat, const void *cookie);
287b46427f0STrond Norbye 
288b46427f0STrond Norbye /**
289b46427f0STrond Norbye  * Flush expired items from the cache
290b46427f0STrond Norbye  * @param engine handle to the storage engine
291b46427f0STrond Norbye  */
29277f3c4f3STrond Norbye void  item_flush_expired(struct default_engine *engine);
293b46427f0STrond Norbye 
294b46427f0STrond Norbye /**
295b46427f0STrond Norbye  * Release our reference to the current item
296b46427f0STrond Norbye  * @param engine handle to the storage engine
297b46427f0STrond Norbye  * @param it the item to release
298b46427f0STrond Norbye  */
299b46427f0STrond Norbye void item_release(struct default_engine *engine, hash_item *it);
300b46427f0STrond Norbye 
301b46427f0STrond Norbye /**
302b46427f0STrond Norbye  * Unlink the item from the hash table (make it inaccessible)
303b46427f0STrond Norbye  * @param engine handle to the storage engine
304b46427f0STrond Norbye  * @param it the item to unlink
305b46427f0STrond Norbye  */
306b46427f0STrond Norbye void item_unlink(struct default_engine *engine, hash_item *it);
307b46427f0STrond Norbye 
308b46427f0STrond Norbye /**
309374efa4bSTrond Norbye  * Unlink the item from the hash table (make it inaccessible),
310374efa4bSTrond Norbye  * but only if the CAS value in the item is the same as the
311374efa4bSTrond Norbye  * one in the hash table (two different connections may operate
312374efa4bSTrond Norbye  * on the same objects, so the cas value for the value in the
313374efa4bSTrond Norbye  * hashtable may be different than the items value. We need
314374efa4bSTrond Norbye  * to have exclusive access to the hashtable to do the actual
315374efa4bSTrond Norbye  * unlink)
316374efa4bSTrond Norbye  *
317374efa4bSTrond Norbye  * @param engine handle to the storage engine
318374efa4bSTrond Norbye  * @param it the item to unlink
319374efa4bSTrond Norbye  */
320374efa4bSTrond Norbye ENGINE_ERROR_CODE safe_item_unlink(struct default_engine *engine,
321374efa4bSTrond Norbye                                    hash_item *it);
322374efa4bSTrond Norbye 
323374efa4bSTrond Norbye /**
324b46427f0STrond Norbye  * Store an item in the cache
325b46427f0STrond Norbye  * @param engine handle to the storage engine
326b46427f0STrond Norbye  * @param item the item to store
327b46427f0STrond Norbye  * @param cas the cas value (OUT)
328b46427f0STrond Norbye  * @param operation what kind of store operation is this (ADD/SET etc)
329374efa4bSTrond Norbye  * @param document_state the state of the document to store
330b46427f0STrond Norbye  * @return ENGINE_SUCCESS on success
331b46427f0STrond Norbye  *
332b46427f0STrond Norbye  * @todo should we refactor this into hash_item ** and remove the cas
333b46427f0STrond Norbye  *       there so that we can get it from the item instead?
334b46427f0STrond Norbye  */
335b46427f0STrond Norbye ENGINE_ERROR_CODE store_item(struct default_engine *engine,
336b46427f0STrond Norbye                              hash_item *item,
337b46427f0STrond Norbye                              uint64_t *cas,
338b46427f0STrond Norbye                              ENGINE_STORE_OPERATION operation,
339374efa4bSTrond Norbye                              const void *cookie,
340374efa4bSTrond Norbye                              const DocumentState document_state);
341b46427f0STrond Norbye 
342b46427f0STrond Norbye /**
3436bbec722Sjim  * Run a single scrub loop for the engine.
344b46427f0STrond Norbye  * @param engine handle to the storage engine
345b46427f0STrond Norbye  */
3466bbec722Sjim void item_scrubber_main(struct default_engine *engine);
3476bbec722Sjim 
3486bbec722Sjim /**
3496bbec722Sjim  * Start the item scrubber for the engine
3506bbec722Sjim  * @param engine handle to the storage engine
3516bbec722Sjim  * @return true if the scrubber has been invoked
3526bbec722Sjim  */
353b46427f0STrond Norbye bool item_start_scrub(struct default_engine *engine);
354b46427f0STrond Norbye 
355b46427f0STrond Norbye #endif
356