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 LOGD("TimeTickMonitor destroy");
36 StopTimeTickMonitor();
37 runtimeCxt_ = nullptr;
38 }
39
StartTimeTickMonitor()40 int TimeTickMonitor::StartTimeTickMonitor()
41 {
42 if (isStarted_) {
43 return E_OK;
44 }
45
46 int errCode = PrepareNotifierChain();
47 if (errCode != E_OK) {
48 return errCode;
49 }
50
51 lastMonotonicTime_ = GetMonotonicTime();
52 lastSystemTime_ = GetSysCurrentTime();
53 monitorCallback_ = std::bind(&TimeTickMonitor::TimeTick, this, std::placeholders::_1);
54 runtimeCxt_ = RuntimeContext::GetInstance();
55 monitorTimerId_ = 0;
56 errCode = runtimeCxt_->SetTimer(MONITOR_INTERVAL, monitorCallback_, nullptr, monitorTimerId_);
57 if (errCode != E_OK) {
58 return errCode;
59 }
60 isStarted_ = true;
61 return E_OK;
62 }
63
StopTimeTickMonitor()64 void TimeTickMonitor::StopTimeTickMonitor()
65 {
66 if (!isStarted_) {
67 return;
68 }
69
70 NotificationChain *notifier;
71 {
72 std::lock_guard<std::mutex> autoLock(timeTickMonitorLock_);
73 notifier = timeChangedNotifier_;
74 timeChangedNotifier_ = nullptr;
75 }
76 if (notifier != nullptr) {
77 notifier->UnRegisterEventType(TIME_CHANGE_EVENT);
78 RefObject::KillAndDecObjRef(notifier);
79 }
80 runtimeCxt_->RemoveTimer(monitorTimerId_, true);
81 isStarted_ = false;
82 }
83
RegisterTimeChangedLister(const TimeChangedAction & action,const TimeFinalizeAction & finalize,int & errCode)84 NotificationChain::Listener *TimeTickMonitor::RegisterTimeChangedLister(const TimeChangedAction &action,
85 const TimeFinalizeAction &finalize, int &errCode)
86 {
87 if (timeChangedNotifier_ == nullptr) {
88 errCode = -E_NOT_INIT;
89 return nullptr;
90 }
91
92 if (action == nullptr) {
93 errCode = -E_INVALID_ARGS;
94 return nullptr;
95 }
96
97 return timeChangedNotifier_->RegisterListener(TIME_CHANGE_EVENT, action, finalize, errCode);
98 }
99
PrepareNotifierChain()100 int TimeTickMonitor::PrepareNotifierChain()
101 {
102 std::lock_guard<std::mutex> autoLock(timeTickMonitorLock_);
103 if (timeChangedNotifier_ != nullptr) {
104 return E_OK;
105 }
106
107 timeChangedNotifier_ = new (std::nothrow) NotificationChain();
108 if (timeChangedNotifier_ == nullptr) {
109 return -E_OUT_OF_MEMORY;
110 }
111
112 int errCode = timeChangedNotifier_->RegisterEventType(TIME_CHANGE_EVENT);
113 if (errCode != E_OK) {
114 RefObject::KillAndDecObjRef(timeChangedNotifier_);
115 timeChangedNotifier_ = nullptr;
116 }
117 return errCode;
118 }
119
TimeTick(TimerId timerId)120 int TimeTickMonitor::TimeTick(TimerId timerId)
121 {
122 if (timerId != monitorTimerId_) {
123 return -E_INVALID_ARGS;
124 }
125
126 uint64_t monotonicTime = GetMonotonicTime();
127 uint64_t systemTime = GetSysCurrentTime();
128 int64_t monotonicOffset = static_cast<int64_t>(monotonicTime - lastMonotonicTime_);
129 int64_t systemOffset = static_cast<int64_t>(systemTime - lastSystemTime_);
130 lastMonotonicTime_ = monotonicTime;
131 lastSystemTime_ = systemTime;
132 int64_t changedOffset = systemOffset - monotonicOffset;
133 if (std::abs(changedOffset) > MAX_NOISE) {
134 LOGI("Local system time may be changed! changedOffset %ld", changedOffset);
135 NotificationChain *notifier = nullptr;
136 {
137 std::lock_guard<std::mutex> autoLock(timeTickMonitorLock_);
138 notifier = timeChangedNotifier_;
139 RefObject::IncObjRef(notifier);
140 }
141 int ret = RuntimeContext::GetInstance()->ScheduleTask([notifier, changedOffset]() {
142 if (notifier == nullptr) {
143 return;
144 }
145 int64_t offset = changedOffset;
146 notifier->NotifyEvent(TIME_CHANGE_EVENT, &offset);
147 RefObject::DecObjRef(notifier);
148 });
149 if (ret != E_OK) {
150 LOGE("TimeTickMonitor ScheduleTask failed %d", ret);
151 }
152 }
153 return E_OK;
154 }
155
GetSysCurrentTime()156 Timestamp TimeTickMonitor::GetSysCurrentTime()
157 {
158 uint64_t curTime = 0;
159 int errCode = OS::GetCurrentSysTimeInMicrosecond(curTime);
160 if (errCode != E_OK) {
161 LOGE("TimeTickMonitor:get system time failed!");
162 return INVALID_TIMESTAMP;
163 }
164 return curTime;
165 }
166
GetMonotonicTime()167 Timestamp TimeTickMonitor::GetMonotonicTime()
168 {
169 uint64_t time;
170 int errCode = OS::GetMonotonicRelativeTimeInMicrosecond(time);
171 if (errCode != E_OK) {
172 LOGE("GetMonotonicTime ERR! err = %d", errCode);
173 return INVALID_TIMESTAMP;
174 }
175 return time;
176 }
177
NotifyTimeChange(TimeOffset offset) const178 void TimeTickMonitor::NotifyTimeChange(TimeOffset offset) const
179 {
180 std::lock_guard<std::mutex> lock(timeTickMonitorLock_);
181 if (timeChangedNotifier_ == nullptr) {
182 LOGD("NotifyTimeChange fail, timeChangedNotifier_ is null.");
183 return;
184 }
185 timeChangedNotifier_->NotifyEvent(TIME_CHANGE_EVENT, static_cast<void *>(&offset));
186 }
187
EmptyListener() const188 bool TimeTickMonitor::EmptyListener() const
189 {
190 std::lock_guard<std::mutex> lock(timeTickMonitorLock_);
191 return timeChangedNotifier_->EmptyListener(TIME_CHANGE_EVENT);
192 }
193 } // namespace DistributedDB