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 "single_ver_natural_store_commit_notify_data.h"
17 #include "db_errno.h"
18 #include "log_print.h"
19 #include "db_common.h"
20
21 namespace DistributedDB {
SingleVerNaturalStoreCommitNotifyData()22 SingleVerNaturalStoreCommitNotifyData::SingleVerNaturalStoreCommitNotifyData() : conflictedFlag_(0) {}
23
GetInsertedEntries(int & errCode) const24 const std::list<Entry> SingleVerNaturalStoreCommitNotifyData::GetInsertedEntries(int &errCode) const
25 {
26 return FilterEntriesByKey(insertedEntries_, keyFilter_, errCode);
27 }
28
GetUpdatedEntries(int & errCode) const29 const std::list<Entry> SingleVerNaturalStoreCommitNotifyData::GetUpdatedEntries(int &errCode) const
30 {
31 return FilterEntriesByKey(updatedEntries_, keyFilter_, errCode);
32 }
33
GetDeletedEntries(int & errCode) const34 const std::list<Entry> SingleVerNaturalStoreCommitNotifyData::GetDeletedEntries(int &errCode) const
35 {
36 return FilterEntriesByKey(deletedEntries_, keyFilter_, errCode);
37 }
38
GetCommitConflicts(int & errCode) const39 const std::list<KvDBConflictEntry> SingleVerNaturalStoreCommitNotifyData::GetCommitConflicts(int &errCode) const
40 {
41 errCode = E_OK;
42 return conflictedEntries_;
43 }
44
SetFilterKey(const Key & key)45 void SingleVerNaturalStoreCommitNotifyData::SetFilterKey(const Key &key)
46 {
47 keyFilter_ = key;
48 }
49
IsChangedDataEmpty() const50 bool SingleVerNaturalStoreCommitNotifyData::IsChangedDataEmpty() const
51 {
52 int errCode;
53 return (!IsCleared() && GetInsertedEntries(errCode).empty() && GetUpdatedEntries(errCode).empty() &&
54 GetDeletedEntries(errCode).empty());
55 }
56
IsConflictedDataEmpty() const57 bool SingleVerNaturalStoreCommitNotifyData::IsConflictedDataEmpty() const
58 {
59 return conflictedEntries_.empty();
60 }
61
InsertCommittedData(const Entry & entry,DataType dataType,bool needMerge)62 int SingleVerNaturalStoreCommitNotifyData::InsertCommittedData(const Entry &entry, DataType dataType, bool needMerge)
63 {
64 if (!needMerge) {
65 return InsertEntry(dataType, entry);
66 }
67
68 Key hashKey;
69 DBCommon::CalcValueHash(entry.key, hashKey);
70 // conclude the operation type
71 if (!IsKeyPropSet(hashKey)) {
72 return E_OK;
73 }
74 DataType type = DataType::NONE;
75 if (keyPropRecord_[hashKey].existStatus == ExistStatus::EXIST) {
76 if (dataType == DataType::INSERT || dataType == DataType::UPDATE) {
77 type = DataType::UPDATE;
78 } else if (dataType == DataType::DELETE) {
79 type = DataType::DELETE;
80 }
81 } else {
82 if (dataType == DataType::INSERT || dataType == DataType::UPDATE) {
83 type = DataType::INSERT;
84 } else if (dataType == DataType::DELETE) {
85 type = DataType::NONE;
86 }
87 }
88
89 // clear the old data
90 DeleteEntryByKey(entry.key, keyPropRecord_[hashKey].latestType);
91
92 // update the latest operation type value
93 keyPropRecord_[hashKey].latestType = type;
94
95 return InsertEntry(type, entry);
96 }
97
InsertEntry(DataType dataType,const Entry & entry)98 int SingleVerNaturalStoreCommitNotifyData::InsertEntry(DataType dataType, const Entry &entry)
99 {
100 if (dataType == DataType::INSERT) {
101 insertedEntries_.push_back(entry);
102 } else if (dataType == DataType::UPDATE) {
103 updatedEntries_.push_back(entry);
104 } else if (dataType == DataType::DELETE) {
105 deletedEntries_.push_back(entry);
106 }
107 return E_OK;
108 }
109
InsertConflictedItem(const DataItemInfo & itemInfo,bool isOriginal)110 int SingleVerNaturalStoreCommitNotifyData::InsertConflictedItem(const DataItemInfo &itemInfo, bool isOriginal)
111 {
112 Key hashKey;
113 DBCommon::CalcValueHash(itemInfo.dataItem.key, hashKey);
114 if (!IsKeyPropSet(hashKey)) {
115 LOGE("key property not set.");
116 return E_OK;
117 }
118 // key not exist in db
119 if (keyPropRecord_[hashKey].existStatus == ExistStatus::NONE) {
120 return E_OK;
121 }
122
123 auto iter = orgDataItem_.find(itemInfo.dataItem.key);
124 if (iter == orgDataItem_.end()) {
125 if (isOriginal) {
126 orgDataItem_[itemInfo.dataItem.key] = itemInfo;
127 }
128 return E_OK;
129 }
130 if (!isOriginal) {
131 PutIntoConflictData(iter->second, itemInfo);
132 }
133
134 return E_OK;
135 }
136
FilterEntriesByKey(const std::list<Entry> & entries,const Key & filterKey,int & errCode)137 const std::list<Entry> SingleVerNaturalStoreCommitNotifyData::FilterEntriesByKey(
138 const std::list<Entry> &entries, const Key &filterKey, int &errCode)
139 {
140 errCode = E_OK;
141 if (filterKey.empty()) {
142 return entries;
143 }
144 std::list<Entry> filterEntries;
145 for (const auto &entry : entries) {
146 if (entry.key == filterKey) {
147 filterEntries.push_back(entry);
148 }
149 }
150 return filterEntries;
151 }
152
DeleteEntry(const Key & key,std::list<Entry> & entries) const153 void SingleVerNaturalStoreCommitNotifyData::DeleteEntry(const Key &key, std::list<Entry> &entries) const
154 {
155 if (entries.empty()) {
156 return;
157 }
158 entries.remove_if([&key](const Entry &entry) {
159 return entry.key == key;
160 });
161 }
162
DeleteEntryByKey(const Key & key,DataType type)163 void SingleVerNaturalStoreCommitNotifyData::DeleteEntryByKey(const Key &key, DataType type)
164 {
165 if (type == DataType::INSERT) {
166 DeleteEntry(key, insertedEntries_);
167 }
168
169 if (type == DataType::UPDATE) {
170 DeleteEntry(key, updatedEntries_);
171 }
172
173 if (type == DataType::DELETE) {
174 DeleteEntry(key, deletedEntries_);
175 }
176 }
177
InitKeyPropRecord(const Key & key,ExistStatus status)178 void SingleVerNaturalStoreCommitNotifyData::InitKeyPropRecord(const Key &key, ExistStatus status)
179 {
180 // check if key status set before, we can only set key status at the first time
181 if (IsKeyPropSet(key)) {
182 return;
183 }
184
185 keyPropRecord_[key].existStatus = status;
186 }
187
SetConflictedNotifiedFlag(int conflictedFlag)188 void SingleVerNaturalStoreCommitNotifyData::SetConflictedNotifiedFlag(int conflictedFlag)
189 {
190 conflictedFlag_ = conflictedFlag;
191 }
192
GetConflictedNotifiedFlag() const193 int SingleVerNaturalStoreCommitNotifyData::GetConflictedNotifiedFlag() const
194 {
195 return conflictedFlag_;
196 }
197
IsConflictedNotifyMatched(const DataItem & itemPut,const DataItem & itemGet) const198 bool SingleVerNaturalStoreCommitNotifyData::IsConflictedNotifyMatched(const DataItem &itemPut,
199 const DataItem &itemGet) const
200 {
201 int dataConflictedType = 0;
202 // Local put
203 if ((itemPut.flag & DataItem::LOCAL_FLAG) != 0) {
204 dataConflictedType = SINGLE_VER_CONFLICT_NATIVE_ALL;
205 } else {
206 // Compare the origin device of the get and put item.
207 if (itemPut.origDev != itemGet.origDev) {
208 dataConflictedType = SINGLE_VER_CONFLICT_FOREIGN_KEY_ORIG;
209 } else {
210 dataConflictedType = SINGLE_VER_CONFLICT_FOREIGN_KEY_ONLY;
211 }
212 }
213
214 int conflictedFlag = GetConflictedNotifiedFlag();
215 LOGD("flag bind kvdb is %d, current data conflicted flag is %d", conflictedFlag, dataConflictedType);
216 return (static_cast<uint32_t>(conflictedFlag) & static_cast<uint32_t>(dataConflictedType)) != 0;
217 }
218
PutIntoConflictData(const DataItemInfo & orgItemInfo,const DataItemInfo & newItemInfo)219 void SingleVerNaturalStoreCommitNotifyData::PutIntoConflictData(const DataItemInfo &orgItemInfo,
220 const DataItemInfo &newItemInfo)
221 {
222 if (orgItemInfo.dataItem.value == newItemInfo.dataItem.value &&
223 orgItemInfo.dataItem.origDev == newItemInfo.dataItem.origDev &&
224 orgItemInfo.dataItem.flag == newItemInfo.dataItem.flag &&
225 orgItemInfo.deviceName == newItemInfo.deviceName) {
226 LOGW("same data no need to put.");
227 return;
228 }
229
230 KvDBConflictEntry conflictData;
231 // Local put
232 if (newItemInfo.isLocal) {
233 conflictData.type = SingleVerNaturalStoreCommitNotifyData::SINGLE_VER_CONFLICT_NATIVE_ALL;
234 } else {
235 // Compare the origin device of the get and put item.
236 conflictData.type = ((newItemInfo.dataItem.origDev != orgItemInfo.dataItem.origDev) ?
237 SingleVerNaturalStoreCommitNotifyData::SINGLE_VER_CONFLICT_FOREIGN_KEY_ORIG :
238 SingleVerNaturalStoreCommitNotifyData::SINGLE_VER_CONFLICT_FOREIGN_KEY_ONLY);
239 }
240
241 bool isDeleted = ((orgItemInfo.dataItem.flag & DataItem::DELETE_FLAG) == DataItem::DELETE_FLAG);
242 conflictData.oldData = {orgItemInfo.dataItem.value, isDeleted, true};
243
244 isDeleted = ((newItemInfo.dataItem.flag & DataItem::DELETE_FLAG) == DataItem::DELETE_FLAG);
245 conflictData.newData = {newItemInfo.dataItem.value, isDeleted, newItemInfo.isLocal};
246
247 // If the new item is deleted, just using the key of the old data item.
248 // If the items are all deleted, this function should not be executed.
249 conflictData.key = isDeleted ? orgItemInfo.dataItem.key : newItemInfo.dataItem.key;
250 if (newItemInfo.dataItem.writeTimestamp <= orgItemInfo.dataItem.writeTimestamp) {
251 std::swap(conflictData.newData, conflictData.oldData);
252 }
253
254 DeleteConflictEntry(conflictData.key);
255 conflictedEntries_.push_back(std::move(conflictData));
256 }
257
DeleteConflictEntry(const Key & key)258 void SingleVerNaturalStoreCommitNotifyData::DeleteConflictEntry(const Key &key)
259 {
260 if (conflictedEntries_.empty()) {
261 return;
262 }
263 auto iter = conflictedEntries_.begin();
264 for (; iter != conflictedEntries_.end(); ++iter) {
265 if (iter->key == key) {
266 conflictedEntries_.erase(iter);
267 return;
268 }
269 }
270 }
271
IsKeyPropSet(const Key & key) const272 bool SingleVerNaturalStoreCommitNotifyData::IsKeyPropSet(const Key &key) const
273 {
274 // check if key status set before
275 return (keyPropRecord_.find(key) != keyPropRecord_.end());
276 }
277
278 DEFINE_OBJECT_TAG_FACILITIES(SingleVerNaturalStoreCommitNotifyData)
279 } // namespace DistributedDB
280