MMKV_IO.cpp 70 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022
  1. /*
  2. * Tencent is pleased to support the open source community by making
  3. * MMKV available.
  4. *
  5. * Copyright (C) 2020 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. #include "MMKV_IO.h"
  21. #include "CodedInputData.h"
  22. #include "CodedOutputData.h"
  23. #include "InterProcessLock.h"
  24. #include "MMBuffer.h"
  25. #include "MMKVLog.h"
  26. #include "MMKVMetaInfo.hpp"
  27. #include "MemoryFile.h"
  28. #include "MiniPBCoder.h"
  29. #include "PBUtility.h"
  30. #include "ScopedLock.hpp"
  31. #include "ThreadLock.h"
  32. #include "aes/AESCrypt.h"
  33. #include "aes/openssl/openssl_aes.h"
  34. #include "aes/openssl/openssl_md5.h"
  35. #include "crc32/Checksum.h"
  36. #include <algorithm>
  37. #include <cassert>
  38. #include <cstring>
  39. #include <ctime>
  40. #ifdef MMKV_IOS
  41. # include "MMKV_OSX.h"
  42. #endif
  43. #ifdef MMKV_APPLE
  44. # if __has_feature(objc_arc)
  45. # error This file must be compiled with MRC. Use -fno-objc-arc flag.
  46. # endif
  47. #endif // MMKV_APPLE
  48. #ifndef MMKV_WIN32
  49. # include <unistd.h>
  50. #endif
  51. using namespace std;
  52. using namespace mmkv;
  53. using KVHolderRet_t = std::pair<bool, KeyValueHolder>;
  54. extern ThreadLock *g_instanceLock;
  55. extern unordered_map<string, MMKV *> *g_instanceDic;
  56. MMKV_NAMESPACE_BEGIN
  57. void MMKV::loadFromFile() {
  58. loadMetaInfoAndCheck();
  59. #ifndef MMKV_DISABLE_CRYPT
  60. if (m_crypter) {
  61. if (m_metaInfo->m_version >= MMKVVersionRandomIV) {
  62. m_crypter->resetIV(m_metaInfo->m_vector, sizeof(m_metaInfo->m_vector));
  63. }
  64. }
  65. #endif
  66. if (!m_file->isFileValid()) {
  67. m_file->reloadFromFile(m_expectedCapacity);
  68. }
  69. if (!m_file->isFileValid()) {
  70. MMKVError("file [%s] not valid", m_path.c_str());
  71. } else {
  72. // error checking
  73. bool loadFromFile = false, needFullWriteback = false;
  74. checkDataValid(loadFromFile, needFullWriteback);
  75. MMKVInfo("loading [%s] with %zu actual size, file size %zu, InterProcess %d, meta info "
  76. "version:%u",
  77. m_mmapID.c_str(), m_actualSize, m_file->getFileSize(), isMultiProcess(), m_metaInfo->m_version);
  78. auto ptr = (uint8_t *) m_file->getMemory();
  79. // loading
  80. if (loadFromFile && m_actualSize > 0) {
  81. MMKVInfo("loading [%s] with crc %u sequence %u version %u", m_mmapID.c_str(), m_metaInfo->m_crcDigest,
  82. m_metaInfo->m_sequence, m_metaInfo->m_version);
  83. MMBuffer inputBuffer(ptr + Fixed32Size, m_actualSize, MMBufferNoCopy);
  84. if (m_crypter) {
  85. clearDictionary(m_dicCrypt);
  86. } else {
  87. clearDictionary(m_dic);
  88. }
  89. if (needFullWriteback) {
  90. #ifndef MMKV_DISABLE_CRYPT
  91. if (m_crypter) {
  92. MiniPBCoder::greedyDecodeMap(*m_dicCrypt, inputBuffer, m_crypter);
  93. } else
  94. #endif
  95. {
  96. MiniPBCoder::greedyDecodeMap(*m_dic, inputBuffer);
  97. }
  98. } else {
  99. #ifndef MMKV_DISABLE_CRYPT
  100. if (m_crypter) {
  101. MiniPBCoder::decodeMap(*m_dicCrypt, inputBuffer, m_crypter);
  102. } else
  103. #endif
  104. {
  105. MiniPBCoder::decodeMap(*m_dic, inputBuffer);
  106. }
  107. }
  108. m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
  109. m_output->seek(m_actualSize);
  110. if (needFullWriteback) {
  111. fullWriteback();
  112. }
  113. } else {
  114. // file not valid or empty, discard everything
  115. SCOPED_LOCK(m_exclusiveProcessLock);
  116. m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
  117. if (m_actualSize > 0) {
  118. writeActualSize(0, 0, nullptr, IncreaseSequence);
  119. sync(MMKV_SYNC);
  120. } else {
  121. writeActualSize(0, 0, nullptr, KeepSequence);
  122. }
  123. }
  124. auto count = m_crypter ? m_dicCrypt->size() : m_dic->size();
  125. MMKVInfo("loaded [%s] with %zu key-values", m_mmapID.c_str(), count);
  126. // auto keys = allKeys();
  127. // for (size_t index = 0; index < count; index++) {
  128. // MMKVInfo("key[%llu]: %s", index, keys[index].c_str());
  129. // }
  130. }
  131. m_needLoadFromFile = false;
  132. }
  133. // read from last m_position
  134. void MMKV::partialLoadFromFile() {
  135. if (!m_file->isFileValid()) {
  136. return;
  137. }
  138. m_metaInfo->read(m_metaFile->getMemory());
  139. size_t oldActualSize = m_actualSize;
  140. m_actualSize = readActualSize();
  141. auto fileSize = m_file->getFileSize();
  142. MMKVDebug("loading [%s] with file size %zu, oldActualSize %zu, newActualSize %zu", m_mmapID.c_str(), fileSize,
  143. oldActualSize, m_actualSize);
  144. if (m_actualSize > 0) {
  145. if (m_actualSize < fileSize && m_actualSize + Fixed32Size <= fileSize) {
  146. if (m_actualSize > oldActualSize) {
  147. auto position = oldActualSize;
  148. size_t addedSize = m_actualSize - position;
  149. auto basePtr = (uint8_t *) m_file->getMemory() + Fixed32Size;
  150. // incremental update crc digest
  151. m_crcDigest = (uint32_t) CRC32(m_crcDigest, basePtr + position, (z_size_t) addedSize);
  152. if (m_crcDigest == m_metaInfo->m_crcDigest) {
  153. MMBuffer inputBuffer(basePtr, m_actualSize, MMBufferNoCopy);
  154. #ifndef MMKV_DISABLE_CRYPT
  155. if (m_crypter) {
  156. MiniPBCoder::greedyDecodeMap(*m_dicCrypt, inputBuffer, m_crypter, position);
  157. } else
  158. #endif
  159. {
  160. MiniPBCoder::greedyDecodeMap(*m_dic, inputBuffer, position);
  161. }
  162. m_output->seek(addedSize);
  163. m_hasFullWriteback = false;
  164. [[maybe_unused]] auto count = m_crypter ? m_dicCrypt->size() : m_dic->size();
  165. MMKVDebug("partial loaded [%s] with %zu values", m_mmapID.c_str(), count);
  166. return;
  167. } else {
  168. MMKVError("m_crcDigest[%u] != m_metaInfo->m_crcDigest[%u]", m_crcDigest, m_metaInfo->m_crcDigest);
  169. }
  170. }
  171. }
  172. }
  173. // something is wrong, do a full load
  174. clearMemoryCache();
  175. loadFromFile();
  176. }
  177. //#if defined(MMKV_APPLE) || defined(MMKV_WIN32)
  178. bool MMKV::checkFileHasDiskError() {
  179. if (m_isSecondLoad) {
  180. return false;
  181. }
  182. m_isSecondLoad = true;
  183. bool needReportReadFail = false;
  184. if (isDiskOfMMAPFileCorrupted(m_metaFile, needReportReadFail)) {
  185. m_metaFile->clearMemoryCache();
  186. deleteFile(m_metaFile->getPath());
  187. m_metaFile->reloadFromFile();
  188. }
  189. if (isDiskOfMMAPFileCorrupted(m_file, needReportReadFail)) {
  190. m_file->clearMemoryCache();
  191. deleteFile(m_file->getPath());
  192. m_file->reloadFromFile(m_expectedCapacity);
  193. }
  194. return needReportReadFail;
  195. }
  196. //#endif
  197. void MMKV::loadMetaInfoAndCheck() {
  198. if (!m_metaFile->isFileValid()) {
  199. m_metaFile->reloadFromFile();
  200. }
  201. if (!m_metaFile->isFileValid()) {
  202. MMKVError("file [%s] not valid", m_metaFile->getPath().c_str());
  203. return;
  204. }
  205. if (checkFileHasDiskError()) {
  206. // let user know?
  207. }
  208. m_metaInfo->read(m_metaFile->getMemory());
  209. // the meta file is in specious status
  210. if (m_metaInfo->m_version >= MMKVVersionHolder) {
  211. MMKVWarning("meta file [%s] in specious state, version %u, flags 0x%llx", m_mmapID.c_str(),
  212. m_metaInfo->m_version, m_metaInfo->m_flags);
  213. // MMKVVersionActualSize is the last version we don't check meta file
  214. m_metaInfo->m_version = MMKVVersionActualSize;
  215. m_metaInfo->m_flags = 0;
  216. m_metaInfo->write(m_metaFile->getMemory());
  217. }
  218. if (m_metaInfo->m_version >= MMKVVersionFlag) {
  219. m_enableKeyExpire = m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre);
  220. if (m_enableKeyExpire && m_enableCompareBeforeSet) {
  221. MMKVError("enableCompareBeforeSet will be invalid when Expiration is on");
  222. m_enableCompareBeforeSet = false;
  223. }
  224. MMKVInfo("meta file [%s] has flag [%llu]", m_mmapID.c_str(), m_metaInfo->m_flags);
  225. } else {
  226. if (m_metaInfo->m_flags != 0) {
  227. m_metaInfo->m_flags = 0;
  228. m_metaInfo->write(m_metaFile->getMemory());
  229. }
  230. }
  231. }
  232. void MMKV::checkDataValid(bool &loadFromFile, bool &needFullWriteback) {
  233. // try auto recover from last confirmed location
  234. auto fileSize = m_file->getFileSize();
  235. auto checkLastConfirmedInfo = [&] {
  236. if (m_metaInfo->m_version >= MMKVVersionActualSize) {
  237. // downgrade & upgrade support
  238. uint32_t oldStyleActualSize = 0;
  239. memcpy(&oldStyleActualSize, m_file->getMemory(), Fixed32Size);
  240. if (oldStyleActualSize != m_actualSize) {
  241. MMKVWarning("oldStyleActualSize %u not equal to meta actual size %lu", oldStyleActualSize,
  242. m_actualSize);
  243. if (oldStyleActualSize < fileSize && (oldStyleActualSize + Fixed32Size) <= fileSize) {
  244. if (checkFileCRCValid(oldStyleActualSize, m_metaInfo->m_crcDigest)) {
  245. MMKVInfo("looks like [%s] been downgrade & upgrade again", m_mmapID.c_str());
  246. loadFromFile = true;
  247. writeActualSize(oldStyleActualSize, m_metaInfo->m_crcDigest, nullptr, KeepSequence);
  248. return;
  249. }
  250. } else {
  251. MMKVWarning("oldStyleActualSize %u greater than file size %lu", oldStyleActualSize, fileSize);
  252. }
  253. }
  254. auto lastActualSize = m_metaInfo->m_lastConfirmedMetaInfo.lastActualSize;
  255. if (lastActualSize < fileSize && (lastActualSize + Fixed32Size) <= fileSize) {
  256. auto lastCRCDigest = m_metaInfo->m_lastConfirmedMetaInfo.lastCRCDigest;
  257. if (checkFileCRCValid(lastActualSize, lastCRCDigest)) {
  258. loadFromFile = true;
  259. writeActualSize(lastActualSize, lastCRCDigest, nullptr, KeepSequence);
  260. } else {
  261. MMKVError("check [%s] error: lastActualSize %u, lastActualCRC %u", m_mmapID.c_str(), lastActualSize,
  262. lastCRCDigest);
  263. }
  264. } else {
  265. MMKVError("check [%s] error: lastActualSize %u, file size is %u", m_mmapID.c_str(), lastActualSize,
  266. fileSize);
  267. }
  268. }
  269. };
  270. m_actualSize = readActualSize();
  271. if (m_actualSize < fileSize && (m_actualSize + Fixed32Size) <= fileSize) {
  272. if (checkFileCRCValid(m_actualSize, m_metaInfo->m_crcDigest)) {
  273. loadFromFile = true;
  274. } else {
  275. checkLastConfirmedInfo();
  276. if (!loadFromFile) {
  277. auto strategic = onMMKVCRCCheckFail(m_mmapID);
  278. if (strategic == OnErrorRecover) {
  279. loadFromFile = true;
  280. needFullWriteback = true;
  281. }
  282. MMKVInfo("recover strategic for [%s] is %d", m_mmapID.c_str(), strategic);
  283. }
  284. }
  285. } else {
  286. MMKVError("check [%s] error: %zu size in total, file size is %zu", m_mmapID.c_str(), m_actualSize, fileSize);
  287. checkLastConfirmedInfo();
  288. if (!loadFromFile) {
  289. auto strategic = onMMKVFileLengthError(m_mmapID);
  290. if (strategic == OnErrorRecover) {
  291. // make sure we don't over read the file
  292. m_actualSize = fileSize - Fixed32Size;
  293. loadFromFile = true;
  294. needFullWriteback = true;
  295. }
  296. MMKVInfo("recover strategic for [%s] is %d", m_mmapID.c_str(), strategic);
  297. }
  298. }
  299. }
  300. void MMKV::checkLoadData() {
  301. if (m_needLoadFromFile) {
  302. SCOPED_LOCK(m_sharedProcessLock);
  303. m_needLoadFromFile = false;
  304. loadFromFile();
  305. return;
  306. }
  307. if (!isMultiProcess()) {
  308. return;
  309. }
  310. if (!m_metaFile->isFileValid()) {
  311. return;
  312. }
  313. SCOPED_LOCK(m_sharedProcessLock);
  314. MMKVMetaInfo metaInfo;
  315. metaInfo.read(m_metaFile->getMemory());
  316. if (m_metaInfo->m_sequence != metaInfo.m_sequence) {
  317. MMKVInfo("[%s] oldSeq %u, newSeq %u", m_mmapID.c_str(), m_metaInfo->m_sequence, metaInfo.m_sequence);
  318. SCOPED_LOCK(m_sharedProcessLock);
  319. clearMemoryCache();
  320. loadFromFile();
  321. notifyContentChanged();
  322. } else if ((m_metaInfo->m_crcDigest != metaInfo.m_crcDigest) || (m_metaInfo->m_actualSize != metaInfo.m_actualSize)) {
  323. MMKVDebug("[%s] crcDigest %u -> %u, actualSize %u -> %u", m_mmapID.c_str(), m_metaInfo->m_crcDigest,
  324. metaInfo.m_crcDigest, m_metaInfo->m_actualSize, metaInfo.m_actualSize);
  325. SCOPED_LOCK(m_sharedProcessLock);
  326. // looks like this is no longer needed
  327. // for we inc sequence on truncate()/trim()/expandAndWriteBack()/fullWriteBack() etc
  328. /*size_t fileSize = m_file->getActualFileSize();
  329. if (m_file->getFileSize() != fileSize) {
  330. MMKVInfo("file size has changed [%s] from %zu to %zu", m_mmapID.c_str(), m_file->getFileSize(), fileSize);
  331. clearMemoryCache();
  332. loadFromFile();
  333. } else*/ {
  334. partialLoadFromFile();
  335. }
  336. notifyContentChanged();
  337. }
  338. }
  339. constexpr uint32_t ItemSizeHolderSize = 4;
  340. static pair<MMBuffer, size_t> prepareEncode(const MMKVMap &dic) {
  341. // make some room for placeholder
  342. size_t totalSize = ItemSizeHolderSize;
  343. for (auto &itr : dic) {
  344. auto &kvHolder = itr.second;
  345. totalSize += kvHolder.computedKVSize + kvHolder.valueSize;
  346. }
  347. return make_pair(MMBuffer(), totalSize);
  348. }
  349. #ifndef MMKV_DISABLE_CRYPT
  350. static pair<MMBuffer, size_t> prepareEncode(const MMKVMapCrypt &dic) {
  351. MMKVVector vec;
  352. size_t totalSize = 0;
  353. // make some room for placeholder
  354. uint32_t smallestOffet = 5 + 1; // 5 is the largest size needed to encode varint32
  355. for (auto &itr : dic) {
  356. auto &kvHolder = itr.second;
  357. if (kvHolder.type == KeyValueHolderType_Offset) {
  358. totalSize += kvHolder.pbKeyValueSize + kvHolder.keySize + kvHolder.valueSize;
  359. smallestOffet = min(smallestOffet, kvHolder.offset);
  360. } else {
  361. vec.emplace_back(itr.first, kvHolder.toMMBuffer(nullptr, nullptr));
  362. }
  363. }
  364. if (smallestOffet > 5) {
  365. smallestOffet = ItemSizeHolderSize;
  366. }
  367. totalSize += smallestOffet;
  368. if (vec.empty()) {
  369. return make_pair(MMBuffer(), totalSize);
  370. }
  371. auto buffer = MiniPBCoder::encodeDataWithObject(vec);
  372. // skip the pb size of buffer
  373. auto sizeOfMap = CodedInputData(buffer.getPtr(), buffer.length()).readUInt32();
  374. totalSize += sizeOfMap;
  375. return make_pair(std::move(buffer), totalSize);
  376. }
  377. #endif
  378. static pair<MMBuffer, size_t> prepareEncode(MMKVVector &&vec) {
  379. // make some room for placeholder
  380. size_t totalSize = ItemSizeHolderSize;
  381. auto buffer = MiniPBCoder::encodeDataWithObject(vec);
  382. // skip the pb size of buffer
  383. auto sizeOfMap = CodedInputData(buffer.getPtr(), buffer.length()).readUInt32();
  384. totalSize += sizeOfMap;
  385. return make_pair(std::move(buffer), totalSize);
  386. }
  387. // since we use append mode, when -[setData: forKey:] many times, space may not be enough
  388. // try a full rewrite to make space
  389. bool MMKV::ensureMemorySize(size_t newSize) {
  390. if (!isFileValid()) {
  391. MMKVWarning("[%s] file not valid", m_mmapID.c_str());
  392. return false;
  393. }
  394. if (isReadOnly()) {
  395. MMKVWarning("[%s] file readonly", m_mmapID.c_str());
  396. return false;
  397. }
  398. if (newSize >= m_output->spaceLeft() || (m_crypter ? m_dicCrypt->empty() : m_dic->empty())) {
  399. // remove expired keys
  400. if (m_enableKeyExpire) {
  401. filterExpiredKeys();
  402. }
  403. // try a full rewrite to make space
  404. auto preparedData = m_crypter ? prepareEncode(*m_dicCrypt) : prepareEncode(*m_dic);
  405. // dic.empty() means inserting key-value for the first time, no need to call msync()
  406. return expandAndWriteBack(newSize, std::move(preparedData), m_crypter ? !m_dicCrypt->empty() : !m_dic->empty());
  407. }
  408. return true;
  409. }
  410. // try a full rewrite to make space
  411. bool MMKV::expandAndWriteBack(size_t newSize, std::pair<mmkv::MMBuffer, size_t> preparedData, bool needSync) {
  412. auto fileSize = m_file->getFileSize();
  413. auto sizeOfDic = preparedData.second;
  414. size_t lenNeeded = sizeOfDic + Fixed32Size + newSize;
  415. size_t nowDicCount = m_crypter ? m_dicCrypt->size() : m_dic->size();
  416. size_t laterDicCount = std::max<size_t>(1, nowDicCount + 1);
  417. // or use <cmath> ceil()
  418. size_t avgItemSize = (lenNeeded + laterDicCount - 1) / laterDicCount;
  419. size_t futureUsage = avgItemSize * std::max<size_t>(8, laterDicCount / 2);
  420. // 1. no space for a full rewrite, double it
  421. // 2. or space is not large enough for future usage, double it to avoid frequently full rewrite
  422. if (lenNeeded >= fileSize || (needSync && (lenNeeded + futureUsage) >= fileSize)) {
  423. size_t oldSize = fileSize;
  424. do {
  425. fileSize *= 2;
  426. } while (lenNeeded + futureUsage >= fileSize);
  427. MMKVInfo("extending [%s] file size from %zu to %zu, incoming size:%zu, future usage:%zu", m_mmapID.c_str(),
  428. oldSize, fileSize, newSize, futureUsage);
  429. // if we can't extend size, rollback to old state
  430. // this is a good place to mock enlarging file failure
  431. if (!m_file->truncate(fileSize)) {
  432. return false;
  433. }
  434. // check if we fail to make more space
  435. if (!isFileValid()) {
  436. MMKVWarning("[%s] file not valid", m_mmapID.c_str());
  437. return false;
  438. }
  439. }
  440. return doFullWriteBack(std::move(preparedData), nullptr, needSync);
  441. }
  442. size_t MMKV::readActualSize() {
  443. MMKV_ASSERT(m_file->getMemory());
  444. MMKV_ASSERT(m_metaFile->isFileValid());
  445. uint32_t actualSize = 0;
  446. memcpy(&actualSize, m_file->getMemory(), Fixed32Size);
  447. if (m_metaInfo->m_version >= MMKVVersionActualSize) {
  448. if (m_metaInfo->m_actualSize != actualSize) {
  449. MMKVWarning("[%s] actual size %u, meta actual size %u", m_mmapID.c_str(), actualSize,
  450. m_metaInfo->m_actualSize);
  451. }
  452. return m_metaInfo->m_actualSize;
  453. } else {
  454. return actualSize;
  455. }
  456. }
  457. void MMKV::oldStyleWriteActualSize(size_t actualSize) {
  458. MMKV_ASSERT(m_file->getMemory());
  459. m_actualSize = actualSize;
  460. memcpy(m_file->getMemory(), &actualSize, Fixed32Size);
  461. }
  462. bool MMKV::writeActualSize(size_t size, uint32_t crcDigest, const void *iv, bool increaseSequence) {
  463. // backward compatibility
  464. oldStyleWriteActualSize(size);
  465. if (!m_metaFile->isFileValid()) {
  466. return false;
  467. }
  468. bool needsFullWrite = false;
  469. m_actualSize = size;
  470. m_metaInfo->m_actualSize = static_cast<uint32_t>(size);
  471. m_crcDigest = crcDigest;
  472. m_metaInfo->m_crcDigest = crcDigest;
  473. if (m_metaInfo->m_version < MMKVVersionSequence) {
  474. m_metaInfo->m_version = MMKVVersionSequence;
  475. needsFullWrite = true;
  476. }
  477. #ifndef MMKV_DISABLE_CRYPT
  478. if (mmkv_unlikely(iv)) {
  479. memcpy(m_metaInfo->m_vector, iv, sizeof(m_metaInfo->m_vector));
  480. if (m_metaInfo->m_version < MMKVVersionRandomIV) {
  481. m_metaInfo->m_version = MMKVVersionRandomIV;
  482. }
  483. needsFullWrite = true;
  484. }
  485. #endif
  486. if (mmkv_unlikely(increaseSequence)) {
  487. m_metaInfo->m_sequence++;
  488. m_metaInfo->m_lastConfirmedMetaInfo.lastActualSize = static_cast<uint32_t>(size);
  489. m_metaInfo->m_lastConfirmedMetaInfo.lastCRCDigest = crcDigest;
  490. if (m_metaInfo->m_version < MMKVVersionActualSize) {
  491. m_metaInfo->m_version = MMKVVersionActualSize;
  492. }
  493. needsFullWrite = true;
  494. MMKVInfo("[%s] increase sequence to %u, crc %u, actualSize %u", m_mmapID.c_str(), m_metaInfo->m_sequence,
  495. m_metaInfo->m_crcDigest, m_metaInfo->m_actualSize);
  496. }
  497. if (m_metaInfo->m_version < MMKVVersionFlag) {
  498. m_metaInfo->m_flags = 0;
  499. m_metaInfo->m_version = MMKVVersionFlag;
  500. needsFullWrite = true;
  501. }
  502. if (mmkv_unlikely(needsFullWrite)) {
  503. m_metaInfo->write(m_metaFile->getMemory());
  504. } else {
  505. m_metaInfo->writeCRCAndActualSizeOnly(m_metaFile->getMemory());
  506. }
  507. return true;
  508. }
  509. MMBuffer MMKV::getRawDataForKey(MMKVKey_t key) {
  510. checkLoadData();
  511. #ifndef MMKV_DISABLE_CRYPT
  512. if (m_crypter) {
  513. auto itr = m_dicCrypt->find(key);
  514. if (itr != m_dicCrypt->end()) {
  515. auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
  516. return itr->second.toMMBuffer(basePtr, m_crypter);
  517. }
  518. } else
  519. #endif
  520. {
  521. auto itr = m_dic->find(key);
  522. if (itr != m_dic->end()) {
  523. auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
  524. return itr->second.toMMBuffer(basePtr);
  525. }
  526. }
  527. MMBuffer nan;
  528. return nan;
  529. }
  530. mmkv::MMBuffer MMKV::getDataForKey(MMKVKey_t key) {
  531. if (mmkv_unlikely(m_enableKeyExpire)) {
  532. return getDataWithoutMTimeForKey(key);
  533. }
  534. return getRawDataForKey(key);
  535. }
  536. #ifndef MMKV_DISABLE_CRYPT
  537. // for Apple watch simulator
  538. # if defined(TARGET_OS_SIMULATOR) && defined(TARGET_CPU_X86)
  539. static AESCryptStatus t_status;
  540. # else
  541. thread_local AESCryptStatus t_status;
  542. # endif
  543. #endif // MMKV_DISABLE_CRYPT
  544. bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
  545. if ((!isDataHolder && data.length() == 0) || isKeyEmpty(key)) {
  546. return false;
  547. }
  548. SCOPED_LOCK(m_lock);
  549. SCOPED_LOCK(m_exclusiveProcessLock);
  550. checkLoadData();
  551. #ifndef MMKV_DISABLE_CRYPT
  552. if (m_crypter) {
  553. if (isDataHolder) {
  554. auto sizeNeededForData = pbRawVarint32Size((uint32_t) data.length()) + data.length();
  555. if (!KeyValueHolderCrypt::isValueStoredAsOffset(sizeNeededForData)) {
  556. data = MiniPBCoder::encodeDataWithObject(data);
  557. isDataHolder = false;
  558. }
  559. }
  560. auto itr = m_dicCrypt->find(key);
  561. if (itr != m_dicCrypt->end()) {
  562. bool onlyOneKey = !isMultiProcess() && m_dicCrypt->size() == 1;
  563. # ifdef MMKV_APPLE
  564. KVHolderRet_t ret;
  565. if (onlyOneKey) {
  566. ret = overrideDataWithKey(data, key, itr->second, isDataHolder);
  567. } else {
  568. ret = appendDataWithKey(data, key, itr->second, isDataHolder);
  569. }
  570. # else
  571. KVHolderRet_t ret;
  572. if (onlyOneKey) {
  573. ret = overrideDataWithKey(data, key, isDataHolder);
  574. } else {
  575. ret = appendDataWithKey(data, key, isDataHolder);
  576. }
  577. # endif
  578. if (!ret.first) {
  579. return false;
  580. }
  581. KeyValueHolderCrypt kvHolder;
  582. if (KeyValueHolderCrypt::isValueStoredAsOffset(ret.second.valueSize)) {
  583. kvHolder = KeyValueHolderCrypt(ret.second.keySize, ret.second.valueSize, ret.second.offset);
  584. memcpy(&kvHolder.cryptStatus, &t_status, sizeof(t_status));
  585. } else {
  586. kvHolder = KeyValueHolderCrypt(std::move(data));
  587. }
  588. if (mmkv_likely(!m_enableKeyExpire)) {
  589. itr->second = std::move(kvHolder);
  590. } else {
  591. itr = m_dicCrypt->find(key);
  592. if (itr != m_dicCrypt->end()) {
  593. itr->second = std::move(kvHolder);
  594. } else {
  595. // in case filterExpiredKeys() is triggered
  596. m_dicCrypt->emplace(key, std::move(kvHolder));
  597. mmkv_retain_key(key);
  598. }
  599. }
  600. } else {
  601. bool needOverride = !isMultiProcess() && m_dicCrypt->empty() && m_actualSize > 0;
  602. KVHolderRet_t ret;
  603. if (needOverride) {
  604. ret = overrideDataWithKey(data, key, isDataHolder);
  605. } else {
  606. ret = appendDataWithKey(data, key, isDataHolder);
  607. }
  608. if (!ret.first) {
  609. return false;
  610. }
  611. if (KeyValueHolderCrypt::isValueStoredAsOffset(ret.second.valueSize)) {
  612. auto r = m_dicCrypt->emplace(
  613. key, KeyValueHolderCrypt(ret.second.keySize, ret.second.valueSize, ret.second.offset));
  614. if (r.second) {
  615. memcpy(&(r.first->second.cryptStatus), &t_status, sizeof(t_status));
  616. }
  617. } else {
  618. m_dicCrypt->emplace(key, KeyValueHolderCrypt(std::move(data)));
  619. }
  620. mmkv_retain_key(key);
  621. }
  622. } else
  623. #endif // MMKV_DISABLE_CRYPT
  624. {
  625. auto itr = m_dic->find(key);
  626. if (itr != m_dic->end()) {
  627. // compare data before appending to file
  628. if (isCompareBeforeSetEnabled()) {
  629. auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
  630. MMBuffer oldValueData = itr->second.toMMBuffer(basePtr);
  631. if (isDataHolder) {
  632. CodedInputData inputData(oldValueData.getPtr(), oldValueData.length());
  633. try {
  634. // read extra holder header bytes and to real MMBuffer
  635. oldValueData = CodedInputData::readRealData(oldValueData);
  636. if (oldValueData == data) {
  637. // MMKVInfo("[key] %s, set the same data", key.c_str());
  638. return true;
  639. }
  640. } catch (std::exception &exception) {
  641. MMKVWarning("compareBeforeSet exception: %s", exception.what());
  642. } catch (...) {
  643. MMKVWarning("compareBeforeSet fail");
  644. }
  645. } else {
  646. if (oldValueData == data) {
  647. // MMKVInfo("[key] %s, set the same data", key.c_str());
  648. return true;
  649. }
  650. }
  651. }
  652. bool onlyOneKey = !isMultiProcess() && m_dic->size() == 1;
  653. if (mmkv_likely(!m_enableKeyExpire)) {
  654. KVHolderRet_t ret;
  655. if (onlyOneKey) {
  656. ret = overrideDataWithKey(data, itr->second, isDataHolder);
  657. } else {
  658. ret = appendDataWithKey(data, itr->second, isDataHolder);
  659. }
  660. if (!ret.first) {
  661. return false;
  662. }
  663. itr->second = std::move(ret.second);
  664. } else {
  665. KVHolderRet_t ret;
  666. if (onlyOneKey) {
  667. ret = overrideDataWithKey(data, key, isDataHolder);
  668. } else {
  669. ret = appendDataWithKey(data, key, isDataHolder);
  670. }
  671. if (!ret.first) {
  672. return false;
  673. }
  674. itr = m_dic->find(key);
  675. if (itr != m_dic->end()) {
  676. itr->second = std::move(ret.second);
  677. } else {
  678. // in case filterExpiredKeys() is triggered
  679. m_dic->emplace(key, std::move(ret.second));
  680. mmkv_retain_key(key);
  681. }
  682. }
  683. } else {
  684. bool needOverride = !isMultiProcess() && m_dic->empty() && m_actualSize > 0;
  685. KVHolderRet_t ret;
  686. if (needOverride) {
  687. ret = overrideDataWithKey(data, key, isDataHolder);
  688. } else {
  689. ret = appendDataWithKey(data, key, isDataHolder);
  690. }
  691. if (!ret.first) {
  692. return false;
  693. }
  694. m_dic->emplace(key, std::move(ret.second));
  695. mmkv_retain_key(key);
  696. }
  697. }
  698. m_hasFullWriteback = false;
  699. return true;
  700. }
  701. template <typename T>
  702. static void eraseHelper(T& container, std::string_view key) {
  703. auto itr = container.find(key);
  704. if (itr != container.end()) {
  705. container.erase(itr);
  706. }
  707. }
  708. bool MMKV::removeDataForKey(MMKVKey_t key) {
  709. if (isKeyEmpty(key)) {
  710. return false;
  711. }
  712. #ifndef MMKV_DISABLE_CRYPT
  713. if (m_crypter) {
  714. auto itr = m_dicCrypt->find(key);
  715. if (itr != m_dicCrypt->end()) {
  716. m_hasFullWriteback = false;
  717. static MMBuffer nan;
  718. # ifdef MMKV_APPLE
  719. auto ret = appendDataWithKey(nan, key, itr->second);
  720. if (ret.first) {
  721. if (mmkv_unlikely(m_enableKeyExpire)) {
  722. // filterExpiredKeys() may invalid itr
  723. itr = m_dicCrypt->find(key);
  724. if (itr == m_dicCrypt->end()) {
  725. return true;
  726. }
  727. }
  728. auto oldKey = itr->first;
  729. m_dicCrypt->erase(itr);
  730. [oldKey release];
  731. }
  732. # else
  733. auto ret = appendDataWithKey(nan, key);
  734. if (ret.first) {
  735. if (mmkv_unlikely(m_enableKeyExpire)) {
  736. eraseHelper(*m_dicCrypt, key);
  737. } else {
  738. m_dicCrypt->erase(itr);
  739. }
  740. }
  741. # endif
  742. return ret.first;
  743. }
  744. } else
  745. #endif // MMKV_DISABLE_CRYPT
  746. {
  747. auto itr = m_dic->find(key);
  748. if (itr != m_dic->end()) {
  749. m_hasFullWriteback = false;
  750. static MMBuffer nan;
  751. auto ret = mmkv_likely(!m_enableKeyExpire) ? appendDataWithKey(nan, itr->second) : appendDataWithKey(nan, key);
  752. if (ret.first) {
  753. #ifdef MMKV_APPLE
  754. if (mmkv_unlikely(m_enableKeyExpire)) {
  755. // filterExpiredKeys() may invalid itr
  756. itr = m_dic->find(key);
  757. if (itr == m_dic->end()) {
  758. return true;
  759. }
  760. }
  761. auto oldKey = itr->first;
  762. m_dic->erase(itr);
  763. [oldKey release];
  764. #else
  765. if (mmkv_unlikely(m_enableKeyExpire)) {
  766. // filterExpiredKeys() may invalid itr
  767. eraseHelper(*m_dic, key);
  768. } else {
  769. m_dic->erase(itr);
  770. }
  771. #endif
  772. }
  773. return ret.first;
  774. }
  775. }
  776. return false;
  777. }
  778. KVHolderRet_t
  779. MMKV::doAppendDataWithKey(const MMBuffer &data, const MMBuffer &keyData, bool isDataHolder, uint32_t originKeyLength) {
  780. auto isKeyEncoded = (originKeyLength < keyData.length());
  781. auto keyLength = static_cast<uint32_t>(keyData.length());
  782. auto valueLength = static_cast<uint32_t>(data.length());
  783. if (isDataHolder) {
  784. valueLength += pbRawVarint32Size(valueLength);
  785. }
  786. // size needed to encode the key
  787. size_t size = isKeyEncoded ? keyLength : (keyLength + pbRawVarint32Size(keyLength));
  788. // size needed to encode the value
  789. size += valueLength + pbRawVarint32Size(valueLength);
  790. SCOPED_LOCK(m_exclusiveProcessLock);
  791. bool hasEnoughSize = ensureMemorySize(size);
  792. if (!hasEnoughSize || !isFileValid()) {
  793. return make_pair(false, KeyValueHolder());
  794. }
  795. #ifndef MMKV_DISABLE_CRYPT
  796. if (m_crypter) {
  797. if (KeyValueHolderCrypt::isValueStoredAsOffset(valueLength)) {
  798. m_crypter->getCurStatus(t_status);
  799. }
  800. }
  801. #endif
  802. try {
  803. if (isKeyEncoded) {
  804. m_output->writeRawData(keyData);
  805. } else {
  806. m_output->writeData(keyData);
  807. }
  808. if (isDataHolder) {
  809. m_output->writeRawVarint32((int32_t) valueLength);
  810. }
  811. m_output->writeData(data); // note: write size of data
  812. } catch (std::exception &e) {
  813. MMKVError("%s", e.what());
  814. return make_pair(false, KeyValueHolder());
  815. } catch (...) {
  816. MMKVError("append fail");
  817. return make_pair(false, KeyValueHolder());
  818. }
  819. auto offset = static_cast<uint32_t>(m_actualSize);
  820. auto ptr = (uint8_t *) m_file->getMemory() + Fixed32Size + m_actualSize;
  821. #ifndef MMKV_DISABLE_CRYPT
  822. if (m_crypter) {
  823. m_crypter->encrypt(ptr, ptr, size);
  824. }
  825. #endif
  826. m_actualSize += size;
  827. updateCRCDigest(ptr, size);
  828. return make_pair(true, KeyValueHolder(originKeyLength, valueLength, offset));
  829. }
  830. KVHolderRet_t MMKV::doOverrideDataWithKey(const MMBuffer &data,
  831. const MMBuffer &keyData,
  832. bool isDataHolder,
  833. uint32_t originKeyLength) {
  834. auto isKeyEncoded = (originKeyLength < keyData.length());
  835. auto keyLength = static_cast<uint32_t>(keyData.length());
  836. auto valueLength = static_cast<uint32_t>(data.length());
  837. if (isDataHolder) {
  838. valueLength += pbRawVarint32Size(valueLength);
  839. }
  840. // size needed to encode the key
  841. size_t size = isKeyEncoded ? keyLength : (keyLength + pbRawVarint32Size(keyLength));
  842. // size needed to encode the value
  843. size += valueLength + pbRawVarint32Size(valueLength);
  844. if (!checkSizeForOverride(size)) {
  845. return doAppendDataWithKey(data, keyData, isDataHolder, originKeyLength);
  846. }
  847. // we don't not support override in multi-process mode
  848. // SCOPED_LOCK(m_exclusiveProcessLock);
  849. #ifndef MMKV_DISABLE_CRYPT
  850. if (m_crypter) {
  851. if (m_metaInfo->m_version >= MMKVVersionRandomIV) {
  852. m_crypter->resetIV(m_metaInfo->m_vector, sizeof(m_metaInfo->m_vector));
  853. } else {
  854. m_crypter->resetIV();
  855. }
  856. }
  857. #endif
  858. try {
  859. // write ItemSizeHolder
  860. m_output->setPosition(0);
  861. m_output->writeUInt32(AESCrypt::randomItemSizeHolder(ItemSizeHolderSize));
  862. m_actualSize = ItemSizeHolderSize;
  863. #ifndef MMKV_DISABLE_CRYPT
  864. if (m_crypter) {
  865. auto ptr = (uint8_t *) m_file->getMemory() + Fixed32Size;
  866. m_crypter->encrypt(ptr, ptr, m_actualSize);
  867. if (KeyValueHolderCrypt::isValueStoredAsOffset(valueLength)) {
  868. m_crypter->getCurStatus(t_status);
  869. }
  870. }
  871. #endif
  872. if (isKeyEncoded) {
  873. m_output->writeRawData(keyData);
  874. } else {
  875. m_output->writeData(keyData);
  876. }
  877. if (isDataHolder) {
  878. m_output->writeRawVarint32((int32_t) valueLength);
  879. }
  880. m_output->writeData(data); // note: write size of data
  881. } catch (std::exception &e) {
  882. MMKVError("%s", e.what());
  883. return make_pair(false, KeyValueHolder());
  884. } catch (...) {
  885. MMKVError("append fail");
  886. return make_pair(false, KeyValueHolder());
  887. }
  888. auto offset = static_cast<uint32_t>(m_actualSize);
  889. m_actualSize += size;
  890. #ifndef MMKV_DISABLE_CRYPT
  891. if (m_crypter) {
  892. auto ptr = (uint8_t *) m_file->getMemory() + Fixed32Size + offset;
  893. m_crypter->encrypt(ptr, ptr, size);
  894. }
  895. #endif
  896. recalculateCRCDigestOnly();
  897. return make_pair(true, KeyValueHolder(originKeyLength, valueLength, offset));
  898. }
  899. bool MMKV::checkSizeForOverride(size_t size) {
  900. if (!isFileValid()) {
  901. MMKVWarning("[%s] file not valid", m_mmapID.c_str());
  902. return false;
  903. }
  904. // only override if the file can hole it without ftruncate()
  905. auto fileSize = m_file->getFileSize();
  906. auto spaceNeededForOverride = size + Fixed32Size + ItemSizeHolderSize;
  907. if (size > fileSize || spaceNeededForOverride > fileSize) {
  908. return false;
  909. }
  910. return true;
  911. }
  912. KVHolderRet_t MMKV::appendDataWithKey(const MMBuffer &data, MMKVKey_t key, bool isDataHolder) {
  913. #ifdef MMKV_APPLE
  914. auto oData = [key dataUsingEncoding:NSUTF8StringEncoding];
  915. auto keyData = MMBuffer(oData, MMBufferNoCopy);
  916. #else
  917. auto keyData = MMBuffer((void *) key.data(), key.size(), MMBufferNoCopy);
  918. #endif
  919. return doAppendDataWithKey(data, keyData, isDataHolder, static_cast<uint32_t>(keyData.length()));
  920. }
  921. KVHolderRet_t MMKV::overrideDataWithKey(const MMBuffer &data, MMKVKey_t key, bool isDataHolder) {
  922. #ifdef MMKV_APPLE
  923. auto oData = [key dataUsingEncoding:NSUTF8StringEncoding];
  924. auto keyData = MMBuffer(oData, MMBufferNoCopy);
  925. #else
  926. auto keyData = MMBuffer((void *) key.data(), key.size(), MMBufferNoCopy);
  927. #endif
  928. return doOverrideDataWithKey(data, keyData, isDataHolder, static_cast<uint32_t>(keyData.length()));
  929. }
  930. KVHolderRet_t MMKV::appendDataWithKey(const MMBuffer &data, const KeyValueHolder &kvHolder, bool isDataHolder) {
  931. SCOPED_LOCK(m_exclusiveProcessLock);
  932. uint32_t keyLength = kvHolder.keySize;
  933. // size needed to encode the key
  934. size_t rawKeySize = keyLength + pbRawVarint32Size(keyLength);
  935. // ensureMemorySize() might change kvHolder.offset, so have to do it early
  936. {
  937. auto valueLength = static_cast<uint32_t>(data.length());
  938. if (isDataHolder) {
  939. valueLength += pbRawVarint32Size(valueLength);
  940. }
  941. auto size = rawKeySize + valueLength + pbRawVarint32Size(valueLength);
  942. bool hasEnoughSize = ensureMemorySize(size);
  943. if (!hasEnoughSize) {
  944. return make_pair(false, KeyValueHolder());
  945. }
  946. }
  947. auto basePtr = (uint8_t *) m_file->getMemory() + Fixed32Size;
  948. MMBuffer keyData(basePtr + kvHolder.offset, rawKeySize, MMBufferNoCopy);
  949. return doAppendDataWithKey(data, keyData, isDataHolder, keyLength);
  950. }
  951. // only one key in dict, do not append, just rewrite from beginning
  952. KVHolderRet_t MMKV::overrideDataWithKey(const MMBuffer &data, const KeyValueHolder &kvHolder, bool isDataHolder) {
  953. // we don't not support override in multi-process mode
  954. // SCOPED_LOCK(m_exclusiveProcessLock);
  955. uint32_t keyLength = kvHolder.keySize;
  956. // size needed to encode the key
  957. size_t rawKeySize = keyLength + pbRawVarint32Size(keyLength);
  958. // ensureMemorySize() (inside doAppendDataWithKey() which be called from doOverrideDataWithKey())
  959. // might change kvHolder.offset, so have to do it early
  960. {
  961. auto valueLength = static_cast<uint32_t>(data.length());
  962. if (isDataHolder) {
  963. valueLength += pbRawVarint32Size(valueLength);
  964. }
  965. auto size = rawKeySize + valueLength + pbRawVarint32Size(valueLength);
  966. bool hasEnoughSize = checkSizeForOverride(size);
  967. if (!hasEnoughSize) {
  968. return appendDataWithKey(data, kvHolder, isDataHolder);
  969. }
  970. }
  971. auto basePtr = (uint8_t *) m_file->getMemory() + Fixed32Size;
  972. MMBuffer keyData(basePtr + kvHolder.offset, rawKeySize, MMBufferNoCopy);
  973. return doOverrideDataWithKey(data, keyData, isDataHolder, keyLength);
  974. }
  975. bool MMKV::fullWriteback(AESCrypt *newCrypter, bool onlyWhileExpire) {
  976. if (m_hasFullWriteback) {
  977. return true;
  978. }
  979. if (m_needLoadFromFile) {
  980. return true;
  981. }
  982. if (!isFileValid()) {
  983. MMKVWarning("[%s] file not valid", m_mmapID.c_str());
  984. return false;
  985. }
  986. if (mmkv_unlikely(m_enableKeyExpire)) {
  987. auto expiredCount = filterExpiredKeys();
  988. if (onlyWhileExpire && expiredCount == 0) {
  989. return true;
  990. }
  991. }
  992. auto isEmpty = m_crypter ? m_dicCrypt->empty() : m_dic->empty();
  993. if (isEmpty) {
  994. clearAll();
  995. return true;
  996. }
  997. SCOPED_LOCK(m_exclusiveProcessLock);
  998. auto preparedData = m_crypter ? prepareEncode(*m_dicCrypt) : prepareEncode(*m_dic);
  999. auto sizeOfDic = preparedData.second;
  1000. if (sizeOfDic > 0) {
  1001. auto fileSize = m_file->getFileSize();
  1002. if (sizeOfDic + Fixed32Size <= fileSize) {
  1003. return doFullWriteBack(std::move(preparedData), newCrypter);
  1004. } else {
  1005. assert(0);
  1006. assert(newCrypter == nullptr);
  1007. // expandAndWriteBack() will extend file & full rewrite, no need to write back again
  1008. auto newSize = sizeOfDic + Fixed32Size - fileSize;
  1009. return expandAndWriteBack(newSize, std::move(preparedData));
  1010. }
  1011. }
  1012. return false;
  1013. }
  1014. // we don't need to really serialize the dictionary, just reuse what's already in the file
  1015. static void
  1016. memmoveDictionary(MMKVMap &dic, CodedOutputData *output, uint8_t *ptr, AESCrypt *encrypter, size_t totalSize) {
  1017. auto originOutputPtr = output->curWritePointer();
  1018. // make space to hold the fake size of dictionary's serialization result
  1019. auto writePtr = originOutputPtr + ItemSizeHolderSize;
  1020. // reuse what's already in the file
  1021. if (!dic.empty()) {
  1022. // sort by offset
  1023. vector<KeyValueHolder *> vec;
  1024. vec.reserve(dic.size());
  1025. for (auto &itr : dic) {
  1026. vec.push_back(&itr.second);
  1027. }
  1028. sort(vec.begin(), vec.end(), [](const auto &left, const auto &right) { return left->offset < right->offset; });
  1029. // merge nearby items to make memmove quicker
  1030. vector<pair<uint32_t, uint32_t>> dataSections; // pair(offset, size)
  1031. dataSections.emplace_back(vec.front()->offset, vec.front()->computedKVSize + vec.front()->valueSize);
  1032. for (size_t index = 1, total = vec.size(); index < total; index++) {
  1033. auto kvHolder = vec[index];
  1034. auto &lastSection = dataSections.back();
  1035. if (kvHolder->offset == lastSection.first + lastSection.second) {
  1036. lastSection.second += kvHolder->computedKVSize + kvHolder->valueSize;
  1037. } else {
  1038. dataSections.emplace_back(kvHolder->offset, kvHolder->computedKVSize + kvHolder->valueSize);
  1039. }
  1040. }
  1041. // do the move
  1042. auto basePtr = ptr + Fixed32Size;
  1043. for (auto &section : dataSections) {
  1044. // memmove() should handle this well: src == dst
  1045. memmove(writePtr, basePtr + section.first, section.second);
  1046. writePtr += section.second;
  1047. }
  1048. // update offset
  1049. if (!encrypter) {
  1050. auto offset = ItemSizeHolderSize;
  1051. for (auto kvHolder : vec) {
  1052. kvHolder->offset = offset;
  1053. offset += kvHolder->computedKVSize + kvHolder->valueSize;
  1054. }
  1055. }
  1056. }
  1057. // hold the fake size of dictionary's serialization result
  1058. output->writeUInt32(AESCrypt::randomItemSizeHolder(ItemSizeHolderSize));
  1059. auto writtenSize = static_cast<size_t>(writePtr - originOutputPtr);
  1060. #ifndef MMKV_DISABLE_CRYPT
  1061. if (encrypter) {
  1062. encrypter->encrypt(originOutputPtr, originOutputPtr, writtenSize);
  1063. }
  1064. #endif
  1065. assert(writtenSize == totalSize);
  1066. output->seek(writtenSize - ItemSizeHolderSize);
  1067. }
  1068. #ifndef MMKV_DISABLE_CRYPT
  1069. static void memmoveDictionary(MMKVMapCrypt &dic,
  1070. CodedOutputData *output,
  1071. uint8_t *ptr,
  1072. AESCrypt *decrypter,
  1073. AESCrypt *encrypter,
  1074. pair<MMBuffer, size_t> &preparedData) {
  1075. // reuse what's already in the file
  1076. vector<KeyValueHolderCrypt *> vec;
  1077. if (!dic.empty()) {
  1078. // sort by offset
  1079. vec.reserve(dic.size());
  1080. for (auto &itr : dic) {
  1081. if (itr.second.type == KeyValueHolderType_Offset) {
  1082. vec.push_back(&itr.second);
  1083. }
  1084. }
  1085. sort(vec.begin(), vec.end(), [](auto left, auto right) { return left->offset < right->offset; });
  1086. }
  1087. auto sizeHolderSize = ItemSizeHolderSize;
  1088. auto sizeHolder = AESCrypt::randomItemSizeHolder(sizeHolderSize);
  1089. if (!vec.empty()) {
  1090. auto smallestOffset = vec.front()->offset;
  1091. if (smallestOffset != ItemSizeHolderSize && smallestOffset <= 5) {
  1092. sizeHolderSize = smallestOffset;
  1093. assert(sizeHolderSize != 0);
  1094. static const uint32_t ItemSizeHolders[] = {0, 0x0f, 0xff, 0xffff, 0xffffff, 0xffffffff};
  1095. sizeHolder = AESCrypt::randomItemSizeHolder(sizeHolderSize);
  1096. assert(sizeHolder >= ItemSizeHolders[sizeHolderSize] && sizeHolder <= ItemSizeHolders[sizeHolderSize]);
  1097. }
  1098. }
  1099. output->writeRawVarint32(static_cast<int32_t>(sizeHolder));
  1100. auto writePtr = output->curWritePointer();
  1101. if (encrypter) {
  1102. encrypter->encrypt(writePtr - sizeHolderSize, writePtr - sizeHolderSize, sizeHolderSize);
  1103. }
  1104. if (!vec.empty()) {
  1105. // merge nearby items to make memmove quicker
  1106. vector<tuple<uint32_t, uint32_t, AESCryptStatus *>> dataSections; // pair(offset, size)
  1107. dataSections.push_back(vec.front()->toTuple());
  1108. for (size_t index = 1, total = vec.size(); index < total; index++) {
  1109. auto kvHolder = vec[index];
  1110. auto &lastSection = dataSections.back();
  1111. if (kvHolder->offset == get<0>(lastSection) + get<1>(lastSection)) {
  1112. get<1>(lastSection) += kvHolder->pbKeyValueSize + kvHolder->keySize + kvHolder->valueSize;
  1113. } else {
  1114. dataSections.push_back(kvHolder->toTuple());
  1115. }
  1116. }
  1117. // do the move
  1118. auto basePtr = ptr + Fixed32Size;
  1119. for (auto &section : dataSections) {
  1120. auto crypter = decrypter->cloneWithStatus(*get<2>(section));
  1121. crypter.decrypt(basePtr + get<0>(section), writePtr, get<1>(section));
  1122. writePtr += get<1>(section);
  1123. }
  1124. // update offset & AESCryptStatus
  1125. if (encrypter) {
  1126. auto offset = sizeHolderSize;
  1127. for (auto kvHolder : vec) {
  1128. kvHolder->offset = offset;
  1129. auto size = kvHolder->pbKeyValueSize + kvHolder->keySize + kvHolder->valueSize;
  1130. encrypter->getCurStatus(kvHolder->cryptStatus);
  1131. encrypter->encrypt(basePtr + offset, basePtr + offset, size);
  1132. offset += size;
  1133. }
  1134. }
  1135. }
  1136. auto &data = preparedData.first;
  1137. if (data.length() > 0) {
  1138. auto dataSize = CodedInputData(data.getPtr(), data.length()).readUInt32();
  1139. if (dataSize > 0) {
  1140. auto dataPtr = (uint8_t *) data.getPtr() + pbRawVarint32Size(dataSize);
  1141. if (encrypter) {
  1142. encrypter->encrypt(dataPtr, writePtr, dataSize);
  1143. } else {
  1144. memcpy(writePtr, dataPtr, dataSize);
  1145. }
  1146. writePtr += dataSize;
  1147. }
  1148. }
  1149. auto writtenSize = static_cast<size_t>(writePtr - output->curWritePointer());
  1150. assert(writtenSize + sizeHolderSize == preparedData.second);
  1151. output->seek(writtenSize);
  1152. }
  1153. # define InvalidCryptPtr ((AESCrypt *) (void *) (1))
  1154. #endif // MMKV_DISABLE_CRYPT
  1155. static void fullWriteBackWholeData(MMBuffer allData, size_t totalSize, CodedOutputData *output) {
  1156. auto originOutputPtr = output->curWritePointer();
  1157. output->writeUInt32(AESCrypt::randomItemSizeHolder(ItemSizeHolderSize));
  1158. if (allData.length() > 0) {
  1159. auto dataSize = CodedInputData(allData.getPtr(), allData.length()).readUInt32();
  1160. if (dataSize > 0) {
  1161. auto dataPtr = (uint8_t *) allData.getPtr() + pbRawVarint32Size(dataSize);
  1162. memcpy(output->curWritePointer(), dataPtr, dataSize);
  1163. output->seek(dataSize);
  1164. }
  1165. }
  1166. [[maybe_unused]] auto writtenSize = (size_t)(output->curWritePointer() - originOutputPtr);
  1167. assert(writtenSize == totalSize);
  1168. }
  1169. #ifndef MMKV_DISABLE_CRYPT
  1170. bool MMKV::doFullWriteBack(pair<MMBuffer, size_t> prepared, AESCrypt *newCrypter, bool needSync) {
  1171. auto ptr = (uint8_t *) m_file->getMemory();
  1172. auto totalSize = prepared.second;
  1173. uint8_t newIV[AES_KEY_LEN];
  1174. auto encrypter = (newCrypter == InvalidCryptPtr) ? nullptr : (newCrypter ? newCrypter : m_crypter);
  1175. if (encrypter) {
  1176. AESCrypt::fillRandomIV(newIV);
  1177. encrypter->resetIV(newIV, sizeof(newIV));
  1178. }
  1179. delete m_output;
  1180. m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
  1181. if (m_crypter) {
  1182. auto decrypter = m_crypter;
  1183. memmoveDictionary(*m_dicCrypt, m_output, ptr, decrypter, encrypter, prepared);
  1184. } else if (prepared.first.length() != 0) {
  1185. auto &preparedData = prepared.first;
  1186. fullWriteBackWholeData(std::move(preparedData), totalSize, m_output);
  1187. if (encrypter) {
  1188. encrypter->encrypt(ptr + Fixed32Size, ptr + Fixed32Size, totalSize);
  1189. }
  1190. } else {
  1191. memmoveDictionary(*m_dic, m_output, ptr, encrypter, totalSize);
  1192. }
  1193. m_actualSize = totalSize;
  1194. if (encrypter) {
  1195. recalculateCRCDigestWithIV(newIV);
  1196. } else {
  1197. recalculateCRCDigestWithIV(nullptr);
  1198. }
  1199. m_hasFullWriteback = true;
  1200. // make sure lastConfirmedMetaInfo is saved if needed
  1201. if (needSync) {
  1202. sync(MMKV_SYNC);
  1203. }
  1204. return true;
  1205. }
  1206. #else // MMKV_DISABLE_CRYPT
  1207. bool MMKV::doFullWriteBack(pair<MMBuffer, size_t> prepared, AESCrypt *, bool needSync) {
  1208. auto ptr = (uint8_t *) m_file->getMemory();
  1209. auto totalSize = prepared.second;
  1210. delete m_output;
  1211. m_output = new CodedOutputData(ptr + Fixed32Size, m_file->getFileSize() - Fixed32Size);
  1212. if (prepared.first.length() != 0) {
  1213. auto &preparedData = prepared.first;
  1214. fullWriteBackWholeData(std::move(preparedData), totalSize, m_output);
  1215. } else {
  1216. constexpr AESCrypt *encrypter = nullptr;
  1217. memmoveDictionary(*m_dic, m_output, ptr, encrypter, totalSize);
  1218. }
  1219. m_actualSize = totalSize;
  1220. recalculateCRCDigestWithIV(nullptr);
  1221. m_hasFullWriteback = true;
  1222. // make sure lastConfirmedMetaInfo is saved if needed
  1223. if (needSync) {
  1224. sync(MMKV_SYNC);
  1225. }
  1226. return true;
  1227. }
  1228. #endif // MMKV_DISABLE_CRYPT
  1229. #ifndef MMKV_DISABLE_CRYPT
  1230. bool MMKV::reKey(const string &cryptKey) {
  1231. if (isReadOnly()) {
  1232. MMKVWarning("[%s] file readonly", m_mmapID.c_str());
  1233. return false;
  1234. }
  1235. SCOPED_LOCK(m_lock);
  1236. SCOPED_LOCK(m_exclusiveProcessLock);
  1237. checkLoadData();
  1238. if (!isFileValid()) {
  1239. MMKVWarning("[%s] file not valid", m_mmapID.c_str());
  1240. return false;
  1241. }
  1242. bool ret = false;
  1243. if (m_crypter) {
  1244. if (cryptKey.length() > 0) {
  1245. string oldKey = this->cryptKey();
  1246. if (cryptKey == oldKey) {
  1247. return true;
  1248. } else {
  1249. // change encryption key
  1250. MMKVInfo("reKey with new aes key");
  1251. auto newCrypt = new AESCrypt(cryptKey.data(), cryptKey.length());
  1252. m_hasFullWriteback = false;
  1253. ret = fullWriteback(newCrypt);
  1254. if (ret) {
  1255. delete m_crypter;
  1256. m_crypter = newCrypt;
  1257. } else {
  1258. delete newCrypt;
  1259. }
  1260. }
  1261. } else {
  1262. // decryption to plain text
  1263. MMKVInfo("reKey to no aes key");
  1264. m_hasFullWriteback = false;
  1265. ret = fullWriteback(InvalidCryptPtr);
  1266. if (ret) {
  1267. delete m_crypter;
  1268. m_crypter = nullptr;
  1269. if (!m_dic) {
  1270. m_dic = new MMKVMap();
  1271. }
  1272. }
  1273. }
  1274. } else {
  1275. if (cryptKey.length() > 0) {
  1276. // transform plain text to encrypted text
  1277. MMKVInfo("reKey to a aes key");
  1278. m_hasFullWriteback = false;
  1279. auto newCrypt = new AESCrypt(cryptKey.data(), cryptKey.length());
  1280. ret = fullWriteback(newCrypt);
  1281. if (ret) {
  1282. m_crypter = newCrypt;
  1283. if (!m_dicCrypt) {
  1284. m_dicCrypt = new MMKVMapCrypt();
  1285. }
  1286. } else {
  1287. delete newCrypt;
  1288. }
  1289. } else {
  1290. return true;
  1291. }
  1292. }
  1293. // m_dic or m_dicCrypt is not valid after reKey
  1294. if (ret) {
  1295. clearMemoryCache();
  1296. }
  1297. return ret;
  1298. }
  1299. #endif
  1300. void MMKV::trim() {
  1301. MMKVInfo("prepare to trim %s", m_mmapID.c_str());
  1302. if (isReadOnly()) {
  1303. MMKVWarning("[%s] file readonly", m_mmapID.c_str());
  1304. return;
  1305. }
  1306. SCOPED_LOCK(m_lock);
  1307. SCOPED_LOCK(m_exclusiveProcessLock);
  1308. checkLoadData();
  1309. if (!isFileValid()) {
  1310. MMKVWarning("[%s] file not valid", m_mmapID.c_str());
  1311. return;
  1312. }
  1313. if (m_actualSize == 0) {
  1314. clearAll();
  1315. return;
  1316. } else if (m_file->getFileSize() <= m_expectedCapacity) {
  1317. return;
  1318. }
  1319. fullWriteback();
  1320. auto oldSize = m_file->getFileSize();
  1321. auto fileSize = oldSize;
  1322. while (fileSize > (m_actualSize + Fixed32Size) * 2) {
  1323. fileSize /= 2;
  1324. }
  1325. fileSize = std::max<size_t>(fileSize, m_expectedCapacity);
  1326. if (oldSize == fileSize) {
  1327. MMKVInfo("there's no need to trim %s with size %zu, actualSize %zu", m_mmapID.c_str(), fileSize, m_actualSize);
  1328. return;
  1329. }
  1330. MMKVInfo("trimming %s from %zu to %zu, actualSize %zu", m_mmapID.c_str(), oldSize, fileSize, m_actualSize);
  1331. if (!m_file->truncate(fileSize)) {
  1332. return;
  1333. }
  1334. fileSize = m_file->getFileSize();
  1335. auto ptr = (uint8_t *) m_file->getMemory();
  1336. delete m_output;
  1337. m_output = new CodedOutputData(ptr + pbFixed32Size(), fileSize - Fixed32Size);
  1338. m_output->seek(m_actualSize);
  1339. MMKVInfo("finish trim %s from %zu to %zu", m_mmapID.c_str(), oldSize, fileSize);
  1340. }
  1341. void MMKV::clearAll(bool keepSpace) {
  1342. MMKVInfo("cleaning all key-values from [%s]", m_mmapID.c_str());
  1343. if (isReadOnly()) {
  1344. MMKVWarning("[%s] file readonly", m_mmapID.c_str());
  1345. return;
  1346. }
  1347. SCOPED_LOCK(m_lock);
  1348. SCOPED_LOCK(m_exclusiveProcessLock);
  1349. checkLoadData();
  1350. if (!isFileValid()) {
  1351. MMKVWarning("[%s] file not valid", m_mmapID.c_str());
  1352. return;
  1353. }
  1354. if (m_file->getFileSize() == m_expectedCapacity && m_actualSize == 0) {
  1355. MMKVInfo("nothing to clear for [%s]", m_mmapID.c_str());
  1356. return;
  1357. }
  1358. if (!keepSpace) {
  1359. m_file->truncate(m_expectedCapacity);
  1360. }
  1361. #ifndef MMKV_DISABLE_CRYPT
  1362. uint8_t newIV[AES_KEY_LEN];
  1363. AESCrypt::fillRandomIV(newIV);
  1364. if (m_crypter) {
  1365. m_crypter->resetIV(newIV, sizeof(newIV));
  1366. }
  1367. writeActualSize(0, 0, newIV, IncreaseSequence);
  1368. #else
  1369. writeActualSize(0, 0, nullptr, IncreaseSequence);
  1370. #endif
  1371. m_metaFile->msync(MMKV_SYNC);
  1372. clearMemoryCache(keepSpace);
  1373. loadFromFile();
  1374. }
  1375. size_t MMKV::importFrom(MMKV *src) {
  1376. if (!src) {
  1377. return 0;
  1378. }
  1379. MMKVInfo("importing from [%s] to [%s]", src->m_mmapID.c_str(), m_mmapID.c_str());
  1380. if (isReadOnly()) {
  1381. MMKVWarning("[%s] file readonly", m_mmapID.c_str());
  1382. return 0;
  1383. }
  1384. SCOPED_LOCK(m_lock);
  1385. SCOPED_LOCK(m_exclusiveProcessLock);
  1386. SCOPED_LOCK(src->m_lock);
  1387. SCOPED_LOCK(src->m_exclusiveProcessLock);
  1388. checkLoadData();
  1389. src->checkLoadData();
  1390. if (!isFileValid() || !src->isFileValid()) {
  1391. MMKVWarning("[%s] or [%s] file not valid", m_mmapID.c_str(), src->m_mmapID.c_str());
  1392. return 0;
  1393. }
  1394. size_t count = 0;
  1395. bool notAutoExpire = !m_enableKeyExpire;
  1396. auto time = UInt32ToInt32((m_expiredInSeconds != ExpireNever) ? getCurrentTimeInSecond() + m_expiredInSeconds : ExpireNever);
  1397. for (auto &key : src->allKeys(false)) {
  1398. auto value = src->getDataForKey(key);
  1399. if (value.length() > 0) {
  1400. if (mmkv_likely(notAutoExpire)) {
  1401. setDataForKey(std::move(value), key, false);
  1402. } else {
  1403. auto tmp = MMBuffer(value.length() + Fixed32Size);
  1404. CodedOutputData output(tmp.getPtr(), tmp.length());
  1405. // no need write size, it's already written in value
  1406. output.writeRawData(value);
  1407. output.writeRawLittleEndian32(time);
  1408. setDataForKey(std::move(tmp), key, false);
  1409. }
  1410. count++;
  1411. }
  1412. }
  1413. MMKVInfo("imported %llu from [%s] to [%s]", count, src->m_mmapID.c_str(), m_mmapID.c_str());
  1414. return count;
  1415. }
  1416. static std::pair<MMKVPath_t, MMKVPath_t> getStorage(const std::string &mmapID, const MMKVPath_t *relatePath, std::string& realID, std::string& mmapKey) {
  1417. #ifdef MMKV_ANDROID
  1418. auto migrateStatus = tryMigrateLegacyMMKVFile(mmapID, relatePath);
  1419. if (migrateStatus == MigrateStatus::NoneExist) {
  1420. MMKVWarning("file id [%s] not exist in path %s", mmapID.c_str(), relatePath ? relatePath->c_str() : "default");
  1421. return {};
  1422. } else if (migrateStatus == MigrateStatus::OldToNewMigrateFail) {
  1423. realID = legacyMmapedKVKey(mmapID, relatePath);
  1424. } else {
  1425. realID = mmapID;
  1426. }
  1427. #else
  1428. realID = mmapID;
  1429. #endif
  1430. mmapKey = mmapedKVKey(realID, relatePath);
  1431. MMKVDebug("mmapKey %s, real ID %s", mmapKey.c_str(), realID.c_str());
  1432. MMKVPath_t kvPath = mappedKVPathWithID(realID, relatePath);
  1433. MMKVPath_t crcPath = crcPathWithPath(kvPath);
  1434. if (!isFileExist(kvPath)) {
  1435. #ifdef MMKV_WIN32
  1436. MMKVInfo("file not exist %ls", kvPath.c_str());
  1437. #else
  1438. MMKVInfo("file not exist %s", kvPath.c_str());
  1439. #endif
  1440. kvPath.resize(0);
  1441. }
  1442. if (!isFileExist(crcPath)) {
  1443. #ifdef MMKV_WIN32
  1444. MMKVInfo("crc file not exist %ls", crcPath.c_str());
  1445. #else
  1446. MMKVInfo("crc file not exist %s", crcPath.c_str());
  1447. #endif // MMKV_WIN32
  1448. crcPath.resize(0);
  1449. }
  1450. return {kvPath, crcPath};
  1451. }
  1452. bool MMKV::isFileValid(const string &mmapID, const MMKVPath_t *relatePath) {
  1453. if (!g_instanceLock) {
  1454. return false;
  1455. }
  1456. SCOPED_LOCK(g_instanceLock);
  1457. std::string realID, mmapKey;
  1458. auto [kvPath, crcPath] = getStorage(mmapID, relatePath, realID, mmapKey);
  1459. if (kvPath.empty()) {
  1460. return true;
  1461. }
  1462. if (crcPath.empty()) {
  1463. return false;
  1464. }
  1465. uint32_t crcFile = 0;
  1466. MMBuffer *data = readWholeFile(crcPath);
  1467. if (data) {
  1468. if (data->getPtr()) {
  1469. MMKVMetaInfo metaInfo;
  1470. metaInfo.read(data->getPtr());
  1471. crcFile = metaInfo.m_crcDigest;
  1472. }
  1473. delete data;
  1474. } else {
  1475. return false;
  1476. }
  1477. uint32_t crcDigest = 0;
  1478. MMBuffer *fileData = readWholeFile(kvPath);
  1479. if (fileData) {
  1480. if (fileData->getPtr() && (fileData->length() >= Fixed32Size)) {
  1481. uint32_t actualSize = 0;
  1482. memcpy(&actualSize, fileData->getPtr(), Fixed32Size);
  1483. if (actualSize > (fileData->length() - Fixed32Size)) {
  1484. delete fileData;
  1485. return false;
  1486. }
  1487. crcDigest = (uint32_t) CRC32(0, (const uint8_t *) fileData->getPtr() + Fixed32Size, (uint32_t) actualSize);
  1488. }
  1489. delete fileData;
  1490. return crcFile == crcDigest;
  1491. } else {
  1492. return false;
  1493. }
  1494. }
  1495. bool MMKV::removeStorage(const std::string &mmapID, const MMKVPath_t *relatePath) {
  1496. if (!g_instanceLock) {
  1497. return false;
  1498. }
  1499. SCOPED_LOCK(g_instanceLock);
  1500. std::string realID, mmapKey;
  1501. auto [kvPath, crcPath] = getStorage(mmapID, relatePath, realID, mmapKey);
  1502. if (kvPath.empty() && crcPath.empty()) {
  1503. return false;
  1504. }
  1505. MMKVInfo("remove storage [%s]", realID.c_str());
  1506. if (crcPath.empty()) {
  1507. deleteFile(kvPath);
  1508. return true;
  1509. }
  1510. File crcFile(crcPath, OpenFlag::ReadOnly);
  1511. if (!crcFile.isFileValid()) {
  1512. deleteFile(kvPath);
  1513. return true;
  1514. }
  1515. FileLock fileLock(crcFile.getFd());
  1516. InterProcessLock lock(&fileLock, ExclusiveLockType);
  1517. SCOPED_LOCK(&lock);
  1518. auto itr = g_instanceDic->find(mmapKey);
  1519. if (itr != g_instanceDic->end()) {
  1520. itr->second->close();
  1521. // itr is not valid after this
  1522. }
  1523. deleteFile(kvPath);
  1524. deleteFile(crcPath);
  1525. return true;
  1526. }
  1527. bool MMKV::checkExist(const std::string &mmapID, const MMKVPath_t *relatePath) {
  1528. if (!g_instanceLock) {
  1529. return false;
  1530. }
  1531. SCOPED_LOCK(g_instanceLock);
  1532. std::string realID, mmapKey;
  1533. auto [kvPath, crcPath] = getStorage(mmapID, relatePath, realID, mmapKey);
  1534. return (!kvPath.empty() && !crcPath.empty());
  1535. }
  1536. // ---- auto expire ----
  1537. uint32_t MMKV::getCurrentTimeInSecond() {
  1538. auto time = ::time(nullptr);
  1539. return static_cast<uint32_t>(time);
  1540. }
  1541. bool MMKV::doFullWriteBack(MMKVVector &&vec) {
  1542. auto preparedData = prepareEncode(std::move(vec));
  1543. // must clean before write-back and after prepareEncode()
  1544. if (m_crypter) {
  1545. clearDictionary(m_dicCrypt);
  1546. } else {
  1547. clearDictionary(m_dic);
  1548. }
  1549. bool ret = false;
  1550. auto sizeOfDic = preparedData.second;
  1551. auto fileSize = m_file->getFileSize();
  1552. if (sizeOfDic + Fixed32Size <= fileSize) {
  1553. ret = doFullWriteBack(std::move(preparedData), nullptr);
  1554. } else {
  1555. // expandAndWriteBack() will extend file & full rewrite, no need to write back again
  1556. auto newSize = sizeOfDic + Fixed32Size - fileSize;
  1557. ret = expandAndWriteBack(newSize, std::move(preparedData));
  1558. }
  1559. clearMemoryCache();
  1560. return ret;
  1561. }
  1562. bool MMKV::enableAutoKeyExpire(uint32_t expiredInSeconds) {
  1563. if (isReadOnly()) {
  1564. MMKVWarning("[%s] file readonly", m_mmapID.c_str());
  1565. return false;
  1566. }
  1567. SCOPED_LOCK(m_lock);
  1568. SCOPED_LOCK(m_exclusiveProcessLock);
  1569. checkLoadData();
  1570. if (!isFileValid() || !m_metaFile->isFileValid()) {
  1571. MMKVWarning("[%s] file not valid", m_mmapID.c_str());
  1572. return false;
  1573. }
  1574. if (m_enableCompareBeforeSet) {
  1575. MMKVError("enableCompareBeforeSet will be invalid when Expiration is on");
  1576. m_enableCompareBeforeSet = false;
  1577. }
  1578. if (m_expiredInSeconds != expiredInSeconds) {
  1579. MMKVInfo("expiredInSeconds: %u", expiredInSeconds);
  1580. m_expiredInSeconds = expiredInSeconds;
  1581. }
  1582. m_enableKeyExpire = true;
  1583. if (m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre)) {
  1584. return true;
  1585. }
  1586. auto autoRecordExpireTime = (m_expiredInSeconds != 0);
  1587. auto time = autoRecordExpireTime ? getCurrentTimeInSecond() + m_expiredInSeconds : 0;
  1588. MMKVInfo("turn on recording expire date for all keys inside [%s] from now %u", m_mmapID.c_str(), time);
  1589. m_metaInfo->setFlag(MMKVMetaInfo::EnableKeyExipre);
  1590. m_metaInfo->m_version = MMKVVersionFlag;
  1591. if (m_file->getFileSize() == m_expectedCapacity && m_actualSize == 0) {
  1592. MMKVInfo("file is new, don't need a full writeback [%s], just update meta file", m_mmapID.c_str());
  1593. writeActualSize(0, 0, nullptr, IncreaseSequence);
  1594. m_metaFile->msync(MMKV_SYNC);
  1595. return true;
  1596. }
  1597. MMKVVector vec;
  1598. auto packKeyValue = [&](const auto &key, const MMBuffer &value) {
  1599. MMBuffer data(value.length() + Fixed32Size);
  1600. auto ptr = (uint8_t *) data.getPtr();
  1601. memcpy(ptr, value.getPtr(), value.length());
  1602. memcpy(ptr + value.length(), &time, Fixed32Size);
  1603. vec.emplace_back(key, std::move(data));
  1604. };
  1605. auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
  1606. #ifndef MMKV_DISABLE_CRYPT
  1607. if (m_crypter) {
  1608. for (auto &pair : *m_dicCrypt) {
  1609. auto &key = pair.first;
  1610. auto &value = pair.second;
  1611. auto buffer = value.toMMBuffer(basePtr, m_crypter);
  1612. packKeyValue(key, buffer);
  1613. }
  1614. } else
  1615. #endif
  1616. {
  1617. for (auto &pair : *m_dic) {
  1618. auto &key = pair.first;
  1619. auto &value = pair.second;
  1620. auto buffer = value.toMMBuffer(basePtr);
  1621. packKeyValue(key, buffer);
  1622. }
  1623. }
  1624. return doFullWriteBack(std::move(vec));
  1625. }
  1626. bool MMKV::disableAutoKeyExpire() {
  1627. if (isReadOnly()) {
  1628. MMKVWarning("[%s] file readonly", m_mmapID.c_str());
  1629. return false;
  1630. }
  1631. SCOPED_LOCK(m_lock);
  1632. SCOPED_LOCK(m_exclusiveProcessLock);
  1633. checkLoadData();
  1634. if (!isFileValid() || !m_metaFile->isFileValid()) {
  1635. MMKVWarning("[%s] file not valid", m_mmapID.c_str());
  1636. return false;
  1637. }
  1638. m_expiredInSeconds = 0;
  1639. m_enableKeyExpire = false;
  1640. if (!m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre)) {
  1641. return true;
  1642. }
  1643. MMKVInfo("erase previous recorded expire date for all keys inside [%s]", m_mmapID.c_str());
  1644. m_metaInfo->unsetFlag(MMKVMetaInfo::EnableKeyExipre);
  1645. m_metaInfo->m_version = MMKVVersionFlag;
  1646. if (m_file->getFileSize() == m_expectedCapacity && m_actualSize == 0) {
  1647. MMKVInfo("file is new, don't need a full write-back [%s], just update meta file", m_mmapID.c_str());
  1648. writeActualSize(0, 0, nullptr, IncreaseSequence);
  1649. m_metaFile->msync(MMKV_SYNC);
  1650. return true;
  1651. }
  1652. MMKVVector vec;
  1653. auto packKeyValue = [&](auto &key, const MMBuffer &value) {
  1654. assert(value.length() >= Fixed32Size);
  1655. if (value.length() < Fixed32Size) {
  1656. #ifdef MMKV_APPLE
  1657. MMKVWarning("key [%@] has invalid value size %u", key, value.length());
  1658. #else
  1659. MMKVWarning("key [%s] has invalid value size %u", key.data(), value.length());
  1660. #endif
  1661. return;
  1662. }
  1663. MMBuffer data(value.length() - Fixed32Size);
  1664. auto ptr = (uint8_t *) data.getPtr();
  1665. memcpy(ptr, value.getPtr(), value.length() - Fixed32Size);
  1666. vec.emplace_back(key, std::move(data));
  1667. };
  1668. auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
  1669. #ifndef MMKV_DISABLE_CRYPT
  1670. if (m_crypter) {
  1671. for (auto &pair : *m_dicCrypt) {
  1672. auto &key = pair.first;
  1673. auto &value = pair.second;
  1674. auto buffer = value.toMMBuffer(basePtr, m_crypter);
  1675. packKeyValue(key, buffer);
  1676. }
  1677. } else
  1678. #endif
  1679. {
  1680. for (auto &pair : *m_dic) {
  1681. auto &key = pair.first;
  1682. auto &value = pair.second;
  1683. auto buffer = value.toMMBuffer(basePtr);
  1684. packKeyValue(key, buffer);
  1685. }
  1686. }
  1687. return doFullWriteBack(std::move(vec));
  1688. }
  1689. uint32_t MMKV::getExpireTimeForKey(MMKVKey_t key) {
  1690. SCOPED_LOCK(m_lock);
  1691. SCOPED_LOCK(m_sharedProcessLock);
  1692. checkLoadData();
  1693. if (!m_enableKeyExpire || mmkv_key_length(key) == 0) {
  1694. return 0;
  1695. }
  1696. auto raw = getRawDataForKey(key);
  1697. assert(raw.length() == 0 || raw.length() >= Fixed32Size);
  1698. if (raw.length() < Fixed32Size) {
  1699. if (raw.length() != 0) {
  1700. #ifdef MMKV_APPLE
  1701. MMKVWarning("key [%@] has invalid value size %u", key, raw.length());
  1702. #else
  1703. MMKVWarning("key [%s] has invalid value size %u", key.data(), raw.length());
  1704. #endif
  1705. }
  1706. return 0;
  1707. }
  1708. auto ptr = (const uint8_t *) raw.getPtr() + raw.length() - Fixed32Size;
  1709. auto time = *(const uint32_t *) ptr;
  1710. return time;
  1711. }
  1712. mmkv::MMBuffer MMKV::getDataWithoutMTimeForKey(MMKVKey_t key) {
  1713. SCOPED_LOCK(m_lock);
  1714. SCOPED_LOCK(m_sharedProcessLock);
  1715. checkLoadData();
  1716. auto raw = getRawDataForKey(key);
  1717. assert(raw.length() == 0 || raw.length() >= Fixed32Size);
  1718. if (raw.length() < Fixed32Size) {
  1719. if (raw.length() != 0) {
  1720. #ifdef MMKV_APPLE
  1721. MMKVWarning("key [%@] has invalid value size %u", key, raw.length());
  1722. #else
  1723. MMKVWarning("key [%s] has invalid value size %u", key.data(), raw.length());
  1724. #endif
  1725. }
  1726. return raw;
  1727. }
  1728. auto newLength = raw.length() - Fixed32Size;
  1729. if (m_enableKeyExpire) {
  1730. auto ptr = (const uint8_t *) raw.getPtr() + newLength;
  1731. auto time = *(const uint32_t *) ptr;
  1732. if (time != ExpireNever && time <= getCurrentTimeInSecond()) {
  1733. #ifdef MMKV_APPLE
  1734. MMKVInfo("deleting expired key [%@] in mmkv [%s], due date %u", key, m_mmapID.c_str(), time);
  1735. #else
  1736. MMKVInfo("deleting expired key [%s] in mmkv [%s], due date %u", key.data(), m_mmapID.c_str(), time);
  1737. #endif
  1738. removeValueForKey(key);
  1739. return MMBuffer();
  1740. }
  1741. }
  1742. return MMBuffer(std::move(raw), newLength);
  1743. }
  1744. #define NOOP ((void) 0)
  1745. size_t MMKV::filterExpiredKeys() {
  1746. if (!m_enableKeyExpire || (m_crypter ? m_dicCrypt->empty() : m_dic->empty())) {
  1747. return 0;
  1748. }
  1749. SCOPED_LOCK(m_sharedProcessLock);
  1750. auto now = getCurrentTimeInSecond();
  1751. MMKVInfo("filtering expired keys inside [%s] now: %u, m_expiredInSeconds: %u", m_mmapID.c_str(), now,
  1752. m_expiredInSeconds);
  1753. size_t count = 0;
  1754. auto basePtr = (uint8_t *) (m_file->getMemory()) + Fixed32Size;
  1755. #ifndef MMKV_DISABLE_CRYPT
  1756. if (m_crypter) {
  1757. for (auto itr = m_dicCrypt->begin(); itr != m_dicCrypt->end(); NOOP) {
  1758. auto &kvHolder = itr->second;
  1759. assert(kvHolder.realValueSize() >= Fixed32Size);
  1760. if (kvHolder.realValueSize() < Fixed32Size) {
  1761. #ifdef MMKV_APPLE
  1762. MMKVWarning("key [%@] has invalid value size %u", itr->first, kvHolder.realValueSize());
  1763. #else
  1764. MMKVWarning("key [%s] has invalid value size %u", itr->first.c_str(), kvHolder.realValueSize());
  1765. #endif
  1766. itr++;
  1767. continue;
  1768. }
  1769. auto buffer = kvHolder.toMMBuffer(basePtr, m_crypter);
  1770. auto ptr = (uint8_t *) buffer.getPtr();
  1771. ptr += buffer.length() - Fixed32Size;
  1772. auto time = *(const uint32_t *) ptr;
  1773. if (time != ExpireNever && time <= now) {
  1774. auto oldKey = itr->first;
  1775. itr = m_dicCrypt->erase(itr);
  1776. # ifdef MMKV_APPLE
  1777. MMKVInfo("deleting expired key [%@], due date %u", oldKey, time);
  1778. [oldKey release];
  1779. # else
  1780. MMKVInfo("deleting expired key [%s], due date %u", oldKey.c_str(), time);
  1781. # endif
  1782. count++;
  1783. } else {
  1784. itr++;
  1785. }
  1786. }
  1787. } else
  1788. #endif // !MMKV_DISABLE_CRYPT
  1789. {
  1790. for (auto itr = m_dic->begin(); itr != m_dic->end(); NOOP) {
  1791. auto &kvHolder = itr->second;
  1792. assert(kvHolder.valueSize >= Fixed32Size);
  1793. if (kvHolder.valueSize < Fixed32Size) {
  1794. #ifdef MMKV_APPLE
  1795. MMKVWarning("key [%@] has invalid value size %u", itr->first, kvHolder.valueSize);
  1796. #else
  1797. MMKVWarning("key [%s] has invalid value size %u", itr->first.c_str(), kvHolder.valueSize);
  1798. #endif
  1799. itr++;
  1800. continue;
  1801. }
  1802. auto ptr = basePtr + kvHolder.offset + kvHolder.computedKVSize;
  1803. ptr += kvHolder.valueSize - Fixed32Size;
  1804. auto time = *(const uint32_t *) ptr;
  1805. if (time != ExpireNever && time <= now) {
  1806. auto oldKey = itr->first;
  1807. itr = m_dic->erase(itr);
  1808. #ifdef MMKV_APPLE
  1809. MMKVInfo("deleting expired key [%@], due date %u", oldKey, time);
  1810. [oldKey release];
  1811. #else
  1812. MMKVInfo("deleting expired key [%s], due date %u", oldKey.c_str(), time);
  1813. #endif
  1814. count++;
  1815. } else {
  1816. itr++;
  1817. }
  1818. }
  1819. }
  1820. if (count != 0) {
  1821. MMKVInfo("deleted %zu expired keys inside [%s]", count, m_mmapID.c_str());
  1822. }
  1823. return count;
  1824. }
  1825. bool MMKV::enableCompareBeforeSet() {
  1826. MMKVInfo("enableCompareBeforeSet for [%s]", m_mmapID.c_str());
  1827. SCOPED_LOCK(m_lock);
  1828. SCOPED_LOCK(m_exclusiveProcessLock);
  1829. assert(!m_enableKeyExpire && "enableCompareBeforeSet is invalid when Expiration is on");
  1830. assert(!m_dicCrypt && "enableCompareBeforeSet is invalid when key encryption is on");
  1831. if (m_enableKeyExpire || m_dicCrypt) {
  1832. return false;
  1833. }
  1834. m_enableCompareBeforeSet = true;
  1835. return true;
  1836. }
  1837. bool MMKV::disableCompareBeforeSet() {
  1838. MMKVInfo("disableCompareBeforeSet for [%s]", m_mmapID.c_str());
  1839. SCOPED_LOCK(m_lock);
  1840. SCOPED_LOCK(m_exclusiveProcessLock);
  1841. assert(!m_enableKeyExpire && "disableCompareBeforeSet is invalid when Expiration is on");
  1842. assert(!m_dicCrypt && "disableCompareBeforeSet is invalid when key encryption is on");
  1843. if (m_enableKeyExpire || m_dicCrypt) {
  1844. return false;
  1845. }
  1846. m_enableCompareBeforeSet = false;
  1847. return true;
  1848. }
  1849. MMKV_NAMESPACE_END