//修改item的时间 base_item* LRU_list::do_item_touch(const char* key, const size_t nkey, const uint32_t exptime, const uint32_t hv) { base_item *it = do_item_get(key, nkey, hv); if (it != NULL) { it->exptime = exptime; } return it; }
enum store_item_type do_store_item(item *it, const uint32_t hv) { enum store_item_type stored; char *key = ITEM_key(it); item *old_it = do_item_get(key, it->nkey, hv); if (old_it != NULL) { assert(old_it != it); before_write(old_it); do_item_unlink_nolock(old_it, hv); //do_item_remove(old_it); /* release our reference */ item_free(old_it); assert((old_it->it_flags & ITEM_LINKED) == 0); assert((old_it->it_flags & ITEM_SLABBED) != 0); after_write(old_it); } before_write(it); int ret = do_item_link_nolock(it, hv); after_write(it); if (ret == 0) { stored = NOT_STORED; printf("not stored\n"); } else { stored = STORED; } return stored; }
/* * Returns an item if it hasn't been marked as expired, * lazy-expiring as needed. */ item *item_get(const char *key, const size_t nkey) { item *it; pthread_mutex_lock(&cache_lock); it = do_item_get(key, nkey); pthread_mutex_unlock(&cache_lock); return it; }
item *do_item_touch(const char *key, size_t nkey, uint32_t exptime, const uint32_t hv) { item *it = do_item_get(key, nkey, hv); if (it != NULL) { it->exptime = exptime; } return it; }
/* * Returns an item if it hasn't been marked as expired, * lazy-expiring as needed. */ hash_item *item_get(struct default_engine *engine, const void *key, const size_t nkey) { hash_item *it; pthread_mutex_lock(&engine->cache_lock); it = do_item_get(engine, key, nkey); pthread_mutex_unlock(&engine->cache_lock); return it; }
item *do_item_touch(const char *key, size_t nkey, uint32_t exptime, const uint32_t hv) { syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__); item *it = do_item_get(key, nkey, hv); if (it != NULL) { it->exptime = exptime; } return it; }
/* * Returns an item if it hasn't been marked as expired, * lazy-expiring as needed. */ item *item_get(const char *key, const size_t nkey, conn *c, const bool do_update) { item *it; uint32_t hv; hv = hash(key, nkey); item_lock(hv); it = do_item_get(key, nkey, hv, c, do_update); item_unlock(hv); return it; }
/* * Returns an item if it hasn't been marked as expired, * lazy-expiring as needed. */ item *item_get(const char *key, const size_t nkey) { item *it; uint32_t hv; hv = hash(key, nkey); item_lock(hv); it = do_item_get(key, nkey, hv); item_unlock(hv); return it; }
base_item* LRU_list::item_get(const char* key, const size_t nkey) { base_item *it; uint32_t hv; hv = HashTable::hash(key, nkey); hashtable.hash_lock(hv); it = do_item_get(key, nkey, hv); hashtable.hash_unlock(hv); return it; }
static hash_item *do_touch_item(struct default_engine *engine, const hash_key *hkey, uint32_t exptime) { hash_item *item = do_item_get(engine, hkey); if (item != NULL) { item->exptime = exptime; } return item; }
/* * Returns an item if it hasn't been marked as expired, * lazy-expiring as needed. */ hash_item *item_get(struct default_engine *engine, const void *cookie, const void *key, const size_t nkey) { hash_item *it; hash_key hkey; if (!hash_key_create(&hkey, key, nkey, engine, cookie)) { return NULL; } cb_mutex_enter(&engine->items.lock); it = do_item_get(engine, &hkey); cb_mutex_exit(&engine->items.lock); hash_key_destroy(&hkey); return it; }
static ENGINE_ERROR_CODE do_arithmetic(struct default_engine *engine, const void* cookie, const hash_key* key, const bool increment, const bool create, const uint64_t delta, const uint64_t initial, const rel_time_t exptime, item **result_item, uint8_t datatype, uint64_t *result) { hash_item *item = do_item_get(engine, key); ENGINE_ERROR_CODE ret; if (item == NULL) { if (!create) { return ENGINE_KEY_ENOENT; } else { char buffer[128]; int len = snprintf(buffer, sizeof(buffer), "%"PRIu64, (uint64_t)initial); if (len < 0 || len >= sizeof(buffer)) { return ENGINE_ENOMEM; } item = do_item_alloc(engine, key, 0, exptime, len, cookie, datatype); if (item == NULL) { return ENGINE_ENOMEM; } memcpy((void*)item_get_data(item), buffer, len); if ((ret = do_store_item(engine, item, OPERATION_ADD, cookie, (hash_item**)result_item)) == ENGINE_SUCCESS) { *result = initial; } else { do_item_release(engine, item); } } } else { ret = do_add_delta(engine, item, increment, delta, result_item, result, cookie); } return ret; }
static ENGINE_ERROR_CODE do_item_delete(struct demo_engine *engine, const void* key, const size_t nkey, uint64_t cas) { ENGINE_ERROR_CODE ret; hash_item *it = do_item_get(engine, key, nkey, true); if (it == NULL) { ret = ENGINE_KEY_ENOENT; } else { if (cas == 0 || cas == dm_item_get_cas(it)) { do_item_unlink(engine, it, ITEM_UNLINK_NORMAL); ret = ENGINE_SUCCESS; } else { ret = ENGINE_KEY_EEXISTS; } do_item_release(engine, it); } return ret; }
enum store_item_type do_store_item ( item *it, int comm, const uint32_t hv ) { char *key = ITEM_key (it); item *old_it = do_item_get (key, it->nkey, hv); enum store_item_type stored = NOT_STORED; item *new_it = NULL; int flags; if ( old_it != NULL && comm == NREAD_ADD ) { do_item_update (old_it); } else if ( ! old_it && ( comm == NREAD_REPLACE || comm == NREAD_APPEND || comm == NREAD_PREPEND ) ) { } else { if ( comm == NREAD_APPEND || comm == NREAD_PREPEND ) { if ( stored == NOT_STORED ) { flags = ( int ) strtol (ITEM_suffix (old_it), ( char ** ) NULL, 10); new_it = do_item_alloc (key, it->nkey, flags, old_it->exptime, ITEM_data (it), it->nbytes + old_it->nbytes - 2, hv); if ( ! new_it ) { if ( old_it ) do_item_remove (old_it); return NOT_STORED; } if ( comm == NREAD_APPEND ) { memcpy (ITEM_data (new_it), ITEM_data (old_it), old_it->nbytes); memcpy (ITEM_data (new_it) + old_it->nbytes - 2, ITEM_data (it), it->nbytes); } else { memcpy (ITEM_data (new_it), ITEM_data (it), it->nbytes); memcpy (ITEM_data (new_it) + it->nbytes - 2, ITEM_data (old_it), old_it->nbytes); } it = new_it; } } if ( stored == NOT_STORED ) { if ( old_it != NULL ) { item_replace (old_it, it, hv); } else { do_item_link (it, hv); } stored = STORED; } } if ( old_it != NULL ) { do_item_remove (old_it); } if ( new_it != NULL ) { do_item_remove (new_it); } return stored; }
int LRU_list::do_store_item(base_item* it, Conn* c, uint32_t hv) { char* key = it->data; //获取旧的数据项 base_item* old_it = do_item_get(key, it->nkey, hv); int store_stat = LRU_list::NOT_STORED; base_item* new_it = 0; int flags = 0; //已经有该项item存在 if (old_it != 0 && c->cmd == NREAD_ADD) { /* * 更新当前item目的 * 1.更新时间,重建LRU链 * 2.后面执行do_item_remove,每次remove会把refcount引用计数减一 * 如果引用计数=1则被删除,重建之后refcount为2 * */ do_item_update(old_it); //旧的item不存在 }else if (!old_it && (c->cmd == NREAD_REPLACE || c->cmd == NREAD_APPEND || c->cmd == NREAD_PREPEND)) { //什么也不做,因为只有replace替换已有值 }else if (c->cmd == NREAD_CAS) { //不存在此项 if (old_it == 0) { store_stat = LRU_list::NOT_FOUND; } if (it->cas == old_it->cas) { item_replace(old_it, it, hv); store_stat = LRU_list::STORED; } else { if (mem_setting.verbose > 1) { std::cerr << "CAS: failure: expected " << old_it->get_cas() << " but got " << it->cas; } store_stat = LRU_list::EXISTS; } } else { //与上面第二个判断不同,这里是旧的item存在的replace append prepend set命令 if (c->cmd == NREAD_APPEND || c->cmd == NREAD_PREPEND) { //if (it->cas != 0) { if (it->cas != old_it->cas) { store_stat = LRU_list::EXISTS; } //} if (store_stat == LRU_list::NOT_STORED) { new_it = do_item_alloc(key, it->nkey, flags, old_it->exptime, it->nbytes + old_it->nbytes - 2, hv); //分配失败 if (new_it == 0) { if (old_it != 0) do_item_remove(old_it); return LRU_list::NOT_STORED; } new_it->nkey = old_it->nkey; new_it->item_flag = flags; new_it->exptime = old_it->exptime; new_it->nbytes = it->nbytes + old_it->nbytes - 2; memcpy(new_it->data, old_it->data, old_it->nkey); new_it->data[old_it->nkey] = '0'; //copy数据 if (c->cmd == NREAD_APPEND) { memcpy(new_it->real_data_addr(), old_it->real_data_addr(), old_it->nbytes); memcpy(new_it->real_data_addr() + old_it->nbytes - 2/*\r\n*/, it->real_data_addr(), it->nbytes); } else { //NREAD_PREPEND memcpy(new_it->real_data_addr(), it->real_data_addr(), it->nbytes); memcpy(new_it->real_data_addr() + it->nbytes - 2, old_it->real_data_addr(), old_it->nbytes); } it = new_it; } } if (store_stat == LRU_list::NOT_STORED) { it->cas++; if (old_it != 0) item_replace(old_it, it, hv); else //set a new key-value do_item_link(it, hv); store_stat = LRU_list::STORED; } } if (old_it != 0) do_item_remove(old_it); if (new_it != 0) do_item_remove(new_it); if (store_stat == LRU_list::STORED) { c->cas = it->get_cas(); } return store_stat; }
/* * Stores an item in the cache according to the semantics of one of the set * commands. In threaded mode, this is protected by the cache lock. * * Returns the state of storage. */ static ENGINE_ERROR_CODE do_item_store(struct demo_engine *engine, hash_item *it, uint64_t *cas, ENGINE_STORE_OPERATION operation, const void *cookie) { const char *key = dm_item_get_key(it); hash_item *old_it; hash_item *new_it = NULL; ENGINE_ERROR_CODE stored; old_it = do_item_get(engine, key, it->nkey, true); if (old_it != NULL) { if (operation == OPERATION_ADD) { do_item_release(engine, old_it); return ENGINE_NOT_STORED; } } else { if (operation == OPERATION_REPLACE || operation == OPERATION_APPEND || operation == OPERATION_PREPEND) { return ENGINE_NOT_STORED; } if (operation == OPERATION_CAS) { return ENGINE_KEY_ENOENT; } } stored = ENGINE_NOT_STORED; if (operation == OPERATION_CAS) { assert(old_it != NULL); if (dm_item_get_cas(it) == dm_item_get_cas(old_it)) { // cas validates // it and old_it may belong to different classes. // I'm updating the stats for the one that's getting pushed out do_item_replace(engine, old_it, it); stored = ENGINE_SUCCESS; } else { if (engine->config.verbose > 1) { logger->log(EXTENSION_LOG_WARNING, NULL, "CAS: failure: expected %"PRIu64", got %"PRIu64"\n", dm_item_get_cas(old_it), dm_item_get_cas(it)); } stored = ENGINE_KEY_EEXISTS; } } else { /* * Append - combine new and old record into single one. Here it's * atomic and thread-safe. */ if (operation == OPERATION_APPEND || operation == OPERATION_PREPEND) { assert(old_it != NULL); /* * Validate CAS */ if (dm_item_get_cas(it) != 0) { // CAS much be equal if (dm_item_get_cas(it) != dm_item_get_cas(old_it)) { stored = ENGINE_KEY_EEXISTS; } } if (stored == ENGINE_NOT_STORED) { /* we have it and old_it here - alloc memory to hold both */ new_it = do_item_alloc(engine, key, it->nkey, old_it->flags, old_it->exptime, it->nbytes + old_it->nbytes - 2 /* CRLF */, cookie); if (new_it == NULL) { /* SERVER_ERROR out of memory */ if (old_it != NULL) do_item_release(engine, old_it); return ENGINE_NOT_STORED; } /* copy data from it and old_it to new_it */ if (operation == OPERATION_APPEND) { memcpy(dm_item_get_data(new_it), dm_item_get_data(old_it), old_it->nbytes); memcpy(dm_item_get_data(new_it) + old_it->nbytes - 2 /* CRLF */, dm_item_get_data(it), it->nbytes); } else { /* OPERATION_PREPEND */ memcpy(dm_item_get_data(new_it), dm_item_get_data(it), it->nbytes); memcpy(dm_item_get_data(new_it) + it->nbytes - 2 /* CRLF */, dm_item_get_data(old_it), old_it->nbytes); } it = new_it; } } if (stored == ENGINE_NOT_STORED) { if (old_it != NULL) { do_item_replace(engine, old_it, it); stored = ENGINE_SUCCESS; } else { stored = do_item_link(engine, it); } if (stored == ENGINE_SUCCESS) { *cas = dm_item_get_cas(it); } } } if (old_it != NULL) { do_item_release(engine, old_it); /* release our reference */ } if (new_it != NULL) { do_item_release(engine, new_it); } if (stored == ENGINE_SUCCESS) { *cas = dm_item_get_cas(it); } return stored; }
/* * Stores an item in the cache according to the semantics of one of the set * commands. In threaded mode, this is protected by the cache lock. * * Returns the state of storage. */ static ENGINE_ERROR_CODE do_store_item(struct default_engine *engine, hash_item *it, uint64_t *cas, ENGINE_STORE_OPERATION operation, const void *cookie) { const char *key = item_get_key(it); hash_item *old_it = do_item_get(engine, key, it->nkey); ENGINE_ERROR_CODE stored = ENGINE_NOT_STORED; hash_item *new_it = NULL; if (old_it != NULL && operation == OPERATION_ADD) { /* add only adds a nonexistent item, but promote to head of LRU */ do_item_update(engine, old_it); } else if (!old_it && (operation == OPERATION_REPLACE || operation == OPERATION_APPEND || operation == OPERATION_PREPEND)) { /* replace only replaces an existing value; don't store */ } else if (operation == OPERATION_CAS) { /* validate cas operation */ if(old_it == NULL) { // LRU expired stored = ENGINE_KEY_ENOENT; } else if (item_get_cas(it) == item_get_cas(old_it)) { // cas validates // it and old_it may belong to different classes. // I'm updating the stats for the one that's getting pushed out do_item_replace(engine, old_it, it); stored = ENGINE_SUCCESS; } else { if (engine->config.verbose > 1) { EXTENSION_LOGGER_DESCRIPTOR *logger; logger = (void*)engine->server.extension->get_extension(EXTENSION_LOGGER); logger->log(EXTENSION_LOG_INFO, NULL, "CAS: failure: expected %"PRIu64", got %"PRIu64"\n", item_get_cas(old_it), item_get_cas(it)); } stored = ENGINE_KEY_EEXISTS; } } else { /* * Append - combine new and old record into single one. Here it's * atomic and thread-safe. */ if (operation == OPERATION_APPEND || operation == OPERATION_PREPEND) { /* * Validate CAS */ if (item_get_cas(it) != 0) { // CAS much be equal if (item_get_cas(it) != item_get_cas(old_it)) { stored = ENGINE_KEY_EEXISTS; } } if (stored == ENGINE_NOT_STORED) { /* we have it and old_it here - alloc memory to hold both */ new_it = do_item_alloc(engine, key, it->nkey, old_it->flags, old_it->exptime, it->nbytes + old_it->nbytes, cookie); if (new_it == NULL) { /* SERVER_ERROR out of memory */ if (old_it != NULL) { do_item_release(engine, old_it); } return ENGINE_NOT_STORED; } /* copy data from it and old_it to new_it */ if (operation == OPERATION_APPEND) { memcpy(item_get_data(new_it), item_get_data(old_it), old_it->nbytes); memcpy(item_get_data(new_it) + old_it->nbytes, item_get_data(it), it->nbytes); } else { /* OPERATION_PREPEND */ memcpy(item_get_data(new_it), item_get_data(it), it->nbytes); memcpy(item_get_data(new_it) + it->nbytes, item_get_data(old_it), old_it->nbytes); } it = new_it; } } if (stored == ENGINE_NOT_STORED) { if (old_it != NULL) { do_item_replace(engine, old_it, it); } else { do_item_link(engine, it); } *cas = item_get_cas(it); stored = ENGINE_SUCCESS; } } if (old_it != NULL) { do_item_release(engine, old_it); /* release our reference */ } if (new_it != NULL) { do_item_release(engine, new_it); } if (stored == ENGINE_SUCCESS) { *cas = item_get_cas(it); } return stored; }