MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
innodb_engine.c
Go to the documentation of this file.
1 /***********************************************************************
2 
3 Copyright (c) 2013, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17 
18 ***********************************************************************/
19 
20 /**************************************************/
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 #include <pthread.h>
32 #include <arpa/inet.h>
33 #include "default_engine.h"
34 #include <memcached/util.h>
35 #include <memcached/config_parser.h>
36 #include <unistd.h>
37 
38 #include "innodb_engine.h"
39 #include "innodb_engine_private.h"
40 #include "innodb_api.h"
41 #include "hash_item_util.h"
42 #include "innodb_cb_api.h"
43 
45 #define KEY_MAX_LENGTH 250
46 
49 #define BK_COMMIT_THREAD_SLEEP_INTERVAL 5
50 
53 #define BK_MAX_PROCESS_COMMIT 5
54 
57 #define CONN_IDLE_TIME_TO_BK_COMMIT 5
58 
60 static bool memcached_shutdown = false;
61 
63 static bool bk_thd_exited = true;
64 
66 typedef struct eng_config_info {
67  char* option_string;
69  void* cb_ptr;
70  unsigned int eng_read_batch_size;
71  unsigned int eng_write_batch_size;
76 
78 
84 /**********************************************************************/
87 extern
88 int
90 /*=================*/
91  void* my_thd,
92  void* my_table,
93  int my_lock_mode);
95 /*******************************************************************/
98 static inline
99 struct innodb_engine*
100 innodb_handle(
101 /*==========*/
102  ENGINE_HANDLE* handle)
103 {
104  return((struct innodb_engine*) handle);
105 }
106 
107 /*******************************************************************/
111 static
112 void
113 innodb_conn_clean_data(
114 /*===================*/
116  bool has_lock,
117  bool free_all);
118 
119 /*******************************************************************/
122 static inline
123 struct default_engine*
124 default_handle(
125 /*===========*/
126  struct innodb_engine* eng)
127 {
128  return((struct default_engine*) eng->default_engine);
129 }
130 
131 /****** Gateway to the default_engine's create_instance() function */
132 ENGINE_ERROR_CODE
133 create_my_default_instance(
134 /*=======================*/
135  uint64_t,
136  GET_SERVER_API,
137  ENGINE_HANDLE **);
138 
139 /*********** FUNCTIONS IMPLEMENTING THE PUBLISHED API BEGIN HERE ********/
140 
141 /*******************************************************************/
144 ENGINE_ERROR_CODE
146 /*============*/
147  uint64_t interface,
149  GET_SERVER_API get_server_api,
152  ENGINE_HANDLE** handle )
153 {
154  ENGINE_ERROR_CODE err_ret;
155  struct innodb_engine* innodb_eng;
156 
158 
159  if (interface != 1 || api == NULL) {
160  return(ENGINE_ENOTSUP);
161  }
162 
163  innodb_eng = malloc(sizeof(struct innodb_engine));
164  memset(innodb_eng, 0, sizeof(*innodb_eng));
165 
166  if (innodb_eng == NULL) {
167  return(ENGINE_ENOMEM);
168  }
169 
170  innodb_eng->engine.interface.interface = 1;
171  innodb_eng->engine.get_info = innodb_get_info;
172  innodb_eng->engine.initialize = innodb_initialize;
173  innodb_eng->engine.destroy = innodb_destroy;
174  innodb_eng->engine.allocate = innodb_allocate;
175  innodb_eng->engine.remove = innodb_remove;
176  innodb_eng->engine.release = innodb_release;
177  innodb_eng->engine.clean_engine= innodb_clean_engine;
178  innodb_eng->engine.get = innodb_get;
179  innodb_eng->engine.get_stats = innodb_get_stats;
180  innodb_eng->engine.reset_stats = innodb_reset_stats;
181  innodb_eng->engine.store = innodb_store;
182  innodb_eng->engine.arithmetic = innodb_arithmetic;
183  innodb_eng->engine.flush = innodb_flush;
184  innodb_eng->engine.unknown_command = innodb_unknown_command;
185  innodb_eng->engine.item_set_cas = item_set_cas;
186  innodb_eng->engine.get_item_info = innodb_get_item_info;
187  innodb_eng->engine.get_stats_struct = NULL;
188  innodb_eng->engine.errinfo = NULL;
189  innodb_eng->engine.bind = innodb_bind;
190 
191  innodb_eng->server = *api;
192  innodb_eng->get_server_api = get_server_api;
193 
194  /* configuration, with default values*/
195  innodb_eng->info.info.description = "InnoDB Memcache " VERSION;
196  innodb_eng->info.info.num_features = 3;
197  innodb_eng->info.info.features[0].feature = ENGINE_FEATURE_CAS;
198  innodb_eng->info.info.features[1].feature =
200  innodb_eng->info.info.features[0].feature = ENGINE_FEATURE_LRU;
201 
202  /* Now call create_instace() for the default engine */
203  err_ret = create_my_default_instance(interface, get_server_api,
204  &(innodb_eng->default_engine));
205 
206  if (err_ret != ENGINE_SUCCESS) {
207  free(innodb_eng);
208  return(err_ret);
209  }
210 
211  innodb_eng->clean_stale_conn = false;
212  innodb_eng->initialized = true;
213 
214  *handle = (ENGINE_HANDLE*) &innodb_eng->engine;
215 
216  return(ENGINE_SUCCESS);
217 }
218 
219 /*******************************************************************/
222 static
223 void*
224 innodb_bk_thread(
225 /*=============*/
226  void* arg)
227 {
228  ENGINE_HANDLE* handle;
229  struct innodb_engine* innodb_eng;
231  void* thd = NULL;
232 
233  bk_thd_exited = false;
234 
235  handle = (ENGINE_HANDLE*) (arg);
236  innodb_eng = innodb_handle(handle);
237 
238  if (innodb_eng->enable_binlog) {
239  /* This thread will commit the transactions
240  on behalf of the other threads. It will "pretend"
241  to be each connection thread while doing it. */
242  thd = handler_create_thd(true);
243  }
244 
245  conn_data = UT_LIST_GET_FIRST(innodb_eng->conn_data);
246 
247  while(!memcached_shutdown) {
248  innodb_conn_data_t* next_conn_data;
249  uint64_t time;
250  uint64_t trx_start = 0;
251  uint64_t processed_count = 0;
252 
253  /* Do the cleanup every innodb_eng->bk_commit_interval
254  seconds. We also check if the plugin is being shutdown
255  every second */
256  for (uint i = 0; i < innodb_eng->bk_commit_interval; i++) {
257  sleep(1);
258 
259  /* If memcached is being shutdown, break */
260  if (memcached_shutdown) {
261  break;
262  }
263  }
264 
265  time = mci_get_time();
266 
267  if (UT_LIST_GET_LEN(innodb_eng->conn_data) == 0) {
268  continue;
269  }
270 
271  /* Set the clean_stale_conn to prevent force clean in
272  innodb_conn_clean. */
273  LOCK_CONN_IF_NOT_LOCKED(false, innodb_eng);
274  innodb_eng->clean_stale_conn = true;
275  UNLOCK_CONN_IF_NOT_LOCKED(false, innodb_eng);
276 
277  if (!conn_data) {
278  conn_data = UT_LIST_GET_FIRST(innodb_eng->conn_data);
279  }
280 
281  if (conn_data) {
282  next_conn_data = UT_LIST_GET_NEXT(conn_list, conn_data);
283  } else {
284  next_conn_data = NULL;
285  }
286 
287  while (conn_data) {
288  LOCK_CURRENT_CONN_IF_NOT_LOCKED(false, conn_data);
289 
290  if (conn_data->is_stale) {
291  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
292  false, conn_data);
293  LOCK_CONN_IF_NOT_LOCKED(false, innodb_eng);
294  UT_LIST_REMOVE(conn_list, innodb_eng->conn_data,
295  conn_data);
296  UNLOCK_CONN_IF_NOT_LOCKED(false, innodb_eng);
297  innodb_conn_clean_data(conn_data, false, true);
298  goto next_item;
299  }
300 
301  if (conn_data->crsr_trx) {
302  trx_start = ib_cb_trx_get_start_time(
303  conn_data->crsr_trx);
304  }
305 
306  /* Check the trx, if it is qualified for
307  reset and commit */
308  if ((conn_data->n_writes_since_commit > 0
309  || conn_data->n_reads_since_commit > 0)
310  && trx_start
311  && (time - trx_start > CONN_IDLE_TIME_TO_BK_COMMIT)
312  && !conn_data->in_use) {
313  /* binlog is running, make the thread
314  attach to conn_data->thd for binlog
315  committing */
316  if (thd) {
318  conn_data->thd, NULL);
319  }
320 
321  innodb_reset_conn(conn_data, true, true,
322  innodb_eng->enable_binlog);
323  processed_count++;
324  }
325 
326  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(false, conn_data);
327 
328 next_item:
329  conn_data = next_conn_data;
330 
331  /* Process BK_MAX_PROCESS_COMMIT (5) trx at a time */
332  if (processed_count > BK_MAX_PROCESS_COMMIT) {
333  break;
334  }
335 
336  if (conn_data) {
337  next_conn_data = UT_LIST_GET_NEXT(
338  conn_list, conn_data);
339  }
340  }
341  /* Set the clean_stale_conn back. */
342  LOCK_CONN_IF_NOT_LOCKED(false, innodb_eng);
343  innodb_eng->clean_stale_conn = false;
344  UNLOCK_CONN_IF_NOT_LOCKED(false, innodb_eng);
345  }
346 
347  bk_thd_exited = true;
348 
349  /* Change to its original state before close the MySQL THD */
350  if (thd) {
351  handler_thd_attach(thd, NULL);
352  handler_close_thd(thd);
353  }
354 
355  pthread_detach(pthread_self());
356  pthread_exit(NULL);
357 
358  return((void*) 0);
359 }
360 
361 /*******************************************************************/
364 static
365 const engine_info*
366 innodb_get_info(
367 /*============*/
368  ENGINE_HANDLE* handle)
369 {
370  return(&innodb_handle(handle)->info.info);
371 }
372 
373 /*******************************************************************/
376 static
377 ENGINE_ERROR_CODE
378 innodb_initialize(
379 /*==============*/
380  ENGINE_HANDLE* handle,
382  const char* config_str)
383 {
384  ENGINE_ERROR_CODE return_status = ENGINE_SUCCESS;
385  struct innodb_engine* innodb_eng = innodb_handle(handle);
386  struct default_engine* def_eng = default_handle(innodb_eng);
387  eng_config_info_t* my_eng_config;
388  pthread_attr_t attr;
389 
390  my_eng_config = (eng_config_info_t*) config_str;
391 
392  /* If no call back function registered (InnoDB engine failed to load),
393  load InnoDB Memcached engine should fail too */
394  if (!my_eng_config->cb_ptr) {
395  return(ENGINE_TMPFAIL);
396  }
397 
398  /* Register the call back function */
399  register_innodb_cb((void*) my_eng_config->cb_ptr);
400 
401  innodb_eng->read_batch_size = (my_eng_config->eng_read_batch_size
402  ? my_eng_config->eng_read_batch_size
404 
405  innodb_eng->write_batch_size = (my_eng_config->eng_write_batch_size
406  ? my_eng_config->eng_write_batch_size
408 
409  innodb_eng->enable_binlog = my_eng_config->eng_enable_binlog;
410 
411  innodb_eng->cfg_status = innodb_cb_get_cfg();
412 
413  /* If binlog is not enabled by InnoDB memcached plugin, let's
414  check whether innodb_direct_access_enable_binlog is turned on */
415  if (!innodb_eng->enable_binlog) {
416  innodb_eng->enable_binlog = innodb_eng->cfg_status
417  & IB_CFG_BINLOG_ENABLED;
418  }
419 
420  innodb_eng->enable_mdl = innodb_eng->cfg_status & IB_CFG_MDL_ENABLED;
421  innodb_eng->trx_level = ib_cb_cfg_trx_level();
422  innodb_eng->bk_commit_interval = ib_cb_cfg_bk_commit_interval();
423 
424  UT_LIST_INIT(innodb_eng->conn_data);
425  pthread_mutex_init(&innodb_eng->conn_mutex, NULL);
426  pthread_mutex_init(&innodb_eng->cas_mutex, NULL);
427 
428  /* Fetch InnoDB specific settings */
429  innodb_eng->meta_info = innodb_config(
430  NULL, 0, &innodb_eng->meta_hash);
431 
432  if (!innodb_eng->meta_info) {
433  return(ENGINE_TMPFAIL);
434  }
435 
436  if (innodb_eng->default_engine) {
437  return_status = def_eng->engine.initialize(
438  innodb_eng->default_engine,
439  my_eng_config->option_string);
440  }
441 
442  memcached_shutdown = false;
443  pthread_attr_init(&attr);
444  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
445  pthread_create(&innodb_eng->bk_thd_for_commit, &attr, innodb_bk_thread,
446  handle);
447 
448  return(return_status);
449 }
450 
451 extern void handler_close_thd(void*);
452 
453 /*******************************************************************/
457 static
458 void
459 innodb_conn_clean_data(
460 /*===================*/
461  innodb_conn_data_t* conn_data,
462  bool has_lock,
463  bool free_all)
464 {
465  if (!conn_data) {
466  return;
467  }
468 
469  LOCK_CURRENT_CONN_IF_NOT_LOCKED(has_lock, conn_data);
470 
471  if (conn_data->idx_crsr) {
472  innodb_cb_cursor_close(conn_data->idx_crsr);
473  conn_data->idx_crsr = NULL;
474  }
475 
476  if (conn_data->idx_read_crsr) {
478  conn_data->idx_read_crsr = NULL;
479  }
480 
481  if (conn_data->crsr) {
482  innodb_cb_cursor_close(conn_data->crsr);
483  conn_data->crsr = NULL;
484  }
485 
486  if (conn_data->read_crsr) {
487  innodb_cb_cursor_close(conn_data->read_crsr);
488  conn_data->read_crsr = NULL;
489  }
490 
491  if (conn_data->crsr_trx) {
492  innodb_cb_trx_commit(conn_data->crsr_trx);
493  conn_data->crsr_trx = NULL;
494  }
495 
496  if (conn_data->mysql_tbl) {
497  assert(conn_data->thd);
498  handler_unlock_table(conn_data->thd,
499  conn_data->mysql_tbl,
500  HDL_READ);
501  conn_data->mysql_tbl = NULL;
502  }
503 
504  if (conn_data->thd) {
505  handler_close_thd(conn_data->thd);
506  conn_data->thd = NULL;
507  }
508 
509  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(has_lock, conn_data);
510 
511  if (free_all) {
512  pthread_mutex_destroy(&conn_data->curr_conn_mutex);
513  free(conn_data);
514  }
515 }
516 
517 /*******************************************************************/
521 static
522 int
523 innodb_conn_clean(
524 /*==============*/
525  innodb_engine_t* engine,
527  bool clear_all,
528  bool has_lock)
529 {
530  innodb_conn_data_t* conn_data;
531  innodb_conn_data_t* next_conn_data;
532  int num_freed = 0;
533  void* thd = NULL;
534 
535  if (engine->enable_binlog && clear_all) {
536  thd = handler_create_thd(true);
537  }
538 
539  LOCK_CONN_IF_NOT_LOCKED(has_lock, engine);
540 
541  conn_data = UT_LIST_GET_FIRST(engine->conn_data);
542 
543  while (conn_data) {
544  void* cookie = conn_data->conn_cookie;
545 
546  next_conn_data = UT_LIST_GET_NEXT(conn_list, conn_data);
547 
548  if (!clear_all && !conn_data->in_use) {
549  innodb_conn_data_t* check_data;
550  check_data = engine->server.cookie->get_engine_specific(
551  cookie);
552 
553  /* The check data is the original conn_data stored
554  in connection "cookie", it can be set to NULL if
555  connection closed, or to a new conn_data if it is
556  closed and reopened. So verify and see if our
557  current conn_data is stale */
558  if (!check_data || check_data != conn_data) {
559  assert(conn_data->is_stale);
560  }
561  }
562 
563  /* If current conn is stale or clear_all is true,
564  clean up it.*/
565  if (conn_data->is_stale) {
566  /* If bk thread is doing the same thing, stop
567  the loop to avoid confliction.*/
568  if (engine->clean_stale_conn)
569  break;
570 
571  UT_LIST_REMOVE(conn_list, engine->conn_data,
572  conn_data);
573  innodb_conn_clean_data(conn_data, false, true);
574  num_freed++;
575  } else {
576  if (clear_all) {
577  UT_LIST_REMOVE(conn_list, engine->conn_data,
578  conn_data);
579 
580  if (thd) {
581  handler_thd_attach(conn_data->thd,
582  NULL);
583  }
584 
585  innodb_reset_conn(conn_data, false, true,
586  engine->enable_binlog);
587  if (conn_data->thd) {
589  conn_data->thd, NULL);
590  }
591  innodb_conn_clean_data(conn_data, false, true);
592 
593  engine->server.cookie->store_engine_specific(
594  cookie, NULL);
595  num_freed++;
596  }
597  }
598 
599  conn_data = next_conn_data;
600  }
601 
602  assert(!clear_all || engine->conn_data.count == 0);
603 
604  UNLOCK_CONN_IF_NOT_LOCKED(has_lock, engine);
605 
606  if (thd) {
607  handler_thd_attach(thd, NULL);
608  handler_close_thd(thd);
609  }
610 
611  return(num_freed);
612 }
613 
614 /*******************************************************************/
616 static
617 void
618 innodb_destroy(
619 /*===========*/
620  ENGINE_HANDLE* handle,
621  bool force)
622 {
623  struct innodb_engine* innodb_eng = innodb_handle(handle);
624  struct default_engine *def_eng = default_handle(innodb_eng);
625 
626  memcached_shutdown = true;
627 
628  /* Wait for the background thread to exit */
629  while (!bk_thd_exited) {
630  sleep(1);
631  }
632 
633  innodb_conn_clean(innodb_eng, true, false);
634 
635  if (innodb_eng->meta_hash) {
636  HASH_CLEANUP(innodb_eng->meta_hash, meta_cfg_info_t*);
637  }
638 
639  pthread_mutex_destroy(&innodb_eng->conn_mutex);
640  pthread_mutex_destroy(&innodb_eng->cas_mutex);
641 
642  if (innodb_eng->default_engine) {
643  def_eng->engine.destroy(innodb_eng->default_engine, force);
644  }
645 
646  free(innodb_eng);
647 }
648 
649 
650 /*** allocate ***/
651 
652 /*******************************************************************/
656 static
657 ENGINE_ERROR_CODE
658 innodb_allocate(
659 /*============*/
660  ENGINE_HANDLE* handle,
661  const void* cookie,
662  item ** item,
663  const void* key,
664  const size_t nkey,
665  const size_t nbytes,
666  const int flags,
667  const rel_time_t exptime)
668 {
669  struct innodb_engine* innodb_eng = innodb_handle(handle);
670  struct default_engine* def_eng = default_handle(innodb_eng);
671 
672  /* We use default engine's memory allocator to allocate memory
673  for item */
674  return(def_eng->engine.allocate(innodb_eng->default_engine,
675  cookie, item, key, nkey, nbytes,
676  flags, exptime));
677 }
678 
682 enum conn_mode {
683  CONN_MODE_READ,
684  CONN_MODE_WRITE,
685  CONN_MODE_NONE
686 };
687 
688 /*******************************************************************/
691 /* Initialize a connection's cursor and transactions
692 @return the connection's conn_data structure */
693 static
695 innodb_conn_init(
696 /*=============*/
697  innodb_engine_t* engine,
699  const void* cookie,
701  int conn_option,
703  ib_lck_mode_t lock_mode,
704  bool has_lock)
705 {
706  innodb_conn_data_t* conn_data;
707  meta_cfg_info_t* meta_info;
709  ib_err_t err = DB_SUCCESS;
710  ib_crsr_t crsr;
711  ib_crsr_t read_crsr;
712  ib_crsr_t idx_crsr;
713  bool trx_updated = false;
714 
715  LOCK_CONN_IF_NOT_LOCKED(has_lock, engine);
716 
717  /* Get this connection's conn_data */
718  conn_data = engine->server.cookie->get_engine_specific(cookie);
719 
720  assert(!conn_data || !conn_data->in_use);
721 
722  if (!conn_data) {
723  if (UT_LIST_GET_LEN(engine->conn_data) > 2048) {
724  /* Some of conn_data can be stale, recycle them */
725  innodb_conn_clean(engine, false, true);
726  }
727 
728  conn_data = malloc(sizeof(*conn_data));
729 
730  if (!conn_data) {
731  return(NULL);
732  }
733 
734  memset(conn_data, 0, sizeof(*conn_data));
735  conn_data->conn_cookie = (void*) cookie;
736  UT_LIST_ADD_LAST(conn_list, engine->conn_data, conn_data);
737  engine->server.cookie->store_engine_specific(
738  cookie, conn_data);
739  conn_data->conn_meta = engine->meta_info;
740  pthread_mutex_init(&conn_data->curr_conn_mutex, NULL);
741  }
742 
743  meta_info = conn_data->conn_meta;
744  meta_index = &meta_info->index_info;
745 
746  assert(engine->conn_data.count > 0);
747 
748  if (conn_option == CONN_MODE_NONE) {
749  UNLOCK_CONN_IF_NOT_LOCKED(has_lock, engine);
750  return(conn_data);
751  }
752 
753  LOCK_CURRENT_CONN_IF_NOT_LOCKED(has_lock, conn_data);
754  conn_data->in_use = true;
755 
756  UNLOCK_CONN_IF_NOT_LOCKED(has_lock, engine);
757 
758  crsr = conn_data->crsr;
759  read_crsr = conn_data->read_crsr;
760 
761  if (lock_mode == IB_LOCK_TABLE_X) {
762  assert(!conn_data->crsr_trx);
763 
764  conn_data->crsr_trx = innodb_cb_trx_begin(
765  engine->trx_level);
766 
767  err = innodb_api_begin(
768  engine,
769  meta_info->col_info[CONTAINER_DB].col_name,
770  meta_info->col_info[CONTAINER_TABLE].col_name,
771  conn_data, conn_data->crsr_trx,
772  &conn_data->crsr, &conn_data->idx_crsr,
773  lock_mode);
774 
775  if (err != DB_SUCCESS) {
777  conn_data->crsr);
778  conn_data->crsr = NULL;
780  conn_data->crsr_trx);
781  conn_data->crsr_trx = NULL;
782  conn_data->in_use = false;
783  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
784  has_lock, conn_data);
785  return(NULL);
786  }
787 
788  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(has_lock, conn_data);
789  return(conn_data);
790  }
791 
792  /* Write operation */
793  if (conn_option == CONN_MODE_WRITE) {
794  if (!crsr) {
795  if (!conn_data->crsr_trx) {
796  conn_data->crsr_trx = innodb_cb_trx_begin(
797  engine->trx_level);
798  trx_updated = true;
799  }
800 
801  err = innodb_api_begin(
802  engine,
803  meta_info->col_info[CONTAINER_DB].col_name,
804  meta_info->col_info[CONTAINER_TABLE].col_name,
805  conn_data, conn_data->crsr_trx,
806  &conn_data->crsr, &conn_data->idx_crsr,
807  lock_mode);
808 
809  if (err != DB_SUCCESS) {
811  conn_data->crsr);
812  conn_data->crsr = NULL;
814  conn_data->crsr_trx);
815  conn_data->crsr_trx = NULL;
816  conn_data->in_use = false;
817 
818  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
819  has_lock, conn_data);
820  return(NULL);
821  }
822 
823  } else if (!conn_data->crsr_trx) {
824 
825  /* There exists a cursor, just need update
826  with a new transaction */
827  conn_data->crsr_trx = innodb_cb_trx_begin(
828  engine->trx_level);
829 
830  innodb_cb_cursor_new_trx(crsr, conn_data->crsr_trx);
831  trx_updated = true;
832 
833  err = innodb_cb_cursor_lock(engine, crsr, lock_mode);
834 
835  if (err != DB_SUCCESS) {
837  conn_data->crsr);
838  conn_data->crsr = NULL;
839  conn_data->crsr_trx = NULL;
840  conn_data->in_use = false;
841  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
842  has_lock, conn_data);
843  return(NULL);
844  }
845 
846  if (meta_index->srch_use_idx == META_USE_SECONDARY) {
847 
848  idx_crsr = conn_data->idx_crsr;
850  idx_crsr, conn_data->crsr_trx);
852  engine, idx_crsr, lock_mode);
853  }
854  } else {
855  err = innodb_cb_cursor_lock(engine, crsr, lock_mode);
856 
857  if (err != DB_SUCCESS) {
859  conn_data->crsr);
860  conn_data->crsr = NULL;
861  conn_data->crsr_trx = NULL;
862  conn_data->in_use = false;
863  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
864  has_lock, conn_data);
865  return(NULL);
866  }
867  }
868 
869  if (trx_updated) {
870  if (conn_data->read_crsr) {
872  conn_data->read_crsr,
873  conn_data->crsr_trx);
874  }
875 
876  if (conn_data->idx_read_crsr) {
878  conn_data->idx_read_crsr,
879  conn_data->crsr_trx);
880  }
881  }
882  } else {
883  assert(conn_option == CONN_MODE_READ);
884 
885  if (!read_crsr) {
886  if (!conn_data->crsr_trx) {
887  conn_data->crsr_trx = innodb_cb_trx_begin(
888  engine->trx_level);
889  trx_updated = true;
890  }
891 
892  err = innodb_api_begin(
893  engine,
894  meta_info->col_info[CONTAINER_DB].col_name,
895  meta_info->col_info[CONTAINER_TABLE].col_name,
896  conn_data,
897  conn_data->crsr_trx,
898  &conn_data->read_crsr,
899  &conn_data->idx_read_crsr,
900  lock_mode);
901 
902  if (err != DB_SUCCESS) {
904  conn_data->read_crsr);
906  conn_data->crsr_trx);
907  conn_data->crsr_trx = NULL;
908  conn_data->read_crsr = NULL;
909  conn_data->in_use = false;
910  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
911  has_lock, conn_data);
912 
913  return(NULL);
914  }
915 
916  } else if (!conn_data->crsr_trx) {
917  conn_data->crsr_trx = innodb_cb_trx_begin(
918  engine->trx_level);
919 
920  trx_updated = true;
921 
923  conn_data->read_crsr,
924  conn_data->crsr_trx);
925 
926  if (conn_data->crsr) {
928  conn_data->crsr,
929  conn_data->crsr_trx);
930  }
931 
933  engine, conn_data->read_crsr, lock_mode);
934 
935  if (meta_index->srch_use_idx == META_USE_SECONDARY) {
936  ib_crsr_t idx_crsr = conn_data->idx_read_crsr;
937 
939  idx_crsr, conn_data->crsr_trx);
941  engine, idx_crsr, lock_mode);
942  }
943  }
944 
945  if (trx_updated) {
946  if (conn_data->crsr) {
948  conn_data->crsr,
949  conn_data->crsr_trx);
950  }
951 
952  if (conn_data->idx_crsr) {
954  conn_data->idx_crsr,
955  conn_data->crsr_trx);
956  }
957  }
958  }
959 
960  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED( has_lock, conn_data);
961 
962  return(conn_data);
963 }
964 
965 /*******************************************************************/
968 static
969 ENGINE_ERROR_CODE
970 innodb_remove(
971 /*==========*/
972  ENGINE_HANDLE* handle,
973  const void* cookie,
974  const void* key,
975  const size_t nkey,
976  uint64_t cas __attribute__((unused)),
978  uint16_t vbucket __attribute__((unused)))
981 {
982  struct innodb_engine* innodb_eng = innodb_handle(handle);
983  struct default_engine* def_eng = default_handle(innodb_eng);
984  ENGINE_ERROR_CODE err_ret = ENGINE_SUCCESS;
985  innodb_conn_data_t* conn_data;
986  meta_cfg_info_t* meta_info = innodb_eng->meta_info;
987  ENGINE_ERROR_CODE cacher_err = ENGINE_KEY_ENOENT;
988 
989  if (meta_info->del_option == META_CACHE_OPT_DISABLE) {
990  return(ENGINE_SUCCESS);
991  }
992 
993  if (meta_info->del_option == META_CACHE_OPT_DEFAULT
994  || meta_info->del_option == META_CACHE_OPT_MIX) {
995  hash_item* item = item_get(def_eng, key, nkey);
996 
997  if (item != NULL) {
998  item_unlink(def_eng, item);
999  item_release(def_eng, item);
1000  cacher_err = ENGINE_SUCCESS;
1001  }
1002 
1003  if (meta_info->del_option == META_CACHE_OPT_DEFAULT) {
1004  return(cacher_err);
1005  }
1006  }
1007 
1008  conn_data = innodb_conn_init(innodb_eng, cookie,
1009  CONN_MODE_WRITE, IB_LOCK_X, false);
1010 
1011  if (!conn_data) {
1012  return(ENGINE_TMPFAIL);
1013  }
1014 
1015  /* In the binary protocol there is such a thing as a CAS delete.
1016  This is the CAS check. If we will also be deleting from the database,
1017  there are two possibilities:
1018  1: The CAS matches; perform the delete.
1019  2: The CAS doesn't match; delete the item because it's stale.
1020  Therefore we skip the check altogether if(do_db_delete) */
1021 
1022  err_ret = innodb_api_delete(innodb_eng, conn_data, key, nkey);
1023 
1024  innodb_api_cursor_reset(innodb_eng, conn_data, CONN_OP_DELETE,
1025  err_ret == ENGINE_SUCCESS);
1026 
1027  return((cacher_err == ENGINE_SUCCESS) ? ENGINE_SUCCESS : err_ret);
1028 }
1029 
1030 /*******************************************************************/
1034 static
1035 ENGINE_ERROR_CODE
1036 innodb_switch_mapping(
1037 /*==================*/
1038  ENGINE_HANDLE* handle,
1039  const void* cookie,
1040  const char* name,
1043  size_t* name_len,
1046  bool has_prefix)
1048 {
1049  struct innodb_engine* innodb_eng = innodb_handle(handle);
1051  char new_name[KEY_MAX_LENGTH];
1052  meta_cfg_info_t* meta_info = innodb_eng->meta_info;
1053  char* new_map_name;
1054  unsigned int new_map_name_len = 0;
1055  char* last;
1056  meta_cfg_info_t* new_meta_info;
1057  int sep_len = 0;
1058 
1059  if (has_prefix) {
1060  char* sep = NULL;
1061 
1062  assert(*name_len > 2 && name[0] == '@' && name[1] == '@');
1063  assert(*name_len < KEY_MAX_LENGTH);
1064 
1065  memcpy(new_name, &name[2], (*name_len) - 2);
1066 
1067  new_name[*name_len - 2] = 0;
1068 
1069  GET_OPTION(meta_info, OPTION_ID_TBL_MAP_SEP, sep, sep_len);
1070 
1071  assert(sep_len > 0);
1072 
1073  new_map_name = strtok_r(new_name, sep, &last);
1074 
1075  if (new_map_name == NULL) {
1076  return(ENGINE_KEY_ENOENT);
1077  }
1078 
1079  new_map_name_len = strlen(new_map_name);
1080  } else {
1081  /* This is used in the "bind" command, and without the
1082  "@@" prefix. */
1083  if (name == NULL) {
1084  return(ENGINE_KEY_ENOENT);
1085  }
1086 
1087  new_map_name = (char*) name;
1088  new_map_name_len = *name_len;
1089  }
1090 
1091  conn_data = innodb_eng->server.cookie->get_engine_specific(cookie);
1092 
1093  /* Check if we are getting the same configure setting as existing one */
1094  if (conn_data && conn_data->conn_meta
1095  && (new_map_name_len
1097  && (strcmp(
1098  new_map_name,
1099  conn_data->conn_meta->col_info[CONTAINER_NAME].col_name) == 0)) {
1100  goto get_key_name;
1101  }
1102 
1103  new_meta_info = innodb_config(
1104  new_map_name, new_map_name_len, &innodb_eng->meta_hash);
1105 
1106  if (!new_meta_info) {
1107  return(ENGINE_KEY_ENOENT);
1108  }
1109 
1110  /* Clean up the existing connection metadata if exists */
1111  if (conn_data) {
1112  innodb_conn_clean_data(conn_data, false, false);
1113  }
1114 
1115  conn_data = innodb_conn_init(innodb_eng, cookie,
1116  CONN_MODE_NONE, 0, false);
1117 
1118  /* Point to the new metadata */
1119  conn_data->conn_meta = new_meta_info;
1120 
1121 get_key_name:
1122  /* Now calculate name length exclude the table mapping name,
1123  this is the length for the remaining key portion */
1124  if (has_prefix) {
1125  assert(*name_len >= strlen(new_map_name) + 2);
1126 
1127  if (*name_len >= strlen(new_map_name) + 2 + sep_len) {
1128  *name_len -= strlen(new_map_name) + 2 + sep_len;
1129  } else {
1130  /* the name does not even contain a delimiter,
1131  so there will be no keys either */
1132  *name_len = 0;
1133  }
1134  }
1135 
1136  return(ENGINE_SUCCESS);
1137 }
1138 
1139 /*******************************************************************/
1143 static inline
1144 ENGINE_ERROR_CODE
1145 check_key_name_for_map_switch(
1146 /*==========================*/
1147  ENGINE_HANDLE* handle,
1148  const void* cookie,
1149  const void* key,
1150  size_t* nkey)
1151 {
1152  ENGINE_ERROR_CODE err_ret = ENGINE_SUCCESS;
1153 
1154  if ((*nkey) > 3 && ((char*)key)[0] == '@'
1155  && ((char*)key)[1] == '@') {
1156  err_ret = innodb_switch_mapping(handle, cookie, key, nkey, true);
1157  }
1158 
1159  return(err_ret);
1160 }
1161 
1162 /*******************************************************************/
1166 static
1167 ENGINE_ERROR_CODE
1168 innodb_bind(
1169 /*========*/
1170  ENGINE_HANDLE* handle,
1171  const void* cookie,
1172  const void* name,
1173  size_t name_len)
1174 {
1175  ENGINE_ERROR_CODE err_ret = ENGINE_SUCCESS;
1176 
1177  err_ret = innodb_switch_mapping(handle, cookie, name, &name_len, false);
1178 
1179  return(err_ret);
1180 }
1181 
1182 /*******************************************************************/
1184 static
1185 void
1186 innodb_clean_engine(
1187 /*================*/
1188  ENGINE_HANDLE* handle,
1189  const void* cookie __attribute__((unused)),
1191  void* conn)
1192 {
1193  innodb_conn_data_t* conn_data = (innodb_conn_data_t*)conn;
1194  struct innodb_engine* engine = innodb_handle(handle);
1195  void* orignal_thd;
1196 
1197  LOCK_CURRENT_CONN_IF_NOT_LOCKED(false, conn_data);
1198  if (conn_data->thd) {
1199  handler_thd_attach(conn_data->thd, &orignal_thd);
1200  }
1201  innodb_reset_conn(conn_data, true, true, engine->enable_binlog);
1202  innodb_conn_clean_data(conn_data, true, false);
1203  conn_data->is_stale = true;
1204  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(false, conn_data);
1205 }
1206 
1207 /*******************************************************************/
1209 static
1210 void
1211 innodb_release(
1212 /*===========*/
1213  ENGINE_HANDLE* handle,
1214  const void* cookie __attribute__((unused)),
1216  item* item)
1217 {
1218  struct innodb_engine* innodb_eng = innodb_handle(handle);
1219  struct default_engine* def_eng = default_handle(innodb_eng);
1220 
1221  if (item) {
1222  item_release(def_eng, (hash_item *) item);
1223  }
1224 
1225  return;
1226 }
1227 
1228 /*******************************************************************/
1231 static
1232 ENGINE_ERROR_CODE
1233 innodb_get(
1234 /*=======*/
1235  ENGINE_HANDLE* handle,
1236  const void* cookie,
1237  item** item,
1238  const void* key,
1239  const int nkey,
1240  uint16_t vbucket __attribute__((unused)))
1243 {
1244  struct innodb_engine* innodb_eng = innodb_handle(handle);
1245  hash_item* it = NULL;
1246  ib_crsr_t crsr;
1247  ib_err_t err = DB_SUCCESS;
1248  mci_item_t result;
1249  ENGINE_ERROR_CODE err_ret = ENGINE_SUCCESS;
1250  uint64_t cas = 0;
1251  uint64_t exp = 0;
1252  uint64_t flags = 0;
1254  int total_len = 0;
1255  meta_cfg_info_t* meta_info = innodb_eng->meta_info;
1256  int option_length;
1257  const char* option_delimiter;
1258  size_t key_len = nkey;
1259  int lock_mode;
1261  + MAX_DATABASE_NAME_LEN];
1262  bool report_table_switch = false;
1263 
1264  if (meta_info->get_option == META_CACHE_OPT_DISABLE) {
1265  return(ENGINE_KEY_ENOENT);
1266  }
1267 
1268  if (meta_info->get_option == META_CACHE_OPT_DEFAULT
1269  || meta_info->get_option == META_CACHE_OPT_MIX) {
1270  *item = item_get(default_handle(innodb_eng), key, nkey);
1271 
1272  if (*item != NULL) {
1273  return(ENGINE_SUCCESS);
1274  }
1275 
1276  if (meta_info->get_option == META_CACHE_OPT_DEFAULT) {
1277  return(ENGINE_KEY_ENOENT);
1278  }
1279  }
1280 
1281  /* Check if we need to switch table mapping */
1282  err_ret = check_key_name_for_map_switch(handle, cookie, key, &key_len);
1283 
1284  /* If specified new table map does not exist, or table does not
1285  qualify for InnoDB memcached, return error */
1286  if (err_ret != ENGINE_SUCCESS) {
1287  goto err_exit;
1288  }
1289 
1290  /* If only the new mapping name is provided, and no key value,
1291  return here */
1292  if (key_len <= 0) {
1293  /* If this is a command in the form of "get @@new_table_map",
1294  for the purpose of switching to the specified table with
1295  the table map name, if the switch is successful, we will
1296  return the table name as result */
1297  if (nkey > 0) {
1298  char* name = meta_info->col_info[
1300  char* dbname = meta_info->col_info[
1302 #ifdef __WIN__
1303  sprintf(table_name, "%s\%s", dbname, name);
1304 #else
1305  snprintf(table_name, sizeof(table_name),
1306  "%s/%s", dbname, name);
1307 #endif
1308  memset(&result, 0, sizeof(result));
1309 
1311  result.col_value[MCI_COL_VALUE].value_len = strlen(table_name);
1312  report_table_switch = true;
1313 
1314  goto search_done;
1315  }
1316 
1317  err_ret = ENGINE_KEY_ENOENT;
1318  goto err_exit;
1319  }
1320 
1321  lock_mode = (innodb_eng->trx_level == IB_TRX_SERIALIZABLE
1322  && innodb_eng->read_batch_size == 1)
1323  ? IB_LOCK_S
1324  : IB_LOCK_NONE;
1325 
1326  conn_data = innodb_conn_init(innodb_eng, cookie, CONN_MODE_READ,
1327  lock_mode, false);
1328 
1329  if (!conn_data) {
1330  return(ENGINE_TMPFAIL);
1331  }
1332 
1333  err = innodb_api_search(conn_data, &crsr, key + nkey - key_len,
1334  key_len, &result, NULL, true);
1335 
1336  if (err != DB_SUCCESS) {
1337  err_ret = ENGINE_KEY_ENOENT;
1338  goto func_exit;
1339  }
1340 
1341 search_done:
1342 
1343  /* Only if expiration field is enabled, and the value is not zero,
1344  we will check whether the item is expired */
1345  if (result.col_value[MCI_COL_EXP].is_valid
1346  && result.col_value[MCI_COL_EXP].value_int) {
1347  uint64_t time;
1348  time = mci_get_time();
1349 
1350  if (time > result.col_value[MCI_COL_EXP].value_int) {
1351  /* Free allocated memory. */
1352  if (result.extra_col_value) {
1353  for (int i = 0; i < result.n_extra_col; i++) {
1354  free(result.extra_col_value[i].value_str);
1355  }
1356 
1357  free(result.extra_col_value);
1358  }
1359  if (result.col_value[MCI_COL_VALUE].allocated) {
1360  free(result.col_value[MCI_COL_VALUE].value_str);
1362  false;
1363  }
1364 
1365  err_ret = ENGINE_KEY_ENOENT;
1366  goto func_exit;
1367  }
1368  }
1369 
1370  if (result.col_value[MCI_COL_FLAG].is_valid) {
1371  flags = ntohl(result.col_value[MCI_COL_FLAG].value_int);
1372  }
1373 
1374  if (result.col_value[MCI_COL_CAS].is_valid) {
1375  cas = result.col_value[MCI_COL_CAS].value_int;
1376  }
1377 
1378  if (result.col_value[MCI_COL_EXP].is_valid) {
1379  exp = result.col_value[MCI_COL_EXP].value_int;
1380  }
1381 
1382  if (result.extra_col_value) {
1383  int i;
1384 
1385  GET_OPTION(meta_info, OPTION_ID_COL_SEP, option_delimiter,
1386  option_length);
1387 
1388  for (i = 0; i < result.n_extra_col; i++) {
1389 
1390  total_len += (result.extra_col_value[i].value_len
1391  + option_length);
1392  }
1393 
1394  /* No need to add the last separator */
1395  total_len -= option_length;
1396  } else {
1397  total_len = result.col_value[MCI_COL_VALUE].value_len;
1398  }
1399 
1400  innodb_allocate(handle, cookie, item, key, nkey, total_len, flags, exp);
1401 
1402  it = *item;
1403 
1404  if (it->iflag & ITEM_WITH_CAS) {
1405  hash_item_set_cas(it, cas);
1406  }
1407 
1408  if (result.extra_col_value) {
1409  int i;
1410  char* c_value = hash_item_get_data(it);
1411  char* value_end = c_value + total_len;
1412 
1413  assert(option_length > 0 && option_delimiter);
1414 
1415  for (i = 0; i < result.n_extra_col; i++) {
1416  mci_column_t* col_value;
1417 
1418  col_value = &result.extra_col_value[i];
1419 
1420  if (col_value->value_len != 0) {
1421  memcpy(c_value,
1422  col_value->value_str,
1423  col_value->value_len);
1424  c_value += col_value->value_len;
1425  }
1426 
1427  if (i < result.n_extra_col - 1 ) {
1428  memcpy(c_value, option_delimiter, option_length);
1429  c_value += option_length;
1430  }
1431 
1432  assert(c_value <= value_end);
1433  free(result.extra_col_value[i].value_str);
1434  }
1435 
1436  free(result.extra_col_value);
1437  } else {
1438  assert(result.col_value[MCI_COL_VALUE].value_len
1439  >= (int) it->nbytes);
1440 
1441  memcpy(hash_item_get_data(it),
1443  it->nbytes);
1444 
1445  if (result.col_value[MCI_COL_VALUE].allocated) {
1446  free(result.col_value[MCI_COL_VALUE].value_str);
1447  result.col_value[MCI_COL_VALUE].allocated = false;
1448  }
1449  }
1450 
1451 func_exit:
1452 
1453  if (!report_table_switch) {
1454  innodb_api_cursor_reset(innodb_eng, conn_data,
1455  CONN_OP_READ, true);
1456  }
1457 
1458 err_exit:
1459  return(err_ret);
1460 }
1461 
1462 /*******************************************************************/
1465 static
1466 ENGINE_ERROR_CODE
1467 innodb_get_stats(
1468 /*=============*/
1469  ENGINE_HANDLE* handle,
1470  const void* cookie,
1471  const char* stat_key,
1472  int nkey,
1473  ADD_STAT add_stat)
1474 {
1475  struct innodb_engine* innodb_eng = innodb_handle(handle);
1476  struct default_engine *def_eng = default_handle(innodb_eng);
1477  return(def_eng->engine.get_stats(innodb_eng->default_engine, cookie,
1478  stat_key, nkey, add_stat));
1479 }
1480 
1481 /*******************************************************************/
1484 static
1485 void
1486 innodb_reset_stats(
1487 /*===============*/
1488  ENGINE_HANDLE* handle,
1489  const void* cookie)
1490 {
1491  struct innodb_engine* innodb_eng = innodb_handle(handle);
1492  struct default_engine *def_eng = default_handle(innodb_eng);
1493  def_eng->engine.reset_stats(innodb_eng->default_engine, cookie);
1494 }
1495 
1496 /*******************************************************************/
1500 static
1501 ENGINE_ERROR_CODE
1502 innodb_store(
1503 /*=========*/
1504  ENGINE_HANDLE* handle,
1505  const void* cookie,
1506  item* item,
1507  uint64_t* cas,
1508  ENGINE_STORE_OPERATION op,
1509  uint16_t vbucket __attribute__((unused)))
1512 {
1513  struct innodb_engine* innodb_eng = innodb_handle(handle);
1514  uint16_t len = hash_item_get_key_len(item);
1515  char* value = hash_item_get_key(item);
1516  uint64_t exptime = hash_item_get_exp(item);
1517  uint64_t flags = hash_item_get_flag(item);
1518  ENGINE_ERROR_CODE result;
1519  uint64_t input_cas;
1521  meta_cfg_info_t* meta_info = innodb_eng->meta_info;
1522  uint32_t val_len = ((hash_item*)item)->nbytes;
1523  size_t key_len = len;
1524  ENGINE_ERROR_CODE err_ret = ENGINE_SUCCESS;
1525 
1526  if (meta_info->set_option == META_CACHE_OPT_DISABLE) {
1527  return(ENGINE_SUCCESS);
1528  }
1529 
1530  if (meta_info->set_option == META_CACHE_OPT_DEFAULT
1531  || meta_info->set_option == META_CACHE_OPT_MIX) {
1532  result = store_item(default_handle(innodb_eng), item, cas,
1533  op, cookie);
1534 
1535  if (meta_info->set_option == META_CACHE_OPT_DEFAULT) {
1536  return(result);
1537  }
1538  }
1539 
1540  err_ret = check_key_name_for_map_switch(handle, cookie,
1541  value, &key_len);
1542 
1543  if (err_ret != ENGINE_SUCCESS) {
1544  return(err_ret);
1545  }
1546 
1547  /* If no key is provided, return here */
1548  if (key_len <= 0) {
1549  return(ENGINE_NOT_STORED);
1550  }
1551 
1552  conn_data = innodb_conn_init(innodb_eng, cookie, CONN_MODE_WRITE,
1553  IB_LOCK_X, false);
1554 
1555  if (!conn_data) {
1556  return(ENGINE_NOT_STORED);
1557  }
1558 
1559  input_cas = hash_item_get_cas(item);
1560 
1561  result = innodb_api_store(innodb_eng, conn_data, value + len - key_len,
1562  key_len, val_len, exptime, cas, input_cas,
1563  flags, op);
1564 
1565  innodb_api_cursor_reset(innodb_eng, conn_data, CONN_OP_WRITE,
1566  result == ENGINE_SUCCESS);
1567  return(result);
1568 }
1569 
1570 /*******************************************************************/
1574 static
1575 ENGINE_ERROR_CODE
1576 innodb_arithmetic(
1577 /*==============*/
1578  ENGINE_HANDLE* handle,
1579  const void* cookie,
1580  const void* key,
1581  const int nkey,
1582  const bool increment,
1584  const bool create,
1586  const uint64_t delta,
1587  const uint64_t initial,
1588  const rel_time_t exptime,
1589  uint64_t* cas,
1590  uint64_t* result,
1591  uint16_t vbucket)
1593 {
1594  struct innodb_engine* innodb_eng = innodb_handle(handle);
1595  struct default_engine* def_eng = default_handle(innodb_eng);
1596  innodb_conn_data_t* conn_data;
1597  meta_cfg_info_t* meta_info = innodb_eng->meta_info;
1598  ENGINE_ERROR_CODE err_ret;
1599 
1600  if (meta_info->set_option == META_CACHE_OPT_DISABLE) {
1601  return(ENGINE_SUCCESS);
1602  }
1603 
1604  if (meta_info->set_option == META_CACHE_OPT_DEFAULT
1605  || meta_info->set_option == META_CACHE_OPT_MIX) {
1606  /* For cache-only, forward this to the
1607  default engine */
1608  err_ret = def_eng->engine.arithmetic(
1609  innodb_eng->default_engine, cookie, key, nkey,
1610  increment, create, delta, initial, exptime, cas,
1611  result, vbucket);
1612 
1613  if (meta_info->set_option == META_CACHE_OPT_DEFAULT) {
1614  return(err_ret);
1615  }
1616  }
1617 
1618  conn_data = innodb_conn_init(innodb_eng, cookie, CONN_MODE_WRITE,
1619  IB_LOCK_X, false);
1620 
1621  if (!conn_data) {
1622  return(ENGINE_NOT_STORED);
1623  }
1624 
1625  innodb_api_arithmetic(innodb_eng, conn_data, key, nkey, delta,
1626  increment, cas, exptime, create, initial,
1627  result);
1628 
1629  innodb_api_cursor_reset(innodb_eng, conn_data, CONN_OP_WRITE,
1630  true);
1631 
1632  return(ENGINE_SUCCESS);
1633 }
1634 
1635 /*******************************************************************/
1639 static
1640 bool
1641 innodb_flush_clean_conn(
1642 /*====================*/
1643  innodb_engine_t* engine,
1645  const void* cookie)
1646 {
1647  innodb_conn_data_t* conn_data = NULL;
1648  innodb_conn_data_t* curr_conn_data;
1649 
1650  curr_conn_data = engine->server.cookie->get_engine_specific(cookie);
1651  assert(curr_conn_data);
1652  assert(!engine->enable_binlog || curr_conn_data->thd);
1653 
1654  conn_data = UT_LIST_GET_FIRST(engine->conn_data);
1655 
1656  while (conn_data) {
1657  if (conn_data != curr_conn_data && (!conn_data->is_stale)) {
1658  if (curr_conn_data->thd) {
1659  handler_thd_attach(conn_data->thd, NULL);
1660  }
1661  innodb_reset_conn(conn_data, false, true,
1662  engine->enable_binlog);
1663  }
1664  conn_data = UT_LIST_GET_NEXT(conn_list, conn_data);
1665  }
1666 
1667  if (curr_conn_data->thd) {
1668  handler_thd_attach(curr_conn_data->thd, NULL);
1669  }
1670  return(true);
1671 }
1672 
1673 /*******************************************************************/
1676 static
1677 ENGINE_ERROR_CODE
1678 innodb_flush(
1679 /*=========*/
1680  ENGINE_HANDLE* handle,
1681  const void* cookie,
1682  time_t when)
1684 {
1685  struct innodb_engine* innodb_eng = innodb_handle(handle);
1686  struct default_engine* def_eng = default_handle(innodb_eng);
1687  ENGINE_ERROR_CODE err = ENGINE_SUCCESS;
1688  meta_cfg_info_t* meta_info = innodb_eng->meta_info;
1689  ib_err_t ib_err = DB_SUCCESS;
1690  innodb_conn_data_t* conn_data;
1691 
1692  if (meta_info->flush_option == META_CACHE_OPT_DISABLE) {
1693  return(ENGINE_SUCCESS);
1694  }
1695 
1696  if (meta_info->flush_option == META_CACHE_OPT_DEFAULT
1697  || meta_info->flush_option == META_CACHE_OPT_MIX) {
1698  /* default engine flush */
1699  err = def_eng->engine.flush(innodb_eng->default_engine,
1700  cookie, when);
1701 
1702  if (meta_info->flush_option == META_CACHE_OPT_DEFAULT) {
1703  return(err);
1704  }
1705  }
1706 
1707  /* Lock the whole engine, so no other connection can start
1708  new opeartion */
1709  pthread_mutex_lock(&innodb_eng->conn_mutex);
1710 
1711  conn_data = innodb_eng->server.cookie->get_engine_specific(cookie);
1712 
1713  if (conn_data) {
1714  /* Commit any work on this connection */
1715  innodb_api_cursor_reset(innodb_eng, conn_data,
1716  CONN_OP_FLUSH, true);
1717  }
1718 
1719  conn_data = innodb_conn_init(innodb_eng, cookie, CONN_MODE_WRITE,
1720  IB_LOCK_TABLE_X, true);
1721 
1722  if (!conn_data) {
1723  pthread_mutex_unlock(&innodb_eng->conn_mutex);
1724  return(ENGINE_SUCCESS);
1725  }
1726 
1727  innodb_flush_clean_conn(innodb_eng, cookie);
1728 
1729  innodb_api_cursor_reset(innodb_eng, conn_data, CONN_OP_FLUSH, true);
1730  meta_info = conn_data->conn_meta;
1731 
1732  ib_err = innodb_api_flush(innodb_eng, conn_data,
1733  meta_info->col_info[CONTAINER_DB].col_name,
1734  meta_info->col_info[CONTAINER_TABLE].col_name);
1735 
1736  pthread_mutex_unlock(&innodb_eng->conn_mutex);
1737 
1738  return((ib_err == DB_SUCCESS) ? ENGINE_SUCCESS : ENGINE_TMPFAIL);
1739 }
1740 
1741 /*******************************************************************/
1744 static
1745 ENGINE_ERROR_CODE
1746 innodb_unknown_command(
1747 /*===================*/
1748  ENGINE_HANDLE* handle,
1749  const void* cookie,
1751  ADD_RESPONSE response)
1752 {
1753  struct innodb_engine* innodb_eng = innodb_handle(handle);
1754  struct default_engine *def_eng = default_handle(innodb_eng);
1755 
1756  return(def_eng->engine.unknown_command(innodb_eng->default_engine,
1757  cookie, request, response));
1758 }
1759 
1760 /*******************************************************************/
1764 static
1765 bool
1766 innodb_get_item_info(
1767 /*=================*/
1768  ENGINE_HANDLE* handle __attribute__((unused)),
1770  const void* cookie __attribute__((unused)),
1772  const item* item,
1773  item_info* item_info)
1774 {
1775  hash_item* it;
1776 
1777  if (item_info->nvalue < 1) {
1778  return(false);
1779  }
1780 
1781  /* Use a hash item */
1782  it = (hash_item*) item;
1783  item_info->cas = hash_item_get_cas(it);
1784  item_info->exptime = it->exptime;
1785  item_info->nbytes = it->nbytes;
1786  item_info->flags = it->flags;
1787  item_info->clsid = it->slabs_clsid;
1788  item_info->nkey = it->nkey;
1789  item_info->nvalue = 1;
1790  item_info->key = hash_item_get_key(it);
1791  item_info->value[0].iov_base = hash_item_get_data(it);
1792  item_info->value[0].iov_len = it->nbytes;
1793  return(true);
1794 }