@@ -48,6 +48,7 @@ static int php_memc_sess_lock(memcached_st *memc, const char *key TSRMLS_DC)
4848 char * lock_key = NULL ;
4949 int lock_key_len = 0 ;
5050 unsigned long attempts ;
51+ long write_retry_attempts = 0 ;
5152 long lock_maxwait ;
5253 long lock_wait = MEMC_G (sess_lock_wait );
5354 time_t expiration ;
@@ -64,6 +65,11 @@ static int php_memc_sess_lock(memcached_st *memc, const char *key TSRMLS_DC)
6465 expiration = time (NULL ) + lock_maxwait + 1 ;
6566 attempts = (unsigned long )((1000000.0 / lock_wait ) * lock_maxwait );
6667
68+ /* Set the number of write retry attempts to the number of replicas times the number of attempts to remove a server */
69+ if (MEMC_G (sess_remove_failed_enabled )) {
70+ write_retry_attempts = MEMC_G (sess_num_replicas ) * ( memcached_behavior_get (memc , MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT ) + 1 );
71+ }
72+
6773 lock_key_len = spprintf (& lock_key , 0 , "lock.%s" , key );
6874 do {
6975 status = memcached_add (memc , lock_key , lock_key_len , "1" , sizeof ("1" )- 1 , expiration , 0 );
@@ -73,6 +79,11 @@ static int php_memc_sess_lock(memcached_st *memc, const char *key TSRMLS_DC)
7379 MEMC_G (sess_lock_key_len ) = lock_key_len ;
7480 return 0 ;
7581 } else if (status != MEMCACHED_NOTSTORED && status != MEMCACHED_DATA_EXISTS ) {
82+ if (write_retry_attempts > 0 ) {
83+ write_retry_attempts -- ;
84+ continue ;
85+ }
86+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Write of lock failed" );
7687 break ;
7788 }
7889
@@ -195,6 +206,30 @@ PS_OPEN_FUNC(memcached)
195206 }
196207 }
197208
209+ if (MEMC_G (sess_consistent_hashing_enabled )) {
210+ if (memcached_behavior_set (memc_sess -> memc_sess , MEMCACHED_BEHAVIOR_KETAMA , (uint64_t ) 1 ) == MEMCACHED_FAILURE ) {
211+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "failed to set memcached consistent hashing" );
212+ return FAILURE ;
213+ }
214+ }
215+
216+ /* Allow libmemcached remove failed servers */
217+ if (MEMC_G (sess_remove_failed_enabled )) {
218+ if (memcached_behavior_set (memc_sess -> memc_sess , MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS , (uint64_t ) 1 ) == MEMCACHED_FAILURE ) {
219+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "failed to set: remove failed servers" );
220+ return FAILURE ;
221+ }
222+ }
223+
224+ /* Allow replicas section */
225+ long num_replicas = MEMC_G (sess_num_replicas );
226+ if (num_replicas > 0 ) {
227+ /* Set the number of replicas libmemcached will use */
228+ if (memcached_behavior_set (memc_sess -> memc_sess , MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS , (uint64_t ) num_replicas ) == MEMCACHED_FAILURE ) {
229+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "failed to set memcached client replicating" );
230+ return FAILURE ;
231+ }
232+ }
198233 return SUCCESS ;
199234 }
200235 }
@@ -243,6 +278,7 @@ PS_READ_FUNC(memcached)
243278
244279 if (MEMC_G (sess_locking_enabled )) {
245280 if (php_memc_sess_lock (memc_sess -> memc_sess , key TSRMLS_CC ) < 0 ) {
281+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Unable to clear session lock record" );
246282 return FAILURE ;
247283 }
248284 }
@@ -263,6 +299,7 @@ PS_WRITE_FUNC(memcached)
263299{
264300 int key_len = strlen (key );
265301 time_t expiration = 0 ;
302+ long write_try_attempts = 1 ;
266303 memcached_return status ;
267304 memcached_sess * memc_sess = PS_GET_MOD_DATA ();
268305 size_t key_length ;
@@ -277,13 +314,22 @@ PS_WRITE_FUNC(memcached)
277314 if (PS (gc_maxlifetime ) > 0 ) {
278315 expiration = PS (gc_maxlifetime );
279316 }
280- status = memcached_set (memc_sess -> memc_sess , key , key_len , val , vallen , expiration , 0 );
281317
282- if (status == MEMCACHED_SUCCESS ) {
283- return SUCCESS ;
284- } else {
285- return FAILURE ;
318+ /* Set the number of write retry attempts to the number of replicas times the number of attempts to remove a server plus the initial write */
319+ if (MEMC_G (sess_remove_failed_enabled )) {
320+ write_try_attempts = 1 + MEMC_G (sess_num_replicas ) * ( memcached_behavior_get (memc_sess -> memc_sess , MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT ) + 1 );
286321 }
322+
323+ do {
324+ status = memcached_set (memc_sess -> memc_sess , key , key_len , val , vallen , expiration , 0 );
325+ if (status == MEMCACHED_SUCCESS ) {
326+ return SUCCESS ;
327+ } else {
328+ write_try_attempts -- ;
329+ }
330+ } while (write_try_attempts > 0 );
331+
332+ return FAILURE ;
287333}
288334
289335PS_DESTROY_FUNC (memcached )
0 commit comments