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