マルチスレッドなmemcachedのincrが想定通り動かない時がある件についてです。
A:memcached 1.4.4に以下のパッチを適用
*** memcached.c_org 2009-11-27 14:45:13.000000000 +0900 --- memcached.c 2010-03-30 21:03:08.000000000 +0900 *************** *** 54,59 **** --- 54,60 ---- #endif #endif + pthread_mutex_t test_lock = PTHREAD_MUTEX_INITIALIZER; /* * forward declarations */ *************** *** 1017,1022 **** --- 1018,1024 ---- req->message.body.expiration); } + pthread_mutex_lock(&test_lock); it = item_get(key, nkey); if (it && (c->binary_header.request.cas == 0 || c->binary_header.request.cas == ITEM_get_cas(it))) { *************** *** 1082,1087 **** --- 1084,1090 ---- write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, 0); } + pthread_mutex_unlock(&test_lock); } static void complete_update_bin(conn *c) {
B:frsyukiさんの検証プログラムに以下のパッチを適用
*** test.c_org 2010-03-30 21:08:36.000000000 +0900 --- test.c 2010-03-30 21:08:56.000000000 +0900 *************** *** 8,14 **** const char* g_host = "127.0.0.1"; unsigned short g_port = 11211; ! bool g_binary = false; const char* g_key = "test"; size_t g_key_len = 4; --- 8,14 ---- const char* g_host = "127.0.0.1"; unsigned short g_port = 11211; ! bool g_binary = true; const char* g_key = "test"; size_t g_key_len = 4;
AなしBなし
$ while true; do ./test_ascii; done expected: 100000 result: 100000 expected: 100000 result: 99960 expected: 100000 result: 100000 expected: 100000 result: 99998
AありBなし
$ while true; do ./test_ascii; done expected: 100000 result: 99976 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 99997
AなしBあり
$ while true; do ./test_binary; done expected: 100000 result: 99998 expected: 100000 result: 100000 expected: 100000 result: 99985 expected: 100000 result: 100000
AありBあり
$ while true; do ./test_binary; done expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000 expected: 100000 result: 100000
いかがでしょう?
2010/03/31追記
ASCIIプロトコルについても修正しました。手元の環境ではAありBなしでも正しく動いています。
*** memcached.c_org 2009-11-27 14:45:13.000000000 +0900 --- memcached.c 2010-03-31 01:29:22.000000000 +0900 *************** *** 54,59 **** --- 54,60 ---- #endif #endif + pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER; /* * forward declarations */ *************** *** 1017,1022 **** --- 1018,1024 ---- req->message.body.expiration); } + pthread_mutex_lock(&incr_lock); it = item_get(key, nkey); if (it && (c->binary_header.request.cas == 0 || c->binary_header.request.cas == ITEM_get_cas(it))) { *************** *** 1082,1087 **** --- 1084,1090 ---- write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, 0); } + pthread_mutex_unlock(&incr_lock); } static void complete_update_bin(conn *c) { *************** *** 2780,2785 **** --- 2783,2789 ---- return; } + pthread_mutex_lock(&incr_lock); it = item_get(key, nkey); if (!it) { pthread_mutex_lock(&c->thread->stats.mutex); *************** *** 2791,2796 **** --- 2795,2801 ---- pthread_mutex_unlock(&c->thread->stats.mutex); out_string(c, "NOT_FOUND"); + pthread_mutex_unlock(&incr_lock); return; } *************** *** 2806,2811 **** --- 2811,2817 ---- break; } item_remove(it); /* release our reference */ + pthread_mutex_unlock(&incr_lock); } /*
ここまでの内容をまとめてコミュニティに報告しました。
Issue 127 - memcached - incr/decr operations are not thread safe. - Project Hosting on Google Code