diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c index 3bd0010bf8..fcbdbdd027 100644 --- a/contrib/pg_prewarm/autoprewarm.c +++ b/contrib/pg_prewarm/autoprewarm.c @@ -226,18 +226,16 @@ autoprewarm_main(Datum main_arg) } else { - long delay_in_ms = 0; - TimestampTz next_dump_time = 0; - long secs = 0; - int usecs = 0; + TimestampTz next_dump_time; + long delay_in_ms; /* Compute the next dump time. */ next_dump_time = TimestampTzPlusMilliseconds(last_dump_time, autoprewarm_interval * 1000); - TimestampDifference(GetCurrentTimestamp(), next_dump_time, - &secs, &usecs); - delay_in_ms = secs + (usecs / 1000); + delay_in_ms = + TimestampDifferenceMilliseconds(GetCurrentTimestamp(), + next_dump_time); /* Perform a dump if it's time. */ if (delay_in_ms <= 0) diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index fed14eb85d..3cac70e39e 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -1139,20 +1139,15 @@ pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result) { int wc; TimestampTz now = GetCurrentTimestamp(); - long secs; - int microsecs; long cur_timeout; /* If timeout has expired, give up, else get sleep time. */ - if (now >= endtime) + cur_timeout = TimestampDifferenceMilliseconds(now, endtime); + if (cur_timeout <= 0) { timed_out = true; goto exit; } - TimestampDifference(now, endtime, &secs, µsecs); - - /* To protect against clock skew, limit sleep to one minute. */ - cur_timeout = Min(60000, secs * USECS_PER_SEC + microsecs); /* Sleep until there's something to do */ wc = WaitLatchOrSocket(MyLatch, diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index d3faa38900..2556bddcdf 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -6128,8 +6128,7 @@ recoveryApplyDelay(XLogReaderState *record) { uint8 xact_info; TimestampTz xtime; - long secs; - int microsecs; + long msecs; /* nothing to do if no delay configured */ if (recovery_min_apply_delay <= 0) @@ -6166,9 +6165,9 @@ recoveryApplyDelay(XLogReaderState *record) * Exit without arming the latch if it's already past time to apply this * record */ - TimestampDifference(GetCurrentTimestamp(), recoveryDelayUntilTime, - &secs, µsecs); - if (secs <= 0 && microsecs <= 0) + msecs = TimestampDifferenceMilliseconds(GetCurrentTimestamp(), + recoveryDelayUntilTime); + if (msecs <= 0) return false; while (true) @@ -6185,20 +6184,18 @@ recoveryApplyDelay(XLogReaderState *record) * Wait for difference between GetCurrentTimestamp() and * recoveryDelayUntilTime */ - TimestampDifference(GetCurrentTimestamp(), recoveryDelayUntilTime, - &secs, µsecs); + msecs = TimestampDifferenceMilliseconds(GetCurrentTimestamp(), + recoveryDelayUntilTime); - /* NB: We're ignoring waits below min_apply_delay's resolution. */ - if (secs <= 0 && microsecs / 1000 <= 0) + if (msecs <= 0) break; - elog(DEBUG2, "recovery apply delay %ld seconds, %d milliseconds", - secs, microsecs / 1000); + elog(DEBUG2, "recovery apply delay %ld milliseconds", msecs); - WaitLatch(&XLogCtl->recoveryWakeupLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - secs * 1000L + microsecs / 1000, - WAIT_EVENT_RECOVERY_APPLY_DELAY); + (void) WaitLatch(&XLogCtl->recoveryWakeupLatch, + WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, + msecs, + WAIT_EVENT_RECOVERY_APPLY_DELAY); } return true; } @@ -8585,33 +8582,24 @@ LogCheckpointStart(int flags, bool restartpoint) static void LogCheckpointEnd(bool restartpoint) { - long write_secs, - sync_secs, - total_secs, - longest_secs, - average_secs; - int write_usecs, - sync_usecs, - total_usecs, - longest_usecs, - average_usecs; + long write_msecs, + sync_msecs, + total_msecs, + longest_msecs, + average_msecs; uint64 average_sync_time; CheckpointStats.ckpt_end_t = GetCurrentTimestamp(); - TimestampDifference(CheckpointStats.ckpt_write_t, - CheckpointStats.ckpt_sync_t, - &write_secs, &write_usecs); + write_msecs = TimestampDifferenceMilliseconds(CheckpointStats.ckpt_write_t, + CheckpointStats.ckpt_sync_t); - TimestampDifference(CheckpointStats.ckpt_sync_t, - CheckpointStats.ckpt_sync_end_t, - &sync_secs, &sync_usecs); + sync_msecs = TimestampDifferenceMilliseconds(CheckpointStats.ckpt_sync_t, + CheckpointStats.ckpt_sync_end_t); /* Accumulate checkpoint timing summary data, in milliseconds. */ - BgWriterStats.m_checkpoint_write_time += - write_secs * 1000 + write_usecs / 1000; - BgWriterStats.m_checkpoint_sync_time += - sync_secs * 1000 + sync_usecs / 1000; + BgWriterStats.m_checkpoint_write_time += write_msecs; + BgWriterStats.m_checkpoint_sync_time += sync_msecs; /* * All of the published timing statistics are accounted for. Only @@ -8620,25 +8608,20 @@ LogCheckpointEnd(bool restartpoint) if (!log_checkpoints) return; - TimestampDifference(CheckpointStats.ckpt_start_t, - CheckpointStats.ckpt_end_t, - &total_secs, &total_usecs); + total_msecs = TimestampDifferenceMilliseconds(CheckpointStats.ckpt_start_t, + CheckpointStats.ckpt_end_t); /* * Timing values returned from CheckpointStats are in microseconds. - * Convert to the second plus microsecond form that TimestampDifference - * returns for homogeneous printing. + * Convert to milliseconds for consistent printing. */ - longest_secs = (long) (CheckpointStats.ckpt_longest_sync / 1000000); - longest_usecs = CheckpointStats.ckpt_longest_sync - - (uint64) longest_secs * 1000000; + longest_msecs = (long) ((CheckpointStats.ckpt_longest_sync + 999) / 1000); average_sync_time = 0; if (CheckpointStats.ckpt_sync_rels > 0) average_sync_time = CheckpointStats.ckpt_agg_sync_time / CheckpointStats.ckpt_sync_rels; - average_secs = (long) (average_sync_time / 1000000); - average_usecs = average_sync_time - (uint64) average_secs * 1000000; + average_msecs = (long) ((average_sync_time + 999) / 1000); elog(LOG, "%s complete: wrote %d buffers (%.1f%%); " "%d WAL file(s) added, %d removed, %d recycled; " @@ -8651,12 +8634,12 @@ LogCheckpointEnd(bool restartpoint) CheckpointStats.ckpt_segs_added, CheckpointStats.ckpt_segs_removed, CheckpointStats.ckpt_segs_recycled, - write_secs, write_usecs / 1000, - sync_secs, sync_usecs / 1000, - total_secs, total_usecs / 1000, + write_msecs / 1000, (int) (write_msecs % 1000), + sync_msecs / 1000, (int) (sync_msecs % 1000), + total_msecs / 1000, (int) (total_msecs % 1000), CheckpointStats.ckpt_sync_rels, - longest_secs, longest_usecs / 1000, - average_secs, average_usecs / 1000, + longest_msecs / 1000, (int) (longest_msecs % 1000), + average_msecs / 1000, (int) (average_msecs % 1000), (int) (PrevCheckPointDistance / 1024.0), (int) (CheckPointDistanceEstimate / 1024.0)); } @@ -12168,13 +12151,10 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, if (!TimestampDifferenceExceeds(last_fail_time, now, wal_retrieve_retry_interval)) { - long secs, - wait_time; - int usecs; + long wait_time; - TimestampDifference(last_fail_time, now, &secs, &usecs); wait_time = wal_retrieve_retry_interval - - (secs * 1000 + usecs / 1000); + TimestampDifferenceMilliseconds(last_fail_time, now); WaitLatch(&XLogCtl->recoveryWakeupLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c index 67b1a074cc..da07088b42 100644 --- a/src/backend/replication/walreceiverfuncs.c +++ b/src/backend/replication/walreceiverfuncs.c @@ -320,10 +320,6 @@ GetReplicationApplyDelay(void) WalRcvData *walrcv = WalRcv; XLogRecPtr receivePtr; XLogRecPtr replayPtr; - - long secs; - int usecs; - TimestampTz chunkReplayStartTime; SpinLockAcquire(&walrcv->mutex); @@ -340,11 +336,8 @@ GetReplicationApplyDelay(void) if (chunkReplayStartTime == 0) return -1; - TimestampDifference(chunkReplayStartTime, - GetCurrentTimestamp(), - &secs, &usecs); - - return (((int) secs * 1000) + (usecs / 1000)); + return TimestampDifferenceMilliseconds(chunkReplayStartTime, + GetCurrentTimestamp()); } /* @@ -355,24 +348,14 @@ int GetReplicationTransferLatency(void) { WalRcvData *walrcv = WalRcv; - TimestampTz lastMsgSendTime; TimestampTz lastMsgReceiptTime; - long secs = 0; - int usecs = 0; - int ms; - SpinLockAcquire(&walrcv->mutex); lastMsgSendTime = walrcv->lastMsgSendTime; lastMsgReceiptTime = walrcv->lastMsgReceiptTime; SpinLockRelease(&walrcv->mutex); - TimestampDifference(lastMsgSendTime, - lastMsgReceiptTime, - &secs, &usecs); - - ms = ((int) secs * 1000) + (usecs / 1000); - - return ms; + return TimestampDifferenceMilliseconds(lastMsgSendTime, + lastMsgReceiptTime); } diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 92bc657784..b6c456f0c5 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -2033,8 +2033,6 @@ WalSndComputeSleeptime(TimestampTz now) if (wal_sender_timeout > 0 && last_reply_timestamp > 0) { TimestampTz wakeup_time; - long sec_to_timeout; - int microsec_to_timeout; /* * At the latest stop sleeping once wal_sender_timeout has been @@ -2053,11 +2051,7 @@ WalSndComputeSleeptime(TimestampTz now) wal_sender_timeout / 2); /* Compute relative time until wakeup. */ - TimestampDifference(now, wakeup_time, - &sec_to_timeout, µsec_to_timeout); - - sleeptime = sec_to_timeout * 1000 + - microsec_to_timeout / 1000; + sleeptime = TimestampDifferenceMilliseconds(now, wakeup_time); } return sleeptime; diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index d4848b7657..cc24bcde71 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -1604,12 +1604,14 @@ GetSQLLocalTimestamp(int32 typmod) * TimestampDifference -- convert the difference between two timestamps * into integer seconds and microseconds * + * This is typically used to calculate a wait timeout for select(2), + * which explains the otherwise-odd choice of output format. + * * Both inputs must be ordinary finite timestamps (in current usage, * they'll be results from GetCurrentTimestamp()). * - * We expect start_time <= stop_time. If not, we return zeros; for current - * callers there is no need to be tense about which way division rounds on - * negative inputs. + * We expect start_time <= stop_time. If not, we return zeros, + * since then we're already past the previously determined stop_time. */ void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, @@ -1629,6 +1631,36 @@ TimestampDifference(TimestampTz start_time, TimestampTz stop_time, } } +/* + * TimestampDifferenceMilliseconds -- convert the difference between two + * timestamps into integer milliseconds + * + * This is typically used to calculate a wait timeout for WaitLatch() + * or a related function. The choice of "long" as the result type + * is to harmonize with that. It is caller's responsibility that the + * input timestamps not be so far apart as to risk overflow of "long" + * (which'd happen at about 25 days on machines with 32-bit "long"). + * + * Both inputs must be ordinary finite timestamps (in current usage, + * they'll be results from GetCurrentTimestamp()). + * + * We expect start_time <= stop_time. If not, we return zero, + * since then we're already past the previously determined stop_time. + * + * Note we round up any fractional millisecond, since waiting for just + * less than the intended timeout is undesirable. + */ +long +TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time) +{ + TimestampTz diff = stop_time - start_time; + + if (diff <= 0) + return 0; + else + return (long) ((diff + 999) / 1000); +} + /* * TimestampDifferenceExceeds -- report whether the difference between two * timestamps is >= a threshold (expressed in milliseconds) diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index 2b3b35703e..bf53647f71 100644 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -72,6 +72,8 @@ extern TimestampTz GetSQLCurrentTimestamp(int32 typmod); extern Timestamp GetSQLLocalTimestamp(int32 typmod); extern void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs); +extern long TimestampDifferenceMilliseconds(TimestampTz start_time, + TimestampTz stop_time); extern bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec);