react-native-mmkv 2.8.0 → 2.9.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/MMKV/Core/Core.xcodeproj/project.pbxproj +15 -19
- package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/Core.xcscheme +1 -1
- package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/MMKVWatchCore.xcscheme +1 -1
- package/MMKV/Core/MMBuffer.cpp +18 -0
- package/MMKV/Core/MMBuffer.h +1 -0
- package/MMKV/Core/MMKV.cpp +173 -33
- package/MMKV/Core/MMKV.h +44 -0
- package/MMKV/Core/MMKVMetaInfo.hpp +18 -0
- package/MMKV/Core/MMKVPredef.h +2 -2
- package/MMKV/Core/MMKV_IO.cpp +477 -68
- package/MMKV/Core/MMKV_OSX.cpp +65 -14
- package/MMKV/Core/MemoryFile_Win32.cpp +39 -35
- package/MMKV/Core/MiniPBCoder.cpp +3 -7
- package/MMKV/Core/MiniPBCoder_OSX.cpp +4 -4
- package/MMKV/Core/PBUtility.cpp +1 -1
- package/MMKV/Core/PBUtility.h +7 -0
- package/MMKV/Core/aes/AESCrypt.h +1 -1
- package/MMKV/Core/aes/openssl/openssl_aes-armv4.S +4 -0
- package/README.md +12 -3
- package/android/build.gradle +1 -0
- package/android/src/main/AndroidManifest.xml +1 -2
- package/lib/commonjs/createMMKV.web.js +23 -0
- package/lib/commonjs/createMMKV.web.js.map +1 -1
- package/lib/module/createMMKV.web.js +23 -0
- package/lib/module/createMMKV.web.js.map +1 -1
- package/lib/typescript/createMMKV.web.d.ts.map +1 -1
- package/package.json +7 -6
- package/src/MMKV.ts +248 -0
- package/src/PlatformChecker.ts +7 -0
- package/src/createMMKV.mock.ts +33 -0
- package/src/createMMKV.ts +70 -0
- package/src/createMMKV.web.ts +119 -0
- package/src/createTextEncoder.ts +16 -0
- package/src/hooks.ts +232 -0
- package/src/index.ts +2 -0
package/MMKV/Core/MMKV_IO.cpp
CHANGED
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
#include <algorithm>
|
|
38
38
|
#include <cassert>
|
|
39
39
|
#include <cstring>
|
|
40
|
+
#include <ctime>
|
|
40
41
|
|
|
41
42
|
#ifdef MMKV_IOS
|
|
42
43
|
# include "MMKV_OSX.h"
|
|
@@ -52,14 +53,10 @@ using namespace std;
|
|
|
52
53
|
using namespace mmkv;
|
|
53
54
|
using KVHolderRet_t = std::pair<bool, KeyValueHolder>;
|
|
54
55
|
|
|
55
|
-
constexpr uint32_t Fixed32Size = pbFixed32Size();
|
|
56
|
-
|
|
57
56
|
MMKV_NAMESPACE_BEGIN
|
|
58
57
|
|
|
59
58
|
void MMKV::loadFromFile() {
|
|
60
|
-
|
|
61
|
-
m_metaInfo->read(m_metaFile->getMemory());
|
|
62
|
-
}
|
|
59
|
+
loadMetaInfoAndCheck();
|
|
63
60
|
#ifndef MMKV_DISABLE_CRYPT
|
|
64
61
|
if (m_crypter) {
|
|
65
62
|
if (m_metaInfo->m_version >= MMKVVersionRandomIV) {
|
|
@@ -164,7 +161,7 @@ void MMKV::partialLoadFromFile() {
|
|
|
164
161
|
m_output->seek(addedSize);
|
|
165
162
|
m_hasFullWriteback = false;
|
|
166
163
|
|
|
167
|
-
auto count = m_crypter ? m_dicCrypt->size() : m_dic->size();
|
|
164
|
+
[[maybe_unused]] auto count = m_crypter ? m_dicCrypt->size() : m_dic->size();
|
|
168
165
|
MMKVDebug("partial loaded [%s] with %zu values", m_mmapID.c_str(), count);
|
|
169
166
|
return;
|
|
170
167
|
} else {
|
|
@@ -178,6 +175,37 @@ void MMKV::partialLoadFromFile() {
|
|
|
178
175
|
loadFromFile();
|
|
179
176
|
}
|
|
180
177
|
|
|
178
|
+
void MMKV::loadMetaInfoAndCheck() {
|
|
179
|
+
if (!m_metaFile->isFileValid()) {
|
|
180
|
+
m_metaFile->reloadFromFile();
|
|
181
|
+
}
|
|
182
|
+
if (!m_metaFile->isFileValid()) {
|
|
183
|
+
MMKVError("file [%s] not valid", m_metaFile->getPath().c_str());
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
m_metaInfo->read(m_metaFile->getMemory());
|
|
188
|
+
// the meta file is in specious status
|
|
189
|
+
if (m_metaInfo->m_version >= MMKVVersionHolder) {
|
|
190
|
+
MMKVWarning("meta file [%s] in specious state, version %u, flags 0x%llx", m_mmapID.c_str(), m_metaInfo->m_version, m_metaInfo->m_flags);
|
|
191
|
+
|
|
192
|
+
// MMKVVersionActualSize is the last version we don't check meta file
|
|
193
|
+
m_metaInfo->m_version = MMKVVersionActualSize;
|
|
194
|
+
m_metaInfo->m_flags = 0;
|
|
195
|
+
m_metaInfo->write(m_metaFile->getMemory());
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (m_metaInfo->m_version >= MMKVVersionFlag) {
|
|
199
|
+
m_enableKeyExpire = m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre);
|
|
200
|
+
MMKVInfo("meta file [%s] has flag [%llu]", m_mmapID.c_str(), m_metaInfo->m_flags);
|
|
201
|
+
} else {
|
|
202
|
+
if (m_metaInfo->m_flags != 0) {
|
|
203
|
+
m_metaInfo->m_flags = 0;
|
|
204
|
+
m_metaInfo->write(m_metaFile->getMemory());
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
181
209
|
void MMKV::checkDataValid(bool &loadFromFile, bool &needFullWriteback) {
|
|
182
210
|
// try auto recover from last confirmed location
|
|
183
211
|
auto fileSize = m_file->getFileSize();
|
|
@@ -335,10 +363,20 @@ static pair<MMBuffer, size_t> prepareEncode(const MMKVMapCrypt &dic) {
|
|
|
335
363
|
// skip the pb size of buffer
|
|
336
364
|
auto sizeOfMap = CodedInputData(buffer.getPtr(), buffer.length()).readUInt32();
|
|
337
365
|
totalSize += sizeOfMap;
|
|
338
|
-
return make_pair(move(buffer), totalSize);
|
|
366
|
+
return make_pair(std::move(buffer), totalSize);
|
|
339
367
|
}
|
|
340
368
|
#endif
|
|
341
369
|
|
|
370
|
+
static pair<MMBuffer, size_t> prepareEncode(MMKVVector &&vec) {
|
|
371
|
+
// make some room for placeholder
|
|
372
|
+
size_t totalSize = ItemSizeHolderSize;
|
|
373
|
+
auto buffer = MiniPBCoder::encodeDataWithObject(vec);
|
|
374
|
+
// skip the pb size of buffer
|
|
375
|
+
auto sizeOfMap = CodedInputData(buffer.getPtr(), buffer.length()).readUInt32();
|
|
376
|
+
totalSize += sizeOfMap;
|
|
377
|
+
return make_pair(std::move(buffer), totalSize);
|
|
378
|
+
}
|
|
379
|
+
|
|
342
380
|
// since we use append mode, when -[setData: forKey:] many times, space may not be enough
|
|
343
381
|
// try a full rewrite to make space
|
|
344
382
|
bool MMKV::ensureMemorySize(size_t newSize) {
|
|
@@ -348,38 +386,47 @@ bool MMKV::ensureMemorySize(size_t newSize) {
|
|
|
348
386
|
}
|
|
349
387
|
|
|
350
388
|
if (newSize >= m_output->spaceLeft() || (m_crypter ? m_dicCrypt->empty() : m_dic->empty())) {
|
|
389
|
+
// remove expired keys
|
|
390
|
+
if (m_enableKeyExpire) {
|
|
391
|
+
filterExpiredKeys();
|
|
392
|
+
}
|
|
351
393
|
// try a full rewrite to make space
|
|
352
|
-
auto fileSize = m_file->getFileSize();
|
|
353
394
|
auto preparedData = m_crypter ? prepareEncode(*m_dicCrypt) : prepareEncode(*m_dic);
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
size_t futureUsage = avgItemSize * std::max<size_t>(8, (dicCount + 1) / 2);
|
|
359
|
-
// 1. no space for a full rewrite, double it
|
|
360
|
-
// 2. or space is not large enough for future usage, double it to avoid frequently full rewrite
|
|
361
|
-
if (lenNeeded >= fileSize || (lenNeeded + futureUsage) >= fileSize) {
|
|
362
|
-
size_t oldSize = fileSize;
|
|
363
|
-
do {
|
|
364
|
-
fileSize *= 2;
|
|
365
|
-
} while (lenNeeded + futureUsage >= fileSize);
|
|
366
|
-
MMKVInfo("extending [%s] file size from %zu to %zu, incoming size:%zu, future usage:%zu", m_mmapID.c_str(),
|
|
367
|
-
oldSize, fileSize, newSize, futureUsage);
|
|
368
|
-
|
|
369
|
-
// if we can't extend size, rollback to old state
|
|
370
|
-
if (!m_file->truncate(fileSize)) {
|
|
371
|
-
return false;
|
|
372
|
-
}
|
|
395
|
+
return expandAndWriteBack(newSize, std::move(preparedData));
|
|
396
|
+
}
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
373
399
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
400
|
+
// try a full rewrite to make space
|
|
401
|
+
bool MMKV::expandAndWriteBack(size_t newSize, std::pair<mmkv::MMBuffer, size_t> preparedData) {
|
|
402
|
+
auto fileSize = m_file->getFileSize();
|
|
403
|
+
auto sizeOfDic = preparedData.second;
|
|
404
|
+
size_t lenNeeded = sizeOfDic + Fixed32Size + newSize;
|
|
405
|
+
size_t dicCount = m_crypter ? m_dicCrypt->size() : m_dic->size();
|
|
406
|
+
size_t avgItemSize = lenNeeded / std::max<size_t>(1, dicCount);
|
|
407
|
+
size_t futureUsage = avgItemSize * std::max<size_t>(8, (dicCount + 1) / 2);
|
|
408
|
+
// 1. no space for a full rewrite, double it
|
|
409
|
+
// 2. or space is not large enough for future usage, double it to avoid frequently full rewrite
|
|
410
|
+
if (lenNeeded >= fileSize || (lenNeeded + futureUsage) >= fileSize) {
|
|
411
|
+
size_t oldSize = fileSize;
|
|
412
|
+
do {
|
|
413
|
+
fileSize *= 2;
|
|
414
|
+
} while (lenNeeded + futureUsage >= fileSize);
|
|
415
|
+
MMKVInfo("extending [%s] file size from %zu to %zu, incoming size:%zu, future usage:%zu", m_mmapID.c_str(),
|
|
416
|
+
oldSize, fileSize, newSize, futureUsage);
|
|
417
|
+
|
|
418
|
+
// if we can't extend size, rollback to old state
|
|
419
|
+
if (!m_file->truncate(fileSize)) {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// check if we fail to make more space
|
|
424
|
+
if (!isFileValid()) {
|
|
425
|
+
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
426
|
+
return false;
|
|
379
427
|
}
|
|
380
|
-
return doFullWriteBack(move(preparedData), nullptr);
|
|
381
428
|
}
|
|
382
|
-
return
|
|
429
|
+
return doFullWriteBack(std::move(preparedData), nullptr);
|
|
383
430
|
}
|
|
384
431
|
|
|
385
432
|
size_t MMKV::readActualSize() {
|
|
@@ -450,6 +497,11 @@ bool MMKV::writeActualSize(size_t size, uint32_t crcDigest, const void *iv, bool
|
|
|
450
497
|
MMKVInfo("[%s] increase sequence to %u, crc %u, actualSize %u", m_mmapID.c_str(), m_metaInfo->m_sequence,
|
|
451
498
|
m_metaInfo->m_crcDigest, m_metaInfo->m_actualSize);
|
|
452
499
|
}
|
|
500
|
+
if (m_metaInfo->m_version < MMKVVersionFlag) {
|
|
501
|
+
m_metaInfo->m_flags = 0;
|
|
502
|
+
m_metaInfo->m_version = MMKVVersionFlag;
|
|
503
|
+
needsFullWrite = true;
|
|
504
|
+
}
|
|
453
505
|
#ifdef MMKV_IOS
|
|
454
506
|
auto ret = guardForBackgroundWriting(m_metaFile->getMemory(), sizeof(MMKVMetaInfo));
|
|
455
507
|
if (!ret.first) {
|
|
@@ -464,7 +516,7 @@ bool MMKV::writeActualSize(size_t size, uint32_t crcDigest, const void *iv, bool
|
|
|
464
516
|
return true;
|
|
465
517
|
}
|
|
466
518
|
|
|
467
|
-
MMBuffer MMKV::
|
|
519
|
+
MMBuffer MMKV::getRawDataForKey(MMKVKey_t key) {
|
|
468
520
|
checkLoadData();
|
|
469
521
|
#ifndef MMKV_DISABLE_CRYPT
|
|
470
522
|
if (m_crypter) {
|
|
@@ -486,6 +538,13 @@ MMBuffer MMKV::getDataForKey(MMKVKey_t key) {
|
|
|
486
538
|
return nan;
|
|
487
539
|
}
|
|
488
540
|
|
|
541
|
+
mmkv::MMBuffer MMKV::getDataForKey(MMKVKey_t key) {
|
|
542
|
+
if (unlikely(m_enableKeyExpire)) {
|
|
543
|
+
return getDataWithoutMTimeForKey(key);
|
|
544
|
+
}
|
|
545
|
+
return getRawDataForKey(key);
|
|
546
|
+
}
|
|
547
|
+
|
|
489
548
|
#ifndef MMKV_DISABLE_CRYPT
|
|
490
549
|
// for Apple watch simulator
|
|
491
550
|
# if defined(TARGET_OS_SIMULATOR) && defined(TARGET_CPU_X86)
|
|
@@ -522,12 +581,24 @@ bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
|
|
|
522
581
|
if (!ret.first) {
|
|
523
582
|
return false;
|
|
524
583
|
}
|
|
584
|
+
KeyValueHolderCrypt kvHolder;
|
|
525
585
|
if (KeyValueHolderCrypt::isValueStoredAsOffset(ret.second.valueSize)) {
|
|
526
|
-
KeyValueHolderCrypt
|
|
586
|
+
kvHolder = KeyValueHolderCrypt(ret.second.keySize, ret.second.valueSize, ret.second.offset);
|
|
527
587
|
memcpy(&kvHolder.cryptStatus, &t_status, sizeof(t_status));
|
|
528
|
-
itr->second = move(kvHolder);
|
|
529
588
|
} else {
|
|
530
|
-
|
|
589
|
+
kvHolder = KeyValueHolderCrypt(std::move(data));
|
|
590
|
+
}
|
|
591
|
+
if (likely(!m_enableKeyExpire)) {
|
|
592
|
+
itr->second = std::move(kvHolder);
|
|
593
|
+
} else {
|
|
594
|
+
itr = m_dicCrypt->find(key);
|
|
595
|
+
if (itr != m_dicCrypt->end()) {
|
|
596
|
+
itr->second = std::move(kvHolder);
|
|
597
|
+
} else {
|
|
598
|
+
// in case filterExpiredKeys() is triggered
|
|
599
|
+
m_dicCrypt->emplace(key, std::move(kvHolder));
|
|
600
|
+
retain_key(key);
|
|
601
|
+
}
|
|
531
602
|
}
|
|
532
603
|
} else {
|
|
533
604
|
auto ret = appendDataWithKey(data, key, isDataHolder);
|
|
@@ -541,31 +612,45 @@ bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
|
|
|
541
612
|
memcpy(&(r.first->second.cryptStatus), &t_status, sizeof(t_status));
|
|
542
613
|
}
|
|
543
614
|
} else {
|
|
544
|
-
m_dicCrypt->emplace(key, KeyValueHolderCrypt(move(data)));
|
|
615
|
+
m_dicCrypt->emplace(key, KeyValueHolderCrypt(std::move(data)));
|
|
545
616
|
}
|
|
617
|
+
retain_key(key);
|
|
546
618
|
}
|
|
547
619
|
} else
|
|
548
620
|
#endif // MMKV_DISABLE_CRYPT
|
|
549
621
|
{
|
|
550
622
|
auto itr = m_dic->find(key);
|
|
551
623
|
if (itr != m_dic->end()) {
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
624
|
+
if (likely(!m_enableKeyExpire)) {
|
|
625
|
+
auto ret = appendDataWithKey(data, itr->second, isDataHolder);
|
|
626
|
+
if (!ret.first) {
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
itr->second = std::move(ret.second);
|
|
630
|
+
} else {
|
|
631
|
+
auto ret = appendDataWithKey(data, key, isDataHolder);
|
|
632
|
+
if (!ret.first) {
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
itr = m_dic->find(key);
|
|
636
|
+
if (itr != m_dic->end()) {
|
|
637
|
+
itr->second = std::move(ret.second);
|
|
638
|
+
} else {
|
|
639
|
+
// in case filterExpiredKeys() is triggered
|
|
640
|
+
m_dic->emplace(key, std::move(ret.second));
|
|
641
|
+
retain_key(key);
|
|
642
|
+
}
|
|
555
643
|
}
|
|
556
|
-
itr->second = std::move(ret.second);
|
|
557
644
|
} else {
|
|
558
645
|
auto ret = appendDataWithKey(data, key, isDataHolder);
|
|
559
646
|
if (!ret.first) {
|
|
560
647
|
return false;
|
|
561
648
|
}
|
|
562
649
|
m_dic->emplace(key, std::move(ret.second));
|
|
650
|
+
retain_key(key);
|
|
563
651
|
}
|
|
564
652
|
}
|
|
565
653
|
m_hasFullWriteback = false;
|
|
566
|
-
#ifdef MMKV_APPLE
|
|
567
|
-
[key retain];
|
|
568
|
-
#endif
|
|
569
654
|
return true;
|
|
570
655
|
}
|
|
571
656
|
|
|
@@ -582,6 +667,13 @@ bool MMKV::removeDataForKey(MMKVKey_t key) {
|
|
|
582
667
|
# ifdef MMKV_APPLE
|
|
583
668
|
auto ret = appendDataWithKey(nan, key, itr->second);
|
|
584
669
|
if (ret.first) {
|
|
670
|
+
if (unlikely(m_enableKeyExpire)) {
|
|
671
|
+
// filterExpiredKeys() may invalid itr
|
|
672
|
+
itr = m_dicCrypt->find(key);
|
|
673
|
+
if (itr == m_dicCrypt->end()) {
|
|
674
|
+
return true;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
585
677
|
auto oldKey = itr->first;
|
|
586
678
|
m_dicCrypt->erase(itr);
|
|
587
679
|
[oldKey release];
|
|
@@ -589,7 +681,11 @@ bool MMKV::removeDataForKey(MMKVKey_t key) {
|
|
|
589
681
|
# else
|
|
590
682
|
auto ret = appendDataWithKey(nan, key);
|
|
591
683
|
if (ret.first) {
|
|
592
|
-
|
|
684
|
+
if (unlikely(m_enableKeyExpire)) {
|
|
685
|
+
m_dicCrypt->erase(key);
|
|
686
|
+
} else {
|
|
687
|
+
m_dicCrypt->erase(itr);
|
|
688
|
+
}
|
|
593
689
|
}
|
|
594
690
|
# endif
|
|
595
691
|
return ret.first;
|
|
@@ -601,14 +697,26 @@ bool MMKV::removeDataForKey(MMKVKey_t key) {
|
|
|
601
697
|
if (itr != m_dic->end()) {
|
|
602
698
|
m_hasFullWriteback = false;
|
|
603
699
|
static MMBuffer nan;
|
|
604
|
-
auto ret = appendDataWithKey(nan, itr->second);
|
|
700
|
+
auto ret = likely(!m_enableKeyExpire) ? appendDataWithKey(nan, itr->second) : appendDataWithKey(nan, key);
|
|
605
701
|
if (ret.first) {
|
|
606
702
|
#ifdef MMKV_APPLE
|
|
703
|
+
if (unlikely(m_enableKeyExpire)) {
|
|
704
|
+
// filterExpiredKeys() may invalid itr
|
|
705
|
+
itr = m_dic->find(key);
|
|
706
|
+
if (itr == m_dic->end()) {
|
|
707
|
+
return true;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
607
710
|
auto oldKey = itr->first;
|
|
608
711
|
m_dic->erase(itr);
|
|
609
712
|
[oldKey release];
|
|
610
713
|
#else
|
|
611
|
-
|
|
714
|
+
if (unlikely(m_enableKeyExpire)) {
|
|
715
|
+
// filterExpiredKeys() may invalid itr
|
|
716
|
+
m_dic->erase(key);
|
|
717
|
+
} else {
|
|
718
|
+
m_dic->erase(itr);
|
|
719
|
+
}
|
|
612
720
|
#endif
|
|
613
721
|
}
|
|
614
722
|
return ret.first;
|
|
@@ -726,23 +834,28 @@ bool MMKV::fullWriteback(AESCrypt *newCrypter) {
|
|
|
726
834
|
return false;
|
|
727
835
|
}
|
|
728
836
|
|
|
837
|
+
if (unlikely(m_enableKeyExpire)) {
|
|
838
|
+
filterExpiredKeys();
|
|
839
|
+
}
|
|
840
|
+
|
|
729
841
|
if (m_crypter ? m_dicCrypt->empty() : m_dic->empty()) {
|
|
730
842
|
clearAll();
|
|
731
843
|
return true;
|
|
732
844
|
}
|
|
733
845
|
|
|
846
|
+
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
734
847
|
auto preparedData = m_crypter ? prepareEncode(*m_dicCrypt) : prepareEncode(*m_dic);
|
|
735
848
|
auto sizeOfDic = preparedData.second;
|
|
736
|
-
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
737
849
|
if (sizeOfDic > 0) {
|
|
738
850
|
auto fileSize = m_file->getFileSize();
|
|
739
851
|
if (sizeOfDic + Fixed32Size <= fileSize) {
|
|
740
|
-
return doFullWriteBack(move(preparedData), newCrypter);
|
|
852
|
+
return doFullWriteBack(std::move(preparedData), newCrypter);
|
|
741
853
|
} else {
|
|
742
854
|
assert(0);
|
|
743
855
|
assert(newCrypter == nullptr);
|
|
744
|
-
//
|
|
745
|
-
|
|
856
|
+
// expandAndWriteBack() will extend file & full rewrite, no need to write back again
|
|
857
|
+
auto newSize = sizeOfDic + Fixed32Size - fileSize;
|
|
858
|
+
return expandAndWriteBack(newSize, std::move(preparedData));
|
|
746
859
|
}
|
|
747
860
|
}
|
|
748
861
|
return false;
|
|
@@ -893,9 +1006,25 @@ static void memmoveDictionary(MMKVMapCrypt &dic,
|
|
|
893
1006
|
|
|
894
1007
|
#endif // MMKV_DISABLE_CRYPT
|
|
895
1008
|
|
|
896
|
-
|
|
1009
|
+
static void fullWriteBackWholeData(MMBuffer allData, size_t totalSize, CodedOutputData *output) {
|
|
1010
|
+
auto originOutputPtr = output->curWritePointer();
|
|
1011
|
+
output->writeRawVarint32(ItemSizeHolder);
|
|
1012
|
+
if (allData.length() > 0) {
|
|
1013
|
+
auto dataSize = CodedInputData(allData.getPtr(), allData.length()).readUInt32();
|
|
1014
|
+
if (dataSize > 0) {
|
|
1015
|
+
auto dataPtr = (uint8_t *)allData.getPtr() + pbRawVarint32Size(dataSize);
|
|
1016
|
+
memcpy(output->curWritePointer(), dataPtr, dataSize);
|
|
1017
|
+
output->seek(dataSize);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
[[maybe_unused]] auto writtenSize = (size_t) (output->curWritePointer() - originOutputPtr);
|
|
1021
|
+
assert(writtenSize == totalSize);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
#ifndef MMKV_DISABLE_CRYPT
|
|
1025
|
+
bool MMKV::doFullWriteBack(pair<MMBuffer, size_t> prepared, AESCrypt *newCrypter) {
|
|
897
1026
|
auto ptr = (uint8_t *) m_file->getMemory();
|
|
898
|
-
auto totalSize =
|
|
1027
|
+
auto totalSize = prepared.second;
|
|
899
1028
|
#ifdef MMKV_IOS
|
|
900
1029
|
auto ret = guardForBackgroundWriting(ptr + Fixed32Size, totalSize);
|
|
901
1030
|
if (!ret.first) {
|
|
@@ -903,36 +1032,32 @@ bool MMKV::doFullWriteBack(pair<MMBuffer, size_t> preparedData, AESCrypt *newCry
|
|
|
903
1032
|
}
|
|
904
1033
|
#endif
|
|
905
1034
|
|
|
906
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
907
1035
|
uint8_t newIV[AES_KEY_LEN];
|
|
908
|
-
auto decrypter = m_crypter;
|
|
909
1036
|
auto encrypter = (newCrypter == InvalidCryptPtr) ? nullptr : (newCrypter ? newCrypter : m_crypter);
|
|
910
1037
|
if (encrypter) {
|
|
911
1038
|
AESCrypt::fillRandomIV(newIV);
|
|
912
1039
|
encrypter->resetIV(newIV, sizeof(newIV));
|
|
913
1040
|
}
|
|
914
|
-
#endif
|
|
915
1041
|
|
|
916
1042
|
delete m_output;
|
|
917
1043
|
m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
|
|
918
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
919
1044
|
if (m_crypter) {
|
|
920
|
-
|
|
1045
|
+
auto decrypter = m_crypter;
|
|
1046
|
+
memmoveDictionary(*m_dicCrypt, m_output, ptr, decrypter, encrypter, prepared);
|
|
1047
|
+
} else if (prepared.first.length() != 0) {
|
|
1048
|
+
auto &preparedData = prepared.first;
|
|
1049
|
+
fullWriteBackWholeData(std::move(preparedData), totalSize, m_output);
|
|
1050
|
+
if (encrypter) {
|
|
1051
|
+
encrypter->encrypt(ptr + Fixed32Size, ptr + Fixed32Size, totalSize);
|
|
1052
|
+
}
|
|
921
1053
|
} else {
|
|
922
|
-
#else
|
|
923
|
-
{
|
|
924
|
-
auto encrypter = m_crypter;
|
|
925
|
-
#endif
|
|
926
1054
|
memmoveDictionary(*m_dic, m_output, ptr, encrypter, totalSize);
|
|
927
1055
|
}
|
|
928
1056
|
|
|
929
1057
|
m_actualSize = totalSize;
|
|
930
|
-
#ifndef MMKV_DISABLE_CRYPT
|
|
931
1058
|
if (encrypter) {
|
|
932
1059
|
recaculateCRCDigestWithIV(newIV);
|
|
933
|
-
} else
|
|
934
|
-
#endif
|
|
935
|
-
{
|
|
1060
|
+
} else {
|
|
936
1061
|
recaculateCRCDigestWithIV(nullptr);
|
|
937
1062
|
}
|
|
938
1063
|
m_hasFullWriteback = true;
|
|
@@ -941,9 +1066,41 @@ bool MMKV::doFullWriteBack(pair<MMBuffer, size_t> preparedData, AESCrypt *newCry
|
|
|
941
1066
|
return true;
|
|
942
1067
|
}
|
|
943
1068
|
|
|
1069
|
+
#else // MMKV_DISABLE_CRYPT
|
|
1070
|
+
|
|
1071
|
+
bool MMKV::doFullWriteBack(pair<MMBuffer, size_t> prepared, AESCrypt *) {
|
|
1072
|
+
auto ptr = (uint8_t *) m_file->getMemory();
|
|
1073
|
+
auto totalSize = prepared.second;
|
|
1074
|
+
#ifdef MMKV_IOS
|
|
1075
|
+
auto ret = guardForBackgroundWriting(ptr + Fixed32Size, totalSize);
|
|
1076
|
+
if (!ret.first) {
|
|
1077
|
+
return false;
|
|
1078
|
+
}
|
|
1079
|
+
#endif
|
|
1080
|
+
|
|
1081
|
+
delete m_output;
|
|
1082
|
+
m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
|
|
1083
|
+
if (prepared.first.length() != 0) {
|
|
1084
|
+
auto &preparedData = prepared.first;
|
|
1085
|
+
fullWriteBackWholeData(std::move(preparedData), totalSize, m_output);
|
|
1086
|
+
} else {
|
|
1087
|
+
constexpr AESCrypt *encrypter = nullptr;
|
|
1088
|
+
memmoveDictionary(*m_dic, m_output, ptr, encrypter, totalSize);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
m_actualSize = totalSize;
|
|
1092
|
+
recaculateCRCDigestWithIV(nullptr);
|
|
1093
|
+
m_hasFullWriteback = true;
|
|
1094
|
+
// make sure lastConfirmedMetaInfo is saved
|
|
1095
|
+
sync(MMKV_SYNC);
|
|
1096
|
+
return true;
|
|
1097
|
+
}
|
|
1098
|
+
#endif // MMKV_DISABLE_CRYPT
|
|
1099
|
+
|
|
944
1100
|
#ifndef MMKV_DISABLE_CRYPT
|
|
945
1101
|
bool MMKV::reKey(const string &cryptKey) {
|
|
946
1102
|
SCOPED_LOCK(m_lock);
|
|
1103
|
+
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
947
1104
|
checkLoadData();
|
|
948
1105
|
|
|
949
1106
|
bool ret = false;
|
|
@@ -1118,4 +1275,256 @@ bool MMKV::isFileValid(const string &mmapID, MMKVPath_t *relatePath) {
|
|
|
1118
1275
|
}
|
|
1119
1276
|
}
|
|
1120
1277
|
|
|
1278
|
+
// ---- auto expire ----
|
|
1279
|
+
|
|
1280
|
+
uint32_t MMKV::getCurrentTimeInSecond() {
|
|
1281
|
+
auto time = ::time(nullptr);
|
|
1282
|
+
return static_cast<uint32_t>(time);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
bool MMKV::doFullWriteBack(MMKVVector &&vec) {
|
|
1286
|
+
auto preparedData = prepareEncode(std::move(vec));
|
|
1287
|
+
|
|
1288
|
+
// must clean before write-back and after prepareEncode()
|
|
1289
|
+
if (m_crypter) {
|
|
1290
|
+
clearDictionary(m_dicCrypt);
|
|
1291
|
+
} else {
|
|
1292
|
+
clearDictionary(m_dic);
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
bool ret = false;
|
|
1296
|
+
auto sizeOfDic = preparedData.second;
|
|
1297
|
+
auto fileSize = m_file->getFileSize();
|
|
1298
|
+
if (sizeOfDic + Fixed32Size <= fileSize) {
|
|
1299
|
+
ret = doFullWriteBack(std::move(preparedData), nullptr);
|
|
1300
|
+
} else {
|
|
1301
|
+
// expandAndWriteBack() will extend file & full rewrite, no need to write back again
|
|
1302
|
+
auto newSize = sizeOfDic + Fixed32Size - fileSize;
|
|
1303
|
+
ret = expandAndWriteBack(newSize, std::move(preparedData));
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
clearMemoryCache();
|
|
1307
|
+
return ret;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
bool MMKV::enableAutoKeyExpire(uint32_t expiredInSeconds) {
|
|
1311
|
+
SCOPED_LOCK(m_lock);
|
|
1312
|
+
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1313
|
+
checkLoadData();
|
|
1314
|
+
|
|
1315
|
+
if (m_expiredInSeconds != expiredInSeconds) {
|
|
1316
|
+
MMKVInfo("expiredInSeconds: %u", expiredInSeconds);
|
|
1317
|
+
m_expiredInSeconds = expiredInSeconds;
|
|
1318
|
+
}
|
|
1319
|
+
m_enableKeyExpire = true;
|
|
1320
|
+
if (m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre)) {
|
|
1321
|
+
return true;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
auto autoRecordExpireTime = (m_expiredInSeconds != 0);
|
|
1325
|
+
auto time = autoRecordExpireTime ? getCurrentTimeInSecond() + m_expiredInSeconds : 0;
|
|
1326
|
+
MMKVInfo("turn on recording expire date for all keys inside [%s] from now %u", m_mmapID.c_str(), time);
|
|
1327
|
+
m_metaInfo->setFlag(MMKVMetaInfo::EnableKeyExipre);
|
|
1328
|
+
m_metaInfo->m_version = MMKVVersionFlag;
|
|
1329
|
+
|
|
1330
|
+
if (m_file->getFileSize() == DEFAULT_MMAP_SIZE && m_actualSize == 0) {
|
|
1331
|
+
MMKVInfo("file is new, don't need a full writeback [%s], just update meta file", m_mmapID.c_str());
|
|
1332
|
+
writeActualSize(0, 0, nullptr, IncreaseSequence);
|
|
1333
|
+
m_metaFile->msync(MMKV_SYNC);
|
|
1334
|
+
return true;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
MMKVVector vec;
|
|
1338
|
+
auto packKeyValue = [&](const MMKVKey_t &key, const MMBuffer &value) {
|
|
1339
|
+
MMBuffer data(value.length() + Fixed32Size);
|
|
1340
|
+
auto ptr = (uint8_t *)data.getPtr();
|
|
1341
|
+
memcpy(ptr, value.getPtr(), value.length());
|
|
1342
|
+
memcpy(ptr + value.length(), &time, Fixed32Size);
|
|
1343
|
+
vec.emplace_back(key, std::move(data));
|
|
1344
|
+
};
|
|
1345
|
+
|
|
1346
|
+
auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
|
|
1347
|
+
#ifndef MMKV_DISABLE_CRYPT
|
|
1348
|
+
if (m_crypter) {
|
|
1349
|
+
for (auto &pair : *m_dicCrypt) {
|
|
1350
|
+
auto &key = pair.first;
|
|
1351
|
+
auto &value = pair.second;
|
|
1352
|
+
auto buffer = value.toMMBuffer(basePtr, m_crypter);
|
|
1353
|
+
packKeyValue(key, buffer);
|
|
1354
|
+
}
|
|
1355
|
+
} else
|
|
1356
|
+
#endif
|
|
1357
|
+
{
|
|
1358
|
+
for (auto &pair : *m_dic) {
|
|
1359
|
+
auto &key = pair.first;
|
|
1360
|
+
auto &value = pair.second;
|
|
1361
|
+
auto buffer = value.toMMBuffer(basePtr);
|
|
1362
|
+
packKeyValue(key, buffer);
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
return doFullWriteBack(std::move(vec));
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
bool MMKV::disableAutoKeyExpire() {
|
|
1370
|
+
SCOPED_LOCK(m_lock);
|
|
1371
|
+
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1372
|
+
checkLoadData();
|
|
1373
|
+
|
|
1374
|
+
m_expiredInSeconds = 0;
|
|
1375
|
+
m_enableKeyExpire = false;
|
|
1376
|
+
if (!m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre)) {
|
|
1377
|
+
return true;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
MMKVInfo("erase previous recorded expire date for all keys inside [%s]", m_mmapID.c_str());
|
|
1381
|
+
m_metaInfo->unsetFlag(MMKVMetaInfo::EnableKeyExipre);
|
|
1382
|
+
m_metaInfo->m_version = MMKVVersionFlag;
|
|
1383
|
+
|
|
1384
|
+
if (m_file->getFileSize() == DEFAULT_MMAP_SIZE && m_actualSize == 0) {
|
|
1385
|
+
MMKVInfo("file is new, don't need a full write-back [%s], just update meta file", m_mmapID.c_str());
|
|
1386
|
+
writeActualSize(0, 0, nullptr, IncreaseSequence);
|
|
1387
|
+
m_metaFile->msync(MMKV_SYNC);
|
|
1388
|
+
return true;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
MMKVVector vec;
|
|
1392
|
+
auto packKeyValue = [&](const MMKVKey_t &key, const MMBuffer &value) {
|
|
1393
|
+
assert(value.length() >= Fixed32Size);
|
|
1394
|
+
MMBuffer data(value.length() - Fixed32Size);
|
|
1395
|
+
auto ptr = (uint8_t *)data.getPtr();
|
|
1396
|
+
memcpy(ptr, value.getPtr(), value.length() - Fixed32Size);
|
|
1397
|
+
vec.emplace_back(key, std::move(data));
|
|
1398
|
+
};
|
|
1399
|
+
|
|
1400
|
+
auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
|
|
1401
|
+
#ifndef MMKV_DISABLE_CRYPT
|
|
1402
|
+
if (m_crypter) {
|
|
1403
|
+
for (auto &pair : *m_dicCrypt) {
|
|
1404
|
+
auto &key = pair.first;
|
|
1405
|
+
auto &value = pair.second;
|
|
1406
|
+
auto buffer = value.toMMBuffer(basePtr, m_crypter);
|
|
1407
|
+
packKeyValue(key, buffer);
|
|
1408
|
+
}
|
|
1409
|
+
} else
|
|
1410
|
+
#endif
|
|
1411
|
+
{
|
|
1412
|
+
for (auto &pair : *m_dic) {
|
|
1413
|
+
auto &key = pair.first;
|
|
1414
|
+
auto &value = pair.second;
|
|
1415
|
+
auto buffer = value.toMMBuffer(basePtr);
|
|
1416
|
+
packKeyValue(key, buffer);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
return doFullWriteBack(std::move(vec));
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
uint32_t MMKV::getExpireTimeForKey(MMKVKey_t key) {
|
|
1424
|
+
SCOPED_LOCK(m_lock);
|
|
1425
|
+
SCOPED_LOCK(m_sharedProcessLock);
|
|
1426
|
+
checkLoadData();
|
|
1427
|
+
|
|
1428
|
+
if (!m_enableKeyExpire || key_length(key) == 0) {
|
|
1429
|
+
return 0;
|
|
1430
|
+
}
|
|
1431
|
+
auto raw = getRawDataForKey(key);
|
|
1432
|
+
assert(raw.length() == 0 || raw.length() >= Fixed32Size);
|
|
1433
|
+
if (raw.length() < Fixed32Size) {
|
|
1434
|
+
return 0;
|
|
1435
|
+
}
|
|
1436
|
+
auto ptr = (const uint8_t *)raw.getPtr() + raw.length() - Fixed32Size;
|
|
1437
|
+
auto time = *(const uint32_t *)ptr;
|
|
1438
|
+
return time;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
mmkv::MMBuffer MMKV::getDataWithoutMTimeForKey(MMKVKey_t key) {
|
|
1442
|
+
SCOPED_LOCK(m_lock);
|
|
1443
|
+
SCOPED_LOCK(m_sharedProcessLock);
|
|
1444
|
+
checkLoadData();
|
|
1445
|
+
|
|
1446
|
+
auto raw = getRawDataForKey(key);
|
|
1447
|
+
assert(raw.length() == 0 || raw.length() >= Fixed32Size);
|
|
1448
|
+
if (raw.length() < Fixed32Size) {
|
|
1449
|
+
return raw;
|
|
1450
|
+
}
|
|
1451
|
+
auto newLength = raw.length() - Fixed32Size;
|
|
1452
|
+
if (m_enableKeyExpire) {
|
|
1453
|
+
auto ptr = (const uint8_t *)raw.getPtr() + newLength;
|
|
1454
|
+
auto time = *(const uint32_t *)ptr;
|
|
1455
|
+
if (time != ExpireNever && time <= getCurrentTimeInSecond()) {
|
|
1456
|
+
#ifdef MMKV_APPLE
|
|
1457
|
+
MMKVInfo("deleting expired key [%@] in mmkv [%s], due date %u", key, m_mmapID.c_str(), time);
|
|
1458
|
+
#else
|
|
1459
|
+
MMKVInfo("deleting expired key [%s] in mmkv [%s], due date %u", key.c_str(), m_mmapID.c_str(), time);
|
|
1460
|
+
#endif
|
|
1461
|
+
removeValueForKey(key);
|
|
1462
|
+
return MMBuffer();
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
return MMBuffer(std::move(raw), newLength);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
#define NOOP ((void)0)
|
|
1469
|
+
|
|
1470
|
+
size_t MMKV::filterExpiredKeys() {
|
|
1471
|
+
if (!m_enableKeyExpire || (m_crypter ? m_dicCrypt->empty() : m_dic->empty())) {
|
|
1472
|
+
return 0;
|
|
1473
|
+
}
|
|
1474
|
+
auto now = getCurrentTimeInSecond();
|
|
1475
|
+
MMKVInfo("filtering expired keys inside [%s] now: %u, m_expiredInSeconds: %u", m_mmapID.c_str(), now, m_expiredInSeconds);
|
|
1476
|
+
|
|
1477
|
+
size_t count = 0;
|
|
1478
|
+
auto basePtr = (uint8_t *)(m_file->getMemory()) + Fixed32Size;
|
|
1479
|
+
#ifndef MMKV_DISABLE_CRYPT
|
|
1480
|
+
if (m_crypter) {
|
|
1481
|
+
for (auto itr = m_dicCrypt->begin(); itr != m_dicCrypt->end(); NOOP) {
|
|
1482
|
+
auto &kvHolder = itr->second;
|
|
1483
|
+
assert(kvHolder.realValueSize() >= Fixed32Size);
|
|
1484
|
+
auto buffer = kvHolder.toMMBuffer(basePtr, m_crypter);
|
|
1485
|
+
auto ptr = (uint8_t*) buffer.getPtr();
|
|
1486
|
+
ptr += buffer.length() - Fixed32Size;
|
|
1487
|
+
auto time = *(const uint32_t *)ptr;
|
|
1488
|
+
if (time != ExpireNever && time <= now) {
|
|
1489
|
+
auto oldKey = itr->first;
|
|
1490
|
+
itr = m_dicCrypt->erase(itr);
|
|
1491
|
+
#ifdef MMKV_APPLE
|
|
1492
|
+
MMKVInfo("deleting expired key [%@], due date %u", oldKey, time);
|
|
1493
|
+
[oldKey release];
|
|
1494
|
+
#else
|
|
1495
|
+
MMKVInfo("deleting expired key [%s], due date %u", oldKey.c_str(), time);
|
|
1496
|
+
#endif
|
|
1497
|
+
count++;
|
|
1498
|
+
} else {
|
|
1499
|
+
itr++;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
} else
|
|
1503
|
+
#endif // !MMKV_DISABLE_CRYPT
|
|
1504
|
+
{
|
|
1505
|
+
for (auto itr = m_dic->begin(); itr != m_dic->end(); NOOP) {
|
|
1506
|
+
auto &kvHolder = itr->second;
|
|
1507
|
+
assert(kvHolder.valueSize >= Fixed32Size);
|
|
1508
|
+
auto ptr = basePtr + kvHolder.offset + kvHolder.computedKVSize;
|
|
1509
|
+
ptr += kvHolder.valueSize - Fixed32Size;
|
|
1510
|
+
auto time = *(const uint32_t *)ptr;
|
|
1511
|
+
if (time != ExpireNever && time <= now) {
|
|
1512
|
+
auto oldKey = itr->first;
|
|
1513
|
+
itr = m_dic->erase(itr);
|
|
1514
|
+
#ifdef MMKV_APPLE
|
|
1515
|
+
MMKVInfo("deleting expired key [%@], due date %u", oldKey, time);
|
|
1516
|
+
[oldKey release];
|
|
1517
|
+
#else
|
|
1518
|
+
MMKVInfo("deleting expired key [%s], due date %u", oldKey.c_str(), time);
|
|
1519
|
+
#endif
|
|
1520
|
+
count++;
|
|
1521
|
+
} else {
|
|
1522
|
+
itr++;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
MMKVInfo("deleted %zu expired keys inside [%s]", count, m_mmapID.c_str());
|
|
1527
|
+
return count;
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1121
1530
|
MMKV_NAMESPACE_END
|