react-native-mmkv 3.0.2 → 3.2.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.
Files changed (91) hide show
  1. package/MMKV/Core/MMKV.cpp +51 -15
  2. package/MMKV/Core/MMKV.h +19 -5
  3. package/MMKV/Core/MMKVPredef.h +2 -2
  4. package/MMKV/Core/MMKV_Android.cpp +13 -13
  5. package/MMKV/Core/MMKV_IO.cpp +37 -6
  6. package/MMKV/Core/MMKV_OSX.cpp +15 -4
  7. package/MMKV/Core/MemoryFile.cpp +24 -10
  8. package/MMKV/Core/MemoryFile.h +8 -2
  9. package/MMKV/Core/MemoryFile_Android.cpp +4 -3
  10. package/MMKV/Core/MemoryFile_Win32.cpp +22 -11
  11. package/MMKV/Core/aes/AESCrypt.cpp +19 -24
  12. package/MMKV/Core/aes/AESCrypt.h +4 -1
  13. package/MMKV/README.md +354 -0
  14. package/README.md +5 -0
  15. package/cpp/MmkvHostObject.cpp +18 -3
  16. package/cpp/NativeMmkvModule.h +1 -1
  17. package/lib/commonjs/MMKV.js +5 -5
  18. package/lib/commonjs/MMKV.js.map +1 -1
  19. package/lib/commonjs/MemoryWarningListener.js +31 -0
  20. package/lib/commonjs/MemoryWarningListener.js.map +1 -0
  21. package/lib/commonjs/MemoryWarningListener.web.js +11 -0
  22. package/lib/commonjs/MemoryWarningListener.web.js.map +1 -0
  23. package/lib/commonjs/NativeMmkv.js +10 -5
  24. package/lib/commonjs/NativeMmkv.js.map +1 -1
  25. package/lib/commonjs/NativeMmkvPlatformContext.js +4 -4
  26. package/lib/commonjs/NativeMmkvPlatformContext.js.map +1 -1
  27. package/lib/commonjs/Types.js +24 -0
  28. package/lib/commonjs/Types.js.map +1 -1
  29. package/lib/commonjs/createMMKV.js +7 -0
  30. package/lib/commonjs/createMMKV.js.map +1 -1
  31. package/lib/commonjs/createMMKV.mock.js +1 -0
  32. package/lib/commonjs/createMMKV.mock.js.map +1 -1
  33. package/lib/commonjs/createMMKV.web.js +1 -0
  34. package/lib/commonjs/createMMKV.web.js.map +1 -1
  35. package/lib/commonjs/index.js +3 -10
  36. package/lib/commonjs/index.js.map +1 -1
  37. package/lib/module/MMKV.js +5 -5
  38. package/lib/module/MMKV.js.map +1 -1
  39. package/lib/module/MemoryWarningListener.js +27 -0
  40. package/lib/module/MemoryWarningListener.js.map +1 -0
  41. package/lib/module/MemoryWarningListener.web.js +6 -0
  42. package/lib/module/MemoryWarningListener.web.js.map +1 -0
  43. package/lib/module/NativeMmkv.js +10 -5
  44. package/lib/module/NativeMmkv.js.map +1 -1
  45. package/lib/module/NativeMmkvPlatformContext.js +4 -4
  46. package/lib/module/NativeMmkvPlatformContext.js.map +1 -1
  47. package/lib/module/Types.js +23 -0
  48. package/lib/module/Types.js.map +1 -1
  49. package/lib/module/createMMKV.js +7 -0
  50. package/lib/module/createMMKV.js.map +1 -1
  51. package/lib/module/createMMKV.mock.js +1 -0
  52. package/lib/module/createMMKV.mock.js.map +1 -1
  53. package/lib/module/createMMKV.web.js +1 -0
  54. package/lib/module/createMMKV.web.js.map +1 -1
  55. package/lib/module/index.js +1 -1
  56. package/lib/module/index.js.map +1 -1
  57. package/lib/typescript/src/MMKV.d.ts +2 -2
  58. package/lib/typescript/src/MMKV.d.ts.map +1 -1
  59. package/lib/typescript/src/MemoryWarningListener.d.ts +3 -0
  60. package/lib/typescript/src/MemoryWarningListener.d.ts.map +1 -0
  61. package/lib/typescript/src/MemoryWarningListener.web.d.ts +3 -0
  62. package/lib/typescript/src/MemoryWarningListener.web.d.ts.map +1 -0
  63. package/lib/typescript/src/NativeMmkv.d.ts +9 -0
  64. package/lib/typescript/src/NativeMmkv.d.ts.map +1 -1
  65. package/lib/typescript/src/NativeMmkvPlatformContext.d.ts.map +1 -1
  66. package/lib/typescript/src/Types.d.ts +76 -0
  67. package/lib/typescript/src/Types.d.ts.map +1 -1
  68. package/lib/typescript/src/createMMKV.d.ts +1 -2
  69. package/lib/typescript/src/createMMKV.d.ts.map +1 -1
  70. package/lib/typescript/src/createMMKV.mock.d.ts.map +1 -1
  71. package/lib/typescript/src/createMMKV.web.d.ts +1 -2
  72. package/lib/typescript/src/createMMKV.web.d.ts.map +1 -1
  73. package/lib/typescript/src/hooks.d.ts +1 -1
  74. package/lib/typescript/src/hooks.d.ts.map +1 -1
  75. package/lib/typescript/src/index.d.ts +1 -1
  76. package/lib/typescript/src/index.d.ts.map +1 -1
  77. package/package.json +12 -14
  78. package/react-native-mmkv.podspec +1 -1
  79. package/src/MMKV.ts +11 -7
  80. package/src/MemoryWarningListener.ts +29 -0
  81. package/src/MemoryWarningListener.web.ts +5 -0
  82. package/src/NativeMmkv.ts +14 -5
  83. package/src/NativeMmkvPlatformContext.ts +6 -4
  84. package/src/Types.ts +79 -0
  85. package/src/createMMKV.mock.ts +1 -0
  86. package/src/createMMKV.ts +9 -2
  87. package/src/createMMKV.web.ts +2 -2
  88. package/src/hooks.ts +1 -1
  89. package/src/index.ts +1 -1
  90. package/img/banner-dark.png +0 -0
  91. package/img/banner-light.png +0 -0
@@ -80,20 +80,21 @@ MMKVPath_t filename(const MMKVPath_t &path);
80
80
  #ifndef MMKV_ANDROID
81
81
  MMKV::MMKV(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath, size_t expectedCapacity)
82
82
  : m_mmapID(mmapID)
83
+ , m_mode(mode)
83
84
  , m_path(mappedKVPathWithID(m_mmapID, mode, rootPath))
84
85
  , m_crcPath(crcPathWithID(m_mmapID, mode, rootPath))
85
86
  , m_dic(nullptr)
86
87
  , m_dicCrypt(nullptr)
87
88
  , m_expectedCapacity(std::max<size_t>(DEFAULT_MMAP_SIZE, roundUp<size_t>(expectedCapacity, DEFAULT_MMAP_SIZE)))
88
- , m_file(new MemoryFile(m_path, m_expectedCapacity))
89
- , m_metaFile(new MemoryFile(m_crcPath))
89
+ , m_file(new MemoryFile(m_path, m_expectedCapacity, isReadOnly()))
90
+ , m_metaFile(new MemoryFile(m_crcPath, 0, isReadOnly()))
90
91
  , m_metaInfo(new MMKVMetaInfo())
91
92
  , m_crypter(nullptr)
92
93
  , m_lock(new ThreadLock())
93
94
  , m_fileLock(new FileLock(m_metaFile->getFd()))
94
95
  , m_sharedProcessLock(new InterProcessLock(m_fileLock, SharedLockType))
95
96
  , m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType))
96
- , m_isInterProcess((mode & MMKV_MULTI_PROCESS) != 0) {
97
+ {
97
98
  m_actualSize = 0;
98
99
  m_output = nullptr;
99
100
 
@@ -114,8 +115,8 @@ MMKV::MMKV(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *ro
114
115
  m_crcDigest = 0;
115
116
 
116
117
  m_lock->initialize();
117
- m_sharedProcessLock->m_enable = m_isInterProcess;
118
- m_exclusiveProcessLock->m_enable = m_isInterProcess;
118
+ m_sharedProcessLock->m_enable = isMultiProcess();
119
+ m_exclusiveProcessLock->m_enable = isMultiProcess();
119
120
 
120
121
  // sensitive zone
121
122
  /*{
@@ -219,8 +220,10 @@ void MMKV::initializeMMKV(const MMKVPath_t &rootDir, MMKVLogLevel logLevel, mmkv
219
220
  # endif
220
221
  #endif
221
222
 
222
- g_rootDir = rootDir;
223
- mkPath(g_rootDir);
223
+ if (g_rootDir.empty()) {
224
+ g_rootDir = rootDir;
225
+ mkPath(g_rootDir);
226
+ }
224
227
 
225
228
  MMKVInfo("root dir: " MMKV_PATH_FORMAT, g_rootDir.c_str());
226
229
  }
@@ -232,7 +235,7 @@ const MMKVPath_t &MMKV::getRootDir() {
232
235
  #ifndef MMKV_ANDROID
233
236
  MMKV *MMKV::mmkvWithID(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath, size_t expectedCapacity) {
234
237
 
235
- if (mmapID.empty()) {
238
+ if (mmapID.empty() || !g_instanceLock) {
236
239
  return nullptr;
237
240
  }
238
241
  SCOPED_LOCK(g_instanceLock);
@@ -260,6 +263,9 @@ MMKV *MMKV::mmkvWithID(const string &mmapID, MMKVMode mode, string *cryptKey, MM
260
263
  #endif
261
264
 
262
265
  void MMKV::onExit() {
266
+ if (!g_instanceLock) {
267
+ return;
268
+ }
263
269
  SCOPED_LOCK(g_instanceLock);
264
270
 
265
271
  for (auto &pair : *g_instanceDic) {
@@ -1094,15 +1100,19 @@ size_t MMKV::actualSize() {
1094
1100
  return m_actualSize;
1095
1101
  }
1096
1102
 
1097
- void MMKV::removeValueForKey(MMKVKey_t key) {
1103
+ bool MMKV::removeValueForKey(MMKVKey_t key) {
1098
1104
  if (isKeyEmpty(key)) {
1099
- return;
1105
+ return false;
1106
+ }
1107
+ if (isReadOnly()) {
1108
+ MMKVWarning("[%s] file readonly", m_mmapID.c_str());
1109
+ return false;
1100
1110
  }
1101
1111
  SCOPED_LOCK(m_lock);
1102
1112
  SCOPED_LOCK(m_exclusiveProcessLock);
1103
1113
  checkLoadData();
1104
1114
 
1105
- removeDataForKey(key);
1115
+ return removeDataForKey(key);
1106
1116
  }
1107
1117
 
1108
1118
  #ifndef MMKV_APPLE
@@ -1129,9 +1139,13 @@ vector<string> MMKV::allKeys(bool filterExpire) {
1129
1139
  return keys;
1130
1140
  }
1131
1141
 
1132
- void MMKV::removeValuesForKeys(const vector<string> &arrKeys) {
1142
+ bool MMKV::removeValuesForKeys(const vector<string> &arrKeys) {
1143
+ if (isReadOnly()) {
1144
+ MMKVWarning("[%s] file readonly", m_mmapID.c_str());
1145
+ return false;
1146
+ }
1133
1147
  if (arrKeys.empty()) {
1134
- return;
1148
+ return true;
1135
1149
  }
1136
1150
  if (arrKeys.size() == 1) {
1137
1151
  return removeValueForKey(arrKeys[0]);
@@ -1162,8 +1176,9 @@ void MMKV::removeValuesForKeys(const vector<string> &arrKeys) {
1162
1176
  if (deleteCount > 0) {
1163
1177
  m_hasFullWriteback = false;
1164
1178
 
1165
- fullWriteback();
1179
+ return fullWriteback();
1166
1180
  }
1181
+ return true;
1167
1182
  }
1168
1183
 
1169
1184
  #endif // MMKV_APPLE
@@ -1238,6 +1253,9 @@ static bool backupOneToDirectoryByFilePath(const string &mmapKey, const MMKVPath
1238
1253
  }
1239
1254
 
1240
1255
  bool MMKV::backupOneToDirectory(const string &mmapKey, const MMKVPath_t &dstPath, const MMKVPath_t &srcPath, bool compareFullPath) {
1256
+ if (!g_instanceLock) {
1257
+ return false;
1258
+ }
1241
1259
  // we have to lock the creation of MMKV instance, regardless of in cache or not
1242
1260
  SCOPED_LOCK(g_instanceLock);
1243
1261
  MMKV *kv = nullptr;
@@ -1400,6 +1418,9 @@ static bool restoreOneFromDirectoryByFilePath(const string &mmapKey, const MMKVP
1400
1418
  // They won't know a difference when the file has been replaced.
1401
1419
  // We have to let them know by overriding the existing file with new content.
1402
1420
  bool MMKV::restoreOneFromDirectory(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath, bool compareFullPath) {
1421
+ if (!g_instanceLock) {
1422
+ return false;
1423
+ }
1403
1424
  // we have to lock the creation of MMKV instance, regardless of in cache or not
1404
1425
  SCOPED_LOCK(g_instanceLock);
1405
1426
  MMKV *kv = nullptr;
@@ -1447,7 +1468,7 @@ bool MMKV::restoreOneFromDirectory(const string &mmapKey, const MMKVPath_t &srcP
1447
1468
  // reload data after restore
1448
1469
  kv->clearMemoryCache();
1449
1470
  kv->loadFromFile();
1450
- if (kv->m_isInterProcess) {
1471
+ if (kv->isMultiProcess()) {
1451
1472
  kv->notifyContentChanged();
1452
1473
  }
1453
1474
 
@@ -1534,26 +1555,41 @@ size_t MMKV::restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t
1534
1555
  // callbacks
1535
1556
 
1536
1557
  void MMKV::registerErrorHandler(ErrorHandler handler) {
1558
+ if (!g_instanceLock) {
1559
+ return;
1560
+ }
1537
1561
  SCOPED_LOCK(g_instanceLock);
1538
1562
  g_errorHandler = handler;
1539
1563
  }
1540
1564
 
1541
1565
  void MMKV::unRegisterErrorHandler() {
1566
+ if (!g_instanceLock) {
1567
+ return;
1568
+ }
1542
1569
  SCOPED_LOCK(g_instanceLock);
1543
1570
  g_errorHandler = nullptr;
1544
1571
  }
1545
1572
 
1546
1573
  void MMKV::registerLogHandler(LogHandler handler) {
1574
+ if (!g_instanceLock) {
1575
+ return;
1576
+ }
1547
1577
  SCOPED_LOCK(g_instanceLock);
1548
1578
  g_logHandler = handler;
1549
1579
  }
1550
1580
 
1551
1581
  void MMKV::unRegisterLogHandler() {
1582
+ if (!g_instanceLock) {
1583
+ return;
1584
+ }
1552
1585
  SCOPED_LOCK(g_instanceLock);
1553
1586
  g_logHandler = nullptr;
1554
1587
  }
1555
1588
 
1556
1589
  void MMKV::setLogLevel(MMKVLogLevel level) {
1590
+ if (!g_instanceLock) {
1591
+ return;
1592
+ }
1557
1593
  SCOPED_LOCK(g_instanceLock);
1558
1594
  g_currentLogLevel = level;
1559
1595
  }
package/MMKV/Core/MMKV.h CHANGED
@@ -58,8 +58,13 @@ enum MMKVMode : uint32_t {
58
58
  MMKV_ASHMEM = 1 << 3,
59
59
  MMKV_BACKUP = 1 << 4,
60
60
  #endif
61
+ MMKV_READ_ONLY = 1 << 5,
61
62
  };
62
63
 
64
+ static inline MMKVMode operator | (MMKVMode one, MMKVMode other) {
65
+ return static_cast<MMKVMode>(static_cast<uint32_t>(one) | static_cast<uint32_t>(other));
66
+ }
67
+
63
68
  #define MMKV_OUT
64
69
 
65
70
  #ifdef MMKV_HAS_CPP20
@@ -105,6 +110,7 @@ class MMKV {
105
110
  ~MMKV();
106
111
 
107
112
  std::string m_mmapID;
113
+ const MMKVMode m_mode;
108
114
  MMKVPath_t m_path;
109
115
  MMKVPath_t m_crcPath;
110
116
  mmkv::MMKVMap *m_dic;
@@ -281,8 +287,16 @@ public:
281
287
  static void onExit();
282
288
 
283
289
  const std::string &mmapID() const;
284
-
285
- const bool m_isInterProcess;
290
+ #ifndef MMKV_ANDROID
291
+ bool isMultiProcess() const { return (m_mode & MMKV_MULTI_PROCESS) != 0; }
292
+ #else
293
+ bool isMultiProcess() const {
294
+ return (m_mode & MMKV_MULTI_PROCESS) != 0
295
+ || (m_mode & CONTEXT_MODE_MULTI_PROCESS) != 0
296
+ || (m_mode & MMKV_ASHMEM) != 0; // ashmem is always multi-process
297
+ }
298
+ #endif
299
+ bool isReadOnly() const { return (m_mode & MMKV_READ_ONLY) != 0; }
286
300
 
287
301
  #ifndef MMKV_DISABLE_CRYPT
288
302
  std::string cryptKey() const;
@@ -428,7 +442,7 @@ public:
428
442
  // filterExpire: return all non-expired keys, keep in mind it comes with cost
429
443
  NSArray *allKeys(bool filterExpire = false);
430
444
 
431
- void removeValuesForKeys(NSArray *arrKeys);
445
+ bool removeValuesForKeys(NSArray *arrKeys);
432
446
 
433
447
  typedef void (^EnumerateBlock)(NSString *key, BOOL *stop);
434
448
  void enumerateKeys(EnumerateBlock block);
@@ -441,10 +455,10 @@ public:
441
455
  // filterExpire: return all non-expired keys, keep in mind it comes with cost
442
456
  std::vector<std::string> allKeys(bool filterExpire = false);
443
457
 
444
- void removeValuesForKeys(const std::vector<std::string> &arrKeys);
458
+ bool removeValuesForKeys(const std::vector<std::string> &arrKeys);
445
459
  #endif // MMKV_APPLE
446
460
 
447
- void removeValueForKey(MMKVKey_t key);
461
+ bool removeValueForKey(MMKVKey_t key);
448
462
 
449
463
  // keepSpace: remove all keys but keep the file size not changed, running faster
450
464
  void clearAll(bool keepSpace = false);
@@ -22,7 +22,7 @@
22
22
  #define MMKV_SRC_MMKVPREDEF_H
23
23
 
24
24
  // disable encryption & decryption to reduce some code
25
- //#define MMKV_DISABLE_CRYPT
25
+ // #define MMKV_DISABLE_CRYPT
26
26
  //#define MMKV_DISABLE_FLUTTER
27
27
 
28
28
  // using POSIX implementation
@@ -34,7 +34,7 @@
34
34
  #include <vector>
35
35
  #include <unordered_map>
36
36
 
37
- constexpr auto MMKV_VERSION = "v1.3.9";
37
+ constexpr auto MMKV_VERSION = "v2.0.0";
38
38
 
39
39
  #ifdef DEBUG
40
40
  # define MMKV_DEBUG
@@ -41,20 +41,20 @@ extern ThreadLock *g_instanceLock;
41
41
 
42
42
  MMKV::MMKV(const string &mmapID, int size, MMKVMode mode, string *cryptKey, string *rootPath, size_t expectedCapacity)
43
43
  : m_mmapID((mode & MMKV_BACKUP) ? mmapID : mmapedKVKey(mmapID, rootPath)) // historically Android mistakenly use mmapKey as mmapID
44
+ , m_mode(mode)
44
45
  , m_path(mappedKVPathWithID(m_mmapID, mode, rootPath))
45
46
  , m_crcPath(crcPathWithID(m_mmapID, mode, rootPath))
46
47
  , m_dic(nullptr)
47
48
  , m_dicCrypt(nullptr)
48
49
  , m_expectedCapacity(std::max<size_t>(DEFAULT_MMAP_SIZE, roundUp<size_t>(expectedCapacity, DEFAULT_MMAP_SIZE)))
49
- , m_file(new MemoryFile(m_path, size, (mode & MMKV_ASHMEM) ? MMFILE_TYPE_ASHMEM : MMFILE_TYPE_FILE, m_expectedCapacity))
50
- , m_metaFile(new MemoryFile(m_crcPath, DEFAULT_MMAP_SIZE, m_file->m_fileType))
50
+ , m_file(new MemoryFile(m_path, size, (mode & MMKV_ASHMEM) ? MMFILE_TYPE_ASHMEM : MMFILE_TYPE_FILE, m_expectedCapacity, isReadOnly()))
51
+ , m_metaFile(new MemoryFile(m_crcPath, DEFAULT_MMAP_SIZE, m_file->m_fileType, 0, isReadOnly()))
51
52
  , m_metaInfo(new MMKVMetaInfo())
52
53
  , m_crypter(nullptr)
53
54
  , m_lock(new ThreadLock())
54
55
  , m_fileLock(new FileLock(m_metaFile->getFd(), (mode & MMKV_ASHMEM)))
55
56
  , m_sharedProcessLock(new InterProcessLock(m_fileLock, SharedLockType))
56
- , m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType))
57
- , m_isInterProcess((mode & MMKV_MULTI_PROCESS) != 0 || (mode & CONTEXT_MODE_MULTI_PROCESS) != 0) {
57
+ , m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType)) {
58
58
  m_actualSize = 0;
59
59
  m_output = nullptr;
60
60
 
@@ -78,8 +78,8 @@ MMKV::MMKV(const string &mmapID, int size, MMKVMode mode, string *cryptKey, stri
78
78
 
79
79
  m_crcDigest = 0;
80
80
 
81
- m_sharedProcessLock->m_enable = m_isInterProcess;
82
- m_exclusiveProcessLock->m_enable = m_isInterProcess;
81
+ m_sharedProcessLock->m_enable = isMultiProcess();
82
+ m_exclusiveProcessLock->m_enable = isMultiProcess();
83
83
 
84
84
  // sensitive zone
85
85
  /*{
@@ -90,6 +90,7 @@ MMKV::MMKV(const string &mmapID, int size, MMKVMode mode, string *cryptKey, stri
90
90
 
91
91
  MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKey)
92
92
  : m_mmapID(mmapID)
93
+ , m_mode(MMKV_ASHMEM)
93
94
  , m_path(mappedKVPathWithID(m_mmapID, MMKV_ASHMEM, nullptr))
94
95
  , m_crcPath(crcPathWithID(m_mmapID, MMKV_ASHMEM, nullptr))
95
96
  , m_dic(nullptr)
@@ -101,8 +102,7 @@ MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKe
101
102
  , m_lock(new ThreadLock())
102
103
  , m_fileLock(new FileLock(m_metaFile->getFd(), true))
103
104
  , m_sharedProcessLock(new InterProcessLock(m_fileLock, SharedLockType))
104
- , m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType))
105
- , m_isInterProcess(true) {
105
+ , m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType)) {
106
106
 
107
107
  m_actualSize = 0;
108
108
  m_output = nullptr;
@@ -127,8 +127,8 @@ MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKe
127
127
 
128
128
  m_crcDigest = 0;
129
129
 
130
- m_sharedProcessLock->m_enable = m_isInterProcess;
131
- m_exclusiveProcessLock->m_enable = m_isInterProcess;
130
+ m_sharedProcessLock->m_enable = true;
131
+ m_exclusiveProcessLock->m_enable = true;
132
132
 
133
133
  // sensitive zone
134
134
  /*{
@@ -138,7 +138,7 @@ MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKe
138
138
  }
139
139
 
140
140
  MMKV *MMKV::mmkvWithID(const string &mmapID, int size, MMKVMode mode, string *cryptKey, string *rootPath, size_t expectedCapacity) {
141
- if (mmapID.empty()) {
141
+ if (mmapID.empty() || !g_instanceLock) {
142
142
  return nullptr;
143
143
  }
144
144
  SCOPED_LOCK(g_instanceLock);
@@ -164,7 +164,7 @@ MMKV *MMKV::mmkvWithID(const string &mmapID, int size, MMKVMode mode, string *cr
164
164
 
165
165
  MMKV *MMKV::mmkvWithAshmemFD(const string &mmapID, int fd, int metaFD, string *cryptKey) {
166
166
 
167
- if (fd < 0) {
167
+ if (fd < 0 || !g_instanceLock) {
168
168
  return nullptr;
169
169
  }
170
170
  SCOPED_LOCK(g_instanceLock);
@@ -213,7 +213,7 @@ bool MMKV::checkProcessMode() {
213
213
  return true;
214
214
  }
215
215
 
216
- if (m_isInterProcess) {
216
+ if (isMultiProcess()) {
217
217
  if (!m_exclusiveProcessModeLock) {
218
218
  m_exclusiveProcessModeLock = new InterProcessLock(m_fileModeLock, ExclusiveLockType);
219
219
  }
@@ -81,7 +81,7 @@ void MMKV::loadFromFile() {
81
81
  checkDataValid(loadFromFile, needFullWriteback);
82
82
  MMKVInfo("loading [%s] with %zu actual size, file size %zu, InterProcess %d, meta info "
83
83
  "version:%u",
84
- m_mmapID.c_str(), m_actualSize, m_file->getFileSize(), m_isInterProcess, m_metaInfo->m_version);
84
+ m_mmapID.c_str(), m_actualSize, m_file->getFileSize(), isMultiProcess(), m_metaInfo->m_version);
85
85
  auto ptr = (uint8_t *) m_file->getMemory();
86
86
  // loading
87
87
  if (loadFromFile && m_actualSize > 0) {
@@ -131,6 +131,10 @@ void MMKV::loadFromFile() {
131
131
  }
132
132
  auto count = m_crypter ? m_dicCrypt->size() : m_dic->size();
133
133
  MMKVInfo("loaded [%s] with %zu key-values", m_mmapID.c_str(), count);
134
+ // auto keys = allKeys();
135
+ // for (size_t index = 0; index < count; index++) {
136
+ // MMKVInfo("key[%llu]: %s", index, keys[index].c_str());
137
+ // }
134
138
  }
135
139
 
136
140
  m_needLoadFromFile = false;
@@ -303,7 +307,7 @@ void MMKV::checkLoadData() {
303
307
  loadFromFile();
304
308
  return;
305
309
  }
306
- if (!m_isInterProcess) {
310
+ if (!isMultiProcess()) {
307
311
  return;
308
312
  }
309
313
 
@@ -397,6 +401,10 @@ bool MMKV::ensureMemorySize(size_t newSize) {
397
401
  MMKVWarning("[%s] file not valid", m_mmapID.c_str());
398
402
  return false;
399
403
  }
404
+ if (isReadOnly()) {
405
+ MMKVWarning("[%s] file readonly", m_mmapID.c_str());
406
+ return false;
407
+ }
400
408
 
401
409
  if (newSize >= m_output->spaceLeft() || (m_crypter ? m_dicCrypt->empty() : m_dic->empty())) {
402
410
  // remove expired keys
@@ -590,7 +598,7 @@ bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
590
598
  }
591
599
  auto itr = m_dicCrypt->find(key);
592
600
  if (itr != m_dicCrypt->end()) {
593
- bool onlyOneKey = !m_isInterProcess && m_dicCrypt->size() == 1;
601
+ bool onlyOneKey = !isMultiProcess() && m_dicCrypt->size() == 1;
594
602
  # ifdef MMKV_APPLE
595
603
  KVHolderRet_t ret;
596
604
  if (onlyOneKey) {
@@ -629,7 +637,7 @@ bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
629
637
  }
630
638
  }
631
639
  } else {
632
- bool needOverride = !m_isInterProcess && m_dicCrypt->empty() && m_actualSize > 0;
640
+ bool needOverride = !isMultiProcess() && m_dicCrypt->empty() && m_actualSize > 0;
633
641
  KVHolderRet_t ret;
634
642
  if (needOverride) {
635
643
  ret = overrideDataWithKey(data, key, isDataHolder);
@@ -681,7 +689,7 @@ bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
681
689
  }
682
690
  }
683
691
 
684
- bool onlyOneKey = !m_isInterProcess && m_dic->size() == 1;
692
+ bool onlyOneKey = !isMultiProcess() && m_dic->size() == 1;
685
693
  if (mmkv_likely(!m_enableKeyExpire)) {
686
694
  KVHolderRet_t ret;
687
695
  if (onlyOneKey) {
@@ -713,7 +721,7 @@ bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
713
721
  }
714
722
  }
715
723
  } else {
716
- bool needOverride = !m_isInterProcess && m_dic->empty() && m_actualSize > 0;
724
+ bool needOverride = !isMultiProcess() && m_dic->empty() && m_actualSize > 0;
717
725
  KVHolderRet_t ret;
718
726
  if (needOverride) {
719
727
  ret = overrideDataWithKey(data, key, isDataHolder);
@@ -1338,6 +1346,10 @@ bool MMKV::reKey(const string &cryptKey) {
1338
1346
  MMKVWarning("[%s] file not valid", m_mmapID.c_str());
1339
1347
  return false;
1340
1348
  }
1349
+ if (isReadOnly()) {
1350
+ MMKVWarning("[%s] file readonly", m_mmapID.c_str());
1351
+ return false;
1352
+ }
1341
1353
 
1342
1354
  bool ret = false;
1343
1355
  if (m_crypter) {
@@ -1408,6 +1420,10 @@ void MMKV::trim() {
1408
1420
  MMKVWarning("[%s] file not valid", m_mmapID.c_str());
1409
1421
  return;
1410
1422
  }
1423
+ if (isReadOnly()) {
1424
+ MMKVWarning("[%s] file readonly", m_mmapID.c_str());
1425
+ return;
1426
+ }
1411
1427
 
1412
1428
  if (m_actualSize == 0) {
1413
1429
  clearAll();
@@ -1452,6 +1468,10 @@ void MMKV::clearAll(bool keepSpace) {
1452
1468
  MMKVWarning("[%s] file not valid", m_mmapID.c_str());
1453
1469
  return;
1454
1470
  }
1471
+ if (isReadOnly()) {
1472
+ MMKVWarning("[%s] file readonly", m_mmapID.c_str());
1473
+ return;
1474
+ }
1455
1475
 
1456
1476
  if (m_file->getFileSize() == m_expectedCapacity && m_actualSize == 0) {
1457
1477
  MMKVInfo("nothing to clear for [%s]", m_mmapID.c_str());
@@ -1524,6 +1544,9 @@ bool MMKV::isFileValid(const string &mmapID, MMKVPath_t *relatePath) {
1524
1544
  }
1525
1545
 
1526
1546
  bool MMKV::removeStorage(const std::string &mmapID, MMKVPath_t *relatePath) {
1547
+ if (!g_instanceLock) {
1548
+ return false;
1549
+ }
1527
1550
  auto mmapKey = mmapedKVKey(mmapID, relatePath);
1528
1551
  #ifdef MMKV_ANDROID
1529
1552
  auto &realID = mmapKey; // historically Android mistakenly use mmapKey as mmapID
@@ -1625,6 +1648,10 @@ bool MMKV::enableAutoKeyExpire(uint32_t expiredInSeconds) {
1625
1648
  if (m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre)) {
1626
1649
  return true;
1627
1650
  }
1651
+ if (isReadOnly()) {
1652
+ MMKVWarning("[%s] file readonly", m_mmapID.c_str());
1653
+ return false;
1654
+ }
1628
1655
 
1629
1656
  auto autoRecordExpireTime = (m_expiredInSeconds != 0);
1630
1657
  auto time = autoRecordExpireTime ? getCurrentTimeInSecond() + m_expiredInSeconds : 0;
@@ -1685,6 +1712,10 @@ bool MMKV::disableAutoKeyExpire() {
1685
1712
  if (!m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre)) {
1686
1713
  return true;
1687
1714
  }
1715
+ if (isReadOnly()) {
1716
+ MMKVWarning("[%s] file readonly", m_mmapID.c_str());
1717
+ return false;
1718
+ }
1688
1719
 
1689
1720
  MMKVInfo("erase previous recorded expire date for all keys inside [%s]", m_mmapID.c_str());
1690
1721
  m_metaInfo->unsetFlag(MMKVMetaInfo::EnableKeyExipre);
@@ -42,7 +42,7 @@
42
42
  # endif
43
43
 
44
44
  # ifdef __aarch64__
45
- # include "Checksum.h"
45
+ # include "crc32/Checksum.h"
46
46
  # endif
47
47
 
48
48
  # if __has_feature(objc_arc)
@@ -94,6 +94,9 @@ bool MLockPtr::isMLockPtrEnabled = true;
94
94
  static bool g_isInBackground = false;
95
95
 
96
96
  void MMKV::setIsInBackground(bool isInBackground) {
97
+ if (!g_instanceLock) {
98
+ return;
99
+ }
97
100
  SCOPED_LOCK(g_instanceLock);
98
101
 
99
102
  g_isInBackground = isInBackground;
@@ -101,6 +104,9 @@ void MMKV::setIsInBackground(bool isInBackground) {
101
104
  }
102
105
 
103
106
  bool MMKV::isInBackground() {
107
+ if (!g_instanceLock) {
108
+ return true;
109
+ }
104
110
  SCOPED_LOCK(g_instanceLock);
105
111
 
106
112
  return g_isInBackground;
@@ -300,9 +306,13 @@ NSArray *MMKV::allKeys(bool filterExpire) {
300
306
  return keys;
301
307
  }
302
308
 
303
- void MMKV::removeValuesForKeys(NSArray *arrKeys) {
309
+ bool MMKV::removeValuesForKeys(NSArray *arrKeys) {
310
+ if (isReadOnly()) {
311
+ MMKVWarning("[%s] file readonly", m_mmapID.c_str());
312
+ return false;
313
+ }
304
314
  if (arrKeys.count == 0) {
305
- return;
315
+ return true;
306
316
  }
307
317
  if (arrKeys.count == 1) {
308
318
  return removeValueForKey(arrKeys[0]);
@@ -337,8 +347,9 @@ void MMKV::removeValuesForKeys(NSArray *arrKeys) {
337
347
  if (deleteCount > 0) {
338
348
  m_hasFullWriteback = false;
339
349
 
340
- fullWriteback();
350
+ return fullWriteback();
341
351
  }
352
+ return true;
342
353
  }
343
354
 
344
355
  void MMKV::enumerateKeys(EnumerateBlock block) {
@@ -50,7 +50,10 @@ File::File(MMKVPath_t path, OpenFlag flag) : m_path(std::move(path)), m_fd(-1),
50
50
  open();
51
51
  }
52
52
 
53
- MemoryFile::MemoryFile(MMKVPath_t path, size_t expectedCapacity) : m_diskFile(std::move(path), OpenFlag::ReadWrite | OpenFlag::Create), m_ptr(nullptr), m_size(0) {
53
+ MemoryFile::MemoryFile(MMKVPath_t path, size_t expectedCapacity, bool readOnly)
54
+ : m_diskFile(std::move(path), readOnly ? OpenFlag::ReadOnly : (OpenFlag::ReadWrite | OpenFlag::Create))
55
+ , m_ptr(nullptr), m_size(0), m_readOnly(readOnly)
56
+ {
54
57
  reloadFromFile(expectedCapacity);
55
58
  }
56
59
  # endif // !defined(MMKV_ANDROID)
@@ -61,7 +64,7 @@ void tryResetFileProtection(const string &path);
61
64
 
62
65
  static int OpenFlag2NativeFlag(OpenFlag flag) {
63
66
  int native = O_CLOEXEC;
64
- if (flag & OpenFlag::ReadWrite) {
67
+ if ((flag & OpenFlagRWMask) == OpenFlag::ReadWrite) {
65
68
  native |= O_RDWR;
66
69
  } else if (flag & OpenFlag::ReadOnly) {
67
70
  native |= O_RDONLY;
@@ -92,10 +95,10 @@ bool File::open() {
92
95
  }
93
96
  m_fd = ::open(m_path.c_str(), OpenFlag2NativeFlag(m_flag), S_IRWXU);
94
97
  if (!isFileValid()) {
95
- MMKVError("fail to open [%s], %d(%s)", m_path.c_str(), errno, strerror(errno));
98
+ MMKVError("fail to open [%s], flag %x, %d(%s)", m_path.c_str(), m_flag, errno, strerror(errno));
96
99
  return false;
97
100
  }
98
- MMKVInfo("open fd[%p], %s", m_fd, m_path.c_str());
101
+ MMKVInfo("open fd[%p], flag %x, %s", m_fd, m_flag, m_path.c_str());
99
102
  return true;
100
103
  }
101
104
 
@@ -128,6 +131,10 @@ bool MemoryFile::truncate(size_t size) {
128
131
  if (size == m_size) {
129
132
  return true;
130
133
  }
134
+ if (m_readOnly) {
135
+ // truncate readonly file not allow
136
+ return false;
137
+ }
131
138
  # ifdef MMKV_ANDROID
132
139
  if (m_diskFile.m_fileType == MMFILE_TYPE_ASHMEM) {
133
140
  if (size > m_size) {
@@ -182,6 +189,10 @@ bool MemoryFile::truncate(size_t size) {
182
189
  }
183
190
 
184
191
  bool MemoryFile::msync(SyncFlag syncFlag) {
192
+ if (m_readOnly) {
193
+ // there's no point in msync() readonly memory
194
+ return true;
195
+ }
185
196
  if (m_ptr) {
186
197
  auto ret = ::msync(m_ptr, m_size, syncFlag ? MS_SYNC : MS_ASYNC);
187
198
  if (ret == 0) {
@@ -194,9 +205,10 @@ bool MemoryFile::msync(SyncFlag syncFlag) {
194
205
 
195
206
  bool MemoryFile::mmap() {
196
207
  auto oldPtr = m_ptr;
197
- m_ptr = (char *) ::mmap(m_ptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_diskFile.m_fd, 0);
208
+ auto mode = m_readOnly ? PROT_READ : (PROT_READ | PROT_WRITE);
209
+ m_ptr = (char *) ::mmap(m_ptr, m_size, mode, MAP_SHARED, m_diskFile.m_fd, 0);
198
210
  if (m_ptr == MAP_FAILED) {
199
- MMKVError("fail to mmap [%s], %s", m_diskFile.m_path.c_str(), strerror(errno));
211
+ MMKVError("fail to mmap [%s], mode %x, %s", m_diskFile.m_path.c_str(), mode, strerror(errno));
200
212
  m_ptr = nullptr;
201
213
  return false;
202
214
  }
@@ -226,7 +238,7 @@ void MemoryFile::reloadFromFile(size_t expectedCapacity) {
226
238
  mmkv::getFileSize(m_diskFile.m_fd, m_size);
227
239
  size_t expectedSize = std::max<size_t>(DEFAULT_MMAP_SIZE, roundUp<size_t>(expectedCapacity, DEFAULT_MMAP_SIZE));
228
240
  // round up to (n * pagesize)
229
- if (m_size < expectedSize || (m_size % DEFAULT_MMAP_SIZE != 0)) {
241
+ if (!m_readOnly && (m_size < expectedSize || (m_size % DEFAULT_MMAP_SIZE != 0))) {
230
242
  InterProcessLock exclusiveLock(&fileLock, ExclusiveLockType);
231
243
  SCOPED_LOCK(&exclusiveLock);
232
244
 
@@ -240,7 +252,9 @@ void MemoryFile::reloadFromFile(size_t expectedCapacity) {
240
252
  }
241
253
  }
242
254
  # ifdef MMKV_IOS
243
- tryResetFileProtection(m_diskFile.m_path);
255
+ if (!m_readOnly) {
256
+ tryResetFileProtection(m_diskFile.m_path);
257
+ }
244
258
  # endif
245
259
  }
246
260
  }
@@ -556,7 +570,7 @@ void walkInDir(const MMKVPath_t &dirPath, WalkType type, const function<void(con
556
570
 
557
571
  while (auto child = readdir(dir)) {
558
572
  if ((child->d_type & DT_REG) && (type & WalkFile)) {
559
- #ifdef _DIRENT_HAVE_D_NAMLEN
573
+ #if defined(_DIRENT_HAVE_D_NAMLEN) || defined(__APPLE__)
560
574
  stpcpy(childPath + folderPathLength, child->d_name);
561
575
  childPath[folderPathLength + child->d_namlen] = 0;
562
576
  #else
@@ -564,7 +578,7 @@ void walkInDir(const MMKVPath_t &dirPath, WalkType type, const function<void(con
564
578
  #endif
565
579
  walker(childPath, WalkFile);
566
580
  } else if ((child->d_type & DT_DIR) && (type & WalkFolder)) {
567
- #ifdef _DIRENT_HAVE_D_NAMLEN
581
+ #if defined(_DIRENT_HAVE_D_NAMLEN) || defined(__APPLE__)
568
582
  if ((child->d_namlen == 1 && child->d_name[0] == '.') ||
569
583
  (child->d_namlen == 2 && child->d_name[0] == '.' && child->d_name[1] == '.')) {
570
584
  continue;