1 /*
2 * Copyright (c) 2024 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 #include "cloud_sync_state_machine.h"
16
17 #include <cmath>
18 #include <climits>
19 #include <algorithm>
20
21 #include "db_errno.h"
22 #include "log_print.h"
23 #include "runtime_context.h"
24
25 namespace DistributedDB {
26 using Event = CloudSyncEvent;
27 using State = CloudSyncState;
28 namespace {
29 // used for state switch table
30 constexpr int CURRENT_STATE_INDEX = 0;
31 constexpr int EVENT_INDEX = 1;
32 constexpr int OUTPUT_STATE_INDEX = 2;
33
34 const std::vector<std::vector<uint8_t>> STATE_SWITCH_TABLE = {
35 // In IDEL state
36 {State::IDLE, Event::START_SYNC_EVENT, State::DO_DOWNLOAD},
37 {State::IDLE, Event::ERROR_EVENT, State::DO_FINISHED},
38
39 // In DO_DOWNLOAD state
40 {State::DO_DOWNLOAD, Event::DOWNLOAD_FINISHED_EVENT, State::DO_UPLOAD},
41 {State::DO_DOWNLOAD, Event::ERROR_EVENT, State::DO_FINISHED},
42
43 // In DO_UPLOAD state
44 {State::DO_UPLOAD, Event::UPLOAD_FINISHED_EVENT, State::DO_FINISHED},
45 {State::DO_UPLOAD, Event::ERROR_EVENT, State::DO_FINISHED},
46 {State::DO_UPLOAD, Event::REPEAT_CHECK_EVENT, State::DO_REPEAT_CHECK},
47
48 // Repeat download check state
49 {State::DO_REPEAT_CHECK, Event::REPEAT_DOWNLOAD_EVENT, State::DO_DOWNLOAD},
50 {State::DO_REPEAT_CHECK, Event::ERROR_EVENT, State::DO_FINISHED},
51
52 // In DO_FINISHED state
53 {State::DO_FINISHED, Event::ALL_TASK_FINISHED_EVENT, State::IDLE},
54 };
55 }
56
57 std::mutex CloudSyncStateMachine::stateSwitchTableLock_;
58 std::vector<CloudStateSwitchTable> CloudSyncStateMachine::stateSwitchTables_;
59 bool CloudSyncStateMachine::isStateSwitchTableInited_ = false;
60
Initialize()61 int CloudSyncStateMachine::Initialize()
62 {
63 InitCloudStateSwitchTables();
64 return E_OK;
65 }
66
SyncStep()67 void CloudSyncStateMachine::SyncStep()
68 {
69 Event event = Event::ERROR_EVENT;
70 do {
71 auto iter = stateMapping_.find(currentState_);
72 if (iter != stateMapping_.end()) {
73 event = static_cast<Event>(iter->second());
74 } else {
75 LOGE("[CloudSyncStateMachine][SyncStep] can not find state=%d", currentState_);
76 break;
77 }
78 } while (SwitchMachineState(event) == E_OK && currentState_ != State::IDLE);
79 }
80
InitCloudStateSwitchTables()81 void CloudSyncStateMachine::InitCloudStateSwitchTables()
82 {
83 if (isStateSwitchTableInited_) {
84 return;
85 }
86
87 std::lock_guard<std::mutex> lock(stateSwitchTableLock_);
88 if (isStateSwitchTableInited_) {
89 return;
90 }
91
92 InitCloudStateSwitchTable(STATE_SWITCH_TABLE);
93 isStateSwitchTableInited_ = true;
94 }
95
InitCloudStateSwitchTable(const std::vector<std::vector<uint8_t>> & switchTable)96 void CloudSyncStateMachine::InitCloudStateSwitchTable(
97 const std::vector<std::vector<uint8_t>> &switchTable)
98 {
99 CloudStateSwitchTable table;
100 for (const auto &stateSwitch : switchTable) {
101 if (stateSwitch.size() <= OUTPUT_STATE_INDEX) {
102 LOGE("[StateMachine][InitSwitchTable] stateSwitch size err,size=%zu", stateSwitch.size());
103 return;
104 }
105 if (table.switchTable.count(stateSwitch[CURRENT_STATE_INDEX]) == 0) {
106 EventToState eventToState; // new EventToState
107 eventToState[stateSwitch[EVENT_INDEX]] = stateSwitch[OUTPUT_STATE_INDEX];
108 table.switchTable[stateSwitch[CURRENT_STATE_INDEX]] = eventToState;
109 } else { // key stateSwitch[CURRENT_STATE_INDEX] already has EventToState
110 EventToState &eventToState = table.switchTable[stateSwitch[CURRENT_STATE_INDEX]];
111 eventToState[stateSwitch[EVENT_INDEX]] = stateSwitch[OUTPUT_STATE_INDEX];
112 }
113 }
114 stateSwitchTables_.push_back(table);
115 }
116
RegisterFunc(State state,const std::function<uint8_t (void)> & function)117 void CloudSyncStateMachine::RegisterFunc(State state, const std::function<uint8_t(void)> &function)
118 {
119 stateMapping_[state] = function;
120 };
121
SwitchMachineState(uint8_t event)122 int CloudSyncStateMachine::SwitchMachineState(uint8_t event)
123 {
124 auto tableIter = std::find_if(stateSwitchTables_.begin(), stateSwitchTables_.end(),
125 [](const CloudStateSwitchTable &table) {
126 return table.version == 0;
127 });
128 if (tableIter == stateSwitchTables_.end()) {
129 LOGE("[CloudSyncStateMachine][SwitchState] Can't find a compatible state switch table.");
130 return -E_NOT_FOUND;
131 }
132
133 const std::map<uint8_t, EventToState> &table = (*tableIter).switchTable;
134 auto eventToStateIter = table.find(currentState_);
135 if (eventToStateIter == table.end()) {
136 LOGE("[CloudSyncStateMachine][SwitchState] Can't find EventToState with currentSate %u",
137 currentState_);
138 return E_OK;
139 }
140
141 const EventToState &eventToState = eventToStateIter->second;
142 auto stateIter = eventToState.find(event);
143 if (stateIter == eventToState.end()) {
144 LOGD("[CloudSyncStateMachine][SwitchState] Can't find event %u int currentSate %u ignore",
145 event, currentState_);
146 return -E_NOT_FOUND;
147 }
148
149 currentState_ = static_cast<CloudSyncState>(stateIter->second);
150 return E_OK;
151 }
152
SwitchStateAndStep(uint8_t event)153 void CloudSyncStateMachine::SwitchStateAndStep(uint8_t event)
154 {
155 if (SwitchMachineState(event) == E_OK) {
156 SyncStep();
157 }
158 }
159
160 } // namespace DistributedDB
161