bdb_layer.c 226 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2019 Red Hat, Inc.
  3. * All rights reserved.
  4. *
  5. * License: GPL (version 3 or any later version).
  6. * See LICENSE for details.
  7. * END COPYRIGHT BLOCK **/
  8. #ifdef HAVE_CONFIG_H
  9. #include <config.h>
  10. #endif
  11. #include "bdb_layer.h"
  12. #include <prthread.h>
  13. #include <prclist.h>
  14. #include <sys/types.h>
  15. #include <sys/statvfs.h>
  16. #include <glob.h>
  17. #define DB_OPEN(oflags, db, txnid, file, database, type, flags, mode, rval) \
  18. { \
  19. if (((oflags)&DB_INIT_TXN) && ((oflags)&DB_INIT_LOG)) { \
  20. (rval) = ((db)->open)((db), (txnid), (file), (database), (type), (flags) | DB_AUTO_COMMIT, (mode)); \
  21. } else { \
  22. (rval) = ((db)->open)((db), (txnid), (file), (database), (type), (flags), (mode)); \
  23. } \
  24. }
  25. #define TXN_BEGIN(env, parent_txn, tid, flags) \
  26. (env)->txn_begin((env), (parent_txn), (tid), (flags))
  27. #define TXN_COMMIT(txn, flags) (txn)->commit((txn), (flags))
  28. #define TXN_ABORT(txn) (txn)->abort(txn)
  29. #define TXN_CHECKPOINT(env, kbyte, min, flags) \
  30. (env)->txn_checkpoint((env), (kbyte), (min), (flags))
  31. #define MEMP_STAT(env, gsp, fsp, flags, malloc) \
  32. (env)->memp_stat((env), (gsp), (fsp), (flags))
  33. #define MEMP_TRICKLE(env, pct, nwrotep) \
  34. (env)->memp_trickle((env), (pct), (nwrotep))
  35. #define LOG_ARCHIVE(env, listp, flags, malloc) \
  36. (env)->log_archive((env), (listp), (flags))
  37. #define LOG_FLUSH(env, lsn) (env)->log_flush((env), (lsn))
  38. /* Use these macros to incr/decrement the thread count for the
  39. database housekeeping threads. This ensures that the
  40. value is changed in a thread safe manner, and safely notifies
  41. the main thread during cleanup. INCR_THREAD_COUNT should be
  42. the first real statement in the thread function, before any
  43. actual work is done, other than perhaps variable assignments.
  44. DECR_THREAD_COUNT should be called as the next to last thing
  45. in the thread function, just before the trace log message and
  46. return.
  47. */
  48. #define INCR_THREAD_COUNT(pEnv) \
  49. PR_Lock(pEnv->bdb_thread_count_lock); \
  50. ++pEnv->bdb_thread_count; \
  51. PR_Unlock(pEnv->bdb_thread_count_lock)
  52. #define DECR_THREAD_COUNT(pEnv) \
  53. PR_Lock(pEnv->bdb_thread_count_lock); \
  54. if (--pEnv->bdb_thread_count == 0) { \
  55. PR_NotifyCondVar(pEnv->bdb_thread_count_cv); \
  56. } \
  57. PR_Unlock(pEnv->bdb_thread_count_lock)
  58. #define NEWDIR_MODE 0755
  59. #define DB_REGION_PREFIX "__db."
  60. static int perf_threadmain(void *param);
  61. static int checkpoint_threadmain(void *param);
  62. static int trickle_threadmain(void *param);
  63. static int deadlock_threadmain(void *param);
  64. static int commit_good_database(bdb_config *priv, int mode);
  65. static int read_metadata(struct ldbminfo *li);
  66. static int count_dbfiles_in_dir(char *directory, int *count, int recurse);
  67. static int dblayer_override_libdb_functions(void);
  68. static int bdb_force_checkpoint(struct ldbminfo *li);
  69. static int bdb_force_logrenewal(struct ldbminfo *li);
  70. static int log_flush_threadmain(void *param);
  71. static int dblayer_delete_transaction_logs(const char *log_dir);
  72. static int dblayer_is_logfilename(const char *path);
  73. static int bdb_start_log_flush_thread(struct ldbminfo *li);
  74. static int bdb_start_deadlock_thread(struct ldbminfo *li);
  75. static int bdb_start_checkpoint_thread(struct ldbminfo *li);
  76. static int bdb_start_trickle_thread(struct ldbminfo *li);
  77. static int bdb_start_perf_thread(struct ldbminfo *li);
  78. static int bdb_start_txn_test_thread(struct ldbminfo *li);
  79. static int trans_batch_count = 0;
  80. static int trans_batch_limit = 0;
  81. static int trans_batch_txn_min_sleep = 50; /* ms */
  82. static int trans_batch_txn_max_sleep = 50;
  83. static PRBool log_flush_thread = PR_FALSE;
  84. static int txn_in_progress_count = 0;
  85. static int *txn_log_flush_pending = NULL;
  86. static PRLock *sync_txn_log_flush = NULL;
  87. static PRCondVar *sync_txn_log_flush_done = NULL;
  88. static PRCondVar *sync_txn_log_do_flush = NULL;
  89. static int bdb_db_remove_ex(bdb_db_env *env, char const path[], char const dbName[], PRBool use_lock);
  90. static int bdb_db_compact_one_db(DB *db, ldbm_instance *inst);
  91. static int bdb_restore_file_check(struct ldbminfo *li);
  92. #define MEGABYTE (1024 * 1024)
  93. #define GIGABYTE (1024 * MEGABYTE)
  94. /* env. vars. you can set to stress txn handling */
  95. #define TXN_TESTING "TXN_TESTING" /* enables the txn test thread */
  96. #define TXN_TEST_HOLD_MSEC "TXN_TEST_HOLD_MSEC" /* time to hold open the db cursors */
  97. #define TXN_TEST_LOOP_MSEC "TXN_TEST_LOOP_MSEC" /* time to wait before looping again */
  98. #define TXN_TEST_USE_TXN "TXN_TEST_USE_TXN" /* use transactions or not */
  99. #define TXN_TEST_USE_RMW "TXN_TEST_USE_RMW" /* use DB_RMW for c_get flags or not */
  100. #define TXN_TEST_INDEXES "TXN_TEST_INDEXES" /* list of indexes to use - comma delimited - id2entry,entryrdn,etc. */
  101. #define TXN_TEST_VERBOSE "TXN_TEST_VERBOSE" /* be wordy */
  102. /* This function compares two index keys. It is assumed
  103. that the values are already normalized, since they should have
  104. been when the index was created (by int_values2keys).
  105. richm - actually, the current syntax compare functions
  106. always normalize both arguments. We need to add an additional
  107. syntax compare function that does not normalize or takes
  108. an argument like value_cmp to specify to normalize or not.
  109. More fun - this function is used to compare both raw database
  110. keys (e.g. with the prefix '=' or '+' or '*' etc.) and without
  111. (in the case of two equality keys, we want to strip off the
  112. leading '=' to compare the actual values). We only use the
  113. value_compare function if both keys are equality keys with
  114. some data after the equality prefix. In every other case,
  115. we will just use a standard berval cmp function.
  116. see also DBTcmp
  117. */
  118. int
  119. bdb_bt_compare(DB *db, const DBT *dbt1, const DBT *dbt2)
  120. {
  121. struct berval bv1, bv2;
  122. value_compare_fn_type syntax_cmp_fn = (value_compare_fn_type)db->app_private;
  123. if ((dbt1->data && (dbt1->size > 1) && (*((char *)dbt1->data) == EQ_PREFIX)) &&
  124. (dbt2->data && (dbt2->size > 1) && (*((char *)dbt2->data) == EQ_PREFIX))) {
  125. bv1.bv_val = (char *)dbt1->data + 1; /* remove leading '=' */
  126. bv1.bv_len = (ber_len_t)dbt1->size - 1;
  127. bv2.bv_val = (char *)dbt2->data + 1; /* remove leading '=' */
  128. bv2.bv_len = (ber_len_t)dbt2->size - 1;
  129. return syntax_cmp_fn(&bv1, &bv2);
  130. }
  131. /* else compare two "raw" index keys */
  132. bv1.bv_val = (char *)dbt1->data;
  133. bv1.bv_len = (ber_len_t)dbt1->size;
  134. bv2.bv_val = (char *)dbt2->data;
  135. bv2.bv_len = (ber_len_t)dbt2->size;
  136. return slapi_berval_cmp(&bv1, &bv2);
  137. }
  138. /* this flag is used if user remotely turned batching off */
  139. #define FLUSH_REMOTEOFF 0
  140. /* routine that allows batch value to be changed remotely:
  141. 1. value = 0 turns batching off
  142. 2. value = 1 makes behavior be like 5.0 but leaves batching on
  143. 3. value > 1 changes batch value
  144. 2 and 3 assume that nsslapd-db-transaction-batch-val is greater 0 at startup
  145. */
  146. int
  147. bdb_set_batch_transactions(void *arg __attribute__((unused)), void *value, char *errorbuf __attribute__((unused)), int phase, int apply)
  148. {
  149. int val = (int)((uintptr_t)value);
  150. int retval = LDAP_SUCCESS;
  151. if (apply) {
  152. if (phase == CONFIG_PHASE_STARTUP) {
  153. trans_batch_limit = val;
  154. } else {
  155. if (val == 0) {
  156. if (log_flush_thread) {
  157. PR_Lock(sync_txn_log_flush);
  158. }
  159. trans_batch_limit = FLUSH_REMOTEOFF;
  160. if (log_flush_thread) {
  161. log_flush_thread = PR_FALSE;
  162. PR_Unlock(sync_txn_log_flush);
  163. }
  164. } else if (val > 0) {
  165. if (trans_batch_limit == FLUSH_REMOTEOFF) {
  166. /* this requires a server restart to take effect */
  167. slapi_log_err(SLAPI_LOG_NOTICE, "dblayer_set_batch_transactions", "Enabling batch transactions "
  168. "requires a server restart.\n");
  169. } else if (!log_flush_thread) {
  170. /* we are already disabled, log a reminder of that fact. */
  171. slapi_log_err(SLAPI_LOG_NOTICE, "dblayer_set_batch_transactions", "Batch transactions was "
  172. "previously disabled, this update requires a server restart.\n");
  173. }
  174. trans_batch_limit = val;
  175. }
  176. }
  177. }
  178. return retval;
  179. }
  180. int
  181. bdb_set_batch_txn_min_sleep(void *arg __attribute__((unused)), void *value, char *errorbuf __attribute__((unused)), int phase, int apply)
  182. {
  183. int val = (int)((uintptr_t)value);
  184. int retval = LDAP_SUCCESS;
  185. if (apply) {
  186. if (phase == CONFIG_PHASE_STARTUP || phase == CONFIG_PHASE_INITIALIZATION) {
  187. trans_batch_txn_min_sleep = val;
  188. } else {
  189. if (val == 0) {
  190. if (log_flush_thread) {
  191. PR_Lock(sync_txn_log_flush);
  192. }
  193. trans_batch_txn_min_sleep = FLUSH_REMOTEOFF;
  194. if (log_flush_thread) {
  195. log_flush_thread = PR_FALSE;
  196. PR_Unlock(sync_txn_log_flush);
  197. }
  198. } else if (val > 0) {
  199. if (trans_batch_txn_min_sleep == FLUSH_REMOTEOFF || !log_flush_thread) {
  200. /* this really has no effect until batch transactions are enabled */
  201. slapi_log_err(SLAPI_LOG_WARNING, "dblayer_set_batch_txn_min_sleep", "Warning batch transactions "
  202. "is not enabled.\n");
  203. }
  204. trans_batch_txn_min_sleep = val;
  205. }
  206. }
  207. }
  208. return retval;
  209. }
  210. int
  211. bdb_set_batch_txn_max_sleep(void *arg __attribute__((unused)), void *value, char *errorbuf __attribute__((unused)), int phase, int apply)
  212. {
  213. int val = (int)((uintptr_t)value);
  214. int retval = LDAP_SUCCESS;
  215. if (apply) {
  216. if (phase == CONFIG_PHASE_STARTUP || phase == CONFIG_PHASE_INITIALIZATION) {
  217. trans_batch_txn_max_sleep = val;
  218. } else {
  219. if (val == 0) {
  220. if (log_flush_thread) {
  221. PR_Lock(sync_txn_log_flush);
  222. }
  223. trans_batch_txn_max_sleep = FLUSH_REMOTEOFF;
  224. if (log_flush_thread) {
  225. log_flush_thread = PR_FALSE;
  226. PR_Unlock(sync_txn_log_flush);
  227. }
  228. } else if (val > 0) {
  229. if (trans_batch_txn_max_sleep == FLUSH_REMOTEOFF || !log_flush_thread) {
  230. /* this really has no effect until batch transactions are enabled */
  231. slapi_log_err(SLAPI_LOG_WARNING,
  232. "dblayer_set_batch_txn_max_sleep", "Warning batch transactions "
  233. "is not enabled.\n");
  234. }
  235. trans_batch_txn_max_sleep = val;
  236. }
  237. }
  238. }
  239. return retval;
  240. }
  241. void *
  242. bdb_get_batch_transactions(void *arg __attribute__((unused)))
  243. {
  244. return (void *)((uintptr_t)trans_batch_limit);
  245. }
  246. void *
  247. bdb_get_batch_txn_min_sleep(void *arg __attribute__((unused)))
  248. {
  249. return (void *)((uintptr_t)trans_batch_txn_min_sleep);
  250. }
  251. void *
  252. bdb_get_batch_txn_max_sleep(void *arg __attribute__((unused)))
  253. {
  254. return (void *)((uintptr_t)trans_batch_txn_max_sleep);
  255. }
  256. /*
  257. Threading: dblayer isolates upper layers from threading considerations
  258. Everything in dblayer is free-threaded. That is, you can have multiple
  259. threads performing operations on a database and not worry about things.
  260. Obviously, if you do something stupid, like move a cursor forward in
  261. one thread, and backwards in another at the same time, you get what you
  262. deserve. However, such a calling pattern will not crash your application !
  263. */
  264. static int
  265. dblayer_txn_checkpoint(struct ldbminfo *li, bdb_db_env *env, PRBool busy_skip, PRBool db_force)
  266. {
  267. int ret = 0;
  268. if (busy_skip && is_anyinstance_busy(li)) {
  269. return ret;
  270. }
  271. ret = TXN_CHECKPOINT(env->bdb_DB_ENV, db_force ? DB_FORCE : 0, 0, 0);
  272. return ret;
  273. }
  274. /*
  275. * return nsslapd-db-home-directory (bdb_dbhome_directory), if exists.
  276. * Otherwise, return nsslapd-directory (bdb_home_directory).
  277. *
  278. * if bdb_dbhome_directory exists, set 1 to dbhome.
  279. */
  280. char *
  281. bdb_get_home_dir(struct ldbminfo *li, int *dbhome)
  282. {
  283. bdb_config *priv = (bdb_config *)li->li_dblayer_config;
  284. char *home_dir = li->li_directory;
  285. if (dbhome)
  286. *dbhome = 0;
  287. if (priv->bdb_dbhome_directory && *(priv->bdb_dbhome_directory)) {
  288. if (dbhome)
  289. *dbhome = 1;
  290. home_dir = priv->bdb_dbhome_directory;
  291. }
  292. if (NULL == home_dir) {
  293. slapi_log_err(SLAPI_LOG_WARNING, "bdb_get_home_dir", "Db home directory is not set. "
  294. "Possibly %s (optionally %s) is missing in the config file.\n",
  295. CONFIG_DIRECTORY, CONFIG_DB_HOME_DIRECTORY);
  296. }
  297. return home_dir;
  298. }
  299. /*
  300. * return the top db directory
  301. */
  302. char *
  303. bdb_get_db_dir(struct ldbminfo *li)
  304. {
  305. return li->li_directory;
  306. }
  307. /* Helper function which deletes the persistent state of the database library
  308. * IMHO this should be in inside libdb, but keith won't have it.
  309. * Stop press---libdb now does delete these files on recovery, so we don't call this any more.
  310. */
  311. static void
  312. dblayer_reset_env(struct ldbminfo *li)
  313. {
  314. /* Remove the memory regions */
  315. dblayer_private *priv = li->li_dblayer_private;
  316. DB_ENV *pEnv = ((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV;
  317. char *home_dir = bdb_get_home_dir(li, NULL);
  318. if (home_dir && *home_dir)
  319. pEnv->remove(pEnv, home_dir, DB_FORCE);
  320. }
  321. /* Function which calls libdb to override some system calls which
  322. * the library makes. We call this before calling any other function
  323. * in libdb.
  324. * Several OS use this, either partially or completely.
  325. * This will eventually change---we will simply pass to libdb
  326. * the addresses of a bunch of NSPR functions, and everything
  327. * will magically work on all platforms (Ha!)
  328. */
  329. #ifdef DB_USE_64LFS
  330. /* What is going on here ?
  331. * Well, some platforms now support an extended API for dealing with
  332. * files larger than 2G. (This apparently comes from the LFS -- "Large
  333. * File Summit"... Summit, indeed.) Anyway, we try to detect at runtime
  334. * whether this machine has the extended API, and use it if it's present.
  335. *
  336. */
  337. /* helper function for open64 */
  338. static int
  339. dblayer_open_large(const char *path, int oflag, mode_t mode)
  340. {
  341. int err;
  342. err = open64(path, oflag, mode);
  343. /* weird but necessary: */
  344. if (err >= 0)
  345. errno = 0;
  346. return err;
  347. }
  348. /* this is REALLY dumb. but nspr 19980529(x) doesn't support 64-bit files
  349. * because of some weirdness we're doing at initialization (?), so we need
  350. * to export some function that can open huge files, so that exporting
  351. * can work right. when we fix the nspr problem (or get a more recent
  352. * version of nspr that might magically work?), this should be blown away.
  353. * (call mode_t an int because NT can't handle that in prototypes.)
  354. * -robey, 28oct98
  355. */
  356. int
  357. bdb_open_huge_file(const char *path, int oflag, int mode)
  358. {
  359. return dblayer_open_large(path, oflag, (mode_t)mode);
  360. }
  361. /* Helper function for large seeks, db4.3 */
  362. static int
  363. dblayer_seek43_large(int fd, off64_t offset, int whence)
  364. {
  365. off64_t ret = 0;
  366. ret = lseek64(fd, offset, whence);
  367. return (ret < 0) ? errno : 0;
  368. }
  369. /* helper function for large fstat -- this depends on 'struct stat64' having
  370. * the following members:
  371. * off64_t st_size;
  372. * long st_blksize;
  373. */
  374. static int
  375. dblayer_ioinfo_large(const char *path __attribute__((unused)), int fd, u_int32_t *mbytesp, u_int32_t *bytesp, u_int32_t *iosizep)
  376. {
  377. struct stat64 sb;
  378. if (fstat64(fd, &sb) < 0)
  379. return (errno);
  380. /* Return the size of the file. */
  381. if (mbytesp)
  382. *mbytesp = (u_int32_t)(sb.st_size / (off64_t)MEGABYTE);
  383. if (bytesp)
  384. *bytesp = (u_int32_t)(sb.st_size % (off64_t)MEGABYTE);
  385. if (iosizep)
  386. *iosizep = (u_int32_t)(sb.st_blksize);
  387. return 0;
  388. }
  389. /* Helper function to tell if a file exists */
  390. /* On Solaris, if you use stat() on a file >4Gbytes, it fails with EOVERFLOW,
  391. causing us to think that the file does not exist when it in fact does */
  392. static int
  393. dblayer_exists_large(const char *path, int *isdirp)
  394. {
  395. struct stat64 sb;
  396. if (stat64(path, &sb) != 0)
  397. return (errno);
  398. if (isdirp != NULL)
  399. *isdirp = S_ISDIR(sb.st_mode);
  400. return (0);
  401. }
  402. #else /* DB_USE_64LFS */
  403. int
  404. bdb_open_huge_file(const char *path, int oflag, int mode)
  405. {
  406. return open(path, oflag, mode);
  407. }
  408. #endif /* DB_USE_64LFS */
  409. static int
  410. dblayer_override_libdb_functions(void)
  411. {
  412. #ifdef DB_USE_64LFS
  413. int major = 0;
  414. int minor = 0;
  415. /* Find out whether we are talking to a 2.3 or 2.4+ libdb */
  416. db_version(&major, &minor, NULL);
  417. #ifndef irix
  418. /* irix doesn't have open64() */
  419. db_env_set_func_open((int (*)(const char *, int, ...))dblayer_open_large);
  420. #endif /* !irix */
  421. db_env_set_func_ioinfo(dblayer_ioinfo_large);
  422. db_env_set_func_exists(dblayer_exists_large);
  423. db_env_set_func_seek((int (*)(int, off_t, int))dblayer_seek43_large);
  424. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_override_libdb_function", "Enabled 64-bit files\n");
  425. #endif /* DB_USE_64LFS */
  426. return 0;
  427. }
  428. static void
  429. dblayer_select_ncache(size_t cachesize, int *ncachep)
  430. {
  431. /* First thing, if the user asked to use a particular ncache,
  432. * we let them, and don't override it here.
  433. */
  434. if (*ncachep) {
  435. return;
  436. }
  437. /* If the user asked for a cache that's larger than 4G,
  438. * we _must_ select an ncache >0 , such that each
  439. * chunk is <4G. This is because DB won't accept a
  440. * larger chunk.
  441. */
  442. #if defined(__LP64__) || defined(_LP64)
  443. if ((sizeof(cachesize) > 4) && (cachesize > (4L * GIGABYTE))) {
  444. *ncachep = (cachesize / (4L * GIGABYTE)) + 1;
  445. slapi_log_err(SLAPI_LOG_NOTICE, "dblayer_select_ncache", "Setting ncache to: %d to keep each chunk below 4Gbytes\n",
  446. *ncachep);
  447. }
  448. #endif
  449. }
  450. void
  451. dblayer_free(void *ptr)
  452. {
  453. slapi_ch_free(&ptr);
  454. }
  455. static void
  456. bdb_init_dbenv(DB_ENV *pEnv, bdb_config *conf, dblayer_private *priv)
  457. {
  458. size_t mysize;
  459. int myncache = 1;
  460. mysize = conf->bdb_cachesize;
  461. myncache = conf->bdb_ncache;
  462. dblayer_select_ncache(mysize, &myncache);
  463. conf->bdb_ncache = myncache;
  464. bdb_set_env_debugging(pEnv, conf);
  465. pEnv->set_lg_max(pEnv, conf->bdb_logfile_size);
  466. pEnv->set_cachesize(pEnv, mysize / GIGABYTE, mysize % GIGABYTE, myncache);
  467. pEnv->set_lk_max_locks(pEnv, conf->bdb_lock_config);
  468. pEnv->set_lk_max_objects(pEnv, conf->bdb_lock_config);
  469. pEnv->set_lk_max_lockers(pEnv, conf->bdb_lock_config);
  470. /* shm_key required for named_regions (DB_SYSTEM_MEM) */
  471. pEnv->set_shm_key(pEnv, conf->bdb_shm_key);
  472. /* increase max number of active transactions */
  473. pEnv->set_tx_max(pEnv, conf->bdb_tx_max);
  474. pEnv->set_alloc(pEnv, (void *)slapi_ch_malloc, (void *)slapi_ch_realloc, dblayer_free);
  475. /*
  476. * The log region is used to store filenames and so needs to be
  477. * increased in size from the default for a large number of files.
  478. */
  479. pEnv->set_lg_regionmax(pEnv, 1 * 1048576); /* 1 MB */
  480. }
  481. static void
  482. dblayer_dump_config_tracing(struct ldbminfo *li)
  483. {
  484. bdb_config *conf =(bdb_config *)li->li_dblayer_config;
  485. dblayer_private *priv = li->li_dblayer_private;
  486. if (conf->bdb_home_directory) {
  487. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "home_directory=%s\n", conf->bdb_home_directory);
  488. }
  489. if (conf->bdb_log_directory) {
  490. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "log_directory=%s\n", conf->bdb_log_directory);
  491. }
  492. if (conf->bdb_dbhome_directory) {
  493. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "dbhome_directory=%s\n", conf->bdb_dbhome_directory);
  494. }
  495. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "trickle_percentage=%d\n", conf->bdb_trickle_percentage);
  496. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "page_size=%" PRIu32 "\n", conf->bdb_page_size);
  497. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "index_page_size=%" PRIu32 "\n", conf->bdb_index_page_size);
  498. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "cachesize=%" PRIu64 "\n", conf->bdb_cachesize);
  499. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "previous_cachesize=%" PRIu64 "\n", conf->bdb_previous_cachesize);
  500. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "ncache=%d\n", conf->bdb_ncache);
  501. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "previous_ncache=%d\n", conf->bdb_previous_ncache);
  502. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "recovery_required=%d\n", conf->bdb_recovery_required);
  503. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "durable_transactions=%d\n", conf->bdb_durable_transactions);
  504. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "checkpoint_interval=%d\n", conf->bdb_checkpoint_interval);
  505. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "transaction_batch_val=%d\n", trans_batch_limit);
  506. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "circular_logging=%d\n", conf->bdb_circular_logging);
  507. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "idl_divisor=%d\n", priv->dblayer_idl_divisor);
  508. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "logfile_size=%" PRIu64 "\n", conf->bdb_logfile_size);
  509. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "logbuf_size=%" PRIu64 "\n", conf->bdb_logbuf_size);
  510. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "file_mode=%d\n", priv->dblayer_file_mode);
  511. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "cache_config=%d\n", conf->bdb_cache_config);
  512. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "lib_version=%d\n", conf->bdb_lib_version);
  513. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "spin_count=%d\n", conf->bdb_spin_count);
  514. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "named_regions=%d\n", conf->bdb_named_regions);
  515. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "private mem=%d\n", conf->bdb_private_mem);
  516. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "private import mem=%d\n", conf->bdb_private_import_mem);
  517. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "shm_key=%ld\n", conf->bdb_shm_key);
  518. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "lockdown=%d\n", conf->bdb_lockdown);
  519. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "locks=%d\n", conf->bdb_lock_config);
  520. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "previous_locks=%d\n", conf->bdb_previous_lock_config);
  521. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_dump_config_tracing", "tx_max=%d\n", conf->bdb_tx_max);
  522. }
  523. /* Check a given filesystem directory for access we need */
  524. #define DBLAYER_DIRECTORY_READ_ACCESS 1
  525. #define DBLAYER_DIRECTORY_WRITE_ACCESS 2
  526. #define DBLAYER_DIRECTORY_READWRITE_ACCESS 3
  527. static int
  528. dblayer_grok_directory(char *directory, int flags)
  529. {
  530. /* First try to open the directory using NSPR */
  531. /* If that fails, we can tell whether it's because it cannot be created or
  532. * we don't have any permission to access it */
  533. /* If that works, proceed to try to access files in the directory */
  534. char filename[MAXPATHLEN];
  535. PRDir *dirhandle = NULL;
  536. PRDirEntry *direntry = NULL;
  537. PRFileInfo64 info;
  538. dirhandle = PR_OpenDir(directory);
  539. if (NULL == dirhandle) {
  540. /* it does not exist or wrong file is there */
  541. /* try delete and mkdir */
  542. PR_Delete(directory);
  543. return mkdir_p(directory, 0700);
  544. }
  545. while (NULL !=
  546. (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
  547. if (NULL == direntry->name) {
  548. break;
  549. }
  550. PR_snprintf(filename, MAXPATHLEN, "%s/%s", directory, direntry->name);
  551. /* Right now this is set up to only look at files here.
  552. * With multiple instances of the backend the are now other directories
  553. * in the db home directory. This function wasn't ment to deal with
  554. * other directories, so we skip them. */
  555. if (PR_GetFileInfo64(filename, &info) == PR_SUCCESS &&
  556. info.type == PR_FILE_DIRECTORY) {
  557. /* go into it (instance dir) */
  558. int retval = dblayer_grok_directory(filename, flags);
  559. PR_CloseDir(dirhandle);
  560. return retval;
  561. }
  562. /* If we are here, it means that the directory exists, that we can read
  563. * from it, and that there is at least one file there */
  564. /* We will try to open that file now if we were asked for read access */
  565. if (flags) {
  566. PRFileDesc *prfd;
  567. PRIntn open_flags = 0;
  568. char *access_string = NULL;
  569. if (DBLAYER_DIRECTORY_READ_ACCESS & flags) {
  570. open_flags = PR_RDONLY;
  571. }
  572. if (DBLAYER_DIRECTORY_WRITE_ACCESS & flags) {
  573. open_flags = PR_RDWR;
  574. }
  575. /* Let's hope that on Solaris we get to open large files OK */
  576. prfd = PR_Open(filename, open_flags, 0);
  577. if (NULL == prfd) {
  578. if (DBLAYER_DIRECTORY_READ_ACCESS == flags) {
  579. access_string = "read";
  580. } else {
  581. if (DBLAYER_DIRECTORY_READ_ACCESS & flags) {
  582. access_string = "write";
  583. } else {
  584. access_string = "****";
  585. }
  586. }
  587. /* If we're here, it means that we did not have the requested
  588. * permission on this file */
  589. slapi_log_err(SLAPI_LOG_WARNING,
  590. "dblayer_grok_directory", "No %s permission to file %s\n",
  591. access_string, filename);
  592. } else {
  593. PR_Close(prfd); /* okay */
  594. }
  595. }
  596. }
  597. PR_CloseDir(dirhandle);
  598. return 0;
  599. }
  600. static void
  601. bdb_set_data_dir(bdb_db_env *pEnv, char **data_directories)
  602. {
  603. char **dirp;
  604. if (!(pEnv->bdb_priv_flags & DBLAYER_PRIV_SET_DATA_DIR)) {
  605. for (dirp = data_directories; dirp && *dirp; dirp++) {
  606. pEnv->bdb_DB_ENV->set_data_dir(pEnv->bdb_DB_ENV, *dirp);
  607. }
  608. pEnv->bdb_priv_flags |= DBLAYER_PRIV_SET_DATA_DIR;
  609. }
  610. }
  611. static int
  612. dblayer_inst_exists(ldbm_instance *inst, char *dbname)
  613. {
  614. PRStatus prst;
  615. char id2entry_file[MAXPATHLEN];
  616. char *parent_dir = inst->inst_parent_dir_name;
  617. char sep = get_sep(parent_dir);
  618. char *dbnamep;
  619. if (dbname)
  620. dbnamep = dbname;
  621. else
  622. dbnamep = ID2ENTRY LDBM_FILENAME_SUFFIX;
  623. PR_snprintf(id2entry_file, sizeof(id2entry_file), "%s%c%s%c%s", parent_dir, sep, inst->inst_dir_name,
  624. sep, dbnamep);
  625. prst = PR_Access(id2entry_file, PR_ACCESS_EXISTS);
  626. if (PR_SUCCESS == prst)
  627. return 1;
  628. return 0;
  629. }
  630. static void
  631. bdb_free_env(void **arg)
  632. {
  633. bdb_db_env **env = (bdb_db_env **)arg;
  634. if (NULL == env || NULL == *env) {
  635. return;
  636. }
  637. if ((*env)->bdb_env_lock) {
  638. slapi_destroy_rwlock((*env)->bdb_env_lock);
  639. (*env)->bdb_env_lock = NULL;
  640. }
  641. PR_DestroyCondVar((*env)->bdb_thread_count_cv);
  642. (*env)->bdb_thread_count_cv = NULL;
  643. PR_DestroyLock((*env)->bdb_thread_count_lock);
  644. (*env)->bdb_thread_count_lock = NULL;
  645. slapi_ch_free((void **)env);
  646. return;
  647. }
  648. /*
  649. * create a new DB_ENV and fill it with the goodies from dblayer_private
  650. */
  651. static int
  652. bdb_make_env(bdb_db_env **env, struct ldbminfo *li)
  653. {
  654. bdb_config *conf = (bdb_config *)li->li_dblayer_config;
  655. bdb_db_env *pEnv;
  656. char *db_dir = NULL;
  657. char *log_dir = NULL;
  658. int ret;
  659. Object *inst_obj;
  660. ldbm_instance *inst = NULL;
  661. pEnv = (bdb_db_env *)slapi_ch_calloc(1, sizeof(bdb_db_env));
  662. pEnv->bdb_thread_count_lock = PR_NewLock();
  663. pEnv->bdb_thread_count_cv = PR_NewCondVar(pEnv->bdb_thread_count_lock);
  664. if ((ret = db_env_create(&pEnv->bdb_DB_ENV, 0)) != 0) {
  665. slapi_log_err(SLAPI_LOG_ERR,
  666. "bdb_make_env", "Failed to create DB_ENV (returned: %d).\n",
  667. ret);
  668. }
  669. pEnv->bdb_DB_ENV->set_flags(pEnv->bdb_DB_ENV, DB_REGION_INIT, 1);
  670. /* Here we overide various system functions called by libdb */
  671. ret = dblayer_override_libdb_functions();
  672. if (ret != 0) {
  673. goto fail;
  674. }
  675. if (conf->bdb_spin_count != 0) {
  676. pEnv->bdb_DB_ENV->mutex_set_tas_spins(pEnv->bdb_DB_ENV,
  677. conf->bdb_spin_count);
  678. }
  679. dblayer_dump_config_tracing(li);
  680. /* set data dir to avoid having absolute paths in the transaction log */
  681. for (inst_obj = objset_first_obj(li->li_instance_set);
  682. inst_obj;
  683. inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
  684. inst = (ldbm_instance *)object_get_data(inst_obj);
  685. if (inst->inst_parent_dir_name) {
  686. if (!charray_utf8_inlist(conf->bdb_data_directories,
  687. inst->inst_parent_dir_name)) {
  688. charray_add(&(conf->bdb_data_directories),
  689. slapi_ch_strdup(inst->inst_parent_dir_name));
  690. }
  691. }
  692. }
  693. /* also set the main db directory as potential parent */
  694. db_dir = bdb_get_db_dir(li);
  695. if (db_dir && *db_dir &&
  696. !charray_utf8_inlist(conf->bdb_data_directories, db_dir)) {
  697. charray_add(&(conf->bdb_data_directories), slapi_ch_strdup(db_dir));
  698. }
  699. /* user specified log dir */
  700. log_dir = (char *)bdb_config_db_logdirectory_get_ext(li);
  701. if (log_dir && *log_dir) {
  702. pEnv->bdb_DB_ENV->set_lg_dir(pEnv->bdb_DB_ENV,log_dir);
  703. }
  704. /* set up cache sizes */
  705. bdb_init_dbenv(pEnv->bdb_DB_ENV, conf, li->li_dblayer_private);
  706. pEnv->bdb_env_lock = slapi_new_rwlock();
  707. if (pEnv->bdb_env_lock) {
  708. *env = pEnv;
  709. pEnv = NULL; /* do not free below */
  710. } else {
  711. slapi_log_err(SLAPI_LOG_ERR,
  712. "bdb_make_env", "Failed to create RWLock (returned: %d).\n",
  713. ret);
  714. }
  715. fail:
  716. if (pEnv) {
  717. slapi_ch_array_free(conf->bdb_data_directories);
  718. conf->bdb_data_directories = NULL;
  719. if (pEnv->bdb_DB_ENV) {
  720. pEnv->bdb_DB_ENV->close(pEnv->bdb_DB_ENV, 0);
  721. }
  722. bdb_free_env((void **)&pEnv); /* pEnv is now garbage */
  723. }
  724. return ret;
  725. }
  726. /*
  727. * Get the total size of all the __db files
  728. */
  729. static PRUint64
  730. dblayer_get_region_size(const char *dir)
  731. {
  732. PRFileInfo64 info;
  733. PRDir *dirhandle = NULL;
  734. PRDirEntry *direntry = NULL;
  735. PRUint64 region_size = 0;
  736. dirhandle = PR_OpenDir(dir);
  737. if (NULL == dirhandle) {
  738. return region_size;
  739. }
  740. while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
  741. if (NULL == direntry->name) {
  742. continue;
  743. }
  744. if (0 == strncmp(direntry->name, DB_REGION_PREFIX, 5)) {
  745. char filename[MAXPATHLEN];
  746. PR_snprintf(filename, MAXPATHLEN, "%s/%s", dir, direntry->name);
  747. if (PR_GetFileInfo64(filename, &info) != PR_FAILURE) {
  748. region_size += info.size;
  749. }
  750. }
  751. }
  752. PR_CloseDir(dirhandle);
  753. return region_size;
  754. }
  755. /*
  756. * Check that there is enough room for the dbcache and region files.
  757. * We can ignore this check if using db_home_dir and shared/private memory.
  758. */
  759. static int
  760. no_diskspace(struct ldbminfo *li, int dbenv_flags)
  761. {
  762. struct statvfs dbhome_buf;
  763. struct statvfs db_buf;
  764. int using_region_files = !(dbenv_flags & (DB_PRIVATE | DB_SYSTEM_MEM));
  765. /* value of 10 == 10% == little more than the average overhead calculated for very large files on 64-bit system for bdb 4.7 */
  766. uint64_t expected_siz = li->li_dbcachesize + li->li_dbcachesize / 10; /* dbcache + region files */
  767. uint64_t fsiz;
  768. char *region_dir;
  769. if (statvfs(li->li_directory, &db_buf) < 0) {
  770. slapi_log_err(SLAPI_LOG_ERR,
  771. "no_diskspace", "Cannot get file system info for (%s); file system corrupted?\n",
  772. li->li_directory);
  773. return 1;
  774. } else {
  775. /*
  776. * If db_home_directory is set, and it's not the same as the db_directory,
  777. * then check the disk space.
  778. */
  779. if (BDB_CONFIG(li)->bdb_dbhome_directory &&
  780. strcmp(BDB_CONFIG(li)->bdb_dbhome_directory, "") &&
  781. strcmp(li->li_directory, BDB_CONFIG(li)->bdb_dbhome_directory)) {
  782. /* Calculate the available space as long as we are not using shared memory */
  783. if (using_region_files) {
  784. if (statvfs(BDB_CONFIG(li)->bdb_dbhome_directory, &dbhome_buf) < 0) {
  785. slapi_log_err(SLAPI_LOG_ERR,
  786. "no_diskspace", "Cannot get file system info for (%s); file system corrupted?\n",
  787. BDB_CONFIG(li)->bdb_dbhome_directory);
  788. return 1;
  789. }
  790. fsiz = ((uint64_t)dbhome_buf.f_bavail) * ((uint64_t)dbhome_buf.f_bsize);
  791. region_dir = BDB_CONFIG(li)->bdb_dbhome_directory;
  792. } else {
  793. /* Shared/private memory. No need to check disk space, return success */
  794. return 0;
  795. }
  796. } else {
  797. /* Ok, just check the db directory */
  798. region_dir = li->li_directory;
  799. fsiz = ((PRUint64)db_buf.f_bavail) * ((PRUint64)db_buf.f_bsize);
  800. }
  801. /* Adjust the size for the region files */
  802. fsiz += dblayer_get_region_size(region_dir);
  803. /* Check if we have enough space */
  804. if (fsiz < expected_siz) {
  805. slapi_log_err(SLAPI_LOG_ERR,
  806. "no_diskspace", "No enough space left on device (%s) (%" PRIu64 " bytes); "
  807. "at least %" PRIu64 " bytes space is needed for db region files\n",
  808. region_dir, fsiz, expected_siz);
  809. return 1;
  810. }
  811. return 0;
  812. }
  813. }
  814. /*
  815. * This function is called after all the config options have been read in,
  816. * so we can do real initialization work here.
  817. */
  818. #define DBCONFLEN 3
  819. #define CATASTROPHIC (bdb_db_env *)-1
  820. int
  821. bdb_start(struct ldbminfo *li, int dbmode)
  822. {
  823. /*
  824. * So, here we open our DB_ENV session. We store it away for future use.
  825. * We also check to see if we exited cleanly last time. If we didn't,
  826. * we try to recover. If recovery fails, we're hosed.
  827. * We also create the thread which handles checkpointing and logfile
  828. * truncation here.
  829. */
  830. int return_value = -1;
  831. bdb_config *conf = NULL;
  832. dblayer_private *priv = NULL;
  833. bdb_db_env *pEnv = NULL;
  834. char *region_dir = NULL; /* directory to place region files */
  835. char *log_dir = NULL; /* directory to place txn log files */
  836. int open_flags = 0;
  837. PR_ASSERT(NULL != li);
  838. conf = (bdb_config *)li->li_dblayer_config;
  839. priv = li->li_dblayer_private;
  840. if (NULL == priv) {
  841. /* you didn't call init successfully */
  842. return -1;
  843. }
  844. if (NULL != priv->dblayer_env) {
  845. if (CATASTROPHIC == priv->dblayer_env) {
  846. slapi_log_err(SLAPI_LOG_CRIT,
  847. "bdb_start", "DB previously failed to start.\n");
  848. return -1;
  849. } else {
  850. slapi_log_err(SLAPI_LOG_WARNING,
  851. "bdb_start", "DB already started.\n");
  852. return 0;
  853. }
  854. }
  855. /* DBDB we should pick these up in our config routine, and do away with
  856. * the li_ one */
  857. if (NULL == li->li_directory || '\0' == *li->li_directory) {
  858. slapi_log_err(SLAPI_LOG_CRIT,
  859. "bdb_start", "DB directory is not specified.\n");
  860. return -1;
  861. }
  862. PR_Lock(li->li_config_mutex);
  863. /* li->li_directory comes from nsslapd-directory */
  864. /* bdb_home_directory is freed in bdb_post_close.
  865. * li_directory needs to live beyond dblayer. */
  866. slapi_ch_free_string(&conf->bdb_home_directory);
  867. conf->bdb_home_directory = slapi_ch_strdup(li->li_directory);
  868. conf->bdb_cachesize = li->li_dbcachesize;
  869. conf->bdb_lock_config = li->li_dblock;
  870. priv->dblayer_file_mode = li->li_mode;
  871. conf->bdb_ncache = li->li_dbncache;
  872. PR_Unlock(li->li_config_mutex);
  873. /* use nsslapd-db-home-directory (bdb_dbhome_directory), if set */
  874. /* Otherwise, nsslapd-directory (bdb_home_directory). */
  875. region_dir = bdb_get_home_dir(li, NULL);
  876. if (!region_dir || !(*region_dir)) {
  877. return -1;
  878. }
  879. if (!bdb_version_exists(li, region_dir)) {
  880. bdb_version_write(li, region_dir, NULL, DBVERSION_ALL);
  881. }
  882. /* Check here that the database directory both exists, and that we have
  883. * the appropriate access to it */
  884. return_value = dblayer_grok_directory(region_dir,
  885. DBLAYER_DIRECTORY_READWRITE_ACCESS);
  886. if (0 != return_value) {
  887. slapi_log_err(SLAPI_LOG_CRIT, "bdb_start",
  888. "Can't start because the database directory \"%s\" either doesn't exist, or is not accessible\n",
  889. region_dir);
  890. return return_value;
  891. }
  892. log_dir = conf->bdb_log_directory; /* nsslapd-db-logdirectory */
  893. if (log_dir && *log_dir) {
  894. /* checking the user defined log dir's accessability */
  895. return_value = dblayer_grok_directory(log_dir,
  896. DBLAYER_DIRECTORY_READWRITE_ACCESS);
  897. if (0 != return_value) {
  898. slapi_log_err(SLAPI_LOG_CRIT, "bdb_start",
  899. "Can't start because the log directory \"%s\" either doesn't exist, or is not accessible\n",
  900. log_dir);
  901. return return_value;
  902. }
  903. }
  904. /* Sanity check on cache size on platforms which allow us to figure out
  905. * the available phys mem */
  906. slapi_pal_meminfo *mi = spal_meminfo_get();
  907. util_cachesize_result result = util_is_cachesize_sane(mi, &(conf->bdb_cachesize));
  908. if (result == UTIL_CACHESIZE_ERROR) {
  909. slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", "Unable to determine if cachesize was valid!!!");
  910. } else if (result == UTIL_CACHESIZE_REDUCED) {
  911. /* In some cases we saw this go to 0, prevent this. */
  912. if (conf->bdb_cachesize < MINCACHESIZE) {
  913. conf->bdb_cachesize = MINCACHESIZE;
  914. }
  915. /* Oops---looks like the admin misconfigured, let's warn them */
  916. slapi_log_err(SLAPI_LOG_WARNING, "bdb_start",
  917. "Likely CONFIGURATION ERROR - dbcachesize is configured to use more than the available "
  918. "memory, decreased to (%" PRIu64 " bytes).\n", conf->bdb_cachesize);
  919. li->li_dbcachesize = conf->bdb_cachesize;
  920. }
  921. spal_meminfo_destroy(mi);
  922. /* fill in DB_ENV stuff from the common configuration */
  923. return_value = bdb_make_env(&pEnv, li);
  924. if (return_value != 0)
  925. return return_value;
  926. if ((DBLAYER_NORMAL_MODE | DBLAYER_CLEAN_RECOVER_MODE) & dbmode) {
  927. /* Now, we read our metadata */
  928. return_value = read_metadata(li);
  929. if (0 != return_value) {
  930. /* The error message was output by read_metadata() */
  931. return -1;
  932. }
  933. if (bdb_restore_file_check(li)) {
  934. dblayer_set_restored();
  935. }
  936. }
  937. bdb_free_env(&priv->dblayer_env);
  938. priv->dblayer_env = pEnv;
  939. open_flags = DB_CREATE | DB_INIT_MPOOL | DB_THREAD;
  940. if (conf->bdb_enable_transactions) {
  941. open_flags |= (DB_INIT_TXN | DB_INIT_LOG | DB_INIT_LOCK);
  942. if (conf->bdb_recovery_required) {
  943. open_flags |= DB_RECOVER;
  944. if (DBLAYER_RESTORE_MODE & dbmode) {
  945. slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start",
  946. "Recovering database after restore from archive.\n");
  947. } else if (DBLAYER_CLEAN_RECOVER_MODE & dbmode) {
  948. slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start",
  949. "Clean up db environment and start from archive.\n");
  950. } else {
  951. glob_t globbuf;
  952. char file_pattern[MAXPATHLEN];
  953. slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start",
  954. "Detected Disorderly Shutdown last time Directory Server was running, recovering database.\n");
  955. slapi_disorderly_shutdown(PR_TRUE);
  956. /* Better wipe out the region files to help ensure a clean start */
  957. PR_snprintf(file_pattern, MAXPATHLEN, "%s/%s", region_dir, "__db.*");
  958. if (glob(file_pattern, 0, NULL, &globbuf) == 0) {
  959. for (size_t i = 0; i < globbuf.gl_pathc; i++) {
  960. remove(globbuf.gl_pathv[i]);
  961. }
  962. globfree(&globbuf);
  963. }
  964. }
  965. }
  966. switch (dbmode & DBLAYER_RESTORE_MASK) {
  967. case DBLAYER_RESTORE_MODE:
  968. open_flags |= DB_RECOVER_FATAL;
  969. open_flags &= ~DB_RECOVER; /* shouldn't set both */
  970. if (!(dbmode & DBLAYER_NO_DBTHREADS_MODE))
  971. dbmode = DBLAYER_NORMAL_MODE; /* to restart helper threads */
  972. break;
  973. case DBLAYER_RESTORE_NO_RECOVERY_MODE:
  974. open_flags &= ~(DB_RECOVER | DB_RECOVER_FATAL);
  975. if (!(dbmode & DBLAYER_NO_DBTHREADS_MODE))
  976. dbmode = DBLAYER_NORMAL_MODE; /* to restart helper threads */
  977. }
  978. }
  979. if (conf->bdb_private_mem) {
  980. slapi_log_err(SLAPI_LOG_INFO, "bdb_start",
  981. "Server is running with nsslapd-db-private-mem on; "
  982. "No other process is allowed to access the database\n");
  983. open_flags |= DB_PRIVATE;
  984. }
  985. if (conf->bdb_named_regions) {
  986. open_flags |= DB_SYSTEM_MEM;
  987. }
  988. if (conf->bdb_lockdown) {
  989. open_flags |= DB_LOCKDOWN;
  990. }
  991. /* Is the cache being re-sized ? (If we're just doing an archive or export,
  992. * we don't care if the cache is being re-sized) */
  993. if ((conf->bdb_previous_cachesize || conf->bdb_previous_ncache) &&
  994. (conf->bdb_previous_lock_config) &&
  995. ((conf->bdb_cachesize != conf->bdb_previous_cachesize) ||
  996. (conf->bdb_ncache != conf->bdb_previous_ncache) ||
  997. (conf->bdb_lock_config != conf->bdb_previous_lock_config)) &&
  998. !(dbmode & (DBLAYER_ARCHIVE_MODE | DBLAYER_EXPORT_MODE))) {
  999. if (conf->bdb_cachesize != conf->bdb_previous_cachesize) {
  1000. slapi_log_err(SLAPI_LOG_INFO, "bdb_start", "Resizing db cache size: %" PRIu64 " -> %" PRIu64 "\n",
  1001. conf->bdb_previous_cachesize, conf->bdb_cachesize);
  1002. }
  1003. if (conf->bdb_ncache != conf->bdb_previous_ncache) {
  1004. slapi_log_err(SLAPI_LOG_INFO, "bdb_start", "Resizing db cache count: %d -> %d\n",
  1005. conf->bdb_previous_ncache, conf->bdb_ncache);
  1006. }
  1007. if (conf->bdb_lock_config != conf->bdb_previous_lock_config) {
  1008. /*
  1009. * The default value of nsslapd-db-locks is BDB_LOCKS_MIN.
  1010. * We don't allow lower value than that.
  1011. */
  1012. if (conf->bdb_lock_config <= BDB_LOCK_NB_MIN) {
  1013. slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start", "New max db lock count is too small. "
  1014. "Resetting it to the default value %d.\n",
  1015. BDB_LOCK_NB_MIN);
  1016. conf->bdb_lock_config = BDB_LOCK_NB_MIN;
  1017. }
  1018. if (conf->bdb_lock_config != conf->bdb_previous_lock_config) {
  1019. slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start", "Resizing max db lock count: %d -> %d\n",
  1020. conf->bdb_previous_lock_config, conf->bdb_lock_config);
  1021. }
  1022. }
  1023. dblayer_reset_env(li);
  1024. /*
  1025. * Once pEnv->remove (via dblayer_reset_env) has been called,
  1026. * the DB_ENV (pEnv) needs to be created again.
  1027. */
  1028. if ((return_value = bdb_make_env(&pEnv, li)) != 0) {
  1029. slapi_log_err(SLAPI_LOG_CRIT,
  1030. "bdb_start", "Failed to create DBENV (returned: %d).\n",
  1031. return_value);
  1032. }
  1033. bdb_free_env(&priv->dblayer_env);
  1034. priv->dblayer_env = pEnv;
  1035. }
  1036. /* transactions enabled and logbuf size greater than sleepycat's default */
  1037. if (conf->bdb_enable_transactions && (conf->bdb_logbuf_size > 0)) {
  1038. if (conf->bdb_logbuf_size >= 32768) {
  1039. pEnv->bdb_DB_ENV->set_lg_bsize(pEnv->bdb_DB_ENV, conf->bdb_logbuf_size);
  1040. } else {
  1041. slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start",
  1042. "Using default value for log bufsize because configured value (%" PRIu64 ") is too small.\n",
  1043. conf->bdb_logbuf_size);
  1044. }
  1045. }
  1046. /* check if there's enough disk space to start */
  1047. if (no_diskspace(li, open_flags)) {
  1048. return ENOSPC;
  1049. }
  1050. bdb_set_data_dir(pEnv, conf->bdb_data_directories);
  1051. /* If we're doing recovery, we MUST open the env single-threaded ! */
  1052. if ((open_flags & DB_RECOVER) || (open_flags & DB_RECOVER_FATAL)) {
  1053. /* Recover, then close, then open again */
  1054. int recover_flags = open_flags & ~DB_THREAD;
  1055. if (DBLAYER_CLEAN_RECOVER_MODE & dbmode) /* upgrade case */
  1056. {
  1057. DB_ENV *thisenv = pEnv->bdb_DB_ENV;
  1058. return_value = thisenv->remove(thisenv, region_dir, DB_FORCE);
  1059. if (0 != return_value) {
  1060. slapi_log_err(SLAPI_LOG_CRIT, "bdb_start",
  1061. "Failed to remove old db env in %s: %s\n",
  1062. region_dir, dblayer_strerror(return_value));
  1063. return return_value;
  1064. }
  1065. dbmode = DBLAYER_NORMAL_MODE;
  1066. if ((return_value = bdb_make_env(&pEnv, li)) != 0) {
  1067. slapi_log_err(SLAPI_LOG_CRIT, "bdb_start",
  1068. "Failed to create DBENV (returned: %d).\n", return_value);
  1069. return return_value;
  1070. }
  1071. }
  1072. return_value = (pEnv->bdb_DB_ENV->open)(
  1073. pEnv->bdb_DB_ENV,
  1074. region_dir,
  1075. recover_flags,
  1076. priv->dblayer_file_mode);
  1077. if (0 != return_value) {
  1078. if (return_value == ENOMEM) {
  1079. /*
  1080. * https://blackflag.mcom.com/show_bug.cgi?id=557319
  1081. * Crash ns-slapd while running scalab01 after restart slapd
  1082. */
  1083. slapi_log_err(SLAPI_LOG_CRIT,
  1084. "bdb_start", "mmap in opening database environment (recovery mode) "
  1085. "failed trying to allocate %" PRIu64 " bytes. (OS err %d - %s)\n",
  1086. li->li_dbcachesize, return_value, dblayer_strerror(return_value));
  1087. bdb_free_env(&priv->dblayer_env);
  1088. priv->dblayer_env = CATASTROPHIC;
  1089. } else {
  1090. slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", "Database Recovery Process FAILED. "
  1091. "The database is not recoverable. err=%d: %s\n",
  1092. return_value, dblayer_strerror(return_value));
  1093. slapi_log_err(SLAPI_LOG_CRIT, "bdb_start",
  1094. "Please make sure there is enough disk space for dbcache (%" PRIu64 " bytes) and db region files\n",
  1095. li->li_dbcachesize);
  1096. }
  1097. return return_value;
  1098. } else {
  1099. open_flags &= ~(DB_RECOVER | DB_RECOVER_FATAL);
  1100. pEnv->bdb_DB_ENV->close(pEnv->bdb_DB_ENV, 0);
  1101. if ((return_value = bdb_make_env(&pEnv, li)) != 0) {
  1102. slapi_log_err(SLAPI_LOG_CRIT, "bdb_start",
  1103. "Failed to create DBENV (returned: %d).\n", return_value);
  1104. return return_value;
  1105. }
  1106. bdb_free_env(&priv->dblayer_env);
  1107. priv->dblayer_env = pEnv;
  1108. bdb_set_data_dir(pEnv, conf->bdb_data_directories);
  1109. }
  1110. }
  1111. if ((!conf->bdb_durable_transactions) ||
  1112. ((conf->bdb_enable_transactions) && (trans_batch_limit > 0))) {
  1113. pEnv->bdb_DB_ENV->set_flags(pEnv->bdb_DB_ENV, DB_TXN_WRITE_NOSYNC, 1);
  1114. }
  1115. /* ldbm2index uses transactions but sets the transaction flag to off - we
  1116. need to dblayer_init_pvt_txn in that case */
  1117. dblayer_init_pvt_txn();
  1118. if (!((DBLAYER_IMPORT_MODE | DBLAYER_INDEX_MODE) & dbmode)) {
  1119. pEnv->bdb_openflags = open_flags;
  1120. return_value = (pEnv->bdb_DB_ENV->open)(
  1121. pEnv->bdb_DB_ENV,
  1122. region_dir,
  1123. open_flags,
  1124. priv->dblayer_file_mode);
  1125. /* Now attempt to start up the checkpoint and deadlock threads */
  1126. /* note: need to be '==', not '&' to omit DBLAYER_NO_DBTHREADS_MODE */
  1127. if ((DBLAYER_NORMAL_MODE == dbmode) &&
  1128. (0 == return_value)) {
  1129. /* update the dbversion file */
  1130. bdb_version_write(li, region_dir, NULL, DBVERSION_ALL);
  1131. /* if dblayer_close then bdb_start is called,
  1132. this flag is set */
  1133. conf->bdb_stop_threads = 0;
  1134. if (0 != (return_value = bdb_start_deadlock_thread(li))) {
  1135. return return_value;
  1136. }
  1137. if (0 != (return_value = bdb_start_checkpoint_thread(li))) {
  1138. return return_value;
  1139. }
  1140. if (0 != (return_value = bdb_start_log_flush_thread(li))) {
  1141. return return_value;
  1142. }
  1143. if (0 != (return_value = bdb_start_trickle_thread(li))) {
  1144. return return_value;
  1145. }
  1146. if (0 != (return_value = bdb_start_perf_thread(li))) {
  1147. return return_value;
  1148. }
  1149. /* We need to free the memory to avoid a leak
  1150. * Also, we have to evaluate if the performance counter
  1151. * should be preserved or not for database restore.
  1152. * Look - https://pagure.io/389-ds-base/issue/51020
  1153. */
  1154. if (conf->perf_private) {
  1155. perfctrs_terminate(&conf->perf_private, pEnv->bdb_DB_ENV);
  1156. }
  1157. /* Now open the performance counters stuff */
  1158. perfctrs_init(li, &(conf->perf_private));
  1159. if (getenv(TXN_TESTING)) {
  1160. bdb_start_txn_test_thread(li);
  1161. }
  1162. }
  1163. if (return_value != 0) {
  1164. if (return_value == ENOMEM) {
  1165. /*
  1166. * https://blackflag.mcom.com/show_bug.cgi?id=557319
  1167. * Crash ns-slapd while running scalab01 after restart slapd
  1168. */
  1169. slapi_log_err(SLAPI_LOG_CRIT, "bdb_start",
  1170. "mmap in opening database environment failed trying to allocate %" PRIu64 " bytes. (OS err %d - %s)\n",
  1171. li->li_dbcachesize, return_value, dblayer_strerror(return_value));
  1172. bdb_free_env(&priv->dblayer_env);
  1173. priv->dblayer_env = CATASTROPHIC;
  1174. } else {
  1175. slapi_log_err(SLAPI_LOG_CRIT, "bdb_start",
  1176. "Opening database environment (%s) failed. err=%d: %s\n",
  1177. region_dir, return_value, dblayer_strerror(return_value));
  1178. }
  1179. }
  1180. return return_value;
  1181. }
  1182. return 0;
  1183. }
  1184. /*
  1185. * If import cache autosize is enabled:
  1186. * nsslapd-import-cache-autosize: -1 or 1 ~ 99
  1187. * calculate the import cache size.
  1188. * If import cache is disabled:
  1189. * nsslapd-import-cache-autosize: 0
  1190. * get the nsslapd-import-cachesize.
  1191. * Calculate the memory size left after allocating the import cache size.
  1192. *
  1193. * Note: this function is called only if the import is executed as a stand
  1194. * alone command line (ldif2db).
  1195. */
  1196. int
  1197. bdb_check_and_set_import_cache(struct ldbminfo *li)
  1198. {
  1199. uint64_t import_cache = 0;
  1200. char s[64]; /* big enough to hold %ld */
  1201. /* Get our platform memory values. */
  1202. slapi_pal_meminfo *mi = spal_meminfo_get();
  1203. if (mi == NULL) {
  1204. slapi_log_err(SLAPI_LOG_ERR, "check_and_set_import_cache", "Failed to get system memory infomation\n");
  1205. return ENOENT;
  1206. }
  1207. slapi_log_err(SLAPI_LOG_INFO, "check_and_set_import_cache", "pagesize: %" PRIu64 ", available bytes %" PRIu64 ", process usage %" PRIu64 " \n", mi->pagesize_bytes, mi->system_available_bytes, mi->process_consumed_bytes);
  1208. /*
  1209. * default behavior for ldif2db import cache,
  1210. * nsslapd-import-cache-autosize==-1,
  1211. * autosize 50% mem to import cache
  1212. */
  1213. if (li->li_import_cache_autosize < 0) {
  1214. li->li_import_cache_autosize = 50;
  1215. }
  1216. /* sanity check */
  1217. if (li->li_import_cache_autosize >= 100) {
  1218. slapi_log_err(SLAPI_LOG_NOTICE,
  1219. "check_and_set_import_cache",
  1220. "Import cache autosizing value (nsslapd-import-cache-autosize) should not be "
  1221. "greater than or equal to 100%%. Reset to 50%%.\n");
  1222. li->li_import_cache_autosize = 50;
  1223. }
  1224. if (li->li_import_cache_autosize == 0) {
  1225. /* user specified importCache */
  1226. import_cache = li->li_import_cachesize;
  1227. } else {
  1228. /* autosizing importCache */
  1229. /* ./125 instead of ./100 is for adjusting the BDB overhead. */
  1230. import_cache = (li->li_import_cache_autosize * mi->system_available_bytes) / 125;
  1231. }
  1232. if (util_is_cachesize_sane(mi, &import_cache) == UTIL_CACHESIZE_ERROR) {
  1233. slapi_log_err(SLAPI_LOG_INFO, "check_and_set_import_cache", "Import failed to run: unable to validate system memory limits.\n");
  1234. spal_meminfo_destroy(mi);
  1235. return ENOMEM;
  1236. }
  1237. slapi_log_err(SLAPI_LOG_INFO, "check_and_set_import_cache", "Import allocates %" PRIu64 "KB import cache.\n", import_cache / 1024);
  1238. if (li->li_import_cache_autosize > 0) {
  1239. /* import cache autosizing */
  1240. /* set the calculated import cache size to the config */
  1241. sprintf(s, "%" PRIu64, import_cache);
  1242. bdb_config_internal_set(li, CONFIG_IMPORT_CACHESIZE, s);
  1243. }
  1244. spal_meminfo_destroy(mi);
  1245. return 0;
  1246. }
  1247. /* mode is one of
  1248. * DBLAYER_NORMAL_MODE,
  1249. * DBLAYER_INDEX_MODE,
  1250. * DBLAYER_IMPORT_MODE,
  1251. * DBLAYER_EXPORT_MODE
  1252. */
  1253. int
  1254. bdb_instance_start(backend *be, int mode)
  1255. {
  1256. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  1257. ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
  1258. bdb_config *conf;
  1259. dblayer_private *priv;
  1260. bdb_db_env *pEnv;
  1261. char inst_dir[MAXPATHLEN];
  1262. char *inst_dirp = NULL;
  1263. int return_value = -1;
  1264. conf = (bdb_config *)li->li_dblayer_config;
  1265. priv = li->li_dblayer_private;
  1266. pEnv = priv->dblayer_env;
  1267. if (CATASTROPHIC == pEnv || NULL == pEnv) {
  1268. slapi_log_err(SLAPI_LOG_ERR,
  1269. "bdb_instance_start", "DB Instance %s: dbenv is not available (0x%p).\n",
  1270. inst ? inst->inst_name : "unknown", pEnv);
  1271. return return_value;
  1272. }
  1273. if (NULL != inst->inst_id2entry) {
  1274. slapi_log_err(SLAPI_LOG_WARNING,
  1275. "bdb_instance_start", "DB instance \"%s\" already started.\n",
  1276. inst->inst_name);
  1277. return 0;
  1278. }
  1279. if (attrcrypt_init(inst)) {
  1280. slapi_log_err(SLAPI_LOG_ERR,
  1281. "bdb_instance_start", "Unable to initialize attrcrypt system for %s\n",
  1282. inst->inst_name);
  1283. return return_value;
  1284. }
  1285. /* Get the name of the directory that holds index files
  1286. * for this instance. */
  1287. if (dblayer_get_instance_data_dir(be) != 0) {
  1288. /* Problem getting the name of the directory that holds the
  1289. * index files for this instance. */
  1290. return return_value;
  1291. }
  1292. inst_dirp = dblayer_get_full_inst_dir(li, inst, inst_dir, MAXPATHLEN);
  1293. if (inst_dirp && *inst_dirp) {
  1294. return_value = dblayer_grok_directory(inst_dirp,
  1295. DBLAYER_DIRECTORY_READWRITE_ACCESS);
  1296. } else {
  1297. slapi_log_err(SLAPI_LOG_ERR, "bdb_instance_start",
  1298. "Can't start because the database instance "
  1299. "directory is NULL\n");
  1300. goto errout;
  1301. }
  1302. if (0 != return_value) {
  1303. slapi_log_err(SLAPI_LOG_ERR, "bdb_instance_start",
  1304. "Can't start because the database instance "
  1305. "directory \"%s\" either doesn't exist, "
  1306. "or the db files are not accessible\n",
  1307. inst_dirp);
  1308. goto errout;
  1309. }
  1310. if (mode & DBLAYER_NORMAL_MODE) {
  1311. /* In normal mode (not db2ldif, ldif2db, etc.) we need to deal with
  1312. * the dbversion file here. */
  1313. /* Read the dbversion file if there is one, and create it
  1314. * if it doesn't exist. */
  1315. if (bdb_version_exists(li, inst_dirp)) {
  1316. char *ldbmversion = NULL;
  1317. char *dataversion = NULL;
  1318. if (bdb_version_read(li, inst_dirp, &ldbmversion, &dataversion) != 0) {
  1319. slapi_log_err(SLAPI_LOG_WARNING, "bdb_instance_start", "Unable to read dbversion "
  1320. "file in %s\n",
  1321. inst->inst_dir_name);
  1322. } else {
  1323. int rval = 0;
  1324. /* check the DBVERSION and reset idl-switch if needed (DS6.2) */
  1325. /* from the next major rel, we won't do this and just upgrade */
  1326. if (!(li->li_flags & LI_FORCE_MOD_CONFIG)) {
  1327. adjust_idl_switch(ldbmversion, li);
  1328. }
  1329. slapi_ch_free_string(&ldbmversion);
  1330. /* check to make sure these instance was made with the correct
  1331. * version. */
  1332. rval = check_db_inst_version(inst);
  1333. if (rval & DBVERSION_NOT_SUPPORTED) {
  1334. slapi_log_err(SLAPI_LOG_ERR, "bdb_instance_start", " DB Instance %s does not have the "
  1335. "expected version\n",
  1336. inst->inst_name);
  1337. PR_ASSERT(0);
  1338. slapi_ch_free_string(&dataversion);
  1339. return_value = -1;
  1340. goto errout;
  1341. } else if (rval & DBVERSION_NEED_DN2RDN) {
  1342. slapi_log_err(SLAPI_LOG_ERR,
  1343. "bdb_instance_start", "%s is on, while the instance %s is in the DN format. "
  1344. "Please run dn2rdn to convert the database format.\n",
  1345. CONFIG_ENTRYRDN_SWITCH, inst->inst_name);
  1346. slapi_ch_free_string(&dataversion);
  1347. return_value = -1;
  1348. goto errout;
  1349. } else if (rval & DBVERSION_NEED_RDN2DN) {
  1350. slapi_log_err(SLAPI_LOG_ERR,
  1351. "bdb_instance_start", "%s is off, while the instance %s is in the RDN "
  1352. "format. Please change the value to on in dse.ldif.\n",
  1353. CONFIG_ENTRYRDN_SWITCH, inst->inst_name);
  1354. slapi_ch_free_string(&dataversion);
  1355. return_value = -1;
  1356. goto errout;
  1357. }
  1358. /* record the dataversion */
  1359. if (dataversion != NULL && *dataversion != '\0') {
  1360. inst->inst_dataversion = dataversion;
  1361. } else {
  1362. slapi_ch_free_string(&dataversion);
  1363. }
  1364. rval = ldbm_upgrade(inst, rval);
  1365. if (0 != rval) {
  1366. slapi_log_err(SLAPI_LOG_ERR, "bdb_instance_start", "Upgrading instance %s failed\n",
  1367. inst->inst_name);
  1368. PR_ASSERT(0);
  1369. return_value = -1;
  1370. goto errout;
  1371. }
  1372. }
  1373. } else {
  1374. /* The dbversion file didn't exist, so we'll create one. */
  1375. bdb_version_write(li, inst_dirp, NULL, DBVERSION_ALL);
  1376. }
  1377. } /* on import we don't mess with the dbversion file except to write it
  1378. * when done with the import. */
  1379. /* Now attempt to open id2entry */
  1380. {
  1381. char *id2entry_file;
  1382. int open_flags = 0;
  1383. DB *dbp;
  1384. char *subname;
  1385. bdb_db_env *mypEnv;
  1386. id2entry_file = slapi_ch_smprintf("%s/%s", inst->inst_dir_name,
  1387. ID2ENTRY LDBM_FILENAME_SUFFIX);
  1388. open_flags = DB_CREATE | DB_THREAD;
  1389. /* The subname argument allows applications to have
  1390. * subdatabases, i.e., multiple databases inside of a single
  1391. * physical file. This is useful when the logical databases
  1392. * are both numerous and reasonably small, in order to
  1393. * avoid creating a large number of underlying files.
  1394. */
  1395. subname = NULL;
  1396. mypEnv = NULL;
  1397. if (mode & (DBLAYER_IMPORT_MODE | DBLAYER_INDEX_MODE)) {
  1398. size_t cachesize;
  1399. char *data_directories[2] = {0, 0};
  1400. /* [605974] delete DB_PRIVATE:
  1401. * to make import visible to the other process */
  1402. int oflags = DB_CREATE | DB_INIT_MPOOL | DB_THREAD;
  1403. /*
  1404. * but nsslapd-db-private-import-mem should work with import,
  1405. * as well */
  1406. if (conf->bdb_private_import_mem) {
  1407. slapi_log_err(SLAPI_LOG_INFO,
  1408. "bdb_instance_start", "Import is running with "
  1409. "nsslapd-db-private-import-mem on; "
  1410. "No other process is allowed to access the database\n");
  1411. oflags |= DB_PRIVATE;
  1412. }
  1413. PR_Lock(li->li_config_mutex);
  1414. /* import cache checking and autosizing is available only
  1415. * for the command line */
  1416. if (li->li_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE) {
  1417. return_value = bdb_check_and_set_import_cache(li);
  1418. if (return_value) {
  1419. goto out;
  1420. }
  1421. }
  1422. cachesize = li->li_import_cachesize;
  1423. PR_Unlock(li->li_config_mutex);
  1424. if (cachesize < 1048576) {
  1425. /* make it at least 1M */
  1426. cachesize = 1048576;
  1427. }
  1428. conf->bdb_cachesize = cachesize;
  1429. /* We always auto-calculate ncache for the import region */
  1430. conf->bdb_ncache = 0;
  1431. /* use our own env */
  1432. return_value = bdb_make_env(&mypEnv, li);
  1433. if (return_value != 0) {
  1434. slapi_log_err(SLAPI_LOG_ERR,
  1435. "bdb_instance_start", "Unable to create new DB_ENV for import/export! %d\n",
  1436. return_value);
  1437. goto out;
  1438. }
  1439. /* do not assume import cache size is under 1G */
  1440. mypEnv->bdb_DB_ENV->set_cachesize(mypEnv->bdb_DB_ENV,
  1441. cachesize / GIGABYTE,
  1442. cachesize % GIGABYTE,
  1443. conf->bdb_ncache);
  1444. /* probably want to change this -- but for now, create the
  1445. * mpool files in the instance directory.
  1446. */
  1447. mypEnv->bdb_openflags = oflags;
  1448. data_directories[0] = inst->inst_parent_dir_name;
  1449. bdb_set_data_dir(mypEnv, data_directories);
  1450. return_value = (mypEnv->bdb_DB_ENV->open)(mypEnv->bdb_DB_ENV,
  1451. inst_dirp,
  1452. oflags,
  1453. priv->dblayer_file_mode);
  1454. if (return_value != 0) {
  1455. slapi_log_err(SLAPI_LOG_ERR,
  1456. "bdb_instance_start", "Unable to open new DB_ENV for import/export! %d\n",
  1457. return_value);
  1458. goto out;
  1459. }
  1460. inst->inst_db = mypEnv;
  1461. } else {
  1462. mypEnv = pEnv;
  1463. }
  1464. inst->inst_id2entry = NULL;
  1465. return_value = db_create(&inst->inst_id2entry, mypEnv->bdb_DB_ENV, 0);
  1466. if (0 != return_value) {
  1467. slapi_log_err(SLAPI_LOG_ERR,
  1468. "bdb_instance_start", "Unable to create id2entry db file! %d\n",
  1469. return_value);
  1470. goto out;
  1471. }
  1472. dbp = inst->inst_id2entry;
  1473. return_value = dbp->set_pagesize(dbp,
  1474. (conf->bdb_page_size == 0) ? DBLAYER_PAGESIZE : conf->bdb_page_size);
  1475. if (0 != return_value) {
  1476. slapi_log_err(SLAPI_LOG_ERR,
  1477. "bdb_instance_start", "dbp->set_pagesize(%" PRIu32 " or %" PRIu32 ") failed %d\n",
  1478. conf->bdb_page_size, DBLAYER_PAGESIZE,
  1479. return_value);
  1480. goto out;
  1481. }
  1482. if ((charray_get_index(conf->bdb_data_directories,
  1483. inst->inst_parent_dir_name) != 0) &&
  1484. !dblayer_inst_exists(inst, NULL)) {
  1485. char *abs_id2entry_file = NULL;
  1486. /* create a file with abs path, then try again */
  1487. abs_id2entry_file = slapi_ch_smprintf("%s%c%s", inst_dirp,
  1488. get_sep(inst_dirp), ID2ENTRY LDBM_FILENAME_SUFFIX);
  1489. DB_OPEN(mypEnv->bdb_openflags,
  1490. dbp, NULL /* txnid */, abs_id2entry_file, subname, DB_BTREE,
  1491. open_flags, priv->dblayer_file_mode, return_value);
  1492. dbp->close(dbp, 0);
  1493. return_value = db_create(&inst->inst_id2entry,
  1494. mypEnv->bdb_DB_ENV, 0);
  1495. if (0 != return_value)
  1496. goto out;
  1497. dbp = inst->inst_id2entry;
  1498. return_value = dbp->set_pagesize(dbp,
  1499. (conf->bdb_page_size == 0) ? DBLAYER_PAGESIZE : conf->bdb_page_size);
  1500. if (0 != return_value) {
  1501. slapi_log_err(SLAPI_LOG_ERR,
  1502. "bdb_instance_start", "dbp->set_pagesize(%" PRIu32 " or %" PRIu32 ") failed %d\n",
  1503. conf->bdb_page_size, DBLAYER_PAGESIZE,
  1504. return_value);
  1505. goto out;
  1506. }
  1507. slapi_ch_free_string(&abs_id2entry_file);
  1508. }
  1509. DB_OPEN(mypEnv->bdb_openflags,
  1510. dbp, NULL /* txnid */, id2entry_file, subname, DB_BTREE,
  1511. open_flags, priv->dblayer_file_mode, return_value);
  1512. if (0 != return_value) {
  1513. slapi_log_err(SLAPI_LOG_ERR,
  1514. "bdb_instance_start", "dbp->open(\"%s\") failed: %s (%d)\n",
  1515. id2entry_file, dblayer_strerror(return_value),
  1516. return_value);
  1517. /* if it's a newly created backend instance,
  1518. * need to check the inst_parent_dir already exists and
  1519. * set as a data dir */
  1520. if (strstr(dblayer_strerror(return_value),
  1521. "No such file or directory")) {
  1522. slapi_log_err(SLAPI_LOG_ERR,
  1523. "bdb_instance_start", "Instance %s is not registered as a db data directory. "
  1524. "Please restart the server to create it.\n",
  1525. inst ? inst->inst_name : "unknown");
  1526. } else if (strstr(dblayer_strerror(return_value),
  1527. "Permission denied")) {
  1528. slapi_log_err(SLAPI_LOG_ERR,
  1529. "bdb_instance_start", "Instance directory %s may not be writable\n",
  1530. inst_dirp);
  1531. }
  1532. goto out;
  1533. }
  1534. out:
  1535. slapi_ch_free_string(&id2entry_file);
  1536. }
  1537. if (0 == return_value) {
  1538. /* get nextid from disk now */
  1539. get_ids_from_disk(be);
  1540. }
  1541. if (mode & DBLAYER_NORMAL_MODE) {
  1542. bdb_version_write(li, inst_dirp, NULL, DBVERSION_ALL);
  1543. /* richm - not sure if need to acquire the be lock first? */
  1544. /* need to set state back to started - set to stopped in
  1545. dblayer_instance_close */
  1546. be->be_state = BE_STATE_STARTED;
  1547. }
  1548. /*
  1549. * check if nextid is valid: it only matters if the database is either
  1550. * being imported or is in normal mode
  1551. */
  1552. if (inst->inst_nextid > MAXID && !(mode & DBLAYER_EXPORT_MODE)) {
  1553. slapi_log_err(SLAPI_LOG_CRIT, "bdb_instance_start", "Backend '%s' "
  1554. "has no IDs left. DATABASE MUST BE REBUILT.\n",
  1555. be->be_name);
  1556. return 1;
  1557. }
  1558. if (return_value != 0) {
  1559. slapi_log_err(SLAPI_LOG_ERR, "bdb_instance_start", "Failure %s (%d)\n",
  1560. dblayer_strerror(return_value), return_value);
  1561. }
  1562. errout:
  1563. if (inst_dirp != inst_dir)
  1564. slapi_ch_free_string(&inst_dirp);
  1565. return return_value;
  1566. }
  1567. /*
  1568. * dblayer_get_aux_id2entry:
  1569. * - create a dedicated db env and db handler for id2entry.
  1570. * - introduced for upgradedb not to share the env and db handler with
  1571. * other index files to support multiple passes and merge.
  1572. * - Argument path is for returning the full path for the id2entry.db#,
  1573. * if the memory to store the address of the full path is given. The
  1574. * caller is supposed to release the full path.
  1575. */
  1576. int
  1577. bdb_get_aux_id2entry(backend *be, DB **ppDB, DB_ENV **ppEnv, char **path)
  1578. {
  1579. return bdb_get_aux_id2entry_ext(be, ppDB, ppEnv, path, 0);
  1580. }
  1581. /*
  1582. * flags:
  1583. * DBLAYER_AUX_ID2ENTRY_TMP -- create id2entry_tmp.db#
  1584. *
  1585. * - if non-NULL *ppEnv is given, env is already open.
  1586. * Just open an id2entry[_tmp].db#.
  1587. * - Argument path is for returning the full path for the id2entry[_tmp].db#,
  1588. * if the memory to store the address of the full path is given. The
  1589. * caller is supposed to release the full path.
  1590. */
  1591. int
  1592. bdb_get_aux_id2entry_ext(backend *be, DB **ppDB, DB_ENV **ppEnv, char **path, int flags)
  1593. {
  1594. ldbm_instance *inst;
  1595. bdb_db_env *mypEnv = NULL;
  1596. DB *dbp = NULL;
  1597. int rval = 1;
  1598. struct ldbminfo *li = NULL;
  1599. bdb_config *oconf = NULL;
  1600. bdb_config *conf = NULL;
  1601. dblayer_private *priv = NULL;
  1602. char *subname = NULL;
  1603. int envflags = 0;
  1604. int dbflags = 0;
  1605. size_t cachesize;
  1606. PRFileInfo64 prfinfo;
  1607. PRStatus prst;
  1608. char *id2entry_file = NULL;
  1609. char inst_dir[MAXPATHLEN];
  1610. char *inst_dirp = NULL;
  1611. char *data_directories[2] = {0, 0};
  1612. PR_ASSERT(NULL != be);
  1613. if ((NULL == ppEnv) || (NULL == ppDB)) {
  1614. slapi_log_err(SLAPI_LOG_ERR, "dblayer_get_aux_id2entry_ext", "No memory for DB_ENV or DB handle\n");
  1615. goto done;
  1616. }
  1617. *ppDB = NULL;
  1618. inst = (ldbm_instance *)be->be_instance_info;
  1619. if (NULL == inst) {
  1620. slapi_log_err(SLAPI_LOG_ERR,
  1621. "dblayer_get_aux_id2entry_ext", "No instance/env: persistent id2entry is not available\n");
  1622. goto done;
  1623. }
  1624. li = inst->inst_li;
  1625. if (NULL == li) {
  1626. slapi_log_err(SLAPI_LOG_ERR,
  1627. "dblayer_get_aux_id2entry_ext", "No ldbm info: persistent id2entry is not available\n");
  1628. goto done;
  1629. }
  1630. priv = li->li_dblayer_private;
  1631. oconf = (bdb_config *)li->li_dblayer_config;
  1632. if (NULL == oconf) {
  1633. slapi_log_err(SLAPI_LOG_ERR,
  1634. "dblayer_get_aux_id2entry_ext", "No dblayer info: persistent id2entry is not available\n");
  1635. goto done;
  1636. }
  1637. conf = (bdb_config *)slapi_ch_calloc(1, sizeof(bdb_config));
  1638. memcpy(conf, oconf, sizeof(bdb_config));
  1639. conf->bdb_spin_count = 0;
  1640. inst_dirp = dblayer_get_full_inst_dir(li, inst, inst_dir, MAXPATHLEN);
  1641. if (inst_dirp && *inst_dirp) {
  1642. conf->bdb_home_directory = slapi_ch_smprintf("%s/dbenv", inst_dirp);
  1643. } else {
  1644. slapi_log_err(SLAPI_LOG_ERR,
  1645. "dblayer_get_aux_id2entry_ext", "Instance dir is NULL: persistent id2entry is not available\n");
  1646. goto done;
  1647. }
  1648. conf->bdb_log_directory = slapi_ch_strdup(conf->bdb_home_directory);
  1649. prst = PR_GetFileInfo64(inst_dirp, &prfinfo);
  1650. if (PR_FAILURE == prst || PR_FILE_DIRECTORY != prfinfo.type) {
  1651. slapi_log_err(SLAPI_LOG_ERR,
  1652. "dblayer_get_aux_id2entry_ext", "No inst dir: persistent id2entry is not available\n");
  1653. goto done;
  1654. }
  1655. prst = PR_GetFileInfo64(conf->bdb_home_directory, &prfinfo);
  1656. if (PR_SUCCESS == prst) {
  1657. ldbm_delete_dirs(conf->bdb_home_directory);
  1658. }
  1659. rval = mkdir_p(conf->bdb_home_directory, 0700);
  1660. if (rval) {
  1661. slapi_log_err(SLAPI_LOG_ERR,
  1662. "dblayer_get_aux_id2entry_ext", "Can't create env dir: persistent id2entry is not available\n");
  1663. goto done;
  1664. }
  1665. /* use our own env if not passed */
  1666. if (!*ppEnv) {
  1667. rval = bdb_make_env(&mypEnv, li);
  1668. if (rval) {
  1669. slapi_log_err(SLAPI_LOG_ERR,
  1670. "dblayer_get_aux_id2entry_ext", "Unable to create new DB_ENV for import/export! %d\n", rval);
  1671. goto err;
  1672. }
  1673. }
  1674. envflags = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE;
  1675. cachesize = DEFAULT_DBCACHE_SIZE;
  1676. if (!*ppEnv) {
  1677. mypEnv->bdb_DB_ENV->set_cachesize(mypEnv->bdb_DB_ENV,
  1678. 0, cachesize, conf->bdb_ncache);
  1679. /* probably want to change this -- but for now, create the
  1680. * mpool files in the instance directory.
  1681. */
  1682. mypEnv->bdb_openflags = envflags;
  1683. data_directories[0] = inst->inst_parent_dir_name;
  1684. bdb_set_data_dir(mypEnv, data_directories);
  1685. rval = (mypEnv->bdb_DB_ENV->open)(mypEnv->bdb_DB_ENV,
  1686. conf->bdb_home_directory, envflags, priv->dblayer_file_mode);
  1687. if (rval) {
  1688. slapi_log_err(SLAPI_LOG_ERR,
  1689. "dblayer_get_aux_id2entry_ext", "Unable to open new DB_ENV for upgradedb/reindex %d\n", rval);
  1690. goto err;
  1691. }
  1692. *ppEnv = mypEnv->bdb_DB_ENV;
  1693. }
  1694. rval = db_create(&dbp, *ppEnv, 0);
  1695. if (rval) {
  1696. slapi_log_err(SLAPI_LOG_ERR,
  1697. "dblayer_get_aux_id2entry_ext", "Unable to create id2entry db handler! %d\n", rval);
  1698. goto err;
  1699. }
  1700. rval = dbp->set_pagesize(dbp, (conf->bdb_page_size == 0) ? DBLAYER_PAGESIZE : conf->bdb_page_size);
  1701. if (rval) {
  1702. slapi_log_err(SLAPI_LOG_ERR,
  1703. "dblayer_get_aux_id2entry_ext", "dbp->set_pagesize(%" PRIu32 " or %" PRIu32 ") failed %d\n",
  1704. conf->bdb_page_size, DBLAYER_PAGESIZE, rval);
  1705. goto err;
  1706. }
  1707. if (flags & DBLAYER_AUX_ID2ENTRY_TMP) {
  1708. id2entry_file = slapi_ch_smprintf("%s/%s_tmp%s",
  1709. inst->inst_dir_name, ID2ENTRY, LDBM_FILENAME_SUFFIX);
  1710. dbflags = DB_CREATE;
  1711. } else {
  1712. id2entry_file = slapi_ch_smprintf("%s/%s",
  1713. inst->inst_dir_name, ID2ENTRY LDBM_FILENAME_SUFFIX);
  1714. }
  1715. PR_ASSERT(dblayer_inst_exists(inst, NULL));
  1716. DB_OPEN(envflags, dbp, NULL /* txnid */, id2entry_file, subname, DB_BTREE,
  1717. dbflags, priv->dblayer_file_mode, rval);
  1718. if (rval) {
  1719. slapi_log_err(SLAPI_LOG_ERR,
  1720. "dblayer_get_aux_id2entry_ext", "dbp->open(\"%s\") failed: %s (%d)\n",
  1721. id2entry_file, dblayer_strerror(rval), rval);
  1722. if (strstr(dblayer_strerror(rval), "Permission denied")) {
  1723. slapi_log_err(SLAPI_LOG_ERR,
  1724. "dblayer_get_aux_id2entry_ext", "Instance directory %s may not be writable\n", inst_dirp);
  1725. }
  1726. goto err;
  1727. }
  1728. *ppDB = dbp;
  1729. rval = 0; /* to make it sure ... */
  1730. goto done;
  1731. err:
  1732. if (*ppEnv) {
  1733. (*ppEnv)->close(*ppEnv, 0);
  1734. *ppEnv = NULL;
  1735. }
  1736. if (conf->bdb_home_directory) {
  1737. ldbm_delete_dirs(conf->bdb_home_directory);
  1738. }
  1739. done:
  1740. if (path) {
  1741. if (0 == rval) { /* return the path only when successfull */
  1742. *path = slapi_ch_smprintf("%s/%s", inst->inst_parent_dir_name,
  1743. id2entry_file);
  1744. } else {
  1745. *path = NULL;
  1746. }
  1747. }
  1748. slapi_ch_free_string(&id2entry_file);
  1749. if (priv) {
  1750. slapi_ch_free_string(&conf->bdb_home_directory);
  1751. slapi_ch_free_string(&conf->bdb_log_directory);
  1752. }
  1753. /* Don't free priv->bdb_data_directories since priv doesn't own the memory */
  1754. slapi_ch_free((void **)&conf);
  1755. bdb_free_env((void **)&mypEnv);
  1756. if (inst_dirp != inst_dir)
  1757. slapi_ch_free_string(&inst_dirp);
  1758. return rval;
  1759. }
  1760. int
  1761. bdb_release_aux_id2entry(backend *be, DB *pDB, DB_ENV *pEnv)
  1762. {
  1763. ldbm_instance *inst;
  1764. char *envdir = NULL;
  1765. char inst_dir[MAXPATHLEN];
  1766. char *inst_dirp = NULL;
  1767. inst = (ldbm_instance *)be->be_instance_info;
  1768. if (NULL == inst) {
  1769. slapi_log_err(SLAPI_LOG_ERR,
  1770. "bdb_release_aux_id2entry", "No instance/env: persistent id2entry is not available\n");
  1771. goto done;
  1772. }
  1773. inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
  1774. inst_dir, MAXPATHLEN);
  1775. if (inst_dirp && *inst_dirp) {
  1776. envdir = slapi_ch_smprintf("%s/dbenv", inst_dirp);
  1777. }
  1778. done:
  1779. if (pDB) {
  1780. pDB->close(pDB, 0);
  1781. }
  1782. if (pEnv) {
  1783. pEnv->close(pEnv, 0);
  1784. }
  1785. if (envdir) {
  1786. ldbm_delete_dirs(envdir);
  1787. slapi_ch_free_string(&envdir);
  1788. }
  1789. if (inst_dirp != inst_dir)
  1790. slapi_ch_free_string(&inst_dirp);
  1791. return 0;
  1792. }
  1793. void
  1794. bdb_pre_close(struct ldbminfo *li)
  1795. {
  1796. dblayer_private *priv = 0;
  1797. bdb_config *conf;
  1798. PRInt32 threadcount = 0;
  1799. PR_ASSERT(NULL != li);
  1800. priv = li->li_dblayer_private;
  1801. conf = (bdb_config *)li->li_dblayer_config;
  1802. bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
  1803. if (conf->bdb_stop_threads) /* already stopped. do nothing... */
  1804. return;
  1805. /* first, see if there are any housekeeping threads running */
  1806. PR_Lock(pEnv->bdb_thread_count_lock);
  1807. threadcount = pEnv->bdb_thread_count;
  1808. PR_Unlock(pEnv->bdb_thread_count_lock);
  1809. if (threadcount) {
  1810. PRIntervalTime cvwaittime = PR_MillisecondsToInterval(DBLAYER_SLEEP_INTERVAL * 100);
  1811. int timedout = 0;
  1812. /* Print handy-dandy log message */
  1813. slapi_log_err(SLAPI_LOG_INFO, "bdb_pre_close", "Waiting for %d database threads to stop\n",
  1814. threadcount);
  1815. PR_Lock(pEnv->bdb_thread_count_lock);
  1816. /* Tell them to stop - we wait until the last possible moment to invoke
  1817. this. If we do this much sooner than this, we could find ourselves
  1818. in a situation where the threads see the stop_threads and exit before
  1819. we can issue the WaitCondVar below, which means the last thread to
  1820. exit will do a NotifyCondVar that has nothing waiting. If we do this
  1821. inside the lock, we will ensure that the threads will block until we
  1822. issue the WaitCondVar below */
  1823. conf->bdb_stop_threads = 1;
  1824. /* Wait for them to exit */
  1825. while (pEnv->bdb_thread_count > 0) {
  1826. PRIntervalTime before = PR_IntervalNow();
  1827. /* There are 3 ways to wake up from this WaitCondVar:
  1828. 1) The last database thread exits and calls NotifyCondVar - thread_count
  1829. should be 0 in this case
  1830. 2) Timeout - in this case, thread_count will be > 0 - bad
  1831. 3) A bad error occurs - bad - will be reported as a timeout
  1832. */
  1833. PR_WaitCondVar(pEnv->bdb_thread_count_cv, cvwaittime);
  1834. if (pEnv->bdb_thread_count > 0) {
  1835. /* still at least 1 thread running - see if this is a timeout */
  1836. if ((PR_IntervalNow() - before) >= cvwaittime) {
  1837. threadcount = pEnv->bdb_thread_count;
  1838. timedout = 1;
  1839. break;
  1840. }
  1841. /* else just a spurious interrupt */
  1842. }
  1843. }
  1844. PR_Unlock(pEnv->bdb_thread_count_lock);
  1845. if (timedout) {
  1846. slapi_log_err(SLAPI_LOG_ERR,
  1847. "bdb_pre_close", "Timeout after [%d] milliseconds; leave %d database thread(s)...\n",
  1848. (DBLAYER_SLEEP_INTERVAL * 100), threadcount);
  1849. priv->dblayer_bad_stuff_happened = 1;
  1850. goto timeout_escape;
  1851. }
  1852. }
  1853. slapi_log_err(SLAPI_LOG_INFO, "bdb_pre_close", "All database threads now stopped\n");
  1854. timeout_escape:
  1855. return;
  1856. }
  1857. int
  1858. bdb_post_close(struct ldbminfo *li, int dbmode)
  1859. {
  1860. bdb_config *conf = 0;
  1861. int return_value = 0;
  1862. PR_ASSERT(NULL != li);
  1863. dblayer_private *priv = li->li_dblayer_private;
  1864. bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
  1865. conf = (bdb_config *)li->li_dblayer_config;
  1866. /* We close all the files we ever opened, and call pEnv->close. */
  1867. if (NULL == pEnv) /* db env is already closed. do nothing. */
  1868. return return_value;
  1869. /* Shutdown the performance counter stuff */
  1870. if (DBLAYER_NORMAL_MODE & dbmode) {
  1871. if (conf->perf_private) {
  1872. perfctrs_terminate(&conf->perf_private, pEnv->bdb_DB_ENV);
  1873. }
  1874. }
  1875. /* Now release the db environment */
  1876. return_value = pEnv->bdb_DB_ENV->close(pEnv->bdb_DB_ENV, 0);
  1877. bdb_free_env((void **)&pEnv); /* pEnv is now garbage */
  1878. priv->dblayer_env = NULL;
  1879. if (0 == return_value && !((DBLAYER_ARCHIVE_MODE | DBLAYER_EXPORT_MODE) & dbmode) && !priv->dblayer_bad_stuff_happened) {
  1880. commit_good_database(conf, priv->dblayer_file_mode);
  1881. }
  1882. if (conf->bdb_data_directories) {
  1883. /* bdb_data_directories are set in bdb_make_env via
  1884. * dblayer_start, which is paired with dblayer_close. */
  1885. /* no need to release bdb_home_directory,
  1886. * which is one of bdb_data_directories */
  1887. charray_free(conf->bdb_data_directories);
  1888. conf->bdb_data_directories = NULL;
  1889. }
  1890. if (g_get_shutdown()) {
  1891. /* if the dblayer is closed temporarily
  1892. * eg. in online restore keep the directory settings
  1893. */
  1894. slapi_ch_free_string(&conf->bdb_dbhome_directory);
  1895. slapi_ch_free_string(&conf->bdb_home_directory);
  1896. }
  1897. return return_value;
  1898. }
  1899. /*
  1900. * This function is called when the server is shutting down, or when the
  1901. * backend is being disabled (e.g. backup/restore).
  1902. * This is not safe to call while other threads are calling into the open
  1903. * databases !!! So: DON'T !
  1904. */
  1905. int
  1906. bdb_close(struct ldbminfo *li, int dbmode)
  1907. {
  1908. backend *be = NULL;
  1909. ldbm_instance *inst;
  1910. Object *inst_obj;
  1911. int return_value = 0;
  1912. int shutdown = g_get_shutdown();
  1913. bdb_pre_close(li);
  1914. /*
  1915. * dblayer_close_indexes and pDB->close used to be located above loop:
  1916. * while(priv->dblayer_thread_count > 0) in pre_close.
  1917. * This order fixes a bug: shutdown under the stress makes txn_checkpoint
  1918. * (checkpoint_thread) fail b/c the mpool might have been already closed.
  1919. */
  1920. for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
  1921. inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
  1922. inst = (ldbm_instance *)object_get_data(inst_obj);
  1923. if (shutdown) {
  1924. vlv_close(inst);
  1925. }
  1926. be = inst->inst_be;
  1927. if (NULL != be->be_instance_info) {
  1928. return_value |= dblayer_instance_close(be);
  1929. }
  1930. }
  1931. if (return_value != 0) {
  1932. /* force recovery next startup if any close failed */
  1933. dblayer_private *priv;
  1934. PR_ASSERT(NULL != li);
  1935. priv = li->li_dblayer_private;
  1936. PR_ASSERT(NULL != priv);
  1937. priv->dblayer_bad_stuff_happened = 1;
  1938. }
  1939. return_value |= bdb_post_close(li, dbmode);
  1940. return return_value;
  1941. }
  1942. /* API to remove the environment */
  1943. int
  1944. bdb_remove_env(struct ldbminfo *li)
  1945. {
  1946. DB_ENV *env = NULL;
  1947. char *home_dir = NULL;
  1948. int rc = db_env_create(&env, 0);
  1949. if (rc) {
  1950. slapi_log_err(SLAPI_LOG_ERR,
  1951. "bdb_remove_env", "Failed to create DB_ENV (returned: %d)\n", rc);
  1952. return rc;
  1953. }
  1954. if (NULL == li) {
  1955. slapi_log_err(SLAPI_LOG_ERR, "bdb_remove_env", "No ldbm info is given\n");
  1956. return -1;
  1957. }
  1958. home_dir = bdb_get_home_dir(li, NULL);
  1959. if (home_dir) {
  1960. rc = env->remove(env, home_dir, 0);
  1961. if (rc) {
  1962. slapi_log_err(SLAPI_LOG_ERR,
  1963. "bdb_remove_env", "Failed to remove DB environment files. "
  1964. "Please remove %s/__db.00# (# is 1 through 6)\n",
  1965. home_dir);
  1966. }
  1967. }
  1968. return rc;
  1969. }
  1970. #if !defined(DB_DUPSORT)
  1971. #define DB_DUPSORT 0
  1972. #endif
  1973. static int
  1974. _dblayer_set_db_callbacks(bdb_config *conf, DB *dbp, struct attrinfo *ai)
  1975. {
  1976. int idl_use_new = 0;
  1977. int rc = 0;
  1978. /* With the new idl design, the large 8Kbyte pages we use are not
  1979. optimal. The page pool churns very quickly as we add new IDs under a
  1980. sustained add load. Smaller pages stop this happening so much and
  1981. consequently make us spend less time flushing dirty pages on checkpoints.
  1982. But 8K is still a good page size for id2entry. So we now allow different
  1983. page sizes for the primary and secondary indices.
  1984. Filed as bug: 604654
  1985. */
  1986. if (idl_get_idl_new()) {
  1987. rc = dbp->set_pagesize(
  1988. dbp,
  1989. (conf->bdb_index_page_size == 0) ? DBLAYER_INDEX_PAGESIZE : conf->bdb_index_page_size);
  1990. } else {
  1991. rc = dbp->set_pagesize(
  1992. dbp,
  1993. (conf->bdb_page_size == 0) ? DBLAYER_PAGESIZE : conf->bdb_page_size);
  1994. }
  1995. if (rc)
  1996. return rc;
  1997. /*
  1998. * If using the "new" idl, set the flags and the compare function.
  1999. * If using the "old" idl, we still need to set the index DB flags
  2000. * for the attribute "entryRDN".
  2001. */
  2002. if (((idl_use_new = idl_get_idl_new()) ||
  2003. 0 == strcasecmp(ai->ai_type, LDBM_ENTRYRDN_STR)) &&
  2004. !(ai->ai_indexmask & INDEX_VLV)) {
  2005. /* set the flags */
  2006. rc = dbp->set_flags(dbp, DB_DUP | DB_DUPSORT);
  2007. if (rc)
  2008. return rc;
  2009. /* set the compare function */
  2010. if (ai->ai_dup_cmp_fn) {
  2011. /* If set, use the special dup compare callback */
  2012. rc = dbp->set_dup_compare(dbp, ai->ai_dup_cmp_fn);
  2013. } else if (idl_use_new) {
  2014. rc = dbp->set_dup_compare(dbp, idl_new_compare_dups);
  2015. }
  2016. if (rc)
  2017. return rc;
  2018. }
  2019. if (ai->ai_indexmask & INDEX_VLV) {
  2020. /*
  2021. * Need index with record numbers for
  2022. * Virtual List View index
  2023. */
  2024. rc = dbp->set_flags(dbp, DB_RECNUM);
  2025. if (rc)
  2026. return rc;
  2027. } else if (ai->ai_key_cmp_fn) { /* set in attr_index_config() */
  2028. /*
  2029. This is so that we can have ordered keys in the index, so that
  2030. greater than/less than searches work on indexed attrs. We had
  2031. to introduce this when we changed the integer key format from
  2032. a 32/64 bit value to a normalized string value. The default
  2033. bdb key cmp is based on length and lexicographic order, which
  2034. does not work with integer strings.
  2035. NOTE: If we ever need to use app_private for something else, we
  2036. will have to create some sort of data structure with different
  2037. fields for different uses. We will also need to have a new()
  2038. function that creates and allocates that structure, and a
  2039. destroy() function that destroys the structure, and make sure
  2040. to call it when the DB* is closed and/or freed.
  2041. */
  2042. dbp->app_private = (void *)ai->ai_key_cmp_fn;
  2043. dbp->set_bt_compare(dbp, bdb_bt_compare);
  2044. }
  2045. return rc;
  2046. }
  2047. /* Routines for opening and closing random files in the DB_ENV.
  2048. Used by ldif2db merging code currently.
  2049. Return value:
  2050. Success: 0
  2051. Failure: -1
  2052. */
  2053. int
  2054. bdb_get_db(backend *be, char *indexname, int open_flag, struct attrinfo *ai, DB **ppDB)
  2055. {
  2056. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  2057. ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
  2058. int open_flags = 0;
  2059. char *file_name = NULL;
  2060. char *rel_path = NULL;
  2061. bdb_db_env *pENV = 0;
  2062. bdb_config *conf = NULL;
  2063. dblayer_private *priv = NULL;
  2064. int return_value = 0;
  2065. DB *dbp = NULL;
  2066. char *subname = NULL;
  2067. char inst_dir[MAXPATHLEN];
  2068. char *inst_dirp = NULL;
  2069. PR_ASSERT(NULL != li);
  2070. conf = (bdb_config *)li->li_dblayer_config;
  2071. priv = li->li_dblayer_private;
  2072. PR_ASSERT(NULL != priv);
  2073. if (NULL == inst->inst_dir_name) {
  2074. if (dblayer_get_instance_data_dir(be) != 0)
  2075. return -1;
  2076. }
  2077. if (NULL != inst->inst_parent_dir_name) {
  2078. if (!charray_utf8_inlist(conf->bdb_data_directories,
  2079. inst->inst_parent_dir_name) &&
  2080. !is_fullpath(inst->inst_dir_name))
  2081. {
  2082. slapi_log_err(SLAPI_LOG_ERR,
  2083. "dblayer_open_file", "The instance path %s is not registered for db_data_dir, "
  2084. "although %s is a relative path.\n",
  2085. inst->inst_parent_dir_name, inst->inst_dir_name);
  2086. return -1;
  2087. }
  2088. }
  2089. pENV = (bdb_db_env *)priv->dblayer_env;
  2090. if (inst->inst_db)
  2091. pENV = (bdb_db_env *)inst->inst_db;
  2092. PR_ASSERT(NULL != pENV);
  2093. file_name = slapi_ch_smprintf("%s%s", indexname, LDBM_FILENAME_SUFFIX);
  2094. rel_path = slapi_ch_smprintf("%s/%s", inst->inst_dir_name, file_name);
  2095. open_flags = DB_THREAD;
  2096. if (open_flag & DBOPEN_CREATE)
  2097. open_flags |= DB_CREATE;
  2098. if (open_flag & DBOPEN_TRUNCATE)
  2099. open_flags |= DB_TRUNCATE;
  2100. if (!ppDB)
  2101. goto out;
  2102. return_value = db_create(ppDB, pENV->bdb_DB_ENV, 0);
  2103. if (0 != return_value)
  2104. goto out;
  2105. dbp = *ppDB;
  2106. if (ai) {
  2107. return_value = _dblayer_set_db_callbacks(conf, dbp, ai);
  2108. if (return_value) {
  2109. goto out;
  2110. }
  2111. }
  2112. /* The subname argument allows applications to have
  2113. * subdatabases, i.e., multiple databases inside of a single
  2114. * physical file. This is useful when the logical databases
  2115. * are both numerous and reasonably small, in order to
  2116. * avoid creating a large number of underlying files.
  2117. */
  2118. /* If inst_parent_dir_name is not the primary DB dir &&
  2119. * the index file does not exist */
  2120. if ((charray_get_index(conf->bdb_data_directories,
  2121. inst->inst_parent_dir_name) > 0) &&
  2122. !dblayer_inst_exists(inst, file_name)) {
  2123. char *abs_file_name = NULL;
  2124. /* create a file with abs path, then try again */
  2125. inst_dirp = dblayer_get_full_inst_dir(li, inst, inst_dir, MAXPATHLEN);
  2126. if (!inst_dirp || !*inst_dirp) {
  2127. return_value = -1;
  2128. goto out;
  2129. }
  2130. abs_file_name = slapi_ch_smprintf("%s%c%s",
  2131. inst_dirp, get_sep(inst_dirp), file_name);
  2132. DB_OPEN(pENV->bdb_openflags,
  2133. dbp, NULL /* txnid */, abs_file_name, subname, DB_BTREE,
  2134. open_flags, priv->dblayer_file_mode, return_value);
  2135. dbp->close(dbp, 0);
  2136. return_value = db_create(ppDB, pENV->bdb_DB_ENV, 0);
  2137. if (0 != return_value) {
  2138. goto out;
  2139. }
  2140. dbp = *ppDB;
  2141. if (ai) {
  2142. return_value = _dblayer_set_db_callbacks(conf, dbp, ai);
  2143. if (return_value) {
  2144. goto out;
  2145. }
  2146. }
  2147. slapi_ch_free_string(&abs_file_name);
  2148. }
  2149. DB_OPEN(pENV->bdb_openflags,
  2150. dbp, NULL, /* txnid */ rel_path, subname, DB_BTREE,
  2151. open_flags, priv->dblayer_file_mode, return_value);
  2152. out:
  2153. slapi_ch_free((void **)&file_name);
  2154. slapi_ch_free((void **)&rel_path);
  2155. if (inst_dirp != inst_dir) {
  2156. slapi_ch_free_string(&inst_dirp);
  2157. }
  2158. /* close the database handle to avoid handle leak */
  2159. if (dbp && (return_value != 0)) {
  2160. bdb_close_file(&dbp);
  2161. }
  2162. return return_value;
  2163. }
  2164. int
  2165. bdb_close_file(DB **db)
  2166. {
  2167. if (db) {
  2168. DB *dbp = *db;
  2169. *db = NULL; /* To avoid to leave stale DB, set NULL before closing. */
  2170. return dbp->close(dbp, 0);
  2171. }
  2172. return 1;
  2173. }
  2174. /*
  2175. bdb_db_remove assumptions:
  2176. No environment has the given database open.
  2177. */
  2178. static int
  2179. bdb_db_remove_ex(bdb_db_env *env, char const path[], char const dbName[], PRBool use_lock)
  2180. {
  2181. DB_ENV *db_env = 0;
  2182. int rc;
  2183. DB *db;
  2184. if (env) {
  2185. if (use_lock)
  2186. slapi_rwlock_wrlock(env->bdb_env_lock); /* We will be causing logging activity */
  2187. db_env = env->bdb_DB_ENV;
  2188. }
  2189. rc = db_create(&db, db_env, 0); /* must use new handle to database */
  2190. if (0 != rc) {
  2191. slapi_log_err(SLAPI_LOG_ERR, "bdb_db_remove_ex", "Failed to create db (%d) %s\n",
  2192. rc, dblayer_strerror(rc));
  2193. goto done;
  2194. }
  2195. rc = db->remove(db, path, dbName, 0); /* kiss the db goodbye! */
  2196. done:
  2197. if (env) {
  2198. if (use_lock)
  2199. slapi_rwlock_unlock(env->bdb_env_lock);
  2200. }
  2201. return rc;
  2202. }
  2203. int
  2204. bdb_db_remove(bdb_db_env *env, char const path[], char const dbName[])
  2205. {
  2206. return (bdb_db_remove_ex(env, path, dbName, PR_TRUE));
  2207. }
  2208. static int
  2209. bdb_db_compact_one_db(DB *db, ldbm_instance *inst)
  2210. {
  2211. DBTYPE type;
  2212. int rc = 0;
  2213. back_txn txn;
  2214. DB_COMPACT c_data = {0};
  2215. rc = db->get_type(db, &type);
  2216. if (rc) {
  2217. slapi_log_err(SLAPI_LOG_ERR, "bdb_db_compact_one_db",
  2218. "compactdb: failed to determine db type for %s: db error - %d %s\n",
  2219. inst->inst_name, rc, db_strerror(rc));
  2220. return rc;
  2221. }
  2222. rc = dblayer_txn_begin(inst->inst_be, NULL, &txn);
  2223. if (rc) {
  2224. slapi_log_err(SLAPI_LOG_ERR, "bdb_db_compact_one_db", "compactdb: transaction begin failed: %d\n", rc);
  2225. return rc;
  2226. }
  2227. /*
  2228. * https://docs.oracle.com/cd/E17275_01/html/api_reference/C/BDB-C_APIReference.pdf
  2229. * "DB_FREELIST_ONLY
  2230. * Do no page compaction, only returning pages to the filesystem that are already free and at the end
  2231. * of the file. This flag must be set if the database is a Hash access method database."
  2232. *
  2233. */
  2234. uint32_t compact_flags = DB_FREE_SPACE;
  2235. if (type == DB_HASH) {
  2236. compact_flags |= DB_FREELIST_ONLY;
  2237. }
  2238. rc = db->compact(db, txn.back_txn_txn, NULL /*start*/, NULL /*stop*/,
  2239. &c_data, compact_flags, NULL /*end*/);
  2240. if (rc) {
  2241. slapi_log_err(SLAPI_LOG_ERR, "bdb_db_compact_one_db",
  2242. "compactdb: failed to compact %s; db error - %d %s\n",
  2243. inst->inst_name, rc, db_strerror(rc));
  2244. if ((rc = dblayer_txn_abort(inst->inst_be, &txn))) {
  2245. slapi_log_err(SLAPI_LOG_ERR, "bdb_db_compact_one_db", "compactdb: failed to abort txn (%s) db error - %d %s\n",
  2246. inst->inst_name, rc, db_strerror(rc));
  2247. }
  2248. } else {
  2249. slapi_log_err(SLAPI_LOG_NOTICE, "bdb_db_compact_one_db",
  2250. "compactdb: compact %s - %d pages freed\n",
  2251. inst->inst_name, c_data.compact_pages_free);
  2252. if ((rc = dblayer_txn_commit(inst->inst_be, &txn))) {
  2253. slapi_log_err(SLAPI_LOG_ERR, "bdb_db_compact_one_db", "compactdb: failed to commit txn (%s) db error - %d %s\n",
  2254. inst->inst_name, rc, db_strerror(rc));
  2255. }
  2256. }
  2257. return rc;
  2258. }
  2259. #define DBLAYER_CACHE_DELAY PR_MillisecondsToInterval(250)
  2260. int
  2261. bdb_rm_db_file(backend *be, struct attrinfo *a, PRBool use_lock, int no_force_checkpoint)
  2262. {
  2263. struct ldbminfo *li = NULL;
  2264. dblayer_private *priv;
  2265. bdb_db_env *pEnv = NULL;
  2266. ldbm_instance *inst = NULL;
  2267. dblayer_handle *handle = NULL;
  2268. char dbName[MAXPATHLEN] = {0};
  2269. char *dbNamep = NULL;
  2270. char *p;
  2271. int dbbasenamelen, dbnamelen;
  2272. int rc = 0;
  2273. DB *db = 0;
  2274. if ((NULL == be) || (NULL == be->be_database)) {
  2275. return rc;
  2276. }
  2277. inst = (ldbm_instance *)be->be_instance_info;
  2278. if (NULL == inst) {
  2279. return rc;
  2280. }
  2281. li = (struct ldbminfo *)be->be_database->plg_private;
  2282. if (NULL == li) {
  2283. return rc;
  2284. }
  2285. priv = li->li_dblayer_private;
  2286. if (NULL == priv) {
  2287. return rc;
  2288. }
  2289. pEnv = (bdb_db_env *)priv->dblayer_env;
  2290. if (NULL == pEnv) { /* db does not exist */
  2291. return rc;
  2292. }
  2293. /* Added for bug 600401. Somehow the checkpoint thread deadlocked on
  2294. index file with this function, index file couldn't be removed on win2k.
  2295. Force a checkpoint here to break deadlock.
  2296. */
  2297. if (0 == no_force_checkpoint) {
  2298. bdb_force_checkpoint(li);
  2299. }
  2300. if (0 == dblayer_get_index_file(be, a, &db, 0 /* Don't create an index file
  2301. if it does not exist. */)) {
  2302. if (use_lock)
  2303. slapi_rwlock_wrlock(pEnv->bdb_env_lock); /* We will be causing logging activity */
  2304. /* first, remove the file handle for this index, if we have it open */
  2305. PR_Lock(inst->inst_handle_list_mutex);
  2306. if (a->ai_dblayer) {
  2307. /* there is a handle */
  2308. handle = (dblayer_handle *)a->ai_dblayer;
  2309. /* when we successfully called dblayer_get_index_file we bumped up
  2310. the reference count of how many threads are using the index. So we
  2311. must manually back off the count by one here.... rwagner */
  2312. dblayer_release_index_file(be, a, db);
  2313. while (slapi_atomic_load_64(&(a->ai_dblayer_count), __ATOMIC_ACQUIRE) > 0) {
  2314. /* someone is using this index file */
  2315. /* ASSUMPTION: you have already set the INDEX_OFFLINE flag, because
  2316. * you intend to mess with this index. therefore no new requests
  2317. * for this indexfile should happen, so the dblayer_count should
  2318. * NEVER increase.
  2319. */
  2320. PR_ASSERT(a->ai_indexmask & INDEX_OFFLINE);
  2321. PR_Unlock(inst->inst_handle_list_mutex);
  2322. DS_Sleep(DBLAYER_CACHE_DELAY);
  2323. PR_Lock(inst->inst_handle_list_mutex);
  2324. }
  2325. bdb_close_file(&(handle->dblayer_dbp));
  2326. /* remove handle from handle-list */
  2327. if (inst->inst_handle_head == handle) {
  2328. inst->inst_handle_head = handle->dblayer_handle_next;
  2329. if (inst->inst_handle_tail == handle) {
  2330. inst->inst_handle_tail = NULL;
  2331. }
  2332. } else {
  2333. dblayer_handle *hp;
  2334. for (hp = inst->inst_handle_head; hp; hp = hp->dblayer_handle_next) {
  2335. if (hp->dblayer_handle_next == handle) {
  2336. hp->dblayer_handle_next = handle->dblayer_handle_next;
  2337. if (inst->inst_handle_tail == handle) {
  2338. inst->inst_handle_tail = hp;
  2339. }
  2340. break;
  2341. }
  2342. }
  2343. }
  2344. dbNamep = dblayer_get_full_inst_dir(li, inst, dbName, MAXPATHLEN);
  2345. if (dbNamep && *dbNamep) {
  2346. dbbasenamelen = strlen(dbNamep);
  2347. dbnamelen = dbbasenamelen + strlen(a->ai_type) + 6;
  2348. if (dbnamelen > MAXPATHLEN) {
  2349. dbNamep = (char *)slapi_ch_realloc(dbNamep, dbnamelen);
  2350. }
  2351. p = dbNamep + dbbasenamelen;
  2352. sprintf(p, "%c%s%s", get_sep(dbNamep), a->ai_type, LDBM_FILENAME_SUFFIX);
  2353. rc = bdb_db_remove_ex(pEnv, dbNamep, 0, 0);
  2354. a->ai_dblayer = NULL;
  2355. } else {
  2356. rc = -1;
  2357. }
  2358. if (dbNamep != dbName) {
  2359. slapi_ch_free_string(&dbNamep);
  2360. }
  2361. slapi_ch_free((void **)&handle);
  2362. } else {
  2363. /* no handle to close */
  2364. }
  2365. PR_Unlock(inst->inst_handle_list_mutex);
  2366. if (use_lock)
  2367. slapi_rwlock_unlock(pEnv->bdb_env_lock);
  2368. }
  2369. return rc;
  2370. }
  2371. /*
  2372. * Transaction stuff. The idea is that the caller doesn't need to
  2373. * know the transaction mechanism underneath (because the caller is
  2374. * typically a few calls up the stack from any DB stuff).
  2375. * Sadly, in slapd there was no handy structure associated with
  2376. * an LDAP operation, and passed around everywhere, so we had
  2377. * to invent the back_txn structure.
  2378. * The lower levels of the back-end look into this structure, and
  2379. * take out the DB_TXN they need.
  2380. */
  2381. int
  2382. bdb_txn_begin(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn, PRBool use_lock)
  2383. {
  2384. int return_value = -1;
  2385. bdb_config *conf = NULL;
  2386. dblayer_private *priv = NULL;
  2387. back_txn new_txn = {NULL};
  2388. PR_ASSERT(NULL != li);
  2389. /*
  2390. * When server is shutting down, some components need to
  2391. * flush some data (e.g. replication to write ruv).
  2392. * So don't check shutdown signal unless we can't write.
  2393. */
  2394. if (g_get_shutdown() == SLAPI_SHUTDOWN_DISKFULL) {
  2395. return return_value;
  2396. }
  2397. conf = (bdb_config *)li->li_dblayer_config;
  2398. priv = li->li_dblayer_private;
  2399. PR_ASSERT(NULL != priv);
  2400. if (txn) {
  2401. txn->back_txn_txn = NULL;
  2402. }
  2403. if (conf->bdb_enable_transactions) {
  2404. int txn_begin_flags;
  2405. bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
  2406. if (use_lock)
  2407. slapi_rwlock_rdlock(pEnv->bdb_env_lock);
  2408. if (!parent_txn) {
  2409. /* see if we have a stored parent txn */
  2410. back_txn *par_txn_txn = dblayer_get_pvt_txn();
  2411. if (par_txn_txn) {
  2412. parent_txn = par_txn_txn->back_txn_txn;
  2413. }
  2414. }
  2415. if (conf->bdb_txn_wait) {
  2416. txn_begin_flags = 0;
  2417. } else {
  2418. txn_begin_flags = DB_TXN_NOWAIT;
  2419. }
  2420. return_value = TXN_BEGIN(pEnv->bdb_DB_ENV,
  2421. (DB_TXN *)parent_txn,
  2422. &new_txn.back_txn_txn,
  2423. txn_begin_flags);
  2424. if (0 != return_value) {
  2425. if (use_lock)
  2426. slapi_rwlock_unlock(pEnv->bdb_env_lock);
  2427. } else {
  2428. /* this txn is now our current transaction for current operations
  2429. and new parent for any nested transactions created */
  2430. if (use_lock && log_flush_thread) {
  2431. int txn_id = new_txn.back_txn_txn->id(new_txn.back_txn_txn);
  2432. PR_Lock(sync_txn_log_flush);
  2433. txn_in_progress_count++;
  2434. slapi_log_err(SLAPI_LOG_BACKLDBM, "dblayer_txn_begin_ext",
  2435. "Batchcount: %d, txn_in_progress: %d, curr_txn: %x\n",
  2436. trans_batch_count, txn_in_progress_count, txn_id);
  2437. PR_Unlock(sync_txn_log_flush);
  2438. }
  2439. dblayer_push_pvt_txn(&new_txn);
  2440. if (txn) {
  2441. txn->back_txn_txn = new_txn.back_txn_txn;
  2442. }
  2443. }
  2444. } else {
  2445. return_value = 0;
  2446. }
  2447. if (0 != return_value) {
  2448. slapi_log_err(SLAPI_LOG_CRIT,
  2449. "dblayer_txn_begin_ext", "Serious Error---Failed in dblayer_txn_begin, err=%d (%s)\n",
  2450. return_value, dblayer_strerror(return_value));
  2451. }
  2452. return return_value;
  2453. }
  2454. int
  2455. bdb_txn_commit(struct ldbminfo *li, back_txn *txn, PRBool use_lock)
  2456. {
  2457. int return_value = -1;
  2458. bdb_config *conf = NULL;
  2459. dblayer_private *priv = NULL;
  2460. DB_TXN *db_txn = NULL;
  2461. back_txn *cur_txn = NULL;
  2462. int txn_id = 0;
  2463. int txn_batch_slot = 0;
  2464. PR_ASSERT(NULL != li);
  2465. conf = (bdb_config *)li->li_dblayer_config;
  2466. priv = li->li_dblayer_private;
  2467. PR_ASSERT(NULL != priv);
  2468. /* use the transaction we are given - if none, see if there
  2469. is a transaction in progress */
  2470. if (txn) {
  2471. db_txn = txn->back_txn_txn;
  2472. }
  2473. cur_txn = dblayer_get_pvt_txn();
  2474. if (!db_txn) {
  2475. if (cur_txn) {
  2476. db_txn = cur_txn->back_txn_txn;
  2477. }
  2478. }
  2479. if (NULL != db_txn &&
  2480. 1 != conf->bdb_stop_threads &&
  2481. priv->dblayer_env &&
  2482. conf->bdb_enable_transactions) {
  2483. bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
  2484. txn_id = db_txn->id(db_txn);
  2485. return_value = TXN_COMMIT(db_txn, 0);
  2486. /* if we were given a transaction, and it is the same as the
  2487. current transaction in progress, pop it off the stack
  2488. or, if no transaction was given, we must be using the
  2489. current one - must pop it */
  2490. if (!txn || (cur_txn && (cur_txn->back_txn_txn == db_txn))) {
  2491. dblayer_pop_pvt_txn();
  2492. }
  2493. if (txn) {
  2494. /* this handle is no longer value - set it to NULL */
  2495. txn->back_txn_txn = NULL;
  2496. }
  2497. if ((conf->bdb_durable_transactions) && use_lock) {
  2498. if (trans_batch_limit > 0 && log_flush_thread) {
  2499. /* let log_flush thread do the flushing */
  2500. PR_Lock(sync_txn_log_flush);
  2501. txn_batch_slot = trans_batch_count++;
  2502. txn_log_flush_pending[txn_batch_slot] = txn_id;
  2503. slapi_log_err(SLAPI_LOG_BACKLDBM, "dblayer_txn_commit_ext", "(before notify): batchcount: %d, "
  2504. "txn_in_progress: %d, curr_txn: %x\n",
  2505. trans_batch_count,
  2506. txn_in_progress_count, txn_id);
  2507. /*
  2508. * The log flush thread will periodically flush the txn log,
  2509. * but in two cases it should be notified to do it immediately:
  2510. * - the batch limit is passed
  2511. * - there is no other outstanding txn
  2512. */
  2513. if (trans_batch_count > trans_batch_limit ||
  2514. trans_batch_count == txn_in_progress_count) {
  2515. PR_NotifyCondVar(sync_txn_log_do_flush);
  2516. }
  2517. /*
  2518. * We need to wait until the txn has been flushed before continuing
  2519. * and returning success to the client, nit to vialate durability
  2520. * PR_WaitCondvar releases and reaquires the lock
  2521. */
  2522. while (txn_log_flush_pending[txn_batch_slot] == txn_id) {
  2523. PR_WaitCondVar(sync_txn_log_flush_done, PR_INTERVAL_NO_TIMEOUT);
  2524. }
  2525. txn_in_progress_count--;
  2526. slapi_log_err(SLAPI_LOG_BACKLDBM, "dblayer_txn_commit_ext", "(before unlock): batchcount: %d, "
  2527. "txn_in_progress: %d, curr_txn %x\n",
  2528. trans_batch_count,
  2529. txn_in_progress_count, txn_id);
  2530. PR_Unlock(sync_txn_log_flush);
  2531. } else if (trans_batch_limit == FLUSH_REMOTEOFF) { /* user remotely turned batching off */
  2532. LOG_FLUSH(pEnv->bdb_DB_ENV, 0);
  2533. }
  2534. }
  2535. if (use_lock)
  2536. slapi_rwlock_unlock(pEnv->bdb_env_lock);
  2537. } else {
  2538. return_value = 0;
  2539. }
  2540. if (0 != return_value) {
  2541. slapi_log_err(SLAPI_LOG_CRIT,
  2542. "dblayer_txn_commit_ext", "Serious Error---Failed in dblayer_txn_commit, err=%d (%s)\n",
  2543. return_value, dblayer_strerror(return_value));
  2544. if (LDBM_OS_ERR_IS_DISKFULL(return_value)) {
  2545. operation_out_of_disk_space();
  2546. }
  2547. }
  2548. return return_value;
  2549. }
  2550. int
  2551. bdb_txn_abort(struct ldbminfo *li, back_txn *txn, PRBool use_lock)
  2552. {
  2553. int return_value = -1;
  2554. dblayer_private *priv = NULL;
  2555. DB_TXN *db_txn = NULL;
  2556. back_txn *cur_txn = NULL;
  2557. PR_ASSERT(NULL != li);
  2558. priv = li->li_dblayer_private;
  2559. PR_ASSERT(NULL != priv);
  2560. /* use the transaction we are given - if none, see if there
  2561. is a transaction in progress */
  2562. if (txn) {
  2563. db_txn = txn->back_txn_txn;
  2564. }
  2565. cur_txn = dblayer_get_pvt_txn();
  2566. if (!db_txn) {
  2567. if (cur_txn) {
  2568. db_txn = cur_txn->back_txn_txn;
  2569. }
  2570. }
  2571. if (NULL != db_txn &&
  2572. priv->dblayer_env &&
  2573. BDB_CONFIG(li)->bdb_enable_transactions) {
  2574. int txn_id = db_txn->id(db_txn);
  2575. bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
  2576. if (use_lock && log_flush_thread) {
  2577. PR_Lock(sync_txn_log_flush);
  2578. txn_in_progress_count--;
  2579. PR_Unlock(sync_txn_log_flush);
  2580. slapi_log_err(SLAPI_LOG_BACKLDBM, "dblayer_txn_abort_ext",
  2581. "Batchcount: %d, txn_in_progress: %d, curr_txn: %x\n",
  2582. trans_batch_count, txn_in_progress_count, txn_id);
  2583. }
  2584. return_value = TXN_ABORT(db_txn);
  2585. /* if we were given a transaction, and it is the same as the
  2586. current transaction in progress, pop it off the stack
  2587. or, if no transaction was given, we must be using the
  2588. current one - must pop it */
  2589. if (!txn || (cur_txn && (cur_txn->back_txn_txn == db_txn))) {
  2590. dblayer_pop_pvt_txn();
  2591. }
  2592. if (txn) {
  2593. /* this handle is no longer value - set it to NULL */
  2594. txn->back_txn_txn = NULL;
  2595. }
  2596. if (use_lock)
  2597. slapi_rwlock_unlock(pEnv->bdb_env_lock);
  2598. } else {
  2599. return_value = 0;
  2600. }
  2601. if (0 != return_value) {
  2602. slapi_log_err(SLAPI_LOG_CRIT,
  2603. "dblayer_txn_abort_ext", "Serious Error---Failed in dblayer_txn_abort, err=%d (%s)\n",
  2604. return_value, dblayer_strerror(return_value));
  2605. if (LDBM_OS_ERR_IS_DISKFULL(return_value)) {
  2606. operation_out_of_disk_space();
  2607. }
  2608. }
  2609. return return_value;
  2610. }
  2611. uint32_t
  2612. dblayer_get_optimal_block_size(struct ldbminfo *li)
  2613. {
  2614. uint32_t page_size = 0;
  2615. PR_ASSERT(NULL != li);
  2616. page_size = (BDB_CONFIG(li)->bdb_page_size == 0) ? DBLAYER_PAGESIZE : BDB_CONFIG(li)->bdb_page_size;
  2617. if (li->li_dblayer_private->dblayer_idl_divisor == 0) {
  2618. return page_size - DB_EXTN_PAGE_HEADER_SIZE;
  2619. } else {
  2620. return page_size / li->li_dblayer_private->dblayer_idl_divisor;
  2621. }
  2622. }
  2623. /* code which implements checkpointing and log file truncation */
  2624. /*
  2625. * create a thread for perf_threadmain
  2626. */
  2627. static int
  2628. bdb_start_perf_thread(struct ldbminfo *li)
  2629. {
  2630. int return_value = 0;
  2631. if (NULL == PR_CreateThread(PR_USER_THREAD,
  2632. (VFP)(void *)perf_threadmain, li,
  2633. PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  2634. PR_UNJOINABLE_THREAD,
  2635. SLAPD_DEFAULT_THREAD_STACKSIZE)) {
  2636. PRErrorCode prerr = PR_GetError();
  2637. slapi_log_err(SLAPI_LOG_ERR, "bdb_start_perf_thread",
  2638. "Failed to create database perf thread, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  2639. prerr, slapd_pr_strerror(prerr));
  2640. return_value = -1;
  2641. }
  2642. return return_value;
  2643. }
  2644. /* Performance thread */
  2645. static int
  2646. perf_threadmain(void *param)
  2647. {
  2648. struct ldbminfo *li = NULL;
  2649. PR_ASSERT(NULL != param);
  2650. li = (struct ldbminfo *)param;
  2651. dblayer_private *priv = li->li_dblayer_private;
  2652. bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
  2653. PR_ASSERT(NULL != priv);
  2654. INCR_THREAD_COUNT(pEnv);
  2655. while (!BDB_CONFIG(li)->bdb_stop_threads) {
  2656. /* sleep for a while, updating perf counters if we need to */
  2657. perfctrs_wait(1000, BDB_CONFIG(li)->perf_private, pEnv->bdb_DB_ENV);
  2658. }
  2659. DECR_THREAD_COUNT(pEnv);
  2660. slapi_log_err(SLAPI_LOG_TRACE, "perf_threadmain", "Leaving perf_threadmain\n");
  2661. return 0;
  2662. }
  2663. /*
  2664. * create a thread for deadlock_threadmain
  2665. */
  2666. static int
  2667. bdb_start_deadlock_thread(struct ldbminfo *li)
  2668. {
  2669. int return_value = 0;
  2670. if (NULL == PR_CreateThread(PR_USER_THREAD,
  2671. (VFP)(void *)deadlock_threadmain, li,
  2672. PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  2673. PR_UNJOINABLE_THREAD,
  2674. SLAPD_DEFAULT_THREAD_STACKSIZE)) {
  2675. PRErrorCode prerr = PR_GetError();
  2676. slapi_log_err(SLAPI_LOG_ERR, "bdb_start_deadlock_thread",
  2677. "Failed to create database deadlock thread, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  2678. prerr, slapd_pr_strerror(prerr));
  2679. return_value = -1;
  2680. }
  2681. return return_value;
  2682. }
  2683. static const u_int32_t default_flags = DB_NEXT;
  2684. /* this is the loop delay - how long after we release the db pages
  2685. until we acquire them again */
  2686. #define TXN_TEST_LOOP_WAIT(msecs) \
  2687. do { \
  2688. if (msecs) { \
  2689. DS_Sleep(PR_MillisecondsToInterval(slapi_rand() % msecs)); \
  2690. } \
  2691. } while (0)
  2692. /* this is how long we hold the pages open until we close the cursors */
  2693. #define TXN_TEST_PAGE_HOLD(msecs) \
  2694. do { \
  2695. if (msecs) { \
  2696. DS_Sleep(PR_MillisecondsToInterval(slapi_rand() % msecs)); \
  2697. } \
  2698. } while (0)
  2699. typedef struct txn_test_iter
  2700. {
  2701. DB *db;
  2702. DBC *cur;
  2703. uint64_t cnt;
  2704. const char *attr;
  2705. uint32_t flags;
  2706. backend *be;
  2707. } txn_test_iter;
  2708. typedef struct txn_test_cfg
  2709. {
  2710. PRUint32 hold_msec;
  2711. PRUint32 loop_msec;
  2712. uint32_t flags;
  2713. int use_txn;
  2714. char **indexes;
  2715. int verbose;
  2716. } txn_test_cfg;
  2717. static txn_test_iter *
  2718. new_txn_test_iter(DB *db, const char *attr, backend *be, uint32_t flags)
  2719. {
  2720. txn_test_iter *tti = (txn_test_iter *)slapi_ch_malloc(sizeof(txn_test_iter));
  2721. tti->db = db;
  2722. tti->cur = NULL;
  2723. tti->cnt = 0;
  2724. tti->attr = attr;
  2725. tti->flags = default_flags | flags;
  2726. tti->be = be;
  2727. return tti;
  2728. }
  2729. static void
  2730. init_txn_test_iter(txn_test_iter *tti)
  2731. {
  2732. if (tti->cur) {
  2733. if (tti->cur->dbp && (tti->cur->dbp->open_flags == 0x58585858)) {
  2734. /* already closed? */
  2735. } else if (tti->be && (tti->be->be_state != BE_STATE_STARTED)) {
  2736. /* already closed? */
  2737. } else {
  2738. tti->cur->c_close(tti->cur);
  2739. }
  2740. tti->cur = NULL;
  2741. }
  2742. tti->cnt = 0;
  2743. tti->flags = default_flags;
  2744. }
  2745. static void
  2746. free_txn_test_iter(txn_test_iter *tti)
  2747. {
  2748. init_txn_test_iter(tti);
  2749. slapi_ch_free((void **)&tti);
  2750. }
  2751. static void
  2752. free_ttilist(txn_test_iter ***ttilist, uint64_t *tticnt)
  2753. {
  2754. if (!ttilist || !*ttilist || !**ttilist) {
  2755. return;
  2756. }
  2757. while (*tticnt > 0) {
  2758. (*tticnt)--;
  2759. free_txn_test_iter((*ttilist)[*tticnt]);
  2760. }
  2761. slapi_ch_free((void *)ttilist);
  2762. }
  2763. static void
  2764. init_ttilist(txn_test_iter **ttilist, uint64_t tticnt)
  2765. {
  2766. if (!ttilist || !*ttilist) {
  2767. return;
  2768. }
  2769. while (tticnt > 0) {
  2770. tticnt--;
  2771. init_txn_test_iter(ttilist[tticnt]);
  2772. }
  2773. }
  2774. static void
  2775. print_ttilist(txn_test_iter **ttilist, uint64_t tticnt)
  2776. {
  2777. while (tticnt > 0) {
  2778. tticnt--;
  2779. slapi_log_err(SLAPI_LOG_ERR,
  2780. "txn_test_threadmain", "attr [%s] cnt [%" PRIu64 "]\n",
  2781. ttilist[tticnt]->attr, ttilist[tticnt]->cnt);
  2782. }
  2783. }
  2784. #define TXN_TEST_IDX_OK_IF_NULL "nscpEntryDN"
  2785. static void
  2786. txn_test_init_cfg(txn_test_cfg *cfg)
  2787. {
  2788. static char *indexlist = "aci,entryrdn,numsubordinates,uid,ancestorid,objectclass,uniquemember,cn,parentid,nsuniqueid,sn,id2entry," TXN_TEST_IDX_OK_IF_NULL;
  2789. char *indexlist_copy = NULL;
  2790. cfg->hold_msec = getenv(TXN_TEST_HOLD_MSEC) ? atoi(getenv(TXN_TEST_HOLD_MSEC)) : 200;
  2791. cfg->loop_msec = getenv(TXN_TEST_LOOP_MSEC) ? atoi(getenv(TXN_TEST_LOOP_MSEC)) : 10;
  2792. cfg->flags = getenv(TXN_TEST_USE_RMW) ? DB_RMW : 0;
  2793. cfg->use_txn = getenv(TXN_TEST_USE_TXN) ? 1 : 0;
  2794. if (getenv(TXN_TEST_INDEXES)) {
  2795. indexlist_copy = slapi_ch_strdup(getenv(TXN_TEST_INDEXES));
  2796. } else {
  2797. indexlist_copy = slapi_ch_strdup(indexlist);
  2798. }
  2799. cfg->indexes = slapi_str2charray(indexlist_copy, ",");
  2800. slapi_ch_free_string(&indexlist_copy);
  2801. cfg->verbose = getenv(TXN_TEST_VERBOSE) ? 1 : 0;
  2802. slapi_log_err(SLAPI_LOG_ERR, "txn_test_init_cfg",
  2803. "Config hold_msec [%d] loop_msec [%d] rmw [%d] txn [%d] indexes [%s]\n",
  2804. cfg->hold_msec, cfg->loop_msec, cfg->flags, cfg->use_txn,
  2805. getenv(TXN_TEST_INDEXES) ? getenv(TXN_TEST_INDEXES) : indexlist);
  2806. }
  2807. static int
  2808. txn_test_threadmain(void *param)
  2809. {
  2810. struct ldbminfo *li = NULL;
  2811. Object *inst_obj;
  2812. int rc = 0;
  2813. txn_test_iter **ttilist = NULL;
  2814. uint64_t tticnt = 0;
  2815. DB_TXN *txn = NULL;
  2816. txn_test_cfg cfg = {0};
  2817. uint64_t counter = 0;
  2818. char keybuf[8192];
  2819. char databuf[8192];
  2820. int dbattempts = 0;
  2821. int dbmaxretries = 3;
  2822. PR_ASSERT(NULL != param);
  2823. li = (struct ldbminfo *)param;
  2824. dblayer_private *priv = li->li_dblayer_private;
  2825. PR_ASSERT(NULL != priv);
  2826. bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
  2827. INCR_THREAD_COUNT(pEnv);
  2828. txn_test_init_cfg(&cfg);
  2829. if(!BDB_CONFIG(li)->bdb_enable_transactions) {
  2830. goto end;
  2831. }
  2832. wait_for_init:
  2833. free_ttilist(&ttilist, &tticnt);
  2834. DS_Sleep(PR_MillisecondsToInterval(1000));
  2835. if (BDB_CONFIG(li)->bdb_stop_threads) {
  2836. goto end;
  2837. }
  2838. dbattempts++;
  2839. for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
  2840. inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
  2841. char **idx = NULL;
  2842. ldbm_instance *inst = (ldbm_instance *)object_get_data(inst_obj);
  2843. backend *be = inst->inst_be;
  2844. if (be->be_state != BE_STATE_STARTED) {
  2845. slapi_log_err(SLAPI_LOG_ERR,
  2846. "txn_test_threadmain", "Backend not started, retrying\n");
  2847. object_release(inst_obj);
  2848. goto wait_for_init;
  2849. }
  2850. for (idx = cfg.indexes; idx && *idx; ++idx) {
  2851. DB *db = NULL;
  2852. if (be->be_state != BE_STATE_STARTED) {
  2853. slapi_log_err(SLAPI_LOG_ERR,
  2854. "txn_test_threadmain", "Backend not started, retrying\n");
  2855. object_release(inst_obj);
  2856. goto wait_for_init;
  2857. }
  2858. if (!strcmp(*idx, "id2entry")) {
  2859. dblayer_get_id2entry(be, &db);
  2860. if (db == NULL) {
  2861. slapi_log_err(SLAPI_LOG_ERR,
  2862. "txn_test_threadmain", "id2entry database not found or not ready yet, retrying\n");
  2863. object_release(inst_obj);
  2864. goto wait_for_init;
  2865. }
  2866. } else {
  2867. struct attrinfo *ai = NULL;
  2868. ainfo_get(be, *idx, &ai);
  2869. if (NULL == ai) {
  2870. if (dbattempts >= dbmaxretries) {
  2871. slapi_log_err(SLAPI_LOG_ERR,
  2872. "txn_test_threadmain", "Index [%s] not found or not ready yet, skipping\n",
  2873. *idx);
  2874. continue;
  2875. } else {
  2876. slapi_log_err(SLAPI_LOG_ERR,
  2877. "txn_test_threadmain", "Index [%s] not found or not ready yet, retrying\n",
  2878. *idx);
  2879. object_release(inst_obj);
  2880. goto wait_for_init;
  2881. }
  2882. }
  2883. if (dblayer_get_index_file(be, ai, &db, 0) || (NULL == db)) {
  2884. if ((NULL == db) && strcasecmp(*idx, TXN_TEST_IDX_OK_IF_NULL)) {
  2885. if (dbattempts >= dbmaxretries) {
  2886. slapi_log_err(SLAPI_LOG_ERR,
  2887. "txn_test_threadmain", "Database file for index [%s] not found or not ready yet, skipping\n",
  2888. *idx);
  2889. continue;
  2890. } else {
  2891. slapi_log_err(SLAPI_LOG_ERR,
  2892. "txn_test_threadmain", "Database file for index [%s] not found or not ready yet, retrying\n",
  2893. *idx);
  2894. object_release(inst_obj);
  2895. goto wait_for_init;
  2896. }
  2897. }
  2898. }
  2899. }
  2900. if (db) {
  2901. ttilist = (txn_test_iter **)slapi_ch_realloc((char *)ttilist, sizeof(txn_test_iter *) * (tticnt + 1));
  2902. ttilist[tticnt++] = new_txn_test_iter(db, *idx, be, cfg.flags);
  2903. }
  2904. }
  2905. }
  2906. slapi_log_err(SLAPI_LOG_ERR, "txn_test_threadmain", "Starting main txn stress loop\n");
  2907. print_ttilist(ttilist, tticnt);
  2908. while (!BDB_CONFIG(li)->bdb_stop_threads) {
  2909. retry_txn:
  2910. init_ttilist(ttilist, tticnt);
  2911. if (txn) {
  2912. TXN_ABORT(txn);
  2913. txn = NULL;
  2914. }
  2915. if (cfg.use_txn) {
  2916. rc = TXN_BEGIN(((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV, NULL, &txn, 0);
  2917. if (rc || !txn) {
  2918. slapi_log_err(SLAPI_LOG_ERR,
  2919. "txn_test_threadmain", "Failed to create a new transaction, err=%d (%s)\n",
  2920. rc, dblayer_strerror(rc));
  2921. }
  2922. } else {
  2923. rc = 0;
  2924. }
  2925. if (!rc) {
  2926. DBT key;
  2927. DBT data;
  2928. uint64_t ii;
  2929. uint64_t donecnt = 0;
  2930. uint64_t cnt = 0;
  2931. /* phase 1 - open a cursor to each db */
  2932. if (cfg.verbose) {
  2933. slapi_log_err(SLAPI_LOG_ERR,
  2934. "txn_test_threadmain", "Starting [%" PRIu64 "] indexes\n", tticnt);
  2935. }
  2936. for (ii = 0; ii < tticnt; ++ii) {
  2937. txn_test_iter *tti = ttilist[ii];
  2938. retry_cursor:
  2939. if (BDB_CONFIG(li)->bdb_stop_threads) {
  2940. goto end;
  2941. }
  2942. if (tti->be->be_state != BE_STATE_STARTED) {
  2943. if (txn) {
  2944. TXN_ABORT(txn);
  2945. txn = NULL;
  2946. }
  2947. goto wait_for_init;
  2948. }
  2949. if (tti->db->open_flags == 0xdbdbdbdb) {
  2950. if (txn) {
  2951. TXN_ABORT(txn);
  2952. txn = NULL;
  2953. }
  2954. goto wait_for_init;
  2955. }
  2956. rc = tti->db->cursor(tti->db, txn, &tti->cur, 0);
  2957. if (DB_LOCK_DEADLOCK == rc) {
  2958. if (cfg.verbose) {
  2959. slapi_log_err(SLAPI_LOG_ERR,
  2960. "txn_test_threadmain", "Cursor create deadlock - retry\n");
  2961. }
  2962. if (cfg.use_txn) {
  2963. goto retry_txn;
  2964. } else {
  2965. goto retry_cursor;
  2966. }
  2967. } else if (rc) {
  2968. slapi_log_err(SLAPI_LOG_ERR,
  2969. "txn_test_threadmain", "Failed to create a new cursor, err=%d (%s)\n",
  2970. rc, dblayer_strerror(rc));
  2971. }
  2972. }
  2973. memset(&key, 0, sizeof(key));
  2974. key.flags = DB_DBT_USERMEM;
  2975. key.data = keybuf;
  2976. key.ulen = sizeof(keybuf);
  2977. memset(&data, 0, sizeof(data));
  2978. data.flags = DB_DBT_USERMEM;
  2979. data.data = databuf;
  2980. data.ulen = sizeof(databuf);
  2981. /* phase 2 - iterate over each cursor at the same time until
  2982. 1) get error
  2983. 2) get deadlock
  2984. 3) all cursors are exhausted
  2985. */
  2986. while (donecnt < tticnt) {
  2987. for (ii = 0; ii < tticnt; ++ii) {
  2988. txn_test_iter *tti = ttilist[ii];
  2989. if (tti->cur) {
  2990. retry_get:
  2991. if (BDB_CONFIG(li)->bdb_stop_threads) {
  2992. goto end;
  2993. }
  2994. if (tti->be->be_state != BE_STATE_STARTED) {
  2995. if (txn) {
  2996. TXN_ABORT(txn);
  2997. txn = NULL;
  2998. }
  2999. goto wait_for_init;
  3000. }
  3001. if (tti->db->open_flags == 0xdbdbdbdb) {
  3002. if (txn) {
  3003. TXN_ABORT(txn);
  3004. txn = NULL;
  3005. }
  3006. goto wait_for_init;
  3007. }
  3008. rc = tti->cur->c_get(tti->cur, &key, &data, tti->flags);
  3009. if (DB_LOCK_DEADLOCK == rc) {
  3010. if (cfg.verbose) {
  3011. slapi_log_err(SLAPI_LOG_ERR,
  3012. "txn_test_threadmain", "Cursor get deadlock - retry\n");
  3013. }
  3014. if (cfg.use_txn) {
  3015. goto retry_txn;
  3016. } else {
  3017. goto retry_get;
  3018. }
  3019. } else if (DB_NOTFOUND == rc) {
  3020. donecnt++; /* ran out of this one */
  3021. tti->flags = DB_FIRST | cfg.flags; /* start over until all indexes are done */
  3022. } else if (rc) {
  3023. if ((DB_BUFFER_SMALL != rc) || cfg.verbose) {
  3024. slapi_log_err(SLAPI_LOG_ERR,
  3025. "txn_test_threadmain", "Failed to read a cursor, err=%d (%s)\n",
  3026. rc, dblayer_strerror(rc));
  3027. }
  3028. tti->cur->c_close(tti->cur);
  3029. tti->cur = NULL;
  3030. donecnt++;
  3031. } else {
  3032. tti->cnt++;
  3033. tti->flags = default_flags | cfg.flags;
  3034. cnt++;
  3035. }
  3036. }
  3037. }
  3038. }
  3039. TXN_TEST_PAGE_HOLD(cfg.hold_msec);
  3040. /*print_ttilist(ttilist, tticnt);*/
  3041. init_ttilist(ttilist, tticnt);
  3042. if (cfg.verbose) {
  3043. slapi_log_err(SLAPI_LOG_ERR,
  3044. "txn_test_threadmain", "Finished [%" PRIu64 "] indexes [%" PRIu64 "] records\n", tticnt, cnt);
  3045. }
  3046. TXN_TEST_LOOP_WAIT(cfg.loop_msec);
  3047. } else {
  3048. TXN_TEST_LOOP_WAIT(cfg.loop_msec);
  3049. }
  3050. counter++;
  3051. if (!(counter % 40)) {
  3052. /* some operations get completely stuck - so every once in a while,
  3053. pause to allow those ops to go through */
  3054. DS_Sleep(PR_SecondsToInterval(1));
  3055. }
  3056. }
  3057. end:
  3058. slapi_ch_array_free(cfg.indexes);
  3059. free_ttilist(&ttilist, &tticnt);
  3060. if (txn) {
  3061. TXN_ABORT(txn);
  3062. }
  3063. DECR_THREAD_COUNT(pEnv);
  3064. return 0;
  3065. }
  3066. /*
  3067. * create a thread for transaction deadlock testing
  3068. */
  3069. static int
  3070. bdb_start_txn_test_thread(struct ldbminfo *li)
  3071. {
  3072. int return_value = 0;
  3073. if (NULL == PR_CreateThread(PR_USER_THREAD,
  3074. (VFP)(void *)txn_test_threadmain, li,
  3075. PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  3076. PR_UNJOINABLE_THREAD,
  3077. SLAPD_DEFAULT_THREAD_STACKSIZE)) {
  3078. PRErrorCode prerr = PR_GetError();
  3079. slapi_log_err(SLAPI_LOG_ERR, "bdb_start_txn_test_thread",
  3080. "Failed to create txn test thread, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  3081. prerr, slapd_pr_strerror(prerr));
  3082. return_value = -1;
  3083. }
  3084. return return_value;
  3085. }
  3086. /* deadlock thread main function */
  3087. static int
  3088. deadlock_threadmain(void *param)
  3089. {
  3090. int rval = -1;
  3091. struct ldbminfo *li = NULL;
  3092. PRIntervalTime interval; /*NSPR timeout stuffy*/
  3093. u_int32_t flags = 0;
  3094. PR_ASSERT(NULL != param);
  3095. li = (struct ldbminfo *)param;
  3096. dblayer_private *priv = li->li_dblayer_private;
  3097. PR_ASSERT(NULL != priv);
  3098. bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
  3099. INCR_THREAD_COUNT(pEnv);
  3100. interval = PR_MillisecondsToInterval(100);
  3101. while (!BDB_CONFIG(li)->bdb_stop_threads) {
  3102. if (BDB_CONFIG(li)->bdb_enable_transactions) {
  3103. DB_ENV *db_env = ((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV;
  3104. u_int32_t deadlock_policy = BDB_CONFIG(li)->bdb_deadlock_policy;
  3105. if (dblayer_db_uses_locking(db_env) && (deadlock_policy > DB_LOCK_NORUN)) {
  3106. int rejected = 0;
  3107. rval = db_env->lock_detect(db_env, flags, deadlock_policy, &rejected);
  3108. if (rval != 0) {
  3109. slapi_log_err(SLAPI_LOG_CRIT,
  3110. "deadlock_threadmain", "Serious Error---Failed in deadlock detect (aborted at 0x%x), err=%d (%s)\n",
  3111. rejected, rval, dblayer_strerror(rval));
  3112. } else if (rejected) {
  3113. slapi_log_err(SLAPI_LOG_TRACE, "deadlock_threadmain", "Found and rejected %d lock requests\n", rejected);
  3114. }
  3115. }
  3116. }
  3117. DS_Sleep(interval);
  3118. }
  3119. DECR_THREAD_COUNT(pEnv);
  3120. slapi_log_err(SLAPI_LOG_TRACE, "deadlock_threadmain", "Leaving deadlock_threadmain\n");
  3121. return 0;
  3122. }
  3123. #define checkpoint_debug_message(debug, ...) \
  3124. if (debug) { \
  3125. slapi_log_err(SLAPI_LOG_DEBUG, "CHECKPOINT", __VA_ARGS__); \
  3126. }
  3127. /* this thread tries to do two things:
  3128. 1. catch a group of transactions that are pending allowing a worker thread
  3129. to work
  3130. 2. flush any left over transactions ( a single transaction for example)
  3131. */
  3132. static int
  3133. bdb_start_log_flush_thread(struct ldbminfo *li)
  3134. {
  3135. int return_value = 0;
  3136. int max_threads = config_get_threadnumber();
  3137. if ((BDB_CONFIG(li)->bdb_durable_transactions) &&
  3138. (BDB_CONFIG(li)->bdb_enable_transactions) && (trans_batch_limit > 0)) {
  3139. /* initialize the synchronization objects for the log_flush and worker threads */
  3140. sync_txn_log_flush = PR_NewLock();
  3141. sync_txn_log_flush_done = PR_NewCondVar(sync_txn_log_flush);
  3142. sync_txn_log_do_flush = PR_NewCondVar(sync_txn_log_flush);
  3143. txn_log_flush_pending = (int *)slapi_ch_malloc(max_threads * sizeof(int));
  3144. log_flush_thread = PR_TRUE;
  3145. if (NULL == PR_CreateThread(PR_USER_THREAD,
  3146. (VFP)(void *)log_flush_threadmain, li,
  3147. PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  3148. PR_UNJOINABLE_THREAD,
  3149. SLAPD_DEFAULT_THREAD_STACKSIZE)) {
  3150. PRErrorCode prerr = PR_GetError();
  3151. slapi_log_err(SLAPI_LOG_ERR,
  3152. "bdb_start_log_flush_thread", "Failed to create database log flush thread, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  3153. prerr, slapd_pr_strerror(prerr));
  3154. return_value = -1;
  3155. }
  3156. }
  3157. return return_value;
  3158. }
  3159. /* this thread tries to do two things:
  3160. 1. catch a group of transactions that are pending allowing a worker thread
  3161. to work
  3162. 2. flush any left over transactions ( a single transaction for example)
  3163. */
  3164. static int
  3165. log_flush_threadmain(void *param)
  3166. {
  3167. PRIntervalTime interval_wait, interval_flush, interval_def;
  3168. PRIntervalTime last_flush = 0;
  3169. int i;
  3170. int do_flush = 0;
  3171. PR_ASSERT(NULL != param);
  3172. struct ldbminfo *li = (struct ldbminfo *)param;
  3173. dblayer_private *priv = li->li_dblayer_private;
  3174. bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
  3175. INCR_THREAD_COUNT(pEnv);
  3176. interval_flush = PR_MillisecondsToInterval(trans_batch_txn_min_sleep);
  3177. interval_wait = PR_MillisecondsToInterval(trans_batch_txn_max_sleep);
  3178. interval_def = PR_MillisecondsToInterval(300); /*used while no txn or txn batching */
  3179. /* LK this is only needed if online change of
  3180. * of txn config is supported ???
  3181. */
  3182. while ((!BDB_CONFIG(li)->bdb_stop_threads) && (log_flush_thread)) {
  3183. if (BDB_CONFIG(li)->bdb_enable_transactions) {
  3184. if (trans_batch_limit > 0) {
  3185. /* synchronize flushing thread with workers */
  3186. PR_Lock(sync_txn_log_flush);
  3187. if (!log_flush_thread) {
  3188. /* batch transactions was disabled while waiting for the lock */
  3189. PR_Unlock(sync_txn_log_flush);
  3190. break;
  3191. }
  3192. slapi_log_err(SLAPI_LOG_BACKLDBM, "log_flush_threadmain", "(in loop): batchcount: %d, "
  3193. "txn_in_progress: %d\n",
  3194. trans_batch_count, txn_in_progress_count);
  3195. /*
  3196. * if here, do flush the txn logs if any of the following conditions are met
  3197. * - batch limit exceeded
  3198. * - no more active transaction, no need to wait
  3199. * - do_flush indicate that the max waiting interval is exceeded
  3200. */
  3201. if (trans_batch_count >= trans_batch_limit || trans_batch_count >= txn_in_progress_count || do_flush) {
  3202. slapi_log_err(SLAPI_LOG_BACKLDBM, "log_flush_threadmain", "(working): batchcount: %d, "
  3203. "txn_in_progress: %d\n",
  3204. trans_batch_count, txn_in_progress_count);
  3205. LOG_FLUSH(((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV, 0);
  3206. for (i = 0; i < trans_batch_count; i++) {
  3207. txn_log_flush_pending[i] = 0;
  3208. }
  3209. trans_batch_count = 0;
  3210. last_flush = PR_IntervalNow();
  3211. do_flush = 0;
  3212. slapi_log_err(SLAPI_LOG_BACKLDBM, "log_flush_threadmain", "(before notify): batchcount: %d, "
  3213. "txn_in_progress: %d\n",
  3214. trans_batch_count, txn_in_progress_count);
  3215. PR_NotifyAllCondVar(sync_txn_log_flush_done);
  3216. }
  3217. /* wait until flushing conditions are met */
  3218. while ((trans_batch_count == 0) ||
  3219. (trans_batch_count < trans_batch_limit && trans_batch_count < txn_in_progress_count)) {
  3220. if (BDB_CONFIG(li)->bdb_stop_threads)
  3221. break;
  3222. if (PR_IntervalNow() - last_flush > interval_flush) {
  3223. do_flush = 1;
  3224. break;
  3225. }
  3226. PR_WaitCondVar(sync_txn_log_do_flush, interval_wait);
  3227. }
  3228. PR_Unlock(sync_txn_log_flush);
  3229. slapi_log_err(SLAPI_LOG_BACKLDBM, "log_flush_threadmain", "(wakeup): batchcount: %d, "
  3230. "txn_in_progress: %d\n",
  3231. trans_batch_count, txn_in_progress_count);
  3232. } else {
  3233. DS_Sleep(interval_def);
  3234. }
  3235. } else {
  3236. DS_Sleep(interval_def);
  3237. }
  3238. }
  3239. DECR_THREAD_COUNT(pEnv);
  3240. slapi_log_err(SLAPI_LOG_TRACE, "log_flush_threadmain", "Leaving log_flush_threadmain\n");
  3241. return 0;
  3242. }
  3243. /*
  3244. * create a thread for checkpoint_threadmain
  3245. */
  3246. static int
  3247. bdb_start_checkpoint_thread(struct ldbminfo *li)
  3248. {
  3249. int return_value = 0;
  3250. if (NULL == PR_CreateThread(PR_USER_THREAD,
  3251. (VFP)(void *)checkpoint_threadmain, li,
  3252. PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  3253. PR_UNJOINABLE_THREAD,
  3254. SLAPD_DEFAULT_THREAD_STACKSIZE)) {
  3255. PRErrorCode prerr = PR_GetError();
  3256. slapi_log_err(SLAPI_LOG_ERR,
  3257. "bdb_start_checkpoint_thread", "Failed to create database checkpoint thread, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  3258. prerr, slapd_pr_strerror(prerr));
  3259. return_value = -1;
  3260. }
  3261. return return_value;
  3262. }
  3263. /*
  3264. * checkpoint thread -- borrow the timing for compacting id2entry, and eventually changelog, as well.
  3265. */
  3266. static int
  3267. checkpoint_threadmain(void *param)
  3268. {
  3269. PRIntervalTime interval;
  3270. int rval = -1;
  3271. struct ldbminfo *li = NULL;
  3272. int debug_checkpointing = 0;
  3273. char *home_dir = NULL;
  3274. char **list = NULL;
  3275. char **listp = NULL;
  3276. bdb_db_env *penv = NULL;
  3277. struct timespec checkpoint_expire;
  3278. struct timespec compactdb_expire;
  3279. time_t compactdb_interval_update = 0;
  3280. time_t checkpoint_interval_update = 0;
  3281. time_t compactdb_interval = 0;
  3282. time_t checkpoint_interval = 0;
  3283. PR_ASSERT(NULL != param);
  3284. li = (struct ldbminfo *)param;
  3285. dblayer_private *priv = li->li_dblayer_private;
  3286. PR_ASSERT(NULL != priv);
  3287. bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
  3288. INCR_THREAD_COUNT(pEnv);
  3289. interval = PR_MillisecondsToInterval(DBLAYER_SLEEP_INTERVAL * 10);
  3290. home_dir = bdb_get_home_dir(li, NULL);
  3291. if (NULL == home_dir || '\0' == *home_dir) {
  3292. slapi_log_err(SLAPI_LOG_ERR,
  3293. "checkpoint_threadmain", "Failed due to missing db home directory info\n");
  3294. goto error_return;
  3295. }
  3296. /* work around a problem with newly created environments */
  3297. bdb_force_checkpoint(li);
  3298. PR_Lock(li->li_config_mutex);
  3299. checkpoint_interval = (time_t)BDB_CONFIG(li)->bdb_checkpoint_interval;
  3300. compactdb_interval = (time_t)BDB_CONFIG(li)->bdb_compactdb_interval;
  3301. penv = (bdb_db_env *)priv->dblayer_env;
  3302. debug_checkpointing = BDB_CONFIG(li)->bdb_debug_checkpointing;
  3303. PR_Unlock(li->li_config_mutex);
  3304. /* assumes bdb_force_checkpoint worked */
  3305. /*
  3306. * Importantly, the use of this api is not affected by backwards time steps
  3307. * and the like. Because this use relative system time, rather than utc,
  3308. * it makes it much more reliable to run.
  3309. */
  3310. slapi_timespec_expire_at(compactdb_interval, &compactdb_expire);
  3311. slapi_timespec_expire_at(checkpoint_interval, &checkpoint_expire);
  3312. while (!BDB_CONFIG(li)->bdb_stop_threads) {
  3313. /* sleep for a while */
  3314. /* why aren't we sleeping exactly the right amount of time ? */
  3315. /* answer---because the interval might be changed after the server
  3316. * starts up */
  3317. DS_Sleep(interval);
  3318. if (0 == BDB_CONFIG(li)->bdb_enable_transactions) {
  3319. continue;
  3320. }
  3321. PR_Lock(li->li_config_mutex);
  3322. checkpoint_interval_update = (time_t)BDB_CONFIG(li)->bdb_checkpoint_interval;
  3323. compactdb_interval_update = (time_t)BDB_CONFIG(li)->bdb_compactdb_interval;
  3324. PR_Unlock(li->li_config_mutex);
  3325. /* If the checkpoint has been updated OR we have expired */
  3326. if (checkpoint_interval != checkpoint_interval_update ||
  3327. slapi_timespec_expire_check(&checkpoint_expire) == TIMER_EXPIRED) {
  3328. /* If our interval has changed, update it. */
  3329. checkpoint_interval = checkpoint_interval_update;
  3330. if (!dblayer_db_uses_transactions(((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV)) {
  3331. continue;
  3332. }
  3333. /* now checkpoint */
  3334. checkpoint_debug_message(debug_checkpointing,
  3335. "checkpoint_threadmain - Starting checkpoint\n");
  3336. rval = dblayer_txn_checkpoint(li, (bdb_db_env *)priv->dblayer_env,
  3337. PR_TRUE, PR_FALSE);
  3338. checkpoint_debug_message(debug_checkpointing,
  3339. "checkpoint_threadmain - Checkpoint Done\n");
  3340. if (rval != 0) {
  3341. /* bad error */
  3342. slapi_log_err(SLAPI_LOG_CRIT,
  3343. "checkpoint_threadmain", "Serious Error---Failed to checkpoint database, "
  3344. "err=%d (%s)\n",
  3345. rval, dblayer_strerror(rval));
  3346. if (LDBM_OS_ERR_IS_DISKFULL(rval)) {
  3347. operation_out_of_disk_space();
  3348. goto error_return;
  3349. }
  3350. }
  3351. rval = LOG_ARCHIVE(penv->bdb_DB_ENV, &list,
  3352. DB_ARCH_ABS, (void *)slapi_ch_malloc);
  3353. if (rval) {
  3354. slapi_log_err(SLAPI_LOG_ERR, "checkpoint_threadmain",
  3355. "log archive failed - %s (%d)\n",
  3356. dblayer_strerror(rval), rval);
  3357. } else {
  3358. for (listp = list; listp && *listp != NULL; ++listp) {
  3359. if (BDB_CONFIG(li)->bdb_circular_logging) {
  3360. checkpoint_debug_message(debug_checkpointing,
  3361. "Deleting %s\n", *listp);
  3362. unlink(*listp);
  3363. } else {
  3364. char new_filename[MAXPATHLEN];
  3365. PR_snprintf(new_filename, sizeof(new_filename),
  3366. "%s.old", *listp);
  3367. checkpoint_debug_message(debug_checkpointing,
  3368. "Renaming %s -> %s\n", *listp, new_filename);
  3369. if (rename(*listp, new_filename) != 0) {
  3370. slapi_log_err(SLAPI_LOG_ERR, "checkpoint_threadmain", "Failed to rename log (%s) to (%s)\n",
  3371. *listp, new_filename);
  3372. rval = -1;
  3373. goto error_return;
  3374. }
  3375. }
  3376. }
  3377. slapi_ch_free((void **)&list);
  3378. /* Note: references inside the returned memory need not be
  3379. * individually freed. */
  3380. }
  3381. slapi_timespec_expire_at(checkpoint_interval, &checkpoint_expire);
  3382. }
  3383. /* Compacting DB borrowing the timing of the log flush */
  3384. /*
  3385. * Remember that if compactdb_interval is 0, timer_expired can
  3386. * never occur unless the value in compctdb_interval changes.
  3387. *
  3388. * this could have been a bug infact, where compactdb_interval
  3389. * was 0, if you change while running it would never take effect ....
  3390. */
  3391. if (compactdb_interval_update != compactdb_interval ||
  3392. slapi_timespec_expire_check(&compactdb_expire) == TIMER_EXPIRED) {
  3393. int rc = 0;
  3394. Object *inst_obj;
  3395. ldbm_instance *inst;
  3396. DB *db = NULL;
  3397. for (inst_obj = objset_first_obj(li->li_instance_set);
  3398. inst_obj;
  3399. inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
  3400. inst = (ldbm_instance *)object_get_data(inst_obj);
  3401. rc = dblayer_get_id2entry(inst->inst_be, &db);
  3402. if (!db || rc) {
  3403. continue;
  3404. }
  3405. slapi_log_err(SLAPI_LOG_NOTICE, "checkpoint_threadmain", "Compacting DB start: %s\n",
  3406. inst->inst_name);
  3407. rc = bdb_db_compact_one_db(db, inst);
  3408. if (rc) {
  3409. slapi_log_err(SLAPI_LOG_ERR, "checkpoint_threadmain",
  3410. "compactdb: failed to compact id2entry for %s; db error - %d %s\n",
  3411. inst->inst_name, rc, db_strerror(rc));
  3412. break;
  3413. }
  3414. /* compact changelog db */
  3415. /* NOTE (LK) this is now done along regular compaction,
  3416. * if it should be configurable add a switch to changelog config
  3417. */
  3418. dblayer_get_changelog(inst->inst_be, &db, 0);
  3419. rc = bdb_db_compact_one_db(db, inst);
  3420. if (rc) {
  3421. slapi_log_err(SLAPI_LOG_ERR, "checkpoint_threadmain",
  3422. "compactdb: failed to compact changelog for %s; db error - %d %s\n",
  3423. inst->inst_name, rc, db_strerror(rc));
  3424. break;
  3425. }
  3426. }
  3427. compactdb_interval = compactdb_interval_update;
  3428. slapi_timespec_expire_at(compactdb_interval, &compactdb_expire);
  3429. }
  3430. }
  3431. slapi_log_err(SLAPI_LOG_TRACE, "checkpoint_threadmain", "Check point before leaving\n");
  3432. rval = bdb_force_checkpoint(li);
  3433. error_return:
  3434. DECR_THREAD_COUNT(pEnv);
  3435. slapi_log_err(SLAPI_LOG_TRACE, "checkpoint_threadmain", "Leaving checkpoint_threadmain\n");
  3436. return rval;
  3437. }
  3438. /*
  3439. * create a thread for trickle_threadmain
  3440. */
  3441. static int
  3442. bdb_start_trickle_thread(struct ldbminfo *li)
  3443. {
  3444. int return_value = 0;
  3445. bdb_config *priv = (bdb_config *)li->li_dblayer_config;
  3446. if (priv->bdb_trickle_percentage == 0)
  3447. return return_value;
  3448. if (NULL == PR_CreateThread(PR_USER_THREAD,
  3449. (VFP)(void *)trickle_threadmain, li,
  3450. PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  3451. PR_UNJOINABLE_THREAD,
  3452. SLAPD_DEFAULT_THREAD_STACKSIZE)) {
  3453. PRErrorCode prerr = PR_GetError();
  3454. slapi_log_err(SLAPI_LOG_ERR, "bdb_start_trickle_thread",
  3455. "Failed to create database trickle thread, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  3456. prerr, slapd_pr_strerror(prerr));
  3457. return_value = -1;
  3458. }
  3459. return return_value;
  3460. }
  3461. static int
  3462. trickle_threadmain(void *param)
  3463. {
  3464. PRIntervalTime interval; /*NSPR timeout stuffy*/
  3465. int rval = -1;
  3466. dblayer_private *priv = NULL;
  3467. struct ldbminfo *li = NULL;
  3468. int debug_checkpointing = 0;
  3469. PR_ASSERT(NULL != param);
  3470. li = (struct ldbminfo *)param;
  3471. priv = li->li_dblayer_private;
  3472. PR_ASSERT(NULL != priv);
  3473. bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
  3474. INCR_THREAD_COUNT(pEnv);
  3475. interval = PR_MillisecondsToInterval(DBLAYER_SLEEP_INTERVAL);
  3476. debug_checkpointing = BDB_CONFIG(li)->bdb_debug_checkpointing;
  3477. while (!BDB_CONFIG(li)->bdb_stop_threads) {
  3478. DS_Sleep(interval); /* 622855: wait for other threads fully started */
  3479. if (BDB_CONFIG(li)->bdb_enable_transactions) {
  3480. if (dblayer_db_uses_mpool(((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV) &&
  3481. (0 != BDB_CONFIG(li)->bdb_trickle_percentage)) {
  3482. int pages_written = 0;
  3483. if ((rval = MEMP_TRICKLE(((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV,
  3484. BDB_CONFIG(li)->bdb_trickle_percentage,
  3485. &pages_written)) != 0) {
  3486. slapi_log_err(SLAPI_LOG_ERR, "trickle_threadmain", "Serious Error---Failed to trickle, err=%d (%s)\n",
  3487. rval, dblayer_strerror(rval));
  3488. }
  3489. if (pages_written > 0) {
  3490. checkpoint_debug_message(debug_checkpointing, "trickle_threadmain - Trickle thread wrote %d pages\n",
  3491. pages_written);
  3492. }
  3493. }
  3494. }
  3495. }
  3496. DECR_THREAD_COUNT(pEnv);
  3497. slapi_log_err(SLAPI_LOG_TRACE, "trickle_threadmain", "Leaving trickle_threadmain priv\n");
  3498. return 0;
  3499. }
  3500. /* Helper function for monitor stuff */
  3501. int
  3502. bdb_memp_stat(struct ldbminfo *li, DB_MPOOL_STAT **gsp, DB_MPOOL_FSTAT ***fsp)
  3503. {
  3504. DB_ENV *env = NULL;
  3505. PR_ASSERT(NULL != li);
  3506. dblayer_private *priv = li->li_dblayer_private;
  3507. PR_ASSERT(NULL != priv);
  3508. env = ((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV;
  3509. PR_ASSERT(NULL != env);
  3510. return MEMP_STAT(env, gsp, fsp, 0, (void *)slapi_ch_malloc);
  3511. }
  3512. /* import wants this one */
  3513. int
  3514. bdb_memp_stat_instance(ldbm_instance *inst, DB_MPOOL_STAT **gsp, DB_MPOOL_FSTAT ***fsp)
  3515. {
  3516. DB_ENV *env = NULL;
  3517. PR_ASSERT(NULL != inst);
  3518. if (((bdb_db_env *)inst->inst_db)->bdb_DB_ENV) {
  3519. env = ((bdb_db_env *)inst->inst_db)->bdb_DB_ENV;
  3520. } else {
  3521. dblayer_private *priv = inst->inst_li->li_dblayer_private;
  3522. PR_ASSERT(NULL != priv);
  3523. env = ((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV;
  3524. }
  3525. PR_ASSERT(NULL != env);
  3526. return MEMP_STAT(env, gsp, fsp, 0, (void *)slapi_ch_malloc);
  3527. }
  3528. /* Helper functions for recovery */
  3529. #define DB_LINE_LENGTH 80
  3530. static int
  3531. commit_good_database(bdb_config *conf, int mode)
  3532. {
  3533. /* Write out the guard file */
  3534. char filename[MAXPATHLEN];
  3535. char line[DB_LINE_LENGTH * 2];
  3536. PRFileDesc *prfd;
  3537. int return_value = 0;
  3538. int num_bytes;
  3539. PR_snprintf(filename, sizeof(filename), "%s/guardian", conf->bdb_home_directory);
  3540. prfd = PR_Open(filename, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, mode);
  3541. if (NULL == prfd) {
  3542. slapi_log_err(SLAPI_LOG_CRIT, "commit_good_database", "Failed to write guardian file %s, database corruption possible" SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
  3543. filename, PR_GetError(), slapd_pr_strerror(PR_GetError()));
  3544. return -1;
  3545. }
  3546. PR_snprintf(line, sizeof(line), "cachesize:%lu\nncache:%d\nversion:%d\nlocks:%d\n",
  3547. (long unsigned int)conf->bdb_cachesize, conf->bdb_ncache, DB_VERSION_MAJOR, conf->bdb_lock_config);
  3548. num_bytes = strlen(line);
  3549. return_value = slapi_write_buffer(prfd, line, num_bytes);
  3550. if (return_value != num_bytes) {
  3551. goto error;
  3552. }
  3553. return_value = PR_Close(prfd);
  3554. if (PR_SUCCESS == return_value) {
  3555. return 0;
  3556. } else {
  3557. slapi_log_err(SLAPI_LOG_CRIT, "commit_good_database",
  3558. "Failed to write guardian file, database corruption possible\n");
  3559. (void)PR_Delete(filename);
  3560. return -1;
  3561. }
  3562. error:
  3563. (void)PR_Close(prfd);
  3564. (void)PR_Delete(filename);
  3565. return -1;
  3566. }
  3567. /* read the guardian file from db/ and possibly recover the database */
  3568. static int
  3569. read_metadata(struct ldbminfo *li)
  3570. {
  3571. char filename[MAXPATHLEN];
  3572. char *buf;
  3573. char *thisline;
  3574. char *nextline;
  3575. char **dirp;
  3576. PRFileDesc *prfd;
  3577. PRFileInfo64 prfinfo;
  3578. int return_value = 0;
  3579. PRInt32 byte_count = 0;
  3580. char attribute[513];
  3581. char value[129], delimiter;
  3582. int number = 0;
  3583. bdb_config *conf = (bdb_config *)li->li_dblayer_config;
  3584. dblayer_private *priv = li->li_dblayer_private;
  3585. /* bdb_recovery_required is initialized in dblayer_init;
  3586. * and might be set 1 in check_db_version;
  3587. * we don't want to override it
  3588. * priv->bdb_recovery_required = 0; */
  3589. conf->bdb_previous_cachesize = 0;
  3590. conf->bdb_previous_ncache = 0;
  3591. conf->bdb_previous_lock_config = 0;
  3592. /* Open the guard file and read stuff, then delete it */
  3593. PR_snprintf(filename, sizeof(filename), "%s/guardian", conf->bdb_home_directory);
  3594. memset(&prfinfo, '\0', sizeof(PRFileInfo64));
  3595. (void)PR_GetFileInfo64(filename, &prfinfo);
  3596. prfd = PR_Open(filename, PR_RDONLY, priv->dblayer_file_mode);
  3597. if (NULL == prfd || 0 == prfinfo.size) {
  3598. /* file empty or not present--means the database needs recovered */
  3599. /* Note count is correctly zerod! */
  3600. int count = 0;
  3601. for (dirp = conf->bdb_data_directories; dirp && *dirp; dirp++) {
  3602. count_dbfiles_in_dir(*dirp, &count, 1 /* recurse */);
  3603. if (count > 0) {
  3604. conf->bdb_recovery_required = 1;
  3605. return 0;
  3606. }
  3607. }
  3608. return 0; /* no files found; no need to run recover start */
  3609. }
  3610. /* So, we opened the file, now let's read the cache size and version stuff
  3611. */
  3612. buf = slapi_ch_calloc(1, prfinfo.size + 1);
  3613. byte_count = slapi_read_buffer(prfd, buf, prfinfo.size);
  3614. if (byte_count < 0) {
  3615. /* something bad happened while reading */
  3616. conf->bdb_recovery_required = 1;
  3617. } else {
  3618. buf[byte_count] = '\0';
  3619. thisline = buf;
  3620. while (1) {
  3621. /* Find the end of the line */
  3622. nextline = strchr(thisline, '\n');
  3623. if (NULL != nextline) {
  3624. *nextline++ = '\0';
  3625. while ('\n' == *nextline) {
  3626. nextline++;
  3627. }
  3628. }
  3629. sscanf(thisline, "%512[a-z]%c%128s", attribute, &delimiter, value);
  3630. if (0 == strcmp("cachesize", attribute)) {
  3631. conf->bdb_previous_cachesize = strtoul(value, NULL, 10);
  3632. } else if (0 == strcmp("ncache", attribute)) {
  3633. number = atoi(value);
  3634. conf->bdb_previous_ncache = number;
  3635. } else if (0 == strcmp("version", attribute)) {
  3636. } else if (0 == strcmp("locks", attribute)) {
  3637. number = atoi(value);
  3638. conf->bdb_previous_lock_config = number;
  3639. }
  3640. if (NULL == nextline || '\0' == *nextline) {
  3641. /* Nothing more to read */
  3642. break;
  3643. }
  3644. thisline = nextline;
  3645. }
  3646. }
  3647. slapi_ch_free((void **)&buf);
  3648. (void)PR_Close(prfd);
  3649. return_value = PR_Delete(filename); /* very important that this happen ! */
  3650. if (PR_SUCCESS != return_value) {
  3651. slapi_log_err(SLAPI_LOG_CRIT,
  3652. "read_metadata", "Failed to delete guardian file, "
  3653. "database corruption possible\n");
  3654. }
  3655. return return_value;
  3656. }
  3657. /* handy routine for checkpointing the db */
  3658. static int
  3659. bdb_force_checkpoint(struct ldbminfo *li)
  3660. {
  3661. int ret = 0, i;
  3662. dblayer_private *priv = li->li_dblayer_private;
  3663. bdb_db_env *pEnv;
  3664. if (NULL == priv || NULL == priv->dblayer_env) {
  3665. /* already terminated. nothing to do */
  3666. return -1;
  3667. }
  3668. pEnv = (bdb_db_env *)priv->dblayer_env;
  3669. if (BDB_CONFIG(li)->bdb_enable_transactions) {
  3670. slapi_log_err(SLAPI_LOG_TRACE, "bdb_force_checkpoint", "Checkpointing database ...\n");
  3671. /*
  3672. * DB workaround. Newly created environments do not know what the
  3673. * previous checkpoint LSN is. The default LSN of [0][0] would
  3674. * cause us to read all log files from very beginning during a
  3675. * later recovery. Taking two checkpoints solves the problem.
  3676. */
  3677. for (i = 0; i < 2; i++) {
  3678. ret = dblayer_txn_checkpoint(li, pEnv, PR_FALSE, PR_TRUE);
  3679. if (ret != 0) {
  3680. slapi_log_err(SLAPI_LOG_ERR, "bdb_force_checkpoint", "Checkpoint FAILED, error %s (%d)\n",
  3681. dblayer_strerror(ret), ret);
  3682. break;
  3683. }
  3684. }
  3685. }
  3686. return ret;
  3687. }
  3688. /* routine to force all existing transaction logs to be cleared
  3689. * This is necessary if the transaction logs can contain references
  3690. * to no longer existing files, but would be processed in a fatal
  3691. * recovery (like in backup/restore).
  3692. * There is no straight forward way to do this, but the following
  3693. * scenario should work:
  3694. *
  3695. * 1. check for no longer needed transaction logs by
  3696. * calling log_archive()
  3697. * 2. delete these logs (1and2 similar to checkpointing
  3698. * 3. force a checkpoint
  3699. * 4. use log_printf() to write a "comment" to the current txn log
  3700. * force a checkpoint
  3701. * this could be done by writing once about 10MB or
  3702. * by writing smaller chunks in a loop
  3703. * 5. force a checkpoint and check again
  3704. * if a txn log to remove exists remove it and we are done
  3705. * else repeat step 4
  3706. *
  3707. * NOTE: double check if force_checkpoint also does remove txn files
  3708. * then the check would have to be modified
  3709. */
  3710. static int
  3711. bdb_force_logrenewal(struct ldbminfo *li)
  3712. {
  3713. return 0;
  3714. }
  3715. static int
  3716. _dblayer_delete_aux_dir(struct ldbminfo *li, char *path)
  3717. {
  3718. PRDir *dirhandle = NULL;
  3719. PRDirEntry *direntry = NULL;
  3720. char filename[MAXPATHLEN];
  3721. dblayer_private *priv = NULL;
  3722. bdb_db_env *pEnv = NULL;
  3723. int rc = -1;
  3724. if (NULL == li || NULL == path) {
  3725. slapi_log_err(SLAPI_LOG_ERR,
  3726. "_dblayer_delete_aux_dir", "Invalid LDBM info (0x%p) "
  3727. "or path (0x%p)\n",
  3728. li, path);
  3729. return rc;
  3730. }
  3731. priv = li->li_dblayer_private;
  3732. if (priv) {
  3733. pEnv = (bdb_db_env *)priv->dblayer_env;
  3734. }
  3735. dirhandle = PR_OpenDir(path);
  3736. if (!dirhandle) {
  3737. return 0; /* The dir does not exist. */
  3738. }
  3739. while (NULL != (direntry = PR_ReadDir(dirhandle,
  3740. PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
  3741. if (!direntry->name)
  3742. break;
  3743. PR_snprintf(filename, sizeof(filename), "%s/%s", path, direntry->name);
  3744. if (pEnv &&
  3745. /* PL_strcmp takes NULL arg */
  3746. (PL_strcmp(LDBM_FILENAME_SUFFIX, strrchr(direntry->name, '.')) == 0)) {
  3747. rc = bdb_db_remove_ex(pEnv, filename, 0, PR_TRUE);
  3748. } else {
  3749. rc = ldbm_delete_dirs(filename);
  3750. }
  3751. }
  3752. PR_CloseDir(dirhandle);
  3753. PR_RmDir(path);
  3754. return rc;
  3755. }
  3756. /* TEL: Added startdb flag. If set (1), the DB environment will be started so
  3757. * that bdb_db_remove_ex will be used to remove the database files instead
  3758. * of simply deleting them. That is important when doing a selective restoration
  3759. * of a single backend (FRI). If not set (0), the traditional remove is used.
  3760. */
  3761. static int
  3762. _dblayer_delete_instance_dir(ldbm_instance *inst, int startdb)
  3763. {
  3764. PRDir *dirhandle = NULL;
  3765. PRDirEntry *direntry = NULL;
  3766. char filename[MAXPATHLEN];
  3767. struct ldbminfo *li = inst->inst_li;
  3768. dblayer_private *priv = NULL;
  3769. bdb_db_env *pEnv = NULL;
  3770. char inst_dir[MAXPATHLEN];
  3771. char *inst_dirp = NULL;
  3772. int rval = 0;
  3773. if (NULL == li) {
  3774. slapi_log_err(SLAPI_LOG_ERR,
  3775. "_dblayer_delete_instance_dir", "NULL LDBM info\n");
  3776. rval = -1;
  3777. goto done;
  3778. }
  3779. if (startdb) {
  3780. /* close immediately; no need to run db threads */
  3781. rval = bdb_start(li, DBLAYER_NORMAL_MODE | DBLAYER_NO_DBTHREADS_MODE);
  3782. if (rval) {
  3783. slapi_log_err(SLAPI_LOG_ERR, "_dblayer_delete_instance_dir", "bdb_start failed! %s (%d)\n",
  3784. dblayer_strerror(rval), rval);
  3785. goto done;
  3786. }
  3787. }
  3788. priv = li->li_dblayer_private;
  3789. if (NULL != priv) {
  3790. pEnv = (bdb_db_env *)priv->dblayer_env;
  3791. }
  3792. if (inst->inst_dir_name == NULL)
  3793. dblayer_get_instance_data_dir(inst->inst_be);
  3794. inst_dirp = dblayer_get_full_inst_dir(li, inst, inst_dir, MAXPATHLEN);
  3795. if (inst_dirp && *inst_dirp) {
  3796. dirhandle = PR_OpenDir(inst_dirp);
  3797. }
  3798. if (!dirhandle) {
  3799. if (PR_GetError() == PR_FILE_NOT_FOUND_ERROR) {
  3800. /* the directory does not exist... that's not an error */
  3801. rval = 0;
  3802. goto done;
  3803. }
  3804. if (inst_dirp && *inst_dirp) {
  3805. slapi_log_err(SLAPI_LOG_ERR,
  3806. "_dblayer_delete_instance_dir", "inst_dir is NULL\n");
  3807. } else {
  3808. slapi_log_err(SLAPI_LOG_ERR,
  3809. "_dblayer_delete_instance_dir", "PR_OpenDir(%s) failed (%d): %s\n",
  3810. inst_dirp, PR_GetError(), slapd_pr_strerror(PR_GetError()));
  3811. }
  3812. rval = -1;
  3813. goto done;
  3814. }
  3815. /*
  3816. Note the use of PR_Delete here as opposed to using
  3817. sleepycat to "remove" the file. Reason: One should
  3818. not expect logging to be able to recover the wholesale
  3819. removal of a complete directory... a directory that includes
  3820. files outside the scope of sleepycat's logging. rwagner
  3821. ADDITIONAL COMMENT:
  3822. libdb41 is more strict on the transaction log control.
  3823. Even if checkpoint is forced before this delete function,
  3824. no log regarding the file deleted found in the log file,
  3825. following checkpoint repeatedly complains with these error messages:
  3826. libdb: <path>/mail.db4: cannot sync: No such file or directory
  3827. libdb: txn_checkpoint: failed to flush the buffer cache
  3828. No such file or directory
  3829. */
  3830. while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT |
  3831. PR_SKIP_DOT_DOT))) {
  3832. if (!direntry->name)
  3833. break;
  3834. PR_snprintf(filename, MAXPATHLEN, "%s/%s", inst_dirp, direntry->name);
  3835. if (pEnv &&
  3836. /* PL_strcmp takes NULL arg */
  3837. (PL_strcmp(LDBM_FILENAME_SUFFIX, strrchr(direntry->name, '.')) == 0)) {
  3838. if (strcmp(direntry->name, "changelog.db") == 0) {
  3839. /* do not delete the changelog, if it no longer
  3840. * matches the database it will be recreated later
  3841. */
  3842. continue;
  3843. }
  3844. rval = bdb_db_remove_ex(pEnv, filename, 0, PR_TRUE);
  3845. } else {
  3846. rval = ldbm_delete_dirs(filename);
  3847. }
  3848. }
  3849. PR_CloseDir(dirhandle);
  3850. if (pEnv && startdb) {
  3851. rval = dblayer_close(li, DBLAYER_NORMAL_MODE);
  3852. if (rval) {
  3853. slapi_log_err(SLAPI_LOG_ERR, "_dblayer_delete_instance_dir", "dblayer_close failed! %s (%d)\n",
  3854. dblayer_strerror(rval), rval);
  3855. }
  3856. }
  3857. done:
  3858. /* remove the directory itself too */
  3859. /* no
  3860. if (0 == rval)
  3861. PR_RmDir(inst_dirp);
  3862. */
  3863. if (inst_dirp != inst_dir)
  3864. slapi_ch_free_string(&inst_dirp);
  3865. return rval;
  3866. }
  3867. /* delete the db3 files in a specific backend instance --
  3868. * this is probably only used for import.
  3869. * assumption: dblayer is open, but the instance has been closed.
  3870. */
  3871. int
  3872. dblayer_delete_instance_dir(backend *be)
  3873. {
  3874. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  3875. int ret = bdb_force_checkpoint(li);
  3876. if (ret != 0) {
  3877. return ret;
  3878. } else {
  3879. ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
  3880. return _dblayer_delete_instance_dir(inst, 0);
  3881. }
  3882. }
  3883. static int
  3884. bdb_delete_database_ex(struct ldbminfo *li, char *cldir)
  3885. {
  3886. dblayer_private *priv = NULL;
  3887. Object *inst_obj;
  3888. PRDir *dirhandle = NULL;
  3889. PRDirEntry *direntry = NULL;
  3890. PRFileInfo64 fileinfo;
  3891. char filename[MAXPATHLEN];
  3892. char *log_dir;
  3893. int ret;
  3894. PR_ASSERT(NULL != li);
  3895. priv = (dblayer_private *)li->li_dblayer_private;
  3896. PR_ASSERT(NULL != priv);
  3897. /* delete each instance */
  3898. for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
  3899. inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
  3900. ldbm_instance *inst = (ldbm_instance *)object_get_data(inst_obj);
  3901. if (inst->inst_be->be_instance_info != NULL) {
  3902. ret = _dblayer_delete_instance_dir(inst, 0 /* Do not start DB environment: traditional */);
  3903. if (ret != 0) {
  3904. slapi_log_err(SLAPI_LOG_ERR,
  3905. "bdb_delete_database_ex", "Failed (%d)\n", ret);
  3906. return ret;
  3907. }
  3908. }
  3909. }
  3910. /* changelog path is given; delete it, too. */
  3911. if (cldir) {
  3912. ret = _dblayer_delete_aux_dir(li, cldir);
  3913. if (ret) {
  3914. slapi_log_err(SLAPI_LOG_ERR,
  3915. "bdb_delete_database_ex", "Failed to delete \"%s\"\n",
  3916. cldir);
  3917. return ret;
  3918. }
  3919. }
  3920. /* now smash everything else in the db/ dir */
  3921. if (BDB_CONFIG(li)->bdb_home_directory == NULL){
  3922. slapi_log_err(SLAPI_LOG_ERR, "bdb_delete_database_ex",
  3923. "bdb_home_directory is NULL, can not proceed\n");
  3924. return -1;
  3925. }
  3926. dirhandle = PR_OpenDir(BDB_CONFIG(li)->bdb_home_directory);
  3927. if (!dirhandle) {
  3928. slapi_log_err(SLAPI_LOG_ERR, "bdb_delete_database_ex", "PR_OpenDir (%s) failed (%d): %s\n",
  3929. BDB_CONFIG(li)->bdb_home_directory,
  3930. PR_GetError(), slapd_pr_strerror(PR_GetError()));
  3931. return -1;
  3932. }
  3933. while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT |
  3934. PR_SKIP_DOT_DOT))) {
  3935. int rval_tmp = 0;
  3936. if (!direntry->name)
  3937. break;
  3938. PR_snprintf(filename, MAXPATHLEN, "%s/%s", BDB_CONFIG(li)->bdb_home_directory,
  3939. direntry->name);
  3940. /* Do not call PR_Delete on the instance directories if they exist.
  3941. * It would not work, but we still should not do it. */
  3942. rval_tmp = PR_GetFileInfo64(filename, &fileinfo);
  3943. if (rval_tmp == PR_SUCCESS && fileinfo.type != PR_FILE_DIRECTORY) {
  3944. /* Skip deleting log files; that should be handled below.
  3945. * (Note, we don't want to use "filename," because that is qualified and would
  3946. * not be compatibile with what dblayer_is_logfilename expects.) */
  3947. if (!dblayer_is_logfilename(direntry->name)) {
  3948. PR_Delete(filename);
  3949. }
  3950. }
  3951. }
  3952. PR_CloseDir(dirhandle);
  3953. /* remove transaction logs */
  3954. if ((NULL != BDB_CONFIG(li)->bdb_log_directory) &&
  3955. (0 != strlen(BDB_CONFIG(li)->bdb_log_directory))) {
  3956. log_dir = BDB_CONFIG(li)->bdb_log_directory;
  3957. } else {
  3958. log_dir = bdb_get_home_dir(li, NULL);
  3959. }
  3960. if (log_dir && *log_dir) {
  3961. ret = dblayer_delete_transaction_logs(log_dir);
  3962. if (ret) {
  3963. slapi_log_err(SLAPI_LOG_ERR,
  3964. "bdb_delete_database_ex", "dblayer_delete_transaction_logs failed (%d)\n", ret);
  3965. return -1;
  3966. }
  3967. }
  3968. return 0;
  3969. }
  3970. /* delete an entire db/ directory, including all instances under it!
  3971. * this is used mostly for restores.
  3972. * dblayer is assumed to be closed.
  3973. */
  3974. int
  3975. bdb_delete_db(struct ldbminfo *li)
  3976. {
  3977. return bdb_delete_database_ex(li, NULL);
  3978. }
  3979. /*
  3980. * Return the size of the database (in kilobytes). XXXggood returning
  3981. * the size in units of kb is really a hack, and is done because we
  3982. * didn't have NSPR support for 64-bit file offsets originally (now we do)
  3983. * Caveats:
  3984. * - We can still return incorrect results if an individual file is
  3985. * larger than fit in a PRUint32.
  3986. * - PR_GetFileInfo64 doesn't do any special processing for symlinks,
  3987. * nor does it inform us if the file is a symlink. Nice. So if
  3988. * a file in the db directory is a symlink, the size we return
  3989. * will probably be way too small.
  3990. */
  3991. int
  3992. dblayer_database_size(struct ldbminfo *li, unsigned int *size)
  3993. {
  3994. bdb_config *priv = NULL;
  3995. int return_value = 0;
  3996. char filename[MAXPATHLEN];
  3997. PRDir *dirhandle = NULL;
  3998. unsigned int cumulative_size = 0;
  3999. unsigned int remainder = 0;
  4000. PRFileInfo64 info;
  4001. PR_ASSERT(NULL != li);
  4002. priv = (bdb_config *)li->li_dblayer_config;
  4003. PR_ASSERT(NULL != priv);
  4004. dirhandle = PR_OpenDir(priv->bdb_home_directory);
  4005. if (NULL != dirhandle) {
  4006. PRDirEntry *direntry = NULL;
  4007. while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
  4008. if (NULL == direntry->name) {
  4009. break;
  4010. }
  4011. PR_snprintf(filename, MAXPATHLEN, "%s/%s", priv->bdb_home_directory, direntry->name);
  4012. return_value = PR_GetFileInfo64(filename, &info);
  4013. if (PR_SUCCESS == return_value) {
  4014. cumulative_size += (info.size / 1024);
  4015. remainder += (info.size % 1024);
  4016. } else {
  4017. cumulative_size = (PRUint32)0;
  4018. return_value = -1;
  4019. break;
  4020. }
  4021. }
  4022. PR_CloseDir(dirhandle);
  4023. } else {
  4024. return_value = -1;
  4025. }
  4026. *size = cumulative_size + (remainder / 1024);
  4027. return return_value;
  4028. }
  4029. /*
  4030. * Obtain a count of all the BDB files in the indicated directory.
  4031. *
  4032. * directory : The path to examine.
  4033. * count : Output parameter for the final count.
  4034. * recurse : 0/1, recursion is not complete, it only goes down one level.
  4035. *
  4036. * IMPORTANT: 'count' must be set to 0 by the caller before being passed.
  4037. */
  4038. static int
  4039. count_dbfiles_in_dir(char *directory, int *count, int recurse)
  4040. {
  4041. /* The new recurse argument was added to help with multiple backend
  4042. * instances. When recurse is true, this function will also look through
  4043. * the directories in the given directory for .db3 files. */
  4044. int return_value = 0;
  4045. PRDir *dirhandle = NULL;
  4046. dirhandle = PR_OpenDir(directory);
  4047. if (NULL != dirhandle) {
  4048. PRDirEntry *direntry = NULL;
  4049. char *direntry_name;
  4050. PRFileInfo64 info;
  4051. while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
  4052. if (NULL == direntry->name) {
  4053. break;
  4054. }
  4055. direntry_name = PR_smprintf("%s/%s", directory, direntry->name);
  4056. if ((PR_GetFileInfo64(direntry_name, &info) == PR_SUCCESS) &&
  4057. (PR_FILE_DIRECTORY == info.type) && recurse) {
  4058. /* Recurse into this directory but not any further. This is
  4059. * because each instance gets its own directory, but in those
  4060. * directories there should be only .db3 files. There should
  4061. * not be any more directories in an instance directory. */
  4062. count_dbfiles_in_dir(direntry_name, count, 0 /* don't recurse */);
  4063. }
  4064. if (direntry_name) {
  4065. PR_smprintf_free(direntry_name);
  4066. }
  4067. /* PL_strcmp takes NULL arg */
  4068. if (PL_strcmp(LDBM_FILENAME_SUFFIX, strrchr(direntry->name, '.')) == 0) {
  4069. (*count)++;
  4070. }
  4071. }
  4072. PR_CloseDir(dirhandle);
  4073. } else {
  4074. return_value = -1;
  4075. }
  4076. return return_value;
  4077. }
  4078. /* And finally... Tubular Bells.
  4079. * Well, no, actually backup and restore...
  4080. */
  4081. /* Backup works like this:
  4082. * the slapd executable is run like for ldif2ldbm and so on.
  4083. * this means that the front-end gets the back-end loaded, and then calls
  4084. * into the back-end backup entry point. This then gets us down to here.
  4085. *
  4086. * So, we need to copy the data files to the backup point.
  4087. * While we are doing that, we need to make sure that the logfile
  4088. * truncator in slapd doesn't delete our files. To do this we need
  4089. * some way to signal to it that it should cease its work, or we need
  4090. * to do something like start a long-lived transaction so that the
  4091. * log files look like they're needed.
  4092. *
  4093. * When we've copied the data files, we can then copy the log files
  4094. * too.
  4095. *
  4096. * Finally, we tell the log file truncator to go back about its business in peace
  4097. *
  4098. */
  4099. int
  4100. dblayer_copyfile(char *source, char *destination, int overwrite __attribute__((unused)), int mode)
  4101. {
  4102. #ifdef DB_USE_64LFS
  4103. #define OPEN_FUNCTION dblayer_open_large
  4104. #else
  4105. #define OPEN_FUNCTION open
  4106. #endif
  4107. int source_fd = -1;
  4108. int dest_fd = -1;
  4109. char *buffer = NULL;
  4110. int return_value = -1;
  4111. int bytes_to_write = 0;
  4112. /* malloc the buffer */
  4113. buffer = slapi_ch_malloc(64 * 1024);
  4114. if (NULL == buffer) {
  4115. goto error;
  4116. }
  4117. /* Open source file */
  4118. source_fd = OPEN_FUNCTION(source, O_RDONLY, 0);
  4119. if (-1 == source_fd) {
  4120. slapi_log_err(SLAPI_LOG_ERR, "dblayer_copyfile", "Failed to open source file %s by \"%s\"\n",
  4121. source, strerror(errno));
  4122. goto error;
  4123. }
  4124. /* Open destination file */
  4125. dest_fd = OPEN_FUNCTION(destination, O_CREAT | O_WRONLY, mode);
  4126. if (-1 == dest_fd) {
  4127. slapi_log_err(SLAPI_LOG_ERR, "dblayer_copyfile", "Failed to open dest file %s by \"%s\"\n",
  4128. destination, strerror(errno));
  4129. goto error;
  4130. }
  4131. slapi_log_err(SLAPI_LOG_INFO,
  4132. "dblayer_copyfile", "Copying %s to %s\n", source, destination);
  4133. /* Loop round reading data and writing it */
  4134. while (1) {
  4135. int i;
  4136. char *ptr = NULL;
  4137. return_value = read(source_fd, buffer, 64 * 1024);
  4138. if (return_value <= 0) {
  4139. /* means error or EOF */
  4140. if (return_value < 0) {
  4141. slapi_log_err(SLAPI_LOG_ERR, "dblayer_copyfile", "Failed to read by \"%s\": rval = %d\n",
  4142. strerror(errno), return_value);
  4143. }
  4144. break;
  4145. }
  4146. bytes_to_write = return_value;
  4147. ptr = buffer;
  4148. #define CPRETRY 4
  4149. for (i = 0; i < CPRETRY; i++) { /* retry twice */
  4150. return_value = write(dest_fd, ptr, bytes_to_write);
  4151. if (return_value == bytes_to_write) {
  4152. break;
  4153. } else {
  4154. /* means error */
  4155. slapi_log_err(SLAPI_LOG_ERR, "dblayer_copyfile", "Failed to write by \"%s\"; real: %d bytes, exp: %d bytes\n",
  4156. strerror(errno), return_value, bytes_to_write);
  4157. if (return_value > 0) {
  4158. bytes_to_write -= return_value;
  4159. ptr += return_value;
  4160. slapi_log_err(SLAPI_LOG_NOTICE, "dblayer_copyfile", "Retrying to write %d bytes\n", bytes_to_write);
  4161. } else {
  4162. break;
  4163. }
  4164. }
  4165. }
  4166. if ((CPRETRY == i) || (return_value < 0)) {
  4167. return_value = -1;
  4168. break;
  4169. }
  4170. }
  4171. error:
  4172. if (source_fd != -1) {
  4173. close(source_fd);
  4174. }
  4175. if (dest_fd != -1) {
  4176. close(dest_fd);
  4177. }
  4178. slapi_ch_free((void **)&buffer);
  4179. return return_value;
  4180. }
  4181. /*
  4182. * Copies all the .db# files in instance_dir to a directory with the same name
  4183. * in destination_dir. Both instance_dir and destination_dir are absolute
  4184. * paths.
  4185. * (#604921: added indexonly flag for the use in convindices
  4186. * -- backup/restore indices)
  4187. *
  4188. * If the argument restore is true,
  4189. * logging messages will be about "Restoring" files.
  4190. * If the argument restore is false,
  4191. * logging messages will be about "Backing up" files.
  4192. * The argument cnt is used to count the number of files that were copied.
  4193. *
  4194. * This function is used during db2bak and bak2db.
  4195. */
  4196. int
  4197. bdb_copy_directory(struct ldbminfo *li,
  4198. Slapi_Task *task,
  4199. char *src_dir,
  4200. char *dest_dir,
  4201. int restore,
  4202. int *cnt,
  4203. int indexonly,
  4204. int is_changelog)
  4205. {
  4206. dblayer_private *priv = NULL;
  4207. char *new_src_dir = NULL;
  4208. char *new_dest_dir = NULL;
  4209. PRDir *dirhandle = NULL;
  4210. PRDirEntry *direntry = NULL;
  4211. char *compare_piece = NULL;
  4212. char *filename1;
  4213. char *filename2;
  4214. int return_value = -1;
  4215. char *relative_instance_name = NULL;
  4216. char *inst_dirp = NULL;
  4217. char inst_dir[MAXPATHLEN];
  4218. char sep;
  4219. int src_is_fullpath = 0;
  4220. ldbm_instance *inst = NULL;
  4221. if (!src_dir || '\0' == *src_dir) {
  4222. slapi_log_err(SLAPI_LOG_ERR,
  4223. "bdb_copy_directory", "src_dir is empty\n");
  4224. return return_value;
  4225. }
  4226. if (!dest_dir || '\0' == *dest_dir) {
  4227. slapi_log_err(SLAPI_LOG_ERR,
  4228. "bdb_copy_directory", "dest_dir is empty\n");
  4229. return return_value;
  4230. }
  4231. priv = li->li_dblayer_private;
  4232. /* get the backend instance name */
  4233. sep = get_sep(src_dir);
  4234. if ((relative_instance_name = strrchr(src_dir, sep)) == NULL)
  4235. relative_instance_name = src_dir;
  4236. else
  4237. relative_instance_name++;
  4238. if (is_fullpath(src_dir)) {
  4239. src_is_fullpath = 1;
  4240. }
  4241. if (is_changelog) {
  4242. if (!src_is_fullpath) {
  4243. slapi_log_err(SLAPI_LOG_ERR, "bdb_copy_directory", "Changelogdir \"%s\" is not full path; "
  4244. "Skipping it.\n",
  4245. src_dir);
  4246. return 0;
  4247. }
  4248. } else {
  4249. inst = ldbm_instance_find_by_name(li, relative_instance_name);
  4250. if (NULL == inst) {
  4251. slapi_log_err(SLAPI_LOG_ERR, "bdb_copy_directory", "Backend instance \"%s\" does not exist; "
  4252. "Instance path %s could be invalid.\n",
  4253. relative_instance_name, src_dir);
  4254. return return_value;
  4255. }
  4256. }
  4257. if (src_is_fullpath) {
  4258. new_src_dir = src_dir;
  4259. } else {
  4260. int len;
  4261. inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
  4262. inst_dir, MAXPATHLEN);
  4263. if (!inst_dirp || !*inst_dirp) {
  4264. slapi_log_err(SLAPI_LOG_ERR, "bdb_copy_directory", "Instance dir is NULL.\n");
  4265. if (inst_dirp != inst_dir) {
  4266. slapi_ch_free_string(&inst_dirp);
  4267. }
  4268. return return_value;
  4269. }
  4270. len = strlen(inst_dirp);
  4271. sep = get_sep(inst_dirp);
  4272. if (*(inst_dirp + len - 1) == sep)
  4273. sep = '\0';
  4274. new_src_dir = inst_dirp;
  4275. }
  4276. dirhandle = PR_OpenDir(new_src_dir);
  4277. if (NULL == dirhandle) {
  4278. slapi_log_err(SLAPI_LOG_ERR,
  4279. "bdb_copy_directory", "Failed to open dir %s\n",
  4280. new_src_dir);
  4281. return return_value;
  4282. }
  4283. while (NULL != (direntry =
  4284. PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
  4285. if (NULL == direntry->name) {
  4286. /* NSPR doesn't behave like the docs say it should */
  4287. break;
  4288. }
  4289. if (indexonly &&
  4290. 0 == strcmp(direntry->name, ID2ENTRY LDBM_FILENAME_SUFFIX)) {
  4291. continue;
  4292. }
  4293. compare_piece = PL_strrchr((char *)direntry->name, '.');
  4294. if (NULL == compare_piece) {
  4295. compare_piece = (char *)direntry->name;
  4296. }
  4297. /* rename .db3 -> .db4 or .db4 -> .db */
  4298. if (0 == strcmp(compare_piece, LDBM_FILENAME_SUFFIX) ||
  4299. 0 == strcmp(compare_piece, LDBM_SUFFIX_OLD) ||
  4300. 0 == strcmp(direntry->name, DBVERSION_FILENAME)) {
  4301. /* Found a database file. Copy it. */
  4302. if (NULL == new_dest_dir) {
  4303. /* Need to create the new directory where the files will be
  4304. * copied to. */
  4305. PRFileInfo64 info;
  4306. char *prefix = "";
  4307. char mysep = 0;
  4308. if (!is_fullpath(dest_dir)) {
  4309. prefix = bdb_get_home_dir(li, NULL);
  4310. if (!prefix || !*prefix) {
  4311. continue;
  4312. }
  4313. mysep = get_sep(prefix);
  4314. }
  4315. if (mysep)
  4316. new_dest_dir = slapi_ch_smprintf("%s%c%s%c%s",
  4317. prefix, mysep, dest_dir, mysep, relative_instance_name);
  4318. else
  4319. new_dest_dir = slapi_ch_smprintf("%s/%s",
  4320. dest_dir, relative_instance_name);
  4321. /* } */
  4322. if (PR_SUCCESS == PR_GetFileInfo64(new_dest_dir, &info)) {
  4323. ldbm_delete_dirs(new_dest_dir);
  4324. }
  4325. if (mkdir_p(new_dest_dir, 0700) != PR_SUCCESS) {
  4326. slapi_log_err(SLAPI_LOG_ERR, "bdb_copy_directory", "Can't create new directory %s, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  4327. new_dest_dir, PR_GetError(),
  4328. slapd_pr_strerror(PR_GetError()));
  4329. goto out;
  4330. }
  4331. }
  4332. filename1 = slapi_ch_smprintf("%s/%s", new_src_dir, direntry->name);
  4333. filename2 = slapi_ch_smprintf("%s/%s", new_dest_dir, direntry->name);
  4334. if (restore) {
  4335. slapi_log_err(SLAPI_LOG_INFO, "bdb_copy_directory", "Restoring file %d (%s)\n",
  4336. *cnt, filename2);
  4337. if (task) {
  4338. slapi_task_log_notice(task,
  4339. "Restoring file %d (%s)", *cnt, filename2);
  4340. slapi_task_log_status(task,
  4341. "Restoring file %d (%s)", *cnt, filename2);
  4342. }
  4343. } else {
  4344. slapi_log_err(SLAPI_LOG_INFO, "bdb_copy_directory", "Backing up file %d (%s)\n",
  4345. *cnt, filename2);
  4346. if (task) {
  4347. slapi_task_log_notice(task,
  4348. "Backing up file %d (%s)", *cnt, filename2);
  4349. slapi_task_log_status(task,
  4350. "Backing up file %d (%s)", *cnt, filename2);
  4351. }
  4352. }
  4353. /* copy filename1 to filename2 */
  4354. /* PL_strcmp takes NULL arg */
  4355. return_value = dblayer_copyfile(filename1, filename2,
  4356. 0, priv->dblayer_file_mode);
  4357. if (return_value < 0) {
  4358. slapi_log_err(SLAPI_LOG_ERR, "bdb_copy_directory", "Failed to copy file %s to %s\n",
  4359. filename1, filename2);
  4360. slapi_ch_free((void **)&filename1);
  4361. slapi_ch_free((void **)&filename2);
  4362. break;
  4363. }
  4364. slapi_ch_free((void **)&filename1);
  4365. slapi_ch_free((void **)&filename2);
  4366. (*cnt)++;
  4367. }
  4368. }
  4369. out:
  4370. PR_CloseDir(dirhandle);
  4371. slapi_ch_free_string(&new_dest_dir);
  4372. if ((new_src_dir != src_dir) && (new_src_dir != inst_dir)) {
  4373. slapi_ch_free_string(&new_src_dir);
  4374. }
  4375. return return_value;
  4376. }
  4377. /* Destination Directory is an absolute pathname */
  4378. int
  4379. bdb_backup(struct ldbminfo *li, char *dest_dir, Slapi_Task *task)
  4380. {
  4381. dblayer_private *priv = NULL;
  4382. bdb_config *conf = NULL;
  4383. char **listA = NULL, **listB = NULL, **listi, **listj, *prefix;
  4384. char *home_dir = NULL;
  4385. char *db_dir = NULL;
  4386. int return_value = -1;
  4387. char *pathname1;
  4388. char *pathname2;
  4389. back_txn txn;
  4390. int cnt = 1, ok = 0;
  4391. Object *inst_obj;
  4392. char inst_dir[MAXPATHLEN];
  4393. char *inst_dirp = NULL;
  4394. char *changelogdir = NULL;
  4395. PR_ASSERT(NULL != li);
  4396. conf = (bdb_config *)li->li_dblayer_config;
  4397. priv = li->li_dblayer_private;
  4398. PR_ASSERT(NULL != priv);
  4399. db_dir = bdb_get_db_dir(li);
  4400. home_dir = bdb_get_home_dir(li, NULL);
  4401. if (NULL == home_dir || '\0' == *home_dir) {
  4402. slapi_log_err(SLAPI_LOG_ERR,
  4403. "dblayer_backup", "Missing db home directory info\n");
  4404. return return_value;
  4405. }
  4406. /*
  4407. * What are we doing here ?
  4408. * We want to copy into the backup directory:
  4409. * All the backend instance dir / database files;
  4410. * All the logfiles
  4411. * The version file
  4412. */
  4413. /* changed in may 1999 for political correctness.
  4414. * 1. take checkpoint
  4415. * 2. open transaction
  4416. * 3. get list of logfiles (A)
  4417. * 4. copy the db# files
  4418. * 5. get list of logfiles (B)
  4419. * 6. if !(A in B), goto 3
  4420. * (logfiles were flushed during our backup)
  4421. * 7. copy logfiles from list B
  4422. * 8. abort transaction
  4423. * 9. backup index config info
  4424. */
  4425. /* Order of checkpointing and txn creation reversed to work
  4426. * around DB problem. If we don't do it this way around DB
  4427. * thinks all old transaction logs are required for recovery
  4428. * when the DB environment has been newly created (such as
  4429. * after an import).
  4430. */
  4431. /* do a quick checkpoint */
  4432. bdb_force_checkpoint(li);
  4433. dblayer_txn_init(li, &txn);
  4434. return_value = dblayer_txn_begin_all(li, NULL, &txn);
  4435. if (return_value) {
  4436. slapi_log_err(SLAPI_LOG_ERR,
  4437. "dblayer_backup", "Transaction error\n");
  4438. return return_value;
  4439. }
  4440. if (g_get_shutdown() || c_get_shutdown()) {
  4441. slapi_log_err(SLAPI_LOG_WARNING, "dblayer_backup", "Server shutting down, backup aborted\n");
  4442. return_value = -1;
  4443. goto bail;
  4444. }
  4445. /* repeat this until the logfile sets match... */
  4446. do {
  4447. /* get the list of logfiles currently existing */
  4448. if (conf->bdb_enable_transactions) {
  4449. return_value = LOG_ARCHIVE(((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV,
  4450. &listA, DB_ARCH_LOG, (void *)slapi_ch_malloc);
  4451. if (return_value || (listA == NULL)) {
  4452. slapi_log_err(SLAPI_LOG_ERR,
  4453. "dblayer_backup", "Log archive error\n");
  4454. if (task) {
  4455. slapi_task_log_notice(task, "Backup: log archive error\n");
  4456. }
  4457. return_value = -1;
  4458. goto bail;
  4459. }
  4460. } else {
  4461. ok = 1;
  4462. }
  4463. if (g_get_shutdown() || c_get_shutdown()) {
  4464. slapi_log_err(SLAPI_LOG_ERR, "dblayer_backup", "Server shutting down, backup aborted\n");
  4465. return_value = -1;
  4466. goto bail;
  4467. }
  4468. for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
  4469. inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
  4470. ldbm_instance *inst = (ldbm_instance *)object_get_data(inst_obj);
  4471. inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
  4472. inst_dir, MAXPATHLEN);
  4473. if ((NULL == inst_dirp) || ('\0' == *inst_dirp)) {
  4474. slapi_log_err(SLAPI_LOG_ERR,
  4475. "dblayer_backup", "Instance dir is empty\n");
  4476. if (task) {
  4477. slapi_task_log_notice(task,
  4478. "Backup: Instance dir is empty\n");
  4479. }
  4480. if (inst_dirp != inst_dir) {
  4481. slapi_ch_free_string(&inst_dirp);
  4482. }
  4483. return_value = -1;
  4484. goto bail;
  4485. }
  4486. return_value = bdb_copy_directory(li, task, inst_dirp,
  4487. dest_dir, 0 /* backup */,
  4488. &cnt, 0, 0);
  4489. if (return_value) {
  4490. slapi_log_err(SLAPI_LOG_ERR,
  4491. "dblayer_backup", "Error in copying directory "
  4492. "(%s -> %s): err=%d\n",
  4493. inst_dirp, dest_dir, return_value);
  4494. if (task) {
  4495. slapi_task_log_notice(task,
  4496. "Backup: error in copying directory "
  4497. "(%s -> %s): err=%d\n",
  4498. inst_dirp, dest_dir, return_value);
  4499. }
  4500. if (inst_dirp != inst_dir) {
  4501. slapi_ch_free_string(&inst_dirp);
  4502. }
  4503. goto bail;
  4504. }
  4505. if (inst_dirp != inst_dir)
  4506. slapi_ch_free_string(&inst_dirp);
  4507. }
  4508. if (conf->bdb_enable_transactions) {
  4509. /* now, get the list of logfiles that still exist */
  4510. return_value = LOG_ARCHIVE(((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV,
  4511. &listB, DB_ARCH_LOG, (void *)slapi_ch_malloc);
  4512. if (return_value || (listB == NULL)) {
  4513. slapi_log_err(SLAPI_LOG_ERR,
  4514. "dblayer_backup", "Can't get list of logs\n");
  4515. goto bail;
  4516. }
  4517. /* compare: make sure everything in list A is still in list B */
  4518. ok = 1;
  4519. for (listi = listA; listi && *listi && ok; listi++) {
  4520. int found = 0;
  4521. for (listj = listB; listj && *listj && !found; listj++) {
  4522. if (strcmp(*listi, *listj) == 0) {
  4523. found = 1;
  4524. break;
  4525. }
  4526. }
  4527. if (!found) {
  4528. ok = 0; /* missing log: start over */
  4529. slapi_log_err(SLAPI_LOG_WARNING,
  4530. "dblayer_backup", "Log %s has been swiped "
  4531. "out from under me! (retrying)\n",
  4532. *listi);
  4533. if (task) {
  4534. slapi_task_log_notice(task,
  4535. "WARNING: Log %s has been swiped out from under me! "
  4536. "(retrying)",
  4537. *listi);
  4538. }
  4539. }
  4540. }
  4541. if (g_get_shutdown() || c_get_shutdown()) {
  4542. slapi_log_err(SLAPI_LOG_ERR, "dblayer_backup", "Server shutting down, backup aborted\n");
  4543. return_value = -1;
  4544. goto bail;
  4545. }
  4546. if (ok) {
  4547. size_t p1len, p2len;
  4548. char **listptr;
  4549. prefix = NULL;
  4550. if ((NULL != conf->bdb_log_directory) &&
  4551. (0 != strlen(conf->bdb_log_directory))) {
  4552. prefix = conf->bdb_log_directory;
  4553. } else {
  4554. prefix = db_dir;
  4555. }
  4556. /* log files have the same filename len(100 is a safety net:) */
  4557. p1len = strlen(prefix) + strlen(*listB) + 100;
  4558. pathname1 = (char *)slapi_ch_malloc(p1len);
  4559. p2len = strlen(dest_dir) + strlen(*listB) + 100;
  4560. pathname2 = (char *)slapi_ch_malloc(p2len);
  4561. /* We copy those over */
  4562. for (listptr = listB; listptr && *listptr && ok; ++listptr) {
  4563. PR_snprintf(pathname1, p1len, "%s/%s", prefix, *listptr);
  4564. PR_snprintf(pathname2, p2len, "%s/%s", dest_dir, *listptr);
  4565. slapi_log_err(SLAPI_LOG_INFO, "dblayer_backup", "Backing up file %d (%s)\n",
  4566. cnt, pathname2);
  4567. if (task) {
  4568. slapi_task_log_notice(task,
  4569. "Backing up file %d (%s)", cnt, pathname2);
  4570. slapi_task_log_status(task,
  4571. "Backing up file %d (%s)", cnt, pathname2);
  4572. }
  4573. return_value = dblayer_copyfile(pathname1, pathname2,
  4574. 0, priv->dblayer_file_mode);
  4575. if (0 > return_value) {
  4576. slapi_log_err(SLAPI_LOG_ERR, "dblayer_backup", "Error in copying file '%s' (err=%d)\n",
  4577. pathname1, return_value);
  4578. if (task) {
  4579. slapi_task_log_notice(task, "Error copying file '%s' (err=%d)",
  4580. pathname1, return_value);
  4581. }
  4582. slapi_ch_free((void **)&pathname1);
  4583. slapi_ch_free((void **)&pathname2);
  4584. goto bail;
  4585. }
  4586. if (g_get_shutdown() || c_get_shutdown()) {
  4587. slapi_log_err(SLAPI_LOG_ERR, "dblayer_backup", "Server shutting down, backup aborted\n");
  4588. return_value = -1;
  4589. slapi_ch_free((void **)&pathname1);
  4590. slapi_ch_free((void **)&pathname2);
  4591. goto bail;
  4592. }
  4593. cnt++;
  4594. }
  4595. slapi_ch_free((void **)&pathname1);
  4596. slapi_ch_free((void **)&pathname2);
  4597. }
  4598. slapi_ch_free((void **)&listA);
  4599. slapi_ch_free((void **)&listB);
  4600. }
  4601. } while (!ok);
  4602. /* now copy the version file */
  4603. pathname1 = slapi_ch_smprintf("%s/%s", home_dir, DBVERSION_FILENAME);
  4604. pathname2 = slapi_ch_smprintf("%s/%s", dest_dir, DBVERSION_FILENAME);
  4605. slapi_log_err(SLAPI_LOG_INFO, "dblayer_backup", "Backing up file %d (%s)\n", cnt, pathname2);
  4606. if (task) {
  4607. slapi_task_log_notice(task, "Backing up file %d (%s)", cnt, pathname2);
  4608. slapi_task_log_status(task, "Backing up file %d (%s)", cnt, pathname2);
  4609. }
  4610. return_value = dblayer_copyfile(pathname1, pathname2, 0, priv->dblayer_file_mode);
  4611. if (0 > return_value) {
  4612. slapi_log_err(SLAPI_LOG_ERR,
  4613. "dblayer_backup", "Error in copying version file "
  4614. "(%s -> %s): err=%d\n",
  4615. pathname1, pathname2, return_value);
  4616. if (task) {
  4617. slapi_task_log_notice(task,
  4618. "Backup: error in copying version file "
  4619. "(%s -> %s): err=%d\n",
  4620. pathname1, pathname2, return_value);
  4621. }
  4622. }
  4623. slapi_ch_free((void **)&pathname1);
  4624. slapi_ch_free((void **)&pathname2);
  4625. /* Lastly we tell log file truncation to start again */
  4626. if (0 == return_value) /* if everything went well, backup the index conf */
  4627. return_value = dse_conf_backup(li, dest_dir);
  4628. bail:
  4629. slapi_ch_free((void **)&listA);
  4630. slapi_ch_free((void **)&listB);
  4631. dblayer_txn_abort_all(li, &txn);
  4632. slapi_ch_free_string(&changelogdir);
  4633. return return_value;
  4634. }
  4635. /*
  4636. * Restore is pretty easy.
  4637. * We delete the current database.
  4638. * We then copy all the files over from the backup point.
  4639. * We then leave them there for the slapd process to pick up and do the recovery
  4640. * (which it will do as it sees no guard file).
  4641. */
  4642. /* Helper function first */
  4643. static int
  4644. dblayer_is_logfilename(const char *path)
  4645. {
  4646. int ret = 0;
  4647. /* Is the filename at least 4 characters long ? */
  4648. if (strlen(path) < 4) {
  4649. return 0; /* Not a log file then */
  4650. }
  4651. /* Are the first 4 characters "log." ? */
  4652. ret = strncmp(path, "log.", 4);
  4653. if (0 == ret) {
  4654. /* Now, are the last 4 characters _not_ .db# ? */
  4655. const char *piece = path + (strlen(path) - 4);
  4656. ret = strcmp(piece, LDBM_FILENAME_SUFFIX);
  4657. if (0 != ret) {
  4658. /* Is */
  4659. return 1;
  4660. }
  4661. }
  4662. return 0; /* Is not */
  4663. }
  4664. /* remove log.xxx from log directory*/
  4665. static int
  4666. dblayer_delete_transaction_logs(const char *log_dir)
  4667. {
  4668. int rc = 0;
  4669. char filename1[MAXPATHLEN];
  4670. PRDir *dirhandle = NULL;
  4671. dirhandle = PR_OpenDir(log_dir);
  4672. if (NULL != dirhandle) {
  4673. PRDirEntry *direntry = NULL;
  4674. int is_a_logfile = 0;
  4675. int pre = 0;
  4676. PRFileInfo64 info;
  4677. while (NULL != (direntry =
  4678. PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
  4679. if (NULL == direntry->name) {
  4680. /* NSPR doesn't behave like the docs say it should */
  4681. slapi_log_err(SLAPI_LOG_ERR, "dblayer_delete_transaction_logs", "PR_ReadDir failed (%d): %s\n",
  4682. PR_GetError(), slapd_pr_strerror(PR_GetError()));
  4683. break;
  4684. }
  4685. PR_snprintf(filename1, MAXPATHLEN, "%s/%s", log_dir, direntry->name);
  4686. pre = PR_GetFileInfo64(filename1, &info);
  4687. if (pre == PR_SUCCESS && PR_FILE_DIRECTORY == info.type) {
  4688. continue;
  4689. }
  4690. is_a_logfile = dblayer_is_logfilename(direntry->name);
  4691. if (is_a_logfile && (NULL != log_dir) && (0 != strlen(log_dir))) {
  4692. slapi_log_err(SLAPI_LOG_INFO, "dblayer_delete_transaction_logs", "Deleting log file: (%s)\n",
  4693. filename1);
  4694. unlink(filename1);
  4695. }
  4696. }
  4697. PR_CloseDir(dirhandle);
  4698. } else if (PR_FILE_NOT_FOUND_ERROR != PR_GetError()) {
  4699. slapi_log_err(SLAPI_LOG_ERR,
  4700. "dblayer_delete_transaction_logs", "PR_OpenDir(%s) failed (%d): %s\n",
  4701. log_dir, PR_GetError(), slapd_pr_strerror(PR_GetError()));
  4702. rc = 1;
  4703. }
  4704. return rc;
  4705. }
  4706. const char *skip_list[] =
  4707. {
  4708. ".ldif",
  4709. NULL};
  4710. static int
  4711. doskip(const char *filename)
  4712. {
  4713. const char **p;
  4714. int len = strlen(filename);
  4715. for (p = skip_list; p && *p; p++) {
  4716. int n = strlen(*p);
  4717. if (0 == strncmp(filename + len - n, *p, n))
  4718. return 1;
  4719. }
  4720. return 0;
  4721. }
  4722. int
  4723. bdb_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
  4724. {
  4725. bdb_config *conf = NULL;
  4726. dblayer_private *priv = NULL;
  4727. int return_value = 0;
  4728. int tmp_rval;
  4729. char filename1[MAXPATHLEN];
  4730. char filename2[MAXPATHLEN];
  4731. PRDir *dirhandle = NULL;
  4732. PRDirEntry *direntry = NULL;
  4733. PRFileInfo64 info;
  4734. ldbm_instance *inst = NULL;
  4735. int seen_logfiles = 0; /* Tells us if we restored any logfiles */
  4736. int is_a_logfile = 0;
  4737. int dbmode;
  4738. int action = 0;
  4739. char *home_dir = NULL;
  4740. char *real_src_dir = NULL;
  4741. struct stat sbuf;
  4742. char *changelogdir = NULL;
  4743. char *restore_dir = NULL;
  4744. char *prefix = NULL;
  4745. int cnt = 1;
  4746. PR_ASSERT(NULL != li);
  4747. conf = (bdb_config *)li->li_dblayer_config;
  4748. priv = li->li_dblayer_private;
  4749. PR_ASSERT(NULL != priv);
  4750. /* DBDB this is a hack, take out later */
  4751. PR_Lock(li->li_config_mutex);
  4752. /* bdb_home_directory is freed in bdb_post_close.
  4753. * li_directory needs to live beyond dblayer. */
  4754. slapi_ch_free_string(&conf->bdb_home_directory);
  4755. conf->bdb_home_directory = slapi_ch_strdup(li->li_directory);
  4756. conf->bdb_cachesize = li->li_dbcachesize;
  4757. conf->bdb_lock_config = li->li_dblock;
  4758. conf->bdb_ncache = li->li_dbncache;
  4759. priv->dblayer_file_mode = li->li_mode;
  4760. PR_Unlock(li->li_config_mutex);
  4761. home_dir = bdb_get_home_dir(li, NULL);
  4762. if (NULL == home_dir || '\0' == *home_dir) {
  4763. slapi_log_err(SLAPI_LOG_ERR, "bdb_restore",
  4764. "Missing db home directory info\n");
  4765. return -1;
  4766. }
  4767. /* We find out if slapd is running */
  4768. /* If it is, we fail */
  4769. /* We check on the source staging area, no point in going further if it
  4770. * isn't there */
  4771. if (stat(src_dir, &sbuf) < 0) {
  4772. slapi_log_err(SLAPI_LOG_ERR, "bdb_restore", "Backup directory %s does not "
  4773. "exist.\n",
  4774. src_dir);
  4775. if (task) {
  4776. slapi_task_log_notice(task, "Restore: backup directory %s does not exist.",
  4777. src_dir);
  4778. }
  4779. return LDAP_UNWILLING_TO_PERFORM;
  4780. } else if (!S_ISDIR(sbuf.st_mode)) {
  4781. slapi_log_err(SLAPI_LOG_ERR, "bdb_restore", "Backup directory %s is not "
  4782. "a directory.\n",
  4783. src_dir);
  4784. if (task) {
  4785. slapi_task_log_notice(task, "Restore: backup directory %s is not a directory.",
  4786. src_dir);
  4787. }
  4788. return LDAP_UNWILLING_TO_PERFORM;
  4789. }
  4790. if (!bdb_version_exists(li, src_dir)) {
  4791. slapi_log_err(SLAPI_LOG_ERR, "bdb_restore", "Backup directory %s does not "
  4792. "contain a complete backup\n",
  4793. src_dir);
  4794. if (task) {
  4795. slapi_task_log_notice(task, "Restore: backup directory %s does not "
  4796. "contain a complete backup",
  4797. src_dir);
  4798. }
  4799. return LDAP_UNWILLING_TO_PERFORM;
  4800. }
  4801. /*
  4802. * Check if the target is a superset of the backup.
  4803. * If not don't restore any db at all, otherwise
  4804. * the target will be crippled.
  4805. */
  4806. dirhandle = PR_OpenDir(src_dir);
  4807. if (NULL != dirhandle) {
  4808. while ((direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT)) && direntry->name) {
  4809. PR_snprintf(filename1, sizeof(filename1), "%s/%s",
  4810. src_dir, direntry->name);
  4811. {
  4812. tmp_rval = PR_GetFileInfo64(filename1, &info);
  4813. if (tmp_rval == PR_SUCCESS && PR_FILE_DIRECTORY == info.type) {
  4814. inst = ldbm_instance_find_by_name(li, (char *)direntry->name);
  4815. if (inst == NULL) {
  4816. slapi_log_err(SLAPI_LOG_ERR,
  4817. "bdb_restore", "Target server has no backend (%s) configured\n",
  4818. direntry->name);
  4819. if (task) {
  4820. slapi_task_log_notice(task,
  4821. "bdb_restore - Target server has no backend (%s) configured",
  4822. direntry->name);
  4823. slapi_task_cancel(task, LDAP_UNWILLING_TO_PERFORM);
  4824. }
  4825. PR_CloseDir(dirhandle);
  4826. return_value = LDAP_UNWILLING_TO_PERFORM;
  4827. goto error_out;
  4828. }
  4829. if (slapd_comp_path(src_dir, inst->inst_parent_dir_name) == 0) {
  4830. slapi_log_err(SLAPI_LOG_ERR,
  4831. "bdb_restore", "Backup dir %s and target dir %s are identical\n",
  4832. src_dir, inst->inst_parent_dir_name);
  4833. if (task) {
  4834. slapi_task_log_notice(task,
  4835. "Restore: backup dir %s and target dir %s are identical",
  4836. src_dir, inst->inst_parent_dir_name);
  4837. }
  4838. PR_CloseDir(dirhandle);
  4839. return_value = LDAP_UNWILLING_TO_PERFORM;
  4840. goto error_out;
  4841. }
  4842. }
  4843. }
  4844. }
  4845. PR_CloseDir(dirhandle);
  4846. }
  4847. /* We delete the existing database */
  4848. /* changelogdir is taken care only when it's not NULL. */
  4849. return_value = bdb_delete_database_ex(li, changelogdir);
  4850. if (return_value) {
  4851. goto error_out;
  4852. }
  4853. {
  4854. /* Otherwise use the src_dir from the caller */
  4855. real_src_dir = src_dir;
  4856. }
  4857. /* We copy the files over from the staging area */
  4858. /* We want to treat the logfiles specially: if there's
  4859. * a log file directory configured, copy the logfiles there
  4860. * rather than to the db dirctory */
  4861. dirhandle = PR_OpenDir(real_src_dir);
  4862. if (NULL == dirhandle) {
  4863. slapi_log_err(SLAPI_LOG_ERR,
  4864. "bdb_restore", "Failed to open the directory \"%s\"\n", real_src_dir);
  4865. if (task) {
  4866. slapi_task_log_notice(task,
  4867. "Restore: failed to open the directory \"%s\"", real_src_dir);
  4868. }
  4869. return_value = -1;
  4870. goto error_out;
  4871. }
  4872. while (NULL !=
  4873. (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
  4874. if (NULL == direntry->name) {
  4875. /* NSPR doesn't behave like the docs say it should */
  4876. break;
  4877. }
  4878. /* Is this entry a directory? */
  4879. PR_snprintf(filename1, sizeof(filename1), "%s/%s",
  4880. real_src_dir, direntry->name);
  4881. tmp_rval = PR_GetFileInfo64(filename1, &info);
  4882. if (tmp_rval == PR_SUCCESS && PR_FILE_DIRECTORY == info.type) {
  4883. /* This is an instance directory. It contains the *.db#
  4884. * files for the backend instance.
  4885. * restore directory is supposed to be where the backend
  4886. * directory is located.
  4887. */
  4888. if (0 == strcmp(CHANGELOG_BACKUPDIR, direntry->name)) {
  4889. if (changelogdir) {
  4890. char *cldirname = PL_strrchr(changelogdir, '/');
  4891. char *p = filename1 + strlen(filename1);
  4892. if (NULL == cldirname) {
  4893. slapi_log_err(SLAPI_LOG_ERR,
  4894. "bdb_restore", "Broken changelog dir path %s\n",
  4895. changelogdir);
  4896. if (task) {
  4897. slapi_task_log_notice(task,
  4898. "Restore: broken changelog dir path %s",
  4899. changelogdir);
  4900. }
  4901. goto error_out;
  4902. }
  4903. PR_snprintf(p, sizeof(filename1) - (p - filename1),
  4904. "/%s", cldirname + 1);
  4905. /* Get the parent dir of changelogdir */
  4906. *cldirname = '\0';
  4907. return_value = bdb_copy_directory(li, task, filename1,
  4908. changelogdir, 1 /* restore */,
  4909. &cnt, 0, 1);
  4910. *cldirname = '/';
  4911. if (return_value) {
  4912. slapi_log_err(SLAPI_LOG_ERR,
  4913. "bdb_restore", "Failed to copy directory %s\n",
  4914. filename1);
  4915. if (task) {
  4916. slapi_task_log_notice(task,
  4917. "Restore: failed to copy directory %s",
  4918. filename1);
  4919. }
  4920. goto error_out;
  4921. }
  4922. /* Copy DBVERSION */
  4923. p = filename1 + strlen(filename1);
  4924. PR_snprintf(p, sizeof(filename1) - (p - filename1),
  4925. "/%s", DBVERSION_FILENAME);
  4926. PR_snprintf(filename2, sizeof(filename2), "%s/%s",
  4927. changelogdir, DBVERSION_FILENAME);
  4928. return_value = dblayer_copyfile(filename1, filename2,
  4929. 0, priv->dblayer_file_mode);
  4930. if (0 > return_value) {
  4931. slapi_log_err(SLAPI_LOG_ERR, "bdb_restore", "Failed to copy file %s\n", filename1);
  4932. goto error_out;
  4933. }
  4934. }
  4935. continue;
  4936. }
  4937. inst = ldbm_instance_find_by_name(li, (char *)direntry->name);
  4938. if (inst == NULL)
  4939. continue;
  4940. restore_dir = inst->inst_parent_dir_name;
  4941. /* If we're doing a partial restore, we need to reset the LSNs on the data files */
  4942. if (bdb_copy_directory(li, task, filename1,
  4943. restore_dir, 1 /* restore */, &cnt, 0, 0) == 0)
  4944. continue;
  4945. else {
  4946. slapi_log_err(SLAPI_LOG_ERR,
  4947. "bdb_restore", "Failed to copy directory %s\n",
  4948. filename1);
  4949. if (task) {
  4950. slapi_task_log_notice(task,
  4951. "bdb_restore - Failed to copy directory %s", filename1);
  4952. }
  4953. goto error_out;
  4954. }
  4955. }
  4956. if (doskip(direntry->name))
  4957. continue;
  4958. /* Is this a log file ? */
  4959. /* Log files have names of the form "log.xxxxx" */
  4960. /* We detect these by looking for the prefix "log." and
  4961. * the lack of the ".db#" suffix */
  4962. is_a_logfile = dblayer_is_logfilename(direntry->name);
  4963. if (is_a_logfile) {
  4964. seen_logfiles = 1;
  4965. }
  4966. if (is_a_logfile && (NULL != BDB_CONFIG(li)->bdb_log_directory) &&
  4967. (0 != strlen(BDB_CONFIG(li)->bdb_log_directory))) {
  4968. prefix = BDB_CONFIG(li)->bdb_log_directory;
  4969. } else {
  4970. prefix = home_dir;
  4971. }
  4972. mkdir_p(prefix, 0700);
  4973. PR_snprintf(filename1, sizeof(filename1), "%s/%s",
  4974. real_src_dir, direntry->name);
  4975. PR_snprintf(filename2, sizeof(filename2), "%s/%s",
  4976. prefix, direntry->name);
  4977. slapi_log_err(SLAPI_LOG_INFO, "bdb_restore", "Restoring file %d (%s)\n",
  4978. cnt, filename2);
  4979. if (task) {
  4980. slapi_task_log_notice(task, "Restoring file %d (%s)",
  4981. cnt, filename2);
  4982. slapi_task_log_status(task, "Restoring file %d (%s)",
  4983. cnt, filename2);
  4984. }
  4985. return_value = dblayer_copyfile(filename1, filename2, 0,
  4986. priv->dblayer_file_mode);
  4987. if (0 > return_value) {
  4988. slapi_log_err(SLAPI_LOG_ERR, "bdb_restore", "Failed to copy file %s\n", filename1);
  4989. goto error_out;
  4990. }
  4991. cnt++;
  4992. }
  4993. PR_CloseDir(dirhandle);
  4994. /* We're done ! */
  4995. /* [605024] check the DBVERSION and reset idl-switch if needed */
  4996. if (bdb_version_exists(li, home_dir)) {
  4997. char *ldbmversion = NULL;
  4998. char *dataversion = NULL;
  4999. if (bdb_version_read(li, home_dir, &ldbmversion, &dataversion) != 0) {
  5000. slapi_log_err(SLAPI_LOG_WARNING, "bdb_restore", "Unable to read dbversion file in %s\n",
  5001. home_dir);
  5002. } else {
  5003. adjust_idl_switch(ldbmversion, li);
  5004. slapi_ch_free_string(&ldbmversion);
  5005. slapi_ch_free_string(&dataversion);
  5006. }
  5007. }
  5008. return_value = check_db_version(li, &action);
  5009. if (action &
  5010. (DBVERSION_UPGRADE_3_4 | DBVERSION_UPGRADE_4_4 | DBVERSION_UPGRADE_4_5)) {
  5011. dbmode = DBLAYER_CLEAN_RECOVER_MODE; /* upgrade: remove logs & recover */
  5012. } else if (seen_logfiles) {
  5013. dbmode = DBLAYER_RESTORE_MODE;
  5014. } else if (action & DBVERSION_NEED_DN2RDN) {
  5015. slapi_log_err(SLAPI_LOG_ERR,
  5016. "bdb_restore", "%s is on, while the instance %s is in the DN format. "
  5017. "Please run dn2rdn to convert the database format.\n",
  5018. CONFIG_ENTRYRDN_SWITCH, inst->inst_name);
  5019. return_value = -1;
  5020. goto error_out;
  5021. } else if (action & DBVERSION_NEED_RDN2DN) {
  5022. slapi_log_err(SLAPI_LOG_ERR,
  5023. "bdb_restore", "%s is off, while the instance %s is in the RDN format. "
  5024. "Please change the value to on in dse.ldif.\n",
  5025. CONFIG_ENTRYRDN_SWITCH, inst->inst_name);
  5026. return_value = -1;
  5027. goto error_out;
  5028. } else {
  5029. dbmode = DBLAYER_RESTORE_NO_RECOVERY_MODE;
  5030. }
  5031. /* now start the database code up, to prevent recovery next time the
  5032. * server starts;
  5033. * dse_conf_verify may need to have db started, as well. */
  5034. /* If no logfiles were stored, then fatal recovery isn't required */
  5035. if (li->li_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE) {
  5036. /* command line mode; no need to run db threads */
  5037. dbmode |= DBLAYER_NO_DBTHREADS_MODE;
  5038. } else /* on-line mode */
  5039. {
  5040. allinstance_set_not_busy(li);
  5041. }
  5042. tmp_rval = bdb_start(li, dbmode);
  5043. if (0 != tmp_rval) {
  5044. slapi_log_err(SLAPI_LOG_ERR,
  5045. "bdb_restore", "Failed to init database\n");
  5046. if (task) {
  5047. slapi_task_log_notice(task, "bdb_restore - Failed to init database");
  5048. }
  5049. return_value = tmp_rval;
  5050. goto error_out;
  5051. }
  5052. if (0 == return_value) { /* only when the copyfile succeeded */
  5053. /* check the DSE_* files, if any */
  5054. tmp_rval = dse_conf_verify(li, real_src_dir);
  5055. if (0 != tmp_rval)
  5056. slapi_log_err(SLAPI_LOG_WARNING,
  5057. "bdb_restore", "Unable to verify the index configuration\n");
  5058. }
  5059. if (li->li_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE) {
  5060. /* command line: close the database down again */
  5061. tmp_rval = dblayer_close(li, dbmode);
  5062. if (0 != tmp_rval) {
  5063. slapi_log_err(SLAPI_LOG_ERR,
  5064. "bdb_restore", "Failed to close database\n");
  5065. }
  5066. } else {
  5067. allinstance_set_busy(li); /* on-line mode */
  5068. }
  5069. return_value = tmp_rval ? tmp_rval : return_value;
  5070. error_out:
  5071. /* Free the restore src dir, but only if we allocated it above */
  5072. if (real_src_dir && (real_src_dir != src_dir)) {
  5073. /* If this was an FRI restore and the staging area exists, go ahead and remove it */
  5074. slapi_ch_free_string(&real_src_dir);
  5075. }
  5076. slapi_ch_free_string(&changelogdir);
  5077. return return_value;
  5078. }
  5079. static char *
  5080. bdb__import_file_name(ldbm_instance *inst)
  5081. {
  5082. char *fname = slapi_ch_smprintf("%s/.import_%s",
  5083. inst->inst_parent_dir_name,
  5084. inst->inst_dir_name);
  5085. return fname;
  5086. }
  5087. static char *
  5088. bdb_restore_file_name(struct ldbminfo *li)
  5089. {
  5090. char *fname = slapi_ch_smprintf("%s/../.restore", li->li_directory);
  5091. return fname;
  5092. }
  5093. static int
  5094. bdb_file_open(char *fname, int flags, int mode, PRFileDesc **prfd)
  5095. {
  5096. int rc = 0;
  5097. *prfd = PR_Open(fname, flags, mode);
  5098. if (NULL == *prfd)
  5099. rc = PR_GetError();
  5100. if (rc && rc != PR_FILE_NOT_FOUND_ERROR) {
  5101. slapi_log_err(SLAPI_LOG_ERR,
  5102. "bdb_file_open", "Failed to open file: %s, error: (%d) %s\n",
  5103. fname, rc, slapd_pr_strerror(rc));
  5104. }
  5105. return rc;
  5106. }
  5107. int
  5108. dblayer_import_file_init(ldbm_instance *inst)
  5109. {
  5110. int rc = -1;
  5111. PRFileDesc *prfd = NULL;
  5112. char *fname = bdb__import_file_name(inst);
  5113. rc = bdb_file_open(fname, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, inst->inst_li->li_mode, &prfd);
  5114. if (prfd) {
  5115. PR_Close(prfd);
  5116. rc = 0;
  5117. }
  5118. slapi_ch_free_string(&fname);
  5119. return rc;
  5120. }
  5121. int
  5122. dblayer_restore_file_init(struct ldbminfo *li)
  5123. {
  5124. int rc = -1;
  5125. PRFileDesc *prfd;
  5126. char *fname = bdb_restore_file_name(li);
  5127. rc = bdb_file_open(fname, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, li->li_mode, &prfd);
  5128. if (prfd) {
  5129. PR_Close(prfd);
  5130. rc = 0;
  5131. }
  5132. slapi_ch_free_string(&fname);
  5133. return rc;
  5134. }
  5135. void
  5136. dblayer_import_file_update(ldbm_instance *inst)
  5137. {
  5138. PRFileDesc *prfd;
  5139. char *fname = bdb__import_file_name(inst);
  5140. bdb_file_open(fname, PR_RDWR, inst->inst_li->li_mode, &prfd);
  5141. if (prfd) {
  5142. char *line = slapi_ch_smprintf("import of %s succeeded", inst->inst_dir_name);
  5143. slapi_write_buffer(prfd, line, strlen(line));
  5144. slapi_ch_free_string(&line);
  5145. PR_Close(prfd);
  5146. }
  5147. slapi_ch_free_string(&fname);
  5148. }
  5149. int
  5150. bdb_file_check(char *fname, int mode)
  5151. {
  5152. int rc = 0;
  5153. int err;
  5154. PRFileDesc *prfd;
  5155. err = bdb_file_open(fname, PR_RDWR, mode, &prfd);
  5156. if (prfd) {
  5157. /* file exists, additional check on size */
  5158. PRFileInfo64 prfinfo;
  5159. rc = 1;
  5160. /* read it */
  5161. err = PR_GetOpenFileInfo64(prfd, &prfinfo);
  5162. if (err == PR_SUCCESS && 0 == prfinfo.size) {
  5163. /* it is empty restore or import has failed */
  5164. slapi_log_err(SLAPI_LOG_ERR,
  5165. "bdb_file_check", "Previous import or restore failed, file: %s is empty\n", fname);
  5166. }
  5167. PR_Close(prfd);
  5168. PR_Delete(fname);
  5169. } else {
  5170. if (PR_FILE_NOT_FOUND_ERROR == err) {
  5171. rc = 0;
  5172. } else {
  5173. /* file exists, but we cannot open it */
  5174. rc = 1;
  5175. /* error is already looged try to delete it*/
  5176. PR_Delete(fname);
  5177. }
  5178. }
  5179. return rc;
  5180. }
  5181. int
  5182. dblayer_import_file_check(ldbm_instance *inst)
  5183. {
  5184. int rc;
  5185. char *fname = bdb__import_file_name(inst);
  5186. rc = bdb_file_check(fname, inst->inst_li->li_mode);
  5187. slapi_ch_free_string(&fname);
  5188. return rc;
  5189. }
  5190. static int
  5191. bdb_restore_file_check(struct ldbminfo *li)
  5192. {
  5193. int rc;
  5194. char *fname = bdb_restore_file_name(li);
  5195. rc = bdb_file_check(fname, li->li_mode);
  5196. slapi_ch_free_string(&fname);
  5197. return rc;
  5198. }
  5199. void
  5200. dblayer_restore_file_update(struct ldbminfo *li, char *directory)
  5201. {
  5202. PRFileDesc *prfd;
  5203. char *fname = bdb_restore_file_name(li);
  5204. bdb_file_open(fname, PR_RDWR, li->li_mode, &prfd);
  5205. slapi_ch_free_string(&fname);
  5206. if (prfd) {
  5207. char *line = slapi_ch_smprintf("restore of %s succeeded", directory);
  5208. slapi_write_buffer(prfd, line, strlen(line));
  5209. slapi_ch_free_string(&line);
  5210. PR_Close(prfd);
  5211. }
  5212. }
  5213. /*
  5214. * to change the db extention (e.g., .db3 -> .db4)
  5215. */
  5216. int
  5217. dblayer_update_db_ext(ldbm_instance *inst, char *oldext, char *newext)
  5218. {
  5219. struct attrinfo *a = NULL;
  5220. struct ldbminfo *li = NULL;
  5221. dblayer_private *priv = NULL;
  5222. DB *thisdb = NULL;
  5223. int rval = 0;
  5224. char *ofile = NULL;
  5225. char *nfile = NULL;
  5226. char inst_dir[MAXPATHLEN];
  5227. char *inst_dirp;
  5228. if (NULL == inst) {
  5229. slapi_log_err(SLAPI_LOG_ERR,
  5230. "dblayer_update_db_ext", "Null instance is passed\n");
  5231. return -1; /* non zero */
  5232. }
  5233. li = inst->inst_li;
  5234. priv = li->li_dblayer_private;
  5235. inst_dirp = dblayer_get_full_inst_dir(li, inst, inst_dir, MAXPATHLEN);
  5236. if (NULL == inst_dirp || '\0' == *inst_dirp) {
  5237. slapi_log_err(SLAPI_LOG_ERR,
  5238. "dblayer_update_db_ext", "Instance dir is NULL\n");
  5239. if (inst_dirp != inst_dir) {
  5240. slapi_ch_free_string(&inst_dirp);
  5241. }
  5242. return -1; /* non zero */
  5243. }
  5244. for (a = (struct attrinfo *)avl_getfirst(inst->inst_attrs);
  5245. NULL != a;
  5246. a = (struct attrinfo *)avl_getnext()) {
  5247. PRFileInfo64 info;
  5248. ofile = slapi_ch_smprintf("%s/%s%s", inst_dirp, a->ai_type, oldext);
  5249. if (PR_GetFileInfo64(ofile, &info) != PR_SUCCESS) {
  5250. slapi_ch_free_string(&ofile);
  5251. continue;
  5252. }
  5253. /* db->rename disable DB in it; we need to create for each */
  5254. rval = db_create(&thisdb, ((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV, 0);
  5255. if (0 != rval) {
  5256. slapi_log_err(SLAPI_LOG_ERR, "dblayer_update_db_ext", "db_create returned %d (%s)\n",
  5257. rval, dblayer_strerror(rval));
  5258. goto done;
  5259. }
  5260. nfile = slapi_ch_smprintf("%s/%s%s", inst_dirp, a->ai_type, newext);
  5261. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_update_db_ext", "Rename %s -> %s\n",
  5262. ofile, nfile);
  5263. rval = thisdb->rename(thisdb, (const char *)ofile, NULL /* subdb */,
  5264. (const char *)nfile, 0);
  5265. if (0 != rval) {
  5266. slapi_log_err(SLAPI_LOG_ERR, "dblayer_update_db_ext", "Rename returned %d (%s)\n",
  5267. rval, dblayer_strerror(rval));
  5268. slapi_log_err(SLAPI_LOG_ERR,
  5269. "dblayer_update_db_ext", "Index (%s) Failed to update index %s -> %s\n",
  5270. inst->inst_name, ofile, nfile);
  5271. goto done;
  5272. }
  5273. slapi_ch_free_string(&ofile);
  5274. slapi_ch_free_string(&nfile);
  5275. }
  5276. rval = db_create(&thisdb, ((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV, 0);
  5277. if (0 != rval) {
  5278. slapi_log_err(SLAPI_LOG_ERR, "dblayer_update_db_ext", "db_create returned %d (%s)\n",
  5279. rval, dblayer_strerror(rval));
  5280. goto done;
  5281. }
  5282. ofile = slapi_ch_smprintf("%s/%s%s", inst_dirp, ID2ENTRY, oldext);
  5283. nfile = slapi_ch_smprintf("%s/%s%s", inst_dirp, ID2ENTRY, newext);
  5284. slapi_log_err(SLAPI_LOG_TRACE, "dblayer_update_db_ext", "Rename %s -> %s\n",
  5285. ofile, nfile);
  5286. rval = thisdb->rename(thisdb, (const char *)ofile, NULL /* subdb */,
  5287. (const char *)nfile, 0);
  5288. if (0 != rval) {
  5289. slapi_log_err(SLAPI_LOG_ERR, "dblayer_update_db_ext", "Rename returned %d (%s)\n",
  5290. rval, dblayer_strerror(rval));
  5291. slapi_log_err(SLAPI_LOG_ERR,
  5292. "dblayer_update_db_ext", "Index (%s) Failed to update index %s -> %s\n",
  5293. inst->inst_name, ofile, nfile);
  5294. }
  5295. done:
  5296. slapi_ch_free_string(&ofile);
  5297. slapi_ch_free_string(&nfile);
  5298. if (inst_dirp != inst_dir) {
  5299. slapi_ch_free_string(&inst_dirp);
  5300. }
  5301. return rval;
  5302. }
  5303. /*
  5304. * delete the index files belonging to the instance
  5305. */
  5306. int
  5307. dblayer_delete_indices(ldbm_instance *inst)
  5308. {
  5309. int rval = -1;
  5310. struct attrinfo *a = NULL;
  5311. int i;
  5312. if (NULL == inst) {
  5313. slapi_log_err(SLAPI_LOG_ERR,
  5314. "dblayer_delete_indices", "NULL instance is passed\n");
  5315. return rval;
  5316. }
  5317. rval = 0;
  5318. for (a = (struct attrinfo *)avl_getfirst(inst->inst_attrs), i = 0;
  5319. NULL != a;
  5320. a = (struct attrinfo *)avl_getnext(), i++) {
  5321. rval += bdb_rm_db_file(inst->inst_be, a, PR_TRUE, i /* chkpt; 1st time only */);
  5322. }
  5323. return rval;
  5324. }
  5325. void
  5326. bdb_set_recovery_required(struct ldbminfo *li)
  5327. {
  5328. if (NULL == li || NULL == li->li_dblayer_config) {
  5329. slapi_log_err(SLAPI_LOG_ERR, "bdb_set_recovery_required", "No dblayer info\n");
  5330. return;
  5331. }
  5332. BDB_CONFIG(li)->bdb_recovery_required = 1;
  5333. }
  5334. int
  5335. bdb_get_info(Slapi_Backend *be, int cmd, void **info)
  5336. {
  5337. int rc = -1;
  5338. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  5339. dblayer_private *prv = NULL;
  5340. bdb_db_env *penv = NULL;
  5341. if ( !info) {
  5342. return rc;
  5343. }
  5344. if (li) {
  5345. prv = li->li_dblayer_private;
  5346. if (prv) {
  5347. penv = (bdb_db_env *)prv->dblayer_env;
  5348. }
  5349. }
  5350. switch (cmd) {
  5351. case BACK_INFO_DBENV: {
  5352. if (penv && penv->bdb_DB_ENV) {
  5353. *(DB_ENV **)info = penv->bdb_DB_ENV;
  5354. rc = 0;
  5355. }
  5356. break;
  5357. }
  5358. case BACK_INFO_DBENV_OPENFLAGS: {
  5359. if (penv) {
  5360. *(int *)info = penv->bdb_openflags;
  5361. rc = 0;
  5362. }
  5363. break;
  5364. }
  5365. case BACK_INFO_DB_PAGESIZE: {
  5366. if (li && BDB_CONFIG(li)->bdb_page_size) {
  5367. *(uint32_t *)info = BDB_CONFIG(li)->bdb_page_size;
  5368. } else {
  5369. *(uint32_t *)info = DBLAYER_PAGESIZE;
  5370. }
  5371. rc = 0;
  5372. break;
  5373. }
  5374. case BACK_INFO_INDEXPAGESIZE: {
  5375. if (li && BDB_CONFIG(li)->bdb_index_page_size) {
  5376. *(uint32_t *)info = BDB_CONFIG(li)->bdb_index_page_size;
  5377. } else {
  5378. *(uint32_t *)info = DBLAYER_INDEX_PAGESIZE;
  5379. }
  5380. rc = 0;
  5381. break;
  5382. }
  5383. case BACK_INFO_DIRECTORY: {
  5384. if (li) {
  5385. *(char **)info = li->li_directory;
  5386. rc = 0;
  5387. }
  5388. break;
  5389. }
  5390. case BACK_INFO_DB_DIRECTORY: {
  5391. if (li) {
  5392. *(char **)info = BDB_CONFIG(li)->bdb_home_directory;
  5393. rc = 0;
  5394. }
  5395. break;
  5396. }
  5397. case BACK_INFO_DBHOME_DIRECTORY: {
  5398. if (li) {
  5399. if (BDB_CONFIG(li)->bdb_dbhome_directory &&
  5400. BDB_CONFIG(li)->bdb_dbhome_directory[0] != '\0') {
  5401. *(char **)info = BDB_CONFIG(li)->bdb_dbhome_directory;
  5402. } else {
  5403. *(char **)info = BDB_CONFIG(li)->bdb_home_directory;
  5404. }
  5405. rc = 0;
  5406. }
  5407. break;
  5408. }
  5409. case BACK_INFO_INSTANCE_DIR: {
  5410. if (li) {
  5411. ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
  5412. *(char **)info = dblayer_get_full_inst_dir(li, inst, NULL, 0);
  5413. rc = 0;
  5414. }
  5415. break;
  5416. }
  5417. case BACK_INFO_LOG_DIRECTORY: {
  5418. if (li) {
  5419. *(char **)info = bdb_config_db_logdirectory_get_ext((void *)li);
  5420. rc = 0;
  5421. }
  5422. break;
  5423. }
  5424. case BACK_INFO_IS_ENTRYRDN: {
  5425. *(int *)info = entryrdn_get_switch();
  5426. break;
  5427. }
  5428. case BACK_INFO_INDEX_KEY : {
  5429. rc = get_suffix_key(be, (struct _back_info_index_key *)info);
  5430. break;
  5431. }
  5432. case BACK_INFO_DBENV_CLDB: {
  5433. ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
  5434. if (inst->inst_changelog) {
  5435. rc = 0;
  5436. } else {
  5437. DB *db;
  5438. rc = dblayer_get_changelog(be, &db,DB_CREATE);
  5439. }
  5440. if (rc == 0) {
  5441. *(DB **)info = inst->inst_changelog;
  5442. } else {
  5443. *(DB **)info = NULL;
  5444. }
  5445. break;
  5446. }
  5447. default:
  5448. break;
  5449. }
  5450. return rc;
  5451. }
  5452. int
  5453. bdb_set_info(Slapi_Backend *be, int cmd, void **info)
  5454. {
  5455. int rc = -1;
  5456. switch (cmd) {
  5457. case BACK_INFO_INDEX_KEY : {
  5458. rc = set_suffix_key(be, (struct _back_info_index_key *)info);
  5459. break;
  5460. }
  5461. default:
  5462. break;
  5463. }
  5464. return rc;
  5465. }
  5466. int
  5467. bdb_back_ctrl(Slapi_Backend *be, int cmd, void *info)
  5468. {
  5469. int rc = -1;
  5470. if (!be || !info) {
  5471. return rc;
  5472. }
  5473. switch (cmd) {
  5474. case BACK_INFO_CRYPT_INIT: {
  5475. back_info_crypt_init *crypt_init = (back_info_crypt_init *)info;
  5476. Slapi_DN configdn;
  5477. slapi_sdn_init(&configdn);
  5478. be_getbasedn(be, &configdn);
  5479. char *crypt_dn = slapi_ch_smprintf("%s,%s",
  5480. crypt_init->dn,
  5481. slapi_sdn_get_dn(&configdn));
  5482. rc = back_crypt_init(crypt_init->be, crypt_dn,
  5483. crypt_init->encryptionAlgorithm,
  5484. &(crypt_init->state_priv));
  5485. break;
  5486. }
  5487. case BACK_INFO_CRYPT_DESTROY: {
  5488. back_info_crypt_destroy *crypt_init = (back_info_crypt_destroy *)info;
  5489. rc = back_crypt_destroy(crypt_init->state_priv);
  5490. break;
  5491. }
  5492. case BACK_INFO_CRYPT_ENCRYPT_VALUE: {
  5493. back_info_crypt_value *crypt_value = (back_info_crypt_value *)info;
  5494. rc = back_crypt_encrypt_value(crypt_value->state_priv, crypt_value->in,
  5495. &(crypt_value->out));
  5496. break;
  5497. }
  5498. case BACK_INFO_CRYPT_DECRYPT_VALUE: {
  5499. back_info_crypt_value *crypt_value = (back_info_crypt_value *)info;
  5500. rc = back_crypt_decrypt_value(crypt_value->state_priv, crypt_value->in,
  5501. &(crypt_value->out));
  5502. break;
  5503. }
  5504. case BACK_INFO_DBENV_CLDB_REMOVE: {
  5505. DB *db = (DB *)info;
  5506. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  5507. ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
  5508. if (li) {
  5509. dblayer_private *priv = (dblayer_private *)li->li_dblayer_private;
  5510. if (priv && priv->dblayer_env) {
  5511. char *instancedir;
  5512. slapi_back_get_info(be, BACK_INFO_INSTANCE_DIR, (void **)&instancedir);
  5513. char *path = slapi_ch_smprintf("%s/changelog.db", instancedir);
  5514. db->close(db, 0);
  5515. rc = bdb_db_remove_ex((bdb_db_env *)priv->dblayer_env, path, NULL, PR_TRUE);
  5516. inst->inst_changelog = NULL;
  5517. slapi_ch_free_string(&instancedir);
  5518. }
  5519. }
  5520. break;
  5521. }
  5522. case BACK_INFO_DBENV_CLDB_UPGRADE: {
  5523. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  5524. char *oldFile = (char *)info;
  5525. if (li) {
  5526. dblayer_private *priv = (dblayer_private *)li->li_dblayer_private;
  5527. if (priv && priv->dblayer_env) {
  5528. DB_ENV *pEnv = ((bdb_db_env *)priv->dblayer_env)->bdb_DB_ENV;
  5529. if (pEnv) {
  5530. char *instancedir;
  5531. slapi_back_get_info(be, BACK_INFO_INSTANCE_DIR, (void **)&instancedir);
  5532. char *newFile = slapi_ch_smprintf("%s/changelog.db", instancedir);
  5533. rc = pEnv->dbrename(pEnv, 0, oldFile, 0, newFile, 0);
  5534. slapi_ch_free_string(&instancedir);
  5535. bdb_force_logrenewal(li);
  5536. }
  5537. }
  5538. }
  5539. break;
  5540. }
  5541. case BACK_INFO_CLDB_GET_CONFIG: {
  5542. /* get a config entry relative to the
  5543. * backend config entry
  5544. * Caller must free the returned entry (config->ce)
  5545. * If it fails config->ce is left unchanged
  5546. */
  5547. back_info_config_entry *config = (back_info_config_entry *)info;
  5548. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  5549. Slapi_DN configdn;
  5550. slapi_sdn_init(&configdn);
  5551. be_getbasedn(be, &configdn);
  5552. char *config_dn = slapi_ch_smprintf("%s,%s",
  5553. config->dn,
  5554. slapi_sdn_get_dn(&configdn));
  5555. Slapi_PBlock *search_pb = slapi_pblock_new();
  5556. slapi_search_internal_set_pb(search_pb, config_dn, LDAP_SCOPE_BASE, "objectclass=*",
  5557. NULL, 0, NULL, NULL, li->li_identity, 0);
  5558. slapi_search_internal_pb(search_pb);
  5559. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  5560. if (LDAP_SUCCESS == rc ) {
  5561. Slapi_Entry **entries;
  5562. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  5563. if (entries && entries[0]) {
  5564. config->ce = slapi_entry_dup(entries[0]);
  5565. } else {
  5566. rc = -1;
  5567. }
  5568. }
  5569. slapi_free_search_results_internal(search_pb);
  5570. slapi_pblock_destroy(search_pb);
  5571. slapi_ch_free_string(&config_dn);
  5572. break;
  5573. }
  5574. case BACK_INFO_CLDB_SET_CONFIG: {
  5575. /* This control option allows a plugin to set a backend configuration
  5576. * entry without knowing the location of the backend config.
  5577. * It passes an entry with a relative dn and this dn is expanded by the
  5578. * backend config dn.
  5579. */
  5580. Slapi_DN fulldn;
  5581. Slapi_DN configdn;
  5582. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  5583. Slapi_Entry *config_entry = (Slapi_Entry *)info;
  5584. slapi_sdn_init(&configdn);
  5585. be_getbasedn(be, &configdn);
  5586. char *newdn = slapi_ch_smprintf("%s,%s",
  5587. slapi_entry_get_dn_const(config_entry),
  5588. slapi_sdn_get_dn(&configdn));
  5589. slapi_sdn_init(&fulldn);
  5590. slapi_sdn_init_dn_byref(&fulldn, newdn);
  5591. slapi_entry_set_sdn(config_entry, &fulldn);
  5592. slapi_ch_free_string(&newdn);
  5593. Slapi_PBlock *pb = slapi_pblock_new();
  5594. slapi_pblock_init(pb);
  5595. slapi_add_entry_internal_set_pb(pb, config_entry, NULL,
  5596. li->li_identity, 0);
  5597. slapi_add_internal_pb(pb);
  5598. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  5599. slapi_pblock_destroy(pb);
  5600. break;
  5601. }
  5602. default:
  5603. break;
  5604. }
  5605. return rc;
  5606. }