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 #ifndef OMIT_MULTI_VER
16 #include "distributed_crud_transaction_tools.h"
17 #include <gtest/gtest.h>
18 #include <dirent.h>
19 #include <string>
20 #include <sys/stat.h>
21 #include <random>
22 #include <algorithm>
23 #include <thread>
24 #include <cstdio>
25 #include <chrono>
26 #include <cmath>
27 
28 #include "distributed_test_tools.h"
29 #include "distributeddb_data_generator.h"
30 #include "kv_store_delegate.h"
31 #include "kv_store_delegate_manager.h"
32 
33 using namespace std;
34 using namespace chrono;
35 using namespace std::placeholders;
36 using namespace DistributedDB;
37 using namespace DistributedDBDataGenerator;
38 
DistributedCrudTransactionTools(KvStoreDelegate & delegate,CrudMode first,CrudMode second,bool preset,bool isLocal)39 DistributedCrudTransactionTools::DistributedCrudTransactionTools(KvStoreDelegate &delegate,
40     CrudMode first, CrudMode second, bool preset, bool isLocal)
41 {
42     this->storeDelegate_ = &delegate,
43     this->firstMode_ = first;
44     this->secondMode_ = second;
45     this->needPresetData_ = preset;
46     this->isLocal_ = isLocal;
47 }
48 
PresetValue()49 bool DistributedCrudTransactionTools::PresetValue()
50 {
51     vector<Entry> entriesBatch;
52     vector<Key> allKeys;
53     GenerateRecords(this->presetCount_, DEFAULT_START, allKeys, entriesBatch);
54 
55     for (unsigned long i = 0; i < this->presetCount_; ++i) {
56         entriesBatch[i].value = GetValueWithInt(this->presetValue_);
57     }
58     DBStatus status = DistributedTestTools::PutBatch(*storeDelegate_, entriesBatch);
59     if (status != DistributedDB::OK) {
60         MST_LOG("PresetValue failed, status %d", status);
61         return false;
62     }
63     return true;
64 }
65 
CheckFirst()66 bool DistributedCrudTransactionTools::CheckFirst()
67 {
68     vector<Entry> values = DistributedTestTools::GetEntries(*storeDelegate_, KEY_SEARCH_4);
69     if (firstMode_ == CrudMode::PUT_BATCH) {
70         MST_LOG("[CHECK LOG]putbatch first %zu", values.size());
71         if (needPresetData_) {
72             if (values.size() != 0) {
73                 return GetIntValue(values[0].value) == presetValue_;
74             } else {
75                 return true;
76             }
77         } else {
78             return (values.size() == NO_RECORD) || (values.size() == presetCount_);
79         }
80     }
81     if (firstMode_ == CrudMode::UPDATE_BATCH) {
82         if (values.size() != presetCount_) {
83             return false;
84         }
85         for (unsigned long index = 0; index < values.size(); ++index) {
86             if (GetIntValue(values[index].value) != presetValue_) {
87                 return false;
88             }
89         }
90         return true;
91     }
92     if (firstMode_ == CrudMode::DELETE_BATCH || firstMode_ == CrudMode::CLEAR) {
93         MST_LOG("[CHECK LOG]check clear first %zu", values.size());
94         if ((values.size() > NO_RECORD) && (values.size() < presetCount_)) {
95             return false;
96         }
97         return (values.size() == NO_RECORD) ||
98             ((values.size() == presetCount_ && GetIntValue(values[0].value) == presetValue_));
99     }
100     return false;
101 }
102 
CheckSecond()103 bool DistributedCrudTransactionTools::CheckSecond()
104 {
105     if (secondMode_ == CrudMode::PUT) {
106         vector<Entry> values = DistributedTestTools::GetEntries(*storeDelegate_, KEY_SEARCH_4);
107         return values.size() == NO_RECORD || GetIntValue(values[0].value) == SMALL_VALUE_SIZE ||
108             GetIntValue(values[0].value) == presetValue_;
109     }
110     if (secondMode_ == CrudMode::DELETE) {
111         Key key0 = { 'k', '0' };
112         Value value = DistributedTestTools::Get(*storeDelegate_, key0);
113         return value.size() == NO_RECORD || GetIntValue(value) == presetValue_;
114     }
115     if (secondMode_ == CrudMode::PUT_BATCH) {
116         vector<Entry> values = DistributedTestTools::GetEntries(*storeDelegate_, KEY_SEARCH_4);
117         if ((values.size() != NO_RECORD) && (values.size() != presetCount_)) {
118             return false;
119         }
120         for (unsigned long index = 0; index < values.size(); ++index) {
121             if (GetIntValue(values[0].value) != presetValue_) {
122                 return false;
123             }
124         }
125         return true;
126     }
127     if (secondMode_ == CrudMode::DELETE_BATCH || secondMode_ == CrudMode::CLEAR) {
128         vector<Entry> values = DistributedTestTools::GetEntries(*storeDelegate_, KEY_SEARCH_4);
129         if ((values.size() != NO_RECORD) && (values.size() != presetCount_)) {
130             return false;
131         }
132         for (unsigned long index = 0; index < values.size(); ++index) {
133             if (GetIntValue(values[0].value) != presetValue_) {
134                 return false;
135             }
136         }
137         return true;
138     }
139     return false;
140 }
141 
Check()142 void DistributedCrudTransactionTools::Check()
143 {
144     while (!secondComplete_) {
145         if (!firstComplete_) {
146             bool result = CheckFirst();
147             if (!result) {
148                 MST_LOG("[CHECK LOG]check first failed;%d", success_);
149             }
150             MST_LOG("[CHECK LOG]firstComplete_ failed %d;", success_);
151             success_ = result;
152         } else if (firstComplete_ && !secondComplete_) {
153             bool result = CheckSecond();
154             if (!result) {
155                 MST_LOG("[CHECK LOG]check second failed;%d", success_);
156             }
157             MST_LOG("[CHECK LOG]secondComplete_ failed %d;", success_);
158             success_ = result;
159         }
160     }
161 }
162 
Action1(KvStoreDelegate & delegate)163 bool DistributedCrudTransactionTools::Action1(KvStoreDelegate &delegate)
164 {
165     MST_LOG("firstmode %d", static_cast<int>(firstMode_));
166     if (firstMode_ == CrudMode::PUT_BATCH) {
167         return DBStatus::OK == delegate.PutBatch(entriesBatch_);
168     } else if (firstMode_ == CrudMode::DELETE_BATCH) {
169         return DBStatus::OK == delegate.DeleteBatch(allKeys_) ||
170             DBStatus::NOT_FOUND == delegate.DeleteBatch(allKeys_);
171     } else if (firstMode_ == CrudMode::CLEAR) {
172         return DBStatus::OK == delegate.Clear();
173     } else {
174         MST_LOG("unknown first %d", static_cast<int>(firstMode_));
175         return false;
176     }
177 }
178 
Action2(KvStoreDelegate & delegate)179 bool DistributedCrudTransactionTools::Action2(KvStoreDelegate &delegate)
180 {
181     MST_LOG("secondmode %d", static_cast<int>(secondMode_));
182     if (secondMode_ == CrudMode::PUT) {
183         entriesBatch_[0].value = GetValueWithInt(SMALL_VALUE_SIZE);
184         return DBStatus::OK == delegate.Put(entriesBatch_[0].key, entriesBatch_[0].value);
185     } else if (secondMode_ == CrudMode::DELETE) {
186         return DBStatus::OK == delegate.Delete(entriesBatch_[0].key) ||
187             DBStatus::NOT_FOUND == delegate.DeleteBatch(allKeys_);
188     } else if (secondMode_ == CrudMode::CLEAR) {
189         return DBStatus::OK == delegate.Clear();
190     } else if (secondMode_ == CrudMode::PUT_BATCH) {
191         return DBStatus::OK == delegate.PutBatch(entriesBatch_);
192     } else {
193         MST_LOG("unknown secondmode %d", static_cast<int>(secondMode_));
194         return false;
195     }
196 }
197 
SleepOneSecond()198 void SleepOneSecond()
199 {
200     std::this_thread::sleep_for(std::chrono::duration<int>(1));
201 }
202 
DeleteDataBase(bool success_,KvStoreDelegate * & delegate1,KvStoreDelegate * & delegate2,KvStoreDelegateManager * & delegateManager1,KvStoreDelegateManager * & delegateManager2)203 bool DeleteDataBase(bool success_, KvStoreDelegate *&delegate1, KvStoreDelegate *&delegate2,
204     KvStoreDelegateManager *&delegateManager1, KvStoreDelegateManager *&delegateManager2)
205 {
206     SleepOneSecond();
207     if ((delegateManager1->CloseKvStore(delegate1) != OK) ||
208         (delegateManager2->CloseKvStore(delegate2) != OK)) {
209         MST_LOG("closed failed!");
210     }
211     delegate1 = nullptr;
212     delegate2 = nullptr;
213     delete delegateManager1;
214     delegateManager1 = nullptr;
215     delete delegateManager2;
216     delegateManager2 = nullptr;
217     MST_LOG("[CHECK LOG]check result %d", success_);
218     return success_;
219 }
220 
testCrudTransaction()221 bool DistributedCrudTransactionTools::testCrudTransaction()
222 {
223     if (storeDelegate_ == nullptr) {
224         return false;
225     }
226 
227     DistributedTestTools::Clear(*storeDelegate_);
228     if (this->needPresetData_) {
229         if (!PresetValue()) {
230             return false;
231         }
232     }
233     GenerateRecords(this->presetCount_, DEFAULT_START, allKeys_, entriesBatch_);
234     for (unsigned long i = 0; i < this->presetCount_; ++i) {
235         entriesBatch_[i].value = GetValueWithInt(this->presetValue_);
236     }
237 
238     KvStoreDelegate *delegate1 = nullptr;
239     KvStoreDelegateManager *delegateManager1 = nullptr;
240     delegate1 = DistributedTestTools::GetDelegateSuccess(delegateManager1,
241         g_kvdbParameter1, g_kvOption);
242     if (delegateManager1 == nullptr || delegate1 == nullptr) {
243         MST_LOG("[testCrudTransaction] delegateManager1 or delegate1 is nullptr");
244         return false;
245     }
246 
247     KvStoreDelegate *delegate2 = nullptr;
248     KvStoreDelegateManager *delegateManager2 = nullptr;
249     delegate2 = DistributedTestTools::GetDelegateSuccess(delegateManager2,
250         g_kvdbParameter1, g_kvOption);
251     if (delegateManager2 == nullptr || delegate2 == nullptr) {
252         MST_LOG("[testCrudTransaction] delegateManager2 or delegate2 is nullptr");
253         return false;
254     }
255 
256     std::thread th(&DistributedCrudTransactionTools::Check, this);
257     th.detach();
258 
259     if (!Action1(*delegate1)) {
260         MST_LOG("action1 failed");
261         goto ERROR;
262     }
263     firstComplete_ = true;
264     MST_LOG("firstComplete_");
265 
266     if (!Action2(*delegate2)) {
267         MST_LOG("action2 failed");
268         goto ERROR;
269     }
270     secondComplete_ = true;
271     return DeleteDataBase(success_, delegate1, delegate2, delegateManager1, delegateManager2);
272 ERROR:
273     secondComplete_ = true;
274     return false;
275 }
276 #endif // OMIT_MULTI_VER