MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
default_engine.c
1 #include "config.h"
2 
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <assert.h>
7 #include <errno.h>
8 #include <ctype.h>
9 #include <unistd.h>
10 #include <stddef.h>
11 #include <inttypes.h>
12 #include <arpa/inet.h>
13 
14 #include "default_engine.h"
15 #include "memcached/util.h"
16 #include "memcached/config_parser.h"
17 
18 #define CMD_SET_VBUCKET 0x83
19 #define CMD_GET_VBUCKET 0x84
20 #define CMD_DEL_VBUCKET 0x85
21 
22 static const engine_info* default_get_info(ENGINE_HANDLE* handle);
23 static ENGINE_ERROR_CODE default_initialize(ENGINE_HANDLE* handle,
24  const char* config_str);
25 static void default_destroy(ENGINE_HANDLE* handle, bool force);
26 static ENGINE_ERROR_CODE default_item_allocate(ENGINE_HANDLE* handle,
27  const void* cookie,
28  item **item,
29  const void* key,
30  const size_t nkey,
31  const size_t nbytes,
32  const int flags,
33  const rel_time_t exptime);
34 static ENGINE_ERROR_CODE default_item_delete(ENGINE_HANDLE* handle,
35  const void* cookie,
36  const void* key,
37  const size_t nkey,
38  uint64_t cas,
39  uint16_t vbucket);
40 
41 static void default_item_release(ENGINE_HANDLE* handle, const void *cookie,
42  item* item);
43 static ENGINE_ERROR_CODE default_get(ENGINE_HANDLE* handle,
44  const void* cookie,
45  item** item,
46  const void* key,
47  const int nkey,
48  uint16_t vbucket);
49 static ENGINE_ERROR_CODE default_get_stats(ENGINE_HANDLE* handle,
50  const void *cookie,
51  const char *stat_key,
52  int nkey,
53  ADD_STAT add_stat);
54 static void default_reset_stats(ENGINE_HANDLE* handle, const void *cookie);
55 static ENGINE_ERROR_CODE default_store(ENGINE_HANDLE* handle,
56  const void *cookie,
57  item* item,
58  uint64_t *cas,
59  ENGINE_STORE_OPERATION operation,
60  uint16_t vbucket);
61 static ENGINE_ERROR_CODE default_arithmetic(ENGINE_HANDLE* handle,
62  const void* cookie,
63  const void* key,
64  const int nkey,
65  const bool increment,
66  const bool create,
67  const uint64_t delta,
68  const uint64_t initial,
69  const rel_time_t exptime,
70  uint64_t *cas,
71  uint64_t *result,
72  uint16_t vbucket);
73 static ENGINE_ERROR_CODE default_flush(ENGINE_HANDLE* handle,
74  const void* cookie, time_t when);
75 static ENGINE_ERROR_CODE initalize_configuration(struct default_engine *se,
76  const char *cfg_str);
77 static TAP_ITERATOR get_tap_iterator(ENGINE_HANDLE* handle, const void* cookie,
78  const void* client, size_t nclient,
79  uint32_t flags,
80  const void* userdata, size_t nuserdata);
81 static ENGINE_ERROR_CODE default_unknown_command(ENGINE_HANDLE* handle,
82  const void* cookie,
84  ADD_RESPONSE response);
85 
87  char c;
88  struct vbucket_info v;
89 };
90 
91 static void set_vbucket_state(struct default_engine *e,
92  uint16_t vbid, enum vbucket_state to) {
93  union vbucket_info_adapter vi;
94  vi.c = e->vbucket_infos[vbid];
95  vi.v.state = to;
96  e->vbucket_infos[vbid] = vi.c;
97 }
98 
99 static enum vbucket_state get_vbucket_state(struct default_engine *e,
100  uint16_t vbid) {
101  union vbucket_info_adapter vi;
102  vi.c = e->vbucket_infos[vbid];
103  return vi.v.state;
104 }
105 
106 static bool handled_vbucket(struct default_engine *e, uint16_t vbid) {
107  return e->config.ignore_vbucket
108  || (get_vbucket_state(e, vbid) == VBUCKET_STATE_ACTIVE);
109 }
110 
111 /* mechanism for handling bad vbucket requests */
112 #define VBUCKET_GUARD(e, v) if (!handled_vbucket(e, v)) { return ENGINE_NOT_MY_VBUCKET; }
113 
114 static bool get_item_info(ENGINE_HANDLE *handle, const void *cookie,
115  const item* item, item_info *item_info);
116 
117 static const char const * vbucket_state_name(enum vbucket_state s) {
118  static const char const * vbucket_states[] = {
119  "dead", "active", "replica", "pending"
120  };
121  return vbucket_states[s];
122 }
123 
124 ENGINE_ERROR_CODE create_instance(uint64_t interface,
125  GET_SERVER_API get_server_api,
126  ENGINE_HANDLE **handle) {
127  SERVER_HANDLE_V1 *api = get_server_api();
128  if (interface != 1 || api == NULL) {
129  return ENGINE_ENOTSUP;
130  }
131 
132  struct default_engine *engine = malloc(sizeof(*engine));
133  if (engine == NULL) {
134  return ENGINE_ENOMEM;
135  }
136 
137  struct default_engine default_engine = {
138  .engine = {
139  .interface = {
140  .interface = 1
141  },
142  .get_info = default_get_info,
143  .initialize = default_initialize,
144  .destroy = default_destroy,
145  .allocate = default_item_allocate,
146  .remove = default_item_delete,
147  .release = default_item_release,
148  .get = default_get,
149  .get_stats = default_get_stats,
150  .reset_stats = default_reset_stats,
151  .store = default_store,
152  .arithmetic = default_arithmetic,
153  .flush = default_flush,
154  .unknown_command = default_unknown_command,
155  .item_set_cas = item_set_cas,
156  .get_item_info = get_item_info,
157  .get_tap_iterator = get_tap_iterator
158  },
159  .server = *api,
160  .get_server_api = get_server_api,
161  .initialized = true,
162  .assoc = {
163  .hashpower = 16,
164  },
165  .slabs = {
166  .lock = PTHREAD_MUTEX_INITIALIZER
167  },
168  .cache_lock = PTHREAD_MUTEX_INITIALIZER,
169  .stats = {
170  .lock = PTHREAD_MUTEX_INITIALIZER,
171  },
172  .config = {
173  .use_cas = true,
174  .verbose = 0,
175  .oldest_live = 0,
176  .evict_to_free = true,
177  .maxbytes = 64 * 1024 * 1024,
178  .preallocate = false,
179  .factor = 1.25,
180  .chunk_size = 48,
181  .item_size_max= 1024 * 1024,
182  },
183  .scrubber = {
184  .lock = PTHREAD_MUTEX_INITIALIZER,
185  },
186  /* FIXME: compilation issue on solaris x86
187  .info.engine_info = {
188  .description = "Default engine v0.1",
189  .num_features = 1,
190  .features = {
191  [0].feature = ENGINE_FEATURE_LRU
192  }
193  } */
194  };
195 
196  *engine = default_engine;
197 
198  *handle = (ENGINE_HANDLE*)&engine->engine;
199  return ENGINE_SUCCESS;
200 }
201 
202 static inline struct default_engine* get_handle(ENGINE_HANDLE* handle) {
203  return (struct default_engine*)handle;
204 }
205 
206 static inline hash_item* get_real_item(item* item) {
207  return (hash_item*)item;
208 }
209 
210 static const engine_info* default_get_info(ENGINE_HANDLE* handle) {
211  return &get_handle(handle)->info.engine_info;
212 }
213 
214 static ENGINE_ERROR_CODE default_initialize(ENGINE_HANDLE* handle,
215  const char* config_str) {
216  struct default_engine* se = get_handle(handle);
217 
218  ENGINE_ERROR_CODE ret = initalize_configuration(se, config_str);
219  if (ret != ENGINE_SUCCESS) {
220  return ret;
221  }
222 
223  /* fixup feature_info */
224  if (se->config.use_cas) {
225  se->info.engine_info.features[se->info.engine_info.num_features++].feature = ENGINE_FEATURE_CAS;
226  }
227 
228  ret = assoc_init(se);
229  if (ret != ENGINE_SUCCESS) {
230  return ret;
231  }
232 
233  ret = slabs_init(se, se->config.maxbytes, se->config.factor,
234  se->config.preallocate);
235  if (ret != ENGINE_SUCCESS) {
236  return ret;
237  }
238 
239  return ENGINE_SUCCESS;
240 }
241 
242 static void default_destroy(ENGINE_HANDLE* handle, bool force) {
243  struct default_engine* se = get_handle(handle);
244 
245  if (se->initialized) {
246  pthread_mutex_destroy(&se->cache_lock);
247  pthread_mutex_destroy(&se->stats.lock);
248  pthread_mutex_destroy(&se->slabs.lock);
249  se->initialized = false;
250  free(se);
251  }
252 }
253 
254 static ENGINE_ERROR_CODE default_item_allocate(ENGINE_HANDLE* handle,
255  const void* cookie,
256  item **item,
257  const void* key,
258  const size_t nkey,
259  const size_t nbytes,
260  const int flags,
261  const rel_time_t exptime) {
262  struct default_engine* engine = get_handle(handle);
263  size_t ntotal = sizeof(hash_item) + nkey + nbytes;
264  if (engine->config.use_cas) {
265  ntotal += sizeof(uint64_t);
266  }
267  unsigned int id = slabs_clsid(engine, ntotal);
268  if (id == 0) {
269  return ENGINE_E2BIG;
270  }
271 
272  hash_item *it;
273  it = item_alloc(engine, key, nkey, flags, exptime, nbytes, cookie);
274 
275  if (it != NULL) {
276  *item = it;
277  return ENGINE_SUCCESS;
278  } else {
279  return ENGINE_ENOMEM;
280  }
281 }
282 
283 static ENGINE_ERROR_CODE default_item_delete(ENGINE_HANDLE* handle,
284  const void* cookie,
285  const void* key,
286  const size_t nkey,
287  uint64_t cas,
288  uint16_t vbucket)
289 {
290  struct default_engine* engine = get_handle(handle);
291  VBUCKET_GUARD(engine, vbucket);
292 
293  hash_item *it = item_get(engine, key, nkey);
294  if (it == NULL) {
295  return ENGINE_KEY_ENOENT;
296  }
297 
298  if (cas == 0 || cas == item_get_cas(it)) {
299  item_unlink(engine, it);
300  item_release(engine, it);
301  } else {
302  return ENGINE_KEY_EEXISTS;
303  }
304 
305  return ENGINE_SUCCESS;
306 }
307 
308 static void default_item_release(ENGINE_HANDLE* handle,
309  const void *cookie,
310  item* item) {
311  item_release(get_handle(handle), get_real_item(item));
312 }
313 
314 static ENGINE_ERROR_CODE default_get(ENGINE_HANDLE* handle,
315  const void* cookie,
316  item** item,
317  const void* key,
318  const int nkey,
319  uint16_t vbucket) {
320  struct default_engine *engine = get_handle(handle);
321  VBUCKET_GUARD(engine, vbucket);
322 
323  *item = item_get(engine, key, nkey);
324  if (*item != NULL) {
325  return ENGINE_SUCCESS;
326  } else {
327  return ENGINE_KEY_ENOENT;
328  }
329 }
330 
331 static void stats_vbucket(struct default_engine *e,
332  ADD_STAT add_stat,
333  const void *cookie) {
334  for (int i = 0; i < NUM_VBUCKETS; i++) {
335  enum vbucket_state state = get_vbucket_state(e, i);
336  if (state != VBUCKET_STATE_DEAD) {
337  char buf[16];
338  snprintf(buf, sizeof(buf), "vb_%d", i);
339  const char * state_name = vbucket_state_name(state);
340  add_stat(buf, strlen(buf), state_name, strlen(state_name), cookie);
341  }
342  }
343 }
344 
345 static ENGINE_ERROR_CODE default_get_stats(ENGINE_HANDLE* handle,
346  const void* cookie,
347  const char* stat_key,
348  int nkey,
349  ADD_STAT add_stat)
350 {
351  struct default_engine* engine = get_handle(handle);
352  ENGINE_ERROR_CODE ret = ENGINE_SUCCESS;
353 
354  if (stat_key == NULL) {
355  char val[128];
356  int len;
357 
358  pthread_mutex_lock(&engine->stats.lock);
359  len = sprintf(val, "%"PRIu64, (uint64_t)engine->stats.evictions);
360  add_stat("evictions", 9, val, len, cookie);
361  len = sprintf(val, "%"PRIu64, (uint64_t)engine->stats.curr_items);
362  add_stat("curr_items", 10, val, len, cookie);
363  len = sprintf(val, "%"PRIu64, (uint64_t)engine->stats.total_items);
364  add_stat("total_items", 11, val, len, cookie);
365  len = sprintf(val, "%"PRIu64, (uint64_t)engine->stats.curr_bytes);
366  add_stat("bytes", 5, val, len, cookie);
367  len = sprintf(val, "%"PRIu64, engine->stats.reclaimed);
368  add_stat("reclaimed", 9, val, len, cookie);
369  len = sprintf(val, "%"PRIu64, (uint64_t)engine->config.maxbytes);
370  add_stat("engine_maxbytes", 15, val, len, cookie);
371  pthread_mutex_unlock(&engine->stats.lock);
372  } else if (strncmp(stat_key, "slabs", 5) == 0) {
373  slabs_stats(engine, add_stat, cookie);
374  } else if (strncmp(stat_key, "items", 5) == 0) {
375  item_stats(engine, add_stat, cookie);
376  } else if (strncmp(stat_key, "sizes", 5) == 0) {
377  item_stats_sizes(engine, add_stat, cookie);
378  } else if (strncmp(stat_key, "vbucket", 7) == 0) {
379  stats_vbucket(engine, add_stat, cookie);
380  } else if (strncmp(stat_key, "scrub", 5) == 0) {
381  char val[128];
382  int len;
383 
384  pthread_mutex_lock(&engine->scrubber.lock);
385  if (engine->scrubber.running) {
386  add_stat("scrubber:status", 15, "running", 7, cookie);
387  } else {
388  add_stat("scrubber:status", 15, "stopped", 7, cookie);
389  }
390 
391  if (engine->scrubber.started != 0) {
392  if (engine->scrubber.stopped != 0) {
393  time_t diff = engine->scrubber.started - engine->scrubber.stopped;
394  len = sprintf(val, "%"PRIu64, (uint64_t)diff);
395  add_stat("scrubber:last_run", 17, val, len, cookie);
396  }
397 
398  len = sprintf(val, "%"PRIu64, engine->scrubber.visited);
399  add_stat("scrubber:visited", 16, val, len, cookie);
400  len = sprintf(val, "%"PRIu64, engine->scrubber.cleaned);
401  add_stat("scrubber:cleaned", 16, val, len, cookie);
402  }
403  pthread_mutex_unlock(&engine->scrubber.lock);
404  } else {
405  ret = ENGINE_KEY_ENOENT;
406  }
407 
408  return ret;
409 }
410 
411 static ENGINE_ERROR_CODE default_store(ENGINE_HANDLE* handle,
412  const void *cookie,
413  item* item,
414  uint64_t *cas,
415  ENGINE_STORE_OPERATION operation,
416  uint16_t vbucket) {
417  struct default_engine *engine = get_handle(handle);
418  VBUCKET_GUARD(engine, vbucket);
419  return store_item(engine, get_real_item(item), cas, operation,
420  cookie);
421 }
422 
423 static ENGINE_ERROR_CODE default_arithmetic(ENGINE_HANDLE* handle,
424  const void* cookie,
425  const void* key,
426  const int nkey,
427  const bool increment,
428  const bool create,
429  const uint64_t delta,
430  const uint64_t initial,
431  const rel_time_t exptime,
432  uint64_t *cas,
433  uint64_t *result,
434  uint16_t vbucket) {
435  struct default_engine *engine = get_handle(handle);
436  VBUCKET_GUARD(engine, vbucket);
437 
438  return arithmetic(engine, cookie, key, nkey, increment,
439  create, delta, initial, exptime, cas,
440  result);
441 }
442 
443 static ENGINE_ERROR_CODE default_flush(ENGINE_HANDLE* handle,
444  const void* cookie, time_t when) {
445  item_flush_expired(get_handle(handle), when);
446 
447  return ENGINE_SUCCESS;
448 }
449 
450 static void default_reset_stats(ENGINE_HANDLE* handle, const void *cookie) {
451  struct default_engine *engine = get_handle(handle);
452  item_stats_reset(engine);
453 
454  pthread_mutex_lock(&engine->stats.lock);
455  engine->stats.evictions = 0;
456  engine->stats.reclaimed = 0;
457  engine->stats.total_items = 0;
458  pthread_mutex_unlock(&engine->stats.lock);
459 }
460 
461 static tap_event_t tap_always_pause(ENGINE_HANDLE *e,
462  const void *cookie, item **itm, void **es,
463  uint16_t *nes, uint8_t *ttl, uint16_t *flags,
464  uint32_t *seqno, uint16_t *vbucket) {
465  return TAP_PAUSE;
466 }
467 
468 static tap_event_t tap_always_disconnect(ENGINE_HANDLE *e,
469  const void *cookie, item **itm, void **es,
470  uint16_t *nes, uint8_t *ttl, uint16_t *flags,
471  uint32_t *seqno, uint16_t *vbucket) {
472  return TAP_DISCONNECT;
473 }
474 
475 static TAP_ITERATOR get_tap_iterator(ENGINE_HANDLE* handle, const void* cookie,
476  const void* client, size_t nclient,
477  uint32_t flags,
478  const void* userdata, size_t nuserdata) {
479  TAP_ITERATOR rv = tap_always_pause;
480  if ((flags & TAP_CONNECT_FLAG_DUMP)
481  || (flags & TAP_CONNECT_FLAG_TAKEOVER_VBUCKETS)) {
482  rv = tap_always_disconnect;
483  }
484  return rv;
485 }
486 
487 static ENGINE_ERROR_CODE initalize_configuration(struct default_engine *se,
488  const char *cfg_str) {
489  ENGINE_ERROR_CODE ret = ENGINE_SUCCESS;
490 
491  se->config.vb0 = true;
492 
493  if (cfg_str != NULL) {
494  struct config_item items[] = {
495  { .key = "use_cas",
496  .datatype = DT_BOOL,
497  .value.dt_bool = &se->config.use_cas },
498  { .key = "verbose",
499  .datatype = DT_SIZE,
500  .value.dt_size = &se->config.verbose },
501  { .key = "eviction",
502  .datatype = DT_BOOL,
503  .value.dt_bool = &se->config.evict_to_free },
504  { .key = "cache_size",
505  .datatype = DT_SIZE,
506  .value.dt_size = &se->config.maxbytes },
507  { .key = "preallocate",
508  .datatype = DT_BOOL,
509  .value.dt_bool = &se->config.preallocate },
510  { .key = "factor",
511  .datatype = DT_FLOAT,
512  .value.dt_float = &se->config.factor },
513  { .key = "chunk_size",
514  .datatype = DT_SIZE,
515  .value.dt_size = &se->config.chunk_size },
516  { .key = "item_size_max",
517  .datatype = DT_SIZE,
518  .value.dt_size = &se->config.item_size_max },
519  { .key = "ignore_vbucket",
520  .datatype = DT_BOOL,
521  .value.dt_bool = &se->config.ignore_vbucket },
522  { .key = "vb0",
523  .datatype = DT_BOOL,
524  .value.dt_bool = &se->config.vb0 },
525  { .key = "config_file",
526  .datatype = DT_CONFIGFILE },
527  { .key = NULL}
528  };
529 
530  ret = se->server.core->parse_config(cfg_str, items, stderr);
531  }
532 
533  if (se->config.vb0) {
534  set_vbucket_state(se, 0, VBUCKET_STATE_ACTIVE);
535  }
536 
537  return ENGINE_SUCCESS;
538 }
539 
540 static protocol_binary_response_status set_vbucket(struct default_engine *e,
542  const char **msg) {
545  assert(req);
546 
547  char keyz[32];
548  char valz[32];
549 
550  // Read the key.
551  int keylen = ntohs(req->message.header.request.keylen);
552  if (keylen >= (int)sizeof(keyz)) {
553  *msg = "Key is too large.";
554  return PROTOCOL_BINARY_RESPONSE_EINVAL;
555  }
556  memcpy(keyz, ((char*)request) + sizeof(req->message.header), keylen);
557  keyz[keylen] = 0x00;
558 
559  // Read the value.
560  size_t bodylen = ntohl(req->message.header.request.bodylen)
561  - ntohs(req->message.header.request.keylen);
562  if (bodylen >= sizeof(valz)) {
563  *msg = "Value is too large.";
564  return PROTOCOL_BINARY_RESPONSE_EINVAL;
565  }
566  memcpy(valz, (char*)request + sizeof(req->message.header)
567  + keylen, bodylen);
568  valz[bodylen] = 0x00;
569 
570  protocol_binary_response_status rv = PROTOCOL_BINARY_RESPONSE_SUCCESS;
571  *msg = "Configured";
572 
573  enum vbucket_state state;
574  if (strcmp(valz, "active") == 0) {
575  state = VBUCKET_STATE_ACTIVE;
576  } else if(strcmp(valz, "replica") == 0) {
577  state = VBUCKET_STATE_REPLICA;
578  } else if(strcmp(valz, "pending") == 0) {
579  state = VBUCKET_STATE_PENDING;
580  } else if(strcmp(valz, "dead") == 0) {
581  state = VBUCKET_STATE_DEAD;
582  } else {
583  *msg = "Invalid state.";
584  return PROTOCOL_BINARY_RESPONSE_EINVAL;
585  }
586 
587  uint32_t vbucket = 0;
588  if (!safe_strtoul(keyz, &vbucket) || vbucket > NUM_VBUCKETS) {
589  *msg = "Value out of range.";
590  rv = PROTOCOL_BINARY_RESPONSE_EINVAL;
591  } else {
592  set_vbucket_state(e, (uint16_t)vbucket, state);
593  }
594 
595  return rv;
596 }
597 
598 static protocol_binary_response_status get_vbucket(struct default_engine *e,
600  const char **msg) {
603  assert(req);
604 
605  char keyz[8]; // stringy 2^16 int
606 
607  // Read the key.
608  int keylen = ntohs(req->message.header.request.keylen);
609  if (keylen >= (int)sizeof(keyz)) {
610  *msg = "Key is too large.";
611  return PROTOCOL_BINARY_RESPONSE_EINVAL;
612  }
613  memcpy(keyz, ((char*)request) + sizeof(req->message.header), keylen);
614  keyz[keylen] = 0x00;
615 
616  protocol_binary_response_status rv = PROTOCOL_BINARY_RESPONSE_SUCCESS;
617 
618  uint32_t vbucket = 0;
619  if (!safe_strtoul(keyz, &vbucket) || vbucket > NUM_VBUCKETS) {
620  *msg = "Value out of range.";
621  rv = PROTOCOL_BINARY_RESPONSE_EINVAL;
622  } else {
623  *msg = vbucket_state_name(get_vbucket_state(e, (uint16_t)vbucket));
624  }
625 
626  return rv;
627 }
628 
629 static protocol_binary_response_status rm_vbucket(struct default_engine *e,
631  const char **msg) {
634  assert(req);
635 
636  char keyz[8]; // stringy 2^16 int
637 
638  // Read the key.
639  int keylen = ntohs(req->message.header.request.keylen);
640  if (keylen >= (int)sizeof(keyz)) {
641  *msg = "Key is too large.";
642  return PROTOCOL_BINARY_RESPONSE_EINVAL;
643  }
644  memcpy(keyz, ((char*)request) + sizeof(req->message.header), keylen);
645  keyz[keylen] = 0x00;
646 
647  protocol_binary_response_status rv = PROTOCOL_BINARY_RESPONSE_SUCCESS;
648 
649  uint32_t vbucket = 0;
650  if (!safe_strtoul(keyz, &vbucket) || vbucket > NUM_VBUCKETS) {
651  *msg = "Value out of range.";
652  rv = PROTOCOL_BINARY_RESPONSE_EINVAL;
653  } else {
654  set_vbucket_state(e, (uint16_t)vbucket, VBUCKET_STATE_DEAD);
655  }
656 
657  assert(msg);
658  return rv;
659 }
660 
661 static protocol_binary_response_status scrub_cmd(struct default_engine *e,
663  const char **msg) {
664  return item_start_scrub(e) ? PROTOCOL_BINARY_RESPONSE_SUCCESS
665  : PROTOCOL_BINARY_RESPONSE_EBUSY;
666 }
667 
668 static ENGINE_ERROR_CODE default_unknown_command(ENGINE_HANDLE* handle,
669  const void* cookie,
671  ADD_RESPONSE response)
672 {
673  struct default_engine* e = get_handle(handle);
674 
675  bool handled = true;
676  const char *msg = NULL;
678  PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND;
679 
680  switch(request->request.opcode) {
681  case PROTOCOL_BINARY_CMD_SCRUB:
682  res = scrub_cmd(e, request, &msg);
683  break;
684  case CMD_DEL_VBUCKET:
685  res = rm_vbucket(e, request, &msg);
686  break;
687  case CMD_SET_VBUCKET:
688  res = set_vbucket(e, request, &msg);
689  break;
690  case CMD_GET_VBUCKET:
691  res = get_vbucket(e, request, &msg);
692  break;
693  default:
694  handled = false;
695  break;
696  }
697 
698  bool sent = false;
699  if (handled) {
700  size_t msg_size = msg ? strlen(msg) : 0;
701  sent = response(NULL, 0, NULL, 0,
702  msg, (uint16_t)msg_size,
703  PROTOCOL_BINARY_RAW_BYTES,
704  (uint16_t)res, 0, cookie);
705  } else {
706  sent = response(NULL, 0, NULL, 0, NULL, 0,
707  PROTOCOL_BINARY_RAW_BYTES,
708  PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND, 0, cookie);
709  }
710 
711  if (sent) {
712  return ENGINE_SUCCESS;
713  } else {
714  return ENGINE_FAILED;
715  }
716 }
717 
718 
719 uint64_t item_get_cas(const hash_item* item)
720 {
721  if (item->iflag & ITEM_WITH_CAS) {
722  return *(uint64_t*)(item + 1);
723  }
724  return 0;
725 }
726 
727 void item_set_cas(ENGINE_HANDLE *handle, const void *cookie,
728  item* item, uint64_t val)
729 {
730  hash_item* it = get_real_item(item);
731  if (it->iflag & ITEM_WITH_CAS) {
732  *(uint64_t*)(it + 1) = val;
733  }
734 }
735 
736 const void* item_get_key(const hash_item* item)
737 {
738  char *ret = (void*)(item + 1);
739  if (item->iflag & ITEM_WITH_CAS) {
740  ret += sizeof(uint64_t);
741  }
742 
743  return ret;
744 }
745 
746 char* item_get_data(const hash_item* item)
747 {
748  return ((char*)item_get_key(item)) + item->nkey;
749 }
750 
751 uint8_t item_get_clsid(const hash_item* item)
752 {
753  return 0;
754 }
755 
756 static bool get_item_info(ENGINE_HANDLE *handle, const void *cookie,
757  const item* item, item_info *item_info)
758 {
759  hash_item* it = (hash_item*)item;
760  if (item_info->nvalue < 1) {
761  return false;
762  }
763  item_info->cas = item_get_cas(it);
764  item_info->exptime = it->exptime;
765  item_info->nbytes = it->nbytes;
766  item_info->flags = it->flags;
767  item_info->clsid = it->slabs_clsid;
768  item_info->nkey = it->nkey;
769  item_info->nvalue = 1;
770  item_info->key = item_get_key(it);
771  item_info->value[0].iov_base = item_get_data(it);
772  item_info->value[0].iov_len = it->nbytes;
773  return true;
774 }