void item_update(item *it) { assert((it->it_flags & ITEM_SLABBED) == 0); item_unlink_q(it); it->time = current_time; item_link_q(it); }
int do_item_link(item *it) { MEMCACHED_ITEM_LINK(ITEM_key(it), it->nkey, it->nbytes); assert((it->it_flags & (ITEM_LINKED|ITEM_SLABBED)) == 0); assert(it->nbytes < (1024 * 1024)); /* 1MB max size */ it->it_flags |= ITEM_LINKED; it->time = current_time; assoc_insert(it); #ifdef MOXI_ITEM_MALLOC it->refcount++; #endif STATS_LOCK(); stats.curr_bytes += ITEM_ntotal(it); stats.curr_items += 1; stats.total_items += 1; STATS_UNLOCK(); /* Allocate a new CAS ID on link. */ ITEM_set_cas(it, (settings.use_cas) ? get_cas_id() : 0); item_link_q(it); return 1; }
//将item插入到哈希表和LRU队列中,hv为哈希值 int do_item_link(item *it, const uint32_t hv) { MEMCACHED_ITEM_LINK(ITEM_key(it), it->nkey, it->nbytes); //确保这个item已经从slab分配出去并且还没插入到LRU队列中 assert((it->it_flags & (ITEM_LINKED|ITEM_SLABBED)) == 0); mutex_lock(&cache_lock); //加入link标记 it->it_flags |= ITEM_LINKED; it->time = current_time; STATS_LOCK(); stats.curr_bytes += ITEM_ntotal(it); stats.curr_items += 1; stats.total_items += 1; STATS_UNLOCK(); /* Allocate a new CAS ID on link. */ ITEM_set_cas(it, (settings.use_cas) ? get_cas_id() : 0); //插入到hash表中 assoc_insert(it, hv); //item插入到链表中 item_link_q(it); //引用计数加1 refcount_incr(&it->refcount); mutex_unlock(&cache_lock); return 1; }
int do_item_link(item *it) { MEMCACHED_ITEM_LINK(ITEM_key(it), it->nbytes); assert((it->it_flags & (ITEM_LINKED|ITEM_SLABBED)) == 0); assert(it->nbytes < (1024 * 1024)); /* 1MB max size */ it->it_flags |= ITEM_LINKED; it->time = current_time; assoc_insert(it); STATS_LOCK(); stats.curr_bytes += ITEM_ntotal(it); stats.curr_items += 1; stats.total_items += 1; STATS_UNLOCK(); #ifdef USE_REPLICATION /* Allocate a new CAS ID on link. */ if(!(it->it_flags & ITEM_REPDATA)) it->cas_id = get_cas_id(); #else /* Allocate a new CAS ID on link. */ it->cas_id = get_cas_id(); #endif /* USE_REPLICATION */ item_link_q(it); return 1; }
int item_link(item *it) { int needed = it->ntotal; unsigned long long maxbytes; int maxitems; maxbytes = settings.maxbytes ? settings.maxbytes : UINT_MAX; maxitems = settings.maxitems ? settings.maxitems : INT_MAX; while(items_tail && (stats.curr_bytes + needed > maxbytes || stats.curr_items + 1 > maxitems)) { drop_tail(); } it->it_flags |= ITEM_LINKED; it->time = time(0); assoc_insert(it->key, (void *)it); stats.curr_bytes += needed; stats.curr_items += 1; stats.total_items += 1; item_link_q(it); return 1; }
/* 形成了一个完成的 item 后, 就要把它放入两个数据结构中, 一是 memcached 的哈希表, memcached 运行过程中只有一个哈希表, 二是 item 所在的 slabclass 的 LRU 队列. */ int do_item_link(item *it, const uint32_t hv) { MEMCACHED_ITEM_LINK(ITEM_key(it), it->nkey, it->nbytes); assert((it->it_flags & (ITEM_LINKED|ITEM_SLABBED)) == 0); mutex_lock(&cache_lock); it->it_flags |= ITEM_LINKED; it->time = current_time; STATS_LOCK(); stats.curr_bytes += ITEM_ntotal(it); stats.curr_items += 1; stats.total_items += 1; STATS_UNLOCK(); /* Allocate a new CAS ID on link. */ ITEM_set_cas(it, (settings.use_cas) ? get_cas_id() : 0); /* 把 item 放入哈希表 */ assoc_insert(it, hv); /* 把 item 放入 LRU 队列*/ item_link_q(it); refcount_incr(&it->refcount); mutex_unlock(&cache_lock); return 1; }
static void _item_link(struct item *it) { assert(it->magic == ITEM_MAGIC); assert(!item_is_linked(it)); assert(!item_is_slabbed(it)); it->flags |= ITEM_LINKED; assoc_insert(it); item_link_q(it, true); }
void do_item_update(item *it) { if (it->time < now_ms - ITEM_UPDATE_INTERVAL) { if ((it->it_flags & ITEM_LINKED) != 0) { item_unlink_q(it); it->time = now_ms; item_link_q(it); } } }
static void _item_touch(struct item *it) { assert(it->magic == ITEM_MAGIC); assert(!item_is_slabbed(it)); if (it->atime >= (time_now() - ITEM_UPDATE_INTERVAL)) { return; } assert(item_is_linked(it)); item_unlink_q(it); item_link_q(it, false); }
void do_item_update(item *it) { if (it->time < current_time - ITEM_UPDATE_INTERVAL) { assert((it->it_flags & ITEM_SLABBED) == 0); if ((it->it_flags & ITEM_LINKED) != 0) { item_unlink_q(it); it->time = current_time; item_link_q(it); } } }
void do_item_update(item *it) { MEMCACHED_ITEM_UPDATE(ITEM_key(it), it->nkey, it->nbytes); if (it->time < current_time - ITEM_UPDATE_INTERVAL) { assert((it->it_flags & ITEM_SLABBED) == 0); if ((it->it_flags & ITEM_LINKED) != 0) { item_unlink_q(it); it->time = current_time; item_link_q(it); } } }
void do_item_update(struct default_engine *engine, hash_item *it) { rel_time_t current_time = engine->server.core->get_current_time(); MEMCACHED_ITEM_UPDATE(item_get_key(it), it->nkey, it->nbytes); if (it->time < current_time - ITEM_UPDATE_INTERVAL) { assert((it->iflag & ITEM_SLABBED) == 0); if ((it->iflag & ITEM_LINKED) != 0) { item_unlink_q(engine, it); it->time = current_time; item_link_q(engine, it); } } }
void LRU_list::do_item_update(base_item* item) { if (item->realtime < current_time() - ITEM_UPDATE_INTERVAL) { if ((item->item_flag & Slab::ITEM_SLABBED) != 0) { return; } mutex_lock(&cache_lock); if ((item->item_flag & Slab::ITEM_LINKED) != 0){ item_unlink_q(item); item->realtime = current_time(); item_link_q(item); } cache_lock.unlock(); } }
void do_item_update(item *it) { syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__); MEMCACHED_ITEM_UPDATE(ITEM_key(it), it->nkey, it->nbytes); if (it->time < current_time - ITEM_UPDATE_INTERVAL) { assert((it->it_flags & ITEM_SLABBED) == 0); mutex_lock(&cache_lock); if ((it->it_flags & ITEM_LINKED) != 0) { item_unlink_q(it); it->time = current_time; item_link_q(it); } mutex_unlock(&cache_lock); } }
int item_link(item *it) { assert((it->it_flags & (ITEM_LINKED|ITEM_SLABBED)) == 0); assert(it->nbytes < 1048576); it->it_flags |= ITEM_LINKED; it->time = current_time; assoc_insert(ITEM_key(it), it); stats.curr_bytes += ITEM_ntotal(it); stats.curr_items += 1; stats.total_items += 1; item_link_q(it); return 1; }
/* Copy/paste to avoid adding two extra branches for all common calls, since * _nolock is only used in an uncommon case. */ void do_item_update_nolock(item *it) { #ifdef CLOCK_REPLACEMENT if (it->recency == 0) it->recency = 1; #else MEMCACHED_ITEM_UPDATE(ITEM_key(it), it->nkey, it->nbytes); if (it->time < current_time - ITEM_UPDATE_INTERVAL) { assert((it->it_flags & ITEM_SLABBED) == 0); if ((it->it_flags & ITEM_LINKED) != 0) { item_unlink_q(it); it->time = current_time; item_link_q(it); } } #endif }
//按访问时间,更新在LRU队列的位置 void do_item_update(item *it) { MEMCACHED_ITEM_UPDATE(ITEM_key(it), it->nkey, it->nbytes); if (it->time < current_time - ITEM_UPDATE_INTERVAL) { assert((it->it_flags & ITEM_SLABBED) == 0); mutex_lock(&cache_lock); //达到更新时间间隔 if ((it->it_flags & ITEM_LINKED) != 0) { //从LUR中删除 item_unlink_q(it); //更新访问时间 it->time = current_time; //插入到LRU队列头部 item_link_q(it); } mutex_unlock(&cache_lock); } }
//更新item,这个只更新时间 void do_item_update(item *it) { MEMCACHED_ITEM_UPDATE(ITEM_key(it), it->nkey, it->nbytes); if (it->time < current_time - ITEM_UPDATE_INTERVAL) {//更新有时间限制 assert((it->it_flags & ITEM_SLABBED) == 0); mutex_lock(&cache_lock);//保持同步 //更新LRU队列的Item ,先删除,然后在添加,相当于刚刚使用 if ((it->it_flags & ITEM_LINKED) != 0) { item_unlink_q(it);//断开连接 it->time = current_time;//更新item的时间 item_link_q(it);//重新添加 } mutex_unlock(&cache_lock); } }
int do_item_link(item *it) { assert((it->it_flags & (ITEM_LINKED|ITEM_SLABBED)) == 0); assert(it->nbytes < (1024 * 1024)); /* 1MB max size */ it->it_flags |= ITEM_LINKED; it->time = current_time; assoc_insert(it); STATS_LOCK(); stats.curr_bytes += ITEM_ntotal(it); stats.curr_items += 1; stats.total_items += 1; STATS_UNLOCK(); /* Allocate a new CAS ID on link. */ it->cas_id = get_cas_id(); item_link_q(it); return 1; }
int do_item_link(item *it) { // MEMCACHED_ITEM_LINK(ITEM_key(it), it->nbytes); // assert((it->it_flags & (ITEM_LINKED|ITEM_SLABBED)) == 0); assert(it->nbytes < (1024 * 1024)); /* 1MB max size */ it->it_flags |= ITEM_LINKED; //<> it->time = now_ms; assoc_insert(it); stats.curr_bytes += ITEM_ntotal(it); stats.curr_items++; stats.total_items++; /* Allocate a new CAS ID on link. */ it->cas_id = get_cas_id(); item_link_q(it); return 1; }
int LRU_list::do_item_link(base_item* item, const uint32_t hv) { if ((item->item_flag & (Slab::ITEM_LINKED | Slab::ITEM_SLABBED)) != 0){ return 0; } mutex_lock(&cache_lock); item->item_flag |= Slab::ITEM_LINKED; item->realtime = current_time(); //stats.stat_lock.lock(); //stats.curr_bytes -= sizeof(base_item); //stats.curr_items -= 1; //stats.stat_lock.unlock(); item->set_cas(base_item::get_cas_id()); hashtable.hash_insert(item, hv); item_link_q(item); std::atomic_fetch_add(&(item->refcount), 1u); cache_lock.unlock(); return 1; }
int do_item_link(struct default_engine *engine, hash_item *it) { MEMCACHED_ITEM_LINK(item_get_key(it), it->nkey, it->nbytes); assert((it->iflag & (ITEM_LINKED|ITEM_SLABBED)) == 0); assert(it->nbytes < (1024 * 1024)); /* 1MB max size */ it->iflag |= ITEM_LINKED; it->time = engine->server.core->get_current_time(); assoc_insert(engine, engine->server.core->hash(item_get_key(it), it->nkey, 0), it); pthread_mutex_lock(&engine->stats.lock); engine->stats.curr_bytes += ITEM_ntotal(engine, it); engine->stats.curr_items += 1; engine->stats.total_items += 1; pthread_mutex_unlock(&engine->stats.lock); /* Allocate a new CAS ID on link. */ item_set_cas(NULL, NULL, it, get_cas_id()); item_link_q(engine, it); return 1; }
//将item加入到hashtable和LRU链中 int do_item_link(item *it, const uint32_t hv) { syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__); MEMCACHED_ITEM_LINK(ITEM_key(it), it->nkey, it->nbytes); assert((it->it_flags & (ITEM_LINKED|ITEM_SLABBED)) == 0); //判断状态,即没有在hash表LRU链中或被释放 mutex_lock(&cache_lock); it->it_flags |= ITEM_LINKED; //设置linked状态 it->time = current_time;//设置最近访问的时间 STATS_LOCK(); stats.curr_bytes += ITEM_ntotal(it); //增加每个item所需要的字节大小,包括item结构体和item内容大小 stats.curr_items += 1; stats.total_items += 1; STATS_UNLOCK(); /* Allocate a new CAS ID on link. */ ITEM_set_cas(it, (settings.use_cas) ? get_cas_id() : 0); //设置新CAS,CAS是memcache用来处理并发请求的一种机制 assoc_insert(it, hv);//插入hashtable item_link_q(it); //加入LRU链 refcount_incr(&it->refcount); mutex_unlock(&cache_lock); return 1; }
int do_item_link(struct default_engine *engine, hash_item *it) { const hash_key* key = item_get_key(it); MEMCACHED_ITEM_LINK(hash_key_get_client_key(key), hash_key_get_client_key_len(key), it->nbytes); cb_assert((it->iflag & (ITEM_LINKED|ITEM_SLABBED)) == 0); it->iflag |= ITEM_LINKED; it->time = engine->server.core->get_current_time(); assoc_insert(engine, crc32c(hash_key_get_key(key), hash_key_get_key_len(key), 0), it); cb_mutex_enter(&engine->stats.lock); engine->stats.curr_bytes += ITEM_ntotal(engine, it); engine->stats.curr_items += 1; engine->stats.total_items += 1; cb_mutex_exit(&engine->stats.lock); /* Allocate a new CAS ID on link. */ item_set_cas(NULL, NULL, it, get_cas_id()); item_link_q(engine, it); return 1; }
/* Returns number of items remove, expired, or evicted. * Callable from worker threads or the LRU maintainer thread */ static int lru_pull_tail(const int orig_id, const int cur_lru, const uint64_t total_bytes, uint8_t flags) { item *it = NULL; int id = orig_id; int removed = 0; if (id == 0) return 0; int tries = 5; item *search; item *next_it; void *hold_lock = NULL; unsigned int move_to_lru = 0; uint64_t limit = 0; id |= cur_lru; pthread_mutex_lock(&lru_locks[id]); search = tails[id]; /* We walk up *only* for locked items, and if bottom is expired. */ for (; tries > 0 && search != NULL; tries--, search=next_it) { /* we might relink search mid-loop, so search->prev isn't reliable */ next_it = search->prev; if (search->nbytes == 0 && search->nkey == 0 && search->it_flags == 1) { /* We are a crawler, ignore it. */ if (flags & LRU_PULL_CRAWL_BLOCKS) { pthread_mutex_unlock(&lru_locks[id]); return 0; } tries++; continue; } uint32_t hv = hash(ITEM_key(search), search->nkey); /* Attempt to hash item lock the "search" item. If locked, no * other callers can incr the refcount. Also skip ourselves. */ if ((hold_lock = item_trylock(hv)) == NULL) continue; /* Now see if the item is refcount locked */ if (refcount_incr(&search->refcount) != 2) { /* Note pathological case with ref'ed items in tail. * Can still unlink the item, but it won't be reusable yet */ itemstats[id].lrutail_reflocked++; /* In case of refcount leaks, enable for quick workaround. */ /* WARNING: This can cause terrible corruption */ if (settings.tail_repair_time && search->time + settings.tail_repair_time < current_time) { itemstats[id].tailrepairs++; search->refcount = 1; /* This will call item_remove -> item_free since refcnt is 1 */ do_item_unlink_nolock(search, hv); item_trylock_unlock(hold_lock); continue; } } /* Expired or flushed */ if ((search->exptime != 0 && search->exptime < current_time) || item_is_flushed(search)) { itemstats[id].reclaimed++; if ((search->it_flags & ITEM_FETCHED) == 0) { itemstats[id].expired_unfetched++; } /* refcnt 2 -> 1 */ do_item_unlink_nolock(search, hv); /* refcnt 1 -> 0 -> item_free */ do_item_remove(search); item_trylock_unlock(hold_lock); removed++; /* If all we're finding are expired, can keep going */ continue; } /* If we're HOT_LRU or WARM_LRU and over size limit, send to COLD_LRU. * If we're COLD_LRU, send to WARM_LRU unless we need to evict */ switch (cur_lru) { case HOT_LRU: limit = total_bytes * settings.hot_lru_pct / 100; case WARM_LRU: if (limit == 0) limit = total_bytes * settings.warm_lru_pct / 100; if (sizes_bytes[id] > limit) { itemstats[id].moves_to_cold++; move_to_lru = COLD_LRU; do_item_unlink_q(search); it = search; removed++; break; } else if ((search->it_flags & ITEM_ACTIVE) != 0) { /* Only allow ACTIVE relinking if we're not too large. */ itemstats[id].moves_within_lru++; search->it_flags &= ~ITEM_ACTIVE; do_item_update_nolock(search); do_item_remove(search); item_trylock_unlock(hold_lock); } else { /* Don't want to move to COLD, not active, bail out */ it = search; } break; case COLD_LRU: it = search; /* No matter what, we're stopping */ if (flags & LRU_PULL_EVICT) { if (settings.evict_to_free == 0) { /* Don't think we need a counter for this. It'll OOM. */ break; } itemstats[id].evicted++; itemstats[id].evicted_time = current_time - search->time; if (search->exptime != 0) itemstats[id].evicted_nonzero++; if ((search->it_flags & ITEM_FETCHED) == 0) { itemstats[id].evicted_unfetched++; } LOGGER_LOG(NULL, LOG_EVICTIONS, LOGGER_EVICTION, search); do_item_unlink_nolock(search, hv); removed++; if (settings.slab_automove == 2) { slabs_reassign(-1, orig_id); } } else if ((search->it_flags & ITEM_ACTIVE) != 0 && settings.lru_maintainer_thread) { itemstats[id].moves_to_warm++; search->it_flags &= ~ITEM_ACTIVE; move_to_lru = WARM_LRU; do_item_unlink_q(search); removed++; } break; } if (it != NULL) break; } pthread_mutex_unlock(&lru_locks[id]); if (it != NULL) { if (move_to_lru) { it->slabs_clsid = ITEM_clsid(it); it->slabs_clsid |= move_to_lru; item_link_q(it); } do_item_remove(it); item_trylock_unlock(hold_lock); } return removed; }
void item_update(item *it) { item_unlink_q(it); item_link_q(it); }