options_test.cc 214 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #include <cctype>
  10. #include <cinttypes>
  11. #include <cstring>
  12. #include <unordered_map>
  13. #include "cache/lru_cache.h"
  14. #include "cache/sharded_cache.h"
  15. #include "options/options_helper.h"
  16. #include "options/options_parser.h"
  17. #include "port/port.h"
  18. #include "rocksdb/cache.h"
  19. #include "rocksdb/convenience.h"
  20. #include "rocksdb/file_checksum.h"
  21. #include "rocksdb/memtablerep.h"
  22. #include "rocksdb/utilities/leveldb_options.h"
  23. #include "rocksdb/utilities/object_registry.h"
  24. #include "rocksdb/utilities/options_type.h"
  25. #include "table/block_based/filter_policy_internal.h"
  26. #include "test_util/testharness.h"
  27. #include "test_util/testutil.h"
  28. #include "util/random.h"
  29. #include "util/stderr_logger.h"
  30. #include "util/string_util.h"
  31. #include "utilities/merge_operators/bytesxor.h"
  32. #include "utilities/merge_operators/sortlist.h"
  33. #include "utilities/merge_operators/string_append/stringappend.h"
  34. #include "utilities/merge_operators/string_append/stringappend2.h"
  35. #ifndef GFLAGS
  36. bool FLAGS_enable_print = false;
  37. #else
  38. #include "util/gflags_compat.h"
  39. using GFLAGS_NAMESPACE::ParseCommandLineFlags;
  40. DEFINE_bool(enable_print, false, "Print options generated to console.");
  41. #endif // GFLAGS
  42. namespace ROCKSDB_NAMESPACE {
  43. class OptionsTest : public testing::Test {};
  44. class UnregisteredTableFactory : public TableFactory {
  45. public:
  46. UnregisteredTableFactory() = default;
  47. const char* Name() const override { return "Unregistered"; }
  48. using TableFactory::NewTableReader;
  49. Status NewTableReader(const ReadOptions&, const TableReaderOptions&,
  50. std::unique_ptr<RandomAccessFileReader>&&, uint64_t,
  51. std::unique_ptr<TableReader>*, bool) const override {
  52. return Status::NotSupported();
  53. }
  54. TableBuilder* NewTableBuilder(const TableBuilderOptions&,
  55. WritableFileWriter*) const override {
  56. return nullptr;
  57. }
  58. std::unique_ptr<TableFactory> Clone() const override {
  59. return std::make_unique<UnregisteredTableFactory>();
  60. }
  61. };
  62. TEST_F(OptionsTest, GetOptionsFromMapTest) {
  63. std::unordered_map<std::string, std::string> cf_options_map = {
  64. {"write_buffer_size", "1"},
  65. {"max_write_buffer_number", "2"},
  66. {"min_write_buffer_number_to_merge", "3"},
  67. {"max_write_buffer_number_to_maintain", "99"},
  68. {"max_write_buffer_size_to_maintain", "-99999"},
  69. {"compression", "kSnappyCompression"},
  70. {"compression_per_level",
  71. "kNoCompression:"
  72. "kSnappyCompression:"
  73. "kZlibCompression:"
  74. "kBZip2Compression:"
  75. "kLZ4Compression:"
  76. "kLZ4HCCompression:"
  77. "kXpressCompression:"
  78. "kZSTD"},
  79. {"bottommost_compression", "kLZ4Compression"},
  80. {"bottommost_compression_opts", "5:6:7:8:10:true"},
  81. {"compression_opts", "4:5:6:7:8:2:true:100:false"},
  82. {"num_levels", "8"},
  83. {"level0_file_num_compaction_trigger", "8"},
  84. {"level0_slowdown_writes_trigger", "9"},
  85. {"level0_stop_writes_trigger", "10"},
  86. {"target_file_size_base", "12"},
  87. {"target_file_size_multiplier", "13"},
  88. {"max_bytes_for_level_base", "14"},
  89. {"level_compaction_dynamic_level_bytes", "true"},
  90. {"max_bytes_for_level_multiplier", "15.0"},
  91. {"max_bytes_for_level_multiplier_additional", "16:17:18"},
  92. {"max_compaction_bytes", "21"},
  93. {"hard_pending_compaction_bytes_limit", "211"},
  94. {"arena_block_size", "22"},
  95. {"disable_auto_compactions", "true"},
  96. {"compaction_style", "kCompactionStyleLevel"},
  97. {"compaction_pri", "kOldestSmallestSeqFirst"},
  98. {"verify_checksums_in_compaction", "false"},
  99. {"compaction_options_fifo",
  100. "{allow_compaction=true;max_table_files_size=11002244;"
  101. "file_temperature_age_thresholds={{temperature=kCold;age=12345}}}"},
  102. {"max_sequential_skip_in_iterations", "24"},
  103. {"inplace_update_support", "true"},
  104. {"report_bg_io_stats", "true"},
  105. {"compaction_measure_io_stats", "false"},
  106. {"purge_redundant_kvs_while_flush", "false"},
  107. {"inplace_update_num_locks", "25"},
  108. {"memtable_prefix_bloom_size_ratio", "0.26"},
  109. {"memtable_whole_key_filtering", "true"},
  110. {"memtable_huge_page_size", "28"},
  111. {"bloom_locality", "29"},
  112. {"max_successive_merges", "30"},
  113. {"strict_max_successive_merges", "true"},
  114. {"min_partial_merge_operands", "31"},
  115. {"prefix_extractor", "fixed:31"},
  116. {"experimental_mempurge_threshold", "0.003"},
  117. {"optimize_filters_for_hits", "true"},
  118. {"enable_blob_files", "true"},
  119. {"min_blob_size", "1K"},
  120. {"blob_file_size", "1G"},
  121. {"blob_compression_type", "kZSTD"},
  122. {"enable_blob_garbage_collection", "true"},
  123. {"blob_garbage_collection_age_cutoff", "0.5"},
  124. {"blob_garbage_collection_force_threshold", "0.75"},
  125. {"blob_compaction_readahead_size", "256K"},
  126. {"blob_file_starting_level", "1"},
  127. {"prepopulate_blob_cache", "kDisable"},
  128. {"last_level_temperature", "kWarm"},
  129. {"default_write_temperature", "kCold"},
  130. {"default_temperature", "kHot"},
  131. {"persist_user_defined_timestamps", "true"},
  132. {"memtable_max_range_deletions", "0"},
  133. };
  134. std::unordered_map<std::string, std::string> db_options_map = {
  135. {"create_if_missing", "false"},
  136. {"create_missing_column_families", "true"},
  137. {"error_if_exists", "false"},
  138. {"paranoid_checks", "true"},
  139. {"track_and_verify_wals_in_manifest", "true"},
  140. {"track_and_verify_wals", "true"},
  141. {"verify_sst_unique_id_in_manifest", "true"},
  142. {"max_open_files", "32"},
  143. {"max_total_wal_size", "33"},
  144. {"use_fsync", "true"},
  145. {"db_log_dir", "/db_log_dir"},
  146. {"wal_dir", "/wal_dir"},
  147. {"delete_obsolete_files_period_micros", "34"},
  148. {"max_background_compactions", "35"},
  149. {"max_background_flushes", "36"},
  150. {"max_log_file_size", "37"},
  151. {"log_file_time_to_roll", "38"},
  152. {"keep_log_file_num", "39"},
  153. {"recycle_log_file_num", "5"},
  154. {"max_manifest_file_size", "40"},
  155. {"table_cache_numshardbits", "41"},
  156. {"WAL_ttl_seconds", "43"},
  157. {"WAL_size_limit_MB", "44"},
  158. {"manifest_preallocation_size", "45"},
  159. {"allow_mmap_reads", "true"},
  160. {"allow_mmap_writes", "false"},
  161. {"use_direct_reads", "false"},
  162. {"use_direct_io_for_flush_and_compaction", "false"},
  163. {"is_fd_close_on_exec", "true"},
  164. {"skip_log_error_on_recovery", "false"},
  165. {"stats_dump_period_sec", "46"},
  166. {"stats_persist_period_sec", "57"},
  167. {"persist_stats_to_disk", "false"},
  168. {"stats_history_buffer_size", "69"},
  169. {"advise_random_on_open", "true"},
  170. {"use_adaptive_mutex", "false"},
  171. {"compaction_readahead_size", "100"},
  172. {"writable_file_max_buffer_size", "314159"},
  173. {"bytes_per_sync", "47"},
  174. {"wal_bytes_per_sync", "48"},
  175. {"strict_bytes_per_sync", "true"},
  176. {"preserve_deletes", "false"},
  177. {"daily_offpeak_time_utc", ""},
  178. };
  179. ColumnFamilyOptions base_cf_opt;
  180. ColumnFamilyOptions new_cf_opt;
  181. ConfigOptions exact, loose;
  182. exact.input_strings_escaped = false;
  183. exact.ignore_unknown_options = false;
  184. exact.sanity_level = ConfigOptions::kSanityLevelExactMatch;
  185. loose.sanity_level = ConfigOptions::kSanityLevelLooselyCompatible;
  186. loose.input_strings_escaped = false;
  187. loose.ignore_unknown_options = true;
  188. ASSERT_OK(GetColumnFamilyOptionsFromMap(exact, base_cf_opt, cf_options_map,
  189. &new_cf_opt));
  190. ASSERT_EQ(new_cf_opt.write_buffer_size, 1U);
  191. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 2);
  192. ASSERT_EQ(new_cf_opt.min_write_buffer_number_to_merge, 3);
  193. ASSERT_EQ(new_cf_opt.max_write_buffer_size_to_maintain, -99999);
  194. ASSERT_EQ(new_cf_opt.compression, kSnappyCompression);
  195. ASSERT_EQ(new_cf_opt.compression_per_level.size(), 8U);
  196. ASSERT_EQ(new_cf_opt.compression_per_level[0], kNoCompression);
  197. ASSERT_EQ(new_cf_opt.compression_per_level[1], kSnappyCompression);
  198. ASSERT_EQ(new_cf_opt.compression_per_level[2], kZlibCompression);
  199. ASSERT_EQ(new_cf_opt.compression_per_level[3], kBZip2Compression);
  200. ASSERT_EQ(new_cf_opt.compression_per_level[4], kLZ4Compression);
  201. ASSERT_EQ(new_cf_opt.compression_per_level[5], kLZ4HCCompression);
  202. ASSERT_EQ(new_cf_opt.compression_per_level[6], kXpressCompression);
  203. ASSERT_EQ(new_cf_opt.compression_per_level[7], kZSTD);
  204. ASSERT_EQ(new_cf_opt.compression_opts.window_bits, 4);
  205. ASSERT_EQ(new_cf_opt.compression_opts.level, 5);
  206. ASSERT_EQ(new_cf_opt.compression_opts.strategy, 6);
  207. ASSERT_EQ(new_cf_opt.compression_opts.max_dict_bytes, 7u);
  208. ASSERT_EQ(new_cf_opt.compression_opts.zstd_max_train_bytes, 8u);
  209. ASSERT_EQ(new_cf_opt.compression_opts.parallel_threads, 2u);
  210. ASSERT_EQ(new_cf_opt.compression_opts.enabled, true);
  211. ASSERT_EQ(new_cf_opt.compression_opts.max_dict_buffer_bytes, 100u);
  212. ASSERT_EQ(new_cf_opt.compression_opts.use_zstd_dict_trainer, false);
  213. ASSERT_EQ(new_cf_opt.bottommost_compression, kLZ4Compression);
  214. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.window_bits, 5);
  215. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.level, 6);
  216. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.strategy, 7);
  217. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.max_dict_bytes, 8u);
  218. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.zstd_max_train_bytes, 10u);
  219. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.parallel_threads,
  220. CompressionOptions().parallel_threads);
  221. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.enabled, true);
  222. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.use_zstd_dict_trainer,
  223. CompressionOptions().use_zstd_dict_trainer);
  224. ASSERT_EQ(new_cf_opt.num_levels, 8);
  225. ASSERT_EQ(new_cf_opt.level0_file_num_compaction_trigger, 8);
  226. ASSERT_EQ(new_cf_opt.level0_slowdown_writes_trigger, 9);
  227. ASSERT_EQ(new_cf_opt.level0_stop_writes_trigger, 10);
  228. ASSERT_EQ(new_cf_opt.target_file_size_base, static_cast<uint64_t>(12));
  229. ASSERT_EQ(new_cf_opt.target_file_size_multiplier, 13);
  230. ASSERT_EQ(new_cf_opt.max_bytes_for_level_base, 14U);
  231. ASSERT_EQ(new_cf_opt.level_compaction_dynamic_level_bytes, true);
  232. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier, 15.0);
  233. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional.size(), 3U);
  234. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[0], 16);
  235. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[1], 17);
  236. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[2], 18);
  237. ASSERT_EQ(new_cf_opt.max_compaction_bytes, 21);
  238. ASSERT_EQ(new_cf_opt.hard_pending_compaction_bytes_limit, 211);
  239. ASSERT_EQ(new_cf_opt.arena_block_size, 22U);
  240. ASSERT_EQ(new_cf_opt.disable_auto_compactions, true);
  241. ASSERT_EQ(new_cf_opt.compaction_style, kCompactionStyleLevel);
  242. ASSERT_EQ(new_cf_opt.compaction_pri, kOldestSmallestSeqFirst);
  243. ASSERT_EQ(new_cf_opt.compaction_options_fifo.max_table_files_size,
  244. static_cast<uint64_t>(11002244));
  245. ASSERT_EQ(new_cf_opt.compaction_options_fifo.allow_compaction, true);
  246. ASSERT_EQ(
  247. new_cf_opt.compaction_options_fifo.file_temperature_age_thresholds.size(),
  248. 1);
  249. ASSERT_EQ(
  250. new_cf_opt.compaction_options_fifo.file_temperature_age_thresholds[0]
  251. .temperature,
  252. Temperature::kCold);
  253. ASSERT_EQ(
  254. new_cf_opt.compaction_options_fifo.file_temperature_age_thresholds[0].age,
  255. 12345);
  256. ASSERT_EQ(new_cf_opt.max_sequential_skip_in_iterations,
  257. static_cast<uint64_t>(24));
  258. ASSERT_EQ(new_cf_opt.inplace_update_support, true);
  259. ASSERT_EQ(new_cf_opt.inplace_update_num_locks, 25U);
  260. ASSERT_EQ(new_cf_opt.memtable_prefix_bloom_size_ratio, 0.26);
  261. ASSERT_EQ(new_cf_opt.memtable_whole_key_filtering, true);
  262. ASSERT_EQ(new_cf_opt.memtable_huge_page_size, 28U);
  263. ASSERT_EQ(new_cf_opt.bloom_locality, 29U);
  264. ASSERT_EQ(new_cf_opt.max_successive_merges, 30U);
  265. ASSERT_EQ(new_cf_opt.strict_max_successive_merges, true);
  266. ASSERT_TRUE(new_cf_opt.prefix_extractor != nullptr);
  267. ASSERT_EQ(new_cf_opt.optimize_filters_for_hits, true);
  268. ASSERT_EQ(new_cf_opt.prefix_extractor->AsString(), "rocksdb.FixedPrefix.31");
  269. ASSERT_EQ(new_cf_opt.experimental_mempurge_threshold, 0.003);
  270. ASSERT_EQ(new_cf_opt.enable_blob_files, true);
  271. ASSERT_EQ(new_cf_opt.min_blob_size, 1ULL << 10);
  272. ASSERT_EQ(new_cf_opt.blob_file_size, 1ULL << 30);
  273. ASSERT_EQ(new_cf_opt.blob_compression_type, kZSTD);
  274. ASSERT_EQ(new_cf_opt.enable_blob_garbage_collection, true);
  275. ASSERT_EQ(new_cf_opt.blob_garbage_collection_age_cutoff, 0.5);
  276. ASSERT_EQ(new_cf_opt.blob_garbage_collection_force_threshold, 0.75);
  277. ASSERT_EQ(new_cf_opt.blob_compaction_readahead_size, 262144);
  278. ASSERT_EQ(new_cf_opt.blob_file_starting_level, 1);
  279. ASSERT_EQ(new_cf_opt.prepopulate_blob_cache, PrepopulateBlobCache::kDisable);
  280. ASSERT_EQ(new_cf_opt.last_level_temperature, Temperature::kWarm);
  281. ASSERT_EQ(new_cf_opt.default_write_temperature, Temperature::kCold);
  282. ASSERT_EQ(new_cf_opt.default_temperature, Temperature::kHot);
  283. ASSERT_EQ(new_cf_opt.persist_user_defined_timestamps, true);
  284. ASSERT_EQ(new_cf_opt.memtable_max_range_deletions, 0);
  285. cf_options_map["write_buffer_size"] = "hello";
  286. ASSERT_NOK(GetColumnFamilyOptionsFromMap(exact, base_cf_opt, cf_options_map,
  287. &new_cf_opt));
  288. ASSERT_OK(
  289. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  290. cf_options_map["write_buffer_size"] = "1";
  291. ASSERT_OK(GetColumnFamilyOptionsFromMap(exact, base_cf_opt, cf_options_map,
  292. &new_cf_opt));
  293. cf_options_map["unknown_option"] = "1";
  294. ASSERT_NOK(GetColumnFamilyOptionsFromMap(exact, base_cf_opt, cf_options_map,
  295. &new_cf_opt));
  296. ASSERT_OK(
  297. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  298. // ignore_unknown_options=true;input_strings_escaped=false
  299. ASSERT_OK(GetColumnFamilyOptionsFromMap(loose, base_cf_opt, cf_options_map,
  300. &new_cf_opt));
  301. ASSERT_OK(
  302. RocksDBOptionsParser::VerifyCFOptions(loose, base_cf_opt, new_cf_opt));
  303. ASSERT_NOK(
  304. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  305. DBOptions base_db_opt;
  306. DBOptions new_db_opt;
  307. ASSERT_OK(
  308. GetDBOptionsFromMap(exact, base_db_opt, db_options_map, &new_db_opt));
  309. ASSERT_EQ(new_db_opt.create_if_missing, false);
  310. ASSERT_EQ(new_db_opt.create_missing_column_families, true);
  311. ASSERT_EQ(new_db_opt.error_if_exists, false);
  312. ASSERT_EQ(new_db_opt.paranoid_checks, true);
  313. ASSERT_EQ(new_db_opt.track_and_verify_wals_in_manifest, true);
  314. ASSERT_EQ(new_db_opt.track_and_verify_wals, true);
  315. ASSERT_EQ(new_db_opt.verify_sst_unique_id_in_manifest, true);
  316. ASSERT_EQ(new_db_opt.max_open_files, 32);
  317. ASSERT_EQ(new_db_opt.max_total_wal_size, static_cast<uint64_t>(33));
  318. ASSERT_EQ(new_db_opt.use_fsync, true);
  319. ASSERT_EQ(new_db_opt.db_log_dir, "/db_log_dir");
  320. ASSERT_EQ(new_db_opt.wal_dir, "/wal_dir");
  321. ASSERT_EQ(new_db_opt.delete_obsolete_files_period_micros,
  322. static_cast<uint64_t>(34));
  323. ASSERT_EQ(new_db_opt.max_background_compactions, 35);
  324. ASSERT_EQ(new_db_opt.max_background_flushes, 36);
  325. ASSERT_EQ(new_db_opt.max_log_file_size, 37U);
  326. ASSERT_EQ(new_db_opt.log_file_time_to_roll, 38U);
  327. ASSERT_EQ(new_db_opt.keep_log_file_num, 39U);
  328. ASSERT_EQ(new_db_opt.recycle_log_file_num, 5U);
  329. ASSERT_EQ(new_db_opt.max_manifest_file_size, static_cast<uint64_t>(40));
  330. ASSERT_EQ(new_db_opt.table_cache_numshardbits, 41);
  331. ASSERT_EQ(new_db_opt.WAL_ttl_seconds, static_cast<uint64_t>(43));
  332. ASSERT_EQ(new_db_opt.WAL_size_limit_MB, static_cast<uint64_t>(44));
  333. ASSERT_EQ(new_db_opt.manifest_preallocation_size, 45U);
  334. ASSERT_EQ(new_db_opt.allow_mmap_reads, true);
  335. ASSERT_EQ(new_db_opt.allow_mmap_writes, false);
  336. ASSERT_EQ(new_db_opt.use_direct_reads, false);
  337. ASSERT_EQ(new_db_opt.use_direct_io_for_flush_and_compaction, false);
  338. ASSERT_EQ(new_db_opt.is_fd_close_on_exec, true);
  339. ASSERT_EQ(new_db_opt.stats_dump_period_sec, 46U);
  340. ASSERT_EQ(new_db_opt.stats_persist_period_sec, 57U);
  341. ASSERT_EQ(new_db_opt.persist_stats_to_disk, false);
  342. ASSERT_EQ(new_db_opt.stats_history_buffer_size, 69U);
  343. ASSERT_EQ(new_db_opt.advise_random_on_open, true);
  344. ASSERT_EQ(new_db_opt.use_adaptive_mutex, false);
  345. ASSERT_EQ(new_db_opt.compaction_readahead_size, 100);
  346. ASSERT_EQ(new_db_opt.writable_file_max_buffer_size, 314159);
  347. ASSERT_EQ(new_db_opt.bytes_per_sync, static_cast<uint64_t>(47));
  348. ASSERT_EQ(new_db_opt.wal_bytes_per_sync, static_cast<uint64_t>(48));
  349. ASSERT_EQ(new_db_opt.strict_bytes_per_sync, true);
  350. ASSERT_EQ(new_db_opt.daily_offpeak_time_utc, "");
  351. db_options_map["max_open_files"] = "hello";
  352. Status s =
  353. GetDBOptionsFromMap(exact, base_db_opt, db_options_map, &new_db_opt);
  354. ASSERT_NOK(s);
  355. ASSERT_TRUE(s.IsInvalidArgument());
  356. ASSERT_OK(
  357. RocksDBOptionsParser::VerifyDBOptions(exact, base_db_opt, new_db_opt));
  358. ASSERT_OK(
  359. RocksDBOptionsParser::VerifyDBOptions(loose, base_db_opt, new_db_opt));
  360. // unknow options should fail parsing without ignore_unknown_options = true
  361. db_options_map["unknown_db_option"] = "1";
  362. s = GetDBOptionsFromMap(exact, base_db_opt, db_options_map, &new_db_opt);
  363. ASSERT_NOK(s);
  364. ASSERT_TRUE(s.IsInvalidArgument());
  365. ASSERT_OK(
  366. RocksDBOptionsParser::VerifyDBOptions(exact, base_db_opt, new_db_opt));
  367. ASSERT_OK(
  368. GetDBOptionsFromMap(loose, base_db_opt, db_options_map, &new_db_opt));
  369. ASSERT_OK(
  370. RocksDBOptionsParser::VerifyDBOptions(loose, base_db_opt, new_db_opt));
  371. ASSERT_NOK(
  372. RocksDBOptionsParser::VerifyDBOptions(exact, base_db_opt, new_db_opt));
  373. }
  374. TEST_F(OptionsTest, GetColumnFamilyOptionsFromStringTest) {
  375. ColumnFamilyOptions base_cf_opt;
  376. ColumnFamilyOptions new_cf_opt;
  377. ConfigOptions config_options;
  378. config_options.input_strings_escaped = false;
  379. config_options.ignore_unknown_options = false;
  380. base_cf_opt.table_factory.reset();
  381. ASSERT_OK(GetColumnFamilyOptionsFromString(config_options, base_cf_opt, "",
  382. &new_cf_opt));
  383. ASSERT_OK(GetColumnFamilyOptionsFromString(
  384. config_options, base_cf_opt, "write_buffer_size=5", &new_cf_opt));
  385. ASSERT_EQ(new_cf_opt.write_buffer_size, 5U);
  386. ASSERT_TRUE(new_cf_opt.table_factory == nullptr);
  387. ASSERT_OK(GetColumnFamilyOptionsFromString(
  388. config_options, base_cf_opt, "write_buffer_size=6;", &new_cf_opt));
  389. ASSERT_EQ(new_cf_opt.write_buffer_size, 6U);
  390. ASSERT_OK(GetColumnFamilyOptionsFromString(
  391. config_options, base_cf_opt, " write_buffer_size = 7 ", &new_cf_opt));
  392. ASSERT_EQ(new_cf_opt.write_buffer_size, 7U);
  393. ASSERT_OK(GetColumnFamilyOptionsFromString(
  394. config_options, base_cf_opt, " write_buffer_size = 8 ; ", &new_cf_opt));
  395. ASSERT_EQ(new_cf_opt.write_buffer_size, 8U);
  396. ASSERT_OK(GetColumnFamilyOptionsFromString(
  397. config_options, base_cf_opt,
  398. "write_buffer_size=9;max_write_buffer_number=10", &new_cf_opt));
  399. ASSERT_EQ(new_cf_opt.write_buffer_size, 9U);
  400. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 10);
  401. ASSERT_OK(GetColumnFamilyOptionsFromString(
  402. config_options, base_cf_opt,
  403. "write_buffer_size=11; max_write_buffer_number = 12 ;", &new_cf_opt));
  404. ASSERT_EQ(new_cf_opt.write_buffer_size, 11U);
  405. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 12);
  406. // Wrong name "max_write_buffer_number_"
  407. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  408. config_options, base_cf_opt,
  409. "write_buffer_size=13;max_write_buffer_number_=14;", &new_cf_opt));
  410. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base_cf_opt,
  411. new_cf_opt));
  412. // Comparator from object registry
  413. std::string kCompName = "reverse_comp";
  414. ObjectLibrary::Default()->AddFactory<const Comparator>(
  415. kCompName,
  416. [](const std::string& /*name*/,
  417. std::unique_ptr<const Comparator>* /*guard*/,
  418. std::string* /* errmsg */) { return ReverseBytewiseComparator(); });
  419. ASSERT_OK(GetColumnFamilyOptionsFromString(config_options, base_cf_opt,
  420. "comparator=" + kCompName + ";",
  421. &new_cf_opt));
  422. ASSERT_EQ(new_cf_opt.comparator, ReverseBytewiseComparator());
  423. // MergeOperator from object registry
  424. std::unique_ptr<BytesXOROperator> bxo(new BytesXOROperator());
  425. std::string kMoName = bxo->Name();
  426. ASSERT_OK(GetColumnFamilyOptionsFromString(config_options, base_cf_opt,
  427. "merge_operator=" + kMoName + ";",
  428. &new_cf_opt));
  429. ASSERT_EQ(kMoName, std::string(new_cf_opt.merge_operator->Name()));
  430. // Wrong key/value pair
  431. Status s = GetColumnFamilyOptionsFromString(
  432. config_options, base_cf_opt,
  433. "write_buffer_size=13;max_write_buffer_number;", &new_cf_opt);
  434. ASSERT_NOK(s);
  435. ASSERT_TRUE(s.IsInvalidArgument());
  436. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base_cf_opt,
  437. new_cf_opt));
  438. // Error Parsing value
  439. s = GetColumnFamilyOptionsFromString(
  440. config_options, base_cf_opt,
  441. "write_buffer_size=13;max_write_buffer_number=;", &new_cf_opt);
  442. ASSERT_NOK(s);
  443. ASSERT_TRUE(s.IsInvalidArgument());
  444. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base_cf_opt,
  445. new_cf_opt));
  446. // Missing option name
  447. s = GetColumnFamilyOptionsFromString(
  448. config_options, base_cf_opt, "write_buffer_size=13; =100;", &new_cf_opt);
  449. ASSERT_NOK(s);
  450. ASSERT_TRUE(s.IsInvalidArgument());
  451. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base_cf_opt,
  452. new_cf_opt));
  453. const uint64_t kilo = 1024UL;
  454. const uint64_t mega = 1024 * kilo;
  455. const uint64_t giga = 1024 * mega;
  456. const uint64_t tera = 1024 * giga;
  457. // Units (k)
  458. ASSERT_OK(GetColumnFamilyOptionsFromString(
  459. config_options, base_cf_opt, "max_write_buffer_number=15K", &new_cf_opt));
  460. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 15 * kilo);
  461. // Units (m)
  462. ASSERT_OK(GetColumnFamilyOptionsFromString(
  463. config_options, base_cf_opt,
  464. "max_write_buffer_number=16m;inplace_update_num_locks=17M", &new_cf_opt));
  465. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 16 * mega);
  466. ASSERT_EQ(new_cf_opt.inplace_update_num_locks, 17u * mega);
  467. // Units (g)
  468. ASSERT_OK(GetColumnFamilyOptionsFromString(
  469. config_options, base_cf_opt,
  470. "write_buffer_size=18g;prefix_extractor=capped:8;"
  471. "arena_block_size=19G",
  472. &new_cf_opt));
  473. ASSERT_EQ(new_cf_opt.write_buffer_size, 18 * giga);
  474. ASSERT_EQ(new_cf_opt.arena_block_size, 19 * giga);
  475. ASSERT_TRUE(new_cf_opt.prefix_extractor.get() != nullptr);
  476. ASSERT_EQ(new_cf_opt.prefix_extractor->AsString(), "rocksdb.CappedPrefix.8");
  477. // Units (t)
  478. ASSERT_OK(GetColumnFamilyOptionsFromString(
  479. config_options, base_cf_opt, "write_buffer_size=20t;arena_block_size=21T",
  480. &new_cf_opt));
  481. ASSERT_EQ(new_cf_opt.write_buffer_size, 20 * tera);
  482. ASSERT_EQ(new_cf_opt.arena_block_size, 21 * tera);
  483. // Nested block based table options
  484. // Empty
  485. ASSERT_OK(GetColumnFamilyOptionsFromString(
  486. config_options, base_cf_opt,
  487. "write_buffer_size=10;max_write_buffer_number=16;"
  488. "block_based_table_factory={};arena_block_size=1024",
  489. &new_cf_opt));
  490. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  491. // Non-empty
  492. ASSERT_OK(GetColumnFamilyOptionsFromString(
  493. config_options, base_cf_opt,
  494. "write_buffer_size=10;max_write_buffer_number=16;"
  495. "block_based_table_factory={block_cache=1M;block_size=4;};"
  496. "arena_block_size=1024",
  497. &new_cf_opt));
  498. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  499. // Last one
  500. ASSERT_OK(GetColumnFamilyOptionsFromString(
  501. config_options, base_cf_opt,
  502. "write_buffer_size=10;max_write_buffer_number=16;"
  503. "block_based_table_factory={block_cache=1M;block_size=4;}",
  504. &new_cf_opt));
  505. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  506. // Mismatch curly braces
  507. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  508. config_options, base_cf_opt,
  509. "write_buffer_size=10;max_write_buffer_number=16;"
  510. "block_based_table_factory={{{block_size=4;};"
  511. "arena_block_size=1024",
  512. &new_cf_opt));
  513. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base_cf_opt,
  514. new_cf_opt));
  515. // Unexpected chars after closing curly brace
  516. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  517. config_options, base_cf_opt,
  518. "write_buffer_size=10;max_write_buffer_number=16;"
  519. "block_based_table_factory={block_size=4;}};"
  520. "arena_block_size=1024",
  521. &new_cf_opt));
  522. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base_cf_opt,
  523. new_cf_opt));
  524. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  525. config_options, base_cf_opt,
  526. "write_buffer_size=10;max_write_buffer_number=16;"
  527. "block_based_table_factory={block_size=4;}xdfa;"
  528. "arena_block_size=1024",
  529. &new_cf_opt));
  530. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base_cf_opt,
  531. new_cf_opt));
  532. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  533. config_options, base_cf_opt,
  534. "write_buffer_size=10;max_write_buffer_number=16;"
  535. "block_based_table_factory={block_size=4;}xdfa",
  536. &new_cf_opt));
  537. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base_cf_opt,
  538. new_cf_opt));
  539. // Invalid block based table option
  540. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  541. config_options, base_cf_opt,
  542. "write_buffer_size=10;max_write_buffer_number=16;"
  543. "block_based_table_factory={xx_block_size=4;}",
  544. &new_cf_opt));
  545. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base_cf_opt,
  546. new_cf_opt));
  547. ASSERT_OK(GetColumnFamilyOptionsFromString(config_options, base_cf_opt,
  548. "optimize_filters_for_hits=true",
  549. &new_cf_opt));
  550. ASSERT_OK(GetColumnFamilyOptionsFromString(config_options, base_cf_opt,
  551. "optimize_filters_for_hits=false",
  552. &new_cf_opt));
  553. ASSERT_NOK(GetColumnFamilyOptionsFromString(config_options, base_cf_opt,
  554. "optimize_filters_for_hits=junk",
  555. &new_cf_opt));
  556. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base_cf_opt,
  557. new_cf_opt));
  558. // Nested plain table options
  559. // Empty
  560. ASSERT_OK(GetColumnFamilyOptionsFromString(
  561. config_options, base_cf_opt,
  562. "write_buffer_size=10;max_write_buffer_number=16;"
  563. "plain_table_factory={};arena_block_size=1024",
  564. &new_cf_opt));
  565. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  566. ASSERT_EQ(std::string(new_cf_opt.table_factory->Name()), "PlainTable");
  567. // Non-empty
  568. ASSERT_OK(GetColumnFamilyOptionsFromString(
  569. config_options, base_cf_opt,
  570. "write_buffer_size=10;max_write_buffer_number=16;"
  571. "plain_table_factory={user_key_len=66;bloom_bits_per_key=20;};"
  572. "arena_block_size=1024",
  573. &new_cf_opt));
  574. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  575. ASSERT_EQ(std::string(new_cf_opt.table_factory->Name()), "PlainTable");
  576. // memtable factory
  577. ASSERT_OK(GetColumnFamilyOptionsFromString(
  578. config_options, base_cf_opt,
  579. "write_buffer_size=10;max_write_buffer_number=16;"
  580. "memtable=skip_list:10;arena_block_size=1024",
  581. &new_cf_opt));
  582. ASSERT_TRUE(new_cf_opt.memtable_factory != nullptr);
  583. ASSERT_EQ(std::string(new_cf_opt.memtable_factory->Name()),
  584. "SkipListFactory");
  585. ASSERT_TRUE(new_cf_opt.memtable_factory->IsInstanceOf("SkipListFactory"));
  586. // blob cache
  587. ASSERT_OK(GetColumnFamilyOptionsFromString(
  588. config_options, base_cf_opt,
  589. "blob_cache={capacity=1M;num_shard_bits=4;"
  590. "strict_capacity_limit=true;high_pri_pool_ratio=0.5;};",
  591. &new_cf_opt));
  592. ASSERT_NE(new_cf_opt.blob_cache, nullptr);
  593. ASSERT_EQ(new_cf_opt.blob_cache->GetCapacity(), 1024UL * 1024UL);
  594. ASSERT_EQ(static_cast<ShardedCacheBase*>(new_cf_opt.blob_cache.get())
  595. ->GetNumShardBits(),
  596. 4);
  597. ASSERT_EQ(new_cf_opt.blob_cache->HasStrictCapacityLimit(), true);
  598. ASSERT_EQ(static_cast<LRUCache*>(new_cf_opt.blob_cache.get())
  599. ->GetHighPriPoolRatio(),
  600. 0.5);
  601. }
  602. TEST_F(OptionsTest, CompressionOptionsFromString) {
  603. ColumnFamilyOptions base_cf_opt;
  604. ColumnFamilyOptions new_cf_opt;
  605. ConfigOptions config_options;
  606. std::string opts_str;
  607. config_options.ignore_unknown_options = false;
  608. CompressionOptions dflt;
  609. // Test with some optional values removed....
  610. ASSERT_OK(
  611. GetColumnFamilyOptionsFromString(config_options, ColumnFamilyOptions(),
  612. "compression_opts=3:4:5; "
  613. "bottommost_compression_opts=4:5:6:7",
  614. &base_cf_opt));
  615. ASSERT_EQ(base_cf_opt.compression_opts.window_bits, 3);
  616. ASSERT_EQ(base_cf_opt.compression_opts.level, 4);
  617. ASSERT_EQ(base_cf_opt.compression_opts.strategy, 5);
  618. ASSERT_EQ(base_cf_opt.compression_opts.max_dict_bytes, dflt.max_dict_bytes);
  619. ASSERT_EQ(base_cf_opt.compression_opts.zstd_max_train_bytes,
  620. dflt.zstd_max_train_bytes);
  621. ASSERT_EQ(base_cf_opt.compression_opts.parallel_threads,
  622. dflt.parallel_threads);
  623. ASSERT_EQ(base_cf_opt.compression_opts.enabled, dflt.enabled);
  624. ASSERT_EQ(base_cf_opt.compression_opts.use_zstd_dict_trainer,
  625. dflt.use_zstd_dict_trainer);
  626. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.window_bits, 4);
  627. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.level, 5);
  628. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.strategy, 6);
  629. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.max_dict_bytes, 7u);
  630. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.zstd_max_train_bytes,
  631. dflt.zstd_max_train_bytes);
  632. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.parallel_threads,
  633. dflt.parallel_threads);
  634. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.enabled, dflt.enabled);
  635. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.use_zstd_dict_trainer,
  636. dflt.use_zstd_dict_trainer);
  637. ASSERT_OK(GetColumnFamilyOptionsFromString(
  638. config_options, ColumnFamilyOptions(),
  639. "compression_opts=4:5:6:7:8:9:true:10:false; "
  640. "bottommost_compression_opts=5:6:7:8:9:false",
  641. &base_cf_opt));
  642. ASSERT_EQ(base_cf_opt.compression_opts.window_bits, 4);
  643. ASSERT_EQ(base_cf_opt.compression_opts.level, 5);
  644. ASSERT_EQ(base_cf_opt.compression_opts.strategy, 6);
  645. ASSERT_EQ(base_cf_opt.compression_opts.max_dict_bytes, 7u);
  646. ASSERT_EQ(base_cf_opt.compression_opts.zstd_max_train_bytes, 8u);
  647. ASSERT_EQ(base_cf_opt.compression_opts.parallel_threads, 9u);
  648. ASSERT_EQ(base_cf_opt.compression_opts.enabled, true);
  649. ASSERT_EQ(base_cf_opt.compression_opts.max_dict_buffer_bytes, 10u);
  650. ASSERT_EQ(base_cf_opt.compression_opts.use_zstd_dict_trainer, false);
  651. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.window_bits, 5);
  652. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.level, 6);
  653. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.strategy, 7);
  654. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.max_dict_bytes, 8u);
  655. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.zstd_max_train_bytes, 9u);
  656. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.parallel_threads,
  657. dflt.parallel_threads);
  658. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.enabled, false);
  659. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.use_zstd_dict_trainer,
  660. dflt.use_zstd_dict_trainer);
  661. ASSERT_OK(
  662. GetStringFromColumnFamilyOptions(config_options, base_cf_opt, &opts_str));
  663. ASSERT_OK(GetColumnFamilyOptionsFromString(
  664. config_options, ColumnFamilyOptions(), opts_str, &new_cf_opt));
  665. ASSERT_EQ(new_cf_opt.compression_opts.window_bits, 4);
  666. ASSERT_EQ(new_cf_opt.compression_opts.level, 5);
  667. ASSERT_EQ(new_cf_opt.compression_opts.strategy, 6);
  668. ASSERT_EQ(new_cf_opt.compression_opts.max_dict_bytes, 7u);
  669. ASSERT_EQ(new_cf_opt.compression_opts.zstd_max_train_bytes, 8u);
  670. ASSERT_EQ(new_cf_opt.compression_opts.parallel_threads, 9u);
  671. ASSERT_EQ(new_cf_opt.compression_opts.enabled, true);
  672. ASSERT_EQ(base_cf_opt.compression_opts.max_dict_buffer_bytes, 10u);
  673. ASSERT_EQ(base_cf_opt.compression_opts.use_zstd_dict_trainer, false);
  674. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.window_bits, 5);
  675. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.level, 6);
  676. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.strategy, 7);
  677. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.max_dict_bytes, 8u);
  678. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.zstd_max_train_bytes, 9u);
  679. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.parallel_threads,
  680. dflt.parallel_threads);
  681. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.enabled, false);
  682. ASSERT_EQ(base_cf_opt.bottommost_compression_opts.use_zstd_dict_trainer,
  683. dflt.use_zstd_dict_trainer);
  684. // Test as struct values
  685. ASSERT_OK(GetColumnFamilyOptionsFromString(
  686. config_options, ColumnFamilyOptions(),
  687. "compression_opts={window_bits=5; level=6; strategy=7; max_dict_bytes=8;"
  688. "zstd_max_train_bytes=9;parallel_threads=10;enabled=true;use_zstd_dict_"
  689. "trainer=false}; "
  690. "bottommost_compression_opts={window_bits=4; level=5; strategy=6;"
  691. " max_dict_bytes=7;zstd_max_train_bytes=8;parallel_threads=9;"
  692. "enabled=false;use_zstd_dict_trainer=true}; ",
  693. &new_cf_opt));
  694. ASSERT_EQ(new_cf_opt.compression_opts.window_bits, 5);
  695. ASSERT_EQ(new_cf_opt.compression_opts.level, 6);
  696. ASSERT_EQ(new_cf_opt.compression_opts.strategy, 7);
  697. ASSERT_EQ(new_cf_opt.compression_opts.max_dict_bytes, 8u);
  698. ASSERT_EQ(new_cf_opt.compression_opts.zstd_max_train_bytes, 9u);
  699. ASSERT_EQ(new_cf_opt.compression_opts.parallel_threads, 10u);
  700. ASSERT_EQ(new_cf_opt.compression_opts.enabled, true);
  701. ASSERT_EQ(new_cf_opt.compression_opts.use_zstd_dict_trainer, false);
  702. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.window_bits, 4);
  703. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.level, 5);
  704. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.strategy, 6);
  705. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.max_dict_bytes, 7u);
  706. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.zstd_max_train_bytes, 8u);
  707. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.parallel_threads, 9u);
  708. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.enabled, false);
  709. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.use_zstd_dict_trainer, true);
  710. ASSERT_OK(GetColumnFamilyOptionsFromString(
  711. config_options, base_cf_opt,
  712. "compression_opts={window_bits=4; strategy=5;};"
  713. "bottommost_compression_opts={level=6; strategy=7;}",
  714. &new_cf_opt));
  715. ASSERT_EQ(new_cf_opt.compression_opts.window_bits, 4);
  716. ASSERT_EQ(new_cf_opt.compression_opts.strategy, 5);
  717. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.level, 6);
  718. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.strategy, 7);
  719. ASSERT_EQ(new_cf_opt.compression_opts.level,
  720. base_cf_opt.compression_opts.level);
  721. ASSERT_EQ(new_cf_opt.compression_opts.max_dict_bytes,
  722. base_cf_opt.compression_opts.max_dict_bytes);
  723. ASSERT_EQ(new_cf_opt.compression_opts.zstd_max_train_bytes,
  724. base_cf_opt.compression_opts.zstd_max_train_bytes);
  725. ASSERT_EQ(new_cf_opt.compression_opts.parallel_threads,
  726. base_cf_opt.compression_opts.parallel_threads);
  727. ASSERT_EQ(new_cf_opt.compression_opts.enabled,
  728. base_cf_opt.compression_opts.enabled);
  729. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.window_bits,
  730. base_cf_opt.bottommost_compression_opts.window_bits);
  731. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.max_dict_bytes,
  732. base_cf_opt.bottommost_compression_opts.max_dict_bytes);
  733. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.zstd_max_train_bytes,
  734. base_cf_opt.bottommost_compression_opts.zstd_max_train_bytes);
  735. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.parallel_threads,
  736. base_cf_opt.bottommost_compression_opts.parallel_threads);
  737. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.enabled,
  738. base_cf_opt.bottommost_compression_opts.enabled);
  739. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.use_zstd_dict_trainer,
  740. base_cf_opt.bottommost_compression_opts.use_zstd_dict_trainer);
  741. // Test a few individual struct values
  742. ASSERT_OK(GetColumnFamilyOptionsFromString(
  743. config_options, base_cf_opt,
  744. "compression_opts.enabled=false; "
  745. "bottommost_compression_opts.enabled=true; ",
  746. &new_cf_opt));
  747. ASSERT_EQ(new_cf_opt.compression_opts.enabled, false);
  748. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.enabled, true);
  749. // Now test some illegal values
  750. ConfigOptions ignore;
  751. ignore.ignore_unknown_options = true;
  752. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  753. config_options, ColumnFamilyOptions(),
  754. "compression_opts=5:6:7:8:9:x:false", &base_cf_opt));
  755. ASSERT_OK(GetColumnFamilyOptionsFromString(
  756. ignore, ColumnFamilyOptions(), "compression_opts=5:6:7:8:9:x:false",
  757. &base_cf_opt));
  758. ASSERT_OK(GetColumnFamilyOptionsFromString(
  759. config_options, ColumnFamilyOptions(),
  760. "compression_opts=1:2:3:4:5:6:true:8", &base_cf_opt));
  761. ASSERT_OK(GetColumnFamilyOptionsFromString(
  762. ignore, ColumnFamilyOptions(), "compression_opts=1:2:3:4:5:6:true:8",
  763. &base_cf_opt));
  764. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  765. config_options, ColumnFamilyOptions(),
  766. "compression_opts=1:2:3:4:5:6:true:8:9", &base_cf_opt));
  767. ASSERT_OK(GetColumnFamilyOptionsFromString(
  768. ignore, ColumnFamilyOptions(), "compression_opts=1:2:3:4:5:6:true:8:9",
  769. &base_cf_opt));
  770. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  771. config_options, ColumnFamilyOptions(), "compression_opts={unknown=bad;}",
  772. &base_cf_opt));
  773. ASSERT_OK(GetColumnFamilyOptionsFromString(ignore, ColumnFamilyOptions(),
  774. "compression_opts={unknown=bad;}",
  775. &base_cf_opt));
  776. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  777. config_options, ColumnFamilyOptions(), "compression_opts.unknown=bad",
  778. &base_cf_opt));
  779. ASSERT_OK(GetColumnFamilyOptionsFromString(ignore, ColumnFamilyOptions(),
  780. "compression_opts.unknown=bad",
  781. &base_cf_opt));
  782. // Test with some additional values added
  783. config_options.ignore_unknown_options = false;
  784. ASSERT_NOK(
  785. GetColumnFamilyOptionsFromString(config_options, ColumnFamilyOptions(),
  786. "new_unknown_field=whatever; "
  787. "bottommost_compression_opts=4:5:6:7",
  788. &base_cf_opt));
  789. // Test Ignoring Unknown Options
  790. config_options.ignore_unknown_options = true;
  791. ASSERT_OK(
  792. GetColumnFamilyOptionsFromString(config_options, ColumnFamilyOptions(),
  793. "new_unknown_field=whatever; "
  794. "bottommost_compression_opts=4:5:6:7",
  795. &base_cf_opt));
  796. }
  797. TEST_F(OptionsTest, OldInterfaceTest) {
  798. ColumnFamilyOptions base_cf_opt;
  799. ColumnFamilyOptions new_cf_opt;
  800. ConfigOptions exact;
  801. ConfigOptions cf_config_options;
  802. cf_config_options.input_strings_escaped = false;
  803. cf_config_options.ignore_unknown_options = false;
  804. ASSERT_OK(GetColumnFamilyOptionsFromString(
  805. cf_config_options, base_cf_opt,
  806. "write_buffer_size=18;prefix_extractor=capped:8;"
  807. "arena_block_size=19",
  808. &new_cf_opt));
  809. ASSERT_EQ(new_cf_opt.write_buffer_size, 18);
  810. ASSERT_EQ(new_cf_opt.arena_block_size, 19);
  811. ASSERT_TRUE(new_cf_opt.prefix_extractor.get() != nullptr);
  812. // And with a bad option
  813. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  814. cf_config_options, base_cf_opt,
  815. "write_buffer_size=10;max_write_buffer_number=16;"
  816. "block_based_table_factory={xx_block_size=4;}",
  817. &new_cf_opt));
  818. ASSERT_OK(
  819. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  820. std::unordered_map<std::string, std::string> cf_options_map = {
  821. {"write_buffer_size", "1"},
  822. {"max_write_buffer_number", "2"},
  823. {"min_write_buffer_number_to_merge", "3"},
  824. };
  825. ASSERT_OK(GetColumnFamilyOptionsFromMap(cf_config_options, base_cf_opt,
  826. cf_options_map, &new_cf_opt));
  827. cf_options_map["unknown_option"] = "1";
  828. ASSERT_NOK(GetColumnFamilyOptionsFromMap(cf_config_options, base_cf_opt,
  829. cf_options_map, &new_cf_opt));
  830. ASSERT_OK(
  831. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  832. cf_config_options.input_strings_escaped = true;
  833. cf_config_options.ignore_unknown_options = true;
  834. ASSERT_OK(GetColumnFamilyOptionsFromMap(cf_config_options, base_cf_opt,
  835. cf_options_map, &new_cf_opt));
  836. DBOptions base_db_opt;
  837. DBOptions new_db_opt;
  838. std::unordered_map<std::string, std::string> db_options_map = {
  839. {"create_if_missing", "false"},
  840. {"create_missing_column_families", "true"},
  841. {"error_if_exists", "false"},
  842. {"paranoid_checks", "true"},
  843. {"track_and_verify_wals_in_manifest", "true"},
  844. {"track_and_verify_wals", "true"},
  845. {"verify_sst_unique_id_in_manifest", "true"},
  846. {"max_open_files", "32"},
  847. {"daily_offpeak_time_utc", "06:30-23:30"},
  848. };
  849. ConfigOptions db_config_options(base_db_opt);
  850. db_config_options.input_strings_escaped = false;
  851. db_config_options.ignore_unknown_options = false;
  852. ASSERT_OK(GetDBOptionsFromMap(db_config_options, base_db_opt, db_options_map,
  853. &new_db_opt));
  854. ASSERT_EQ(new_db_opt.create_if_missing, false);
  855. ASSERT_EQ(new_db_opt.create_missing_column_families, true);
  856. ASSERT_EQ(new_db_opt.error_if_exists, false);
  857. ASSERT_EQ(new_db_opt.paranoid_checks, true);
  858. ASSERT_EQ(new_db_opt.track_and_verify_wals_in_manifest, true);
  859. ASSERT_EQ(new_db_opt.track_and_verify_wals, true);
  860. ASSERT_EQ(new_db_opt.verify_sst_unique_id_in_manifest, true);
  861. ASSERT_EQ(new_db_opt.max_open_files, 32);
  862. db_options_map["unknown_option"] = "1";
  863. Status s = GetDBOptionsFromMap(db_config_options, base_db_opt, db_options_map,
  864. &new_db_opt);
  865. ASSERT_NOK(s);
  866. ASSERT_TRUE(s.IsInvalidArgument());
  867. ASSERT_OK(
  868. RocksDBOptionsParser::VerifyDBOptions(exact, base_db_opt, new_db_opt));
  869. db_config_options.input_strings_escaped = true;
  870. db_config_options.ignore_unknown_options = true;
  871. ASSERT_OK(GetDBOptionsFromMap(db_config_options, base_db_opt, db_options_map,
  872. &new_db_opt));
  873. db_config_options.input_strings_escaped = false;
  874. db_config_options.ignore_unknown_options = false;
  875. ASSERT_OK(GetDBOptionsFromString(
  876. db_config_options, base_db_opt,
  877. "create_if_missing=false;error_if_exists=false;max_open_files=42;"
  878. "daily_offpeak_time_utc=08:30-19:00;",
  879. &new_db_opt));
  880. ASSERT_EQ(new_db_opt.create_if_missing, false);
  881. ASSERT_EQ(new_db_opt.error_if_exists, false);
  882. ASSERT_EQ(new_db_opt.max_open_files, 42);
  883. ASSERT_EQ(new_db_opt.daily_offpeak_time_utc, "08:30-19:00");
  884. s = GetDBOptionsFromString(
  885. db_config_options, base_db_opt,
  886. "create_if_missing=false;error_if_exists=false;max_open_files=42;"
  887. "unknown_option=1;",
  888. &new_db_opt);
  889. ASSERT_NOK(s);
  890. ASSERT_TRUE(s.IsInvalidArgument());
  891. ASSERT_OK(
  892. RocksDBOptionsParser::VerifyDBOptions(exact, base_db_opt, new_db_opt));
  893. }
  894. TEST_F(OptionsTest, GetBlockBasedTableOptionsFromString) {
  895. BlockBasedTableOptions table_opt;
  896. BlockBasedTableOptions new_opt;
  897. ConfigOptions config_options;
  898. config_options.input_strings_escaped = false;
  899. config_options.ignore_unknown_options = false;
  900. config_options.ignore_unsupported_options = false;
  901. // make sure default values are overwritten by something else
  902. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  903. config_options, table_opt,
  904. "cache_index_and_filter_blocks=1;index_type=kHashSearch;"
  905. "checksum=kxxHash;"
  906. "block_cache=1M;block_cache_compressed=1k;block_size=1024;"
  907. "block_size_deviation=8;block_restart_interval=4;"
  908. "format_version=5;whole_key_filtering=1;"
  909. "filter_policy=bloomfilter:4.567:false;detect_filter_construct_"
  910. "corruption=true;"
  911. // A bug caused read_amp_bytes_per_bit to be a large integer in OPTIONS
  912. // file generated by 6.10 to 6.14. Though bug is fixed in these releases,
  913. // we need to handle the case of loading OPTIONS file generated before the
  914. // fix.
  915. "read_amp_bytes_per_bit=17179869185;",
  916. &new_opt));
  917. ASSERT_TRUE(new_opt.cache_index_and_filter_blocks);
  918. ASSERT_EQ(new_opt.index_type, BlockBasedTableOptions::kHashSearch);
  919. ASSERT_EQ(new_opt.checksum, ChecksumType::kxxHash);
  920. ASSERT_TRUE(new_opt.block_cache != nullptr);
  921. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 1024UL * 1024UL);
  922. ASSERT_EQ(new_opt.block_size, 1024UL);
  923. ASSERT_EQ(new_opt.block_size_deviation, 8);
  924. ASSERT_EQ(new_opt.block_restart_interval, 4);
  925. ASSERT_EQ(new_opt.format_version, 5U);
  926. ASSERT_EQ(new_opt.whole_key_filtering, true);
  927. ASSERT_EQ(new_opt.detect_filter_construct_corruption, true);
  928. ASSERT_TRUE(new_opt.filter_policy != nullptr);
  929. auto bfp = new_opt.filter_policy->CheckedCast<BloomFilterPolicy>();
  930. ASSERT_NE(bfp, nullptr);
  931. EXPECT_EQ(bfp->GetMillibitsPerKey(), 4567);
  932. EXPECT_EQ(bfp->GetWholeBitsPerKey(), 5);
  933. // Verify that only the lower 32bits are stored in
  934. // new_opt.read_amp_bytes_per_bit.
  935. EXPECT_EQ(1U, new_opt.read_amp_bytes_per_bit);
  936. // unknown option
  937. Status s = GetBlockBasedTableOptionsFromString(
  938. config_options, table_opt,
  939. "cache_index_and_filter_blocks=1;index_type=kBinarySearch;"
  940. "bad_option=1",
  941. &new_opt);
  942. ASSERT_NOK(s);
  943. ASSERT_TRUE(s.IsInvalidArgument());
  944. ASSERT_EQ(static_cast<bool>(table_opt.cache_index_and_filter_blocks),
  945. new_opt.cache_index_and_filter_blocks);
  946. ASSERT_EQ(table_opt.index_type, new_opt.index_type);
  947. // unrecognized index type
  948. s = GetBlockBasedTableOptionsFromString(
  949. config_options, table_opt,
  950. "cache_index_and_filter_blocks=1;index_type=kBinarySearchXX", &new_opt);
  951. ASSERT_NOK(s);
  952. ASSERT_TRUE(s.IsInvalidArgument());
  953. ASSERT_EQ(table_opt.cache_index_and_filter_blocks,
  954. new_opt.cache_index_and_filter_blocks);
  955. ASSERT_EQ(table_opt.index_type, new_opt.index_type);
  956. // unrecognized checksum type
  957. ASSERT_NOK(GetBlockBasedTableOptionsFromString(
  958. config_options, table_opt,
  959. "cache_index_and_filter_blocks=1;checksum=kxxHashXX", &new_opt));
  960. ASSERT_EQ(table_opt.cache_index_and_filter_blocks,
  961. new_opt.cache_index_and_filter_blocks);
  962. ASSERT_EQ(table_opt.index_type, new_opt.index_type);
  963. // unrecognized filter policy name
  964. s = GetBlockBasedTableOptionsFromString(config_options, table_opt,
  965. "filter_policy=bloomfilterxx:4:true",
  966. &new_opt);
  967. ASSERT_NOK(s);
  968. ASSERT_TRUE(s.IsInvalidArgument());
  969. // missing bits per key
  970. s = GetBlockBasedTableOptionsFromString(
  971. config_options, table_opt, "filter_policy=bloomfilter", &new_opt);
  972. ASSERT_NOK(s);
  973. ASSERT_TRUE(s.IsInvalidArgument());
  974. // Used to be rejected, now accepted
  975. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  976. config_options, table_opt, "filter_policy=bloomfilter:4", &new_opt));
  977. bfp = dynamic_cast<const BloomFilterPolicy*>(new_opt.filter_policy.get());
  978. EXPECT_EQ(bfp->GetMillibitsPerKey(), 4000);
  979. EXPECT_EQ(bfp->GetWholeBitsPerKey(), 4);
  980. // use_block_based_builder=true now ignored in public API (same as false)
  981. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  982. config_options, table_opt, "filter_policy=bloomfilter:4:true", &new_opt));
  983. bfp = dynamic_cast<const BloomFilterPolicy*>(new_opt.filter_policy.get());
  984. EXPECT_EQ(bfp->GetMillibitsPerKey(), 4000);
  985. EXPECT_EQ(bfp->GetWholeBitsPerKey(), 4);
  986. // Test configuring using other internal names
  987. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  988. config_options, table_opt,
  989. "filter_policy=rocksdb.internal.LegacyBloomFilter:3", &new_opt));
  990. auto builtin =
  991. dynamic_cast<const BuiltinFilterPolicy*>(new_opt.filter_policy.get());
  992. EXPECT_EQ(builtin->GetId(), "rocksdb.internal.LegacyBloomFilter:3");
  993. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  994. config_options, table_opt,
  995. "filter_policy=rocksdb.internal.FastLocalBloomFilter:1.234", &new_opt));
  996. builtin =
  997. dynamic_cast<const BuiltinFilterPolicy*>(new_opt.filter_policy.get());
  998. EXPECT_EQ(builtin->GetId(), "rocksdb.internal.FastLocalBloomFilter:1.234");
  999. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  1000. config_options, table_opt,
  1001. "filter_policy=rocksdb.internal.Standard128RibbonFilter:1.234",
  1002. &new_opt));
  1003. builtin =
  1004. dynamic_cast<const BuiltinFilterPolicy*>(new_opt.filter_policy.get());
  1005. EXPECT_EQ(builtin->GetId(), "rocksdb.internal.Standard128RibbonFilter:1.234");
  1006. // Ribbon filter policy (no Bloom hybrid)
  1007. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  1008. config_options, table_opt, "filter_policy=ribbonfilter:5.678:-1;",
  1009. &new_opt));
  1010. ASSERT_TRUE(new_opt.filter_policy != nullptr);
  1011. auto rfp =
  1012. dynamic_cast<const RibbonFilterPolicy*>(new_opt.filter_policy.get());
  1013. EXPECT_EQ(rfp->GetMillibitsPerKey(), 5678);
  1014. EXPECT_EQ(rfp->GetBloomBeforeLevel(), -1);
  1015. // Ribbon filter policy (default Bloom hybrid)
  1016. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  1017. config_options, table_opt, "filter_policy=ribbonfilter:6.789;",
  1018. &new_opt));
  1019. ASSERT_TRUE(new_opt.filter_policy != nullptr);
  1020. rfp = dynamic_cast<const RibbonFilterPolicy*>(new_opt.filter_policy.get());
  1021. EXPECT_EQ(rfp->GetMillibitsPerKey(), 6789);
  1022. EXPECT_EQ(rfp->GetBloomBeforeLevel(), 0);
  1023. // Ribbon filter policy (custom Bloom hybrid)
  1024. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  1025. config_options, table_opt, "filter_policy=ribbonfilter:6.789:5;",
  1026. &new_opt));
  1027. ASSERT_TRUE(new_opt.filter_policy != nullptr);
  1028. rfp = dynamic_cast<const RibbonFilterPolicy*>(new_opt.filter_policy.get());
  1029. EXPECT_EQ(rfp->GetMillibitsPerKey(), 6789);
  1030. EXPECT_EQ(rfp->GetBloomBeforeLevel(), 5);
  1031. // Check block cache options are overwritten when specified
  1032. // in new format as a struct.
  1033. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  1034. config_options, table_opt,
  1035. "block_cache={capacity=1M;num_shard_bits=4;"
  1036. "strict_capacity_limit=true;high_pri_pool_ratio=0.5;};"
  1037. "block_cache_compressed={capacity=1M;num_shard_bits=4;"
  1038. "strict_capacity_limit=true;high_pri_pool_ratio=0.5;}",
  1039. &new_opt));
  1040. ASSERT_TRUE(new_opt.block_cache != nullptr);
  1041. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 1024UL * 1024UL);
  1042. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(new_opt.block_cache)
  1043. ->GetNumShardBits(),
  1044. 4);
  1045. ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), true);
  1046. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
  1047. ->GetHighPriPoolRatio(),
  1048. 0.5);
  1049. // Set only block cache capacity. Check other values are
  1050. // reset to default values.
  1051. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  1052. config_options, table_opt,
  1053. "block_cache={capacity=2M};"
  1054. "block_cache_compressed={capacity=2M}",
  1055. &new_opt));
  1056. ASSERT_TRUE(new_opt.block_cache != nullptr);
  1057. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 2 * 1024UL * 1024UL);
  1058. // Default values
  1059. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(new_opt.block_cache)
  1060. ->GetNumShardBits(),
  1061. GetDefaultCacheShardBits(new_opt.block_cache->GetCapacity()));
  1062. ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), false);
  1063. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
  1064. ->GetHighPriPoolRatio(),
  1065. 0.5);
  1066. // Set couple of block cache options.
  1067. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  1068. config_options, table_opt,
  1069. "block_cache={num_shard_bits=5;high_pri_pool_ratio=0.5;};"
  1070. "block_cache_compressed={num_shard_bits=5;"
  1071. "high_pri_pool_ratio=0.0;}",
  1072. &new_opt));
  1073. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 0);
  1074. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(new_opt.block_cache)
  1075. ->GetNumShardBits(),
  1076. 5);
  1077. ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), false);
  1078. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
  1079. ->GetHighPriPoolRatio(),
  1080. 0.5);
  1081. // Set couple of block cache options.
  1082. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  1083. config_options, table_opt,
  1084. "block_cache={capacity=1M;num_shard_bits=4;"
  1085. "strict_capacity_limit=true;};"
  1086. "block_cache_compressed={capacity=1M;num_shard_bits=4;"
  1087. "strict_capacity_limit=true;}",
  1088. &new_opt));
  1089. ASSERT_TRUE(new_opt.block_cache != nullptr);
  1090. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 1024UL * 1024UL);
  1091. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(new_opt.block_cache)
  1092. ->GetNumShardBits(),
  1093. 4);
  1094. ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), true);
  1095. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
  1096. ->GetHighPriPoolRatio(),
  1097. 0.5);
  1098. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  1099. config_options, table_opt, "filter_policy=rocksdb.BloomFilter:1.234",
  1100. &new_opt));
  1101. ASSERT_TRUE(new_opt.filter_policy != nullptr);
  1102. ASSERT_TRUE(
  1103. new_opt.filter_policy->IsInstanceOf(BloomFilterPolicy::kClassName()));
  1104. ASSERT_TRUE(
  1105. new_opt.filter_policy->IsInstanceOf(BloomFilterPolicy::kNickName()));
  1106. // Ribbon filter policy alternative name
  1107. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  1108. config_options, table_opt, "filter_policy=rocksdb.RibbonFilter:6.789:5;",
  1109. &new_opt));
  1110. ASSERT_TRUE(new_opt.filter_policy != nullptr);
  1111. ASSERT_TRUE(
  1112. new_opt.filter_policy->IsInstanceOf(RibbonFilterPolicy::kClassName()));
  1113. ASSERT_TRUE(
  1114. new_opt.filter_policy->IsInstanceOf(RibbonFilterPolicy::kNickName()));
  1115. }
  1116. TEST_F(OptionsTest, GetPlainTableOptionsFromString) {
  1117. PlainTableOptions table_opt;
  1118. PlainTableOptions new_opt;
  1119. ConfigOptions config_options;
  1120. config_options.input_strings_escaped = false;
  1121. config_options.ignore_unknown_options = false;
  1122. // make sure default values are overwritten by something else
  1123. ASSERT_OK(GetPlainTableOptionsFromString(
  1124. config_options, table_opt,
  1125. "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
  1126. "index_sparseness=8;huge_page_tlb_size=4;encoding_type=kPrefix;"
  1127. "full_scan_mode=true;store_index_in_file=true",
  1128. &new_opt));
  1129. ASSERT_EQ(new_opt.user_key_len, 66u);
  1130. ASSERT_EQ(new_opt.bloom_bits_per_key, 20);
  1131. ASSERT_EQ(new_opt.hash_table_ratio, 0.5);
  1132. ASSERT_EQ(new_opt.index_sparseness, 8);
  1133. ASSERT_EQ(new_opt.huge_page_tlb_size, 4);
  1134. ASSERT_EQ(new_opt.encoding_type, EncodingType::kPrefix);
  1135. ASSERT_TRUE(new_opt.full_scan_mode);
  1136. ASSERT_TRUE(new_opt.store_index_in_file);
  1137. // unknown option
  1138. Status s = GetPlainTableOptionsFromString(
  1139. config_options, table_opt,
  1140. "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
  1141. "bad_option=1",
  1142. &new_opt);
  1143. ASSERT_NOK(s);
  1144. ASSERT_TRUE(s.IsInvalidArgument());
  1145. // unrecognized EncodingType
  1146. s = GetPlainTableOptionsFromString(
  1147. config_options, table_opt,
  1148. "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
  1149. "encoding_type=kPrefixXX",
  1150. &new_opt);
  1151. ASSERT_NOK(s);
  1152. ASSERT_TRUE(s.IsInvalidArgument());
  1153. }
  1154. TEST_F(OptionsTest, GetMemTableRepFactoryFromString) {
  1155. std::unique_ptr<MemTableRepFactory> new_mem_factory = nullptr;
  1156. ASSERT_OK(GetMemTableRepFactoryFromString("skip_list", &new_mem_factory));
  1157. ASSERT_OK(GetMemTableRepFactoryFromString("skip_list:16", &new_mem_factory));
  1158. ASSERT_STREQ(new_mem_factory->Name(), "SkipListFactory");
  1159. ASSERT_NOK(GetMemTableRepFactoryFromString("skip_list:16:invalid_opt",
  1160. &new_mem_factory));
  1161. ASSERT_OK(GetMemTableRepFactoryFromString("prefix_hash", &new_mem_factory));
  1162. ASSERT_OK(
  1163. GetMemTableRepFactoryFromString("prefix_hash:1000", &new_mem_factory));
  1164. ASSERT_STREQ(new_mem_factory->Name(), "HashSkipListRepFactory");
  1165. ASSERT_NOK(GetMemTableRepFactoryFromString("prefix_hash:1000:invalid_opt",
  1166. &new_mem_factory));
  1167. ASSERT_OK(
  1168. GetMemTableRepFactoryFromString("hash_linkedlist", &new_mem_factory));
  1169. ASSERT_OK(GetMemTableRepFactoryFromString("hash_linkedlist:1000",
  1170. &new_mem_factory));
  1171. ASSERT_EQ(std::string(new_mem_factory->Name()), "HashLinkListRepFactory");
  1172. ASSERT_NOK(GetMemTableRepFactoryFromString("hash_linkedlist:1000:invalid_opt",
  1173. &new_mem_factory));
  1174. ASSERT_OK(GetMemTableRepFactoryFromString("vector", &new_mem_factory));
  1175. ASSERT_OK(GetMemTableRepFactoryFromString("vector:1024", &new_mem_factory));
  1176. ASSERT_EQ(std::string(new_mem_factory->Name()), "VectorRepFactory");
  1177. ASSERT_NOK(GetMemTableRepFactoryFromString("vector:1024:invalid_opt",
  1178. &new_mem_factory));
  1179. ASSERT_NOK(GetMemTableRepFactoryFromString("cuckoo", &new_mem_factory));
  1180. // CuckooHash memtable is already removed.
  1181. ASSERT_NOK(GetMemTableRepFactoryFromString("cuckoo:1024", &new_mem_factory));
  1182. ASSERT_NOK(GetMemTableRepFactoryFromString("bad_factory", &new_mem_factory));
  1183. }
  1184. TEST_F(OptionsTest, MemTableRepFactoryCreateFromString) {
  1185. std::unique_ptr<MemTableRepFactory> new_mem_factory = nullptr;
  1186. ConfigOptions config_options;
  1187. config_options.ignore_unsupported_options = false;
  1188. config_options.ignore_unknown_options = false;
  1189. ASSERT_OK(MemTableRepFactory::CreateFromString(config_options, "skip_list",
  1190. &new_mem_factory));
  1191. ASSERT_OK(MemTableRepFactory::CreateFromString(config_options, "skip_list:16",
  1192. &new_mem_factory));
  1193. ASSERT_STREQ(new_mem_factory->Name(), "SkipListFactory");
  1194. ASSERT_TRUE(new_mem_factory->IsInstanceOf("skip_list"));
  1195. ASSERT_TRUE(new_mem_factory->IsInstanceOf("SkipListFactory"));
  1196. ASSERT_NOK(MemTableRepFactory::CreateFromString(
  1197. config_options, "skip_list:16:invalid_opt", &new_mem_factory));
  1198. ASSERT_NOK(MemTableRepFactory::CreateFromString(
  1199. config_options, "invalid_opt=10", &new_mem_factory));
  1200. // Test a reset
  1201. ASSERT_OK(MemTableRepFactory::CreateFromString(config_options, "",
  1202. &new_mem_factory));
  1203. ASSERT_EQ(new_mem_factory, nullptr);
  1204. ASSERT_NOK(MemTableRepFactory::CreateFromString(
  1205. config_options, "invalid_opt=10", &new_mem_factory));
  1206. ASSERT_OK(MemTableRepFactory::CreateFromString(
  1207. config_options, "id=skip_list; lookahead=32", &new_mem_factory));
  1208. ASSERT_OK(MemTableRepFactory::CreateFromString(config_options, "prefix_hash",
  1209. &new_mem_factory));
  1210. ASSERT_OK(MemTableRepFactory::CreateFromString(
  1211. config_options, "prefix_hash:1000", &new_mem_factory));
  1212. ASSERT_STREQ(new_mem_factory->Name(), "HashSkipListRepFactory");
  1213. ASSERT_TRUE(new_mem_factory->IsInstanceOf("prefix_hash"));
  1214. ASSERT_TRUE(new_mem_factory->IsInstanceOf("HashSkipListRepFactory"));
  1215. ASSERT_NOK(MemTableRepFactory::CreateFromString(
  1216. config_options, "prefix_hash:1000:invalid_opt", &new_mem_factory));
  1217. ASSERT_OK(MemTableRepFactory::CreateFromString(
  1218. config_options,
  1219. "id=prefix_hash; bucket_count=32; skiplist_height=64; "
  1220. "branching_factor=16",
  1221. &new_mem_factory));
  1222. ASSERT_NOK(MemTableRepFactory::CreateFromString(
  1223. config_options,
  1224. "id=prefix_hash; bucket_count=32; skiplist_height=64; "
  1225. "branching_factor=16; invalid=unknown",
  1226. &new_mem_factory));
  1227. ASSERT_OK(MemTableRepFactory::CreateFromString(
  1228. config_options, "hash_linkedlist", &new_mem_factory));
  1229. ASSERT_OK(MemTableRepFactory::CreateFromString(
  1230. config_options, "hash_linkedlist:1000", &new_mem_factory));
  1231. ASSERT_STREQ(new_mem_factory->Name(), "HashLinkListRepFactory");
  1232. ASSERT_TRUE(new_mem_factory->IsInstanceOf("hash_linkedlist"));
  1233. ASSERT_TRUE(new_mem_factory->IsInstanceOf("HashLinkListRepFactory"));
  1234. ASSERT_NOK(MemTableRepFactory::CreateFromString(
  1235. config_options, "hash_linkedlist:1000:invalid_opt", &new_mem_factory));
  1236. ASSERT_OK(MemTableRepFactory::CreateFromString(
  1237. config_options,
  1238. "id=hash_linkedlist; bucket_count=32; threshold=64; huge_page_size=16; "
  1239. "logging_threshold=12; log_when_flash=true",
  1240. &new_mem_factory));
  1241. ASSERT_NOK(MemTableRepFactory::CreateFromString(
  1242. config_options,
  1243. "id=hash_linkedlist; bucket_count=32; threshold=64; huge_page_size=16; "
  1244. "logging_threshold=12; log_when_flash=true; invalid=unknown",
  1245. &new_mem_factory));
  1246. ASSERT_OK(MemTableRepFactory::CreateFromString(config_options, "vector",
  1247. &new_mem_factory));
  1248. ASSERT_OK(MemTableRepFactory::CreateFromString(config_options, "vector:1024",
  1249. &new_mem_factory));
  1250. ASSERT_STREQ(new_mem_factory->Name(), "VectorRepFactory");
  1251. ASSERT_TRUE(new_mem_factory->IsInstanceOf("vector"));
  1252. ASSERT_TRUE(new_mem_factory->IsInstanceOf("VectorRepFactory"));
  1253. ASSERT_NOK(MemTableRepFactory::CreateFromString(
  1254. config_options, "vector:1024:invalid_opt", &new_mem_factory));
  1255. ASSERT_OK(MemTableRepFactory::CreateFromString(
  1256. config_options, "id=vector; count=42", &new_mem_factory));
  1257. ASSERT_NOK(MemTableRepFactory::CreateFromString(
  1258. config_options, "id=vector; invalid=unknown", &new_mem_factory));
  1259. ASSERT_NOK(MemTableRepFactory::CreateFromString(config_options, "cuckoo",
  1260. &new_mem_factory));
  1261. // CuckooHash memtable is already removed.
  1262. ASSERT_NOK(MemTableRepFactory::CreateFromString(config_options, "cuckoo:1024",
  1263. &new_mem_factory));
  1264. ASSERT_NOK(MemTableRepFactory::CreateFromString(config_options, "bad_factory",
  1265. &new_mem_factory));
  1266. }
  1267. class CustomEnv : public EnvWrapper {
  1268. public:
  1269. explicit CustomEnv(Env* _target) : EnvWrapper(_target) {}
  1270. static const char* kClassName() { return "CustomEnv"; }
  1271. const char* Name() const override { return kClassName(); }
  1272. };
  1273. TEST_F(OptionsTest, GetOptionsFromStringTest) {
  1274. Options base_options, new_options;
  1275. ConfigOptions config_options;
  1276. config_options.input_strings_escaped = false;
  1277. config_options.ignore_unknown_options = false;
  1278. base_options.write_buffer_size = 20;
  1279. base_options.min_write_buffer_number_to_merge = 15;
  1280. BlockBasedTableOptions block_based_table_options;
  1281. block_based_table_options.cache_index_and_filter_blocks = true;
  1282. base_options.table_factory.reset(
  1283. NewBlockBasedTableFactory(block_based_table_options));
  1284. // Register an Env with object registry.
  1285. ObjectLibrary::Default()->AddFactory<Env>(
  1286. CustomEnv::kClassName(),
  1287. [](const std::string& /*name*/, std::unique_ptr<Env>* /*env_guard*/,
  1288. std::string* /* errmsg */) {
  1289. static CustomEnv env(Env::Default());
  1290. return &env;
  1291. });
  1292. ASSERT_OK(GetOptionsFromString(
  1293. config_options, base_options,
  1294. "write_buffer_size=10;max_write_buffer_number=16;"
  1295. "block_based_table_factory={block_cache=1M;block_size=4;};"
  1296. "compression_opts=4:5:6;create_if_missing=true;max_open_files=1;"
  1297. "bottommost_compression_opts=5:6:7;create_if_missing=true;max_open_files="
  1298. "1;"
  1299. "rate_limiter_bytes_per_sec=1024;env=CustomEnv",
  1300. &new_options));
  1301. ASSERT_EQ(new_options.compression_opts.window_bits, 4);
  1302. ASSERT_EQ(new_options.compression_opts.level, 5);
  1303. ASSERT_EQ(new_options.compression_opts.strategy, 6);
  1304. ASSERT_EQ(new_options.compression_opts.max_dict_bytes, 0u);
  1305. ASSERT_EQ(new_options.compression_opts.zstd_max_train_bytes, 0u);
  1306. ASSERT_EQ(new_options.compression_opts.parallel_threads, 1u);
  1307. ASSERT_EQ(new_options.compression_opts.enabled, false);
  1308. ASSERT_EQ(new_options.compression_opts.use_zstd_dict_trainer, true);
  1309. ASSERT_EQ(new_options.bottommost_compression, kDisableCompressionOption);
  1310. ASSERT_EQ(new_options.bottommost_compression_opts.window_bits, 5);
  1311. ASSERT_EQ(new_options.bottommost_compression_opts.level, 6);
  1312. ASSERT_EQ(new_options.bottommost_compression_opts.strategy, 7);
  1313. ASSERT_EQ(new_options.bottommost_compression_opts.max_dict_bytes, 0u);
  1314. ASSERT_EQ(new_options.bottommost_compression_opts.zstd_max_train_bytes, 0u);
  1315. ASSERT_EQ(new_options.bottommost_compression_opts.parallel_threads, 1u);
  1316. ASSERT_EQ(new_options.bottommost_compression_opts.enabled, false);
  1317. ASSERT_EQ(new_options.bottommost_compression_opts.use_zstd_dict_trainer,
  1318. true);
  1319. ASSERT_EQ(new_options.write_buffer_size, 10U);
  1320. ASSERT_EQ(new_options.max_write_buffer_number, 16);
  1321. const auto new_bbto =
  1322. new_options.table_factory->GetOptions<BlockBasedTableOptions>();
  1323. ASSERT_NE(new_bbto, nullptr);
  1324. ASSERT_EQ(new_bbto->block_cache->GetCapacity(), 1U << 20);
  1325. ASSERT_EQ(new_bbto->block_size, 4U);
  1326. // don't overwrite block based table options
  1327. ASSERT_TRUE(new_bbto->cache_index_and_filter_blocks);
  1328. ASSERT_EQ(new_options.create_if_missing, true);
  1329. ASSERT_EQ(new_options.max_open_files, 1);
  1330. ASSERT_TRUE(new_options.rate_limiter.get() != nullptr);
  1331. Env* newEnv = new_options.env;
  1332. ASSERT_OK(Env::CreateFromString({}, CustomEnv::kClassName(), &newEnv));
  1333. ASSERT_EQ(newEnv, new_options.env);
  1334. config_options.ignore_unknown_options = false;
  1335. // Test a bad value for a DBOption returns a failure
  1336. base_options.dump_malloc_stats = false;
  1337. base_options.write_buffer_size = 1024;
  1338. Options bad_options = new_options;
  1339. Status s = GetOptionsFromString(config_options, base_options,
  1340. "create_if_missing=XX;dump_malloc_stats=true",
  1341. &bad_options);
  1342. ASSERT_NOK(s);
  1343. ASSERT_TRUE(s.IsInvalidArgument());
  1344. ASSERT_EQ(bad_options.dump_malloc_stats, false);
  1345. bad_options = new_options;
  1346. s = GetOptionsFromString(config_options, base_options,
  1347. "write_buffer_size=XX;dump_malloc_stats=true",
  1348. &bad_options);
  1349. ASSERT_NOK(s);
  1350. ASSERT_TRUE(s.IsInvalidArgument());
  1351. ASSERT_EQ(bad_options.dump_malloc_stats, false);
  1352. // Test a bad value for a TableFactory Option returns a failure
  1353. bad_options = new_options;
  1354. s = GetOptionsFromString(config_options, base_options,
  1355. "write_buffer_size=16;dump_malloc_stats=true"
  1356. "block_based_table_factory={block_size=XX;};",
  1357. &bad_options);
  1358. ASSERT_TRUE(s.IsInvalidArgument());
  1359. ASSERT_EQ(bad_options.dump_malloc_stats, false);
  1360. ASSERT_EQ(bad_options.write_buffer_size, 1024);
  1361. config_options.ignore_unknown_options = true;
  1362. ASSERT_OK(GetOptionsFromString(config_options, base_options,
  1363. "create_if_missing=XX;dump_malloc_stats=true;"
  1364. "write_buffer_size=XX;"
  1365. "block_based_table_factory={block_size=XX;};",
  1366. &bad_options));
  1367. ASSERT_EQ(bad_options.create_if_missing, base_options.create_if_missing);
  1368. ASSERT_EQ(bad_options.dump_malloc_stats, true);
  1369. ASSERT_EQ(bad_options.write_buffer_size, base_options.write_buffer_size);
  1370. // Test the old interface
  1371. ASSERT_OK(GetOptionsFromString(
  1372. base_options,
  1373. "write_buffer_size=22;max_write_buffer_number=33;max_open_files=44;",
  1374. &new_options));
  1375. ASSERT_EQ(new_options.write_buffer_size, 22U);
  1376. ASSERT_EQ(new_options.max_write_buffer_number, 33);
  1377. ASSERT_EQ(new_options.max_open_files, 44);
  1378. }
  1379. TEST_F(OptionsTest, DBOptionsSerialization) {
  1380. Options base_options, new_options;
  1381. Random rnd(301);
  1382. ConfigOptions config_options;
  1383. config_options.input_strings_escaped = false;
  1384. config_options.ignore_unknown_options = false;
  1385. // Phase 1: Make big change in base_options
  1386. test::RandomInitDBOptions(&base_options, &rnd);
  1387. // Phase 2: obtain a string from base_option
  1388. std::string base_options_file_content;
  1389. ASSERT_OK(GetStringFromDBOptions(config_options, base_options,
  1390. &base_options_file_content));
  1391. // Phase 3: Set new_options from the derived string and expect
  1392. // new_options == base_options
  1393. ASSERT_OK(GetDBOptionsFromString(config_options, DBOptions(),
  1394. base_options_file_content, &new_options));
  1395. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(config_options, base_options,
  1396. new_options));
  1397. }
  1398. TEST_F(OptionsTest, OptionsComposeDecompose) {
  1399. // build an Options from DBOptions + CFOptions, then decompose it to verify
  1400. // we get same constituent options.
  1401. DBOptions base_db_opts;
  1402. ColumnFamilyOptions base_cf_opts;
  1403. ConfigOptions
  1404. config_options; // Use default for ignore(false) and check (exact)
  1405. config_options.input_strings_escaped = false;
  1406. Random rnd(301);
  1407. test::RandomInitDBOptions(&base_db_opts, &rnd);
  1408. test::RandomInitCFOptions(&base_cf_opts, base_db_opts, &rnd);
  1409. Options base_opts(base_db_opts, base_cf_opts);
  1410. DBOptions new_db_opts(base_opts);
  1411. ColumnFamilyOptions new_cf_opts(base_opts);
  1412. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(config_options, base_db_opts,
  1413. new_db_opts));
  1414. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base_cf_opts,
  1415. new_cf_opts));
  1416. delete new_cf_opts.compaction_filter;
  1417. }
  1418. TEST_F(OptionsTest, DBOptionsComposeImmutable) {
  1419. // Build a DBOptions from an Immutable/Mutable one and verify that
  1420. // we get same constituent options.
  1421. ConfigOptions config_options;
  1422. Random rnd(301);
  1423. DBOptions base_opts, new_opts;
  1424. test::RandomInitDBOptions(&base_opts, &rnd);
  1425. MutableDBOptions m_opts(base_opts);
  1426. ImmutableDBOptions i_opts(base_opts);
  1427. new_opts = BuildDBOptions(i_opts, m_opts);
  1428. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(config_options, base_opts,
  1429. new_opts));
  1430. }
  1431. TEST_F(OptionsTest, GetMutableDBOptions) {
  1432. Random rnd(228);
  1433. DBOptions base_opts;
  1434. std::string opts_str;
  1435. std::unordered_map<std::string, std::string> opts_map;
  1436. ConfigOptions config_options;
  1437. test::RandomInitDBOptions(&base_opts, &rnd);
  1438. ImmutableDBOptions i_opts(base_opts);
  1439. MutableDBOptions m_opts(base_opts);
  1440. MutableDBOptions new_opts;
  1441. ASSERT_OK(GetStringFromMutableDBOptions(config_options, m_opts, &opts_str));
  1442. ASSERT_OK(StringToMap(opts_str, &opts_map));
  1443. ASSERT_OK(GetMutableDBOptionsFromStrings(m_opts, opts_map, &new_opts));
  1444. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(
  1445. config_options, base_opts, BuildDBOptions(i_opts, new_opts)));
  1446. }
  1447. TEST_F(OptionsTest, CFOptionsComposeImmutable) {
  1448. // Build a DBOptions from an Immutable/Mutable one and verify that
  1449. // we get same constituent options.
  1450. ConfigOptions config_options;
  1451. Random rnd(301);
  1452. ColumnFamilyOptions base_opts, new_opts;
  1453. DBOptions dummy; // Needed to create ImmutableCFOptions
  1454. test::RandomInitCFOptions(&base_opts, dummy, &rnd);
  1455. MutableCFOptions m_opts(base_opts);
  1456. ImmutableCFOptions i_opts(base_opts);
  1457. UpdateColumnFamilyOptions(i_opts, &new_opts);
  1458. UpdateColumnFamilyOptions(m_opts, &new_opts);
  1459. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base_opts,
  1460. new_opts));
  1461. delete new_opts.compaction_filter;
  1462. }
  1463. TEST_F(OptionsTest, GetMutableCFOptions) {
  1464. Random rnd(228);
  1465. ColumnFamilyOptions base, copy;
  1466. std::string opts_str;
  1467. std::unordered_map<std::string, std::string> opts_map;
  1468. ConfigOptions config_options;
  1469. DBOptions dummy; // Needed to create ImmutableCFOptions
  1470. test::RandomInitCFOptions(&base, dummy, &rnd);
  1471. ColumnFamilyOptions result;
  1472. MutableCFOptions m_opts(base), new_opts;
  1473. ASSERT_OK(GetStringFromMutableCFOptions(config_options, m_opts, &opts_str));
  1474. ASSERT_OK(StringToMap(opts_str, &opts_map));
  1475. ASSERT_OK(GetMutableOptionsFromStrings(m_opts, opts_map, nullptr, &new_opts));
  1476. UpdateColumnFamilyOptions(ImmutableCFOptions(base), &copy);
  1477. UpdateColumnFamilyOptions(new_opts, &copy);
  1478. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, base, copy));
  1479. delete copy.compaction_filter;
  1480. }
  1481. TEST_F(OptionsTest, ColumnFamilyOptionsSerialization) {
  1482. Options options;
  1483. ColumnFamilyOptions base_opt, new_opt;
  1484. base_opt.comparator = test::BytewiseComparatorWithU64TsWrapper();
  1485. Random rnd(302);
  1486. ConfigOptions config_options;
  1487. config_options.input_strings_escaped = false;
  1488. // Phase 1: randomly assign base_opt
  1489. // custom type options
  1490. test::RandomInitCFOptions(&base_opt, options, &rnd);
  1491. // Phase 2: obtain a string from base_opt
  1492. std::string base_options_file_content;
  1493. ASSERT_OK(GetStringFromColumnFamilyOptions(config_options, base_opt,
  1494. &base_options_file_content));
  1495. // Phase 3: Set new_opt from the derived string and expect
  1496. // new_opt == base_opt
  1497. ASSERT_OK(
  1498. GetColumnFamilyOptionsFromString(config_options, ColumnFamilyOptions(),
  1499. base_options_file_content, &new_opt));
  1500. ASSERT_OK(
  1501. RocksDBOptionsParser::VerifyCFOptions(config_options, base_opt, new_opt));
  1502. ASSERT_EQ(base_opt.comparator, new_opt.comparator);
  1503. if (base_opt.compaction_filter) {
  1504. delete base_opt.compaction_filter;
  1505. }
  1506. }
  1507. TEST_F(OptionsTest, CheckBlockBasedTableOptions) {
  1508. ColumnFamilyOptions cf_opts;
  1509. DBOptions db_opts;
  1510. ConfigOptions config_opts;
  1511. ASSERT_OK(GetColumnFamilyOptionsFromString(
  1512. config_opts, cf_opts, "prefix_extractor=capped:8", &cf_opts));
  1513. ASSERT_OK(TableFactory::CreateFromString(config_opts, "BlockBasedTable",
  1514. &cf_opts.table_factory));
  1515. ASSERT_NE(cf_opts.table_factory.get(), nullptr);
  1516. ASSERT_TRUE(cf_opts.table_factory->IsInstanceOf(
  1517. TableFactory::kBlockBasedTableName()));
  1518. auto bbto = cf_opts.table_factory->GetOptions<BlockBasedTableOptions>();
  1519. ASSERT_OK(cf_opts.table_factory->ConfigureFromString(
  1520. config_opts,
  1521. "block_cache={capacity=1M;num_shard_bits=4;};"
  1522. "block_size_deviation=101;"
  1523. "block_restart_interval=0;"
  1524. "index_block_restart_interval=5;"
  1525. "partition_filters=true;"
  1526. "index_type=kHashSearch;"
  1527. "no_block_cache=1;"));
  1528. ASSERT_NE(bbto, nullptr);
  1529. ASSERT_EQ(bbto->block_cache.get(), nullptr);
  1530. ASSERT_EQ(bbto->block_size_deviation, 0);
  1531. ASSERT_EQ(bbto->block_restart_interval, 1);
  1532. ASSERT_EQ(bbto->index_block_restart_interval, 1);
  1533. ASSERT_FALSE(bbto->partition_filters);
  1534. ASSERT_OK(TableFactory::CreateFromString(config_opts, "BlockBasedTable",
  1535. &cf_opts.table_factory));
  1536. bbto = cf_opts.table_factory->GetOptions<BlockBasedTableOptions>();
  1537. ASSERT_OK(cf_opts.table_factory->ConfigureFromString(config_opts,
  1538. "no_block_cache=0;"));
  1539. ASSERT_NE(bbto->block_cache.get(), nullptr);
  1540. ASSERT_OK(cf_opts.table_factory->ValidateOptions(db_opts, cf_opts));
  1541. }
  1542. TEST_F(OptionsTest, MutableTableOptions) {
  1543. ConfigOptions config_options;
  1544. std::shared_ptr<TableFactory> bbtf;
  1545. bbtf.reset(NewBlockBasedTableFactory());
  1546. auto bbto = bbtf->GetOptions<BlockBasedTableOptions>();
  1547. ASSERT_NE(bbto, nullptr);
  1548. ASSERT_OK(bbtf->ConfigureOption(config_options, "no_block_cache", "true"));
  1549. ASSERT_OK(bbtf->ConfigureOption(config_options, "block_size", "1024"));
  1550. ASSERT_EQ(bbto->no_block_cache, true);
  1551. ASSERT_EQ(bbto->block_size, 1024);
  1552. ASSERT_OK(bbtf->PrepareOptions(config_options));
  1553. config_options.mutable_options_only = true;
  1554. // Options on BlockBasedTableOptions/Factory are no longer directly mutable
  1555. // but have to be mutated on a live DB with SetOptions replacing the
  1556. // table_factory with a copy using the new options.
  1557. ASSERT_NOK(bbtf->ConfigureOption(config_options, "no_block_cache", "false"));
  1558. ASSERT_NOK(bbtf->ConfigureOption(config_options, "block_size", "2048"));
  1559. ASSERT_EQ(bbto->no_block_cache, true);
  1560. ASSERT_EQ(bbto->block_size, 1024);
  1561. ColumnFamilyOptions cf_opts;
  1562. cf_opts.table_factory = bbtf;
  1563. // FIXME: find a way to make this fail again
  1564. /*
  1565. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  1566. config_options, cf_opts, "block_based_table_factory.no_block_cache=false",
  1567. &cf_opts));
  1568. */
  1569. ASSERT_OK(GetColumnFamilyOptionsFromString(
  1570. config_options, cf_opts, "block_based_table_factory.block_size=8192",
  1571. &cf_opts));
  1572. const auto new_bbto =
  1573. cf_opts.table_factory->GetOptions<BlockBasedTableOptions>();
  1574. ASSERT_NE(new_bbto, nullptr);
  1575. ASSERT_NE(new_bbto, bbto);
  1576. ASSERT_EQ(new_bbto->no_block_cache, true);
  1577. ASSERT_EQ(new_bbto->block_size, 8192);
  1578. ASSERT_EQ(bbto->block_size, 1024);
  1579. }
  1580. TEST_F(OptionsTest, MutableCFOptions) {
  1581. ConfigOptions config_options;
  1582. ColumnFamilyOptions cf_opts;
  1583. ASSERT_OK(GetColumnFamilyOptionsFromString(
  1584. config_options, cf_opts,
  1585. "paranoid_file_checks=true; block_based_table_factory.block_align=false; "
  1586. "block_based_table_factory.super_block_alignment_size=65536; "
  1587. "block_based_table_factory.super_block_alignment_space_overhead_ratio="
  1588. "4096; "
  1589. "block_based_table_factory.block_size=8192;",
  1590. &cf_opts));
  1591. ASSERT_TRUE(cf_opts.paranoid_file_checks);
  1592. ASSERT_NE(cf_opts.table_factory.get(), nullptr);
  1593. auto* bbto = cf_opts.table_factory->GetOptions<BlockBasedTableOptions>();
  1594. ASSERT_NE(bbto, nullptr);
  1595. ASSERT_EQ(bbto->block_size, 8192);
  1596. ASSERT_EQ(bbto->block_align, false);
  1597. ASSERT_EQ(bbto->super_block_alignment_size, 65536);
  1598. ASSERT_EQ(bbto->super_block_alignment_space_overhead_ratio, 4096);
  1599. std::unordered_map<std::string, std::string> unused_opts;
  1600. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  1601. config_options, cf_opts, {{"paranoid_file_checks", "false"}}, &cf_opts));
  1602. ASSERT_EQ(cf_opts.paranoid_file_checks, false);
  1603. // Should replace the factory with the new setting
  1604. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  1605. config_options, cf_opts,
  1606. {{"block_based_table_factory.block_size", "16384"}}, &cf_opts));
  1607. bbto = cf_opts.table_factory->GetOptions<BlockBasedTableOptions>();
  1608. ASSERT_EQ(bbto->block_size, 16384);
  1609. config_options.mutable_options_only = true;
  1610. // Force consistency checks is not mutable
  1611. ASSERT_NOK(GetColumnFamilyOptionsFromMap(
  1612. config_options, cf_opts, {{"force_consistency_checks", "true"}},
  1613. &cf_opts));
  1614. // Attempt to change the table factory kind. This was previously disallowed
  1615. // and is a dubious operation but is tricky to disallow without breaking
  1616. // other things (FIXME?)
  1617. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  1618. config_options, cf_opts, {{"table_factory", "PlainTable"}}, &cf_opts));
  1619. ASSERT_STREQ(cf_opts.table_factory->Name(), TableFactory::kPlainTableName());
  1620. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  1621. config_options, cf_opts, {{"table_factory", "BlockBasedTable"}},
  1622. &cf_opts));
  1623. ASSERT_STREQ(cf_opts.table_factory->Name(),
  1624. TableFactory::kBlockBasedTableName());
  1625. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  1626. config_options, cf_opts, {{"table_factory.id", "PlainTable"}}, &cf_opts));
  1627. ASSERT_STREQ(cf_opts.table_factory->Name(), TableFactory::kPlainTableName());
  1628. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  1629. config_options, cf_opts, {{"table_factory.id", "BlockBasedTable"}},
  1630. &cf_opts));
  1631. ASSERT_STREQ(cf_opts.table_factory->Name(),
  1632. TableFactory::kBlockBasedTableName());
  1633. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  1634. config_options, cf_opts,
  1635. {{"table_factory", "{id=PlainTable;bloom_bits_per_key=42}"}}, &cf_opts));
  1636. ASSERT_STREQ(cf_opts.table_factory->Name(), TableFactory::kPlainTableName());
  1637. // Should at least be allowed to instantiate in place of nullptr, for
  1638. // initialization purposes.
  1639. cf_opts.table_factory = nullptr;
  1640. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  1641. config_options, cf_opts,
  1642. {{"table_factory", "{id=BlockBasedTable;block_size=12345}"}}, &cf_opts));
  1643. ASSERT_STREQ(cf_opts.table_factory->Name(),
  1644. TableFactory::kBlockBasedTableName());
  1645. bbto = cf_opts.table_factory->GetOptions<BlockBasedTableOptions>();
  1646. ASSERT_EQ(bbto->block_size, 12345);
  1647. // Accessing through the wrong factory alias fails gracefully
  1648. ASSERT_NOK(GetColumnFamilyOptionsFromMap(
  1649. config_options, cf_opts,
  1650. {{"plain_table_factory", "{bloom_bits_per_key=42}"}}, &cf_opts));
  1651. ASSERT_NOK(GetColumnFamilyOptionsFromMap(
  1652. config_options, cf_opts,
  1653. {{"plain_table_factory.bloom_bits_per_key", "42"}}, &cf_opts));
  1654. ASSERT_STREQ(cf_opts.table_factory->Name(),
  1655. TableFactory::kBlockBasedTableName());
  1656. // Change the block size.
  1657. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  1658. config_options, cf_opts,
  1659. {{"block_based_table_factory.block_size", "8192"}}, &cf_opts));
  1660. bbto = cf_opts.table_factory->GetOptions<BlockBasedTableOptions>();
  1661. ASSERT_EQ(bbto->block_size, 8192);
  1662. // Attempt to turn off block cache fails, as this option is not mutable
  1663. // FIXME: find a way to make this fail again
  1664. /*
  1665. ASSERT_NOK(GetColumnFamilyOptionsFromMap(
  1666. config_options, cf_opts,
  1667. {{"block_based_table_factory.no_block_cache", "true"}}, &cf_opts));
  1668. */
  1669. // Attempt to change the block size via a config string/map.
  1670. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  1671. config_options, cf_opts,
  1672. {{"block_based_table_factory", "{block_size=32768}"}}, &cf_opts));
  1673. bbto = cf_opts.table_factory->GetOptions<BlockBasedTableOptions>();
  1674. ASSERT_EQ(bbto->block_size, 32768);
  1675. // Attempt to change the block size and no cache through the map. Should
  1676. // fail, leaving the old values intact
  1677. // FIXME: find a way to make this fail again
  1678. /*
  1679. ASSERT_NOK(GetColumnFamilyOptionsFromMap(
  1680. config_options, cf_opts,
  1681. {{"block_based_table_factory",
  1682. "{block_size=16384; no_block_cache=true}"}},
  1683. &cf_opts));
  1684. */
  1685. ASSERT_EQ(bbto->block_size, 32768);
  1686. // Switch to plain table for some tests
  1687. cf_opts.table_factory = nullptr;
  1688. ASSERT_OK(GetColumnFamilyOptionsFromMap(
  1689. config_options, cf_opts,
  1690. {{"table_factory", "{id=PlainTable;bloom_bits_per_key=42}"}}, &cf_opts));
  1691. ASSERT_STREQ(cf_opts.table_factory->Name(), TableFactory::kPlainTableName());
  1692. auto* pto = cf_opts.table_factory->GetOptions<PlainTableOptions>();
  1693. ASSERT_EQ(pto->bloom_bits_per_key, 42);
  1694. // Accessing through the wrong factory alias fails gracefully
  1695. ASSERT_NOK(GetColumnFamilyOptionsFromMap(
  1696. config_options, cf_opts,
  1697. {{"block_based_table_factory.block_size", "8192"}}, &cf_opts));
  1698. ASSERT_NOK(GetColumnFamilyOptionsFromMap(
  1699. config_options, cf_opts,
  1700. {{"block_based_table_factory", "{block_size=32768}"}}, &cf_opts));
  1701. ASSERT_STREQ(cf_opts.table_factory->Name(), TableFactory::kPlainTableName());
  1702. ASSERT_EQ(pto, cf_opts.table_factory->GetOptions<PlainTableOptions>());
  1703. }
  1704. Status StringToMap(const std::string& opts_str,
  1705. std::unordered_map<std::string, std::string>* opts_map);
  1706. TEST_F(OptionsTest, StringToMapTest) {
  1707. std::unordered_map<std::string, std::string> opts_map;
  1708. // Regular options
  1709. ASSERT_OK(StringToMap("k1=v1;k2=v2;k3=v3", &opts_map));
  1710. ASSERT_EQ(opts_map["k1"], "v1");
  1711. ASSERT_EQ(opts_map["k2"], "v2");
  1712. ASSERT_EQ(opts_map["k3"], "v3");
  1713. // Value with '='
  1714. opts_map.clear();
  1715. ASSERT_OK(StringToMap("k1==v1;k2=v2=;", &opts_map));
  1716. ASSERT_EQ(opts_map["k1"], "=v1");
  1717. ASSERT_EQ(opts_map["k2"], "v2=");
  1718. // Overwrriten option
  1719. opts_map.clear();
  1720. ASSERT_OK(StringToMap("k1=v1;k1=v2;k3=v3", &opts_map));
  1721. ASSERT_EQ(opts_map["k1"], "v2");
  1722. ASSERT_EQ(opts_map["k3"], "v3");
  1723. // Empty value
  1724. opts_map.clear();
  1725. ASSERT_OK(StringToMap("k1=v1;k2=;k3=v3;k4=", &opts_map));
  1726. ASSERT_EQ(opts_map["k1"], "v1");
  1727. ASSERT_TRUE(opts_map.find("k2") != opts_map.end());
  1728. ASSERT_EQ(opts_map["k2"], "");
  1729. ASSERT_EQ(opts_map["k3"], "v3");
  1730. ASSERT_TRUE(opts_map.find("k4") != opts_map.end());
  1731. ASSERT_EQ(opts_map["k4"], "");
  1732. opts_map.clear();
  1733. ASSERT_OK(StringToMap("k1=v1;k2=;k3=v3;k4= ", &opts_map));
  1734. ASSERT_EQ(opts_map["k1"], "v1");
  1735. ASSERT_TRUE(opts_map.find("k2") != opts_map.end());
  1736. ASSERT_EQ(opts_map["k2"], "");
  1737. ASSERT_EQ(opts_map["k3"], "v3");
  1738. ASSERT_TRUE(opts_map.find("k4") != opts_map.end());
  1739. ASSERT_EQ(opts_map["k4"], "");
  1740. opts_map.clear();
  1741. ASSERT_OK(StringToMap("k1=v1;k2=;k3=", &opts_map));
  1742. ASSERT_EQ(opts_map["k1"], "v1");
  1743. ASSERT_TRUE(opts_map.find("k2") != opts_map.end());
  1744. ASSERT_EQ(opts_map["k2"], "");
  1745. ASSERT_TRUE(opts_map.find("k3") != opts_map.end());
  1746. ASSERT_EQ(opts_map["k3"], "");
  1747. opts_map.clear();
  1748. ASSERT_OK(StringToMap("k1=v1;k2=;k3=;", &opts_map));
  1749. ASSERT_EQ(opts_map["k1"], "v1");
  1750. ASSERT_TRUE(opts_map.find("k2") != opts_map.end());
  1751. ASSERT_EQ(opts_map["k2"], "");
  1752. ASSERT_TRUE(opts_map.find("k3") != opts_map.end());
  1753. ASSERT_EQ(opts_map["k3"], "");
  1754. // Regular nested options
  1755. opts_map.clear();
  1756. ASSERT_OK(StringToMap("k1=v1;k2={nk1=nv1;nk2=nv2};k3=v3", &opts_map));
  1757. ASSERT_EQ(opts_map["k1"], "v1");
  1758. ASSERT_EQ(opts_map["k2"], "nk1=nv1;nk2=nv2");
  1759. ASSERT_EQ(opts_map["k3"], "v3");
  1760. // Multi-level nested options
  1761. opts_map.clear();
  1762. ASSERT_OK(
  1763. StringToMap("k1=v1;k2={nk1=nv1;nk2={nnk1=nnk2}};"
  1764. "k3={nk1={nnk1={nnnk1=nnnv1;nnnk2;nnnv2}}};k4=v4",
  1765. &opts_map));
  1766. ASSERT_EQ(opts_map["k1"], "v1");
  1767. ASSERT_EQ(opts_map["k2"], "nk1=nv1;nk2={nnk1=nnk2}");
  1768. ASSERT_EQ(opts_map["k3"], "nk1={nnk1={nnnk1=nnnv1;nnnk2;nnnv2}}");
  1769. ASSERT_EQ(opts_map["k4"], "v4");
  1770. // Garbage inside curly braces
  1771. opts_map.clear();
  1772. ASSERT_OK(StringToMap("k1=v1;k2={dfad=};k3={=};k4=v4", &opts_map));
  1773. ASSERT_EQ(opts_map["k1"], "v1");
  1774. ASSERT_EQ(opts_map["k2"], "dfad=");
  1775. ASSERT_EQ(opts_map["k3"], "=");
  1776. ASSERT_EQ(opts_map["k4"], "v4");
  1777. // Empty nested options
  1778. opts_map.clear();
  1779. ASSERT_OK(StringToMap("k1=v1;k2={};", &opts_map));
  1780. ASSERT_EQ(opts_map["k1"], "v1");
  1781. ASSERT_EQ(opts_map["k2"], "");
  1782. opts_map.clear();
  1783. ASSERT_OK(StringToMap("k1=v1;k2={{{{}}}{}{}};", &opts_map));
  1784. ASSERT_EQ(opts_map["k1"], "v1");
  1785. ASSERT_EQ(opts_map["k2"], "{{{}}}{}{}");
  1786. // With random spaces
  1787. opts_map.clear();
  1788. ASSERT_OK(
  1789. StringToMap(" k1 = v1 ; k2= {nk1=nv1; nk2={nnk1=nnk2}} ; "
  1790. "k3={ { } }; k4= v4 ",
  1791. &opts_map));
  1792. ASSERT_EQ(opts_map["k1"], "v1");
  1793. ASSERT_EQ(opts_map["k2"], "nk1=nv1; nk2={nnk1=nnk2}");
  1794. ASSERT_EQ(opts_map["k3"], "{ }");
  1795. ASSERT_EQ(opts_map["k4"], "v4");
  1796. // Empty key
  1797. ASSERT_NOK(StringToMap("k1=v1;k2=v2;=", &opts_map));
  1798. ASSERT_NOK(StringToMap("=v1;k2=v2", &opts_map));
  1799. ASSERT_NOK(StringToMap("k1=v1;k2v2;", &opts_map));
  1800. ASSERT_NOK(StringToMap("k1=v1;k2=v2;fadfa", &opts_map));
  1801. ASSERT_NOK(StringToMap("k1=v1;k2=v2;;", &opts_map));
  1802. // Mismatch curly braces
  1803. ASSERT_NOK(StringToMap("k1=v1;k2={;k3=v3", &opts_map));
  1804. ASSERT_NOK(StringToMap("k1=v1;k2={{};k3=v3", &opts_map));
  1805. ASSERT_NOK(StringToMap("k1=v1;k2={}};k3=v3", &opts_map));
  1806. ASSERT_NOK(StringToMap("k1=v1;k2={{}{}}};k3=v3", &opts_map));
  1807. // However this is valid!
  1808. opts_map.clear();
  1809. ASSERT_OK(StringToMap("k1=v1;k2=};k3=v3", &opts_map));
  1810. ASSERT_EQ(opts_map["k1"], "v1");
  1811. ASSERT_EQ(opts_map["k2"], "}");
  1812. ASSERT_EQ(opts_map["k3"], "v3");
  1813. // Invalid chars after closing curly brace
  1814. ASSERT_NOK(StringToMap("k1=v1;k2={{}}{};k3=v3", &opts_map));
  1815. ASSERT_NOK(StringToMap("k1=v1;k2={{}}cfda;k3=v3", &opts_map));
  1816. ASSERT_NOK(StringToMap("k1=v1;k2={{}} cfda;k3=v3", &opts_map));
  1817. ASSERT_NOK(StringToMap("k1=v1;k2={{}} cfda", &opts_map));
  1818. ASSERT_NOK(StringToMap("k1=v1;k2={{}}{}", &opts_map));
  1819. ASSERT_NOK(StringToMap("k1=v1;k2={{dfdl}adfa}{}", &opts_map));
  1820. }
  1821. TEST_F(OptionsTest, StringToMapRandomTest) {
  1822. std::unordered_map<std::string, std::string> opts_map;
  1823. // Make sure segfault is not hit by semi-random strings
  1824. std::vector<std::string> bases = {
  1825. "a={aa={};tt={xxx={}}};c=defff",
  1826. "a={aa={};tt={xxx={}}};c=defff;d={{}yxx{}3{xx}}",
  1827. "abc={{}{}{}{{{}}}{{}{}{}{}{}{}{}"};
  1828. for (const std::string& base : bases) {
  1829. for (int rand_seed = 301; rand_seed < 401; rand_seed++) {
  1830. Random rnd(rand_seed);
  1831. for (int attempt = 0; attempt < 10; attempt++) {
  1832. std::string str = base;
  1833. // Replace random position to space
  1834. size_t pos =
  1835. static_cast<size_t>(rnd.Uniform(static_cast<int>(base.size())));
  1836. str[pos] = ' ';
  1837. Status s = StringToMap(str, &opts_map);
  1838. ASSERT_TRUE(s.ok() || s.IsInvalidArgument());
  1839. opts_map.clear();
  1840. }
  1841. }
  1842. }
  1843. // Random Construct a string
  1844. std::vector<char> chars = {'{', '}', ' ', '=', ';', 'c'};
  1845. for (int rand_seed = 301; rand_seed < 1301; rand_seed++) {
  1846. Random rnd(rand_seed);
  1847. int len = rnd.Uniform(30);
  1848. std::string str;
  1849. for (int attempt = 0; attempt < len; attempt++) {
  1850. // Add a random character
  1851. size_t pos =
  1852. static_cast<size_t>(rnd.Uniform(static_cast<int>(chars.size())));
  1853. str.append(1, chars[pos]);
  1854. }
  1855. Status s = StringToMap(str, &opts_map);
  1856. ASSERT_TRUE(s.ok() || s.IsInvalidArgument());
  1857. s = StringToMap("name=" + str, &opts_map);
  1858. ASSERT_TRUE(s.ok() || s.IsInvalidArgument());
  1859. opts_map.clear();
  1860. }
  1861. }
  1862. TEST_F(OptionsTest, GetStringFromCompressionType) {
  1863. std::string res;
  1864. ASSERT_OK(GetStringFromCompressionType(&res, kNoCompression));
  1865. ASSERT_EQ(res, "kNoCompression");
  1866. ASSERT_OK(GetStringFromCompressionType(&res, kSnappyCompression));
  1867. ASSERT_EQ(res, "kSnappyCompression");
  1868. ASSERT_OK(GetStringFromCompressionType(&res, kDisableCompressionOption));
  1869. ASSERT_EQ(res, "kDisableCompressionOption");
  1870. ASSERT_OK(GetStringFromCompressionType(&res, kLZ4Compression));
  1871. ASSERT_EQ(res, "kLZ4Compression");
  1872. ASSERT_OK(GetStringFromCompressionType(&res, kZlibCompression));
  1873. ASSERT_EQ(res, "kZlibCompression");
  1874. ASSERT_NOK(
  1875. GetStringFromCompressionType(&res, static_cast<CompressionType>(0x7F)));
  1876. }
  1877. TEST_F(OptionsTest, OnlyMutableDBOptions) {
  1878. std::string opt_str;
  1879. Random rnd(302);
  1880. ConfigOptions cfg_opts;
  1881. DBOptions db_opts;
  1882. DBOptions mdb_opts;
  1883. std::unordered_set<std::string> m_names;
  1884. std::unordered_set<std::string> a_names;
  1885. test::RandomInitDBOptions(&db_opts, &rnd);
  1886. auto db_config = DBOptionsAsConfigurable(db_opts);
  1887. // Get all of the DB Option names (mutable or not)
  1888. ASSERT_OK(db_config->GetOptionNames(cfg_opts, &a_names));
  1889. // Get only the mutable options from db_opts and set those in mdb_opts
  1890. cfg_opts.mutable_options_only = true;
  1891. // Get only the Mutable DB Option names
  1892. ASSERT_OK(db_config->GetOptionNames(cfg_opts, &m_names));
  1893. ASSERT_OK(GetStringFromDBOptions(cfg_opts, db_opts, &opt_str));
  1894. ASSERT_OK(GetDBOptionsFromString(cfg_opts, mdb_opts, opt_str, &mdb_opts));
  1895. std::string mismatch;
  1896. // Comparing only the mutable options, the two are equivalent
  1897. auto mdb_config = DBOptionsAsConfigurable(mdb_opts);
  1898. ASSERT_TRUE(mdb_config->AreEquivalent(cfg_opts, db_config.get(), &mismatch));
  1899. ASSERT_TRUE(db_config->AreEquivalent(cfg_opts, mdb_config.get(), &mismatch));
  1900. ASSERT_GT(a_names.size(), m_names.size());
  1901. for (const auto& n : m_names) {
  1902. std::string m, d;
  1903. ASSERT_OK(mdb_config->GetOption(cfg_opts, n, &m));
  1904. ASSERT_OK(db_config->GetOption(cfg_opts, n, &d));
  1905. ASSERT_EQ(m, d);
  1906. }
  1907. cfg_opts.mutable_options_only = false;
  1908. // Comparing all of the options, the two are not equivalent
  1909. ASSERT_FALSE(mdb_config->AreEquivalent(cfg_opts, db_config.get(), &mismatch));
  1910. ASSERT_FALSE(db_config->AreEquivalent(cfg_opts, mdb_config.get(), &mismatch));
  1911. // Make sure there are only mutable options being configured
  1912. ASSERT_OK(GetDBOptionsFromString(cfg_opts, DBOptions(), opt_str, &db_opts));
  1913. }
  1914. TEST_F(OptionsTest, OnlyMutableCFOptions) {
  1915. std::string opt_str;
  1916. Random rnd(302);
  1917. ConfigOptions cfg_opts;
  1918. DBOptions db_opts;
  1919. ColumnFamilyOptions mcf_opts;
  1920. ColumnFamilyOptions cf_opts;
  1921. std::unordered_set<std::string> m_names;
  1922. std::unordered_set<std::string> a_names;
  1923. test::RandomInitCFOptions(&cf_opts, db_opts, &rnd);
  1924. cf_opts.comparator = ReverseBytewiseComparator();
  1925. auto cf_config = CFOptionsAsConfigurable(cf_opts);
  1926. // Get all of the CF Option names (mutable or not)
  1927. ASSERT_OK(cf_config->GetOptionNames(cfg_opts, &a_names));
  1928. // Get only the mutable options from cf_opts and set those in mcf_opts
  1929. cfg_opts.mutable_options_only = true;
  1930. // Get only the Mutable CF Option names
  1931. ASSERT_OK(cf_config->GetOptionNames(cfg_opts, &m_names));
  1932. ASSERT_OK(GetStringFromColumnFamilyOptions(cfg_opts, cf_opts, &opt_str));
  1933. ASSERT_OK(
  1934. GetColumnFamilyOptionsFromString(cfg_opts, mcf_opts, opt_str, &mcf_opts));
  1935. std::string mismatch;
  1936. auto mcf_config = CFOptionsAsConfigurable(mcf_opts);
  1937. // Comparing only the mutable options, the two are equivalent
  1938. ASSERT_TRUE(mcf_config->AreEquivalent(cfg_opts, cf_config.get(), &mismatch));
  1939. ASSERT_TRUE(cf_config->AreEquivalent(cfg_opts, mcf_config.get(), &mismatch));
  1940. ASSERT_GT(a_names.size(), m_names.size());
  1941. for (const auto& n : m_names) {
  1942. std::string m, d;
  1943. ASSERT_OK(mcf_config->GetOption(cfg_opts, n, &m));
  1944. ASSERT_OK(cf_config->GetOption(cfg_opts, n, &d));
  1945. ASSERT_EQ(m, d);
  1946. }
  1947. cfg_opts.mutable_options_only = false;
  1948. // Comparing all of the options, the two are not equivalent
  1949. ASSERT_FALSE(mcf_config->AreEquivalent(cfg_opts, cf_config.get(), &mismatch));
  1950. ASSERT_FALSE(cf_config->AreEquivalent(cfg_opts, mcf_config.get(), &mismatch));
  1951. delete cf_opts.compaction_filter;
  1952. // Make sure the options string contains only mutable options
  1953. ASSERT_OK(GetColumnFamilyOptionsFromString(cfg_opts, ColumnFamilyOptions(),
  1954. opt_str, &cf_opts));
  1955. delete cf_opts.compaction_filter;
  1956. }
  1957. TEST_F(OptionsTest, SstPartitionerTest) {
  1958. ConfigOptions cfg_opts;
  1959. ColumnFamilyOptions cf_opts, new_opt;
  1960. std::string opts_str, mismatch;
  1961. ASSERT_OK(SstPartitionerFactory::CreateFromString(
  1962. cfg_opts, SstPartitionerFixedPrefixFactory::kClassName(),
  1963. &cf_opts.sst_partitioner_factory));
  1964. ASSERT_NE(cf_opts.sst_partitioner_factory, nullptr);
  1965. ASSERT_STREQ(cf_opts.sst_partitioner_factory->Name(),
  1966. SstPartitionerFixedPrefixFactory::kClassName());
  1967. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  1968. cfg_opts, ColumnFamilyOptions(),
  1969. std::string("sst_partitioner_factory={id=") +
  1970. SstPartitionerFixedPrefixFactory::kClassName() + "; unknown=10;}",
  1971. &cf_opts));
  1972. ASSERT_OK(GetColumnFamilyOptionsFromString(
  1973. cfg_opts, ColumnFamilyOptions(),
  1974. std::string("sst_partitioner_factory={id=") +
  1975. SstPartitionerFixedPrefixFactory::kClassName() + "; length=10;}",
  1976. &cf_opts));
  1977. ASSERT_NE(cf_opts.sst_partitioner_factory, nullptr);
  1978. ASSERT_STREQ(cf_opts.sst_partitioner_factory->Name(),
  1979. SstPartitionerFixedPrefixFactory::kClassName());
  1980. ASSERT_OK(GetStringFromColumnFamilyOptions(cfg_opts, cf_opts, &opts_str));
  1981. ASSERT_OK(
  1982. GetColumnFamilyOptionsFromString(cfg_opts, cf_opts, opts_str, &new_opt));
  1983. ASSERT_NE(new_opt.sst_partitioner_factory, nullptr);
  1984. ASSERT_STREQ(new_opt.sst_partitioner_factory->Name(),
  1985. SstPartitionerFixedPrefixFactory::kClassName());
  1986. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(cfg_opts, cf_opts, new_opt));
  1987. ASSERT_TRUE(cf_opts.sst_partitioner_factory->AreEquivalent(
  1988. cfg_opts, new_opt.sst_partitioner_factory.get(), &mismatch));
  1989. }
  1990. TEST_F(OptionsTest, FileChecksumGenFactoryTest) {
  1991. ConfigOptions cfg_opts;
  1992. DBOptions db_opts, new_opt;
  1993. std::string opts_str, mismatch;
  1994. auto factory = GetFileChecksumGenCrc32cFactory();
  1995. cfg_opts.ignore_unsupported_options = false;
  1996. ASSERT_OK(GetStringFromDBOptions(cfg_opts, db_opts, &opts_str));
  1997. ASSERT_OK(GetDBOptionsFromString(cfg_opts, db_opts, opts_str, &new_opt));
  1998. ASSERT_NE(factory, nullptr);
  1999. ASSERT_OK(FileChecksumGenFactory::CreateFromString(
  2000. cfg_opts, factory->Name(), &db_opts.file_checksum_gen_factory));
  2001. ASSERT_NE(db_opts.file_checksum_gen_factory, nullptr);
  2002. ASSERT_STREQ(db_opts.file_checksum_gen_factory->Name(), factory->Name());
  2003. ASSERT_NOK(GetDBOptionsFromString(
  2004. cfg_opts, DBOptions(), "file_checksum_gen_factory=unknown", &db_opts));
  2005. ASSERT_OK(GetDBOptionsFromString(
  2006. cfg_opts, DBOptions(),
  2007. std::string("file_checksum_gen_factory=") + factory->Name(), &db_opts));
  2008. ASSERT_NE(db_opts.file_checksum_gen_factory, nullptr);
  2009. ASSERT_STREQ(db_opts.file_checksum_gen_factory->Name(), factory->Name());
  2010. ASSERT_OK(GetStringFromDBOptions(cfg_opts, db_opts, &opts_str));
  2011. ASSERT_OK(GetDBOptionsFromString(cfg_opts, db_opts, opts_str, &new_opt));
  2012. ASSERT_NE(new_opt.file_checksum_gen_factory, nullptr);
  2013. ASSERT_STREQ(new_opt.file_checksum_gen_factory->Name(), factory->Name());
  2014. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(cfg_opts, db_opts, new_opt));
  2015. ASSERT_TRUE(factory->AreEquivalent(
  2016. cfg_opts, new_opt.file_checksum_gen_factory.get(), &mismatch));
  2017. ASSERT_TRUE(db_opts.file_checksum_gen_factory->AreEquivalent(
  2018. cfg_opts, new_opt.file_checksum_gen_factory.get(), &mismatch));
  2019. }
  2020. class TestTablePropertiesCollectorFactory
  2021. : public TablePropertiesCollectorFactory {
  2022. private:
  2023. std::string id_;
  2024. public:
  2025. explicit TestTablePropertiesCollectorFactory(const std::string& id)
  2026. : id_(id) {}
  2027. TablePropertiesCollector* CreateTablePropertiesCollector(
  2028. TablePropertiesCollectorFactory::Context /*context*/) override {
  2029. return nullptr;
  2030. }
  2031. static const char* kClassName() { return "TestCollector"; }
  2032. const char* Name() const override { return kClassName(); }
  2033. std::string GetId() const override {
  2034. return std::string(kClassName()) + ":" + id_;
  2035. }
  2036. };
  2037. TEST_F(OptionsTest, OptionTablePropertiesTest) {
  2038. ConfigOptions cfg_opts;
  2039. ColumnFamilyOptions orig, copy;
  2040. orig.table_properties_collector_factories.push_back(
  2041. std::make_shared<TestTablePropertiesCollectorFactory>("1"));
  2042. orig.table_properties_collector_factories.push_back(
  2043. std::make_shared<TestTablePropertiesCollectorFactory>("2"));
  2044. // Push two TablePropertiesCollectorFactories then create a new
  2045. // ColumnFamilyOptions based on those settings. The copy should
  2046. // have no properties but still match the original
  2047. std::string opts_str;
  2048. ASSERT_OK(GetStringFromColumnFamilyOptions(cfg_opts, orig, &opts_str));
  2049. ASSERT_OK(GetColumnFamilyOptionsFromString(cfg_opts, orig, opts_str, &copy));
  2050. ASSERT_EQ(copy.table_properties_collector_factories.size(), 0);
  2051. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(cfg_opts, orig, copy));
  2052. // Now register a TablePropertiesCollectorFactory
  2053. // Repeat the experiment. The copy should have the same
  2054. // properties as the original
  2055. cfg_opts.registry->AddLibrary("collector")
  2056. ->AddFactory<TablePropertiesCollectorFactory>(
  2057. ObjectLibrary::PatternEntry(
  2058. TestTablePropertiesCollectorFactory::kClassName(), false)
  2059. .AddSeparator(":"),
  2060. [](const std::string& name,
  2061. std::unique_ptr<TablePropertiesCollectorFactory>* guard,
  2062. std::string* /* errmsg */) {
  2063. std::string id = name.substr(
  2064. strlen(TestTablePropertiesCollectorFactory::kClassName()) + 1);
  2065. guard->reset(new TestTablePropertiesCollectorFactory(id));
  2066. return guard->get();
  2067. });
  2068. ASSERT_OK(GetColumnFamilyOptionsFromString(cfg_opts, orig, opts_str, &copy));
  2069. ASSERT_EQ(copy.table_properties_collector_factories.size(), 2);
  2070. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(cfg_opts, orig, copy));
  2071. }
  2072. TEST_F(OptionsTest, ConvertOptionsTest) {
  2073. LevelDBOptions leveldb_opt;
  2074. Options converted_opt = ConvertOptions(leveldb_opt);
  2075. ASSERT_EQ(converted_opt.create_if_missing, leveldb_opt.create_if_missing);
  2076. ASSERT_EQ(converted_opt.error_if_exists, leveldb_opt.error_if_exists);
  2077. ASSERT_EQ(converted_opt.paranoid_checks, leveldb_opt.paranoid_checks);
  2078. ASSERT_EQ(converted_opt.env, leveldb_opt.env);
  2079. ASSERT_EQ(converted_opt.info_log.get(), leveldb_opt.info_log);
  2080. ASSERT_EQ(converted_opt.write_buffer_size, leveldb_opt.write_buffer_size);
  2081. ASSERT_EQ(converted_opt.max_open_files, leveldb_opt.max_open_files);
  2082. ASSERT_EQ(converted_opt.compression, leveldb_opt.compression);
  2083. std::shared_ptr<TableFactory> table_factory = converted_opt.table_factory;
  2084. const auto table_opt = table_factory->GetOptions<BlockBasedTableOptions>();
  2085. ASSERT_NE(table_opt, nullptr);
  2086. ASSERT_EQ(table_opt->block_cache->GetCapacity(), 32UL << 20);
  2087. ASSERT_EQ(table_opt->block_size, leveldb_opt.block_size);
  2088. ASSERT_EQ(table_opt->block_restart_interval,
  2089. leveldb_opt.block_restart_interval);
  2090. ASSERT_EQ(table_opt->filter_policy.get(), leveldb_opt.filter_policy);
  2091. }
  2092. class TestEventListener : public EventListener {
  2093. private:
  2094. std::string id_;
  2095. public:
  2096. explicit TestEventListener(const std::string& id) : id_("Test" + id) {}
  2097. const char* Name() const override { return id_.c_str(); }
  2098. };
  2099. static std::unordered_map<std::string, OptionTypeInfo>
  2100. test_listener_option_info = {
  2101. {"s",
  2102. {0, OptionType::kString, OptionVerificationType::kNormal,
  2103. OptionTypeFlags::kNone}},
  2104. };
  2105. class TestConfigEventListener : public TestEventListener {
  2106. private:
  2107. std::string s_;
  2108. public:
  2109. explicit TestConfigEventListener(const std::string& id)
  2110. : TestEventListener("Config" + id) {
  2111. s_ = id;
  2112. RegisterOptions("Test", &s_, &test_listener_option_info);
  2113. }
  2114. };
  2115. static int RegisterTestEventListener(ObjectLibrary& library,
  2116. const std::string& arg) {
  2117. library.AddFactory<EventListener>(
  2118. "Test" + arg,
  2119. [](const std::string& name, std::unique_ptr<EventListener>* guard,
  2120. std::string* /* errmsg */) {
  2121. guard->reset(new TestEventListener(name.substr(4)));
  2122. return guard->get();
  2123. });
  2124. library.AddFactory<EventListener>(
  2125. "TestConfig" + arg,
  2126. [](const std::string& name, std::unique_ptr<EventListener>* guard,
  2127. std::string* /* errmsg */) {
  2128. guard->reset(new TestConfigEventListener(name.substr(10)));
  2129. return guard->get();
  2130. });
  2131. return 1;
  2132. }
  2133. TEST_F(OptionsTest, OptionsListenerTest) {
  2134. DBOptions orig, copy;
  2135. orig.listeners.push_back(std::make_shared<TestEventListener>("1"));
  2136. orig.listeners.push_back(std::make_shared<TestEventListener>("2"));
  2137. orig.listeners.push_back(std::make_shared<TestEventListener>(""));
  2138. orig.listeners.push_back(std::make_shared<TestConfigEventListener>("1"));
  2139. orig.listeners.push_back(std::make_shared<TestConfigEventListener>("2"));
  2140. orig.listeners.push_back(std::make_shared<TestConfigEventListener>(""));
  2141. ConfigOptions config_opts(orig);
  2142. config_opts.registry->AddLibrary("listener", RegisterTestEventListener, "1");
  2143. std::string opts_str;
  2144. ASSERT_OK(GetStringFromDBOptions(config_opts, orig, &opts_str));
  2145. ASSERT_OK(GetDBOptionsFromString(config_opts, orig, opts_str, &copy));
  2146. ASSERT_OK(GetStringFromDBOptions(config_opts, copy, &opts_str));
  2147. ASSERT_EQ(
  2148. copy.listeners.size(),
  2149. 2); // The Test{Config}1 Listeners could be loaded but not the others
  2150. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(config_opts, orig, copy));
  2151. }
  2152. const static std::string kCustomEnvName = "Custom";
  2153. const static std::string kCustomEnvProp = "env=" + kCustomEnvName;
  2154. static int RegisterCustomEnv(ObjectLibrary& library, const std::string& arg) {
  2155. library.AddFactory<Env>(
  2156. arg, [](const std::string& /*name*/, std::unique_ptr<Env>* /*env_guard*/,
  2157. std::string* /* errmsg */) {
  2158. static CustomEnv env(Env::Default());
  2159. return &env;
  2160. });
  2161. return 1;
  2162. }
  2163. // This test suite tests the old APIs into the Configure options methods.
  2164. // Once those APIs are officially deprecated, this test suite can be deleted.
  2165. class OptionsOldApiTest : public testing::Test {};
  2166. TEST_F(OptionsOldApiTest, GetOptionsFromMapTest) {
  2167. std::unordered_map<std::string, std::string> cf_options_map = {
  2168. {"write_buffer_size", "1"},
  2169. {"max_write_buffer_number", "2"},
  2170. {"min_write_buffer_number_to_merge", "3"},
  2171. {"max_write_buffer_number_to_maintain", "99"},
  2172. {"max_write_buffer_size_to_maintain", "-99999"},
  2173. {"compression", "kSnappyCompression"},
  2174. {"compression_per_level",
  2175. "kNoCompression:"
  2176. "kSnappyCompression:"
  2177. "kZlibCompression:"
  2178. "kBZip2Compression:"
  2179. "kLZ4Compression:"
  2180. "kLZ4HCCompression:"
  2181. "kXpressCompression:"
  2182. "kZSTD"},
  2183. {"bottommost_compression", "kLZ4Compression"},
  2184. {"bottommost_compression_opts", "5:6:7:8:9:true"},
  2185. {"compression_opts", "4:5:6:7:8:9:true:10:false"},
  2186. {"num_levels", "8"},
  2187. {"level0_file_num_compaction_trigger", "8"},
  2188. {"level0_slowdown_writes_trigger", "9"},
  2189. {"level0_stop_writes_trigger", "10"},
  2190. {"target_file_size_base", "12"},
  2191. {"target_file_size_multiplier", "13"},
  2192. {"max_bytes_for_level_base", "14"},
  2193. {"level_compaction_dynamic_level_bytes", "true"},
  2194. {"level_compaction_dynamic_file_size", "true"},
  2195. {"max_bytes_for_level_multiplier", "15.0"},
  2196. {"max_bytes_for_level_multiplier_additional", "16:17:18"},
  2197. {"max_compaction_bytes", "21"},
  2198. {"soft_rate_limit", "1.1"},
  2199. {"hard_rate_limit", "2.1"},
  2200. {"rate_limit_delay_max_milliseconds", "100"},
  2201. {"hard_pending_compaction_bytes_limit", "211"},
  2202. {"arena_block_size", "22"},
  2203. {"disable_auto_compactions", "true"},
  2204. {"compaction_style", "kCompactionStyleLevel"},
  2205. {"compaction_pri", "kOldestSmallestSeqFirst"},
  2206. {"verify_checksums_in_compaction", "false"},
  2207. {"compaction_options_fifo",
  2208. "{allow_compaction=true;max_table_files_size=11002244;"
  2209. "file_temperature_age_thresholds={{temperature=kCold;age=12345}}}"},
  2210. {"max_sequential_skip_in_iterations", "24"},
  2211. {"inplace_update_support", "true"},
  2212. {"report_bg_io_stats", "true"},
  2213. {"compaction_measure_io_stats", "false"},
  2214. {"purge_redundant_kvs_while_flush", "false"},
  2215. {"inplace_update_num_locks", "25"},
  2216. {"memtable_prefix_bloom_size_ratio", "0.26"},
  2217. {"memtable_whole_key_filtering", "true"},
  2218. {"memtable_huge_page_size", "28"},
  2219. {"bloom_locality", "29"},
  2220. {"max_successive_merges", "30"},
  2221. {"strict_max_successive_merges", "true"},
  2222. {"min_partial_merge_operands", "31"},
  2223. {"prefix_extractor", "fixed:31"},
  2224. {"experimental_mempurge_threshold", "0.003"},
  2225. {"optimize_filters_for_hits", "true"},
  2226. {"enable_blob_files", "true"},
  2227. {"min_blob_size", "1K"},
  2228. {"blob_file_size", "1G"},
  2229. {"blob_compression_type", "kZSTD"},
  2230. {"enable_blob_garbage_collection", "true"},
  2231. {"blob_garbage_collection_age_cutoff", "0.5"},
  2232. {"blob_garbage_collection_force_threshold", "0.75"},
  2233. {"blob_compaction_readahead_size", "256K"},
  2234. {"blob_file_starting_level", "1"},
  2235. {"prepopulate_blob_cache", "kDisable"},
  2236. {"last_level_temperature", "kWarm"},
  2237. {"default_write_temperature", "kCold"},
  2238. {"default_temperature", "kHot"},
  2239. {"persist_user_defined_timestamps", "true"},
  2240. {"memtable_max_range_deletions", "0"},
  2241. };
  2242. std::unordered_map<std::string, std::string> db_options_map = {
  2243. {"create_if_missing", "false"},
  2244. {"create_missing_column_families", "true"},
  2245. {"error_if_exists", "false"},
  2246. {"paranoid_checks", "true"},
  2247. {"track_and_verify_wals_in_manifest", "true"},
  2248. {"track_and_verify_wals", "true"},
  2249. {"verify_sst_unique_id_in_manifest", "true"},
  2250. {"max_open_files", "32"},
  2251. {"max_total_wal_size", "33"},
  2252. {"use_fsync", "true"},
  2253. {"db_log_dir", "/db_log_dir"},
  2254. {"wal_dir", "/wal_dir"},
  2255. {"delete_obsolete_files_period_micros", "34"},
  2256. {"max_background_compactions", "35"},
  2257. {"max_background_flushes", "36"},
  2258. {"max_log_file_size", "37"},
  2259. {"log_file_time_to_roll", "38"},
  2260. {"keep_log_file_num", "39"},
  2261. {"recycle_log_file_num", "5"},
  2262. {"max_manifest_file_size", "40"},
  2263. {"table_cache_numshardbits", "41"},
  2264. {"WAL_ttl_seconds", "43"},
  2265. {"WAL_size_limit_MB", "44"},
  2266. {"manifest_preallocation_size", "45"},
  2267. {"allow_mmap_reads", "true"},
  2268. {"allow_mmap_writes", "false"},
  2269. {"use_direct_reads", "false"},
  2270. {"use_direct_io_for_flush_and_compaction", "false"},
  2271. {"is_fd_close_on_exec", "true"},
  2272. {"skip_log_error_on_recovery", "false"},
  2273. {"stats_dump_period_sec", "46"},
  2274. {"stats_persist_period_sec", "57"},
  2275. {"persist_stats_to_disk", "false"},
  2276. {"stats_history_buffer_size", "69"},
  2277. {"advise_random_on_open", "true"},
  2278. {"use_adaptive_mutex", "false"},
  2279. {"compaction_readahead_size", "100"},
  2280. {"writable_file_max_buffer_size", "314159"},
  2281. {"bytes_per_sync", "47"},
  2282. {"wal_bytes_per_sync", "48"},
  2283. {"strict_bytes_per_sync", "true"},
  2284. {"preserve_deletes", "false"},
  2285. };
  2286. ColumnFamilyOptions base_cf_opt;
  2287. ColumnFamilyOptions new_cf_opt;
  2288. ConfigOptions cf_config_options;
  2289. cf_config_options.ignore_unknown_options = false;
  2290. cf_config_options.input_strings_escaped = false;
  2291. ASSERT_OK(GetColumnFamilyOptionsFromMap(cf_config_options, base_cf_opt,
  2292. cf_options_map, &new_cf_opt));
  2293. ASSERT_EQ(new_cf_opt.write_buffer_size, 1U);
  2294. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 2);
  2295. ASSERT_EQ(new_cf_opt.min_write_buffer_number_to_merge, 3);
  2296. ASSERT_EQ(new_cf_opt.max_write_buffer_size_to_maintain, -99999);
  2297. ASSERT_EQ(new_cf_opt.compression, kSnappyCompression);
  2298. ASSERT_EQ(new_cf_opt.compression_per_level.size(), 8U);
  2299. ASSERT_EQ(new_cf_opt.compression_per_level[0], kNoCompression);
  2300. ASSERT_EQ(new_cf_opt.compression_per_level[1], kSnappyCompression);
  2301. ASSERT_EQ(new_cf_opt.compression_per_level[2], kZlibCompression);
  2302. ASSERT_EQ(new_cf_opt.compression_per_level[3], kBZip2Compression);
  2303. ASSERT_EQ(new_cf_opt.compression_per_level[4], kLZ4Compression);
  2304. ASSERT_EQ(new_cf_opt.compression_per_level[5], kLZ4HCCompression);
  2305. ASSERT_EQ(new_cf_opt.compression_per_level[6], kXpressCompression);
  2306. ASSERT_EQ(new_cf_opt.compression_per_level[7], kZSTD);
  2307. ASSERT_EQ(new_cf_opt.compression_opts.window_bits, 4);
  2308. ASSERT_EQ(new_cf_opt.compression_opts.level, 5);
  2309. ASSERT_EQ(new_cf_opt.compression_opts.strategy, 6);
  2310. ASSERT_EQ(new_cf_opt.compression_opts.max_dict_bytes, 7u);
  2311. ASSERT_EQ(new_cf_opt.compression_opts.zstd_max_train_bytes, 8u);
  2312. ASSERT_EQ(new_cf_opt.compression_opts.parallel_threads, 9u);
  2313. ASSERT_EQ(new_cf_opt.compression_opts.enabled, true);
  2314. ASSERT_EQ(new_cf_opt.compression_opts.max_dict_buffer_bytes, 10u);
  2315. ASSERT_EQ(new_cf_opt.compression_opts.use_zstd_dict_trainer, false);
  2316. ASSERT_EQ(new_cf_opt.bottommost_compression, kLZ4Compression);
  2317. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.window_bits, 5);
  2318. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.level, 6);
  2319. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.strategy, 7);
  2320. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.max_dict_bytes, 8u);
  2321. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.zstd_max_train_bytes, 9u);
  2322. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.parallel_threads,
  2323. CompressionOptions().parallel_threads);
  2324. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.enabled, true);
  2325. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.max_dict_buffer_bytes,
  2326. CompressionOptions().max_dict_buffer_bytes);
  2327. ASSERT_EQ(new_cf_opt.bottommost_compression_opts.use_zstd_dict_trainer,
  2328. CompressionOptions().use_zstd_dict_trainer);
  2329. ASSERT_EQ(new_cf_opt.num_levels, 8);
  2330. ASSERT_EQ(new_cf_opt.level0_file_num_compaction_trigger, 8);
  2331. ASSERT_EQ(new_cf_opt.level0_slowdown_writes_trigger, 9);
  2332. ASSERT_EQ(new_cf_opt.level0_stop_writes_trigger, 10);
  2333. ASSERT_EQ(new_cf_opt.target_file_size_base, static_cast<uint64_t>(12));
  2334. ASSERT_EQ(new_cf_opt.target_file_size_multiplier, 13);
  2335. ASSERT_EQ(new_cf_opt.max_bytes_for_level_base, 14U);
  2336. ASSERT_EQ(new_cf_opt.level_compaction_dynamic_level_bytes, true);
  2337. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier, 15.0);
  2338. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional.size(), 3U);
  2339. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[0], 16);
  2340. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[1], 17);
  2341. ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[2], 18);
  2342. ASSERT_EQ(new_cf_opt.max_compaction_bytes, 21);
  2343. ASSERT_EQ(new_cf_opt.hard_pending_compaction_bytes_limit, 211);
  2344. ASSERT_EQ(new_cf_opt.arena_block_size, 22U);
  2345. ASSERT_EQ(new_cf_opt.disable_auto_compactions, true);
  2346. ASSERT_EQ(new_cf_opt.compaction_style, kCompactionStyleLevel);
  2347. ASSERT_EQ(new_cf_opt.compaction_pri, kOldestSmallestSeqFirst);
  2348. ASSERT_EQ(new_cf_opt.compaction_options_fifo.max_table_files_size,
  2349. static_cast<uint64_t>(11002244));
  2350. ASSERT_EQ(new_cf_opt.compaction_options_fifo.allow_compaction, true);
  2351. ASSERT_EQ(
  2352. new_cf_opt.compaction_options_fifo.file_temperature_age_thresholds.size(),
  2353. 1);
  2354. ASSERT_EQ(
  2355. new_cf_opt.compaction_options_fifo.file_temperature_age_thresholds[0]
  2356. .temperature,
  2357. Temperature::kCold);
  2358. ASSERT_EQ(
  2359. new_cf_opt.compaction_options_fifo.file_temperature_age_thresholds[0].age,
  2360. 12345);
  2361. ASSERT_EQ(new_cf_opt.max_sequential_skip_in_iterations,
  2362. static_cast<uint64_t>(24));
  2363. ASSERT_EQ(new_cf_opt.inplace_update_support, true);
  2364. ASSERT_EQ(new_cf_opt.inplace_update_num_locks, 25U);
  2365. ASSERT_EQ(new_cf_opt.memtable_prefix_bloom_size_ratio, 0.26);
  2366. ASSERT_EQ(new_cf_opt.memtable_whole_key_filtering, true);
  2367. ASSERT_EQ(new_cf_opt.memtable_huge_page_size, 28U);
  2368. ASSERT_EQ(new_cf_opt.bloom_locality, 29U);
  2369. ASSERT_EQ(new_cf_opt.max_successive_merges, 30U);
  2370. ASSERT_EQ(new_cf_opt.strict_max_successive_merges, true);
  2371. ASSERT_TRUE(new_cf_opt.prefix_extractor != nullptr);
  2372. ASSERT_EQ(new_cf_opt.optimize_filters_for_hits, true);
  2373. ASSERT_EQ(new_cf_opt.prefix_extractor->AsString(), "rocksdb.FixedPrefix.31");
  2374. ASSERT_EQ(new_cf_opt.experimental_mempurge_threshold, 0.003);
  2375. ASSERT_EQ(new_cf_opt.enable_blob_files, true);
  2376. ASSERT_EQ(new_cf_opt.min_blob_size, 1ULL << 10);
  2377. ASSERT_EQ(new_cf_opt.blob_file_size, 1ULL << 30);
  2378. ASSERT_EQ(new_cf_opt.blob_compression_type, kZSTD);
  2379. ASSERT_EQ(new_cf_opt.enable_blob_garbage_collection, true);
  2380. ASSERT_EQ(new_cf_opt.blob_garbage_collection_age_cutoff, 0.5);
  2381. ASSERT_EQ(new_cf_opt.blob_garbage_collection_force_threshold, 0.75);
  2382. ASSERT_EQ(new_cf_opt.blob_compaction_readahead_size, 262144);
  2383. ASSERT_EQ(new_cf_opt.blob_file_starting_level, 1);
  2384. ASSERT_EQ(new_cf_opt.prepopulate_blob_cache, PrepopulateBlobCache::kDisable);
  2385. ASSERT_EQ(new_cf_opt.last_level_temperature, Temperature::kWarm);
  2386. ASSERT_EQ(new_cf_opt.default_write_temperature, Temperature::kCold);
  2387. ASSERT_EQ(new_cf_opt.default_temperature, Temperature::kHot);
  2388. ASSERT_EQ(new_cf_opt.persist_user_defined_timestamps, true);
  2389. ASSERT_EQ(new_cf_opt.memtable_max_range_deletions, 0);
  2390. cf_options_map["write_buffer_size"] = "hello";
  2391. ASSERT_NOK(GetColumnFamilyOptionsFromMap(cf_config_options, base_cf_opt,
  2392. cf_options_map, &new_cf_opt));
  2393. ConfigOptions exact, loose;
  2394. exact.sanity_level = ConfigOptions::kSanityLevelExactMatch;
  2395. loose.sanity_level = ConfigOptions::kSanityLevelLooselyCompatible;
  2396. ASSERT_OK(
  2397. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  2398. cf_options_map["write_buffer_size"] = "1";
  2399. ASSERT_OK(GetColumnFamilyOptionsFromMap(cf_config_options, base_cf_opt,
  2400. cf_options_map, &new_cf_opt));
  2401. cf_options_map["unknown_option"] = "1";
  2402. ASSERT_NOK(GetColumnFamilyOptionsFromMap(cf_config_options, base_cf_opt,
  2403. cf_options_map, &new_cf_opt));
  2404. ASSERT_OK(
  2405. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  2406. cf_config_options.input_strings_escaped = false;
  2407. cf_config_options.ignore_unknown_options = true;
  2408. ASSERT_OK(GetColumnFamilyOptionsFromMap(cf_config_options, base_cf_opt,
  2409. cf_options_map, &new_cf_opt));
  2410. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
  2411. loose, base_cf_opt, new_cf_opt, nullptr /* new_opt_map */));
  2412. ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
  2413. exact /* default for VerifyCFOptions */, base_cf_opt, new_cf_opt,
  2414. nullptr));
  2415. DBOptions base_db_opt;
  2416. DBOptions new_db_opt;
  2417. ConfigOptions db_config_options(base_db_opt);
  2418. db_config_options.input_strings_escaped = false;
  2419. db_config_options.ignore_unknown_options = false;
  2420. ASSERT_OK(GetDBOptionsFromMap(db_config_options, base_db_opt, db_options_map,
  2421. &new_db_opt));
  2422. ASSERT_EQ(new_db_opt.create_if_missing, false);
  2423. ASSERT_EQ(new_db_opt.create_missing_column_families, true);
  2424. ASSERT_EQ(new_db_opt.error_if_exists, false);
  2425. ASSERT_EQ(new_db_opt.paranoid_checks, true);
  2426. ASSERT_EQ(new_db_opt.track_and_verify_wals_in_manifest, true);
  2427. ASSERT_EQ(new_db_opt.track_and_verify_wals, true);
  2428. ASSERT_EQ(new_db_opt.max_open_files, 32);
  2429. ASSERT_EQ(new_db_opt.max_total_wal_size, static_cast<uint64_t>(33));
  2430. ASSERT_EQ(new_db_opt.use_fsync, true);
  2431. ASSERT_EQ(new_db_opt.db_log_dir, "/db_log_dir");
  2432. ASSERT_EQ(new_db_opt.wal_dir, "/wal_dir");
  2433. ASSERT_EQ(new_db_opt.delete_obsolete_files_period_micros,
  2434. static_cast<uint64_t>(34));
  2435. ASSERT_EQ(new_db_opt.max_background_compactions, 35);
  2436. ASSERT_EQ(new_db_opt.max_background_flushes, 36);
  2437. ASSERT_EQ(new_db_opt.max_log_file_size, 37U);
  2438. ASSERT_EQ(new_db_opt.log_file_time_to_roll, 38U);
  2439. ASSERT_EQ(new_db_opt.keep_log_file_num, 39U);
  2440. ASSERT_EQ(new_db_opt.recycle_log_file_num, 5U);
  2441. ASSERT_EQ(new_db_opt.max_manifest_file_size, static_cast<uint64_t>(40));
  2442. ASSERT_EQ(new_db_opt.table_cache_numshardbits, 41);
  2443. ASSERT_EQ(new_db_opt.WAL_ttl_seconds, static_cast<uint64_t>(43));
  2444. ASSERT_EQ(new_db_opt.WAL_size_limit_MB, static_cast<uint64_t>(44));
  2445. ASSERT_EQ(new_db_opt.manifest_preallocation_size, 45U);
  2446. ASSERT_EQ(new_db_opt.allow_mmap_reads, true);
  2447. ASSERT_EQ(new_db_opt.allow_mmap_writes, false);
  2448. ASSERT_EQ(new_db_opt.use_direct_reads, false);
  2449. ASSERT_EQ(new_db_opt.use_direct_io_for_flush_and_compaction, false);
  2450. ASSERT_EQ(new_db_opt.is_fd_close_on_exec, true);
  2451. ASSERT_EQ(new_db_opt.stats_dump_period_sec, 46U);
  2452. ASSERT_EQ(new_db_opt.stats_persist_period_sec, 57U);
  2453. ASSERT_EQ(new_db_opt.persist_stats_to_disk, false);
  2454. ASSERT_EQ(new_db_opt.stats_history_buffer_size, 69U);
  2455. ASSERT_EQ(new_db_opt.advise_random_on_open, true);
  2456. ASSERT_EQ(new_db_opt.use_adaptive_mutex, false);
  2457. ASSERT_EQ(new_db_opt.compaction_readahead_size, 100);
  2458. ASSERT_EQ(new_db_opt.writable_file_max_buffer_size, 314159);
  2459. ASSERT_EQ(new_db_opt.bytes_per_sync, static_cast<uint64_t>(47));
  2460. ASSERT_EQ(new_db_opt.wal_bytes_per_sync, static_cast<uint64_t>(48));
  2461. ASSERT_EQ(new_db_opt.strict_bytes_per_sync, true);
  2462. db_options_map["max_open_files"] = "hello";
  2463. ASSERT_NOK(GetDBOptionsFromMap(db_config_options, base_db_opt, db_options_map,
  2464. &new_db_opt));
  2465. ASSERT_OK(
  2466. RocksDBOptionsParser::VerifyDBOptions(exact, base_db_opt, new_db_opt));
  2467. ASSERT_OK(
  2468. RocksDBOptionsParser::VerifyDBOptions(loose, base_db_opt, new_db_opt));
  2469. // unknow options should fail parsing without ignore_unknown_options = true
  2470. db_options_map["unknown_db_option"] = "1";
  2471. ASSERT_NOK(GetDBOptionsFromMap(db_config_options, base_db_opt, db_options_map,
  2472. &new_db_opt));
  2473. ASSERT_OK(
  2474. RocksDBOptionsParser::VerifyDBOptions(exact, base_db_opt, new_db_opt));
  2475. db_config_options.input_strings_escaped = false;
  2476. db_config_options.ignore_unknown_options = true;
  2477. ASSERT_OK(GetDBOptionsFromMap(db_config_options, base_db_opt, db_options_map,
  2478. &new_db_opt));
  2479. ASSERT_OK(
  2480. RocksDBOptionsParser::VerifyDBOptions(loose, base_db_opt, new_db_opt));
  2481. ASSERT_NOK(
  2482. RocksDBOptionsParser::VerifyDBOptions(exact, base_db_opt, new_db_opt));
  2483. }
  2484. TEST_F(OptionsOldApiTest, GetColumnFamilyOptionsFromStringTest) {
  2485. ColumnFamilyOptions base_cf_opt;
  2486. ColumnFamilyOptions new_cf_opt;
  2487. base_cf_opt.table_factory.reset();
  2488. ConfigOptions config_options;
  2489. config_options.input_strings_escaped = false;
  2490. config_options.ignore_unknown_options = false;
  2491. ASSERT_OK(GetColumnFamilyOptionsFromString(config_options, base_cf_opt, "",
  2492. &new_cf_opt));
  2493. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2494. config_options, base_cf_opt, "write_buffer_size=5", &new_cf_opt));
  2495. ASSERT_EQ(new_cf_opt.write_buffer_size, 5U);
  2496. ASSERT_TRUE(new_cf_opt.table_factory == nullptr);
  2497. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2498. config_options, base_cf_opt, "write_buffer_size=6;", &new_cf_opt));
  2499. ASSERT_EQ(new_cf_opt.write_buffer_size, 6U);
  2500. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2501. config_options, base_cf_opt, " write_buffer_size = 7 ", &new_cf_opt));
  2502. ASSERT_EQ(new_cf_opt.write_buffer_size, 7U);
  2503. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2504. config_options, base_cf_opt, " write_buffer_size = 8 ; ", &new_cf_opt));
  2505. ASSERT_EQ(new_cf_opt.write_buffer_size, 8U);
  2506. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2507. config_options, base_cf_opt,
  2508. "write_buffer_size=9;max_write_buffer_number=10", &new_cf_opt));
  2509. ASSERT_EQ(new_cf_opt.write_buffer_size, 9U);
  2510. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 10);
  2511. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2512. config_options, base_cf_opt,
  2513. "write_buffer_size=11; max_write_buffer_number = 12 ;", &new_cf_opt));
  2514. ASSERT_EQ(new_cf_opt.write_buffer_size, 11U);
  2515. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 12);
  2516. // Wrong name "max_write_buffer_number_"
  2517. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  2518. config_options, base_cf_opt,
  2519. "write_buffer_size=13;max_write_buffer_number_=14;", &new_cf_opt));
  2520. ConfigOptions exact;
  2521. exact.sanity_level = ConfigOptions::kSanityLevelExactMatch;
  2522. ASSERT_OK(
  2523. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  2524. // Comparator from object registry
  2525. std::string kCompName = "reverse_comp";
  2526. ObjectLibrary::Default()->AddFactory<const Comparator>(
  2527. kCompName,
  2528. [](const std::string& /*name*/,
  2529. std::unique_ptr<const Comparator>* /*guard*/,
  2530. std::string* /* errmsg */) { return ReverseBytewiseComparator(); });
  2531. ASSERT_OK(GetColumnFamilyOptionsFromString(config_options, base_cf_opt,
  2532. "comparator=" + kCompName + ";",
  2533. &new_cf_opt));
  2534. ASSERT_EQ(new_cf_opt.comparator, ReverseBytewiseComparator());
  2535. // MergeOperator from object registry
  2536. std::unique_ptr<BytesXOROperator> bxo(new BytesXOROperator());
  2537. std::string kMoName = bxo->Name();
  2538. ASSERT_OK(GetColumnFamilyOptionsFromString(config_options, base_cf_opt,
  2539. "merge_operator=" + kMoName + ";",
  2540. &new_cf_opt));
  2541. ASSERT_EQ(kMoName, std::string(new_cf_opt.merge_operator->Name()));
  2542. // Wrong key/value pair
  2543. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  2544. config_options, base_cf_opt,
  2545. "write_buffer_size=13;max_write_buffer_number;", &new_cf_opt));
  2546. ASSERT_OK(
  2547. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  2548. // Error Paring value
  2549. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  2550. config_options, base_cf_opt,
  2551. "write_buffer_size=13;max_write_buffer_number=;", &new_cf_opt));
  2552. ASSERT_OK(
  2553. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  2554. // Missing option name
  2555. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  2556. config_options, base_cf_opt, "write_buffer_size=13; =100;", &new_cf_opt));
  2557. ASSERT_OK(
  2558. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  2559. const uint64_t kilo = 1024UL;
  2560. const uint64_t mega = 1024 * kilo;
  2561. const uint64_t giga = 1024 * mega;
  2562. const uint64_t tera = 1024 * giga;
  2563. // Units (k)
  2564. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2565. config_options, base_cf_opt, "max_write_buffer_number=15K", &new_cf_opt));
  2566. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 15 * kilo);
  2567. // Units (m)
  2568. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2569. config_options, base_cf_opt,
  2570. "max_write_buffer_number=16m;inplace_update_num_locks=17M", &new_cf_opt));
  2571. ASSERT_EQ(new_cf_opt.max_write_buffer_number, 16 * mega);
  2572. ASSERT_EQ(new_cf_opt.inplace_update_num_locks, 17u * mega);
  2573. // Units (g)
  2574. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2575. config_options, base_cf_opt,
  2576. "write_buffer_size=18g;prefix_extractor=capped:8;"
  2577. "arena_block_size=19G",
  2578. &new_cf_opt));
  2579. ASSERT_EQ(new_cf_opt.write_buffer_size, 18 * giga);
  2580. ASSERT_EQ(new_cf_opt.arena_block_size, 19 * giga);
  2581. ASSERT_TRUE(new_cf_opt.prefix_extractor.get() != nullptr);
  2582. ASSERT_EQ(new_cf_opt.prefix_extractor->AsString(), "rocksdb.CappedPrefix.8");
  2583. // Units (t)
  2584. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2585. config_options, base_cf_opt, "write_buffer_size=20t;arena_block_size=21T",
  2586. &new_cf_opt));
  2587. ASSERT_EQ(new_cf_opt.write_buffer_size, 20 * tera);
  2588. ASSERT_EQ(new_cf_opt.arena_block_size, 21 * tera);
  2589. // Nested block based table options
  2590. // Empty
  2591. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2592. config_options, base_cf_opt,
  2593. "write_buffer_size=10;max_write_buffer_number=16;"
  2594. "block_based_table_factory={};arena_block_size=1024",
  2595. &new_cf_opt));
  2596. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  2597. // Non-empty
  2598. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2599. config_options, base_cf_opt,
  2600. "write_buffer_size=10;max_write_buffer_number=16;"
  2601. "block_based_table_factory={block_cache=1M;block_size=4;};"
  2602. "arena_block_size=1024",
  2603. &new_cf_opt));
  2604. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  2605. // Last one
  2606. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2607. config_options, base_cf_opt,
  2608. "write_buffer_size=10;max_write_buffer_number=16;"
  2609. "block_based_table_factory={block_cache=1M;block_size=4;}",
  2610. &new_cf_opt));
  2611. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  2612. // Mismatch curly braces
  2613. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  2614. config_options, base_cf_opt,
  2615. "write_buffer_size=10;max_write_buffer_number=16;"
  2616. "block_based_table_factory={{{block_size=4;};"
  2617. "arena_block_size=1024",
  2618. &new_cf_opt));
  2619. ASSERT_OK(
  2620. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  2621. // Unexpected chars after closing curly brace
  2622. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  2623. config_options, base_cf_opt,
  2624. "write_buffer_size=10;max_write_buffer_number=16;"
  2625. "block_based_table_factory={block_size=4;}};"
  2626. "arena_block_size=1024",
  2627. &new_cf_opt));
  2628. ASSERT_OK(
  2629. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  2630. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  2631. config_options, base_cf_opt,
  2632. "write_buffer_size=10;max_write_buffer_number=16;"
  2633. "block_based_table_factory={block_size=4;}xdfa;"
  2634. "arena_block_size=1024",
  2635. &new_cf_opt));
  2636. ASSERT_OK(
  2637. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  2638. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  2639. config_options, base_cf_opt,
  2640. "write_buffer_size=10;max_write_buffer_number=16;"
  2641. "block_based_table_factory={block_size=4;}xdfa",
  2642. &new_cf_opt));
  2643. ASSERT_OK(
  2644. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  2645. // Invalid block based table option
  2646. ASSERT_NOK(GetColumnFamilyOptionsFromString(
  2647. config_options, base_cf_opt,
  2648. "write_buffer_size=10;max_write_buffer_number=16;"
  2649. "block_based_table_factory={xx_block_size=4;}",
  2650. &new_cf_opt));
  2651. ASSERT_OK(
  2652. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  2653. ASSERT_OK(GetColumnFamilyOptionsFromString(config_options, base_cf_opt,
  2654. "optimize_filters_for_hits=true",
  2655. &new_cf_opt));
  2656. ASSERT_OK(GetColumnFamilyOptionsFromString(config_options, base_cf_opt,
  2657. "optimize_filters_for_hits=false",
  2658. &new_cf_opt));
  2659. ASSERT_NOK(GetColumnFamilyOptionsFromString(config_options, base_cf_opt,
  2660. "optimize_filters_for_hits=junk",
  2661. &new_cf_opt));
  2662. ASSERT_OK(
  2663. RocksDBOptionsParser::VerifyCFOptions(exact, base_cf_opt, new_cf_opt));
  2664. // Nested plain table options
  2665. // Empty
  2666. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2667. config_options, base_cf_opt,
  2668. "write_buffer_size=10;max_write_buffer_number=16;"
  2669. "plain_table_factory={};arena_block_size=1024",
  2670. &new_cf_opt));
  2671. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  2672. ASSERT_EQ(std::string(new_cf_opt.table_factory->Name()), "PlainTable");
  2673. // Non-empty
  2674. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2675. config_options, base_cf_opt,
  2676. "write_buffer_size=10;max_write_buffer_number=16;"
  2677. "plain_table_factory={user_key_len=66;bloom_bits_per_key=20;};"
  2678. "arena_block_size=1024",
  2679. &new_cf_opt));
  2680. ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
  2681. ASSERT_EQ(std::string(new_cf_opt.table_factory->Name()), "PlainTable");
  2682. // memtable factory
  2683. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2684. config_options, base_cf_opt,
  2685. "write_buffer_size=10;max_write_buffer_number=16;"
  2686. "memtable=skip_list:10;arena_block_size=1024",
  2687. &new_cf_opt));
  2688. ASSERT_TRUE(new_cf_opt.memtable_factory != nullptr);
  2689. ASSERT_TRUE(new_cf_opt.memtable_factory->IsInstanceOf("SkipListFactory"));
  2690. // blob cache
  2691. ASSERT_OK(GetColumnFamilyOptionsFromString(
  2692. config_options, base_cf_opt,
  2693. "blob_cache={capacity=1M;num_shard_bits=4;"
  2694. "strict_capacity_limit=true;high_pri_pool_ratio=0.5;};",
  2695. &new_cf_opt));
  2696. ASSERT_NE(new_cf_opt.blob_cache, nullptr);
  2697. ASSERT_EQ(new_cf_opt.blob_cache->GetCapacity(), 1024UL * 1024UL);
  2698. ASSERT_EQ(static_cast<ShardedCacheBase*>(new_cf_opt.blob_cache.get())
  2699. ->GetNumShardBits(),
  2700. 4);
  2701. ASSERT_EQ(new_cf_opt.blob_cache->HasStrictCapacityLimit(), true);
  2702. ASSERT_EQ(static_cast<LRUCache*>(new_cf_opt.blob_cache.get())
  2703. ->GetHighPriPoolRatio(),
  2704. 0.5);
  2705. }
  2706. TEST_F(OptionsTest, SliceTransformCreateFromString) {
  2707. std::shared_ptr<const SliceTransform> transform = nullptr;
  2708. ConfigOptions config_options;
  2709. config_options.ignore_unsupported_options = false;
  2710. config_options.ignore_unknown_options = false;
  2711. ASSERT_OK(
  2712. SliceTransform::CreateFromString(config_options, "fixed:31", &transform));
  2713. ASSERT_NE(transform, nullptr);
  2714. ASSERT_FALSE(transform->IsInstanceOf("capped"));
  2715. ASSERT_TRUE(transform->IsInstanceOf("fixed"));
  2716. ASSERT_TRUE(transform->IsInstanceOf("rocksdb.FixedPrefix"));
  2717. ASSERT_EQ(transform->GetId(), "rocksdb.FixedPrefix.31");
  2718. ASSERT_OK(SliceTransform::CreateFromString(
  2719. config_options, "rocksdb.FixedPrefix.42", &transform));
  2720. ASSERT_NE(transform, nullptr);
  2721. ASSERT_EQ(transform->GetId(), "rocksdb.FixedPrefix.42");
  2722. ASSERT_OK(SliceTransform::CreateFromString(config_options, "capped:16",
  2723. &transform));
  2724. ASSERT_NE(transform, nullptr);
  2725. ASSERT_FALSE(transform->IsInstanceOf("fixed"));
  2726. ASSERT_TRUE(transform->IsInstanceOf("capped"));
  2727. ASSERT_TRUE(transform->IsInstanceOf("rocksdb.CappedPrefix"));
  2728. ASSERT_EQ(transform->GetId(), "rocksdb.CappedPrefix.16");
  2729. ASSERT_OK(SliceTransform::CreateFromString(
  2730. config_options, "rocksdb.CappedPrefix.42", &transform));
  2731. ASSERT_NE(transform, nullptr);
  2732. ASSERT_EQ(transform->GetId(), "rocksdb.CappedPrefix.42");
  2733. ASSERT_OK(SliceTransform::CreateFromString(config_options, "rocksdb.Noop",
  2734. &transform));
  2735. ASSERT_NE(transform, nullptr);
  2736. ASSERT_NOK(SliceTransform::CreateFromString(config_options,
  2737. "fixed:21:invalid", &transform));
  2738. ASSERT_NOK(SliceTransform::CreateFromString(config_options,
  2739. "capped:21:invalid", &transform));
  2740. ASSERT_NOK(
  2741. SliceTransform::CreateFromString(config_options, "fixed", &transform));
  2742. ASSERT_NOK(
  2743. SliceTransform::CreateFromString(config_options, "capped", &transform));
  2744. ASSERT_NOK(
  2745. SliceTransform::CreateFromString(config_options, "fixed:", &transform));
  2746. ASSERT_NOK(
  2747. SliceTransform::CreateFromString(config_options, "capped:", &transform));
  2748. ASSERT_NOK(SliceTransform::CreateFromString(
  2749. config_options, "rocksdb.FixedPrefix:42", &transform));
  2750. ASSERT_NOK(SliceTransform::CreateFromString(
  2751. config_options, "rocksdb.CappedPrefix:42", &transform));
  2752. ASSERT_NOK(SliceTransform::CreateFromString(
  2753. config_options, "rocksdb.FixedPrefix", &transform));
  2754. ASSERT_NOK(SliceTransform::CreateFromString(
  2755. config_options, "rocksdb.CappedPrefix", &transform));
  2756. ASSERT_NOK(SliceTransform::CreateFromString(
  2757. config_options, "rocksdb.FixedPrefix.", &transform));
  2758. ASSERT_NOK(SliceTransform::CreateFromString(
  2759. config_options, "rocksdb.CappedPrefix.", &transform));
  2760. ASSERT_NOK(
  2761. SliceTransform::CreateFromString(config_options, "invalid", &transform));
  2762. ASSERT_OK(SliceTransform::CreateFromString(
  2763. config_options, "rocksdb.CappedPrefix.11", &transform));
  2764. ASSERT_NE(transform, nullptr);
  2765. ASSERT_EQ(transform->GetId(), "rocksdb.CappedPrefix.11");
  2766. ASSERT_TRUE(transform->IsInstanceOf("capped"));
  2767. ASSERT_TRUE(transform->IsInstanceOf("capped:11"));
  2768. ASSERT_TRUE(transform->IsInstanceOf("rocksdb.CappedPrefix"));
  2769. ASSERT_TRUE(transform->IsInstanceOf("rocksdb.CappedPrefix.11"));
  2770. ASSERT_FALSE(transform->IsInstanceOf("fixed"));
  2771. ASSERT_FALSE(transform->IsInstanceOf("fixed:11"));
  2772. ASSERT_FALSE(transform->IsInstanceOf("rocksdb.FixedPrefix"));
  2773. ASSERT_FALSE(transform->IsInstanceOf("rocksdb.FixedPrefix.11"));
  2774. ASSERT_OK(SliceTransform::CreateFromString(
  2775. config_options, "rocksdb.FixedPrefix.11", &transform));
  2776. ASSERT_TRUE(transform->IsInstanceOf("fixed"));
  2777. ASSERT_TRUE(transform->IsInstanceOf("fixed:11"));
  2778. ASSERT_TRUE(transform->IsInstanceOf("rocksdb.FixedPrefix"));
  2779. ASSERT_TRUE(transform->IsInstanceOf("rocksdb.FixedPrefix.11"));
  2780. ASSERT_FALSE(transform->IsInstanceOf("capped"));
  2781. ASSERT_FALSE(transform->IsInstanceOf("capped:11"));
  2782. ASSERT_FALSE(transform->IsInstanceOf("rocksdb.CappedPrefix"));
  2783. ASSERT_FALSE(transform->IsInstanceOf("rocksdb.CappedPrefix.11"));
  2784. }
  2785. TEST_F(OptionsOldApiTest, GetBlockBasedTableOptionsFromString) {
  2786. BlockBasedTableOptions table_opt;
  2787. BlockBasedTableOptions new_opt;
  2788. ConfigOptions config_options;
  2789. config_options.input_strings_escaped = false;
  2790. config_options.ignore_unknown_options = false;
  2791. config_options.invoke_prepare_options = false;
  2792. config_options.ignore_unsupported_options = false;
  2793. // make sure default values are overwritten by something else
  2794. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  2795. config_options, table_opt,
  2796. "cache_index_and_filter_blocks=1;index_type=kHashSearch;"
  2797. "checksum=kxxHash;no_block_cache=1;"
  2798. "block_cache=1M;block_cache_compressed=1k;block_size=1024;"
  2799. "block_size_deviation=8;block_restart_interval=4;"
  2800. "format_version=5;whole_key_filtering=1;"
  2801. "filter_policy=bloomfilter:4.567:false;",
  2802. &new_opt));
  2803. ASSERT_TRUE(new_opt.cache_index_and_filter_blocks);
  2804. ASSERT_EQ(new_opt.index_type, BlockBasedTableOptions::kHashSearch);
  2805. ASSERT_EQ(new_opt.checksum, ChecksumType::kxxHash);
  2806. ASSERT_TRUE(new_opt.no_block_cache);
  2807. ASSERT_TRUE(new_opt.block_cache != nullptr);
  2808. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 1024UL * 1024UL);
  2809. ASSERT_EQ(new_opt.block_size, 1024UL);
  2810. ASSERT_EQ(new_opt.block_size_deviation, 8);
  2811. ASSERT_EQ(new_opt.block_restart_interval, 4);
  2812. ASSERT_EQ(new_opt.format_version, 5U);
  2813. ASSERT_EQ(new_opt.whole_key_filtering, true);
  2814. ASSERT_TRUE(new_opt.filter_policy != nullptr);
  2815. const BloomFilterPolicy* bfp =
  2816. dynamic_cast<const BloomFilterPolicy*>(new_opt.filter_policy.get());
  2817. EXPECT_EQ(bfp->GetMillibitsPerKey(), 4567);
  2818. EXPECT_EQ(bfp->GetWholeBitsPerKey(), 5);
  2819. // unknown option
  2820. ASSERT_NOK(GetBlockBasedTableOptionsFromString(
  2821. config_options, table_opt,
  2822. "cache_index_and_filter_blocks=1;index_type=kBinarySearch;"
  2823. "bad_option=1",
  2824. &new_opt));
  2825. ASSERT_EQ(static_cast<bool>(table_opt.cache_index_and_filter_blocks),
  2826. new_opt.cache_index_and_filter_blocks);
  2827. ASSERT_EQ(table_opt.index_type, new_opt.index_type);
  2828. // unrecognized index type
  2829. ASSERT_NOK(GetBlockBasedTableOptionsFromString(
  2830. config_options, table_opt,
  2831. "cache_index_and_filter_blocks=1;index_type=kBinarySearchXX", &new_opt));
  2832. ASSERT_EQ(table_opt.cache_index_and_filter_blocks,
  2833. new_opt.cache_index_and_filter_blocks);
  2834. ASSERT_EQ(table_opt.index_type, new_opt.index_type);
  2835. // unrecognized checksum type
  2836. ASSERT_NOK(GetBlockBasedTableOptionsFromString(
  2837. config_options, table_opt,
  2838. "cache_index_and_filter_blocks=1;checksum=kxxHashXX", &new_opt));
  2839. ASSERT_EQ(table_opt.cache_index_and_filter_blocks,
  2840. new_opt.cache_index_and_filter_blocks);
  2841. ASSERT_EQ(table_opt.index_type, new_opt.index_type);
  2842. // unrecognized filter policy name
  2843. ASSERT_NOK(
  2844. GetBlockBasedTableOptionsFromString(config_options, table_opt,
  2845. "cache_index_and_filter_blocks=1;"
  2846. "filter_policy=bloomfilterxx:4:true",
  2847. &new_opt));
  2848. ASSERT_EQ(table_opt.cache_index_and_filter_blocks,
  2849. new_opt.cache_index_and_filter_blocks);
  2850. ASSERT_EQ(table_opt.filter_policy, new_opt.filter_policy);
  2851. // Used to be rejected, now accepted
  2852. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  2853. config_options, table_opt, "filter_policy=bloomfilter:4", &new_opt));
  2854. bfp = dynamic_cast<const BloomFilterPolicy*>(new_opt.filter_policy.get());
  2855. EXPECT_EQ(bfp->GetMillibitsPerKey(), 4000);
  2856. EXPECT_EQ(bfp->GetWholeBitsPerKey(), 4);
  2857. // Check block cache options are overwritten when specified
  2858. // in new format as a struct.
  2859. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  2860. config_options, table_opt,
  2861. "block_cache={capacity=1M;num_shard_bits=4;"
  2862. "strict_capacity_limit=true;high_pri_pool_ratio=0.5;};"
  2863. "block_cache_compressed={capacity=1M;num_shard_bits=4;"
  2864. "strict_capacity_limit=true;high_pri_pool_ratio=0.5;}",
  2865. &new_opt));
  2866. ASSERT_TRUE(new_opt.block_cache != nullptr);
  2867. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 1024UL * 1024UL);
  2868. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(new_opt.block_cache)
  2869. ->GetNumShardBits(),
  2870. 4);
  2871. ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), true);
  2872. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
  2873. ->GetHighPriPoolRatio(),
  2874. 0.5);
  2875. // Set only block cache capacity. Check other values are
  2876. // reset to default values.
  2877. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  2878. config_options, table_opt,
  2879. "block_cache={capacity=2M};"
  2880. "block_cache_compressed={capacity=2M}",
  2881. &new_opt));
  2882. ASSERT_TRUE(new_opt.block_cache != nullptr);
  2883. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 2 * 1024UL * 1024UL);
  2884. // Default values
  2885. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(new_opt.block_cache)
  2886. ->GetNumShardBits(),
  2887. GetDefaultCacheShardBits(new_opt.block_cache->GetCapacity()));
  2888. ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), false);
  2889. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
  2890. ->GetHighPriPoolRatio(),
  2891. 0.5);
  2892. // Set couple of block cache options.
  2893. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  2894. config_options, table_opt,
  2895. "block_cache={num_shard_bits=5;high_pri_pool_ratio=0.5;};"
  2896. "block_cache_compressed={num_shard_bits=5;"
  2897. "high_pri_pool_ratio=0.0;}",
  2898. &new_opt));
  2899. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 0);
  2900. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(new_opt.block_cache)
  2901. ->GetNumShardBits(),
  2902. 5);
  2903. ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), false);
  2904. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
  2905. ->GetHighPriPoolRatio(),
  2906. 0.5);
  2907. // Set couple of block cache options.
  2908. ASSERT_OK(GetBlockBasedTableOptionsFromString(
  2909. config_options, table_opt,
  2910. "block_cache={capacity=1M;num_shard_bits=4;"
  2911. "strict_capacity_limit=true;};"
  2912. "block_cache_compressed={capacity=1M;num_shard_bits=4;"
  2913. "strict_capacity_limit=true;}",
  2914. &new_opt));
  2915. ASSERT_TRUE(new_opt.block_cache != nullptr);
  2916. ASSERT_EQ(new_opt.block_cache->GetCapacity(), 1024UL * 1024UL);
  2917. ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(new_opt.block_cache)
  2918. ->GetNumShardBits(),
  2919. 4);
  2920. ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), true);
  2921. ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
  2922. ->GetHighPriPoolRatio(),
  2923. 0.5);
  2924. }
  2925. TEST_F(OptionsOldApiTest, GetPlainTableOptionsFromString) {
  2926. PlainTableOptions table_opt;
  2927. PlainTableOptions new_opt;
  2928. // make sure default values are overwritten by something else
  2929. ConfigOptions config_options_from_string;
  2930. config_options_from_string.input_strings_escaped = false;
  2931. config_options_from_string.ignore_unknown_options = false;
  2932. config_options_from_string.invoke_prepare_options = false;
  2933. ASSERT_OK(GetPlainTableOptionsFromString(
  2934. config_options_from_string, table_opt,
  2935. "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
  2936. "index_sparseness=8;huge_page_tlb_size=4;encoding_type=kPrefix;"
  2937. "full_scan_mode=true;store_index_in_file=true",
  2938. &new_opt));
  2939. ASSERT_EQ(new_opt.user_key_len, 66u);
  2940. ASSERT_EQ(new_opt.bloom_bits_per_key, 20);
  2941. ASSERT_EQ(new_opt.hash_table_ratio, 0.5);
  2942. ASSERT_EQ(new_opt.index_sparseness, 8);
  2943. ASSERT_EQ(new_opt.huge_page_tlb_size, 4);
  2944. ASSERT_EQ(new_opt.encoding_type, EncodingType::kPrefix);
  2945. ASSERT_TRUE(new_opt.full_scan_mode);
  2946. ASSERT_TRUE(new_opt.store_index_in_file);
  2947. std::unordered_map<std::string, std::string> opt_map;
  2948. ASSERT_OK(StringToMap(
  2949. "user_key_len=55;bloom_bits_per_key=10;huge_page_tlb_size=8;", &opt_map));
  2950. ConfigOptions config_options_from_map;
  2951. config_options_from_map.input_strings_escaped = false;
  2952. config_options_from_map.ignore_unknown_options = false;
  2953. ASSERT_OK(GetPlainTableOptionsFromMap(config_options_from_map, table_opt,
  2954. opt_map, &new_opt));
  2955. ASSERT_EQ(new_opt.user_key_len, 55u);
  2956. ASSERT_EQ(new_opt.bloom_bits_per_key, 10);
  2957. ASSERT_EQ(new_opt.huge_page_tlb_size, 8);
  2958. // unknown option
  2959. ASSERT_NOK(GetPlainTableOptionsFromString(
  2960. config_options_from_string, table_opt,
  2961. "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
  2962. "bad_option=1",
  2963. &new_opt));
  2964. // unrecognized EncodingType
  2965. ASSERT_NOK(GetPlainTableOptionsFromString(
  2966. config_options_from_string, table_opt,
  2967. "user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
  2968. "encoding_type=kPrefixXX",
  2969. &new_opt));
  2970. }
  2971. TEST_F(OptionsOldApiTest, GetOptionsFromStringTest) {
  2972. Options base_options, new_options;
  2973. base_options.write_buffer_size = 20;
  2974. base_options.min_write_buffer_number_to_merge = 15;
  2975. BlockBasedTableOptions block_based_table_options;
  2976. block_based_table_options.cache_index_and_filter_blocks = true;
  2977. base_options.table_factory.reset(
  2978. NewBlockBasedTableFactory(block_based_table_options));
  2979. // Register an Env with object registry.
  2980. ObjectLibrary::Default()->AddFactory<Env>(
  2981. "CustomEnvDefault",
  2982. [](const std::string& /*name*/, std::unique_ptr<Env>* /*env_guard*/,
  2983. std::string* /* errmsg */) {
  2984. static CustomEnv env(Env::Default());
  2985. return &env;
  2986. });
  2987. ASSERT_OK(GetOptionsFromString(
  2988. base_options,
  2989. "write_buffer_size=10;max_write_buffer_number=16;"
  2990. "block_based_table_factory={block_cache=1M;block_size=4;};"
  2991. "compression_opts=4:5:6;create_if_missing=true;max_open_files=1;"
  2992. "bottommost_compression_opts=5:6:7;create_if_missing=true;max_open_files="
  2993. "1;"
  2994. "rate_limiter_bytes_per_sec=1024;env=CustomEnvDefault",
  2995. &new_options));
  2996. ASSERT_EQ(new_options.compression_opts.window_bits, 4);
  2997. ASSERT_EQ(new_options.compression_opts.level, 5);
  2998. ASSERT_EQ(new_options.compression_opts.strategy, 6);
  2999. ASSERT_EQ(new_options.compression_opts.max_dict_bytes, 0u);
  3000. ASSERT_EQ(new_options.compression_opts.zstd_max_train_bytes, 0u);
  3001. ASSERT_EQ(new_options.compression_opts.parallel_threads, 1u);
  3002. ASSERT_EQ(new_options.compression_opts.enabled, false);
  3003. ASSERT_EQ(new_options.compression_opts.use_zstd_dict_trainer, true);
  3004. ASSERT_EQ(new_options.bottommost_compression, kDisableCompressionOption);
  3005. ASSERT_EQ(new_options.bottommost_compression_opts.window_bits, 5);
  3006. ASSERT_EQ(new_options.bottommost_compression_opts.level, 6);
  3007. ASSERT_EQ(new_options.bottommost_compression_opts.strategy, 7);
  3008. ASSERT_EQ(new_options.bottommost_compression_opts.max_dict_bytes, 0u);
  3009. ASSERT_EQ(new_options.bottommost_compression_opts.zstd_max_train_bytes, 0u);
  3010. ASSERT_EQ(new_options.bottommost_compression_opts.parallel_threads, 1u);
  3011. ASSERT_EQ(new_options.bottommost_compression_opts.enabled, false);
  3012. ASSERT_EQ(new_options.bottommost_compression_opts.use_zstd_dict_trainer,
  3013. true);
  3014. ASSERT_EQ(new_options.write_buffer_size, 10U);
  3015. ASSERT_EQ(new_options.max_write_buffer_number, 16);
  3016. auto new_block_based_table_options =
  3017. new_options.table_factory->GetOptions<BlockBasedTableOptions>();
  3018. ASSERT_NE(new_block_based_table_options, nullptr);
  3019. ASSERT_EQ(new_block_based_table_options->block_cache->GetCapacity(),
  3020. 1U << 20);
  3021. ASSERT_EQ(new_block_based_table_options->block_size, 4U);
  3022. // don't overwrite block based table options
  3023. ASSERT_TRUE(new_block_based_table_options->cache_index_and_filter_blocks);
  3024. ASSERT_EQ(new_options.create_if_missing, true);
  3025. ASSERT_EQ(new_options.max_open_files, 1);
  3026. ASSERT_TRUE(new_options.rate_limiter.get() != nullptr);
  3027. Env* newEnv = new_options.env;
  3028. ASSERT_OK(Env::CreateFromString({}, "CustomEnvDefault", &newEnv));
  3029. ASSERT_EQ(newEnv, new_options.env);
  3030. }
  3031. TEST_F(OptionsOldApiTest, DBOptionsSerialization) {
  3032. Options base_options, new_options;
  3033. Random rnd(301);
  3034. // Phase 1: Make big change in base_options
  3035. test::RandomInitDBOptions(&base_options, &rnd);
  3036. // Phase 2: obtain a string from base_option
  3037. std::string base_options_file_content;
  3038. ASSERT_OK(GetStringFromDBOptions(&base_options_file_content, base_options));
  3039. // Phase 3: Set new_options from the derived string and expect
  3040. // new_options == base_options
  3041. const DBOptions base_db_options;
  3042. ConfigOptions db_config_options(base_db_options);
  3043. db_config_options.input_strings_escaped = false;
  3044. db_config_options.ignore_unknown_options = false;
  3045. ASSERT_OK(GetDBOptionsFromString(db_config_options, base_db_options,
  3046. base_options_file_content, &new_options));
  3047. ConfigOptions verify_db_config_options;
  3048. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(verify_db_config_options,
  3049. base_options, new_options));
  3050. }
  3051. TEST_F(OptionsOldApiTest, ColumnFamilyOptionsSerialization) {
  3052. Options options;
  3053. ColumnFamilyOptions base_opt, new_opt;
  3054. Random rnd(302);
  3055. // Phase 1: randomly assign base_opt
  3056. // custom type options
  3057. test::RandomInitCFOptions(&base_opt, options, &rnd);
  3058. // Phase 2: obtain a string from base_opt
  3059. std::string base_options_file_content;
  3060. ASSERT_OK(
  3061. GetStringFromColumnFamilyOptions(&base_options_file_content, base_opt));
  3062. // Phase 3: Set new_opt from the derived string and expect
  3063. // new_opt == base_opt
  3064. ConfigOptions cf_config_options;
  3065. cf_config_options.input_strings_escaped = false;
  3066. cf_config_options.ignore_unknown_options = false;
  3067. ASSERT_OK(
  3068. GetColumnFamilyOptionsFromString(cf_config_options, ColumnFamilyOptions(),
  3069. base_options_file_content, &new_opt));
  3070. ConfigOptions verify_cf_config_options;
  3071. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(verify_cf_config_options,
  3072. base_opt, new_opt));
  3073. if (base_opt.compaction_filter) {
  3074. delete base_opt.compaction_filter;
  3075. }
  3076. }
  3077. class OptionsParserTest : public testing::Test {
  3078. public:
  3079. OptionsParserTest() { fs_.reset(new test::StringFS(FileSystem::Default())); }
  3080. protected:
  3081. std::shared_ptr<test::StringFS> fs_;
  3082. };
  3083. TEST_F(OptionsParserTest, Comment) {
  3084. DBOptions db_opt;
  3085. db_opt.max_open_files = 12345;
  3086. db_opt.max_background_flushes = 301;
  3087. db_opt.max_total_wal_size = 1024;
  3088. ColumnFamilyOptions cf_opt;
  3089. std::string options_file_content =
  3090. "# This is a testing option string.\n"
  3091. "# Currently we only support \"#\" styled comment.\n"
  3092. "\n"
  3093. "[Version]\n"
  3094. " rocksdb_version=3.14.0\n"
  3095. " options_file_version=1\n"
  3096. "[ DBOptions ]\n"
  3097. " # note that we don't support space around \"=\"\n"
  3098. " max_open_files=12345;\n"
  3099. " max_background_flushes=301 # comment after a statement is fine\n"
  3100. " # max_background_flushes=1000 # this line would be ignored\n"
  3101. " # max_background_compactions=2000 # so does this one\n"
  3102. " max_total_wal_size=1024 # keep_log_file_num=1000\n"
  3103. "[CFOptions \"default\"] # column family must be specified\n"
  3104. " # in the correct order\n"
  3105. " # if a section is blank, we will use the default\n";
  3106. const std::string kTestFileName = "test-rocksdb-options.ini";
  3107. ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
  3108. RocksDBOptionsParser parser;
  3109. ASSERT_OK(
  3110. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  3111. ConfigOptions exact;
  3112. exact.input_strings_escaped = false;
  3113. exact.sanity_level = ConfigOptions::kSanityLevelExactMatch;
  3114. ASSERT_OK(
  3115. RocksDBOptionsParser::VerifyDBOptions(exact, *parser.db_opt(), db_opt));
  3116. ASSERT_EQ(parser.NumColumnFamilies(), 1U);
  3117. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
  3118. exact, *parser.GetCFOptions("default"), cf_opt));
  3119. }
  3120. TEST_F(OptionsParserTest, ExtraSpace) {
  3121. std::string options_file_content =
  3122. "# This is a testing option string.\n"
  3123. "# Currently we only support \"#\" styled comment.\n"
  3124. "\n"
  3125. "[ Version ]\n"
  3126. " rocksdb_version = 3.14.0 \n"
  3127. " options_file_version=1 # some comment\n"
  3128. "[DBOptions ] # some comment\n"
  3129. "max_open_files=12345 \n"
  3130. " max_background_flushes = 301 \n"
  3131. " max_total_wal_size = 1024 # keep_log_file_num=1000\n"
  3132. " [CFOptions \"default\" ]\n"
  3133. " # if a section is blank, we will use the default\n";
  3134. const std::string kTestFileName = "test-rocksdb-options.ini";
  3135. ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
  3136. RocksDBOptionsParser parser;
  3137. ASSERT_OK(
  3138. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  3139. }
  3140. TEST_F(OptionsParserTest, MissingDBOptions) {
  3141. std::string options_file_content =
  3142. "# This is a testing option string.\n"
  3143. "# Currently we only support \"#\" styled comment.\n"
  3144. "\n"
  3145. "[Version]\n"
  3146. " rocksdb_version=3.14.0\n"
  3147. " options_file_version=1\n"
  3148. "[CFOptions \"default\"]\n"
  3149. " # if a section is blank, we will use the default\n";
  3150. const std::string kTestFileName = "test-rocksdb-options.ini";
  3151. ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
  3152. RocksDBOptionsParser parser;
  3153. ASSERT_NOK(
  3154. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  3155. ;
  3156. }
  3157. TEST_F(OptionsParserTest, DoubleDBOptions) {
  3158. DBOptions db_opt;
  3159. db_opt.max_open_files = 12345;
  3160. db_opt.max_background_flushes = 301;
  3161. db_opt.max_total_wal_size = 1024;
  3162. ColumnFamilyOptions cf_opt;
  3163. std::string options_file_content =
  3164. "# This is a testing option string.\n"
  3165. "# Currently we only support \"#\" styled comment.\n"
  3166. "\n"
  3167. "[Version]\n"
  3168. " rocksdb_version=3.14.0\n"
  3169. " options_file_version=1\n"
  3170. "[DBOptions]\n"
  3171. " max_open_files=12345\n"
  3172. " max_background_flushes=301\n"
  3173. " max_total_wal_size=1024 # keep_log_file_num=1000\n"
  3174. "[DBOptions]\n"
  3175. "[CFOptions \"default\"]\n"
  3176. " # if a section is blank, we will use the default\n";
  3177. const std::string kTestFileName = "test-rocksdb-options.ini";
  3178. ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
  3179. RocksDBOptionsParser parser;
  3180. ASSERT_NOK(
  3181. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  3182. }
  3183. TEST_F(OptionsParserTest, NoDefaultCFOptions) {
  3184. DBOptions db_opt;
  3185. db_opt.max_open_files = 12345;
  3186. db_opt.max_background_flushes = 301;
  3187. db_opt.max_total_wal_size = 1024;
  3188. ColumnFamilyOptions cf_opt;
  3189. std::string options_file_content =
  3190. "# This is a testing option string.\n"
  3191. "# Currently we only support \"#\" styled comment.\n"
  3192. "\n"
  3193. "[Version]\n"
  3194. " rocksdb_version=3.14.0\n"
  3195. " options_file_version=1\n"
  3196. "[DBOptions]\n"
  3197. " max_open_files=12345\n"
  3198. " max_background_flushes=301\n"
  3199. " max_total_wal_size=1024 # keep_log_file_num=1000\n"
  3200. "[CFOptions \"something_else\"]\n"
  3201. " # if a section is blank, we will use the default\n";
  3202. const std::string kTestFileName = "test-rocksdb-options.ini";
  3203. ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
  3204. RocksDBOptionsParser parser;
  3205. ASSERT_NOK(
  3206. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  3207. }
  3208. TEST_F(OptionsParserTest, DefaultCFOptionsMustBeTheFirst) {
  3209. DBOptions db_opt;
  3210. db_opt.max_open_files = 12345;
  3211. db_opt.max_background_flushes = 301;
  3212. db_opt.max_total_wal_size = 1024;
  3213. ColumnFamilyOptions cf_opt;
  3214. std::string options_file_content =
  3215. "# This is a testing option string.\n"
  3216. "# Currently we only support \"#\" styled comment.\n"
  3217. "\n"
  3218. "[Version]\n"
  3219. " rocksdb_version=3.14.0\n"
  3220. " options_file_version=1\n"
  3221. "[DBOptions]\n"
  3222. " max_open_files=12345\n"
  3223. " max_background_flushes=301\n"
  3224. " max_total_wal_size=1024 # keep_log_file_num=1000\n"
  3225. "[CFOptions \"something_else\"]\n"
  3226. " # if a section is blank, we will use the default\n"
  3227. "[CFOptions \"default\"]\n"
  3228. " # if a section is blank, we will use the default\n";
  3229. const std::string kTestFileName = "test-rocksdb-options.ini";
  3230. ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
  3231. RocksDBOptionsParser parser;
  3232. ASSERT_NOK(
  3233. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  3234. }
  3235. TEST_F(OptionsParserTest, DuplicateCFOptions) {
  3236. DBOptions db_opt;
  3237. db_opt.max_open_files = 12345;
  3238. db_opt.max_background_flushes = 301;
  3239. db_opt.max_total_wal_size = 1024;
  3240. ColumnFamilyOptions cf_opt;
  3241. std::string options_file_content =
  3242. "# This is a testing option string.\n"
  3243. "# Currently we only support \"#\" styled comment.\n"
  3244. "\n"
  3245. "[Version]\n"
  3246. " rocksdb_version=3.14.0\n"
  3247. " options_file_version=1\n"
  3248. "[DBOptions]\n"
  3249. " max_open_files=12345\n"
  3250. " max_background_flushes=301\n"
  3251. " max_total_wal_size=1024 # keep_log_file_num=1000\n"
  3252. "[CFOptions \"default\"]\n"
  3253. "[CFOptions \"something_else\"]\n"
  3254. "[CFOptions \"something_else\"]\n";
  3255. const std::string kTestFileName = "test-rocksdb-options.ini";
  3256. ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
  3257. RocksDBOptionsParser parser;
  3258. ASSERT_NOK(
  3259. parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
  3260. }
  3261. TEST_F(OptionsParserTest, IgnoreUnknownOptions) {
  3262. auto testCase = [&](bool should_ignore, const std::string& version_string) {
  3263. SCOPED_TRACE(std::to_string(should_ignore) + ", " + version_string);
  3264. std::string options_file_content =
  3265. "# This is a testing option string.\n"
  3266. "# Currently we only support \"#\" styled comment.\n"
  3267. "\n"
  3268. "[Version]\n"
  3269. " rocksdb_version=" +
  3270. version_string +
  3271. "\n"
  3272. " options_file_version=1\n"
  3273. "[DBOptions]\n"
  3274. " max_open_files=12345\n"
  3275. " max_background_flushes=301\n"
  3276. " max_total_wal_size=1024 # keep_log_file_num=1000\n"
  3277. " unknown_db_option1=321\n"
  3278. " unknown_db_option2=false\n"
  3279. "[CFOptions \"default\"]\n"
  3280. " unknown_cf_option1=hello\n"
  3281. "[CFOptions \"something_else\"]\n"
  3282. " unknown_cf_option2=world\n"
  3283. " # if a section is blank, we will use the default\n";
  3284. const std::string kTestFileName = "test-rocksdb-options.ini";
  3285. auto s = fs_->FileExists(kTestFileName, IOOptions(), nullptr);
  3286. ASSERT_TRUE(s.ok() || s.IsNotFound());
  3287. if (s.ok()) {
  3288. ASSERT_OK(fs_->DeleteFile(kTestFileName, IOOptions(), nullptr));
  3289. }
  3290. ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
  3291. RocksDBOptionsParser parser;
  3292. ASSERT_NOK(parser.Parse(kTestFileName, fs_.get(), false,
  3293. 4096 /* readahead_size */));
  3294. Status parse_status = parser.Parse(kTestFileName, fs_.get(),
  3295. true /* ignore_unknown_options */,
  3296. 4096 /* readahead_size */);
  3297. if (should_ignore) {
  3298. ASSERT_OK(parse_status);
  3299. } else {
  3300. ASSERT_NOK(parse_status);
  3301. }
  3302. };
  3303. // Same version
  3304. testCase(false, GetRocksVersionAsString());
  3305. // Same except .0 patch
  3306. testCase(false, std::to_string(ROCKSDB_MAJOR) + "." +
  3307. std::to_string(ROCKSDB_MINOR) + ".0");
  3308. // Higher major version
  3309. testCase(true, std::to_string(ROCKSDB_MAJOR + 1) + "." +
  3310. std::to_string(ROCKSDB_MINOR) + ".0");
  3311. // Higher minor version
  3312. testCase(true, std::to_string(ROCKSDB_MAJOR) + "." +
  3313. std::to_string(ROCKSDB_MINOR + 1) + ".0");
  3314. // Higher patch version
  3315. testCase(true, std::to_string(ROCKSDB_MAJOR) + "." +
  3316. std::to_string(ROCKSDB_MINOR) + "." +
  3317. std::to_string(ROCKSDB_PATCH + 1));
  3318. // Lower major version
  3319. testCase(false, std::to_string(ROCKSDB_MAJOR - 1) + "." +
  3320. std::to_string(ROCKSDB_MINOR) + ".0");
  3321. #if ROCKSDB_MINOR > 0
  3322. // Lower minor version
  3323. testCase(false, std::to_string(ROCKSDB_MAJOR) + "." +
  3324. std::to_string(ROCKSDB_MINOR - 1) + ".0");
  3325. #endif
  3326. #if ROCKSDB_PATCH > 0
  3327. // Lower patch version
  3328. testCase(false, std::to_string(ROCKSDB_MAJOR) + "." +
  3329. std::to_string(ROCKSDB_MINOR - 1) + "." +
  3330. std::to_string(ROCKSDB_PATCH - 1));
  3331. #endif
  3332. }
  3333. TEST_F(OptionsParserTest, ParseVersion) {
  3334. DBOptions db_opt;
  3335. db_opt.max_open_files = 12345;
  3336. db_opt.max_background_flushes = 301;
  3337. db_opt.max_total_wal_size = 1024;
  3338. ColumnFamilyOptions cf_opt;
  3339. std::string file_template =
  3340. "# This is a testing option string.\n"
  3341. "# Currently we only support \"#\" styled comment.\n"
  3342. "\n"
  3343. "[Version]\n"
  3344. " rocksdb_version=3.13.1\n"
  3345. " options_file_version=%s\n"
  3346. "[DBOptions]\n"
  3347. "[CFOptions \"default\"]\n";
  3348. const int kLength = 1000;
  3349. char buffer[kLength];
  3350. RocksDBOptionsParser parser;
  3351. const std::vector<std::string> invalid_versions = {
  3352. "a.b.c",
  3353. "3.2.2b",
  3354. "3.-12",
  3355. "3. 1", // only digits and dots are allowed
  3356. "1.2.3.4",
  3357. "1.2.3" // can only contains at most one dot.
  3358. "0", // options_file_version must be at least one
  3359. "3..2",
  3360. ".",
  3361. ".1.2", // must have at least one digit before each dot
  3362. "1.2.",
  3363. "1.",
  3364. "2.34."}; // must have at least one digit after each dot
  3365. for (const auto& iv : invalid_versions) {
  3366. snprintf(buffer, kLength - 1, file_template.c_str(), iv.c_str());
  3367. parser.Reset();
  3368. ASSERT_OK(fs_->WriteToNewFile(iv, buffer));
  3369. ASSERT_NOK(parser.Parse(iv, fs_.get(), false, 0 /* readahead_size */));
  3370. }
  3371. const std::vector<std::string> valid_versions = {
  3372. "1.232", "100", "3.12", "1", "12.3 ", " 1.25 "};
  3373. for (const auto& vv : valid_versions) {
  3374. snprintf(buffer, kLength - 1, file_template.c_str(), vv.c_str());
  3375. parser.Reset();
  3376. ASSERT_OK(fs_->WriteToNewFile(vv, buffer));
  3377. ASSERT_OK(parser.Parse(vv, fs_.get(), false, 0 /* readahead_size */));
  3378. }
  3379. }
  3380. void VerifyCFPointerTypedOptions(
  3381. ColumnFamilyOptions* base_cf_opt, const ColumnFamilyOptions* new_cf_opt,
  3382. const std::unordered_map<std::string, std::string>* new_cf_opt_map) {
  3383. std::string name_buffer;
  3384. ConfigOptions config_options;
  3385. config_options.input_strings_escaped = false;
  3386. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_options, *base_cf_opt,
  3387. *new_cf_opt, new_cf_opt_map));
  3388. // change the name of merge operator back-and-forth
  3389. {
  3390. auto* merge_operator = base_cf_opt->merge_operator
  3391. ->CheckedCast<test::ChanglingMergeOperator>();
  3392. if (merge_operator != nullptr) {
  3393. name_buffer = merge_operator->Name();
  3394. // change the name and expect non-ok status
  3395. merge_operator->SetName("some-other-name");
  3396. ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
  3397. config_options, *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  3398. // change the name back and expect ok status
  3399. merge_operator->SetName(name_buffer);
  3400. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
  3401. config_options, *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  3402. }
  3403. }
  3404. // change the name of the compaction filter factory back-and-forth
  3405. {
  3406. auto* compaction_filter_factory =
  3407. base_cf_opt->compaction_filter_factory
  3408. ->CheckedCast<test::ChanglingCompactionFilterFactory>();
  3409. if (compaction_filter_factory != nullptr) {
  3410. name_buffer = compaction_filter_factory->Name();
  3411. // change the name and expect non-ok status
  3412. compaction_filter_factory->SetName("some-other-name");
  3413. ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
  3414. config_options, *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  3415. // change the name back and expect ok status
  3416. compaction_filter_factory->SetName(name_buffer);
  3417. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
  3418. config_options, *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  3419. }
  3420. }
  3421. // test by setting compaction_filter to nullptr
  3422. {
  3423. auto* tmp_compaction_filter = base_cf_opt->compaction_filter;
  3424. if (tmp_compaction_filter != nullptr) {
  3425. base_cf_opt->compaction_filter = nullptr;
  3426. // set compaction_filter to nullptr and expect non-ok status
  3427. ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
  3428. config_options, *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  3429. // set the value back and expect ok status
  3430. base_cf_opt->compaction_filter = tmp_compaction_filter;
  3431. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
  3432. config_options, *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  3433. }
  3434. }
  3435. // test by setting table_factory to nullptr
  3436. {
  3437. auto tmp_table_factory = base_cf_opt->table_factory;
  3438. if (tmp_table_factory != nullptr) {
  3439. base_cf_opt->table_factory.reset();
  3440. // set table_factory to nullptr and expect non-ok status
  3441. ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
  3442. config_options, *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  3443. // set the value back and expect ok status
  3444. base_cf_opt->table_factory = tmp_table_factory;
  3445. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
  3446. config_options, *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  3447. }
  3448. }
  3449. // test by setting memtable_factory to nullptr
  3450. {
  3451. auto tmp_memtable_factory = base_cf_opt->memtable_factory;
  3452. if (tmp_memtable_factory != nullptr) {
  3453. base_cf_opt->memtable_factory.reset();
  3454. // set memtable_factory to nullptr and expect non-ok status
  3455. ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
  3456. config_options, *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  3457. // set the value back and expect ok status
  3458. base_cf_opt->memtable_factory = tmp_memtable_factory;
  3459. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
  3460. config_options, *base_cf_opt, *new_cf_opt, new_cf_opt_map));
  3461. }
  3462. }
  3463. }
  3464. TEST_F(OptionsParserTest, Readahead) {
  3465. DBOptions base_db_opt;
  3466. std::vector<ColumnFamilyOptions> base_cf_opts;
  3467. base_cf_opts.emplace_back();
  3468. base_cf_opts.emplace_back();
  3469. std::string one_mb_string = std::string(1024 * 1024, 'x');
  3470. std::vector<std::string> cf_names = {"default", one_mb_string};
  3471. const std::string kOptionsFileName = "test-persisted-options.ini";
  3472. ASSERT_OK(PersistRocksDBOptions(WriteOptions(), base_db_opt, cf_names,
  3473. base_cf_opts, kOptionsFileName, fs_.get()));
  3474. uint64_t file_size = 0;
  3475. ASSERT_OK(
  3476. fs_->GetFileSize(kOptionsFileName, IOOptions(), &file_size, nullptr));
  3477. assert(file_size > 0);
  3478. RocksDBOptionsParser parser;
  3479. fs_->num_seq_file_read_ = 0;
  3480. size_t readahead_size = 128 * 1024;
  3481. ASSERT_OK(parser.Parse(kOptionsFileName, fs_.get(), false, readahead_size));
  3482. ASSERT_EQ(fs_->num_seq_file_read_.load(),
  3483. (file_size - 1) / readahead_size + 1);
  3484. fs_->num_seq_file_read_.store(0);
  3485. readahead_size = 1024 * 1024;
  3486. ASSERT_OK(parser.Parse(kOptionsFileName, fs_.get(), false, readahead_size));
  3487. ASSERT_EQ(fs_->num_seq_file_read_.load(),
  3488. (file_size - 1) / readahead_size + 1);
  3489. // Tiny readahead. 8 KB is read each time.
  3490. fs_->num_seq_file_read_.store(0);
  3491. ASSERT_OK(
  3492. parser.Parse(kOptionsFileName, fs_.get(), false, 1 /* readahead_size */));
  3493. ASSERT_GE(fs_->num_seq_file_read_.load(), file_size / (8 * 1024));
  3494. ASSERT_LT(fs_->num_seq_file_read_.load(), file_size / (8 * 1024) * 2);
  3495. // Disable readahead means 512KB readahead.
  3496. fs_->num_seq_file_read_.store(0);
  3497. ASSERT_OK(
  3498. parser.Parse(kOptionsFileName, fs_.get(), false, 0 /* readahead_size */));
  3499. ASSERT_GE(fs_->num_seq_file_read_.load(), (file_size - 1) / (512 * 1024) + 1);
  3500. }
  3501. TEST_F(OptionsParserTest, DumpAndParse) {
  3502. DBOptions base_db_opt;
  3503. std::vector<ColumnFamilyOptions> base_cf_opts;
  3504. std::vector<std::string> cf_names = {"default",
  3505. "cf1",
  3506. "cf2",
  3507. "cf3",
  3508. "c:f:4:4:4"
  3509. "p\\i\\k\\a\\chu\\\\\\",
  3510. "###rocksdb#1-testcf#2###"};
  3511. const int num_cf = static_cast<int>(cf_names.size());
  3512. Random rnd(302);
  3513. test::RandomInitDBOptions(&base_db_opt, &rnd);
  3514. base_db_opt.db_log_dir += "/#odd #but #could #happen #path #/\\\\#OMG";
  3515. BlockBasedTableOptions special_bbto;
  3516. special_bbto.cache_index_and_filter_blocks = true;
  3517. special_bbto.block_size = 999999;
  3518. for (int c = 0; c < num_cf; ++c) {
  3519. ColumnFamilyOptions cf_opt;
  3520. Random cf_rnd(0xFB + c);
  3521. test::RandomInitCFOptions(&cf_opt, base_db_opt, &cf_rnd);
  3522. if (c < 4) {
  3523. cf_opt.prefix_extractor.reset(test::RandomSliceTransform(&rnd, c));
  3524. }
  3525. if (c < 3) {
  3526. cf_opt.table_factory.reset(test::RandomTableFactory(&rnd, c));
  3527. } else if (c == 4) {
  3528. cf_opt.table_factory.reset(NewBlockBasedTableFactory(special_bbto));
  3529. } else if (c == 5) {
  3530. // A table factory that doesn't support deserialization should be
  3531. // supported.
  3532. cf_opt.table_factory.reset(new UnregisteredTableFactory());
  3533. }
  3534. base_cf_opts.emplace_back(cf_opt);
  3535. }
  3536. const std::string kOptionsFileName = "test-persisted-options.ini";
  3537. // Use default for escaped(true), unknown(false) and check (exact)
  3538. ConfigOptions config_options;
  3539. ASSERT_OK(PersistRocksDBOptions(WriteOptions(), base_db_opt, cf_names,
  3540. base_cf_opts, kOptionsFileName, fs_.get()));
  3541. RocksDBOptionsParser parser;
  3542. ASSERT_OK(parser.Parse(config_options, kOptionsFileName, fs_.get()));
  3543. // Make sure block-based table factory options was deserialized correctly
  3544. std::shared_ptr<TableFactory> ttf = (*parser.cf_opts())[4].table_factory;
  3545. ASSERT_EQ(TableFactory::kBlockBasedTableName(), std::string(ttf->Name()));
  3546. const auto parsed_bbto = ttf->GetOptions<BlockBasedTableOptions>();
  3547. ASSERT_NE(parsed_bbto, nullptr);
  3548. ASSERT_EQ(special_bbto.block_size, parsed_bbto->block_size);
  3549. ASSERT_EQ(special_bbto.cache_index_and_filter_blocks,
  3550. parsed_bbto->cache_index_and_filter_blocks);
  3551. ASSERT_OK(RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
  3552. config_options, base_db_opt, cf_names, base_cf_opts, kOptionsFileName,
  3553. fs_.get()));
  3554. ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(
  3555. config_options, *parser.db_opt(), base_db_opt));
  3556. for (int c = 0; c < num_cf; ++c) {
  3557. const auto* cf_opt = parser.GetCFOptions(cf_names[c]);
  3558. ASSERT_NE(cf_opt, nullptr);
  3559. ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
  3560. config_options, base_cf_opts[c], *cf_opt,
  3561. &(parser.cf_opt_maps()->at(c))));
  3562. }
  3563. // Further verify pointer-typed options
  3564. for (int c = 0; c < num_cf; ++c) {
  3565. const auto* cf_opt = parser.GetCFOptions(cf_names[c]);
  3566. ASSERT_NE(cf_opt, nullptr);
  3567. VerifyCFPointerTypedOptions(&base_cf_opts[c], cf_opt,
  3568. &(parser.cf_opt_maps()->at(c)));
  3569. }
  3570. ASSERT_EQ(parser.GetCFOptions("does not exist"), nullptr);
  3571. base_db_opt.max_open_files++;
  3572. ASSERT_NOK(RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
  3573. config_options, base_db_opt, cf_names, base_cf_opts, kOptionsFileName,
  3574. fs_.get()));
  3575. for (int c = 0; c < num_cf; ++c) {
  3576. if (base_cf_opts[c].compaction_filter) {
  3577. delete base_cf_opts[c].compaction_filter;
  3578. }
  3579. }
  3580. }
  3581. TEST_F(OptionsParserTest, DifferentDefault) {
  3582. const std::string kOptionsFileName = "test-persisted-options.ini";
  3583. ColumnFamilyOptions cf_level_opts;
  3584. ASSERT_EQ(CompactionPri::kMinOverlappingRatio, cf_level_opts.compaction_pri);
  3585. cf_level_opts.OptimizeLevelStyleCompaction();
  3586. ColumnFamilyOptions cf_univ_opts;
  3587. cf_univ_opts.OptimizeUniversalStyleCompaction();
  3588. ASSERT_OK(PersistRocksDBOptions(
  3589. WriteOptions(), DBOptions(), {"default", "universal"},
  3590. {cf_level_opts, cf_univ_opts}, kOptionsFileName, fs_.get()));
  3591. RocksDBOptionsParser parser;
  3592. ASSERT_OK(parser.Parse(kOptionsFileName, fs_.get(), false,
  3593. 4096 /* readahead_size */));
  3594. {
  3595. Options old_default_opts;
  3596. old_default_opts.OldDefaults();
  3597. ASSERT_EQ(10 * 1048576, old_default_opts.max_bytes_for_level_base);
  3598. ASSERT_EQ(5000, old_default_opts.max_open_files);
  3599. ASSERT_EQ(2 * 1024U * 1024U, old_default_opts.delayed_write_rate);
  3600. ASSERT_EQ(WALRecoveryMode::kTolerateCorruptedTailRecords,
  3601. old_default_opts.wal_recovery_mode);
  3602. }
  3603. {
  3604. Options old_default_opts;
  3605. old_default_opts.OldDefaults(4, 6);
  3606. ASSERT_EQ(10 * 1048576, old_default_opts.max_bytes_for_level_base);
  3607. ASSERT_EQ(5000, old_default_opts.max_open_files);
  3608. }
  3609. {
  3610. Options old_default_opts;
  3611. old_default_opts.OldDefaults(4, 7);
  3612. ASSERT_NE(10 * 1048576, old_default_opts.max_bytes_for_level_base);
  3613. ASSERT_NE(4, old_default_opts.table_cache_numshardbits);
  3614. ASSERT_EQ(5000, old_default_opts.max_open_files);
  3615. ASSERT_EQ(2 * 1024U * 1024U, old_default_opts.delayed_write_rate);
  3616. }
  3617. {
  3618. ColumnFamilyOptions old_default_cf_opts;
  3619. old_default_cf_opts.OldDefaults();
  3620. ASSERT_EQ(2 * 1048576, old_default_cf_opts.target_file_size_base);
  3621. ASSERT_EQ(4 << 20, old_default_cf_opts.write_buffer_size);
  3622. ASSERT_EQ(2 * 1048576, old_default_cf_opts.target_file_size_base);
  3623. ASSERT_EQ(0, old_default_cf_opts.soft_pending_compaction_bytes_limit);
  3624. ASSERT_EQ(0, old_default_cf_opts.hard_pending_compaction_bytes_limit);
  3625. ASSERT_EQ(CompactionPri::kByCompensatedSize,
  3626. old_default_cf_opts.compaction_pri);
  3627. }
  3628. {
  3629. ColumnFamilyOptions old_default_cf_opts;
  3630. old_default_cf_opts.OldDefaults(4, 6);
  3631. ASSERT_EQ(2 * 1048576, old_default_cf_opts.target_file_size_base);
  3632. ASSERT_EQ(CompactionPri::kByCompensatedSize,
  3633. old_default_cf_opts.compaction_pri);
  3634. }
  3635. {
  3636. ColumnFamilyOptions old_default_cf_opts;
  3637. old_default_cf_opts.OldDefaults(4, 7);
  3638. ASSERT_NE(2 * 1048576, old_default_cf_opts.target_file_size_base);
  3639. ASSERT_EQ(CompactionPri::kByCompensatedSize,
  3640. old_default_cf_opts.compaction_pri);
  3641. }
  3642. {
  3643. Options old_default_opts;
  3644. old_default_opts.OldDefaults(5, 1);
  3645. ASSERT_EQ(2 * 1024U * 1024U, old_default_opts.delayed_write_rate);
  3646. }
  3647. {
  3648. Options old_default_opts;
  3649. old_default_opts.OldDefaults(5, 2);
  3650. ASSERT_EQ(16 * 1024U * 1024U, old_default_opts.delayed_write_rate);
  3651. ASSERT_TRUE(old_default_opts.compaction_pri ==
  3652. CompactionPri::kByCompensatedSize);
  3653. }
  3654. {
  3655. Options old_default_opts;
  3656. old_default_opts.OldDefaults(5, 18);
  3657. ASSERT_TRUE(old_default_opts.compaction_pri ==
  3658. CompactionPri::kByCompensatedSize);
  3659. }
  3660. Options small_opts;
  3661. small_opts.OptimizeForSmallDb();
  3662. ASSERT_EQ(2 << 20, small_opts.write_buffer_size);
  3663. ASSERT_EQ(5000, small_opts.max_open_files);
  3664. }
  3665. class OptionsSanityCheckTest : public OptionsParserTest,
  3666. public ::testing::WithParamInterface<bool> {
  3667. protected:
  3668. ConfigOptions config_options_;
  3669. public:
  3670. OptionsSanityCheckTest() {
  3671. config_options_.ignore_unknown_options = false;
  3672. config_options_.ignore_unsupported_options = GetParam();
  3673. config_options_.input_strings_escaped = true;
  3674. }
  3675. protected:
  3676. Status SanityCheckOptions(const DBOptions& db_opts,
  3677. const ColumnFamilyOptions& cf_opts,
  3678. ConfigOptions::SanityLevel level) {
  3679. config_options_.sanity_level = level;
  3680. return RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
  3681. config_options_, db_opts, {"default"}, {cf_opts}, kOptionsFileName,
  3682. fs_.get());
  3683. }
  3684. Status SanityCheckCFOptions(const ColumnFamilyOptions& cf_opts,
  3685. ConfigOptions::SanityLevel level) {
  3686. return SanityCheckOptions(DBOptions(), cf_opts, level);
  3687. }
  3688. void SanityCheckCFOptions(const ColumnFamilyOptions& opts, bool exact) {
  3689. ASSERT_OK(SanityCheckCFOptions(
  3690. opts, ConfigOptions::kSanityLevelLooselyCompatible));
  3691. ASSERT_OK(SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelNone));
  3692. if (exact) {
  3693. ASSERT_OK(
  3694. SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3695. } else {
  3696. ASSERT_NOK(
  3697. SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3698. }
  3699. }
  3700. Status SanityCheckDBOptions(const DBOptions& db_opts,
  3701. ConfigOptions::SanityLevel level) {
  3702. return SanityCheckOptions(db_opts, ColumnFamilyOptions(), level);
  3703. }
  3704. void SanityCheckDBOptions(const DBOptions& opts, bool exact) {
  3705. ASSERT_OK(SanityCheckDBOptions(
  3706. opts, ConfigOptions::kSanityLevelLooselyCompatible));
  3707. ASSERT_OK(SanityCheckDBOptions(opts, ConfigOptions::kSanityLevelNone));
  3708. if (exact) {
  3709. ASSERT_OK(
  3710. SanityCheckDBOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3711. } else {
  3712. ASSERT_NOK(
  3713. SanityCheckDBOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3714. }
  3715. }
  3716. Status PersistOptions(const DBOptions& db_opts,
  3717. const ColumnFamilyOptions& cf_opts) {
  3718. Status s = fs_->DeleteFile(kOptionsFileName, IOOptions(), nullptr);
  3719. if (!s.ok()) {
  3720. return s;
  3721. }
  3722. return PersistRocksDBOptions(WriteOptions(), db_opts, {"default"},
  3723. {cf_opts}, kOptionsFileName, fs_.get());
  3724. }
  3725. Status PersistCFOptions(const ColumnFamilyOptions& cf_opts) {
  3726. return PersistOptions(DBOptions(), cf_opts);
  3727. }
  3728. Status PersistDBOptions(const DBOptions& db_opts) {
  3729. return PersistOptions(db_opts, ColumnFamilyOptions());
  3730. }
  3731. const std::string kOptionsFileName = "OPTIONS";
  3732. };
  3733. TEST_P(OptionsSanityCheckTest, MergeOperatorErrorMessage) {
  3734. ColumnFamilyOptions opts;
  3735. Random rnd(301);
  3736. opts.merge_operator.reset(test::RandomMergeOperator(&rnd));
  3737. std::string merge_op_name = opts.merge_operator->Name();
  3738. ASSERT_OK(PersistCFOptions(opts));
  3739. // Test when going from merge operator -> nullptr
  3740. opts.merge_operator = nullptr;
  3741. Status s =
  3742. SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelLooselyCompatible);
  3743. ASSERT_TRUE(s.IsInvalidArgument());
  3744. std::string err_msg = s.ToString();
  3745. std::string specified = "The specified one is " + kNullptrString;
  3746. std::string persisted = "the persisted one is " + merge_op_name;
  3747. ASSERT_TRUE(err_msg.find(specified) != std::string::npos);
  3748. ASSERT_TRUE(err_msg.find(persisted) != std::string::npos);
  3749. // Test when using a different merge operator
  3750. opts.merge_operator.reset(test::RandomMergeOperator(&rnd));
  3751. s = SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelLooselyCompatible);
  3752. ASSERT_TRUE(s.IsInvalidArgument());
  3753. err_msg = s.ToString();
  3754. specified =
  3755. "The specified one is " + std::string(opts.merge_operator->Name());
  3756. persisted = "the persisted one is " + merge_op_name;
  3757. ASSERT_TRUE(err_msg.find(specified) != std::string::npos);
  3758. ASSERT_TRUE(err_msg.find(persisted) != std::string::npos);
  3759. }
  3760. TEST_P(OptionsSanityCheckTest, CFOptionsSanityCheck) {
  3761. ColumnFamilyOptions opts;
  3762. Random rnd(301);
  3763. // default ColumnFamilyOptions
  3764. {
  3765. ASSERT_OK(PersistCFOptions(opts));
  3766. ASSERT_OK(
  3767. SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3768. }
  3769. // prefix_extractor
  3770. {
  3771. // Okay to change prefix_extractor form nullptr to non-nullptr
  3772. ASSERT_EQ(opts.prefix_extractor.get(), nullptr);
  3773. opts.prefix_extractor.reset(NewCappedPrefixTransform(10));
  3774. ASSERT_OK(SanityCheckCFOptions(
  3775. opts, ConfigOptions::kSanityLevelLooselyCompatible));
  3776. ASSERT_OK(SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelNone));
  3777. // persist the change
  3778. ASSERT_OK(PersistCFOptions(opts));
  3779. ASSERT_OK(
  3780. SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3781. // use same prefix extractor but with different parameter
  3782. opts.prefix_extractor.reset(NewCappedPrefixTransform(15));
  3783. // expect pass only in
  3784. // ConfigOptions::kSanityLevelLooselyCompatible
  3785. ASSERT_NOK(
  3786. SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3787. ASSERT_OK(SanityCheckCFOptions(
  3788. opts, ConfigOptions::kSanityLevelLooselyCompatible));
  3789. ASSERT_OK(SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelNone));
  3790. // repeat the test with FixedPrefixTransform
  3791. opts.prefix_extractor.reset(NewFixedPrefixTransform(10));
  3792. ASSERT_NOK(
  3793. SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3794. ASSERT_OK(SanityCheckCFOptions(
  3795. opts, ConfigOptions::kSanityLevelLooselyCompatible));
  3796. ASSERT_OK(SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelNone));
  3797. // persist the change of prefix_extractor
  3798. ASSERT_OK(PersistCFOptions(opts));
  3799. ASSERT_OK(
  3800. SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3801. // use same prefix extractor but with different parameter
  3802. opts.prefix_extractor.reset(NewFixedPrefixTransform(15));
  3803. // expect pass only in
  3804. // ConfigOptions::kSanityLevelLooselyCompatible
  3805. SanityCheckCFOptions(opts, false);
  3806. // Change prefix extractor from non-nullptr to nullptr
  3807. opts.prefix_extractor.reset();
  3808. // expect pass as it's safe to change prefix_extractor
  3809. // from non-null to null
  3810. ASSERT_OK(SanityCheckCFOptions(
  3811. opts, ConfigOptions::kSanityLevelLooselyCompatible));
  3812. ASSERT_OK(SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelNone));
  3813. }
  3814. // persist the change
  3815. ASSERT_OK(PersistCFOptions(opts));
  3816. ASSERT_OK(SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3817. // table_factory
  3818. {
  3819. for (int tb = 0; tb <= 2; ++tb) {
  3820. // change the table factory
  3821. opts.table_factory.reset(test::RandomTableFactory(&rnd, tb));
  3822. ASSERT_NOK(SanityCheckCFOptions(
  3823. opts, ConfigOptions::kSanityLevelLooselyCompatible));
  3824. ASSERT_OK(SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelNone));
  3825. // persist the change
  3826. ASSERT_OK(PersistCFOptions(opts));
  3827. ASSERT_OK(
  3828. SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3829. }
  3830. }
  3831. // merge_operator
  3832. {
  3833. // Test when going from nullptr -> merge operator
  3834. opts.merge_operator.reset(test::RandomMergeOperator(&rnd));
  3835. ASSERT_OK(SanityCheckCFOptions(
  3836. opts, ConfigOptions::kSanityLevelLooselyCompatible));
  3837. ASSERT_OK(SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelNone));
  3838. // persist the change
  3839. ASSERT_OK(PersistCFOptions(opts));
  3840. SanityCheckCFOptions(opts, config_options_.ignore_unsupported_options);
  3841. for (int test = 0; test < 5; ++test) {
  3842. // change the merge operator
  3843. opts.merge_operator.reset(test::RandomMergeOperator(&rnd));
  3844. ASSERT_NOK(SanityCheckCFOptions(
  3845. opts, ConfigOptions::kSanityLevelLooselyCompatible));
  3846. ASSERT_OK(SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelNone));
  3847. // persist the change
  3848. ASSERT_OK(PersistCFOptions(opts));
  3849. SanityCheckCFOptions(opts, config_options_.ignore_unsupported_options);
  3850. }
  3851. // Test when going from merge operator -> nullptr
  3852. opts.merge_operator = nullptr;
  3853. ASSERT_NOK(SanityCheckCFOptions(
  3854. opts, ConfigOptions::kSanityLevelLooselyCompatible));
  3855. ASSERT_OK(SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelNone));
  3856. // persist the change
  3857. ASSERT_OK(PersistCFOptions(opts));
  3858. SanityCheckCFOptions(opts, true);
  3859. }
  3860. // compaction_filter
  3861. {
  3862. for (int test = 0; test < 5; ++test) {
  3863. // change the compaction filter
  3864. opts.compaction_filter = test::RandomCompactionFilter(&rnd);
  3865. SanityCheckCFOptions(opts, false);
  3866. // persist the change
  3867. ASSERT_OK(PersistCFOptions(opts));
  3868. SanityCheckCFOptions(opts, config_options_.ignore_unsupported_options);
  3869. delete opts.compaction_filter;
  3870. opts.compaction_filter = nullptr;
  3871. }
  3872. }
  3873. // compaction_filter_factory
  3874. {
  3875. for (int test = 0; test < 5; ++test) {
  3876. // change the compaction filter factory
  3877. opts.compaction_filter_factory.reset(
  3878. test::RandomCompactionFilterFactory(&rnd));
  3879. SanityCheckCFOptions(opts, false);
  3880. // persist the change
  3881. ASSERT_OK(PersistCFOptions(opts));
  3882. SanityCheckCFOptions(opts, config_options_.ignore_unsupported_options);
  3883. }
  3884. }
  3885. // persist_user_defined_timestamps
  3886. {
  3887. // Test change from true to false not allowed in loose and exact mode.
  3888. opts.persist_user_defined_timestamps = false;
  3889. ASSERT_NOK(SanityCheckCFOptions(
  3890. opts, ConfigOptions::kSanityLevelLooselyCompatible));
  3891. ASSERT_NOK(
  3892. SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3893. // persist the change
  3894. ASSERT_OK(PersistCFOptions(opts));
  3895. SanityCheckCFOptions(opts, config_options_.ignore_unsupported_options);
  3896. // Test change from false to true not allowed in loose and exact mode.
  3897. opts.persist_user_defined_timestamps = true;
  3898. ASSERT_NOK(SanityCheckCFOptions(
  3899. opts, ConfigOptions::kSanityLevelLooselyCompatible));
  3900. ASSERT_NOK(
  3901. SanityCheckCFOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3902. // persist the change
  3903. ASSERT_OK(PersistCFOptions(opts));
  3904. }
  3905. }
  3906. TEST_P(OptionsSanityCheckTest, DBOptionsSanityCheck) {
  3907. DBOptions opts;
  3908. Random rnd(301);
  3909. // default DBOptions
  3910. {
  3911. ASSERT_OK(PersistDBOptions(opts));
  3912. ASSERT_OK(
  3913. SanityCheckDBOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3914. }
  3915. // File checksum generator
  3916. {
  3917. class MockFileChecksumGenFactory : public FileChecksumGenFactory {
  3918. public:
  3919. static const char* kClassName() { return "Mock"; }
  3920. const char* Name() const override { return kClassName(); }
  3921. std::unique_ptr<FileChecksumGenerator> CreateFileChecksumGenerator(
  3922. const FileChecksumGenContext& /*context*/) override {
  3923. return nullptr;
  3924. }
  3925. };
  3926. // Okay to change file_checksum_gen_factory form nullptr to non-nullptr
  3927. ASSERT_EQ(opts.file_checksum_gen_factory.get(), nullptr);
  3928. opts.file_checksum_gen_factory.reset(new MockFileChecksumGenFactory());
  3929. // persist the change
  3930. ASSERT_OK(PersistDBOptions(opts));
  3931. SanityCheckDBOptions(opts, config_options_.ignore_unsupported_options);
  3932. // Change file_checksum_gen_factory from non-nullptr to nullptr
  3933. opts.file_checksum_gen_factory.reset();
  3934. // expect pass as it's safe to change file_checksum_gen_factory
  3935. // from non-null to null
  3936. SanityCheckDBOptions(opts, false);
  3937. }
  3938. // persist the change
  3939. ASSERT_OK(PersistDBOptions(opts));
  3940. ASSERT_OK(SanityCheckDBOptions(opts, ConfigOptions::kSanityLevelExactMatch));
  3941. }
  3942. namespace {
  3943. bool IsEscapedString(const std::string& str) {
  3944. for (size_t i = 0; i < str.size(); ++i) {
  3945. if (str[i] == '\\') {
  3946. // since we already handle those two consecutive '\'s in
  3947. // the next if-then branch, any '\' appear at the end
  3948. // of an escaped string in such case is not valid.
  3949. if (i == str.size() - 1) {
  3950. return false;
  3951. }
  3952. if (str[i + 1] == '\\') {
  3953. // if there're two consecutive '\'s, skip the second one.
  3954. i++;
  3955. continue;
  3956. }
  3957. switch (str[i + 1]) {
  3958. case ':':
  3959. case '\\':
  3960. case '#':
  3961. continue;
  3962. default:
  3963. // if true, '\' together with str[i + 1] is not a valid escape.
  3964. if (UnescapeChar(str[i + 1]) == str[i + 1]) {
  3965. return false;
  3966. }
  3967. }
  3968. } else if (isSpecialChar(str[i]) && (i == 0 || str[i - 1] != '\\')) {
  3969. return false;
  3970. }
  3971. }
  3972. return true;
  3973. }
  3974. } // namespace
  3975. TEST_F(OptionsParserTest, IntegerParsing) {
  3976. ASSERT_EQ(ParseUint64("18446744073709551615"), 18446744073709551615U);
  3977. ASSERT_EQ(ParseUint32("4294967295"), 4294967295U);
  3978. ASSERT_EQ(ParseSizeT("18446744073709551615"), 18446744073709551615U);
  3979. ASSERT_EQ(ParseInt64("9223372036854775807"), 9223372036854775807);
  3980. ASSERT_EQ(ParseInt64("-9223372036854775808"),
  3981. std::numeric_limits<int64_t>::min());
  3982. ASSERT_EQ(ParseInt32("2147483647"), 2147483647);
  3983. ASSERT_EQ(ParseInt32("-2147483648"), std::numeric_limits<int32_t>::min());
  3984. ASSERT_EQ(ParseInt("-32767"), -32767);
  3985. ASSERT_EQ(ParseDouble("-1.234567"), -1.234567);
  3986. }
  3987. TEST_F(OptionsParserTest, EscapeOptionString) {
  3988. ASSERT_EQ(UnescapeOptionString(
  3989. "This is a test string with \\# \\: and \\\\ escape chars."),
  3990. "This is a test string with # : and \\ escape chars.");
  3991. ASSERT_EQ(
  3992. EscapeOptionString("This is a test string with # : and \\ escape chars."),
  3993. "This is a test string with \\# \\: and \\\\ escape chars.");
  3994. std::string readible_chars =
  3995. "A String like this \"1234567890-=_)(*&^%$#@!ertyuiop[]{POIU"
  3996. "YTREWQasdfghjkl;':LKJHGFDSAzxcvbnm,.?>"
  3997. "<MNBVCXZ\\\" should be okay to \\#\\\\\\:\\#\\#\\#\\ "
  3998. "be serialized and deserialized";
  3999. std::string escaped_string = EscapeOptionString(readible_chars);
  4000. ASSERT_TRUE(IsEscapedString(escaped_string));
  4001. // This two transformations should be canceled and should output
  4002. // the original input.
  4003. ASSERT_EQ(UnescapeOptionString(escaped_string), readible_chars);
  4004. std::string all_chars;
  4005. for (unsigned char c = 0;; ++c) {
  4006. all_chars += c;
  4007. if (c == 255) {
  4008. break;
  4009. }
  4010. }
  4011. escaped_string = EscapeOptionString(all_chars);
  4012. ASSERT_TRUE(IsEscapedString(escaped_string));
  4013. ASSERT_EQ(UnescapeOptionString(escaped_string), all_chars);
  4014. ASSERT_EQ(RocksDBOptionsParser::TrimAndRemoveComment(
  4015. " A simple statement with a comment. # like this :)"),
  4016. "A simple statement with a comment.");
  4017. ASSERT_EQ(RocksDBOptionsParser::TrimAndRemoveComment(
  4018. "Escape \\# and # comment together ."),
  4019. "Escape \\# and");
  4020. }
  4021. static void TestAndCompareOption(const ConfigOptions& config_options,
  4022. const OptionTypeInfo& opt_info,
  4023. const std::string& opt_name, void* base_ptr,
  4024. void* comp_ptr, bool strip = false) {
  4025. std::string result, mismatch;
  4026. ASSERT_OK(opt_info.Serialize(config_options, opt_name, base_ptr, &result));
  4027. if (strip) {
  4028. ASSERT_EQ(result.at(0), '{');
  4029. ASSERT_EQ(result.at(result.size() - 1), '}');
  4030. result = result.substr(1, result.size() - 2);
  4031. }
  4032. ASSERT_OK(opt_info.Parse(config_options, opt_name, result, comp_ptr));
  4033. ASSERT_TRUE(opt_info.AreEqual(config_options, opt_name, base_ptr, comp_ptr,
  4034. &mismatch));
  4035. }
  4036. static void TestParseAndCompareOption(const ConfigOptions& config_options,
  4037. const OptionTypeInfo& opt_info,
  4038. const std::string& opt_name,
  4039. const std::string& opt_value,
  4040. void* base_ptr, void* comp_ptr,
  4041. bool strip = false) {
  4042. ASSERT_OK(opt_info.Parse(config_options, opt_name, opt_value, base_ptr));
  4043. TestAndCompareOption(config_options, opt_info, opt_name, base_ptr, comp_ptr,
  4044. strip);
  4045. }
  4046. template <typename T>
  4047. void TestOptInfo(const ConfigOptions& config_options, OptionType opt_type,
  4048. T* base, T* comp) {
  4049. std::string result;
  4050. OptionTypeInfo opt_info(0, opt_type);
  4051. ASSERT_FALSE(opt_info.AreEqual(config_options, "base", base, comp, &result));
  4052. ASSERT_EQ(result, "base");
  4053. ASSERT_NE(*base, *comp);
  4054. TestAndCompareOption(config_options, opt_info, "base", base, comp);
  4055. ASSERT_EQ(*base, *comp);
  4056. }
  4057. class OptionTypeInfoTest : public testing::Test {};
  4058. TEST_F(OptionTypeInfoTest, BasicTypes) {
  4059. ConfigOptions config_options;
  4060. {
  4061. bool a = true, b = false;
  4062. TestOptInfo(config_options, OptionType::kBoolean, &a, &b);
  4063. }
  4064. {
  4065. int a = 100, b = 200;
  4066. TestOptInfo(config_options, OptionType::kInt, &a, &b);
  4067. }
  4068. {
  4069. int32_t a = 100, b = 200;
  4070. TestOptInfo(config_options, OptionType::kInt32T, &a, &b);
  4071. }
  4072. {
  4073. int64_t a = 100, b = 200;
  4074. TestOptInfo(config_options, OptionType::kInt64T, &a, &b);
  4075. }
  4076. {
  4077. unsigned int a = 100, b = 200;
  4078. TestOptInfo(config_options, OptionType::kUInt, &a, &b);
  4079. }
  4080. {
  4081. uint32_t a = 100, b = 200;
  4082. TestOptInfo(config_options, OptionType::kUInt32T, &a, &b);
  4083. }
  4084. {
  4085. uint64_t a = 100, b = 200;
  4086. TestOptInfo(config_options, OptionType::kUInt64T, &a, &b);
  4087. }
  4088. {
  4089. size_t a = 100, b = 200;
  4090. TestOptInfo(config_options, OptionType::kSizeT, &a, &b);
  4091. }
  4092. {
  4093. std::string a = "100", b = "200";
  4094. TestOptInfo(config_options, OptionType::kString, &a, &b);
  4095. }
  4096. {
  4097. double a = 1.0, b = 2.0;
  4098. TestOptInfo(config_options, OptionType::kDouble, &a, &b);
  4099. }
  4100. }
  4101. TEST_F(OptionTypeInfoTest, TestInvalidArgs) {
  4102. ConfigOptions config_options;
  4103. bool b;
  4104. int i;
  4105. int32_t i32;
  4106. int64_t i64;
  4107. unsigned int u;
  4108. int32_t u32;
  4109. int64_t u64;
  4110. size_t sz;
  4111. double d;
  4112. ASSERT_NOK(OptionTypeInfo(0, OptionType::kBoolean)
  4113. .Parse(config_options, "b", "x", &b));
  4114. ASSERT_NOK(
  4115. OptionTypeInfo(0, OptionType::kInt).Parse(config_options, "b", "x", &i));
  4116. ASSERT_NOK(OptionTypeInfo(0, OptionType::kInt32T)
  4117. .Parse(config_options, "b", "x", &i32));
  4118. ASSERT_NOK(OptionTypeInfo(0, OptionType::kInt64T)
  4119. .Parse(config_options, "b", "x", &i64));
  4120. ASSERT_NOK(
  4121. OptionTypeInfo(0, OptionType::kUInt).Parse(config_options, "b", "x", &u));
  4122. ASSERT_NOK(OptionTypeInfo(0, OptionType::kUInt32T)
  4123. .Parse(config_options, "b", "x", &u32));
  4124. ASSERT_NOK(OptionTypeInfo(0, OptionType::kUInt64T)
  4125. .Parse(config_options, "b", "x", &u64));
  4126. ASSERT_NOK(OptionTypeInfo(0, OptionType::kSizeT)
  4127. .Parse(config_options, "b", "x", &sz));
  4128. ASSERT_NOK(OptionTypeInfo(0, OptionType::kDouble)
  4129. .Parse(config_options, "b", "x", &d));
  4130. // Don't know how to convert Unknowns to anything else
  4131. ASSERT_NOK(OptionTypeInfo(0, OptionType::kUnknown)
  4132. .Parse(config_options, "b", "x", &d));
  4133. // Verify that if the parse function throws an exception, it is also trapped
  4134. OptionTypeInfo func_info(0, OptionType::kUnknown,
  4135. OptionVerificationType::kNormal,
  4136. OptionTypeFlags::kNone,
  4137. [](const ConfigOptions&, const std::string&,
  4138. const std::string& value, void* addr) {
  4139. auto ptr = static_cast<int*>(addr);
  4140. *ptr = ParseInt(value);
  4141. return Status::OK();
  4142. });
  4143. ASSERT_OK(func_info.Parse(config_options, "b", "1", &i));
  4144. ASSERT_NOK(func_info.Parse(config_options, "b", "x", &i));
  4145. }
  4146. TEST_F(OptionTypeInfoTest, TestParseFunc) {
  4147. OptionTypeInfo opt_info(0, OptionType::kUnknown,
  4148. OptionVerificationType::kNormal,
  4149. OptionTypeFlags::kNone);
  4150. opt_info.SetParseFunc([](const ConfigOptions& /*opts*/,
  4151. const std::string& name, const std::string& value,
  4152. void* addr) {
  4153. auto ptr = static_cast<std::string*>(addr);
  4154. if (name == "Oops") {
  4155. return Status::InvalidArgument(value);
  4156. } else {
  4157. *ptr = value + " " + name;
  4158. return Status::OK();
  4159. }
  4160. });
  4161. ConfigOptions config_options;
  4162. std::string base;
  4163. ASSERT_OK(opt_info.Parse(config_options, "World", "Hello", &base));
  4164. ASSERT_EQ(base, "Hello World");
  4165. ASSERT_NOK(opt_info.Parse(config_options, "Oops", "Hello", &base));
  4166. }
  4167. TEST_F(OptionTypeInfoTest, TestSerializeFunc) {
  4168. OptionTypeInfo opt_info(0, OptionType::kString,
  4169. OptionVerificationType::kNormal,
  4170. OptionTypeFlags::kNone);
  4171. opt_info.SetSerializeFunc([](const ConfigOptions& /*opts*/,
  4172. const std::string& name, const void* /*addr*/,
  4173. std::string* value) {
  4174. if (name == "Oops") {
  4175. return Status::InvalidArgument(name);
  4176. } else {
  4177. *value = name;
  4178. return Status::OK();
  4179. }
  4180. });
  4181. ConfigOptions config_options;
  4182. std::string base;
  4183. std::string value;
  4184. ASSERT_OK(opt_info.Serialize(config_options, "Hello", &base, &value));
  4185. ASSERT_EQ(value, "Hello");
  4186. ASSERT_NOK(opt_info.Serialize(config_options, "Oops", &base, &value));
  4187. }
  4188. TEST_F(OptionTypeInfoTest, TestEqualsFunc) {
  4189. OptionTypeInfo opt_info(0, OptionType::kInt, OptionVerificationType::kNormal,
  4190. OptionTypeFlags::kNone);
  4191. opt_info.SetEqualsFunc([](const ConfigOptions& /*opts*/,
  4192. const std::string& name, const void* addr1,
  4193. const void* addr2, std::string* mismatch) {
  4194. auto i1 = *(static_cast<const int*>(addr1));
  4195. auto i2 = *(static_cast<const int*>(addr2));
  4196. if (name == "LT") {
  4197. return i1 < i2;
  4198. } else if (name == "GT") {
  4199. return i1 > i2;
  4200. } else if (name == "EQ") {
  4201. return i1 == i2;
  4202. } else {
  4203. *mismatch = name + "???";
  4204. return false;
  4205. }
  4206. });
  4207. ConfigOptions config_options;
  4208. int int1 = 100;
  4209. int int2 = 200;
  4210. std::string mismatch;
  4211. ASSERT_TRUE(opt_info.AreEqual(config_options, "LT", &int1, &int2, &mismatch));
  4212. ASSERT_EQ(mismatch, "");
  4213. ASSERT_FALSE(
  4214. opt_info.AreEqual(config_options, "GT", &int1, &int2, &mismatch));
  4215. ASSERT_EQ(mismatch, "GT");
  4216. ASSERT_FALSE(
  4217. opt_info.AreEqual(config_options, "NO", &int1, &int2, &mismatch));
  4218. ASSERT_EQ(mismatch, "NO???");
  4219. }
  4220. TEST_F(OptionTypeInfoTest, TestPrepareFunc) {
  4221. OptionTypeInfo opt_info(0, OptionType::kInt, OptionVerificationType::kNormal,
  4222. OptionTypeFlags::kNone);
  4223. opt_info.SetPrepareFunc(
  4224. [](const ConfigOptions& /*opts*/, const std::string& name, void* addr) {
  4225. auto i1 = static_cast<int*>(addr);
  4226. if (name == "x2") {
  4227. *i1 *= 2;
  4228. } else if (name == "/2") {
  4229. *i1 /= 2;
  4230. } else {
  4231. return Status::InvalidArgument("Bad Argument", name);
  4232. }
  4233. return Status::OK();
  4234. });
  4235. ConfigOptions config_options;
  4236. int int1 = 100;
  4237. ASSERT_OK(opt_info.Prepare(config_options, "x2", &int1));
  4238. ASSERT_EQ(int1, 200);
  4239. ASSERT_OK(opt_info.Prepare(config_options, "/2", &int1));
  4240. ASSERT_EQ(int1, 100);
  4241. ASSERT_NOK(opt_info.Prepare(config_options, "??", &int1));
  4242. ASSERT_EQ(int1, 100);
  4243. }
  4244. TEST_F(OptionTypeInfoTest, TestValidateFunc) {
  4245. OptionTypeInfo opt_info(0, OptionType::kSizeT,
  4246. OptionVerificationType::kNormal,
  4247. OptionTypeFlags::kNone);
  4248. opt_info.SetValidateFunc([](const DBOptions& db_opts,
  4249. const ColumnFamilyOptions& cf_opts,
  4250. const std::string& name, const void* addr) {
  4251. const auto sz = static_cast<const size_t*>(addr);
  4252. bool is_valid = false;
  4253. if (name == "keep_log_file_num") {
  4254. is_valid = (*sz == db_opts.keep_log_file_num);
  4255. } else if (name == "write_buffer_size") {
  4256. is_valid = (*sz == cf_opts.write_buffer_size);
  4257. }
  4258. if (is_valid) {
  4259. return Status::OK();
  4260. } else {
  4261. return Status::InvalidArgument("Mismatched value", name);
  4262. }
  4263. });
  4264. ConfigOptions config_options;
  4265. DBOptions db_options;
  4266. ColumnFamilyOptions cf_options;
  4267. ASSERT_OK(opt_info.Validate(db_options, cf_options, "keep_log_file_num",
  4268. &db_options.keep_log_file_num));
  4269. ASSERT_OK(opt_info.Validate(db_options, cf_options, "write_buffer_size",
  4270. &cf_options.write_buffer_size));
  4271. ASSERT_NOK(opt_info.Validate(db_options, cf_options, "keep_log_file_num",
  4272. &cf_options.write_buffer_size));
  4273. ASSERT_NOK(opt_info.Validate(db_options, cf_options, "write_buffer_size",
  4274. &db_options.keep_log_file_num));
  4275. }
  4276. TEST_F(OptionTypeInfoTest, TestOptionFlags) {
  4277. OptionTypeInfo opt_none(0, OptionType::kString,
  4278. OptionVerificationType::kNormal,
  4279. OptionTypeFlags::kDontSerialize);
  4280. OptionTypeInfo opt_never(0, OptionType::kString,
  4281. OptionVerificationType::kNormal,
  4282. OptionTypeFlags::kCompareNever);
  4283. OptionTypeInfo opt_alias(0, OptionType::kString,
  4284. OptionVerificationType::kAlias,
  4285. OptionTypeFlags::kNone);
  4286. OptionTypeInfo opt_deprecated(0, OptionType::kString,
  4287. OptionVerificationType::kDeprecated,
  4288. OptionTypeFlags::kNone);
  4289. ConfigOptions config_options;
  4290. std::string opts_str;
  4291. std::string base = "base";
  4292. std::string comp = "comp";
  4293. // If marked string none, the serialization returns not supported
  4294. ASSERT_NOK(opt_none.Serialize(config_options, "None", &base, &opts_str));
  4295. // If marked never compare, they match even when they do not
  4296. ASSERT_TRUE(opt_never.AreEqual(config_options, "Never", &base, &comp, &base));
  4297. ASSERT_FALSE(opt_none.AreEqual(config_options, "Never", &base, &comp, &base));
  4298. // An alias can change the value via parse, but does nothing on serialize on
  4299. // match
  4300. std::string result;
  4301. ASSERT_OK(opt_alias.Parse(config_options, "Alias", "Alias", &base));
  4302. ASSERT_OK(opt_alias.Serialize(config_options, "Alias", &base, &result));
  4303. ASSERT_TRUE(
  4304. opt_alias.AreEqual(config_options, "Alias", &base, &comp, &result));
  4305. ASSERT_EQ(base, "Alias");
  4306. ASSERT_NE(base, comp);
  4307. // Deprecated options do nothing on any of the commands
  4308. ASSERT_OK(opt_deprecated.Parse(config_options, "Alias", "Deprecated", &base));
  4309. ASSERT_OK(opt_deprecated.Serialize(config_options, "Alias", &base, &result));
  4310. ASSERT_TRUE(
  4311. opt_deprecated.AreEqual(config_options, "Alias", &base, &comp, &result));
  4312. ASSERT_EQ(base, "Alias");
  4313. ASSERT_NE(base, comp);
  4314. }
  4315. TEST_F(OptionTypeInfoTest, TestCustomEnum) {
  4316. enum TestEnum { kA, kB, kC };
  4317. std::unordered_map<std::string, TestEnum> enum_map = {
  4318. {"A", TestEnum::kA},
  4319. {"B", TestEnum::kB},
  4320. {"C", TestEnum::kC},
  4321. };
  4322. OptionTypeInfo opt_info = OptionTypeInfo::Enum<TestEnum>(0, &enum_map);
  4323. TestEnum e1, e2;
  4324. ConfigOptions config_options;
  4325. std::string result, mismatch;
  4326. e2 = TestEnum::kA;
  4327. ASSERT_OK(opt_info.Parse(config_options, "", "B", &e1));
  4328. ASSERT_OK(opt_info.Serialize(config_options, "", &e1, &result));
  4329. ASSERT_EQ(e1, TestEnum::kB);
  4330. ASSERT_EQ(result, "B");
  4331. ASSERT_FALSE(opt_info.AreEqual(config_options, "Enum", &e1, &e2, &mismatch));
  4332. ASSERT_EQ(mismatch, "Enum");
  4333. TestParseAndCompareOption(config_options, opt_info, "", "C", &e1, &e2);
  4334. ASSERT_EQ(e2, TestEnum::kC);
  4335. ASSERT_NOK(opt_info.Parse(config_options, "", "D", &e1));
  4336. ASSERT_EQ(e1, TestEnum::kC);
  4337. }
  4338. TEST_F(OptionTypeInfoTest, TestBuiltinEnum) {
  4339. ConfigOptions config_options;
  4340. for (const auto& iter : OptionsHelper::compaction_style_string_map) {
  4341. CompactionStyle e1, e2;
  4342. TestParseAndCompareOption(config_options,
  4343. OptionTypeInfo(0, OptionType::kCompactionStyle),
  4344. "CompactionStyle", iter.first, &e1, &e2);
  4345. ASSERT_EQ(e1, iter.second);
  4346. }
  4347. for (const auto& iter : OptionsHelper::compaction_pri_string_map) {
  4348. CompactionPri e1, e2;
  4349. TestParseAndCompareOption(config_options,
  4350. OptionTypeInfo(0, OptionType::kCompactionPri),
  4351. "CompactionPri", iter.first, &e1, &e2);
  4352. ASSERT_EQ(e1, iter.second);
  4353. }
  4354. for (const auto& iter : OptionsHelper::compression_type_string_map) {
  4355. CompressionType e1, e2;
  4356. TestParseAndCompareOption(config_options,
  4357. OptionTypeInfo(0, OptionType::kCompressionType),
  4358. "CompressionType", iter.first, &e1, &e2);
  4359. ASSERT_EQ(e1, iter.second);
  4360. }
  4361. for (const auto& iter : OptionsHelper::compaction_stop_style_string_map) {
  4362. CompactionStopStyle e1, e2;
  4363. TestParseAndCompareOption(
  4364. config_options, OptionTypeInfo(0, OptionType::kCompactionStopStyle),
  4365. "CompactionStopStyle", iter.first, &e1, &e2);
  4366. ASSERT_EQ(e1, iter.second);
  4367. }
  4368. for (const auto& iter : OptionsHelper::checksum_type_string_map) {
  4369. ChecksumType e1, e2;
  4370. TestParseAndCompareOption(config_options,
  4371. OptionTypeInfo(0, OptionType::kChecksumType),
  4372. "CheckSumType", iter.first, &e1, &e2);
  4373. ASSERT_EQ(e1, iter.second);
  4374. }
  4375. for (const auto& iter : OptionsHelper::encoding_type_string_map) {
  4376. EncodingType e1, e2;
  4377. TestParseAndCompareOption(config_options,
  4378. OptionTypeInfo(0, OptionType::kEncodingType),
  4379. "EncodingType", iter.first, &e1, &e2);
  4380. ASSERT_EQ(e1, iter.second);
  4381. }
  4382. }
  4383. TEST_F(OptionTypeInfoTest, TestStruct) {
  4384. struct Basic {
  4385. int i = 42;
  4386. std::string s = "Hello";
  4387. };
  4388. struct Extended {
  4389. int j = 11;
  4390. Basic b;
  4391. };
  4392. std::unordered_map<std::string, OptionTypeInfo> basic_type_map = {
  4393. {"i", {offsetof(struct Basic, i), OptionType::kInt}},
  4394. {"s", {offsetof(struct Basic, s), OptionType::kString}},
  4395. };
  4396. OptionTypeInfo basic_info = OptionTypeInfo::Struct(
  4397. "b", &basic_type_map, 0, OptionVerificationType::kNormal,
  4398. OptionTypeFlags::kMutable);
  4399. std::unordered_map<std::string, OptionTypeInfo> extended_type_map = {
  4400. {"j", {offsetof(struct Extended, j), OptionType::kInt}},
  4401. {"b", OptionTypeInfo::Struct(
  4402. "b", &basic_type_map, offsetof(struct Extended, b),
  4403. OptionVerificationType::kNormal, OptionTypeFlags::kNone)},
  4404. {"m", OptionTypeInfo::Struct(
  4405. "m", &basic_type_map, offsetof(struct Extended, b),
  4406. OptionVerificationType::kNormal, OptionTypeFlags::kMutable)},
  4407. };
  4408. OptionTypeInfo extended_info = OptionTypeInfo::Struct(
  4409. "e", &extended_type_map, 0, OptionVerificationType::kNormal,
  4410. OptionTypeFlags::kMutable);
  4411. Extended e1, e2;
  4412. ConfigOptions config_options;
  4413. std::string mismatch;
  4414. TestParseAndCompareOption(config_options, basic_info, "b", "{i=33;s=33}",
  4415. &e1.b, &e2.b);
  4416. ASSERT_EQ(e1.b.i, 33);
  4417. ASSERT_EQ(e1.b.s, "33");
  4418. TestParseAndCompareOption(config_options, basic_info, "b.i", "44", &e1.b,
  4419. &e2.b);
  4420. ASSERT_EQ(e1.b.i, 44);
  4421. TestParseAndCompareOption(config_options, basic_info, "i", "55", &e1.b,
  4422. &e2.b);
  4423. ASSERT_EQ(e1.b.i, 55);
  4424. e1.b.i = 0;
  4425. ASSERT_FALSE(
  4426. basic_info.AreEqual(config_options, "b", &e1.b, &e2.b, &mismatch));
  4427. ASSERT_EQ(mismatch, "b.i");
  4428. mismatch.clear();
  4429. ASSERT_FALSE(
  4430. basic_info.AreEqual(config_options, "b.i", &e1.b, &e2.b, &mismatch));
  4431. ASSERT_EQ(mismatch, "b.i");
  4432. mismatch.clear();
  4433. ASSERT_FALSE(
  4434. basic_info.AreEqual(config_options, "i", &e1.b, &e2.b, &mismatch));
  4435. ASSERT_EQ(mismatch, "b.i");
  4436. mismatch.clear();
  4437. e1 = e2;
  4438. ASSERT_NOK(basic_info.Parse(config_options, "b", "{i=33;s=33;j=44}", &e1.b));
  4439. ASSERT_NOK(basic_info.Parse(config_options, "b.j", "44", &e1.b));
  4440. ASSERT_NOK(basic_info.Parse(config_options, "j", "44", &e1.b));
  4441. TestParseAndCompareOption(config_options, extended_info, "e",
  4442. "b={i=55;s=55}; j=22;", &e1, &e2);
  4443. ASSERT_EQ(e1.b.i, 55);
  4444. ASSERT_EQ(e1.j, 22);
  4445. ASSERT_EQ(e1.b.s, "55");
  4446. TestParseAndCompareOption(config_options, extended_info, "e.b",
  4447. "{i=66;s=66;}", &e1, &e2);
  4448. ASSERT_EQ(e1.b.i, 66);
  4449. ASSERT_EQ(e1.j, 22);
  4450. ASSERT_EQ(e1.b.s, "66");
  4451. TestParseAndCompareOption(config_options, extended_info, "e.b.i", "77", &e1,
  4452. &e2);
  4453. ASSERT_EQ(e1.b.i, 77);
  4454. ASSERT_EQ(e1.j, 22);
  4455. ASSERT_EQ(e1.b.s, "66");
  4456. }
  4457. TEST_F(OptionTypeInfoTest, TestArrayType) {
  4458. OptionTypeInfo array_info = OptionTypeInfo::Array<std::string, 4>(
  4459. 0, OptionVerificationType::kNormal, OptionTypeFlags::kNone,
  4460. {0, OptionType::kString});
  4461. std::array<std::string, 4> array1, array2;
  4462. std::string mismatch;
  4463. ConfigOptions config_options;
  4464. TestParseAndCompareOption(config_options, array_info, "v", "a:b:c:d", &array1,
  4465. &array2);
  4466. ASSERT_EQ(array1.size(), 4);
  4467. ASSERT_EQ(array1[0], "a");
  4468. ASSERT_EQ(array1[1], "b");
  4469. ASSERT_EQ(array1[2], "c");
  4470. ASSERT_EQ(array1[3], "d");
  4471. array1[3] = "e";
  4472. ASSERT_FALSE(
  4473. array_info.AreEqual(config_options, "v", &array1, &array2, &mismatch));
  4474. ASSERT_EQ(mismatch, "v");
  4475. // Test vectors with inner brackets
  4476. TestParseAndCompareOption(config_options, array_info, "v", "a:{b}:c:d",
  4477. &array1, &array2);
  4478. ASSERT_EQ(array1.size(), 4);
  4479. ASSERT_EQ(array1[0], "a");
  4480. ASSERT_EQ(array1[1], "b");
  4481. ASSERT_EQ(array1[2], "c");
  4482. ASSERT_EQ(array1[3], "d");
  4483. std::array<std::string, 3> array3, array4;
  4484. OptionTypeInfo bar_info = OptionTypeInfo::Array<std::string, 3>(
  4485. 0, OptionVerificationType::kNormal, OptionTypeFlags::kNone,
  4486. {0, OptionType::kString}, '|');
  4487. TestParseAndCompareOption(config_options, bar_info, "v", "x|y|z", &array3,
  4488. &array4);
  4489. // Test arrays with inner array
  4490. TestParseAndCompareOption(config_options, bar_info, "v",
  4491. "a|{b1|b2}|{c1|c2|{d1|d2}}", &array3, &array4,
  4492. false);
  4493. ASSERT_EQ(array3.size(), 3);
  4494. ASSERT_EQ(array3[0], "a");
  4495. ASSERT_EQ(array3[1], "b1|b2");
  4496. ASSERT_EQ(array3[2], "c1|c2|{d1|d2}");
  4497. TestParseAndCompareOption(config_options, bar_info, "v",
  4498. "{a1|a2}|{b1|{c1|c2}}|d1", &array3, &array4, true);
  4499. ASSERT_EQ(array3.size(), 3);
  4500. ASSERT_EQ(array3[0], "a1|a2");
  4501. ASSERT_EQ(array3[1], "b1|{c1|c2}");
  4502. ASSERT_EQ(array3[2], "d1");
  4503. // Test invalid input: less element than requested
  4504. auto s = bar_info.Parse(config_options, "opt_name1", "a1|a2", &array3);
  4505. ASSERT_TRUE(s.IsInvalidArgument());
  4506. // Test invalid input: more element than requested
  4507. s = bar_info.Parse(config_options, "opt_name2", "a1|b|c1|d3", &array3);
  4508. ASSERT_TRUE(s.IsInvalidArgument());
  4509. }
  4510. TEST_F(OptionTypeInfoTest, TestVectorType) {
  4511. OptionTypeInfo vec_info = OptionTypeInfo::Vector<std::string>(
  4512. 0, OptionVerificationType::kNormal, OptionTypeFlags::kNone,
  4513. {0, OptionType::kString});
  4514. std::vector<std::string> vec1, vec2;
  4515. std::string mismatch;
  4516. ConfigOptions config_options;
  4517. TestParseAndCompareOption(config_options, vec_info, "v", "a:b:c:d", &vec1,
  4518. &vec2);
  4519. ASSERT_EQ(vec1.size(), 4);
  4520. ASSERT_EQ(vec1[0], "a");
  4521. ASSERT_EQ(vec1[1], "b");
  4522. ASSERT_EQ(vec1[2], "c");
  4523. ASSERT_EQ(vec1[3], "d");
  4524. vec1[3] = "e";
  4525. ASSERT_FALSE(vec_info.AreEqual(config_options, "v", &vec1, &vec2, &mismatch));
  4526. ASSERT_EQ(mismatch, "v");
  4527. // Test vectors with inner brackets
  4528. TestParseAndCompareOption(config_options, vec_info, "v", "a:{b}:c:d", &vec1,
  4529. &vec2);
  4530. ASSERT_EQ(vec1.size(), 4);
  4531. ASSERT_EQ(vec1[0], "a");
  4532. ASSERT_EQ(vec1[1], "b");
  4533. ASSERT_EQ(vec1[2], "c");
  4534. ASSERT_EQ(vec1[3], "d");
  4535. OptionTypeInfo bar_info = OptionTypeInfo::Vector<std::string>(
  4536. 0, OptionVerificationType::kNormal, OptionTypeFlags::kNone,
  4537. {0, OptionType::kString}, '|');
  4538. TestParseAndCompareOption(config_options, vec_info, "v", "x|y|z", &vec1,
  4539. &vec2);
  4540. // Test vectors with inner vector
  4541. TestParseAndCompareOption(config_options, bar_info, "v",
  4542. "a|{b1|b2}|{c1|c2|{d1|d2}}", &vec1, &vec2, false);
  4543. ASSERT_EQ(vec1.size(), 3);
  4544. ASSERT_EQ(vec1[0], "a");
  4545. ASSERT_EQ(vec1[1], "b1|b2");
  4546. ASSERT_EQ(vec1[2], "c1|c2|{d1|d2}");
  4547. TestParseAndCompareOption(config_options, bar_info, "v",
  4548. "{a1|a2}|{b1|{c1|c2}}|d1", &vec1, &vec2, true);
  4549. ASSERT_EQ(vec1.size(), 3);
  4550. ASSERT_EQ(vec1[0], "a1|a2");
  4551. ASSERT_EQ(vec1[1], "b1|{c1|c2}");
  4552. ASSERT_EQ(vec1[2], "d1");
  4553. TestParseAndCompareOption(config_options, bar_info, "v", "{a1}", &vec1, &vec2,
  4554. false);
  4555. ASSERT_EQ(vec1.size(), 1);
  4556. ASSERT_EQ(vec1[0], "a1");
  4557. TestParseAndCompareOption(config_options, bar_info, "v", "{a1|a2}|{b1|b2}",
  4558. &vec1, &vec2, true);
  4559. ASSERT_EQ(vec1.size(), 2);
  4560. ASSERT_EQ(vec1[0], "a1|a2");
  4561. ASSERT_EQ(vec1[1], "b1|b2");
  4562. }
  4563. TEST_F(OptionTypeInfoTest, TestStaticType) {
  4564. struct SimpleOptions {
  4565. size_t size = 0;
  4566. bool verify = true;
  4567. };
  4568. static std::unordered_map<std::string, OptionTypeInfo> type_map = {
  4569. {"size", {offsetof(struct SimpleOptions, size), OptionType::kSizeT}},
  4570. {"verify",
  4571. {offsetof(struct SimpleOptions, verify), OptionType::kBoolean}},
  4572. };
  4573. ConfigOptions config_options;
  4574. SimpleOptions opts, copy;
  4575. opts.size = 12345;
  4576. opts.verify = false;
  4577. std::string str, mismatch;
  4578. ASSERT_OK(
  4579. OptionTypeInfo::SerializeType(config_options, type_map, &opts, &str));
  4580. ASSERT_FALSE(OptionTypeInfo::TypesAreEqual(config_options, type_map, &opts,
  4581. &copy, &mismatch));
  4582. ASSERT_OK(OptionTypeInfo::ParseType(config_options, str, type_map, &copy));
  4583. ASSERT_TRUE(OptionTypeInfo::TypesAreEqual(config_options, type_map, &opts,
  4584. &copy, &mismatch));
  4585. }
  4586. class ConfigOptionsTest : public testing::Test {};
  4587. TEST_F(ConfigOptionsTest, EnvFromConfigOptions) {
  4588. ConfigOptions config_options;
  4589. DBOptions db_opts;
  4590. Options opts;
  4591. Env* mem_env = NewMemEnv(Env::Default());
  4592. config_options.registry->AddLibrary("custom-env", RegisterCustomEnv,
  4593. kCustomEnvName);
  4594. config_options.env = mem_env;
  4595. // First test that we can get the env as expected
  4596. ASSERT_OK(GetDBOptionsFromString(config_options, DBOptions(), kCustomEnvProp,
  4597. &db_opts));
  4598. ASSERT_OK(
  4599. GetOptionsFromString(config_options, Options(), kCustomEnvProp, &opts));
  4600. ASSERT_NE(config_options.env, db_opts.env);
  4601. ASSERT_EQ(opts.env, db_opts.env);
  4602. Env* custom_env = db_opts.env;
  4603. // Now try a "bad" env" and check that nothing changed
  4604. config_options.ignore_unsupported_options = true;
  4605. ASSERT_OK(
  4606. GetDBOptionsFromString(config_options, db_opts, "env=unknown", &db_opts));
  4607. ASSERT_OK(GetOptionsFromString(config_options, opts, "env=unknown", &opts));
  4608. ASSERT_EQ(config_options.env, mem_env);
  4609. ASSERT_EQ(db_opts.env, custom_env);
  4610. ASSERT_EQ(opts.env, db_opts.env);
  4611. // Now try a "bad" env" ignoring unknown objects
  4612. config_options.ignore_unsupported_options = false;
  4613. ASSERT_NOK(
  4614. GetDBOptionsFromString(config_options, db_opts, "env=unknown", &db_opts));
  4615. ASSERT_EQ(config_options.env, mem_env);
  4616. ASSERT_EQ(db_opts.env, custom_env);
  4617. ASSERT_EQ(opts.env, db_opts.env);
  4618. delete mem_env;
  4619. }
  4620. TEST_F(ConfigOptionsTest, MergeOperatorFromString) {
  4621. ConfigOptions config_options;
  4622. std::shared_ptr<MergeOperator> merge_op;
  4623. ASSERT_OK(MergeOperator::CreateFromString(config_options, "put", &merge_op));
  4624. ASSERT_NE(merge_op, nullptr);
  4625. ASSERT_TRUE(merge_op->IsInstanceOf("put"));
  4626. ASSERT_STREQ(merge_op->Name(), "PutOperator");
  4627. ASSERT_OK(
  4628. MergeOperator::CreateFromString(config_options, "put_v1", &merge_op));
  4629. ASSERT_NE(merge_op, nullptr);
  4630. ASSERT_TRUE(merge_op->IsInstanceOf("PutOperator"));
  4631. ASSERT_OK(
  4632. MergeOperator::CreateFromString(config_options, "uint64add", &merge_op));
  4633. ASSERT_NE(merge_op, nullptr);
  4634. ASSERT_TRUE(merge_op->IsInstanceOf("uint64add"));
  4635. ASSERT_STREQ(merge_op->Name(), "UInt64AddOperator");
  4636. ASSERT_OK(MergeOperator::CreateFromString(config_options, "max", &merge_op));
  4637. ASSERT_NE(merge_op, nullptr);
  4638. ASSERT_TRUE(merge_op->IsInstanceOf("max"));
  4639. ASSERT_STREQ(merge_op->Name(), "MaxOperator");
  4640. ASSERT_OK(
  4641. MergeOperator::CreateFromString(config_options, "bytesxor", &merge_op));
  4642. ASSERT_NE(merge_op, nullptr);
  4643. ASSERT_TRUE(merge_op->IsInstanceOf("bytesxor"));
  4644. ASSERT_STREQ(merge_op->Name(), BytesXOROperator::kClassName());
  4645. ASSERT_OK(
  4646. MergeOperator::CreateFromString(config_options, "sortlist", &merge_op));
  4647. ASSERT_NE(merge_op, nullptr);
  4648. ASSERT_TRUE(merge_op->IsInstanceOf("sortlist"));
  4649. ASSERT_STREQ(merge_op->Name(), SortList::kClassName());
  4650. ASSERT_OK(MergeOperator::CreateFromString(config_options, "stringappend",
  4651. &merge_op));
  4652. ASSERT_NE(merge_op, nullptr);
  4653. ASSERT_TRUE(merge_op->IsInstanceOf("stringappend"));
  4654. ASSERT_STREQ(merge_op->Name(), StringAppendOperator::kClassName());
  4655. auto delimiter = merge_op->GetOptions<std::string>("Delimiter");
  4656. ASSERT_NE(delimiter, nullptr);
  4657. ASSERT_EQ(*delimiter, ",");
  4658. ASSERT_OK(MergeOperator::CreateFromString(config_options, "stringappendtest",
  4659. &merge_op));
  4660. ASSERT_NE(merge_op, nullptr);
  4661. ASSERT_TRUE(merge_op->IsInstanceOf("stringappendtest"));
  4662. ASSERT_STREQ(merge_op->Name(), StringAppendTESTOperator::kClassName());
  4663. delimiter = merge_op->GetOptions<std::string>("Delimiter");
  4664. ASSERT_NE(delimiter, nullptr);
  4665. ASSERT_EQ(*delimiter, ",");
  4666. ASSERT_OK(MergeOperator::CreateFromString(
  4667. config_options, "id=stringappend; delimiter=||", &merge_op));
  4668. ASSERT_NE(merge_op, nullptr);
  4669. ASSERT_TRUE(merge_op->IsInstanceOf("stringappend"));
  4670. ASSERT_STREQ(merge_op->Name(), StringAppendOperator::kClassName());
  4671. delimiter = merge_op->GetOptions<std::string>("Delimiter");
  4672. ASSERT_NE(delimiter, nullptr);
  4673. ASSERT_EQ(*delimiter, "||");
  4674. ASSERT_OK(MergeOperator::CreateFromString(
  4675. config_options, "id=stringappendtest; delimiter=&&", &merge_op));
  4676. ASSERT_NE(merge_op, nullptr);
  4677. ASSERT_TRUE(merge_op->IsInstanceOf("stringappendtest"));
  4678. ASSERT_STREQ(merge_op->Name(), StringAppendTESTOperator::kClassName());
  4679. delimiter = merge_op->GetOptions<std::string>("Delimiter");
  4680. ASSERT_NE(delimiter, nullptr);
  4681. ASSERT_EQ(*delimiter, "&&");
  4682. std::shared_ptr<MergeOperator> copy;
  4683. std::string mismatch;
  4684. std::string opts_str = merge_op->ToString(config_options);
  4685. ASSERT_OK(MergeOperator::CreateFromString(config_options, opts_str, &copy));
  4686. ASSERT_TRUE(merge_op->AreEquivalent(config_options, copy.get(), &mismatch));
  4687. ASSERT_NE(copy, nullptr);
  4688. delimiter = copy->GetOptions<std::string>("Delimiter");
  4689. ASSERT_NE(delimiter, nullptr);
  4690. ASSERT_EQ(*delimiter, "&&");
  4691. }
  4692. TEST_F(ConfigOptionsTest, ConfiguringOptionsDoesNotRevertRateLimiterBandwidth) {
  4693. // Regression test for bug where rate limiter's dynamically set bandwidth
  4694. // could be silently reverted when configuring an options structure with an
  4695. // existing `rate_limiter`.
  4696. Options base_options;
  4697. base_options.rate_limiter.reset(
  4698. NewGenericRateLimiter(1 << 20 /* rate_bytes_per_sec */));
  4699. Options copy_options(base_options);
  4700. base_options.rate_limiter->SetBytesPerSecond(2 << 20);
  4701. ASSERT_EQ(2 << 20, base_options.rate_limiter->GetBytesPerSecond());
  4702. ASSERT_OK(GetOptionsFromString(base_options, "", &copy_options));
  4703. ASSERT_EQ(2 << 20, base_options.rate_limiter->GetBytesPerSecond());
  4704. }
  4705. INSTANTIATE_TEST_CASE_P(OptionsSanityCheckTest, OptionsSanityCheckTest,
  4706. ::testing::Bool());
  4707. } // namespace ROCKSDB_NAMESPACE
  4708. int main(int argc, char** argv) {
  4709. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  4710. ::testing::InitGoogleTest(&argc, argv);
  4711. #ifdef GFLAGS
  4712. ParseCommandLineFlags(&argc, &argv, true);
  4713. #endif // GFLAGS
  4714. return RUN_ALL_TESTS();
  4715. }