• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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