• 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     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