react-native-mmkv 3.3.0 → 4.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/CMakeLists.txt +18 -9
- package/android/build.gradle +6 -2
- package/cpp/{MMKVManagedBuffer.h → ManagedMMBuffer.h} +6 -6
- package/cpp/MmkvHostObject.cpp +13 -8
- package/cpp/MmkvHostObject.h +1 -2
- package/cpp/MmkvTypes.h +50 -0
- package/cpp/NativeMmkvModule.cpp +3 -3
- package/cpp/NativeMmkvModule.h +1 -8
- package/package.json +22 -23
- package/react-native-mmkv.podspec +3 -9
- package/react-native.config.js +9 -0
- package/MMKV/Core/CMakeLists.txt +0 -172
- package/MMKV/Core/CodedInputData.cpp +0 -252
- package/MMKV/Core/CodedInputData.h +0 -87
- package/MMKV/Core/CodedInputDataCrypt.cpp +0 -280
- package/MMKV/Core/CodedInputDataCrypt.h +0 -87
- package/MMKV/Core/CodedInputDataCrypt_OSX.cpp +0 -62
- package/MMKV/Core/CodedInputData_OSX.cpp +0 -92
- package/MMKV/Core/CodedOutputData.cpp +0 -186
- package/MMKV/Core/CodedOutputData.h +0 -88
- package/MMKV/Core/Core.xcodeproj/project.pbxproj +0 -707
- package/MMKV/Core/Core.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/MMKV/Core/Core.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/Core.xcscheme +0 -67
- package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/MMKVWatchCore.xcscheme +0 -67
- package/MMKV/Core/InterProcessLock.cpp +0 -186
- package/MMKV/Core/InterProcessLock.h +0 -119
- package/MMKV/Core/InterProcessLock_Android.cpp +0 -103
- package/MMKV/Core/InterProcessLock_Win32.cpp +0 -108
- package/MMKV/Core/KeyValueHolder.cpp +0 -236
- package/MMKV/Core/KeyValueHolder.h +0 -122
- package/MMKV/Core/MMBuffer.cpp +0 -210
- package/MMKV/Core/MMBuffer.h +0 -111
- package/MMKV/Core/MMKV.cpp +0 -1702
- package/MMKV/Core/MMKV.h +0 -595
- package/MMKV/Core/MMKVLog.cpp +0 -127
- package/MMKV/Core/MMKVLog.h +0 -86
- package/MMKV/Core/MMKVLog_Android.cpp +0 -134
- package/MMKV/Core/MMKVMetaInfo.hpp +0 -99
- package/MMKV/Core/MMKVPredef.h +0 -293
- package/MMKV/Core/MMKV_Android.cpp +0 -261
- package/MMKV/Core/MMKV_IO.cpp +0 -1905
- package/MMKV/Core/MMKV_IO.h +0 -57
- package/MMKV/Core/MMKV_OSX.cpp +0 -423
- package/MMKV/Core/MMKV_OSX.h +0 -57
- package/MMKV/Core/MemoryFile.cpp +0 -603
- package/MMKV/Core/MemoryFile.h +0 -194
- package/MMKV/Core/MemoryFile_Android.cpp +0 -236
- package/MMKV/Core/MemoryFile_Linux.cpp +0 -125
- package/MMKV/Core/MemoryFile_OSX.cpp +0 -142
- package/MMKV/Core/MemoryFile_Win32.cpp +0 -554
- package/MMKV/Core/MiniPBCoder.cpp +0 -672
- package/MMKV/Core/MiniPBCoder.h +0 -151
- package/MMKV/Core/MiniPBCoder_OSX.cpp +0 -237
- package/MMKV/Core/PBEncodeItem.hpp +0 -104
- package/MMKV/Core/PBUtility.cpp +0 -61
- package/MMKV/Core/PBUtility.h +0 -148
- package/MMKV/Core/ScopedLock.hpp +0 -69
- package/MMKV/Core/ThreadLock.cpp +0 -75
- package/MMKV/Core/ThreadLock.h +0 -81
- package/MMKV/Core/ThreadLock_Win32.cpp +0 -89
- package/MMKV/Core/aes/AESCrypt.cpp +0 -273
- package/MMKV/Core/aes/AESCrypt.h +0 -112
- package/MMKV/Core/aes/openssl/openssl_aes-armv4.S +0 -1243
- package/MMKV/Core/aes/openssl/openssl_aes.h +0 -130
- package/MMKV/Core/aes/openssl/openssl_aes_core.cpp +0 -1044
- package/MMKV/Core/aes/openssl/openssl_aes_locl.h +0 -38
- package/MMKV/Core/aes/openssl/openssl_aesv8-armx.S +0 -308
- package/MMKV/Core/aes/openssl/openssl_arm_arch.h +0 -84
- package/MMKV/Core/aes/openssl/openssl_cfb128.cpp +0 -97
- package/MMKV/Core/aes/openssl/openssl_md32_common.h +0 -254
- package/MMKV/Core/aes/openssl/openssl_md5.h +0 -49
- package/MMKV/Core/aes/openssl/openssl_md5_dgst.cpp +0 -166
- package/MMKV/Core/aes/openssl/openssl_md5_locl.h +0 -75
- package/MMKV/Core/aes/openssl/openssl_md5_one.cpp +0 -30
- package/MMKV/Core/aes/openssl/openssl_opensslconf.h +0 -271
- package/MMKV/Core/core.vcxproj +0 -288
- package/MMKV/Core/core.vcxproj.filters +0 -150
- package/MMKV/Core/crc32/Checksum.h +0 -75
- package/MMKV/Core/crc32/crc32_armv8.cpp +0 -134
- package/MMKV/Core/crc32/zlib/CMakeLists.txt +0 -60
- package/MMKV/Core/crc32/zlib/crc32.cpp +0 -55
- package/MMKV/Core/crc32/zlib/crc32.h +0 -48
- package/MMKV/Core/crc32/zlib/zconf.h +0 -380
- package/MMKV/Core/crc32/zlib/zutil.h +0 -25
- package/MMKV/LICENSE.TXT +0 -193
- package/MMKV/README.md +0 -354
package/MMKV/Core/MMKV_IO.cpp
DELETED
|
@@ -1,1905 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Tencent is pleased to support the open source community by making
|
|
3
|
-
* MMKV available.
|
|
4
|
-
*
|
|
5
|
-
* Copyright (C) 2020 THL A29 Limited, a Tencent company.
|
|
6
|
-
* All rights reserved.
|
|
7
|
-
*
|
|
8
|
-
* Licensed under the BSD 3-Clause License (the "License"); you may not use
|
|
9
|
-
* this file except in compliance with the License. You may obtain a copy of
|
|
10
|
-
* the License at
|
|
11
|
-
*
|
|
12
|
-
* https://opensource.org/licenses/BSD-3-Clause
|
|
13
|
-
*
|
|
14
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
15
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
16
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17
|
-
* See the License for the specific language governing permissions and
|
|
18
|
-
* limitations under the License.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
#include "MMKV_IO.h"
|
|
22
|
-
#include "CodedInputData.h"
|
|
23
|
-
#include "CodedOutputData.h"
|
|
24
|
-
#include "InterProcessLock.h"
|
|
25
|
-
#include "MMBuffer.h"
|
|
26
|
-
#include "MMKVLog.h"
|
|
27
|
-
#include "MMKVMetaInfo.hpp"
|
|
28
|
-
#include "MemoryFile.h"
|
|
29
|
-
#include "MiniPBCoder.h"
|
|
30
|
-
#include "PBUtility.h"
|
|
31
|
-
#include "ScopedLock.hpp"
|
|
32
|
-
#include "ThreadLock.h"
|
|
33
|
-
#include "aes/AESCrypt.h"
|
|
34
|
-
#include "aes/openssl/openssl_aes.h"
|
|
35
|
-
#include "aes/openssl/openssl_md5.h"
|
|
36
|
-
#include "crc32/Checksum.h"
|
|
37
|
-
#include <algorithm>
|
|
38
|
-
#include <cassert>
|
|
39
|
-
#include <cstring>
|
|
40
|
-
#include <ctime>
|
|
41
|
-
|
|
42
|
-
#ifdef MMKV_IOS
|
|
43
|
-
# include "MMKV_OSX.h"
|
|
44
|
-
#endif
|
|
45
|
-
|
|
46
|
-
#ifdef MMKV_APPLE
|
|
47
|
-
# if __has_feature(objc_arc)
|
|
48
|
-
# error This file must be compiled with MRC. Use -fno-objc-arc flag.
|
|
49
|
-
# endif
|
|
50
|
-
#endif // MMKV_APPLE
|
|
51
|
-
|
|
52
|
-
#ifndef MMKV_WIN32
|
|
53
|
-
# include <unistd.h>
|
|
54
|
-
#endif
|
|
55
|
-
|
|
56
|
-
using namespace std;
|
|
57
|
-
using namespace mmkv;
|
|
58
|
-
using KVHolderRet_t = std::pair<bool, KeyValueHolder>;
|
|
59
|
-
extern ThreadLock *g_instanceLock;
|
|
60
|
-
extern unordered_map<string, MMKV *> *g_instanceDic;
|
|
61
|
-
|
|
62
|
-
MMKV_NAMESPACE_BEGIN
|
|
63
|
-
|
|
64
|
-
void MMKV::loadFromFile() {
|
|
65
|
-
loadMetaInfoAndCheck();
|
|
66
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
67
|
-
if (m_crypter) {
|
|
68
|
-
if (m_metaInfo->m_version >= MMKVVersionRandomIV) {
|
|
69
|
-
m_crypter->resetIV(m_metaInfo->m_vector, sizeof(m_metaInfo->m_vector));
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
#endif
|
|
73
|
-
if (!m_file->isFileValid()) {
|
|
74
|
-
m_file->reloadFromFile(m_expectedCapacity);
|
|
75
|
-
}
|
|
76
|
-
if (!m_file->isFileValid()) {
|
|
77
|
-
MMKVError("file [%s] not valid", m_path.c_str());
|
|
78
|
-
} else {
|
|
79
|
-
// error checking
|
|
80
|
-
bool loadFromFile = false, needFullWriteback = false;
|
|
81
|
-
checkDataValid(loadFromFile, needFullWriteback);
|
|
82
|
-
MMKVInfo("loading [%s] with %zu actual size, file size %zu, InterProcess %d, meta info "
|
|
83
|
-
"version:%u",
|
|
84
|
-
m_mmapID.c_str(), m_actualSize, m_file->getFileSize(), isMultiProcess(), m_metaInfo->m_version);
|
|
85
|
-
auto ptr = (uint8_t *) m_file->getMemory();
|
|
86
|
-
// loading
|
|
87
|
-
if (loadFromFile && m_actualSize > 0) {
|
|
88
|
-
MMKVInfo("loading [%s] with crc %u sequence %u version %u", m_mmapID.c_str(), m_metaInfo->m_crcDigest,
|
|
89
|
-
m_metaInfo->m_sequence, m_metaInfo->m_version);
|
|
90
|
-
MMBuffer inputBuffer(ptr + Fixed32Size, m_actualSize, MMBufferNoCopy);
|
|
91
|
-
if (m_crypter) {
|
|
92
|
-
clearDictionary(m_dicCrypt);
|
|
93
|
-
} else {
|
|
94
|
-
clearDictionary(m_dic);
|
|
95
|
-
}
|
|
96
|
-
if (needFullWriteback) {
|
|
97
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
98
|
-
if (m_crypter) {
|
|
99
|
-
MiniPBCoder::greedyDecodeMap(*m_dicCrypt, inputBuffer, m_crypter);
|
|
100
|
-
} else
|
|
101
|
-
#endif
|
|
102
|
-
{
|
|
103
|
-
MiniPBCoder::greedyDecodeMap(*m_dic, inputBuffer);
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
107
|
-
if (m_crypter) {
|
|
108
|
-
MiniPBCoder::decodeMap(*m_dicCrypt, inputBuffer, m_crypter);
|
|
109
|
-
} else
|
|
110
|
-
#endif
|
|
111
|
-
{
|
|
112
|
-
MiniPBCoder::decodeMap(*m_dic, inputBuffer);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
|
|
116
|
-
m_output->seek(m_actualSize);
|
|
117
|
-
if (needFullWriteback) {
|
|
118
|
-
fullWriteback();
|
|
119
|
-
}
|
|
120
|
-
} else {
|
|
121
|
-
// file not valid or empty, discard everything
|
|
122
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
123
|
-
|
|
124
|
-
m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
|
|
125
|
-
if (m_actualSize > 0) {
|
|
126
|
-
writeActualSize(0, 0, nullptr, IncreaseSequence);
|
|
127
|
-
sync(MMKV_SYNC);
|
|
128
|
-
} else {
|
|
129
|
-
writeActualSize(0, 0, nullptr, KeepSequence);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
auto count = m_crypter ? m_dicCrypt->size() : m_dic->size();
|
|
133
|
-
MMKVInfo("loaded [%s] with %zu key-values", m_mmapID.c_str(), count);
|
|
134
|
-
// auto keys = allKeys();
|
|
135
|
-
// for (size_t index = 0; index < count; index++) {
|
|
136
|
-
// MMKVInfo("key[%llu]: %s", index, keys[index].c_str());
|
|
137
|
-
// }
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
m_needLoadFromFile = false;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// read from last m_position
|
|
144
|
-
void MMKV::partialLoadFromFile() {
|
|
145
|
-
if (!m_file->isFileValid()) {
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
m_metaInfo->read(m_metaFile->getMemory());
|
|
149
|
-
|
|
150
|
-
size_t oldActualSize = m_actualSize;
|
|
151
|
-
m_actualSize = readActualSize();
|
|
152
|
-
auto fileSize = m_file->getFileSize();
|
|
153
|
-
MMKVDebug("loading [%s] with file size %zu, oldActualSize %zu, newActualSize %zu", m_mmapID.c_str(), fileSize,
|
|
154
|
-
oldActualSize, m_actualSize);
|
|
155
|
-
|
|
156
|
-
if (m_actualSize > 0) {
|
|
157
|
-
if (m_actualSize < fileSize && m_actualSize + Fixed32Size <= fileSize) {
|
|
158
|
-
if (m_actualSize > oldActualSize) {
|
|
159
|
-
auto position = oldActualSize;
|
|
160
|
-
size_t addedSize = m_actualSize - position;
|
|
161
|
-
auto basePtr = (uint8_t *) m_file->getMemory() + Fixed32Size;
|
|
162
|
-
// incremental update crc digest
|
|
163
|
-
m_crcDigest = (uint32_t) CRC32(m_crcDigest, basePtr + position, (z_size_t) addedSize);
|
|
164
|
-
if (m_crcDigest == m_metaInfo->m_crcDigest) {
|
|
165
|
-
MMBuffer inputBuffer(basePtr, m_actualSize, MMBufferNoCopy);
|
|
166
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
167
|
-
if (m_crypter) {
|
|
168
|
-
MiniPBCoder::greedyDecodeMap(*m_dicCrypt, inputBuffer, m_crypter, position);
|
|
169
|
-
} else
|
|
170
|
-
#endif
|
|
171
|
-
{
|
|
172
|
-
MiniPBCoder::greedyDecodeMap(*m_dic, inputBuffer, position);
|
|
173
|
-
}
|
|
174
|
-
m_output->seek(addedSize);
|
|
175
|
-
m_hasFullWriteback = false;
|
|
176
|
-
|
|
177
|
-
[[maybe_unused]] auto count = m_crypter ? m_dicCrypt->size() : m_dic->size();
|
|
178
|
-
MMKVDebug("partial loaded [%s] with %zu values", m_mmapID.c_str(), count);
|
|
179
|
-
return;
|
|
180
|
-
} else {
|
|
181
|
-
MMKVError("m_crcDigest[%u] != m_metaInfo->m_crcDigest[%u]", m_crcDigest, m_metaInfo->m_crcDigest);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
// something is wrong, do a full load
|
|
187
|
-
clearMemoryCache();
|
|
188
|
-
loadFromFile();
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
void MMKV::loadMetaInfoAndCheck() {
|
|
192
|
-
if (!m_metaFile->isFileValid()) {
|
|
193
|
-
m_metaFile->reloadFromFile();
|
|
194
|
-
}
|
|
195
|
-
if (!m_metaFile->isFileValid()) {
|
|
196
|
-
MMKVError("file [%s] not valid", m_metaFile->getPath().c_str());
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
m_metaInfo->read(m_metaFile->getMemory());
|
|
201
|
-
// the meta file is in specious status
|
|
202
|
-
if (m_metaInfo->m_version >= MMKVVersionHolder) {
|
|
203
|
-
MMKVWarning("meta file [%s] in specious state, version %u, flags 0x%llx", m_mmapID.c_str(),
|
|
204
|
-
m_metaInfo->m_version, m_metaInfo->m_flags);
|
|
205
|
-
|
|
206
|
-
// MMKVVersionActualSize is the last version we don't check meta file
|
|
207
|
-
m_metaInfo->m_version = MMKVVersionActualSize;
|
|
208
|
-
m_metaInfo->m_flags = 0;
|
|
209
|
-
m_metaInfo->write(m_metaFile->getMemory());
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (m_metaInfo->m_version >= MMKVVersionFlag) {
|
|
213
|
-
m_enableKeyExpire = m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre);
|
|
214
|
-
if (m_enableKeyExpire && m_enableCompareBeforeSet) {
|
|
215
|
-
MMKVError("enableCompareBeforeSet will be invalid when Expiration is on");
|
|
216
|
-
m_enableCompareBeforeSet = false;
|
|
217
|
-
}
|
|
218
|
-
MMKVInfo("meta file [%s] has flag [%llu]", m_mmapID.c_str(), m_metaInfo->m_flags);
|
|
219
|
-
} else {
|
|
220
|
-
if (m_metaInfo->m_flags != 0) {
|
|
221
|
-
m_metaInfo->m_flags = 0;
|
|
222
|
-
m_metaInfo->write(m_metaFile->getMemory());
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
void MMKV::checkDataValid(bool &loadFromFile, bool &needFullWriteback) {
|
|
228
|
-
// try auto recover from last confirmed location
|
|
229
|
-
auto fileSize = m_file->getFileSize();
|
|
230
|
-
auto checkLastConfirmedInfo = [&] {
|
|
231
|
-
if (m_metaInfo->m_version >= MMKVVersionActualSize) {
|
|
232
|
-
// downgrade & upgrade support
|
|
233
|
-
uint32_t oldStyleActualSize = 0;
|
|
234
|
-
memcpy(&oldStyleActualSize, m_file->getMemory(), Fixed32Size);
|
|
235
|
-
if (oldStyleActualSize != m_actualSize) {
|
|
236
|
-
MMKVWarning("oldStyleActualSize %u not equal to meta actual size %lu", oldStyleActualSize,
|
|
237
|
-
m_actualSize);
|
|
238
|
-
if (oldStyleActualSize < fileSize && (oldStyleActualSize + Fixed32Size) <= fileSize) {
|
|
239
|
-
if (checkFileCRCValid(oldStyleActualSize, m_metaInfo->m_crcDigest)) {
|
|
240
|
-
MMKVInfo("looks like [%s] been downgrade & upgrade again", m_mmapID.c_str());
|
|
241
|
-
loadFromFile = true;
|
|
242
|
-
writeActualSize(oldStyleActualSize, m_metaInfo->m_crcDigest, nullptr, KeepSequence);
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
} else {
|
|
246
|
-
MMKVWarning("oldStyleActualSize %u greater than file size %lu", oldStyleActualSize, fileSize);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
auto lastActualSize = m_metaInfo->m_lastConfirmedMetaInfo.lastActualSize;
|
|
251
|
-
if (lastActualSize < fileSize && (lastActualSize + Fixed32Size) <= fileSize) {
|
|
252
|
-
auto lastCRCDigest = m_metaInfo->m_lastConfirmedMetaInfo.lastCRCDigest;
|
|
253
|
-
if (checkFileCRCValid(lastActualSize, lastCRCDigest)) {
|
|
254
|
-
loadFromFile = true;
|
|
255
|
-
writeActualSize(lastActualSize, lastCRCDigest, nullptr, KeepSequence);
|
|
256
|
-
} else {
|
|
257
|
-
MMKVError("check [%s] error: lastActualSize %u, lastActualCRC %u", m_mmapID.c_str(), lastActualSize,
|
|
258
|
-
lastCRCDigest);
|
|
259
|
-
}
|
|
260
|
-
} else {
|
|
261
|
-
MMKVError("check [%s] error: lastActualSize %u, file size is %u", m_mmapID.c_str(), lastActualSize,
|
|
262
|
-
fileSize);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
m_actualSize = readActualSize();
|
|
268
|
-
|
|
269
|
-
if (m_actualSize < fileSize && (m_actualSize + Fixed32Size) <= fileSize) {
|
|
270
|
-
if (checkFileCRCValid(m_actualSize, m_metaInfo->m_crcDigest)) {
|
|
271
|
-
loadFromFile = true;
|
|
272
|
-
} else {
|
|
273
|
-
checkLastConfirmedInfo();
|
|
274
|
-
if (!loadFromFile) {
|
|
275
|
-
|
|
276
|
-
auto strategic = onMMKVCRCCheckFail(m_mmapID);
|
|
277
|
-
if (strategic == OnErrorRecover) {
|
|
278
|
-
loadFromFile = true;
|
|
279
|
-
needFullWriteback = true;
|
|
280
|
-
}
|
|
281
|
-
MMKVInfo("recover strategic for [%s] is %d", m_mmapID.c_str(), strategic);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
} else {
|
|
285
|
-
MMKVError("check [%s] error: %zu size in total, file size is %zu", m_mmapID.c_str(), m_actualSize, fileSize);
|
|
286
|
-
|
|
287
|
-
checkLastConfirmedInfo();
|
|
288
|
-
|
|
289
|
-
if (!loadFromFile) {
|
|
290
|
-
auto strategic = onMMKVFileLengthError(m_mmapID);
|
|
291
|
-
if (strategic == OnErrorRecover) {
|
|
292
|
-
// make sure we don't over read the file
|
|
293
|
-
m_actualSize = fileSize - Fixed32Size;
|
|
294
|
-
loadFromFile = true;
|
|
295
|
-
needFullWriteback = true;
|
|
296
|
-
}
|
|
297
|
-
MMKVInfo("recover strategic for [%s] is %d", m_mmapID.c_str(), strategic);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
void MMKV::checkLoadData() {
|
|
303
|
-
if (m_needLoadFromFile) {
|
|
304
|
-
SCOPED_LOCK(m_sharedProcessLock);
|
|
305
|
-
|
|
306
|
-
m_needLoadFromFile = false;
|
|
307
|
-
loadFromFile();
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
if (!isMultiProcess()) {
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
if (!m_metaFile->isFileValid()) {
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
SCOPED_LOCK(m_sharedProcessLock);
|
|
318
|
-
|
|
319
|
-
MMKVMetaInfo metaInfo;
|
|
320
|
-
metaInfo.read(m_metaFile->getMemory());
|
|
321
|
-
if (m_metaInfo->m_sequence != metaInfo.m_sequence) {
|
|
322
|
-
MMKVInfo("[%s] oldSeq %u, newSeq %u", m_mmapID.c_str(), m_metaInfo->m_sequence, metaInfo.m_sequence);
|
|
323
|
-
SCOPED_LOCK(m_sharedProcessLock);
|
|
324
|
-
|
|
325
|
-
clearMemoryCache();
|
|
326
|
-
loadFromFile();
|
|
327
|
-
notifyContentChanged();
|
|
328
|
-
} else if (m_metaInfo->m_crcDigest != metaInfo.m_crcDigest) {
|
|
329
|
-
MMKVDebug("[%s] oldCrc %u, newCrc %u, new actualSize %u", m_mmapID.c_str(), m_metaInfo->m_crcDigest,
|
|
330
|
-
metaInfo.m_crcDigest, metaInfo.m_actualSize);
|
|
331
|
-
SCOPED_LOCK(m_sharedProcessLock);
|
|
332
|
-
|
|
333
|
-
size_t fileSize = m_file->getActualFileSize();
|
|
334
|
-
if (m_file->getFileSize() != fileSize) {
|
|
335
|
-
MMKVInfo("file size has changed [%s] from %zu to %zu", m_mmapID.c_str(), m_file->getFileSize(), fileSize);
|
|
336
|
-
clearMemoryCache();
|
|
337
|
-
loadFromFile();
|
|
338
|
-
} else {
|
|
339
|
-
partialLoadFromFile();
|
|
340
|
-
}
|
|
341
|
-
notifyContentChanged();
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
constexpr uint32_t ItemSizeHolderSize = 4;
|
|
346
|
-
|
|
347
|
-
static pair<MMBuffer, size_t> prepareEncode(const MMKVMap &dic) {
|
|
348
|
-
// make some room for placeholder
|
|
349
|
-
size_t totalSize = ItemSizeHolderSize;
|
|
350
|
-
for (auto &itr : dic) {
|
|
351
|
-
auto &kvHolder = itr.second;
|
|
352
|
-
totalSize += kvHolder.computedKVSize + kvHolder.valueSize;
|
|
353
|
-
}
|
|
354
|
-
return make_pair(MMBuffer(), totalSize);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
358
|
-
static pair<MMBuffer, size_t> prepareEncode(const MMKVMapCrypt &dic) {
|
|
359
|
-
MMKVVector vec;
|
|
360
|
-
size_t totalSize = 0;
|
|
361
|
-
// make some room for placeholder
|
|
362
|
-
uint32_t smallestOffet = 5 + 1; // 5 is the largest size needed to encode varint32
|
|
363
|
-
for (auto &itr : dic) {
|
|
364
|
-
auto &kvHolder = itr.second;
|
|
365
|
-
if (kvHolder.type == KeyValueHolderType_Offset) {
|
|
366
|
-
totalSize += kvHolder.pbKeyValueSize + kvHolder.keySize + kvHolder.valueSize;
|
|
367
|
-
smallestOffet = min(smallestOffet, kvHolder.offset);
|
|
368
|
-
} else {
|
|
369
|
-
vec.emplace_back(itr.first, kvHolder.toMMBuffer(nullptr, nullptr));
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
if (smallestOffet > 5) {
|
|
373
|
-
smallestOffet = ItemSizeHolderSize;
|
|
374
|
-
}
|
|
375
|
-
totalSize += smallestOffet;
|
|
376
|
-
if (vec.empty()) {
|
|
377
|
-
return make_pair(MMBuffer(), totalSize);
|
|
378
|
-
}
|
|
379
|
-
auto buffer = MiniPBCoder::encodeDataWithObject(vec);
|
|
380
|
-
// skip the pb size of buffer
|
|
381
|
-
auto sizeOfMap = CodedInputData(buffer.getPtr(), buffer.length()).readUInt32();
|
|
382
|
-
totalSize += sizeOfMap;
|
|
383
|
-
return make_pair(std::move(buffer), totalSize);
|
|
384
|
-
}
|
|
385
|
-
#endif
|
|
386
|
-
|
|
387
|
-
static pair<MMBuffer, size_t> prepareEncode(MMKVVector &&vec) {
|
|
388
|
-
// make some room for placeholder
|
|
389
|
-
size_t totalSize = ItemSizeHolderSize;
|
|
390
|
-
auto buffer = MiniPBCoder::encodeDataWithObject(vec);
|
|
391
|
-
// skip the pb size of buffer
|
|
392
|
-
auto sizeOfMap = CodedInputData(buffer.getPtr(), buffer.length()).readUInt32();
|
|
393
|
-
totalSize += sizeOfMap;
|
|
394
|
-
return make_pair(std::move(buffer), totalSize);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// since we use append mode, when -[setData: forKey:] many times, space may not be enough
|
|
398
|
-
// try a full rewrite to make space
|
|
399
|
-
bool MMKV::ensureMemorySize(size_t newSize) {
|
|
400
|
-
if (!isFileValid()) {
|
|
401
|
-
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
402
|
-
return false;
|
|
403
|
-
}
|
|
404
|
-
if (isReadOnly()) {
|
|
405
|
-
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
406
|
-
return false;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
if (newSize >= m_output->spaceLeft() || (m_crypter ? m_dicCrypt->empty() : m_dic->empty())) {
|
|
410
|
-
// remove expired keys
|
|
411
|
-
if (m_enableKeyExpire) {
|
|
412
|
-
filterExpiredKeys();
|
|
413
|
-
}
|
|
414
|
-
// try a full rewrite to make space
|
|
415
|
-
auto preparedData = m_crypter ? prepareEncode(*m_dicCrypt) : prepareEncode(*m_dic);
|
|
416
|
-
// dic.empty() means inserting key-value for the first time, no need to call msync()
|
|
417
|
-
return expandAndWriteBack(newSize, std::move(preparedData), m_crypter ? !m_dicCrypt->empty() : !m_dic->empty());
|
|
418
|
-
}
|
|
419
|
-
return true;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// try a full rewrite to make space
|
|
423
|
-
bool MMKV::expandAndWriteBack(size_t newSize, std::pair<mmkv::MMBuffer, size_t> preparedData, bool needSync) {
|
|
424
|
-
auto fileSize = m_file->getFileSize();
|
|
425
|
-
auto sizeOfDic = preparedData.second;
|
|
426
|
-
size_t lenNeeded = sizeOfDic + Fixed32Size + newSize;
|
|
427
|
-
size_t nowDicCount = m_crypter ? m_dicCrypt->size() : m_dic->size();
|
|
428
|
-
size_t laterDicCount = std::max<size_t>(1, nowDicCount + 1);
|
|
429
|
-
// or use <cmath> ceil()
|
|
430
|
-
size_t avgItemSize = (lenNeeded + laterDicCount - 1) / laterDicCount;
|
|
431
|
-
size_t futureUsage = avgItemSize * std::max<size_t>(8, laterDicCount / 2);
|
|
432
|
-
// 1. no space for a full rewrite, double it
|
|
433
|
-
// 2. or space is not large enough for future usage, double it to avoid frequently full rewrite
|
|
434
|
-
if (lenNeeded >= fileSize || (needSync && (lenNeeded + futureUsage) >= fileSize)) {
|
|
435
|
-
size_t oldSize = fileSize;
|
|
436
|
-
do {
|
|
437
|
-
fileSize *= 2;
|
|
438
|
-
} while (lenNeeded + futureUsage >= fileSize);
|
|
439
|
-
MMKVInfo("extending [%s] file size from %zu to %zu, incoming size:%zu, future usage:%zu", m_mmapID.c_str(),
|
|
440
|
-
oldSize, fileSize, newSize, futureUsage);
|
|
441
|
-
|
|
442
|
-
// if we can't extend size, rollback to old state
|
|
443
|
-
// this is a good place to mock enlarging file failure
|
|
444
|
-
if (!m_file->truncate(fileSize)) {
|
|
445
|
-
return false;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// check if we fail to make more space
|
|
449
|
-
if (!isFileValid()) {
|
|
450
|
-
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
451
|
-
return false;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
return doFullWriteBack(std::move(preparedData), nullptr, needSync);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
size_t MMKV::readActualSize() {
|
|
458
|
-
MMKV_ASSERT(m_file->getMemory());
|
|
459
|
-
MMKV_ASSERT(m_metaFile->isFileValid());
|
|
460
|
-
|
|
461
|
-
uint32_t actualSize = 0;
|
|
462
|
-
memcpy(&actualSize, m_file->getMemory(), Fixed32Size);
|
|
463
|
-
|
|
464
|
-
if (m_metaInfo->m_version >= MMKVVersionActualSize) {
|
|
465
|
-
if (m_metaInfo->m_actualSize != actualSize) {
|
|
466
|
-
MMKVWarning("[%s] actual size %u, meta actual size %u", m_mmapID.c_str(), actualSize,
|
|
467
|
-
m_metaInfo->m_actualSize);
|
|
468
|
-
}
|
|
469
|
-
return m_metaInfo->m_actualSize;
|
|
470
|
-
} else {
|
|
471
|
-
return actualSize;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
void MMKV::oldStyleWriteActualSize(size_t actualSize) {
|
|
476
|
-
MMKV_ASSERT(m_file->getMemory());
|
|
477
|
-
|
|
478
|
-
m_actualSize = actualSize;
|
|
479
|
-
#ifdef MMKV_IOS
|
|
480
|
-
auto ret = guardForBackgroundWriting(m_file->getMemory(), Fixed32Size);
|
|
481
|
-
if (!ret.first) {
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
#endif
|
|
485
|
-
memcpy(m_file->getMemory(), &actualSize, Fixed32Size);
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
bool MMKV::writeActualSize(size_t size, uint32_t crcDigest, const void *iv, bool increaseSequence) {
|
|
489
|
-
// backward compatibility
|
|
490
|
-
oldStyleWriteActualSize(size);
|
|
491
|
-
|
|
492
|
-
if (!m_metaFile->isFileValid()) {
|
|
493
|
-
return false;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
bool needsFullWrite = false;
|
|
497
|
-
m_actualSize = size;
|
|
498
|
-
m_metaInfo->m_actualSize = static_cast<uint32_t>(size);
|
|
499
|
-
m_crcDigest = crcDigest;
|
|
500
|
-
m_metaInfo->m_crcDigest = crcDigest;
|
|
501
|
-
if (m_metaInfo->m_version < MMKVVersionSequence) {
|
|
502
|
-
m_metaInfo->m_version = MMKVVersionSequence;
|
|
503
|
-
needsFullWrite = true;
|
|
504
|
-
}
|
|
505
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
506
|
-
if (mmkv_unlikely(iv)) {
|
|
507
|
-
memcpy(m_metaInfo->m_vector, iv, sizeof(m_metaInfo->m_vector));
|
|
508
|
-
if (m_metaInfo->m_version < MMKVVersionRandomIV) {
|
|
509
|
-
m_metaInfo->m_version = MMKVVersionRandomIV;
|
|
510
|
-
}
|
|
511
|
-
needsFullWrite = true;
|
|
512
|
-
}
|
|
513
|
-
#endif
|
|
514
|
-
if (mmkv_unlikely(increaseSequence)) {
|
|
515
|
-
m_metaInfo->m_sequence++;
|
|
516
|
-
m_metaInfo->m_lastConfirmedMetaInfo.lastActualSize = static_cast<uint32_t>(size);
|
|
517
|
-
m_metaInfo->m_lastConfirmedMetaInfo.lastCRCDigest = crcDigest;
|
|
518
|
-
if (m_metaInfo->m_version < MMKVVersionActualSize) {
|
|
519
|
-
m_metaInfo->m_version = MMKVVersionActualSize;
|
|
520
|
-
}
|
|
521
|
-
needsFullWrite = true;
|
|
522
|
-
MMKVInfo("[%s] increase sequence to %u, crc %u, actualSize %u", m_mmapID.c_str(), m_metaInfo->m_sequence,
|
|
523
|
-
m_metaInfo->m_crcDigest, m_metaInfo->m_actualSize);
|
|
524
|
-
}
|
|
525
|
-
if (m_metaInfo->m_version < MMKVVersionFlag) {
|
|
526
|
-
m_metaInfo->m_flags = 0;
|
|
527
|
-
m_metaInfo->m_version = MMKVVersionFlag;
|
|
528
|
-
needsFullWrite = true;
|
|
529
|
-
}
|
|
530
|
-
#ifdef MMKV_IOS
|
|
531
|
-
auto ret = guardForBackgroundWriting(m_metaFile->getMemory(), sizeof(MMKVMetaInfo));
|
|
532
|
-
if (!ret.first) {
|
|
533
|
-
return false;
|
|
534
|
-
}
|
|
535
|
-
#endif
|
|
536
|
-
if (mmkv_unlikely(needsFullWrite)) {
|
|
537
|
-
m_metaInfo->write(m_metaFile->getMemory());
|
|
538
|
-
} else {
|
|
539
|
-
m_metaInfo->writeCRCAndActualSizeOnly(m_metaFile->getMemory());
|
|
540
|
-
}
|
|
541
|
-
return true;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
MMBuffer MMKV::getRawDataForKey(MMKVKey_t key) {
|
|
545
|
-
checkLoadData();
|
|
546
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
547
|
-
if (m_crypter) {
|
|
548
|
-
auto itr = m_dicCrypt->find(key);
|
|
549
|
-
if (itr != m_dicCrypt->end()) {
|
|
550
|
-
auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
|
|
551
|
-
return itr->second.toMMBuffer(basePtr, m_crypter);
|
|
552
|
-
}
|
|
553
|
-
} else
|
|
554
|
-
#endif
|
|
555
|
-
{
|
|
556
|
-
auto itr = m_dic->find(key);
|
|
557
|
-
if (itr != m_dic->end()) {
|
|
558
|
-
auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
|
|
559
|
-
return itr->second.toMMBuffer(basePtr);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
MMBuffer nan;
|
|
563
|
-
return nan;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
mmkv::MMBuffer MMKV::getDataForKey(MMKVKey_t key) {
|
|
567
|
-
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
568
|
-
return getDataWithoutMTimeForKey(key);
|
|
569
|
-
}
|
|
570
|
-
return getRawDataForKey(key);
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
574
|
-
// for Apple watch simulator
|
|
575
|
-
# if defined(TARGET_OS_SIMULATOR) && defined(TARGET_CPU_X86)
|
|
576
|
-
static AESCryptStatus t_status;
|
|
577
|
-
# else
|
|
578
|
-
thread_local AESCryptStatus t_status;
|
|
579
|
-
# endif
|
|
580
|
-
#endif // MMKV_DISABLE_CRYPT
|
|
581
|
-
|
|
582
|
-
bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
|
|
583
|
-
if ((!isDataHolder && data.length() == 0) || isKeyEmpty(key)) {
|
|
584
|
-
return false;
|
|
585
|
-
}
|
|
586
|
-
SCOPED_LOCK(m_lock);
|
|
587
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
588
|
-
checkLoadData();
|
|
589
|
-
|
|
590
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
591
|
-
if (m_crypter) {
|
|
592
|
-
if (isDataHolder) {
|
|
593
|
-
auto sizeNeededForData = pbRawVarint32Size((uint32_t) data.length()) + data.length();
|
|
594
|
-
if (!KeyValueHolderCrypt::isValueStoredAsOffset(sizeNeededForData)) {
|
|
595
|
-
data = MiniPBCoder::encodeDataWithObject(data);
|
|
596
|
-
isDataHolder = false;
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
auto itr = m_dicCrypt->find(key);
|
|
600
|
-
if (itr != m_dicCrypt->end()) {
|
|
601
|
-
bool onlyOneKey = !isMultiProcess() && m_dicCrypt->size() == 1;
|
|
602
|
-
# ifdef MMKV_APPLE
|
|
603
|
-
KVHolderRet_t ret;
|
|
604
|
-
if (onlyOneKey) {
|
|
605
|
-
ret = overrideDataWithKey(data, key, itr->second, isDataHolder);
|
|
606
|
-
} else {
|
|
607
|
-
ret = appendDataWithKey(data, key, itr->second, isDataHolder);
|
|
608
|
-
}
|
|
609
|
-
# else
|
|
610
|
-
KVHolderRet_t ret;
|
|
611
|
-
if (onlyOneKey) {
|
|
612
|
-
ret = overrideDataWithKey(data, key, isDataHolder);
|
|
613
|
-
} else {
|
|
614
|
-
ret = appendDataWithKey(data, key, isDataHolder);
|
|
615
|
-
}
|
|
616
|
-
# endif
|
|
617
|
-
if (!ret.first) {
|
|
618
|
-
return false;
|
|
619
|
-
}
|
|
620
|
-
KeyValueHolderCrypt kvHolder;
|
|
621
|
-
if (KeyValueHolderCrypt::isValueStoredAsOffset(ret.second.valueSize)) {
|
|
622
|
-
kvHolder = KeyValueHolderCrypt(ret.second.keySize, ret.second.valueSize, ret.second.offset);
|
|
623
|
-
memcpy(&kvHolder.cryptStatus, &t_status, sizeof(t_status));
|
|
624
|
-
} else {
|
|
625
|
-
kvHolder = KeyValueHolderCrypt(std::move(data));
|
|
626
|
-
}
|
|
627
|
-
if (mmkv_likely(!m_enableKeyExpire)) {
|
|
628
|
-
itr->second = std::move(kvHolder);
|
|
629
|
-
} else {
|
|
630
|
-
itr = m_dicCrypt->find(key);
|
|
631
|
-
if (itr != m_dicCrypt->end()) {
|
|
632
|
-
itr->second = std::move(kvHolder);
|
|
633
|
-
} else {
|
|
634
|
-
// in case filterExpiredKeys() is triggered
|
|
635
|
-
m_dicCrypt->emplace(key, std::move(kvHolder));
|
|
636
|
-
mmkv_retain_key(key);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
} else {
|
|
640
|
-
bool needOverride = !isMultiProcess() && m_dicCrypt->empty() && m_actualSize > 0;
|
|
641
|
-
KVHolderRet_t ret;
|
|
642
|
-
if (needOverride) {
|
|
643
|
-
ret = overrideDataWithKey(data, key, isDataHolder);
|
|
644
|
-
} else {
|
|
645
|
-
ret = appendDataWithKey(data, key, isDataHolder);
|
|
646
|
-
}
|
|
647
|
-
if (!ret.first) {
|
|
648
|
-
return false;
|
|
649
|
-
}
|
|
650
|
-
if (KeyValueHolderCrypt::isValueStoredAsOffset(ret.second.valueSize)) {
|
|
651
|
-
auto r = m_dicCrypt->emplace(
|
|
652
|
-
key, KeyValueHolderCrypt(ret.second.keySize, ret.second.valueSize, ret.second.offset));
|
|
653
|
-
if (r.second) {
|
|
654
|
-
memcpy(&(r.first->second.cryptStatus), &t_status, sizeof(t_status));
|
|
655
|
-
}
|
|
656
|
-
} else {
|
|
657
|
-
m_dicCrypt->emplace(key, KeyValueHolderCrypt(std::move(data)));
|
|
658
|
-
}
|
|
659
|
-
mmkv_retain_key(key);
|
|
660
|
-
}
|
|
661
|
-
} else
|
|
662
|
-
#endif // MMKV_DISABLE_CRYPT
|
|
663
|
-
{
|
|
664
|
-
auto itr = m_dic->find(key);
|
|
665
|
-
if (itr != m_dic->end()) {
|
|
666
|
-
// compare data before appending to file
|
|
667
|
-
if (isCompareBeforeSetEnabled()) {
|
|
668
|
-
auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
|
|
669
|
-
MMBuffer oldValueData = itr->second.toMMBuffer(basePtr);
|
|
670
|
-
if (isDataHolder) {
|
|
671
|
-
CodedInputData inputData(oldValueData.getPtr(), oldValueData.length());
|
|
672
|
-
try {
|
|
673
|
-
// read extra holder header bytes and to real MMBuffer
|
|
674
|
-
oldValueData = CodedInputData::readRealData(oldValueData);
|
|
675
|
-
if (oldValueData == data) {
|
|
676
|
-
// MMKVInfo("[key] %s, set the same data", key.c_str());
|
|
677
|
-
return true;
|
|
678
|
-
}
|
|
679
|
-
} catch (std::exception &exception) {
|
|
680
|
-
MMKVWarning("compareBeforeSet exception: %s", exception.what());
|
|
681
|
-
} catch (...) {
|
|
682
|
-
MMKVWarning("compareBeforeSet fail");
|
|
683
|
-
}
|
|
684
|
-
} else {
|
|
685
|
-
if (oldValueData == data) {
|
|
686
|
-
// MMKVInfo("[key] %s, set the same data", key.c_str());
|
|
687
|
-
return true;
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
bool onlyOneKey = !isMultiProcess() && m_dic->size() == 1;
|
|
693
|
-
if (mmkv_likely(!m_enableKeyExpire)) {
|
|
694
|
-
KVHolderRet_t ret;
|
|
695
|
-
if (onlyOneKey) {
|
|
696
|
-
ret = overrideDataWithKey(data, itr->second, isDataHolder);
|
|
697
|
-
} else {
|
|
698
|
-
ret = appendDataWithKey(data, itr->second, isDataHolder);
|
|
699
|
-
}
|
|
700
|
-
if (!ret.first) {
|
|
701
|
-
return false;
|
|
702
|
-
}
|
|
703
|
-
itr->second = std::move(ret.second);
|
|
704
|
-
} else {
|
|
705
|
-
KVHolderRet_t ret;
|
|
706
|
-
if (onlyOneKey) {
|
|
707
|
-
ret = overrideDataWithKey(data, key, isDataHolder);
|
|
708
|
-
} else {
|
|
709
|
-
ret = appendDataWithKey(data, key, isDataHolder);
|
|
710
|
-
}
|
|
711
|
-
if (!ret.first) {
|
|
712
|
-
return false;
|
|
713
|
-
}
|
|
714
|
-
itr = m_dic->find(key);
|
|
715
|
-
if (itr != m_dic->end()) {
|
|
716
|
-
itr->second = std::move(ret.second);
|
|
717
|
-
} else {
|
|
718
|
-
// in case filterExpiredKeys() is triggered
|
|
719
|
-
m_dic->emplace(key, std::move(ret.second));
|
|
720
|
-
mmkv_retain_key(key);
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
} else {
|
|
724
|
-
bool needOverride = !isMultiProcess() && m_dic->empty() && m_actualSize > 0;
|
|
725
|
-
KVHolderRet_t ret;
|
|
726
|
-
if (needOverride) {
|
|
727
|
-
ret = overrideDataWithKey(data, key, isDataHolder);
|
|
728
|
-
} else {
|
|
729
|
-
ret = appendDataWithKey(data, key, isDataHolder);
|
|
730
|
-
}
|
|
731
|
-
if (!ret.first) {
|
|
732
|
-
return false;
|
|
733
|
-
}
|
|
734
|
-
m_dic->emplace(key, std::move(ret.second));
|
|
735
|
-
mmkv_retain_key(key);
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
m_hasFullWriteback = false;
|
|
739
|
-
return true;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
template <typename T>
|
|
743
|
-
static void eraseHelper(T& container, std::string_view key) {
|
|
744
|
-
auto itr = container.find(key);
|
|
745
|
-
if (itr != container.end()) {
|
|
746
|
-
container.erase(itr);
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
bool MMKV::removeDataForKey(MMKVKey_t key) {
|
|
751
|
-
if (isKeyEmpty(key)) {
|
|
752
|
-
return false;
|
|
753
|
-
}
|
|
754
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
755
|
-
if (m_crypter) {
|
|
756
|
-
auto itr = m_dicCrypt->find(key);
|
|
757
|
-
if (itr != m_dicCrypt->end()) {
|
|
758
|
-
m_hasFullWriteback = false;
|
|
759
|
-
static MMBuffer nan;
|
|
760
|
-
# ifdef MMKV_APPLE
|
|
761
|
-
auto ret = appendDataWithKey(nan, key, itr->second);
|
|
762
|
-
if (ret.first) {
|
|
763
|
-
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
764
|
-
// filterExpiredKeys() may invalid itr
|
|
765
|
-
itr = m_dicCrypt->find(key);
|
|
766
|
-
if (itr == m_dicCrypt->end()) {
|
|
767
|
-
return true;
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
auto oldKey = itr->first;
|
|
771
|
-
m_dicCrypt->erase(itr);
|
|
772
|
-
[oldKey release];
|
|
773
|
-
}
|
|
774
|
-
# else
|
|
775
|
-
auto ret = appendDataWithKey(nan, key);
|
|
776
|
-
if (ret.first) {
|
|
777
|
-
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
778
|
-
eraseHelper(*m_dicCrypt, key);
|
|
779
|
-
} else {
|
|
780
|
-
m_dicCrypt->erase(itr);
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
# endif
|
|
784
|
-
return ret.first;
|
|
785
|
-
}
|
|
786
|
-
} else
|
|
787
|
-
#endif // MMKV_DISABLE_CRYPT
|
|
788
|
-
{
|
|
789
|
-
auto itr = m_dic->find(key);
|
|
790
|
-
if (itr != m_dic->end()) {
|
|
791
|
-
m_hasFullWriteback = false;
|
|
792
|
-
static MMBuffer nan;
|
|
793
|
-
auto ret = mmkv_likely(!m_enableKeyExpire) ? appendDataWithKey(nan, itr->second) : appendDataWithKey(nan, key);
|
|
794
|
-
if (ret.first) {
|
|
795
|
-
#ifdef MMKV_APPLE
|
|
796
|
-
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
797
|
-
// filterExpiredKeys() may invalid itr
|
|
798
|
-
itr = m_dic->find(key);
|
|
799
|
-
if (itr == m_dic->end()) {
|
|
800
|
-
return true;
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
auto oldKey = itr->first;
|
|
804
|
-
m_dic->erase(itr);
|
|
805
|
-
[oldKey release];
|
|
806
|
-
#else
|
|
807
|
-
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
808
|
-
// filterExpiredKeys() may invalid itr
|
|
809
|
-
eraseHelper(*m_dic, key);
|
|
810
|
-
} else {
|
|
811
|
-
m_dic->erase(itr);
|
|
812
|
-
}
|
|
813
|
-
#endif
|
|
814
|
-
}
|
|
815
|
-
return ret.first;
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
return false;
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
KVHolderRet_t
|
|
823
|
-
MMKV::doAppendDataWithKey(const MMBuffer &data, const MMBuffer &keyData, bool isDataHolder, uint32_t originKeyLength) {
|
|
824
|
-
auto isKeyEncoded = (originKeyLength < keyData.length());
|
|
825
|
-
auto keyLength = static_cast<uint32_t>(keyData.length());
|
|
826
|
-
auto valueLength = static_cast<uint32_t>(data.length());
|
|
827
|
-
if (isDataHolder) {
|
|
828
|
-
valueLength += pbRawVarint32Size(valueLength);
|
|
829
|
-
}
|
|
830
|
-
// size needed to encode the key
|
|
831
|
-
size_t size = isKeyEncoded ? keyLength : (keyLength + pbRawVarint32Size(keyLength));
|
|
832
|
-
// size needed to encode the value
|
|
833
|
-
size += valueLength + pbRawVarint32Size(valueLength);
|
|
834
|
-
|
|
835
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
836
|
-
|
|
837
|
-
bool hasEnoughSize = ensureMemorySize(size);
|
|
838
|
-
if (!hasEnoughSize || !isFileValid()) {
|
|
839
|
-
return make_pair(false, KeyValueHolder());
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
#ifdef MMKV_IOS
|
|
843
|
-
auto ret = guardForBackgroundWriting(m_output->curWritePointer(), size);
|
|
844
|
-
if (!ret.first) {
|
|
845
|
-
return make_pair(false, KeyValueHolder());
|
|
846
|
-
}
|
|
847
|
-
#endif
|
|
848
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
849
|
-
if (m_crypter) {
|
|
850
|
-
if (KeyValueHolderCrypt::isValueStoredAsOffset(valueLength)) {
|
|
851
|
-
m_crypter->getCurStatus(t_status);
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
#endif
|
|
855
|
-
try {
|
|
856
|
-
if (isKeyEncoded) {
|
|
857
|
-
m_output->writeRawData(keyData);
|
|
858
|
-
} else {
|
|
859
|
-
m_output->writeData(keyData);
|
|
860
|
-
}
|
|
861
|
-
if (isDataHolder) {
|
|
862
|
-
m_output->writeRawVarint32((int32_t) valueLength);
|
|
863
|
-
}
|
|
864
|
-
m_output->writeData(data); // note: write size of data
|
|
865
|
-
} catch (std::exception &e) {
|
|
866
|
-
MMKVError("%s", e.what());
|
|
867
|
-
return make_pair(false, KeyValueHolder());
|
|
868
|
-
} catch (...) {
|
|
869
|
-
MMKVError("append fail");
|
|
870
|
-
return make_pair(false, KeyValueHolder());
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
auto offset = static_cast<uint32_t>(m_actualSize);
|
|
874
|
-
auto ptr = (uint8_t *) m_file->getMemory() + Fixed32Size + m_actualSize;
|
|
875
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
876
|
-
if (m_crypter) {
|
|
877
|
-
m_crypter->encrypt(ptr, ptr, size);
|
|
878
|
-
}
|
|
879
|
-
#endif
|
|
880
|
-
m_actualSize += size;
|
|
881
|
-
updateCRCDigest(ptr, size);
|
|
882
|
-
|
|
883
|
-
return make_pair(true, KeyValueHolder(originKeyLength, valueLength, offset));
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
KVHolderRet_t MMKV::doOverrideDataWithKey(const MMBuffer &data,
|
|
887
|
-
const MMBuffer &keyData,
|
|
888
|
-
bool isDataHolder,
|
|
889
|
-
uint32_t originKeyLength) {
|
|
890
|
-
auto isKeyEncoded = (originKeyLength < keyData.length());
|
|
891
|
-
auto keyLength = static_cast<uint32_t>(keyData.length());
|
|
892
|
-
auto valueLength = static_cast<uint32_t>(data.length());
|
|
893
|
-
if (isDataHolder) {
|
|
894
|
-
valueLength += pbRawVarint32Size(valueLength);
|
|
895
|
-
}
|
|
896
|
-
// size needed to encode the key
|
|
897
|
-
size_t size = isKeyEncoded ? keyLength : (keyLength + pbRawVarint32Size(keyLength));
|
|
898
|
-
// size needed to encode the value
|
|
899
|
-
size += valueLength + pbRawVarint32Size(valueLength);
|
|
900
|
-
|
|
901
|
-
if (!checkSizeForOverride(size)) {
|
|
902
|
-
return doAppendDataWithKey(data, keyData, isDataHolder, originKeyLength);
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
// we don't not support override in multi-process mode
|
|
906
|
-
// SCOPED_LOCK(m_exclusiveProcessLock);
|
|
907
|
-
|
|
908
|
-
#ifdef MMKV_IOS
|
|
909
|
-
auto ret = guardForBackgroundWriting(m_output->curWritePointer(), size);
|
|
910
|
-
if (!ret.first) {
|
|
911
|
-
return make_pair(false, KeyValueHolder());
|
|
912
|
-
}
|
|
913
|
-
#endif
|
|
914
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
915
|
-
if (m_crypter) {
|
|
916
|
-
if (m_metaInfo->m_version >= MMKVVersionRandomIV) {
|
|
917
|
-
m_crypter->resetIV(m_metaInfo->m_vector, sizeof(m_metaInfo->m_vector));
|
|
918
|
-
} else {
|
|
919
|
-
m_crypter->resetIV();
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
#endif
|
|
923
|
-
try {
|
|
924
|
-
// write ItemSizeHolder
|
|
925
|
-
m_output->setPosition(0);
|
|
926
|
-
m_output->writeUInt32(AESCrypt::randomItemSizeHolder(ItemSizeHolderSize));
|
|
927
|
-
m_actualSize = ItemSizeHolderSize;
|
|
928
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
929
|
-
if (m_crypter) {
|
|
930
|
-
auto ptr = (uint8_t *) m_file->getMemory() + Fixed32Size;
|
|
931
|
-
m_crypter->encrypt(ptr, ptr, m_actualSize);
|
|
932
|
-
if (KeyValueHolderCrypt::isValueStoredAsOffset(valueLength)) {
|
|
933
|
-
m_crypter->getCurStatus(t_status);
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
#endif
|
|
937
|
-
if (isKeyEncoded) {
|
|
938
|
-
m_output->writeRawData(keyData);
|
|
939
|
-
} else {
|
|
940
|
-
m_output->writeData(keyData);
|
|
941
|
-
}
|
|
942
|
-
if (isDataHolder) {
|
|
943
|
-
m_output->writeRawVarint32((int32_t) valueLength);
|
|
944
|
-
}
|
|
945
|
-
m_output->writeData(data); // note: write size of data
|
|
946
|
-
} catch (std::exception &e) {
|
|
947
|
-
MMKVError("%s", e.what());
|
|
948
|
-
return make_pair(false, KeyValueHolder());
|
|
949
|
-
} catch (...) {
|
|
950
|
-
MMKVError("append fail");
|
|
951
|
-
return make_pair(false, KeyValueHolder());
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
auto offset = static_cast<uint32_t>(m_actualSize);
|
|
955
|
-
m_actualSize += size;
|
|
956
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
957
|
-
if (m_crypter) {
|
|
958
|
-
auto ptr = (uint8_t *) m_file->getMemory() + Fixed32Size + offset;
|
|
959
|
-
m_crypter->encrypt(ptr, ptr, size);
|
|
960
|
-
}
|
|
961
|
-
#endif
|
|
962
|
-
recalculateCRCDigestOnly();
|
|
963
|
-
|
|
964
|
-
return make_pair(true, KeyValueHolder(originKeyLength, valueLength, offset));
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
bool MMKV::checkSizeForOverride(size_t size) {
|
|
968
|
-
if (!isFileValid()) {
|
|
969
|
-
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
970
|
-
return false;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
// only override if the file can hole it without ftruncate()
|
|
974
|
-
auto fileSize = m_file->getFileSize();
|
|
975
|
-
auto spaceNeededForOverride = size + Fixed32Size + ItemSizeHolderSize;
|
|
976
|
-
if (size > fileSize || spaceNeededForOverride > fileSize) {
|
|
977
|
-
return false;
|
|
978
|
-
}
|
|
979
|
-
return true;
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
KVHolderRet_t MMKV::appendDataWithKey(const MMBuffer &data, MMKVKey_t key, bool isDataHolder) {
|
|
983
|
-
#ifdef MMKV_APPLE
|
|
984
|
-
auto oData = [key dataUsingEncoding:NSUTF8StringEncoding];
|
|
985
|
-
auto keyData = MMBuffer(oData, MMBufferNoCopy);
|
|
986
|
-
#else
|
|
987
|
-
auto keyData = MMBuffer((void *) key.data(), key.size(), MMBufferNoCopy);
|
|
988
|
-
#endif
|
|
989
|
-
return doAppendDataWithKey(data, keyData, isDataHolder, static_cast<uint32_t>(keyData.length()));
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
KVHolderRet_t MMKV::overrideDataWithKey(const MMBuffer &data, MMKVKey_t key, bool isDataHolder) {
|
|
993
|
-
#ifdef MMKV_APPLE
|
|
994
|
-
auto oData = [key dataUsingEncoding:NSUTF8StringEncoding];
|
|
995
|
-
auto keyData = MMBuffer(oData, MMBufferNoCopy);
|
|
996
|
-
#else
|
|
997
|
-
auto keyData = MMBuffer((void *) key.data(), key.size(), MMBufferNoCopy);
|
|
998
|
-
#endif
|
|
999
|
-
return doOverrideDataWithKey(data, keyData, isDataHolder, static_cast<uint32_t>(keyData.length()));
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
KVHolderRet_t MMKV::appendDataWithKey(const MMBuffer &data, const KeyValueHolder &kvHolder, bool isDataHolder) {
|
|
1003
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1004
|
-
|
|
1005
|
-
uint32_t keyLength = kvHolder.keySize;
|
|
1006
|
-
// size needed to encode the key
|
|
1007
|
-
size_t rawKeySize = keyLength + pbRawVarint32Size(keyLength);
|
|
1008
|
-
|
|
1009
|
-
// ensureMemorySize() might change kvHolder.offset, so have to do it early
|
|
1010
|
-
{
|
|
1011
|
-
auto valueLength = static_cast<uint32_t>(data.length());
|
|
1012
|
-
if (isDataHolder) {
|
|
1013
|
-
valueLength += pbRawVarint32Size(valueLength);
|
|
1014
|
-
}
|
|
1015
|
-
auto size = rawKeySize + valueLength + pbRawVarint32Size(valueLength);
|
|
1016
|
-
bool hasEnoughSize = ensureMemorySize(size);
|
|
1017
|
-
if (!hasEnoughSize) {
|
|
1018
|
-
return make_pair(false, KeyValueHolder());
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
auto basePtr = (uint8_t *) m_file->getMemory() + Fixed32Size;
|
|
1022
|
-
MMBuffer keyData(basePtr + kvHolder.offset, rawKeySize, MMBufferNoCopy);
|
|
1023
|
-
|
|
1024
|
-
return doAppendDataWithKey(data, keyData, isDataHolder, keyLength);
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
// only one key in dict, do not append, just rewrite from beginning
|
|
1028
|
-
KVHolderRet_t MMKV::overrideDataWithKey(const MMBuffer &data, const KeyValueHolder &kvHolder, bool isDataHolder) {
|
|
1029
|
-
// we don't not support override in multi-process mode
|
|
1030
|
-
// SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1031
|
-
|
|
1032
|
-
uint32_t keyLength = kvHolder.keySize;
|
|
1033
|
-
// size needed to encode the key
|
|
1034
|
-
size_t rawKeySize = keyLength + pbRawVarint32Size(keyLength);
|
|
1035
|
-
|
|
1036
|
-
// ensureMemorySize() (inside doAppendDataWithKey() which be called from doOverrideDataWithKey())
|
|
1037
|
-
// might change kvHolder.offset, so have to do it early
|
|
1038
|
-
{
|
|
1039
|
-
auto valueLength = static_cast<uint32_t>(data.length());
|
|
1040
|
-
if (isDataHolder) {
|
|
1041
|
-
valueLength += pbRawVarint32Size(valueLength);
|
|
1042
|
-
}
|
|
1043
|
-
auto size = rawKeySize + valueLength + pbRawVarint32Size(valueLength);
|
|
1044
|
-
bool hasEnoughSize = checkSizeForOverride(size);
|
|
1045
|
-
if (!hasEnoughSize) {
|
|
1046
|
-
return appendDataWithKey(data, kvHolder, isDataHolder);
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
auto basePtr = (uint8_t *) m_file->getMemory() + Fixed32Size;
|
|
1050
|
-
MMBuffer keyData(basePtr + kvHolder.offset, rawKeySize, MMBufferNoCopy);
|
|
1051
|
-
|
|
1052
|
-
return doOverrideDataWithKey(data, keyData, isDataHolder, keyLength);
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
bool MMKV::fullWriteback(AESCrypt *newCrypter, bool onlyWhileExpire) {
|
|
1056
|
-
if (m_hasFullWriteback) {
|
|
1057
|
-
return true;
|
|
1058
|
-
}
|
|
1059
|
-
if (m_needLoadFromFile) {
|
|
1060
|
-
return true;
|
|
1061
|
-
}
|
|
1062
|
-
if (!isFileValid()) {
|
|
1063
|
-
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
1064
|
-
return false;
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
if (mmkv_unlikely(m_enableKeyExpire)) {
|
|
1068
|
-
auto expiredCount = filterExpiredKeys();
|
|
1069
|
-
if (onlyWhileExpire && expiredCount == 0) {
|
|
1070
|
-
return true;
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
auto isEmpty = m_crypter ? m_dicCrypt->empty() : m_dic->empty();
|
|
1075
|
-
if (isEmpty) {
|
|
1076
|
-
clearAll();
|
|
1077
|
-
return true;
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1081
|
-
auto preparedData = m_crypter ? prepareEncode(*m_dicCrypt) : prepareEncode(*m_dic);
|
|
1082
|
-
auto sizeOfDic = preparedData.second;
|
|
1083
|
-
if (sizeOfDic > 0) {
|
|
1084
|
-
auto fileSize = m_file->getFileSize();
|
|
1085
|
-
if (sizeOfDic + Fixed32Size <= fileSize) {
|
|
1086
|
-
return doFullWriteBack(std::move(preparedData), newCrypter);
|
|
1087
|
-
} else {
|
|
1088
|
-
assert(0);
|
|
1089
|
-
assert(newCrypter == nullptr);
|
|
1090
|
-
// expandAndWriteBack() will extend file & full rewrite, no need to write back again
|
|
1091
|
-
auto newSize = sizeOfDic + Fixed32Size - fileSize;
|
|
1092
|
-
return expandAndWriteBack(newSize, std::move(preparedData));
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
return false;
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
// we don't need to really serialize the dictionary, just reuse what's already in the file
|
|
1099
|
-
static void
|
|
1100
|
-
memmoveDictionary(MMKVMap &dic, CodedOutputData *output, uint8_t *ptr, AESCrypt *encrypter, size_t totalSize) {
|
|
1101
|
-
auto originOutputPtr = output->curWritePointer();
|
|
1102
|
-
// make space to hold the fake size of dictionary's serialization result
|
|
1103
|
-
auto writePtr = originOutputPtr + ItemSizeHolderSize;
|
|
1104
|
-
// reuse what's already in the file
|
|
1105
|
-
if (!dic.empty()) {
|
|
1106
|
-
// sort by offset
|
|
1107
|
-
vector<KeyValueHolder *> vec;
|
|
1108
|
-
vec.reserve(dic.size());
|
|
1109
|
-
for (auto &itr : dic) {
|
|
1110
|
-
vec.push_back(&itr.second);
|
|
1111
|
-
}
|
|
1112
|
-
sort(vec.begin(), vec.end(), [](const auto &left, const auto &right) { return left->offset < right->offset; });
|
|
1113
|
-
|
|
1114
|
-
// merge nearby items to make memmove quicker
|
|
1115
|
-
vector<pair<uint32_t, uint32_t>> dataSections; // pair(offset, size)
|
|
1116
|
-
dataSections.emplace_back(vec.front()->offset, vec.front()->computedKVSize + vec.front()->valueSize);
|
|
1117
|
-
for (size_t index = 1, total = vec.size(); index < total; index++) {
|
|
1118
|
-
auto kvHolder = vec[index];
|
|
1119
|
-
auto &lastSection = dataSections.back();
|
|
1120
|
-
if (kvHolder->offset == lastSection.first + lastSection.second) {
|
|
1121
|
-
lastSection.second += kvHolder->computedKVSize + kvHolder->valueSize;
|
|
1122
|
-
} else {
|
|
1123
|
-
dataSections.emplace_back(kvHolder->offset, kvHolder->computedKVSize + kvHolder->valueSize);
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
// do the move
|
|
1127
|
-
auto basePtr = ptr + Fixed32Size;
|
|
1128
|
-
for (auto §ion : dataSections) {
|
|
1129
|
-
// memmove() should handle this well: src == dst
|
|
1130
|
-
memmove(writePtr, basePtr + section.first, section.second);
|
|
1131
|
-
writePtr += section.second;
|
|
1132
|
-
}
|
|
1133
|
-
// update offset
|
|
1134
|
-
if (!encrypter) {
|
|
1135
|
-
auto offset = ItemSizeHolderSize;
|
|
1136
|
-
for (auto kvHolder : vec) {
|
|
1137
|
-
kvHolder->offset = offset;
|
|
1138
|
-
offset += kvHolder->computedKVSize + kvHolder->valueSize;
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
// hold the fake size of dictionary's serialization result
|
|
1143
|
-
output->writeUInt32(AESCrypt::randomItemSizeHolder(ItemSizeHolderSize));
|
|
1144
|
-
auto writtenSize = static_cast<size_t>(writePtr - originOutputPtr);
|
|
1145
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
1146
|
-
if (encrypter) {
|
|
1147
|
-
encrypter->encrypt(originOutputPtr, originOutputPtr, writtenSize);
|
|
1148
|
-
}
|
|
1149
|
-
#endif
|
|
1150
|
-
assert(writtenSize == totalSize);
|
|
1151
|
-
output->seek(writtenSize - ItemSizeHolderSize);
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
1155
|
-
|
|
1156
|
-
static void memmoveDictionary(MMKVMapCrypt &dic,
|
|
1157
|
-
CodedOutputData *output,
|
|
1158
|
-
uint8_t *ptr,
|
|
1159
|
-
AESCrypt *decrypter,
|
|
1160
|
-
AESCrypt *encrypter,
|
|
1161
|
-
pair<MMBuffer, size_t> &preparedData) {
|
|
1162
|
-
// reuse what's already in the file
|
|
1163
|
-
vector<KeyValueHolderCrypt *> vec;
|
|
1164
|
-
if (!dic.empty()) {
|
|
1165
|
-
// sort by offset
|
|
1166
|
-
vec.reserve(dic.size());
|
|
1167
|
-
for (auto &itr : dic) {
|
|
1168
|
-
if (itr.second.type == KeyValueHolderType_Offset) {
|
|
1169
|
-
vec.push_back(&itr.second);
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
sort(vec.begin(), vec.end(), [](auto left, auto right) { return left->offset < right->offset; });
|
|
1173
|
-
}
|
|
1174
|
-
auto sizeHolderSize = ItemSizeHolderSize;
|
|
1175
|
-
auto sizeHolder = AESCrypt::randomItemSizeHolder(sizeHolderSize);
|
|
1176
|
-
if (!vec.empty()) {
|
|
1177
|
-
auto smallestOffset = vec.front()->offset;
|
|
1178
|
-
if (smallestOffset != ItemSizeHolderSize && smallestOffset <= 5) {
|
|
1179
|
-
sizeHolderSize = smallestOffset;
|
|
1180
|
-
assert(sizeHolderSize != 0);
|
|
1181
|
-
static const uint32_t ItemSizeHolders[] = {0, 0x0f, 0xff, 0xffff, 0xffffff, 0xffffffff};
|
|
1182
|
-
sizeHolder = AESCrypt::randomItemSizeHolder(sizeHolderSize);
|
|
1183
|
-
assert(sizeHolder >= ItemSizeHolders[sizeHolderSize] && sizeHolder <= ItemSizeHolders[sizeHolderSize]);
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
output->writeRawVarint32(static_cast<int32_t>(sizeHolder));
|
|
1187
|
-
auto writePtr = output->curWritePointer();
|
|
1188
|
-
if (encrypter) {
|
|
1189
|
-
encrypter->encrypt(writePtr - sizeHolderSize, writePtr - sizeHolderSize, sizeHolderSize);
|
|
1190
|
-
}
|
|
1191
|
-
if (!vec.empty()) {
|
|
1192
|
-
// merge nearby items to make memmove quicker
|
|
1193
|
-
vector<tuple<uint32_t, uint32_t, AESCryptStatus *>> dataSections; // pair(offset, size)
|
|
1194
|
-
dataSections.push_back(vec.front()->toTuple());
|
|
1195
|
-
for (size_t index = 1, total = vec.size(); index < total; index++) {
|
|
1196
|
-
auto kvHolder = vec[index];
|
|
1197
|
-
auto &lastSection = dataSections.back();
|
|
1198
|
-
if (kvHolder->offset == get<0>(lastSection) + get<1>(lastSection)) {
|
|
1199
|
-
get<1>(lastSection) += kvHolder->pbKeyValueSize + kvHolder->keySize + kvHolder->valueSize;
|
|
1200
|
-
} else {
|
|
1201
|
-
dataSections.push_back(kvHolder->toTuple());
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
// do the move
|
|
1205
|
-
auto basePtr = ptr + Fixed32Size;
|
|
1206
|
-
for (auto §ion : dataSections) {
|
|
1207
|
-
auto crypter = decrypter->cloneWithStatus(*get<2>(section));
|
|
1208
|
-
crypter.decrypt(basePtr + get<0>(section), writePtr, get<1>(section));
|
|
1209
|
-
writePtr += get<1>(section);
|
|
1210
|
-
}
|
|
1211
|
-
// update offset & AESCryptStatus
|
|
1212
|
-
if (encrypter) {
|
|
1213
|
-
auto offset = sizeHolderSize;
|
|
1214
|
-
for (auto kvHolder : vec) {
|
|
1215
|
-
kvHolder->offset = offset;
|
|
1216
|
-
auto size = kvHolder->pbKeyValueSize + kvHolder->keySize + kvHolder->valueSize;
|
|
1217
|
-
encrypter->getCurStatus(kvHolder->cryptStatus);
|
|
1218
|
-
encrypter->encrypt(basePtr + offset, basePtr + offset, size);
|
|
1219
|
-
offset += size;
|
|
1220
|
-
}
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
auto &data = preparedData.first;
|
|
1224
|
-
if (data.length() > 0) {
|
|
1225
|
-
auto dataSize = CodedInputData(data.getPtr(), data.length()).readUInt32();
|
|
1226
|
-
if (dataSize > 0) {
|
|
1227
|
-
auto dataPtr = (uint8_t *) data.getPtr() + pbRawVarint32Size(dataSize);
|
|
1228
|
-
if (encrypter) {
|
|
1229
|
-
encrypter->encrypt(dataPtr, writePtr, dataSize);
|
|
1230
|
-
} else {
|
|
1231
|
-
memcpy(writePtr, dataPtr, dataSize);
|
|
1232
|
-
}
|
|
1233
|
-
writePtr += dataSize;
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
auto writtenSize = static_cast<size_t>(writePtr - output->curWritePointer());
|
|
1237
|
-
assert(writtenSize + sizeHolderSize == preparedData.second);
|
|
1238
|
-
output->seek(writtenSize);
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
# define InvalidCryptPtr ((AESCrypt *) (void *) (1))
|
|
1242
|
-
|
|
1243
|
-
#endif // MMKV_DISABLE_CRYPT
|
|
1244
|
-
|
|
1245
|
-
static void fullWriteBackWholeData(MMBuffer allData, size_t totalSize, CodedOutputData *output) {
|
|
1246
|
-
auto originOutputPtr = output->curWritePointer();
|
|
1247
|
-
output->writeUInt32(AESCrypt::randomItemSizeHolder(ItemSizeHolderSize));
|
|
1248
|
-
if (allData.length() > 0) {
|
|
1249
|
-
auto dataSize = CodedInputData(allData.getPtr(), allData.length()).readUInt32();
|
|
1250
|
-
if (dataSize > 0) {
|
|
1251
|
-
auto dataPtr = (uint8_t *) allData.getPtr() + pbRawVarint32Size(dataSize);
|
|
1252
|
-
memcpy(output->curWritePointer(), dataPtr, dataSize);
|
|
1253
|
-
output->seek(dataSize);
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
[[maybe_unused]] auto writtenSize = (size_t)(output->curWritePointer() - originOutputPtr);
|
|
1257
|
-
assert(writtenSize == totalSize);
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
1261
|
-
bool MMKV::doFullWriteBack(pair<MMBuffer, size_t> prepared, AESCrypt *newCrypter, bool needSync) {
|
|
1262
|
-
auto ptr = (uint8_t *) m_file->getMemory();
|
|
1263
|
-
auto totalSize = prepared.second;
|
|
1264
|
-
# ifdef MMKV_IOS
|
|
1265
|
-
auto ret = guardForBackgroundWriting(ptr + Fixed32Size, totalSize);
|
|
1266
|
-
if (!ret.first) {
|
|
1267
|
-
return false;
|
|
1268
|
-
}
|
|
1269
|
-
# endif
|
|
1270
|
-
|
|
1271
|
-
uint8_t newIV[AES_KEY_LEN];
|
|
1272
|
-
auto encrypter = (newCrypter == InvalidCryptPtr) ? nullptr : (newCrypter ? newCrypter : m_crypter);
|
|
1273
|
-
if (encrypter) {
|
|
1274
|
-
AESCrypt::fillRandomIV(newIV);
|
|
1275
|
-
encrypter->resetIV(newIV, sizeof(newIV));
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
delete m_output;
|
|
1279
|
-
m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
|
|
1280
|
-
if (m_crypter) {
|
|
1281
|
-
auto decrypter = m_crypter;
|
|
1282
|
-
memmoveDictionary(*m_dicCrypt, m_output, ptr, decrypter, encrypter, prepared);
|
|
1283
|
-
} else if (prepared.first.length() != 0) {
|
|
1284
|
-
auto &preparedData = prepared.first;
|
|
1285
|
-
fullWriteBackWholeData(std::move(preparedData), totalSize, m_output);
|
|
1286
|
-
if (encrypter) {
|
|
1287
|
-
encrypter->encrypt(ptr + Fixed32Size, ptr + Fixed32Size, totalSize);
|
|
1288
|
-
}
|
|
1289
|
-
} else {
|
|
1290
|
-
memmoveDictionary(*m_dic, m_output, ptr, encrypter, totalSize);
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
m_actualSize = totalSize;
|
|
1294
|
-
if (encrypter) {
|
|
1295
|
-
recalculateCRCDigestWithIV(newIV);
|
|
1296
|
-
} else {
|
|
1297
|
-
recalculateCRCDigestWithIV(nullptr);
|
|
1298
|
-
}
|
|
1299
|
-
m_hasFullWriteback = true;
|
|
1300
|
-
// make sure lastConfirmedMetaInfo is saved if needed
|
|
1301
|
-
if (needSync) {
|
|
1302
|
-
sync(MMKV_SYNC);
|
|
1303
|
-
}
|
|
1304
|
-
return true;
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
#else // MMKV_DISABLE_CRYPT
|
|
1308
|
-
|
|
1309
|
-
bool MMKV::doFullWriteBack(pair<MMBuffer, size_t> prepared, AESCrypt *, bool needSync) {
|
|
1310
|
-
auto ptr = (uint8_t *) m_file->getMemory();
|
|
1311
|
-
auto totalSize = prepared.second;
|
|
1312
|
-
# ifdef MMKV_IOS
|
|
1313
|
-
auto ret = guardForBackgroundWriting(ptr + Fixed32Size, totalSize);
|
|
1314
|
-
if (!ret.first) {
|
|
1315
|
-
return false;
|
|
1316
|
-
}
|
|
1317
|
-
# endif
|
|
1318
|
-
|
|
1319
|
-
delete m_output;
|
|
1320
|
-
m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
|
|
1321
|
-
if (prepared.first.length() != 0) {
|
|
1322
|
-
auto &preparedData = prepared.first;
|
|
1323
|
-
fullWriteBackWholeData(std::move(preparedData), totalSize, m_output);
|
|
1324
|
-
} else {
|
|
1325
|
-
constexpr AESCrypt *encrypter = nullptr;
|
|
1326
|
-
memmoveDictionary(*m_dic, m_output, ptr, encrypter, totalSize);
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
m_actualSize = totalSize;
|
|
1330
|
-
recalculateCRCDigestWithIV(nullptr);
|
|
1331
|
-
m_hasFullWriteback = true;
|
|
1332
|
-
// make sure lastConfirmedMetaInfo is saved if needed
|
|
1333
|
-
if (needSync) {
|
|
1334
|
-
sync(MMKV_SYNC);
|
|
1335
|
-
}
|
|
1336
|
-
return true;
|
|
1337
|
-
}
|
|
1338
|
-
#endif // MMKV_DISABLE_CRYPT
|
|
1339
|
-
|
|
1340
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
1341
|
-
bool MMKV::reKey(const string &cryptKey) {
|
|
1342
|
-
SCOPED_LOCK(m_lock);
|
|
1343
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1344
|
-
checkLoadData();
|
|
1345
|
-
if (!isFileValid()) {
|
|
1346
|
-
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
1347
|
-
return false;
|
|
1348
|
-
}
|
|
1349
|
-
if (isReadOnly()) {
|
|
1350
|
-
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
1351
|
-
return false;
|
|
1352
|
-
}
|
|
1353
|
-
|
|
1354
|
-
bool ret = false;
|
|
1355
|
-
if (m_crypter) {
|
|
1356
|
-
if (cryptKey.length() > 0) {
|
|
1357
|
-
string oldKey = this->cryptKey();
|
|
1358
|
-
if (cryptKey == oldKey) {
|
|
1359
|
-
return true;
|
|
1360
|
-
} else {
|
|
1361
|
-
// change encryption key
|
|
1362
|
-
MMKVInfo("reKey with new aes key");
|
|
1363
|
-
auto newCrypt = new AESCrypt(cryptKey.data(), cryptKey.length());
|
|
1364
|
-
m_hasFullWriteback = false;
|
|
1365
|
-
ret = fullWriteback(newCrypt);
|
|
1366
|
-
if (ret) {
|
|
1367
|
-
delete m_crypter;
|
|
1368
|
-
m_crypter = newCrypt;
|
|
1369
|
-
} else {
|
|
1370
|
-
delete newCrypt;
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
} else {
|
|
1374
|
-
// decryption to plain text
|
|
1375
|
-
MMKVInfo("reKey to no aes key");
|
|
1376
|
-
m_hasFullWriteback = false;
|
|
1377
|
-
ret = fullWriteback(InvalidCryptPtr);
|
|
1378
|
-
if (ret) {
|
|
1379
|
-
delete m_crypter;
|
|
1380
|
-
m_crypter = nullptr;
|
|
1381
|
-
if (!m_dic) {
|
|
1382
|
-
m_dic = new MMKVMap();
|
|
1383
|
-
}
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
} else {
|
|
1387
|
-
if (cryptKey.length() > 0) {
|
|
1388
|
-
// transform plain text to encrypted text
|
|
1389
|
-
MMKVInfo("reKey to a aes key");
|
|
1390
|
-
m_hasFullWriteback = false;
|
|
1391
|
-
auto newCrypt = new AESCrypt(cryptKey.data(), cryptKey.length());
|
|
1392
|
-
ret = fullWriteback(newCrypt);
|
|
1393
|
-
if (ret) {
|
|
1394
|
-
m_crypter = newCrypt;
|
|
1395
|
-
if (!m_dicCrypt) {
|
|
1396
|
-
m_dicCrypt = new MMKVMapCrypt();
|
|
1397
|
-
}
|
|
1398
|
-
} else {
|
|
1399
|
-
delete newCrypt;
|
|
1400
|
-
}
|
|
1401
|
-
} else {
|
|
1402
|
-
return true;
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
// m_dic or m_dicCrypt is not valid after reKey
|
|
1406
|
-
if (ret) {
|
|
1407
|
-
clearMemoryCache();
|
|
1408
|
-
}
|
|
1409
|
-
return ret;
|
|
1410
|
-
}
|
|
1411
|
-
#endif
|
|
1412
|
-
|
|
1413
|
-
void MMKV::trim() {
|
|
1414
|
-
SCOPED_LOCK(m_lock);
|
|
1415
|
-
MMKVInfo("prepare to trim %s", m_mmapID.c_str());
|
|
1416
|
-
|
|
1417
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1418
|
-
checkLoadData();
|
|
1419
|
-
if (!isFileValid()) {
|
|
1420
|
-
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
1421
|
-
return;
|
|
1422
|
-
}
|
|
1423
|
-
if (isReadOnly()) {
|
|
1424
|
-
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
1425
|
-
return;
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
if (m_actualSize == 0) {
|
|
1429
|
-
clearAll();
|
|
1430
|
-
return;
|
|
1431
|
-
} else if (m_file->getFileSize() <= m_expectedCapacity) {
|
|
1432
|
-
return;
|
|
1433
|
-
}
|
|
1434
|
-
|
|
1435
|
-
fullWriteback();
|
|
1436
|
-
auto oldSize = m_file->getFileSize();
|
|
1437
|
-
auto fileSize = oldSize;
|
|
1438
|
-
while (fileSize > (m_actualSize + Fixed32Size) * 2) {
|
|
1439
|
-
fileSize /= 2;
|
|
1440
|
-
}
|
|
1441
|
-
fileSize = std::max<size_t>(fileSize, m_expectedCapacity);
|
|
1442
|
-
if (oldSize == fileSize) {
|
|
1443
|
-
MMKVInfo("there's no need to trim %s with size %zu, actualSize %zu", m_mmapID.c_str(), fileSize, m_actualSize);
|
|
1444
|
-
return;
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
MMKVInfo("trimming %s from %zu to %zu, actualSize %zu", m_mmapID.c_str(), oldSize, fileSize, m_actualSize);
|
|
1448
|
-
|
|
1449
|
-
if (!m_file->truncate(fileSize)) {
|
|
1450
|
-
return;
|
|
1451
|
-
}
|
|
1452
|
-
fileSize = m_file->getFileSize();
|
|
1453
|
-
auto ptr = (uint8_t *) m_file->getMemory();
|
|
1454
|
-
delete m_output;
|
|
1455
|
-
m_output = new CodedOutputData(ptr + pbFixed32Size(), fileSize - Fixed32Size);
|
|
1456
|
-
m_output->seek(m_actualSize);
|
|
1457
|
-
|
|
1458
|
-
MMKVInfo("finish trim %s from %zu to %zu", m_mmapID.c_str(), oldSize, fileSize);
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
void MMKV::clearAll(bool keepSpace) {
|
|
1462
|
-
MMKVInfo("cleaning all key-values from [%s]", m_mmapID.c_str());
|
|
1463
|
-
SCOPED_LOCK(m_lock);
|
|
1464
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1465
|
-
|
|
1466
|
-
checkLoadData();
|
|
1467
|
-
if (!isFileValid()) {
|
|
1468
|
-
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
1469
|
-
return;
|
|
1470
|
-
}
|
|
1471
|
-
if (isReadOnly()) {
|
|
1472
|
-
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
1473
|
-
return;
|
|
1474
|
-
}
|
|
1475
|
-
|
|
1476
|
-
if (m_file->getFileSize() == m_expectedCapacity && m_actualSize == 0) {
|
|
1477
|
-
MMKVInfo("nothing to clear for [%s]", m_mmapID.c_str());
|
|
1478
|
-
return;
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
if (!keepSpace) {
|
|
1482
|
-
m_file->truncate(m_expectedCapacity);
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
1486
|
-
uint8_t newIV[AES_KEY_LEN];
|
|
1487
|
-
AESCrypt::fillRandomIV(newIV);
|
|
1488
|
-
if (m_crypter) {
|
|
1489
|
-
m_crypter->resetIV(newIV, sizeof(newIV));
|
|
1490
|
-
}
|
|
1491
|
-
writeActualSize(0, 0, newIV, IncreaseSequence);
|
|
1492
|
-
#else
|
|
1493
|
-
writeActualSize(0, 0, nullptr, IncreaseSequence);
|
|
1494
|
-
#endif
|
|
1495
|
-
|
|
1496
|
-
m_metaFile->msync(MMKV_SYNC);
|
|
1497
|
-
|
|
1498
|
-
clearMemoryCache(keepSpace);
|
|
1499
|
-
loadFromFile();
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
bool MMKV::isFileValid(const string &mmapID, MMKVPath_t *relatePath) {
|
|
1503
|
-
MMKVPath_t kvPath = mappedKVPathWithID(mmapID, MMKV_SINGLE_PROCESS, relatePath);
|
|
1504
|
-
if (!isFileExist(kvPath)) {
|
|
1505
|
-
return true;
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
MMKVPath_t crcPath = crcPathWithID(mmapID, MMKV_SINGLE_PROCESS, relatePath);
|
|
1509
|
-
if (!isFileExist(crcPath)) {
|
|
1510
|
-
return false;
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
uint32_t crcFile = 0;
|
|
1514
|
-
MMBuffer *data = readWholeFile(crcPath);
|
|
1515
|
-
if (data) {
|
|
1516
|
-
if (data->getPtr()) {
|
|
1517
|
-
MMKVMetaInfo metaInfo;
|
|
1518
|
-
metaInfo.read(data->getPtr());
|
|
1519
|
-
crcFile = metaInfo.m_crcDigest;
|
|
1520
|
-
}
|
|
1521
|
-
delete data;
|
|
1522
|
-
} else {
|
|
1523
|
-
return false;
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
uint32_t crcDigest = 0;
|
|
1527
|
-
MMBuffer *fileData = readWholeFile(kvPath);
|
|
1528
|
-
if (fileData) {
|
|
1529
|
-
if (fileData->getPtr() && (fileData->length() >= Fixed32Size)) {
|
|
1530
|
-
uint32_t actualSize = 0;
|
|
1531
|
-
memcpy(&actualSize, fileData->getPtr(), Fixed32Size);
|
|
1532
|
-
if (actualSize > (fileData->length() - Fixed32Size)) {
|
|
1533
|
-
delete fileData;
|
|
1534
|
-
return false;
|
|
1535
|
-
}
|
|
1536
|
-
|
|
1537
|
-
crcDigest = (uint32_t) CRC32(0, (const uint8_t *) fileData->getPtr() + Fixed32Size, (uint32_t) actualSize);
|
|
1538
|
-
}
|
|
1539
|
-
delete fileData;
|
|
1540
|
-
return crcFile == crcDigest;
|
|
1541
|
-
} else {
|
|
1542
|
-
return false;
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
bool MMKV::removeStorage(const std::string &mmapID, MMKVPath_t *relatePath) {
|
|
1547
|
-
if (!g_instanceLock) {
|
|
1548
|
-
return false;
|
|
1549
|
-
}
|
|
1550
|
-
auto mmapKey = mmapedKVKey(mmapID, relatePath);
|
|
1551
|
-
#ifdef MMKV_ANDROID
|
|
1552
|
-
auto &realID = mmapKey; // historically Android mistakenly use mmapKey as mmapID
|
|
1553
|
-
#else
|
|
1554
|
-
auto &realID = mmapID;
|
|
1555
|
-
#endif
|
|
1556
|
-
MMKVDebug("mmapKey %s", mmapKey.c_str());
|
|
1557
|
-
|
|
1558
|
-
MMKVPath_t kvPath = mappedKVPathWithID(realID, MMKV_SINGLE_PROCESS, relatePath);
|
|
1559
|
-
if (!isFileExist(kvPath)) {
|
|
1560
|
-
MMKVWarning("file not exist %s", kvPath.c_str());
|
|
1561
|
-
return false;
|
|
1562
|
-
}
|
|
1563
|
-
MMKVPath_t crcPath = crcPathWithID(realID, MMKV_SINGLE_PROCESS, relatePath);
|
|
1564
|
-
if (!isFileExist(crcPath)) {
|
|
1565
|
-
MMKVWarning("file not exist %s", crcPath.c_str());
|
|
1566
|
-
return false;
|
|
1567
|
-
}
|
|
1568
|
-
|
|
1569
|
-
MMKVInfo("remove storage [%s]", mmapID.c_str());
|
|
1570
|
-
SCOPED_LOCK(g_instanceLock);
|
|
1571
|
-
|
|
1572
|
-
File crcFile(crcPath, OpenFlag::ReadOnly);
|
|
1573
|
-
if (!crcFile.isFileValid()) {
|
|
1574
|
-
return false;
|
|
1575
|
-
}
|
|
1576
|
-
FileLock fileLock(crcFile.getFd());
|
|
1577
|
-
InterProcessLock lock(&fileLock, ExclusiveLockType);
|
|
1578
|
-
SCOPED_LOCK(&lock);
|
|
1579
|
-
|
|
1580
|
-
auto itr = g_instanceDic->find(mmapKey);
|
|
1581
|
-
if (itr != g_instanceDic->end()) {
|
|
1582
|
-
itr->second->close();
|
|
1583
|
-
// itr is not valid after this
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1586
|
-
#ifndef MMKV_WIN32
|
|
1587
|
-
::unlink(kvPath.c_str());
|
|
1588
|
-
::unlink(crcPath.c_str());
|
|
1589
|
-
#else
|
|
1590
|
-
DeleteFile(kvPath.c_str());
|
|
1591
|
-
DeleteFile(crcPath.c_str());
|
|
1592
|
-
#endif
|
|
1593
|
-
|
|
1594
|
-
return true;
|
|
1595
|
-
}
|
|
1596
|
-
|
|
1597
|
-
// ---- auto expire ----
|
|
1598
|
-
|
|
1599
|
-
uint32_t MMKV::getCurrentTimeInSecond() {
|
|
1600
|
-
auto time = ::time(nullptr);
|
|
1601
|
-
return static_cast<uint32_t>(time);
|
|
1602
|
-
}
|
|
1603
|
-
|
|
1604
|
-
bool MMKV::doFullWriteBack(MMKVVector &&vec) {
|
|
1605
|
-
auto preparedData = prepareEncode(std::move(vec));
|
|
1606
|
-
|
|
1607
|
-
// must clean before write-back and after prepareEncode()
|
|
1608
|
-
if (m_crypter) {
|
|
1609
|
-
clearDictionary(m_dicCrypt);
|
|
1610
|
-
} else {
|
|
1611
|
-
clearDictionary(m_dic);
|
|
1612
|
-
}
|
|
1613
|
-
|
|
1614
|
-
bool ret = false;
|
|
1615
|
-
auto sizeOfDic = preparedData.second;
|
|
1616
|
-
auto fileSize = m_file->getFileSize();
|
|
1617
|
-
if (sizeOfDic + Fixed32Size <= fileSize) {
|
|
1618
|
-
ret = doFullWriteBack(std::move(preparedData), nullptr);
|
|
1619
|
-
} else {
|
|
1620
|
-
// expandAndWriteBack() will extend file & full rewrite, no need to write back again
|
|
1621
|
-
auto newSize = sizeOfDic + Fixed32Size - fileSize;
|
|
1622
|
-
ret = expandAndWriteBack(newSize, std::move(preparedData));
|
|
1623
|
-
}
|
|
1624
|
-
|
|
1625
|
-
clearMemoryCache();
|
|
1626
|
-
return ret;
|
|
1627
|
-
}
|
|
1628
|
-
|
|
1629
|
-
bool MMKV::enableAutoKeyExpire(uint32_t expiredInSeconds) {
|
|
1630
|
-
SCOPED_LOCK(m_lock);
|
|
1631
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1632
|
-
checkLoadData();
|
|
1633
|
-
if (!isFileValid() || !m_metaFile->isFileValid()) {
|
|
1634
|
-
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
1635
|
-
return false;
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
if (m_enableCompareBeforeSet) {
|
|
1639
|
-
MMKVError("enableCompareBeforeSet will be invalid when Expiration is on");
|
|
1640
|
-
m_enableCompareBeforeSet = false;
|
|
1641
|
-
}
|
|
1642
|
-
|
|
1643
|
-
if (m_expiredInSeconds != expiredInSeconds) {
|
|
1644
|
-
MMKVInfo("expiredInSeconds: %u", expiredInSeconds);
|
|
1645
|
-
m_expiredInSeconds = expiredInSeconds;
|
|
1646
|
-
}
|
|
1647
|
-
m_enableKeyExpire = true;
|
|
1648
|
-
if (m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre)) {
|
|
1649
|
-
return true;
|
|
1650
|
-
}
|
|
1651
|
-
if (isReadOnly()) {
|
|
1652
|
-
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
1653
|
-
return false;
|
|
1654
|
-
}
|
|
1655
|
-
|
|
1656
|
-
auto autoRecordExpireTime = (m_expiredInSeconds != 0);
|
|
1657
|
-
auto time = autoRecordExpireTime ? getCurrentTimeInSecond() + m_expiredInSeconds : 0;
|
|
1658
|
-
MMKVInfo("turn on recording expire date for all keys inside [%s] from now %u", m_mmapID.c_str(), time);
|
|
1659
|
-
m_metaInfo->setFlag(MMKVMetaInfo::EnableKeyExipre);
|
|
1660
|
-
m_metaInfo->m_version = MMKVVersionFlag;
|
|
1661
|
-
|
|
1662
|
-
if (m_file->getFileSize() == m_expectedCapacity && m_actualSize == 0) {
|
|
1663
|
-
MMKVInfo("file is new, don't need a full writeback [%s], just update meta file", m_mmapID.c_str());
|
|
1664
|
-
writeActualSize(0, 0, nullptr, IncreaseSequence);
|
|
1665
|
-
m_metaFile->msync(MMKV_SYNC);
|
|
1666
|
-
return true;
|
|
1667
|
-
}
|
|
1668
|
-
|
|
1669
|
-
MMKVVector vec;
|
|
1670
|
-
auto packKeyValue = [&](const MMKVKey_t &key, const MMBuffer &value) {
|
|
1671
|
-
MMBuffer data(value.length() + Fixed32Size);
|
|
1672
|
-
auto ptr = (uint8_t *) data.getPtr();
|
|
1673
|
-
memcpy(ptr, value.getPtr(), value.length());
|
|
1674
|
-
memcpy(ptr + value.length(), &time, Fixed32Size);
|
|
1675
|
-
vec.emplace_back(key, std::move(data));
|
|
1676
|
-
};
|
|
1677
|
-
|
|
1678
|
-
auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
|
|
1679
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
1680
|
-
if (m_crypter) {
|
|
1681
|
-
for (auto &pair : *m_dicCrypt) {
|
|
1682
|
-
auto &key = pair.first;
|
|
1683
|
-
auto &value = pair.second;
|
|
1684
|
-
auto buffer = value.toMMBuffer(basePtr, m_crypter);
|
|
1685
|
-
packKeyValue(key, buffer);
|
|
1686
|
-
}
|
|
1687
|
-
} else
|
|
1688
|
-
#endif
|
|
1689
|
-
{
|
|
1690
|
-
for (auto &pair : *m_dic) {
|
|
1691
|
-
auto &key = pair.first;
|
|
1692
|
-
auto &value = pair.second;
|
|
1693
|
-
auto buffer = value.toMMBuffer(basePtr);
|
|
1694
|
-
packKeyValue(key, buffer);
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
|
-
return doFullWriteBack(std::move(vec));
|
|
1699
|
-
}
|
|
1700
|
-
|
|
1701
|
-
bool MMKV::disableAutoKeyExpire() {
|
|
1702
|
-
SCOPED_LOCK(m_lock);
|
|
1703
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1704
|
-
checkLoadData();
|
|
1705
|
-
if (!isFileValid() || !m_metaFile->isFileValid()) {
|
|
1706
|
-
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
1707
|
-
return false;
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
|
-
m_expiredInSeconds = 0;
|
|
1711
|
-
m_enableKeyExpire = false;
|
|
1712
|
-
if (!m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre)) {
|
|
1713
|
-
return true;
|
|
1714
|
-
}
|
|
1715
|
-
if (isReadOnly()) {
|
|
1716
|
-
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
1717
|
-
return false;
|
|
1718
|
-
}
|
|
1719
|
-
|
|
1720
|
-
MMKVInfo("erase previous recorded expire date for all keys inside [%s]", m_mmapID.c_str());
|
|
1721
|
-
m_metaInfo->unsetFlag(MMKVMetaInfo::EnableKeyExipre);
|
|
1722
|
-
m_metaInfo->m_version = MMKVVersionFlag;
|
|
1723
|
-
|
|
1724
|
-
if (m_file->getFileSize() == m_expectedCapacity && m_actualSize == 0) {
|
|
1725
|
-
MMKVInfo("file is new, don't need a full write-back [%s], just update meta file", m_mmapID.c_str());
|
|
1726
|
-
writeActualSize(0, 0, nullptr, IncreaseSequence);
|
|
1727
|
-
m_metaFile->msync(MMKV_SYNC);
|
|
1728
|
-
return true;
|
|
1729
|
-
}
|
|
1730
|
-
|
|
1731
|
-
MMKVVector vec;
|
|
1732
|
-
auto packKeyValue = [&](const MMKVKey_t &key, const MMBuffer &value) {
|
|
1733
|
-
assert(value.length() >= Fixed32Size);
|
|
1734
|
-
MMBuffer data(value.length() - Fixed32Size);
|
|
1735
|
-
auto ptr = (uint8_t *) data.getPtr();
|
|
1736
|
-
memcpy(ptr, value.getPtr(), value.length() - Fixed32Size);
|
|
1737
|
-
vec.emplace_back(key, std::move(data));
|
|
1738
|
-
};
|
|
1739
|
-
|
|
1740
|
-
auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
|
|
1741
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
1742
|
-
if (m_crypter) {
|
|
1743
|
-
for (auto &pair : *m_dicCrypt) {
|
|
1744
|
-
auto &key = pair.first;
|
|
1745
|
-
auto &value = pair.second;
|
|
1746
|
-
auto buffer = value.toMMBuffer(basePtr, m_crypter);
|
|
1747
|
-
packKeyValue(key, buffer);
|
|
1748
|
-
}
|
|
1749
|
-
} else
|
|
1750
|
-
#endif
|
|
1751
|
-
{
|
|
1752
|
-
for (auto &pair : *m_dic) {
|
|
1753
|
-
auto &key = pair.first;
|
|
1754
|
-
auto &value = pair.second;
|
|
1755
|
-
auto buffer = value.toMMBuffer(basePtr);
|
|
1756
|
-
packKeyValue(key, buffer);
|
|
1757
|
-
}
|
|
1758
|
-
}
|
|
1759
|
-
|
|
1760
|
-
return doFullWriteBack(std::move(vec));
|
|
1761
|
-
}
|
|
1762
|
-
|
|
1763
|
-
uint32_t MMKV::getExpireTimeForKey(MMKVKey_t key) {
|
|
1764
|
-
SCOPED_LOCK(m_lock);
|
|
1765
|
-
SCOPED_LOCK(m_sharedProcessLock);
|
|
1766
|
-
checkLoadData();
|
|
1767
|
-
|
|
1768
|
-
if (!m_enableKeyExpire || mmkv_key_length(key) == 0) {
|
|
1769
|
-
return 0;
|
|
1770
|
-
}
|
|
1771
|
-
auto raw = getRawDataForKey(key);
|
|
1772
|
-
assert(raw.length() == 0 || raw.length() >= Fixed32Size);
|
|
1773
|
-
if (raw.length() < Fixed32Size) {
|
|
1774
|
-
return 0;
|
|
1775
|
-
}
|
|
1776
|
-
auto ptr = (const uint8_t *) raw.getPtr() + raw.length() - Fixed32Size;
|
|
1777
|
-
auto time = *(const uint32_t *) ptr;
|
|
1778
|
-
return time;
|
|
1779
|
-
}
|
|
1780
|
-
|
|
1781
|
-
mmkv::MMBuffer MMKV::getDataWithoutMTimeForKey(MMKVKey_t key) {
|
|
1782
|
-
SCOPED_LOCK(m_lock);
|
|
1783
|
-
SCOPED_LOCK(m_sharedProcessLock);
|
|
1784
|
-
checkLoadData();
|
|
1785
|
-
|
|
1786
|
-
auto raw = getRawDataForKey(key);
|
|
1787
|
-
assert(raw.length() == 0 || raw.length() >= Fixed32Size);
|
|
1788
|
-
if (raw.length() < Fixed32Size) {
|
|
1789
|
-
return raw;
|
|
1790
|
-
}
|
|
1791
|
-
auto newLength = raw.length() - Fixed32Size;
|
|
1792
|
-
if (m_enableKeyExpire) {
|
|
1793
|
-
auto ptr = (const uint8_t *) raw.getPtr() + newLength;
|
|
1794
|
-
auto time = *(const uint32_t *) ptr;
|
|
1795
|
-
if (time != ExpireNever && time <= getCurrentTimeInSecond()) {
|
|
1796
|
-
#ifdef MMKV_APPLE
|
|
1797
|
-
MMKVInfo("deleting expired key [%@] in mmkv [%s], due date %u", key, m_mmapID.c_str(), time);
|
|
1798
|
-
#else
|
|
1799
|
-
MMKVInfo("deleting expired key [%s] in mmkv [%s], due date %u", key.data(), m_mmapID.c_str(), time);
|
|
1800
|
-
#endif
|
|
1801
|
-
removeValueForKey(key);
|
|
1802
|
-
return MMBuffer();
|
|
1803
|
-
}
|
|
1804
|
-
}
|
|
1805
|
-
return MMBuffer(std::move(raw), newLength);
|
|
1806
|
-
}
|
|
1807
|
-
|
|
1808
|
-
#define NOOP ((void) 0)
|
|
1809
|
-
|
|
1810
|
-
size_t MMKV::filterExpiredKeys() {
|
|
1811
|
-
if (!m_enableKeyExpire || (m_crypter ? m_dicCrypt->empty() : m_dic->empty())) {
|
|
1812
|
-
return 0;
|
|
1813
|
-
}
|
|
1814
|
-
SCOPED_LOCK(m_sharedProcessLock);
|
|
1815
|
-
|
|
1816
|
-
auto now = getCurrentTimeInSecond();
|
|
1817
|
-
MMKVInfo("filtering expired keys inside [%s] now: %u, m_expiredInSeconds: %u", m_mmapID.c_str(), now,
|
|
1818
|
-
m_expiredInSeconds);
|
|
1819
|
-
|
|
1820
|
-
size_t count = 0;
|
|
1821
|
-
auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
|
|
1822
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
1823
|
-
if (m_crypter) {
|
|
1824
|
-
for (auto itr = m_dicCrypt->begin(); itr != m_dicCrypt->end(); NOOP) {
|
|
1825
|
-
auto &kvHolder = itr->second;
|
|
1826
|
-
assert(kvHolder.realValueSize() >= Fixed32Size);
|
|
1827
|
-
auto buffer = kvHolder.toMMBuffer(basePtr, m_crypter);
|
|
1828
|
-
auto ptr = (uint8_t *) buffer.getPtr();
|
|
1829
|
-
ptr += buffer.length() - Fixed32Size;
|
|
1830
|
-
auto time = *(const uint32_t *) ptr;
|
|
1831
|
-
if (time != ExpireNever && time <= now) {
|
|
1832
|
-
auto oldKey = itr->first;
|
|
1833
|
-
itr = m_dicCrypt->erase(itr);
|
|
1834
|
-
# ifdef MMKV_APPLE
|
|
1835
|
-
MMKVInfo("deleting expired key [%@], due date %u", oldKey, time);
|
|
1836
|
-
[oldKey release];
|
|
1837
|
-
# else
|
|
1838
|
-
MMKVInfo("deleting expired key [%s], due date %u", oldKey.c_str(), time);
|
|
1839
|
-
# endif
|
|
1840
|
-
count++;
|
|
1841
|
-
} else {
|
|
1842
|
-
itr++;
|
|
1843
|
-
}
|
|
1844
|
-
}
|
|
1845
|
-
} else
|
|
1846
|
-
#endif // !MMKV_DISABLE_CRYPT
|
|
1847
|
-
{
|
|
1848
|
-
for (auto itr = m_dic->begin(); itr != m_dic->end(); NOOP) {
|
|
1849
|
-
auto &kvHolder = itr->second;
|
|
1850
|
-
assert(kvHolder.valueSize >= Fixed32Size);
|
|
1851
|
-
auto ptr = basePtr + kvHolder.offset + kvHolder.computedKVSize;
|
|
1852
|
-
ptr += kvHolder.valueSize - Fixed32Size;
|
|
1853
|
-
auto time = *(const uint32_t *) ptr;
|
|
1854
|
-
if (time != ExpireNever && time <= now) {
|
|
1855
|
-
auto oldKey = itr->first;
|
|
1856
|
-
itr = m_dic->erase(itr);
|
|
1857
|
-
#ifdef MMKV_APPLE
|
|
1858
|
-
MMKVInfo("deleting expired key [%@], due date %u", oldKey, time);
|
|
1859
|
-
[oldKey release];
|
|
1860
|
-
#else
|
|
1861
|
-
MMKVInfo("deleting expired key [%s], due date %u", oldKey.c_str(), time);
|
|
1862
|
-
#endif
|
|
1863
|
-
count++;
|
|
1864
|
-
} else {
|
|
1865
|
-
itr++;
|
|
1866
|
-
}
|
|
1867
|
-
}
|
|
1868
|
-
}
|
|
1869
|
-
if (count != 0) {
|
|
1870
|
-
MMKVInfo("deleted %zu expired keys inside [%s]", count, m_mmapID.c_str());
|
|
1871
|
-
}
|
|
1872
|
-
return count;
|
|
1873
|
-
}
|
|
1874
|
-
|
|
1875
|
-
bool MMKV::enableCompareBeforeSet() {
|
|
1876
|
-
MMKVInfo("enableCompareBeforeSet for [%s]", m_mmapID.c_str());
|
|
1877
|
-
SCOPED_LOCK(m_lock);
|
|
1878
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1879
|
-
|
|
1880
|
-
assert(!m_enableKeyExpire && "enableCompareBeforeSet is invalid when Expiration is on");
|
|
1881
|
-
assert(!m_dicCrypt && "enableCompareBeforeSet is invalid when key encryption is on");
|
|
1882
|
-
if (m_enableKeyExpire || m_dicCrypt) {
|
|
1883
|
-
return false;
|
|
1884
|
-
}
|
|
1885
|
-
|
|
1886
|
-
m_enableCompareBeforeSet = true;
|
|
1887
|
-
return true;
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
|
-
bool MMKV::disableCompareBeforeSet() {
|
|
1891
|
-
MMKVInfo("disableCompareBeforeSet for [%s]", m_mmapID.c_str());
|
|
1892
|
-
SCOPED_LOCK(m_lock);
|
|
1893
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1894
|
-
|
|
1895
|
-
assert(!m_enableKeyExpire && "disableCompareBeforeSet is invalid when Expiration is on");
|
|
1896
|
-
assert(!m_dicCrypt && "disableCompareBeforeSet is invalid when key encryption is on");
|
|
1897
|
-
if (m_enableKeyExpire || m_dicCrypt) {
|
|
1898
|
-
return false;
|
|
1899
|
-
}
|
|
1900
|
-
|
|
1901
|
-
m_enableCompareBeforeSet = false;
|
|
1902
|
-
return true;
|
|
1903
|
-
}
|
|
1904
|
-
|
|
1905
|
-
MMKV_NAMESPACE_END
|