@@ -146,6 +146,12 @@ static void assoc_expand(void) {
146146static void assoc_start_expand (void ) {
147147 if (started_expanding )
148148 return ;
149+
150+ /*With this condition, we can expanding holding only one item lock,
151+ * and it should always be false*/
152+ if (item_lock_hashpower >= hashpower )
153+ return ;
154+
149155 started_expanding = true;
150156 pthread_cond_signal (& maintenance_cond );
151157}
@@ -206,54 +212,57 @@ static void *assoc_maintenance_thread(void *arg) {
206212 while (do_run_maintenance_thread ) {
207213 int ii = 0 ;
208214
209- /* Lock the cache, and bulk move multiple buckets to the new
210- * hash table. */
211- item_lock_global ();
212- mutex_lock (& cache_lock );
213-
215+ /* As there is only one thread process expanding, and we hold the item
216+ * lock, it seems not necessary to hold the cache_lock . */
214217 for (ii = 0 ; ii < hash_bulk_move && expanding ; ++ ii ) {
215218 item * it , * next ;
216219 int bucket ;
217-
218- for (it = old_hashtable [expand_bucket ]; NULL != it ; it = next ) {
219- next = it -> h_next ;
220-
221- bucket = hash (ITEM_key (it ), it -> nkey ) & hashmask (hashpower );
222- it -> h_next = primary_hashtable [bucket ];
223- primary_hashtable [bucket ] = it ;
220+ void * item_lock = NULL ;
221+
222+ /* bucket = hv & hashmask(hashpower) =>the bucket of hash table
223+ * is the lowest N bits of the hv, and the bucket of item_locks is
224+ * also the lowest M bits of hv, and N is greater than M.
225+ * So we can process expanding with only one item_lock. cool! */
226+ /*Get item lock for the slot in old hashtable*/
227+ if ((item_lock = item_trylock (expand_bucket ))) {
228+ for (it = old_hashtable [expand_bucket ]; NULL != it ; it = next ) {
229+ next = it -> h_next ;
230+ bucket = hash (ITEM_key (it ), it -> nkey ) & hashmask (hashpower );
231+ it -> h_next = primary_hashtable [bucket ];
232+ primary_hashtable [bucket ] = it ;
233+ }
234+
235+ old_hashtable [expand_bucket ] = NULL ;
236+
237+ expand_bucket ++ ;
238+ if (expand_bucket == hashsize (hashpower - 1 )) {
239+ expanding = false;
240+ free (old_hashtable );
241+ STATS_LOCK ();
242+ stats .hash_bytes -= hashsize (hashpower - 1 ) * sizeof (void * );
243+ stats .hash_is_expanding = 0 ;
244+ STATS_UNLOCK ();
245+ if (settings .verbose > 1 )
246+ fprintf (stderr , "Hash table expansion done\n" );
247+ }
248+
249+ } else {
250+ /*wait for 100ms. since only one expanding thread, it's not
251+ * necessary to sleep a random value*/
252+ usleep (100 * 1000 );
224253 }
225254
226- old_hashtable [expand_bucket ] = NULL ;
227-
228- expand_bucket ++ ;
229- if (expand_bucket == hashsize (hashpower - 1 )) {
230- expanding = false;
231- free (old_hashtable );
232- STATS_LOCK ();
233- stats .hash_bytes -= hashsize (hashpower - 1 ) * sizeof (void * );
234- stats .hash_is_expanding = 0 ;
235- STATS_UNLOCK ();
236- if (settings .verbose > 1 )
237- fprintf (stderr , "Hash table expansion done\n" );
255+ if (item_lock ) {
256+ item_trylock_unlock (item_lock );
257+ item_lock = NULL ;
238258 }
239259 }
240260
241- mutex_unlock (& cache_lock );
242- item_unlock_global ();
243-
244261 if (!expanding ) {
245- /* finished expanding. tell all threads to use fine-grained locks */
246- switch_item_lock_type (ITEM_LOCK_GRANULAR );
247- slabs_rebalancer_resume ();
248262 /* We are done expanding.. just wait for next invocation */
249263 mutex_lock (& cache_lock );
250264 started_expanding = false;
251265 pthread_cond_wait (& maintenance_cond , & cache_lock );
252- /* Before doing anything, tell threads to use a global lock */
253- mutex_unlock (& cache_lock );
254- slabs_rebalancer_pause ();
255- switch_item_lock_type (ITEM_LOCK_GLOBAL );
256- mutex_lock (& cache_lock );
257266 assoc_expand ();
258267 mutex_unlock (& cache_lock );
259268 }
0 commit comments