1534f5100STrond Norbye/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2534f5100STrond Norbye#include "config.h"
3534f5100STrond Norbye#include <stdio.h>
4534f5100STrond Norbye#include <stdlib.h>
5534f5100STrond Norbye#include <ctype.h>
6534f5100STrond Norbye#include <string.h>
7534f5100STrond Norbye#include <unistd.h>
8534f5100STrond Norbye#include <stddef.h>
9534f5100STrond Norbye#include <stdarg.h>
10534f5100STrond Norbye
11534f5100STrond Norbye#include <memcached/engine.h>
12f603fdb6STrond Norbye#include <platform/platform.h>
13534f5100STrond Norbye#include "genhash.h"
14534f5100STrond Norbye#include "topkeys.h"
15534f5100STrond Norbye#include "bucket_engine.h"
16534f5100STrond Norbye
17534f5100STrond Norbyestatic rel_time_t (*get_current_time)(void);
18534f5100STrond Norbyestatic EXTENSION_LOGGER_DESCRIPTOR *logger;
19534f5100STrond Norbye
20f603fdb6STrond Norbye#ifdef WIN32
21f603fdb6STrond Norbye
22f603fdb6STrond Norbyestatic int ATOMIC_ADD(volatile int *dest, int value) {
23f603fdb6STrond Norbye    LONG old = InterlockedExchangeAdd((LPLONG)dest, (LONG)value);
24f603fdb6STrond Norbye    return (int)(old + value);
25f603fdb6STrond Norbye}
26f603fdb6STrond Norbye
27f603fdb6STrond Norbyestatic int ATOMIC_INCR(volatile int *dest) {
28f603fdb6STrond Norbye    return (int)InterlockedIncrement((LPLONG)dest);
29f603fdb6STrond Norbye}
30f603fdb6STrond Norbye
31f603fdb6STrond Norbyestatic int ATOMIC_DECR(volatile int *dest) {
32f603fdb6STrond Norbye    return (int)InterlockedDecrement((LPLONG)dest);
33f603fdb6STrond Norbye}
34f603fdb6STrond Norbye
35f603fdb6STrond Norbyestatic int ATOMIC_CAS(volatile bucket_state_t *dest, int prev, int next) {
36f603fdb6STrond Norbye    LONG old = InterlockedCompareExchange((LONG*)dest, (LONG)next, (LONG)prev);
37f603fdb6STrond Norbye    return old == prev;
38f603fdb6STrond Norbye}
39f603fdb6STrond Norbye
40f603fdb6STrond Norbye#elif defined(HAVE_ATOMIC_H) && defined(__SUNPRO_C)
41534f5100STrond Norbye#include <atomic.h>
42534f5100STrond Norbyestatic inline int ATOMIC_ADD(volatile int *dest, int value) {
43534f5100STrond Norbye    return atomic_add_int_nv((volatile unsigned int *)dest, value);
44534f5100STrond Norbye}
45534f5100STrond Norbye
46534f5100STrond Norbyestatic inline int ATOMIC_INCR(volatile int *dest) {
47534f5100STrond Norbye    return atomic_inc_32_nv((volatile unsigned int *)dest);
48534f5100STrond Norbye}
49534f5100STrond Norbye
50534f5100STrond Norbyestatic inline int ATOMIC_DECR(volatile int *dest) {
51534f5100STrond Norbye    return atomic_dec_32_nv((volatile unsigned int *)dest);
52534f5100STrond Norbye}
53534f5100STrond Norbye
54534f5100STrond Norbyestatic inline int ATOMIC_CAS(volatile bucket_state_t *dest, int prev, int next) {
55534f5100STrond Norbye    return (prev == atomic_cas_uint((volatile uint_t*)dest, (uint_t)prev,
56534f5100STrond Norbye                                    (uint_t)next));
57534f5100STrond Norbye}
58534f5100STrond Norbye#else
59534f5100STrond Norbye#define ATOMIC_ADD(i, by) __sync_add_and_fetch(i, by)
60534f5100STrond Norbye#define ATOMIC_INCR(i) ATOMIC_ADD(i, 1)
61534f5100STrond Norbye#define ATOMIC_DECR(i) ATOMIC_ADD(i, -1)
62534f5100STrond Norbye#define ATOMIC_CAS(ptr, oldval, newval) \
63534f5100STrond Norbye            __sync_bool_compare_and_swap(ptr, oldval, newval)
64534f5100STrond Norbye#endif
65534f5100STrond Norbye
66534f5100STrond Norbyestatic ENGINE_ERROR_CODE (*upstream_reserve_cookie)(const void *cookie);
67534f5100STrond Norbyestatic ENGINE_ERROR_CODE (*upstream_release_cookie)(const void *cookie);
68534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_engine_reserve_cookie(const void *cookie);
69534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_engine_release_cookie(const void *cookie);
70534f5100STrond Norbye
71534f5100STrond Norbyestruct bucket_list {
72534f5100STrond Norbye    char *name;
73ce9a18d0STrond Norbye    size_t namelen;
74534f5100STrond Norbye    proxied_engine_handle_t *peh;
75534f5100STrond Norbye    struct bucket_list *next;
76534f5100STrond Norbye};
77534f5100STrond Norbye
78534f5100STrond NorbyeMEMCACHED_PUBLIC_API
79534f5100STrond NorbyeENGINE_ERROR_CODE create_instance(uint64_t interface,
80534f5100STrond Norbye                                  GET_SERVER_API gsapi,
81534f5100STrond Norbye                                  ENGINE_HANDLE **handle);
82534f5100STrond Norbye
83534f5100STrond Norbyestatic const engine_info* bucket_get_info(ENGINE_HANDLE* handle);
84534f5100STrond Norbye
85534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_initialize(ENGINE_HANDLE* handle,
86534f5100STrond Norbye                                           const char* config_str);
87534f5100STrond Norbyestatic void bucket_destroy(ENGINE_HANDLE* handle,
88534f5100STrond Norbye                           const bool force);
89534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_item_allocate(ENGINE_HANDLE* handle,
90534f5100STrond Norbye                                              const void* cookie,
91534f5100STrond Norbye                                              item **item,
92534f5100STrond Norbye                                              const void* key,
93534f5100STrond Norbye                                              const size_t nkey,
94534f5100STrond Norbye                                              const size_t nbytes,
95534f5100STrond Norbye                                              const int flags,
961639b21aSabhinavdangeti                                              const rel_time_t exptime,
971639b21aSabhinavdangeti                                              uint8_t datatype);
98534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_item_delete(ENGINE_HANDLE* handle,
99534f5100STrond Norbye                                            const void* cookie,
100534f5100STrond Norbye                                            const void* key,
101534f5100STrond Norbye                                            const size_t nkey,
102534f5100STrond Norbye                                            uint64_t* cas,
103534f5100STrond Norbye                                            uint16_t vbucket);
104534f5100STrond Norbyestatic void bucket_item_release(ENGINE_HANDLE* handle,
105534f5100STrond Norbye                                const void *cookie,
106534f5100STrond Norbye                                item* item);
107534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_get(ENGINE_HANDLE* handle,
108534f5100STrond Norbye                                    const void* cookie,
109534f5100STrond Norbye                                    item** item,
110534f5100STrond Norbye                                    const void* key,
111534f5100STrond Norbye                                    const int nkey,
112534f5100STrond Norbye                                    uint16_t vbucket);
113534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_get_stats(ENGINE_HANDLE* handle,
114534f5100STrond Norbye                                          const void *cookie,
115534f5100STrond Norbye                                          const char *stat_key,
116534f5100STrond Norbye                                          int nkey,
117534f5100STrond Norbye                                          ADD_STAT add_stat);
118534f5100STrond Norbyestatic void *bucket_get_stats_struct(ENGINE_HANDLE* handle,
119534f5100STrond Norbye                                                    const void *cookie);
120534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_aggregate_stats(ENGINE_HANDLE* handle,
121534f5100STrond Norbye                                                const void* cookie,
122534f5100STrond Norbye                                                void (*callback)(void*, void*),
123534f5100STrond Norbye                                                void *stats);
124534f5100STrond Norbyestatic void bucket_reset_stats(ENGINE_HANDLE* handle, const void *cookie);
125534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_store(ENGINE_HANDLE* handle,
126534f5100STrond Norbye                                      const void *cookie,
127534f5100STrond Norbye                                      item* item,
128534f5100STrond Norbye                                      uint64_t *cas,
129534f5100STrond Norbye                                      ENGINE_STORE_OPERATION operation,
130534f5100STrond Norbye                                      uint16_t vbucket);
131534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_arithmetic(ENGINE_HANDLE* handle,
132534f5100STrond Norbye                                           const void* cookie,
133534f5100STrond Norbye                                           const void* key,
134534f5100STrond Norbye                                           const int nkey,
135534f5100STrond Norbye                                           const bool increment,
136534f5100STrond Norbye                                           const bool create,
137534f5100STrond Norbye                                           const uint64_t delta,
138534f5100STrond Norbye                                           const uint64_t initial,
139534f5100STrond Norbye                                           const rel_time_t exptime,
140534f5100STrond Norbye                                           uint64_t *cas,
1411639b21aSabhinavdangeti                                           uint8_t datatype,
142534f5100STrond Norbye                                           uint64_t *result,
143534f5100STrond Norbye                                           uint16_t vbucket);
144534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_flush(ENGINE_HANDLE* handle,
145534f5100STrond Norbye                                      const void* cookie, time_t when);
146534f5100STrond Norbyestatic ENGINE_ERROR_CODE initialize_configuration(struct bucket_engine *me,
147534f5100STrond Norbye                                                  const char *cfg_str);
148534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_unknown_command(ENGINE_HANDLE* handle,
149534f5100STrond Norbye                                                const void* cookie,
150534f5100STrond Norbye                                                protocol_binary_request_header *request,
151534f5100STrond Norbye                                                ADD_RESPONSE response);
152534f5100STrond Norbye
153534f5100STrond Norbyestatic bool bucket_get_item_info(ENGINE_HANDLE *handle,
154534f5100STrond Norbye                                 const void *cookie,
155534f5100STrond Norbye                                 const item* item,
156534f5100STrond Norbye                                 item_info *item_info);
157534f5100STrond Norbye
1584688e0f4Sabhinavdangetistatic bool bucket_set_item_info(ENGINE_HANDLE *handle,
1594688e0f4Sabhinavdangeti                                 const void *cookie,
1604688e0f4Sabhinavdangeti                                 item* item,
1614688e0f4Sabhinavdangeti                                 const item_info *itm_info);
163534f5100STrond Norbyestatic void bucket_item_set_cas(ENGINE_HANDLE *handle, const void *cookie,
164534f5100STrond Norbye                                item *item, uint64_t cas);
165534f5100STrond Norbye
166534f5100STrond Norbyestatic ENGINE_ERROR_CODE bucket_tap_notify(ENGINE_HANDLE* handle,
167534f5100STrond Norbye                                           const void *cookie,
168534f5100STrond Norbye                                           void *engine_specific,
169534f5100STrond Norbye                                           uint16_t nengine,
170534f5100STrond Norbye                                           uint8_t ttl,
171534f5100STrond Norbye                                           uint16_t tap_flags,
172534f5100STrond Norbye                                           tap_event_t tap_event,
173534f5100STrond Norbye                                           uint32_t tap_seqno,
174534f5100STrond Norbye                                           const void *key,
175534f5100STrond Norbye                                           size_t nkey,
176534f5100STrond Norbye                                           uint32_t flags,
177534f5100STrond Norbye                                           uint32_t exptime,
178534f5100STrond Norbye                                           uint64_t cas,
1791639b21aSabhinavdangeti                                           uint8_t datatype,
180534f5100STrond Norbye                                           const void *data,
181534f5100STrond Norbye                                           size_t ndata,
182534f5100STrond Norbye                                           uint16_t vbucket);
183534f5100STrond Norbye
184534f5100STrond Norbyestatic TAP_ITERATOR bucket_get_tap_iterator(ENGINE_HANDLE* handle, const void* cookie,
185534f5100STrond Norbye                                            const void* client, size_t nclient,
186534f5100STrond Norbye                                            uint32_t flags,
187534f5100STrond Norbye                                            const void* userdata, size_t nuserdata);
188534f5100STrond Norbye
189f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_step(ENGINE_HANDLE* handle, const void* cookie,
190f1818198STrond Norbye                                  struct dcp_message_producers *producers);
191001dd25dSTrond Norbye
192f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_open(ENGINE_HANDLE* handle,
193e7e6249aSTrond Norbye                                  const void* cookie,
194e7e6249aSTrond Norbye                                  uint32_t opaque,
195e7e6249aSTrond Norbye                                  uint32_t seqno,
196e7e6249aSTrond Norbye                                  uint32_t flags,
197e7e6249aSTrond Norbye                                  void *name,
198638cd3e3STrond Norbye                                  uint16_t nname);
199e7e6249aSTrond Norbye
200f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_add_stream(ENGINE_HANDLE* handle,
201e7e6249aSTrond Norbye                                        const void* cookie,
202e7e6249aSTrond Norbye                                        uint32_t opaque,
203e7e6249aSTrond Norbye                                        uint16_t vbucket,
2048ebcf118SMike Wiederhold                                        uint32_t flags);
205e7e6249aSTrond Norbye
206f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_close_stream(ENGINE_HANDLE* handle,
207e7e6249aSTrond Norbye                                          const void* cookie,
208c9c7fecaSMike Wiederhold                                          uint32_t opaque,
209e7e6249aSTrond Norbye                                          uint16_t vbucket);
210e7e6249aSTrond Norbye
211f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_stream_req(ENGINE_HANDLE* handle, const void* cookie,
212001dd25dSTrond Norbye                                        uint32_t flags,
213001dd25dSTrond Norbye                                        uint32_t opaque,
214001dd25dSTrond Norbye                                        uint16_t vbucket,
215001dd25dSTrond Norbye                                        uint64_t start_seqno,
216001dd25dSTrond Norbye                                        uint64_t end_seqno,
217001dd25dSTrond Norbye                                        uint64_t vbucket_uuid,
218ee7191d1SDavid Liao                                        uint64_t snap_start_seqno,
219ee7191d1SDavid Liao                                        uint64_t snap_end_seqno,
2208b19c4aeSMike Wiederhold                                        uint64_t *rollback_seqno,
221f1818198STrond Norbye                                        dcp_add_failover_log callback);
222001dd25dSTrond Norbye
223001dd25dSTrond Norbye
224f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_get_failover_log(ENGINE_HANDLE* handle, const void* cookie,
225001dd25dSTrond Norbye                                              uint32_t opaque,
226001dd25dSTrond Norbye                                              uint16_t vbucket,
227001dd25dSTrond Norbye                                              ENGINE_ERROR_CODE (*failover_log)(vbucket_failover_t*,
228001dd25dSTrond Norbye                                                                                size_t nentries,
229001dd25dSTrond Norbye                                                                                const void *cookie));
230001dd25dSTrond Norbye
231f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_stream_end(ENGINE_HANDLE* handle, const void* cookie,
232001dd25dSTrond Norbye                                        uint32_t opaque,
233001dd25dSTrond Norbye                                        uint16_t vbucket,
234001dd25dSTrond Norbye                                        uint32_t flags);
235001dd25dSTrond Norbye
236f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_snapshot_marker(ENGINE_HANDLE* handle,
237ee7191d1SDavid Liao                                             const void* cookie,
238e7e6249aSTrond Norbye                                             uint32_t opaque,
239ee7191d1SDavid Liao                                             uint16_t vbucket,
240ee7191d1SDavid Liao                                             uint64_t start_seqno,
241ee7191d1SDavid Liao                                             uint64_t end_seqno,
242ee7191d1SDavid Liao                                             uint32_t flags);
243001dd25dSTrond Norbye
244f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_mutation(ENGINE_HANDLE* handle, const void* cookie,
245001dd25dSTrond Norbye                                      uint32_t opaque,
246001dd25dSTrond Norbye                                      const void *key,
247001dd25dSTrond Norbye                                      uint16_t nkey,
248001dd25dSTrond Norbye                                      const void *value,
249001dd25dSTrond Norbye                                      uint32_t nvalue,
250001dd25dSTrond Norbye                                      uint64_t cas,
251001dd25dSTrond Norbye                                      uint16_t vbucket,
252001dd25dSTrond Norbye                                      uint32_t flags,
253001dd25dSTrond Norbye                                      uint8_t datatype,
254001dd25dSTrond Norbye                                      uint64_t by_seqno,
255001dd25dSTrond Norbye                                      uint64_t rev_seqno,
256001dd25dSTrond Norbye                                      uint32_t expiration,
2577954bb01STrond Norbye                                      uint32_t lock_time,
2587954bb01STrond Norbye                                      const void *meta,
259c2f70513STrond Norbye                                      uint16_t nmeta,
260c2f70513STrond Norbye                                      uint8_t nru);
261001dd25dSTrond Norbye
262f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_deletion(ENGINE_HANDLE* handle, const void* cookie,
263001dd25dSTrond Norbye                                      uint32_t opaque,
264001dd25dSTrond Norbye                                      const void *key,
265001dd25dSTrond Norbye                                      uint16_t nkey,
266001dd25dSTrond Norbye                                      uint64_t cas,
267001dd25dSTrond Norbye                                      uint16_t vbucket,
268001dd25dSTrond Norbye                                      uint64_t by_seqno,
2697954bb01STrond Norbye                                      uint64_t rev_seqno,
2707954bb01STrond Norbye                                      const void *meta,
2717954bb01STrond Norbye                                      uint16_t nmeta);
272001dd25dSTrond Norbye
273f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_expiration(ENGINE_HANDLE* handle, const void* cookie,
274001dd25dSTrond Norbye                                        uint32_t opaque,
275001dd25dSTrond Norbye                                        const void *key,
276001dd25dSTrond Norbye                                        uint16_t nkey,
277001dd25dSTrond Norbye                                        uint64_t cas,
278001dd25dSTrond Norbye                                        uint16_t vbucket,
279001dd25dSTrond Norbye                                        uint64_t by_seqno,
2807954bb01STrond Norbye                                        uint64_t rev_seqno,
2817954bb01STrond Norbye                                        const void *meta,
2827954bb01STrond Norbye                                        uint16_t nmeta);
283001dd25dSTrond Norbye
284f1818198STrond Norbyestatic  ENGINE_ERROR_CODE dcp_flush(ENGINE_HANDLE* handle, const void* cookie,
285001dd25dSTrond Norbye                                   uint32_t opaque,
286001dd25dSTrond Norbye                                   uint16_t vbucket);
287001dd25dSTrond Norbye
288f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_set_vbucket_state(ENGINE_HANDLE* handle, const void* cookie,
289001dd25dSTrond Norbye                                               uint32_t opaque,
290001dd25dSTrond Norbye                                               uint16_t vbucket,
291001dd25dSTrond Norbye                                               vbucket_state_t state);
292001dd25dSTrond Norbye
293f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_noop(ENGINE_HANDLE* handle,
29488eb6934STrond Norbye                                  const void* cookie,
29588eb6934STrond Norbye                                  uint32_t opaque);
29688eb6934STrond Norbye
297f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_buffer_acknowledgement(ENGINE_HANDLE* handle,
298942a867aSMike Wiederhold                                                    const void* cookie,
299942a867aSMike Wiederhold                                                    uint32_t opaque,
300942a867aSMike Wiederhold                                                    uint16_t vbucket,
301942a867aSMike Wiederhold                                                    uint32_t bb);
302942a867aSMike Wiederhold
303f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_control(ENGINE_HANDLE* handle,
3043d213c36STrond Norbye                                     const void* cookie,
3053d213c36STrond Norbye                                     uint32_t opaque,
3063d213c36STrond Norbye                                     const void *key,
3073d213c36STrond Norbye                                     uint16_t nkey,
3083d213c36STrond Norbye                                     const void *value,
3093d213c36STrond Norbye                                     uint32_t nvalue);
3103d213c36STrond Norbye
311f1818198STrond Norbyestatic ENGINE_ERROR_CODE dcp_response_handler(ENGINE_HANDLE* handle,
31214f2f4b6STrond Norbye                                              const void* cookie,
31314f2f4b6STrond Norbye                                              protocol_binary_response_header *r);
31414f2f4b6STrond Norbye
315534f5100STrond Norbyestatic size_t bucket_errinfo(ENGINE_HANDLE *handle, const void* cookie,
316534f5100STrond Norbye                             char *buffer, size_t buffsz);
317534f5100STrond Norbye
318288d1a8bSTrond Norbyestatic ENGINE_ERROR_CODE bucket_get_engine_vb_map(ENGINE_HANDLE* handle,
319288d1a8bSTrond Norbye                                                  const void * cookie,
320288d1a8bSTrond Norbye                                                  engine_get_vb_map_cb callback);
321288d1a8bSTrond Norbye
322f603fdb6STrond Norbyestatic ENGINE_HANDLE *load_engine(cb_dlhandle_t *dlhandle, const char *soname);
323534f5100STrond Norbye
324534f5100STrond Norbyestatic bool is_authorized(ENGINE_HANDLE* handle, const void* cookie);
325534f5100STrond Norbye
326534f5100STrond Norbyestatic void free_engine_handle(proxied_engine_handle_t *);
327534f5100STrond Norbye
328534f5100STrond Norbyestatic bool list_buckets(struct bucket_engine *e, struct bucket_list **blist);
329534f5100STrond Norbyestatic void bucket_list_free(struct bucket_list *blist);
330534f5100STrond Norbyestatic void maybe_start_engine_shutdown(proxied_engine_handle_t *e);
331534f5100STrond Norbye
332534f5100STrond Norbye
333534f5100STrond Norbye/**
334534f5100STrond Norbye * This is the one and only instance of the bucket engine.
335534f5100STrond Norbye */
336f603fdb6STrond Norbyestruct bucket_engine bucket_engine;
337534f5100STrond Norbye/**
338534f5100STrond Norbye * To help us detect if we're using free'd memory, let's write a
339534f5100STrond Norbye * pattern to the memory before releasing it. That makes it more easy
340534f5100STrond Norbye * to identify in a core file if we're operating on a freed memory area
341534f5100STrond Norbye */
342534f5100STrond Norbyestatic void release_memory(void *ptr, size_t size)
343534f5100STrond Norbye{
344534f5100STrond Norbye    memset(ptr, 0xae, size);
345534f5100STrond Norbye    free(ptr);
346534f5100STrond Norbye}
347534f5100STrond Norbye
348534f5100STrond Norbye
349534f5100STrond Norbye/**
350534f5100STrond Norbye * Access to the global list of engines is protected by a single lock.
351534f5100STrond Norbye * To make the code more readable we're using a separate function
352534f5100STrond Norbye * to acquire the lock
353534f5100STrond Norbye */
354534f5100STrond Norbyestatic void lock_engines(void)
355534f5100STrond Norbye{
356f603fdb6STrond Norbye    cb_mutex_enter(&bucket_engine.engines_mutex);
357534f5100STrond Norbye}
358534f5100STrond Norbye
359534f5100STrond Norbye/**
360534f5100STrond Norbye * This is the corresponding function to release the lock for
361534f5100STrond Norbye * the list of engines.
362534f5100STrond Norbye */
363534f5100STrond Norbyestatic void unlock_engines(void)
364534f5100STrond Norbye{
365f603fdb6STrond Norbye    cb_mutex_exit(&bucket_engine.engines_mutex);
366534f5100STrond Norbye}
367534f5100STrond Norbye
368534f5100STrond Norbye/**
369534f5100STrond Norbye * Convert a bucket state (enum) t a textual string
370534f5100STrond Norbye */
371534f5100STrond Norbyestatic const char * bucket_state_name(bucket_state_t s) {
372534f5100STrond Norbye    const char * rv = NULL;
373534f5100STrond Norbye    switch(s) {
374534f5100STrond Norbye    case STATE_NULL: rv = "NULL"; break;
375534f5100STrond Norbye    case STATE_RUNNING: rv = "running"; break;
376534f5100STrond Norbye    case STATE_STOPPING: rv = "stopping"; break;
377534f5100STrond Norbye    case STATE_STOPPED: rv = "stopped"; break;
378534f5100STrond Norbye    }
379464d6f0bSTrond Norbye    cb_assert(rv);
380534f5100STrond Norbye    return rv;
381534f5100STrond Norbye}
382534f5100STrond Norbye
383534f5100STrond Norbye/**
384534f5100STrond Norbye * Helper function to get a pointer to the server API
385534f5100STrond Norbye */
386534f5100STrond Norbyestatic SERVER_HANDLE_V1 *bucket_get_server_api(void) {
387534f5100STrond Norbye    return &bucket_engine.server;
388534f5100STrond Norbye}
389534f5100STrond Norbye
390534f5100STrond Norbye/**
391534f5100STrond Norbye * Helper structure used by find_bucket_by_engine
392534f5100STrond Norbye */
393534f5100STrond Norbyestruct bucket_find_by_handle_data {
394534f5100STrond Norbye    /** The engine we're searching for */
395534f5100STrond Norbye    ENGINE_HANDLE *needle;
396534f5100STrond Norbye    /** The engine-handle for this engine */
397534f5100STrond Norbye    proxied_engine_handle_t *peh;
398534f5100STrond Norbye};
399534f5100STrond Norbye
400534f5100STrond Norbye/**
401534f5100STrond Norbye * A callback function used by genhash_iter to locate the engine handle
402534f5100STrond Norbye * object for a given engine.
403534f5100STrond Norbye *
404534f5100STrond Norbye * Runs with engines lock held.
405534f5100STrond Norbye *
406534f5100STrond Norbye * @param key not used
407534f5100STrond Norbye * @param nkey not used
408534f5100STrond Norbye * @param val the engine handle stored at this position in the hash
409534f5100STrond Norbye * @param nval not used
410534f5100STrond Norbye * @param args pointer to a bucket_find_by_handle_data structure
411534f5100STrond Norbye *             used to pass the search cirtera into the function and
412534f5100STrond Norbye *             return the object (if found).
413534f5100STrond Norbye */
414534f5100STrond Norbyestatic void find_bucket_by_engine(const void* key, size_t nkey,
415534f5100STrond Norbye                                  const void *val, size_t nval,
416534f5100STrond Norbye                                  void *args) {
417f603fdb6STrond Norbye    struct bucket_find_by_handle_data *find_data = args;
418f603fdb6STrond Norbye    const proxied_engine_handle_t *peh;
419534f5100STrond Norbye    (void)key;
420534f5100STrond Norbye    (void)nkey;
421534f5100STrond Norbye    (void)nval;
422f603fdb6STrond Norbye
423464d6f0bSTrond Norbye    cb_assert(find_data);
424464d6f0bSTrond Norbye    cb_assert(find_data->needle);
425534f5100STrond Norbye
426f603fdb6STrond Norbye    peh = val;
427534f5100STrond Norbye    if (find_data->needle == peh->pe.v0) {
428534f5100STrond Norbye        find_data->peh = (proxied_engine_handle_t *)peh;
429534f5100STrond Norbye    }
430534f5100STrond Norbye}
431534f5100STrond Norbye
432534f5100STrond Norbye/**
433534f5100STrond Norbye * bucket_engine intercepts the calls from the underlying engine to
434534f5100STrond Norbye * register callbacks. During startup bucket engine registers a callback
435534f5100STrond Norbye * for ON_DISCONNECT in memcached, so we should always be notified
436534f5100STrond Norbye * whenever a client disconnects. The underlying engine may however also
437534f5100STrond Norbye * want this notification, so we intercept their attemt to register
438534f5100STrond Norbye * callbacks and forward the callback to the correct engine.
439534f5100STrond Norbye *
440534f5100STrond Norbye * This function will _always_ be called while we're holding the global
441534f5100STrond Norbye * lock for the hash table (during the call to "initialize" in the
442534f5100STrond Norbye * underlying engine. It is therefore safe to try to traverse the
443534f5100STrond Norbye * engines list.
444534f5100STrond Norbye */
445534f5100STrond Norbyestatic void bucket_register_callback(ENGINE_HANDLE *eh,
446534f5100STrond Norbye                                     ENGINE_EVENT_TYPE type,
447534f5100STrond Norbye                                     EVENT_CALLBACK cb, const void *cb_data) {
448534f5100STrond Norbye
449f603fdb6STrond Norbye    struct bucket_find_by_handle_data find_data;
450f603fdb6STrond Norbye
451534f5100STrond Norbye    /* For simplicity, we're not going to test every combination until
452534f5100STrond Norbye       we need them. */
453464d6f0bSTrond Norbye    cb_assert(type == ON_DISCONNECT);
454534f5100STrond Norbye
455534f5100STrond Norbye    /* Assume this always happens while holding the hash table lock. */
456534f5100STrond Norbye    /* This is called from underlying engine 'initialize' handler
457534f5100STrond Norbye     * which we invoke with engines_mutex held */
458f603fdb6STrond Norbye    find_data.needle = eh;
459f603fdb6STrond Norbye    find_data.peh = NULL;
460534f5100STrond Norbye
461534f5100STrond Norbye    genhash_iter(bucket_engine.engines, find_bucket_by_engine, &find_data);
462534f5100STrond Norbye
463534f5100STrond Norbye    if (find_data.peh) {
464534f5100STrond Norbye        find_data.peh->cb = cb;
465534f5100STrond Norbye        find_data.peh->cb_data = cb_data;
466534f5100STrond Norbye        find_data.peh->wants_disconnects = true;
467534f5100STrond Norbye    } else if (bucket_engine.has_default && eh == bucket_engine.default_engine.pe.v0){
468534f5100STrond Norbye        bucket_engine.default_engine.cb = cb;
469534f5100STrond Norbye        bucket_engine.default_engine.cb_data = cb_data;
470534f5100STrond Norbye        bucket_engine.default_engine.wants_disconnects = true;
471534f5100STrond Norbye    }
472534f5100STrond Norbye}
473534f5100STrond Norbye
474534f5100STrond Norbye/**
475534f5100STrond Norbye * The engine api allows the underlying engine to perform various callbacks
476534f5100STrond Norbye * This isn't implemented in bucket engine as of today.
477534f5100STrond Norbye */
478534f5100STrond Norbyestatic void bucket_perform_callbacks(ENGINE_EVENT_TYPE type,
479534f5100STrond Norbye                                     const void *data, const void *cookie) {
480534f5100STrond Norbye    (void)type;
481534f5100STrond Norbye    (void)data;
482534f5100STrond Norbye    (void)cookie;
483534f5100STrond Norbye    abort(); /* Not implemented */
484534f5100STrond Norbye}
485534f5100STrond Norbye
486534f5100STrond Norbye/**
487534f5100STrond Norbye * Store engine-specific data in the engine-specific section of this
488534f5100STrond Norbye * cookie's data stored in the memcached core. The "upstream" cookie
489534f5100STrond Norbye * should have been registered during the "ON_CONNECT" callback, so it
490534f5100STrond Norbye * would be a bug if it isn't here anymore
491534f5100STrond Norbye */
492534f5100STrond Norbyestatic void bucket_store_engine_specific(const void *cookie, void *engine_data) {
493534f5100STrond Norbye    engine_specific_t *es;
494534f5100STrond Norbye    es = bucket_engine.upstream_server->cookie->get_engine_specific(cookie);
495464d6f0bSTrond Norbye    cb_assert(es);
496534f5100STrond Norbye    es->engine_specific = engine_data;
497534f5100STrond Norbye}
498534f5100STrond Norbye
499534f5100STrond Norbye/**
500534f5100STrond Norbye * Get the engine-specific data from the engine-specific section of
501534f5100STrond Norbye * this cookies data stored in the memcached core.
502534f5100STrond Norbye */
503534f5100STrond Norbyestatic void* bucket_get_engine_specific(const void *cookie) {
504f603fdb6STrond Norbye    engine_specific_t *es;
505f603fdb6STrond Norbye    es = bucket_engine.upstream_server->cookie->get_engine_specific(cookie);
506464d6f0bSTrond Norbye    cb_assert(es);
507534f5100STrond Norbye    return es->engine_specific;
508534f5100STrond Norbye}
509534f5100STrond Norbye
5112c217587Sabhinavdangeti * Get the session-token stored in the memcached core.
5122c217587Sabhinavdangeti */
5132c217587Sabhinavdangetistatic bool bucket_validate_session_cas(const uint64_t cas) {
5142c217587Sabhinavdangeti    return bucket_engine.upstream_server->cookie->validate_session_cas(cas);
5184f426e26Sabhinavdangeti * Decrement the session_cas's counter held in memcached core.
5194f426e26Sabhinavdangeti */
5204f426e26Sabhinavdangetistatic void bucket_decrement_session_ctr(void) {
5214f426e26Sabhinavdangeti    bucket_engine.upstream_server->cookie->decrement_session_ctr();
524534f5100STrond Norbye/**
525534f5100STrond Norbye * We don't allow the underlying engines to register or remove extensions
526534f5100STrond Norbye */
527534f5100STrond Norbyestatic bool bucket_register_extension(extension_type_t type,
528534f5100STrond Norbye                                      void *extension) {
529534f5100STrond Norbye    (void)type;
530534f5100STrond Norbye    (void)extension;
531534f5100STrond Norbye    logger->log(EXTENSION_LOG_WARNING, NULL,
532534f5100STrond Norbye                "Extension support isn't implemented in this version "
533534f5100STrond Norbye                "of bucket_engine");
534534f5100STrond Norbye    return false;
535534f5100STrond Norbye}
536534f5100STrond Norbye
537534f5100STrond Norbye/**
538534f5100STrond Norbye * Since you can't register an extension this function should _never_ be
539534f5100STrond Norbye * called...
540534f5100STrond Norbye */
541534f5100STrond Norbyestatic void bucket_unregister_extension(extension_type_t type, void *extension) {
542534f5100STrond Norbye    (void)type;
543534f5100STrond Norbye    (void)extension;
544534f5100STrond Norbye    logger->log(EXTENSION_LOG_WARNING, NULL,
545534f5100STrond Norbye                "Extension support isn't implemented in this version "
546534f5100STrond Norbye                "of bucket_engine");
547534f5100STrond Norbye    abort(); /* No extensions registered, none can unregister */
548534f5100STrond Norbye}
549534f5100STrond Norbye
550534f5100STrond Norbye/**
551534f5100STrond Norbye * Get a given extension type from the memcached core.
552534f5100STrond Norbye * @todo Why do we overload this when all we do is wrap it directly?
553534f5100STrond Norbye */
554534f5100STrond Norbyestatic void* bucket_get_extension(extension_type_t type) {
555534f5100STrond Norbye    return bucket_engine.upstream_server->extension->get_extension(type);
556534f5100STrond Norbye}
557534f5100STrond Norbye
558534f5100STrond Norbye/* Engine API functions */
559534f5100STrond Norbye
560534f5100STrond Norbye/**
561534f5100STrond Norbye * This is the public entry point for bucket_engine. It is called by
562534f5100STrond Norbye * the memcached core and is responsible for doing basic allocation and
563534f5100STrond Norbye * initialization of the one and only instance of the bucket_engine object.
564534f5100STrond Norbye *
565534f5100STrond Norbye * The "normal" initialization is performed in bucket_initialize which is
566534f5100STrond Norbye * called from the memcached core after a successful call to create_instance.
567534f5100STrond Norbye */
568534f5100STrond NorbyeENGINE_ERROR_CODE create_instance(uint64_t interface,
569534f5100STrond Norbye                                  GET_SERVER_API gsapi,
570534f5100STrond Norbye                                  ENGINE_HANDLE **handle) {
571534f5100STrond Norbye    if (interface != 1) {
572534f5100STrond Norbye        return ENGINE_ENOTSUP;
573534f5100STrond Norbye    }
574534f5100STrond Norbye
575f603fdb6STrond Norbye    memset(&bucket_engine, 0, sizeof(bucket_engine));
576f603fdb6STrond Norbye    bucket_engine.engine.interface.interface = 1;
577f603fdb6STrond Norbye    bucket_engine.engine.get_info = bucket_get_info;
578f603fdb6STrond Norbye    bucket_engine.engine.