12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799 |
- /*
- * Tencent is pleased to support the open source community by making
- * MMKV available.
- *
- * Copyright (C) 2018 THL A29 Limited, a Tencent company.
- * All rights reserved.
- *
- * Licensed under the BSD 3-Clause License (the "License"); you may not use
- * this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * https://opensource.org/licenses/BSD-3-Clause
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "CodedInputData.h"
- #include "CodedOutputData.h"
- #include "InterProcessLock.h"
- #include "KeyValueHolder.h"
- #include "MMBuffer.h"
- #include "MMKVLog.h"
- #include "MMKVMetaInfo.hpp"
- #include "MMKV_IO.h"
- #include "MMKV_OSX.h"
- #include "MemoryFile.h"
- #include "MiniPBCoder.h"
- #include "PBUtility.h"
- #include "ScopedLock.hpp"
- #include "ThreadLock.h"
- #include "aes/AESCrypt.h"
- #include "aes/openssl/openssl_aes.h"
- #include "aes/openssl/openssl_md5.h"
- #include "crc32/Checksum.h"
- #include <algorithm>
- #include <cstdio>
- #include <cstring>
- #include <unordered_set>
- #include <cassert>
- #if defined(__aarch64__) && defined(__linux__) && !defined (MMKV_OHOS)
- # include <asm/hwcap.h>
- # include <sys/auxv.h>
- #endif
- #ifdef MMKV_APPLE
- # if __has_feature(objc_arc)
- # error This file must be compiled with MRC. Use -fno-objc-arc flag.
- # endif
- # include "MMKV_OSX.h"
- #endif // MMKV_APPLE
- using namespace std;
- using namespace mmkv;
- unordered_map<string, MMKV *> *g_instanceDic;
- ThreadLock *g_instanceLock;
- MMKVPath_t g_rootDir;
- MMKVPath_t g_realRootDir;
- static ThreadLock *g_namespaceLock;
- static unordered_map<MMKVPath_t, MMKVPath_t> g_realRootMap;
- static mmkv::ErrorHandler g_errorHandler;
- size_t mmkv::DEFAULT_MMAP_SIZE;
- #ifndef MMKV_WIN32
- constexpr auto SPECIAL_CHARACTER_DIRECTORY_NAME = "specialCharacter";
- constexpr auto CRC_SUFFIX = ".crc";
- #else
- constexpr auto SPECIAL_CHARACTER_DIRECTORY_NAME = L"specialCharacter";
- constexpr auto CRC_SUFFIX = L".crc";
- #endif
- MMKV_NAMESPACE_BEGIN
- static MMKVPath_t encodeFilePath(const string &mmapID, const MMKVPath_t &rootDir);
- bool endsWith(const MMKVPath_t &str, const MMKVPath_t &suffix);
- MMKVPath_t filename(const MMKVPath_t &path);
- #ifndef MMKV_ANDROID
- MMKV::MMKV(const string &mmapID, MMKVMode mode, const string *cryptKey, const MMKVPath_t *rootPath, size_t expectedCapacity)
- : m_mmapID(mmapID)
- , m_mode(mode)
- , m_path(mappedKVPathWithID(m_mmapID, rootPath))
- , m_crcPath(crcPathWithPath(m_path))
- , m_dic(nullptr)
- , m_dicCrypt(nullptr)
- , m_expectedCapacity(std::max<size_t>(DEFAULT_MMAP_SIZE, roundUp<size_t>(expectedCapacity, DEFAULT_MMAP_SIZE)))
- , m_file(new MemoryFile(m_path, m_expectedCapacity, isReadOnly(), true))
- , m_metaFile(new MemoryFile(m_crcPath, 0, isReadOnly(), !isMultiProcess()))
- , m_metaInfo(new MMKVMetaInfo())
- , m_crypter(nullptr)
- , m_lock(new ThreadLock())
- , m_fileLock(new FileLock(isMultiProcess() ? m_metaFile->getFd() : MMKVFileHandleInvalidValue))
- , m_sharedProcessLock(new InterProcessLock(m_fileLock, SharedLockType))
- , m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType))
- {
- m_actualSize = 0;
- m_output = nullptr;
- # ifndef MMKV_DISABLE_CRYPT
- if (cryptKey && !cryptKey->empty()) {
- m_dicCrypt = new MMKVMapCrypt();
- m_crypter = new AESCrypt(cryptKey->data(), cryptKey->length());
- } else {
- m_dic = new MMKVMap();
- }
- # else
- m_dic = new MMKVMap();
- # endif
- m_needLoadFromFile = true;
- m_hasFullWriteback = false;
- m_crcDigest = 0;
- m_lock->initialize();
- m_sharedProcessLock->m_enable = isMultiProcess();
- m_exclusiveProcessLock->m_enable = isMultiProcess();
- // sensitive zone
- /*{
- SCOPED_LOCK(m_sharedProcessLock);
- loadFromFile();
- }*/
- }
- #endif
- MMKV::~MMKV() {
- clearMemoryCache();
- delete m_dic;
- #ifndef MMKV_DISABLE_CRYPT
- delete m_dicCrypt;
- delete m_crypter;
- #endif
- delete m_metaInfo;
- delete m_lock;
- delete m_fileLock;
- delete m_sharedProcessLock;
- delete m_exclusiveProcessLock;
- #ifdef MMKV_ANDROID
- #ifndef MMKV_OHOS
- delete m_sharedProcessModeLock;
- delete m_exclusiveProcessModeLock;
- delete m_fileModeLock;
- #endif // !MMKV_OHOS
- delete m_sharedMigrationLock;
- delete m_fileMigrationLock;
- #endif // MMKV_ANDROID
- delete m_metaFile;
- delete m_file;
- MMKVInfo("destruct [%s]", m_mmapID.c_str());
- }
- MMKV *MMKV::defaultMMKV(MMKVMode mode, const string *cryptKey) {
- #ifndef MMKV_ANDROID
- return mmkvWithID(DEFAULT_MMAP_ID, mode, cryptKey);
- #else
- return mmkvWithID(DEFAULT_MMAP_ID, DEFAULT_MMAP_SIZE, mode, cryptKey);
- #endif
- }
- static void initialize() {
- g_instanceDic = new unordered_map<string, MMKV *>;
- g_instanceLock = new ThreadLock();
- g_instanceLock->initialize();
- mmkv::DEFAULT_MMAP_SIZE = mmkv::getPageSize();
- MMKVInfo("version %s, page size %d, arch %s", MMKV_VERSION, DEFAULT_MMAP_SIZE, MMKV_ABI);
- // get CPU status of ARMv8 extensions (CRC32, AES)
- #if defined(__aarch64__) && defined(__linux__) && !defined (MMKV_OHOS)
- auto hwcaps = getauxval(AT_HWCAP);
- # ifndef MMKV_DISABLE_CRYPT
- if (hwcaps & HWCAP_AES) {
- openssl::AES_set_encrypt_key = openssl_aes_arm_set_encrypt_key;
- openssl::AES_set_decrypt_key = openssl_aes_arm_set_decrypt_key;
- openssl::AES_encrypt = openssl_aes_arm_encrypt;
- openssl::AES_decrypt = openssl_aes_arm_decrypt;
- MMKVInfo("armv8 AES instructions is supported");
- } else {
- MMKVInfo("armv8 AES instructions is not supported");
- }
- # endif // MMKV_DISABLE_CRYPT
- # ifdef MMKV_USE_ARMV8_CRC32
- if (hwcaps & HWCAP_CRC32) {
- CRC32 = mmkv::armv8_crc32;
- MMKVInfo("armv8 CRC32 instructions is supported");
- } else {
- MMKVInfo("armv8 CRC32 instructions is not supported");
- }
- # endif // MMKV_USE_ARMV8_CRC32
- #endif // __aarch64__ && defined(__linux__) && !defined (MMKV_OHOS)
- #if defined(MMKV_DEBUG) && !defined(MMKV_DISABLE_CRYPT)
- // AESCrypt::testAESCrypt();
- // KeyValueHolderCrypt::testAESToMMBuffer();
- #endif
- }
- static void ensureMinimalInitialize() {
- static ThreadOnceToken_t once_control = ThreadOnceUninitialized;
- ThreadLock::ThreadOnce(&once_control, initialize);
- }
- void MMKV::initializeMMKV(const MMKVPath_t &rootDir, MMKVLogLevel logLevel, mmkv::LogHandler handler) {
- g_currentLogLevel = logLevel;
- g_logHandler = handler;
- ensureMinimalInitialize();
- #ifdef MMKV_APPLE
- // crc32 instruction requires A10 chip, aka iPhone 7 or iPad 6th generation
- int device = 0, version = 0;
- GetAppleMachineInfo(device, version);
- MMKVInfo("Apple Device: %d, version: %d", device, version);
- #endif
- if (g_rootDir.empty()) {
- g_rootDir = rootDir;
- // avoid operating g_realRootMap directly
- g_realRootDir = nameSpace(rootDir).getRootDir();
- mkPath(g_realRootDir);
- }
- MMKVInfo("root dir: " MMKV_PATH_FORMAT, g_realRootDir.c_str());
- }
- const MMKVPath_t &MMKV::getRootDir() {
- // for backword consistency we can't return g_realRootDir
- return g_rootDir;
- }
- #ifndef MMKV_ANDROID
- MMKV *MMKV::mmkvWithID(const string &mmapID, MMKVMode mode, const string *cryptKey, const MMKVPath_t *rootPath, size_t expectedCapacity) {
- if (mmapID.empty() || !g_instanceLock) {
- return nullptr;
- }
- SCOPED_LOCK(g_instanceLock);
- auto mmapKey = mmapedKVKey(mmapID, rootPath);
- auto itr = g_instanceDic->find(mmapKey);
- if (itr != g_instanceDic->end()) {
- MMKV *kv = itr->second;
- return kv;
- }
- if (rootPath && !(mode & MMKV_READ_ONLY)) {
- MMKVPath_t specialPath = (*rootPath) + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
- if (!isFileExist(specialPath)) {
- mkPath(specialPath);
- }
- }
- auto theRootDir = rootPath ? rootPath : &g_realRootDir;
- #ifdef MMKV_WIN32
- MMKVInfo("prepare to load %s (id %s) from rootPath %ls", mmapID.c_str(), mmapKey.c_str(), theRootDir->c_str());
- #else
- MMKVInfo("prepare to load %s (id %s) from rootPath %s", mmapID.c_str(), mmapKey.c_str(), theRootDir->c_str());
- #endif
- auto kv = new MMKV(mmapID, mode, cryptKey, rootPath, expectedCapacity);
- kv->m_mmapKey = mmapKey;
- (*g_instanceDic)[mmapKey] = kv;
- return kv;
- }
- #endif
- void MMKV::onExit() {
- if (!g_instanceLock) {
- return;
- }
- SCOPED_LOCK(g_instanceLock);
- for (auto &pair : *g_instanceDic) {
- MMKV *kv = pair.second;
- kv->sync();
- kv->clearMemoryCache();
- delete kv;
- pair.second = nullptr;
- }
- delete g_instanceDic;
- g_instanceDic = nullptr;
- }
- const string &MMKV::mmapID() const {
- return m_mmapID;
- }
- mmkv::ContentChangeHandler g_contentChangeHandler = nullptr;
- void MMKV::notifyContentChanged() {
- if (g_contentChangeHandler) {
- g_contentChangeHandler(m_mmapID);
- }
- }
- void MMKV::checkContentChanged() {
- SCOPED_LOCK(m_lock);
- checkLoadData();
- }
- void MMKV::registerContentChangeHandler(mmkv::ContentChangeHandler handler) {
- g_contentChangeHandler = handler;
- }
- void MMKV::unRegisterContentChangeHandler() {
- g_contentChangeHandler = nullptr;
- }
- void MMKV::clearMemoryCache(bool keepSpace) {
- SCOPED_LOCK(m_lock);
- if (m_needLoadFromFile) {
- return;
- }
- MMKVInfo("clearMemoryCache [%s]", m_mmapID.c_str());
- m_needLoadFromFile = true;
- m_hasFullWriteback = false;
- clearDictionary(m_dic);
- #ifndef MMKV_DISABLE_CRYPT
- clearDictionary(m_dicCrypt);
- if (m_crypter) {
- if (m_metaInfo->m_version >= MMKVVersionRandomIV) {
- m_crypter->resetIV(m_metaInfo->m_vector, sizeof(m_metaInfo->m_vector));
- } else {
- m_crypter->resetIV();
- }
- }
- #endif
- delete m_output;
- m_output = nullptr;
- if (!keepSpace) {
- m_file->clearMemoryCache();
- }
- // inter-process lock rely on MetaFile's fd, never close it
- // m_metaFile->clearMemoryCache();
- m_actualSize = 0;
- m_metaInfo->m_crcDigest = 0;
- }
- void MMKV::close() {
- MMKVInfo("close [%s]", m_mmapID.c_str());
- SCOPED_LOCK(g_instanceLock);
- m_lock->lock();
- auto itr = g_instanceDic->find(m_mmapKey);
- if (itr != g_instanceDic->end()) {
- g_instanceDic->erase(itr);
- }
- delete this;
- }
- #ifndef MMKV_DISABLE_CRYPT
- string MMKV::cryptKey() const {
- SCOPED_LOCK(m_lock);
- if (m_crypter) {
- char key[AES_KEY_LEN];
- m_crypter->getKey(key);
- return {key, strnlen(key, AES_KEY_LEN)};
- }
- return "";
- }
- void MMKV::checkReSetCryptKey(const string *cryptKey) {
- SCOPED_LOCK(m_lock);
- if (m_crypter) {
- if (cryptKey && !cryptKey->empty()) {
- string oldKey = this->cryptKey();
- if (oldKey != *cryptKey) {
- MMKVInfo("setting new aes key");
- delete m_crypter;
- auto ptr = cryptKey->data();
- m_crypter = new AESCrypt(ptr, cryptKey->length());
- checkLoadData();
- } else {
- // nothing to do
- }
- } else {
- MMKVInfo("reset aes key");
- delete m_crypter;
- m_crypter = nullptr;
- checkLoadData();
- }
- } else {
- if (cryptKey && !cryptKey->empty()) {
- MMKVInfo("setting new aes key");
- auto ptr = cryptKey->data();
- m_crypter = new AESCrypt(ptr, cryptKey->length());
- checkLoadData();
- } else {
- // nothing to do
- }
- }
- }
- #endif // MMKV_DISABLE_CRYPT
- bool MMKV::isFileValid() {
- return m_file->isFileValid();
- }
- // crc
- // assuming m_file is valid
- bool MMKV::checkFileCRCValid(size_t actualSize, uint32_t crcDigest) {
- auto ptr = (uint8_t *) m_file->getMemory();
- if (ptr) {
- m_crcDigest = (uint32_t) CRC32(0, (const uint8_t *) ptr + Fixed32Size, (uint32_t) actualSize);
- if (m_crcDigest == crcDigest) {
- return true;
- }
- MMKVError("check crc [%s] fail, crc32:%u, m_crcDigest:%u", m_mmapID.c_str(), crcDigest, m_crcDigest);
- }
- return false;
- }
- void MMKV::recalculateCRCDigestWithIV(const void *iv) {
- auto ptr = (const uint8_t *) m_file->getMemory();
- if (ptr) {
- m_crcDigest = 0;
- m_crcDigest = (uint32_t) CRC32(0, ptr + Fixed32Size, (uint32_t) m_actualSize);
- writeActualSize(m_actualSize, m_crcDigest, iv, IncreaseSequence);
- }
- }
- void MMKV::recalculateCRCDigestOnly() {
- auto ptr = (const uint8_t *) m_file->getMemory();
- if (ptr) {
- m_crcDigest = 0;
- m_crcDigest = (uint32_t) CRC32(0, ptr + Fixed32Size, (uint32_t) m_actualSize);
- writeActualSize(m_actualSize, m_crcDigest, nullptr, KeepSequence);
- }
- }
- void MMKV::updateCRCDigest(const uint8_t *ptr, size_t length) {
- if (ptr == nullptr) {
- return;
- }
- m_crcDigest = (uint32_t) CRC32(m_crcDigest, ptr, (uint32_t) length);
- writeActualSize(m_actualSize, m_crcDigest, nullptr, KeepSequence);
- }
- // set & get
- bool MMKV::set(bool value, MMKVKey_t key) {
- return set(value, key, m_expiredInSeconds);
- }
- bool MMKV::set(bool value, MMKVKey_t key, uint32_t expireDuration) {
- if (isKeyEmpty(key)) {
- return false;
- }
- size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbBoolSize() : pbBoolSize();
- MMBuffer data(size);
- CodedOutputData output(data.getPtr(), size);
- output.writeBool(value);
- if (mmkv_unlikely(m_enableKeyExpire)) {
- auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
- output.writeRawLittleEndian32(UInt32ToInt32(time));
- } else {
- assert(expireDuration == ExpireNever && "setting expire duration without calling enableAutoKeyExpire() first");
- }
- return setDataForKey(std::move(data), key);
- }
- bool MMKV::set(int32_t value, MMKVKey_t key) {
- return set(value, key, m_expiredInSeconds);
- }
- bool MMKV::set(int32_t value, MMKVKey_t key, uint32_t expireDuration) {
- if (isKeyEmpty(key)) {
- return false;
- }
- size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbInt32Size(value) : pbInt32Size(value);
- MMBuffer data(size);
- CodedOutputData output(data.getPtr(), size);
- output.writeInt32(value);
- if (mmkv_unlikely(m_enableKeyExpire)) {
- auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
- output.writeRawLittleEndian32(UInt32ToInt32(time));
- } else {
- assert(expireDuration == ExpireNever && "setting expire duration without calling enableAutoKeyExpire() first");
- }
- return setDataForKey(std::move(data), key);
- }
- bool MMKV::set(uint32_t value, MMKVKey_t key) {
- return set(value, key, m_expiredInSeconds);
- }
- bool MMKV::set(uint32_t value, MMKVKey_t key, uint32_t expireDuration) {
- if (isKeyEmpty(key)) {
- return false;
- }
- size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbUInt32Size(value) : pbUInt32Size(value);
- MMBuffer data(size);
- CodedOutputData output(data.getPtr(), size);
- output.writeUInt32(value);
- if (mmkv_unlikely(m_enableKeyExpire)) {
- auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
- output.writeRawLittleEndian32(UInt32ToInt32(time));
- } else {
- assert(expireDuration == ExpireNever && "setting expire duration without calling enableAutoKeyExpire() first");
- }
- return setDataForKey(std::move(data), key);
- }
- bool MMKV::set(int64_t value, MMKVKey_t key) {
- return set(value, key, m_expiredInSeconds);
- }
- bool MMKV::set(int64_t value, MMKVKey_t key, uint32_t expireDuration) {
- if (isKeyEmpty(key)) {
- return false;
- }
- size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbInt64Size(value) : pbInt64Size(value);
- MMBuffer data(size);
- CodedOutputData output(data.getPtr(), size);
- output.writeInt64(value);
- if (mmkv_unlikely(m_enableKeyExpire)) {
- auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
- output.writeRawLittleEndian32(UInt32ToInt32(time));
- } else {
- assert(expireDuration == ExpireNever && "setting expire duration without calling enableAutoKeyExpire() first");
- }
- return setDataForKey(std::move(data), key);
- }
- bool MMKV::set(uint64_t value, MMKVKey_t key) {
- return set(value, key, m_expiredInSeconds);
- }
- bool MMKV::set(uint64_t value, MMKVKey_t key, uint32_t expireDuration) {
- if (isKeyEmpty(key)) {
- return false;
- }
- size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbUInt64Size(value) : pbUInt64Size(value);
- MMBuffer data(size);
- CodedOutputData output(data.getPtr(), size);
- output.writeUInt64(value);
- if (mmkv_unlikely(m_enableKeyExpire)) {
- auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
- output.writeRawLittleEndian32(UInt32ToInt32(time));
- } else {
- assert(expireDuration == ExpireNever && "setting expire duration without calling enableAutoKeyExpire() first");
- }
- return setDataForKey(std::move(data), key);
- }
- bool MMKV::set(float value, MMKVKey_t key) {
- return set(value, key, m_expiredInSeconds);
- }
- bool MMKV::set(float value, MMKVKey_t key, uint32_t expireDuration) {
- if (isKeyEmpty(key)) {
- return false;
- }
- size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbFloatSize() : pbFloatSize();
- MMBuffer data(size);
- CodedOutputData output(data.getPtr(), size);
- output.writeFloat(value);
- if (mmkv_unlikely(m_enableKeyExpire)) {
- auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
- output.writeRawLittleEndian32(UInt32ToInt32(time));
- } else {
- assert(expireDuration == ExpireNever && "setting expire duration without calling enableAutoKeyExpire() first");
- }
- return setDataForKey(std::move(data), key);
- }
- bool MMKV::set(double value, MMKVKey_t key) {
- return set(value, key, m_expiredInSeconds);
- }
- bool MMKV::set(double value, MMKVKey_t key, uint32_t expireDuration) {
- if (isKeyEmpty(key)) {
- return false;
- }
- size_t size = mmkv_unlikely(m_enableKeyExpire) ? Fixed32Size + pbDoubleSize() : pbDoubleSize();
- MMBuffer data(size);
- CodedOutputData output(data.getPtr(), size);
- output.writeDouble(value);
- if (mmkv_unlikely(m_enableKeyExpire)) {
- auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
- output.writeRawLittleEndian32(UInt32ToInt32(time));
- } else {
- assert(expireDuration == ExpireNever && "setting expire duration without calling enableAutoKeyExpire() first");
- }
- return setDataForKey(std::move(data), key);
- }
- bool MMKV::setDataForKey(mmkv::MMBuffer &&data, MMKV::MMKVKey_t key, uint32_t expireDuration) {
- if (mmkv_likely(!m_enableKeyExpire)) {
- assert(expireDuration == ExpireNever && "setting expire duration without calling enableAutoKeyExpire() first");
- return setDataForKey(std::move(data), key, true);
- } else {
- auto tmp = MMBuffer(pbMMBufferSize(data) + Fixed32Size);
- CodedOutputData output(tmp.getPtr(), tmp.length());
- output.writeData(data);
- auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
- output.writeRawLittleEndian32(UInt32ToInt32(time));
- return setDataForKey(std::move(tmp), key);
- }
- }
- bool MMKV::set(const char *value, MMKVKey_t key) {
- return set(value, key, m_expiredInSeconds);
- }
- bool MMKV::set(const char *value, MMKVKey_t key, uint32_t expireDuration) {
- if (!value) {
- removeValueForKey(key);
- return true;
- }
- return setDataForKey(MMBuffer((void *) value, strlen(value), MMBufferNoCopy), key, expireDuration);
- }
- bool MMKV::set(const string &value, MMKVKey_t key) {
- return set(value, key, m_expiredInSeconds);
- }
- bool MMKV::set(const string &value, MMKVKey_t key, uint32_t expireDuration) {
- if (isKeyEmpty(key)) {
- return false;
- }
- return setDataForKey(MMBuffer((void *) value.data(), value.length(), MMBufferNoCopy), key, expireDuration);
- }
- bool MMKV::set(string_view value, MMKVKey_t key) {
- return set(value, key, m_expiredInSeconds);
- }
- bool MMKV::set(string_view value, MMKVKey_t key, uint32_t expireDuration) {
- if (isKeyEmpty(key)) {
- return false;
- }
- return setDataForKey(MMBuffer((void *) value.data(), value.length(), MMBufferNoCopy), key, expireDuration);
- }
- bool MMKV::set(const MMBuffer &value, MMKVKey_t key) {
- return set(value, key, m_expiredInSeconds);
- }
- bool MMKV::set(const MMBuffer &value, MMKVKey_t key, uint32_t expireDuration) {
- if (isKeyEmpty(key)) {
- return false;
- }
- return setDataForKey(MMBuffer(value.getPtr(), value.length(), MMBufferNoCopy), key, expireDuration);
- }
- bool MMKV::set(const vector<string> &value, MMKVKey_t key) {
- return set(value, key, m_expiredInSeconds);
- }
- bool MMKV::set(const vector<string> &v, MMKVKey_t key, uint32_t expireDuration) {
- if (isKeyEmpty(key)) {
- return false;
- }
- #ifdef MMKV_HAS_CPP20
- auto data = MiniPBCoder::encodeDataWithObject(std::span(v));
- #else
- auto data = MiniPBCoder::encodeDataWithObject(v);
- #endif
- if (mmkv_unlikely(m_enableKeyExpire) && data.length() > 0) {
- auto tmp = MMBuffer(data.length() + Fixed32Size);
- auto ptr = (uint8_t *) tmp.getPtr();
- memcpy(ptr, data.getPtr(), data.length());
- auto time = (expireDuration != ExpireNever) ? getCurrentTimeInSecond() + expireDuration : ExpireNever;
- memcpy(ptr + data.length(), &time, Fixed32Size);
- data = std::move(tmp);
- }
- return setDataForKey(std::move(data), key);
- }
- bool MMKV::getString(MMKVKey_t key, string &result, bool inplaceModification) {
- if (isKeyEmpty(key)) {
- return false;
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- if (data.length() > 0) {
- try {
- CodedInputData input(data.getPtr(), data.length());
- if (inplaceModification) {
- input.readString(result);
- } else {
- result = input.readString();
- }
- return true;
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("decode fail");
- }
- }
- return false;
- }
- bool MMKV::getBytes(MMKVKey_t key, mmkv::MMBuffer &result) {
- if (isKeyEmpty(key)) {
- return false;
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- if (data.length() > 0) {
- try {
- CodedInputData input(data.getPtr(), data.length());
- result = input.readData();
- return true;
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("decode fail");
- }
- }
- return false;
- }
- MMBuffer MMKV::getBytes(MMKVKey_t key) {
- if (isKeyEmpty(key)) {
- return MMBuffer();
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- if (data.length() > 0) {
- try {
- CodedInputData input(data.getPtr(), data.length());
- return input.readData();
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("decode fail");
- }
- }
- return MMBuffer();
- }
- bool MMKV::getVector(MMKVKey_t key, vector<string> &result) {
- if (isKeyEmpty(key)) {
- return false;
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- if (data.length() > 0) {
- try {
- result = MiniPBCoder::decodeVector(data);
- return true;
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("decode fail");
- }
- }
- return false;
- }
- void MMKV::shared_lock() {
- m_lock->lock();
- m_sharedProcessLock->lock();
- }
- void MMKV::shared_unlock() {
- m_sharedProcessLock->unlock();
- m_lock->unlock();
- }
- bool MMKV::getBool(MMKVKey_t key, bool defaultValue, bool *hasValue) {
- if (isKeyEmpty(key)) {
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- if (data.length() > 0) {
- try {
- CodedInputData input(data.getPtr(), data.length());
- if (hasValue != nullptr) {
- *hasValue = true;
- }
- return input.readBool();
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("decode fail");
- }
- }
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- int32_t MMKV::getInt32(MMKVKey_t key, int32_t defaultValue, bool *hasValue) {
- if (isKeyEmpty(key)) {
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- if (data.length() > 0) {
- try {
- CodedInputData input(data.getPtr(), data.length());
- if (hasValue != nullptr) {
- *hasValue = true;
- }
- return input.readInt32();
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("decode fail");
- }
- }
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- uint32_t MMKV::getUInt32(MMKVKey_t key, uint32_t defaultValue, bool *hasValue) {
- if (isKeyEmpty(key)) {
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- if (data.length() > 0) {
- try {
- CodedInputData input(data.getPtr(), data.length());
- if (hasValue != nullptr) {
- *hasValue = true;
- }
- return input.readUInt32();
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("decode fail");
- }
- }
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- int64_t MMKV::getInt64(MMKVKey_t key, int64_t defaultValue, bool *hasValue) {
- if (isKeyEmpty(key)) {
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- if (data.length() > 0) {
- try {
- CodedInputData input(data.getPtr(), data.length());
- if (hasValue != nullptr) {
- *hasValue = true;
- }
- return input.readInt64();
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("decode fail");
- }
- }
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- uint64_t MMKV::getUInt64(MMKVKey_t key, uint64_t defaultValue, bool *hasValue) {
- if (isKeyEmpty(key)) {
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- if (data.length() > 0) {
- try {
- CodedInputData input(data.getPtr(), data.length());
- if (hasValue != nullptr) {
- *hasValue = true;
- }
- return input.readUInt64();
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("decode fail");
- }
- }
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- float MMKV::getFloat(MMKVKey_t key, float defaultValue, bool *hasValue) {
- if (isKeyEmpty(key)) {
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- if (data.length() > 0) {
- try {
- CodedInputData input(data.getPtr(), data.length());
- if (hasValue != nullptr) {
- *hasValue = true;
- }
- return input.readFloat();
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("decode fail");
- }
- }
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- double MMKV::getDouble(MMKVKey_t key, double defaultValue, bool *hasValue) {
- if (isKeyEmpty(key)) {
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- if (data.length() > 0) {
- try {
- CodedInputData input(data.getPtr(), data.length());
- if (hasValue != nullptr) {
- *hasValue = true;
- }
- return input.readDouble();
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("decode fail");
- }
- }
- if (hasValue != nullptr) {
- *hasValue = false;
- }
- return defaultValue;
- }
- size_t MMKV::getValueSize(MMKVKey_t key, bool actualSize) {
- if (isKeyEmpty(key)) {
- return 0;
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- if (actualSize) {
- try {
- CodedInputData input(data.getPtr(), data.length());
- auto length = input.readInt32();
- if (length >= 0) {
- auto s_length = static_cast<size_t>(length);
- if (pbRawVarint32Size(length) + s_length == data.length()) {
- return s_length;
- }
- }
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("decode fail");
- }
- }
- return data.length();
- }
- int32_t MMKV::writeValueToBuffer(MMKVKey_t key, void *ptr, int32_t size) {
- if (isKeyEmpty(key) || size < 0) {
- return -1;
- }
- auto s_size = static_cast<size_t>(size);
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_sharedProcessLock);
- auto data = getDataForKey(key);
- try {
- CodedInputData input(data.getPtr(), data.length());
- auto length = input.readInt32();
- auto offset = pbRawVarint32Size(length);
- if (length >= 0) {
- auto s_length = static_cast<size_t>(length);
- if (offset + s_length == data.length()) {
- if (s_length <= s_size) {
- memcpy(ptr, (uint8_t *) data.getPtr() + offset, s_length);
- return length;
- }
- } else {
- if (data.length() <= s_size) {
- memcpy(ptr, data.getPtr(), data.length());
- return static_cast<int32_t>(data.length());
- }
- }
- }
- } catch (std::exception &exception) {
- MMKVError("%s", exception.what());
- } catch (...) {
- MMKVError("encode fail");
- }
- return -1;
- }
- // enumerate
- bool MMKV::containsKey(MMKVKey_t key) {
- SCOPED_LOCK(m_lock);
- checkLoadData();
- if (mmkv_likely(!m_enableKeyExpire)) {
- if (m_crypter) {
- return m_dicCrypt->find(key) != m_dicCrypt->end();
- } else {
- return m_dic->find(key) != m_dic->end();
- }
- }
- auto raw = getDataWithoutMTimeForKey(key);
- return raw.length() != 0;
- }
- size_t MMKV::count(bool filterExpire) {
- SCOPED_LOCK(m_lock);
- checkLoadData();
- if (mmkv_unlikely(filterExpire && m_enableKeyExpire)) {
- SCOPED_LOCK(m_exclusiveProcessLock);
- fullWriteback(nullptr, true);
- }
- if (m_crypter) {
- return m_dicCrypt->size();
- } else {
- return m_dic->size();
- }
- }
- size_t MMKV::totalSize() {
- SCOPED_LOCK(m_lock);
- checkLoadData();
- return m_file->getFileSize();
- }
- size_t MMKV::actualSize() {
- SCOPED_LOCK(m_lock);
- checkLoadData();
- return m_actualSize;
- }
- bool MMKV::removeValueForKey(MMKVKey_t key) {
- if (isKeyEmpty(key)) {
- return false;
- }
- if (isReadOnly()) {
- MMKVWarning("[%s] file readonly", m_mmapID.c_str());
- return false;
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_exclusiveProcessLock);
- checkLoadData();
- return removeDataForKey(key);
- }
- #ifndef MMKV_APPLE
- vector<string> MMKV::allKeys(bool filterExpire) {
- SCOPED_LOCK(m_lock);
- checkLoadData();
- if (mmkv_unlikely(filterExpire && m_enableKeyExpire)) {
- SCOPED_LOCK(m_exclusiveProcessLock);
- fullWriteback(nullptr, true);
- }
- vector<string> keys;
- if (m_crypter) {
- for (const auto &itr : *m_dicCrypt) {
- keys.push_back(itr.first);
- }
- } else {
- for (const auto &itr : *m_dic) {
- keys.push_back(itr.first);
- }
- }
- return keys;
- }
- bool MMKV::removeValuesForKeys(const vector<string> &arrKeys) {
- if (isReadOnly()) {
- MMKVWarning("[%s] file readonly", m_mmapID.c_str());
- return false;
- }
- if (arrKeys.empty()) {
- return true;
- }
- if (arrKeys.size() == 1) {
- return removeValueForKey(arrKeys[0]);
- }
- SCOPED_LOCK(m_lock);
- SCOPED_LOCK(m_exclusiveProcessLock);
- checkLoadData();
- size_t deleteCount = 0;
- if (m_crypter) {
- for (const auto &key : arrKeys) {
- auto itr = m_dicCrypt->find(key);
- if (itr != m_dicCrypt->end()) {
- m_dicCrypt->erase(itr);
- deleteCount++;
- }
- }
- } else {
- for (const auto &key : arrKeys) {
- auto itr = m_dic->find(key);
- if (itr != m_dic->end()) {
- m_dic->erase(itr);
- deleteCount++;
- }
- }
- }
- if (deleteCount > 0) {
- m_hasFullWriteback = false;
- return fullWriteback();
- }
- return true;
- }
- #endif // MMKV_APPLE
- // file
- void MMKV::sync(SyncFlag flag) {
- MMKVInfo("MMKV::sync, SyncFlag = %d", flag);
- SCOPED_LOCK(m_lock);
- if (m_needLoadFromFile || !isFileValid()) {
- return;
- }
- SCOPED_LOCK(m_exclusiveProcessLock);
- m_file->msync(flag);
- m_metaFile->msync(flag);
- }
- void MMKV::lock() {
- SCOPED_LOCK(m_lock);
- m_exclusiveProcessLock->lock();
- }
- void MMKV::unlock() {
- SCOPED_LOCK(m_lock);
- m_exclusiveProcessLock->unlock();
- }
- bool MMKV::try_lock() {
- SCOPED_LOCK(m_lock);
- return m_exclusiveProcessLock->try_lock();
- }
- #ifndef MMKV_WIN32
- void MMKV::lock_thread() {
- m_lock->lock();
- }
- void MMKV::unlock_thread() {
- m_lock->unlock();
- }
- bool MMKV::try_lock_thread() {
- return m_lock->try_lock();
- }
- #endif
- // backup
- static bool backupOneToDirectoryByFilePath(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
- File crcFile(srcPath, OpenFlag::ReadOnly);
- if (!crcFile.isFileValid()) {
- return false;
- }
- bool ret;
- {
- #ifdef MMKV_WIN32
- MMKVInfo("backup one mmkv[%s] from [%ls] to [%ls]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
- #else
- MMKVInfo("backup one mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
- #endif
- FileLock fileLock(crcFile.getFd());
- InterProcessLock lock(&fileLock, SharedLockType);
- SCOPED_LOCK(&lock);
- ret = copyFile(srcPath, dstPath);
- if (ret) {
- auto srcCRCPath = srcPath + CRC_SUFFIX;
- auto dstCRCPath = dstPath + CRC_SUFFIX;
- ret = copyFile(srcCRCPath, dstCRCPath);
- }
- MMKVInfo("finish backup one mmkv[%s]", mmapKey.c_str());
- }
- return ret;
- }
- bool MMKV::backupOneToDirectory(const string &mmapKey, const MMKVPath_t &dstPath, const MMKVPath_t &srcPath, bool compareFullPath) {
- if (!g_instanceLock) {
- return false;
- }
- // we have to lock the creation of MMKV instance, regardless of in cache or not
- SCOPED_LOCK(g_instanceLock);
- MMKV *kv = nullptr;
- if (!compareFullPath) {
- auto itr = g_instanceDic->find(mmapKey);
- if (itr != g_instanceDic->end()) {
- kv = itr->second;
- }
- } else {
- // mmapKey is actually filename, we can't simply call find()
- for (auto &pair : *g_instanceDic) {
- if (pair.second->m_path == srcPath) {
- kv = pair.second;
- break;
- }
- }
- }
- // get one in cache, do it the easy way
- if (kv) {
- #ifdef MMKV_WIN32
- MMKVInfo("backup one cached mmkv[%s] from [%ls] to [%ls]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
- #else
- MMKVInfo("backup one cached mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
- #endif
- SCOPED_LOCK(kv->m_lock);
- SCOPED_LOCK(kv->m_sharedProcessLock);
- kv->sync();
- auto ret = copyFile(kv->m_path, dstPath);
- if (ret) {
- auto dstCRCPath = dstPath + CRC_SUFFIX;
- ret = copyFile(kv->m_crcPath, dstCRCPath);
- }
- MMKVInfo("finish backup one mmkv[%s], ret: %d", mmapKey.c_str(), ret);
- return ret;
- }
- // no luck with cache, do it the hard way
- bool ret = backupOneToDirectoryByFilePath(mmapKey, srcPath, dstPath);
- return ret;
- }
- bool MMKV::backupOneToDirectory(const string &mmapID, const MMKVPath_t &dstDir, const MMKVPath_t *srcDir) {
- auto rootPath = srcDir ? srcDir : &g_realRootDir;
- if (*rootPath == dstDir) {
- return true;
- }
- mkPath(dstDir);
- auto dstPath = mappedKVPathWithID(mmapID, &dstDir);
- string mmapKey = mmapedKVKey(mmapID, rootPath);
- #ifdef MMKV_ANDROID
- string srcPath;
- switch (tryMigrateLegacyMMKVFile(mmapID, rootPath)) {
- case MigrateStatus::OldToNewMigrateFail: {
- auto legacyID = legacyMmapedKVKey(mmapID, rootPath);
- srcPath = mappedKVPathWithID(legacyID, rootPath);
- break;
- }
- case MigrateStatus::NoneExist:
- MMKVWarning("file with ID [%s] not exist in path [%s]", mmapID.c_str(), rootPath->c_str());
- return false;
- default:
- srcPath = mappedKVPathWithID(mmapID, rootPath);
- break;
- }
- #else
- auto srcPath = mappedKVPathWithID(mmapID, rootPath);
- #endif
- return backupOneToDirectory(mmapKey, dstPath, srcPath, false);
- }
- bool endsWith(const MMKVPath_t &str, const MMKVPath_t &suffix) {
- if (str.length() >= suffix.length()) {
- return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
- } else {
- return false;
- }
- }
- MMKVPath_t filename(const MMKVPath_t &path) {
- auto startPos = path.rfind(MMKV_PATH_SLASH);
- startPos++; // don't need to check for npos, because npos+1 == 0
- auto filename = path.substr(startPos);
- return filename;
- }
- size_t MMKV::backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t &srcDir, bool isInSpecialDir) {
- unordered_set<MMKVPath_t> mmapIDSet;
- unordered_set<MMKVPath_t> mmapIDCRCSet;
- walkInDir(srcDir, WalkFile, [&](const MMKVPath_t &filePath, WalkType) {
- if (endsWith(filePath, CRC_SUFFIX)) {
- mmapIDCRCSet.insert(filePath);
- } else {
- mmapIDSet.insert(filePath);
- }
- });
- size_t count = 0;
- if (!mmapIDSet.empty()) {
- mkPath(dstDir);
- auto compareFullPath = isInSpecialDir;
- for (auto &srcPath : mmapIDSet) {
- auto srcCRCPath = srcPath + CRC_SUFFIX;
- if (mmapIDCRCSet.find(srcCRCPath) == mmapIDCRCSet.end()) {
- #ifdef MMKV_WIN32
- MMKVWarning("crc not exist [%ls]", srcCRCPath.c_str());
- #else
- MMKVWarning("crc not exist [%s]", srcCRCPath.c_str());
- #endif
- continue;
- }
- auto basename = filename(srcPath);
- const auto &strBasename = MMKVPath_t2String(basename);
- auto mmapKey = isInSpecialDir ? strBasename : mmapedKVKey(strBasename, &srcDir);
- auto dstPath = dstDir + MMKV_PATH_SLASH;
- dstPath += basename;
- if (backupOneToDirectory(mmapKey, dstPath, srcPath, compareFullPath)) {
- count++;
- }
- }
- }
- return count;
- }
- size_t MMKV::backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t *srcDir) {
- auto rootPath = srcDir ? srcDir : &g_realRootDir;
- if (*rootPath == dstDir) {
- return true;
- }
- auto count = backupAllToDirectory(dstDir, *rootPath, false);
- auto specialSrcDir = *rootPath + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
- if (isFileExist(specialSrcDir)) {
- auto specialDstDir = dstDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
- count += backupAllToDirectory(specialDstDir, specialSrcDir, true);
- }
- return count;
- }
- // restore
- static bool restoreOneFromDirectoryByFilePath(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
- auto dstCRCPath = dstPath + CRC_SUFFIX;
- File dstCRCFile(std::move(dstCRCPath), OpenFlag::ReadWrite | OpenFlag::Create);
- if (!dstCRCFile.isFileValid()) {
- return false;
- }
- bool ret;
- {
- #ifdef MMKV_WIN32
- MMKVInfo("restore one mmkv[%s] from [%ls] to [%ls]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
- #else
- MMKVInfo("restore one mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
- #endif
- FileLock fileLock(dstCRCFile.getFd());
- InterProcessLock lock(&fileLock, ExclusiveLockType);
- SCOPED_LOCK(&lock);
- ret = copyFileContent(srcPath, dstPath);
- if (ret) {
- auto srcCRCPath = srcPath + CRC_SUFFIX;
- ret = copyFileContent(srcCRCPath, dstCRCFile.getFd());
- }
- MMKVInfo("finish restore one mmkv[%s]", mmapKey.c_str());
- }
- return ret;
- }
- // We can't simply replace the existing file, because other processes might have already open it.
- // They won't know a difference when the file has been replaced.
- // We have to let them know by overriding the existing file with new content.
- bool MMKV::restoreOneFromDirectory(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath, bool compareFullPath) {
- if (!g_instanceLock) {
- return false;
- }
- // we have to lock the creation of MMKV instance, regardless of in cache or not
- SCOPED_LOCK(g_instanceLock);
- MMKV *kv = nullptr;
- if (!compareFullPath) {
- auto itr = g_instanceDic->find(mmapKey);
- if (itr != g_instanceDic->end()) {
- kv = itr->second;
- }
- } else {
- // mmapKey is actually filename, we can't simply call find()
- for (auto &pair : *g_instanceDic) {
- if (pair.second->m_path == dstPath) {
- kv = pair.second;
- break;
- }
- }
- }
- // get one in cache, do it the easy way
- if (kv) {
- #ifdef MMKV_WIN32
- MMKVInfo("restore one cached mmkv[%s] from [%ls] to [%ls]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
- #else
- MMKVInfo("restore one cached mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
- #endif
- SCOPED_LOCK(kv->m_lock);
- SCOPED_LOCK(kv->m_exclusiveProcessLock);
- kv->sync();
- auto ret = copyFileContent(srcPath, kv->m_file->getFd());
- kv->m_file->cleanMayflyFD();
- if (ret) {
- auto srcCRCPath = srcPath + CRC_SUFFIX;
- // ret = copyFileContent(srcCRCPath, kv->m_metaFile->getFd());
- // kv->m_metaFile->cleanMayflyFD();
- #ifndef MMKV_ANDROID
- MemoryFile srcCRCFile(srcCRCPath);
- #else
- MemoryFile srcCRCFile(srcCRCPath, DEFAULT_MMAP_SIZE, MMFILE_TYPE_FILE);
- #endif
- if (srcCRCFile.isFileValid()) {
- memcpy(kv->m_metaFile->getMemory(), srcCRCFile.getMemory(), sizeof(MMKVMetaInfo));
- } else {
- ret = false;
- }
- }
- // reload data after restore
- kv->clearMemoryCache();
- kv->loadFromFile();
- if (kv->isMultiProcess()) {
- kv->notifyContentChanged();
- }
- MMKVInfo("finish restore one mmkv[%s], ret: %d", mmapKey.c_str(), ret);
- return ret;
- }
- // no luck with cache, do it the hard way
- bool ret = restoreOneFromDirectoryByFilePath(mmapKey, srcPath, dstPath);
- return ret;
- }
- bool MMKV::restoreOneFromDirectory(const string &mmapID, const MMKVPath_t &srcDir, const MMKVPath_t *dstDir) {
- auto rootPath = dstDir ? dstDir : &g_realRootDir;
- if (*rootPath == srcDir) {
- return true;
- }
- mkPath(*rootPath);
- auto srcPath = mappedKVPathWithID(mmapID, &srcDir);
- auto mmapKey = mmapedKVKey(mmapID, rootPath);
- #ifdef MMKV_ANDROID
- string dstPath;
- if (tryMigrateLegacyMMKVFile(mmapID, rootPath) == MigrateStatus::OldToNewMigrateFail) {
- auto legacyID = legacyMmapedKVKey(mmapID, rootPath);
- dstPath = mappedKVPathWithID(legacyID, rootPath);
- } else {
- dstPath = mappedKVPathWithID(mmapID, rootPath);
- }
- #else
- auto dstPath = mappedKVPathWithID(mmapID, rootPath);
- #endif
- return restoreOneFromDirectory(mmapKey, srcPath, dstPath, false);
- }
- size_t MMKV::restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t &dstDir, bool isInSpecialDir) {
- unordered_set<MMKVPath_t> mmapIDSet;
- unordered_set<MMKVPath_t> mmapIDCRCSet;
- walkInDir(srcDir, WalkFile, [&](const MMKVPath_t &filePath, WalkType) {
- if (endsWith(filePath, CRC_SUFFIX)) {
- mmapIDCRCSet.insert(filePath);
- } else {
- mmapIDSet.insert(filePath);
- }
- });
- size_t count = 0;
- if (!mmapIDSet.empty()) {
- mkPath(dstDir);
- auto compareFullPath = isInSpecialDir;
- for (auto &srcPath : mmapIDSet) {
- auto srcCRCPath = srcPath + CRC_SUFFIX;
- if (mmapIDCRCSet.find(srcCRCPath) == mmapIDCRCSet.end()) {
- #ifdef MMKV_WIN32
- MMKVWarning("crc not exist [%ls]", srcCRCPath.c_str());
- #else
- MMKVWarning("crc not exist [%s]", srcCRCPath.c_str());
- #endif
- continue;
- }
- auto basename = filename(srcPath);
- const auto &strBasename = MMKVPath_t2String(basename);
- auto mmapKey = isInSpecialDir ? strBasename : mmapedKVKey(strBasename, &dstDir);
- auto dstPath = dstDir + MMKV_PATH_SLASH;
- dstPath += basename;
- if (restoreOneFromDirectory(mmapKey, srcPath, dstPath, compareFullPath)) {
- count++;
- }
- }
- }
- return count;
- }
- size_t MMKV::restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t *dstDir) {
- auto rootPath = dstDir ? dstDir : &g_realRootDir;
- if (*rootPath == srcDir) {
- return true;
- }
- auto count = restoreAllFromDirectory(srcDir, *rootPath, true);
- auto specialSrcDir = srcDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
- if (isFileExist(specialSrcDir)) {
- auto specialDstDir = *rootPath + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
- count += restoreAllFromDirectory(specialSrcDir, specialDstDir, false);
- }
- return count;
- }
- // callbacks
- void MMKV::registerErrorHandler(ErrorHandler handler) {
- if (!g_instanceLock) {
- return;
- }
- SCOPED_LOCK(g_instanceLock);
- g_errorHandler = handler;
- }
- void MMKV::unRegisterErrorHandler() {
- if (!g_instanceLock) {
- return;
- }
- SCOPED_LOCK(g_instanceLock);
- g_errorHandler = nullptr;
- }
- void MMKV::registerLogHandler(LogHandler handler) {
- if (!g_instanceLock) {
- return;
- }
- SCOPED_LOCK(g_instanceLock);
- g_logHandler = handler;
- }
- void MMKV::unRegisterLogHandler() {
- if (!g_instanceLock) {
- return;
- }
- SCOPED_LOCK(g_instanceLock);
- g_logHandler = nullptr;
- }
- void MMKV::setLogLevel(MMKVLogLevel level) {
- if (!g_instanceLock) {
- return;
- }
- SCOPED_LOCK(g_instanceLock);
- g_currentLogLevel = level;
- }
- static void mkSpecialCharacterFileDirectory() {
- MMKVPath_t path = g_realRootDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
- mkPath(path);
- }
- template <typename T>
- static string md5(const basic_string<T> &value) {
- uint8_t md[MD5_DIGEST_LENGTH] = {};
- char tmp[3] = {}, buf[33] = {};
- openssl::MD5((const uint8_t *) value.c_str(), value.size() * (sizeof(T) / sizeof(uint8_t)), md);
- for (auto ch : md) {
- snprintf(tmp, sizeof(tmp), "%2.2x", ch);
- strcat(buf, tmp);
- }
- return {buf};
- }
- static MMKVPath_t encodeFilePath(const string &mmapID) {
- const char *specialCharacters = "\\/:*?\"<>|";
- string encodedID;
- bool hasSpecialCharacter = false;
- for (auto ch : mmapID) {
- if (strchr(specialCharacters, ch) != nullptr) {
- encodedID = md5(mmapID);
- hasSpecialCharacter = true;
- break;
- }
- }
- if (hasSpecialCharacter) {
- static ThreadOnceToken_t once = ThreadOnceUninitialized;
- ThreadLock::ThreadOnce(&once, mkSpecialCharacterFileDirectory);
- return MMKVPath_t(SPECIAL_CHARACTER_DIRECTORY_NAME) + MMKV_PATH_SLASH + string2MMKVPath_t(encodedID);
- } else {
- return string2MMKVPath_t(mmapID);
- }
- }
- static MMKVPath_t encodeFilePath(const string &mmapID, const MMKVPath_t &rootDir) {
- const char *specialCharacters = "\\/:*?\"<>|";
- string encodedID;
- bool hasSpecialCharacter = false;
- for (auto ch : mmapID) {
- if (strchr(specialCharacters, ch) != nullptr) {
- encodedID = md5(mmapID);
- hasSpecialCharacter = true;
- break;
- }
- }
- if (hasSpecialCharacter) {
- MMKVPath_t path = rootDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
- mkPath(path);
- return MMKVPath_t(SPECIAL_CHARACTER_DIRECTORY_NAME) + MMKV_PATH_SLASH + string2MMKVPath_t(encodedID);
- } else {
- return string2MMKVPath_t(mmapID);
- }
- }
- string mmapedKVKey(const string &mmapID, const MMKVPath_t *rootPath) {
- MMKVPath_t path;
- // compare by pointer to speedup a bit, it's OK false detecting
- if (rootPath && (rootPath != &g_realRootDir)) {
- auto tmp = *rootPath + MMKV_PATH_SLASH + string2MMKVPath_t(mmapID);
- path = absolutePath(tmp);
- } else {
- path = g_realRootDir + MMKV_PATH_SLASH + string2MMKVPath_t(mmapID);
- }
- return md5(path);
- }
- string legacyMmapedKVKey(const string &mmapID, const MMKVPath_t *rootPath) {
- if (rootPath && (*rootPath != g_rootDir)) {
- return md5(*rootPath + MMKV_PATH_SLASH + string2MMKVPath_t(mmapID));
- }
- return mmapID;
- }
- #ifndef MMKV_ANDROID
- MMKVPath_t mappedKVPathWithID(const string &mmapID, const MMKVPath_t *rootPath) {
- if (rootPath && (rootPath != &g_realRootDir)) {
- auto path = *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapID, *rootPath);
- return absolutePath(path);
- }
- auto path = g_realRootDir + MMKV_PATH_SLASH + encodeFilePath(mmapID);
- return path;
- }
- #else
- MMKVPath_t mappedKVPathWithID(const string &mmapID, const MMKVPath_t *rootPath, MMKVMode mode) {
- if (mode & MMKV_ASHMEM) {
- return ashmemMMKVPathWithID(encodeFilePath(mmapID));
- } else if (rootPath && (rootPath != &g_realRootDir)) {
- auto path = *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapID, *rootPath);
- return absolutePath(path);
- }
- auto path = g_realRootDir + MMKV_PATH_SLASH + encodeFilePath(mmapID);
- return path;
- }
- #endif
- MMKVPath_t crcPathWithPath(const MMKVPath_t &kvPath) {
- return kvPath + CRC_SUFFIX;
- }
- MMKVRecoverStrategic onMMKVCRCCheckFail(const string &mmapID) {
- if (g_errorHandler) {
- return g_errorHandler(mmapID, MMKVErrorType::MMKVCRCCheckFail);
- }
- return OnErrorDiscard;
- }
- MMKVRecoverStrategic onMMKVFileLengthError(const string &mmapID) {
- if (g_errorHandler) {
- return g_errorHandler(mmapID, MMKVErrorType::MMKVFileLength);
- }
- return OnErrorDiscard;
- }
- // NameSpace
- NameSpace MMKV::nameSpace(const MMKVPath_t &rootDir) {
- if (!g_instanceLock) {
- ensureMinimalInitialize();
- }
- static ThreadOnceToken_t once = ThreadOnceUninitialized;
- ThreadLock::ThreadOnce(&once, []{
- g_namespaceLock = new ThreadLock;
- g_namespaceLock->initialize();
- });
- SCOPED_LOCK(g_namespaceLock);
- auto itr = g_realRootMap.find(rootDir);
- if (itr == g_realRootMap.end()) {
- auto realRoot = absolutePath(rootDir);
- if (realRoot.ends_with(MMKV_PATH_SLASH)) {
- realRoot.erase(realRoot.size() - 1);
- }
- itr = g_realRootMap.emplace(rootDir, realRoot).first;
- }
- return NameSpace(itr->second);
- }
- NameSpace MMKV::defaultNameSpace() {
- if (g_rootDir.empty()) {
- MMKVWarning("MMKV has not been initialized, there's no default NameSpace.");
- return NameSpace(MMKVPath_t());
- }
- return NameSpace(g_realRootDir);
- }
- #ifndef MMKV_ANDROID
- MMKV *NameSpace::mmkvWithID(const string &mmapID, MMKVMode mode, const string *cryptKey, size_t expectedCapacity) {
- return MMKV::mmkvWithID(mmapID, mode, cryptKey, &m_rootDir, expectedCapacity);
- }
- #endif
- bool NameSpace::backupOneToDirectory(const std::string &mmapID, const MMKVPath_t &dstDir) {
- return MMKV::backupOneToDirectory(mmapID, dstDir, &m_rootDir);
- }
- bool NameSpace::restoreOneFromDirectory(const std::string &mmapID, const MMKVPath_t &srcDir) {
- return MMKV::restoreOneFromDirectory(mmapID, srcDir, &m_rootDir);
- }
- size_t NameSpace::backupAllToDirectory(const MMKVPath_t &dstDir) {
- return MMKV::backupAllToDirectory(dstDir, &m_rootDir);
- }
- size_t NameSpace::restoreAllFromDirectory(const MMKVPath_t &srcDir) {
- return MMKV::restoreAllFromDirectory(srcDir, &m_rootDir);
- }
- bool NameSpace::isFileValid(const std::string &mmapID) {
- return MMKV::isFileValid(mmapID, &m_rootDir);
- }
- bool NameSpace::removeStorage(const std::string &mmapID) {
- return MMKV::removeStorage(mmapID, &m_rootDir);
- }
- bool NameSpace::checkExist(const std::string &mmapID) {
- return MMKV::checkExist(mmapID, &m_rootDir);
- }
- MMKV_NAMESPACE_END
|