react-native-mmkv 3.3.0 → 4.0.0-beta.1

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.
Files changed (95) hide show
  1. package/android/CMakeLists.txt +18 -9
  2. package/android/build.gradle +6 -2
  3. package/cpp/{MMKVManagedBuffer.h → ManagedMMBuffer.h} +6 -6
  4. package/cpp/MmkvHostObject.cpp +13 -8
  5. package/cpp/MmkvHostObject.h +1 -2
  6. package/cpp/MmkvTypes.h +50 -0
  7. package/cpp/NativeMmkvModule.cpp +3 -3
  8. package/cpp/NativeMmkvModule.h +1 -8
  9. package/lib/commonjs/hooks.js +2 -2
  10. package/lib/commonjs/hooks.js.map +1 -1
  11. package/lib/module/hooks.js +2 -2
  12. package/lib/module/hooks.js.map +1 -1
  13. package/lib/typescript/src/MemoryWarningListener.web.d.ts.map +1 -1
  14. package/lib/typescript/src/createMMKV.d.ts.map +1 -1
  15. package/lib/typescript/src/createMMKV.web.d.ts.map +1 -1
  16. package/package.json +24 -24
  17. package/react-native-mmkv.podspec +3 -9
  18. package/react-native.config.js +9 -0
  19. package/src/hooks.ts +2 -2
  20. package/MMKV/Core/CMakeLists.txt +0 -172
  21. package/MMKV/Core/CodedInputData.cpp +0 -252
  22. package/MMKV/Core/CodedInputData.h +0 -87
  23. package/MMKV/Core/CodedInputDataCrypt.cpp +0 -280
  24. package/MMKV/Core/CodedInputDataCrypt.h +0 -87
  25. package/MMKV/Core/CodedInputDataCrypt_OSX.cpp +0 -62
  26. package/MMKV/Core/CodedInputData_OSX.cpp +0 -92
  27. package/MMKV/Core/CodedOutputData.cpp +0 -186
  28. package/MMKV/Core/CodedOutputData.h +0 -88
  29. package/MMKV/Core/Core.xcodeproj/project.pbxproj +0 -707
  30. package/MMKV/Core/Core.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  31. package/MMKV/Core/Core.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  32. package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/Core.xcscheme +0 -67
  33. package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/MMKVWatchCore.xcscheme +0 -67
  34. package/MMKV/Core/InterProcessLock.cpp +0 -186
  35. package/MMKV/Core/InterProcessLock.h +0 -119
  36. package/MMKV/Core/InterProcessLock_Android.cpp +0 -103
  37. package/MMKV/Core/InterProcessLock_Win32.cpp +0 -108
  38. package/MMKV/Core/KeyValueHolder.cpp +0 -236
  39. package/MMKV/Core/KeyValueHolder.h +0 -122
  40. package/MMKV/Core/MMBuffer.cpp +0 -210
  41. package/MMKV/Core/MMBuffer.h +0 -111
  42. package/MMKV/Core/MMKV.cpp +0 -1702
  43. package/MMKV/Core/MMKV.h +0 -595
  44. package/MMKV/Core/MMKVLog.cpp +0 -127
  45. package/MMKV/Core/MMKVLog.h +0 -86
  46. package/MMKV/Core/MMKVLog_Android.cpp +0 -134
  47. package/MMKV/Core/MMKVMetaInfo.hpp +0 -99
  48. package/MMKV/Core/MMKVPredef.h +0 -293
  49. package/MMKV/Core/MMKV_Android.cpp +0 -261
  50. package/MMKV/Core/MMKV_IO.cpp +0 -1905
  51. package/MMKV/Core/MMKV_IO.h +0 -57
  52. package/MMKV/Core/MMKV_OSX.cpp +0 -423
  53. package/MMKV/Core/MMKV_OSX.h +0 -57
  54. package/MMKV/Core/MemoryFile.cpp +0 -603
  55. package/MMKV/Core/MemoryFile.h +0 -194
  56. package/MMKV/Core/MemoryFile_Android.cpp +0 -236
  57. package/MMKV/Core/MemoryFile_Linux.cpp +0 -125
  58. package/MMKV/Core/MemoryFile_OSX.cpp +0 -142
  59. package/MMKV/Core/MemoryFile_Win32.cpp +0 -554
  60. package/MMKV/Core/MiniPBCoder.cpp +0 -672
  61. package/MMKV/Core/MiniPBCoder.h +0 -151
  62. package/MMKV/Core/MiniPBCoder_OSX.cpp +0 -237
  63. package/MMKV/Core/PBEncodeItem.hpp +0 -104
  64. package/MMKV/Core/PBUtility.cpp +0 -61
  65. package/MMKV/Core/PBUtility.h +0 -148
  66. package/MMKV/Core/ScopedLock.hpp +0 -69
  67. package/MMKV/Core/ThreadLock.cpp +0 -75
  68. package/MMKV/Core/ThreadLock.h +0 -81
  69. package/MMKV/Core/ThreadLock_Win32.cpp +0 -89
  70. package/MMKV/Core/aes/AESCrypt.cpp +0 -273
  71. package/MMKV/Core/aes/AESCrypt.h +0 -112
  72. package/MMKV/Core/aes/openssl/openssl_aes-armv4.S +0 -1243
  73. package/MMKV/Core/aes/openssl/openssl_aes.h +0 -130
  74. package/MMKV/Core/aes/openssl/openssl_aes_core.cpp +0 -1044
  75. package/MMKV/Core/aes/openssl/openssl_aes_locl.h +0 -38
  76. package/MMKV/Core/aes/openssl/openssl_aesv8-armx.S +0 -308
  77. package/MMKV/Core/aes/openssl/openssl_arm_arch.h +0 -84
  78. package/MMKV/Core/aes/openssl/openssl_cfb128.cpp +0 -97
  79. package/MMKV/Core/aes/openssl/openssl_md32_common.h +0 -254
  80. package/MMKV/Core/aes/openssl/openssl_md5.h +0 -49
  81. package/MMKV/Core/aes/openssl/openssl_md5_dgst.cpp +0 -166
  82. package/MMKV/Core/aes/openssl/openssl_md5_locl.h +0 -75
  83. package/MMKV/Core/aes/openssl/openssl_md5_one.cpp +0 -30
  84. package/MMKV/Core/aes/openssl/openssl_opensslconf.h +0 -271
  85. package/MMKV/Core/core.vcxproj +0 -288
  86. package/MMKV/Core/core.vcxproj.filters +0 -150
  87. package/MMKV/Core/crc32/Checksum.h +0 -75
  88. package/MMKV/Core/crc32/crc32_armv8.cpp +0 -134
  89. package/MMKV/Core/crc32/zlib/CMakeLists.txt +0 -60
  90. package/MMKV/Core/crc32/zlib/crc32.cpp +0 -55
  91. package/MMKV/Core/crc32/zlib/crc32.h +0 -48
  92. package/MMKV/Core/crc32/zlib/zconf.h +0 -380
  93. package/MMKV/Core/crc32/zlib/zutil.h +0 -25
  94. package/MMKV/LICENSE.TXT +0 -193
  95. package/MMKV/README.md +0 -354
@@ -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 &section : 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 &section : 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