@@ -1712,7 +1712,7 @@ pgsm_store(pgsmEntry *entry)
17121712
17131713 pgsm = pgsm_get_ss ();
17141714
1715- prev_bucket_id = pg_atomic_read_u64 (& pgsm -> current_wbucket );
1715+ prev_bucket_id = pg_atomic_read_u64 (& pgsm -> current_bucket );
17161716 bucketid = get_next_wbucket (pgsm );
17171717
17181718 if (bucketid != prev_bucket_id )
@@ -2405,7 +2405,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
24052405 values [i ++ ] = BoolGetDatum (toplevel );
24062406
24072407 /* bucket_done at column number 72 */
2408- values [i ++ ] = BoolGetDatum (pg_atomic_read_u64 (& pgsm -> current_wbucket ) != bucketid );
2408+ values [i ++ ] = BoolGetDatum (pg_atomic_read_u64 (& pgsm -> current_bucket ) != bucketid );
24092409
24102410 /* clean up and return the tuplestore */
24112411 tuplestore_putvalues (tupstore , tupdesc , values , nulls );
@@ -2423,64 +2423,45 @@ static uint64
24232423get_next_wbucket (pgsmSharedState * pgsm )
24242424{
24252425 struct timeval tv ;
2426- uint64 current_bucket_sec ;
2427- bool update_bucket = false ;
2426+ uint64 new_bucket_start ;
2427+ uint64 new_bucket_id ;
24282428
24292429 gettimeofday (& tv , NULL );
2430- current_bucket_sec = pg_atomic_read_u64 (& pgsm -> prev_bucket_sec );
2430+
2431+ new_bucket_start = (tv .tv_sec / pgsm_bucket_time ) * (uint64 ) pgsm_bucket_time ;
24312432
24322433 /*
2433- * If current bucket expired we loop attempting to update prev_bucket_sec.
2434- *
2435- * pg_atomic_compare_exchange_u64 may fail in two possible ways: 1.
2436- * Another thread/process updated the variable before us. 2. A spurious
2437- * failure / hardware event.
2434+ * If current bucket expired we loop attempting to update current_bucket_sec.
24382435 *
2439- * In both failure cases we read prev_bucket_sec from memory again, if it
2440- * was a spurious failure then the value of prev_bucket_sec must be the
2441- * same as before, which will cause the while loop to execute again.
2436+ * If another thread updated current_bucket_sec, then use the new bucket
2437+ * created by that thread.
24422438 *
2443- * If another thread updated prev_bucket_sec, then its current value will
2444- * definitely make the while condition to fail, we can stop the loop as
2445- * another thread has already updated prev_bucket_sec.
2439+ * XXX: This code looks potentially racy, especially if we skip buckets.
24462440 */
2447- while ((tv .tv_sec - (uint ) current_bucket_sec ) >= ((uint ) pgsm_bucket_time ))
2448- {
2449- if (pg_atomic_compare_exchange_u64 (& pgsm -> prev_bucket_sec , & current_bucket_sec , (uint64 ) tv .tv_sec ))
2450- {
2451- update_bucket = true;
2452- break ;
2453- }
2454-
2455- current_bucket_sec = pg_atomic_read_u64 (& pgsm -> prev_bucket_sec );
2456- }
2457-
2458- if (update_bucket )
2441+ while (1 )
24592442 {
2460- uint64 new_bucket_id ;
2443+ uint64 current_bucket_sec = pg_atomic_read_u64 ( & pgsm -> current_bucket_sec ) ;
24612444
2462- new_bucket_id = (tv .tv_sec / pgsm_bucket_time ) % pgsm_max_buckets ;
2445+ if (current_bucket_sec + (uint64 ) pgsm_bucket_time > (uint64 ) tv .tv_sec )
2446+ return pg_atomic_read_u64 (& pgsm -> current_bucket );
24632447
2464- /* Update bucket id and retrieve the previous one. */
2465- pg_atomic_exchange_u64 (& pgsm -> current_wbucket , new_bucket_id );
2466-
2467- pgsm_lock_aquire (pgsm , LW_EXCLUSIVE );
2468- hash_entry_dealloc (new_bucket_id );
2448+ if (pg_atomic_compare_exchange_u64 (& pgsm -> current_bucket_sec , & current_bucket_sec , new_bucket_start ))
2449+ break ;
2450+ }
24692451
2470- pgsm_lock_release ( pgsm ) ;
2452+ new_bucket_id = ( new_bucket_start / pgsm_bucket_time ) % pgsm_max_buckets ;
24712453
2472- /* Align the value in prev_bucket_sec to the bucket start time */
2473- tv . tv_sec = ( tv . tv_sec ) - ( tv . tv_sec % pgsm_bucket_time );
2454+ /* Update bucket id and retrieve the previous one. */
2455+ pg_atomic_exchange_u64 ( & pgsm -> current_bucket , new_bucket_id );
24742456
2475- pg_atomic_exchange_u64 (& pgsm -> prev_bucket_sec , (uint64 ) tv .tv_sec );
2457+ pgsm_lock_aquire (pgsm , LW_EXCLUSIVE );
2458+ hash_entry_dealloc (new_bucket_id );
2459+ pgsm_lock_release (pgsm );
24762460
2477- pgsm -> bucket_start_time [new_bucket_id ] = (TimestampTz ) tv .tv_sec -
2478- ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE ) * SECS_PER_DAY );
2479- pgsm -> bucket_start_time [new_bucket_id ] = pgsm -> bucket_start_time [new_bucket_id ] * USECS_PER_SEC ;
2480- return new_bucket_id ;
2481- }
2461+ pgsm -> bucket_start_time [new_bucket_id ] = (TimestampTz ) (new_bucket_start -
2462+ ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE ) * SECS_PER_DAY )) * USECS_PER_SEC ;
24822463
2483- return pg_atomic_read_u64 ( & pgsm -> current_wbucket ) ;
2464+ return new_bucket_id ;
24842465}
24852466
24862467/*
0 commit comments