react-native-mmkv 1.6.2 → 2.1.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/CHANGELOG.md +30 -0
- package/MMKV/Core/CMakeLists.txt +2 -1
- package/MMKV/Core/CodedInputDataCrypt.cpp +1 -1
- package/MMKV/Core/Core.xcodeproj/project.pbxproj +7 -4
- package/MMKV/Core/InterProcessLock_Win32.cpp +10 -5
- package/MMKV/Core/MMBuffer.h +1 -0
- package/MMKV/Core/MMKV.cpp +359 -17
- package/MMKV/Core/MMKV.h +29 -4
- package/MMKV/Core/MMKVLog.cpp +11 -10
- package/MMKV/Core/MMKVLog.h +1 -1
- package/MMKV/Core/MMKVPredef.h +6 -4
- package/MMKV/Core/MMKV_Android.cpp +2 -6
- package/MMKV/Core/MMKV_IO.cpp +1 -3
- package/MMKV/Core/MMKV_IO.h +3 -3
- package/MMKV/Core/MemoryFile.cpp +276 -43
- package/MMKV/Core/MemoryFile.h +85 -9
- package/MMKV/Core/MemoryFile_Android.cpp +37 -18
- package/MMKV/Core/MemoryFile_Linux.cpp +120 -0
- package/MMKV/Core/MemoryFile_OSX.cpp +92 -2
- package/MMKV/Core/MemoryFile_Win32.cpp +254 -34
- package/MMKV/Core/aes/openssl/openssl_aes.h +2 -2
- package/MMKV/Core/aes/openssl/openssl_aes_core.cpp +4 -4
- package/MMKV/README.md +4 -4
- package/README.md +25 -18
- package/android/CMakeLists.txt +1 -1
- package/android/build.gradle +41 -9
- package/android/src/main/cpp/MmkvHostObject.cpp +36 -0
- package/android/src/main/java/com/reactnativemmkv/MmkvModule.java +33 -8
- package/android/src/main/java/com/reactnativemmkv/MmkvPackage.java +1 -2
- package/ios/MmkvHostObject.mm +48 -5
- package/ios/MmkvModule.h +5 -0
- package/ios/MmkvModule.mm +68 -0
- package/lib/commonjs/MMKV.js +16 -1
- package/lib/commonjs/MMKV.js.map +1 -1
- package/lib/commonjs/createMMKV.js +50 -2
- package/lib/commonjs/createMMKV.js.map +1 -1
- package/lib/commonjs/createMMKV.web.js +4 -1
- package/lib/commonjs/createMMKV.web.js.map +1 -1
- package/lib/commonjs/hooks.js +37 -3
- package/lib/commonjs/hooks.js.map +1 -1
- package/lib/module/MMKV.js +16 -1
- package/lib/module/MMKV.js.map +1 -1
- package/lib/module/createMMKV.js +48 -2
- package/lib/module/createMMKV.js.map +1 -1
- package/lib/module/createMMKV.web.js +4 -1
- package/lib/module/createMMKV.web.js.map +1 -1
- package/lib/module/hooks.js +33 -2
- package/lib/module/hooks.js.map +1 -1
- package/lib/typescript/MMKV.d.ts +19 -3
- package/lib/typescript/createMMKV.d.ts +1 -0
- package/lib/typescript/hooks.d.ts +15 -1
- package/package.json +1 -1
- package/react-native-mmkv.podspec +2 -2
- package/android/src/main/java/com/reactnativemmkv/MmkvModulePackage.java +0 -16
- package/ios/Mmkv.h +0 -7
- package/ios/Mmkv.mm +0 -76
package/MMKV/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# MMKV Change Log
|
|
2
2
|
|
|
3
|
+
## v1.2.12 / 2022-01-17
|
|
4
|
+
### Changes for All platforms
|
|
5
|
+
* Fix a bug that a subsequential `clearAll()` call may fail to take effect in multi-process mode.
|
|
6
|
+
* Hide some OpenSSL symbols to prevent link-time symbol conflict, when an App somehow also static linking OpenSSL.
|
|
7
|
+
|
|
8
|
+
### Android
|
|
9
|
+
* Upgrade `compileSdkVersion` & `targetSdkVersion` from `30` to `31`.
|
|
10
|
+
|
|
11
|
+
## v1.2.11 / 2021-10-26
|
|
12
|
+
|
|
13
|
+
### Android
|
|
14
|
+
* Due to increasing report about crash inside STL, we have decided to make MMKV **static linking** `libc++` **by default**. Starting from v1.2.11, `com.tencent:mmkv-static` is the same as `com.tencent:mmkv`.
|
|
15
|
+
* For those still in need of MMKV with shared linking of `libc++_shared`, you could use `com.tencent:mmkv-shared` instead.
|
|
16
|
+
* Add backup & restore ability.
|
|
17
|
+
|
|
18
|
+
### iOS / macOS
|
|
19
|
+
* Add backup & restore ability.
|
|
20
|
+
* Support tvOS.
|
|
21
|
+
* Fix a compile error on some old Xcode.
|
|
22
|
+
|
|
23
|
+
### Flutter (v1.2.12)
|
|
24
|
+
* Add backup & restore ability.
|
|
25
|
+
|
|
26
|
+
### POSIX / golang / Python
|
|
27
|
+
* Add backup & restore ability.
|
|
28
|
+
* Fix a compile error on Gentoo.
|
|
29
|
+
|
|
30
|
+
### Win32
|
|
31
|
+
* Add backup & restore ability.
|
|
32
|
+
|
|
3
33
|
## v1.2.10 / 2021-06-25
|
|
4
34
|
This version is mainly for Android & Flutter.
|
|
5
35
|
|
package/MMKV/Core/CMakeLists.txt
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
# Sets the minimum version of CMake required to build the native library.
|
|
22
22
|
|
|
23
|
-
cmake_minimum_required(VERSION 3.
|
|
23
|
+
cmake_minimum_required(VERSION 3.10.0)
|
|
24
24
|
|
|
25
25
|
IF(APPLE)
|
|
26
26
|
# tell ranlib to ignore empty compilation units
|
|
@@ -102,6 +102,7 @@ add_library(core
|
|
|
102
102
|
MemoryFile.h
|
|
103
103
|
MemoryFile.cpp
|
|
104
104
|
MemoryFile_Android.cpp
|
|
105
|
+
MemoryFile_Linux.cpp
|
|
105
106
|
MemoryFile_Win32.cpp
|
|
106
107
|
MemoryFile_OSX.cpp
|
|
107
108
|
ThreadLock.h
|
|
@@ -108,7 +108,7 @@ void CodedInputDataCrypt::consumeBytes(size_t length, bool discardPreData) {
|
|
|
108
108
|
bytesLeftInBuffer = m_decryptBufferSize - m_decryptBufferDecryptLength;
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
-
// still no enough
|
|
111
|
+
// still no enough space, try realloc()
|
|
112
112
|
if (bytesLeftInBuffer < length) {
|
|
113
113
|
auto newSize = m_decryptBufferSize + length;
|
|
114
114
|
auto newBuffer = realloc(m_decryptBuffer, newSize);
|
|
@@ -256,6 +256,7 @@
|
|
|
256
256
|
CB58B3FE23AB3035002457F1 /* Frameworks */,
|
|
257
257
|
CB9563D923AB2D9500ACCD39 /* Products */,
|
|
258
258
|
);
|
|
259
|
+
indentWidth = 4;
|
|
259
260
|
sourceTree = "<group>";
|
|
260
261
|
};
|
|
261
262
|
CB9563D923AB2D9500ACCD39 /* Products */ = {
|
|
@@ -576,8 +577,9 @@
|
|
|
576
577
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
577
578
|
SDKROOT = "";
|
|
578
579
|
SKIP_INSTALL = YES;
|
|
579
|
-
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx";
|
|
580
|
-
TARGETED_DEVICE_FAMILY = "1,2";
|
|
580
|
+
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvsimulator appletvos";
|
|
581
|
+
TARGETED_DEVICE_FAMILY = "1,2,3";
|
|
582
|
+
TVOS_DEPLOYMENT_TARGET = 13.0;
|
|
581
583
|
};
|
|
582
584
|
name = Debug;
|
|
583
585
|
};
|
|
@@ -603,8 +605,9 @@
|
|
|
603
605
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
604
606
|
SDKROOT = "";
|
|
605
607
|
SKIP_INSTALL = YES;
|
|
606
|
-
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx";
|
|
607
|
-
TARGETED_DEVICE_FAMILY = "1,2";
|
|
608
|
+
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvsimulator appletvos";
|
|
609
|
+
TARGETED_DEVICE_FAMILY = "1,2,3";
|
|
610
|
+
TVOS_DEPLOYMENT_TARGET = 13.0;
|
|
608
611
|
};
|
|
609
612
|
name = Release;
|
|
610
613
|
};
|
|
@@ -50,7 +50,10 @@ bool FileLock::platformLock(LockType lockType, bool wait, bool unLockFirstIfNeed
|
|
|
50
50
|
// let's be gentleman: unlock my shared-lock to prevent deadlock
|
|
51
51
|
auto ret = UnlockFileEx(m_fd, 0, 1, 0, &m_overLapped);
|
|
52
52
|
if (!ret) {
|
|
53
|
-
|
|
53
|
+
auto lastError = GetLastError();
|
|
54
|
+
if (lastError != ERROR_NOT_LOCKED) {
|
|
55
|
+
MMKVError("fail to try unlock first fd=%p, error:%d", m_fd, lastError);
|
|
56
|
+
}
|
|
54
57
|
}
|
|
55
58
|
}
|
|
56
59
|
|
|
@@ -91,11 +94,13 @@ bool FileLock::platformUnLock(bool unlockToSharedLock) {
|
|
|
91
94
|
}
|
|
92
95
|
auto ret = UnlockFileEx(m_fd, 0, 1, 0, &m_overLapped);
|
|
93
96
|
if (!ret) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
97
|
+
auto lastError = GetLastError();
|
|
98
|
+
if (lastError != ERROR_NOT_LOCKED) {
|
|
99
|
+
MMKVError("fail to unlock fd=%p, error:%d", m_fd, lastError);
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
98
102
|
}
|
|
103
|
+
return true;
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
} // namespace mmkv
|
package/MMKV/Core/MMBuffer.h
CHANGED
package/MMKV/Core/MMKV.cpp
CHANGED
|
@@ -38,6 +38,8 @@
|
|
|
38
38
|
#include <algorithm>
|
|
39
39
|
#include <cstdio>
|
|
40
40
|
#include <cstring>
|
|
41
|
+
#include <unordered_set>
|
|
42
|
+
//#include <unistd.h>
|
|
41
43
|
|
|
42
44
|
#if defined(__aarch64__) && defined(__linux)
|
|
43
45
|
# include <asm/hwcap.h>
|
|
@@ -53,7 +55,7 @@
|
|
|
53
55
|
using namespace std;
|
|
54
56
|
using namespace mmkv;
|
|
55
57
|
|
|
56
|
-
unordered_map<
|
|
58
|
+
unordered_map<string, MMKV *> *g_instanceDic;
|
|
57
59
|
ThreadLock *g_instanceLock;
|
|
58
60
|
MMKVPath_t g_rootDir;
|
|
59
61
|
static mmkv::ErrorHandler g_errorHandler;
|
|
@@ -61,15 +63,22 @@ size_t mmkv::DEFAULT_MMAP_SIZE;
|
|
|
61
63
|
|
|
62
64
|
#ifndef MMKV_WIN32
|
|
63
65
|
constexpr auto SPECIAL_CHARACTER_DIRECTORY_NAME = "specialCharacter";
|
|
66
|
+
constexpr auto CRC_SUFFIX = ".crc";
|
|
64
67
|
#else
|
|
65
68
|
constexpr auto SPECIAL_CHARACTER_DIRECTORY_NAME = L"specialCharacter";
|
|
69
|
+
constexpr auto CRC_SUFFIX = L".crc";
|
|
66
70
|
#endif
|
|
71
|
+
|
|
67
72
|
constexpr uint32_t Fixed32Size = pbFixed32Size();
|
|
68
73
|
|
|
69
74
|
MMKV_NAMESPACE_BEGIN
|
|
70
75
|
|
|
76
|
+
static MMKVPath_t encodeFilePath(const string &mmapID, const MMKVPath_t &rootDir);
|
|
77
|
+
bool endsWith(const MMKVPath_t &str, const MMKVPath_t &suffix);
|
|
78
|
+
MMKVPath_t filename(const MMKVPath_t &path);
|
|
79
|
+
|
|
71
80
|
#ifndef MMKV_ANDROID
|
|
72
|
-
MMKV::MMKV(const
|
|
81
|
+
MMKV::MMKV(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath)
|
|
73
82
|
: m_mmapID(mmapID)
|
|
74
83
|
, m_path(mappedKVPathWithID(m_mmapID, mode, rootPath))
|
|
75
84
|
, m_crcPath(crcPathWithID(m_mmapID, mode, rootPath))
|
|
@@ -160,10 +169,10 @@ void initialize() {
|
|
|
160
169
|
auto hwcaps = getauxval(AT_HWCAP);
|
|
161
170
|
# ifndef MMKV_DISABLE_CRYPT
|
|
162
171
|
if (hwcaps & HWCAP_AES) {
|
|
163
|
-
AES_set_encrypt_key = openssl_aes_armv8_set_encrypt_key;
|
|
164
|
-
AES_set_decrypt_key = openssl_aes_armv8_set_decrypt_key;
|
|
165
|
-
AES_encrypt = openssl_aes_armv8_encrypt;
|
|
166
|
-
AES_decrypt = openssl_aes_armv8_decrypt;
|
|
172
|
+
openssl::AES_set_encrypt_key = openssl_aes_armv8_set_encrypt_key;
|
|
173
|
+
openssl::AES_set_decrypt_key = openssl_aes_armv8_set_decrypt_key;
|
|
174
|
+
openssl::AES_encrypt = openssl_aes_armv8_encrypt;
|
|
175
|
+
openssl::AES_decrypt = openssl_aes_armv8_decrypt;
|
|
167
176
|
MMKVInfo("armv8 AES instructions is supported");
|
|
168
177
|
} else {
|
|
169
178
|
MMKVInfo("armv8 AES instructions is not supported");
|
|
@@ -198,6 +207,10 @@ void MMKV::initializeMMKV(const MMKVPath_t &rootDir, MMKVLogLevel logLevel) {
|
|
|
198
207
|
MMKVInfo("root dir: " MMKV_PATH_FORMAT, g_rootDir.c_str());
|
|
199
208
|
}
|
|
200
209
|
|
|
210
|
+
const MMKVPath_t &MMKV::getRootDir() {
|
|
211
|
+
return g_rootDir;
|
|
212
|
+
}
|
|
213
|
+
|
|
201
214
|
#ifndef MMKV_ANDROID
|
|
202
215
|
MMKV *MMKV::mmkvWithID(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath) {
|
|
203
216
|
|
|
@@ -321,7 +334,7 @@ string MMKV::cryptKey() const {
|
|
|
321
334
|
if (m_crypter) {
|
|
322
335
|
char key[AES_KEY_LEN];
|
|
323
336
|
m_crypter->getKey(key);
|
|
324
|
-
return
|
|
337
|
+
return {key, strnlen(key, AES_KEY_LEN)};
|
|
325
338
|
}
|
|
326
339
|
return "";
|
|
327
340
|
}
|
|
@@ -895,6 +908,320 @@ bool MMKV::try_lock() {
|
|
|
895
908
|
return m_exclusiveProcessLock->try_lock();
|
|
896
909
|
}
|
|
897
910
|
|
|
911
|
+
// backup
|
|
912
|
+
|
|
913
|
+
static bool backupOneToDirectoryByFilePath(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
|
|
914
|
+
File crcFile(srcPath, OpenFlag::ReadOnly);
|
|
915
|
+
if (!crcFile.isFileValid()) {
|
|
916
|
+
return false;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
bool ret = false;
|
|
920
|
+
{
|
|
921
|
+
#ifdef MMKV_WIN32
|
|
922
|
+
MMKVInfo("backup one mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
923
|
+
#else
|
|
924
|
+
MMKVInfo("backup one mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
925
|
+
#endif
|
|
926
|
+
FileLock fileLock(crcFile.getFd());
|
|
927
|
+
InterProcessLock lock(&fileLock, SharedLockType);
|
|
928
|
+
SCOPED_LOCK(&lock);
|
|
929
|
+
|
|
930
|
+
ret = copyFile(srcPath, dstPath);
|
|
931
|
+
if (ret) {
|
|
932
|
+
auto srcCRCPath = srcPath + CRC_SUFFIX;
|
|
933
|
+
auto dstCRCPath = dstPath + CRC_SUFFIX;
|
|
934
|
+
ret = copyFile(srcCRCPath, dstCRCPath);
|
|
935
|
+
}
|
|
936
|
+
MMKVInfo("finish backup one mmkv[%s]", mmapKey.c_str());
|
|
937
|
+
}
|
|
938
|
+
return ret;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
bool MMKV::backupOneToDirectory(const string &mmapKey, const MMKVPath_t &dstPath, const MMKVPath_t &srcPath, bool compareFullPath) {
|
|
942
|
+
// we have to lock the creation of MMKV instance, regardless of in cache or not
|
|
943
|
+
SCOPED_LOCK(g_instanceLock);
|
|
944
|
+
MMKV *kv = nullptr;
|
|
945
|
+
if (!compareFullPath) {
|
|
946
|
+
auto itr = g_instanceDic->find(mmapKey);
|
|
947
|
+
if (itr != g_instanceDic->end()) {
|
|
948
|
+
kv = itr->second;
|
|
949
|
+
}
|
|
950
|
+
} else {
|
|
951
|
+
// mmapKey is actually filename, we can't simply call find()
|
|
952
|
+
for (auto &pair : *g_instanceDic) {
|
|
953
|
+
if (pair.second->m_path == srcPath) {
|
|
954
|
+
kv = pair.second;
|
|
955
|
+
break;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
// get one in cache, do it the easy way
|
|
960
|
+
if (kv) {
|
|
961
|
+
#ifdef MMKV_WIN32
|
|
962
|
+
MMKVInfo("backup one cached mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
963
|
+
#else
|
|
964
|
+
MMKVInfo("backup one cached mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
965
|
+
#endif
|
|
966
|
+
SCOPED_LOCK(kv->m_lock);
|
|
967
|
+
SCOPED_LOCK(kv->m_sharedProcessLock);
|
|
968
|
+
|
|
969
|
+
kv->sync();
|
|
970
|
+
auto ret = copyFile(kv->m_path, dstPath);
|
|
971
|
+
if (ret) {
|
|
972
|
+
auto dstCRCPath = dstPath + CRC_SUFFIX;
|
|
973
|
+
ret = copyFile(kv->m_crcPath, dstCRCPath);
|
|
974
|
+
}
|
|
975
|
+
MMKVInfo("finish backup one mmkv[%s], ret: %d", mmapKey.c_str(), ret);
|
|
976
|
+
return ret;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// no luck with cache, do it the hard way
|
|
980
|
+
bool ret = backupOneToDirectoryByFilePath(mmapKey, srcPath, dstPath);
|
|
981
|
+
return ret;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
bool MMKV::backupOneToDirectory(const string &mmapID, const MMKVPath_t &dstDir, const MMKVPath_t *srcDir) {
|
|
985
|
+
auto rootPath = srcDir ? srcDir : &g_rootDir;
|
|
986
|
+
if (*rootPath == dstDir) {
|
|
987
|
+
return true;
|
|
988
|
+
}
|
|
989
|
+
mkPath(dstDir);
|
|
990
|
+
auto encodePath = encodeFilePath(mmapID, dstDir);
|
|
991
|
+
auto dstPath = dstDir + MMKV_PATH_SLASH + encodePath;
|
|
992
|
+
auto mmapKey = mmapedKVKey(mmapID, rootPath);
|
|
993
|
+
#ifdef MMKV_ANDROID
|
|
994
|
+
// historically Android mistakenly use mmapKey as mmapID
|
|
995
|
+
auto srcPath = *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapKey, *rootPath);
|
|
996
|
+
#else
|
|
997
|
+
auto srcPath = *rootPath + MMKV_PATH_SLASH + encodePath;
|
|
998
|
+
#endif
|
|
999
|
+
return backupOneToDirectory(mmapKey, dstPath, srcPath, false);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
bool endsWith(const MMKVPath_t &str, const MMKVPath_t &suffix) {
|
|
1003
|
+
if (str.length() >= suffix.length()) {
|
|
1004
|
+
return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
|
|
1005
|
+
} else {
|
|
1006
|
+
return false;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
MMKVPath_t filename(const MMKVPath_t &path) {
|
|
1011
|
+
auto startPos = path.rfind(MMKV_PATH_SLASH);
|
|
1012
|
+
startPos++; // don't need to check for npos, because npos+1 == 0
|
|
1013
|
+
auto filename = path.substr(startPos);
|
|
1014
|
+
return filename;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
size_t MMKV::backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t &srcDir, bool isInSpecialDir) {
|
|
1018
|
+
unordered_set<MMKVPath_t> mmapIDSet;
|
|
1019
|
+
unordered_set<MMKVPath_t> mmapIDCRCSet;
|
|
1020
|
+
walkInDir(srcDir, WalkFile, [&](const MMKVPath_t &filePath, WalkType) {
|
|
1021
|
+
if (endsWith(filePath, CRC_SUFFIX)) {
|
|
1022
|
+
mmapIDCRCSet.insert(filePath);
|
|
1023
|
+
} else {
|
|
1024
|
+
mmapIDSet.insert(filePath);
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
size_t count = 0;
|
|
1029
|
+
if (!mmapIDSet.empty()) {
|
|
1030
|
+
mkPath(dstDir);
|
|
1031
|
+
auto compareFullPath = isInSpecialDir;
|
|
1032
|
+
for (auto &srcPath : mmapIDSet) {
|
|
1033
|
+
auto srcCRCPath = srcPath + CRC_SUFFIX;
|
|
1034
|
+
if (mmapIDCRCSet.find(srcCRCPath) == mmapIDCRCSet.end()) {
|
|
1035
|
+
#ifdef MMKV_WIN32
|
|
1036
|
+
MMKVWarning("crc not exist [%ws]", srcCRCPath.c_str());
|
|
1037
|
+
#else
|
|
1038
|
+
MMKVWarning("crc not exist [%s]", srcCRCPath.c_str());
|
|
1039
|
+
#endif
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
auto basename = filename(srcPath);
|
|
1043
|
+
const auto &strBasename = MMKVPath_t2String(basename);
|
|
1044
|
+
auto mmapKey = isInSpecialDir ? strBasename : mmapedKVKey(strBasename, &srcDir);
|
|
1045
|
+
auto dstPath = dstDir + MMKV_PATH_SLASH + basename;
|
|
1046
|
+
if (backupOneToDirectory(mmapKey, dstPath, srcPath, compareFullPath)) {
|
|
1047
|
+
count++;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
return count;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
size_t MMKV::backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t *srcDir) {
|
|
1055
|
+
auto rootPath = srcDir ? srcDir : &g_rootDir;
|
|
1056
|
+
if (*rootPath == dstDir) {
|
|
1057
|
+
return true;
|
|
1058
|
+
}
|
|
1059
|
+
auto count = backupAllToDirectory(dstDir, *rootPath, false);
|
|
1060
|
+
|
|
1061
|
+
auto specialSrcDir = *rootPath + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
|
1062
|
+
if (isFileExist(specialSrcDir)) {
|
|
1063
|
+
auto specialDstDir = dstDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
|
1064
|
+
count += backupAllToDirectory(specialDstDir, specialSrcDir, true);
|
|
1065
|
+
}
|
|
1066
|
+
return count;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
// restore
|
|
1070
|
+
|
|
1071
|
+
static bool restoreOneFromDirectoryByFilePath(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
|
|
1072
|
+
auto dstCRCPath = dstPath + CRC_SUFFIX;
|
|
1073
|
+
File dstCRCFile(move(dstCRCPath), OpenFlag::ReadWrite | OpenFlag::Create);
|
|
1074
|
+
if (!dstCRCFile.isFileValid()) {
|
|
1075
|
+
return false;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
bool ret = false;
|
|
1079
|
+
{
|
|
1080
|
+
#ifdef MMKV_WIN32
|
|
1081
|
+
MMKVInfo("restore one mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
1082
|
+
#else
|
|
1083
|
+
MMKVInfo("restore one mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
1084
|
+
#endif
|
|
1085
|
+
FileLock fileLock(dstCRCFile.getFd());
|
|
1086
|
+
InterProcessLock lock(&fileLock, ExclusiveLockType);
|
|
1087
|
+
SCOPED_LOCK(&lock);
|
|
1088
|
+
|
|
1089
|
+
ret = copyFileContent(srcPath, dstPath);
|
|
1090
|
+
if (ret) {
|
|
1091
|
+
auto srcCRCPath = srcPath + CRC_SUFFIX;
|
|
1092
|
+
ret = copyFileContent(srcCRCPath, dstCRCFile.getFd());
|
|
1093
|
+
}
|
|
1094
|
+
MMKVInfo("finish restore one mmkv[%s]", mmapKey.c_str());
|
|
1095
|
+
}
|
|
1096
|
+
return ret;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// We can't simply replace the existing file, because other processes might have already open it.
|
|
1100
|
+
// They won't know a difference when the file has been replaced.
|
|
1101
|
+
// We have to let them know by overriding the existing file with new content.
|
|
1102
|
+
bool MMKV::restoreOneFromDirectory(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath, bool compareFullPath) {
|
|
1103
|
+
// we have to lock the creation of MMKV instance, regardless of in cache or not
|
|
1104
|
+
SCOPED_LOCK(g_instanceLock);
|
|
1105
|
+
MMKV *kv = nullptr;
|
|
1106
|
+
if (!compareFullPath) {
|
|
1107
|
+
auto itr = g_instanceDic->find(mmapKey);
|
|
1108
|
+
if (itr != g_instanceDic->end()) {
|
|
1109
|
+
kv = itr->second;
|
|
1110
|
+
}
|
|
1111
|
+
} else {
|
|
1112
|
+
// mmapKey is actually filename, we can't simply call find()
|
|
1113
|
+
for (auto &pair : *g_instanceDic) {
|
|
1114
|
+
if (pair.second->m_path == dstPath) {
|
|
1115
|
+
kv = pair.second;
|
|
1116
|
+
break;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
// get one in cache, do it the easy way
|
|
1121
|
+
if (kv) {
|
|
1122
|
+
#ifdef MMKV_WIN32
|
|
1123
|
+
MMKVInfo("restore one cached mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
1124
|
+
#else
|
|
1125
|
+
MMKVInfo("restore one cached mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
|
|
1126
|
+
#endif
|
|
1127
|
+
SCOPED_LOCK(kv->m_lock);
|
|
1128
|
+
SCOPED_LOCK(kv->m_exclusiveProcessLock);
|
|
1129
|
+
|
|
1130
|
+
kv->sync();
|
|
1131
|
+
auto ret = copyFileContent(srcPath, kv->m_file->getFd());
|
|
1132
|
+
if (ret) {
|
|
1133
|
+
auto srcCRCPath = srcPath + CRC_SUFFIX;
|
|
1134
|
+
ret = copyFileContent(srcCRCPath, kv->m_metaFile->getFd());
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// reload data after restore
|
|
1138
|
+
kv->clearMemoryCache();
|
|
1139
|
+
kv->loadFromFile();
|
|
1140
|
+
if (kv->m_isInterProcess) {
|
|
1141
|
+
kv->notifyContentChanged();
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
MMKVInfo("finish restore one mmkv[%s], ret: %d", mmapKey.c_str(), ret);
|
|
1145
|
+
return ret;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// no luck with cache, do it the hard way
|
|
1149
|
+
bool ret = restoreOneFromDirectoryByFilePath(mmapKey, srcPath, dstPath);
|
|
1150
|
+
return ret;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
bool MMKV::restoreOneFromDirectory(const string &mmapID, const MMKVPath_t &srcDir, const MMKVPath_t *dstDir) {
|
|
1154
|
+
auto rootPath = dstDir ? dstDir : &g_rootDir;
|
|
1155
|
+
if (*rootPath == srcDir) {
|
|
1156
|
+
return true;
|
|
1157
|
+
}
|
|
1158
|
+
mkPath(*rootPath);
|
|
1159
|
+
auto encodePath = encodeFilePath(mmapID, *rootPath);
|
|
1160
|
+
auto srcPath = srcDir + MMKV_PATH_SLASH + encodePath;
|
|
1161
|
+
auto mmapKey = mmapedKVKey(mmapID, rootPath);
|
|
1162
|
+
#ifdef MMKV_ANDROID
|
|
1163
|
+
// historically Android mistakenly use mmapKey as mmapID
|
|
1164
|
+
auto dstPath = *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapKey, *rootPath);
|
|
1165
|
+
#else
|
|
1166
|
+
auto dstPath = *rootPath + MMKV_PATH_SLASH + encodePath;
|
|
1167
|
+
#endif
|
|
1168
|
+
return restoreOneFromDirectory(mmapKey, srcPath, dstPath, false);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
size_t MMKV::restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t &dstDir, bool isInSpecialDir) {
|
|
1172
|
+
unordered_set<MMKVPath_t> mmapIDSet;
|
|
1173
|
+
unordered_set<MMKVPath_t> mmapIDCRCSet;
|
|
1174
|
+
walkInDir(srcDir, WalkFile, [&](const MMKVPath_t &filePath, WalkType) {
|
|
1175
|
+
if (endsWith(filePath, CRC_SUFFIX)) {
|
|
1176
|
+
mmapIDCRCSet.insert(filePath);
|
|
1177
|
+
} else {
|
|
1178
|
+
mmapIDSet.insert(filePath);
|
|
1179
|
+
}
|
|
1180
|
+
});
|
|
1181
|
+
|
|
1182
|
+
size_t count = 0;
|
|
1183
|
+
if (!mmapIDSet.empty()) {
|
|
1184
|
+
mkPath(dstDir);
|
|
1185
|
+
auto compareFullPath = isInSpecialDir;
|
|
1186
|
+
for (auto &srcPath : mmapIDSet) {
|
|
1187
|
+
auto srcCRCPath = srcPath + CRC_SUFFIX;
|
|
1188
|
+
if (mmapIDCRCSet.find(srcCRCPath) == mmapIDCRCSet.end()) {
|
|
1189
|
+
#ifdef MMKV_WIN32
|
|
1190
|
+
MMKVWarning("crc not exist [%ws]", srcCRCPath.c_str());
|
|
1191
|
+
#else
|
|
1192
|
+
MMKVWarning("crc not exist [%s]", srcCRCPath.c_str());
|
|
1193
|
+
#endif
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1196
|
+
auto basename = filename(srcPath);
|
|
1197
|
+
const auto &strBasename = MMKVPath_t2String(basename);
|
|
1198
|
+
auto mmapKey = isInSpecialDir ? strBasename : mmapedKVKey(strBasename, &dstDir);
|
|
1199
|
+
auto dstPath = dstDir + MMKV_PATH_SLASH + basename;
|
|
1200
|
+
if (restoreOneFromDirectory(mmapKey, srcPath, dstPath, compareFullPath)) {
|
|
1201
|
+
count++;
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
return count;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
size_t MMKV::restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t *dstDir) {
|
|
1209
|
+
auto rootPath = dstDir ? dstDir : &g_rootDir;
|
|
1210
|
+
if (*rootPath == srcDir) {
|
|
1211
|
+
return true;
|
|
1212
|
+
}
|
|
1213
|
+
auto count = restoreAllFromDirectory(srcDir, *rootPath, true);
|
|
1214
|
+
|
|
1215
|
+
auto specialSrcDir = srcDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
|
1216
|
+
if (isFileExist(specialSrcDir)) {
|
|
1217
|
+
auto specialDstDir = *rootPath + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
|
1218
|
+
count += restoreAllFromDirectory(specialSrcDir, specialDstDir, false);
|
|
1219
|
+
}
|
|
1220
|
+
return count;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
// callbacks
|
|
1224
|
+
|
|
898
1225
|
void MMKV::registerErrorHandler(ErrorHandler handler) {
|
|
899
1226
|
SCOPED_LOCK(g_instanceLock);
|
|
900
1227
|
g_errorHandler = handler;
|
|
@@ -934,7 +1261,7 @@ static string md5(const basic_string<T> &value) {
|
|
|
934
1261
|
snprintf(tmp, sizeof(tmp), "%2.2x", ch);
|
|
935
1262
|
strcat(buf, tmp);
|
|
936
1263
|
}
|
|
937
|
-
return
|
|
1264
|
+
return {buf};
|
|
938
1265
|
}
|
|
939
1266
|
|
|
940
1267
|
static MMKVPath_t encodeFilePath(const string &mmapID) {
|
|
@@ -957,14 +1284,35 @@ static MMKVPath_t encodeFilePath(const string &mmapID) {
|
|
|
957
1284
|
}
|
|
958
1285
|
}
|
|
959
1286
|
|
|
960
|
-
|
|
1287
|
+
static MMKVPath_t encodeFilePath(const string &mmapID, const MMKVPath_t &rootDir) {
|
|
1288
|
+
const char *specialCharacters = "\\/:*?\"<>|";
|
|
1289
|
+
string encodedID;
|
|
1290
|
+
bool hasSpecialCharacter = false;
|
|
1291
|
+
for (auto ch : mmapID) {
|
|
1292
|
+
if (strchr(specialCharacters, ch) != nullptr) {
|
|
1293
|
+
encodedID = md5(mmapID);
|
|
1294
|
+
hasSpecialCharacter = true;
|
|
1295
|
+
break;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
if (hasSpecialCharacter) {
|
|
1299
|
+
MMKVPath_t path = rootDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
|
|
1300
|
+
mkPath(path);
|
|
1301
|
+
|
|
1302
|
+
return MMKVPath_t(SPECIAL_CHARACTER_DIRECTORY_NAME) + MMKV_PATH_SLASH + string2MMKVPath_t(encodedID);
|
|
1303
|
+
} else {
|
|
1304
|
+
return string2MMKVPath_t(mmapID);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
string mmapedKVKey(const string &mmapID, const MMKVPath_t *rootPath) {
|
|
961
1309
|
if (rootPath && g_rootDir != (*rootPath)) {
|
|
962
1310
|
return md5(*rootPath + MMKV_PATH_SLASH + string2MMKVPath_t(mmapID));
|
|
963
1311
|
}
|
|
964
1312
|
return mmapID;
|
|
965
1313
|
}
|
|
966
1314
|
|
|
967
|
-
MMKVPath_t mappedKVPathWithID(const string &mmapID, MMKVMode mode, MMKVPath_t *rootPath) {
|
|
1315
|
+
MMKVPath_t mappedKVPathWithID(const string &mmapID, MMKVMode mode, const MMKVPath_t *rootPath) {
|
|
968
1316
|
#ifndef MMKV_ANDROID
|
|
969
1317
|
if (rootPath) {
|
|
970
1318
|
#else
|
|
@@ -977,13 +1325,7 @@ MMKVPath_t mappedKVPathWithID(const string &mmapID, MMKVMode mode, MMKVPath_t *r
|
|
|
977
1325
|
return g_rootDir + MMKV_PATH_SLASH + encodeFilePath(mmapID);
|
|
978
1326
|
}
|
|
979
1327
|
|
|
980
|
-
|
|
981
|
-
constexpr auto CRC_SUFFIX = ".crc";
|
|
982
|
-
#else
|
|
983
|
-
constexpr auto CRC_SUFFIX = L".crc";
|
|
984
|
-
#endif
|
|
985
|
-
|
|
986
|
-
MMKVPath_t crcPathWithID(const string &mmapID, MMKVMode mode, MMKVPath_t *rootPath) {
|
|
1328
|
+
MMKVPath_t crcPathWithID(const string &mmapID, MMKVMode mode, const MMKVPath_t *rootPath) {
|
|
987
1329
|
#ifndef MMKV_ANDROID
|
|
988
1330
|
if (rootPath) {
|
|
989
1331
|
#else
|
package/MMKV/Core/MMKV.h
CHANGED
|
@@ -38,11 +38,12 @@ class ThreadLock;
|
|
|
38
38
|
MMKV_NAMESPACE_BEGIN
|
|
39
39
|
|
|
40
40
|
enum MMKVMode : uint32_t {
|
|
41
|
-
MMKV_SINGLE_PROCESS =
|
|
42
|
-
MMKV_MULTI_PROCESS =
|
|
41
|
+
MMKV_SINGLE_PROCESS = 1 << 0,
|
|
42
|
+
MMKV_MULTI_PROCESS = 1 << 1,
|
|
43
43
|
#ifdef MMKV_ANDROID
|
|
44
|
-
CONTEXT_MODE_MULTI_PROCESS =
|
|
45
|
-
MMKV_ASHMEM =
|
|
44
|
+
CONTEXT_MODE_MULTI_PROCESS = 1 << 2, // in case someone mistakenly pass Context.MODE_MULTI_PROCESS
|
|
45
|
+
MMKV_ASHMEM = 1 << 3,
|
|
46
|
+
MMKV_BACKUP = 1 << 4,
|
|
46
47
|
#endif
|
|
47
48
|
};
|
|
48
49
|
|
|
@@ -146,6 +147,10 @@ class MMKV {
|
|
|
146
147
|
#if defined(MMKV_ANDROID) && !defined(MMKV_DISABLE_CRYPT)
|
|
147
148
|
void checkReSetCryptKey(int fd, int metaFD, std::string *cryptKey);
|
|
148
149
|
#endif
|
|
150
|
+
static bool backupOneToDirectory(const std::string &mmapKey, const MMKVPath_t &dstPath, const MMKVPath_t &srcPath, bool compareFullPath);
|
|
151
|
+
static size_t backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t &srcDir, bool isInSpecialDir);
|
|
152
|
+
static bool restoreOneFromDirectory(const std::string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath, bool compareFullPath);
|
|
153
|
+
static size_t restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t &dstDir, bool isInSpecialDir);
|
|
149
154
|
|
|
150
155
|
public:
|
|
151
156
|
// call this before getting any MMKV instance
|
|
@@ -322,6 +327,26 @@ public:
|
|
|
322
327
|
void unlock();
|
|
323
328
|
bool try_lock();
|
|
324
329
|
|
|
330
|
+
static const MMKVPath_t &getRootDir();
|
|
331
|
+
|
|
332
|
+
// backup one MMKV instance from srcDir to dstDir
|
|
333
|
+
// if srcDir is null, then backup from the root dir of MMKV
|
|
334
|
+
static bool backupOneToDirectory(const std::string &mmapID, const MMKVPath_t &dstDir, const MMKVPath_t *srcDir = nullptr);
|
|
335
|
+
|
|
336
|
+
// restore one MMKV instance from srcDir to dstDir
|
|
337
|
+
// if dstDir is null, then restore to the root dir of MMKV
|
|
338
|
+
static bool restoreOneFromDirectory(const std::string &mmapID, const MMKVPath_t &srcDir, const MMKVPath_t *dstDir = nullptr);
|
|
339
|
+
|
|
340
|
+
// backup all MMKV instance from srcDir to dstDir
|
|
341
|
+
// if srcDir is null, then backup from the root dir of MMKV
|
|
342
|
+
// return count of MMKV successfully backuped
|
|
343
|
+
static size_t backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t *srcDir = nullptr);
|
|
344
|
+
|
|
345
|
+
// restore all MMKV instance from srcDir to dstDir
|
|
346
|
+
// if dstDir is null, then restore to the root dir of MMKV
|
|
347
|
+
// return count of MMKV successfully restored
|
|
348
|
+
static size_t restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t *dstDir = nullptr);
|
|
349
|
+
|
|
325
350
|
// check if content been changed by other process
|
|
326
351
|
void checkContentChanged();
|
|
327
352
|
|
package/MMKV/Core/MMKVLog.cpp
CHANGED
|
@@ -30,15 +30,7 @@ MMKVLogLevel g_currentLogLevel = MMKVLogInfo;
|
|
|
30
30
|
|
|
31
31
|
mmkv::LogHandler g_logHandler;
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
#ifdef ENABLE_MMKV_LOG
|
|
36
|
-
# include <cstdarg>
|
|
37
|
-
# include <string>
|
|
38
|
-
|
|
39
|
-
using namespace mmkv;
|
|
40
|
-
|
|
41
|
-
# ifndef __FILE_NAME__
|
|
33
|
+
#ifndef __FILE_NAME__
|
|
42
34
|
const char *_getFileName(const char *path) {
|
|
43
35
|
const char *ptr = strrchr(path, '/');
|
|
44
36
|
if (!ptr) {
|
|
@@ -50,7 +42,16 @@ const char *_getFileName(const char *path) {
|
|
|
50
42
|
return path;
|
|
51
43
|
}
|
|
52
44
|
}
|
|
53
|
-
#
|
|
45
|
+
#endif
|
|
46
|
+
|
|
47
|
+
MMKV_NAMESPACE_END
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
#ifdef ENABLE_MMKV_LOG
|
|
51
|
+
# include <cstdarg>
|
|
52
|
+
# include <string>
|
|
53
|
+
|
|
54
|
+
using namespace mmkv;
|
|
54
55
|
|
|
55
56
|
# ifndef MMKV_ANDROID
|
|
56
57
|
|
package/MMKV/Core/MMKVLog.h
CHANGED
|
@@ -45,7 +45,7 @@ extern mmkv::LogHandler g_logHandler;
|
|
|
45
45
|
# define __MMKV_FILE_NAME__ __FILE_NAME__
|
|
46
46
|
# else
|
|
47
47
|
const char *_getFileName(const char *path);
|
|
48
|
-
# define __MMKV_FILE_NAME__ _getFileName(__FILE__)
|
|
48
|
+
# define __MMKV_FILE_NAME__ MMKV_NAMESPACE_PREFIX::_getFileName(__FILE__)
|
|
49
49
|
# endif
|
|
50
50
|
|
|
51
51
|
# define MMKVError(format, ...) \
|