1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "time_tick_monitor.h"
17
18 #include "db_errno.h"
19 #include "log_print.h"
20
21 namespace DistributedDB {
TimeTickMonitor()22 TimeTickMonitor::TimeTickMonitor()
23 : timeChangedNotifier_(nullptr),
24 runtimeCxt_(nullptr),
25 monitorTimerId_(0),
26 monitorCallback_(0),
27 lastMonotonicTime_(0),
28 lastSystemTime_(0),
29 isStarted_(false)
30 {
31 }
32
~TimeTickMonitor()33 TimeTickMonitor::~TimeTickMonitor()
34 {
35 StopTimeTickMonitor();
36 runtimeCxt_ = nullptr;
37 }
38
StartTimeTickMonitor()39 int TimeTickMonitor::StartTimeTickMonitor()
40 {
41 if (isStarted_) {
42 return E_OK;
43 }
44
45 int errCode = PrepareNotifierChain();
46 if (errCode != E_OK) {
47 return errCode;
48 }
49
50 lastMonotonicTime_ = GetMonotonicTime();
51 lastSystemTime_ = GetSysCurrentTime();
52 monitorCallback_ = std::bind(&TimeTickMonitor::TimeTick, this, std::placeholders::_1);
53 runtimeCxt_ = RuntimeContext::GetInstance();
54 monitorTimerId_ = 0;
55 errCode = runtimeCxt_->SetTimer(MONITOR_INTERVAL, monitorCallback_, nullptr, monitorTimerId_);
56 if (errCode != E_OK) {
57 return errCode;
58 }
59 isStarted_ = true;
60 return E_OK;
61 }
62
StopTimeTickMonitor()63 void TimeTickMonitor::StopTimeTickMonitor()
64 {
65 if (!isStarted_) {
66 return;
67 }
68
69 NotificationChain *notifier;
70 {
71 std::lock_guard<std::mutex> autoLock(timeTickMonitorLock_);
72 notifier = timeChangedNotifier_;
73 timeChangedNotifier_ = nullptr;
74 }
75 if (notifier != nullptr) {
76 notifier->UnRegisterEventType(TIME_CHANGE_EVENT);
77 RefObject::KillAndDecObjRef(notifier);
78 }
79 runtimeCxt_->RemoveTimer(monitorTimerId_, true);
80 isStarted_ = false;
81 }
82
RegisterTimeChangedLister(const TimeChangedAction & action,int & errCode)83 NotificationChain::Listener *TimeTickMonitor::RegisterTimeChangedLister(const TimeChangedAction &action, int &errCode)
84 {
85 if (timeChangedNotifier_ == nullptr) {
86 errCode = -E_NOT_INIT;
87 return nullptr;
88 }
89
90 if (action == nullptr) {
91 errCode = -E_INVALID_ARGS;
92 return nullptr;
93 }
94
95 return timeChangedNotifier_->RegisterListener(TIME_CHANGE_EVENT, action, nullptr, errCode);
96 }
97
PrepareNotifierChain()98 int TimeTickMonitor::PrepareNotifierChain()
99 {
100 std::lock_guard<std::mutex> autoLock(timeTickMonitorLock_);
101 if (timeChangedNotifier_ != nullptr) {
102 return E_OK;
103 }
104
105 timeChangedNotifier_ = new (std::nothrow) NotificationChain();
106 if (timeChangedNotifier_ == nullptr) {
107 return -E_OUT_OF_MEMORY;
108 }
109
110 int errCode = timeChangedNotifier_->RegisterEventType(TIME_CHANGE_EVENT);
111 if (errCode != E_OK) {
112 RefObject::KillAndDecObjRef(timeChangedNotifier_);
113 timeChangedNotifier_ = nullptr;
114 }
115 return errCode;
116 }
117
TimeTick(TimerId timerId)118 int TimeTickMonitor::TimeTick(TimerId timerId)
119 {
120 if (timerId != monitorTimerId_) {
121 return -E_INVALID_ARGS;
122 }
123
124 uint64_t monotonicTime = GetMonotonicTime();
125 uint64_t systemTime = GetSysCurrentTime();
126 int64_t monotonicOffset = static_cast<int64_t>(monotonicTime - lastMonotonicTime_);
127 int64_t systemOffset = static_cast<int64_t>(systemTime - lastSystemTime_);
128 lastMonotonicTime_ = monotonicTime;
129 lastSystemTime_ = systemTime;
130 int64_t changedOffset = systemOffset - monotonicOffset;
131 if (std::abs(changedOffset) > MAX_NOISE) {
132 LOGI("Local system time may be changed! changedOffset %ld", changedOffset);
133 NotificationChain *notifier = nullptr;
134 {
135 std::lock_guard<std::mutex> autoLock(timeTickMonitorLock_);
136 notifier = timeChangedNotifier_;
137 RefObject::IncObjRef(notifier);
138 }
139 int ret = RuntimeContext::GetInstance()->ScheduleTask([notifier, changedOffset]() {
140 if (notifier == nullptr) {
141 return;
142 }
143 int64_t offset = changedOffset;
144 notifier->NotifyEvent(TIME_CHANGE_EVENT, &offset);
145 RefObject::DecObjRef(notifier);
146 });
147 if (ret != E_OK) {
148 LOGE("TimeTickMonitor ScheduleTask failed %d", ret);
149 }
150 }
151 return E_OK;
152 }
153
GetSysCurrentTime()154 Timestamp TimeTickMonitor::GetSysCurrentTime()
155 {
156 uint64_t curTime = 0;
157 int errCode = OS::GetCurrentSysTimeInMicrosecond(curTime);
158 if (errCode != E_OK) {
159 LOGE("TimeTickMonitor:get system time failed!");
160 return INVALID_TIMESTAMP;
161 }
162 return curTime;
163 }
164
GetMonotonicTime()165 Timestamp TimeTickMonitor::GetMonotonicTime()
166 {
167 uint64_t time;
168 int errCode = OS::GetMonotonicRelativeTimeInMicrosecond(time);
169 if (errCode != E_OK) {
170 LOGE("GetMonotonicTime ERR! err = %d", errCode);
171 return INVALID_TIMESTAMP;
172 }
173 return time;
174 }
175
NotifyTimeChange(TimeOffset offset) const176 void TimeTickMonitor::NotifyTimeChange(TimeOffset offset) const
177 {
178 std::lock_guard<std::mutex> lock(timeTickMonitorLock_);
179 if (timeChangedNotifier_ == nullptr) {
180 LOGD("NotifyTimeChange fail, timeChangedNotifier_ is null.");
181 return;
182 }
183 timeChangedNotifier_->NotifyEvent(TIME_CHANGE_EVENT, static_cast<void *>(&offset));
184 }
185
EmptyListener() const186 bool TimeTickMonitor::EmptyListener() const
187 {
188 std::lock_guard<std::mutex> lock(timeTickMonitorLock_);
189 return timeChangedNotifier_->EmptyListener(TIME_CHANGE_EVENT);
190 }
191 } // namespace DistributedDB