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 "intercepted_data_impl.h"
17 #include "db_common.h"
18 #include "db_constant.h"
19 #include "generic_single_ver_kv_entry.h"
20 #include "parcel.h"
21 #include "version.h"
22
23 namespace DistributedDB {
24 namespace {
CheckKey(const Key & key)25 bool CheckKey(const Key &key)
26 {
27 if (key.empty() || key.size() > DBConstant::MAX_KEY_SIZE) {
28 LOGE("Key is too large:%zu.", key.size());
29 return false;
30 }
31 return true;
32 }
33
CheckValue(const Value & value,const std::function<int (const Value &)> & checkSchema)34 bool CheckValue(const Value &value, const std::function<int(const Value &)> &checkSchema)
35 {
36 if (value.size() > DBConstant::MAX_VALUE_SIZE) {
37 LOGE("Value is too large:%zu.", value.size());
38 return false;
39 }
40
41 if (checkSchema == nullptr) {
42 LOGE("Check schema failed, no check func.");
43 return false;
44 }
45
46 int errCode = checkSchema(value);
47 if (errCode != E_OK) {
48 LOGE("Check schema failed, value is invalid:%d.", errCode);
49 return false;
50 }
51 return true;
52 }
53
CheckLength(size_t len,size_t maxPacketSize)54 bool CheckLength(size_t len, size_t maxPacketSize)
55 {
56 if (len > maxPacketSize) {
57 LOGE("Packet is too large:%zu.", len);
58 return false;
59 }
60 return true;
61 }
62 } // anonymous namespace
63
InterceptedDataImpl(std::vector<SingleVerKvEntry * > dataItems,const std::function<int (const Value &)> & checkSchema)64 InterceptedDataImpl::InterceptedDataImpl(std::vector<SingleVerKvEntry *> dataItems,
65 const std::function<int(const Value&)> &checkSchema)
66 : kvEntriesReady_(false),
67 isError_(false),
68 totalLength_(),
69 maxPacketSize_(),
70 checkSchema_(checkSchema),
71 dataItems_(dataItems),
72 kvEntries_(),
73 indexes_()
74 {
75 totalLength_ = GenericSingleVerKvEntry::CalculateLens(dataItems, SOFTWARE_VERSION_CURRENT);
76 // New packet cannot exceed both twice the MTU and twice the original size.
77 // Besides, it cannot exceed 30 MB.
78 maxPacketSize_ = std::min(DBConstant::MAX_SYNC_BLOCK_SIZE,
79 std::max(totalLength_, static_cast<size_t>(DBConstant::MAX_MTU_SIZE)) * 2); // 2 times MAX_MTU size
80 }
81
~InterceptedDataImpl()82 InterceptedDataImpl::~InterceptedDataImpl()
83 {}
84
GetEntries()85 std::vector<KVEntry> InterceptedDataImpl::GetEntries()
86 {
87 if (!kvEntriesReady_) {
88 GetKvEntries();
89 }
90 return kvEntries_;
91 }
92
CheckIndex(size_t index)93 bool InterceptedDataImpl::CheckIndex(size_t index)
94 {
95 if (!kvEntriesReady_) {
96 GetKvEntries();
97 }
98
99 if (index >= kvEntries_.size()) {
100 LOGE("Index is too large:%zu, size:%zu.", index, kvEntries_.size());
101 return false;
102 }
103 return true;
104 }
105
ModifyKey(size_t index,const Key & newKey)106 DBStatus InterceptedDataImpl::ModifyKey(size_t index, const Key &newKey)
107 {
108 // Check index.
109 if (!CheckIndex(index)) {
110 isError_ = true;
111 return INVALID_ARGS;
112 }
113
114 // Check key.
115 if (!CheckKey(newKey)) {
116 isError_ = true;
117 return INVALID_ARGS;
118 }
119
120 // Check length.
121 const auto &oldKey = dataItems_[indexes_[index]]->GetKey();
122 size_t newLength = totalLength_ - Parcel::GetVectorCharLen(oldKey) + Parcel::GetVectorCharLen(newKey);
123 if (!CheckLength(newLength, maxPacketSize_)) {
124 isError_ = true;
125 return INVALID_ARGS;
126 }
127 totalLength_ = newLength;
128
129 // Modify data
130 auto entry = dataItems_[indexes_[index]];
131 entry->SetKey(newKey);
132 Key hashKey;
133 int errCode = DBCommon::CalcValueHash(newKey, hashKey);
134 if (errCode != E_OK) {
135 LOGE("Calc hashkey failed.");
136 isError_ = true;
137 return INVALID_ARGS;
138 }
139 entry->SetHashKey(hashKey);
140 return OK;
141 }
142
ModifyValue(size_t index,const Value & newValue)143 DBStatus InterceptedDataImpl::ModifyValue(size_t index, const Value &newValue)
144 {
145 // Check index.
146 if (!CheckIndex(index)) {
147 isError_ = true;
148 return INVALID_ARGS;
149 }
150
151 // Check value.
152 if (!CheckValue(newValue, checkSchema_)) {
153 isError_ = true;
154 return INVALID_ARGS;
155 }
156
157 // Check length.
158 const auto &oldValue = dataItems_[indexes_[index]]->GetValue();
159 size_t newLength = totalLength_ - Parcel::GetVectorCharLen(oldValue) + Parcel::GetVectorCharLen(newValue);
160 if (!CheckLength(newLength, maxPacketSize_)) {
161 isError_ = true;
162 return INVALID_ARGS;
163 }
164 totalLength_ = newLength;
165
166 // Modify data
167 auto entry = dataItems_[indexes_[index]];
168 entry->SetValue(newValue);
169 return OK;
170 }
171
IsError() const172 bool InterceptedDataImpl::IsError() const
173 {
174 return isError_;
175 }
176
GetKvEntries()177 void InterceptedDataImpl::GetKvEntries()
178 {
179 for (size_t i = 0; i < dataItems_.size(); ++i) {
180 const auto &kvEntry = dataItems_[i];
181 if (kvEntry == nullptr) {
182 continue;
183 }
184 if ((kvEntry->GetFlag() & DataItem::DELETE_FLAG) == 0) { // For deleted data, do not modify.
185 kvEntries_.push_back({ kvEntry->GetKey(), kvEntry->GetValue() });
186 indexes_.push_back(i);
187 }
188 }
189 kvEntriesReady_ = true;
190 }
191 } // namespace DistributedDB
192
193