phpとmemcachedサーバのインタラクティブな分散実装ソース分析[memcache版]

66873 ワード

この間、あるプロジェクトの関係でphpがmemcacheとmemcached PECL拡張ライブラリを呼び出すインタフェースを通じて分散キャッシュサーバに格納されるメカニズムを研究しました.ここでは、それぞれのソースコードに基づいて分析し、興味のある人に役立つことを望んでいます.
この文章ではphpとmemcache拡張ライブラリのインタラクションについてソースコードに基づいて分析を展開します.
PHPがmemcacheを呼び出すインタフェースは、通常、次の手順に従います.
 

   
   
   
   
  1. [cc lang="php"
  2. $mmc = new Memcache(); 
  3. $mmc->addServer(‘node1′, 11211); 
  4. $mmc->addServer(‘node2′, 11211, MemcacheConfig::MEMCACHE_PERSISTENT, 2); 
  5. $mmc->set(‘key’, ‘value’); 
  6. echo $mmc->get(‘key’); 
  7. $mmc->delete(‘key’); 
  8. [/cc] 

わずか数行のコードで、キャッシュキーのライフサイクルが完全に表示されます.Memcacheの初期化からaddServerに2つのサーバノードを追加し、1つのkeyをサーバにセットし、getをこのkeyに出力し、最後にdeleteというkeyにします.このライフサイクルの中で、Memcacheは底層でいったいどんなことをして、データストレージサーバーの均一な分布、データの完全性を保証しましたか?
次に、上記のライフサイクルの順序に従って、逐次漸進的に分析します(テーマは分布式アルゴリズムの分析なので、次に関係のないコードは省略します.多くの分析はソースコードに直接注釈します).
1.Memcacheの初期化
PHP対応コード:
 

   
   
   
   
  1. [cc lang="php"
  2. $mmc = new Memcache(); 
  3. [/cc] 

Cに対応するコード:
 

   
   
   
   
  1. [cc lang="c"
  2. // Memcache c , 。 。 
  3. static zend_function_entry php_memcache_class_functions[] = { 
  4. PHP_FALIAS(addserver, memcache_add_server, NULL) 
  5. PHP_FALIAS(set, memcache_set, NULL) 
  6. PHP_FALIAS(get, memcache_get, NULL) 
  7. PHP_FALIAS(delete, memcache_delete, NULL) 
  8. …… 
  9. }; 
  10. PHP_MINIT_FUNCTION(memcache) 
  11. //  Memcache , php  
  12. zend_class_entry memcache_class_entry; 
  13. INIT_CLASS_ENTRY(memcache_class_entry, "Memcache", php_memcache_class_functions); 
  14. memcache_class_entry_ptr = zend_register_internal_class(&memcache_class_entry TSRMLS_CC); 
  15. …… 
  16. [/cc] 

以上の過程はModule Initializationの一環ですでに完成しており,newの過程では残りの処理はない.
2.分散型ストレージとなるようにキャッシュサーバを追加
PHP対応コード:
 

   
   
   
   
  1. [cc lang="php"
  2. $mmc->addServer(‘node1′, 11211); 
  3. $mmc->addServer(‘node2′, 11211, MemcacheConfig::MEMCACHE_PERSISTENT, 2); 
  4. [/cc] 

上のphp_からmemcache_class_functions構造からaddServerメソッドはmemcache_に対応していることがわかる.add_server関数ですので、Cのコードに対応します.
 

   
   
   
   
  1. [cc lang="c"
  2. PHP_FUNCTION(memcache_add_server) 
  3. zval **connection, *mmc_object = getThis(), *failure_callback = NULL; 
  4. //  Memcache mmc_pool_t 
  5. mmc_pool_t *pool; 
  6. //   
  7. mmc_t *mmc; 
  8. …… 
  9. //  pool ,  
  10. if (zend_hash_find(Z_OBJPROP_P(mmc_object), "connection"sizeof("connection"), (void **) &connection) == FAILURE) { 
  11. //  mmp_pool_new  
  12. pool = mmc_pool_new(TSRMLS_C); 
  13. …… 
  14. else { 
  15. …… 
  16. // pool  
  17. mmc_pool_add(pool, mmc, weight); 
  18. RETURN_TRUE; 
  19. [/cc] 
  20. mmc_pool_t : 
  21. [cc lang="c"
  22. typedef struct mmc_pool { 
  23. mmc_t **servers; //   
  24. int num_servers; //   
  25. mmc_t **requests; //  get array key  
  26. int compress_threshold; //   
  27. double min_compress_savings; //   
  28. zend_bool in_free; //  pool  
  29. mmc_hash_t *hash; // hash  
  30. void *hash_state; // hash  
  31. } mmc_pool_t; 
  32. [/cc] 
  33. mmc_hash_t , : 
  34. [cc lang="c"
  35. //  , ,  
  36. typedef struct mmc_hash { 
  37. mmc_hash_create_state create_state; //  hash , hash  
  38. mmc_hash_free_state free_state; //  hash  
  39. mmc_hash_find_server find_server; //  key  
  40. mmc_hash_add_server add_server; //  hash 、  
  41. } mmc_hash_t; 
  42. [/cc] 

次にmemcacheを追跡しますadd_server関数のmmc_pool_new関数呼び出し方法:
 

   
   
   
   
  1. [cc lang="c"
  2. mmc_pool_t *mmc_pool_new(TSRMLS_D) /* {{{ */ 
  3. //   
  4. mmc_pool_t *pool = emalloc(sizeof(mmc_pool_t)); 
  5. pool->num_servers = 0; 
  6. pool->compress_threshold = 0; 
  7. pool->in_free = 0; 
  8. pool->min_compress_savings = MMC_DEFAULT_SAVINGS; 
  9. //   
  10. mmc_pool_init_hash(pool TSRMLS_CC); 
  11. return pool; 
  12. [/cc] 

初期化hashアルゴリズムが徐々に現れ、mmc_を追跡し続けている.pool_init_hash関数:

   
   
   
   
  1. [cc lang="c"
  2. static void mmc_pool_init_hash(mmc_pool_t *pool TSRMLS_DC) /* {{{ */ 
  3. mmc_hash_function hash; //  hash  
  4. //  php.ini memcache.hash_strategy hash , hash  
  5. switch (MEMCACHE_G(hash_strategy)) { 
  6. case MMC_CONSISTENT_HASH: 
  7. pool->hash = &mmc_consistent_hash; //  hash  
  8. break
  9. default
  10. pool->hash = &mmc_standard_hash; //  hash  
  11. //  php.ini memcache.hash_function hash , crc32  
  12. switch (MEMCACHE_G(hash_function)) { 
  13. case MMC_HASH_FNV1A: 
  14. hash = &mmc_hash_fnv1a; //  fnv1a  
  15. break
  16. default
  17. hash = &mmc_hash_crc32; //  crc32  
  18. // hash hash  
  19. pool->hash_state = pool->hash->create_state(hash); 
  20. [/cc] 

上の2つのswitchから分かるようにcreate_stateの場合、2つのポリシーが選択される可能性があり、次に入力されるhashパラメータにも2つの可能性があります.ここでは、標準hashストレージポリシーと対応する2つのhashアルゴリズムを分析してから、永続化hashポリシーを分析します.
まずmmc_を見てみましょうconsistent_hash構造:
 

   
   
   
   
  1. [cc lang="c"
  2. //  mmc_hash_t  
  3. mmc_hash_t mmc_standard_hash = { 
  4. mmc_standard_create_state, 
  5. mmc_standard_free_state, 
  6. mmc_standard_find_server, 
  7. mmc_standard_add_server 
  8. }; 
  9. [/cc] 

上から分かるようにpool->hash->create_stateの関数呼び出しは実際にはmmc_standard_create_stateの関数呼び出し、mmc_を見続けますstandard_create_state関数コードの実装:
 

   
   
   
   
  1. [cc lang="c"
  2. // hash  
  3. typedef struct mmc_standard_state { 
  4. int num_servers; //   
  5. mmc_t **buckets; //  ,  
  6. int num_buckets; //   
  7. mmc_hash_function hash; // hash  
  8. } mmc_standard_state_t; 
  9. void *mmc_standard_create_state(mmc_hash_function hash) /* {{{ */ 
  10. //   
  11. mmc_standard_state_t *state = emalloc(sizeof(mmc_standard_state_t)); 
  12. memset(state, 0, sizeof(mmc_standard_state_t)); 
  13. //  hash hash  
  14. state->hash = hash; 
  15. return state; 
  16. [/cc] 
  17. crc : 
  18. [cc lang="c"
  19. static unsigned int mmc_hash_crc32(const char *key, int key_len) /* CRC32 hash {{{ */ 
  20. unsigned int crc = ~0; 
  21. int i; 
  22. for (i=0; i CRC32(crc, key[i]); 
  23. return ~crc; 
  24. [/cc] 
  25. CRC32 Cyclic redundancy check 
  26. fnv : 
  27. [cc lang="c"
  28. /* 32 bit magic FNV-1a prime and init */ 
  29. #define FNV_32_PRIME 0×01000193 
  30. #define FNV_32_INIT 0x811c9dc5 
  31. static unsigned int mmc_hash_fnv1a(const char *key, int key_len) /* FNV-1a hash {{{ */ 
  32. unsigned int hval = FNV_32_INIT; 
  33. int i; 
  34. for (i=0; i hval ^= (unsigned int)key[i]; 
  35. hval *= FNV_32_PRIME; 
  36. return hval; 
  37. [/cc] 

具体的なfnvアルゴリズムの深い実現は参考にすることができる
Fowler–Noll–Vo hash function
 
最後にmmc_を見てみましょうconsistent_hash構造:
 

   
   
   
   
  1. [cc lang="c"
  2. mmc_hash_t mmc_consistent_hash = { 
  3. mmc_consistent_create_state, 
  4. mmc_consistent_free_state, 
  5. mmc_consistent_find_server, 
  6. mmc_consistent_add_server 
  7. }; 
  8. [/cc] 

同じ4つの関数で、対応するcreateを見てみましょう.stateのmmc_consistent_create_stateの実装:
 

   
   
   
   
  1. [cc lang="c"
  2. /* number of precomputed buckets, should be power of 2 */ 
  3. #define MMC_CONSISTENT_BUCKETS 1024 
  4. typedef struct mmc_consistent_point { 
  5. mmc_t *server; //   
  6. unsigned int point; //   
  7. } mmc_consistent_point_t; 
  8. typedef struct mmc_consistent_state { 
  9. int num_servers; //   
  10. mmc_consistent_point_t *points; //   
  11. int num_points; //   
  12. mmc_t *buckets[MMC_CONSISTENT_BUCKETS]; //   
  13. int buckets_populated; //   
  14. mmc_hash_function hash; // hash  
  15. } mmc_consistent_state_t; 
  16. void *mmc_consistent_create_state(mmc_hash_function hash) /* {{{ */ 
  17. //  state 
  18. mmc_consistent_state_t *state = emalloc(sizeof(mmc_consistent_state_t)); 
  19. memset(state, 0, sizeof(mmc_consistent_state_t)); 
  20. //  hash hash  
  21. state->hash = hash; 
  22. return state; 
  23. [/cc] 

これでmemcache_add_server中mmc_pool_new関数の流れが終わり、次にmmc_を見てみましょう.pool_add関数:
 

   
   
   
   
  1. [cc lang="c"
  2. void mmc_pool_add(mmc_pool_t *pool, mmc_t *mmc, unsigned int weight) /* {{{ */ 
  3. /* add server and a preallocated request pointer */ 
  4. if (pool->num_servers) { 
  5. pool->servers = erealloc(pool->servers, sizeof(mmc_t *) * (pool->num_servers + 1)); 
  6. pool->requests = erealloc(pool->requests, sizeof(mmc_t *) * (pool->num_servers + 1)); 
  7. else { 
  8. pool->servers = emalloc(sizeof(mmc_t *)); 
  9. pool->requests = emalloc(sizeof(mmc_t *)); 
  10. pool->servers[pool->num_servers] = mmc; 
  11. pool->num_servers++; 
  12. //  pool , add_server  
  13. pool->hash->add_server(pool->hash_state, mmc, weight); 
  14. [/cc] 
  15. add_server hash mmc_standard_add_server : 
  16. [cc lang="c"
  17. void mmc_standard_add_server(void *s, mmc_t *mmc, unsigned int weight) /* {{{ */ 
  18. mmc_standard_state_t *state = s; 
  19. int i; 
  20. //   
  21. if (state->num_buckets) { 
  22. state->buckets = erealloc(state->buckets, sizeof(mmc_t *) * (state->num_buckets + weight)); 
  23. else { 
  24. state->buckets = emalloc(sizeof(mmc_t *) * (weight)); 
  25. //   
  26. for (i=0; i buckets[state->num_buckets + i] = mmc; 
  27. state->num_buckets += weight; 
  28. state->num_servers++; 
  29. [/cc] 

永続化hashモードではmmc_に対応するconsistent_add_server関数:
 

   
   
   
   
  1. [cc lang="c"
  2. #define MMC_CONSISTENT_POINTS 160 /* points per server */ 
  3. void mmc_consistent_add_server(void *s, mmc_t *mmc, unsigned int weight) /* {{{ */ 
  4. mmc_consistent_state_t *state = s; 
  5. int i, key_len, points = weight * MMC_CONSISTENT_POINTS; 
  6. /* buffer for "host:port-i\0" */ 
  7. char *key = emalloc(strlen(mmc->host) + MAX_LENGTH_OF_LONG * 2 + 3); 
  8. /* add weight * MMC_CONSISTENT_POINTS number of points for this server */ 
  9. state->points = erealloc(state->points, sizeof(mmc_consistent_point_t) * (state->num_points + points)); 
  10. //  server ,point hash  
  11. for (i=0; i key_len = sprintf(key, "%s:%d-%d", mmc->host, mmc->port, i); 
  12. state->points[state->num_points + i].server = mmc; 
  13. state->points[state->num_points + i].point = state->hash(key, key_len); 
  14. MMC_DEBUG(("mmc_consistent_add_server: key %s, point %lu", key, state->points[state->num_points + i].point)); 
  15. state->num_points += points; 
  16. state->num_servers++; 
  17. //  buckets  
  18. state->buckets_populated = 0; 
  19. efree(key); 
  20. [/cc] 

以上のコードは永続化hashアルゴリズムの賦値実現があり、具体的にはConsistent hashingと国内の大侠charlee翻訳の小日本の文章memcached全面剖析–PDF総括編を参照してください.
Consistent hashingアルゴリズムの最大の特徴は、キャッシュ・サーバの数が変更された場合、既存のキャッシュを再分散する必要がなく、既存のキャッシュをそのまま保持できることです.
これでmemcache全体がadd_serverプロセスが終了しました.
3.キャッシュサーバへのデータ保存
PHP対応コード:
 

   
   
   
   
  1. [cc lang="php"
  2. $mmc->set(‘key’, ‘value’); 
  3. [/cc] 
  4. ,set memcache_set : 
  5. [cc lang="c"
  6. /* {{{ proto bool memcache_set( object memcache, string key, mixed var [, int flag [, int expire ] ] ) 
  7. Sets the value of an item. Item may exist or not */ 
  8. PHP_FUNCTION(memcache_set) 
  9. // Memcache add,set replace  
  10. php_mmc_store(INTERNAL_FUNCTION_PARAM_PASSTHRU, "set", sizeof("set") – 1); 
  11. [/cc] 

php_を見てmmc_store関数:
 

   
   
   
   
  1. [cc lang="c"
  2. static void php_mmc_store(INTERNAL_FUNCTION_PARAMETERS, char *command, int command_len) /* {{{ */ 
  3. mmc_pool_t *pool; 
  4. …… 
  5. //  pool 
  6. if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) { 
  7. RETURN_FALSE; 
  8. //   
  9. switch (Z_TYPE_P(value)) { 
  10. //   
  11. case IS_STRING: 
  12. result = mmc_pool_store( 
  13. pool, command, command_len, key_tmp, key_tmp_len, flags, expire, 
  14. Z_STRVAL_P(value), Z_STRLEN_P(value) TSRMLS_CC); 
  15. break
  16. //  , ,  
  17. case IS_LONG: 
  18. case IS_DOUBLE: 
  19. case IS_BOOL: { 
  20. …… 
  21. result = mmc_pool_store( 
  22. pool, command, command_len, key_tmp, key_tmp_len, flags, expire, 
  23. Z_STRVAL(value_copy), Z_STRLEN(value_copy) TSRMLS_CC); 
  24. zval_dtor(&value_copy); 
  25. break
  26. //   
  27. default: { 
  28. …… 
  29. result = mmc_pool_store( 
  30. pool, command, command_len, key_tmp, key_tmp_len, flags, expire, 
  31. buf.c, buf.len TSRMLS_CC); 
  32. …… 
  33. [/cc] 

上のコードから分かるように、格納データは主にmmc_に渡されている.pool_store処理:
 

   
   
   
   
  1. [cc lang="c"
  2. 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) /* {{{ */ 
  3. /*  ,  */ 
  4. …… 
  5. //  key  
  6. while (result < 0 && (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) { 
  7. //  ,  
  8. if ((result = mmc_server_store(mmc, request, request_len TSRMLS_CC)) < 0) { 
  9. mmc_server_failure(mmc TSRMLS_CC); 
  10. if (key_copy != NULL) { 
  11. efree(key_copy); 
  12. if (data != NULL) { 
  13. efree(data); 
  14. efree(request); 
  15. return result; 
  16. [/cc] 

次にmmc_を見てみましょうpool_findは処理されています
 

   
   
   
   
  1. [cc lang="c"
  2. #define mmc_pool_find(pool, key, key_len) \ 
  3. pool->hash->find_server(pool->hash_state, key, key_len) 
  4. [/cc] 

再びマルチステート呼び出しfind_server関数、前の分析からfind_がわかりますserverの標準hashモードでの関数はmmc_standard_find_server、持続化hashモードでの関数はmmc_consistent_find_server、同じようにmmc_を先に見ますstandard_find_server
 

   
   
   
   
  1. [cc lang="c"
  2. mmc_t *mmc_standard_find_server(void *s, const char *key, int key_len TSRMLS_DC) /* {{{ */ 
  3. mmc_standard_state_t *state = s; 
  4. mmc_t *mmc; 
  5. if (state->num_servers > 1) { 
  6. //  hash ,  
  7. unsigned int hash = mmc_hash(state, key, key_len), i; 
  8. mmc = state->buckets[hash % state->num_buckets]; 
  9. //  , hash  
  10. for (i=0; !mmc_open(mmc, 0, NULL, NULL TSRMLS_CC) && MEMCACHE_G(allow_failover) && i char *next_key = emalloc(key_len + MAX_LENGTH_OF_LONG + 1); 
  11. int next_len = sprintf(next_key, "%d%s", i+1, key); 
  12. MMC_DEBUG(("mmc_standard_find_server: failed to connect to server '%s:%d' status %d, trying next", mmc->host, mmc->port, mmc->status)); 
  13. hash += mmc_hash(state, next_key, next_len); 
  14. mmc = state->buckets[hash % state->num_buckets]; 
  15. efree(next_key); 
  16. else { 
  17. mmc = state->buckets[0]; 
  18. mmc_open(mmc, 0, NULL, NULL TSRMLS_CC); 
  19. return mmc->status != MMC_STATUS_FAILED ? mmc : NULL; 
  20. [/cc] 

mmc_を見てconsistent_find_server
 

   
   
   
   
  1. [cc lang="c"
  2. mmc_t *mmc_consistent_find_server(void *s, const char *key, int key_len TSRMLS_DC) /* {{{ */ 
  3. mmc_consistent_state_t *state = s; 
  4. mmc_t *mmc; 
  5. if (state->num_servers > 1) { 
  6. unsigned int i, hash = state->hash(key, key_len); 
  7. //  ,  
  8. if (!state->buckets_populated) { 
  9. mmc_consistent_populate_buckets(state); 
  10. mmc = state->buckets[hash % MMC_CONSISTENT_BUCKETS]; 
  11. //  , hash  
  12. for (i=0; !mmc_open(mmc, 0, NULL, NULL TSRMLS_CC) && MEMCACHE_G(allow_failover) && i char *next_key = emalloc(key_len + MAX_LENGTH_OF_LONG + 1); 
  13. int next_len = sprintf(next_key, "%s-%d", key, i); 
  14. MMC_DEBUG(("mmc_consistent_find_server: failed to connect to server '%s:%d' status %d, trying next", mmc->host, mmc->port, mmc->status)); 
  15. hash = state->hash(next_key, next_len); 
  16. mmc = state->buckets[hash % MMC_CONSISTENT_BUCKETS]; 
  17. efree(next_key); 
  18. else { 
  19. mmc = state->points[0].server; 
  20. mmc_open(mmc, 0, NULL, NULL TSRMLS_CC); 
  21. return mmc->status != MMC_STATUS_FAILED ? mmc : NULL; 
  22. //   
  23. static void mmc_consistent_populate_buckets(mmc_consistent_state_t *state) /* {{{ */ 
  24. unsigned int i, step = 0xffffffff / MMC_CONSISTENT_BUCKETS; 
  25. qsort((void *)state->points, state->num_points, sizeof(mmc_consistent_point_t), mmc_consistent_compare); 
  26. for (i=0; i state->buckets[i] = mmc_consistent_find(state, step * i); 
  27. state->buckets_populated = 1; 
  28. static int mmc_consistent_compare(const void *a, const void *b) /* {{{ */ 
  29. if (((mmc_consistent_point_t *)a)->point < ((mmc_consistent_point_t *)b)->point) { 
  30. return -1; 
  31. if (((mmc_consistent_point_t *)a)->point > ((mmc_consistent_point_t *)b)->point) { 
  32. return 1; 
  33. return 0; 
  34. static mmc_t *mmc_consistent_find(mmc_consistent_state_t *state, unsigned int point) /* {{{ */ 
  35. int lo = 0, hi = state->num_points – 1, mid; 
  36. while (1) { 
  37. /* point is outside interval or lo >= hi, wrap-around */ 
  38. if (point <= state->points[lo].point || point > state->points[hi].point) { 
  39. return state->points[lo].server; 
  40. /* test middle point */ 
  41. mid = lo + (hi – lo) / 2; 
  42. MMC_DEBUG(("mmc_consistent_find: lo %d, hi %d, mid %d, point %u, midpoint %u", lo, hi, mid, point, state->points[mid].point)); 
  43. /* perfect match */ 
  44. if (point <= state->points[mid].point && point > (mid ? state->points[mid-1].point : 0)) { 
  45. return state->points[mid].server; 
  46. /* too low, go up */ 
  47. if (state->points[mid].point < point) { 
  48. lo = mid + 1; 
  49. else { 
  50. hi = mid - 1; 
  51. [/cc] 

これでmemcache_setプロセスが終了します.
4.保存したデータをキャッシュサーバに取得する
PHP対応コード:
 

   
   
   
   
  1. [cc lang="php"
  2. echo $mmc->get(‘key’); 
  3. [/cc] 

以上の解析から,getメソッドはmemcache_に対応することが分かった.get関数:
 

   
   
   
   
  1. [cc lang="php"
  2. PHP_FUNCTION(memcache_get) 
  3. …… 
  4. //  pool 
  5. if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) { 
  6. RETURN_FALSE; 
  7. //  key  
  8. if (Z_TYPE_P(zkey) != IS_ARRAY) { 
  9. //  key  
  10. if (mmc_prepare_key(zkey, key, &key_len TSRMLS_CC) == MMC_OK) { 
  11. //  key value 
  12. if (mmc_exec_retrieval_cmd(pool, key, key_len, &return_value, flags TSRMLS_CC) < 0) { 
  13. zval_dtor(return_value); 
  14. RETVAL_FALSE; 
  15. else { 
  16. RETVAL_FALSE; 
  17. //   
  18. else if (zend_hash_num_elements(Z_ARRVAL_P(zkey))){ 
  19. // key  
  20. if (mmc_exec_retrieval_cmd_multi(pool, zkey, &return_value, flags TSRMLS_CC) < 0) { 
  21. zval_dtor(return_value); 
  22. RETVAL_FALSE; 
  23. else { 
  24. RETVAL_FALSE; 
  25. [/cc] 

次にmmc_を見てexec_retrieval_cmdとmmc_exec_retrieval_cmd_Multi関数:
 

   
   
   
   
  1. [cc lang="c"
  2. int mmc_exec_retrieval_cmd(mmc_pool_t *pool, const char *key, int key_len, zval **return_value, zval *return_flags TSRMLS_DC) /* {{{ */ 
  3. mmc_t *mmc; 
  4. char *command, *value; 
  5. int result = -1, command_len, response_len, value_len, flags = 0; 
  6. MMC_DEBUG(("mmc_exec_retrieval_cmd: key '%s'", key)); 
  7. command_len = spprintf(&command, 0, "get %s", key); 
  8. //  key value  
  9. while (result < 0 && (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) { 
  10. ...... 
  11. if (return_flags != NULL) { 
  12. zval_dtor(return_flags); 
  13. ZVAL_LONG(return_flags, flags); 
  14. efree(command); 
  15. return result; 
  16. static int mmc_exec_retrieval_cmd_multi(mmc_pool_t *pool, zval *keys, zval **return_value, zval *return_flags TSRMLS_DC) /* {{{ */ 
  17. ...... 
  18. do { 
  19. result_status = num_requests = 0; 
  20. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos); 
  21. //  key key pool->requests  
  22. while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&zkey, &pos) == SUCCESS) { 
  23. if (mmc_prepare_key(*zkey, key, &key_len TSRMLS_CC) == MMC_OK) { 
  24. /* schedule key if first round or if missing from result */ 
  25. if ((!i || !zend_hash_exists(Z_ARRVAL_PP(return_value), key, key_len)) && 
  26. //  key  
  27. (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) { 
  28. if (!(mmc->outbuf.len)) { 
  29. smart_str_appendl(&(mmc->outbuf), "get"sizeof("get")-1); 
  30. pool->requests[num_requests++] = mmc; 
  31. smart_str_appendl(&(mmc->outbuf), " ", 1); 
  32. smart_str_appendl(&(mmc->outbuf), key, key_len); 
  33. MMC_DEBUG(("mmc_exec_retrieval_cmd_multi: scheduled key ‘%s’ for ‘%s:%d’ request length ‘%d’", key, mmc->host, mmc->port, mmc->outbuf.len)); 
  34. zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos); 
  35. …… 
  36. while (result_status < 0 && MEMCACHE_G(allow_failover) && i++ < MEMCACHE_G(max_failover_attempts)); 
  37. ...... 
  38. return result_status; 
  39. [/cc] 

上から見える分布式hashのコア関数はすべてmmc_pool_findは、まずkeyに対応するサーバリソースを見つけ、サーバリソースに基づいてデータを要求します.
これでmemcache_getのプロセスは終了します.
5.保存したデータをキャッシュサーバに削除する
対応するphpコード:
 

   
   
   
   
  1. [cc lang="php"
  2. $mmc->delete(‘key’); 
  3. [/cc] 

以前の解析からdeleteはmemcache_に対応することが分かった.delete:
 

   
   
   
   
  1. [cc lang="c"
  2. /* {{{ proto bool memcache_delete( object memcache, string key [, int expire ]) 
  3. Deletes existing item */ 
  4. PHP_FUNCTION(memcache_delete) 
  5. mmc_t *mmc; 
  6. mmc_pool_t *pool; 
  7. int result = -1, key_len; 
  8. zval *mmc_object = getThis(); 
  9. char *key; 
  10. long time = 0; 
  11. char key_tmp[MMC_KEY_MAX_SIZE]; 
  12. unsigned int key_tmp_len; 
  13. if (mmc_object == NULL) { 
  14. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &mmc_object, memcache_class_entry_ptr, &key, &key_len, &time) == FAILURE) { 
  15. return
  16. else { 
  17. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &key, &key_len, &time) == FAILURE) { 
  18. return
  19. if (!mmc_get_pool(mmc_object, &pool TSRMLS_CC) || !pool->num_servers) { 
  20. RETURN_FALSE; 
  21. if (mmc_prepare_key_ex(key, key_len, key_tmp, &key_tmp_len TSRMLS_CC) != MMC_OK) { 
  22. RETURN_FALSE; 
  23. //   
  24. while (result < 0 && (mmc = mmc_pool_find(pool, key_tmp, key_tmp_len TSRMLS_CC)) != NULL) { 
  25. //   
  26. if ((result = mmc_delete(mmc, key_tmp, key_tmp_len, time TSRMLS_CC)) < 0) { 
  27. mmc_server_failure(mmc TSRMLS_CC); 
  28. if (result > 0) { 
  29. RETURN_TRUE; 
  30. RETURN_FALSE; 
  31. /* }}} */ 
  32. [/cc] 

これでmemcache_deleteプロセスが終了しました.
当サイトの文章はすべて転載して、出典:http://blog.liubijian.com/php_memcache_code_analysis.html
... other posts by lbj