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; }
//将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 item_free(item *it) { size_t ntotal = 0; if (NULL == it) return 0; /* ntotal may be wrong, if 'it' is not a full item. */ ntotal = ITEM_ntotal(it); if (ntotal > settings.item_buf_size){ if (settings.verbose > 1) { fprintf(stderr, "ntotal: %d, use free() directly.\n", ntotal); } free(it); }else{ if (0 != item_add_to_freelist(it)) { if (settings.verbose > 1) { fprintf(stderr, "ntotal: %d, add a item buffer to freelist fail, use free() directly.\n", ntotal); } free(it); }else{ if (settings.verbose > 1) { fprintf(stderr, "ntotal: %d, add a item buffer to freelist.\n", ntotal); } } } return 0; }
/*@null@*/ void do_item_stats_sizes(ADD_STAT add_stats, void *c) { /* max 1MB object, divided into 32 bytes size buckets */ const int num_buckets = 32768; unsigned int *histogram = calloc(num_buckets, sizeof(int)); if (histogram != NULL) { int i; /* build the histogram */ for (i = 0; i < LARGEST_ID; i++) { item *iter = heads[i]; while (iter) { int ntotal = ITEM_ntotal(iter); int bucket = ntotal / 32; if ((ntotal % 32) != 0) bucket++; if (bucket < num_buckets) histogram[bucket]++; iter = iter->next; } } /* write the buffer */ for (i = 0; i < num_buckets; i++) { if (histogram[i] != 0) { char key[8]; int klen = 0; klen = snprintf(key, sizeof(key), "%d", i * 32); assert(klen < sizeof(key)); APPEND_STAT(key, "%u", histogram[i]); } } free(histogram); } add_stats(NULL, 0, NULL, 0, c); }
/* 形成了一个完成的 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; }
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; }
/* I think there's no way for this to be accurate without using the CAS value. * Since items getting their time value bumped will pass this validation. */ void item_stats_sizes_remove(item *it) { if (stats_sizes_hist == NULL || stats_sizes_cas_min > ITEM_get_cas(it)) return; int ntotal = ITEM_ntotal(it); int bucket = ntotal / 32; if ((ntotal % 32) != 0) bucket++; if (bucket < stats_sizes_buckets) stats_sizes_hist[bucket]--; }
void item_unlink(item *it) { if (it->it_flags & ITEM_LINKED) { it->it_flags &= ~ITEM_LINKED; stats.curr_bytes -= ITEM_ntotal(it); stats.curr_items -= 1; assoc_delete(ITEM_key(it)); item_unlink_q(it); } if (it->refcount == 0) item_free(it); }
void do_item_unlink(item *it) { // MEMCACHED_ITEM_UNLINK(ITEM_key(it), it->nbytes); if ((it->it_flags & ITEM_LINKED) != 0) { it->it_flags &= ~ITEM_LINKED; stats.curr_bytes -= ITEM_ntotal(it); stats.curr_items--; assoc_delete(ITEM_key(it), it->nkey); item_unlink_q(it); if (it->refcount == 0) item_free(it); } }
void do_item_unlink(item *it) { if ((it->it_flags & ITEM_LINKED) != 0) { it->it_flags &= ~ITEM_LINKED; STATS_LOCK(); stats.curr_bytes -= ITEM_ntotal(it); stats.curr_items -= 1; STATS_UNLOCK(); assoc_delete(ITEM_key(it), it->nkey); item_unlink_q(it); if (it->refcount == 0) item_free(it); } }
void item_free(item *it) { unsigned int ntotal = ITEM_ntotal(it); assert((it->it_flags & ITEM_LINKED) == 0); assert(it != heads[it->slabs_clsid]); assert(it != tails[it->slabs_clsid]); assert(it->refcount == 0); /* so slab size changer can tell later if item is already free or not */ it->slabs_clsid = 0; it->it_flags |= ITEM_SLABBED; slabs_free(it, ntotal); }
/*@null@*/ char *do_item_stats_sizes(uint32_t (*add_stats)(char *buf, const char *key, const uint16_t klen, const char *val, const uint32_t vlen, void *cookie), void *c, int *bytes) { const int num_buckets = 32768; /* max 1MB object, divided into 32 bytes size buckets */ unsigned int *histogram = (unsigned int *)malloc((size_t)num_buckets * sizeof(int)); char *buf = (char *)malloc(2 * 1024 * 1024); /* 2MB max response size */ char *ptr = buf; uint32_t nbytes, linelen = 0; int i; if (histogram == 0 || buf == 0) { if (histogram) free(histogram); if (buf) free(buf); *bytes = -1; return NULL; } /* build the histogram */ memset(histogram, 0, (size_t)num_buckets * sizeof(int)); for (i = 0; i < LARGEST_ID; i++) { item *iter = heads[i]; while (iter) { int ntotal = ITEM_ntotal(iter); int bucket = ntotal / 32; if ((ntotal % 32) != 0) bucket++; if (bucket < num_buckets) histogram[bucket]++; iter = iter->next; } } /* write the buffer */ *bytes = 0; char key[128]; char val[128]; for (i = 0; i < num_buckets; i++) { if (histogram[i] != 0) { sprintf(key, "%d", i * 32); sprintf(val, "%u", histogram[i]); nbytes = add_stats(ptr, key, strlen(key), val, strlen(val), c); linelen += nbytes; ptr += nbytes; } } nbytes = add_stats(ptr, NULL, 0, NULL, 0, c); *bytes = linelen + nbytes; free(histogram); return buf; }
/* FIXME: Is it necessary to keep this copy/pasted code? */ void do_item_unlink_nolock(item *it, const uint32_t hv) { MEMCACHED_ITEM_UNLINK(ITEM_key(it), it->nkey, it->nbytes); if ((it->it_flags & ITEM_LINKED) != 0) { it->it_flags &= ~ITEM_LINKED; STATS_LOCK(); stats.curr_bytes -= ITEM_ntotal(it); stats.curr_items -= 1; STATS_UNLOCK(); assoc_delete(ITEM_key(it), it->nkey, hv); item_unlink_q(it); do_item_remove(it); } }
/* slawek */ void do_item_unlink_nolock_nostat(item *it, const uint32_t hv, uint64_t *items_removed, uint64_t *bytes_removed) { MEMCACHED_ITEM_UNLINK(ITEM_key(it), it->nkey, it->nbytes); if ((it->it_flags & ITEM_LINKED) != 0) { it->it_flags &= ~ITEM_LINKED; *items_removed += 1; *bytes_removed += ITEM_ntotal(it); assoc_delete(ITEM_key(it), it->nkey, hv); item_unlink_q(it); do_item_remove(it); } }
void item_free(item *it) { size_t ntotal = ITEM_ntotal(it); unsigned int clsid; assert((it->it_flags & ITEM_LINKED) == 0); assert(it != heads[it->slabs_clsid]); assert(it != tails[it->slabs_clsid]); assert(it->refcount == 0); /* so slab size changer can tell later if item is already free or not */ clsid = ITEM_clsid(it); DEBUG_REFCNT(it, 'F'); slabs_free(it, ntotal, clsid); }
//释放item void item_free(item *it) { size_t ntotal = ITEM_ntotal(it);//获得item的大小 unsigned int clsid; assert((it->it_flags & ITEM_LINKED) == 0);//判断item的状态是否正确 assert(it != heads[it->slabs_clsid]);//item不能为LRU的头指针 assert(it != tails[it->slabs_clsid]);//item不能为LRU的尾指针 assert(it->refcount == 0);//释放时,需保证引用次数为0 /* so slab size changer can tell later if item is already free or not */ clsid = it->slabs_clsid; it->slabs_clsid = 0;//断开slabclass的链接 DEBUG_REFCNT(it, 'F'); slabs_free(it, ntotal, clsid);//slabclass结构执行释放 }
/* FIXME: Is it necessary to keep this copy/pasted code? */ void do_item_unlink_nolock(item *it, const uint32_t hv) { syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__); MEMCACHED_ITEM_UNLINK(ITEM_key(it), it->nkey, it->nbytes); if ((it->it_flags & ITEM_LINKED) != 0) { it->it_flags &= ~ITEM_LINKED; STATS_LOCK(); stats.curr_bytes -= ITEM_ntotal(it); stats.curr_items -= 1; STATS_UNLOCK(); assoc_delete(ITEM_key(it), it->nkey, hv); item_unlink_q(it); do_item_remove(it); } }
void item_free(item *it) { size_t ntotal = ITEM_ntotal(it); unsigned int clsid; assert((it->it_flags & ITEM_LINKED) == 0); assert(it->refcount == 0); /* so slab size changer can tell later if item is already free or not */ clsid = it->slabs_clsid; it->slabs_clsid = 0; // it->it_flags |= ITEM_SLABBED; DEBUG_REFCNT(it, 'F'); //[TODO] allocate management zfree(it); }
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; }
static void item_free(struct default_engine *engine, hash_item *it) { size_t ntotal = ITEM_ntotal(engine, it); unsigned int clsid; assert((it->iflag & ITEM_LINKED) == 0); assert(it != engine->items.heads[it->slabs_clsid]); assert(it != engine->items.tails[it->slabs_clsid]); assert(it->refcount == 0); /* so slab size changer can tell later if item is already free or not */ clsid = it->slabs_clsid; it->slabs_clsid = 0; it->iflag |= ITEM_SLABBED; DEBUG_REFCNT(it, 'F'); slabs_free(engine, it, ntotal, clsid); }
//释放item void item_free(item *it) { syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__); size_t ntotal = ITEM_ntotal(it); unsigned int clsid; assert((it->it_flags & ITEM_LINKED) == 0);//没有在hash表和LUR链中 assert(it != heads[it->slabs_clsid]); assert(it != tails[it->slabs_clsid]); assert(it->refcount == 0); /* so slab size changer can tell later if item is already free or not */ clsid = it->slabs_clsid; it->slabs_clsid = 0; DEBUG_REFCNT(it, 'F'); slabs_free(it, ntotal, clsid); }
/* 0 for Success -1 for SERVER_ERROR */ int bdb_set(char *key, item *it){ pthread_rwlock_rdlock(&qlist_ht_lock); queue_t *q = (queue_t *)hashtable_search(qlist_htp, (void *)key); DB_TXN *txnp = NULL; int ret; if (NULL == q) { pthread_rwlock_unlock(&qlist_ht_lock); ret = bdb_create_queue(key); if (0 != ret){ return -1; } /* search again */ pthread_rwlock_rdlock(&qlist_ht_lock); q = (queue_t *)hashtable_search(qlist_htp, (void *)key); } if (NULL != q) { db_recno_t recno; DBT dbkey, dbdata; BDB_CLEANUP_DBT(); dbkey.data = &recno; dbkey.ulen = sizeof(recno); dbkey.flags = DB_DBT_USERMEM; dbdata.data = it; dbdata.size = ITEM_ntotal(it); ret = envp->txn_begin(envp, NULL, &txnp, 0); CHECK_DB_RET(ret); ret = q->dbp->put(q->dbp, txnp, &dbkey, &dbdata, DB_APPEND); CHECK_DB_RET(ret); ret = txnp->commit(txnp, 0); CHECK_DB_RET(ret); pthread_mutex_lock(&(q->lock)); (q->set_hits)++; pthread_mutex_unlock(&(q->lock)); } pthread_rwlock_unlock(&qlist_ht_lock); return 0; dberr: if (txnp != NULL){ txnp->abort(txnp); } if (settings.verbose > 1) { fprintf(stderr, "bdb_set: %s\n", db_strerror(ret)); } pthread_rwlock_unlock(&qlist_ht_lock); return -1; }
void do_item_unlink(item *it, const uint32_t hv) { syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__); MEMCACHED_ITEM_UNLINK(ITEM_key(it), it->nkey, it->nbytes); mutex_lock(&cache_lock); if ((it->it_flags & ITEM_LINKED) != 0) { it->it_flags &= ~ITEM_LINKED;//设置为非linked STATS_LOCK(); stats.curr_bytes -= ITEM_ntotal(it); stats.curr_items -= 1; STATS_UNLOCK(); assoc_delete(ITEM_key(it), it->nkey, hv); //从hash表中删除 item_unlink_q(it); //从LRU链中删除 do_item_remove(it); } mutex_unlock(&cache_lock); }
//将item从hashtable和LRU链中移除,而且还释放掉 item 所占的内存 (其实只是把 item 放到空闲链表中),是do_item_link的逆操作 void do_item_unlink(item *it, const uint32_t hv) { MEMCACHED_ITEM_UNLINK(ITEM_key(it), it->nkey, it->nbytes); mutex_lock(&cache_lock);//执行同步 if ((it->it_flags & ITEM_LINKED) != 0) {//判断状态值,保证item还在LRU队列中 it->it_flags &= ~ITEM_LINKED;//修改状态值 STATS_LOCK();//更新统计信息 stats.curr_bytes -= ITEM_ntotal(it); stats.curr_items -= 1; STATS_UNLOCK(); assoc_delete(ITEM_key(it), it->nkey, hv);//从Hash表中删除 item_unlink_q(it);//将item从slabclass对应的LRU队列摘除 do_item_remove(it);//释放 item 所占的内存 } mutex_unlock(&cache_lock); }
void do_item_unlink(item *it) { MEMCACHED_ITEM_UNLINK(ITEM_key(it), it->nkey, it->nbytes); if ((it->it_flags & ITEM_LINKED) != 0) { it->it_flags &= ~ITEM_LINKED; STATS_LOCK(); stats.curr_bytes -= ITEM_ntotal(it); stats.curr_items -= 1; STATS_UNLOCK(); assoc_delete(ITEM_key(it), it->nkey); item_unlink_q(it); #ifndef MOXI_ITEM_MALLOC if (it->refcount == 0) item_free(it); #endif } }
void do_item_unlink(struct default_engine *engine, hash_item *it) { MEMCACHED_ITEM_UNLINK(item_get_key(it), it->nkey, it->nbytes); if ((it->iflag & ITEM_LINKED) != 0) { it->iflag &= ~ITEM_LINKED; pthread_mutex_lock(&engine->stats.lock); engine->stats.curr_bytes -= ITEM_ntotal(engine, it); engine->stats.curr_items -= 1; pthread_mutex_unlock(&engine->stats.lock); assoc_delete(engine, engine->server.core->hash(item_get_key(it), it->nkey, 0), item_get_key(it), it->nkey); item_unlink_q(engine, it); if (it->refcount == 0) { item_free(engine, it); } } }
static void do_item_link_q(item *it) { /* item is the new head */ item **head, **tail; assert((it->it_flags & ITEM_SLABBED) == 0); head = &heads[it->slabs_clsid]; tail = &tails[it->slabs_clsid]; assert(it != *head); assert((*head && *tail) || (*head == 0 && *tail == 0)); it->prev = 0; it->next = *head; if (it->next) it->next->prev = it; *head = it; if (*tail == 0) *tail = it; sizes[it->slabs_clsid]++; sizes_bytes[it->slabs_clsid] += ITEM_ntotal(it); return; }
//从哈希表和LRU中删除 void do_item_unlink(item *it, const uint32_t hv) { MEMCACHED_ITEM_UNLINK(ITEM_key(it), it->nkey, it->nbytes); mutex_lock(&cache_lock); if ((it->it_flags & ITEM_LINKED) != 0) { it->it_flags &= ~ITEM_LINKED; STATS_LOCK(); stats.curr_bytes -= ITEM_ntotal(it); stats.curr_items -= 1; STATS_UNLOCK(); //从哈希表中删除 assoc_delete(ITEM_key(it), it->nkey, hv); //从链表中删除 item_unlink_q(it); //向slab归还这个item do_item_remove(it); } mutex_unlock(&cache_lock); }
/* 0 for Success -1 for SERVER_ERROR */ int item_put(char *key, size_t nkey, item *it){ int ret; DBT dbkey, dbdata; BDB_CLEANUP_DBT(); dbkey.data = key; dbkey.size = nkey; dbdata.data = it; dbdata.size = ITEM_ntotal(it); ret = dbp->put(dbp, NULL, &dbkey, &dbdata, 0); if (ret == 0) { return 0; } else { if (settings.verbose > 1) { fprintf(stderr, "dbp->put: %s\n", db_strerror(ret)); } return -1; } }
/*@null@*/ static void do_item_stats_sizes(struct default_engine *engine, ADD_STAT add_stats, const void *c) { /* max 1MB object, divided into 32 bytes size buckets */ const int num_buckets = 32768; unsigned int *histogram = calloc(num_buckets, sizeof(unsigned int)); if (histogram != NULL) { int i; /* build the histogram */ for (i = 0; i < POWER_LARGEST; i++) { hash_item *iter = engine->items.heads[i]; while (iter) { size_t ntotal = ITEM_ntotal(engine, iter); size_t bucket = ntotal / 32; if ((ntotal % 32) != 0) { bucket++; } if (bucket < num_buckets) { histogram[bucket]++; } iter = iter->next; } } /* write the buffer */ for (i = 0; i < num_buckets; i++) { if (histogram[i] != 0) { char key[8], val[32]; int klen, vlen; klen = snprintf(key, sizeof(key), "%d", i * 32); vlen = snprintf(val, sizeof(val), "%u", histogram[i]); if (klen > 0 && klen < sizeof(key) && vlen > 0 && vlen < sizeof(val)) { add_stats(key, klen, val, vlen, c); } } } free(histogram); } }