| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487 |
- // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
- // This source code is licensed under both the GPLv2 (found in the
- // COPYING file in the root directory) and Apache 2.0 License
- // (found in the LICENSE.Apache file in the root directory).
- //
- // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file. See the AUTHORS file for names of contributors.
- #include "db/version_set.h"
- #include <algorithm>
- #include "db/blob/blob_log_writer.h"
- #include "db/db_impl/db_impl.h"
- #include "db/db_test_util.h"
- #include "db/log_writer.h"
- #include "db/manifest_ops.h"
- #include "db/version_edit.h"
- #include "rocksdb/advanced_options.h"
- #include "rocksdb/convenience.h"
- #include "rocksdb/file_system.h"
- #include "table/block_based/block_based_table_factory.h"
- #include "table/mock_table.h"
- #include "table/unique_id_impl.h"
- #include "test_util/mock_time_env.h"
- #include "test_util/testharness.h"
- #include "test_util/testutil.h"
- #include "util/defer.h"
- #include "util/string_util.h"
- namespace ROCKSDB_NAMESPACE {
- class GenerateLevelFilesBriefTest : public testing::Test {
- public:
- std::vector<FileMetaData*> files_;
- LevelFilesBrief file_level_;
- Arena arena_;
- GenerateLevelFilesBriefTest() = default;
- ~GenerateLevelFilesBriefTest() override {
- for (size_t i = 0; i < files_.size(); i++) {
- delete files_[i];
- }
- }
- void Add(const char* smallest, const char* largest,
- SequenceNumber smallest_seq = 100,
- SequenceNumber largest_seq = 100) {
- FileMetaData* f = new FileMetaData(
- files_.size() + 1, 0, 0,
- InternalKey(smallest, smallest_seq, kTypeValue),
- InternalKey(largest, largest_seq, kTypeValue), smallest_seq,
- largest_seq, /* marked_for_compact */ false, Temperature::kUnknown,
- kInvalidBlobFileNumber, kUnknownOldestAncesterTime,
- kUnknownFileCreationTime, kUnknownEpochNumber, kUnknownFileChecksum,
- kUnknownFileChecksumFuncName, kNullUniqueId64x2, 0, 0,
- /* user_defined_timestamps_persisted */ true);
- files_.push_back(f);
- }
- int Compare() {
- int diff = 0;
- for (size_t i = 0; i < files_.size(); i++) {
- if (file_level_.files[i].fd.GetNumber() != files_[i]->fd.GetNumber()) {
- diff++;
- }
- }
- return diff;
- }
- };
- TEST_F(GenerateLevelFilesBriefTest, Empty) {
- DoGenerateLevelFilesBrief(&file_level_, files_, &arena_);
- ASSERT_EQ(0u, file_level_.num_files);
- ASSERT_EQ(0, Compare());
- }
- TEST_F(GenerateLevelFilesBriefTest, Single) {
- Add("p", "q");
- DoGenerateLevelFilesBrief(&file_level_, files_, &arena_);
- ASSERT_EQ(1u, file_level_.num_files);
- ASSERT_EQ(0, Compare());
- }
- TEST_F(GenerateLevelFilesBriefTest, Multiple) {
- Add("150", "200");
- Add("200", "250");
- Add("300", "350");
- Add("400", "450");
- DoGenerateLevelFilesBrief(&file_level_, files_, &arena_);
- ASSERT_EQ(4u, file_level_.num_files);
- ASSERT_EQ(0, Compare());
- }
- class CountingLogger : public Logger {
- public:
- CountingLogger() : log_count(0) {}
- using Logger::Logv;
- void Logv(const char* /*format*/, va_list /*ap*/) override { log_count++; }
- int log_count;
- };
- Options GetOptionsWithNumLevels(int num_levels,
- std::shared_ptr<CountingLogger> logger) {
- Options opt;
- opt.num_levels = num_levels;
- opt.info_log = logger;
- return opt;
- }
- class VersionStorageInfoTestBase : public testing::Test {
- public:
- const Comparator* ucmp_;
- InternalKeyComparator icmp_;
- std::shared_ptr<CountingLogger> logger_;
- Options options_;
- ImmutableOptions ioptions_;
- MutableCFOptions mutable_cf_options_;
- VersionStorageInfo vstorage_;
- InternalKey GetInternalKey(const char* ukey,
- SequenceNumber smallest_seq = 100) {
- return InternalKey(ukey, smallest_seq, kTypeValue);
- }
- explicit VersionStorageInfoTestBase(const Comparator* ucmp)
- : ucmp_(ucmp),
- icmp_(ucmp_),
- logger_(new CountingLogger()),
- options_(GetOptionsWithNumLevels(6, logger_)),
- ioptions_(options_),
- mutable_cf_options_(options_),
- vstorage_(&icmp_, ucmp_, 6, kCompactionStyleLevel,
- /*src_vstorage=*/nullptr,
- /*_force_consistency_checks=*/false,
- EpochNumberRequirement::kMustPresent, ioptions_.clock,
- mutable_cf_options_.bottommost_file_compaction_delay,
- OffpeakTimeOption()) {}
- ~VersionStorageInfoTestBase() override {
- for (int i = 0; i < vstorage_.num_levels(); ++i) {
- for (auto* f : vstorage_.LevelFiles(i)) {
- if (--f->refs == 0) {
- delete f;
- }
- }
- }
- }
- void Add(int level, uint32_t file_number, const char* smallest,
- const char* largest, uint64_t file_size = 0,
- uint64_t oldest_blob_file_number = kInvalidBlobFileNumber,
- uint64_t compensated_range_deletion_size = 0) {
- constexpr SequenceNumber dummy_seq = 0;
- Add(level, file_number, GetInternalKey(smallest, dummy_seq),
- GetInternalKey(largest, dummy_seq), file_size, oldest_blob_file_number,
- compensated_range_deletion_size);
- }
- void Add(int level, uint32_t file_number, const InternalKey& smallest,
- const InternalKey& largest, uint64_t file_size = 0,
- uint64_t oldest_blob_file_number = kInvalidBlobFileNumber,
- uint64_t compensated_range_deletion_size = 0) {
- assert(level < vstorage_.num_levels());
- FileMetaData* f = new FileMetaData(
- file_number, 0, file_size, smallest, largest, /* smallest_seq */ 0,
- /* largest_seq */ 0, /* marked_for_compact */ false,
- Temperature::kUnknown, oldest_blob_file_number,
- kUnknownOldestAncesterTime, kUnknownFileCreationTime,
- kUnknownEpochNumber, kUnknownFileChecksum, kUnknownFileChecksumFuncName,
- kNullUniqueId64x2, compensated_range_deletion_size, 0,
- /* user_defined_timestamps_persisted */ true);
- vstorage_.AddFile(level, f);
- }
- void AddBlob(uint64_t blob_file_number, uint64_t total_blob_count,
- uint64_t total_blob_bytes,
- BlobFileMetaData::LinkedSsts linked_ssts,
- uint64_t garbage_blob_count, uint64_t garbage_blob_bytes) {
- auto shared_meta = SharedBlobFileMetaData::Create(
- blob_file_number, total_blob_count, total_blob_bytes,
- /* checksum_method */ std::string(),
- /* checksum_value */ std::string());
- auto meta =
- BlobFileMetaData::Create(std::move(shared_meta), std::move(linked_ssts),
- garbage_blob_count, garbage_blob_bytes);
- vstorage_.AddBlobFile(std::move(meta));
- }
- void UpdateVersionStorageInfo() {
- vstorage_.PrepareForVersionAppend(ioptions_, mutable_cf_options_);
- vstorage_.SetFinalized();
- }
- std::string GetOverlappingFiles(int level, const InternalKey& begin,
- const InternalKey& end) {
- std::vector<FileMetaData*> inputs;
- vstorage_.GetOverlappingInputs(level, &begin, &end, &inputs);
- std::string result;
- for (size_t i = 0; i < inputs.size(); ++i) {
- if (i > 0) {
- result += ",";
- }
- AppendNumberTo(&result, inputs[i]->fd.GetNumber());
- }
- return result;
- }
- };
- class VersionStorageInfoTest : public VersionStorageInfoTestBase {
- public:
- VersionStorageInfoTest() : VersionStorageInfoTestBase(BytewiseComparator()) {}
- ~VersionStorageInfoTest() override = default;
- };
- TEST_F(VersionStorageInfoTest, MaxBytesForLevelStatic) {
- ioptions_.level_compaction_dynamic_level_bytes = false;
- mutable_cf_options_.max_bytes_for_level_base = 10;
- mutable_cf_options_.max_bytes_for_level_multiplier = 5;
- Add(4, 100U, "1", "2", 100U);
- Add(5, 101U, "1", "2", 100U);
- UpdateVersionStorageInfo();
- ASSERT_EQ(vstorage_.MaxBytesForLevel(1), 10U);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(2), 50U);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(3), 250U);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(4), 1250U);
- ASSERT_EQ(0, logger_->log_count);
- }
- TEST_F(VersionStorageInfoTest, MaxBytesForLevelDynamic_1) {
- ioptions_.level_compaction_dynamic_level_bytes = true;
- mutable_cf_options_.max_bytes_for_level_base = 1000;
- mutable_cf_options_.max_bytes_for_level_multiplier = 5;
- Add(5, 1U, "1", "2", 500U);
- UpdateVersionStorageInfo();
- ASSERT_EQ(0, logger_->log_count);
- ASSERT_EQ(vstorage_.base_level(), 5);
- }
- TEST_F(VersionStorageInfoTest, MaxBytesForLevelDynamic_2) {
- ioptions_.level_compaction_dynamic_level_bytes = true;
- mutable_cf_options_.max_bytes_for_level_base = 1000;
- mutable_cf_options_.max_bytes_for_level_multiplier = 5;
- Add(5, 1U, "1", "2", 500U);
- Add(5, 2U, "3", "4", 550U);
- UpdateVersionStorageInfo();
- ASSERT_EQ(0, logger_->log_count);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(4), 1000U);
- ASSERT_EQ(vstorage_.base_level(), 4);
- }
- TEST_F(VersionStorageInfoTest, MaxBytesForLevelDynamic_3) {
- ioptions_.level_compaction_dynamic_level_bytes = true;
- mutable_cf_options_.max_bytes_for_level_base = 1000;
- mutable_cf_options_.max_bytes_for_level_multiplier = 5;
- Add(5, 1U, "1", "2", 500U);
- Add(5, 2U, "3", "4", 550U);
- Add(4, 3U, "3", "4", 550U);
- UpdateVersionStorageInfo();
- ASSERT_EQ(0, logger_->log_count);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(4), 1000U);
- ASSERT_EQ(vstorage_.base_level(), 4);
- }
- TEST_F(VersionStorageInfoTest, MaxBytesForLevelDynamic_4) {
- ioptions_.level_compaction_dynamic_level_bytes = true;
- mutable_cf_options_.max_bytes_for_level_base = 1000;
- mutable_cf_options_.max_bytes_for_level_multiplier = 5;
- Add(5, 1U, "1", "2", 500U);
- Add(5, 2U, "3", "4", 550U);
- Add(4, 3U, "3", "4", 550U);
- Add(3, 4U, "3", "4", 250U);
- Add(3, 5U, "5", "7", 300U);
- UpdateVersionStorageInfo();
- ASSERT_EQ(1, logger_->log_count);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(4), 1005U);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(3), 1000U);
- ASSERT_EQ(vstorage_.base_level(), 3);
- }
- TEST_F(VersionStorageInfoTest, MaxBytesForLevelDynamic_5) {
- ioptions_.level_compaction_dynamic_level_bytes = true;
- mutable_cf_options_.max_bytes_for_level_base = 1000;
- mutable_cf_options_.max_bytes_for_level_multiplier = 5;
- Add(5, 1U, "1", "2", 500U);
- Add(5, 2U, "3", "4", 550U);
- Add(4, 3U, "3", "4", 550U);
- Add(3, 4U, "3", "4", 250U);
- Add(3, 5U, "5", "7", 300U);
- Add(1, 6U, "3", "4", 5U);
- Add(1, 7U, "8", "9", 5U);
- UpdateVersionStorageInfo();
- ASSERT_EQ(1, logger_->log_count);
- ASSERT_GT(vstorage_.MaxBytesForLevel(4), 1005U);
- ASSERT_GT(vstorage_.MaxBytesForLevel(3), 1005U);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(2), 1005U);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(1), 1000U);
- ASSERT_EQ(vstorage_.base_level(), 1);
- }
- TEST_F(VersionStorageInfoTest, MaxBytesForLevelDynamicLotsOfData) {
- ioptions_.level_compaction_dynamic_level_bytes = true;
- mutable_cf_options_.max_bytes_for_level_base = 100;
- mutable_cf_options_.max_bytes_for_level_multiplier = 2;
- Add(0, 1U, "1", "2", 50U);
- Add(1, 2U, "1", "2", 50U);
- Add(2, 3U, "1", "2", 500U);
- Add(3, 4U, "1", "2", 500U);
- Add(4, 5U, "1", "2", 1700U);
- Add(5, 6U, "1", "2", 500U);
- UpdateVersionStorageInfo();
- ASSERT_EQ(vstorage_.MaxBytesForLevel(4), 800U);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(3), 400U);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(2), 200U);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(1), 100U);
- ASSERT_EQ(vstorage_.base_level(), 1);
- ASSERT_EQ(0, logger_->log_count);
- }
- TEST_F(VersionStorageInfoTest, MaxBytesForLevelDynamicLargeLevel) {
- uint64_t kOneGB = 1000U * 1000U * 1000U;
- ioptions_.level_compaction_dynamic_level_bytes = true;
- mutable_cf_options_.max_bytes_for_level_base = 10U * kOneGB;
- mutable_cf_options_.max_bytes_for_level_multiplier = 10;
- Add(0, 1U, "1", "2", 50U);
- Add(3, 4U, "1", "2", 32U * kOneGB);
- Add(4, 5U, "1", "2", 500U * kOneGB);
- Add(5, 6U, "1", "2", 3000U * kOneGB);
- UpdateVersionStorageInfo();
- ASSERT_EQ(vstorage_.MaxBytesForLevel(5), 3000U * kOneGB);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(4), 300U * kOneGB);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(3), 30U * kOneGB);
- ASSERT_EQ(vstorage_.MaxBytesForLevel(2), 10U * kOneGB);
- ASSERT_EQ(vstorage_.base_level(), 2);
- ASSERT_EQ(0, logger_->log_count);
- }
- TEST_F(VersionStorageInfoTest, MaxBytesForLevelDynamicWithLargeL0_1) {
- ioptions_.level_compaction_dynamic_level_bytes = true;
- mutable_cf_options_.max_bytes_for_level_base = 40000;
- mutable_cf_options_.max_bytes_for_level_multiplier = 5;
- mutable_cf_options_.level0_file_num_compaction_trigger = 2;
- Add(0, 1U, "1", "2", 10000U);
- Add(0, 2U, "1", "2", 10000U);
- Add(0, 3U, "1", "2", 10000U);
- Add(5, 4U, "1", "2", 1286250U);
- Add(4, 5U, "1", "2", 200000U);
- Add(3, 6U, "1", "2", 40000U);
- Add(2, 7U, "1", "2", 8000U);
- UpdateVersionStorageInfo();
- ASSERT_EQ(0, logger_->log_count);
- ASSERT_EQ(2, vstorage_.base_level());
- // level multiplier should be 3.5
- ASSERT_EQ(vstorage_.level_multiplier(), 5.0);
- ASSERT_EQ(40000U, vstorage_.MaxBytesForLevel(2));
- ASSERT_EQ(51450U, vstorage_.MaxBytesForLevel(3));
- ASSERT_EQ(257250U, vstorage_.MaxBytesForLevel(4));
- vstorage_.ComputeCompactionScore(ioptions_, mutable_cf_options_);
- // Only L0 hits compaction.
- ASSERT_EQ(vstorage_.CompactionScoreLevel(0), 0);
- }
- TEST_F(VersionStorageInfoTest, MaxBytesForLevelDynamicWithLargeL0_2) {
- ioptions_.level_compaction_dynamic_level_bytes = true;
- mutable_cf_options_.max_bytes_for_level_base = 10000;
- mutable_cf_options_.max_bytes_for_level_multiplier = 5;
- mutable_cf_options_.level0_file_num_compaction_trigger = 4;
- Add(0, 11U, "1", "2", 10000U);
- Add(0, 12U, "1", "2", 10000U);
- Add(0, 13U, "1", "2", 10000U);
- // Level size should be around 10,000, 10,290, 51,450, 257,250
- Add(5, 4U, "1", "2", 1286250U);
- Add(4, 5U, "1", "2", 258000U); // unadjusted score 1.003
- Add(3, 6U, "1", "2", 53000U); // unadjusted score 1.03
- Add(2, 7U, "1", "2", 20000U); // unadjusted score 1.94
- UpdateVersionStorageInfo();
- ASSERT_EQ(0, logger_->log_count);
- ASSERT_EQ(1, vstorage_.base_level());
- ASSERT_EQ(10000U, vstorage_.MaxBytesForLevel(1));
- ASSERT_EQ(10290U, vstorage_.MaxBytesForLevel(2));
- ASSERT_EQ(51450U, vstorage_.MaxBytesForLevel(3));
- ASSERT_EQ(257250U, vstorage_.MaxBytesForLevel(4));
- vstorage_.ComputeCompactionScore(ioptions_, mutable_cf_options_);
- // Although L2 and l3 have higher unadjusted compaction score, considering
- // a relatively large L0 being compacted down soon, L4 is picked up for
- // compaction.
- // L0 is still picked up for oversizing.
- ASSERT_EQ(0, vstorage_.CompactionScoreLevel(0));
- ASSERT_EQ(4, vstorage_.CompactionScoreLevel(1));
- }
- TEST_F(VersionStorageInfoTest, MaxBytesForLevelDynamicWithLargeL0_3) {
- ioptions_.level_compaction_dynamic_level_bytes = true;
- mutable_cf_options_.max_bytes_for_level_base = 20000;
- mutable_cf_options_.max_bytes_for_level_multiplier = 5;
- mutable_cf_options_.level0_file_num_compaction_trigger = 5;
- Add(0, 11U, "1", "2", 2500U);
- Add(0, 12U, "1", "2", 2500U);
- Add(0, 13U, "1", "2", 2500U);
- Add(0, 14U, "1", "2", 2500U);
- // Level size should be around 20,000, 53000, 258000
- Add(5, 4U, "1", "2", 1286250U);
- Add(4, 5U, "1", "2", 260000U); // Unadjusted score 1.01, adjusted about 4.3
- Add(3, 6U, "1", "2", 85000U); // Unadjusted score 1.42, adjusted about 11.6
- Add(2, 7U, "1", "2", 30000); // Unadjusted score 1.5, adjusted about 10.0
- UpdateVersionStorageInfo();
- ASSERT_EQ(0, logger_->log_count);
- ASSERT_EQ(2, vstorage_.base_level());
- ASSERT_EQ(20000U, vstorage_.MaxBytesForLevel(2));
- vstorage_.ComputeCompactionScore(ioptions_, mutable_cf_options_);
- // Although L2 has higher unadjusted compaction score, considering
- // a relatively large L0 being compacted down soon, L3 is picked up for
- // compaction.
- ASSERT_EQ(3, vstorage_.CompactionScoreLevel(0));
- ASSERT_EQ(2, vstorage_.CompactionScoreLevel(1));
- ASSERT_EQ(4, vstorage_.CompactionScoreLevel(2));
- }
- TEST_F(VersionStorageInfoTest, DrainUnnecessaryLevel) {
- ioptions_.level_compaction_dynamic_level_bytes = true;
- mutable_cf_options_.max_bytes_for_level_base = 1000;
- mutable_cf_options_.max_bytes_for_level_multiplier = 10;
- // Create a few unnecessary levels.
- // See if score is calculated correctly.
- Add(5, 1U, "1", "2", 2000U); // target size 1010000
- Add(4, 2U, "1", "2", 200U); // target size 101000
- // Unnecessary levels
- Add(3, 3U, "1", "2", 100U); // target size 10100
- // Level 2: target size 1010
- Add(1, 4U, "1", "2",
- 10U); // target size 1000 = max(base_bytes_min + 1, base_bytes_max)
- UpdateVersionStorageInfo();
- ASSERT_EQ(1, vstorage_.base_level());
- ASSERT_EQ(1000, vstorage_.MaxBytesForLevel(1));
- ASSERT_EQ(10100, vstorage_.MaxBytesForLevel(3));
- vstorage_.ComputeCompactionScore(ioptions_, mutable_cf_options_);
- // Tests that levels 1 and 3 are eligible for compaction.
- // Levels 1 and 3 are much smaller than target size,
- // so size does not contribute to a high compaction score.
- ASSERT_EQ(1, vstorage_.CompactionScoreLevel(0));
- ASSERT_GT(vstorage_.CompactionScore(0), 10);
- ASSERT_EQ(3, vstorage_.CompactionScoreLevel(1));
- ASSERT_GT(vstorage_.CompactionScore(1), 10);
- }
- TEST_F(VersionStorageInfoTest, EstimateLiveDataSize) {
- // Test whether the overlaps are detected as expected
- Add(1, 1U, "4", "7", 1U); // Perfect overlap with last level
- Add(2, 2U, "3", "5", 1U); // Partial overlap with last level
- Add(2, 3U, "6", "8", 1U); // Partial overlap with last level
- Add(3, 4U, "1", "9", 1U); // Contains range of last level
- Add(4, 5U, "4", "5", 1U); // Inside range of last level
- Add(4, 6U, "6", "7", 1U); // Inside range of last level
- Add(5, 7U, "4", "7", 10U);
- UpdateVersionStorageInfo();
- ASSERT_EQ(10U, vstorage_.EstimateLiveDataSize());
- }
- TEST_F(VersionStorageInfoTest, EstimateLiveDataSize2) {
- Add(0, 1U, "9", "9", 1U); // Level 0 is not ordered
- Add(0, 2U, "5", "6", 1U); // Ignored because of [5,6] in l1
- Add(1, 3U, "1", "2", 1U); // Ignored because of [2,3] in l2
- Add(1, 4U, "3", "4", 1U); // Ignored because of [2,3] in l2
- Add(1, 5U, "5", "6", 1U);
- Add(2, 6U, "2", "3", 1U);
- Add(3, 7U, "7", "8", 1U);
- UpdateVersionStorageInfo();
- ASSERT_EQ(4U, vstorage_.EstimateLiveDataSize());
- }
- TEST_F(VersionStorageInfoTest, SingleLevelBottommostData) {
- // In case of a single level, the oldest L0 file is bottommost. This could be
- // improved in case the L0 files cover disjoint key-ranges.
- Add(0 /* level */, 1U /* file_number */, "A" /* smallest */,
- "Z" /* largest */, 1U /* file_size */);
- Add(0 /* level */, 2U /* file_number */, "A" /* smallest */,
- "Z" /* largest */, 1U /* file_size */);
- Add(0 /* level */, 3U /* file_number */, "0" /* smallest */,
- "9" /* largest */, 1U /* file_size */);
- UpdateVersionStorageInfo();
- ASSERT_EQ(1, vstorage_.BottommostFiles().size());
- ASSERT_EQ(0, vstorage_.BottommostFiles()[0].first);
- ASSERT_EQ(3U, vstorage_.BottommostFiles()[0].second->fd.GetNumber());
- }
- TEST_F(VersionStorageInfoTest, MultiLevelBottommostData) {
- // In case of multiple levels, the oldest file for a key-range from each L1+
- // level is bottommost. This could be improved in case an L0 file contains the
- // oldest data for some range of keys.
- Add(0 /* level */, 1U /* file_number */, "A" /* smallest */,
- "Z" /* largest */, 1U /* file_size */);
- Add(0 /* level */, 2U /* file_number */, "0" /* smallest */,
- "9" /* largest */, 1U /* file_size */);
- Add(1 /* level */, 3U /* file_number */, "A" /* smallest */,
- "D" /* largest */, 1U /* file_size */);
- Add(2 /* level */, 4U /* file_number */, "E" /* smallest */,
- "H" /* largest */, 1U /* file_size */);
- Add(2 /* level */, 5U /* file_number */, "I" /* smallest */,
- "L" /* largest */, 1U /* file_size */);
- UpdateVersionStorageInfo();
- autovector<std::pair<int, FileMetaData*>> bottommost_files =
- vstorage_.BottommostFiles();
- std::sort(bottommost_files.begin(), bottommost_files.end(),
- [](const std::pair<int, FileMetaData*>& lhs,
- const std::pair<int, FileMetaData*>& rhs) {
- assert(lhs.second);
- assert(rhs.second);
- return lhs.second->fd.GetNumber() < rhs.second->fd.GetNumber();
- });
- ASSERT_EQ(3, bottommost_files.size());
- ASSERT_EQ(3U, bottommost_files[0].second->fd.GetNumber());
- ASSERT_EQ(4U, bottommost_files[1].second->fd.GetNumber());
- ASSERT_EQ(5U, bottommost_files[2].second->fd.GetNumber());
- }
- TEST_F(VersionStorageInfoTest, GetOverlappingInputs) {
- // Two files that overlap at the range deletion tombstone sentinel.
- Add(1, 1U, {"a", 0, kTypeValue},
- {"b", kMaxSequenceNumber, kTypeRangeDeletion}, 1);
- Add(1, 2U, {"b", 0, kTypeValue}, {"c", 0, kTypeValue}, 1);
- // Two files that overlap at the same user key.
- Add(1, 3U, {"d", 0, kTypeValue}, {"e", kMaxSequenceNumber, kTypeValue}, 1);
- Add(1, 4U, {"e", 0, kTypeValue}, {"f", 0, kTypeValue}, 1);
- // Two files that do not overlap.
- Add(1, 5U, {"g", 0, kTypeValue}, {"h", 0, kTypeValue}, 1);
- Add(1, 6U, {"i", 0, kTypeValue}, {"j", 0, kTypeValue}, 1);
- UpdateVersionStorageInfo();
- ASSERT_EQ("1,2",
- GetOverlappingFiles(1, {"a", 0, kTypeValue}, {"b", 0, kTypeValue}));
- ASSERT_EQ("1",
- GetOverlappingFiles(1, {"a", 0, kTypeValue},
- {"b", kMaxSequenceNumber, kTypeRangeDeletion}));
- ASSERT_EQ("2", GetOverlappingFiles(1, {"b", kMaxSequenceNumber, kTypeValue},
- {"c", 0, kTypeValue}));
- ASSERT_EQ("3,4",
- GetOverlappingFiles(1, {"d", 0, kTypeValue}, {"e", 0, kTypeValue}));
- ASSERT_EQ("3",
- GetOverlappingFiles(1, {"d", 0, kTypeValue},
- {"e", kMaxSequenceNumber, kTypeRangeDeletion}));
- ASSERT_EQ("3,4", GetOverlappingFiles(1, {"e", kMaxSequenceNumber, kTypeValue},
- {"f", 0, kTypeValue}));
- ASSERT_EQ("3,4",
- GetOverlappingFiles(1, {"e", 0, kTypeValue}, {"f", 0, kTypeValue}));
- ASSERT_EQ("5",
- GetOverlappingFiles(1, {"g", 0, kTypeValue}, {"h", 0, kTypeValue}));
- ASSERT_EQ("6",
- GetOverlappingFiles(1, {"i", 0, kTypeValue}, {"j", 0, kTypeValue}));
- }
- TEST_F(VersionStorageInfoTest, FileLocationAndMetaDataByNumber) {
- Add(0, 11U, "1", "2", 5000U);
- Add(0, 12U, "1", "2", 5000U);
- Add(2, 7U, "1", "2", 8000U);
- UpdateVersionStorageInfo();
- ASSERT_EQ(vstorage_.GetFileLocation(11U),
- VersionStorageInfo::FileLocation(0, 0));
- ASSERT_NE(vstorage_.GetFileMetaDataByNumber(11U), nullptr);
- ASSERT_EQ(vstorage_.GetFileLocation(12U),
- VersionStorageInfo::FileLocation(0, 1));
- ASSERT_NE(vstorage_.GetFileMetaDataByNumber(12U), nullptr);
- ASSERT_EQ(vstorage_.GetFileLocation(7U),
- VersionStorageInfo::FileLocation(2, 0));
- ASSERT_NE(vstorage_.GetFileMetaDataByNumber(7U), nullptr);
- ASSERT_FALSE(vstorage_.GetFileLocation(999U).IsValid());
- ASSERT_EQ(vstorage_.GetFileMetaDataByNumber(999U), nullptr);
- }
- TEST_F(VersionStorageInfoTest, ForcedBlobGCEmpty) {
- // No SST or blob files in VersionStorageInfo
- UpdateVersionStorageInfo();
- constexpr double age_cutoff = 0.5;
- constexpr double force_threshold = 0.75;
- vstorage_.ComputeFilesMarkedForForcedBlobGC(
- age_cutoff, force_threshold, /*enable_blob_garbage_collection=*/true);
- ASSERT_TRUE(vstorage_.FilesMarkedForForcedBlobGC().empty());
- }
- TEST_F(VersionStorageInfoTest, ForcedBlobGCSingleBatch) {
- // Test the edge case when all blob files are part of the oldest batch.
- // We have one L0 SST file #1, and four blob files #10, #11, #12, and #13.
- // The oldest blob file used by SST #1 is blob file #10.
- constexpr int level = 0;
- constexpr uint64_t sst = 1;
- constexpr uint64_t first_blob = 10;
- constexpr uint64_t second_blob = 11;
- constexpr uint64_t third_blob = 12;
- constexpr uint64_t fourth_blob = 13;
- {
- constexpr char smallest[] = "bar1";
- constexpr char largest[] = "foo1";
- constexpr uint64_t file_size = 1000;
- Add(level, sst, smallest, largest, file_size, first_blob);
- }
- {
- constexpr uint64_t total_blob_count = 10;
- constexpr uint64_t total_blob_bytes = 100000;
- constexpr uint64_t garbage_blob_count = 2;
- constexpr uint64_t garbage_blob_bytes = 15000;
- AddBlob(first_blob, total_blob_count, total_blob_bytes,
- BlobFileMetaData::LinkedSsts{sst}, garbage_blob_count,
- garbage_blob_bytes);
- }
- {
- constexpr uint64_t total_blob_count = 4;
- constexpr uint64_t total_blob_bytes = 400000;
- constexpr uint64_t garbage_blob_count = 3;
- constexpr uint64_t garbage_blob_bytes = 235000;
- AddBlob(second_blob, total_blob_count, total_blob_bytes,
- BlobFileMetaData::LinkedSsts{}, garbage_blob_count,
- garbage_blob_bytes);
- }
- {
- constexpr uint64_t total_blob_count = 20;
- constexpr uint64_t total_blob_bytes = 1000000;
- constexpr uint64_t garbage_blob_count = 8;
- constexpr uint64_t garbage_blob_bytes = 400000;
- AddBlob(third_blob, total_blob_count, total_blob_bytes,
- BlobFileMetaData::LinkedSsts{}, garbage_blob_count,
- garbage_blob_bytes);
- }
- {
- constexpr uint64_t total_blob_count = 128;
- constexpr uint64_t total_blob_bytes = 1000000;
- constexpr uint64_t garbage_blob_count = 67;
- constexpr uint64_t garbage_blob_bytes = 600000;
- AddBlob(fourth_blob, total_blob_count, total_blob_bytes,
- BlobFileMetaData::LinkedSsts{}, garbage_blob_count,
- garbage_blob_bytes);
- }
- UpdateVersionStorageInfo();
- assert(vstorage_.num_levels() > 0);
- const auto& level_files = vstorage_.LevelFiles(level);
- assert(level_files.size() == 1);
- assert(level_files[0] && level_files[0]->fd.GetNumber() == sst);
- // No blob files eligible for GC due to the age cutoff
- {
- constexpr double age_cutoff = 0.1;
- constexpr double force_threshold = 0.0;
- vstorage_.ComputeFilesMarkedForForcedBlobGC(
- age_cutoff, force_threshold, /*enable_blob_garbage_collection=*/true);
- ASSERT_TRUE(vstorage_.FilesMarkedForForcedBlobGC().empty());
- }
- // Overall garbage ratio of eligible files is below threshold
- {
- constexpr double age_cutoff = 1.0;
- constexpr double force_threshold = 0.6;
- vstorage_.ComputeFilesMarkedForForcedBlobGC(
- age_cutoff, force_threshold, /*enable_blob_garbage_collection=*/true);
- ASSERT_TRUE(vstorage_.FilesMarkedForForcedBlobGC().empty());
- }
- // Overall garbage ratio of eligible files meets threshold
- {
- constexpr double age_cutoff = 1.0;
- constexpr double force_threshold = 0.5;
- vstorage_.ComputeFilesMarkedForForcedBlobGC(
- age_cutoff, force_threshold, /*enable_blob_garbage_collection=*/true);
- auto ssts_to_be_compacted = vstorage_.FilesMarkedForForcedBlobGC();
- ASSERT_EQ(ssts_to_be_compacted.size(), 1);
- const autovector<std::pair<int, FileMetaData*>>
- expected_ssts_to_be_compacted{{level, level_files[0]}};
- ASSERT_EQ(ssts_to_be_compacted[0], expected_ssts_to_be_compacted[0]);
- }
- }
- TEST_F(VersionStorageInfoTest, ForcedBlobGCMultipleBatches) {
- // Add three L0 SSTs (1, 2, and 3) and four blob files (10, 11, 12, and 13).
- // The first two SSTs have the same oldest blob file, namely, the very oldest
- // one (10), while the third SST's oldest blob file reference points to the
- // third blob file (12). Thus, the oldest batch of blob files contains the
- // first two blob files 10 and 11, and assuming they are eligible for GC based
- // on the age cutoff, compacting away the SSTs 1 and 2 will eliminate them.
- constexpr int level = 0;
- constexpr uint64_t first_sst = 1;
- constexpr uint64_t second_sst = 2;
- constexpr uint64_t third_sst = 3;
- constexpr uint64_t first_blob = 10;
- constexpr uint64_t second_blob = 11;
- constexpr uint64_t third_blob = 12;
- constexpr uint64_t fourth_blob = 13;
- {
- constexpr char smallest[] = "bar1";
- constexpr char largest[] = "foo1";
- constexpr uint64_t file_size = 1000;
- Add(level, first_sst, smallest, largest, file_size, first_blob);
- }
- {
- constexpr char smallest[] = "bar2";
- constexpr char largest[] = "foo2";
- constexpr uint64_t file_size = 2000;
- Add(level, second_sst, smallest, largest, file_size, first_blob);
- }
- {
- constexpr char smallest[] = "bar3";
- constexpr char largest[] = "foo3";
- constexpr uint64_t file_size = 3000;
- Add(level, third_sst, smallest, largest, file_size, third_blob);
- }
- {
- constexpr uint64_t total_blob_count = 10;
- constexpr uint64_t total_blob_bytes = 100000;
- constexpr uint64_t garbage_blob_count = 2;
- constexpr uint64_t garbage_blob_bytes = 15000;
- AddBlob(first_blob, total_blob_count, total_blob_bytes,
- BlobFileMetaData::LinkedSsts{first_sst, second_sst},
- garbage_blob_count, garbage_blob_bytes);
- }
- {
- constexpr uint64_t total_blob_count = 4;
- constexpr uint64_t total_blob_bytes = 400000;
- constexpr uint64_t garbage_blob_count = 3;
- constexpr uint64_t garbage_blob_bytes = 235000;
- AddBlob(second_blob, total_blob_count, total_blob_bytes,
- BlobFileMetaData::LinkedSsts{}, garbage_blob_count,
- garbage_blob_bytes);
- }
- {
- constexpr uint64_t total_blob_count = 20;
- constexpr uint64_t total_blob_bytes = 1000000;
- constexpr uint64_t garbage_blob_count = 8;
- constexpr uint64_t garbage_blob_bytes = 123456;
- AddBlob(third_blob, total_blob_count, total_blob_bytes,
- BlobFileMetaData::LinkedSsts{third_sst}, garbage_blob_count,
- garbage_blob_bytes);
- }
- {
- constexpr uint64_t total_blob_count = 128;
- constexpr uint64_t total_blob_bytes = 789012345;
- constexpr uint64_t garbage_blob_count = 67;
- constexpr uint64_t garbage_blob_bytes = 88888888;
- AddBlob(fourth_blob, total_blob_count, total_blob_bytes,
- BlobFileMetaData::LinkedSsts{}, garbage_blob_count,
- garbage_blob_bytes);
- }
- UpdateVersionStorageInfo();
- assert(vstorage_.num_levels() > 0);
- const auto& level_files = vstorage_.LevelFiles(level);
- assert(level_files.size() == 3);
- assert(level_files[0] && level_files[0]->fd.GetNumber() == first_sst);
- assert(level_files[1] && level_files[1]->fd.GetNumber() == second_sst);
- assert(level_files[2] && level_files[2]->fd.GetNumber() == third_sst);
- // No blob files eligible for GC due to the age cutoff
- {
- constexpr double age_cutoff = 0.1;
- constexpr double force_threshold = 0.0;
- vstorage_.ComputeFilesMarkedForForcedBlobGC(
- age_cutoff, force_threshold, /*enable_blob_garbage_collection=*/true);
- ASSERT_TRUE(vstorage_.FilesMarkedForForcedBlobGC().empty());
- }
- // Overall garbage ratio of eligible files is below threshold
- {
- constexpr double age_cutoff = 0.5;
- constexpr double force_threshold = 0.6;
- vstorage_.ComputeFilesMarkedForForcedBlobGC(
- age_cutoff, force_threshold, /*enable_blob_garbage_collection=*/true);
- ASSERT_TRUE(vstorage_.FilesMarkedForForcedBlobGC().empty());
- }
- // Overall garbage ratio of eligible files meets threshold
- {
- constexpr double age_cutoff = 0.5;
- constexpr double force_threshold = 0.5;
- vstorage_.ComputeFilesMarkedForForcedBlobGC(
- age_cutoff, force_threshold, /*enable_blob_garbage_collection=*/true);
- auto ssts_to_be_compacted = vstorage_.FilesMarkedForForcedBlobGC();
- ASSERT_EQ(ssts_to_be_compacted.size(), 2);
- std::sort(ssts_to_be_compacted.begin(), ssts_to_be_compacted.end(),
- [](const std::pair<int, FileMetaData*>& lhs,
- const std::pair<int, FileMetaData*>& rhs) {
- assert(lhs.second);
- assert(rhs.second);
- return lhs.second->fd.GetNumber() < rhs.second->fd.GetNumber();
- });
- const autovector<std::pair<int, FileMetaData*>>
- expected_ssts_to_be_compacted{{level, level_files[0]},
- {level, level_files[1]}};
- ASSERT_EQ(ssts_to_be_compacted[0], expected_ssts_to_be_compacted[0]);
- ASSERT_EQ(ssts_to_be_compacted[1], expected_ssts_to_be_compacted[1]);
- }
- }
- class VersionStorageInfoTimestampTest : public VersionStorageInfoTestBase {
- public:
- VersionStorageInfoTimestampTest()
- : VersionStorageInfoTestBase(test::BytewiseComparatorWithU64TsWrapper()) {
- }
- ~VersionStorageInfoTimestampTest() override = default;
- std::string Timestamp(uint64_t ts) const {
- std::string ret;
- PutFixed64(&ret, ts);
- return ret;
- }
- std::string PackUserKeyAndTimestamp(const Slice& ukey, uint64_t ts) const {
- std::string ret;
- ret.assign(ukey.data(), ukey.size());
- PutFixed64(&ret, ts);
- return ret;
- }
- };
- TEST_F(VersionStorageInfoTimestampTest, GetOverlappingInputs) {
- Add(/*level=*/1, /*file_number=*/1, /*smallest=*/
- {PackUserKeyAndTimestamp("a", /*ts=*/9), /*s=*/0, kTypeValue},
- /*largest=*/
- {PackUserKeyAndTimestamp("a", /*ts=*/8), /*s=*/0, kTypeValue},
- /*file_size=*/100);
- Add(/*level=*/1, /*file_number=*/2, /*smallest=*/
- {PackUserKeyAndTimestamp("a", /*ts=*/5), /*s=*/0, kTypeValue},
- /*largest=*/
- {PackUserKeyAndTimestamp("b", /*ts=*/10), /*s=*/0, kTypeValue},
- /*file_size=*/100);
- Add(/*level=*/1, /*file_number=*/3, /*smallest=*/
- {PackUserKeyAndTimestamp("c", /*ts=*/12), /*s=*/0, kTypeValue},
- /*largest=*/
- {PackUserKeyAndTimestamp("d", /*ts=*/1), /*s=*/0, kTypeValue},
- /*file_size=*/100);
- UpdateVersionStorageInfo();
- ASSERT_EQ(
- "1,2",
- GetOverlappingFiles(
- /*level=*/1,
- {PackUserKeyAndTimestamp("a", /*ts=*/12), /*s=*/0, kTypeValue},
- {PackUserKeyAndTimestamp("a", /*ts=*/11), /*s=*/0, kTypeValue}));
- ASSERT_EQ("3",
- GetOverlappingFiles(
- /*level=*/1,
- {PackUserKeyAndTimestamp("c", /*ts=*/15), /*s=*/0, kTypeValue},
- {PackUserKeyAndTimestamp("c", /*ts=*/2), /*s=*/0, kTypeValue}));
- }
- class FindLevelFileTest : public testing::Test {
- public:
- LevelFilesBrief file_level_;
- bool disjoint_sorted_files_;
- Arena arena_;
- FindLevelFileTest() : disjoint_sorted_files_(true) {}
- ~FindLevelFileTest() override = default;
- void LevelFileInit(size_t num = 0) {
- char* mem = arena_.AllocateAligned(num * sizeof(FdWithKeyRange));
- file_level_.files = new (mem) FdWithKeyRange[num];
- file_level_.num_files = 0;
- }
- void Add(const char* smallest, const char* largest,
- SequenceNumber smallest_seq = 100,
- SequenceNumber largest_seq = 100) {
- InternalKey smallest_key = InternalKey(smallest, smallest_seq, kTypeValue);
- InternalKey largest_key = InternalKey(largest, largest_seq, kTypeValue);
- Slice smallest_slice = smallest_key.Encode();
- Slice largest_slice = largest_key.Encode();
- char* mem =
- arena_.AllocateAligned(smallest_slice.size() + largest_slice.size());
- memcpy(mem, smallest_slice.data(), smallest_slice.size());
- memcpy(mem + smallest_slice.size(), largest_slice.data(),
- largest_slice.size());
- // add to file_level_
- size_t num = file_level_.num_files;
- auto& file = file_level_.files[num];
- file.fd = FileDescriptor(num + 1, 0, 0);
- file.smallest_key = Slice(mem, smallest_slice.size());
- file.largest_key = Slice(mem + smallest_slice.size(), largest_slice.size());
- file_level_.num_files++;
- }
- int Find(const char* key) {
- InternalKey target(key, 100, kTypeValue);
- InternalKeyComparator cmp(BytewiseComparator());
- return FindFile(cmp, file_level_, target.Encode());
- }
- bool Overlaps(const char* smallest, const char* largest) {
- InternalKeyComparator cmp(BytewiseComparator());
- Slice s(smallest != nullptr ? smallest : "");
- Slice l(largest != nullptr ? largest : "");
- return SomeFileOverlapsRange(cmp, disjoint_sorted_files_, file_level_,
- (smallest != nullptr ? &s : nullptr),
- (largest != nullptr ? &l : nullptr));
- }
- };
- TEST_F(FindLevelFileTest, LevelEmpty) {
- LevelFileInit(0);
- ASSERT_EQ(0, Find("foo"));
- ASSERT_TRUE(!Overlaps("a", "z"));
- ASSERT_TRUE(!Overlaps(nullptr, "z"));
- ASSERT_TRUE(!Overlaps("a", nullptr));
- ASSERT_TRUE(!Overlaps(nullptr, nullptr));
- }
- TEST_F(FindLevelFileTest, LevelSingle) {
- LevelFileInit(1);
- Add("p", "q");
- ASSERT_EQ(0, Find("a"));
- ASSERT_EQ(0, Find("p"));
- ASSERT_EQ(0, Find("p1"));
- ASSERT_EQ(0, Find("q"));
- ASSERT_EQ(1, Find("q1"));
- ASSERT_EQ(1, Find("z"));
- ASSERT_TRUE(!Overlaps("a", "b"));
- ASSERT_TRUE(!Overlaps("z1", "z2"));
- ASSERT_TRUE(Overlaps("a", "p"));
- ASSERT_TRUE(Overlaps("a", "q"));
- ASSERT_TRUE(Overlaps("a", "z"));
- ASSERT_TRUE(Overlaps("p", "p1"));
- ASSERT_TRUE(Overlaps("p", "q"));
- ASSERT_TRUE(Overlaps("p", "z"));
- ASSERT_TRUE(Overlaps("p1", "p2"));
- ASSERT_TRUE(Overlaps("p1", "z"));
- ASSERT_TRUE(Overlaps("q", "q"));
- ASSERT_TRUE(Overlaps("q", "q1"));
- ASSERT_TRUE(!Overlaps(nullptr, "j"));
- ASSERT_TRUE(!Overlaps("r", nullptr));
- ASSERT_TRUE(Overlaps(nullptr, "p"));
- ASSERT_TRUE(Overlaps(nullptr, "p1"));
- ASSERT_TRUE(Overlaps("q", nullptr));
- ASSERT_TRUE(Overlaps(nullptr, nullptr));
- }
- TEST_F(FindLevelFileTest, LevelMultiple) {
- LevelFileInit(4);
- Add("150", "200");
- Add("200", "250");
- Add("300", "350");
- Add("400", "450");
- ASSERT_EQ(0, Find("100"));
- ASSERT_EQ(0, Find("150"));
- ASSERT_EQ(0, Find("151"));
- ASSERT_EQ(0, Find("199"));
- ASSERT_EQ(0, Find("200"));
- ASSERT_EQ(1, Find("201"));
- ASSERT_EQ(1, Find("249"));
- ASSERT_EQ(1, Find("250"));
- ASSERT_EQ(2, Find("251"));
- ASSERT_EQ(2, Find("299"));
- ASSERT_EQ(2, Find("300"));
- ASSERT_EQ(2, Find("349"));
- ASSERT_EQ(2, Find("350"));
- ASSERT_EQ(3, Find("351"));
- ASSERT_EQ(3, Find("400"));
- ASSERT_EQ(3, Find("450"));
- ASSERT_EQ(4, Find("451"));
- ASSERT_TRUE(!Overlaps("100", "149"));
- ASSERT_TRUE(!Overlaps("251", "299"));
- ASSERT_TRUE(!Overlaps("451", "500"));
- ASSERT_TRUE(!Overlaps("351", "399"));
- ASSERT_TRUE(Overlaps("100", "150"));
- ASSERT_TRUE(Overlaps("100", "200"));
- ASSERT_TRUE(Overlaps("100", "300"));
- ASSERT_TRUE(Overlaps("100", "400"));
- ASSERT_TRUE(Overlaps("100", "500"));
- ASSERT_TRUE(Overlaps("375", "400"));
- ASSERT_TRUE(Overlaps("450", "450"));
- ASSERT_TRUE(Overlaps("450", "500"));
- }
- TEST_F(FindLevelFileTest, LevelMultipleNullBoundaries) {
- LevelFileInit(4);
- Add("150", "200");
- Add("200", "250");
- Add("300", "350");
- Add("400", "450");
- ASSERT_TRUE(!Overlaps(nullptr, "149"));
- ASSERT_TRUE(!Overlaps("451", nullptr));
- ASSERT_TRUE(Overlaps(nullptr, nullptr));
- ASSERT_TRUE(Overlaps(nullptr, "150"));
- ASSERT_TRUE(Overlaps(nullptr, "199"));
- ASSERT_TRUE(Overlaps(nullptr, "200"));
- ASSERT_TRUE(Overlaps(nullptr, "201"));
- ASSERT_TRUE(Overlaps(nullptr, "400"));
- ASSERT_TRUE(Overlaps(nullptr, "800"));
- ASSERT_TRUE(Overlaps("100", nullptr));
- ASSERT_TRUE(Overlaps("200", nullptr));
- ASSERT_TRUE(Overlaps("449", nullptr));
- ASSERT_TRUE(Overlaps("450", nullptr));
- }
- TEST_F(FindLevelFileTest, LevelOverlapSequenceChecks) {
- LevelFileInit(1);
- Add("200", "200", 5000, 3000);
- ASSERT_TRUE(!Overlaps("199", "199"));
- ASSERT_TRUE(!Overlaps("201", "300"));
- ASSERT_TRUE(Overlaps("200", "200"));
- ASSERT_TRUE(Overlaps("190", "200"));
- ASSERT_TRUE(Overlaps("200", "210"));
- }
- TEST_F(FindLevelFileTest, LevelOverlappingFiles) {
- LevelFileInit(2);
- Add("150", "600");
- Add("400", "500");
- disjoint_sorted_files_ = false;
- ASSERT_TRUE(!Overlaps("100", "149"));
- ASSERT_TRUE(!Overlaps("601", "700"));
- ASSERT_TRUE(Overlaps("100", "150"));
- ASSERT_TRUE(Overlaps("100", "200"));
- ASSERT_TRUE(Overlaps("100", "300"));
- ASSERT_TRUE(Overlaps("100", "400"));
- ASSERT_TRUE(Overlaps("100", "500"));
- ASSERT_TRUE(Overlaps("375", "400"));
- ASSERT_TRUE(Overlaps("450", "450"));
- ASSERT_TRUE(Overlaps("450", "500"));
- ASSERT_TRUE(Overlaps("450", "700"));
- ASSERT_TRUE(Overlaps("600", "700"));
- }
- class VersionSetTestBase {
- public:
- const static std::string kColumnFamilyName1;
- const static std::string kColumnFamilyName2;
- const static std::string kColumnFamilyName3;
- const static int kNumColumnFamilies = 4;
- int num_initial_edits_;
- explicit VersionSetTestBase(const std::string& name)
- : env_(nullptr),
- dbname_(test::PerThreadDBPath(name)),
- options_(),
- db_options_(options_),
- cf_options_(options_),
- immutable_options_(db_options_, cf_options_),
- mutable_cf_options_(cf_options_),
- table_cache_(NewLRUCache(50000, 16)),
- write_buffer_manager_(db_options_.db_write_buffer_size),
- shutting_down_(false),
- table_factory_(std::make_shared<mock::MockTableFactory>()) {
- EXPECT_OK(test::CreateEnvFromSystem(ConfigOptions(), &env_, &env_guard_));
- if (env_ == Env::Default() && getenv("MEM_ENV")) {
- env_guard_.reset(NewMemEnv(Env::Default()));
- env_ = env_guard_.get();
- }
- EXPECT_NE(nullptr, env_);
- fs_ = env_->GetFileSystem();
- EXPECT_OK(fs_->CreateDirIfMissing(dbname_, IOOptions(), nullptr));
- options_.env = env_;
- db_options_.env = env_;
- db_options_.fs = fs_;
- immutable_options_.env = env_;
- immutable_options_.fs = fs_;
- immutable_options_.clock = env_->GetSystemClock().get();
- cf_options_.table_factory = table_factory_;
- mutable_cf_options_.table_factory = table_factory_;
- versions_.reset(new VersionSet(
- dbname_, &db_options_, env_options_, table_cache_.get(),
- &write_buffer_manager_, &write_controller_,
- /*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
- /*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
- /*error_handler=*/nullptr, /*read_only=*/false));
- reactive_versions_ = std::make_shared<ReactiveVersionSet>(
- dbname_, &db_options_, env_options_, table_cache_.get(),
- &write_buffer_manager_, &write_controller_, nullptr);
- db_options_.db_paths.emplace_back(dbname_,
- std::numeric_limits<uint64_t>::max());
- }
- virtual ~VersionSetTestBase() {
- if (getenv("KEEP_DB")) {
- fprintf(stdout, "DB is still at %s\n", dbname_.c_str());
- } else {
- Options options;
- options.env = env_;
- EXPECT_OK(DestroyDB(dbname_, options));
- }
- }
- protected:
- virtual void PrepareManifest(
- std::vector<ColumnFamilyDescriptor>* column_families,
- SequenceNumber* last_seqno, std::unique_ptr<log::Writer>* log_writer) {
- assert(column_families != nullptr);
- assert(last_seqno != nullptr);
- assert(log_writer != nullptr);
- ASSERT_OK(
- SetIdentityFile(WriteOptions(), env_, dbname_, Temperature::kUnknown));
- VersionEdit new_db;
- if (db_options_.write_dbid_to_manifest) {
- DBOptions tmp_db_options;
- tmp_db_options.env = env_;
- std::unique_ptr<DBImpl> impl(new DBImpl(tmp_db_options, dbname_));
- std::string db_id;
- ASSERT_OK(impl->GetDbIdentityFromIdentityFile(IOOptions(), &db_id));
- new_db.SetDBId(db_id);
- }
- new_db.SetLogNumber(0);
- new_db.SetNextFile(2);
- new_db.SetLastSequence(0);
- const std::vector<std::string> cf_names = {
- kDefaultColumnFamilyName, kColumnFamilyName1, kColumnFamilyName2,
- kColumnFamilyName3};
- const int kInitialNumOfCfs = static_cast<int>(cf_names.size());
- autovector<VersionEdit> new_cfs;
- uint64_t last_seq = 1;
- uint32_t cf_id = 1;
- for (int i = 1; i != kInitialNumOfCfs; ++i) {
- VersionEdit new_cf;
- new_cf.AddColumnFamily(cf_names[i]);
- new_cf.SetColumnFamily(cf_id++);
- new_cf.SetLogNumber(0);
- new_cf.SetNextFile(2);
- new_cf.SetLastSequence(last_seq++);
- new_cfs.emplace_back(new_cf);
- }
- *last_seqno = last_seq;
- num_initial_edits_ = static_cast<int>(new_cfs.size() + 1);
- std::unique_ptr<WritableFileWriter> file_writer;
- const std::string manifest = DescriptorFileName(dbname_, 1);
- const auto& fs = env_->GetFileSystem();
- Status s = WritableFileWriter::Create(
- fs, manifest, fs->OptimizeForManifestWrite(env_options_), &file_writer,
- nullptr);
- ASSERT_OK(s);
- {
- log_writer->reset(new log::Writer(std::move(file_writer), 0, false));
- std::string record;
- new_db.EncodeTo(&record);
- s = (*log_writer)->AddRecord(WriteOptions(), record);
- for (const auto& e : new_cfs) {
- record.clear();
- e.EncodeTo(&record);
- s = (*log_writer)->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- }
- }
- ASSERT_OK(s);
- cf_options_.table_factory = table_factory_;
- for (const auto& cf_name : cf_names) {
- column_families->emplace_back(cf_name, cf_options_);
- }
- }
- struct SstInfo {
- uint64_t file_number;
- std::string column_family;
- std::string key; // the only key
- int level = 0;
- uint64_t epoch_number;
- bool file_missing = false;
- uint64_t oldest_blob_file_number = kInvalidBlobFileNumber;
- SstInfo(uint64_t file_num, const std::string& cf_name,
- const std::string& _key,
- uint64_t _epoch_number = kUnknownEpochNumber,
- bool _file_missing = false,
- uint64_t _oldest_blob_file_number = kInvalidBlobFileNumber)
- : SstInfo(file_num, cf_name, _key, 0, _epoch_number, _file_missing,
- _oldest_blob_file_number) {}
- SstInfo(uint64_t file_num, const std::string& cf_name,
- const std::string& _key, int lvl,
- uint64_t _epoch_number = kUnknownEpochNumber,
- bool _file_missing = false,
- uint64_t _oldest_blob_file_number = kInvalidBlobFileNumber)
- : file_number(file_num),
- column_family(cf_name),
- key(_key),
- level(lvl),
- epoch_number(_epoch_number),
- file_missing(_file_missing),
- oldest_blob_file_number(_oldest_blob_file_number) {}
- };
- // Create dummy sst, return their metadata. Note that only file name and size
- // are used.
- void CreateDummyTableFiles(const std::vector<SstInfo>& file_infos,
- std::vector<FileMetaData>* file_metas) {
- assert(file_metas != nullptr);
- for (const auto& info : file_infos) {
- uint64_t file_num = info.file_number;
- std::string fname = MakeTableFileName(dbname_, file_num);
- std::unique_ptr<FSWritableFile> file;
- Status s = fs_->NewWritableFile(fname, FileOptions(), &file, nullptr);
- ASSERT_OK(s);
- std::unique_ptr<WritableFileWriter> fwriter(new WritableFileWriter(
- std::move(file), fname, FileOptions(), env_->GetSystemClock().get()));
- InternalTblPropCollFactories internal_tbl_prop_coll_factories;
- const ReadOptions read_options;
- const WriteOptions write_options;
- std::unique_ptr<TableBuilder> builder(table_factory_->NewTableBuilder(
- TableBuilderOptions(
- immutable_options_, mutable_cf_options_, read_options,
- write_options, InternalKeyComparator(options_.comparator),
- &internal_tbl_prop_coll_factories, kNoCompression,
- CompressionOptions(),
- TablePropertiesCollectorFactory::Context::kUnknownColumnFamily,
- info.column_family, info.level, kUnknownNewestKeyTime),
- fwriter.get()));
- InternalKey ikey(info.key, 0, ValueType::kTypeValue);
- builder->Add(ikey.Encode(), "value");
- ASSERT_OK(builder->Finish());
- ASSERT_OK(fwriter->Flush(IOOptions()));
- uint64_t file_size = 0;
- s = fs_->GetFileSize(fname, IOOptions(), &file_size, nullptr);
- ASSERT_OK(s);
- ASSERT_NE(0, file_size);
- file_metas->emplace_back(
- file_num, /*file_path_id=*/0, file_size, ikey, ikey, 0, 0, false,
- Temperature::kUnknown, info.oldest_blob_file_number, 0, 0,
- info.epoch_number, kUnknownFileChecksum, kUnknownFileChecksumFuncName,
- kNullUniqueId64x2, 0, 0,
- /* user_defined_timestamps_persisted */ true);
- if (info.file_missing) {
- ASSERT_OK(fs_->DeleteFile(fname, IOOptions(), nullptr));
- }
- }
- }
- void CreateCurrentFile() {
- // Make "CURRENT" file point to the new manifest file.
- ASSERT_OK(SetCurrentFile(WriteOptions(), fs_.get(), dbname_, 1,
- Temperature::kUnknown,
- /* dir_contains_current_file */ nullptr));
- }
- // Create DB with 3 column families.
- void NewDB() {
- SequenceNumber last_seqno;
- std::unique_ptr<log::Writer> log_writer;
- PrepareManifest(&column_families_, &last_seqno, &log_writer);
- log_writer.reset();
- CreateCurrentFile();
- EXPECT_OK(versions_->Recover(column_families_, false));
- EXPECT_EQ(column_families_.size(),
- versions_->GetColumnFamilySet()->NumberOfColumnFamilies());
- }
- void CloseDB() {
- mutex_.Lock();
- versions_->Close(nullptr, &mutex_).PermitUncheckedError();
- versions_.reset();
- mutex_.Unlock();
- }
- void ReopenDB() {
- versions_.reset(new VersionSet(
- dbname_, &db_options_, env_options_, table_cache_.get(),
- &write_buffer_manager_, &write_controller_,
- /*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
- /*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
- /*error_handler=*/nullptr, /*read_only=*/false));
- EXPECT_OK(versions_->Recover(column_families_, false));
- }
- void GetManifestPath(std::string* manifest_path) const {
- assert(manifest_path != nullptr);
- uint64_t manifest_file_number = 0;
- Status s = GetCurrentManifestPath(dbname_, fs_.get(), /*is_retry=*/false,
- manifest_path, &manifest_file_number);
- ASSERT_OK(s);
- }
- void VerifyManifest(std::string* manifest_path) const {
- assert(manifest_path != nullptr);
- uint64_t manifest_file_number = 0;
- Status s = GetCurrentManifestPath(dbname_, fs_.get(), /*is_retry=*/false,
- manifest_path, &manifest_file_number);
- ASSERT_OK(s);
- ASSERT_EQ(1, manifest_file_number);
- }
- Status LogAndApplyToDefaultCF(VersionEdit& edit) {
- mutex_.Lock();
- Status s = versions_->LogAndApply(
- versions_->GetColumnFamilySet()->GetDefault(), read_options_,
- write_options_, &edit, &mutex_, nullptr);
- mutex_.Unlock();
- return s;
- }
- Status LogAndApplyToDefaultCF(
- const autovector<std::unique_ptr<VersionEdit>>& edits) {
- autovector<VersionEdit*> vedits;
- for (auto& e : edits) {
- vedits.push_back(e.get());
- }
- mutex_.Lock();
- Status s = versions_->LogAndApply(
- versions_->GetColumnFamilySet()->GetDefault(), read_options_,
- write_options_, vedits, &mutex_, nullptr);
- mutex_.Unlock();
- return s;
- }
- void CreateNewManifest() {
- constexpr FSDirectory* db_directory = nullptr;
- constexpr bool new_descriptor_log = true;
- mutex_.Lock();
- VersionEdit dummy;
- ASSERT_OK(versions_->LogAndApply(
- versions_->GetColumnFamilySet()->GetDefault(), read_options_,
- write_options_, &dummy, &mutex_, db_directory, new_descriptor_log));
- mutex_.Unlock();
- }
- ColumnFamilyData* CreateColumnFamily(const std::string& cf_name,
- const ColumnFamilyOptions& cf_options) {
- VersionEdit new_cf;
- new_cf.AddColumnFamily(cf_name);
- uint32_t new_id = versions_->GetColumnFamilySet()->GetNextColumnFamilyID();
- new_cf.SetColumnFamily(new_id);
- new_cf.SetLogNumber(0);
- new_cf.SetComparatorName(cf_options.comparator->Name());
- new_cf.SetPersistUserDefinedTimestamps(
- cf_options.persist_user_defined_timestamps);
- Status s;
- mutex_.Lock();
- s = versions_->LogAndApply(/*column_family_data=*/nullptr, read_options_,
- write_options_, &new_cf, &mutex_,
- /*db_directory=*/nullptr,
- /*new_descriptor_log=*/false, &cf_options);
- mutex_.Unlock();
- EXPECT_OK(s);
- ColumnFamilyData* cfd =
- versions_->GetColumnFamilySet()->GetColumnFamily(cf_name);
- EXPECT_NE(nullptr, cfd);
- return cfd;
- }
- Env* mem_env_;
- Env* env_;
- std::shared_ptr<Env> env_guard_;
- std::shared_ptr<FileSystem> fs_;
- const std::string dbname_;
- EnvOptions env_options_;
- Options options_;
- ImmutableDBOptions db_options_;
- ColumnFamilyOptions cf_options_;
- ImmutableOptions immutable_options_;
- MutableCFOptions mutable_cf_options_;
- const ReadOptions read_options_;
- const WriteOptions write_options_;
- std::shared_ptr<Cache> table_cache_;
- WriteController write_controller_;
- WriteBufferManager write_buffer_manager_;
- std::shared_ptr<VersionSet> versions_;
- std::shared_ptr<ReactiveVersionSet> reactive_versions_;
- InstrumentedMutex mutex_;
- std::atomic<bool> shutting_down_;
- std::shared_ptr<TableFactory> table_factory_;
- std::vector<ColumnFamilyDescriptor> column_families_;
- };
- const std::string VersionSetTestBase::kColumnFamilyName1 = "alice";
- const std::string VersionSetTestBase::kColumnFamilyName2 = "bob";
- const std::string VersionSetTestBase::kColumnFamilyName3 = "charles";
- class VersionSetTest : public VersionSetTestBase, public testing::Test {
- public:
- VersionSetTest() : VersionSetTestBase("version_set_test") {}
- };
- TEST_F(VersionSetTest, SameColumnFamilyGroupCommit) {
- NewDB();
- const int kGroupSize = 5;
- const ReadOptions read_options;
- const WriteOptions write_options;
- autovector<VersionEdit> edits;
- for (int i = 0; i != kGroupSize; ++i) {
- edits.emplace_back(VersionEdit());
- }
- autovector<ColumnFamilyData*> cfds;
- autovector<autovector<VersionEdit*>> edit_lists;
- for (int i = 0; i != kGroupSize; ++i) {
- cfds.emplace_back(versions_->GetColumnFamilySet()->GetDefault());
- autovector<VersionEdit*> edit_list;
- edit_list.emplace_back(&edits[i]);
- edit_lists.emplace_back(edit_list);
- }
- SyncPoint::GetInstance()->DisableProcessing();
- SyncPoint::GetInstance()->ClearAllCallBacks();
- int count = 0;
- SyncPoint::GetInstance()->SetCallBack(
- "VersionSet::ProcessManifestWrites:SameColumnFamily", [&](void* arg) {
- uint32_t* cf_id = static_cast<uint32_t*>(arg);
- EXPECT_EQ(0u, *cf_id);
- ++count;
- });
- SyncPoint::GetInstance()->EnableProcessing();
- mutex_.Lock();
- Status s = versions_->LogAndApply(cfds, read_options, write_options,
- edit_lists, &mutex_, nullptr);
- mutex_.Unlock();
- EXPECT_OK(s);
- EXPECT_EQ(kGroupSize - 1, count);
- }
- TEST_F(VersionSetTest, PersistBlobFileStateInNewManifest) {
- // Initialize the database and add a couple of blob files, one with some
- // garbage in it, and one without any garbage.
- NewDB();
- assert(versions_);
- assert(versions_->GetColumnFamilySet());
- ColumnFamilyData* const cfd = versions_->GetColumnFamilySet()->GetDefault();
- assert(cfd);
- Version* const version = cfd->current();
- assert(version);
- VersionStorageInfo* const storage_info = version->storage_info();
- assert(storage_info);
- {
- constexpr uint64_t blob_file_number = 123;
- constexpr uint64_t total_blob_count = 456;
- constexpr uint64_t total_blob_bytes = 77777777;
- constexpr char checksum_method[] = "SHA1";
- constexpr char checksum_value[] =
- "\xbd\xb7\xf3\x4a\x59\xdf\xa1\x59\x2c\xe7\xf5\x2e\x99\xf9\x8c\x57\x0c"
- "\x52\x5c\xbd";
- auto shared_meta = SharedBlobFileMetaData::Create(
- blob_file_number, total_blob_count, total_blob_bytes, checksum_method,
- checksum_value);
- constexpr uint64_t garbage_blob_count = 89;
- constexpr uint64_t garbage_blob_bytes = 1000000;
- auto meta = BlobFileMetaData::Create(
- std::move(shared_meta), BlobFileMetaData::LinkedSsts(),
- garbage_blob_count, garbage_blob_bytes);
- storage_info->AddBlobFile(std::move(meta));
- }
- {
- constexpr uint64_t blob_file_number = 234;
- constexpr uint64_t total_blob_count = 555;
- constexpr uint64_t total_blob_bytes = 66666;
- constexpr char checksum_method[] = "CRC32";
- constexpr char checksum_value[] = "\x3d\x87\xff\x57";
- auto shared_meta = SharedBlobFileMetaData::Create(
- blob_file_number, total_blob_count, total_blob_bytes, checksum_method,
- checksum_value);
- constexpr uint64_t garbage_blob_count = 0;
- constexpr uint64_t garbage_blob_bytes = 0;
- auto meta = BlobFileMetaData::Create(
- std::move(shared_meta), BlobFileMetaData::LinkedSsts(),
- garbage_blob_count, garbage_blob_bytes);
- storage_info->AddBlobFile(std::move(meta));
- }
- // Force the creation of a new manifest file and make sure metadata for
- // the blob files is re-persisted.
- size_t addition_encoded = 0;
- SyncPoint::GetInstance()->SetCallBack(
- "BlobFileAddition::EncodeTo::CustomFields",
- [&](void* /* arg */) { ++addition_encoded; });
- size_t garbage_encoded = 0;
- SyncPoint::GetInstance()->SetCallBack(
- "BlobFileGarbage::EncodeTo::CustomFields",
- [&](void* /* arg */) { ++garbage_encoded; });
- SyncPoint::GetInstance()->EnableProcessing();
- CreateNewManifest();
- ASSERT_EQ(addition_encoded, 2);
- ASSERT_EQ(garbage_encoded, 1);
- SyncPoint::GetInstance()->DisableProcessing();
- SyncPoint::GetInstance()->ClearAllCallBacks();
- }
- TEST_F(VersionSetTest, AddLiveBlobFiles) {
- // Initialize the database and add a blob file.
- NewDB();
- assert(versions_);
- assert(versions_->GetColumnFamilySet());
- ColumnFamilyData* const cfd = versions_->GetColumnFamilySet()->GetDefault();
- assert(cfd);
- Version* const first_version = cfd->current();
- assert(first_version);
- VersionStorageInfo* const first_storage_info = first_version->storage_info();
- assert(first_storage_info);
- constexpr uint64_t first_blob_file_number = 234;
- constexpr uint64_t first_total_blob_count = 555;
- constexpr uint64_t first_total_blob_bytes = 66666;
- constexpr char first_checksum_method[] = "CRC32";
- constexpr char first_checksum_value[] = "\x3d\x87\xff\x57";
- auto first_shared_meta = SharedBlobFileMetaData::Create(
- first_blob_file_number, first_total_blob_count, first_total_blob_bytes,
- first_checksum_method, first_checksum_value);
- constexpr uint64_t garbage_blob_count = 0;
- constexpr uint64_t garbage_blob_bytes = 0;
- auto first_meta = BlobFileMetaData::Create(
- std::move(first_shared_meta), BlobFileMetaData::LinkedSsts(),
- garbage_blob_count, garbage_blob_bytes);
- first_storage_info->AddBlobFile(first_meta);
- // Reference the version so it stays alive even after the following version
- // edit.
- first_version->Ref();
- // Get live files directly from version.
- std::vector<uint64_t> version_table_files;
- std::vector<uint64_t> version_blob_files;
- first_version->AddLiveFiles(&version_table_files, &version_blob_files);
- ASSERT_EQ(version_blob_files.size(), 1);
- ASSERT_EQ(version_blob_files[0], first_blob_file_number);
- // Create a new version containing an additional blob file.
- versions_->TEST_CreateAndAppendVersion(cfd);
- Version* const second_version = cfd->current();
- assert(second_version);
- assert(second_version != first_version);
- VersionStorageInfo* const second_storage_info =
- second_version->storage_info();
- assert(second_storage_info);
- constexpr uint64_t second_blob_file_number = 456;
- constexpr uint64_t second_total_blob_count = 100;
- constexpr uint64_t second_total_blob_bytes = 2000000;
- constexpr char second_checksum_method[] = "CRC32B";
- constexpr char second_checksum_value[] = "\x6d\xbd\xf2\x3a";
- auto second_shared_meta = SharedBlobFileMetaData::Create(
- second_blob_file_number, second_total_blob_count, second_total_blob_bytes,
- second_checksum_method, second_checksum_value);
- auto second_meta = BlobFileMetaData::Create(
- std::move(second_shared_meta), BlobFileMetaData::LinkedSsts(),
- garbage_blob_count, garbage_blob_bytes);
- second_storage_info->AddBlobFile(std::move(first_meta));
- second_storage_info->AddBlobFile(std::move(second_meta));
- // Get all live files from version set. Note that the result contains
- // duplicates.
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_EQ(all_blob_files.size(), 3);
- ASSERT_EQ(all_blob_files[0], first_blob_file_number);
- ASSERT_EQ(all_blob_files[1], first_blob_file_number);
- ASSERT_EQ(all_blob_files[2], second_blob_file_number);
- // Clean up previous version.
- first_version->Unref();
- }
- TEST_F(VersionSetTest, ObsoleteBlobFile) {
- // Initialize the database and add a blob file that is entirely garbage
- // and thus can immediately be marked obsolete.
- NewDB();
- VersionEdit edit;
- constexpr uint64_t blob_file_number = 234;
- constexpr uint64_t total_blob_count = 555;
- constexpr uint64_t total_blob_bytes = 66666;
- constexpr char checksum_method[] = "CRC32";
- constexpr char checksum_value[] = "\x3d\x87\xff\x57";
- edit.AddBlobFile(blob_file_number, total_blob_count, total_blob_bytes,
- checksum_method, checksum_value);
- edit.AddBlobFileGarbage(blob_file_number, total_blob_count, total_blob_bytes);
- mutex_.Lock();
- Status s = versions_->LogAndApply(
- versions_->GetColumnFamilySet()->GetDefault(), read_options_,
- write_options_, &edit, &mutex_, nullptr);
- mutex_.Unlock();
- ASSERT_OK(s);
- // Make sure blob files from the pending number range are not returned
- // as obsolete.
- {
- std::vector<ObsoleteFileInfo> table_files;
- std::vector<ObsoleteBlobFileInfo> blob_files;
- std::vector<std::string> manifest_files;
- constexpr uint64_t min_pending_output = blob_file_number;
- versions_->GetObsoleteFiles(&table_files, &blob_files, &manifest_files,
- min_pending_output);
- ASSERT_TRUE(blob_files.empty());
- }
- // Make sure the blob file is returned as obsolete if it's not in the pending
- // range.
- {
- std::vector<ObsoleteFileInfo> table_files;
- std::vector<ObsoleteBlobFileInfo> blob_files;
- std::vector<std::string> manifest_files;
- constexpr uint64_t min_pending_output = blob_file_number + 1;
- versions_->GetObsoleteFiles(&table_files, &blob_files, &manifest_files,
- min_pending_output);
- ASSERT_EQ(blob_files.size(), 1);
- ASSERT_EQ(blob_files[0].GetBlobFileNumber(), blob_file_number);
- }
- // Make sure it's not returned a second time.
- {
- std::vector<ObsoleteFileInfo> table_files;
- std::vector<ObsoleteBlobFileInfo> blob_files;
- std::vector<std::string> manifest_files;
- constexpr uint64_t min_pending_output = blob_file_number + 1;
- versions_->GetObsoleteFiles(&table_files, &blob_files, &manifest_files,
- min_pending_output);
- ASSERT_TRUE(blob_files.empty());
- }
- }
- TEST_F(VersionSetTest, WalEditsNotAppliedToVersion) {
- NewDB();
- constexpr uint64_t kNumWals = 5;
- autovector<std::unique_ptr<VersionEdit>> edits;
- // Add some WALs.
- for (uint64_t i = 1; i <= kNumWals; i++) {
- edits.emplace_back(new VersionEdit);
- // WAL's size equals its log number.
- edits.back()->AddWal(i, WalMetadata(i));
- }
- // Delete the first half of the WALs.
- edits.emplace_back(new VersionEdit);
- edits.back()->DeleteWalsBefore(kNumWals / 2 + 1);
- autovector<Version*> versions;
- SyncPoint::GetInstance()->SetCallBack(
- "VersionSet::ProcessManifestWrites:NewVersion",
- [&](void* arg) { versions.push_back(static_cast<Version*>(arg)); });
- SyncPoint::GetInstance()->EnableProcessing();
- ASSERT_OK(LogAndApplyToDefaultCF(edits));
- SyncPoint::GetInstance()->DisableProcessing();
- SyncPoint::GetInstance()->ClearAllCallBacks();
- // Since the edits are all WAL edits, no version should be created.
- ASSERT_EQ(versions.size(), 1);
- ASSERT_EQ(versions[0], nullptr);
- }
- // Similar to WalEditsNotAppliedToVersion, but contains a non-WAL edit.
- TEST_F(VersionSetTest, NonWalEditsAppliedToVersion) {
- NewDB();
- const std::string kDBId = "db_db";
- constexpr uint64_t kNumWals = 5;
- autovector<std::unique_ptr<VersionEdit>> edits;
- // Add some WALs.
- for (uint64_t i = 1; i <= kNumWals; i++) {
- edits.emplace_back(new VersionEdit);
- // WAL's size equals its log number.
- edits.back()->AddWal(i, WalMetadata(i));
- }
- // Delete the first half of the WALs.
- edits.emplace_back(new VersionEdit);
- edits.back()->DeleteWalsBefore(kNumWals / 2 + 1);
- edits.emplace_back(new VersionEdit);
- edits.back()->SetDBId(kDBId);
- autovector<Version*> versions;
- SyncPoint::GetInstance()->SetCallBack(
- "VersionSet::ProcessManifestWrites:NewVersion",
- [&](void* arg) { versions.push_back(static_cast<Version*>(arg)); });
- SyncPoint::GetInstance()->EnableProcessing();
- ASSERT_OK(LogAndApplyToDefaultCF(edits));
- SyncPoint::GetInstance()->DisableProcessing();
- SyncPoint::GetInstance()->ClearAllCallBacks();
- // Since the edits are all WAL edits, no version should be created.
- ASSERT_EQ(versions.size(), 1);
- ASSERT_NE(versions[0], nullptr);
- }
- TEST_F(VersionSetTest, WalAddition) {
- NewDB();
- constexpr WalNumber kLogNumber = 10;
- constexpr uint64_t kSizeInBytes = 111;
- // A WAL is just created.
- {
- VersionEdit edit;
- edit.AddWal(kLogNumber);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- const auto& wals = versions_->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 1);
- ASSERT_TRUE(wals.find(kLogNumber) != wals.end());
- ASSERT_FALSE(wals.at(kLogNumber).HasSyncedSize());
- }
- // The WAL is synced for several times before closing.
- {
- for (uint64_t size_delta = 100; size_delta > 0; size_delta /= 2) {
- uint64_t size = kSizeInBytes - size_delta;
- WalMetadata wal(size);
- VersionEdit edit;
- edit.AddWal(kLogNumber, wal);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- const auto& wals = versions_->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 1);
- ASSERT_TRUE(wals.find(kLogNumber) != wals.end());
- ASSERT_TRUE(wals.at(kLogNumber).HasSyncedSize());
- ASSERT_EQ(wals.at(kLogNumber).GetSyncedSizeInBytes(), size);
- }
- }
- // The WAL is closed.
- {
- WalMetadata wal(kSizeInBytes);
- VersionEdit edit;
- edit.AddWal(kLogNumber, wal);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- const auto& wals = versions_->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 1);
- ASSERT_TRUE(wals.find(kLogNumber) != wals.end());
- ASSERT_TRUE(wals.at(kLogNumber).HasSyncedSize());
- ASSERT_EQ(wals.at(kLogNumber).GetSyncedSizeInBytes(), kSizeInBytes);
- }
- // Recover a new VersionSet.
- {
- std::unique_ptr<VersionSet> new_versions(new VersionSet(
- dbname_, &db_options_, env_options_, table_cache_.get(),
- &write_buffer_manager_, &write_controller_,
- /*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
- /*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
- /*error_handler=*/nullptr, /*unchanging=*/false));
- ASSERT_OK(new_versions->Recover(column_families_, /*read_only=*/false));
- const auto& wals = new_versions->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 1);
- ASSERT_TRUE(wals.find(kLogNumber) != wals.end());
- ASSERT_TRUE(wals.at(kLogNumber).HasSyncedSize());
- ASSERT_EQ(wals.at(kLogNumber).GetSyncedSizeInBytes(), kSizeInBytes);
- }
- }
- TEST_F(VersionSetTest, WalCloseWithoutSync) {
- NewDB();
- constexpr WalNumber kLogNumber = 10;
- constexpr uint64_t kSizeInBytes = 111;
- constexpr uint64_t kSyncedSizeInBytes = kSizeInBytes / 2;
- // A WAL is just created.
- {
- VersionEdit edit;
- edit.AddWal(kLogNumber);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- const auto& wals = versions_->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 1);
- ASSERT_TRUE(wals.find(kLogNumber) != wals.end());
- ASSERT_FALSE(wals.at(kLogNumber).HasSyncedSize());
- }
- // The WAL is synced before closing.
- {
- WalMetadata wal(kSyncedSizeInBytes);
- VersionEdit edit;
- edit.AddWal(kLogNumber, wal);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- const auto& wals = versions_->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 1);
- ASSERT_TRUE(wals.find(kLogNumber) != wals.end());
- ASSERT_TRUE(wals.at(kLogNumber).HasSyncedSize());
- ASSERT_EQ(wals.at(kLogNumber).GetSyncedSizeInBytes(), kSyncedSizeInBytes);
- }
- // A new WAL with larger log number is created,
- // implicitly marking the current WAL closed.
- {
- VersionEdit edit;
- edit.AddWal(kLogNumber + 1);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- const auto& wals = versions_->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 2);
- ASSERT_TRUE(wals.find(kLogNumber) != wals.end());
- ASSERT_TRUE(wals.at(kLogNumber).HasSyncedSize());
- ASSERT_EQ(wals.at(kLogNumber).GetSyncedSizeInBytes(), kSyncedSizeInBytes);
- ASSERT_TRUE(wals.find(kLogNumber + 1) != wals.end());
- ASSERT_FALSE(wals.at(kLogNumber + 1).HasSyncedSize());
- }
- // Recover a new VersionSet.
- {
- std::unique_ptr<VersionSet> new_versions(new VersionSet(
- dbname_, &db_options_, env_options_, table_cache_.get(),
- &write_buffer_manager_, &write_controller_,
- /*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
- /*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
- /*error_handler=*/nullptr, /*unchanging=*/false));
- ASSERT_OK(new_versions->Recover(column_families_, false));
- const auto& wals = new_versions->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 2);
- ASSERT_TRUE(wals.find(kLogNumber) != wals.end());
- ASSERT_TRUE(wals.at(kLogNumber).HasSyncedSize());
- ASSERT_EQ(wals.at(kLogNumber).GetSyncedSizeInBytes(), kSyncedSizeInBytes);
- }
- }
- TEST_F(VersionSetTest, WalDeletion) {
- NewDB();
- constexpr WalNumber kClosedLogNumber = 10;
- constexpr WalNumber kNonClosedLogNumber = 20;
- constexpr uint64_t kSizeInBytes = 111;
- // Add a non-closed and a closed WAL.
- {
- VersionEdit edit;
- edit.AddWal(kClosedLogNumber, WalMetadata(kSizeInBytes));
- edit.AddWal(kNonClosedLogNumber);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- const auto& wals = versions_->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 2);
- ASSERT_TRUE(wals.find(kNonClosedLogNumber) != wals.end());
- ASSERT_TRUE(wals.find(kClosedLogNumber) != wals.end());
- ASSERT_FALSE(wals.at(kNonClosedLogNumber).HasSyncedSize());
- ASSERT_TRUE(wals.at(kClosedLogNumber).HasSyncedSize());
- ASSERT_EQ(wals.at(kClosedLogNumber).GetSyncedSizeInBytes(), kSizeInBytes);
- }
- // Delete the closed WAL.
- {
- VersionEdit edit;
- edit.DeleteWalsBefore(kNonClosedLogNumber);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- const auto& wals = versions_->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 1);
- ASSERT_TRUE(wals.find(kNonClosedLogNumber) != wals.end());
- ASSERT_FALSE(wals.at(kNonClosedLogNumber).HasSyncedSize());
- }
- // Recover a new VersionSet, only the non-closed WAL should show up.
- {
- std::unique_ptr<VersionSet> new_versions(new VersionSet(
- dbname_, &db_options_, env_options_, table_cache_.get(),
- &write_buffer_manager_, &write_controller_,
- /*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
- /*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
- /*error_handler=*/nullptr, /*unchanging=*/false));
- ASSERT_OK(new_versions->Recover(column_families_, false));
- const auto& wals = new_versions->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 1);
- ASSERT_TRUE(wals.find(kNonClosedLogNumber) != wals.end());
- ASSERT_FALSE(wals.at(kNonClosedLogNumber).HasSyncedSize());
- }
- // Force the creation of a new MANIFEST file,
- // only the non-closed WAL should be written to the new MANIFEST.
- {
- std::vector<WalAddition> wal_additions;
- SyncPoint::GetInstance()->SetCallBack(
- "VersionSet::WriteCurrentStateToManifest:SaveWal", [&](void* arg) {
- VersionEdit* edit = static_cast<VersionEdit*>(arg);
- ASSERT_TRUE(edit->IsWalAddition());
- for (auto& addition : edit->GetWalAdditions()) {
- wal_additions.push_back(addition);
- }
- });
- SyncPoint::GetInstance()->EnableProcessing();
- CreateNewManifest();
- SyncPoint::GetInstance()->DisableProcessing();
- SyncPoint::GetInstance()->ClearAllCallBacks();
- ASSERT_EQ(wal_additions.size(), 1);
- ASSERT_EQ(wal_additions[0].GetLogNumber(), kNonClosedLogNumber);
- ASSERT_FALSE(wal_additions[0].GetMetadata().HasSyncedSize());
- }
- // Recover from the new MANIFEST, only the non-closed WAL should show up.
- {
- std::unique_ptr<VersionSet> new_versions(new VersionSet(
- dbname_, &db_options_, env_options_, table_cache_.get(),
- &write_buffer_manager_, &write_controller_,
- /*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
- /*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
- /*error_handler=*/nullptr, /*unchanging=*/false));
- ASSERT_OK(new_versions->Recover(column_families_, false));
- const auto& wals = new_versions->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 1);
- ASSERT_TRUE(wals.find(kNonClosedLogNumber) != wals.end());
- ASSERT_FALSE(wals.at(kNonClosedLogNumber).HasSyncedSize());
- }
- }
- TEST_F(VersionSetTest, WalCreateTwice) {
- NewDB();
- constexpr WalNumber kLogNumber = 10;
- VersionEdit edit;
- edit.AddWal(kLogNumber);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- Status s = LogAndApplyToDefaultCF(edit);
- ASSERT_TRUE(s.IsCorruption());
- ASSERT_TRUE(s.ToString().find("WAL 10 is created more than once") !=
- std::string::npos)
- << s.ToString();
- }
- TEST_F(VersionSetTest, WalCreateAfterClose) {
- NewDB();
- constexpr WalNumber kLogNumber = 10;
- constexpr uint64_t kSizeInBytes = 111;
- {
- // Add a closed WAL.
- VersionEdit edit;
- edit.AddWal(kLogNumber);
- WalMetadata wal(kSizeInBytes);
- edit.AddWal(kLogNumber, wal);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- }
- {
- // Create the same WAL again.
- VersionEdit edit;
- edit.AddWal(kLogNumber);
- Status s = LogAndApplyToDefaultCF(edit);
- ASSERT_TRUE(s.IsCorruption());
- ASSERT_TRUE(s.ToString().find("WAL 10 is created more than once") !=
- std::string::npos)
- << s.ToString();
- }
- }
- TEST_F(VersionSetTest, AddWalWithSmallerSize) {
- NewDB();
- assert(versions_);
- constexpr WalNumber kLogNumber = 10;
- constexpr uint64_t kSizeInBytes = 111;
- {
- // Add a closed WAL.
- VersionEdit edit;
- WalMetadata wal(kSizeInBytes);
- edit.AddWal(kLogNumber, wal);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- }
- // Copy for future comparison.
- const std::map<WalNumber, WalMetadata> wals1 =
- versions_->GetWalSet().GetWals();
- {
- // Add the same WAL with smaller synced size.
- VersionEdit edit;
- WalMetadata wal(kSizeInBytes / 2);
- edit.AddWal(kLogNumber, wal);
- Status s = LogAndApplyToDefaultCF(edit);
- ASSERT_OK(s);
- }
- const std::map<WalNumber, WalMetadata> wals2 =
- versions_->GetWalSet().GetWals();
- ASSERT_EQ(wals1, wals2);
- }
- TEST_F(VersionSetTest, DeleteWalsBeforeNonExistingWalNumber) {
- NewDB();
- constexpr WalNumber kLogNumber0 = 10;
- constexpr WalNumber kLogNumber1 = 20;
- constexpr WalNumber kNonExistingNumber = 15;
- constexpr uint64_t kSizeInBytes = 111;
- {
- // Add closed WALs.
- VersionEdit edit;
- WalMetadata wal(kSizeInBytes);
- edit.AddWal(kLogNumber0, wal);
- edit.AddWal(kLogNumber1, wal);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- }
- {
- // Delete WALs before a non-existing WAL.
- VersionEdit edit;
- edit.DeleteWalsBefore(kNonExistingNumber);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- }
- // Recover a new VersionSet, WAL0 is deleted, WAL1 is not.
- {
- std::unique_ptr<VersionSet> new_versions(new VersionSet(
- dbname_, &db_options_, env_options_, table_cache_.get(),
- &write_buffer_manager_, &write_controller_,
- /*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
- /*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
- /*error_handler=*/nullptr, /*unchanging=*/false));
- ASSERT_OK(new_versions->Recover(column_families_, false));
- const auto& wals = new_versions->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 1);
- ASSERT_TRUE(wals.find(kLogNumber1) != wals.end());
- }
- }
- TEST_F(VersionSetTest, DeleteAllWals) {
- NewDB();
- constexpr WalNumber kMaxLogNumber = 10;
- constexpr uint64_t kSizeInBytes = 111;
- {
- // Add a closed WAL.
- VersionEdit edit;
- WalMetadata wal(kSizeInBytes);
- edit.AddWal(kMaxLogNumber, wal);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- }
- {
- VersionEdit edit;
- edit.DeleteWalsBefore(kMaxLogNumber + 10);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- }
- // Recover a new VersionSet, all WALs are deleted.
- {
- std::unique_ptr<VersionSet> new_versions(new VersionSet(
- dbname_, &db_options_, env_options_, table_cache_.get(),
- &write_buffer_manager_, &write_controller_,
- /*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
- /*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
- /*error_handler=*/nullptr, /*unchanging=*/false));
- ASSERT_OK(new_versions->Recover(column_families_, false));
- const auto& wals = new_versions->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 0);
- }
- }
- TEST_F(VersionSetTest, AtomicGroupWithWalEdits) {
- NewDB();
- constexpr int kAtomicGroupSize = 7;
- constexpr uint64_t kNumWals = 5;
- const std::string kDBId = "db_db";
- int remaining = kAtomicGroupSize;
- autovector<std::unique_ptr<VersionEdit>> edits;
- // Add 5 WALs.
- for (uint64_t i = 1; i <= kNumWals; i++) {
- edits.emplace_back(new VersionEdit);
- // WAL's size equals its log number.
- edits.back()->AddWal(i, WalMetadata(i));
- edits.back()->MarkAtomicGroup(--remaining);
- }
- // One edit with the min log number set.
- edits.emplace_back(new VersionEdit);
- edits.back()->SetDBId(kDBId);
- edits.back()->MarkAtomicGroup(--remaining);
- // Delete the first added 4 WALs.
- edits.emplace_back(new VersionEdit);
- edits.back()->DeleteWalsBefore(kNumWals);
- edits.back()->MarkAtomicGroup(--remaining);
- ASSERT_EQ(remaining, 0);
- ASSERT_OK(LogAndApplyToDefaultCF(edits));
- // Recover a new VersionSet, the min log number and the last WAL should be
- // kept.
- {
- std::unique_ptr<VersionSet> new_versions(new VersionSet(
- dbname_, &db_options_, env_options_, table_cache_.get(),
- &write_buffer_manager_, &write_controller_,
- /*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
- /*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
- /*error_handler=*/nullptr, /*unchanging=*/false));
- std::string db_id;
- ASSERT_OK(
- new_versions->Recover(column_families_, /*read_only=*/false, &db_id));
- ASSERT_EQ(db_id, kDBId);
- const auto& wals = new_versions->GetWalSet().GetWals();
- ASSERT_EQ(wals.size(), 1);
- ASSERT_TRUE(wals.find(kNumWals) != wals.end());
- ASSERT_TRUE(wals.at(kNumWals).HasSyncedSize());
- ASSERT_EQ(wals.at(kNumWals).GetSyncedSizeInBytes(), kNumWals);
- }
- }
- TEST_F(VersionSetTest, OffpeakTimeInfoTest) {
- Random rnd(test::RandomSeed());
- // Sets off-peak time from 11:30PM to 4:30AM next day.
- // Starting at 1:30PM, use mock sleep to make time pass
- // and see if IsNowOffpeak() returns correctly per time changes
- int now_hour = 13;
- int now_minute = 30;
- versions_->ChangeOffpeakTimeOption("23:30-04:30");
- auto mock_clock = std::make_shared<MockSystemClock>(env_->GetSystemClock());
- // Add some extra random days to current time
- int days = rnd.Uniform(100);
- mock_clock->SetCurrentTime(days * 86400 + now_hour * 3600 + now_minute * 60);
- int64_t now;
- ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
- // Starting at 1:30PM. It's not off-peak
- ASSERT_FALSE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- // Now it's at 4:30PM. Still not off-peak
- mock_clock->MockSleepForSeconds(3 * 3600);
- ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
- ASSERT_FALSE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- // Now it's at 11:30PM. It's off-peak
- mock_clock->MockSleepForSeconds(7 * 3600);
- ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
- ASSERT_TRUE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- // Now it's at 2:30AM next day. It's still off-peak
- mock_clock->MockSleepForSeconds(3 * 3600);
- ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
- ASSERT_TRUE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- // Now it's at 4:30AM. It's still off-peak
- mock_clock->MockSleepForSeconds(2 * 3600);
- ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
- ASSERT_TRUE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- // Sleep for one more minute. It's at 4:31AM It's no longer off-peak
- mock_clock->MockSleepForSeconds(60);
- ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
- ASSERT_FALSE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- // Entire day offpeak
- versions_->ChangeOffpeakTimeOption("00:00-23:59");
- // It doesn't matter what time it is. It should be just offpeak.
- ASSERT_TRUE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- // Mock Sleep for 3 hours. It's still off-peak
- mock_clock->MockSleepForSeconds(3 * 3600);
- ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
- ASSERT_TRUE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- // Mock Sleep for 20 hours. It's still off-peak
- mock_clock->MockSleepForSeconds(20 * 3600);
- ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
- ASSERT_TRUE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- // Mock Sleep for 59 minutes. It's still off-peak
- mock_clock->MockSleepForSeconds(59 * 60);
- ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
- ASSERT_TRUE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- // Mock Sleep for 59 seconds. It's still off-peak
- mock_clock->MockSleepForSeconds(59);
- ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
- ASSERT_TRUE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- // Mock Sleep for 1 second (exactly 24h passed). It's still off-peak
- mock_clock->MockSleepForSeconds(1);
- ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
- ASSERT_TRUE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- // Another second for sanity check
- mock_clock->MockSleepForSeconds(1);
- ASSERT_OK(mock_clock.get()->GetCurrentTime(&now));
- ASSERT_TRUE(
- versions_->offpeak_time_option().GetOffpeakTimeInfo(now).is_now_offpeak);
- }
- TEST_F(VersionSetTest, ManifestTruncateAfterClose) {
- std::string manifest_path;
- VersionEdit edit;
- NewDB();
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- SyncPoint::GetInstance()->SetCallBack(
- "VersionSet::Close:AfterClose", [&](void*) {
- GetManifestPath(&manifest_path);
- std::unique_ptr<WritableFile> manifest_file;
- EXPECT_OK(env_->ReopenWritableFile(manifest_path, &manifest_file,
- EnvOptions()));
- EXPECT_OK(manifest_file->Truncate(0));
- EXPECT_OK(manifest_file->Close());
- });
- SyncPoint::GetInstance()->EnableProcessing();
- CloseDB();
- SyncPoint::GetInstance()->DisableProcessing();
- ReopenDB();
- }
- TEST_F(VersionStorageInfoTest, AddRangeDeletionCompensatedFileSize) {
- // Tests that compensated range deletion size is added to compensated file
- // size.
- Add(4, 100U, "1", "2", 100U, kInvalidBlobFileNumber, 1000U);
- UpdateVersionStorageInfo();
- auto meta = vstorage_.GetFileMetaDataByNumber(100U);
- ASSERT_EQ(meta->compensated_file_size, 100U + 1000U);
- }
- class VersionSetWithTimestampTest : public VersionSetTest {
- public:
- static const std::string kNewCfName;
- explicit VersionSetWithTimestampTest() : VersionSetTest() {}
- void SetUp() override {
- NewDB();
- Options options;
- options.comparator = test::BytewiseComparatorWithU64TsWrapper();
- cfd_ = CreateColumnFamily(kNewCfName, options);
- EXPECT_NE(nullptr, cfd_);
- column_families_.emplace_back(kNewCfName, options);
- }
- void TearDown() override {
- for (auto* e : edits_) {
- delete e;
- }
- edits_.clear();
- }
- void GenVersionEditsToSetFullHistoryTsLow(
- const std::vector<uint64_t>& ts_lbs) {
- for (const auto ts_lb : ts_lbs) {
- VersionEdit* edit = new VersionEdit;
- edit->SetColumnFamily(cfd_->GetID());
- std::string ts_str = test::EncodeInt(ts_lb);
- edit->SetFullHistoryTsLow(ts_str);
- edits_.emplace_back(edit);
- }
- }
- void VerifyFullHistoryTsLow(uint64_t expected_ts_low) {
- std::unique_ptr<VersionSet> vset(new VersionSet(
- dbname_, &db_options_, env_options_, table_cache_.get(),
- &write_buffer_manager_, &write_controller_,
- /*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
- /*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
- /*error_handler=*/nullptr, /*unchanging=*/false));
- ASSERT_OK(vset->Recover(column_families_, /*read_only=*/false,
- /*db_id=*/nullptr));
- for (auto* cfd : *(vset->GetColumnFamilySet())) {
- ASSERT_NE(nullptr, cfd);
- if (cfd->GetName() == kNewCfName) {
- ASSERT_EQ(test::EncodeInt(expected_ts_low), cfd->GetFullHistoryTsLow());
- } else {
- ASSERT_TRUE(cfd->GetFullHistoryTsLow().empty());
- }
- }
- }
- void DoTest(const std::vector<uint64_t>& ts_lbs) {
- if (ts_lbs.empty()) {
- return;
- }
- GenVersionEditsToSetFullHistoryTsLow(ts_lbs);
- Status s;
- mutex_.Lock();
- s = versions_->LogAndApply(cfd_, read_options_, write_options_, edits_,
- &mutex_, nullptr);
- mutex_.Unlock();
- ASSERT_OK(s);
- VerifyFullHistoryTsLow(*std::max_element(ts_lbs.begin(), ts_lbs.end()));
- }
- protected:
- ColumnFamilyData* cfd_{nullptr};
- // edits_ must contain and own pointers to heap-alloc VersionEdit objects.
- autovector<VersionEdit*> edits_;
- private:
- const ReadOptions read_options_;
- };
- const std::string VersionSetWithTimestampTest::kNewCfName("new_cf");
- TEST_F(VersionSetWithTimestampTest, SetFullHistoryTsLbOnce) {
- constexpr uint64_t kTsLow = 100;
- DoTest({kTsLow});
- }
- // Simulate the application increasing full_history_ts_low.
- TEST_F(VersionSetWithTimestampTest, IncreaseFullHistoryTsLb) {
- const std::vector<uint64_t> ts_lbs = {100, 101, 102, 103};
- DoTest(ts_lbs);
- }
- // Simulate the application trying to decrease full_history_ts_low
- // unsuccessfully. If the application calls public API sequentially to
- // decrease the lower bound ts, RocksDB will return an InvalidArgument
- // status before involving VersionSet. Only when multiple threads trying
- // to decrease the lower bound concurrently will this case ever happen. Even
- // so, the lower bound cannot be decreased. The application will be notified
- // via return value of the API.
- TEST_F(VersionSetWithTimestampTest, TryDecreaseFullHistoryTsLb) {
- const std::vector<uint64_t> ts_lbs = {103, 102, 101, 100};
- DoTest(ts_lbs);
- }
- class VersionSetAtomicGroupTest : public VersionSetTestBase,
- public testing::Test {
- public:
- VersionSetAtomicGroupTest()
- : VersionSetTestBase("version_set_atomic_group_test") {}
- explicit VersionSetAtomicGroupTest(const std::string& name)
- : VersionSetTestBase(name) {}
- void SetUp() override {
- PrepareManifest(&column_families_, &last_seqno_, &log_writer_);
- SetupTestSyncPoints();
- }
- void SetupValidAtomicGroup(int atomic_group_size) {
- edits_.resize(atomic_group_size);
- int remaining = atomic_group_size;
- for (size_t i = 0; i != edits_.size(); ++i) {
- edits_[i].SetLogNumber(0);
- edits_[i].SetNextFile(2);
- edits_[i].MarkAtomicGroup(--remaining);
- edits_[i].SetLastSequence(last_seqno_++);
- }
- CreateCurrentFile();
- }
- void SetupIncompleteTrailingAtomicGroup(int atomic_group_size) {
- edits_.resize(atomic_group_size);
- int remaining = atomic_group_size;
- for (size_t i = 0; i != edits_.size(); ++i) {
- edits_[i].SetLogNumber(0);
- edits_[i].SetNextFile(2);
- edits_[i].MarkAtomicGroup(--remaining);
- edits_[i].SetLastSequence(last_seqno_++);
- }
- CreateCurrentFile();
- }
- void SetupCorruptedAtomicGroup(int atomic_group_size) {
- edits_.resize(atomic_group_size);
- int remaining = atomic_group_size;
- for (size_t i = 0; i != edits_.size(); ++i) {
- edits_[i].SetLogNumber(0);
- edits_[i].SetNextFile(2);
- if (i != ((size_t)atomic_group_size / 2)) {
- edits_[i].MarkAtomicGroup(--remaining);
- }
- edits_[i].SetLastSequence(last_seqno_++);
- }
- CreateCurrentFile();
- }
- void SetupIncorrectAtomicGroup(int atomic_group_size) {
- edits_.resize(atomic_group_size);
- int remaining = atomic_group_size;
- for (size_t i = 0; i != edits_.size(); ++i) {
- edits_[i].SetLogNumber(0);
- edits_[i].SetNextFile(2);
- if (i != 1) {
- edits_[i].MarkAtomicGroup(--remaining);
- } else {
- edits_[i].MarkAtomicGroup(remaining--);
- }
- edits_[i].SetLastSequence(last_seqno_++);
- }
- CreateCurrentFile();
- }
- void SetupTestSyncPoints() {
- SyncPoint::GetInstance()->DisableProcessing();
- SyncPoint::GetInstance()->ClearAllCallBacks();
- SyncPoint::GetInstance()->SetCallBack(
- "AtomicGroupReadBuffer::AddEdit:FirstInAtomicGroup", [&](void* arg) {
- VersionEdit* e = static_cast<VersionEdit*>(arg);
- EXPECT_EQ(edits_.front().DebugString(),
- e->DebugString()); // compare based on value
- first_in_atomic_group_ = true;
- });
- SyncPoint::GetInstance()->SetCallBack(
- "AtomicGroupReadBuffer::AddEdit:LastInAtomicGroup", [&](void* arg) {
- VersionEdit* e = static_cast<VersionEdit*>(arg);
- EXPECT_EQ(edits_.back().DebugString(),
- e->DebugString()); // compare based on value
- EXPECT_TRUE(first_in_atomic_group_);
- last_in_atomic_group_ = true;
- });
- SyncPoint::GetInstance()->SetCallBack(
- "VersionEditHandlerBase::Iterate:Finish",
- [&](void* arg) { num_recovered_edits_ = *static_cast<size_t*>(arg); });
- SyncPoint::GetInstance()->SetCallBack(
- "AtomicGroupReadBuffer::AddEdit:AtomicGroup",
- [&](void* /* arg */) { ++num_edits_in_atomic_group_; });
- SyncPoint::GetInstance()->SetCallBack(
- "AtomicGroupReadBuffer::AddEdit:AtomicGroupMixedWithNormalEdits",
- [&](void* arg) { corrupted_edit_ = *static_cast<VersionEdit*>(arg); });
- SyncPoint::GetInstance()->SetCallBack(
- "AtomicGroupReadBuffer::AddEdit:IncorrectAtomicGroupSize",
- [&](void* arg) {
- edit_with_incorrect_group_size_ = *static_cast<VersionEdit*>(arg);
- });
- SyncPoint::GetInstance()->EnableProcessing();
- }
- void AddNewEditsToLog(int num_edits) {
- for (int i = 0; i < num_edits; i++) {
- std::string record;
- edits_[i].EncodeTo(&record, 0 /* ts_sz */);
- ASSERT_OK(log_writer_->AddRecord(WriteOptions(), record));
- }
- }
- void TearDown() override {
- SyncPoint::GetInstance()->DisableProcessing();
- SyncPoint::GetInstance()->ClearAllCallBacks();
- log_writer_.reset();
- }
- protected:
- std::vector<ColumnFamilyDescriptor> column_families_;
- SequenceNumber last_seqno_;
- std::vector<VersionEdit> edits_;
- bool first_in_atomic_group_ = false;
- bool last_in_atomic_group_ = false;
- int num_edits_in_atomic_group_ = 0;
- size_t num_recovered_edits_ = 0;
- VersionEdit corrupted_edit_;
- VersionEdit edit_with_incorrect_group_size_;
- std::unique_ptr<log::Writer> log_writer_;
- };
- TEST_F(VersionSetAtomicGroupTest, HandleValidAtomicGroupWithVersionSetRecover) {
- const int kAtomicGroupSize = 3;
- SetupValidAtomicGroup(kAtomicGroupSize);
- AddNewEditsToLog(kAtomicGroupSize);
- EXPECT_OK(versions_->Recover(column_families_, false));
- EXPECT_EQ(column_families_.size(),
- versions_->GetColumnFamilySet()->NumberOfColumnFamilies());
- EXPECT_TRUE(first_in_atomic_group_);
- EXPECT_TRUE(last_in_atomic_group_);
- EXPECT_EQ(num_initial_edits_ + kAtomicGroupSize, num_recovered_edits_);
- }
- TEST_F(VersionSetAtomicGroupTest,
- HandleValidAtomicGroupWithReactiveVersionSetRecover) {
- const int kAtomicGroupSize = 3;
- SetupValidAtomicGroup(kAtomicGroupSize);
- AddNewEditsToLog(kAtomicGroupSize);
- std::unique_ptr<log::FragmentBufferedReader> manifest_reader;
- std::unique_ptr<log::Reader::Reporter> manifest_reporter;
- std::unique_ptr<Status> manifest_reader_status;
- EXPECT_OK(reactive_versions_->Recover(column_families_, &manifest_reader,
- &manifest_reporter,
- &manifest_reader_status));
- EXPECT_EQ(column_families_.size(),
- reactive_versions_->GetColumnFamilySet()->NumberOfColumnFamilies());
- EXPECT_TRUE(first_in_atomic_group_);
- EXPECT_TRUE(last_in_atomic_group_);
- // The recover should clean up the replay buffer.
- EXPECT_TRUE(reactive_versions_->TEST_read_edits_in_atomic_group() == 0);
- EXPECT_TRUE(reactive_versions_->replay_buffer().size() == 0);
- EXPECT_EQ(num_initial_edits_ + kAtomicGroupSize, num_recovered_edits_);
- }
- TEST_F(VersionSetAtomicGroupTest,
- HandleValidAtomicGroupWithReactiveVersionSetReadAndApply) {
- const int kAtomicGroupSize = 3;
- SetupValidAtomicGroup(kAtomicGroupSize);
- std::unique_ptr<log::FragmentBufferedReader> manifest_reader;
- std::unique_ptr<log::Reader::Reporter> manifest_reporter;
- std::unique_ptr<Status> manifest_reader_status;
- EXPECT_OK(reactive_versions_->Recover(column_families_, &manifest_reader,
- &manifest_reporter,
- &manifest_reader_status));
- EXPECT_EQ(num_initial_edits_, num_recovered_edits_);
- AddNewEditsToLog(kAtomicGroupSize);
- InstrumentedMutex mu;
- std::unordered_set<ColumnFamilyData*> cfds_changed;
- mu.Lock();
- EXPECT_OK(reactive_versions_->ReadAndApply(
- &mu, &manifest_reader, manifest_reader_status.get(), &cfds_changed,
- /*files_to_delete=*/nullptr));
- mu.Unlock();
- EXPECT_TRUE(first_in_atomic_group_);
- EXPECT_TRUE(last_in_atomic_group_);
- // The recover should clean up the replay buffer.
- EXPECT_TRUE(reactive_versions_->TEST_read_edits_in_atomic_group() == 0);
- EXPECT_TRUE(reactive_versions_->replay_buffer().size() == 0);
- EXPECT_EQ(kAtomicGroupSize, num_recovered_edits_);
- }
- TEST_F(VersionSetAtomicGroupTest,
- HandleIncompleteTrailingAtomicGroupWithVersionSetRecover) {
- const int kAtomicGroupSize = 4;
- const int kNumberOfPersistedVersionEdits = kAtomicGroupSize - 1;
- SetupIncompleteTrailingAtomicGroup(kAtomicGroupSize);
- AddNewEditsToLog(kNumberOfPersistedVersionEdits);
- EXPECT_OK(versions_->Recover(column_families_, false));
- EXPECT_EQ(column_families_.size(),
- versions_->GetColumnFamilySet()->NumberOfColumnFamilies());
- EXPECT_TRUE(first_in_atomic_group_);
- EXPECT_FALSE(last_in_atomic_group_);
- EXPECT_EQ(kNumberOfPersistedVersionEdits, num_edits_in_atomic_group_);
- EXPECT_EQ(num_initial_edits_, num_recovered_edits_);
- }
- TEST_F(VersionSetAtomicGroupTest,
- HandleIncompleteTrailingAtomicGroupWithReactiveVersionSetRecover) {
- const int kAtomicGroupSize = 4;
- const int kNumberOfPersistedVersionEdits = kAtomicGroupSize - 1;
- SetupIncompleteTrailingAtomicGroup(kAtomicGroupSize);
- AddNewEditsToLog(kNumberOfPersistedVersionEdits);
- std::unique_ptr<log::FragmentBufferedReader> manifest_reader;
- std::unique_ptr<log::Reader::Reporter> manifest_reporter;
- std::unique_ptr<Status> manifest_reader_status;
- EXPECT_OK(reactive_versions_->Recover(column_families_, &manifest_reader,
- &manifest_reporter,
- &manifest_reader_status));
- EXPECT_EQ(column_families_.size(),
- reactive_versions_->GetColumnFamilySet()->NumberOfColumnFamilies());
- EXPECT_TRUE(first_in_atomic_group_);
- EXPECT_FALSE(last_in_atomic_group_);
- EXPECT_EQ(kNumberOfPersistedVersionEdits, num_edits_in_atomic_group_);
- // Reactive version set should store the edits in the replay buffer.
- EXPECT_TRUE(reactive_versions_->TEST_read_edits_in_atomic_group() ==
- kNumberOfPersistedVersionEdits);
- EXPECT_TRUE(reactive_versions_->replay_buffer().size() == kAtomicGroupSize);
- // Write the last record. The reactive version set should now apply all
- // edits.
- std::string last_record;
- edits_[kAtomicGroupSize - 1].EncodeTo(&last_record);
- EXPECT_OK(log_writer_->AddRecord(WriteOptions(), last_record));
- InstrumentedMutex mu;
- std::unordered_set<ColumnFamilyData*> cfds_changed;
- mu.Lock();
- EXPECT_OK(reactive_versions_->ReadAndApply(
- &mu, &manifest_reader, manifest_reader_status.get(), &cfds_changed,
- /*files_to_delete=*/nullptr));
- mu.Unlock();
- // Reactive version set should be empty now.
- EXPECT_TRUE(reactive_versions_->TEST_read_edits_in_atomic_group() == 0);
- EXPECT_TRUE(reactive_versions_->replay_buffer().size() == 0);
- EXPECT_EQ(num_initial_edits_, num_recovered_edits_);
- }
- TEST_F(VersionSetAtomicGroupTest,
- HandleIncompleteTrailingAtomicGroupWithReactiveVersionSetReadAndApply) {
- const int kAtomicGroupSize = 4;
- const int kNumberOfPersistedVersionEdits = kAtomicGroupSize - 1;
- SetupIncompleteTrailingAtomicGroup(kAtomicGroupSize);
- std::unique_ptr<log::FragmentBufferedReader> manifest_reader;
- std::unique_ptr<log::Reader::Reporter> manifest_reporter;
- std::unique_ptr<Status> manifest_reader_status;
- // No edits in an atomic group.
- EXPECT_OK(reactive_versions_->Recover(column_families_, &manifest_reader,
- &manifest_reporter,
- &manifest_reader_status));
- EXPECT_EQ(column_families_.size(),
- reactive_versions_->GetColumnFamilySet()->NumberOfColumnFamilies());
- EXPECT_EQ(num_initial_edits_, num_recovered_edits_);
- // Write a few edits in an atomic group.
- AddNewEditsToLog(kNumberOfPersistedVersionEdits);
- InstrumentedMutex mu;
- std::unordered_set<ColumnFamilyData*> cfds_changed;
- mu.Lock();
- EXPECT_OK(reactive_versions_->ReadAndApply(
- &mu, &manifest_reader, manifest_reader_status.get(), &cfds_changed,
- /*files_to_delete=*/nullptr));
- mu.Unlock();
- EXPECT_TRUE(first_in_atomic_group_);
- EXPECT_FALSE(last_in_atomic_group_);
- EXPECT_EQ(kNumberOfPersistedVersionEdits, num_edits_in_atomic_group_);
- // Reactive version set should store the edits in the replay buffer.
- EXPECT_TRUE(reactive_versions_->TEST_read_edits_in_atomic_group() ==
- kNumberOfPersistedVersionEdits);
- EXPECT_TRUE(reactive_versions_->replay_buffer().size() == kAtomicGroupSize);
- }
- TEST_F(VersionSetAtomicGroupTest,
- HandleCorruptedAtomicGroupWithVersionSetRecover) {
- const int kAtomicGroupSize = 4;
- SetupCorruptedAtomicGroup(kAtomicGroupSize);
- AddNewEditsToLog(kAtomicGroupSize);
- EXPECT_NOK(versions_->Recover(column_families_, false));
- EXPECT_EQ(column_families_.size(),
- versions_->GetColumnFamilySet()->NumberOfColumnFamilies());
- EXPECT_EQ(edits_[kAtomicGroupSize / 2].DebugString(),
- corrupted_edit_.DebugString());
- }
- TEST_F(VersionSetAtomicGroupTest,
- HandleCorruptedAtomicGroupWithReactiveVersionSetRecover) {
- const int kAtomicGroupSize = 4;
- SetupCorruptedAtomicGroup(kAtomicGroupSize);
- AddNewEditsToLog(kAtomicGroupSize);
- std::unique_ptr<log::FragmentBufferedReader> manifest_reader;
- std::unique_ptr<log::Reader::Reporter> manifest_reporter;
- std::unique_ptr<Status> manifest_reader_status;
- EXPECT_NOK(reactive_versions_->Recover(column_families_, &manifest_reader,
- &manifest_reporter,
- &manifest_reader_status));
- EXPECT_EQ(column_families_.size(),
- reactive_versions_->GetColumnFamilySet()->NumberOfColumnFamilies());
- EXPECT_EQ(edits_[kAtomicGroupSize / 2].DebugString(),
- corrupted_edit_.DebugString());
- }
- TEST_F(VersionSetAtomicGroupTest,
- HandleCorruptedAtomicGroupWithReactiveVersionSetReadAndApply) {
- const int kAtomicGroupSize = 4;
- SetupCorruptedAtomicGroup(kAtomicGroupSize);
- InstrumentedMutex mu;
- std::unordered_set<ColumnFamilyData*> cfds_changed;
- std::unique_ptr<log::FragmentBufferedReader> manifest_reader;
- std::unique_ptr<log::Reader::Reporter> manifest_reporter;
- std::unique_ptr<Status> manifest_reader_status;
- EXPECT_OK(reactive_versions_->Recover(column_families_, &manifest_reader,
- &manifest_reporter,
- &manifest_reader_status));
- // Write the corrupted edits.
- AddNewEditsToLog(kAtomicGroupSize);
- mu.Lock();
- EXPECT_NOK(reactive_versions_->ReadAndApply(
- &mu, &manifest_reader, manifest_reader_status.get(), &cfds_changed,
- /*files_to_delete=*/nullptr));
- mu.Unlock();
- EXPECT_EQ(edits_[kAtomicGroupSize / 2].DebugString(),
- corrupted_edit_.DebugString());
- }
- TEST_F(VersionSetAtomicGroupTest,
- HandleIncorrectAtomicGroupSizeWithVersionSetRecover) {
- const int kAtomicGroupSize = 4;
- SetupIncorrectAtomicGroup(kAtomicGroupSize);
- AddNewEditsToLog(kAtomicGroupSize);
- EXPECT_NOK(versions_->Recover(column_families_, false));
- EXPECT_EQ(column_families_.size(),
- versions_->GetColumnFamilySet()->NumberOfColumnFamilies());
- EXPECT_EQ(edits_[1].DebugString(),
- edit_with_incorrect_group_size_.DebugString());
- }
- TEST_F(VersionSetAtomicGroupTest,
- HandleIncorrectAtomicGroupSizeWithReactiveVersionSetRecover) {
- const int kAtomicGroupSize = 4;
- SetupIncorrectAtomicGroup(kAtomicGroupSize);
- AddNewEditsToLog(kAtomicGroupSize);
- std::unique_ptr<log::FragmentBufferedReader> manifest_reader;
- std::unique_ptr<log::Reader::Reporter> manifest_reporter;
- std::unique_ptr<Status> manifest_reader_status;
- EXPECT_NOK(reactive_versions_->Recover(column_families_, &manifest_reader,
- &manifest_reporter,
- &manifest_reader_status));
- EXPECT_EQ(column_families_.size(),
- reactive_versions_->GetColumnFamilySet()->NumberOfColumnFamilies());
- EXPECT_EQ(edits_[1].DebugString(),
- edit_with_incorrect_group_size_.DebugString());
- }
- TEST_F(VersionSetAtomicGroupTest,
- HandleIncorrectAtomicGroupSizeWithReactiveVersionSetReadAndApply) {
- const int kAtomicGroupSize = 4;
- SetupIncorrectAtomicGroup(kAtomicGroupSize);
- InstrumentedMutex mu;
- std::unordered_set<ColumnFamilyData*> cfds_changed;
- std::unique_ptr<log::FragmentBufferedReader> manifest_reader;
- std::unique_ptr<log::Reader::Reporter> manifest_reporter;
- std::unique_ptr<Status> manifest_reader_status;
- EXPECT_OK(reactive_versions_->Recover(column_families_, &manifest_reader,
- &manifest_reporter,
- &manifest_reader_status));
- AddNewEditsToLog(kAtomicGroupSize);
- mu.Lock();
- EXPECT_NOK(reactive_versions_->ReadAndApply(
- &mu, &manifest_reader, manifest_reader_status.get(), &cfds_changed,
- /*files_to_delete=*/nullptr));
- mu.Unlock();
- EXPECT_EQ(edits_[1].DebugString(),
- edit_with_incorrect_group_size_.DebugString());
- }
- class AtomicGroupBestEffortRecoveryTest : public VersionSetAtomicGroupTest {
- public:
- AtomicGroupBestEffortRecoveryTest()
- : VersionSetAtomicGroupTest("atomic_group_best_effort_recovery_test") {}
- };
- TEST_F(AtomicGroupBestEffortRecoveryTest,
- HandleAtomicGroupUpdatesValidInitially) {
- // One AtomicGroup contains updates that are valid at the outset.
- std::vector<SstInfo> file_infos;
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- int file_number = 10 + cfid;
- file_infos.emplace_back(file_number, column_families_[cfid].name,
- "" /* key */, 0 /* level */,
- file_number /* epoch_number */);
- }
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(file_infos, &file_metas);
- edits_.clear();
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- edits_.emplace_back();
- edits_.back().SetColumnFamily(cfid);
- edits_.back().AddFile(0 /* level */, file_metas[cfid]);
- edits_.back().SetLastSequence(++last_seqno_);
- edits_.back().MarkAtomicGroup(kNumColumnFamilies - 1 -
- cfid /* remaining_entries */);
- }
- AddNewEditsToLog(kNumColumnFamilies);
- {
- bool has_missing_table_file;
- ASSERT_OK(versions_->TryRecover(column_families_, false /* read_only */,
- {DescriptorFileName(1 /* number */)},
- nullptr /* db_id */,
- &has_missing_table_file));
- ASSERT_FALSE(has_missing_table_file);
- }
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_EQ(file_metas.size(), all_table_files.size());
- }
- TEST_F(AtomicGroupBestEffortRecoveryTest, HandleAtomicGroupUpdatesValidLater) {
- // One AtomicGroup contains updates that become valid after applying further
- // updates.
- // `SetupTestSyncPoints()` creates sync points that assume there is only one
- // AtomicGroup, which is not the case in this test.
- SyncPoint::GetInstance()->DisableProcessing();
- SyncPoint::GetInstance()->ClearAllCallBacks();
- std::vector<SstInfo> file_infos;
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- int file_number = 10 + cfid;
- file_infos.emplace_back(file_number, column_families_[cfid].name,
- "" /* key */, 0 /* level */,
- file_number /* epoch_number */);
- }
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(file_infos, &file_metas);
- edits_.clear();
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- if (cfid == kNumColumnFamilies - 1) {
- // Corrupt the number of the last file.
- file_metas[cfid].fd.packed_number_and_path_id =
- PackFileNumberAndPathId(20 /* number */, 0 /* path_id */);
- }
- edits_.emplace_back();
- edits_.back().SetColumnFamily(cfid);
- edits_.back().AddFile(0 /* level */, file_metas[cfid]);
- edits_.back().SetLastSequence(++last_seqno_);
- edits_.back().MarkAtomicGroup(kNumColumnFamilies - 1 -
- cfid /* remaining_entries */);
- }
- AddNewEditsToLog(kNumColumnFamilies);
- {
- // Delete the file with the corrupted number.
- VersionEdit fixup_edit;
- fixup_edit.SetColumnFamily(kNumColumnFamilies - 1);
- fixup_edit.DeleteFile(0 /* level */, 20 /* number */);
- assert(log_writer_.get() != nullptr);
- std::string record;
- ASSERT_TRUE(fixup_edit.EncodeTo(&record, 0 /* ts_sz */));
- ASSERT_OK(log_writer_->AddRecord(WriteOptions(), record));
- // Throw in an impossible AtomicGroup afterwards for extra challenge.
- VersionEdit broken_edit;
- broken_edit.SetColumnFamily(0 /* column_family_id */);
- file_metas[0].fd.packed_number_and_path_id =
- PackFileNumberAndPathId(30 /* number */, 0 /* path_id */);
- broken_edit.AddFile(0 /* level */, file_metas[0]);
- broken_edit.SetLastSequence(++last_seqno_);
- broken_edit.MarkAtomicGroup(0 /* remaining_entries */);
- record.clear();
- ASSERT_TRUE(broken_edit.EncodeTo(&record, 0 /* ts_sz */));
- ASSERT_OK(log_writer_->AddRecord(WriteOptions(), record));
- assert(log_writer_.get() != nullptr);
- }
- {
- bool has_missing_table_file = false;
- ASSERT_OK(versions_->TryRecover(column_families_, false /* read_only */,
- {DescriptorFileName(1 /* number */)},
- nullptr /* db_id */,
- &has_missing_table_file));
- ASSERT_TRUE(has_missing_table_file);
- }
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_EQ(file_metas.size() - 1, all_table_files.size());
- }
- TEST_F(AtomicGroupBestEffortRecoveryTest, HandleAtomicGroupUpdatesInvalid) {
- // One AtomicGroup contains updates that never become valid.
- std::vector<SstInfo> file_infos;
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- int file_number = 10 + cfid;
- file_infos.emplace_back(file_number, column_families_[cfid].name,
- "" /* key */, 0 /* level */,
- file_number /* epoch_number */);
- }
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(file_infos, &file_metas);
- edits_.clear();
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- if (cfid == kNumColumnFamilies - 1) {
- // Corrupt the number of the last file.
- file_metas[cfid].fd.packed_number_and_path_id =
- PackFileNumberAndPathId(20 /* number */, 0 /* path_id */);
- }
- edits_.emplace_back();
- edits_.back().SetColumnFamily(cfid);
- edits_.back().AddFile(0 /* level */, file_metas[cfid]);
- edits_.back().SetLastSequence(++last_seqno_);
- edits_.back().MarkAtomicGroup(kNumColumnFamilies - 1 -
- cfid /* remaining_entries */);
- }
- AddNewEditsToLog(kNumColumnFamilies);
- {
- bool has_missing_table_file = false;
- ASSERT_OK(versions_->TryRecover(column_families_, false /* read_only */,
- {DescriptorFileName(1 /* number */)},
- nullptr /* db_id */,
- &has_missing_table_file));
- ASSERT_TRUE(has_missing_table_file);
- }
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_TRUE(all_table_files.empty());
- }
- TEST_F(AtomicGroupBestEffortRecoveryTest,
- HandleAtomicGroupUpdatesValidTooLate) {
- // One AtomicGroup contains updates that become valid after the next
- // AtomicGroup is reached, which is too late.
- // `SetupTestSyncPoints()` creates sync points that assume there is only one
- // AtomicGroup, which is not the case in this test.
- SyncPoint::GetInstance()->DisableProcessing();
- SyncPoint::GetInstance()->ClearAllCallBacks();
- std::vector<SstInfo> file_infos;
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- int file_number = 10 + cfid;
- file_infos.emplace_back(file_number, column_families_[cfid].name,
- "" /* key */, 0 /* level */,
- file_number /* epoch_number */);
- }
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(file_infos, &file_metas);
- edits_.clear();
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- if (cfid == kNumColumnFamilies - 1) {
- // Corrupt the number of the last file.
- file_metas[cfid].fd.packed_number_and_path_id =
- PackFileNumberAndPathId(20 /* number */, 0 /* path_id */);
- }
- edits_.emplace_back();
- edits_.back().SetColumnFamily(cfid);
- edits_.back().AddFile(0 /* level */, file_metas[cfid]);
- edits_.back().SetLastSequence(++last_seqno_);
- edits_.back().MarkAtomicGroup(kNumColumnFamilies - 1 -
- cfid /* remaining_entries */);
- }
- AddNewEditsToLog(kNumColumnFamilies);
- {
- // Delete the file with the corrupted number. But bundle it in an
- // AtomicGroup with an update that can never be applied.
- VersionEdit broken_edit;
- broken_edit.SetColumnFamily(0 /* column_family_id */);
- file_metas[0].fd.packed_number_and_path_id =
- PackFileNumberAndPathId(30 /* number */, 0 /* path_id */);
- broken_edit.AddFile(0 /* level */, file_metas[0]);
- broken_edit.SetLastSequence(++last_seqno_);
- broken_edit.MarkAtomicGroup(1 /* remaining_entries */);
- std::string record;
- ASSERT_TRUE(broken_edit.EncodeTo(&record, 0 /* ts_sz */));
- ASSERT_OK(log_writer_->AddRecord(WriteOptions(), record));
- VersionEdit fixup_edit;
- fixup_edit.SetColumnFamily(kNumColumnFamilies - 1);
- fixup_edit.DeleteFile(0 /* level */, 20 /* number */);
- fixup_edit.MarkAtomicGroup(0 /* remaining_entries */);
- record.clear();
- ASSERT_TRUE(fixup_edit.EncodeTo(&record, 0 /* ts_sz */));
- ASSERT_OK(log_writer_->AddRecord(WriteOptions(), record));
- assert(log_writer_.get() != nullptr);
- }
- {
- bool has_missing_table_file = false;
- ASSERT_OK(versions_->TryRecover(column_families_, false /* read_only */,
- {DescriptorFileName(1 /* number */)},
- nullptr /* db_id */,
- &has_missing_table_file));
- ASSERT_TRUE(has_missing_table_file);
- }
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_TRUE(all_table_files.empty());
- }
- TEST_F(AtomicGroupBestEffortRecoveryTest,
- HandleAtomicGroupUpdatesInDuplicateInvalid) {
- // One AtomicGroup has multiple updates for the same CF. One of the earlier
- // updates for this CF can lead to a valid state if applied. But the last
- // update for this CF is invalid so the AtomicGroup must not be recovered.
- std::vector<SstInfo> file_infos;
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- int file_number = 10 + cfid;
- file_infos.emplace_back(file_number, column_families_[cfid].name,
- "" /* key */, 0 /* level */,
- file_number /* epoch_number */);
- }
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(file_infos, &file_metas);
- edits_.clear();
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- edits_.emplace_back();
- edits_.back().SetColumnFamily(cfid);
- edits_.back().AddFile(0 /* level */, file_metas[cfid]);
- edits_.back().SetLastSequence(++last_seqno_);
- edits_.back().MarkAtomicGroup(kNumColumnFamilies -
- cfid /* remaining_entries */);
- }
- // Here is the unrecoverable update.
- edits_.emplace_back();
- edits_.back().SetColumnFamily(0 /* column_family_id */);
- file_metas[0].fd.packed_number_and_path_id =
- PackFileNumberAndPathId(20 /* number */, 0 /* path_id */);
- edits_.back().AddFile(0 /* level */, file_metas[0]);
- edits_.back().SetLastSequence(++last_seqno_);
- edits_.back().MarkAtomicGroup(0 /* remaining_entries */);
- AddNewEditsToLog(kNumColumnFamilies + 1);
- {
- bool has_missing_table_file = false;
- ASSERT_OK(versions_->TryRecover(column_families_, false /* read_only */,
- {DescriptorFileName(1 /* number */)},
- nullptr /* db_id */,
- &has_missing_table_file));
- ASSERT_TRUE(has_missing_table_file);
- }
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_TRUE(all_table_files.empty());
- }
- TEST_F(AtomicGroupBestEffortRecoveryTest,
- HandleAtomicGroupMadeWholeByDeletingCf) {
- // One AtomicGroup contains an update that becomes valid when its column
- // family is deleted, making it irrelevant.
- std::vector<SstInfo> file_infos;
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- int file_number = 10 + cfid;
- file_infos.emplace_back(file_number, column_families_[cfid].name,
- "" /* key */, 0 /* level */,
- file_number /* epoch_number */);
- }
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(file_infos, &file_metas);
- edits_.clear();
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- if (cfid == kNumColumnFamilies - 1) {
- // Corrupt the number of the last file.
- file_metas[cfid].fd.packed_number_and_path_id =
- PackFileNumberAndPathId(20 /* number */, 0 /* path_id */);
- }
- edits_.emplace_back();
- edits_.back().SetColumnFamily(cfid);
- edits_.back().AddFile(0 /* level */, file_metas[cfid]);
- edits_.back().SetLastSequence(++last_seqno_);
- edits_.back().MarkAtomicGroup(kNumColumnFamilies - 1 -
- cfid /* remaining_entries */);
- }
- AddNewEditsToLog(kNumColumnFamilies);
- {
- // Delete the column family with the corrupted file number.
- VersionEdit fixup_edit;
- fixup_edit.DropColumnFamily();
- fixup_edit.SetColumnFamily(kNumColumnFamilies - 1);
- assert(log_writer_.get() != nullptr);
- std::string record;
- ASSERT_TRUE(fixup_edit.EncodeTo(&record, 0 /* ts_sz */));
- ASSERT_OK(log_writer_->AddRecord(WriteOptions(), record));
- }
- {
- bool has_missing_table_file = false;
- ASSERT_OK(versions_->TryRecover(column_families_, false /* read_only */,
- {DescriptorFileName(1 /* number */)},
- nullptr /* db_id */,
- &has_missing_table_file));
- ASSERT_FALSE(has_missing_table_file);
- }
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_EQ(file_metas.size() - 1, all_table_files.size());
- }
- TEST_F(AtomicGroupBestEffortRecoveryTest,
- HandleAtomicGroupMadeWholeAfterNewCf) {
- // One AtomicGroup contains updates that become valid after a new column
- // family is added.
- std::vector<SstInfo> file_infos;
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- int file_number = 10 + cfid;
- file_infos.emplace_back(file_number, column_families_[cfid].name,
- "" /* key */, 0 /* level */,
- file_number /* epoch_number */);
- }
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(file_infos, &file_metas);
- edits_.clear();
- for (int cfid = 0; cfid < kNumColumnFamilies; cfid++) {
- if (cfid == kNumColumnFamilies - 1) {
- // Corrupt the number of the last file.
- file_metas[cfid].fd.packed_number_and_path_id =
- PackFileNumberAndPathId(20 /* number */, 0 /* path_id */);
- }
- edits_.emplace_back();
- edits_.back().SetColumnFamily(cfid);
- edits_.back().AddFile(0 /* level */, file_metas[cfid]);
- edits_.back().SetLastSequence(++last_seqno_);
- edits_.back().MarkAtomicGroup(kNumColumnFamilies - 1 -
- cfid /* remaining_entries */);
- }
- AddNewEditsToLog(kNumColumnFamilies);
- {
- // Add a new CF.
- VersionEdit add_cf_edit;
- add_cf_edit.AddColumnFamily("extra_cf");
- add_cf_edit.SetColumnFamily(kNumColumnFamilies);
- std::string record;
- ASSERT_TRUE(add_cf_edit.EncodeTo(&record, 0 /* ts_sz */));
- ASSERT_OK(log_writer_->AddRecord(WriteOptions(), record));
- // Have the new CF refer to a non-existent file for an extra challenge.
- VersionEdit broken_edit;
- broken_edit.SetColumnFamily(kNumColumnFamilies);
- file_metas[0].fd.packed_number_and_path_id =
- PackFileNumberAndPathId(30 /* number */, 0 /* path_id */);
- broken_edit.AddFile(0 /* level */, file_metas[0]);
- broken_edit.SetLastSequence(++last_seqno_);
- record.clear();
- ASSERT_TRUE(broken_edit.EncodeTo(&record, 0 /* ts_sz */));
- ASSERT_OK(log_writer_->AddRecord(WriteOptions(), record));
- // This fixes up the first of the two non-existent file references.
- VersionEdit fixup_edit;
- fixup_edit.SetColumnFamily(kNumColumnFamilies - 1);
- fixup_edit.DeleteFile(0 /* level */, 20 /* number */);
- record.clear();
- ASSERT_TRUE(fixup_edit.EncodeTo(&record, 0 /* ts_sz */));
- ASSERT_OK(log_writer_->AddRecord(WriteOptions(), record));
- assert(log_writer_.get() != nullptr);
- }
- {
- bool has_missing_table_file = false;
- std::vector<ColumnFamilyDescriptor> column_families = column_families_;
- column_families.emplace_back("extra_cf", cf_options_);
- ASSERT_OK(versions_->TryRecover(column_families, false /* read_only */,
- {DescriptorFileName(1 /* number */)},
- nullptr /* db_id */,
- &has_missing_table_file));
- ASSERT_TRUE(has_missing_table_file);
- }
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_EQ(file_metas.size() - 1, all_table_files.size());
- }
- class VersionSetTestDropOneCF : public VersionSetTestBase,
- public testing::TestWithParam<std::string> {
- public:
- VersionSetTestDropOneCF()
- : VersionSetTestBase("version_set_test_drop_one_cf") {}
- };
- // This test simulates the following execution sequence
- // Time thread1 bg_flush_thr
- // | Prepare version edits (e1,e2,e3) for atomic
- // | flush cf1, cf2, cf3
- // | Enqueue e to drop cfi
- // | to manifest_writers_
- // | Enqueue (e1,e2,e3) to manifest_writers_
- // |
- // | Apply e,
- // | cfi.IsDropped() is true
- // | Apply (e1,e2,e3),
- // | since cfi.IsDropped() == true, we need to
- // | drop ei and write the rest to MANIFEST.
- // V
- //
- // Repeat the test for i = 1, 2, 3 to simulate dropping the first, middle and
- // last column family in an atomic group.
- TEST_P(VersionSetTestDropOneCF, HandleDroppedColumnFamilyInAtomicGroup) {
- const ReadOptions read_options;
- const WriteOptions write_options;
- std::vector<ColumnFamilyDescriptor> column_families;
- SequenceNumber last_seqno;
- std::unique_ptr<log::Writer> log_writer;
- PrepareManifest(&column_families, &last_seqno, &log_writer);
- CreateCurrentFile();
- EXPECT_OK(versions_->Recover(column_families, false /* read_only */));
- EXPECT_EQ(column_families.size(),
- versions_->GetColumnFamilySet()->NumberOfColumnFamilies());
- const int kAtomicGroupSize = 3;
- const std::vector<std::string> non_default_cf_names = {
- kColumnFamilyName1, kColumnFamilyName2, kColumnFamilyName3};
- // Drop one column family
- VersionEdit drop_cf_edit;
- drop_cf_edit.DropColumnFamily();
- const std::string cf_to_drop_name(GetParam());
- auto cfd_to_drop =
- versions_->GetColumnFamilySet()->GetColumnFamily(cf_to_drop_name);
- ASSERT_NE(nullptr, cfd_to_drop);
- // Increase its refcount because cfd_to_drop is used later, and we need to
- // prevent it from being deleted.
- cfd_to_drop->Ref();
- drop_cf_edit.SetColumnFamily(cfd_to_drop->GetID());
- mutex_.Lock();
- Status s = versions_->LogAndApply(cfd_to_drop, read_options, write_options,
- &drop_cf_edit, &mutex_, nullptr);
- mutex_.Unlock();
- ASSERT_OK(s);
- std::vector<VersionEdit> edits(kAtomicGroupSize);
- uint32_t remaining = kAtomicGroupSize;
- size_t i = 0;
- autovector<ColumnFamilyData*> cfds;
- autovector<autovector<VersionEdit*>> edit_lists;
- for (const auto& cf_name : non_default_cf_names) {
- auto cfd = (cf_name != cf_to_drop_name)
- ? versions_->GetColumnFamilySet()->GetColumnFamily(cf_name)
- : cfd_to_drop;
- ASSERT_NE(nullptr, cfd);
- cfds.push_back(cfd);
- edits[i].SetColumnFamily(cfd->GetID());
- edits[i].SetLogNumber(0);
- edits[i].SetNextFile(2);
- edits[i].MarkAtomicGroup(--remaining);
- edits[i].SetLastSequence(last_seqno++);
- autovector<VersionEdit*> tmp_edits;
- tmp_edits.push_back(&edits[i]);
- edit_lists.emplace_back(tmp_edits);
- ++i;
- }
- int called = 0;
- SyncPoint::GetInstance()->DisableProcessing();
- SyncPoint::GetInstance()->ClearAllCallBacks();
- SyncPoint::GetInstance()->SetCallBack(
- "VersionSet::ProcessManifestWrites:CheckOneAtomicGroup", [&](void* arg) {
- std::vector<VersionEdit*>* tmp_edits =
- static_cast<std::vector<VersionEdit*>*>(arg);
- EXPECT_EQ(kAtomicGroupSize - 1, tmp_edits->size());
- for (const auto e : *tmp_edits) {
- bool found = false;
- for (const auto& e2 : edits) {
- if (&e2 == e) {
- found = true;
- break;
- }
- }
- ASSERT_TRUE(found);
- }
- ++called;
- });
- SyncPoint::GetInstance()->EnableProcessing();
- mutex_.Lock();
- s = versions_->LogAndApply(cfds, read_options, write_options, edit_lists,
- &mutex_, nullptr);
- mutex_.Unlock();
- ASSERT_OK(s);
- ASSERT_EQ(1, called);
- cfd_to_drop->UnrefAndTryDelete();
- }
- INSTANTIATE_TEST_CASE_P(
- AtomicGroup, VersionSetTestDropOneCF,
- testing::Values(VersionSetTestBase::kColumnFamilyName1,
- VersionSetTestBase::kColumnFamilyName2,
- VersionSetTestBase::kColumnFamilyName3));
- class EmptyDefaultCfNewManifest : public VersionSetTestBase,
- public testing::Test {
- public:
- EmptyDefaultCfNewManifest() : VersionSetTestBase("version_set_new_db_test") {}
- // Emulate DBImpl::NewDB()
- void PrepareManifest(std::vector<ColumnFamilyDescriptor>* /*column_families*/,
- SequenceNumber* /*last_seqno*/,
- std::unique_ptr<log::Writer>* log_writer) override {
- assert(log_writer != nullptr);
- VersionEdit new_db;
- new_db.SetLogNumber(0);
- const std::string manifest_path = DescriptorFileName(dbname_, 1);
- const auto& fs = env_->GetFileSystem();
- std::unique_ptr<WritableFileWriter> file_writer;
- Status s = WritableFileWriter::Create(
- fs, manifest_path, fs->OptimizeForManifestWrite(env_options_),
- &file_writer, nullptr);
- ASSERT_OK(s);
- log_writer->reset(new log::Writer(std::move(file_writer), 0, true));
- std::string record;
- ASSERT_TRUE(new_db.EncodeTo(&record));
- s = (*log_writer)->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- // Create new column family
- VersionEdit new_cf;
- new_cf.AddColumnFamily(VersionSetTestBase::kColumnFamilyName1);
- new_cf.SetColumnFamily(1);
- new_cf.SetLastSequence(2);
- new_cf.SetNextFile(2);
- record.clear();
- ASSERT_TRUE(new_cf.EncodeTo(&record));
- s = (*log_writer)->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- }
- protected:
- bool write_dbid_to_manifest_ = false;
- std::unique_ptr<log::Writer> log_writer_;
- };
- // Create db, create column family. Cf creation will switch to a new MANIFEST.
- // Then reopen db, trying to recover.
- TEST_F(EmptyDefaultCfNewManifest, Recover) {
- PrepareManifest(nullptr, nullptr, &log_writer_);
- log_writer_.reset();
- CreateCurrentFile();
- std::string manifest_path;
- VerifyManifest(&manifest_path);
- std::vector<ColumnFamilyDescriptor> column_families;
- column_families.emplace_back(kDefaultColumnFamilyName, cf_options_);
- column_families.emplace_back(VersionSetTestBase::kColumnFamilyName1,
- cf_options_);
- std::string db_id;
- bool has_missing_table_file = false;
- Status s = versions_->TryRecoverFromOneManifest(
- manifest_path, column_families, false, &db_id, &has_missing_table_file);
- ASSERT_OK(s);
- ASSERT_FALSE(has_missing_table_file);
- }
- class VersionSetTestEmptyDb
- : public VersionSetTestBase,
- public testing::TestWithParam<
- std::tuple<bool, bool, std::vector<std::string>>> {
- public:
- static const std::string kUnknownColumnFamilyName;
- VersionSetTestEmptyDb() : VersionSetTestBase("version_set_test_empty_db") {}
- protected:
- void PrepareManifest(std::vector<ColumnFamilyDescriptor>* /*column_families*/,
- SequenceNumber* /*last_seqno*/,
- std::unique_ptr<log::Writer>* log_writer) override {
- assert(nullptr != log_writer);
- VersionEdit new_db;
- if (db_options_.write_dbid_to_manifest) {
- ASSERT_OK(SetIdentityFile(WriteOptions(), env_, dbname_,
- Temperature::kUnknown));
- DBOptions tmp_db_options;
- tmp_db_options.env = env_;
- std::unique_ptr<DBImpl> impl(new DBImpl(tmp_db_options, dbname_));
- std::string db_id;
- ASSERT_OK(impl->GetDbIdentityFromIdentityFile(IOOptions(), &db_id));
- new_db.SetDBId(db_id);
- }
- const std::string manifest_path = DescriptorFileName(dbname_, 1);
- const auto& fs = env_->GetFileSystem();
- std::unique_ptr<WritableFileWriter> file_writer;
- Status s = WritableFileWriter::Create(
- fs, manifest_path, fs->OptimizeForManifestWrite(env_options_),
- &file_writer, nullptr);
- ASSERT_OK(s);
- {
- log_writer->reset(new log::Writer(std::move(file_writer), 0, false));
- std::string record;
- new_db.EncodeTo(&record);
- s = (*log_writer)->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- }
- }
- std::unique_ptr<log::Writer> log_writer_;
- };
- const std::string VersionSetTestEmptyDb::kUnknownColumnFamilyName = "unknown";
- TEST_P(VersionSetTestEmptyDb, OpenFromIncompleteManifest0) {
- db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
- PrepareManifest(nullptr, nullptr, &log_writer_);
- log_writer_.reset();
- CreateCurrentFile();
- std::string manifest_path;
- VerifyManifest(&manifest_path);
- bool read_only = std::get<1>(GetParam());
- const std::vector<std::string> cf_names = std::get<2>(GetParam());
- std::vector<ColumnFamilyDescriptor> column_families;
- for (const auto& cf_name : cf_names) {
- column_families.emplace_back(cf_name, cf_options_);
- }
- std::string db_id;
- bool has_missing_table_file = false;
- Status s = versions_->TryRecoverFromOneManifest(
- manifest_path, column_families, read_only, &db_id,
- &has_missing_table_file);
- auto iter =
- std::find(cf_names.begin(), cf_names.end(), kDefaultColumnFamilyName);
- if (iter == cf_names.end()) {
- ASSERT_TRUE(s.IsInvalidArgument());
- } else {
- ASSERT_NE(s.ToString().find(manifest_path), std::string::npos);
- ASSERT_TRUE(s.IsCorruption());
- }
- }
- TEST_P(VersionSetTestEmptyDb, OpenFromIncompleteManifest1) {
- db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
- PrepareManifest(nullptr, nullptr, &log_writer_);
- // Only a subset of column families in the MANIFEST.
- VersionEdit new_cf1;
- new_cf1.AddColumnFamily(VersionSetTestBase::kColumnFamilyName1);
- new_cf1.SetColumnFamily(1);
- Status s;
- {
- std::string record;
- new_cf1.EncodeTo(&record);
- s = log_writer_->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- }
- log_writer_.reset();
- CreateCurrentFile();
- std::string manifest_path;
- VerifyManifest(&manifest_path);
- bool read_only = std::get<1>(GetParam());
- const std::vector<std::string>& cf_names = std::get<2>(GetParam());
- std::vector<ColumnFamilyDescriptor> column_families;
- for (const auto& cf_name : cf_names) {
- column_families.emplace_back(cf_name, cf_options_);
- }
- std::string db_id;
- bool has_missing_table_file = false;
- s = versions_->TryRecoverFromOneManifest(manifest_path, column_families,
- read_only, &db_id,
- &has_missing_table_file);
- auto iter =
- std::find(cf_names.begin(), cf_names.end(), kDefaultColumnFamilyName);
- if (iter == cf_names.end()) {
- ASSERT_TRUE(s.IsInvalidArgument());
- } else {
- ASSERT_NE(s.ToString().find(manifest_path), std::string::npos);
- ASSERT_TRUE(s.IsCorruption());
- }
- }
- TEST_P(VersionSetTestEmptyDb, OpenFromInCompleteManifest2) {
- db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
- PrepareManifest(nullptr, nullptr, &log_writer_);
- // Write all column families but no log_number, next_file_number and
- // last_sequence.
- const std::vector<std::string> all_cf_names = {
- kDefaultColumnFamilyName, kColumnFamilyName1, kColumnFamilyName2,
- kColumnFamilyName3};
- uint32_t cf_id = 1;
- Status s;
- for (size_t i = 1; i != all_cf_names.size(); ++i) {
- VersionEdit new_cf;
- new_cf.AddColumnFamily(all_cf_names[i]);
- new_cf.SetColumnFamily(cf_id++);
- std::string record;
- ASSERT_TRUE(new_cf.EncodeTo(&record));
- s = log_writer_->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- }
- log_writer_.reset();
- CreateCurrentFile();
- std::string manifest_path;
- VerifyManifest(&manifest_path);
- bool read_only = std::get<1>(GetParam());
- const std::vector<std::string>& cf_names = std::get<2>(GetParam());
- std::vector<ColumnFamilyDescriptor> column_families;
- for (const auto& cf_name : cf_names) {
- column_families.emplace_back(cf_name, cf_options_);
- }
- std::string db_id;
- bool has_missing_table_file = false;
- s = versions_->TryRecoverFromOneManifest(manifest_path, column_families,
- read_only, &db_id,
- &has_missing_table_file);
- auto iter =
- std::find(cf_names.begin(), cf_names.end(), kDefaultColumnFamilyName);
- if (iter == cf_names.end()) {
- ASSERT_TRUE(s.IsInvalidArgument());
- } else {
- ASSERT_NE(s.ToString().find(manifest_path), std::string::npos);
- ASSERT_TRUE(s.IsCorruption());
- }
- }
- TEST_P(VersionSetTestEmptyDb, OpenManifestWithUnknownCF) {
- db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
- PrepareManifest(nullptr, nullptr, &log_writer_);
- // Write all column families but no log_number, next_file_number and
- // last_sequence.
- const std::vector<std::string> all_cf_names = {
- kDefaultColumnFamilyName, kColumnFamilyName1, kColumnFamilyName2,
- kColumnFamilyName3};
- uint32_t cf_id = 1;
- Status s;
- for (size_t i = 1; i != all_cf_names.size(); ++i) {
- VersionEdit new_cf;
- new_cf.AddColumnFamily(all_cf_names[i]);
- new_cf.SetColumnFamily(cf_id++);
- std::string record;
- ASSERT_TRUE(new_cf.EncodeTo(&record));
- s = log_writer_->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- }
- {
- VersionEdit tmp_edit;
- tmp_edit.SetColumnFamily(4);
- tmp_edit.SetLogNumber(0);
- tmp_edit.SetNextFile(2);
- tmp_edit.SetLastSequence(0);
- std::string record;
- ASSERT_TRUE(tmp_edit.EncodeTo(&record));
- s = log_writer_->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- }
- log_writer_.reset();
- CreateCurrentFile();
- std::string manifest_path;
- VerifyManifest(&manifest_path);
- bool read_only = std::get<1>(GetParam());
- const std::vector<std::string>& cf_names = std::get<2>(GetParam());
- std::vector<ColumnFamilyDescriptor> column_families;
- for (const auto& cf_name : cf_names) {
- column_families.emplace_back(cf_name, cf_options_);
- }
- std::string db_id;
- bool has_missing_table_file = false;
- s = versions_->TryRecoverFromOneManifest(manifest_path, column_families,
- read_only, &db_id,
- &has_missing_table_file);
- auto iter =
- std::find(cf_names.begin(), cf_names.end(), kDefaultColumnFamilyName);
- if (iter == cf_names.end()) {
- ASSERT_TRUE(s.IsInvalidArgument());
- } else {
- ASSERT_NE(s.ToString().find(manifest_path), std::string::npos);
- ASSERT_TRUE(s.IsCorruption());
- }
- }
- TEST_P(VersionSetTestEmptyDb, OpenCompleteManifest) {
- db_options_.write_dbid_to_manifest = std::get<0>(GetParam());
- PrepareManifest(nullptr, nullptr, &log_writer_);
- // Write all column families but no log_number, next_file_number and
- // last_sequence.
- const std::vector<std::string> all_cf_names = {
- kDefaultColumnFamilyName, kColumnFamilyName1, kColumnFamilyName2,
- kColumnFamilyName3};
- uint32_t cf_id = 1;
- Status s;
- for (size_t i = 1; i != all_cf_names.size(); ++i) {
- VersionEdit new_cf;
- new_cf.AddColumnFamily(all_cf_names[i]);
- new_cf.SetColumnFamily(cf_id++);
- std::string record;
- ASSERT_TRUE(new_cf.EncodeTo(&record));
- s = log_writer_->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- }
- {
- VersionEdit tmp_edit;
- tmp_edit.SetLogNumber(0);
- tmp_edit.SetNextFile(2);
- tmp_edit.SetLastSequence(0);
- std::string record;
- ASSERT_TRUE(tmp_edit.EncodeTo(&record));
- s = log_writer_->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- }
- log_writer_.reset();
- CreateCurrentFile();
- std::string manifest_path;
- VerifyManifest(&manifest_path);
- bool read_only = std::get<1>(GetParam());
- const std::vector<std::string>& cf_names = std::get<2>(GetParam());
- std::vector<ColumnFamilyDescriptor> column_families;
- for (const auto& cf_name : cf_names) {
- column_families.emplace_back(cf_name, cf_options_);
- }
- std::string db_id;
- bool has_missing_table_file = false;
- SaveAndRestore<bool> override_unchanging(&versions_->TEST_unchanging(),
- read_only);
- s = versions_->TryRecoverFromOneManifest(manifest_path, column_families,
- read_only, &db_id,
- &has_missing_table_file);
- auto iter =
- std::find(cf_names.begin(), cf_names.end(), kDefaultColumnFamilyName);
- if (iter == cf_names.end()) {
- ASSERT_TRUE(s.IsInvalidArgument());
- } else if (read_only) {
- ASSERT_OK(s);
- ASSERT_FALSE(has_missing_table_file);
- } else if (cf_names.size() == all_cf_names.size()) {
- ASSERT_OK(s);
- ASSERT_FALSE(has_missing_table_file);
- } else if (cf_names.size() < all_cf_names.size()) {
- ASSERT_TRUE(s.IsInvalidArgument());
- } else {
- ASSERT_OK(s);
- ASSERT_FALSE(has_missing_table_file);
- ColumnFamilyData* cfd = versions_->GetColumnFamilySet()->GetColumnFamily(
- kUnknownColumnFamilyName);
- ASSERT_EQ(nullptr, cfd);
- }
- }
- INSTANTIATE_TEST_CASE_P(
- BestEffortRecovery, VersionSetTestEmptyDb,
- testing::Combine(
- /*write_dbid_to_manifest=*/testing::Bool(),
- /*read_only=*/testing::Bool(),
- /*cf_names=*/
- testing::Values(
- std::vector<std::string>(),
- std::vector<std::string>({kDefaultColumnFamilyName}),
- std::vector<std::string>({VersionSetTestBase::kColumnFamilyName1,
- VersionSetTestBase::kColumnFamilyName2,
- VersionSetTestBase::kColumnFamilyName3}),
- std::vector<std::string>({kDefaultColumnFamilyName,
- VersionSetTestBase::kColumnFamilyName1}),
- std::vector<std::string>({kDefaultColumnFamilyName,
- VersionSetTestBase::kColumnFamilyName1,
- VersionSetTestBase::kColumnFamilyName2,
- VersionSetTestBase::kColumnFamilyName3}),
- std::vector<std::string>(
- {kDefaultColumnFamilyName,
- VersionSetTestBase::kColumnFamilyName1,
- VersionSetTestBase::kColumnFamilyName2,
- VersionSetTestBase::kColumnFamilyName3,
- VersionSetTestEmptyDb::kUnknownColumnFamilyName}))));
- class VersionSetTestMissingFiles : public VersionSetTestBase,
- public testing::Test {
- public:
- explicit VersionSetTestMissingFiles(
- const std::string& test_name = "version_set_test_missing_files")
- : VersionSetTestBase(test_name),
- internal_comparator_(
- std::make_shared<InternalKeyComparator>(options_.comparator)) {}
- protected:
- void PrepareManifest(std::vector<ColumnFamilyDescriptor>* column_families,
- SequenceNumber* last_seqno,
- std::unique_ptr<log::Writer>* log_writer) override {
- assert(column_families != nullptr);
- assert(last_seqno != nullptr);
- assert(log_writer != nullptr);
- ASSERT_OK(
- SetIdentityFile(WriteOptions(), env_, dbname_, Temperature::kUnknown));
- const std::string manifest = DescriptorFileName(dbname_, 1);
- const auto& fs = env_->GetFileSystem();
- std::unique_ptr<WritableFileWriter> file_writer;
- Status s = WritableFileWriter::Create(
- fs, manifest, fs->OptimizeForManifestWrite(env_options_), &file_writer,
- nullptr);
- ASSERT_OK(s);
- log_writer->reset(new log::Writer(std::move(file_writer), 0, false));
- VersionEdit new_db;
- if (db_options_.write_dbid_to_manifest) {
- DBOptions tmp_db_options;
- tmp_db_options.env = env_;
- std::unique_ptr<DBImpl> impl(new DBImpl(tmp_db_options, dbname_));
- std::string db_id;
- ASSERT_OK(impl->GetDbIdentityFromIdentityFile(IOOptions(), &db_id));
- new_db.SetDBId(db_id);
- }
- {
- std::string record;
- ASSERT_TRUE(new_db.EncodeTo(&record));
- s = (*log_writer)->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- }
- const std::vector<std::string> cf_names = {
- kDefaultColumnFamilyName, kColumnFamilyName1, kColumnFamilyName2,
- kColumnFamilyName3};
- uint32_t cf_id = 1; // default cf id is 0
- cf_options_.table_factory = table_factory_;
- for (const auto& cf_name : cf_names) {
- column_families->emplace_back(cf_name, cf_options_);
- if (cf_name == kDefaultColumnFamilyName) {
- continue;
- }
- VersionEdit new_cf;
- new_cf.AddColumnFamily(cf_name);
- new_cf.SetColumnFamily(cf_id);
- std::string record;
- ASSERT_TRUE(new_cf.EncodeTo(&record));
- s = (*log_writer)->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- VersionEdit cf_files;
- cf_files.SetColumnFamily(cf_id);
- cf_files.SetLogNumber(0);
- record.clear();
- ASSERT_TRUE(cf_files.EncodeTo(&record));
- s = (*log_writer)->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- ++cf_id;
- }
- SequenceNumber seq = 2;
- {
- VersionEdit edit;
- edit.SetNextFile(7);
- edit.SetLastSequence(seq);
- std::string record;
- ASSERT_TRUE(edit.EncodeTo(&record));
- s = (*log_writer)->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- }
- *last_seqno = seq + 1;
- }
- // This method updates last_sequence_.
- void WriteFileAdditionAndDeletionToManifest(
- uint32_t cf, const std::vector<std::pair<int, FileMetaData>>& added_files,
- const std::vector<std::pair<int, uint64_t>>& deleted_files,
- const std::vector<BlobFileAddition>& blob_files = {}) {
- VersionEdit edit;
- edit.SetColumnFamily(cf);
- for (const auto& elem : added_files) {
- int level = elem.first;
- edit.AddFile(level, elem.second);
- }
- for (const auto& elem : deleted_files) {
- int level = elem.first;
- edit.DeleteFile(level, elem.second);
- }
- for (const auto& elem : blob_files) {
- edit.AddBlobFile(elem);
- }
- edit.SetLastSequence(last_seqno_);
- ++last_seqno_;
- assert(log_writer_.get() != nullptr);
- std::string record;
- ASSERT_TRUE(edit.EncodeTo(&record, 0 /* ts_sz */));
- Status s = log_writer_->AddRecord(WriteOptions(), record);
- ASSERT_OK(s);
- }
- std::shared_ptr<InternalKeyComparator> internal_comparator_;
- std::vector<ColumnFamilyDescriptor> column_families_;
- SequenceNumber last_seqno_;
- std::unique_ptr<log::Writer> log_writer_;
- };
- TEST_F(VersionSetTestMissingFiles, ManifestFarBehindSst) {
- std::vector<SstInfo> existing_files = {
- SstInfo(100, kDefaultColumnFamilyName, "a", 100 /* epoch_number */),
- SstInfo(102, kDefaultColumnFamilyName, "b", 102 /* epoch_number */),
- SstInfo(103, kDefaultColumnFamilyName, "c", 103 /* epoch_number */),
- SstInfo(107, kDefaultColumnFamilyName, "d", 107 /* epoch_number */),
- SstInfo(110, kDefaultColumnFamilyName, "e", 110 /* epoch_number */)};
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(existing_files, &file_metas);
- PrepareManifest(&column_families_, &last_seqno_, &log_writer_);
- std::vector<std::pair<int, FileMetaData>> added_files;
- for (uint64_t file_num = 10; file_num < 15; ++file_num) {
- std::string smallest_ukey = "a";
- std::string largest_ukey = "b";
- InternalKey smallest_ikey(smallest_ukey, 1, ValueType::kTypeValue);
- InternalKey largest_ikey(largest_ukey, 1, ValueType::kTypeValue);
- FileMetaData meta = FileMetaData(
- file_num, /*file_path_id=*/0, /*file_size=*/12, smallest_ikey,
- largest_ikey, 0, 0, false, Temperature::kUnknown, 0, 0, 0,
- file_num /* epoch_number */, kUnknownFileChecksum,
- kUnknownFileChecksumFuncName, kNullUniqueId64x2, 0, 0,
- /* user_defined_timestamps_persisted */ true);
- added_files.emplace_back(0, meta);
- }
- WriteFileAdditionAndDeletionToManifest(
- /*cf=*/0, added_files, std::vector<std::pair<int, uint64_t>>());
- std::vector<std::pair<int, uint64_t>> deleted_files;
- deleted_files.emplace_back(0, 10);
- WriteFileAdditionAndDeletionToManifest(
- /*cf=*/0, std::vector<std::pair<int, FileMetaData>>(), deleted_files);
- log_writer_.reset();
- CreateCurrentFile();
- std::string manifest_path;
- VerifyManifest(&manifest_path);
- std::string db_id;
- bool has_missing_table_file = false;
- Status s = versions_->TryRecoverFromOneManifest(
- manifest_path, column_families_,
- /*read_only=*/false, &db_id, &has_missing_table_file);
- ASSERT_OK(s);
- ASSERT_TRUE(has_missing_table_file);
- for (ColumnFamilyData* cfd : *(versions_->GetColumnFamilySet())) {
- VersionStorageInfo* vstorage = cfd->current()->storage_info();
- const std::vector<FileMetaData*>& files = vstorage->LevelFiles(0);
- ASSERT_TRUE(files.empty());
- }
- }
- TEST_F(VersionSetTestMissingFiles, ManifestAheadofSst) {
- std::vector<SstInfo> existing_files = {
- SstInfo(100, kDefaultColumnFamilyName, "a", 0 /* level */,
- 100 /* epoch_number */),
- SstInfo(102, kDefaultColumnFamilyName, "b", 0 /* level */,
- 102 /* epoch_number */),
- SstInfo(103, kDefaultColumnFamilyName, "c", 0 /* level */,
- 103 /* epoch_number */),
- SstInfo(107, kDefaultColumnFamilyName, "d", 0 /* level */,
- 107 /* epoch_number */),
- SstInfo(110, kDefaultColumnFamilyName, "e", 0 /* level */,
- 110 /* epoch_number */)};
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(existing_files, &file_metas);
- PrepareManifest(&column_families_, &last_seqno_, &log_writer_);
- std::vector<std::pair<int, FileMetaData>> added_files;
- for (size_t i = 3; i != 5; ++i) {
- added_files.emplace_back(0, file_metas[i]);
- }
- WriteFileAdditionAndDeletionToManifest(
- /*cf=*/0, added_files, std::vector<std::pair<int, uint64_t>>());
- added_files.clear();
- for (uint64_t file_num = 120; file_num < 130; ++file_num) {
- std::string smallest_ukey = "a";
- std::string largest_ukey = "b";
- InternalKey smallest_ikey(smallest_ukey, 1, ValueType::kTypeValue);
- InternalKey largest_ikey(largest_ukey, 1, ValueType::kTypeValue);
- FileMetaData meta = FileMetaData(
- file_num, /*file_path_id=*/0, /*file_size=*/12, smallest_ikey,
- largest_ikey, 0, 0, false, Temperature::kUnknown, 0, 0, 0,
- file_num /* epoch_number */, kUnknownFileChecksum,
- kUnknownFileChecksumFuncName, kNullUniqueId64x2, 0, 0,
- /* user_defined_timestamps_persisted */ true);
- added_files.emplace_back(0, meta);
- }
- WriteFileAdditionAndDeletionToManifest(
- /*cf=*/0, added_files, std::vector<std::pair<int, uint64_t>>());
- log_writer_.reset();
- CreateCurrentFile();
- std::string manifest_path;
- VerifyManifest(&manifest_path);
- std::string db_id;
- bool has_missing_table_file = false;
- Status s = versions_->TryRecoverFromOneManifest(
- manifest_path, column_families_,
- /*read_only=*/false, &db_id, &has_missing_table_file);
- ASSERT_OK(s);
- ASSERT_TRUE(has_missing_table_file);
- for (ColumnFamilyData* cfd : *(versions_->GetColumnFamilySet())) {
- VersionStorageInfo* vstorage = cfd->current()->storage_info();
- const std::vector<FileMetaData*>& files = vstorage->LevelFiles(0);
- if (cfd->GetName() == kDefaultColumnFamilyName) {
- ASSERT_EQ(2, files.size());
- for (const auto* fmeta : files) {
- if (fmeta->fd.GetNumber() != 107 && fmeta->fd.GetNumber() != 110) {
- ASSERT_FALSE(true);
- }
- }
- } else {
- ASSERT_TRUE(files.empty());
- }
- }
- }
- TEST_F(VersionSetTestMissingFiles, NoFileMissing) {
- std::vector<SstInfo> existing_files = {
- SstInfo(100, kDefaultColumnFamilyName, "a", 0 /* level */,
- 100 /* epoch_number */),
- SstInfo(102, kDefaultColumnFamilyName, "b", 0 /* level */,
- 102 /* epoch_number */),
- SstInfo(103, kDefaultColumnFamilyName, "c", 0 /* level */,
- 103 /* epoch_number */),
- SstInfo(107, kDefaultColumnFamilyName, "d", 0 /* level */,
- 107 /* epoch_number */),
- SstInfo(110, kDefaultColumnFamilyName, "e", 0 /* level */,
- 110 /* epoch_number */)};
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(existing_files, &file_metas);
- PrepareManifest(&column_families_, &last_seqno_, &log_writer_);
- std::vector<std::pair<int, FileMetaData>> added_files;
- for (const auto& meta : file_metas) {
- added_files.emplace_back(0, meta);
- }
- WriteFileAdditionAndDeletionToManifest(
- /*cf=*/0, added_files, std::vector<std::pair<int, uint64_t>>());
- std::vector<std::pair<int, uint64_t>> deleted_files;
- deleted_files.emplace_back(/*level=*/0, 100);
- WriteFileAdditionAndDeletionToManifest(
- /*cf=*/0, std::vector<std::pair<int, FileMetaData>>(), deleted_files);
- log_writer_.reset();
- CreateCurrentFile();
- std::string manifest_path;
- VerifyManifest(&manifest_path);
- std::string db_id;
- bool has_missing_table_file = false;
- Status s = versions_->TryRecoverFromOneManifest(
- manifest_path, column_families_,
- /*read_only=*/false, &db_id, &has_missing_table_file);
- ASSERT_OK(s);
- ASSERT_FALSE(has_missing_table_file);
- for (ColumnFamilyData* cfd : *(versions_->GetColumnFamilySet())) {
- VersionStorageInfo* vstorage = cfd->current()->storage_info();
- const std::vector<FileMetaData*>& files = vstorage->LevelFiles(0);
- if (cfd->GetName() == kDefaultColumnFamilyName) {
- ASSERT_EQ(existing_files.size() - deleted_files.size(), files.size());
- bool has_deleted_file = false;
- for (const auto* fmeta : files) {
- if (fmeta->fd.GetNumber() == 100) {
- has_deleted_file = true;
- break;
- }
- }
- ASSERT_FALSE(has_deleted_file);
- } else {
- ASSERT_TRUE(files.empty());
- }
- }
- }
- TEST_F(VersionSetTestMissingFiles, MinLogNumberToKeep2PC) {
- db_options_.allow_2pc = true;
- NewDB();
- SstInfo sst(100, kDefaultColumnFamilyName, "a", 0 /* level */,
- 100 /* epoch_number */);
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles({sst}, &file_metas);
- constexpr WalNumber kMinWalNumberToKeep2PC = 10;
- VersionEdit edit;
- edit.AddFile(0, file_metas[0]);
- edit.SetMinLogNumberToKeep(kMinWalNumberToKeep2PC);
- ASSERT_OK(LogAndApplyToDefaultCF(edit));
- ASSERT_EQ(versions_->min_log_number_to_keep(), kMinWalNumberToKeep2PC);
- for (int i = 0; i < 3; i++) {
- CreateNewManifest();
- ReopenDB();
- ASSERT_EQ(versions_->min_log_number_to_keep(), kMinWalNumberToKeep2PC);
- }
- }
- class BestEffortsRecoverIncompleteVersionTest
- : public VersionSetTestMissingFiles {
- public:
- BestEffortsRecoverIncompleteVersionTest()
- : VersionSetTestMissingFiles("best_efforts_recover_incomplete_version") {}
- struct BlobInfo {
- uint64_t file_number;
- bool file_missing;
- std::string key;
- std::string blob;
- BlobInfo(uint64_t _file_number, bool _file_missing, std::string _key,
- std::string _blob)
- : file_number(_file_number),
- file_missing(_file_missing),
- key(_key),
- blob(_blob) {}
- };
- void CreateDummyBlobFiles(const std::vector<BlobInfo>& infos,
- std::vector<BlobFileAddition>* blob_metas) {
- for (const auto& info : infos) {
- if (!info.file_missing) {
- WriteDummyBlobFile(info.file_number, info.key, info.blob);
- }
- blob_metas->emplace_back(
- info.file_number, 1 /*total_blob_count*/,
- info.key.size() + info.blob.size() /*total_blob_bytes*/,
- "" /*checksum_method*/, "" /*check_sum_value*/);
- }
- }
- // Creates a test blob file that is valid so it can pass the
- // `VersionEditHandlerPointInTime::VerifyBlobFile` check.
- void WriteDummyBlobFile(uint64_t blob_file_number, const Slice& key,
- const Slice& blob) {
- ImmutableOptions options;
- std::string blob_file_path = BlobFileName(dbname_, blob_file_number);
- std::unique_ptr<FSWritableFile> file;
- ASSERT_OK(
- fs_->NewWritableFile(blob_file_path, FileOptions(), &file, nullptr));
- std::unique_ptr<WritableFileWriter> file_writer(new WritableFileWriter(
- std::move(file), blob_file_path, FileOptions(), options.clock));
- BlobLogWriter blob_log_writer(std::move(file_writer), options.clock,
- /*statistics*/ nullptr, blob_file_number,
- /*use_fsync*/ true,
- /*do_flush*/ false);
- constexpr ExpirationRange expiration_range;
- BlobLogHeader header(/*column_family_id*/ 0, kNoCompression,
- /*has_ttl*/ false, expiration_range);
- ASSERT_OK(blob_log_writer.WriteHeader(WriteOptions(), header));
- std::string compressed_blob;
- uint64_t key_offset = 0;
- uint64_t blob_offset = 0;
- ASSERT_OK(blob_log_writer.AddRecord(WriteOptions(), key, blob, &key_offset,
- &blob_offset));
- BlobLogFooter footer;
- footer.blob_count = 1;
- footer.expiration_range = expiration_range;
- std::string checksum_method;
- std::string checksum_value;
- ASSERT_OK(blob_log_writer.AppendFooter(WriteOptions(), footer,
- &checksum_method, &checksum_value));
- }
- void RecoverFromManifestWithMissingFiles(
- const std::vector<std::pair<int, FileMetaData>>& added_files,
- const std::vector<BlobFileAddition>& blob_files) {
- PrepareManifest(&column_families_, &last_seqno_, &log_writer_);
- WriteFileAdditionAndDeletionToManifest(
- /*cf=*/0, added_files, std::vector<std::pair<int, uint64_t>>(),
- blob_files);
- log_writer_.reset();
- CreateCurrentFile();
- std::string manifest_path;
- VerifyManifest(&manifest_path);
- std::string db_id;
- bool has_missing_table_file = false;
- Status s = versions_->TryRecoverFromOneManifest(
- manifest_path, column_families_,
- /*read_only=*/false, &db_id, &has_missing_table_file);
- ASSERT_OK(s);
- ASSERT_TRUE(has_missing_table_file);
- }
- };
- TEST_F(BestEffortsRecoverIncompleteVersionTest, NonL0MissingFiles) {
- std::vector<SstInfo> sst_files = {
- SstInfo(100, kDefaultColumnFamilyName, "a", 1 /* level */,
- 100 /* epoch_number */, true /* file_missing */),
- SstInfo(101, kDefaultColumnFamilyName, "a", 0 /* level */,
- 101 /* epoch_number */, false /* file_missing */),
- SstInfo(102, kDefaultColumnFamilyName, "a", 0 /* level */,
- 102 /* epoch_number */, false /* file_missing */),
- };
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(sst_files, &file_metas);
- std::vector<std::pair<int, FileMetaData>> added_files;
- for (size_t i = 0; i < sst_files.size(); i++) {
- const auto& info = sst_files[i];
- const auto& meta = file_metas[i];
- added_files.emplace_back(info.level, meta);
- }
- RecoverFromManifestWithMissingFiles(added_files,
- std::vector<BlobFileAddition>());
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_TRUE(all_table_files.empty());
- }
- TEST_F(BestEffortsRecoverIncompleteVersionTest, MissingNonSuffixL0Files) {
- std::vector<SstInfo> sst_files = {
- SstInfo(100, kDefaultColumnFamilyName, "a", 1 /* level */,
- 100 /* epoch_number */, false /* file_missing */),
- SstInfo(101, kDefaultColumnFamilyName, "a", 0 /* level */,
- 101 /* epoch_number */, true /* file_missing */),
- SstInfo(102, kDefaultColumnFamilyName, "a", 0 /* level */,
- 102 /* epoch_number */, false /* file_missing */),
- };
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(sst_files, &file_metas);
- std::vector<std::pair<int, FileMetaData>> added_files;
- for (size_t i = 0; i < sst_files.size(); i++) {
- const auto& info = sst_files[i];
- const auto& meta = file_metas[i];
- added_files.emplace_back(info.level, meta);
- }
- RecoverFromManifestWithMissingFiles(added_files,
- std::vector<BlobFileAddition>());
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_TRUE(all_table_files.empty());
- }
- TEST_F(BestEffortsRecoverIncompleteVersionTest, MissingBlobFiles) {
- std::vector<SstInfo> sst_files = {
- SstInfo(100, kDefaultColumnFamilyName, "a", 0 /* level */,
- 100 /* epoch_number */, false /* file_missing */,
- 102 /*oldest_blob_file_number*/),
- SstInfo(101, kDefaultColumnFamilyName, "a", 0 /* level */,
- 101 /* epoch_number */, false /* file_missing */,
- 103 /*oldest_blob_file_number*/),
- };
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(sst_files, &file_metas);
- std::vector<BlobInfo> blob_files = {
- BlobInfo(102, true /*file_missing*/, "a", "blob1"),
- BlobInfo(103, true /*file_missing*/, "a", "blob2"),
- };
- std::vector<BlobFileAddition> blob_meta;
- CreateDummyBlobFiles(blob_files, &blob_meta);
- std::vector<std::pair<int, FileMetaData>> added_files;
- for (size_t i = 0; i < sst_files.size(); i++) {
- const auto& info = sst_files[i];
- const auto& meta = file_metas[i];
- added_files.emplace_back(info.level, meta);
- }
- RecoverFromManifestWithMissingFiles(added_files, blob_meta);
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_TRUE(all_table_files.empty());
- }
- TEST_F(BestEffortsRecoverIncompleteVersionTest, MissingL0SuffixOnly) {
- std::vector<SstInfo> sst_files = {
- SstInfo(100, kDefaultColumnFamilyName, "a", 1 /* level */,
- 100 /* epoch_number */, false /* file_missing */),
- SstInfo(101, kDefaultColumnFamilyName, "a", 0 /* level */,
- 101 /* epoch_number */, false /* file_missing */),
- SstInfo(102, kDefaultColumnFamilyName, "a", 0 /* level */,
- 102 /* epoch_number */, true /* file_missing */),
- };
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(sst_files, &file_metas);
- std::vector<std::pair<int, FileMetaData>> added_files;
- for (size_t i = 0; i < sst_files.size(); i++) {
- const auto& info = sst_files[i];
- const auto& meta = file_metas[i];
- added_files.emplace_back(info.level, meta);
- }
- RecoverFromManifestWithMissingFiles(added_files,
- std::vector<BlobFileAddition>());
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_EQ(2, all_table_files.size());
- ColumnFamilyData* cfd = versions_->GetColumnFamilySet()->GetDefault();
- VersionStorageInfo* vstorage = cfd->current()->storage_info();
- ASSERT_EQ(1, vstorage->LevelFiles(0).size());
- ASSERT_EQ(1, vstorage->LevelFiles(1).size());
- }
- TEST_F(BestEffortsRecoverIncompleteVersionTest,
- MissingL0SuffixAndTheirBlobFiles) {
- std::vector<SstInfo> sst_files = {
- SstInfo(100, kDefaultColumnFamilyName, "a", 1 /* level */,
- 100 /* epoch_number */, false /* file_missing */),
- SstInfo(101, kDefaultColumnFamilyName, "a", 0 /* level */,
- 101 /* epoch_number */, false /* file_missing */,
- 103 /*oldest_blob_file_number*/),
- SstInfo(102, kDefaultColumnFamilyName, "a", 0 /* level */,
- 102 /* epoch_number */, true /* file_missing */,
- 104 /*oldest_blob_file_number*/),
- };
- std::vector<FileMetaData> file_metas;
- CreateDummyTableFiles(sst_files, &file_metas);
- std::vector<BlobInfo> blob_files = {
- BlobInfo(103, false /*file_missing*/, "a", "blob1"),
- BlobInfo(104, true /*file_missing*/, "a", "blob2"),
- };
- std::vector<BlobFileAddition> blob_meta;
- CreateDummyBlobFiles(blob_files, &blob_meta);
- std::vector<std::pair<int, FileMetaData>> added_files;
- for (size_t i = 0; i < sst_files.size(); i++) {
- const auto& info = sst_files[i];
- const auto& meta = file_metas[i];
- added_files.emplace_back(info.level, meta);
- }
- RecoverFromManifestWithMissingFiles(added_files, blob_meta);
- std::vector<uint64_t> all_table_files;
- std::vector<uint64_t> all_blob_files;
- versions_->AddLiveFiles(&all_table_files, &all_blob_files);
- ASSERT_EQ(2, all_table_files.size());
- ASSERT_EQ(1, all_blob_files.size());
- ColumnFamilyData* cfd = versions_->GetColumnFamilySet()->GetDefault();
- VersionStorageInfo* vstorage = cfd->current()->storage_info();
- ASSERT_EQ(1, vstorage->LevelFiles(0).size());
- ASSERT_EQ(1, vstorage->LevelFiles(1).size());
- ASSERT_EQ(1, vstorage->GetBlobFiles().size());
- }
- class ChargeFileMetadataTest : public DBTestBase {
- public:
- ChargeFileMetadataTest()
- : DBTestBase("charge_file_metadata_test", /*env_do_fsync=*/true) {}
- };
- class ChargeFileMetadataTestWithParam
- : public ChargeFileMetadataTest,
- public testing::WithParamInterface<CacheEntryRoleOptions::Decision> {
- public:
- ChargeFileMetadataTestWithParam() = default;
- };
- INSTANTIATE_TEST_CASE_P(
- ChargeFileMetadataTestWithParam, ChargeFileMetadataTestWithParam,
- ::testing::Values(CacheEntryRoleOptions::Decision::kEnabled,
- CacheEntryRoleOptions::Decision::kDisabled));
- TEST_P(ChargeFileMetadataTestWithParam, Basic) {
- Options options;
- options.level_compaction_dynamic_level_bytes = false;
- BlockBasedTableOptions table_options;
- CacheEntryRoleOptions::Decision charge_file_metadata = GetParam();
- table_options.cache_usage_options.options_overrides.insert(
- {CacheEntryRole::kFileMetadata, {/*.charged = */ charge_file_metadata}});
- std::shared_ptr<TargetCacheChargeTrackingCache<CacheEntryRole::kFileMetadata>>
- file_metadata_charge_only_cache = std::make_shared<
- TargetCacheChargeTrackingCache<CacheEntryRole::kFileMetadata>>(
- NewLRUCache(
- 4 * CacheReservationManagerImpl<
- CacheEntryRole::kFileMetadata>::GetDummyEntrySize(),
- 0 /* num_shard_bits */, true /* strict_capacity_limit */));
- table_options.block_cache = file_metadata_charge_only_cache;
- options.table_factory.reset(NewBlockBasedTableFactory(table_options));
- options.create_if_missing = true;
- options.disable_auto_compactions = true;
- DestroyAndReopen(options);
- // Create 128 file metadata, each of which is roughly 1024 bytes.
- // This results in 1 *
- // CacheReservationManagerImpl<CacheEntryRole::kFileMetadata>::GetDummyEntrySize()
- // cache reservation for file metadata.
- for (int i = 1; i <= 128; ++i) {
- ASSERT_OK(Put(std::string(1024, 'a'), "va"));
- ASSERT_OK(Put("b", "vb"));
- ASSERT_OK(Flush());
- }
- if (charge_file_metadata == CacheEntryRoleOptions::Decision::kEnabled) {
- EXPECT_EQ(file_metadata_charge_only_cache->GetCacheCharge(),
- 1 * CacheReservationManagerImpl<
- CacheEntryRole::kFileMetadata>::GetDummyEntrySize());
- } else {
- EXPECT_EQ(file_metadata_charge_only_cache->GetCacheCharge(), 0);
- }
- // Create another 128 file metadata.
- // This increases the file metadata cache reservation to 2 *
- // CacheReservationManagerImpl<CacheEntryRole::kFileMetadata>::GetDummyEntrySize().
- for (int i = 1; i <= 128; ++i) {
- ASSERT_OK(Put(std::string(1024, 'a'), "vva"));
- ASSERT_OK(Put("b", "vvb"));
- ASSERT_OK(Flush());
- }
- if (charge_file_metadata == CacheEntryRoleOptions::Decision::kEnabled) {
- EXPECT_EQ(file_metadata_charge_only_cache->GetCacheCharge(),
- 2 * CacheReservationManagerImpl<
- CacheEntryRole::kFileMetadata>::GetDummyEntrySize());
- } else {
- EXPECT_EQ(file_metadata_charge_only_cache->GetCacheCharge(), 0);
- }
- // Compaction will create 1 new file metadata, obsolete and delete all 256
- // file metadata above. This results in 1 *
- // CacheReservationManagerImpl<CacheEntryRole::kFileMetadata>::GetDummyEntrySize()
- // cache reservation for file metadata.
- SyncPoint::GetInstance()->LoadDependency(
- {{"DBImpl::BackgroundCallCompaction:PurgedObsoleteFiles",
- "ChargeFileMetadataTestWithParam::"
- "PreVerifyingCacheReservationRelease"}});
- SyncPoint::GetInstance()->EnableProcessing();
- ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
- ASSERT_EQ("0,1", FilesPerLevel(0));
- TEST_SYNC_POINT(
- "ChargeFileMetadataTestWithParam::PreVerifyingCacheReservationRelease");
- if (charge_file_metadata == CacheEntryRoleOptions::Decision::kEnabled) {
- EXPECT_EQ(file_metadata_charge_only_cache->GetCacheCharge(),
- 1 * CacheReservationManagerImpl<
- CacheEntryRole::kFileMetadata>::GetDummyEntrySize());
- } else {
- EXPECT_EQ(file_metadata_charge_only_cache->GetCacheCharge(), 0);
- }
- SyncPoint::GetInstance()->DisableProcessing();
- // Destroying the db will delete the remaining 1 new file metadata
- // This results in no cache reservation for file metadata.
- Destroy(options);
- EXPECT_EQ(file_metadata_charge_only_cache->GetCacheCharge(),
- 0 * CacheReservationManagerImpl<
- CacheEntryRole::kFileMetadata>::GetDummyEntrySize());
- // Reopen the db with a smaller cache in order to test failure in allocating
- // file metadata due to memory limit based on cache capacity
- file_metadata_charge_only_cache = std::make_shared<
- TargetCacheChargeTrackingCache<CacheEntryRole::kFileMetadata>>(
- NewLRUCache(1 * CacheReservationManagerImpl<
- CacheEntryRole::kFileMetadata>::GetDummyEntrySize(),
- 0 /* num_shard_bits */, true /* strict_capacity_limit */));
- table_options.block_cache = file_metadata_charge_only_cache;
- options.table_factory.reset(NewBlockBasedTableFactory(table_options));
- Reopen(options);
- ASSERT_OK(Put(std::string(1024, 'a'), "va"));
- ASSERT_OK(Put("b", "vb"));
- Status s = Flush();
- if (charge_file_metadata == CacheEntryRoleOptions::Decision::kEnabled) {
- EXPECT_TRUE(s.IsMemoryLimit());
- EXPECT_TRUE(s.ToString().find(
- kCacheEntryRoleToCamelString[static_cast<std::uint32_t>(
- CacheEntryRole::kFileMetadata)]) != std::string::npos);
- EXPECT_TRUE(s.ToString().find("memory limit based on cache capacity") !=
- std::string::npos);
- } else {
- EXPECT_TRUE(s.ok());
- }
- }
- } // namespace ROCKSDB_NAMESPACE
- int main(int argc, char** argv) {
- ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
- }
|