@@ -2452,65 +2452,46 @@ static uint64
24522452get_next_wbucket (pgsmSharedState * pgsm )
24532453{
24542454 struct timeval tv ;
2455- uint64 current_bucket_sec ;
2456- bool update_bucket = false;
2455+ uint64 new_bucket_start ;
2456+ uint64 new_bucket_id ;
2457+ uint64 prev_bucket_id ;
24572458
24582459 gettimeofday (& tv , NULL );
2459- current_bucket_sec = pg_atomic_read_u64 (& pgsm -> prev_bucket_sec );
2460+
2461+ new_bucket_start = (tv .tv_sec / pgsm_bucket_time ) * (uint64 ) pgsm_bucket_time ;
24602462
24612463 /*
24622464 * If current bucket expired we loop attempting to update prev_bucket_sec.
24632465 *
2464- * pg_atomic_compare_exchange_u64 may fail in two possible ways: 1.
2465- * Another thread/process updated the variable before us. 2. A spurious
2466- * failure / hardware event.
2467- *
2468- * In both failure cases we read prev_bucket_sec from memory again, if it
2469- * was a spurious failure then the value of prev_bucket_sec must be the
2470- * same as before, which will cause the while loop to execute again.
2466+ * If another thread updated prev_bucket_sec, then use the new bucket
2467+ * created by that thread.
24712468 *
2472- * If another thread updated prev_bucket_sec, then its current value will
2473- * definitely make the while condition to fail, we can stop the loop as
2474- * another thread has already updated prev_bucket_sec.
2469+ * XXX: This code looks potentially racy, especially if we skip buckets.
24752470 */
2476- while ((tv .tv_sec - (uint ) current_bucket_sec ) >= ((uint ) pgsm_bucket_time ))
2477- {
2478- if (pg_atomic_compare_exchange_u64 (& pgsm -> prev_bucket_sec , & current_bucket_sec , (uint64 ) tv .tv_sec ))
2479- {
2480- update_bucket = true;
2481- break ;
2482- }
2483-
2484- current_bucket_sec = pg_atomic_read_u64 (& pgsm -> prev_bucket_sec );
2485- }
2486-
2487- if (update_bucket )
2471+ while (1 )
24882472 {
2489- uint64 new_bucket_id ;
2490- uint64 prev_bucket_id ;
2473+ uint64 current_bucket_sec = pg_atomic_read_u64 (& pgsm -> prev_bucket_sec );
24912474
2492- new_bucket_id = (tv .tv_sec / pgsm_bucket_time ) % pgsm_max_buckets ;
2475+ if (current_bucket_sec + (uint64 ) pgsm_bucket_time > (uint64 ) tv .tv_sec )
2476+ return pg_atomic_read_u64 (& pgsm -> current_wbucket );
24932477
2494- /* Update bucket id and retrieve the previous one. */
2495- prev_bucket_id = pg_atomic_exchange_u64 (& pgsm -> current_wbucket , new_bucket_id );
2478+ if (pg_atomic_compare_exchange_u64 (& pgsm -> prev_bucket_sec , & current_bucket_sec , new_bucket_start ))
2479+ break ;
2480+ }
24962481
2497- pgsm_lock_aquire (pgsm , LW_EXCLUSIVE );
2498- hash_entry_dealloc (new_bucket_id , prev_bucket_id );
2482+ new_bucket_id = (new_bucket_start / pgsm_bucket_time ) % pgsm_max_buckets ;
24992483
2500- pgsm_lock_release (pgsm );
2484+ /* Update bucket id and retrieve the previous one. */
2485+ prev_bucket_id = pg_atomic_exchange_u64 (& pgsm -> current_wbucket , new_bucket_id );
25012486
2502- /* Align the value in prev_bucket_sec to the bucket start time */
2503- tv .tv_sec = (tv .tv_sec ) - (tv .tv_sec % pgsm_bucket_time );
2504-
2505- pg_atomic_exchange_u64 (& pgsm -> prev_bucket_sec , (uint64 ) tv .tv_sec );
2487+ pgsm_lock_aquire (pgsm , LW_EXCLUSIVE );
2488+ hash_entry_dealloc (new_bucket_id , prev_bucket_id );
2489+ pgsm_lock_release (pgsm );
25062490
2507- pgsm -> bucket_start_time [new_bucket_id ] = (TimestampTz ) tv .tv_sec -
2508- ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE ) * SECS_PER_DAY );
2509- pgsm -> bucket_start_time [new_bucket_id ] = pgsm -> bucket_start_time [new_bucket_id ] * USECS_PER_SEC ;
2510- return new_bucket_id ;
2511- }
2491+ pgsm -> bucket_start_time [new_bucket_id ] = (TimestampTz ) (new_bucket_start -
2492+ ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE ) * SECS_PER_DAY )) * USECS_PER_SEC ;
25122493
2513- return pg_atomic_read_u64 ( & pgsm -> current_wbucket ) ;
2494+ return new_bucket_id ;
25142495}
25152496
25162497/*
0 commit comments