Memcached婧愮爜鍒嗘瀽涔媔tems.c
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Memcached婧愮爜鍒嗘瀽涔媔tems.c相关的知识,希望对你有一定的参考价值。
鏍囩锛?/p>
- #include "memcached.h"
- #include <sys/stat.h>
- #include <sys/socket.h>
- #include <sys/signal.h>
- #include <sys/resource.h>
- #include <fcntl.h>
- #include <netinet/in.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <time.h>
- #include <assert.h>
- #include <unistd.h>
- static void item_link_q(item *it);
- static void item_unlink_q(item *it);
- #define LARGEST_ID POWER_LARGEST
- typedef struct {
- uint64_t evicted;
- uint64_t evicted_nonzero;
- rel_time_t evicted_time;
- uint64_t reclaimed;
- uint64_t outofmemory;
- uint64_t tailrepairs;
- uint64_t expired_unfetched;
- uint64_t evicted_unfetched;
- uint64_t crawler_reclaimed;
- } itemstats_t;
- static item *heads[LARGEST_ID]; //鍚勪釜slabclass鐨凩RU闃熷垪澶存寚閽堟暟缁?/span>
- static item *tails[LARGEST_ID]; //鍚勪釜slabclass鐨凩RU闃熷垪灏炬寚閽堟暟缁?/span>
- static crawler crawlers[LARGEST_ID]; //鍚勪釜slabclass鐨刬tem鐖櫕鏁扮粍
- static itemstats_t itemstats[LARGEST_ID]; //鍚勪釜slabclass鐨刬tem缁熻鏁扮粍
- static unsigned int sizes[LARGEST_ID]; //鍚勪釜slabclass鐨刢hunk澶у皬鏁扮粍
- static int crawler_count = 0;
- static volatile int do_run_lru_crawler_thread = 0;
- static int lru_crawler_initialized = 0;
- static pthread_mutex_t lru_crawler_lock = PTHREAD_MUTEX_INITIALIZER;
- static pthread_cond_t lru_crawler_cond = PTHREAD_COND_INITIALIZER;
- //閲嶇疆缁熻
- void item_stats_reset(void) {
- mutex_lock(&cache_lock);
- memset(itemstats, 0, sizeof(itemstats));
- mutex_unlock(&cache_lock);
- }
- /* Get the next CAS id for a new item. */
- uint64_t get_cas_id(void) {
- static uint64_t cas_id = 0;
- return ++cas_id;
- }
- /* Enable this for reference-count debugging. */
- #if 0
- # define DEBUG_REFCNT(it,op) \
- fprintf(stderr, "item %x refcnt(%c) %d %c%c%c\n", \
- it, op, it->refcount, \
- (it->it_flags & ITEM_LINKED) ? 鈥楲鈥?span class="pln"> : 鈥?鈥?span class="pun">, \
- (it->it_flags & ITEM_SLABBED) ? 鈥楽鈥?span class="pln"> : 鈥?鈥?span class="pun">)
- #else
- # define DEBUG_REFCNT(it,op) while(0)
- #endif
- /**
- 绠楀嚭item鎬诲ぇ灏?/span>
- */
- static size_t item_make_header(const uint8_t nkey, const int flags, const int nbytes,
- char *suffix, uint8_t *nsuffix) {
- /* suffix is defined at 40 chars elsewhere.. */
- *nsuffix = (uint8_t) snprintf(suffix, 40, " %d %d\r\n", flags, nbytes - 2);
- return sizeof(item) + nkey + *nsuffix + nbytes;
- }
- /**
- item鍒嗛厤
- 鎶婅繖涓嚱鏁板紕娓呮锛屽熀鏈氨鎶妋emcached鍐呭瓨绠$悊鏈哄埗澶т綋寮勬竻妤氫簡銆?/span>
- */
- item *do_item_alloc(char *key, const size_t nkey, const int flags,
- const rel_time_t exptime, const int nbytes,
- const uint32_t cur_hv) {
- uint8_t nsuffix;
- item *it = NULL;
- char suffix[40];
- size_t ntotal = item_make_header(nkey + 1, flags, nbytes, suffix, &nsuffix); //item鎬诲ぇ灏?/span>
- if (settings.use_cas) {
- ntotal += sizeof(uint64_t); //濡傛灉鏈夌敤鍒癱as 閭d箞item澶у皬杩樿鍔犱笂unit64_t鐨剆ize
- }
- unsigned int id = slabs_clsid(ntotal); //鏍规嵁item澶у皬锛屾壘鍒伴€傚悎鐨剆labclass
- if (id == 0)
- return 0;
- mutex_lock(&cache_lock); //cache閿?/span>
- /* do a quick check if we have any expired items in the tail.. */
- /* 鍑嗗鍒嗛厤鏂扮殑item浜嗭紝闅忎究蹇€熺瀯涓€涓媗ru閾捐〃鏈熬鏈夋病鏈夎繃鏈焛tem锛屾湁鐨勮瘽灏辩敤杩囨湡鐨勭┖闂?*/
- int tries = 5;
- int tried_alloc = 0;
- item *search;
- void *hold_lock = NULL;
- rel_time_t oldest_live = settings.oldest_live;
- search = tails[id]; //杩欎釜tails鏄竴涓叏灞€鍙橀噺锛宼ails[xx]鏄痠d涓簒x鐨剆labclass lru閾捐〃鐨勫熬閮?/span>
- /* We walk up *only* for locked items. Never searching for expired.
- * Waste of CPU for almost all deployments */
- //浠嶭RU閾捐〃灏鹃儴锛堝氨鏄渶涔呮病浣跨敤杩囩殑item锛夊紑濮嬪線鍓嶆壘
- for (; tries > 0 && search != NULL; tries--, search=search->prev) {
- if (search->nbytes == 0 && search->nkey == 0 && search->it_flags == 1) {
- /* We are a crawler, ignore it. */
- /*
- 杩欓噷娉ㄩ噴鎰忔€濇槸璇存垜浠幇鍦ㄦ槸浠ョ埇铏殑韬唤鏉ョ埇鍑鸿繃鏈熺殑绌洪棿锛?/span>
- 鍍忕埇鍒拌繖绉嶅緢鎬殑item锛屽氨鍒浜嗭紝涓嶆槸鐖櫕瑕佸仛鐨勪簨锛屼笉瑕佸氨琛屼簡銆?/span>
- */
- tries++;
- continue;
- }
- /**
- 浣犱細鐪嬪埌寰堝鍦版柟鏈夎繖涓猦v锛岀畝鍗曡涓嬶紝鍏跺疄瀹冩槸瀵筰tem鐨勪竴涓猦ash锛屽緱鍒癶v鍊硷紝杩欎釜hv涓昏鏈変袱涓?/span>
- 浣滅敤锛?/span>
- 1锛夌敤浜巋ash琛ㄤ繚瀛榠tem锛岄€氳繃hv璁$畻鍑哄搱甯岃〃涓殑妗跺彿
- 2锛夌敤浜巌tem lock琛ㄤ腑閿佷綇item锛岄€氳繃hv璁$畻鍑哄簲璇ョ敤item lock琛ㄤ腑鍝釜閿佸褰撳墠item杩涜鍔犻攣
- 杩欎袱鑰呴兘娑夊強鍒颁竴涓矑搴﹂棶棰橈紝涓嶅彲鑳戒繚璇佹瘡涓笉涓€鏍风殑key鐨刪v涓嶄細鐩稿悓锛屾墍鏈塰ash鏂规硶閮藉彲鑳?/span>
- 鍑虹幇鍐茬獊銆?/span>
- 鎵€浠ash琛ㄤ腑鐢ㄩ摼琛ㄧ殑鏂瑰紡澶勭悊鍐茬獊鐨刬tem锛岃€宨tem lock琛ㄤ腑浼氬涓猧tem鍏变韩涓€涓攣锛屾垨鑰呰
- 澶氫釜妗跺叡浜竴涓攣銆?/span>
- */
- uint32_t hv = hash(ITEM_key(search), search->nkey);
- /**
- 灏濊瘯鍘婚攣浣忓綋鍓峣tem銆?/span>
- */
- if (hv == cur_hv || (hold_lock = item_trylock(hv)) == NULL)
- continue;
- /* Now see if the item is refcount locked */
- if (refcount_incr(&search->refcount) != 2) {
- refcount_decr(&search->refcount);
- /* Old rare bug could cause a refcount leak. We haven鈥榯 seen
- * it in years, but we leave this code in to prevent failures
- * just in case
- 娌$湅鎳傝繖閲岀殑鎰忔€?....
- */
- if (settings.tail_repair_time &&
- search->time + settings.tail_repair_time < current_time) {
- itemstats[id].tailrepairs++;
- search->refcount = 1;
- do_item_unlink_nolock(search, hv);
- }
- if (hold_lock)
- item_trylock_unlock(hold_lock);
- continue;
- }
- /* Expired or flushed */
- //瓒呮椂浜?..
- if ((search->exptime != 0 && search->exptime < current_time)
- || (search->time <= oldest_live && oldest_live <= current_time)) {
- itemstats[id].reclaimed++;
- if ((search->it_flags & ITEM_FETCHED) == 0) {
- itemstats[id].expired_unfetched++;
- }
- it = search; //鎷夸笅绌洪棿
- slabs_adjust_mem_requested(it->slabs_clsid, ITEM_ntotal(it), ntotal); //鏇存柊缁熻鏁版嵁
- /**
- 浠€涔堟槸link锛屽湪杩欑畝鍗曡涓嬶紝灏辨槸鎶奿tem鍔犲埌鍝堝笇琛ㄥ拰LRU閾捐〃鐨勮繃绋嬨€傝瑙乮tems::do_item_link鍑芥暟杩欓噷鎶奿tem鏃х殑link鍙栨秷鎺夛紝褰撳墠鍑芥暟do_item_alloc鐨勫伐浣滃彧鏄嬁绌洪棿锛岃€屽線鍚庡彲鐭ラ亾鎷垮埌item绌洪棿鍚庝細瀵硅繖鍧梚tem杩涜“link”宸ヤ綔锛岃€岃繖閲岃繖鍧梚tem绌洪棿鏄棫鐨刬tem瓒呮椂鐒跺悗鎷挎潵鐢ㄧ殑锛屾墍浠ュ厛鎶婂畠unlink鎺?/span>
- */
- do_item_unlink_nolock(it, hv);
- /* Initialize the item block: */
- it->slabs_clsid = 0;
- } else if ((it = slabs_alloc(ntotal, id)) == NULL) {/*濡傛灉娌℃湁鎵惧埌瓒呮椂鐨刬tem锛屽垯
- 璋冪敤slabs_alloc鍒嗛厤绌洪棿锛岃瑙乻labs_alloc
- 濡傛灉slabs_alloc鍒嗛厤绌洪棿澶辫触锛屽嵆杩斿洖NULL锛屽垯寰€涓嬭蛋锛屼笅闈㈢殑浠g爜鏄?/span>
- 鎶奓RU鍒楄〃鏈€鍚庝竴涓粰娣樻卑锛屽嵆浣縤tem娌℃湁杩囨湡銆?/span>
- 杩欓噷涓€鑸槸鍙敤鍐呭瓨宸茬粡婊′簡锛岄渶瑕佹寜LRU杩涜娣樻卑鐨勬椂鍊欍€?/span>
- //************mark: $1**************
- */
- tried_alloc = 1; //鏍囪涓€涓嬶紝琛ㄧず鏈夎繘鍏ユ鍒嗘敮锛岃〃绀烘湁灏濊瘯杩囪皟鐢╯labs_alloc鍘诲垎閰嶆柊鐨勭┖闂淬€?/span>
- //璁颁笅琚窐姹癷tem鐨勪俊鎭紝鍍忔垜浠娇鐢╩emcached缁忓父浼氭煡鐪嬬殑evicted_time灏辨槸鍦ㄨ繖閲岃祴鍊煎暒锛?/span>
- if (settings.evict_to_free == 0) {
- itemstats[id].outofmemory++;
- } else {
- itemstats[id].evicted++;
- itemstats[id].evicted_time = current_time - search->time; //琚窐姹扮殑item璺濈涓婃浣跨敤澶氶暱鏃堕棿浜?/span>
- if (search->exptime != 0)
- itemstats[id].evicted_nonzero++;
- if ((search->it_flags & ITEM_FETCHED) == 0) {
- itemstats[id].evicted_unfetched++;
- }
- it = search;
- slabs_adjust_mem_requested(it->slabs_clsid, ITEM_ntotal(it), ntotal);//鏇存柊缁熻鏁版嵁
- do_item_unlink_nolock(it, hv); //浠庡搱甯岃〃鍜孡RU閾捐〃涓垹鎺?/span>
- /* Initialize the item block: */
- it->slabs_clsid = 0;
- /*
- 濡傛灉褰撳墠slabclass鏈塱tem琚窐姹版帀浜嗭紝璇存槑鍙敤鍐呭瓨閮芥弧浜嗭紝鍐嶄篃娌℃湁
- slab鍙垎閰嶄簡锛?/span>
- 鑰屽鏋?slab_automove=2 (榛樿鏄?)锛岃繖鏍蜂細瀵艰嚧angry妯″紡锛?/span>
- 灏辨槸鍙鍒嗛厤澶辫触浜嗭紝灏遍┈涓婅繘琛宻lab閲嶅垎閰嶏細鎶婂埆鐨剆labclass绌洪棿鐗虹壊
- 鎺変竴浜涳紝椹笂缁欑幇鍦ㄧ殑slabclass鍒嗛厤绌洪棿锛岃€屼笉浼氬悎鐞嗗湴鏍规嵁娣樻卑缁熻
- 鏁版嵁鏉ュ垎鏋愯鎬庝箞閲嶅垎閰嶏紙slab_automove = 1鍒欎細锛夈€?/span>
- */
- if (settings.slab_automove == 2)
- slabs_reassign(-1, id);
- }
- }
- refcount_decr(&search->refcount);
- /* If hash values were equal, we don鈥榯 grab a second lock */
- if (hold_lock)
- item_trylock_unlock(hold_lock);
- break;
- }
- /**
- 濡傛灉涓婇潰鐨刦or寰幆閲岄潰娌℃湁鎵惧埌绌洪棿锛屽苟涓旀病鏈夎繘鍏ヨ繃else if ((it = slabs_alloc(ntotal, id)) == NULL)杩欎釜鍒嗘敮娌℃湁
- 灏濊瘯璋僺labs_alloc鍒嗛厤绌洪棿锛堟湁杩欑鍙兘鎬э級锛岄偅涔堬紝涓嬮潰杩欒浠g爜灏辨槸鍐嶅皾璇曞垎閰嶃€?/span>
- 浣犱細瑙夊緱涓婇潰閭d釜寰幆鍐欏緱鐗圭籂缁擄紝閫昏緫涓嶆竻锛屼及璁′綘涔熺湅閱変簡銆傚叾瀹炴暣涓垎閰嶅師鍒欐槸杩欐牱瀛愶細
- 1锛夊厛浠嶭RU閾捐〃鎵句笅鐪嬬湅鏈夋病鏈夋伆濂借繃鏈熺殑绌洪棿锛屾湁鐨勮瘽灏辩敤杩欎釜绌洪棿銆?/span>
- 2锛夊鏋滄病鏈夎繃鏈熺殑绌洪棿锛屽氨鍒嗛厤鏂扮殑绌洪棿銆?/span>
- 3锛夊鏋滃垎閰嶆柊鐨勭┖闂村け璐ワ紝閭d箞寰€寰€鏄唴瀛橀兘鐢ㄥ厜浜嗭紝鍒欎粠LRU閾捐〃涓妸鏈€鏃х殑鍗充娇娌¤繃鏈熺殑item娣樻卑鎺夛紝绌洪棿鍒嗙粰鏂扮殑item鐢ㄣ€?/span>
- 闂鏄細杩欎釜浠?ldquo;LRU閾捐〃鎵惧埌鐨刬tem”鏄竴涓笉纭畾鐨勪笢瑗匡紝鏈夊彲鑳借繖涓猧tem鏁版嵁寮傚父锛屾湁鍙兘杩欎釜item鐢变簬涓庡埆鐨刬tem鍏辩敤閿佺殑妗跺彿
- 杩欎釜妗惰閿佷綇浜嗭紝鎵€浠ユ€讳箣鍚勭鍘熷洜杩欎釜item姝ゅ埢涓嶄竴瀹氬彲鐢紝鍥犳鐢ㄤ簡涓€涓惊鐜皾璇曟壘鍑犳锛堜笂闈㈡槸5锛夈€?/span>
- 鎵€浠ラ€昏緫鏄細
- 1锛夋垜鍏堟壘5娆RU鐪嬬湅鏈夋病鏈夊彲鐢ㄧ殑杩囨湡鐨刬tem锛屾湁灏辩敤瀹冦€傦紙for寰幆5娆★級
- 2锛?娆℃病鏈夋壘鍒板彲鐢ㄧ殑杩囨湡鐨刬tem锛岄偅鎴戝垎閰嶆柊鐨勩€?/span>
- 3锛夊垎閰嶆柊鐨勪笉鎴愬姛锛岄偅鎴戝啀鎵?娆$湅鐪嬫湁娌℃湁鍙敤鐨勮櫧鐒舵病杩囨湡鐨刬tem锛屾窐姹板畠锛屾妸绌洪棿缁欐柊鐨刬tem鐢ㄣ€傦紙for寰幆5娆★級
- 閭d箞杩欓噷鏈変釜闂锛屽鏋滀唬鐮佽鍐欏緱閫昏緫娓呮櫚涓€鐐癸紝鎴戝緱鍐欎袱涓猣or寰幆锛屼竴涓槸涓轰簡绗?锛夋鍓?ldquo;鎵惧彲鐢ㄧ殑杩囨湡鐨?rdquo;item锛?/span>
- 涓€涓槸绗?锛夋涓嶆垚鍔熷悗“鎵惧彲鐢ㄧ殑鐢ㄦ潵娣樻卑鐨?rdquo;绌洪棿銆傝€屼笖鏈夐噸澶嶇殑閫昏緫“鎵惧埌鍙敤鐨?rdquo;锛屾墍浠emcached浣滆€呭氨鍚堝湪涓€璧蜂簡锛?/span>
- 鐒跺悗鍙兘鎶婄2锛夋涔熷鍒癴or寰幆閲岄潰锛岀‘瀹炴尯灏村艾鐨勩€傘€傘€備及璁emcached浣滆€呬篃鍐欏緱寰堢籂缁撱€傘€傘€?/span>
- 鎵€浠ュ氨寰堟湁鍙兘鍑虹幇5娆¢兘娌℃壘鍒板彲鐢ㄧ殑绌洪棿锛岄兘娌¤繘鍏ヨ繃elseif閭d釜鍒嗘敮灏辫continue鎺変簡锛屼负浜嗚涓嬫湁娌℃湁杩涜繃elseif
- 鍒嗘敮灏辨尗鎸湴鐢ㄤ竴涓猼ried_alloc鍙橀噺鏉ュ仛璁板彿銆傘€?/span>
- */
- if (!tried_alloc && (tries == 0 || search == NULL))
- it = slabs_alloc(ntotal, id);
- if (it == NULL) {
- itemstats[id].outofmemory++;
- mutex_unlock(&cache_lock);
- return NULL; //娌¢敊锛佷細鏈夊垎閰嶆柊绌洪棿涓嶆垚鍔燂紝鑰屼笖灏濊瘯5娆℃窐姹版棫鐨刬tem涔熸病鎴愬姛鐨勬椂鍊欙紝鍙兘杩斿洖NULL銆傘€?/span>
- }
- assert(it->slabs_clsid == 0);
- assert(it != heads[id]);
- //鏉ュ埌杩欓噷锛岃鏄巌tem鍒嗛厤鎴愬姛锛屼笅闈富瑕佹槸涓€浜涘垵濮嬪寲宸ヤ綔銆?/span>
- /* Item initialization can happen outside of the lock; the item鈥榮 already
- * been removed from the slab LRU.
- */
- it->refcount = 1; /* the caller will have a reference */
- mutex_unlock(&cache_lock);
- it->next = it->prev = it->h_next = 0;
- it->slabs_clsid = id;
- DEBUG_REFCNT(it, 鈥?鈥?span class="pun">);
- it->it_flags = settings.use_cas ? ITEM_CAS : 0;
- it->nkey = nkey;
- it->nbytes = nbytes;
- memcpy(ITEM_key(it), key, nkey);
- it->exptime = exptime;
- memcpy(ITEM_suffix(it), suffix, (size_t)nsuffix);
- it->nsuffix = nsuffix;
- return it;
- }
- /**
- 鎶婅繖鍧梚tem free鎺夛紝浠ヤ緵鍐嶅埄鐢紝娉ㄦ剰杩欓噷鐨刦ree涓嶆槸鎸囨妸鍐呭瓨绌洪棿閲婃斁鍝︼紝
- 鑰屾槸鎶婅繖鍧梚tem 鍙樹负“绌洪棽”
- */
- 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 = it->slabs_clsid;
- it->slabs_clsid = 0; //鍦ㄨ繖鎶奻ree鎺夌殑item 鐨剆labs_clsid璁句负0
- DEBUG_REFCNT(it, 鈥楩鈥?span class="pun">);
- slabs_free(it, ntotal, clsid);
- }
- /**
- * 妫€鏌tem澶у皬
- */
- bool item_size_ok(const size_t nkey, const int flags, const int nbytes) {
- char prefix[40];
- uint8_t nsuffix;
- size_t ntotal = item_make_header(nkey + 1, flags, nbytes,
- prefix, &nsuffix);
- if (settings.use_cas) {
- ntotal += sizeof(uint64_t);
- }
- return slabs_clsid(ntotal) != 0;
- }
- /**
- 鎶奿tem鎻掑叆鐩稿簲鐨剆labclass lru閾捐〃涓€屽凡
- */
- static void item_link_q(item *it) { /* item is the new head */
- item **head, **tail;
- assert(it->slabs_clsid < LARGEST_ID);
- 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]++;
- return;
- }
- /**
- 鎶奿tem浠庣浉搴旂殑slabclass lru閾捐〃涓垹鎺夎€屽凡锛屼笅闈㈠氨鏄粡鍏哥殑鍒犻櫎閾捐〃閫昏緫浠g爜浜?/span>
- */
- static void item_unlink_q(item *it) {
- item **head, **tail;
- assert(it->slabs_clsid < LARGEST_ID);
- head = &heads[it->slabs_clsid];
- tail = &tails[it->slabs_clsid];
- if (*head == it) {
- assert(it->prev == 0);
- *head = it->next;
- }
- if (*tail == it) {
- assert(it->next == 0);
- *tail = it->prev;
- }
- assert(it->next != it);
- assert(it->prev != it);
- if (it->next) it->next->prev = it->prev;
- if (it->prev) it->prev->next = it->next;
- sizes[it->slabs_clsid]--;
- return;
- }
- /**
- 鎶奿tem "link"璧锋潵锛屼富瑕佸寘鎷細
- 1锛夋敼鍙樹竴浜涚粺璁℃暟鎹?/span>
- 2锛夋妸item鍔犲埌鍝堝笇琛?/span>
- 3锛夋妸item鎻掑叆鍒扮浉搴旂殑slabclass lru閾捐〃涓?/span>
- */
- 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);
- assoc_insert(it, hv); //鎻掑叆鍝堝笇琛?/span>
- item_link_q(it); //鍔犲叆LRU閾捐〃
- refcount_incr(&it->refcount);
- mutex_unlock(&cache_lock);
- return 1;
- }
- /**
- 灏辨槸鍜宒o_item_link鍙嶈繃鏉ョ殑涓€浜涙搷浣?/span>
- */
- 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);
- do_item_remove(it);
- }
- mutex_unlock(&cache_lock);
- }
- /* 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);
- }
- }
- /**
- 鎸囧悜item鐨勬寚閽堜笉鐢ㄧ殑鏃跺€欓兘浼氳皟鐢ㄦ鍑芥暟
- */
- void do_item_remove(item *it) {
- MEMCACHED_ITEM_REMOVE(ITEM_key(it), it->nkey, it->nbytes);
- assert((it->it_flags & ITEM_SLABBED) == 0);
- assert(it->refcount > 0);
- if (refcount_decr(&it->refcount) == 0) { //寮曠敤璁℃暟鍑?锛屽綋寮曠敤璁℃暟涓?鏃讹紝鎵嶇湡姝f妸item free鎺夈€?/span>
- item_free(it);
- }
- }
- /**
- 涓昏浣滅敤鏄噸缃湪鏈€杩戜娇鐢ㄩ摼琛ㄤ腑鐨勪綅缃紝鏇存柊鏈€杩戜娇鐢ㄦ椂闂?/span>
- */
- 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) {
- item_unlink_q(it);
- it->time = current_time;
- item_link_q(it);
- }
- mutex_unlock(&cache_lock);
- }
- }
- int do_item_replace(item *it, item *new_it, const uint32_t hv) {
- MEMCACHED_ITEM_REPLACE(ITEM_key(it), it->nkey, it->nbytes,
- ITEM_key(new_it), new_it->nkey, new_it->nbytes);
- assert((it->it_flags & ITEM_SLABBED) == 0);
- do_item_unlink(it, hv);
- return do_item_link(new_it, hv);
- }
- void item_stats_evictions(uint64_t *evicted) {
- int i;
- mutex_lock(&cache_lock);
- for (i = 0; i < LARGEST_ID; i++) {
- evicted[i] = itemstats[i].evicted;
- }
- mutex_unlock(&cache_lock);
- }
- void do_item_stats_totals(ADD_STAT add_stats, void *c) {
- itemstats_t totals;
- memset(&totals, 0, sizeof(itemstats_t));
- int i;
- for (i = 0; i < LARGEST_ID; i++) {
- totals.expired_unfetched += itemstats[i].expired_unfetched;
- totals.evicted_unfetched += itemstats[i].evicted_unfetched;
- totals.evicted += itemstats[i].evicted;
- totals.reclaimed += itemstats[i].reclaimed;
- totals.crawler_reclaimed += itemstats[i].crawler_reclaimed;
- }
- APPEND_STAT("expired_unfetched", "%llu",
- (unsigned long long)totals.expired_unfetched);
- APPEND_STAT("evicted_unfetched", "%llu",
- (unsigned long long)totals.evicted_unfetched);
- APPEND_STAT("evictions", "%llu",
- (unsigned long long)totals.evicted);
- APPEND_STAT("reclaimed", "%llu",
- (unsigned long long)totals.reclaimed);
- APPEND_STAT("crawler_reclaimed", "%llu",
- (unsigned long long)totals.crawler_reclaimed);
- }
- void do_item_stats(ADD_STAT add_stats, void *c) {
- int i;
- for (i = 0; i < LARGEST_ID; i++) {
- if (tails[i] != NULL) {
- const char *fmt = "items:%d:%s";
- char key_str[STAT_KEY_LEN];
- char val_str[STAT_VAL_LEN];
- int klen = 0, vlen = 0;
- if (tails[i] == NULL) {
- /* We removed all of the items in this slab class */
- continue;
- }
- APPEND_NUM_FMT_STAT(fmt, i, "number", "%u", sizes[i]);
- APPEND_NUM_FMT_STAT(fmt, i, "age", "%u", current_time - tails[i]->time);
- APPEND_NUM_FMT_STAT(fmt, i, "evicted",
- "%llu", (unsigned long long)itemstats[i].evicted);
- APPEND_NUM_FMT_STAT(fmt, i, "evicted_nonzero",
- "%llu", (unsigned long long)itemstats[i].evicted_nonzero);
- APPEND_NUM_FMT_STAT(fmt, i, "evicted_time",
- "%u", itemstats[i].evicted_time);
- APPEND_NUM_FMT_STAT(fmt, i, "outofmemory",
- "%llu", (unsigned long long)itemstats[i].outofmemory);
- APPEND_NUM_FMT_STAT(fmt, i, "tailrepairs",
- "%llu", (unsigned long long)itemstats[i].tailrepairs);
- APPEND_NUM_FMT_STAT(fmt, i, "reclaimed",
- "%llu", (unsigned long long)itemstats[i].reclaimed);
- APPEND_NUM_FMT_STAT(fmt, i, "expired_unfetched",
- "%llu", (unsigned long long)itemstats[i].expired_unfetched);
- APPEND_NUM_FMT_STAT(fmt, i, "evicted_unfetched",
- "%llu", (unsigned long long)itemstats[i].evicted_unfetched);
- APPEND_NUM_FMT_STAT(fmt, i, "crawler_reclaimed",
- "%llu", (unsigned long long)itemstats[i].crawler_reclaimed);
- }
- }
- /* getting here means both ascii and binary terminators fit */
- add_stats(NULL, 0, NULL, 0, c);
- }
- 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];
- snprintf(key, sizeof(key), "%d", i * 32);
- APPEND_STAT(key, "%u", histogram[i]);
- }
- }
- free(histogram);
- }
- add_stats(NULL, 0, NULL, 0, c);
- }
- //璇诲彇item鏁版嵁
- item *do_item_get(const char *key, const size_t nkey, const uint32_t hv) {
- //mutex_lock(&cache_lock);
- item *it = assoc_find(key, nkey, hv);
- if (it != NULL) {
- refcount_incr(&it->refcount);
- if (slab_rebalance_signal &&
- ((void *)it >= slab_rebal.slab_start && (void *)it < slab_rebal.slab_end)) {
- do_item_unlink_nolock(it, hv);
- do_item_remove(it);
- it = NULL;
- }
- }
- //mutex_unlock(&cache_lock);
- int was_found = 0;
- if (settings.verbose > 2) {
- int ii;
- if (it == NULL) {
- fprintf(stderr, "> NOT FOUND ");
- } else {
- fprintf(stderr, "> FOUND KEY ");
- was_found++;
- }
- for (ii = 0; ii < nkey; ++ii) {
- fprintf(stderr, "%c", key[ii]);
- }
- }
- if (it != NULL) {
- if (settings.oldest_live != 0 && settings.oldest_live <= current_time &&
- it->time <= settings.oldest_live) {
- do_item_unlink(it, hv);
- do_item_remove(it);
- it = NULL;
- if (was_found) {
- fprintf(stderr, " -nuked by flush");
- }
- } else if (it->exptime != 0 && it->exptime <= current_time) {
- do_item_unlink(it, hv);
- do_item_remove(it);
- it = NULL;
- if (was_found) {
- fprintf(stderr, " -nuked by expire");
- }
- } else {
- it->it_flags |= ITEM_FETCHED;
- DEBUG_REFCNT(it, 鈥?鈥?span class="pun">);
- }
- }
- if (settings.verbose > 2)
- fprintf(stderr, "\n");
- 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;
- }
- /* expires items that are more recent than the oldest_live setting. */
- void do_item_flush_expired(void) {
- int i;
- item *iter, *next;
- if (settings.oldest_live == 0)
- return;
- for (i = 0; i < LARGEST_ID; i++) {
- for (iter = heads[i]; iter != NULL; iter = next) {
- /* iter->time of 0 are magic objects. */
- if (iter->time != 0 && iter->time >= settings.oldest_live) {
- next = iter->next;
- if ((iter->it_flags & ITEM_SLABBED) == 0) {
- do_item_unlink_nolock(iter, hash(ITEM_key(iter), iter->nkey));
- }
- } else {
- /* We鈥榲e hit the first old item. Continue to the next queue. */
- break;
- }
- }
- }
- }
- static void crawler_link_q(item *it) { /* item is the new tail */
- item **head, **tail;
- assert(it->slabs_clsid < LARGEST_ID);
- assert(it->it_flags == 1);
- assert(it->nbytes == 0);
- head = &heads[it->slabs_clsid];
- tail = &tails[it->slabs_clsid];
- assert(*tail != 0);
- assert(it != *tail);
- assert((*head && *tail) || (*head == 0 && *tail == 0));
- it->prev = *tail;
- it->next = 0;
- if (it->prev) {
- assert(it->prev->next == 0);
- it->prev->next = it;
- }
- *tail = it;
- if (*head == 0) *head = it;
- return;
- }
- static void crawler_unlink_q(item *it) {
- item **head, **tail;
- assert(it->slabs_clsid < LARGEST_ID);
- head = &heads[it->slabs_clsid];
- tail = &tails[it->slabs_clsid];
- if (*head == it) {
- assert(it->prev == 0);
- *head = it->next;
- }
- if (*tail == it) {
- assert(it->next == 0);
- *tail = it->prev;
- }
- assert(it->next != it);
- assert(it->prev != it);
- if (it->next) it->next->prev = it->prev;
- if (it->prev) it->prev->next = it->next;
- return;
- }
- static item *crawler_crawl_q(item *it) {
- item **head, **tail;
- assert(it->it_flags == 1);
- assert(it->nbytes == 0);
- assert(it->slabs_clsid < LARGEST_ID);
- head = &heads[it->slabs_clsid];
- tail = &tails[it->slabs_clsid];
- /* We鈥榲e hit the head, pop off */
- if (it->prev == 0) {
- assert(*head == it);
- if (it->next) {
- *head = it->next;
- assert(it->next->prev == it);
- it->next->prev = 0;
- }
- return NULL; /* Done */
- }
- assert(it->prev != it);
- if (it->prev) {
- if (*head == it->prev) {
- *head = it;
- }
- if (*tail == it) {
- *tail = it->prev;
- }
- assert(it->next != it);
- if (it->next) {
- assert(it->prev->next == it);
- it->prev->next = it->next;
- it->next->prev = it->prev;
- } else {
- it->prev->next = 0;
- }
- it->next = it->prev;
- it->prev = it->next->prev;
- it->next->prev = it;
- if (it->prev) {
- it->prev->next = it;
- }
- }
- assert(it->next != it);
- assert(it->prev != it);
- return it->next; /* success */
- }
- /* I pulled this out to make the main thread clearer, but it reaches into the
- * main thread鈥榮 values too much. Should rethink again.
- 涓婇潰杩欏彞娉ㄩ噴浣滆€呮槸璇达紝浠栨妸鐢ㄧ埇铏鐞嗚繃鏈熺殑item鐨勫伐浣滄斁鍒板彟涓€涓笓闂ㄧ殑绾跨▼閲屽幓鍋?/span>
- 鏄负浜嗚涓荤嚎绋嬪共鍑€涓€鐐癸紝浣嗘槸杩欑嚎绋嬬殑宸ヤ綔娑夊強鍒板お澶氫富绾跨▼鐨勪笢瑗夸簡锛屽緱閲嶆柊鎯虫兂..
- 杩欎釜鍑芥暟鐨勪綔鐢ㄦ槸“璇勪及”涓€涓嬭繖涓猧tem鏄惁搴旇free鎺夈€傚叾瀹炰富瑕佸氨鏄湅涓嬫湁娌℃湁杩囨湡鍟
- 褰撶劧鐢ㄦ埛璁剧疆鐨剆ettings.oldest_live鍙傛暟涔熷姞鍏ュ埌鑰冭檻涓?/span>
- */
- static void item_crawler_evaluate(item *search, uint32_t hv, int i) {
- rel_time_t oldest_live = settings.oldest_live;
- if ((search->exptime != 0 && search->exptime < current_time)
- || (search->time <= oldest_live && oldest_live <= current_time)) {
- itemstats[i].crawler_reclaimed++;
- if (settings.verbose > 1) {
- int ii;
- char *key = ITEM_key(search);
- fprintf(stderr, "LRU crawler found an expired item (flags: %d, slab: %d): ",
- search->it_flags, search->slabs_clsid);
- for (ii = 0; ii < search->nkey; ++ii) {
- fprintf(stderr, "%c", key[ii]);
- }
- fprintf(stderr, "\n");
- }
- if ((search->it_flags & ITEM_FETCHED) == 0) {
- itemstats[i].expired_unfetched++;
- }
- do_item_unlink_nolock(search, hv);
- do_item_remove(search);
- assert(search->slabs_clsid == 0);
- } else {
- refcount_decr(&search->refcount);
- }
- }
- /**
- item鐖櫕绾跨▼鍏ュ彛锛岃礋璐d粠lru閾捐〃涓妸杩囨湡鐨刬tem free鎺?/span>
- */
- static void *item_crawler_thread(void *arg) {
- int i;
- pthread_mutex_lock(&lru_crawler_lock);
- if (settings.verbose > 2)
- fprintf(stderr, "Starting LRU crawler background thread\n");
- while (do_run_lru_crawler_thread) {
- pthread_cond_wait(&lru_crawler_cond, &lru_crawler_lock);
- while (crawler_count) {
- item *search = NULL;
- void *hold_lock = NULL;
- for (i = 0; i < LARGEST_ID; i++) {
- if (crawlers[i].it_flags != 1) {
- continue;
- }
- pthread_mutex_lock(&cache_lock);
- search = crawler_crawl_q((item *)&crawlers[i]);
- if (search == NULL ||
- (crawlers[i].remaining && --crawlers[i].remaining < 1)) {
- if (settings.verbose > 2)
- fprintf(stderr, "Nothing left to crawl for %d\n", i);
- crawlers[i].it_flags = 0;
- crawler_count--;
- crawler_unlink_q((item *)&crawlers[i]);
- pthread_mutex_unlock(&cache_lock);
- 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
- */
- if ((hold_lock = item_trylock(hv)) == NULL) {
- pthread_mutex_unlock(&cache_lock);
- continue;
- }
- /* Now see if the item is refcount locked */
- if (refcount_incr(&search->refcount) != 2) {
- refcount_decr(&search->refcount);
- if (hold_lock)
- item_trylock_unlock(hold_lock);
- pthread_mutex_unlock(&cache_lock);
- continue;
- }
- item_crawler_evaluate(search, hv, i);
- if (hold_lock)
- item_trylock_unlock(hold_lock);
- pthread_mutex_unlock(&cache_lock);
- if (settings.lru_crawler_sleep)
- usleep(settings.lru_crawler_sleep);
- }
- }
- if (settings.verbose > 2)
- fprintf(stderr, "LRU crawler thread sleeping\n");
- STATS_LOCK();
- stats.lru_crawler_running = false;
- STATS_UNLOCK();
- }
- pthread_mutex_unlock(&lru_crawler_lock);
- if (settings.verbose > 2)
- fprintf(stderr, "LRU crawler thread stopping\n");
- return NULL;
- }
- static pthread_t item_crawler_tid;
- //鍋滄item鐖櫕绾跨▼
- int stop_item_crawler_thread(void) {
- int ret;
- pthread_mutex_lock(&lru_crawler_lock);
- do_run_lru_crawler_thread = 0;
- pthread_cond_signal(&lru_crawler_cond);
- pthread_mutex_unlock(&lru_crawler_lock);
- if ((ret = pthread_join(item_crawler_tid, NULL)) != 0) {
- fprintf(stderr, "Failed to stop LRU crawler thread: %s\n", strerror(ret));
- return -1;
- }
- settings.lru_crawler = false;
- return 0;
- }
- /**
- 鍚姩item 鐖櫕绾跨▼
- */
- int start_item_crawler_thread(void) {
- int ret;
- if (settings.lru_crawler)
- return -1;
- pthread_mutex_lock(&lru_crawler_lock);
- do_run_lru_crawler_thread = 1;
- settings.lru_crawler = true;
- if ((ret = pthread_create(&item_crawler_tid, NULL,
- item_crawler_thread, NULL)) != 0) {
- fprintf(stderr, "Can鈥榯 create LRU crawler thread: %s\n",
- strerror(ret));
- pthread_mutex_unlock(&lru_crawler_lock);
- return -1;
- }
- pthread_mutex_unlock(&lru_crawler_lock);
- return 0;
- }
- enum crawler_result_type lru_crawler_crawl(char *slabs) {
- char *b = NULL;
- uint32_t sid = 0;
- uint8_t tocrawl[POWER_LARGEST];
- if (pthread_mutex_trylock(&lru_crawler_lock) != 0) {
- return CRAWLER_RUNNING;
- }
- pthread_mutex_lock(&cache_lock);
- if (strcmp(slabs, "all") == 0) {
- for (sid = 0; sid < LARGEST_ID; sid++) {
- tocrawl[sid] = 1;
- }
- } else {
- for (char *p = strtok_r(slabs, ",", &b);
- p != NULL;
- p = strtok_r(NULL, ",", &b)) {
- if (!safe_strtoul(p, &sid) || sid < POWER_SMALLEST
- || sid > POWER_LARGEST) {
- pthread_mutex_unlock(&cache_lock);
- pthread_mutex_unlock(&lru_crawler_lock);
- return CRAWLER_BADCLASS;
- }
- tocrawl[sid] = 1;
- }
- }
- for (sid = 0; sid < LARGEST_ID; sid++) {
- if (tocrawl[sid] != 0 && tails[sid] != NULL) {
- if (settings.verbose > 2)
- fprintf(stderr, "Kicking LRU crawler off for slab %d\n", sid);
- crawlers[sid].nbytes = 0;
- crawlers[sid].nkey = 0;
- crawlers[sid].it_flags = 1; /* For a crawler, this means enabled. */
- crawlers[sid].next = 0;
- crawlers[sid].prev = 0;
- crawlers[sid].time = 0;
- crawlers[sid].remaining = settings.lru_crawler_tocrawl;
- crawlers[sid].slabs_clsid = sid;
- crawler_link_q((item *)&crawlers[sid]);
- crawler_count++;
- }
- }
- pthread_mutex_unlock(&cache_lock);
- pthread_cond_signal(&lru_crawler_cond);
- STATS_LOCK();
- stats.lru_crawler_running = true;
- STATS_UNLOCK();
- pthread_mutex_unlock(&lru_crawler_lock);
- return CRAWLER_OK;
- }
- //鍒濆鍖杔ru item鐖櫕绾跨▼
- int init_lru_crawler(void) {
- if (lru_crawler_initialized == 0) {
- if (pthread_cond_init(&lru_crawler_cond, NULL) != 0) {
- fprintf(stderr, "Can鈥榯 initialize lru crawler condition\n");
- return -1;
- }
- pthread_mutex_init(&lru_crawler_lock, NULL);
- lru_crawler_initialized = 1;
- }
- return 0;
- }
以上是关于Memcached婧愮爜鍒嗘瀽涔媔tems.c的主要内容,如果未能解决你的问题,请参考以下文章