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