32 #include <arpa/inet.h>
33 #include "default_engine.h"
34 #include <memcached/util.h>
35 #include <memcached/config_parser.h>
41 #include "hash_item_util.h"
45 #define KEY_MAX_LENGTH 250
49 #define BK_COMMIT_THREAD_SLEEP_INTERVAL 5
53 #define BK_MAX_PROCESS_COMMIT 5
57 #define CONN_IDLE_TIME_TO_BK_COMMIT 5
60 static bool memcached_shutdown =
false;
63 static bool bk_thd_exited =
true;
113 innodb_conn_clean_data(
133 create_my_default_instance(
149 GET_SERVER_API get_server_api,
154 ENGINE_ERROR_CODE err_ret;
159 if (interface != 1 || api == NULL) {
160 return(ENGINE_ENOTSUP);
164 memset(innodb_eng, 0,
sizeof(*innodb_eng));
166 if (innodb_eng == NULL) {
167 return(ENGINE_ENOMEM);
189 innodb_eng->
engine.bind = innodb_bind;
191 innodb_eng->
server = *api;
203 err_ret = create_my_default_instance(interface, get_server_api,
206 if (err_ret != ENGINE_SUCCESS) {
216 return(ENGINE_SUCCESS);
233 bk_thd_exited =
false;
236 innodb_eng = innodb_handle(handle);
247 while(!memcached_shutdown) {
250 uint64_t trx_start = 0;
251 uint64_t processed_count = 0;
260 if (memcached_shutdown) {
275 UNLOCK_CONN_IF_NOT_LOCKED(
false, innodb_eng);
284 next_conn_data = NULL;
291 UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
296 UNLOCK_CONN_IF_NOT_LOCKED(
false, innodb_eng);
297 innodb_conn_clean_data(conn_data,
false,
true);
302 trx_start = ib_cb_trx_get_start_time(
318 conn_data->
thd, NULL);
326 UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
false, conn_data);
329 conn_data = next_conn_data;
338 conn_list, conn_data);
344 UNLOCK_CONN_IF_NOT_LOCKED(
false, innodb_eng);
347 bk_thd_exited =
true;
355 pthread_detach(pthread_self());
370 return(&innodb_handle(handle)->
info.info);
382 const char* config_str)
384 ENGINE_ERROR_CODE return_status = ENGINE_SUCCESS;
394 if (!my_eng_config->
cb_ptr) {
395 return(ENGINE_TMPFAIL);
417 & IB_CFG_BINLOG_ENABLED;
421 innodb_eng->
trx_level = ib_cb_cfg_trx_level();
425 pthread_mutex_init(&innodb_eng->
conn_mutex, NULL);
426 pthread_mutex_init(&innodb_eng->
cas_mutex, NULL);
433 return(ENGINE_TMPFAIL);
442 memcached_shutdown =
false;
443 pthread_attr_init(&attr);
444 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
448 return(return_status);
459 innodb_conn_clean_data(
481 if (conn_data->
crsr) {
483 conn_data->
crsr = NULL;
497 assert(conn_data->
thd);
504 if (conn_data->
thd) {
506 conn_data->
thd = NULL;
509 UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(has_lock, conn_data);
548 if (!clear_all && !conn_data->
in_use) {
558 if (!check_data || check_data != conn_data) {
573 innodb_conn_clean_data(conn_data,
false,
true);
587 if (conn_data->
thd) {
589 conn_data->
thd, NULL);
591 innodb_conn_clean_data(conn_data,
false,
true);
599 conn_data = next_conn_data;
602 assert(!clear_all || engine->
conn_data.count == 0);
604 UNLOCK_CONN_IF_NOT_LOCKED(has_lock, engine);
626 memcached_shutdown =
true;
629 while (!bk_thd_exited) {
633 innodb_conn_clean(innodb_eng,
true,
false);
639 pthread_mutex_destroy(&innodb_eng->
conn_mutex);
640 pthread_mutex_destroy(&innodb_eng->
cas_mutex);
667 const rel_time_t exptime)
675 cookie, item, key, nkey, nbytes,
713 bool trx_updated =
false;
720 assert(!conn_data || !conn_data->
in_use);
725 innodb_conn_clean(engine,
false,
true);
728 conn_data = malloc(
sizeof(*conn_data));
734 memset(conn_data, 0,
sizeof(*conn_data));
748 if (conn_option == CONN_MODE_NONE) {
749 UNLOCK_CONN_IF_NOT_LOCKED(has_lock, engine);
756 UNLOCK_CONN_IF_NOT_LOCKED(has_lock, engine);
758 crsr = conn_data->
crsr;
775 if (err != DB_SUCCESS) {
778 conn_data->
crsr = NULL;
782 conn_data->
in_use =
false;
783 UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
784 has_lock, conn_data);
788 UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(has_lock, conn_data);
793 if (conn_option == CONN_MODE_WRITE) {
809 if (err != DB_SUCCESS) {
812 conn_data->
crsr = NULL;
816 conn_data->
in_use =
false;
818 UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
819 has_lock, conn_data);
835 if (err != DB_SUCCESS) {
838 conn_data->
crsr = NULL;
840 conn_data->
in_use =
false;
841 UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
842 has_lock, conn_data);
852 engine, idx_crsr, lock_mode);
857 if (err != DB_SUCCESS) {
860 conn_data->
crsr = NULL;
862 conn_data->
in_use =
false;
863 UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
864 has_lock, conn_data);
883 assert(conn_option == CONN_MODE_READ);
902 if (err != DB_SUCCESS) {
909 conn_data->
in_use =
false;
910 UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
911 has_lock, conn_data);
926 if (conn_data->
crsr) {
933 engine, conn_data->
read_crsr, lock_mode);
941 engine, idx_crsr, lock_mode);
946 if (conn_data->
crsr) {
960 UNLOCK_CURRENT_CONN_IF_NOT_LOCKED( has_lock, conn_data);
976 uint64_t cas __attribute__((unused)),
978 uint16_t vbucket __attribute__((unused)))
984 ENGINE_ERROR_CODE err_ret = ENGINE_SUCCESS;
987 ENGINE_ERROR_CODE cacher_err = ENGINE_KEY_ENOENT;
990 return(ENGINE_SUCCESS);
995 hash_item* item = item_get(def_eng, key, nkey);
998 item_unlink(def_eng, item);
999 item_release(def_eng, item);
1000 cacher_err = ENGINE_SUCCESS;
1008 conn_data = innodb_conn_init(innodb_eng, cookie,
1012 return(ENGINE_TMPFAIL);
1025 err_ret == ENGINE_SUCCESS);
1027 return((cacher_err == ENGINE_SUCCESS) ? ENGINE_SUCCESS : err_ret);
1036 innodb_switch_mapping(
1054 unsigned int new_map_name_len = 0;
1062 assert(*name_len > 2 && name[0] ==
'@' && name[1] ==
'@');
1065 memcpy(new_name, &name[2], (*name_len) - 2);
1067 new_name[*name_len - 2] = 0;
1071 assert(sep_len > 0);
1073 new_map_name = strtok_r(new_name, sep, &last);
1075 if (new_map_name == NULL) {
1076 return(ENGINE_KEY_ENOENT);
1079 new_map_name_len = strlen(new_map_name);
1084 return(ENGINE_KEY_ENOENT);
1087 new_map_name = (
char*) name;
1088 new_map_name_len = *name_len;
1095 && (new_map_name_len
1104 new_map_name, new_map_name_len, &innodb_eng->
meta_hash);
1106 if (!new_meta_info) {
1107 return(ENGINE_KEY_ENOENT);
1112 innodb_conn_clean_data(conn_data,
false,
false);
1115 conn_data = innodb_conn_init(innodb_eng, cookie,
1116 CONN_MODE_NONE, 0,
false);
1125 assert(*name_len >= strlen(new_map_name) + 2);
1127 if (*name_len >= strlen(new_map_name) + 2 + sep_len) {
1128 *name_len -= strlen(new_map_name) + 2 + sep_len;
1136 return(ENGINE_SUCCESS);
1145 check_key_name_for_map_switch(
1152 ENGINE_ERROR_CODE err_ret = ENGINE_SUCCESS;
1154 if ((*nkey) > 3 && ((
char*)key)[0] ==
'@'
1155 && ((
char*)key)[1] ==
'@') {
1156 err_ret = innodb_switch_mapping(handle, cookie, key, nkey,
true);
1175 ENGINE_ERROR_CODE err_ret = ENGINE_SUCCESS;
1177 err_ret = innodb_switch_mapping(handle, cookie, name, &name_len,
false);
1186 innodb_clean_engine(
1189 const void* cookie __attribute__((unused)),
1198 if (conn_data->
thd) {
1202 innodb_conn_clean_data(conn_data,
true,
false);
1204 UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(
false, conn_data);
1214 const void* cookie __attribute__((unused)),
1222 item_release(def_eng, (
hash_item *) item);
1240 uint16_t vbucket __attribute__((unused)))
1249 ENGINE_ERROR_CODE err_ret = ENGINE_SUCCESS;
1257 const char* option_delimiter;
1258 size_t key_len = nkey;
1261 + MAX_DATABASE_NAME_LEN];
1262 bool report_table_switch =
false;
1265 return(ENGINE_KEY_ENOENT);
1270 *item = item_get(default_handle(innodb_eng), key, nkey);
1272 if (*item != NULL) {
1273 return(ENGINE_SUCCESS);
1277 return(ENGINE_KEY_ENOENT);
1282 err_ret = check_key_name_for_map_switch(handle, cookie, key, &key_len);
1286 if (err_ret != ENGINE_SUCCESS) {
1300 char* dbname = meta_info->
col_info[
1303 sprintf(table_name,
"%s\%s", dbname, name);
1305 snprintf(table_name,
sizeof(table_name),
1306 "%s/%s", dbname, name);
1308 memset(&result, 0,
sizeof(result));
1312 report_table_switch =
true;
1317 err_ret = ENGINE_KEY_ENOENT;
1326 conn_data = innodb_conn_init(innodb_eng, cookie, CONN_MODE_READ,
1330 return(ENGINE_TMPFAIL);
1334 key_len, &result, NULL,
true);
1336 if (err != DB_SUCCESS) {
1337 err_ret = ENGINE_KEY_ENOENT;
1365 err_ret = ENGINE_KEY_ENOENT;
1395 total_len -= option_length;
1400 innodb_allocate(handle, cookie, item, key, nkey, total_len, flags, exp);
1404 if (it->
iflag & ITEM_WITH_CAS) {
1405 hash_item_set_cas(it, cas);
1410 char* c_value = hash_item_get_data(it);
1411 char* value_end = c_value + total_len;
1413 assert(option_length > 0 && option_delimiter);
1428 memcpy(c_value, option_delimiter, option_length);
1429 c_value += option_length;
1432 assert(c_value <= value_end);
1441 memcpy(hash_item_get_data(it),
1453 if (!report_table_switch) {
1471 const char* stat_key,
1478 stat_key, nkey, add_stat));
1508 ENGINE_STORE_OPERATION op,
1509 uint16_t vbucket __attribute__((unused)))
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;
1522 uint32_t val_len = ((
hash_item*)item)->nbytes;
1523 size_t key_len = len;
1524 ENGINE_ERROR_CODE err_ret = ENGINE_SUCCESS;
1527 return(ENGINE_SUCCESS);
1532 result = store_item(default_handle(innodb_eng), item, cas,
1540 err_ret = check_key_name_for_map_switch(handle, cookie,
1543 if (err_ret != ENGINE_SUCCESS) {
1549 return(ENGINE_NOT_STORED);
1552 conn_data = innodb_conn_init(innodb_eng, cookie, CONN_MODE_WRITE,
1556 return(ENGINE_NOT_STORED);
1559 input_cas = hash_item_get_cas(item);
1562 key_len, val_len, exptime, cas, input_cas,
1566 result == ENGINE_SUCCESS);
1582 const bool increment,
1586 const uint64_t delta,
1587 const uint64_t initial,
1588 const rel_time_t exptime,
1598 ENGINE_ERROR_CODE err_ret;
1601 return(ENGINE_SUCCESS);
1610 increment, create, delta, initial, exptime, cas,
1618 conn_data = innodb_conn_init(innodb_eng, cookie, CONN_MODE_WRITE,
1622 return(ENGINE_NOT_STORED);
1626 increment, cas, exptime, create, initial,
1632 return(ENGINE_SUCCESS);
1641 innodb_flush_clean_conn(
1651 assert(curr_conn_data);
1657 if (conn_data != curr_conn_data && (!conn_data->
is_stale)) {
1658 if (curr_conn_data->
thd) {
1667 if (curr_conn_data->
thd) {
1687 ENGINE_ERROR_CODE err = ENGINE_SUCCESS;
1693 return(ENGINE_SUCCESS);
1719 conn_data = innodb_conn_init(innodb_eng, cookie, CONN_MODE_WRITE,
1723 pthread_mutex_unlock(&innodb_eng->
conn_mutex);
1724 return(ENGINE_SUCCESS);
1727 innodb_flush_clean_conn(innodb_eng, cookie);
1736 pthread_mutex_unlock(&innodb_eng->
conn_mutex);
1738 return((ib_err == DB_SUCCESS) ? ENGINE_SUCCESS : ENGINE_TMPFAIL);
1746 innodb_unknown_command(
1757 cookie, request, response));
1766 innodb_get_item_info(
1770 const void* cookie __attribute__((unused)),
1777 if (item_info->nvalue < 1) {
1783 item_info->cas = hash_item_get_cas(it);
1787 item_info->clsid = it->slabs_clsid;
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;