MMKV.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*
  2. * Tencent is pleased to support the open source community by making
  3. * MMKV available.
  4. *
  5. * Copyright (C) 2018 THL A29 Limited, a Tencent company.
  6. * All rights reserved.
  7. *
  8. * Licensed under the BSD 3-Clause License (the "License"); you may not use
  9. * this file except in compliance with the License. You may obtain a copy of
  10. * the License at
  11. *
  12. * https://opensource.org/licenses/BSD-3-Clause
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. */
  20. #ifndef MMKV_MMKV_H
  21. #define MMKV_MMKV_H
  22. #ifdef __cplusplus
  23. #include "MMBuffer.h"
  24. #include <cstdint>
  25. namespace mmkv {
  26. class CodedOutputData;
  27. class MemoryFile;
  28. class AESCrypt;
  29. struct MMKVMetaInfo;
  30. class FileLock;
  31. class InterProcessLock;
  32. class ThreadLock;
  33. } // namespace mmkv
  34. MMKV_NAMESPACE_BEGIN
  35. enum MMKVMode : uint32_t {
  36. MMKV_SINGLE_PROCESS = 1 << 0,
  37. MMKV_MULTI_PROCESS = 1 << 1,
  38. #ifdef MMKV_ANDROID
  39. CONTEXT_MODE_MULTI_PROCESS = 1 << 2, // in case someone mistakenly pass Context.MODE_MULTI_PROCESS
  40. MMKV_ASHMEM = 1 << 3,
  41. MMKV_BACKUP = 1 << 4,
  42. #endif
  43. };
  44. #define OUT
  45. class MMKV {
  46. #ifndef MMKV_ANDROID
  47. std::string m_mmapKey;
  48. MMKV(const std::string &mmapID, MMKVMode mode, std::string *cryptKey, MMKVPath_t *rootPath);
  49. #else // defined(MMKV_ANDROID)
  50. mmkv::FileLock *m_fileModeLock;
  51. mmkv::InterProcessLock *m_sharedProcessModeLock;
  52. mmkv::InterProcessLock *m_exclusiveProcessModeLock;
  53. MMKV(const std::string &mmapID, int size, MMKVMode mode, std::string *cryptKey, MMKVPath_t *rootPath);
  54. MMKV(const std::string &mmapID, int ashmemFD, int ashmemMetaFd, std::string *cryptKey = nullptr);
  55. #endif
  56. ~MMKV();
  57. std::string m_mmapID;
  58. MMKVPath_t m_path;
  59. MMKVPath_t m_crcPath;
  60. mmkv::MMKVMap *m_dic;
  61. mmkv::MMKVMapCrypt *m_dicCrypt;
  62. mmkv::MemoryFile *m_file;
  63. size_t m_actualSize;
  64. mmkv::CodedOutputData *m_output;
  65. bool m_needLoadFromFile;
  66. bool m_hasFullWriteback;
  67. uint32_t m_crcDigest;
  68. mmkv::MemoryFile *m_metaFile;
  69. mmkv::MMKVMetaInfo *m_metaInfo;
  70. mmkv::AESCrypt *m_crypter;
  71. mmkv::ThreadLock *m_lock;
  72. mmkv::FileLock *m_fileLock;
  73. mmkv::InterProcessLock *m_sharedProcessLock;
  74. mmkv::InterProcessLock *m_exclusiveProcessLock;
  75. bool m_enableKeyExpire = false;
  76. uint32_t m_expiredInSeconds = ExpireNever;
  77. #ifdef MMKV_APPLE
  78. using MMKVKey_t = NSString *__unsafe_unretained;
  79. static bool isKeyEmpty(MMKVKey_t key) { return key.length <= 0; }
  80. # define key_length(key) key.length
  81. # define retain_key(key) [key retain]
  82. # define release_key(key) [key release]
  83. #else
  84. using MMKVKey_t = const std::string &;
  85. static bool isKeyEmpty(MMKVKey_t key) { return key.empty(); }
  86. # define key_length(key) key.length()
  87. # define retain_key(key) ((void)0)
  88. # define release_key(key) ((void)0)
  89. #endif
  90. void loadFromFile();
  91. void partialLoadFromFile();
  92. void loadMetaInfoAndCheck();
  93. void checkDataValid(bool &loadFromFile, bool &needFullWriteback);
  94. void checkLoadData();
  95. bool isFileValid();
  96. bool checkFileCRCValid(size_t actualSize, uint32_t crcDigest);
  97. void recaculateCRCDigestWithIV(const void *iv);
  98. void updateCRCDigest(const uint8_t *ptr, size_t length);
  99. size_t readActualSize();
  100. void oldStyleWriteActualSize(size_t actualSize);
  101. bool writeActualSize(size_t size, uint32_t crcDigest, const void *iv, bool increaseSequence);
  102. bool ensureMemorySize(size_t newSize);
  103. bool expandAndWriteBack(size_t newSize, std::pair<mmkv::MMBuffer, size_t> preparedData, bool needSync = true);
  104. bool fullWriteback(mmkv::AESCrypt *newCrypter = nullptr, bool onlyWhileExpire = false);
  105. bool doFullWriteBack(std::pair<mmkv::MMBuffer, size_t> preparedData, mmkv::AESCrypt *newCrypter, bool needSync = true);
  106. bool doFullWriteBack(mmkv::MMKVVector &&vec);
  107. mmkv::MMBuffer getRawDataForKey(MMKVKey_t key);
  108. mmkv::MMBuffer getDataForKey(MMKVKey_t key);
  109. // isDataHolder: avoid memory copying
  110. bool setDataForKey(mmkv::MMBuffer &&data, MMKVKey_t key, bool isDataHolder = false);
  111. bool removeDataForKey(MMKVKey_t key);
  112. using KVHolderRet_t = std::pair<bool, mmkv::KeyValueHolder>;
  113. // isDataHolder: avoid memory copying
  114. KVHolderRet_t doAppendDataWithKey(const mmkv::MMBuffer &data, const mmkv::MMBuffer &key, bool isDataHolder, uint32_t keyLength);
  115. KVHolderRet_t appendDataWithKey(const mmkv::MMBuffer &data, MMKVKey_t key, bool isDataHolder = false);
  116. KVHolderRet_t appendDataWithKey(const mmkv::MMBuffer &data, const mmkv::KeyValueHolder &kvHolder, bool isDataHolder = false);
  117. #ifdef MMKV_APPLE
  118. KVHolderRet_t appendDataWithKey(const mmkv::MMBuffer &data,
  119. MMKVKey_t key,
  120. const mmkv::KeyValueHolderCrypt &kvHolder,
  121. bool isDataHolder = false);
  122. #endif
  123. void notifyContentChanged();
  124. #if defined(MMKV_ANDROID) && !defined(MMKV_DISABLE_CRYPT)
  125. void checkReSetCryptKey(int fd, int metaFD, std::string *cryptKey);
  126. #endif
  127. static bool backupOneToDirectory(const std::string &mmapKey, const MMKVPath_t &dstPath, const MMKVPath_t &srcPath, bool compareFullPath);
  128. static size_t backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t &srcDir, bool isInSpecialDir);
  129. static bool restoreOneFromDirectory(const std::string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath, bool compareFullPath);
  130. static size_t restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t &dstDir, bool isInSpecialDir);
  131. static uint32_t getCurrentTimeInSecond();
  132. uint32_t getExpireTimeForKey(MMKVKey_t key);
  133. mmkv::MMBuffer getDataWithoutMTimeForKey(MMKVKey_t key);
  134. size_t filterExpiredKeys();
  135. public:
  136. // call this before getting any MMKV instance
  137. static void initializeMMKV(const MMKVPath_t &rootDir, MMKVLogLevel logLevel = MMKVLogInfo, mmkv::LogHandler handler = nullptr);
  138. #ifdef MMKV_APPLE
  139. // protect from some old code that don't call initializeMMKV()
  140. static void minimalInit(MMKVPath_t defaultRootDir);
  141. #endif
  142. // a generic purpose instance
  143. static MMKV *defaultMMKV(MMKVMode mode = MMKV_SINGLE_PROCESS, std::string *cryptKey = nullptr);
  144. #ifndef MMKV_ANDROID
  145. // mmapID: any unique ID (com.tencent.xin.pay, etc)
  146. // if you want a per-user mmkv, you could merge user-id within mmapID
  147. // cryptKey: 16 bytes at most
  148. static MMKV *mmkvWithID(const std::string &mmapID,
  149. MMKVMode mode = MMKV_SINGLE_PROCESS,
  150. std::string *cryptKey = nullptr,
  151. MMKVPath_t *rootPath = nullptr);
  152. #else // defined(MMKV_ANDROID)
  153. // mmapID: any unique ID (com.tencent.xin.pay, etc)
  154. // if you want a per-user mmkv, you could merge user-id within mmapID
  155. // cryptKey: 16 bytes at most
  156. static MMKV *mmkvWithID(const std::string &mmapID,
  157. int size = mmkv::DEFAULT_MMAP_SIZE,
  158. MMKVMode mode = MMKV_SINGLE_PROCESS,
  159. std::string *cryptKey = nullptr,
  160. MMKVPath_t *rootPath = nullptr);
  161. static MMKV *mmkvWithAshmemFD(const std::string &mmapID, int fd, int metaFD, std::string *cryptKey = nullptr);
  162. int ashmemFD();
  163. int ashmemMetaFD();
  164. bool checkProcessMode();
  165. #endif // MMKV_ANDROID
  166. // you can call this on application termination, it's totally fine if you don't call
  167. static void onExit();
  168. const std::string &mmapID() const;
  169. const bool m_isInterProcess;
  170. #ifndef MMKV_DISABLE_CRYPT
  171. std::string cryptKey() const;
  172. // transform plain text into encrypted text, or vice versa with empty cryptKey
  173. // you can change existing crypt key with different cryptKey
  174. bool reKey(const std::string &cryptKey);
  175. // just reset cryptKey (will not encrypt or decrypt anything)
  176. // usually you should call this method after other process reKey() the multi-process mmkv
  177. void checkReSetCryptKey(const std::string *cryptKey);
  178. #endif
  179. bool set(bool value, MMKVKey_t key);
  180. bool set(bool value, MMKVKey_t key, uint32_t expireDuration);
  181. bool set(int32_t value, MMKVKey_t key);
  182. bool set(int32_t value, MMKVKey_t key, uint32_t expireDuration);
  183. bool set(uint32_t value, MMKVKey_t key);
  184. bool set(uint32_t value, MMKVKey_t key, uint32_t expireDuration);
  185. bool set(int64_t value, MMKVKey_t key);
  186. bool set(int64_t value, MMKVKey_t key, uint32_t expireDuration);
  187. bool set(uint64_t value, MMKVKey_t key);
  188. bool set(uint64_t value, MMKVKey_t key, uint32_t expireDuration);
  189. bool set(float value, MMKVKey_t key);
  190. bool set(float value, MMKVKey_t key, uint32_t expireDuration);
  191. bool set(double value, MMKVKey_t key);
  192. bool set(double value, MMKVKey_t key, uint32_t expireDuration);
  193. // avoid unexpected type conversion (pointer to bool, etc)
  194. template <typename T>
  195. bool set(T value, MMKVKey_t key) = delete;
  196. template <typename T>
  197. bool set(T value, MMKVKey_t key, uint32_t expireDuration) = delete;
  198. #ifdef MMKV_APPLE
  199. bool set(NSObject<NSCoding> *__unsafe_unretained obj, MMKVKey_t key);
  200. bool set(NSObject<NSCoding> *__unsafe_unretained obj, MMKVKey_t key, uint32_t expireDuration);
  201. NSObject *getObject(MMKVKey_t key, Class cls);
  202. #else // !defined(MMKV_APPLE)
  203. bool set(const char *value, MMKVKey_t key);
  204. bool set(const char *value, MMKVKey_t key, uint32_t expireDuration);
  205. bool set(const std::string &value, MMKVKey_t key);
  206. bool set(const std::string &value, MMKVKey_t key, uint32_t expireDuration);
  207. bool set(const mmkv::MMBuffer &value, MMKVKey_t key);
  208. bool set(const mmkv::MMBuffer &value, MMKVKey_t key, uint32_t expireDuration);
  209. bool set(const std::vector<std::string> &vector, MMKVKey_t key);
  210. bool set(const std::vector<std::string> &vector, MMKVKey_t key, uint32_t expireDuration);
  211. bool getString(MMKVKey_t key, std::string &result);
  212. mmkv::MMBuffer getBytes(MMKVKey_t key);
  213. bool getBytes(MMKVKey_t key, mmkv::MMBuffer &result);
  214. bool getVector(MMKVKey_t key, std::vector<std::string> &result);
  215. #endif // MMKV_APPLE
  216. bool getBool(MMKVKey_t key, bool defaultValue = false, OUT bool *hasValue = nullptr);
  217. int32_t getInt32(MMKVKey_t key, int32_t defaultValue = 0, OUT bool *hasValue = nullptr);
  218. uint32_t getUInt32(MMKVKey_t key, uint32_t defaultValue = 0, OUT bool *hasValue = nullptr);
  219. int64_t getInt64(MMKVKey_t key, int64_t defaultValue = 0, OUT bool *hasValue = nullptr);
  220. uint64_t getUInt64(MMKVKey_t key, uint64_t defaultValue = 0, OUT bool *hasValue = nullptr);
  221. float getFloat(MMKVKey_t key, float defaultValue = 0, OUT bool *hasValue = nullptr);
  222. double getDouble(MMKVKey_t key, double defaultValue = 0, OUT bool *hasValue = nullptr);
  223. // return the actual size consumption of the key's value
  224. // pass actualSize = true to get value's length
  225. size_t getValueSize(MMKVKey_t key, bool actualSize);
  226. // return size written into buffer
  227. // return -1 on any error
  228. int32_t writeValueToBuffer(MMKVKey_t key, void *ptr, int32_t size);
  229. bool containsKey(MMKVKey_t key);
  230. // filterExpire: return count of all non-expired keys, keep in mind it comes with cost
  231. size_t count(bool filterExpire = false);
  232. size_t totalSize();
  233. size_t actualSize();
  234. static constexpr uint32_t ExpireNever = 0;
  235. // all keys created (or last modified) longer than expiredInSeconds will be deleted on next full-write-back
  236. // expiredInSeconds = MMKV::ExpireNever (0) means no common expiration duration for all keys, aka each key will have it's own expiration duration
  237. bool enableAutoKeyExpire(uint32_t expiredInSeconds = 0);
  238. bool disableAutoKeyExpire();
  239. #ifdef MMKV_APPLE
  240. // filterExpire: return all non-expired keys, keep in mind it comes with cost
  241. NSArray *allKeys(bool filterExpire = false);
  242. void removeValuesForKeys(NSArray *arrKeys);
  243. typedef void (^EnumerateBlock)(NSString *key, BOOL *stop);
  244. void enumerateKeys(EnumerateBlock block);
  245. # ifdef MMKV_IOS
  246. static void setIsInBackground(bool isInBackground);
  247. static bool isInBackground();
  248. # endif
  249. #else // !defined(MMKV_APPLE)
  250. // filterExpire: return all non-expired keys, keep in mind it comes with cost
  251. std::vector<std::string> allKeys(bool filterExpire = false);
  252. void removeValuesForKeys(const std::vector<std::string> &arrKeys);
  253. #endif // MMKV_APPLE
  254. void removeValueForKey(MMKVKey_t key);
  255. void clearAll();
  256. // MMKV's size won't reduce after deleting key-values
  257. // call this method after lots of deleting if you care about disk usage
  258. // note that `clearAll` has the similar effect of `trim`
  259. void trim();
  260. // call this method if the instance is no longer needed in the near future
  261. // any subsequent call to the instance is undefined behavior
  262. void close();
  263. // call this method if you are facing memory-warning
  264. // any subsequent call to the instance will load all key-values from file again
  265. void clearMemoryCache();
  266. // you don't need to call this, really, I mean it
  267. // unless you worry about running out of battery
  268. void sync(SyncFlag flag = MMKV_SYNC);
  269. // get exclusive access
  270. void lock();
  271. void unlock();
  272. bool try_lock();
  273. static const MMKVPath_t &getRootDir();
  274. // backup one MMKV instance from srcDir to dstDir
  275. // if srcDir is null, then backup from the root dir of MMKV
  276. static bool backupOneToDirectory(const std::string &mmapID, const MMKVPath_t &dstDir, const MMKVPath_t *srcDir = nullptr);
  277. // restore one MMKV instance from srcDir to dstDir
  278. // if dstDir is null, then restore to the root dir of MMKV
  279. static bool restoreOneFromDirectory(const std::string &mmapID, const MMKVPath_t &srcDir, const MMKVPath_t *dstDir = nullptr);
  280. // backup all MMKV instance from srcDir to dstDir
  281. // if srcDir is null, then backup from the root dir of MMKV
  282. // return count of MMKV successfully backuped
  283. static size_t backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t *srcDir = nullptr);
  284. // restore all MMKV instance from srcDir to dstDir
  285. // if dstDir is null, then restore to the root dir of MMKV
  286. // return count of MMKV successfully restored
  287. static size_t restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t *dstDir = nullptr);
  288. // check if content been changed by other process
  289. void checkContentChanged();
  290. // called when content is changed by other process
  291. // doesn't guarantee real-time notification
  292. static void registerContentChangeHandler(mmkv::ContentChangeHandler handler);
  293. static void unRegisterContentChangeHandler();
  294. // by default MMKV will discard all datas on failure
  295. // return `OnErrorRecover` to recover any data from file
  296. static void registerErrorHandler(mmkv::ErrorHandler handler);
  297. static void unRegisterErrorHandler();
  298. // MMKVLogInfo by default
  299. // pass MMKVLogNone to disable all logging
  300. static void setLogLevel(MMKVLogLevel level);
  301. // by default MMKV will print log to the console
  302. // implement this method to redirect MMKV's log
  303. static void registerLogHandler(mmkv::LogHandler handler);
  304. static void unRegisterLogHandler();
  305. // detect if the MMKV file is valid or not
  306. // Note: Don't use this to check the existence of the instance, the return value is undefined if the file was never created.
  307. static bool isFileValid(const std::string &mmapID, MMKVPath_t *relatePath = nullptr);
  308. // just forbid it for possibly misuse
  309. explicit MMKV(const MMKV &other) = delete;
  310. MMKV &operator=(const MMKV &other) = delete;
  311. };
  312. MMKV_NAMESPACE_END
  313. #endif
  314. #endif // MMKV_MMKV_H