1 /*
2 * This file and its contents are licensed under the Apache License 2.0.
3 * Please see the included NOTICE for copyright information and
4 * LICENSE-APACHE for a copy of the license.
5 */
6 #include <postgres.h>
7 #include <miscadmin.h>
8 #include <postmaster/bgworker.h>
9 #include <storage/ipc.h>
10 #include <storage/latch.h>
11 #include <storage/lwlock.h>
12 #include <storage/proc.h>
13 #include <storage/shmem.h>
14 #include <utils/jsonb.h>
15 #include <utils/timestamp.h>
16 #include <utils/snapmgr.h>
17 #include <utils/memutils.h>
18 #include <access/xact.h>
19 #include <pgstat.h>
20
21 #include "timer.h"
22 #include "compat/compat.h"
23 #include "config.h"
24
25 #define MAX_TIMEOUT (5 * INT64CONST(1000))
26 #define MILLISECS_PER_SEC INT64CONST(1000)
27 #define USECS_PER_MILLISEC INT64CONST(1000)
28
29 static inline void
on_postmaster_death(void)30 on_postmaster_death(void)
31 {
32 /*
33 * Don't call exit hooks cause we want to bail out quickly. We don't care
34 * about cleaning up shared memory in this case anyway since it's
35 * potentially corrupt.
36 */
37 on_exit_reset();
38 ereport(FATAL,
39 (errcode(ERRCODE_ADMIN_SHUTDOWN),
40 errmsg("postmaster exited while timescaledb scheduler was working")));
41 }
42
43 static int64
get_timeout_millisec(TimestampTz by_time)44 get_timeout_millisec(TimestampTz by_time)
45 {
46 long timeout_sec = 0;
47 int timeout_usec = 0;
48
49 if (TIMESTAMP_IS_NOBEGIN(by_time))
50 return 0;
51
52 if (TIMESTAMP_IS_NOEND(by_time))
53 return PG_INT64_MAX;
54
55 TimestampDifference(GetCurrentTimestamp(), by_time, &timeout_sec, &timeout_usec);
56
57 if (timeout_sec < 0 || timeout_usec < 0)
58 return 0;
59
60 return (int64)(timeout_sec * MILLISECS_PER_SEC + ((int64) timeout_usec) / USECS_PER_MILLISEC);
61 }
62
63 static bool
wait_using_wait_latch(TimestampTz until)64 wait_using_wait_latch(TimestampTz until)
65 {
66 int wl_rc;
67
68 int64 timeout = get_timeout_millisec(until);
69
70 Assert(timeout >= 0 && "get_timeout_millisec underflow");
71
72 if (timeout > MAX_TIMEOUT)
73 timeout = MAX_TIMEOUT;
74
75 /* Wait latch requires timeout to be <= INT_MAX */
76 if ((int64) timeout > (int64) INT_MAX)
77 timeout = INT_MAX;
78
79 wl_rc = WaitLatch(MyLatch,
80 WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
81 timeout,
82 PG_WAIT_EXTENSION);
83 ResetLatch(MyLatch);
84 if (wl_rc & WL_POSTMASTER_DEATH)
85 on_postmaster_death();
86
87 return true;
88 }
89
90 static const Timer standard_timer = {
91 .get_current_timestamp = GetCurrentTimestamp,
92 .wait = wait_using_wait_latch,
93 };
94
95 static const Timer *current_timer_implementation = &standard_timer;
96
97 static inline const Timer *
timer_get()98 timer_get()
99 {
100 return current_timer_implementation;
101 }
102
103 bool
ts_timer_wait(TimestampTz until)104 ts_timer_wait(TimestampTz until)
105 {
106 return timer_get()->wait(until);
107 }
108
109 TimestampTz
ts_timer_get_current_timestamp()110 ts_timer_get_current_timestamp()
111 {
112 return timer_get()->get_current_timestamp();
113 }
114
115 #ifdef TS_DEBUG
116 void
ts_timer_set(const Timer * timer)117 ts_timer_set(const Timer *timer)
118 {
119 current_timer_implementation = timer;
120 }
121
122 const Timer *
ts_get_standard_timer()123 ts_get_standard_timer()
124 {
125 return &standard_timer;
126 }
127 #endif
128