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