php與memcached服務器交互的分布式實現源碼分析

fmms 12年前發布 | 39K 次閱讀 緩存服務器 memcached

前段時間,因為一個項目的關系,研究了php通過調用memcachememcached PECL擴展庫的接口存儲到分布式緩存服務器的機制,在此做我根據他們各自的源碼進行分析,希望能對這方面感興趣的人有些幫助。
本篇文章我會針對php和memcache擴展庫的交互根據源碼展開分析。
PHP調用memcache的接口通常會是如下過程:
<?php
$mmc = new Memcache();
$mmc->addServer('node1', 11211);
$mmc->addServer('node2', 11211, MemcacheConfig::MEMCACHE_PERSISTENT, 2);
$mmc->set('key', 'value');
echo $mmc->get('key');
$mmc->delete('key');


短短幾行代碼,一個緩存key的生命周期就已經完整層現。從Memcache的初始化,到addServer添加兩個服務器節點,接著set一個key到服務器上,然后get到這個key輸出,最后delete這個key。在這個生命周期里,Memcache在底層究竟做了哪些事情,保證了數據存儲服務器的均勻分布,數據的完整性?
接下來,我會根據上述生命周期的順序,循序漸進的分析(由于主題是分布式算法的分析,所以接下來不相干的代碼我會略去,很多分析我會直接備注在源碼上)。


1. Memcache的初始化
對應PHP的代碼:$mmc = new Memcache();


對應C的代碼:// Memcache類對應的方法名已經實際在c中實現過程的函數名,在接下來的分析中會用到。忽略不會分析到的方法。
static zend_function_entry php_memcache_class_functions[] = {
PHP_FALIAS(addserver, memcache_add_server, NULL)
PHP_FALIAS(set, memcache_set, NULL)
PHP_FALIAS(get, memcache_get, NULL)
PHP_FALIAS(delete, memcache_delete, NULL)
......
};
PHP_MINIT_FUNCTION(memcache)
{
// 初始化Memcache類實體,給類定在php空間中的調用名稱以及類所擁有的方法
zend_class_entry memcache_class_entry;
INIT_CLASS_ENTRY(memcache_class_entry, "Memcache", php_memcache_class_functions);
memcache_class_entry_ptr = zend_register_internal_class(&memcache_class_entry TSRMLS_CC);
......
}


以上過程是在Module Initialization的環節已經做好,在new的過程中,并無其余處理。
2. 添加緩存服務器,使之成為分布式存儲
對應PHP的代碼:$mmc->addServer('node1', 11211);
$mmc->addServer('node2', 11211, MemcacheConfig::MEMCACHE_PERSISTENT, 2);


由上面的php_memcache_class_functions結構可以看出,addServer方法對應的是memcache_add_server函數,因此對應C的代碼:PHP_FUNCTION(memcache_add_server)
{
zval connection, mmc_object = getThis(), failure_callback = NULL;
// 整個Memcache中最重要的一個結構mmc_pool_t
mmc_pool_t pool;
// 當前新添服務器的結構變量
mmc_t
mmc;
......
// 如果pool之前沒有初始化過,則初始化
if (zend_hash_find(Z_OBJPROP_P(mmc_object), "connection", sizeof("connection"), (void
) &connection) == FAILURE) {
// 調用mmp_pool_new完成初始化
pool = mmc_pool_new(TSRMLS_C);
......
}
else {
......
}
//將新增服務器添加到pool中
mmc_pool_add(pool, mmc, weight);
RETURN_TRUE;
}


來看下mmc_pool_t結構的定義:typedef struct mmc_pool {
mmc_t servers; // 所有服務器的狀態
int num_servers; // 服務器數量
mmc_t
requests; // 根據get的array key請求順序返回的服務器數組狀態
int compress_threshold; // 待存儲的數據壓縮的下限值
double min_compress_savings; // 待存儲的數據最小的壓縮百分比
zend_bool in_free; // 標記該pool是否被釋放
mmc_hash_t hash; // hash策略容器
void
hash_state; // hash函數
} mmc_pool_t;


然后我們看下mmc_hash_t的結構,再接下去的分析中會用到:// 結構定義中包含了四種抽象函數,作為基本結構,用于定義子結構
typedef struct mmc_hash {
mmc_hash_create_state create_state; // 創建hash策略狀態,主要是接納了hash函數算法
mmc_hash_free_state free_state; // 釋放hash策略狀態
mmc_hash_find_server find_server; // 根據key和分布式算法定位到某臺服務器
mmc_hash_add_server add_server; // 根據hash策略、算法以及權重值添加服務器資源
} mmc_hash_t;


接著我們追蹤memcache_add_server函數中的mmc_pool_new函數調用方法:mmc_pool_t mmc_pool_new(TSRMLS_D) / {{{ /
{
// 初始化一些基本的狀態
mmc_pool_t
pool = emalloc(sizeof(mmc_pool_t));
pool->num_servers = 0;
pool->compress_threshold = 0;
pool->in_free = 0;
pool->min_compress_savings = MMC_DEFAULT_SAVINGS;
// 初始化分布式哈希算法
mmc_pool_init_hash(pool TSRMLS_CC);
return pool;
}


現在初始化hash算法已經逐漸顯露,繼續追蹤mmc_pool_init_hash函數:static void mmc_pool_init_hash(mmc_pool_t pool TSRMLS_DC) / {{{ /
{
mmc_hash_function hash;// 初始化hash函數
// 根據php.ini中的memcache.hash_strategy配置選擇hash存儲策略,默認為標準hash存儲策略
switch (MEMCACHE_G(hash_strategy)) {
case MMC_CONSISTENT_HASH:
pool->hash = &mmc_consistent_hash;// 采用持久化hash存儲策略
break;
default:
pool->hash = &mmc_standard_hash;// 采用標準hash存儲策略
}
// 根據php.ini中的memcache.hash_function配置選擇hash函數,默認為crc32算法
switch (MEMCACHE_G(hash_function)) {
case MMC_HASH_FNV1A:
hash = &mmc_hash_fnv1a; // 采用fnv1a算法
break;
default:
hash = &mmc_hash_crc32; // 采用crc32算法
}
// hash策略中根據選擇的hash函數創建對應的狀態
pool->hash_state = pool->hash->create_state(hash);
}


根據上面的兩個switch可以知道,在create_state的時候,是有兩種策略選擇的可能性,接著傳入的hash參數也存在兩種可能性,這里我先分析標準hash存儲策略,以及對應的兩種hash算法,然后再分析持久化hash策略。
先看下mmc_consistent_hash結構:// 根據mmc_hash_t的定義包含了四種具體函數實現
mmc_hash_t mmc_standard_hash = {
mmc_standard_create_state,
mmc_standard_free_state,
mmc_standard_find_server,
mmc_standard_add_server
};


由上可知,pool->hash->create_state的函數調用實際是對mmc_standard_create_state的函數調用,繼續看mmc_standard_create_state函數代碼的實現:// hash策略狀態
typedef struct mmc_standard_state {
int num_servers; // 服務器數量
mmc_t **buckets; // 哈希桶,和權重值相關
int num_buckets; // 哈系桶的數量
mmc_hash_function hash; // hash算法
} mmc_standard_state_t;

void
mmc_standard_create_state(mmc_hash_function hash) / {{{ /
{
// 初始化狀態
mmc_standard_state_t state = emalloc(sizeof(mmc_standard_state_t));
memset(state, 0, sizeof(mmc_standard_state_t));
// 選擇的hash函數賦給hash屬性
state->hash = hash;
return state;
}


crc的算法實現:static unsigned int mmc_hash_crc32(const char
key, int key_len) / CRC32 hash {{{ /
{
unsigned int crc = ~0;
int z;

for (z=0; z<key_len; z++) {
CRC32(crc, key[z]);
}

return ~crc;
}


有關CRC32再深入的實現可以參考Cyclic redundancy check
然后來看看fnv算法實現:/ 32 bit magic FNV-1a prime and init /

define FNV_32_PRIME 0x01000193

define FNV_32_INIT 0x811c9dc5

static unsigned int mmc_hash_fnv1a(const char key, int key_len) / FNV-1a hash {{{ /
{
unsigned int hval = FNV_32_INIT;
int z;

for (z=0; z<key_len; z++) {
hval ^= (unsigned int)key[z];
hval
= FNV_32_PRIME;
}

return hval;
}


具體fnv算法的深入實現可以參考Fowler–Noll–Vo hash function
最后我們看看mmc_consistent_hash結構:mmc_hash_t mmc_consistent_hash = {
mmc_consistent_create_state,
mmc_consistent_free_state,
mmc_consistent_find_server,
mmc_consistent_add_server
};


一樣是四個函數,看下對應的create_state中的mmc_consistent_create_state的實現:/ number of precomputed buckets, should be power of 2 /

define MMC_CONSISTENT_BUCKETS 1024


typedef struct mmc_consistent_point {
mmc_t server; // 服務器狀態
unsigned int point; // 對應的指針
} mmc_consistent_point_t;

typedef struct mmc_consistent_state {
int num_servers; // 服務器數量
mmc_consistent_point_t
points; // 持久化服務器指針
int num_points; // 指針數量
mmc_t buckets[MMC_CONSISTENT_BUCKETS]; // 哈希桶
int buckets_populated; //標記哈希桶是否計算過
mmc_hash_function hash; // hash函數
} mmc_consistent_state_t;

void
mmc_consistent_create_state(mmc_hash_function hash) / {{{ /
{
// 初始化state
mmc_consistent_state_t state = emalloc(sizeof(mmc_consistent_state_t));
memset(state, 0, sizeof(mmc_consistent_state_t));
// 將hash函數賦值給hash屬性
state->hash = hash;
return state;
}


至此,memcache_add_server中mmc_pool_new函數流程結束,接著來看mmc_pool_add函數:void mmc_pool_add(mmc_pool_t
pool, mmc_t mmc, unsigned int weight) / {{{ /
{
/
add server and a preallocated request pointer /
if (pool->num_servers) {
pool->servers = erealloc(pool->servers, sizeof(mmc_t
) (pool->num_servers + 1));
pool->requests = erealloc(pool->requests, sizeof(mmc_t
) (pool->num_servers + 1));
}
else {
pool->servers = emalloc(sizeof(mmc_t
));
pool->requests = emalloc(sizeof(mmc_t ));
}

pool->servers[pool->num_servers] = mmc;
pool->num_servers++;
// 根據pool狀態,當前要添加的服務器狀態和權重調用add_server函數
pool->hash->add_server(pool->hash_state, mmc, weight);
}


由上面的說明可知add_server在標準hash模式下對應mmc_standard_add_server函數:void mmc_standard_add_server(void
s, mmc_t mmc, unsigned int weight) / {{{ /
{
mmc_standard_state_t
state = s;
int i;

// 哈希桶初始化或重新分配相應的權重數值對應的空間
if (state->num_buckets) {
state->buckets = erealloc(state->buckets, sizeof(mmc_t ) (state->num_buckets + weight));
}
else {
state->buckets = emalloc(sizeof(mmc_t ) (weight));
}
// 在某個區間內為哈希桶賦予服務器狀態
for (i=0; i<weight; i++) {
buckets[state->num_buckets + i] = mmc;
}

state->num_buckets += weight;
state->num_servers++;
}


在持久化hash模式下,對應的是mmc_consistent_add_server函數:#define MMC_CONSISTENT_POINTS 160 / points per server /

void mmc_consistent_add_server(void s, mmc_t mmc, unsigned int weight) / {{{ /
{
mmc_consistent_state_t state = s;
int i, key_len, points = weight
MMC_CONSISTENT_POINTS;

/ buffer for "host:port-i\0" /
char key = emalloc(strlen(mmc->host) + MAX_LENGTH_OF_LONG 2 + 3);

/ add weight MMC_CONSISTENT_POINTS number of points for this server /
state->points = erealloc(state->points, sizeof(mmc_consistent_point_t)
(state->num_points + points));

// 將區塊內的server賦予當前服務器狀態,point賦予hash函數處理后的值
for (i=0; i<points; i++) {
key_len = sprintf(key, "%s:%d-%d", mmc->host, mmc->port, i);
state->points[state->num_points + i].server = mmc;
state->points[state->num_points + i].point = state->hash(key, key_len);
MMC_DEBUG(("mmc_consistent_add_server: key %s, point %lu", key, state->points[state->num_points + i].point));
}

state->num_points += points;
state->num_servers++;

// 新增加服務器后需重新計算buckets順序
state->buckets_populated = 0;

efree(key);
}


以上代碼有持久化hash算法的賦值實現,具體深入的了解請看Consistent hashing和國內大俠charlee翻譯的小日本的文章memcached全面剖析–PDF總結篇
Consistent hashing 算法最大的特點是當你的緩存服務器數量變更的時候,它能夠最大化的保留原有的緩存不變,而不需要重新分布原有緩存的服務器位置。
至此,整個memcache_add_server流程結束。
3. 向緩存服務器保存數據
對應PHP的代碼:$mmc->set('key', 'value');


由上面的分析可知,set方法對應的是memcache_set函數:/ {{{ proto bool memcache_set( object memcache, string key, mixed var [, int flag [, int expire ] ] )
Sets the value of an item. Item may exist or not
/
PHP_FUNCTION(memcache_set)
{
// Memcache對象中的add,set和replace皆會走該函數
php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, "set", sizeof("set") - 1);
}


看php_mmc_store函數:static void php_mmc_store(INTERNAL_FUNCTION_PARAMETERS, char command, int command_len) / {{{ /
{
mmc_pool_t
pool;
......
// 獲得pool
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
RETURN_FALSE;
}
// 對不同的存儲的值類型進行不同的處理
switch (Z_TYPE_P(value)) {
// 字符串類型
case IS_STRING:
result = mmc_pool_store(
pool, command, command_len, key_tmp, key_tmp_len, flags, expire,
Z_STRVAL_P(value), Z_STRLEN_P(value) TSRMLS_CC);
break;
// 長整型,浮點型,布爾型
case IS_LONG:
case IS_DOUBLE:
case IS_BOOL: {
......
result = mmc_pool_store(
pool, command, command_len, key_tmp, key_tmp_len, flags, expire,
Z_STRVAL(value_copy), Z_STRLEN(value_copy) TSRMLS_CC);

zval_dtor(&value_copy);
break;
}
// 默認為數組類型
default: {
......
result = mmc_pool_store(
pool, command, command_len, key_tmp, key_tmp_len, flags, expire,
buf.c, buf.len TSRMLS_CC);
}
}
......
}


由上代碼可以看出,存儲數據主要是交由mmc_pool_store處理:int mmc_pool_store(mmc_pool_t pool, const char command, int command_len, const char key, int key_len, int flags, int expire, const char value, int value_len TSRMLS_DC) / {{{ /
{
/ 該省略過程處理數據壓縮,處理待發送的請求數據 /
......

// 通過key確定待保存的服務器
while (result < 0 && (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) {
// 向緩存服務器發送請求,保存數據
if ((result = mmc_server_store(mmc, request, request_len TSRMLS_CC)) < 0) {
mmc_server_failure(mmc TSRMLS_CC);
}
}

if (key_copy != NULL) {
efree(key_copy);
}
if (data != NULL) {
efree(data);
}
efree(request);
return result;
}


接著我們看下mmc_pool_find是處理的#define mmc_pool_find(pool, key, key_len) \
pool->hash->find_server(pool->hash_state, key, key_len)


原來是再次多態調用了find_server函數,由之前的分析可以得知find_server在標準hash模式中的函數為 mmc_standard_find_server,在持久化hash模式中的函數為mmc_consistent_find_server,一樣先看 mmc_standard_find_servermmc_t mmc_standard_find_server(void s, const char key, int key_len TSRMLS_DC) / {{{ /
{
mmc_standard_state_t
state = s;
mmc_t mmc;

if (state->num_servers > 1) {
// 用設定的hash函數算法,找到對應的服務器
unsigned int hash = mmc_hash(state, key, key_len), i;
mmc = state->buckets[hash % state->num_buckets];

// 如果獲取到的服務器狀態有問題,則重新hash遍歷尋找到可用的緩存服務器為止
for (i=0; !mmc_open(mmc, 0, NULL, NULL TSRMLS_CC) && MEMCACHE_G(allow_failover) && i<MEMCACHE_G(max_failover_attempts); i++) {
char
next_key = emalloc(key_len + MAX_LENGTH_OF_LONG + 1);
int next_len = sprintf(next_key, "%d%s", i+1, key);
MMC_DEBUG(("mmc_standard_find_server: failed to connect to server '%s:%d' status %d, trying next", mmc->host, mmc->port, mmc->status));

hash += mmc_hash(state, next_key, next_len);
mmc = state->buckets[hash % state->num_buckets];

efree(next_key);
}
}
else {
mmc = state->buckets[0];
mmc_open(mmc, 0, NULL, NULL TSRMLS_CC);
}

return mmc->status != MMC_STATUS_FAILED ? mmc : NULL;
}


再看mmc_consistent_find_servermmc_t mmc_consistent_find_server(void s, const char key, int key_len TSRMLS_DC) / {{{ /
{
mmc_consistent_state_t
state = s;
mmc_t mmc;

if (state->num_servers > 1) {
unsigned int i, hash = state->hash(key, key_len);
// 如果哈希桶沒有進行過排序,則進行圓環排序操作
if (!state->buckets_populated) {
mmc_consistent_populate_buckets(state);
}
mmc = state->buckets[hash % MMC_CONSISTENT_BUCKETS];

// 如果獲取到的服務器狀態有問題,則重新hash遍歷尋找到可用的緩存服務器為止
for (i=0; !mmc_open(mmc, 0, NULL, NULL TSRMLS_CC) && MEMCACHE_G(allow_failover) && i<MEMCACHE_G(max_failover_attempts); i++) {
char
next_key = emalloc(key_len + MAX_LENGTH_OF_LONG + 1);
int next_len = sprintf(next_key, "%s-%d", key, i);
MMC_DEBUG(("mmc_consistent_find_server: failed to connect to server '%s:%d' status %d, trying next", mmc->host, mmc->port, mmc->status));

hash = state->hash(next_key, next_len);
mmc = state->buckets[hash % MMC_CONSISTENT_BUCKETS];

efree(next_key);
}
}
else {
mmc = state->points[0].server;
mmc_open(mmc, 0, NULL, NULL TSRMLS_CC);
}

return mmc->status != MMC_STATUS_FAILED ? mmc : NULL;
}
// 持久化哈希算法的核心部分
static void mmc_consistent_populate_buckets(mmc_consistent_state_t state) / {{{ /
{
unsigned int z, step = 0xffffffff / MMC_CONSISTENT_BUCKETS;

qsort((void
)state->points, state->num_points, sizeof(mmc_consistent_point_t), mmc_consistent_compare);
for (z=0; z<MMC_CONSISTENT_BUCKETS; z++) {
state->buckets[z] = mmc_consistent_find(state, step z);
}

state->buckets_populated = 1;
}
static int mmc_consistent_compare(const void
a, const void b) / {{{ /
{
if (((mmc_consistent_point_t
)a)->point < ((mmc_consistent_point_t )b)->point) {
return -1;
}
if (((mmc_consistent_point_t
)a)->point > ((mmc_consistent_point_t )b)->point) {
return 1;
}
return 0;
}
static mmc_t
mmc_consistent_find(mmc_consistent_state_t state, unsigned int point) / {{{ /
{
int lo = 0, hi = state->num_points - 1, mid;

while (1) {
/
point is outside interval or lo >= hi, wrap-around /
if (point <= state->points[lo].point || point > state->points[hi].point) {
return state->points[lo].server;
}

/
test middle point /
mid = lo + (hi - lo) / 2;
MMC_DEBUG(("mmc_consistent_find: lo %d, hi %d, mid %d, point %u, midpoint %u", lo, hi, mid, point, state->points[mid].point));

/
perfect match /
if (point <= state->points[mid].point && point > (mid ? state->points[mid-1].point : 0)) {
return state->points[mid].server;
}

/
too low, go up /
if (state->points[mid].point < point) {
lo = mid + 1;
}
else {
hi = mid - 1;
}
}
}


至此,memcache_set過程結束。
4. 向緩存服務器獲得已保存的數據
對應PHP的代碼:echo $mmc->get('key');


由上面的分析可知,get方法對應的是memcache_get函數:PHP_FUNCTION(memcache_get)
{
......
// 獲得pool
if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
RETURN_FALSE;
}
// 當key不為數組的情況下處理
if (Z_TYPE_P(zkey) != IS_ARRAY) {
// 檢查key的合法性
if (mmc_prepare_key(zkey, key, &key_len TSRMLS_CC) == MMC_OK) {
// 獲取key獲取value
if (mmc_exec_retrieval_cmd(pool, key, key_len, &return_value, flags TSRMLS_CC) < 0) {
zval_dtor(return_value);
RETVAL_FALSE;
}
}
else {
RETVAL_FALSE;
}
// 為數組的情況下處理
} else if (zend_hash_num_elements(Z_ARRVAL_P(zkey))){
//根據數據key獲取數組值
if (mmc_exec_retrieval_cmd_multi(pool, zkey, &return_value, flags TSRMLS_CC) < 0) {
zval_dtor(return_value);
RETVAL_FALSE;
}
} else {
RETVAL_FALSE;
}
}


接著看mmc_exec_retrieval_cmd和mmc_exec_retrieval_cmd_multi函數:int mmc_exec_retrieval_cmd(mmc_pool_t
pool, const char key, int key_len, zval **return_value, zval return_flags TSRMLS_DC) / {{{ /
{
mmc_t mmc;
char
command, value;
int result = -1, command_len, response_len, value_len, flags = 0;

MMC_DEBUG(("mmc_exec_retrieval_cmd: key '%s'", key));

command_len = spprintf(&command, 0, "get %s", key);
// 遍歷尋找到key對應的value值
while (result < 0 && (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) {
......
}

if (return_flags != NULL) {
zval_dtor(return_flags);
ZVAL_LONG(return_flags, flags);
}

efree(command);
return result;
}
static int mmc_exec_retrieval_cmd_multi(mmc_pool_t
pool, zval keys, zval **return_value, zval return_flags TSRMLS_DC) / {{{ /
{
......
do {
result_status = num_requests = 0;
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);

// 遍歷key得到所有key對應的服務器資源存入pool->requests中
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void *)&zkey, &pos) == SUCCESS) {
if (mmc_prepare_key(
zkey, key, &key_len TSRMLS_CC) == MMC_OK) {
/ schedule key if first round or if missing from result /
if ((!i || !zend_hash_exists(Z_ARRVAL_PP(return_value), key, key_len)) &&
// 根據key尋找到服務器
(mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) {
if (!(mmc->outbuf.len)) {
smart_str_appendl(&(mmc->outbuf), "get", sizeof("get")-1);
pool->requests[num_requests++] = mmc;
}

smart_str_appendl(&(mmc->outbuf), " ", 1);
smart_str_appendl(&(mmc->outbuf), key, key_len);
MMC_DEBUG(("mmc_exec_retrieval_cmd_multi: scheduled key '%s' for '%s:%d' request length '%d'", key, mmc->host, mmc->port, mmc->outbuf.len));
}
}

zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
}

......

} while (result_status < 0 && MEMCACHE_G(allow_failover) && i++ < MEMCACHE_G(max_failover_attempts));

......

return result_status;
}


由上可見分布式hash的核心函數皆為mmc_pool_find,首先找到key對應的服務器資源,然后根據服務器資源請求數據。
至此,memcache_get的過程結束。
5.向緩存服務器刪除已保存的數據
對應的php代碼:$mmc->delete('key');


由之前的分析可知,delete對應的為memcache_delete:/ {{{ proto bool memcache_delete( object memcache, string key [, int expire ])
Deletes existing item
/
PHP_FUNCTION(memcache_delete)
{
mmc_t mmc;
mmc_pool_t
pool;
int result = -1, key_len;
zval mmc_object = getThis();
char
key;
long time = 0;
char key_tmp[MMC_KEY_MAX_SIZE];
unsigned int key_tmp_len;

if (mmc_object == NULL) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &mmc_object, memcache_class_entry_ptr, &key, &key_len, &time) == FAILURE) {
return;
}
}
else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &key, &key_len, &time) == FAILURE) {
return;
}
}

if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) {
RETURN_FALSE;
}

if (mmc_prepare_key_ex(key, key_len, key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) {
RETURN_FALSE;
}

// 先獲得服務器資源
while (result < 0 && (mmc = mmc_pool_find(pool, key_tmp, key_tmp_len TSRMLS_CC)) != NULL) {
// 根據資源向緩存服務器發送請求刪除存儲的數據
if ((result = mmc_delete(mmc, key_tmp, key_tmp_len, time TSRMLS_CC)) < 0) {
mmc_server_failure(mmc TSRMLS_CC);
}
}

if (result > 0) {
RETURN_TRUE;
}
RETURN_FALSE;
}
/ }}} /


至此,memcache_delete過程結束。

來自:http://blog.liubijian.com/php_memcache_code_analysis.html

 本文由用戶 fmms 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!