react-native-mmkv 2.0.0 → 2.1.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.
- 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 +17 -4
- package/android/CMakeLists.txt +3 -2
- package/android/src/main/cpp/MmkvHostObject.cpp +36 -0
- package/ios/MmkvHostObject.mm +48 -5
- package/ios/MmkvModule.h +0 -2
- package/ios/MmkvModule.mm +16 -16
- package/package.json +26 -2
- package/react-native-mmkv.podspec +1 -1
- package/lib/commonjs/MMKV.js +0 -127
- package/lib/commonjs/MMKV.js.map +0 -1
- package/lib/commonjs/createMMKV.js +0 -30
- package/lib/commonjs/createMMKV.js.map +0 -1
- package/lib/commonjs/createMMKV.web.js +0 -67
- package/lib/commonjs/createMMKV.web.js.map +0 -1
- package/lib/commonjs/hooks.js +0 -142
- package/lib/commonjs/hooks.js.map +0 -1
- package/lib/commonjs/index.js +0 -32
- package/lib/commonjs/index.js.map +0 -1
- package/lib/module/MMKV.js +0 -116
- package/lib/module/MMKV.js.map +0 -1
- package/lib/module/createMMKV.js +0 -19
- package/lib/module/createMMKV.js.map +0 -1
- package/lib/module/createMMKV.web.js +0 -57
- package/lib/module/createMMKV.web.js.map +0 -1
- package/lib/module/hooks.js +0 -127
- package/lib/module/hooks.js.map +0 -1
- package/lib/module/index.js +0 -3
- package/lib/module/index.js.map +0 -1
- package/lib/typescript/MMKV.d.ts +0 -114
- package/lib/typescript/createMMKV.d.ts +0 -5
- package/lib/typescript/createMMKV.web.d.ts +0 -2
- package/lib/typescript/hooks.d.ts +0 -49
- package/lib/typescript/index.d.ts +0 -2
package/MMKV/Core/MMKVPredef.h
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
#include <vector>
|
|
35
35
|
#include <unordered_map>
|
|
36
36
|
|
|
37
|
-
constexpr auto MMKV_VERSION = "v1.2.
|
|
37
|
+
constexpr auto MMKV_VERSION = "v1.2.12";
|
|
38
38
|
|
|
39
39
|
#ifdef DEBUG
|
|
40
40
|
# define MMKV_DEBUG
|
|
@@ -88,6 +88,7 @@ constexpr auto MMKV_PATH_SLASH = L"\\";
|
|
|
88
88
|
using MMKVFileHandle_t = HANDLE;
|
|
89
89
|
using MMKVPath_t = std::wstring;
|
|
90
90
|
extern MMKVPath_t string2MMKVPath_t(const std::string &str);
|
|
91
|
+
extern std::string MMKVPath_t2String(const MMKVPath_t &str);
|
|
91
92
|
|
|
92
93
|
# ifndef MMKV_EMBED_ZLIB
|
|
93
94
|
# define MMKV_EMBED_ZLIB 1
|
|
@@ -100,6 +101,7 @@ constexpr auto MMKV_PATH_SLASH = "/";
|
|
|
100
101
|
using MMKVFileHandle_t = int;
|
|
101
102
|
using MMKVPath_t = std::string;
|
|
102
103
|
# define string2MMKVPath_t(str) (str)
|
|
104
|
+
# define MMKVPath_t2String(str) (str)
|
|
103
105
|
|
|
104
106
|
# ifndef MMKV_EMBED_ZLIB
|
|
105
107
|
# define MMKV_EMBED_ZLIB 0
|
|
@@ -226,15 +228,15 @@ constexpr size_t AES_KEY_BITSET_LEN = 128;
|
|
|
226
228
|
#else
|
|
227
229
|
#define MMKV_ABI "armeabi"
|
|
228
230
|
#endif
|
|
229
|
-
#elif defined(__i386__)
|
|
231
|
+
#elif defined(__i386__) || defined(_M_IX86)
|
|
230
232
|
#define MMKV_ABI "x86"
|
|
231
|
-
#elif defined(__x86_64__)
|
|
233
|
+
#elif defined(__x86_64__) || defined(_M_X64)
|
|
232
234
|
#define MMKV_ABI "x86_64"
|
|
233
235
|
#elif defined(__mips64)
|
|
234
236
|
#define MMKV_ABI "mips64"
|
|
235
237
|
#elif defined(__mips__)
|
|
236
238
|
#define MMKV_ABI "mips"
|
|
237
|
-
#elif defined(__aarch64__)
|
|
239
|
+
#elif defined(__aarch64__) || defined(_M_ARM64)
|
|
238
240
|
#define MMKV_ABI "arm64-v8a"
|
|
239
241
|
#else
|
|
240
242
|
#define MMKV_ABI "unknown"
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
# include "ScopedLock.hpp"
|
|
31
31
|
# include "ThreadLock.h"
|
|
32
32
|
# include <unistd.h>
|
|
33
|
+
# include "MMKV_IO.h"
|
|
33
34
|
|
|
34
35
|
using namespace std;
|
|
35
36
|
using namespace mmkv;
|
|
@@ -37,12 +38,8 @@ using namespace mmkv;
|
|
|
37
38
|
extern unordered_map<string, MMKV *> *g_instanceDic;
|
|
38
39
|
extern ThreadLock *g_instanceLock;
|
|
39
40
|
|
|
40
|
-
extern string mmapedKVKey(const string &mmapID, string *rootPath);
|
|
41
|
-
extern string mappedKVPathWithID(const string &mmapID, MMKVMode mode, string *rootPath);
|
|
42
|
-
extern string crcPathWithID(const string &mmapID, MMKVMode mode, string *rootPath);
|
|
43
|
-
|
|
44
41
|
MMKV::MMKV(const string &mmapID, int size, MMKVMode mode, string *cryptKey, string *rootPath)
|
|
45
|
-
: m_mmapID(mmapedKVKey(mmapID, rootPath)) // historically Android mistakenly use mmapKey as mmapID
|
|
42
|
+
: m_mmapID((mode & MMKV_BACKUP) ? mmapID : mmapedKVKey(mmapID, rootPath)) // historically Android mistakenly use mmapKey as mmapID
|
|
46
43
|
, m_path(mappedKVPathWithID(m_mmapID, mode, rootPath))
|
|
47
44
|
, m_crcPath(crcPathWithID(m_mmapID, mode, rootPath))
|
|
48
45
|
, m_dic(nullptr)
|
|
@@ -139,7 +136,6 @@ MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKe
|
|
|
139
136
|
}
|
|
140
137
|
|
|
141
138
|
MMKV *MMKV::mmkvWithID(const string &mmapID, int size, MMKVMode mode, string *cryptKey, string *rootPath) {
|
|
142
|
-
|
|
143
139
|
if (mmapID.empty()) {
|
|
144
140
|
return nullptr;
|
|
145
141
|
}
|
package/MMKV/Core/MMKV_IO.cpp
CHANGED
|
@@ -1048,9 +1048,7 @@ void MMKV::clearAll() {
|
|
|
1048
1048
|
SCOPED_LOCK(m_lock);
|
|
1049
1049
|
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1050
1050
|
|
|
1051
|
-
|
|
1052
|
-
m_file->reloadFromFile();
|
|
1053
|
-
}
|
|
1051
|
+
checkLoadData();
|
|
1054
1052
|
|
|
1055
1053
|
if (m_file->getFileSize() == DEFAULT_MMAP_SIZE && m_actualSize == 0) {
|
|
1056
1054
|
MMKVInfo("nothing to clear for [%s]", m_mmapID.c_str());
|
package/MMKV/Core/MMKV_IO.h
CHANGED
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
|
|
27
27
|
MMKV_NAMESPACE_BEGIN
|
|
28
28
|
|
|
29
|
-
std::string mmapedKVKey(const std::string &mmapID, MMKVPath_t *rootPath = nullptr);
|
|
30
|
-
MMKVPath_t mappedKVPathWithID(const std::string &mmapID, MMKVMode mode, MMKVPath_t *rootPath);
|
|
31
|
-
MMKVPath_t crcPathWithID(const std::string &mmapID, MMKVMode mode, MMKVPath_t *rootPath);
|
|
29
|
+
std::string mmapedKVKey(const std::string &mmapID, const MMKVPath_t *rootPath = nullptr);
|
|
30
|
+
MMKVPath_t mappedKVPathWithID(const std::string &mmapID, MMKVMode mode, const MMKVPath_t *rootPath);
|
|
31
|
+
MMKVPath_t crcPathWithID(const std::string &mmapID, MMKVMode mode, const MMKVPath_t *rootPath);
|
|
32
32
|
|
|
33
33
|
MMKVRecoverStrategic onMMKVCRCCheckFail(const std::string &mmapID);
|
|
34
34
|
MMKVRecoverStrategic onMMKVFileLengthError(const std::string &mmapID);
|
package/MMKV/Core/MemoryFile.cpp
CHANGED
|
@@ -27,42 +27,112 @@
|
|
|
27
27
|
# include "MMKVLog.h"
|
|
28
28
|
# include "ScopedLock.hpp"
|
|
29
29
|
# include <cerrno>
|
|
30
|
+
# include <utility>
|
|
30
31
|
# include <fcntl.h>
|
|
31
32
|
# include <sys/mman.h>
|
|
32
33
|
# include <sys/stat.h>
|
|
33
34
|
# include <unistd.h>
|
|
35
|
+
# include <sys/file.h>
|
|
36
|
+
# include <dirent.h>
|
|
37
|
+
# include <cstring>
|
|
34
38
|
|
|
35
39
|
using namespace std;
|
|
36
40
|
|
|
37
41
|
namespace mmkv {
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
extern bool getFileSize(int fd, size_t &size);
|
|
40
44
|
|
|
41
45
|
# ifdef MMKV_ANDROID
|
|
42
46
|
extern size_t ASharedMemory_getSize(int fd);
|
|
43
47
|
# else
|
|
44
|
-
|
|
48
|
+
File::File(MMKVPath_t path, OpenFlag flag) : m_path(std::move(path)), m_fd(-1), m_flag(flag) {
|
|
49
|
+
open();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
MemoryFile::MemoryFile(MMKVPath_t path) : m_diskFile(std::move(path), OpenFlag::ReadWrite | OpenFlag::Create), m_ptr(nullptr), m_size(0) {
|
|
45
53
|
reloadFromFile();
|
|
46
54
|
}
|
|
47
|
-
# endif // MMKV_ANDROID
|
|
55
|
+
# endif // !defined(MMKV_ANDROID)
|
|
48
56
|
|
|
49
57
|
# ifdef MMKV_IOS
|
|
50
58
|
void tryResetFileProtection(const string &path);
|
|
51
59
|
# endif
|
|
52
60
|
|
|
61
|
+
static int OpenFlag2NativeFlag(OpenFlag flag) {
|
|
62
|
+
int native = O_CLOEXEC;
|
|
63
|
+
if (flag & OpenFlag::ReadWrite) {
|
|
64
|
+
native |= O_RDWR;
|
|
65
|
+
} else if (flag & OpenFlag::ReadOnly) {
|
|
66
|
+
native |= O_RDONLY;
|
|
67
|
+
} else if (flag & OpenFlag::WriteOnly) {
|
|
68
|
+
native |= O_WRONLY;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (flag & OpenFlag::Create) {
|
|
72
|
+
native |= O_CREAT;
|
|
73
|
+
}
|
|
74
|
+
if (flag & OpenFlag::Excel) {
|
|
75
|
+
native |= O_EXCL;
|
|
76
|
+
}
|
|
77
|
+
if (flag & OpenFlag::Truncate) {
|
|
78
|
+
native |= O_TRUNC;
|
|
79
|
+
}
|
|
80
|
+
return native;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
bool File::open() {
|
|
84
|
+
# ifdef MMKV_ANDROID
|
|
85
|
+
if (m_fileType == MMFILE_TYPE_ASHMEM) {
|
|
86
|
+
return isFileValid();
|
|
87
|
+
}
|
|
88
|
+
# endif
|
|
89
|
+
if (isFileValid()) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
m_fd = ::open(m_path.c_str(), OpenFlag2NativeFlag(m_flag), S_IRWXU);
|
|
93
|
+
if (!isFileValid()) {
|
|
94
|
+
MMKVError("fail to open [%s], %d(%s)", m_path.c_str(), errno, strerror(errno));
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
MMKVInfo("open fd[%p], %s", m_fd, m_path.c_str());
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
void File::close() {
|
|
102
|
+
if (isFileValid()) {
|
|
103
|
+
MMKVInfo("closing fd[%p], %s", m_fd, m_path.c_str());
|
|
104
|
+
if (::close(m_fd) == 0) {
|
|
105
|
+
m_fd = -1;
|
|
106
|
+
} else {
|
|
107
|
+
MMKVError("fail to close [%s], %d(%s)", m_path.c_str(), errno, strerror(errno));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
size_t File::getActualFileSize() const {
|
|
113
|
+
# ifdef MMKV_ANDROID
|
|
114
|
+
if (m_fileType == MMFILE_TYPE_ASHMEM) {
|
|
115
|
+
return ASharedMemory_getSize(m_fd);
|
|
116
|
+
}
|
|
117
|
+
# endif
|
|
118
|
+
size_t size = 0;
|
|
119
|
+
mmkv::getFileSize(m_fd, size);
|
|
120
|
+
return size;
|
|
121
|
+
}
|
|
122
|
+
|
|
53
123
|
bool MemoryFile::truncate(size_t size) {
|
|
54
|
-
if (
|
|
124
|
+
if (!m_diskFile.isFileValid()) {
|
|
55
125
|
return false;
|
|
56
126
|
}
|
|
57
127
|
if (size == m_size) {
|
|
58
128
|
return true;
|
|
59
129
|
}
|
|
60
130
|
# ifdef MMKV_ANDROID
|
|
61
|
-
if (m_fileType == MMFILE_TYPE_ASHMEM) {
|
|
131
|
+
if (m_diskFile.m_fileType == MMFILE_TYPE_ASHMEM) {
|
|
62
132
|
if (size > m_size) {
|
|
63
|
-
MMKVError("ashmem %s reach size limit:%zu, consider configure with larger size",
|
|
133
|
+
MMKVError("ashmem %s reach size limit:%zu, consider configure with larger size", m_diskFile.m_path.c_str(), m_size);
|
|
64
134
|
} else {
|
|
65
|
-
MMKVInfo("no way to trim ashmem %s from %zu to smaller size %zu",
|
|
135
|
+
MMKVInfo("no way to trim ashmem %s from %zu to smaller size %zu", m_diskFile.m_path.c_str(), m_size, size);
|
|
66
136
|
}
|
|
67
137
|
return false;
|
|
68
138
|
}
|
|
@@ -75,14 +145,14 @@ bool MemoryFile::truncate(size_t size) {
|
|
|
75
145
|
m_size = ((m_size / DEFAULT_MMAP_SIZE) + 1) * DEFAULT_MMAP_SIZE;
|
|
76
146
|
}
|
|
77
147
|
|
|
78
|
-
if (::ftruncate(m_fd, static_cast<off_t>(m_size)) != 0) {
|
|
79
|
-
MMKVError("fail to truncate [%s] to size %zu, %s",
|
|
148
|
+
if (::ftruncate(m_diskFile.m_fd, static_cast<off_t>(m_size)) != 0) {
|
|
149
|
+
MMKVError("fail to truncate [%s] to size %zu, %s", m_diskFile.m_path.c_str(), m_size, strerror(errno));
|
|
80
150
|
m_size = oldSize;
|
|
81
151
|
return false;
|
|
82
152
|
}
|
|
83
153
|
if (m_size > oldSize) {
|
|
84
|
-
if (!zeroFillFile(m_fd, oldSize, m_size - oldSize)) {
|
|
85
|
-
MMKVError("fail to zeroFile [%s] to size %zu, %s",
|
|
154
|
+
if (!zeroFillFile(m_diskFile.m_fd, oldSize, m_size - oldSize)) {
|
|
155
|
+
MMKVError("fail to zeroFile [%s] to size %zu, %s", m_diskFile.m_path.c_str(), m_size, strerror(errno));
|
|
86
156
|
m_size = oldSize;
|
|
87
157
|
return false;
|
|
88
158
|
}
|
|
@@ -90,7 +160,7 @@ bool MemoryFile::truncate(size_t size) {
|
|
|
90
160
|
|
|
91
161
|
if (m_ptr) {
|
|
92
162
|
if (munmap(m_ptr, oldSize) != 0) {
|
|
93
|
-
MMKVError("fail to munmap [%s], %s",
|
|
163
|
+
MMKVError("fail to munmap [%s], %s", m_diskFile.m_path.c_str(), strerror(errno));
|
|
94
164
|
}
|
|
95
165
|
}
|
|
96
166
|
auto ret = mmap();
|
|
@@ -106,15 +176,15 @@ bool MemoryFile::msync(SyncFlag syncFlag) {
|
|
|
106
176
|
if (ret == 0) {
|
|
107
177
|
return true;
|
|
108
178
|
}
|
|
109
|
-
MMKVError("fail to msync [%s], %s",
|
|
179
|
+
MMKVError("fail to msync [%s], %s", m_diskFile.m_path.c_str(), strerror(errno));
|
|
110
180
|
}
|
|
111
181
|
return false;
|
|
112
182
|
}
|
|
113
183
|
|
|
114
184
|
bool MemoryFile::mmap() {
|
|
115
|
-
m_ptr = (char *) ::mmap(m_ptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0);
|
|
185
|
+
m_ptr = (char *) ::mmap(m_ptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_diskFile.m_fd, 0);
|
|
116
186
|
if (m_ptr == MAP_FAILED) {
|
|
117
|
-
MMKVError("fail to mmap [%s], %s",
|
|
187
|
+
MMKVError("fail to mmap [%s], %s", m_diskFile.m_path.c_str(), strerror(errno));
|
|
118
188
|
m_ptr = nullptr;
|
|
119
189
|
return false;
|
|
120
190
|
}
|
|
@@ -129,20 +199,19 @@ void MemoryFile::reloadFromFile() {
|
|
|
129
199
|
}
|
|
130
200
|
# endif
|
|
131
201
|
if (isFileValid()) {
|
|
132
|
-
MMKVWarning("calling reloadFromFile while the cache [%s] is still valid",
|
|
202
|
+
MMKVWarning("calling reloadFromFile while the cache [%s] is still valid", m_diskFile.m_path.c_str());
|
|
133
203
|
MMKV_ASSERT(0);
|
|
134
204
|
clearMemoryCache();
|
|
135
205
|
}
|
|
136
206
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
MMKVError("fail to open:%s, %s", m_name.c_str(), strerror(errno));
|
|
207
|
+
if (!m_diskFile.open()) {
|
|
208
|
+
MMKVError("fail to open:%s, %s", m_diskFile.m_path.c_str(), strerror(errno));
|
|
140
209
|
} else {
|
|
141
|
-
FileLock fileLock(m_fd);
|
|
210
|
+
FileLock fileLock(m_diskFile.m_fd);
|
|
142
211
|
InterProcessLock lock(&fileLock, ExclusiveLockType);
|
|
143
212
|
SCOPED_LOCK(&lock);
|
|
144
213
|
|
|
145
|
-
mmkv::getFileSize(m_fd, m_size);
|
|
214
|
+
mmkv::getFileSize(m_diskFile.m_fd, m_size);
|
|
146
215
|
// round up to (n * pagesize)
|
|
147
216
|
if (m_size < DEFAULT_MMAP_SIZE || (m_size % DEFAULT_MMAP_SIZE != 0)) {
|
|
148
217
|
size_t roundSize = ((m_size / DEFAULT_MMAP_SIZE) + 1) * DEFAULT_MMAP_SIZE;
|
|
@@ -154,44 +223,28 @@ void MemoryFile::reloadFromFile() {
|
|
|
154
223
|
}
|
|
155
224
|
}
|
|
156
225
|
# ifdef MMKV_IOS
|
|
157
|
-
tryResetFileProtection(
|
|
226
|
+
tryResetFileProtection(m_diskFile.m_path);
|
|
158
227
|
# endif
|
|
159
228
|
}
|
|
160
229
|
}
|
|
161
230
|
|
|
162
231
|
void MemoryFile::doCleanMemoryCache(bool forceClean) {
|
|
163
232
|
# ifdef MMKV_ANDROID
|
|
164
|
-
if (m_fileType == MMFILE_TYPE_ASHMEM && !forceClean) {
|
|
233
|
+
if (m_diskFile.m_fileType == MMFILE_TYPE_ASHMEM && !forceClean) {
|
|
165
234
|
return;
|
|
166
235
|
}
|
|
167
236
|
# endif
|
|
168
237
|
if (m_ptr && m_ptr != MAP_FAILED) {
|
|
169
238
|
if (munmap(m_ptr, m_size) != 0) {
|
|
170
|
-
MMKVError("fail to munmap [%s], %s",
|
|
239
|
+
MMKVError("fail to munmap [%s], %s", m_diskFile.m_path.c_str(), strerror(errno));
|
|
171
240
|
}
|
|
172
241
|
}
|
|
173
242
|
m_ptr = nullptr;
|
|
174
243
|
|
|
175
|
-
|
|
176
|
-
if (::close(m_fd) != 0) {
|
|
177
|
-
MMKVError("fail to close [%s], %s", m_name.c_str(), strerror(errno));
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
m_fd = -1;
|
|
244
|
+
m_diskFile.close();
|
|
181
245
|
m_size = 0;
|
|
182
246
|
}
|
|
183
247
|
|
|
184
|
-
size_t MemoryFile::getActualFileSize() {
|
|
185
|
-
# ifdef MMKV_ANDROID
|
|
186
|
-
if (m_fileType == MMFILE_TYPE_ASHMEM) {
|
|
187
|
-
return ASharedMemory_getSize(m_fd);
|
|
188
|
-
}
|
|
189
|
-
# endif
|
|
190
|
-
size_t size = 0;
|
|
191
|
-
mmkv::getFileSize(m_fd, size);
|
|
192
|
-
return size;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
248
|
bool isFileExist(const string &nsFilePath) {
|
|
196
249
|
if (nsFilePath.empty()) {
|
|
197
250
|
return false;
|
|
@@ -286,7 +339,7 @@ bool zeroFillFile(int fd, size_t startPos, size_t size) {
|
|
|
286
339
|
return true;
|
|
287
340
|
}
|
|
288
341
|
|
|
289
|
-
|
|
342
|
+
bool getFileSize(int fd, size_t &size) {
|
|
290
343
|
struct stat st = {};
|
|
291
344
|
if (fstat(fd, &st) != -1) {
|
|
292
345
|
size = (size_t) st.st_size;
|
|
@@ -299,6 +352,186 @@ size_t getPageSize() {
|
|
|
299
352
|
return static_cast<size_t>(getpagesize());
|
|
300
353
|
}
|
|
301
354
|
|
|
355
|
+
#ifndef MMKV_APPLE
|
|
356
|
+
|
|
357
|
+
static pair<MMKVPath_t, int> createUniqueTempFile(const char *prefix) {
|
|
358
|
+
char path[PATH_MAX];
|
|
359
|
+
#ifdef MMKV_ANDROID
|
|
360
|
+
snprintf(path, PATH_MAX, "%s/%s.XXXXXX", g_android_tmpDir.c_str(), prefix);
|
|
361
|
+
#else
|
|
362
|
+
snprintf(path, PATH_MAX, "%s/%s.XXXXXX", P_tmpdir, prefix);
|
|
363
|
+
#endif
|
|
364
|
+
|
|
365
|
+
auto fd = mkstemp(path);
|
|
366
|
+
if (fd < 0) {
|
|
367
|
+
MMKVError("fail to create unique temp file [%s], %d(%s)", path, errno, strerror(errno));
|
|
368
|
+
return {"", fd};
|
|
369
|
+
}
|
|
370
|
+
MMKVDebug("create unique temp file [%s] with fd[%d]", path, fd);
|
|
371
|
+
return {MMKVPath_t(path), fd};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
#if !defined(MMKV_ANDROID) && !defined(MMKV_LINUX)
|
|
375
|
+
|
|
376
|
+
bool tryAtomicRename(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
|
|
377
|
+
if (::rename(srcPath.c_str(), dstPath.c_str()) != 0) {
|
|
378
|
+
MMKVError("fail to rename [%s] to [%s], %d(%s)", srcPath.c_str(), dstPath.c_str(), errno, strerror(errno));
|
|
379
|
+
return false;
|
|
380
|
+
}
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD, bool needTruncate) {
|
|
385
|
+
if (dstFD < 0) {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
bool ret = false;
|
|
389
|
+
File srcFile(srcPath, OpenFlag::ReadOnly);
|
|
390
|
+
if (!srcFile.isFileValid()) {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
auto bufferSize = getPageSize();
|
|
394
|
+
auto buffer = (char *) malloc(bufferSize);
|
|
395
|
+
if (!buffer) {
|
|
396
|
+
MMKVError("fail to malloc size %zu, %d(%s)", bufferSize, errno, strerror(errno));
|
|
397
|
+
goto errorOut;
|
|
398
|
+
}
|
|
399
|
+
lseek(dstFD, 0, SEEK_SET);
|
|
400
|
+
|
|
401
|
+
// the POSIX standard don't have sendfile()/fcopyfile() equivalent, do it the hard way
|
|
402
|
+
while (true) {
|
|
403
|
+
auto sizeRead = read(srcFile.getFd(), buffer, bufferSize);
|
|
404
|
+
if (sizeRead < 0) {
|
|
405
|
+
MMKVError("fail to read file [%s], %d(%s)", srcPath.c_str(), errno, strerror(errno));
|
|
406
|
+
goto errorOut;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
size_t totalWrite = 0;
|
|
410
|
+
do {
|
|
411
|
+
auto sizeWrite = write(dstFD, buffer + totalWrite, sizeRead - totalWrite);
|
|
412
|
+
if (sizeWrite < 0) {
|
|
413
|
+
MMKVError("fail to write fd [%d], %d(%s)", dstFD, errno, strerror(errno));
|
|
414
|
+
goto errorOut;
|
|
415
|
+
}
|
|
416
|
+
totalWrite += sizeWrite;
|
|
417
|
+
} while (totalWrite < sizeRead);
|
|
418
|
+
|
|
419
|
+
if (sizeRead < bufferSize) {
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (needTruncate) {
|
|
424
|
+
size_t dstFileSize = 0;
|
|
425
|
+
getFileSize(dstFD, dstFileSize);
|
|
426
|
+
auto srcFileSize = srcFile.getActualFileSize();
|
|
427
|
+
if ((dstFileSize != srcFileSize) && (::ftruncate(dstFD, static_cast<off_t>(srcFileSize)) != 0)) {
|
|
428
|
+
MMKVError("fail to truncate [%d] to size [%zu], %d(%s)", dstFD, srcFileSize, errno, strerror(errno));
|
|
429
|
+
goto errorOut;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
ret = true;
|
|
434
|
+
MMKVInfo("copy content from %s to fd[%d] finish", srcPath.c_str(), dstFD);
|
|
435
|
+
|
|
436
|
+
errorOut:
|
|
437
|
+
free(buffer);
|
|
438
|
+
return ret;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
#endif // !defined(MMKV_ANDROID) && !defined(MMKV_LINUX)
|
|
442
|
+
|
|
443
|
+
// copy to a temp file then rename it
|
|
444
|
+
// this is the best we can do under the POSIX standard
|
|
445
|
+
bool copyFile(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
|
|
446
|
+
auto pair = createUniqueTempFile("MMKV");
|
|
447
|
+
auto tmpFD = pair.second;
|
|
448
|
+
auto &tmpPath = pair.first;
|
|
449
|
+
if (tmpFD < 0) {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
bool renamed = false;
|
|
454
|
+
if (copyFileContent(srcPath, tmpFD, false)) {
|
|
455
|
+
MMKVInfo("copyfile [%s] to [%s]", srcPath.c_str(), tmpPath.c_str());
|
|
456
|
+
renamed = tryAtomicRename(tmpPath, dstPath);
|
|
457
|
+
if (renamed) {
|
|
458
|
+
MMKVInfo("copyfile [%s] to [%s] finish.", srcPath.c_str(), dstPath.c_str());
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
::close(tmpFD);
|
|
463
|
+
if (!renamed) {
|
|
464
|
+
::unlink(tmpPath.c_str());
|
|
465
|
+
}
|
|
466
|
+
return renamed;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
bool copyFileContent(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
|
|
470
|
+
File dstFile(dstPath, OpenFlag::WriteOnly | OpenFlag::Create | OpenFlag::Truncate);
|
|
471
|
+
if (!dstFile.isFileValid()) {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
auto ret = copyFileContent(srcPath, dstFile.getFd(), false);
|
|
475
|
+
if (!ret) {
|
|
476
|
+
MMKVError("fail to copyfile(): target file %s", dstPath.c_str());
|
|
477
|
+
} else {
|
|
478
|
+
MMKVInfo("copy content from %s to [%s] finish", srcPath.c_str(), dstPath.c_str());
|
|
479
|
+
}
|
|
480
|
+
return ret;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD) {
|
|
484
|
+
return copyFileContent(srcPath, dstFD, true);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
#endif // !defined(MMKV_APPLE)
|
|
488
|
+
|
|
489
|
+
void walkInDir(const MMKVPath_t &dirPath, WalkType type, const function<void(const MMKVPath_t&, WalkType)> &walker) {
|
|
490
|
+
auto folderPathStr = dirPath.data();
|
|
491
|
+
DIR *dir = opendir(folderPathStr);
|
|
492
|
+
if (!dir) {
|
|
493
|
+
MMKVError("opendir failed: %d(%s), %s", errno, strerror(errno), dirPath.c_str());
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
char childPath[PATH_MAX];
|
|
498
|
+
size_t folderPathLength = dirPath.size();
|
|
499
|
+
strncpy(childPath, folderPathStr, folderPathLength + 1);
|
|
500
|
+
if (folderPathStr[folderPathLength - 1] != '/') {
|
|
501
|
+
childPath[folderPathLength] = '/';
|
|
502
|
+
folderPathLength++;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
while (auto child = readdir(dir)) {
|
|
506
|
+
if ((child->d_type & DT_REG) && (type & WalkFile)) {
|
|
507
|
+
#ifdef _DIRENT_HAVE_D_NAMLEN
|
|
508
|
+
stpcpy(childPath + folderPathLength, child->d_name);
|
|
509
|
+
childPath[folderPathLength + child->d_namlen] = 0;
|
|
510
|
+
#else
|
|
511
|
+
strcpy(childPath + folderPathLength, child->d_name);
|
|
512
|
+
#endif
|
|
513
|
+
walker(childPath, WalkFile);
|
|
514
|
+
} else if ((child->d_type & DT_DIR) && (type & WalkFolder)) {
|
|
515
|
+
#ifdef _DIRENT_HAVE_D_NAMLEN
|
|
516
|
+
if ((child->d_namlen == 1 && child->d_name[0] == '.') ||
|
|
517
|
+
(child->d_namlen == 2 && child->d_name[0] == '.' && child->d_name[1] == '.')) {
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
stpcpy(childPath + folderPathLength, child->d_name);
|
|
521
|
+
childPath[folderPathLength + child->d_namlen] = 0;
|
|
522
|
+
#else
|
|
523
|
+
if (strcmp(child->d_name, ".") == 0 || strcmp(child->d_name, "..") == 0) {
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
strcpy(childPath + folderPathLength, child->d_name);
|
|
527
|
+
#endif
|
|
528
|
+
walker(childPath, WalkFolder);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
closedir(dir);
|
|
533
|
+
}
|
|
534
|
+
|
|
302
535
|
} // namespace mmkv
|
|
303
536
|
|
|
304
|
-
#endif // MMKV_WIN32
|
|
537
|
+
#endif // !defined(MMKV_WIN32)
|
package/MMKV/Core/MemoryFile.h
CHANGED
|
@@ -23,12 +23,14 @@
|
|
|
23
23
|
#ifdef __cplusplus
|
|
24
24
|
|
|
25
25
|
#include "MMKVPredef.h"
|
|
26
|
+
#include <functional>
|
|
26
27
|
|
|
27
28
|
#ifdef MMKV_ANDROID
|
|
28
29
|
MMKVPath_t ashmemMMKVPathWithID(const MMKVPath_t &mmapID);
|
|
29
30
|
|
|
30
31
|
namespace mmkv {
|
|
31
32
|
extern int g_android_api;
|
|
33
|
+
extern std::string g_android_tmpDir;
|
|
32
34
|
|
|
33
35
|
enum FileType : bool { MMFILE_TYPE_FILE = false, MMFILE_TYPE_ASHMEM = true };
|
|
34
36
|
} // namespace mmkv
|
|
@@ -36,9 +38,66 @@ enum FileType : bool { MMFILE_TYPE_FILE = false, MMFILE_TYPE_ASHMEM = true };
|
|
|
36
38
|
|
|
37
39
|
namespace mmkv {
|
|
38
40
|
|
|
39
|
-
class
|
|
40
|
-
|
|
41
|
+
enum class OpenFlag : uint32_t {
|
|
42
|
+
ReadOnly = 1 << 0,
|
|
43
|
+
WriteOnly = 1 << 1,
|
|
44
|
+
ReadWrite = ReadOnly | WriteOnly,
|
|
45
|
+
Create = 1 << 2,
|
|
46
|
+
Excel = 1 << 3, // fail if Create is set but the file already exist
|
|
47
|
+
Truncate = 1 << 4,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
static inline OpenFlag operator | (OpenFlag left, OpenFlag right) {
|
|
51
|
+
return static_cast<OpenFlag>(static_cast<uint32_t>(left) | static_cast<uint32_t>(right));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static inline bool operator & (OpenFlag left, OpenFlag right) {
|
|
55
|
+
return ((static_cast<uint32_t>(left) & static_cast<uint32_t>(right)) != 0);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class File {
|
|
59
|
+
MMKVPath_t m_path;
|
|
41
60
|
MMKVFileHandle_t m_fd;
|
|
61
|
+
public:
|
|
62
|
+
const OpenFlag m_flag;
|
|
63
|
+
#ifndef MMKV_ANDROID
|
|
64
|
+
explicit File(MMKVPath_t path, OpenFlag flag);
|
|
65
|
+
#else
|
|
66
|
+
File(MMKVPath_t path, OpenFlag flag, size_t size = 0, FileType fileType = MMFILE_TYPE_FILE);
|
|
67
|
+
explicit File(MMKVFileHandle_t ashmemFD);
|
|
68
|
+
|
|
69
|
+
size_t m_size;
|
|
70
|
+
const FileType m_fileType;
|
|
71
|
+
#endif // MMKV_ANDROID
|
|
72
|
+
|
|
73
|
+
~File() { close(); }
|
|
74
|
+
|
|
75
|
+
bool open();
|
|
76
|
+
|
|
77
|
+
void close();
|
|
78
|
+
|
|
79
|
+
MMKVFileHandle_t getFd() { return m_fd; }
|
|
80
|
+
|
|
81
|
+
const MMKVPath_t &getPath() const { return m_path; }
|
|
82
|
+
|
|
83
|
+
#ifndef MMKV_WIN32
|
|
84
|
+
bool isFileValid() const { return m_fd >= 0; }
|
|
85
|
+
#else
|
|
86
|
+
bool isFileValid() const { return m_fd != INVALID_HANDLE_VALUE; }
|
|
87
|
+
#endif
|
|
88
|
+
|
|
89
|
+
// get the actual file size on disk
|
|
90
|
+
size_t getActualFileSize() const;
|
|
91
|
+
|
|
92
|
+
// just forbid it for possibly misuse
|
|
93
|
+
explicit File(const File &other) = delete;
|
|
94
|
+
File &operator=(const File &other) = delete;
|
|
95
|
+
|
|
96
|
+
friend class MemoryFile;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
class MemoryFile {
|
|
100
|
+
File m_diskFile;
|
|
42
101
|
#ifdef MMKV_WIN32
|
|
43
102
|
HANDLE m_fileMapping;
|
|
44
103
|
#endif
|
|
@@ -51,9 +110,9 @@ class MemoryFile {
|
|
|
51
110
|
|
|
52
111
|
public:
|
|
53
112
|
#ifndef MMKV_ANDROID
|
|
54
|
-
explicit MemoryFile(
|
|
113
|
+
explicit MemoryFile(MMKVPath_t path);
|
|
55
114
|
#else
|
|
56
|
-
MemoryFile(
|
|
115
|
+
MemoryFile(MMKVPath_t path, size_t size, FileType fileType);
|
|
57
116
|
explicit MemoryFile(MMKVFileHandle_t ashmemFD);
|
|
58
117
|
|
|
59
118
|
const FileType m_fileType;
|
|
@@ -64,13 +123,13 @@ public:
|
|
|
64
123
|
size_t getFileSize() const { return m_size; }
|
|
65
124
|
|
|
66
125
|
// get the actual file size on disk
|
|
67
|
-
size_t getActualFileSize();
|
|
126
|
+
size_t getActualFileSize() const { return m_diskFile.getActualFileSize(); }
|
|
68
127
|
|
|
69
128
|
void *getMemory() { return m_ptr; }
|
|
70
129
|
|
|
71
|
-
const MMKVPath_t &
|
|
130
|
+
const MMKVPath_t &getPath() { return m_diskFile.getPath(); }
|
|
72
131
|
|
|
73
|
-
MMKVFileHandle_t getFd() { return
|
|
132
|
+
MMKVFileHandle_t getFd() { return m_diskFile.getFd(); }
|
|
74
133
|
|
|
75
134
|
// the newly expanded file content will be zeroed
|
|
76
135
|
bool truncate(size_t size);
|
|
@@ -83,9 +142,9 @@ public:
|
|
|
83
142
|
void clearMemoryCache() { doCleanMemoryCache(false); }
|
|
84
143
|
|
|
85
144
|
#ifndef MMKV_WIN32
|
|
86
|
-
bool isFileValid() { return
|
|
145
|
+
bool isFileValid() { return m_diskFile.isFileValid() && m_size > 0 && m_ptr; }
|
|
87
146
|
#else
|
|
88
|
-
bool isFileValid() { return
|
|
147
|
+
bool isFileValid() { return m_diskFile.isFileValid() && m_size > 0 && m_fileMapping && m_ptr; }
|
|
89
148
|
#endif
|
|
90
149
|
|
|
91
150
|
// just forbid it for possibly misuse
|
|
@@ -100,6 +159,23 @@ extern bool isFileExist(const MMKVPath_t &nsFilePath);
|
|
|
100
159
|
extern MMBuffer *readWholeFile(const MMKVPath_t &path);
|
|
101
160
|
extern bool zeroFillFile(MMKVFileHandle_t fd, size_t startPos, size_t size);
|
|
102
161
|
extern size_t getPageSize();
|
|
162
|
+
|
|
163
|
+
extern bool tryAtomicRename(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath);
|
|
164
|
+
|
|
165
|
+
// copy file by potentially renaming target file, might change file inode
|
|
166
|
+
extern bool copyFile(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath);
|
|
167
|
+
|
|
168
|
+
// copy file by source file content, keep file inode the same
|
|
169
|
+
extern bool copyFileContent(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath);
|
|
170
|
+
extern bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD);
|
|
171
|
+
extern bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD, bool needTruncate);
|
|
172
|
+
|
|
173
|
+
enum WalkType : uint32_t {
|
|
174
|
+
WalkFile = 1 << 0,
|
|
175
|
+
WalkFolder = 1 << 1,
|
|
176
|
+
};
|
|
177
|
+
extern void walkInDir(const MMKVPath_t &dirPath, WalkType type, const std::function<void(const MMKVPath_t&, WalkType)> &walker);
|
|
178
|
+
|
|
103
179
|
} // namespace mmkv
|
|
104
180
|
|
|
105
181
|
#endif
|