/** * Selects multiple keys at once. This method always * works asynchronously. * * @param[in] keys vector of keys to select * @return true if all keys are found */ bool mget(std::vector<std::string> &keys) { std::vector<const char *> real_keys; std::vector<size_t> key_len; /* * Construct an array which will contain the length * of each of the strings in the input vector. Also, to * interface with the memcached C API, we need to convert * the vector of std::string's to a vector of char *. */ real_keys.reserve(keys.size()); key_len.reserve(keys.size()); std::vector<std::string>::iterator it= keys.begin(); while (it != keys.end()) { real_keys.push_back(const_cast<char *>((*it).c_str())); key_len.push_back((*it).length()); ++it; } /* * If the std::vector of keys is empty then we cannot * call memcached_mget as we will get undefined behavior. */ if (! real_keys.empty()) { memcached_return rc= memcached_mget(&memc, &real_keys[0], &key_len[0], real_keys.size()); return (rc == MEMCACHED_SUCCESS); } return false; }
static int cdb_readv(knot_db_t *db, knot_db_val_t *key, knot_db_val_t *val, int maxcount) { if (!db || !key || !val) { return kr_error(EINVAL); } struct memcached_cli *cli = db; /* Convert to libmemcached query format */ assert(maxcount < 1000); /* Sane upper bound */ const char *keys [maxcount]; size_t lengths [maxcount]; for (int i = 0; i < maxcount; ++i) { keys[i] = key[i].data; lengths[i] = key[i].len; } /* Execute multiple get and retrieve results */ memcached_return_t status = memcached_mget(cli->handle, keys, lengths, maxcount); memcached_result_free(&cli->res); memcached_result_create(cli->handle, &cli->res); for (int i = 0; i < maxcount; ++i) { memcached_result_st *res = memcached_fetch_result(cli->handle, &cli->res, &status); if (!res) { /* Less results than expected */ return kr_error(ENOENT); } val[i].len = memcached_result_length(res); val[i].data = (void *)memcached_result_value(res); } return 0; }
/** * @function memcached.mget * * ### Synopsis: * * var o = memcache.get(handle, array_of_keys); * * Get multiple values, identified by an array of keys, from memcached. * * The returned object is a hash of returned values, indexed by the key. * * For each of these keys, the value is an object in the form described at the top of this page. * * @param {object} handle - handle to memcached connection. * @param {array} keys - array of keys of data to get from memcached * @return {object} o - has of objects of the form described at top of the page, or false if an error occurred. */ JSVAL _memcached_mget (JSARGS args) { HandleScope scope; M* handle = HANDLE(args[0]); Handle<Array> aKeys = Handle<Array>::Cast(args[1]); int numKeys = aKeys->Length(); char *keys[numKeys]; size_t key_lengths[numKeys]; for (int i = 0; i < numKeys; i++) { String::Utf8Value k(aKeys->Get(i)); keys[i] = *k; key_lengths[i] = strlen(keys[i]); } R rc = memcached_mget(handle, keys, key_lengths, numKeys); if (rc != MEMCACHED_SUCCESS) { return String::New(memcached_strerror(handle, rc)); } char return_key[MEMCACHED_MAX_KEY]; size_t return_key_length; char *return_value; size_t return_value_length; uint32_t flags; JSOBJ result = Object::New(); while ((return_value = memcached_fetch(handle, return_key, &return_key_length, &return_value_length, &flags, &rc))) { JSOBJ o = Object::New(); o->Set(String::New("value"), String::New(return_value)); o->Set(String::New("flags"), Integer::New(flags)); o->Set(String::New("rc"), Integer::New(rc)); free(return_value); result->Set(String::New(return_key), o); } return scope.Close(result); }
int ssMemcached::multiget(char *sKeySet[], size_t *nKeySetLen, int nKeySetNum, char *pReturnData[], char *pKeySet[], const int nValueLen) { char return_key[MEMCACHED_MAX_KEY]; size_t return_key_length; char *return_value; size_t return_value_length; uint32_t flags; int index = 0; memset(return_key, 0, sizeof(return_key)); retCode_ = memcached_mget(memc_, sKeySet, nKeySetLen, nKeySetNum); if (retCode_ == MEMCACHED_SUCCESS) { int i = 0; return_value = memcached_fetch(memc_, return_key, &return_key_length, &return_value_length, &flags, &retCode_); while (return_value != NULL) { if (retCode_ == MEMCACHED_SUCCESS) { for (i = 0; i < nKeySetNum; i++) { index = index % nKeySetNum; if (strcmp(sKeySet[index], return_key) == 0) { break; } else { index = (index + 1) % nKeySetNum; } } if (i < nKeySetNum) { if (return_value_length >= nValueLen) { strncpy(pReturnData[index], return_value, nValueLen - 1); } else { strncpy(pReturnData[index], return_value, return_value_length); } if (return_key_length >= CACHEKEYLEN) { strncpy(pKeySet[index], return_key, CACHEKEYLEN - 1); } else { strncpy(pKeySet[index], return_key, return_key_length); } memset(return_key, 0, sizeof(return_key)); index++; free(return_value); } else { return 0; } } else { return 0; } } } else { return 0; } return 1; }
/*doc Memcached getMulti(keys) Asks memcached to retrieve data corresponding to the list of keys. Returns a Map with the results. If some of the keys appearing in a retrieval request are not sent back by the server in the item list this means that the server does not hold items with such keys */ IoObject *IoMemcached_getMulti(IoMemcached *self, IoObject *locals, IoMessage *m) { IoList *keys_list = IoMessage_locals_listArgAt_(m, locals, 0); size_t keys_list_size = IoList_rawSize(keys_list); IoObject *results_map = IoMap_new(IOSTATE); if(keys_list_size == 0) return results_map; int i; for(i = 0; i < keys_list_size; i++) { IoSeq *key = IoList_rawAt_(keys_list, i); IOASSERT(ISSEQ(key), "key must be a Sequence"); IOASSERT(IOSEQ_LENGTH(key) > 0, "key cannot be an empty Sequence"); IOASSERT(IOSEQ_LENGTH(key) < MEMCACHED_MAX_KEY, "key is too long"); } const char **ckeys = (const char **) malloc(sizeof(const char *) * keys_list_size); size_t *ckey_lengths = (size_t *) malloc(sizeof(size_t) * keys_list_size); for(i = 0; i < keys_list_size; i++) { ckeys[i] = CSTRING(IoList_rawAt_(keys_list, i)); ckey_lengths[i] = strlen(ckeys[i]); } memcached_return_t rc = memcached_mget(DATA(self)->mc, ckeys, ckey_lengths, keys_list_size); free(ckeys); free(ckey_lengths); char returned_key[MEMCACHED_MAX_KEY], *returned_value; size_t returned_key_length, returned_value_length; uint32_t flags; returned_value = memcached_fetch(DATA(self)->mc, returned_key, &returned_key_length, &returned_value_length, &flags, &rc ); while(returned_value != NULL) { IoMap_rawAtPut(results_map, IoSeq_newSymbolWithData_length_(IOSTATE, returned_key, returned_key_length), IoMemcached_deserialize(self, returned_value, returned_value_length, flags) ); free(returned_value); returned_value = memcached_fetch(DATA(self)->mc, returned_key, &returned_key_length, &returned_value_length, &flags, &rc ); } return results_map; }
void test_memcached_cas(void) { memcached_return rc; const char *key = "caskey"; size_t key_len = strlen(key); const char* keys[2] = { (char *)key, NULL }; size_t key_lens[2] = { key_len, 0 }; memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); grn_test_memcached_assert( memcached_set(memc, key, key_len, "cas test", 8, 0, 0xdeadbeefU), cut_message("memcached set failed.")); { uint64_t cas; memcached_result_st *results; memcached_result_st results_obj; results = memcached_result_create(memc, &results_obj); grn_test_memcached_assert( memcached_mget(memc, keys, key_lens, 1), cut_message("memcached mget failed.")); results = memcached_fetch_result(memc, &results_obj, &rc); cut_assert_not_null(results, cut_message("memcached fetch result failed.")); cas = memcached_result_cas(results); cut_assert_operator(cas, !=, 0, cut_message("memcached cas value is non-zero.")); grn_test_memcached_assert( memcached_cas(memc, key, key_len, "cas changed", 12, 0, 0, cas), cut_message("memcached cas failed.")); grn_test_memcached_assert_equal_rc( MEMCACHED_NOTSTORED, memcached_cas(memc, key, key_len, "cas changed", 12, 0, 0, cas), cut_message("memcached cas value is same.")); memcached_result_free(&results_obj); } }
static bool kv_mget(kv_data* c, libkv_mget_data* mx, char** keys, size_t* keylens, size_t num) { kv_mget_data* m = malloc(sizeof(kv_mget_data)); if(m == NULL) { return NULL; } if(memcached_mget(c->st, keys, keylens, num) != MEMCACHED_SUCCESS) { free(m); return false; } m->c = c; m->lastbuf = NULL; mx->kv_mget_next = (void*)&kv_mget_next; mx->kv_mget_free = (void*)&kv_mget_free; mx->data = (void*)m; return true; }
void test_memcached_cas(void) { memcached_return rc; const char *key = "caskey"; size_t key_len = strlen(key); char* keys[2] = { (char *)key, NULL }; size_t key_lens[2] = { key_len, 0 }; memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); rc = memcached_set(memc, key, key_len, "cas test", 8, 0, 0xdeadbeefU); cut_set_message("memcached set failed."); cut_assert_equal_int(MEMCACHED_SUCCESS, rc); { uint64_t cas; memcached_result_st *results; memcached_result_st results_obj; results = memcached_result_create(memc, &results_obj); rc = memcached_mget(memc, keys, key_lens, 1); cut_set_message("memcached mget failed."); cut_assert_equal_int(MEMCACHED_SUCCESS, rc); results = memcached_fetch_result(memc, &results_obj, &rc); cas = memcached_result_cas(results); cut_set_message("memcached cas value is non-zero."); cut_assert_operator_int(cas, !=, 0); rc = memcached_cas(memc, key, key_len, "cas changed", 12, 0, 0, cas); cut_set_message("memcached cas failed."); cut_assert_equal_int(MEMCACHED_SUCCESS, rc); rc = memcached_cas(memc, key, key_len, "cas changed", 12, 0, 0, cas); cut_set_message("memcached cas value is same."); /* TODO: fix rc after libmemcached fix */ cut_assert_equal_int(MEMCACHED_PROTOCOL_ERROR, rc); /* cut_assert_equal_int(MEMCACHED_DATA_EXISTS, rc); */ memcached_result_free(&results_obj); } }
/// Retrieve the AoR data for a given SIP URI, creating it if there isn't /// any already, and returning NULL if we can't get a connection. AoR* MemcachedStore::get_aor_data(const std::string& aor_id) ///< the SIP URI { memcached_return_t rc; MemcachedAoR* aor_data = NULL; // Try to get a connection struct timespec wait_time; wait_time.tv_sec = 0; wait_time.tv_nsec = 100 * 1000 * 1000; memcached_st* st = memcached_pool_fetch(_pool, &wait_time, &rc); if (st != NULL) { // Got one: use it. const char* key_ptr = aor_id.data(); const size_t key_len = aor_id.length(); rc = memcached_mget(st, &key_ptr, &key_len, 1); if (memcached_success(rc)) { memcached_result_st result; memcached_result_create(st, &result); memcached_fetch_result(st, &result, &rc); if (memcached_success(rc)) { aor_data = deserialize_aor(std::string(memcached_result_value(&result), memcached_result_length(&result))); aor_data->set_cas(memcached_result_cas(&result)); int now = time(NULL); expire_bindings(aor_data, now); } else { // AoR does not exist, so create it. aor_data = new MemcachedAoR(); } } memcached_pool_release(_pool, st); } return (AoR*)aor_data; }
int sstack_memcache_read_multiple(memcached_st * memc, const char **keys, size_t *keylen, int num_keys, log_ctx_t *ctx) { memcached_return_t rc = MEMCACHED_FAILURE; if (NULL == memc || NULL == *keys || num_keys <= 0) { sfs_log(ctx, SFS_ERR, "%s: Invalid parameters specified \n", __FUNCTION__); return -1; } rc = memcached_mget(memc, keys, keylen, num_keys); if (rc == MEMCACHED_SUCCESS) return 0; else return -rc; }
virtual void read(payload_t *keys, int count, payload_t *values = NULL) { char *_value; size_t _value_length; uint32_t _flags; memcached_return_t _error; // Convert keys to arrays suitable for memcached char* __keys[count]; size_t __sizes[count]; for(int i = 0; i < count; i++) { __keys[i] = keys[i].first; __sizes[i] = keys[i].second; } // Do the multiget _error = memcached_mget(&memcached, __keys, __sizes, count); if(_error != MEMCACHED_SUCCESS) { fprintf(stderr, "Error performing multiread operation (%d)\n", _error); exit(-1); } // Fetch the results int i = 0; do { _value = memcached_fetch(&memcached, __keys[i], &__sizes[i], &_value_length, &_flags, &_error); if(_error != MEMCACHED_SUCCESS && _error != MEMCACHED_END) { fprintf(stderr, "Error performing read operation (%d)\n", _error); exit(-1); } if (values != NULL) { if (_value_length != values[i].second || memcmp(_value, values[i].first, _value_length) != 0) { fprintf(stderr, "Incorrect value in database\n"); exit(-1); } } free(_value); i++; } while(_value != NULL); }
memcached_return_t BaseMemcachedStore::get_from_replica(memcached_st* replica, const char* key_ptr, const size_t key_len, std::string& data, uint64_t& cas) { memcached_return_t rc = MEMCACHED_ERROR; cas = 0; // We must use memcached_mget because memcached_get does not retrieve CAS // values. rc = memcached_mget(replica, &key_ptr, &key_len, 1); if (memcached_success(rc)) { // memcached_mget command was successful, so retrieve the result. TRC_DEBUG("Fetch result"); memcached_result_st result; memcached_result_create(replica, &result); memcached_fetch_result(replica, &result, &rc); if (memcached_success(rc)) { // Found a record, so exit the read loop. TRC_DEBUG("Found record on replica"); // Copy the record into a string. std::string::assign copies its // arguments when used with a char*, so we can free the result // afterwards. data.assign(memcached_result_value(&result), memcached_result_length(&result)); cas = memcached_result_cas(&result); } memcached_result_free(&result); } return rc; }
static Variant HHVM_METHOD(Memcache, get, const Variant& key, VRefParam flags /*= null*/) { auto data = Native::data<MemcacheData>(this_); if (key.is(KindOfArray)) { std::vector<const char *> real_keys; std::vector<size_t> key_len; Array keyArr = key.toArray(); real_keys.reserve(keyArr.size()); key_len.reserve(keyArr.size()); for (ArrayIter iter(keyArr); iter; ++iter) { auto key = iter.second().toString(); String serializedKey = memcache_prepare_key(key); char *k = new char[serializedKey.length()+1]; std::strcpy(k, serializedKey.c_str()); real_keys.push_back(k); key_len.push_back(serializedKey.length()); } if (!real_keys.empty()) { const char *payload = NULL; size_t payload_len = 0; uint32_t flags = 0; const char *res_key = NULL; size_t res_key_len = 0; memcached_result_st result; memcached_return_t ret = memcached_mget(&data->m_memcache, &real_keys[0], &key_len[0], real_keys.size()); memcached_result_create(&data->m_memcache, &result); Array return_val; while ((memcached_fetch_result(&data->m_memcache, &result, &ret)) != nullptr) { if (ret != MEMCACHED_SUCCESS) { // should probably notify about errors continue; } payload = memcached_result_value(&result); payload_len = memcached_result_length(&result); flags = memcached_result_flags(&result); res_key = memcached_result_key_value(&result); res_key_len = memcached_result_key_length(&result); return_val.set(String(res_key, res_key_len, CopyString), memcache_fetch_from_storage(payload, payload_len, flags)); } memcached_result_free(&result); for ( size_t i = 0 ; i < real_keys.size() ; i++ ) { delete [] real_keys[i]; } return return_val; } } else { char *payload = NULL; size_t payload_len = 0; uint32_t flags = 0; memcached_return_t ret; String serializedKey = memcache_prepare_key(key.toString()); if (serializedKey.length() == 0) { return false; } payload = memcached_get(&data->m_memcache, serializedKey.c_str(), serializedKey.length(), &payload_len, &flags, &ret); /* This is for historical reasons from libmemcached*/ if (ret == MEMCACHED_END) { ret = MEMCACHED_NOTFOUND; } if (ret == MEMCACHED_NOTFOUND) { return false; } Variant retval = memcache_fetch_from_storage(payload, payload_len, flags); free(payload); return retval; } return false; }
static VALUE mc_get(int argc, VALUE *argv, VALUE self) { memcached_st *mc; VALUE cas, keys, results, key, result; VALUE scalar_key = Qnil; memcached_return status; Data_Get_Struct(self, memcached_st, mc); rb_scan_args(argc, argv, "11", &keys, &cas); memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, RTEST(cas) ? 1 : 0); if (RTEST(cas) && TYPE(keys) != T_ARRAY) { scalar_key = keys; keys = rb_ary_new4(1, &keys); } if (TYPE(keys) != T_ARRAY) { char* str; size_t len; uint32_t flags; key = use_binary(mc) ? keys : escape_key(keys, NULL); str = memcached_get(mc, RSTRING_PTR(key), RSTRING_LEN(key), &len, &flags, &status); if (str == NULL) return Qnil; if (status == MEMCACHED_SUCCESS) { result = rb_hash_new(); rb_hash_aset(result, sym_value, rb_str_new(str, len)); rb_hash_aset(result, sym_flags, INT2NUM(flags)); free(str); return result; } else { printf("Memcache read error: %s %u\n", memcached_strerror(mc, status), status); return Qnil; } } else { memcached_result_st* mc_result; size_t num_keys, i; const char** key_strings; size_t* key_lengths; bool escaped; results = rb_hash_new(); num_keys = RARRAY_LEN(keys); if (num_keys == 0) return results; key_strings = (const char**) malloc(num_keys * sizeof(char *)); key_lengths = (size_t *) malloc(num_keys * sizeof(size_t)); for (i = 0; i < RARRAY_LEN(keys); i++) { key = RARRAY_PTR(keys)[i]; if (!use_binary(mc)) key = escape_key(key, &escaped); key_lengths[i] = RSTRING_LEN(key); key_strings[i] = RSTRING_PTR(key); } memcached_mget(mc, key_strings, key_lengths, num_keys); while ((mc_result = memcached_fetch_result(mc, NULL, &status))) { if (escaped) { key = unescape_key(memcached_result_key_value(mc_result), memcached_result_key_length(mc_result)); } else { key = rb_str_new(memcached_result_key_value(mc_result), memcached_result_key_length(mc_result)); } if (status == MEMCACHED_SUCCESS) { result = rb_hash_new(); rb_hash_aset(result, sym_value, rb_str_new(memcached_result_value(mc_result), memcached_result_length(mc_result))); rb_hash_aset(result, sym_flags, INT2NUM(memcached_result_flags(mc_result))); if (RTEST(cas)) rb_hash_aset(result, sym_cas, ULL2NUM(memcached_result_cas(mc_result))); memcached_result_free(mc_result); rb_hash_aset(results, key, result); } else { printf("Memcache read error: %s %u\n", memcached_strerror(mc, status), status); } } free(key_strings); free(key_lengths); if (!NIL_P(scalar_key)) return rb_hash_aref(results, scalar_key); return results; } }
int main(int argc, char *argv[]) { if (argc < 3) { std::cerr << "Usage: qurluniqmgr set|get servers" << std::endl; exit(1); } std::string cmd = argv[1]; std::string server = argv[2]; memcached_st *queue; queue = memcached_create(NULL); memcached_server_st *servers; servers= memcached_servers_parse(server.c_str()); if (servers != NULL) { memcached_server_push(queue, servers); memcached_server_list_free(servers); } else { std::cerr << "Error server config error" << std::endl; std::cerr << "Usage: qurluniqmgr set|get servers" << std::endl; exit(1); } if (cmd == "set") { std::string line; int count = 0; while (std::getline(std::cin, line)) { ++count; if (count % 100000 == 0) { std::cerr << "get total " << count << std::endl; } if (line.size() == 0) { continue; } memcached_return_t rc = memcached_set(queue, line.c_str(), line.size(), "1", 1, 0, 0); if (rc != MEMCACHED_SUCCESS) { std::cerr << "set " << line << " error " << std::endl; } } } else if (cmd == "set0") { std::string line; int count = 0; while (std::getline(std::cin, line)) { ++count; if (count % 100000 == 0) { std::cerr << "get total " << count << std::endl; } if (line.size() == 0) { continue; } memcached_return_t rc = memcached_set(queue, line.c_str(), line.size(), "0", 1, 0, 0); if (rc != MEMCACHED_SUCCESS) { std::cerr << "set " << line << " error " << std::endl; } } } else if (cmd == "get") { const char* keys[BATCH_SIZE]; size_t key_lens[BATCH_SIZE]; char ret_key[256]; size_t ret_key_len; size_t ret_val_len; uint32_t flags; char * ret_val = NULL; memcached_return rc; std::vector<std::string> batch_vec; std::string line; int count = 0; while (std::getline(std::cin, line)) { ++count; if (count % 100000 == 0) { std::cerr << "get total " << count << std::endl; } if (line.size() == 0) { continue; } batch_vec.push_back(line); if (batch_vec.size() == BATCH_SIZE) { for (size_t i = 0; i < batch_vec.size(); i++) { keys[i] = batch_vec[i].c_str(); key_lens[i] = batch_vec[i].size(); } rc = memcached_mget(queue, keys, key_lens, batch_vec.size()); if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_DATA_EXISTS || rc == MEMCACHED_STORED) { while ((ret_val = memcached_fetch(queue, ret_key, &ret_key_len, &ret_val_len, &flags, &rc))) { free(ret_val); } } else { std::cerr << "ERROR when store " << std::endl; } batch_vec.clear(); } } if (batch_vec.size() > 0) { for (size_t i = 0; i < batch_vec.size(); i++) { keys[i] = batch_vec[i].c_str(); key_lens[i] = batch_vec[i].size(); } rc = memcached_mget(queue, keys, key_lens, batch_vec.size()); if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_DATA_EXISTS || rc == MEMCACHED_STORED) { while ((ret_val = memcached_fetch(queue, ret_key, &ret_key_len, &ret_val_len, &flags, &rc))) { free(ret_val); } } else { std::cerr << "ERROR when store " << std::endl; } batch_vec.clear(); } } else { std::cerr << "No cmd " << cmd << " supported"<< std::endl; std::cerr << "Usage: qurluniqmgr set|get servers" << std::endl; exit(1); } return 0; }
Variant c_Memcache::t_get(CVarRef key, VRefParam flags /*= null*/) { if (key.is(KindOfArray)) { std::vector<const char *> real_keys; std::vector<size_t> key_len; Array keyArr = key.toArray(); real_keys.reserve(keyArr.size()); key_len.reserve(keyArr.size()); for (ArrayIter iter(keyArr); iter; ++iter) { real_keys.push_back(const_cast<char *>(iter.second().toString().c_str())); key_len.push_back(iter.second().toString().length()); } if (!real_keys.empty()) { const char *payload = NULL; size_t payload_len = 0; uint32_t flags = 0; const char *res_key = NULL; size_t res_key_len = 0; memcached_result_st result; memcached_return_t ret = memcached_mget(&m_memcache, &real_keys[0], &key_len[0], real_keys.size()); memcached_result_create(&m_memcache, &result); Array return_val; while ((memcached_fetch_result(&m_memcache, &result, &ret)) != NULL) { if (ret != MEMCACHED_SUCCESS) { // should probably notify about errors continue; } payload = memcached_result_value(&result); payload_len = memcached_result_length(&result); flags = memcached_result_flags(&result); res_key = memcached_result_key_value(&result); res_key_len = memcached_result_key_length(&result); return_val.set(String(res_key, res_key_len, CopyString), memcache_fetch_from_storage(payload, payload_len, flags)); } memcached_result_free(&result); return return_val; } } else { char *payload = NULL; size_t payload_len = 0; uint32_t flags = 0; memcached_return_t ret; String skey = key.toString(); if (skey.length() == 0) { return false; } payload = memcached_get(&m_memcache, skey.c_str(), skey.length(), &payload_len, &flags, &ret); /* This is for historical reasons from libmemcached*/ if (ret == MEMCACHED_END) { ret = MEMCACHED_NOTFOUND; } if (ret == MEMCACHED_NOTFOUND) { return false; } Variant retval = memcache_fetch_from_storage(payload, payload_len, flags); free(payload); return retval; } return false; }
/// Retrieve the data for a given namespace and key. Store::Status MemcachedStore::get_data(const std::string& table, const std::string& key, std::string& data, uint64_t& cas, SAS::TrailId trail) { Store::Status status = Store::Status::OK; // Construct the fully qualified key. std::string fqkey = table + "\\\\" + key; const char* key_ptr = fqkey.data(); const size_t key_len = fqkey.length(); const std::vector<memcached_st*>& replicas = get_replicas(fqkey, Op::READ); if (trail != 0) { SAS::Event start(trail, SASEvent::MEMCACHED_GET_START, 0); start.add_var_param(fqkey); SAS::report_event(start); } LOG_DEBUG("%d read replicas for key %s", replicas.size(), fqkey.c_str()); // Read from all replicas until we get a positive result. memcached_return_t rc = MEMCACHED_ERROR; bool active_not_found = false; size_t failed_replicas = 0; size_t ii; // If we only have one replica, we should try it twice - // libmemcached won't notice a dropped TCP connection until it tries // to make a request on it, and will fail the request then // reconnect, so the second attempt could still work. size_t attempts = (replicas.size() == 1) ? 2 : replicas.size(); for (ii = 0; ii < attempts; ++ii) { size_t replica_idx; if ((replicas.size() == 1) && (ii == 1)) { if (rc != MEMCACHED_CONNECTION_FAILURE) { // This is a legitimate error, not a server failure, so we // shouldn't retry. break; } replica_idx = 0; LOG_WARNING("Failed to read from sole memcached replica: retrying once"); } else { replica_idx = ii; } // We must use memcached_mget because memcached_get does not retrieve CAS // values. LOG_DEBUG("Attempt to read from replica %d (connection %p)", replica_idx, replicas[replica_idx]); rc = memcached_mget(replicas[replica_idx], &key_ptr, &key_len, 1); if (memcached_success(rc)) { // memcached_mget command was successful, so retrieve the result. LOG_DEBUG("Fetch result"); memcached_result_st result; memcached_result_create(replicas[replica_idx], &result); memcached_fetch_result(replicas[replica_idx], &result, &rc); if (memcached_success(rc)) { // Found a record, so exit the read loop. LOG_DEBUG("Found record on replica %d", replica_idx); data.assign(memcached_result_value(&result), memcached_result_length(&result)); cas = (active_not_found) ? 0 : memcached_result_cas(&result); // std::string::assign copies its arguments when used with a // char*, so this is safe. memcached_result_free(&result); break; } else { // Free the result and continue the read loop. memcached_result_free(&result); } } if (rc == MEMCACHED_NOTFOUND) { // Failed to find a record on an active replica. Flag this so if we do // find data on a later replica we can reset the cas value returned to // zero to ensure a subsequent write will succeed. LOG_DEBUG("Read for %s on replica %d returned NOTFOUND", fqkey.c_str(), replica_idx); active_not_found = true; } else { // Error from this node, so consider it inactive. LOG_DEBUG("Read for %s on replica %d returned error %d (%s)", fqkey.c_str(), replica_idx, rc, memcached_strerror(replicas[replica_idx], rc)); ++failed_replicas; } } if (memcached_success(rc)) { if (trail != 0) { SAS::Event got_data(trail, SASEvent::MEMCACHED_GET_SUCCESS, 0); got_data.add_var_param(fqkey); got_data.add_var_param(data); got_data.add_static_param(cas); SAS::report_event(got_data); } // Return the data and CAS value. The CAS value is either set to the CAS // value from the result, or zero if an earlier active replica returned // NOT_FOUND. This ensures that a subsequent set operation will succeed // on the earlier active replica. LOG_DEBUG("Read %d bytes from table %s key %s, CAS = %ld", data.length(), table.c_str(), key.c_str(), cas); } else if (failed_replicas < replicas.size()) { // At least one replica returned NOT_FOUND. if (trail != 0) { SAS::Event not_found(trail, SASEvent::MEMCACHED_GET_NOT_FOUND, 0); not_found.add_var_param(fqkey); SAS::report_event(not_found); } LOG_DEBUG("At least one replica returned not found, so return NOT_FOUND"); status = Store::Status::NOT_FOUND; } else { // All replicas returned an error, so log the error and return the // failure. if (trail != 0) { SAS::Event err(trail, SASEvent::MEMCACHED_GET_ERROR, 0); err.add_var_param(fqkey); SAS::report_event(err); } LOG_ERROR("Failed to read data for %s from %d replicas", fqkey.c_str(), replicas.size()); status = Store::Status::ERROR; } return status; }