dasds.cpp 329 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #define da_decl __declspec(dllexport)
  14. #include "platform.h"
  15. #include "jhash.hpp"
  16. #include "jlib.hpp"
  17. #include "jfile.hpp"
  18. #include "jthread.hpp"
  19. #include "javahash.hpp"
  20. #include "javahash.tpp"
  21. #include "jmisc.hpp"
  22. #include "jlog.hpp"
  23. #include "mplog.hpp"
  24. #include "jptree.ipp"
  25. #include "jqueue.tpp"
  26. #include "dautils.hpp"
  27. #include "dadfs.hpp"
  28. #define DEBUG_DIR "debug"
  29. #define DEFAULT_KEEP_LASTN_STORES 1
  30. #define MAXDELAYS 5
  31. static const char *deltaHeader = "<CRC>0000000000</CRC><SIZE>0000000000000000</SIZE>"; // fill in later
  32. static unsigned deltaHeaderCrcOff = 5;
  33. static unsigned deltaHeaderSizeStart = 21;
  34. static unsigned deltaHeaderSizeOff = 27;
  35. static unsigned readWriteSlowTracing = 10000; // 10s default
  36. static bool readWriteStackTracing = false;
  37. static unsigned fakeCritTimeout = 60000;
  38. static unsigned readWriteTimeout = 60000;
  39. // #define NODELETE
  40. // #define DISABLE_COALESCE_QUIETTIME
  41. #define LEGACY_CLIENT_RESPONSE
  42. #define ENABLE_INSPOS
  43. #include "mpbuff.hpp"
  44. #include "mpcomm.hpp"
  45. #include "mputil.hpp"
  46. #include "dacoven.hpp"
  47. #include "daserver.hpp"
  48. #include "daclient.hpp"
  49. #include "dacsds.ipp"
  50. #include "dasds.ipp"
  51. #define ALWAYSLAZY_NOTUSED
  52. #define NoMoreChildrenMarker ((__int64)-1)
  53. #define DEFAULT_MAXCLOSEDOWNRETRIES 20 // really do not want to give up.
  54. #define DEFAULT_MAXRETRIES 3
  55. #define DEFAULT_RETRYDELAY (2) // (seconds)
  56. #define DELTANAME "daliinc"
  57. #define DELTADETACHED "dalidet"
  58. #define DELTAINPROGRESS "delta.progress"
  59. #define DETACHINPROGRESS "detach.progress"
  60. #define TMPSAVENAME "dali_store_tmp.xml"
  61. #define INIT_NODETABLE_SIZE 0x380000
  62. #define DEFAULT_LCIDLE_PERIOD (60*10) // time has to be quiet for before blocking/saving (when using @lightweightCoalesce)
  63. #define DEFAULT_LCMIN_TIME (24*60*60) // don't save more than once a 'DEFAULT_LCMIN_TIME' period.
  64. #define DEFAULT_LCIDLE_RATE 1 // 1 write transactions per idle period. <= this rate is deemed idle (suitable for save)
  65. #define STORENOTSAVE_WARNING_PERIOD 72 // hours
  66. static unsigned msgCount=(unsigned)-1;
  67. // #define TEST_NOTIFY_HANDLER
  68. #define TRACE_QWAITING
  69. #define CRC_VALIDATION
  70. #define SUBNTFY_POOL_SIZE 400
  71. #define SUBSCAN_POOL_SIZE 100
  72. #define RTM_INTERNAL 0x80000000 // marker for internal connection (performed within a transaction)
  73. #define DEFAULT_EXTERNAL_SIZE_THRESHOLD (10*1024)
  74. #define NOTIFY_ATTR "@sds:notify"
  75. #define FETCH_ENTIRE -1
  76. #define FETCH_ENTIRE_COND -2
  77. #define TIMEOUT_ON_CLOSEDOWN 120000 // On closedown, give up on trying to join a thread in CSDSTransactionServer after two minutes
  78. #define _POOLED_SERVER_REMOTE_TREE // use a pool for CServerRemoteTree allocations
  79. #ifdef _POOLED_SERVER_REMOTE_TREE
  80. static CFixedSizeAllocator *CServerRemoteTree_Allocator;
  81. #endif
  82. enum notifications { notify_delete=1 };
  83. static const char *notificationStr(notifications n)
  84. {
  85. switch (n)
  86. {
  87. case notify_delete: return "Notify Delete";
  88. default: return "UNKNOWN NOTIFY TYPE";
  89. }
  90. }
  91. const char *queryNotifyHandlerName(IPropertyTree *tree)
  92. {
  93. return tree->queryProp(NOTIFY_ATTR);
  94. }
  95. bool setNotifyHandlerName(const char *handlerName, IPropertyTree *tree)
  96. {
  97. #ifdef _DEBUG
  98. CClientRemoteTree *_tree = QUERYINTERFACE(tree, CClientRemoteTree);
  99. if (!_tree) return false; // has to a SDS tree!
  100. #endif
  101. tree->setProp(NOTIFY_ATTR, handlerName);
  102. return true;
  103. }
  104. StringBuffer &getSdsCmdText(SdsCommand cmd, StringBuffer &ret)
  105. {
  106. switch (cmd)
  107. {
  108. case DAMP_SDSCMD_CONNECT:
  109. return ret.append("DAMP_SDSCMD_CONNECT");
  110. case DAMP_SDSCMD_GET:
  111. return ret.append("DAMP_SDSCMD_GET");
  112. case DAMP_SDSCMD_GETCHILDREN:
  113. return ret.append("DAMP_SDSCMD_GETCHILDREN");
  114. case DAMP_SDSCMD_REVISIONS:
  115. return ret.append("DAMP_SDSCMD_REVISIONS");
  116. case DAMP_SDSCMD_DATA:
  117. return ret.append("DAMP_SDSCMD_DATA");
  118. case DAMP_SDSCMD_DISCONNECT:
  119. return ret.append("DAMP_SDSCMD_DISCONNECT");
  120. case DAMP_SDSCMD_CONNECTSERVER:
  121. return ret.append("DAMP_SDSCMD_CONNECTSERVER");
  122. case DAMP_SDSCMD_DATASERVER:
  123. return ret.append("DAMP_SDSCMD_DATASERVER");
  124. case DAMP_SDSCMD_DISCONNECTSERVER:
  125. return ret.append("DAMP_SDSCMD_DISCONNECTSERVER");
  126. case DAMP_SDSCMD_CHANGEMODE:
  127. return ret.append("DAMP_SDSCMD_CHANGEMODE");
  128. case DAMP_SDSCMD_CHANGEMODESERVER:
  129. return ret.append("DAMP_SDSCMD_CHANGEMODESERVER");
  130. case DAMP_SDSCMD_EDITION:
  131. return ret.append("DAMP_SDSCMD_EDITION");
  132. case DAMP_SDSCMD_GETSTORE:
  133. return ret.append("DAMP_SDSCMD_GETSTORE");
  134. case DAMP_SDSCMD_VERSION:
  135. return ret.append("DAMP_SDSCMD_VERSION");
  136. case DAMP_SDSCMD_DIAGNOSTIC:
  137. return ret.append("DAMP_SDSCMD_DIAGNOSTIC");
  138. case DAMP_SDSCMD_GETELEMENTS:
  139. return ret.append("DAMP_SDSCMD_GETELEMENTS");
  140. case DAMP_SDSCMD_MCONNECT:
  141. return ret.append("DAMP_SDSCMD_MCONNECT");
  142. case DAMP_SDSCMD_GETCHILDREN2:
  143. return ret.append("DAMP_SDSCMD_GETCHILDREN2");
  144. case DAMP_SDSCMD_GET2:
  145. return ret.append("DAMP_SDSCMD_GET2");
  146. case DAMP_SDSCMD_GETPROPS:
  147. return ret.append("DAMP_SDSCMD_GETPROPS");
  148. case DAMP_SDSCMD_GETXPATHS:
  149. return ret.append("DAMP_SDSCMD_GETXPATHS");
  150. case DAMP_SDSCMD_GETEXTVALUE:
  151. return ret.append("DAMP_SDSCMD_GETEXTVALUE");
  152. case DAMP_SDSCMD_GETXPATHSPLUSIDS:
  153. return ret.append("DAMP_SDSCMD_GETXPATHSPLUSIDS");
  154. case DAMP_SDSCMD_GETXPATHSCRITERIA:
  155. return ret.append("DAMP_SDSCMD_GETXPATHSCRITERIA");
  156. case DAMP_SDSCMD_GETELEMENTSRAW:
  157. return ret.append("DAMP_SDSCMD_GETELEMENTSRAW");
  158. case DAMP_SDSCMD_GETCOUNT:
  159. return ret.append("DAMP_SDSCMD_GETCOUNT");
  160. default:
  161. return ret.append("UNKNOWN");
  162. };
  163. return ret;
  164. }
  165. #ifdef USECHECKEDCRITICALSECTIONS
  166. class LinkingCriticalBlock : public CheckedCriticalBlock, public CInterface
  167. {
  168. public:
  169. LinkingCriticalBlock(CheckedCriticalSection &crit, const char *file, unsigned line) : CheckedCriticalBlock(crit, fakeCritTimeout, file, line) { }
  170. };
  171. class CLCLockBlock : public CInterface
  172. {
  173. ReadWriteLock &lock;
  174. bool readLocked; // false == writeLocked
  175. unsigned got, lnum;
  176. public:
  177. CLCLockBlock(ReadWriteLock &_lock, bool readLock, unsigned timeout, const char *fname, unsigned _lnum) : lock(_lock), lnum(_lnum)
  178. {
  179. got = msTick();
  180. loop
  181. {
  182. if (readLock)
  183. {
  184. if (lock.lockRead(timeout))
  185. break;
  186. }
  187. else
  188. {
  189. if (lock.lockWrite(timeout))
  190. break;
  191. }
  192. PROGLOG("CLCLockBlock(write=%d) timeout %s(%d), took %d ms",!readLocked,fname,lnum,got-msTick());
  193. PrintStackReport();
  194. }
  195. got = msTick();
  196. readLocked = readLock; // false == writeLocked
  197. };
  198. ~CLCLockBlock()
  199. {
  200. if (readLocked)
  201. lock.unlockRead();
  202. else
  203. lock.unlockWrite();
  204. unsigned e=msTick()-got;
  205. if (e>readWriteSlowTracing)
  206. {
  207. StringBuffer s("TIME: CLCLockBlock(write=");
  208. s.append(!readLocked).append(",lnum=").append(lnum).append(") took ").append(e).append(" ms");
  209. DBGLOG("%s", s.str());
  210. if (readWriteStackTracing)
  211. PrintStackReport();
  212. }
  213. }
  214. };
  215. #else
  216. class LinkingCriticalBlock : public CriticalBlock, public CInterface, implements IInterface
  217. {
  218. public:
  219. IMPLEMENT_IINTERFACE;
  220. LinkingCriticalBlock(CriticalSection &crit, const char *file, unsigned line) : CriticalBlock(crit) { }
  221. };
  222. class CLCLockBlock : public CInterface
  223. {
  224. ReadWriteLock &lock;
  225. bool readLocked; // false == writeLocked
  226. public:
  227. CLCLockBlock(ReadWriteLock &_lock, bool readLock, unsigned timeout, const char *fname, unsigned lnum) : lock(_lock)
  228. {
  229. if (readLock)
  230. lock.lockRead();
  231. else
  232. lock.lockWrite();
  233. readLocked = readLock; // false == writeLocked
  234. };
  235. ~CLCLockBlock()
  236. {
  237. if (readLocked)
  238. lock.unlockRead();
  239. else
  240. lock.unlockWrite();
  241. }
  242. };
  243. #endif
  244. class CLCReadLockBlock : public CLCLockBlock
  245. {
  246. public:
  247. CLCReadLockBlock(ReadWriteLock &lock, unsigned timeout, const char *fname, unsigned lnum) : CLCLockBlock(lock, true, timeout, fname, lnum) { }
  248. };
  249. class CLCWriteLockBlock : public CLCLockBlock
  250. {
  251. public:
  252. CLCWriteLockBlock(ReadWriteLock &lock, unsigned timeout, const char *fname, unsigned lnum) : CLCLockBlock(lock, false, timeout, fname, lnum) { }
  253. };
  254. #ifdef USECHECKEDCRITICALSECTIONS
  255. #define CHECKEDDALIREADLOCKBLOCK(l,timeout) Owned<CLCReadLockBlock> glue(block,__LINE__) = new CLCReadLockBlock(l,timeout,__FILE__,__LINE__)
  256. #define CHECKEDDALIWRITELOCKBLOCK(l,timeout) Owned<CLCWriteLockBlock> glue(block,__LINE__) = new CLCWriteLockBlock(l,timeout,__FILE__,__LINE__)
  257. #else
  258. #define CHECKEDDALIREADLOCKBLOCK(l,timeout) ReadLockBlock glue(block,__LINE__)(l)
  259. #define CHECKEDDALIWRITELOCKBLOCK(l,timeout) WriteLockBlock glue(block,__LINE__)(l)
  260. #endif
  261. #define OVERFLOWSIZE 50000
  262. class CFitArray
  263. {
  264. unsigned size;
  265. CRemoteTreeBase **ptrs; // offset 0 not used
  266. CriticalSection crit;
  267. unsigned nextId, chk;
  268. unsigned freeChainHead;
  269. inline void _ensure(unsigned _size)
  270. {
  271. if (size<_size) {
  272. ptrs = (CRemoteTreeBase **)checked_realloc(ptrs, _size * sizeof(CRemoteTreeBase *), size * sizeof(CRemoteTreeBase *), -100);
  273. memset(&ptrs[size], 0, (_size-size)*sizeof(CRemoteTreeBase *));
  274. size = _size;
  275. }
  276. }
  277. unsigned getId()
  278. {
  279. if (freeChainHead)
  280. {
  281. unsigned nF = freeChainHead;
  282. freeChainHead = (CRemoteTreeBase **)ptrs[nF]-ptrs;
  283. return nF;
  284. }
  285. if (++nextId >= size)
  286. _ensure(nextId+OVERFLOWSIZE);
  287. return nextId;
  288. }
  289. CRemoteTreeBase *_queryElem(__int64 id)
  290. {
  291. unsigned i = (unsigned) id;
  292. if (i>=size)
  293. return NULL;
  294. CRemoteTreeBase *ret = ptrs[i];
  295. if (!ret)
  296. return NULL;
  297. if ((memsize_t)ret >= (memsize_t)&ptrs[0] && (memsize_t)ret < (memsize_t)&ptrs[size])
  298. return NULL; // a ptr within the table is part of the free chain
  299. if (id != ret->queryServerId()) // then obj at index is not the same object.
  300. return NULL;
  301. return ret;
  302. }
  303. public:
  304. CFitArray() : ptrs(NULL), chk(0) { reset(); }
  305. CFitArray(unsigned initSize) : ptrs(NULL), chk(0) { reset(); ensure(initSize); }
  306. ~CFitArray() { free(ptrs); }
  307. void reset()
  308. {
  309. if (ptrs)
  310. free(ptrs);
  311. size = 0;
  312. ptrs = NULL;
  313. nextId = 1;
  314. freeChainHead = 0;
  315. }
  316. void ensure(unsigned size)
  317. {
  318. CriticalBlock b(crit);
  319. _ensure(size);
  320. }
  321. void addElem(CRemoteTreeBase *member)
  322. {
  323. CriticalBlock b(crit);
  324. __int64 id = getId();
  325. ptrs[id] = member;
  326. if (++chk==0x80000000)
  327. chk = 0;
  328. id |= ((__int64)chk << 32);
  329. member->setServerId(id);
  330. }
  331. void freeElem(__int64 id)
  332. {
  333. CriticalBlock b(crit);
  334. unsigned i = (unsigned) id;
  335. assertex(i<size);
  336. ptrs[i] = (CRemoteTreeBase *)&ptrs[freeChainHead];
  337. freeChainHead = i;
  338. }
  339. CRemoteTreeBase *queryElem(__int64 id)
  340. {
  341. CriticalBlock b(crit);
  342. return _queryElem(id);
  343. }
  344. CRemoteTreeBase *getElem(__int64 id)
  345. {
  346. CriticalBlock b(crit);
  347. return LINK(_queryElem(id));
  348. }
  349. unsigned maxElements() const { return nextId; } // actual is nextId - however many in free chain
  350. };
  351. ////////////////
  352. enum IncInfo { IINull=0x00, IncData=0x01, IncDetails=0x02, IncConnect=0x04, IncDisconnect=0x08, IncDisconnectDelete=0x24 };
  353. StringBuffer &constructStoreName(const char *storeBase, unsigned e, StringBuffer &res)
  354. {
  355. res.append(storeBase);
  356. if (e)
  357. res.append(e);
  358. res.append(".xml");
  359. return res;
  360. }
  361. ////////////////
  362. static CheckedCriticalSection loadStoreCrit, saveStoreCrit, saveIncCrit, nfyTableCrit, extCrit, blockedSaveCrit;
  363. class CCovenSDSManager;
  364. static CCovenSDSManager *SDSManager;
  365. static StringAttr remoteBackupLocation;
  366. /////////////////
  367. class TimingStats
  368. {
  369. public:
  370. TimingStats() : count(0), totalTime(0), maxTime(0), minTime((unsigned long)-1), totalSize(0) {}
  371. inline void record(unsigned long interval)
  372. {
  373. count++;
  374. totalTime += interval;
  375. if(interval>maxTime) maxTime = interval;
  376. if(interval<minTime) minTime = interval;
  377. }
  378. inline void recordSize(unsigned long size)
  379. {
  380. totalSize += size;
  381. }
  382. unsigned long queryCount() const { return count; }
  383. unsigned long queryMeanTime() const { return count ? (unsigned long)(((double)totalTime*0.1)/count + 0.5) : 0; }
  384. unsigned long queryMaxTime() const { return maxTime/10; }
  385. unsigned long queryMinTime() const { return count ? minTime/10 : 0; }
  386. unsigned long queryMeanSize() const { return count ? (unsigned long)(((double)totalSize)/count + 0.5) : 0; }
  387. private:
  388. unsigned long count;
  389. unsigned long totalTime;
  390. unsigned long maxTime;
  391. unsigned long minTime;
  392. unsigned long totalSize;
  393. };
  394. class TimingBlock
  395. {
  396. public:
  397. TimingBlock(TimingStats & _stats) : stats(_stats) { start = msTick(); }
  398. ~TimingBlock() { stats.record(msTick()-start); }
  399. protected:
  400. TimingStats & stats;
  401. private:
  402. unsigned long start;
  403. };
  404. class TimingSizeBlock : public TimingBlock
  405. {
  406. public:
  407. TimingSizeBlock(TimingStats & _stats) : TimingBlock(_stats), size(0) {}
  408. ~TimingSizeBlock() { stats.recordSize(size); }
  409. inline void recordSize(unsigned long _size) { size = _size; }
  410. private:
  411. unsigned long size;
  412. };
  413. class CSDSTransactionServer : public Thread, public CTransactionLogTracker
  414. {
  415. public:
  416. IMPLEMENT_IINTERFACE;
  417. CSDSTransactionServer(CCovenSDSManager &_manager);
  418. void stop();
  419. void processMessage(CMessageBuffer &mb);
  420. const bool &queryStopped() const { return stopped; }
  421. inline TimingStats const & queryXactTimingStats() const { return xactTimingStats; }
  422. inline TimingStats const & queryConnectTimingStats() const { return connectTimingStats; }
  423. inline TimingStats const & queryCommitTimingStats() const { return commitTimingStats; }
  424. // Thread
  425. virtual int run();
  426. // CTransactionLogTracker
  427. virtual StringBuffer &getCmdText(unsigned cmd, StringBuffer &ret) const
  428. {
  429. return getSdsCmdText((SdsCommand)cmd, ret);
  430. }
  431. private:
  432. TimingStats xactTimingStats;
  433. TimingStats connectTimingStats;
  434. TimingStats commitTimingStats;
  435. bool stopped;
  436. CCovenSDSManager &manager;
  437. };
  438. //////////////
  439. class CSubscriberContainerBase : public CInterfaceOf<IInterface>
  440. {
  441. DECL_NAMEDCOUNT;
  442. protected:
  443. bool unsubscribed;
  444. Owned<ISubscription> subscriber;
  445. SubscriptionId id;
  446. public:
  447. CSubscriberContainerBase(ISubscription *_subscriber, SubscriptionId _id) :
  448. subscriber(_subscriber), id(_id)
  449. {
  450. INIT_NAMEDCOUNT;
  451. unsubscribed = false;
  452. }
  453. bool notify(MemoryBuffer &mb) const
  454. {
  455. try
  456. {
  457. subscriber->notify(mb);
  458. return true;
  459. }
  460. catch (IException *e)
  461. {
  462. LOG(MCuserWarning, e, "SDS: Error notifying subscriber");
  463. e->Release();
  464. }
  465. return false; // unsubscribe
  466. }
  467. const SubscriptionId &queryId() const { return id; }
  468. const void *queryFindParam() const
  469. {
  470. return (const void *) &id;
  471. }
  472. bool isUnsubscribed() { return unsubscribed || subscriber->aborted(); }
  473. void setUnsubscribed() { unsubscribed = true; }
  474. };
  475. /////////////////
  476. class CConnectionSubscriberContainer : public CSubscriberContainerBase
  477. {
  478. public:
  479. CConnectionSubscriberContainer(ISubscription *subscriber, SubscriptionId id) : CSubscriberContainerBase(subscriber, id) { }
  480. bool notify() { MemoryBuffer mb; return CSubscriberContainerBase::notify(mb); }
  481. };
  482. //////////////
  483. enum ConnInfoFlags { ci_newParent = 0x01 };
  484. //////////////
  485. class CServerConnection : public CConnectionBase, implements ISessionNotify
  486. {
  487. DECL_NAMEDCOUNT;
  488. public:
  489. IMPLEMENT_IINTERFACE;
  490. CServerConnection(ISDSConnectionManager &manager, ConnectionId connectionId, const char *xpath, SessionId id, unsigned mode, unsigned timeout, IPropertyTree *_parent, ConnInfoFlags _connInfoFlags)
  491. : CConnectionBase(manager, connectionId, xpath, id, mode, timeout), parent(_parent), connInfoFlags(_connInfoFlags)
  492. {
  493. INIT_NAMEDCOUNT;
  494. subsid = 0;
  495. established = false;
  496. }
  497. ~CServerConnection();
  498. void initPTreePath(PTree &root, PTree &tail)
  499. {
  500. if (&root != &tail)
  501. {
  502. StringBuffer head;
  503. const char *_tail = splitXPath(xpath, head);
  504. if (_tail == xpath)
  505. ptreePath.append(*LINK(&root));
  506. else
  507. ptreePath.fill(root, head.str(), tail);
  508. #define DEBUG_HPCC_11202
  509. #ifdef DEBUG_HPCC_11202
  510. PTree &parent = ptreePath.tos();
  511. aindex_t pos = parent.queryChildIndex(&tail);
  512. if (pos == NotFound)
  513. {
  514. StringBuffer msg;
  515. msg.append("ConnectionId=").appendf("%"I64F"x", connectionId).append(", xpath=").append(xpath).append(", sessionId=").appendf("%"I64F"x", sessionId).append(", mode=").append(mode).append(", timeout=");
  516. if (INFINITE == timeout)
  517. msg.append("INFINITE");
  518. else
  519. msg.append(timeout);
  520. ERRLOG("Invalid connection: %s", msg.str());
  521. ForEachItemIn(i, ptreePath)
  522. {
  523. PTree &tree = ptreePath.item(i);
  524. DBGLOG("PTree path item %d = %s", i, tree.queryName());
  525. }
  526. assertex(false); // stack report may be useful
  527. }
  528. #endif
  529. }
  530. ptreePath.append(*LINK(&tail));
  531. }
  532. CPTStack &queryPTreePath() { return ptreePath; }
  533. IPropertyTree *queryRootUnvalidated()
  534. {
  535. return root;
  536. }
  537. MemoryBuffer &getInfo(MemoryBuffer &out)
  538. {
  539. out.append(connectionId).append(xpath).append(sessionId).append(mode).append(timeout).append(established);
  540. return out;
  541. }
  542. void subscribe(SessionId id)
  543. {
  544. subsid = querySessionManager().subscribeSession(id, this);
  545. }
  546. void addConnInfoFlag(ConnInfoFlags flag) { connInfoFlags = (ConnInfoFlags) (((unsigned)connInfoFlags) | ((unsigned) flag)); }
  547. void closed(SessionId id)
  548. {
  549. LOG(MCwarning, unknownJob, "Connection (%"I64F"x) was leaked by exiting client (%"I64F"x) path=%s", connectionId, id, queryXPath());
  550. aborted(id);
  551. subsid=0;
  552. }
  553. void aborted(SessionId id);
  554. void unsubscribeSession()
  555. {
  556. if (subsid) {
  557. querySessionManager().unsubscribeSession(subsid);
  558. subsid = 0;
  559. }
  560. }
  561. void notify()
  562. {
  563. ForEachItemInRev(s, subscriptions)
  564. {
  565. CConnectionSubscriberContainer &sub = subscriptions.item(s);
  566. if (!sub.notify())
  567. subscriptions.remove(s);
  568. }
  569. }
  570. void addSubscriber(CConnectionSubscriberContainer &sub)
  571. {
  572. subscriptions.append(sub);
  573. }
  574. void removeSubscriber(SubscriptionId id)
  575. {
  576. ForEachItemIn(s, subscriptions) // do not expect a lot of subscribers per connection - probably ~ 1.
  577. {
  578. if (id == subscriptions.item(s).queryId())
  579. {
  580. subscriptions.remove(s);
  581. break;
  582. }
  583. }
  584. }
  585. bool queryEstablished() { return established; }
  586. void setEstablished() { established = true; }
  587. IPropertyTree *queryParent() { return parent; }
  588. void removeRoot()
  589. {
  590. if (parent)
  591. parent->removeTree(root);
  592. }
  593. virtual IPropertyTree *queryRoot();
  594. private:
  595. ConnInfoFlags connInfoFlags;
  596. IPropertyTree *parent;
  597. SubscriptionId subsid;
  598. CPTStack ptreePath;
  599. IArrayOf<CConnectionSubscriberContainer> subscriptions;
  600. bool established;
  601. };
  602. /////////////////
  603. class CQualifiers : public CInterfaceOf<IInterface>
  604. {
  605. StringArray qualifiers;
  606. public:
  607. inline void add(const char *qualifier) { qualifiers.append(qualifier); }
  608. inline unsigned count() const { return qualifiers.ordinality(); }
  609. inline const char *item(unsigned i) const { return qualifiers.item(i); }
  610. };
  611. class CSubscriberContainer : public CSubscriberContainerBase
  612. {
  613. StringAttr xpath, fullXpath;
  614. PointerIArrayOf<CQualifiers> qualifierStack;
  615. bool sub, sendValue;
  616. unsigned depth;
  617. public:
  618. CSubscriberContainer(ISubscription *subscriber, SubscriptionId id) : CSubscriberContainerBase(subscriber, id)
  619. {
  620. const MemoryAttr &ma = subscriber->queryData();
  621. MemoryBuffer mb(ma.length(), ma.get());
  622. mb.read(xpath);
  623. mb.read(sub);
  624. if (mb.remaining()) // remaining
  625. mb.read(sendValue);
  626. else
  627. sendValue = false;
  628. const char *path = xpath;
  629. const char *nextSep = path+1;
  630. StringBuffer head;
  631. depth = 1; // root
  632. loop
  633. {
  634. nextSep = queryHead(nextSep, head.clear());
  635. ++depth; // inc last
  636. if (!nextSep)
  637. break;
  638. }
  639. StringBuffer strippedXpath;
  640. loop
  641. {
  642. const char *startQ;
  643. if (NULL == (startQ = queryNextUnquoted(path, '['))) // escaped '[]' chars??
  644. {
  645. if (strippedXpath.length()) strippedXpath.append(path);
  646. break;
  647. }
  648. const char *nextSep = path+1;
  649. loop
  650. {
  651. nextSep = queryHead(nextSep, head.clear());
  652. if (!nextSep || startQ < nextSep)
  653. break;
  654. qualifierStack.append(NULL); // no qualifier for this segment.
  655. }
  656. Owned<CQualifiers> qualifiers = new CQualifiers;
  657. strippedXpath.append(startQ-path, path);
  658. loop
  659. {
  660. const char *endQ = queryNextUnquoted(startQ+1, ']');
  661. if (!endQ)
  662. throw MakeSDSException(SDSExcpt_SubscriptionParseError, "Missing closing brace: %s", xpath.get());
  663. StringAttr qualifier(startQ+1, endQ-startQ-1);
  664. qualifiers->add(qualifier);
  665. path = endQ+1;
  666. if ('[' != *path)
  667. break;
  668. startQ = path;
  669. }
  670. qualifierStack.append(qualifiers.getClear());
  671. }
  672. fullXpath.set(xpath);
  673. if (strippedXpath.length()) // some qualifications
  674. xpath.set(strippedXpath.str());
  675. // Notes on qualified (e.g. 'a/b[x="test"]/c' etc.)
  676. // 1) strip out all qualifies from xpath into 'qualifierStack' and translate xpath to simple absolute path.
  677. // 2) collate IPropertyTree stack in processData; to pass to querySubscribers.
  678. // 3) querySubscribers becomes getSubscribers, builds up a list of matching subscribers,
  679. // initially obtained with findList, but pruned based on IPT stack and qualifierStack.
  680. // by walking IPT stack performing either PTree->checkPattern or for index's parent->findChild etc.
  681. }
  682. const char *queryXPath() const { return xpath; }
  683. bool querySub() const { return sub; }
  684. bool querySendValue() const { return sendValue; }
  685. unsigned queryDepth() const { return depth; }
  686. bool qualify(CPTStack &stack, bool matchIfPartial)
  687. {
  688. ForEachItemIn(q, qualifierStack)
  689. {
  690. if (stack.ordinality() <= q+1)
  691. {
  692. // No more stack available (e.g. because deleted below this point)
  693. return matchIfPartial; // NB: return true if matchIfPartial=true (meaning head of subscriber path matched commit stack)
  694. }
  695. PTree &item = stack.item(q+1); // stack +1, top is root unqualified.
  696. CQualifiers *qualifiers = qualifierStack.item(q);
  697. if (qualifiers)
  698. {
  699. for (unsigned q2=0; q2<qualifiers->count(); q2++)
  700. {
  701. const char *qualifier = qualifiers->item(q2);
  702. const char *q = qualifier;
  703. bool numeric = true;
  704. loop
  705. {
  706. if ('\0' == *q) break;
  707. else if (!isdigit(*q)) { numeric = false; break; }
  708. else q++;
  709. }
  710. if (numeric)
  711. {
  712. unsigned qnum = atoi(qualifier);
  713. if (!item.queryParent())
  714. {
  715. if (qnum != 1)
  716. return false;
  717. }
  718. else if (((PTree *)item.queryParent())->findChild(&item) != qnum-1)
  719. return false;
  720. }
  721. else if (!item.checkPattern(qualifier))
  722. return false;
  723. }
  724. }
  725. }
  726. return true;
  727. }
  728. MemoryBuffer &getInfo(MemoryBuffer &out)
  729. {
  730. out.append(id).append(sub).append(fullXpath);
  731. return out;
  732. }
  733. };
  734. typedef IArrayOf<CSubscriberContainer> CSubscriberArray;
  735. class CSubscriberContainerList : public CInterface, public CSubscriberArray
  736. {
  737. public:
  738. CSubscriberContainerList() { }
  739. CSubscriberContainerList(const char *_xpath) : xpath(_xpath) { _xpath = xpath.get(); }
  740. const char *queryXPath() const { return xpath; }
  741. const char *queryFindString() const { return queryXPath(); }
  742. private:
  743. StringAttr xpath;
  744. };
  745. typedef OwningStringSuperHashTableOf<CSubscriberContainerList> CSubscriberXPathTable;
  746. class CSubscriberTable : public ThreadSafeSimpleHashTableOf<CSubscriberContainer, SubscriptionId>
  747. {
  748. public:
  749. ~CSubscriberTable() { kill(); }
  750. virtual void onAdd(void *et)
  751. {
  752. CSubscriberContainer *subscriber = (CSubscriberContainer *) et;
  753. CSubscriberContainerList *list = xpathTable.find(subscriber->queryXPath());
  754. if (!list)
  755. {
  756. list = new CSubscriberContainerList(subscriber->queryXPath());
  757. xpathTable.replace(*list);
  758. }
  759. list->append(*subscriber); // give over ownership.
  760. }
  761. virtual void onRemove(void *et)
  762. {
  763. CSubscriberContainer *subscriber = (CSubscriberContainer *) et;
  764. subscriber->setUnsubscribed();
  765. CSubscriberContainerList *list = xpathTable.find(subscriber->queryXPath());
  766. assertex(list);
  767. verifyex(list->zap(*subscriber));
  768. if (!list->ordinality())
  769. xpathTable.removeExact(list);
  770. }
  771. CSubscriberContainerList *getQualifiedList(const char *xpath, CPTStack &stack)
  772. {
  773. CriticalBlock b(crit);
  774. CSubscriberContainerList *list = xpathTable.find(xpath);
  775. if (!list) return NULL;
  776. CSubscriberContainerList *results = NULL;
  777. ForEachItemIn(s, *list)
  778. {
  779. CSubscriberContainer &subscriber = list->item(s);
  780. if (subscriber.qualify(stack, false))
  781. {
  782. if (!results) results = new CSubscriberContainerList(xpath);
  783. subscriber.Link();
  784. results->append(subscriber);
  785. }
  786. }
  787. return results;
  788. }
  789. void getSubscribers(CSubscriberArray &subs)
  790. {
  791. CriticalBlock b(crit);
  792. SuperHashIteratorOf<CSubscriberContainer> iter(queryBaseTable());
  793. ForEach(iter)
  794. {
  795. CSubscriberContainer &sub = iter.query();
  796. sub.Link();
  797. subs.append(sub);
  798. }
  799. }
  800. private:
  801. CSubscriberXPathTable xpathTable;
  802. };
  803. #ifdef _DEBUG
  804. struct DebugInfo
  805. {
  806. DebugInfo() { clearExclusive(); }
  807. void clearExclusive() { ExclOwningThread =0; ExclOwningConnection=0; ExclOwningSession=0; }
  808. ThreadId ExclOwningThread;
  809. ConnectionId ExclOwningConnection;
  810. SessionId ExclOwningSession;
  811. };
  812. #endif
  813. struct LockData
  814. {
  815. unsigned mode;
  816. SessionId sessId;
  817. unsigned timeLockObtained;
  818. };
  819. class BoolSetBlock
  820. {
  821. public:
  822. BoolSetBlock(bool &_b, bool state=true) : b(_b) { o = b; b = state; }
  823. ~BoolSetBlock() { b = o; }
  824. private:
  825. bool o, &b;
  826. };
  827. //////////////
  828. template <class ET>
  829. class LinkedStringHTMapping : public OwningStringHTMapping<ET>
  830. {
  831. public:
  832. LinkedStringHTMapping(const char *fp, ET &et) : OwningStringHTMapping<ET>(fp, et) { this->et.Link(); }
  833. };
  834. typedef LinkedStringHTMapping<IExternalHandler> CExternalHandlerMapping;
  835. typedef OwningStringSuperHashTableOf<CExternalHandlerMapping> CExternalHandlerTable;
  836. void serializeVisibleAttributes(IPropertyTree &tree, MemoryBuffer &mb)
  837. {
  838. IAttributeIterator *aIter = tree.getAttributes();
  839. if (aIter->first())
  840. {
  841. loop
  842. {
  843. const char *attr = aIter->queryName();
  844. if (0 != strcmp(EXT_ATTR, attr))
  845. {
  846. mb.append(attr);
  847. mb.append(aIter->queryValue());
  848. }
  849. if (!aIter->next())
  850. break;
  851. }
  852. }
  853. aIter->Release();
  854. mb.append(""); // attribute terminator. i.e. blank attr name.
  855. }
  856. void writeDelta(StringBuffer &xml, IFile &iFile, const char *msg="", unsigned retrySecs=0, unsigned retryAttempts=10)
  857. {
  858. Owned<IException> exception;
  859. OwnedIFileIO iFileIO;
  860. unsigned _retryAttempts = retryAttempts;
  861. Owned<IFileIOStream> stream;
  862. offset_t lastGood = 0;
  863. unsigned startCrc = ~0;
  864. MemoryBuffer header;
  865. char strNum[17];
  866. loop
  867. {
  868. header.append(deltaHeader);
  869. try
  870. {
  871. iFileIO.setown(iFile.open(IFOreadwrite));
  872. stream.setown(createIOStream(iFileIO));
  873. if (lastGood)
  874. {
  875. PROGLOG("Resetting delta file size");
  876. iFileIO->setSize(lastGood);
  877. }
  878. else
  879. {
  880. if (iFileIO->size())
  881. {
  882. iFileIO->read(deltaHeaderCrcOff, 10, strNum);
  883. startCrc = ~(unsigned)atoi64_l(strNum, 10);
  884. }
  885. else
  886. stream->write(strlen(deltaHeader), deltaHeader);
  887. lastGood = iFileIO->size();
  888. }
  889. stream->seek(0, IFSend);
  890. stream->write(xml.length(), xml.toCharArray());
  891. stream->flush();
  892. stream.clear();
  893. offset_t fLen = lastGood + xml.length();
  894. unsigned crc = crc32(xml.toCharArray(), xml.length(), startCrc);
  895. char *headerPtr = (char *)header.bufferBase();
  896. sprintf(strNum, "%010u", ~crc);
  897. memcpy(headerPtr + deltaHeaderCrcOff, strNum, 10);
  898. sprintf(strNum, "%016"I64F"X", fLen);
  899. memcpy(headerPtr + deltaHeaderSizeOff, strNum, 16);
  900. iFileIO->write(0, strlen(deltaHeader), headerPtr);
  901. }
  902. catch (IException *e)
  903. {
  904. exception.setown(e);
  905. StringBuffer s(msg);
  906. LOG(MCoperatorError, unknownJob, e, s.append("writeDelta, failed").str());
  907. }
  908. if (!exception.get())
  909. break;
  910. if (0 == retrySecs)
  911. return;
  912. if (0 == --_retryAttempts)
  913. {
  914. WARNLOG("writeDelta, too many retry attemps [%d]", retryAttempts);
  915. return;
  916. }
  917. exception.clear();
  918. WARNLOG("writeDelta, retrying");
  919. MilliSleep(retrySecs*1000);
  920. }
  921. }
  922. struct BackupQueueItem
  923. {
  924. static unsigned typeMask;
  925. enum flagt { f_delta=0x1, f_addext=0x2, f_delext=0x3, f_first=0x10 };
  926. BackupQueueItem() : edition((unsigned)-1), flags(0) { text = new StringBuffer; dataLength = 0; data = NULL; }
  927. ~BackupQueueItem()
  928. {
  929. delete text;
  930. if (data) free(data);
  931. }
  932. StringBuffer *text;
  933. unsigned edition;
  934. unsigned dataLength;
  935. void *data;
  936. byte flags;
  937. };
  938. unsigned BackupQueueItem::typeMask = 0x0f;
  939. class CBackupHandler : public CInterface, implements IThreaded
  940. {
  941. typedef QueueOf<BackupQueueItem, false> BackupQueue;
  942. CThreaded threaded;
  943. BackupQueue itemQueue, freeQueue;
  944. Semaphore pending, softQueueLimitSem;
  945. bool aborted, waiting, addWaiting, async;
  946. unsigned currentEdition, throttleCounter;
  947. CriticalSection queueCrit, freeQueueCrit;
  948. StringAttr backupPath;
  949. unsigned freeQueueLimit; // how many BackupQueueItems to cache for reuse
  950. unsigned largeWarningThreshold; // point at which to start warning about large queue
  951. unsigned softQueueLimit; // threshold over which primary transactions will be delay by small delay, to allow backup catchup.
  952. unsigned softQueueLimitDelay; // delay for above
  953. CTimeMon warningTime;
  954. unsigned recentTimeThrottled;
  955. unsigned lastNumWarnItems;
  956. BackupQueueItem *getFreeItem()
  957. {
  958. BackupQueueItem *item;
  959. {
  960. CriticalBlock b(freeQueueCrit);
  961. item = freeQueue.dequeue();
  962. }
  963. if (!item)
  964. item = new BackupQueueItem;
  965. return item;
  966. }
  967. void clearQueue(BackupQueue &queue)
  968. {
  969. loop
  970. {
  971. BackupQueueItem *item = queue.dequeue();
  972. if (!item) break;
  973. delete item;
  974. }
  975. }
  976. void writeExt(const char *name, const unsigned length, const void *data, unsigned retrySecs=0, unsigned retryAttempts=10)
  977. {
  978. Owned<IException> exception;
  979. unsigned _retryAttempts = retryAttempts;
  980. StringBuffer rL(remoteBackupLocation);
  981. loop
  982. {
  983. try
  984. {
  985. rL.append(name);
  986. Owned<IFile> iFile = createIFile(rL.str());
  987. Owned<IFileIO> fileIO = iFile->open(IFOcreate);
  988. fileIO->write(0, length, data);
  989. }
  990. catch (IException *e)
  991. {
  992. exception.setown(e);
  993. StringBuffer err("Saving external (backup): ");
  994. LOG(MCoperatorError, unknownJob, e, err.append(rL).str());
  995. }
  996. if (!exception.get())
  997. break;
  998. if (0 == retrySecs)
  999. return;
  1000. if (0 == --_retryAttempts)
  1001. {
  1002. WARNLOG("writeExt, too many retry attemps [%d]", retryAttempts);
  1003. return;
  1004. }
  1005. exception.clear();
  1006. WARNLOG("writeExt, retrying");
  1007. MilliSleep(retrySecs*1000);
  1008. }
  1009. }
  1010. void deleteExt(const char *name, unsigned retrySecs=0, unsigned retryAttempts=10)
  1011. {
  1012. Owned<IException> exception;
  1013. unsigned _retryAttempts = retryAttempts;
  1014. StringBuffer rL(remoteBackupLocation);
  1015. loop
  1016. {
  1017. try
  1018. {
  1019. rL.append(name);
  1020. Owned<IFile> iFile = createIFile(rL.str());
  1021. iFile->remove();
  1022. }
  1023. catch (IException *e)
  1024. {
  1025. exception.setown(e);
  1026. StringBuffer err("Removing external (backup): ");
  1027. LOG(MCoperatorWarning, unknownJob, e, err.append(rL).str());
  1028. }
  1029. if (!exception.get())
  1030. break;
  1031. if (0 == retrySecs)
  1032. return;
  1033. if (0 == --_retryAttempts)
  1034. {
  1035. WARNLOG("deleteExt, too many retry attemps [%d]", retryAttempts);
  1036. return;
  1037. }
  1038. exception.clear();
  1039. WARNLOG("deleteExt, retrying");
  1040. MilliSleep(retrySecs*1000);
  1041. }
  1042. }
  1043. bool writeDelta(StringBuffer &xml, unsigned edition, bool first)
  1044. {
  1045. StringBuffer deltaFilename(backupPath);
  1046. constructStoreName(DELTANAME, edition, deltaFilename);
  1047. OwnedIFile iFile = createIFile(deltaFilename.str());
  1048. if (!first && !iFile->exists())
  1049. return false; // discard
  1050. ::writeDelta(xml, *iFile, "CBackupHandler - ", 60, 30);
  1051. return true;
  1052. }
  1053. void clearOld()
  1054. {
  1055. CriticalBlock b(queueCrit);
  1056. loop
  1057. {
  1058. BackupQueueItem *item = itemQueue.dequeue();
  1059. if (!item) break;
  1060. if (BackupQueueItem::f_delta == (item->flags & BackupQueueItem::typeMask))
  1061. {
  1062. item->text->clear();
  1063. if (freeQueue.ordinality() < freeQueueLimit)
  1064. freeQueue.enqueue(item);
  1065. else
  1066. delete item;
  1067. }
  1068. }
  1069. if (addWaiting && itemQueue.ordinality()<softQueueLimit)
  1070. softQueueLimitSem.signal();
  1071. }
  1072. public:
  1073. CBackupHandler() : threaded("CBackupHandler")
  1074. {
  1075. currentEdition = (unsigned)-1;
  1076. addWaiting = waiting = async = false;
  1077. aborted = true;
  1078. throttleCounter = 0;
  1079. freeQueueLimit = 10;
  1080. largeWarningThreshold = 50;
  1081. softQueueLimit = 200;
  1082. softQueueLimitDelay = 200;
  1083. recentTimeThrottled = 0;
  1084. lastNumWarnItems = 0;
  1085. }
  1086. ~CBackupHandler()
  1087. {
  1088. clearQueue(freeQueue);
  1089. clearQueue(itemQueue);
  1090. }
  1091. void init(const char *_backupPath, bool _async)
  1092. {
  1093. backupPath.set(_backupPath);
  1094. async = _async;
  1095. aborted = false;
  1096. PROGLOG("BackupHandler started, async=%s", async?"true":"false");
  1097. threaded.init(this);
  1098. }
  1099. void stop()
  1100. {
  1101. if (!aborted)
  1102. {
  1103. aborted = true;
  1104. pending.signal();
  1105. threaded.join();
  1106. }
  1107. }
  1108. void removeExt(const char *fname)
  1109. {
  1110. if (aborted) return;
  1111. if (!async)
  1112. {
  1113. deleteExt(fname);
  1114. return;
  1115. }
  1116. BackupQueueItem *item = getFreeItem();
  1117. item->text->append(fname);
  1118. item->flags = BackupQueueItem::f_delext;
  1119. add(item);
  1120. }
  1121. void addExt(const char *fname, unsigned length, void *data)
  1122. {
  1123. if (aborted) return;
  1124. if (!async)
  1125. {
  1126. writeExt(fname, length, data);
  1127. return;
  1128. }
  1129. BackupQueueItem *item = getFreeItem();
  1130. item->text->append(fname);
  1131. item->dataLength = length;
  1132. item->data = data; // take ownership
  1133. item->flags = BackupQueueItem::f_addext;
  1134. add(item);
  1135. }
  1136. void addDelta(StringBuffer &xml, unsigned edition, bool first)
  1137. {
  1138. if (aborted) return;
  1139. if (!async)
  1140. {
  1141. writeDelta(xml, edition, first);
  1142. if (xml.length() > 0x100000)
  1143. xml.kill();
  1144. else
  1145. xml.clear();
  1146. return;
  1147. }
  1148. if (edition != currentEdition)
  1149. {
  1150. clearOld();
  1151. currentEdition = edition;
  1152. }
  1153. BackupQueueItem *item = getFreeItem();
  1154. xml.swapWith(*item->text);
  1155. item->edition = edition;
  1156. item->flags = BackupQueueItem::f_delta | BackupQueueItem::f_first;
  1157. add(item);
  1158. }
  1159. void add(BackupQueueItem *item)
  1160. {
  1161. CriticalBlock b(queueCrit);
  1162. itemQueue.enqueue(item);
  1163. unsigned items=itemQueue.ordinality();
  1164. if (0==items%largeWarningThreshold)
  1165. {
  1166. if (items>lastNumWarnItems) // track as they go up
  1167. {
  1168. LOG(MCoperatorWarning, "Backup thread has a high # (%d) of pending transaction queued to write", items);
  1169. lastNumWarnItems = items;
  1170. }
  1171. else if (warningTime.elapsed() >= 60000) // if falling, avoid logging too much
  1172. {
  1173. LOG(MCoperatorWarning, "Backup thread has a high # (%d) of pending transaction queued to write", items);
  1174. lastNumWarnItems = 0;
  1175. warningTime.reset(0);
  1176. }
  1177. }
  1178. if (items>=softQueueLimit)
  1179. {
  1180. addWaiting = true;
  1181. unsigned ms = msTick();
  1182. {
  1183. CriticalUnblock b(queueCrit);
  1184. softQueueLimitSem.wait(softQueueLimitDelay);
  1185. }
  1186. addWaiting = false;
  1187. recentTimeThrottled += (msTick()-ms); // reset when queue < largeWarningThreshold
  1188. if (recentTimeThrottled >= softQueueLimitDelay && (0 == throttleCounter % 10)) // softQueueLimit exceeded - log every 10 transactions if recentTimeThrottled >= softQueueLimitDelay (1 unsignalled delay)
  1189. LOG(MCoperatorWarning, "Primary transactions are being delayed by lagging backup, currently %d queued, recent total throttle delay=%d", items, recentTimeThrottled);
  1190. ++throttleCounter; // also reset when queue < largeWarningThreshold
  1191. }
  1192. if (waiting)
  1193. pending.signal();
  1194. }
  1195. bool doIt(BackupQueueItem &item)
  1196. {
  1197. try
  1198. {
  1199. switch (item.flags & BackupQueueItem::typeMask)
  1200. {
  1201. case BackupQueueItem::f_delta:
  1202. return writeDelta(*item.text, item.edition, 0 != (item.flags & BackupQueueItem::f_first));
  1203. case BackupQueueItem::f_addext:
  1204. writeExt(item.text->str(), item.dataLength, item.data, 60, 30);
  1205. return true;
  1206. case BackupQueueItem::f_delext:
  1207. deleteExt(item.text->str(), 60, 30);
  1208. return true;
  1209. }
  1210. }
  1211. catch (IException *e)
  1212. {
  1213. LOG(MCoperatorWarning, e, "BackupHandler(async) write operation failed, possible backup data loss");
  1214. e->Release();
  1215. }
  1216. return false;
  1217. }
  1218. // IThreaded
  1219. void main()
  1220. {
  1221. loop
  1222. {
  1223. BackupQueueItem *item=NULL;
  1224. do
  1225. {
  1226. CriticalBlock b(queueCrit);
  1227. if (itemQueue.ordinality())
  1228. {
  1229. item = itemQueue.dequeue();
  1230. if (addWaiting && itemQueue.ordinality()<softQueueLimit)
  1231. softQueueLimitSem.signal();
  1232. if (itemQueue.ordinality() < largeWarningThreshold) // reset stats when falls below
  1233. {
  1234. recentTimeThrottled = 0;
  1235. throttleCounter = 0;
  1236. }
  1237. }
  1238. else
  1239. {
  1240. waiting = true;
  1241. {
  1242. CriticalUnblock b(queueCrit);
  1243. if (!aborted)
  1244. pending.wait();
  1245. }
  1246. waiting = false;
  1247. }
  1248. if (aborted)
  1249. {
  1250. if (item) delete item;
  1251. PROGLOG("BackupHandler stopped");
  1252. return;
  1253. }
  1254. }
  1255. while (!item);
  1256. if (!doIt(*item))
  1257. clearOld();
  1258. CriticalBlock b(freeQueueCrit);
  1259. if (freeQueue.ordinality() < freeQueueLimit)
  1260. {
  1261. if (item->text->length() > 0x100000)
  1262. item->text->kill();
  1263. else
  1264. item->text->clear();
  1265. if (item->data)
  1266. {
  1267. free(item->data);
  1268. item->data = NULL;
  1269. item->dataLength = 0;
  1270. }
  1271. freeQueue.enqueue(item);
  1272. }
  1273. else
  1274. delete item;
  1275. }
  1276. }
  1277. };
  1278. class CExternalFile : public CInterface
  1279. {
  1280. StringAttr ext, dataPath;
  1281. protected:
  1282. CBackupHandler &backupHandler;
  1283. public:
  1284. CExternalFile(const char *_ext, const char *_dataPath, CBackupHandler &_backupHandler) : ext(_ext), dataPath(_dataPath), backupHandler(_backupHandler) { }
  1285. const char *queryExt() { return ext; }
  1286. StringBuffer &getName(StringBuffer &fName, const char *base)
  1287. {
  1288. return fName.append(base).append(ext);
  1289. }
  1290. StringBuffer &getFilename(StringBuffer &fName, const char *base)
  1291. {
  1292. return fName.append(dataPath).append(base).append(ext);
  1293. }
  1294. bool isValid(const char *name)
  1295. {
  1296. StringBuffer filename;
  1297. getFilename(filename, name);
  1298. Owned<IFile> iFile = createIFile(filename.str());
  1299. return iFile->exists();
  1300. }
  1301. void remove(const char *name)
  1302. {
  1303. StringBuffer filename;
  1304. getFilename(filename, name);
  1305. Owned<IFile> iFile = createIFile(filename.str());
  1306. iFile->remove();
  1307. if (remoteBackupLocation.length())
  1308. {
  1309. StringBuffer fname(name);
  1310. backupHandler.removeExt(fname.append(queryExt()).str());
  1311. }
  1312. }
  1313. };
  1314. class CLegacyBinaryFileExternal : public CExternalFile, implements IExternalHandler
  1315. {
  1316. public:
  1317. IMPLEMENT_IINTERFACE;
  1318. CLegacyBinaryFileExternal(const char *dataPath, CBackupHandler &backupHandler) : CExternalFile("."EF_LegacyBinaryValue, dataPath, backupHandler) { }
  1319. virtual void resetAsExternal(IPropertyTree &tree)
  1320. {
  1321. tree.setProp(NULL, (char *)NULL);
  1322. }
  1323. virtual void readValue(const char *name, MemoryBuffer &mb)
  1324. {
  1325. StringBuffer filename;
  1326. getFilename(filename, name);
  1327. Owned<IFile> iFile = createIFile(filename.str());
  1328. size32_t sz = (size32_t)iFile->size();
  1329. if ((unsigned)-1 == sz)
  1330. {
  1331. StringBuffer s("Missing external file ");
  1332. Owned<IException> e = MakeSDSException(SDSExcpt_MissingExternalFile, "%s", filename.str());
  1333. LOG(MCoperatorWarning, unknownJob, e, s.str());
  1334. StringBuffer str("EXTERNAL BINARY FILE: \"");
  1335. str.append(filename.str()).append("\" MISSING");
  1336. CPTValue v(str.length()+1, str.toCharArray(), false);
  1337. v.serialize(mb);
  1338. }
  1339. else
  1340. {
  1341. Owned<IFileIO> fileIO = iFile->open(IFOread);
  1342. MemoryBuffer vmb;
  1343. verifyex(sz == ::read(fileIO, 0, sz, vmb));
  1344. CPTValue v(sz, vmb.toByteArray(), true);
  1345. v.serialize(mb);
  1346. }
  1347. }
  1348. virtual void read(const char *name, IPropertyTree &owner, MemoryBuffer &mb, bool withValue)
  1349. {
  1350. StringBuffer filename;
  1351. getFilename(filename, name);
  1352. const char *_name = owner.queryName();
  1353. mb.append(_name?_name:"");
  1354. byte flags = ((PTree &)owner).queryFlags();
  1355. mb.append(IptFlagSet(flags, ipt_binary));
  1356. serializeVisibleAttributes(owner, mb);
  1357. Owned<IFile> iFile = createIFile(filename.str());
  1358. size32_t sz = (size32_t)iFile->size();
  1359. if ((unsigned)-1 == sz)
  1360. {
  1361. StringBuffer s("Missing external file ");
  1362. if (*_name)
  1363. s.append("in property ").append(_name);
  1364. Owned<IException> e = MakeSDSException(SDSExcpt_MissingExternalFile, "%s", filename.str());
  1365. LOG(MCoperatorWarning, unknownJob, e, s.str());
  1366. if (withValue)
  1367. {
  1368. StringBuffer str("EXTERNAL BINARY FILE: \"");
  1369. str.append(filename.str()).append("\" MISSING");
  1370. CPTValue v(str.length()+1, str.toCharArray(), false);
  1371. v.serialize(mb);
  1372. }
  1373. else
  1374. mb.append((size32_t)0);
  1375. }
  1376. else
  1377. {
  1378. if (withValue)
  1379. {
  1380. MemoryBuffer vmb;
  1381. Owned<IFileIO> fileIO = iFile->open(IFOread);
  1382. verifyex(sz == ::read(fileIO, 0, sz, vmb));
  1383. CPTValue v(sz, vmb.toByteArray(), true);
  1384. v.serialize(mb);
  1385. }
  1386. else
  1387. mb.append((size32_t)0);
  1388. }
  1389. }
  1390. virtual void write(const char *name, IPropertyTree &tree)
  1391. {
  1392. StringBuffer filename;
  1393. getFilename(filename, name);
  1394. Owned<IFile> iFile = createIFile(filename.str());
  1395. Owned<IFileIO> fileIO = iFile->open(IFOcreate);
  1396. MemoryBuffer out;
  1397. ((PTree &)tree).queryValue()->serialize(out);
  1398. const char *data = out.toByteArray();
  1399. unsigned length = out.length();
  1400. fileIO->write(0, length, data);
  1401. if (remoteBackupLocation.length())
  1402. {
  1403. StringBuffer fname(name);
  1404. backupHandler.addExt(fname.append(queryExt()).str(), length, out.detach());
  1405. }
  1406. }
  1407. virtual void remove(const char *name) { CExternalFile::remove(name); }
  1408. virtual bool isValid(const char *name) { return CExternalFile::isValid(name); }
  1409. virtual StringBuffer &getName(StringBuffer &fName, const char *base) { return CExternalFile::getName(fName, base); }
  1410. virtual StringBuffer &getFilename(StringBuffer &fName, const char *base) { return CExternalFile::getFilename(fName, base); }
  1411. };
  1412. class CBinaryFileExternal : public CExternalFile, implements IExternalHandler
  1413. {
  1414. public:
  1415. IMPLEMENT_IINTERFACE;
  1416. CBinaryFileExternal(const char *dataPath, CBackupHandler &backupHandler) : CExternalFile("."EF_BinaryValue, dataPath, backupHandler) { }
  1417. virtual void resetAsExternal(IPropertyTree &tree)
  1418. {
  1419. tree.setProp(NULL, (char *)NULL);
  1420. }
  1421. virtual void readValue(const char *name, MemoryBuffer &mb)
  1422. {
  1423. StringBuffer filename;
  1424. getFilename(filename, name);
  1425. Owned<IFile> iFile = createIFile(filename.str());
  1426. size32_t sz = (size32_t)iFile->size();
  1427. if ((unsigned)-1 == sz)
  1428. {
  1429. StringBuffer s("Missing external file ");
  1430. Owned<IException> e = MakeSDSException(SDSExcpt_MissingExternalFile, "%s", filename.str());
  1431. LOG(MCoperatorWarning, unknownJob, e, s.str());
  1432. StringBuffer str("EXTERNAL BINARY FILE: \"");
  1433. str.append(filename.str()).append("\" MISSING");
  1434. CPTValue v(str.length()+1, str.toCharArray(), false);
  1435. v.serialize(mb);
  1436. }
  1437. else
  1438. {
  1439. Owned<IFileIO> fileIO = iFile->open(IFOread);
  1440. verifyex(sz == ::read(fileIO, 0, sz, mb));
  1441. }
  1442. }
  1443. virtual void read(const char *name, IPropertyTree &owner, MemoryBuffer &mb, bool withValue)
  1444. {
  1445. StringBuffer filename;
  1446. getFilename(filename, name);
  1447. const char *_name = owner.queryName();
  1448. mb.append(_name?_name:"");
  1449. Owned<IFile> iFile = createIFile(filename.str());
  1450. size32_t sz = (size32_t)iFile->size();
  1451. if ((unsigned)-1 == sz)
  1452. {
  1453. byte flags = ((PTree &)owner).queryFlags();
  1454. IptFlagClr(flags, ipt_binary);
  1455. mb.append(flags);
  1456. serializeVisibleAttributes(owner, mb);
  1457. StringBuffer s("Missing external file ");
  1458. if (*_name)
  1459. s.append("in property ").append(_name);
  1460. Owned<IException> e = MakeSDSException(SDSExcpt_MissingExternalFile, "%s", filename.str());
  1461. LOG(MCoperatorWarning, unknownJob, e, s.str());
  1462. if (withValue)
  1463. {
  1464. StringBuffer str("EXTERNAL BINARY FILE: \"");
  1465. str.append(filename.str()).append("\" MISSING");
  1466. CPTValue v(str.length()+1, str.toCharArray(), false);
  1467. v.serialize(mb);
  1468. }
  1469. else
  1470. mb.append((size32_t)0);
  1471. }
  1472. else
  1473. {
  1474. byte flags = ((PTree &)owner).queryFlags();
  1475. mb.append(flags);
  1476. serializeVisibleAttributes(owner, mb);
  1477. if (withValue)
  1478. {
  1479. Owned<IFileIO> fileIO = iFile->open(IFOread);
  1480. verifyex(sz == ::read(fileIO, 0, sz, mb));
  1481. }
  1482. else
  1483. mb.append((size32_t)0);
  1484. }
  1485. }
  1486. virtual void write(const char *name, IPropertyTree &tree)
  1487. {
  1488. StringBuffer filename;
  1489. getFilename(filename, name);
  1490. Owned<IFile> iFile = createIFile(filename.str());
  1491. Owned<IFileIO> fileIO = iFile->open(IFOcreate);
  1492. MemoryBuffer out;
  1493. ((PTree &)tree).queryValue()->serialize(out);
  1494. const char *data = out.toByteArray();
  1495. unsigned length = out.length();
  1496. fileIO->write(0, length, data);
  1497. if (remoteBackupLocation.length())
  1498. {
  1499. StringBuffer fname(name);
  1500. backupHandler.addExt(fname.append(queryExt()).str(), length, out.detach());
  1501. }
  1502. }
  1503. virtual void remove(const char *name) { CExternalFile::remove(name); }
  1504. virtual bool isValid(const char *name) { return CExternalFile::isValid(name); }
  1505. virtual StringBuffer &getName(StringBuffer &fName, const char *base) { return CExternalFile::getName(fName, base); }
  1506. virtual StringBuffer &getFilename(StringBuffer &fName, const char *base) { return CExternalFile::getFilename(fName, base); }
  1507. };
  1508. class CXMLFileExternal : public CExternalFile, implements IExternalHandler
  1509. {
  1510. public:
  1511. IMPLEMENT_IINTERFACE;
  1512. CXMLFileExternal(const char *dataPath, CBackupHandler &backupHandler) : CExternalFile("."EF_XML, dataPath, backupHandler) { }
  1513. virtual void resetAsExternal(IPropertyTree &_tree)
  1514. {
  1515. PTree &tree = *QUERYINTERFACE(&_tree, PTree);
  1516. tree.clear();
  1517. }
  1518. virtual void readValue(const char *name, MemoryBuffer &mb)
  1519. {
  1520. StringBuffer filename;
  1521. getFilename(filename, name);
  1522. OwnedIFile ifile = createIFile(filename.str());
  1523. if (!ifile->exists())
  1524. {
  1525. StringBuffer s("Missing external file ");
  1526. Owned<IException> e = MakeSDSException(SDSExcpt_MissingExternalFile, "%s", filename.str());
  1527. LOG(MCoperatorWarning, unknownJob, e, s.str());
  1528. StringBuffer str("EXTERNAL XML FILE: \"");
  1529. str.append(filename.str()).append("\" MISSING");
  1530. CPTValue v(str.length()+1, str.toCharArray(), false);
  1531. v.serialize(mb);
  1532. }
  1533. else
  1534. {
  1535. Owned<IPropertyTree> tree;
  1536. tree.setown(createPTreeFromXMLFile(filename.str()));
  1537. IPTArrayValue *v = ((PTree *)tree.get())->queryValue();
  1538. if (v)
  1539. v->serialize(mb);
  1540. else
  1541. mb.append((size32_t)0);
  1542. }
  1543. }
  1544. virtual void read(const char *name, IPropertyTree &owner, MemoryBuffer &mb, bool withValue)
  1545. {
  1546. StringBuffer filename;
  1547. getFilename(filename, name);
  1548. Owned<IPropertyTree> tree;
  1549. OwnedIFile ifile = createIFile(filename.str());
  1550. if (!ifile->exists())
  1551. {
  1552. StringBuffer s("Missing external file ");
  1553. const char *name = owner.queryName();
  1554. if (name && *name)
  1555. s.append("in property ").append(name);
  1556. Owned<IException> e = MakeSDSException(SDSExcpt_MissingExternalFile, "%s", filename.str());
  1557. LOG(MCoperatorWarning, unknownJob, e, s.str());
  1558. StringBuffer str("EXTERNAL XML FILE: \"");
  1559. str.append(filename.str()).append("\" MISSING");
  1560. tree.setown(createPTree(owner.queryName()));
  1561. if (withValue)
  1562. tree->setProp(NULL, str.toCharArray());
  1563. }
  1564. else
  1565. {
  1566. tree.setown(createPTreeFromXMLFile(filename.str()));
  1567. if (!withValue)
  1568. tree->setProp(NULL, (char *)NULL);
  1569. }
  1570. ((PTree *)tree.get())->serializeSelf(mb);
  1571. }
  1572. virtual void write(const char *name, IPropertyTree &tree)
  1573. {
  1574. StringBuffer filename;
  1575. getFilename(filename, name);
  1576. Owned<IFile> iFile = createIFile(filename.str());
  1577. Owned<IFileIO> fileIO = iFile->open(IFOcreate);
  1578. Owned<IFileIOStream> fstream = createBufferedIOStream(fileIO);
  1579. toXML(&tree, *fstream);
  1580. if (remoteBackupLocation.length())
  1581. {
  1582. StringBuffer fname(name);
  1583. StringBuffer str;
  1584. toXML(&tree, str);
  1585. unsigned l = str.length();
  1586. backupHandler.addExt(fname.append(queryExt()).str(), l, str.detach());
  1587. }
  1588. }
  1589. virtual void remove(const char *name) { CExternalFile::remove(name); }
  1590. virtual bool isValid(const char *name) { return CExternalFile::isValid(name); }
  1591. virtual StringBuffer &getName(StringBuffer &fName, const char *base) { return CExternalFile::getName(fName, base); }
  1592. virtual StringBuffer &getFilename(StringBuffer &fName, const char *base) { return CExternalFile::getFilename(fName, base); }
  1593. };
  1594. //////////////
  1595. class CBranchChange : public CInterface
  1596. {
  1597. DECL_NAMEDCOUNT;
  1598. typedef CIArrayOf<CBranchChange> CBranchChangeChildren;
  1599. public:
  1600. CBranchChange(CRemoteTreeBase &_tree) : tree(&_tree), local(PDS_None), state(PDS_None) { INIT_NAMEDCOUNT; }
  1601. void noteChange(PDState _local, PDState _state) { local = _local; state = _state; }
  1602. void addChildBranch(CBranchChange &child) { children.append(child); }
  1603. const void *queryFindParam() const { return (const void *) &tree; }
  1604. CBranchChangeChildren children;
  1605. Linked<CRemoteTreeBase> tree;
  1606. PDState local, state; // change info
  1607. };
  1608. SDSNotifyFlags translatePDState(PDState state)
  1609. {
  1610. return (SDSNotifyFlags) state; // mirrored for now.
  1611. }
  1612. void buildNotifyData(MemoryBuffer &notifyData, PDState state, CPTStack *stack, MemoryBuffer *data)
  1613. {
  1614. if (stack)
  1615. {
  1616. notifyData.append('/');
  1617. PTree *parent = &stack->item(0); // root
  1618. unsigned n = stack->ordinality();
  1619. if (n>1)
  1620. {
  1621. unsigned s = 1;
  1622. loop
  1623. {
  1624. PTree &child = stack->item(s);
  1625. const char *str = child.queryName();
  1626. notifyData.append(strlen(str), str);
  1627. if (child.queryParent())
  1628. {
  1629. char temp[12];
  1630. unsigned written = numtostr(temp, parent->findChild(&child)+1);
  1631. notifyData.append('[').append(written, temp).append(']');
  1632. }
  1633. else
  1634. notifyData.append(3, "[1]");
  1635. parent = &child;
  1636. s++;
  1637. if (s<n)
  1638. notifyData.append('/');
  1639. else
  1640. break;
  1641. }
  1642. }
  1643. notifyData.append('\0');
  1644. }
  1645. notifyData.append((int)translatePDState(state));
  1646. if (data)
  1647. {
  1648. notifyData.append(true);
  1649. notifyData.append(data->length());
  1650. notifyData.append(*data);
  1651. }
  1652. else
  1653. notifyData.append(false);
  1654. }
  1655. class CSubscriberNotifier;
  1656. typedef SimpleHashTableOf<CSubscriberNotifier, SubscriptionId> CSubscriberNotifierTable;
  1657. class CSubscriberNotifier : public CInterface
  1658. {
  1659. DECL_NAMEDCOUNT;
  1660. class CChange : public CInterface
  1661. {
  1662. public:
  1663. CChange(MemoryBuffer &_notifyData) : notifyData(_notifyData.length(), _notifyData.toByteArray()) { }
  1664. MemoryBuffer notifyData;
  1665. };
  1666. public:
  1667. CSubscriberNotifier(CSubscriberNotifierTable &_table, CSubscriberContainerBase &_subscriber, MemoryBuffer &notifyData)
  1668. : table(_table), subscriber(_subscriber)
  1669. {
  1670. INIT_NAMEDCOUNT;
  1671. change.setown(new CChange(notifyData));
  1672. subscriber.Link();
  1673. }
  1674. ~CSubscriberNotifier() { subscriber.Release(); }
  1675. void queueChange(MemoryBuffer &notifyData)
  1676. {
  1677. changeQueue.append(*new CChange(notifyData));
  1678. }
  1679. void notify()
  1680. {
  1681. loop
  1682. {
  1683. if (!subscriber.notify(change->notifyData))
  1684. {
  1685. subscriber.setUnsubscribed();
  1686. break;
  1687. }
  1688. else if (subscriber.isUnsubscribed())
  1689. break;
  1690. CHECKEDCRITICALBLOCK(nfyTableCrit, fakeCritTimeout);
  1691. if (changeQueue.ordinality())
  1692. {
  1693. change.set(&changeQueue.item(0));
  1694. changeQueue.remove(0);
  1695. }
  1696. else
  1697. {
  1698. table.removeExact(this);
  1699. break;
  1700. }
  1701. }
  1702. if (subscriber.isUnsubscribed())
  1703. {
  1704. { CHECKEDCRITICALBLOCK(nfyTableCrit, fakeCritTimeout);
  1705. table.removeExact(this);
  1706. }
  1707. querySubscriptionManager(SDS_PUBLISHER)->remove(subscriber.queryId());
  1708. }
  1709. }
  1710. const void *queryFindParam() const
  1711. {
  1712. return &(subscriber.queryId());
  1713. }
  1714. private:
  1715. Linked<CChange> change;
  1716. CIArrayOf<CChange> changeQueue;
  1717. CSubscriberContainerBase &subscriber;
  1718. MemoryAttr notifyData;
  1719. CSubscriberNotifierTable &table;
  1720. };
  1721. ////////////////
  1722. typedef MapBetween<SubscriptionId, SubscriptionId, ConnectionId, ConnectionId> SubConnMap;
  1723. class CConnectionSubscriptionManager : CInterface, implements ISubscriptionManager
  1724. {
  1725. public:
  1726. IMPLEMENT_IINTERFACE;
  1727. CConnectionSubscriptionManager()
  1728. {
  1729. }
  1730. unsigned querySubscribers()
  1731. {
  1732. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  1733. return subConnMap.count();
  1734. }
  1735. virtual void add(ISubscription *sub, SubscriptionId id);
  1736. virtual void remove(SubscriptionId id);
  1737. private:
  1738. SubConnMap subConnMap;
  1739. CheckedCriticalSection crit;
  1740. };
  1741. //////////
  1742. class CLockInfo;
  1743. typedef ThreadSafeOwningSimpleHashTableOf<CLockInfo, __int64> CLockInfoTable;
  1744. //////////
  1745. interface IUnlockCallback
  1746. {
  1747. virtual void block() = 0;
  1748. virtual void unblock() = 0;
  1749. };
  1750. //////////
  1751. typedef LinkedStringHTMapping<ISDSNotifyHandler> CSDSNotifyHandlerMapping;
  1752. typedef OwningStringSuperHashTableOf<CSDSNotifyHandlerMapping> CNotifyHandlerTable;
  1753. class CServerRemoteTree;
  1754. typedef CServerRemoteTree *CServerRemoteTreePtr;
  1755. typedef MapBetween<__int64, __int64, CServerRemoteTreePtr, CServerRemoteTreePtr> UniqueTreeMapping;
  1756. struct CStoreInfo
  1757. {
  1758. unsigned edition;
  1759. unsigned crc;
  1760. StringAttr cache;
  1761. };
  1762. interface ICoalesce : extends IInterface
  1763. {
  1764. virtual void start() = 0;
  1765. virtual void stop() = 0;
  1766. };
  1767. //////////////////////
  1768. class CNodeSubscriberContainer;
  1769. interface INodeSubscriptionManager : extends ISubscriptionManager
  1770. {
  1771. virtual void associateSubscriber(CNodeSubscriberContainer &subscriber) = 0;
  1772. virtual void removeSubscriberAssociation(SubscriptionId id) = 0;
  1773. virtual void notifyDelete(CServerRemoteTree &node) = 0;
  1774. virtual void notify(CServerRemoteTree &node, PDState state) = 0;
  1775. virtual MemoryBuffer &collectSubscribers(MemoryBuffer &out) const = 0;
  1776. };
  1777. //////////////////////
  1778. enum LockStatus { LockFailed, LockHeld, LockTimedOut, LockSucceeded };
  1779. class CCovenSDSManager : public CSDSManagerBase, implements ISDSManagerServer, implements ISubscriptionManager, implements IExceptionHandler
  1780. {
  1781. public:
  1782. IMPLEMENT_IINTERFACE;
  1783. CCovenSDSManager(ICoven &_coven, IPropertyTree &config, const char *dataPath);
  1784. ~CCovenSDSManager();
  1785. void start();
  1786. void stop();
  1787. void restart(IException * e);
  1788. void loadStore(const char *store=NULL, const bool *abort=NULL);
  1789. void saveStore(const char *store=NULL, bool currentEdition=false);
  1790. bool unlock(__int64 treeId, ConnectionId connectionId);
  1791. void unlockAll(__int64 treeId);
  1792. void changeLockMode(CServerConnection &connection, unsigned newMode, unsigned timeout);
  1793. void clearSDSLocks();
  1794. void lock(CServerRemoteTree &tree, const char *xpath, ConnectionId connectionId, SessionId sessionId, unsigned mode, unsigned timeout, IUnlockCallback &callback);
  1795. CLockInfo *queryLockInfo(__int64 id) { return lockTable.find(&id); }
  1796. CSubscriberTable &querySubscriberTable() { return subscribers; }
  1797. IExternalHandler *queryExternalHandler(const char *handler) { if (!handler) return NULL; CExternalHandlerMapping *mapping = externalHandlers.find(handler); return mapping ? &mapping->query() : NULL; }
  1798. void handleNotify(CSubscriberContainerBase &subscriber, MemoryBuffer &notifyData);
  1799. void startNotification(IPropertyTree &changeTree, CPTStack &stack, CBranchChange &changes); // subscription notification
  1800. MemoryBuffer &collectUsageStats(MemoryBuffer &out);
  1801. MemoryBuffer &collectConnections(MemoryBuffer &out);
  1802. MemoryBuffer &collectSubscribers(MemoryBuffer &out);
  1803. void blockingSave(unsigned *writeTransactions=NULL);
  1804. bool queryStopped() { return server.queryStopped(); }
  1805. void handleNodeNotify(notifications n, CServerRemoteTree &tree); // server node notification
  1806. void deleteExternal(__int64 index);
  1807. void serializeExternal(__int64 index, IPropertyTree &owner, MemoryBuffer &mb, bool withValue);
  1808. void writeExternal(CServerRemoteTree &tree, bool direct=false, __int64 existing=0);
  1809. inline unsigned queryExternalThreshold() { return externalSizeThreshold; }
  1810. CServerConnection *queryConnection(ConnectionId id);
  1811. CServerConnection *getConnection(ConnectionId id);
  1812. inline CFitArray &queryAllNodes() { return allNodes; }
  1813. unsigned __int64 getNextExternal() { return nextExternal++; }
  1814. CServerConnection *createConnectionInstance(CRemoteTreeBase *root, SessionId sessionId, unsigned mode, unsigned timeout, const char *xpath, CRemoteTreeBase *&tree, ConnectionId connectionId, StringAttr *deltaPath, Owned<IPropertyTree> &deltaChange, Owned<CBranchChange> &branchChange, unsigned &additions);
  1815. void createConnection(SessionId sessionId, unsigned mode, unsigned timeout, const char *xpath, CServerRemoteTree *&tree, ConnectionId &connectionId, bool primary, Owned<LinkingCriticalBlock> &connectCritBlock);
  1816. void disconnect(ConnectionId connectionId, bool deleteRoot=false, Owned<CLCLockBlock> *lockBlock=NULL);
  1817. void registerTree(__int64 serverId, CServerRemoteTree &tree);
  1818. void unregisterTree(__int64 uniqId);
  1819. CServerRemoteTree *queryRegisteredTree(__int64 uniqId);
  1820. CServerRemoteTree *getRegisteredTree(__int64 uniqId);
  1821. CServerRemoteTree *queryRoot();
  1822. void saveDelta(const char *path, IPropertyTree &changeTree);
  1823. CSubscriberContainerList *getSubscribers(const char *xpath, CPTStack &stack);
  1824. void getExternalValue(__int64 index, MemoryBuffer &mb);
  1825. IPropertyTree *getXPathsSortLimitMatchTree(const char *baseXPath, const char *matchXPath, const char *sortby, bool caseinsensitive, bool ascending, unsigned from, unsigned limit);
  1826. void addNodeSubscriber(ISubscription *sub, SubscriptionId id);
  1827. void removeNodeSubscriber(SubscriptionId id);
  1828. void notifyNodeDelete(CServerRemoteTree &node);
  1829. void notifyNode(CServerRemoteTree &node, PDState state);
  1830. // ISDSConnectionManager
  1831. virtual CRemoteTreeBase *get(CRemoteConnection &connection, __int64 serverId);
  1832. virtual void getChildren(CRemoteTreeBase &parent, CRemoteConnection &connection, unsigned levels);
  1833. virtual void getChildrenFor(CRTArray &childLessList, CRemoteConnection &connection, unsigned levels);
  1834. virtual void ensureLocal(CRemoteConnection &connection, CRemoteTreeBase &_parent, IPropertyTree *serverMatchTree, IPTIteratorCodes flags=iptiter_null);
  1835. virtual IPropertyTreeIterator *getElements(CRemoteConnection &connection, const char *xpath);
  1836. virtual void commit(CRemoteConnection &connection, bool *disconnectDeleteRoot);
  1837. virtual void changeMode(CRemoteConnection &connection, unsigned mode, unsigned timeout, bool suppressReload);
  1838. virtual IPropertyTree *getXPaths(__int64 serverId, const char *xpath, bool getServerIds=false);
  1839. virtual IPropertyTreeIterator *getXPathsSortLimit(const char *baseXPath, const char *matchXPath, const char *sortby, bool caseinsensitive, bool ascending, unsigned from, unsigned limit);
  1840. virtual void getExternalValueFromServerId(__int64 serverId, MemoryBuffer &mb);
  1841. virtual bool unlock(__int64 connectionId, bool closeConn, StringBuffer &connectionInfo);
  1842. // ISDSManagerServer
  1843. virtual IRemoteConnections *connect(IMultipleConnector *mConnect, SessionId id, unsigned timeout);
  1844. virtual IRemoteConnection *connect(const char *xpath, SessionId id, unsigned mode, unsigned timeout);
  1845. virtual SubscriptionId subscribe(const char *xpath, ISDSSubscription &notify, bool sub=true, bool sendValue=false);
  1846. virtual SubscriptionId subscribeExact(const char *xpath, ISDSNodeSubscription &notify, bool sendValue=false);
  1847. virtual void unsubscribe(SubscriptionId id);
  1848. virtual void unsubscribeExact(SubscriptionId id);
  1849. virtual StringBuffer &getLocks(StringBuffer &out);
  1850. virtual StringBuffer &getUsageStats(StringBuffer &out);
  1851. virtual StringBuffer &getConnections(StringBuffer &out);
  1852. virtual StringBuffer &getSubscribers(StringBuffer &out);
  1853. virtual StringBuffer &getExternalReport(StringBuffer &out);
  1854. virtual void installNotifyHandler(const char *handlerKey, ISDSNotifyHandler *handler);
  1855. virtual bool removeNotifyHandler(const char *handlerKey);
  1856. virtual IPropertyTree *lockStoreRead() const;
  1857. virtual void unlockStoreRead() const;
  1858. virtual unsigned countConnections();
  1859. virtual bool setSDSDebug(StringArray &params, StringBuffer &reply);
  1860. virtual unsigned countActiveLocks();
  1861. virtual unsigned queryExternalSizeThreshold() const { return externalSizeThreshold; }
  1862. virtual void setExternalSizeThreshold(unsigned _size) { externalSizeThreshold = _size; }
  1863. virtual bool queryRestartOnError() const { return restartOnError; }
  1864. virtual void setRestartOnError(bool _restart) { restartOnError = _restart; }
  1865. unsigned queryRequestsPending() const { return coven.probe(RANK_ALL,MPTAG_DALI_SDS_REQUEST,NULL); }
  1866. unsigned queryXactCount() const { return server.queryXactTimingStats().queryCount(); }
  1867. unsigned queryXactMeanTime() const { return server.queryXactTimingStats().queryMeanTime(); }
  1868. unsigned queryXactMaxTime() const { return server.queryXactTimingStats().queryMaxTime(); }
  1869. unsigned queryXactMinTime() const { return server.queryXactTimingStats().queryMinTime(); }
  1870. unsigned queryConnectMeanTime() const { return server.queryConnectTimingStats().queryMeanTime(); }
  1871. unsigned queryConnectMaxTime() const { return server.queryConnectTimingStats().queryMaxTime(); }
  1872. unsigned queryCommitMeanTime() const { return server.queryCommitTimingStats().queryMeanTime(); }
  1873. unsigned queryCommitMaxTime() const { return server.queryCommitTimingStats().queryMaxTime(); }
  1874. unsigned queryCommitMeanSize() const { return server.queryCommitTimingStats().queryMeanSize(); }
  1875. virtual void saveRequest();
  1876. virtual IPropertyTree &queryProperties() const;
  1877. virtual IPropertyTreeIterator *getElementsRaw(const char *xpath,INode *remotedali=NULL, unsigned timeout=MP_WAIT_FOREVER);
  1878. virtual void setConfigOpt(const char *opt, const char *value);
  1879. virtual unsigned queryCount(const char *xpath);
  1880. virtual bool updateEnvironment(IPropertyTree *newEnv, bool forceGroupUpdate, StringBuffer &response);
  1881. // ISubscriptionManager impl.
  1882. virtual void add(ISubscription *subs,SubscriptionId id);
  1883. virtual void remove(SubscriptionId id);
  1884. // IExceptionHandler
  1885. virtual bool fireException(IException *e);
  1886. public: // data
  1887. mutable ReadWriteLock dataRWLock;
  1888. CheckedCriticalSection connectCrit;
  1889. CheckedCriticalSection connDestructCrit;
  1890. CheckedCriticalSection cTableCrit;
  1891. CheckedCriticalSection sTableCrit;
  1892. CheckedCriticalSection lockCrit;
  1893. CheckedCriticalSection treeRegCrit;
  1894. Owned<Thread> unhandledThread;
  1895. unsigned writeTransactions;
  1896. bool ignoreExternals;
  1897. StringAttr dataPath;
  1898. Owned<IPropertyTree> properties;
  1899. private:
  1900. void validateBackup();
  1901. LockStatus establishLock(CLockInfo &lockInfo, __int64 treeId, ConnectionId connectionId, SessionId sessionId, unsigned mode, unsigned timeout, IUnlockCallback &lockCallback);
  1902. void _getChildren(CRemoteTreeBase &parent, CServerRemoteTree &serverParent, CRemoteConnection &connection, unsigned levels);
  1903. void matchServerTree(CClientRemoteTree *local, IPropertyTree &matchTree, bool allTail);
  1904. CSubscriberTable subscribers;
  1905. CSDSTransactionServer server;
  1906. ICoven &coven;
  1907. CServerRemoteTree *root;
  1908. CFitArray allNodes;
  1909. IPropertyTree &config;
  1910. MemoryBuffer incrementBuffer;
  1911. Owned<ICoalesce> coalesce;
  1912. unsigned __int64 nextExternal;
  1913. unsigned externalSizeThreshold;
  1914. CLockInfoTable lockTable;
  1915. CNotifyHandlerTable nodeNotifyHandlers;
  1916. Owned<IThreadPool> scanNotifyPool, notifyPool;
  1917. CExternalHandlerTable externalHandlers;
  1918. CSubscriberNotifierTable subscriberNotificationTable;
  1919. Owned<CConnectionSubscriptionManager> connectionSubscriptionManager;
  1920. Owned<INodeSubscriptionManager> nodeSubscriptionManager;
  1921. bool restartOnError, externalEnvironment;
  1922. IStoreHelper *iStoreHelper;
  1923. bool doTimeComparison;
  1924. StringBuffer blockedDelta;
  1925. CBackupHandler backupHandler;
  1926. };
  1927. ISDSManagerServer &querySDSServer()
  1928. {
  1929. assertex(queryCoven().inCoven());
  1930. return *SDSManager;
  1931. }
  1932. /////////////////
  1933. void CConnectionSubscriptionManager::add(ISubscription *sub, SubscriptionId id)
  1934. {
  1935. MemoryBuffer mb;
  1936. mb.setBuffer(sub->queryData().length(), (void *)sub->queryData().get());
  1937. ConnectionId connId;
  1938. mb.read(connId);
  1939. Owned<CServerConnection> conn = SDSManager->getConnection(connId);
  1940. if (conn)
  1941. {
  1942. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  1943. conn->addSubscriber(* new CConnectionSubscriberContainer(sub, id));
  1944. subConnMap.setValue(id, connId);
  1945. }
  1946. // else assume connection has since been disconnected.
  1947. }
  1948. void CConnectionSubscriptionManager::remove(SubscriptionId id)
  1949. {
  1950. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  1951. ConnectionId *connId = subConnMap.getValue(id);
  1952. assertex(connId);
  1953. Owned<CServerConnection> conn = SDSManager->getConnection(*connId);
  1954. if (conn)
  1955. conn->removeSubscriber(id);
  1956. subConnMap.remove(id);
  1957. }
  1958. /////////////////
  1959. CDisableFetchChangeBlock::CDisableFetchChangeBlock(CRemoteConnection &_connection) : connection(_connection)
  1960. {
  1961. stateChanges = connection.queryStateChanges();
  1962. connection.setStateChanges(false);
  1963. lazyFetch = connection.setLazyFetch(false);
  1964. }
  1965. CDisableFetchChangeBlock::~CDisableFetchChangeBlock()
  1966. {
  1967. connection.setLazyFetch(lazyFetch);
  1968. connection.setStateChanges(stateChanges);
  1969. }
  1970. CDisableLazyFetchBlock::CDisableLazyFetchBlock(CRemoteConnection &_connection) : connection(_connection)
  1971. {
  1972. lazyFetch = connection.setLazyFetch(false);
  1973. }
  1974. CDisableLazyFetchBlock::~CDisableLazyFetchBlock()
  1975. {
  1976. connection.setLazyFetch(lazyFetch);
  1977. }
  1978. /////////////////
  1979. /// CPTStack impl.
  1980. bool CPTStack::_fill(IPropertyTree &current, const char *xpath, IPropertyTree &tail)
  1981. {
  1982. const char *nextSep = '/' == *xpath ? xpath+1 : xpath;
  1983. StringBuffer head;
  1984. const char *_nextSep = queryHead(nextSep, head);
  1985. if (!_nextSep)
  1986. {
  1987. Owned<IPropertyTreeIterator> iter = current.getElements(nextSep);
  1988. ForEach (*iter)
  1989. {
  1990. if (NotFound != iter->query().queryChildIndex(&tail))
  1991. {
  1992. append(*LINK((PTree *)&iter->query()));
  1993. append(*LINK((PTree *)&current));
  1994. return true;
  1995. }
  1996. }
  1997. }
  1998. else
  1999. {
  2000. Owned<IPropertyTreeIterator> iter = current.getElements(head.str());
  2001. ForEach (*iter)
  2002. {
  2003. if (&tail==&iter->query()) // Afaics, this should not be possible (so this test/block should really be removed)
  2004. {
  2005. ERRLOG("_fill() - tail (%s) found at intermediate level: %s", tail.queryName(), head.str());
  2006. append(*LINK((PTree *)&iter->query()));
  2007. append(*LINK((PTree *)&current));
  2008. return true;
  2009. }
  2010. else if (_fill(iter->query(), _nextSep, tail))
  2011. {
  2012. append(*LINK((PTree *)&current));
  2013. return true;
  2014. }
  2015. }
  2016. }
  2017. return false;
  2018. }
  2019. bool CPTStack::fill(IPropertyTree &root, const char *xpath, IPropertyTree &tail)
  2020. {
  2021. kill();
  2022. bool res = _fill(root, xpath, tail);
  2023. unsigned elems = ordinality();
  2024. if (elems<2) return res;
  2025. elems--;
  2026. unsigned to = 0;
  2027. while (to < elems)
  2028. swap(elems--, to++);
  2029. return res;
  2030. }
  2031. /////////////////////
  2032. StringBuffer &CPTStack::getAbsolutePath(StringBuffer &str)
  2033. {
  2034. str.append('/');
  2035. IPropertyTree *parent = &item(0);
  2036. if (ordinality()>1)
  2037. {
  2038. unsigned i = 1;
  2039. loop
  2040. {
  2041. IPropertyTree *child = &item(i);
  2042. str.append(child->queryName());
  2043. str.append('[');
  2044. aindex_t pos = parent->queryChildIndex(child);
  2045. #ifdef DEBUG_HPCC_11202
  2046. if (NotFound == pos)
  2047. {
  2048. ERRLOG("Invalid CPTStack detected");
  2049. ForEachItemIn(i, *this)
  2050. {
  2051. PTree &tree = item(i);
  2052. DBGLOG("PTree path item %d = %s", i, tree.queryName());
  2053. }
  2054. PrintStackReport();
  2055. }
  2056. #endif
  2057. str.append(pos+1);
  2058. str.append(']');
  2059. if (++i >= ordinality())
  2060. break;
  2061. str.append('/');
  2062. parent = child;
  2063. }
  2064. }
  2065. return str;
  2066. }
  2067. /////////////////////
  2068. CServerConnection::~CServerConnection()
  2069. {
  2070. Owned<LinkingCriticalBlock> checkedCritBlock;
  2071. if (!RTM_MODE(mode, RTM_INTERNAL))
  2072. {
  2073. ForEachItemIn(s, subscriptions)
  2074. SDSManager->remove(subscriptions.item(s).queryId());
  2075. checkedCritBlock.setown(new LinkingCriticalBlock(SDSManager->connDestructCrit, __FILE__, __LINE__));
  2076. }
  2077. ptreePath.kill();
  2078. root.clear();
  2079. }
  2080. void CServerConnection::aborted(SessionId id)
  2081. {
  2082. LOG(MCdebugInfo(100), unknownJob, "CServerConnection: connection aborted (%"I64F"x) sessId=%"I64F"x",connectionId, id);
  2083. #if 0 // JCSMORE - think this is ok, but concerned about deadlock, change later.
  2084. Owned<CLCLockBlock> lockBlock = new CLCWriteLockBlock(((CCovenSDSManager &)manager).dataRWLock, readWriteTimeout, __FILE__, __LINE__);
  2085. SDSManager->disconnect(connectionId, false);
  2086. #else
  2087. Owned<CLCLockBlock> lockBlock = new CLCReadLockBlock(((CCovenSDSManager &)manager).dataRWLock, readWriteTimeout, __FILE__, __LINE__);
  2088. SDSManager->disconnect(connectionId, false, &lockBlock);
  2089. #endif
  2090. }
  2091. ///////////////////
  2092. enum IncCmd { None, PropDelete, AttrDelete, PropChange, PropNew, PropExisting, ChildEndMarker, PropRename, AttrChange };
  2093. CRemoteTreeBase::CRemoteTreeBase(const char *name, IPTArrayValue *value, ChildMap *children, CPState _state)
  2094. : PTree(name, ipt_none, value, children), state(_state)
  2095. {
  2096. serverId = 0;
  2097. }
  2098. CRemoteTreeBase::CRemoteTreeBase(MemoryBuffer &mb, CPState _state)
  2099. : state(_state)
  2100. {
  2101. serverId = 0;
  2102. }
  2103. void CRemoteTreeBase::reset(unsigned _state, bool sub)
  2104. {
  2105. state = _state;
  2106. serverId = 0;
  2107. if (sub)
  2108. {
  2109. IPropertyTreeIterator *iter = getElements("*");
  2110. ForEach(*iter)
  2111. {
  2112. CRemoteTreeBase &child = (CRemoteTreeBase &)iter->query();
  2113. child.reset(state, sub);
  2114. }
  2115. iter->Release();
  2116. }
  2117. }
  2118. void CRemoteTreeBase::deserializeRT(MemoryBuffer &src)
  2119. {
  2120. deserializeSelfRT(src);
  2121. deserializeChildrenRT(src);
  2122. }
  2123. void CRemoteTreeBase::deserializeChildrenRT(MemoryBuffer &src)
  2124. {
  2125. StringAttr eName;
  2126. loop
  2127. {
  2128. size32_t pos = src.getPos();
  2129. src.read(eName);
  2130. if (!eName.length())
  2131. break;
  2132. src.reset(pos); // reset to re-read tree name
  2133. CRemoteTreeBase *child = (CRemoteTreeBase *) create(NULL);
  2134. child->deserializeRT(src);
  2135. addPropTree(eName, child);
  2136. }
  2137. }
  2138. void CRemoteTreeBase::deserializeSelfRT(MemoryBuffer &mb)
  2139. {
  2140. deserializeSelf(mb);
  2141. assertex(!isnocase());
  2142. __int64 _serverId;
  2143. mb.read(_serverId);
  2144. if (_serverId)
  2145. setServerId(_serverId); // ignore deserializing 0 serverId (indicated new)
  2146. }
  2147. IPropertyTree *CRemoteTreeBase::collateData()
  2148. {
  2149. ChangeInfo *changes = queryChanges();
  2150. struct ChangeTree
  2151. {
  2152. ChangeTree(IPropertyTree *donor=NULL) { ptree = LINK(donor); }
  2153. ~ChangeTree() { ::Release(ptree); }
  2154. inline void createTree() { assertex(!ptree); ptree = createPTree(RESERVED_CHANGE_NODE); }
  2155. inline IPropertyTree *queryTree() { return ptree; }
  2156. inline IPropertyTree *getTree() { return LINK(ptree); }
  2157. inline IPropertyTree *queryCreateTree()
  2158. {
  2159. if (!ptree)
  2160. ptree = createPTree(RESERVED_CHANGE_NODE);
  2161. return ptree;
  2162. }
  2163. private:
  2164. StringAttr name;
  2165. IPropertyTree *ptree;
  2166. } ct(changes?changes->tree:NULL);
  2167. if (changes) changes->tree.clear();
  2168. if (0 == serverId)
  2169. {
  2170. if (ct.queryTree())
  2171. {
  2172. ct.queryTree()->removeProp(ATTRDELETE_TAG);
  2173. ct.queryTree()->removeProp(ATTRCHANGE_TAG);
  2174. ct.queryTree()->removeProp(DELETE_TAG);
  2175. }
  2176. else
  2177. ct.createTree();
  2178. Owned<IAttributeIterator> iter = getAttributes();
  2179. if (iter->count())
  2180. {
  2181. IPropertyTree *t = createPTree();
  2182. ForEach(*iter)
  2183. t->setProp(iter->queryName(), queryProp(iter->queryName()));
  2184. ct.queryTree()->addPropTree(ATTRCHANGE_TAG, t);
  2185. }
  2186. ct.queryTree()->setPropBool("@new", true);
  2187. }
  2188. else
  2189. {
  2190. if (ct.queryTree())
  2191. {
  2192. Linked<IPropertyTree> ac = ct.queryTree()->queryPropTree(ATTRCHANGE_TAG);
  2193. if (ac)
  2194. {
  2195. ct.queryTree()->removeTree(ac);
  2196. Owned<IAttributeIterator> iter = ac->getAttributes();
  2197. IPropertyTree *t = createPTree();
  2198. ForEach(*iter)
  2199. t->setProp(iter->queryName(), queryProp(iter->queryName()));
  2200. ct.queryTree()->addPropTree(ATTRCHANGE_TAG, t);
  2201. }
  2202. }
  2203. }
  2204. if ((CPS_Changed & state) || (0 == serverId && queryValue()))
  2205. {
  2206. ct.queryCreateTree()->setPropBool("@localValue", true);
  2207. if (queryValue())
  2208. {
  2209. bool binary=isBinary(NULL);
  2210. ((PTree *)ct.queryTree())->setValue(new CPTValue(queryValue()->queryValueRawSize(), queryValue()->queryValueRaw(), binary, true, isCompressed(NULL)), binary);
  2211. }
  2212. else
  2213. ((PTree *)ct.queryTree())->setValue(new CPTValue(0, NULL, false, true, false), false);
  2214. }
  2215. else if (CPS_PropAppend & state)
  2216. {
  2217. assertex(serverId);
  2218. IPropertyTree *pa = ct.queryTree()->queryPropTree(APPEND_TAG);
  2219. assertex(pa);
  2220. unsigned from = pa->getPropInt(NULL);
  2221. ct.queryTree()->removeTree(pa);
  2222. ct.queryCreateTree()->setPropBool("@appendValue", true);
  2223. MemoryBuffer mb;
  2224. bool binary=isBinary(NULL);
  2225. queryValue()->getValue(mb, true);
  2226. ((PTree *)ct.queryTree())->setValue(new CPTValue(mb.length()-from, mb.toByteArray()+from, binary), binary);
  2227. }
  2228. Owned<IPropertyTree> childTree;
  2229. Owned<IPropertyTreeIterator> _iter = getElements("*");
  2230. IPropertyTreeIterator *iter = _iter;
  2231. if (iter->first())
  2232. {
  2233. while (iter->isValid())
  2234. {
  2235. CRemoteTreeBase *child = (CRemoteTreeBase *) &iter->query();
  2236. childTree.setown(child->collateData());
  2237. if (childTree)
  2238. {
  2239. if (0 == child->queryServerId())
  2240. {
  2241. if (CPS_InsPos & child->queryState())
  2242. {
  2243. int pos = findChild(child);
  2244. assertex(NotFound != pos);
  2245. childTree->setPropInt("@pos", pos+1);
  2246. }
  2247. }
  2248. else
  2249. {
  2250. int pos = findChild(child);
  2251. assertex(NotFound != pos);
  2252. childTree->setPropInt("@pos", pos+1);
  2253. childTree->setPropInt64("@id", child->queryServerId());
  2254. }
  2255. }
  2256. if (childTree)
  2257. ct.queryCreateTree()->addPropTree(RESERVED_CHANGE_NODE, childTree.getClear());
  2258. iter->next();
  2259. }
  2260. }
  2261. if (ct.queryTree())
  2262. ct.queryTree()->setProp("@name", queryName());
  2263. return ct.getTree();
  2264. }
  2265. void CRemoteTreeBase::clearCommitChanges(MemoryBuffer *mb)
  2266. {
  2267. class Cop : implements IIteratorOperator
  2268. {
  2269. public:
  2270. Cop(MemoryBuffer *_mb=NULL) : mb(_mb) { }
  2271. virtual bool applyTop(IPropertyTree &_tree)
  2272. {
  2273. CRemoteTreeBase &tree = (CRemoteTreeBase &) _tree;
  2274. tree.clearChanges();
  2275. if (tree.queryState())
  2276. tree.setState(0);
  2277. return true;
  2278. }
  2279. virtual bool applyChild(IPropertyTree &parent, IPropertyTree &child, bool &levelBreak)
  2280. {
  2281. CRemoteTreeBase &tree = (CRemoteTreeBase &) child;
  2282. if (mb && 0==tree.queryServerId())
  2283. {
  2284. __int64 serverId;
  2285. mb->read(serverId);
  2286. tree.setServerId(serverId);
  2287. }
  2288. return true;
  2289. }
  2290. private:
  2291. MemoryBuffer *mb;
  2292. } op(mb);
  2293. CIterationOperation iop(op);
  2294. iop.iterate(*this);
  2295. }
  2296. bool CRemoteTreeBase::queryStateChanges() const
  2297. {
  2298. return false;
  2299. }
  2300. void CRemoteTreeBase::setServerId(__int64 _serverId)
  2301. {
  2302. serverId = _serverId;
  2303. }
  2304. void CRemoteTreeBase::clearChildren()
  2305. {
  2306. if (children)
  2307. {
  2308. children->Release();
  2309. children=NULL;
  2310. }
  2311. }
  2312. CRemoteTreeBase *CRemoteTreeBase::createChild(int pos, const char *childName)
  2313. {
  2314. CRemoteTreeBase *child = (CRemoteTreeBase *) create(NULL);
  2315. if (-1 == pos)
  2316. child = (CRemoteTreeBase *) addPropTree(childName, child);
  2317. else
  2318. {
  2319. unsigned e = 0;
  2320. if (children)
  2321. {
  2322. PTree *match = (PTree *) children->query(childName);
  2323. if (match)
  2324. {
  2325. IPTArrayValue *value = match->queryValue();
  2326. e = value && value->isArray()?value->elements() : 1;
  2327. }
  2328. }
  2329. if ((unsigned)pos == e)
  2330. child = (CRemoteTreeBase *) addPropTree(childName, child);
  2331. else
  2332. {
  2333. StringBuffer childPos(childName);
  2334. childPos.append("[").append(pos+1).append("]");
  2335. child = (CRemoteTreeBase *) addPropTree(childPos.str(), child);
  2336. }
  2337. }
  2338. return child;
  2339. }
  2340. ///////////
  2341. static CheckedCriticalSection suppressedOrphanUnlockCrit; // to temporarily suppress unlockall
  2342. static bool suppressedOrphanUnlock=false;
  2343. #ifdef __64BIT__
  2344. #pragma pack(push,1) // 64bit pack CServerRemoteTree's (could do for 32bit also)
  2345. #endif
  2346. #if defined(new)
  2347. #define __old_new new
  2348. #undef new
  2349. #endif
  2350. class CServerRemoteTree : public CRemoteTreeBase
  2351. {
  2352. DECL_NAMEDCOUNT;
  2353. class COrphanHandler : public ChildMap
  2354. {
  2355. public:
  2356. COrphanHandler() : ChildMap() { }
  2357. ~COrphanHandler() { kill(); }
  2358. static void setOrphans(CServerRemoteTree &tree, bool tf)
  2359. {
  2360. if (tf)
  2361. IptFlagSet(tree.flags, ipt_ext5);
  2362. else
  2363. IptFlagClr(tree.flags, ipt_ext5);
  2364. IPTArrayValue *v = tree.queryValue();
  2365. if (v && v->isArray())
  2366. {
  2367. unsigned e;
  2368. for(e=0; e<v->elements(); e++)
  2369. setOrphans(*(CServerRemoteTree *)v->queryElement(e), tf);
  2370. }
  2371. if (tree.queryChildren())
  2372. {
  2373. if (SDSManager->queryStopped()) return;
  2374. SuperHashIteratorOf<IPropertyTree> iter(*tree.queryChildren());
  2375. ForEach (iter)
  2376. setOrphans((CServerRemoteTree &)iter.query(), tf);
  2377. }
  2378. }
  2379. virtual void onAdd(void *e) // ensure memory of constructed multi value elements are no longer orphaned.
  2380. {
  2381. ChildMap::onAdd(e);
  2382. CServerRemoteTree &tree = *((CServerRemoteTree *)(IPropertyTree *)e);
  2383. setOrphans(tree, false);
  2384. }
  2385. virtual void onRemove(void *e)
  2386. {
  2387. CServerRemoteTree &tree = *((CServerRemoteTree *)(IPropertyTree *)e);
  2388. bool dounlock;
  2389. {
  2390. CHECKEDCRITICALBLOCK(suppressedOrphanUnlockCrit, fakeCritTimeout);
  2391. dounlock = !suppressedOrphanUnlock;
  2392. }
  2393. if (dounlock) // element is moving, don't orphan or unlock
  2394. {
  2395. setOrphans(tree, true);
  2396. SDSManager->unlockAll(tree.queryServerId());
  2397. }
  2398. ChildMap::onRemove(e);
  2399. }
  2400. virtual bool replace(const char *key, IPropertyTree *tree) // provides different semantics, used if element being replaced is not to be treated as deleted.
  2401. {
  2402. CHECKEDCRITICALBLOCK(suppressedOrphanUnlockCrit, fakeCritTimeout);
  2403. BoolSetBlock bblock(suppressedOrphanUnlock);
  2404. bool ret = ChildMap::replace(key, tree);
  2405. return ret;
  2406. }
  2407. virtual bool set(const char *key, IPropertyTree *tree)
  2408. {
  2409. // NB: be careful if replacing, to remove element first, because may self-destruct if lastref in middle of SuperHashTable::replace, leaving tablecount wrong.
  2410. unsigned vs = getHashFromElement(tree);
  2411. const void *fp = getFindParam(tree);
  2412. IPropertyTree *et = (IPropertyTree *)SuperHashTable::find(vs, fp);
  2413. if (et)
  2414. removeExact(et);
  2415. return ChildMap::set(key, tree);
  2416. }
  2417. };
  2418. public:
  2419. #ifdef _POOLED_SERVER_REMOTE_TREE
  2420. void * operator new(memsize_t sz)
  2421. {
  2422. #ifdef _DEBUG
  2423. assertex(sz==sizeof(CServerRemoteTree));
  2424. #endif
  2425. return CServerRemoteTree_Allocator->alloc();
  2426. }
  2427. void operator delete( void * p )
  2428. {
  2429. CServerRemoteTree_Allocator->dealloc(p);
  2430. }
  2431. #endif
  2432. CServerRemoteTree(MemoryBuffer &mb) : CRemoteTreeBase(mb) { init(); }
  2433. CServerRemoteTree(const char *name=NULL, IPTArrayValue *value=NULL, ChildMap *children=NULL)
  2434. : CRemoteTreeBase(name, value, children) { init(); }
  2435. ~CServerRemoteTree()
  2436. {
  2437. if (hasProp(NOTIFY_ATTR))
  2438. SDSManager->handleNodeNotify(notify_delete, *this);
  2439. __int64 index = getPropInt64(EXT_ATTR);
  2440. if (index)
  2441. {
  2442. try { SDSManager->deleteExternal(index); }
  2443. catch (IException *e)
  2444. {
  2445. LOG(MCoperatorWarning, unknownJob, e, StringBuffer("Deleting external reference for ").append(queryName()).str());
  2446. e->Release();
  2447. }
  2448. }
  2449. if (SDSManager->queryStopped()) return; // don't bother building up free list that will never be used hence (could get v. big/slow)
  2450. if (isSubscribed())
  2451. SDSManager->notifyNodeDelete(*this);
  2452. CHECKEDCRITICALBLOCK(SDSManager->treeRegCrit, fakeCritTimeout);
  2453. SDSManager->queryAllNodes().freeElem(serverId);
  2454. }
  2455. virtual bool isEquivalent(IPropertyTree *tree) { return (NULL != QUERYINTERFACE(tree, CServerRemoteTree)); }
  2456. PDState processData(CServerConnection &connection, IPropertyTree &changeTree, MemoryBuffer &newIds);
  2457. void init()
  2458. {
  2459. INIT_NAMEDCOUNT;
  2460. assertex(!isnocase());
  2461. CHECKEDCRITICALBLOCK(SDSManager->treeRegCrit, fakeCritTimeout);
  2462. SDSManager->queryAllNodes().addElem(this);
  2463. }
  2464. virtual bool isOrphaned() const { return IptFlagTst(flags, ipt_ext5); }
  2465. virtual void setServerId(__int64 _serverId)
  2466. {
  2467. if (serverId && serverId != _serverId)
  2468. WARNLOG("Unexpected - client server id mismatch in %s, id=%"I64F"x", queryName(), _serverId);
  2469. CRemoteTreeBase::setServerId(_serverId);
  2470. }
  2471. virtual CSubscriberContainerList *getSubscribers(const char *xpath, CPTStack &stack)
  2472. {
  2473. return SDSManager->getSubscribers(xpath, stack);
  2474. }
  2475. IPropertyTree *create(const char *name=NULL, IPTArrayValue *value=NULL, ChildMap *children=NULL, bool existing=false)
  2476. {
  2477. return new CServerRemoteTree(name, value, children);
  2478. }
  2479. IPropertyTree *create(MemoryBuffer &mb)
  2480. {
  2481. return new CServerRemoteTree(mb);
  2482. }
  2483. virtual void createChildMap() { children = new COrphanHandler(); }
  2484. inline bool testExternalCandidate()
  2485. {
  2486. // maybe be other cases.
  2487. return (value && value->queryValueSize() >= SDSManager->queryExternalThreshold());
  2488. }
  2489. void serializeCutOffRT(MemoryBuffer &tgt, int cutoff=-1, int depth=0, bool extValues=true)
  2490. {
  2491. serializeSelfRT(tgt, extValues);
  2492. serializeCutOffChildrenRT(tgt, cutoff, depth, extValues);
  2493. }
  2494. void serializeCutOffChildrenRT(MemoryBuffer &tgt, int cutoff=-1, int depth=0, bool extValues=true)
  2495. {
  2496. #ifndef ALWAYSLAZY_NOTUSED
  2497. if (cutoff < 0)
  2498. {
  2499. if (FETCH_ENTIRE_COND == cutoff && getPropBool("@alwaysLazy"))
  2500. {
  2501. tgt.append("");
  2502. return; // i.e. truncate here, this already serialized, lazy fetch children
  2503. }
  2504. }
  2505. else if (getPropBool("@fetchEntire"))
  2506. cutoff = FETCH_ENTIRE_COND;
  2507. #else
  2508. if (cutoff >= 0 && getPropBool("@fetchEntire"))
  2509. cutoff = FETCH_ENTIRE_COND; // NB: can change all _COND references to FETCH_ENTIRE if not using alwaysFetch anymore
  2510. #endif
  2511. if (cutoff < 0 || depth<cutoff)
  2512. {
  2513. IPropertyTreeIterator *iter = getElements("*");
  2514. iter->first();
  2515. while (iter->isValid())
  2516. {
  2517. IPropertyTree *_child = &iter->query();
  2518. CServerRemoteTree *child = QUERYINTERFACE(_child, CServerRemoteTree); assertex(child);
  2519. child->serializeCutOffRT(tgt, cutoff, depth+1, extValues);
  2520. iter->next();
  2521. }
  2522. iter->Release();
  2523. }
  2524. tgt.append(""); // element terminator. i.e. blank child name.
  2525. }
  2526. void serializeSelfRT(MemoryBuffer &mb, bool extValues)
  2527. {
  2528. __int64 index = getPropInt64(EXT_ATTR);
  2529. if (index)
  2530. {
  2531. SDSManager->serializeExternal(index, *this, mb, extValues);
  2532. mb.append(serverId);
  2533. }
  2534. else
  2535. {
  2536. serializeSelf(mb);
  2537. mb.append(serverId);
  2538. }
  2539. byte STIInfo = 0;
  2540. if (children && children->count())
  2541. STIInfo += STI_HaveChildren;
  2542. if (index)
  2543. STIInfo += STI_External;
  2544. mb.append(STIInfo);
  2545. }
  2546. virtual void deserializeSelfRT(MemoryBuffer &src)
  2547. {
  2548. CRemoteTreeBase::deserializeSelfRT(src);
  2549. assertex(!isnocase());
  2550. byte STIInfo;
  2551. src.read(STIInfo);
  2552. }
  2553. virtual void removingElement(IPropertyTree *tree, unsigned pos)
  2554. {
  2555. COrphanHandler::setOrphans(*(CServerRemoteTree *)tree, true);
  2556. CRemoteTreeBase::removingElement(tree, pos);
  2557. }
  2558. virtual bool isCompressed(const char *xpath=NULL) const
  2559. {
  2560. if (isAttribute(xpath)) return false;
  2561. if (CRemoteTreeBase::isCompressed(xpath)) return true;
  2562. if (SDSManager->ignoreExternals) return false;
  2563. CServerRemoteTree *child = (CServerRemoteTree *)queryPropTree(xpath);
  2564. return child->hasProp(EXT_ATTR);
  2565. }
  2566. bool getProp(const char *xpath, StringBuffer &ret) const
  2567. {
  2568. if (xpath)
  2569. return CRemoteTreeBase::getProp(xpath, ret);
  2570. if (SDSManager->ignoreExternals)
  2571. return CRemoteTreeBase::getProp(xpath, ret);
  2572. CHECKEDCRITICALBLOCK(extCrit, fakeCritTimeout);
  2573. __int64 index = getPropInt64(EXT_ATTR);
  2574. if (!index)
  2575. return CRemoteTreeBase::getProp(xpath, ret);
  2576. MemoryBuffer mbv, mb;
  2577. SDSManager->getExternalValue(index, mbv);
  2578. CPTValue v(mbv);
  2579. v.getValue(mb, true);
  2580. unsigned len = mb.length();
  2581. char *mem = (char *)mb.detach();
  2582. mem[len-1] = '\0';
  2583. ret.setBuffer(len, mem, len-1);
  2584. return true;
  2585. }
  2586. void setSubscribed(bool tf)
  2587. {
  2588. if (tf)
  2589. IptFlagSet(flags, ipt_ext4);
  2590. else
  2591. IptFlagClr(flags, ipt_ext4);
  2592. }
  2593. inline bool isSubscribed() const
  2594. {
  2595. return IptFlagTst(flags, ipt_ext4);
  2596. }
  2597. private:
  2598. PDState processData(IPropertyTree &changeTree, Owned<CBranchChange> &parentBranchChange, MemoryBuffer &newIds);
  2599. PDState checkChange(IPropertyTree &tree, CBranchChange *parentBranchChange=NULL);
  2600. friend class COrphanHandler;
  2601. };
  2602. class CNodeSubscriberContainer : public CSubscriberContainerBase
  2603. {
  2604. StringAttr xpath;
  2605. bool sendValue;
  2606. ICopyArrayOf<CServerRemoteTree> nodes; // never linked, node must signal the unsubscription and removal of subscriber and these references
  2607. public:
  2608. CNodeSubscriberContainer(ISubscription *subscriber, SubscriptionId id, bool _sendValue, const char *_xpath)
  2609. : CSubscriberContainerBase(subscriber, id), sendValue(_sendValue), xpath(_xpath)
  2610. {
  2611. }
  2612. bool querySendValue() const { return sendValue; }
  2613. void add(CServerRemoteTree &node) { nodes.append(node); }
  2614. ICopyArrayOf<CServerRemoteTree> &queryNodes() { return nodes; }
  2615. MemoryBuffer &getInfo(MemoryBuffer &out) const
  2616. {
  2617. out.append(id).append(xpath).append(nodes.ordinality());
  2618. return out;
  2619. }
  2620. };
  2621. class CNodeSubscriptionManager : public CSimpleInterface, implements INodeSubscriptionManager
  2622. {
  2623. public:
  2624. class CNodeSubscriberContainerList : public CSimpleInterfaceOf<IInterface>
  2625. {
  2626. CServerRemoteTree *node;
  2627. ICopyArrayOf<CNodeSubscriberContainer> subscribers;
  2628. public:
  2629. CNodeSubscriberContainerList(CServerRemoteTree *_node) : node(_node)
  2630. {
  2631. }
  2632. const void *queryFindParam() const { return &node; }
  2633. ICopyArrayOf<CNodeSubscriberContainer> &querySubscribers() { return subscribers; }
  2634. void add(CNodeSubscriberContainer &subscriber) { subscribers.append(subscriber); }
  2635. };
  2636. CCovenSDSManager &owner;
  2637. OwningSimpleHashTableOf<CNodeSubscriberContainer, SubscriptionId> subscribersById;
  2638. OwningSimpleHashTableOf<CNodeSubscriberContainerList, CServerRemoteTree *> subscriberListByNode;
  2639. CriticalSection lock;
  2640. void _notify(CServerRemoteTree *node, PDState state)
  2641. {
  2642. MemoryBuffer sendValueNotifyData;
  2643. CNodeSubscriberContainerList *subscriberList = subscriberListByNode.find(node);
  2644. assertex(subscriberList);
  2645. ICopyArrayOf<CNodeSubscriberContainer> &subscribers = subscriberList->querySubscribers();
  2646. int lastSendValue = -1;
  2647. ForEachItemIn(s, subscribers)
  2648. {
  2649. CNodeSubscriberContainer &subscriber = subscribers.item(s);
  2650. if (subscriber.querySendValue())
  2651. {
  2652. if (1 != lastSendValue) // overkill unless many subscribers to same node
  2653. {
  2654. MemoryBuffer mb;
  2655. node->getPropBin(NULL, mb);
  2656. buildNotifyData(sendValueNotifyData.clear(), state, NULL, &mb);
  2657. lastSendValue = 1;
  2658. }
  2659. SDSManager->handleNotify(subscriber, sendValueNotifyData);
  2660. }
  2661. else
  2662. {
  2663. if (0 != lastSendValue) // overkill unless many subscribers to same node
  2664. {
  2665. buildNotifyData(sendValueNotifyData.clear(), state, NULL, NULL);
  2666. lastSendValue = 0;
  2667. }
  2668. SDSManager->handleNotify(subscriber, sendValueNotifyData);
  2669. }
  2670. }
  2671. }
  2672. void _removeNode(CServerRemoteTree *node, SubscriptionId id)
  2673. {
  2674. CNodeSubscriberContainerList *subscriberList = subscriberListByNode.find(node);
  2675. assertex(subscriberList);
  2676. ICopyArrayOf<CNodeSubscriberContainer> &subscribers = subscriberList->querySubscribers();
  2677. ForEachItemInRev(s, subscribers)
  2678. {
  2679. CNodeSubscriberContainer &subscriber = subscribers.item(s);
  2680. if (0 == id) // remove all associated subscribers (node being deleted)
  2681. {
  2682. ICopyArrayOf<CServerRemoteTree> &nodes = subscriber.queryNodes();
  2683. verifyex(nodes.zap(*node));
  2684. SubscriptionId sid = subscriber.queryId();
  2685. subscribers.remove(s);
  2686. if (0 == nodes.ordinality()) // IOW this was the last node this subscriber was associated with
  2687. subscribersById.remove(&sid);
  2688. }
  2689. else if (subscriber.queryId() == id)
  2690. subscribers.remove(s);
  2691. }
  2692. if (0 == subscribers.ordinality())
  2693. {
  2694. node->setSubscribed(false);
  2695. subscriberListByNode.removeExact(subscriberList);
  2696. }
  2697. }
  2698. public:
  2699. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  2700. CNodeSubscriptionManager(CCovenSDSManager &_owner) : owner(_owner) { }
  2701. void notify(CServerRemoteTree &node, PDState state)
  2702. {
  2703. // shouldn't be here, unless node is in subscribers table
  2704. CriticalBlock b(lock);
  2705. _notify(&node, state);
  2706. }
  2707. void notifyDelete(CServerRemoteTree &node)
  2708. {
  2709. // shouldn't be here, unless node is in subscribers table
  2710. CriticalBlock b(lock);
  2711. _notify(&node, PDS_Deleted);
  2712. _removeNode(&node, 0);
  2713. }
  2714. // ISubscriptionManager impl.
  2715. virtual void add(ISubscription *sub, SubscriptionId id)
  2716. {
  2717. CriticalBlock b(lock);
  2718. /* calls back out to owner to scan for match, so that SDSManager can protect root/treereg.
  2719. * It calls back (associateSubscriber) in this class to add subscribers based on matches.
  2720. */
  2721. owner.addNodeSubscriber(sub, id);
  2722. }
  2723. virtual void remove(SubscriptionId id)
  2724. {
  2725. CriticalBlock b(lock);
  2726. /* calls back out to owner to protect root/treereg.
  2727. * It calls back into removeSubscriberAssociation.
  2728. */
  2729. owner.removeNodeSubscriber(id);
  2730. }
  2731. virtual void removeSubscriberAssociation(SubscriptionId id) // Always called back from within remove() above.
  2732. {
  2733. CNodeSubscriberContainer *subscriber = subscribersById.find(id);
  2734. if (!subscriber)
  2735. return; // may not exist if removed already
  2736. ICopyArrayOf<CServerRemoteTree> &nodes = subscriber->queryNodes();
  2737. ForEachItemIn(n, nodes)
  2738. {
  2739. CServerRemoteTree &node = nodes.item(n);
  2740. _removeNode(&node, id);
  2741. }
  2742. verifyex(subscribersById.removeExact(subscriber));
  2743. }
  2744. void associateSubscriber(CNodeSubscriberContainer &subscriber) // Always called back from within add() above.
  2745. {
  2746. /* caller has established there are matches and added them to 'subscriber'
  2747. * add to HT's
  2748. */
  2749. verifyex(subscribersById.add(*LINK(&subscriber)));
  2750. ICopyArrayOf<CServerRemoteTree> &nodes = subscriber.queryNodes();
  2751. ForEachItemIn(n, nodes)
  2752. {
  2753. CServerRemoteTree *node = &nodes.item(n);
  2754. CNodeSubscriberContainerList *subscriberList = subscriberListByNode.find(node);
  2755. if (!subscriberList)
  2756. {
  2757. subscriberList = new CNodeSubscriberContainerList(node);
  2758. verifyex(subscriberListByNode.add(* subscriberList));
  2759. }
  2760. subscriberList->add(subscriber);
  2761. }
  2762. }
  2763. MemoryBuffer &collectSubscribers(MemoryBuffer &out) const
  2764. {
  2765. out.append(subscribersById.count());
  2766. SuperHashIteratorOf<CNodeSubscriberContainer> sdsNodeIter(subscribersById);
  2767. ForEach(sdsNodeIter)
  2768. sdsNodeIter.query().getInfo(out);
  2769. return out;
  2770. }
  2771. };
  2772. #if defined(_WIN32) && defined(__old_new)
  2773. #define new __old_new
  2774. #endif
  2775. #ifdef __64BIT__
  2776. #pragma pack(pop) // 64bit pack CServerRemoteTree's (could do for 32bit also)
  2777. #endif
  2778. void populateWithServerIds(IPropertyTree *matchParent, CRemoteTreeBase *parent)
  2779. {
  2780. matchParent->setPropInt64("@serverId", parent->queryServerId());
  2781. Owned<IPropertyTreeIterator> iter = matchParent->getElements("*");
  2782. ForEach (*iter)
  2783. {
  2784. IPropertyTree *matchChild = &iter->query();
  2785. StringBuffer path(matchChild->queryName());
  2786. path.append("[").append(matchChild->queryProp("@pos")).append("]");
  2787. CRemoteTreeBase *child = (CRemoteTreeBase *)parent->queryPropTree(path.str());
  2788. assertex(child);
  2789. populateWithServerIds(matchChild, child);
  2790. }
  2791. }
  2792. IPropertyTree *createServerTree(const char *tag=NULL)
  2793. {
  2794. return new CServerRemoteTree(tag);
  2795. }
  2796. // JCSMORE - these should be error conditions, for consistency with previous release not so for now.
  2797. #define consistencyCheck(TEXT, IDTREE, LOCALTREE, PATH, PARENTNAME, ID) \
  2798. if (!IDTREE) \
  2799. { \
  2800. StringBuffer s(TEXT": Consistency check failure, id'd tree not found: "); \
  2801. s.append(PATH).append(", id=").append(ID); \
  2802. LOG(MCoperatorWarning, unknownJob, s.str()); \
  2803. } \
  2804. else if (!LOCALTREE) \
  2805. { \
  2806. StringBuffer s(TEXT": Consistency check failure, positional property specification: "); \
  2807. s.append(PATH).append(", in client update not found in parent tree: ").append(PARENTNAME); \
  2808. LOG(MCoperatorWarning, unknownJob, s.str()); \
  2809. } \
  2810. else if (IDTREE != LOCALTREE) \
  2811. { \
  2812. StringBuffer s(TEXT": Consistency check failure, positional property specification does not match id'd tree, prop=");\
  2813. s.append(PATH); \
  2814. LOG(MCoperatorWarning, unknownJob, s.str()); \
  2815. }
  2816. PDState CServerRemoteTree::checkChange(IPropertyTree &changeTree, CBranchChange *parentBranchChange)
  2817. {
  2818. PDState res = PDS_None;
  2819. bool checkExternal = false;
  2820. Owned<IPropertyTreeIterator> iter = changeTree.getElements("*");
  2821. ICopyArrayOf<IPropertyTree> toremove;
  2822. ForEach(*iter)
  2823. {
  2824. IPropertyTree &e = iter->query();
  2825. const char *name = e.queryName();
  2826. switch (name[0])
  2827. {
  2828. case 'R':
  2829. {
  2830. IPropertyTree *idTree = SDSManager->queryRegisteredTree(e.getPropInt64("@id"));
  2831. if (!idTree)
  2832. throw MakeSDSException(SDSExcpt_OrphanedNode, "renaming %s to %s", e.queryProp("@from"), e.queryProp("@to"));
  2833. #ifdef SIBLING_MOVEMENT_CHECK
  2834. StringBuffer localTreePath(e.queryProp("@from"));
  2835. localTreePath.append('[').append(e.getPropInt("@pos")).append(']');
  2836. IPropertyTree *localTree = queryPropTree(localTreePath.str());
  2837. consistencyCheck("RENAME", idTree, localTree, localTreePath.str(), queryName(), e.getPropInt64("@id"));
  2838. #endif
  2839. int pos = findChild(idTree);
  2840. if (renameTree(idTree, e.queryProp("@to")))
  2841. {
  2842. e.setPropInt("@pos", pos+1);
  2843. mergePDState(res, PDS_Structure);
  2844. if (parentBranchChange)
  2845. {
  2846. PDState _res = res;
  2847. mergePDState(_res, PDS_Renames);
  2848. Owned<CBranchChange> childChange = new CBranchChange(*(CRemoteTreeBase *)idTree);
  2849. childChange->noteChange(_res, _res);
  2850. childChange->Link();
  2851. parentBranchChange->addChildBranch(*childChange);
  2852. }
  2853. }
  2854. else
  2855. {
  2856. toremove.append(e);
  2857. continue;
  2858. }
  2859. break;
  2860. }
  2861. case 'D':
  2862. {
  2863. IPropertyTree *idTree = SDSManager->queryRegisteredTree(e.getPropInt64("@id"));
  2864. if (!idTree)
  2865. {
  2866. toremove.append(e);
  2867. continue;
  2868. }
  2869. #ifdef SIBLING_MOVEMENT_CHECK
  2870. StringBuffer localTreePath(e.queryProp("@name"));
  2871. localTreePath.append('[').append(e.getPropInt("@pos")).append(']');
  2872. IPropertyTree *localTree = queryPropTree(localTreePath.str());
  2873. consistencyCheck("DELETE", idTree, localTree, localTreePath.str(), queryName(), e.getPropInt64("@id"));
  2874. #endif
  2875. int pos = findChild(idTree);
  2876. if (NotFound == pos)
  2877. {
  2878. toremove.append(e);
  2879. continue;
  2880. }
  2881. e.setPropInt("@pos", pos+1);
  2882. Owned<CBranchChange> childChange = new CBranchChange(*(CRemoteTreeBase *)idTree);
  2883. if (!removeTree(idTree))
  2884. throw MakeSDSException(-1, "::checkChange - Failed to remove child(%s) from parent(%s) at %s(%d)", idTree->queryName(), queryName(), __FILE__, __LINE__);
  2885. mergePDState(res, PDS_Structure);
  2886. if (parentBranchChange)
  2887. {
  2888. PDState _res = res;
  2889. mergePDState(_res, PDS_Deleted);
  2890. childChange->noteChange(_res, _res);
  2891. childChange->Link();
  2892. parentBranchChange->addChildBranch(*childChange);
  2893. }
  2894. break;
  2895. }
  2896. case 'A':
  2897. {
  2898. switch (name[1])
  2899. {
  2900. case 'D':
  2901. {
  2902. Owned<IAttributeIterator> iter = e.getAttributes();
  2903. ForEach(*iter)
  2904. {
  2905. if (removeAttr(iter->queryName()))
  2906. mergePDState(res, PDS_Data);
  2907. }
  2908. break;
  2909. }
  2910. case 'C':
  2911. {
  2912. Owned<IAttributeIterator> iter = e.getAttributes();
  2913. ForEach(*iter)
  2914. setProp(iter->queryName(), iter->queryValue());
  2915. mergePDState(res, PDS_Data);
  2916. break;
  2917. }
  2918. default:
  2919. throwUnexpected();
  2920. }
  2921. break;
  2922. }
  2923. case 'T':
  2924. break;
  2925. }
  2926. }
  2927. ForEachItemIn(tr, toremove)
  2928. changeTree.removeTree(&toremove.item(tr));
  2929. if (changeTree.getPropBool("@localValue"))
  2930. {
  2931. bool binary=changeTree.isBinary(NULL);
  2932. IPTArrayValue *v = ((PTree &)changeTree).queryValue();
  2933. setValue(v?new CPTValue(v->queryValueRawSize(), v->queryValueRaw(), binary, true, v->isCompressed()):NULL, binary);
  2934. if (changeTree.getPropBool("@new"))
  2935. mergePDState(res, PDS_New);
  2936. mergePDState(res, PDS_Data);
  2937. checkExternal = true;
  2938. }
  2939. else if (changeTree.getPropBool("@appendValue"))
  2940. {
  2941. bool binary=changeTree.isBinary(NULL);
  2942. if (binary != isBinary(NULL))
  2943. throw MakeSDSException(-1, "Error attempting to append binary and non-binary data together, in node: %s", queryName());
  2944. __int64 index = getPropInt64(EXT_ATTR);
  2945. MemoryBuffer mb;
  2946. if (index)
  2947. {
  2948. MemoryBuffer mbv;
  2949. SDSManager->getExternalValue(index, mbv);
  2950. CPTValue v(mbv);
  2951. v.getValue(mb, binary);
  2952. }
  2953. else
  2954. getPropBin(NULL, mb);
  2955. changeTree.getPropBin(NULL, mb);
  2956. if (binary)
  2957. setPropBin(NULL, mb.length(), mb.toByteArray());
  2958. else
  2959. {
  2960. mb.append('\0');
  2961. setProp(NULL, (const char *)mb.toByteArray());
  2962. }
  2963. mergePDState(res, PDS_Data);
  2964. checkExternal = true;
  2965. }
  2966. if (checkExternal)
  2967. {
  2968. __int64 index = getPropInt64(EXT_ATTR);
  2969. if (index)
  2970. {
  2971. bool r = false;
  2972. if (!testExternalCandidate())
  2973. {
  2974. SDSManager->deleteExternal(index); // i.e. no longer e.g. now less than threshold.
  2975. r = removeProp(EXT_ATTR);
  2976. }
  2977. else
  2978. SDSManager->writeExternal(*this, false, index);
  2979. if (r)
  2980. {
  2981. IPropertyTree *t = changeTree.queryPropTree(ATTRDELETE_TAG);
  2982. if (!t)
  2983. t = changeTree.addPropTree(ATTRDELETE_TAG, createPTree());
  2984. t->addProp(EXT_ATTR, "");
  2985. }
  2986. else
  2987. changeTree.setProp(NULL, (const char *)NULL);
  2988. }
  2989. else if (testExternalCandidate())
  2990. {
  2991. try
  2992. {
  2993. SDSManager->writeExternal(*this);
  2994. IPropertyTree *t = changeTree.queryPropTree(ATTRCHANGE_TAG);
  2995. if (!t)
  2996. t = changeTree.addPropTree(ATTRCHANGE_TAG, createPTree());
  2997. changeTree.setProp(NULL, (const char *)NULL);
  2998. t->setProp(EXT_ATTR, queryProp(EXT_ATTR));
  2999. }
  3000. catch (IException *)
  3001. {
  3002. setProp(NULL, NULL); // in the event of failure during externalization, lose the value
  3003. throw;
  3004. }
  3005. }
  3006. }
  3007. return res;
  3008. }
  3009. PDState CServerRemoteTree::processData(CServerConnection &connection, IPropertyTree &changeTree, MemoryBuffer &newIds)
  3010. {
  3011. Owned<CBranchChange> top;
  3012. PDState res = processData(changeTree, top, newIds);
  3013. changeTree.removeProp("@name");
  3014. if (res)
  3015. SDSManager->writeTransactions++;
  3016. // return asap from here, don't even wait for pool threads to queue, can take time.
  3017. if (res && !RTM_MODE(connection.queryMode(), RTM_INTERNAL))
  3018. {
  3019. CPTStack stack = connection.queryPTreePath();
  3020. if (connection.queryRoot() == (IPropertyTree *)SDSManager->queryRoot())
  3021. stack.pop();
  3022. connection.notify();
  3023. SDSManager->startNotification(changeTree, stack, *top);
  3024. }
  3025. return res;
  3026. }
  3027. PDState CServerRemoteTree::processData(IPropertyTree &changeTree, Owned<CBranchChange> &parentBranchChange, MemoryBuffer &newIds)
  3028. {
  3029. Owned<CBranchChange> branchChange = new CBranchChange(*this);
  3030. PDState localChange, res;
  3031. localChange = res = checkChange(changeTree, branchChange);
  3032. Owned<IPropertyTreeIterator> iter = changeTree.getElements(RESERVED_CHANGE_NODE);
  3033. if (iter->first())
  3034. {
  3035. bool levelNotified = false;
  3036. do
  3037. {
  3038. IPropertyTree &childChanges = iter->query();
  3039. CServerRemoteTree *child;
  3040. StringAttr childName;
  3041. if (childChanges.getPropBool("@new"))
  3042. {
  3043. child = (CServerRemoteTree *)createChild(childChanges.getPropInt("@pos", -1), childChanges.queryProp("@name"));
  3044. newIds.append(child->queryServerId());
  3045. mergePDState(localChange, PDS_Added);
  3046. mergePDState(res, PDS_Added);
  3047. }
  3048. else
  3049. {
  3050. child = (CServerRemoteTree *) SDSManager->queryRegisteredTree(childChanges.getPropInt64("@id"));
  3051. #ifdef SIBLING_MOVEMENT_CHECK
  3052. StringBuffer localTreePath(childChanges.queryProp("@name"));
  3053. localTreePath.append('[').append(childChanges.getPropInt("@pos")).append(']');
  3054. CRemoteTreeBase *localTree = (CRemoteTreeBase *) queryPropTree(localTreePath.str());
  3055. consistencyCheck("PROP UPDATE", child, localTree, localTreePath.str(), queryName(), childChanges.getPropInt64("@id"))
  3056. #endif
  3057. if (NULL == child)
  3058. throw MakeSDSException(SDSExcpt_ClientCacheDirty, "child(%s) not found in parent(%s) at %s(%d)", childChanges.queryProp("@name"), queryName(), __FILE__, __LINE__);
  3059. int pos = findChild(child);
  3060. if (NotFound == pos)
  3061. throw MakeSDSException(SDSExcpt_ClientCacheDirty, "child(%s) not found in parent(%s) at %s(%d)", child->queryName(), queryName(), __FILE__, __LINE__);
  3062. childChanges.setPropInt("@pos", pos+1);
  3063. }
  3064. if (!levelNotified)
  3065. {
  3066. levelNotified = true;
  3067. branchChange->noteChange(localChange, res);
  3068. }
  3069. mergePDState(res, child->processData(childChanges, branchChange, newIds));
  3070. }
  3071. while (iter->next());
  3072. }
  3073. else
  3074. branchChange->noteChange(localChange, res);
  3075. if ((localChange != PDS_None) && isSubscribed())
  3076. SDSManager->notifyNode(*this, localChange);
  3077. if (!parentBranchChange.get())
  3078. parentBranchChange.setown(branchChange.getClear());
  3079. else
  3080. parentBranchChange->addChildBranch(*branchChange.getClear());
  3081. return res;
  3082. }
  3083. /////////////////
  3084. class CPendingLockBlock
  3085. {
  3086. CLockInfo &lockInfo;
  3087. public:
  3088. CPendingLockBlock(CLockInfo &_lockInfo);
  3089. ~CPendingLockBlock();
  3090. };
  3091. typedef Int64Array IdPath;
  3092. typedef MapBetween<ConnectionId, ConnectionId, LockData, LockData> ConnectionInfoMap;
  3093. #define LOCKSESSCHECK (1000*60*5)
  3094. class CLockInfo : public CInterface, implements IInterface
  3095. {
  3096. DECL_NAMEDCOUNT;
  3097. CLockInfoTable &table;
  3098. unsigned sub, readLocks, holdLocks, pending, waiting;
  3099. IdPath idPath;
  3100. ConnectionInfoMap connectionInfo;
  3101. CheckedCriticalSection crit;
  3102. Semaphore sem;
  3103. StringAttr xpath;
  3104. __int64 treeId;
  3105. bool exclusive;
  3106. Linked<CServerRemoteTree> parent, child;
  3107. #ifdef _DEBUG
  3108. DebugInfo debugInfo;
  3109. #endif
  3110. bool validateConnectionSessions()
  3111. {
  3112. PROGLOG("validateConnectionSessions");
  3113. bool ret = false;
  3114. try
  3115. {
  3116. IArrayOf<IMapping> entries;
  3117. {
  3118. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  3119. HashIterator iter(connectionInfo);
  3120. ForEach (iter)
  3121. entries.append(*LINK(&iter.query()));
  3122. }
  3123. ForEachItemIn(e, entries)
  3124. {
  3125. IMapping &imap = entries.item(e);
  3126. LockData *lD = connectionInfo.mapToValue(&imap);
  3127. Owned<INode> node = querySessionManager().getProcessSessionNode(lD->sessId);
  3128. if (node)
  3129. {
  3130. SessionId nodeSessId = querySessionManager().lookupProcessSession(node);
  3131. if (nodeSessId)
  3132. {
  3133. if (lD->sessId != nodeSessId)
  3134. {
  3135. StringBuffer out("Removing stale connection session [");
  3136. out.appendf("%"I64F"x], connectionId [%"I64F"x]", lD->sessId, * ((ConnectionId *) imap.getKey()));
  3137. out.append(" xpath [").append(xpath).append("]");
  3138. PROGLOG("%s", out.str());
  3139. querySessionManager().stopSession(lD->sessId, true);
  3140. ret = true;
  3141. }
  3142. else
  3143. {
  3144. StringBuffer nodeStr;
  3145. node->endpoint().getUrlStr(nodeStr);
  3146. PROGLOG("Validating connection to %s", nodeStr.str());
  3147. if (!queryWorldCommunicator().verifyConnection(node, LOCKSESSCHECK))
  3148. {
  3149. StringBuffer out("Terminating connection session to ");
  3150. out.append(nodeStr);
  3151. out.append(" [");
  3152. out.appendf("%"I64F"x], connectionId [%"I64F"x]", lD->sessId, * ((ConnectionId *) imap.getKey()));
  3153. out.append(" xpath [").append(xpath).append("]");
  3154. PROGLOG("%s", out.str());
  3155. queryCoven().disconnect(node);
  3156. ret = true;
  3157. }
  3158. }
  3159. }
  3160. }
  3161. }
  3162. }
  3163. catch (IException *e)
  3164. {
  3165. EXCLOG(e, "validateConnectionSessions");
  3166. e->Release();
  3167. }
  3168. PROGLOG("validateConnectionSessions done");
  3169. return ret;
  3170. }
  3171. LockStatus doLock(unsigned mode, unsigned timeout, ConnectionId id, SessionId sessionId, IUnlockCallback &callback, bool change=false)
  3172. {
  3173. class CLockCallbackUnblock
  3174. {
  3175. public:
  3176. CLockCallbackUnblock(IUnlockCallback &_callback) : callback(_callback) { callback.unblock(); }
  3177. ~CLockCallbackUnblock() { callback.block(); }
  3178. private:
  3179. IUnlockCallback &callback;
  3180. };
  3181. if (INFINITE == timeout)
  3182. {
  3183. loop
  3184. {
  3185. if (!SDSManager->queryConnection(id))
  3186. return LockFailed;
  3187. LockStatus lockStatus = tryLock(mode, id, sessionId, change);
  3188. if (lockStatus == LockSucceeded || lockStatus == LockHeld)
  3189. return lockStatus;
  3190. else
  3191. {
  3192. bool timedout = false;
  3193. waiting++;
  3194. {
  3195. CHECKEDCRITICALUNBLOCK(crit, fakeCritTimeout);
  3196. CLockCallbackUnblock cb(callback);
  3197. timedout = !sem.wait(LOCKSESSCHECK);
  3198. }
  3199. if (timedout)
  3200. {
  3201. if (!sem.wait(0))
  3202. {
  3203. waiting--;
  3204. StringBuffer s("Infinite timeout lock still waiting: ");
  3205. getLockInfo(s);
  3206. PROGLOG("%s", s.str());
  3207. }
  3208. {
  3209. CHECKEDCRITICALUNBLOCK(crit, fakeCritTimeout);
  3210. CLockCallbackUnblock cb(callback);
  3211. validateConnectionSessions();
  3212. }
  3213. }
  3214. }
  3215. }
  3216. }
  3217. else
  3218. {
  3219. CTimeMon tm(timeout);
  3220. loop
  3221. {
  3222. if (!SDSManager->queryConnection(id))
  3223. return LockFailed;
  3224. LockStatus lockStatus = tryLock(mode, id, sessionId, change);
  3225. if (lockStatus == LockSucceeded || lockStatus == LockHeld)
  3226. return lockStatus;
  3227. else
  3228. {
  3229. bool timedout = false;
  3230. waiting++;
  3231. {
  3232. CHECKEDCRITICALUNBLOCK(crit, fakeCritTimeout);
  3233. CLockCallbackUnblock cb(callback);
  3234. unsigned remaining;
  3235. if (tm.timedout(&remaining) || !sem.wait(remaining>LOCKSESSCHECK?LOCKSESSCHECK:remaining))
  3236. timedout = true;
  3237. }
  3238. if (timedout) {
  3239. if (!sem.wait(0))
  3240. waiting--; //// only dec waiting if waiting wasn't signalled.
  3241. bool disconnects;
  3242. {
  3243. CHECKEDCRITICALUNBLOCK(crit, fakeCritTimeout);
  3244. CLockCallbackUnblock cb(callback);
  3245. disconnects = validateConnectionSessions();
  3246. }
  3247. if (tm.timedout())
  3248. {
  3249. if (disconnects) // if some sessions disconnected, one final try
  3250. {
  3251. if (!SDSManager->queryConnection(id))
  3252. return LockFailed;
  3253. lockStatus = tryLock(mode, id, sessionId, change);
  3254. if (lockStatus == LockSucceeded || lockStatus == LockHeld)
  3255. return lockStatus;
  3256. }
  3257. break;
  3258. }
  3259. }
  3260. // have to very careful here, have regained crit locks but have since timed out
  3261. // therefore before gaining crits after signal (this lock was unlocked)
  3262. // other thread can grab lock at this time, but this thread can't cause others to increase 'waiting' at this time.
  3263. // and not after crit locks regained.
  3264. if (tm.timedout())
  3265. break;
  3266. }
  3267. }
  3268. }
  3269. return LockTimedOut;
  3270. }
  3271. LockStatus tryLock(unsigned mode, ConnectionId id, SessionId sessId, bool changingMode=false)
  3272. {
  3273. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  3274. LockData *existingLd = NULL;
  3275. bool hadReadLock = false;
  3276. bool hadHoldLock = false;
  3277. if (changingMode)
  3278. {
  3279. existingLd = connectionInfo.getValue(id);
  3280. if (existingLd)
  3281. {
  3282. if ((existingLd->mode & RTM_LOCKBASIC_MASK) == (mode & RTM_LOCKBASIC_MASK))
  3283. return LockSucceeded; // nothing to do
  3284. // record and unlock existing state
  3285. switch (existingLd->mode & RTM_LOCKBASIC_MASK)
  3286. {
  3287. case (RTM_LOCK_HOLD+RTM_LOCK_READ):
  3288. holdLocks--;
  3289. hadHoldLock = true;
  3290. // fall into...
  3291. case RTM_LOCK_READ:
  3292. readLocks--;
  3293. hadReadLock = true;
  3294. break;
  3295. case (RTM_LOCK_WRITE+RTM_LOCK_READ):
  3296. case RTM_LOCK_WRITE:
  3297. exclusive = false;
  3298. // change will succeed
  3299. break;
  3300. case 0: // no locking
  3301. break;
  3302. default:
  3303. throwUnexpected();
  3304. }
  3305. }
  3306. else
  3307. changingMode = false; // nothing to restore in event of no change
  3308. }
  3309. switch (mode & RTM_LOCKBASIC_MASK)
  3310. {
  3311. case 0:
  3312. {
  3313. if (changingMode)
  3314. break;
  3315. return LockSucceeded;
  3316. }
  3317. case (RTM_LOCK_READ+RTM_LOCK_HOLD):
  3318. case RTM_LOCK_READ: // cannot fail if changingMode=true (exclusive will have been unlocked)
  3319. if (exclusive)
  3320. return LockFailed;
  3321. readLocks++;
  3322. if (mode & RTM_LOCK_HOLD)
  3323. holdLocks++;
  3324. break;
  3325. case (RTM_LOCK_WRITE+RTM_LOCK_READ):
  3326. case RTM_LOCK_WRITE:
  3327. if (exclusive || readLocks || holdLocks)
  3328. {
  3329. if (changingMode)
  3330. {
  3331. // only an unlocked read lock can fail and need restore here.
  3332. if (hadReadLock)
  3333. readLocks++;
  3334. if (hadHoldLock)
  3335. holdLocks++;
  3336. }
  3337. return holdLocks ? LockHeld : LockFailed;
  3338. }
  3339. exclusive = true;
  3340. #ifdef _DEBUG
  3341. debugInfo.ExclOwningThread = GetCurrentThreadId();
  3342. debugInfo.ExclOwningConnection = id;
  3343. debugInfo.ExclOwningSession = sessId;
  3344. #endif
  3345. break;
  3346. default:
  3347. if (changingMode)
  3348. {
  3349. // only an unlocked read lock can fail and need restore here.
  3350. if (hadReadLock)
  3351. readLocks++;
  3352. if (hadHoldLock)
  3353. holdLocks++;
  3354. }
  3355. throwUnexpected();
  3356. }
  3357. if (changingMode)
  3358. {
  3359. existingLd->mode = mode;
  3360. wakeWaiting();
  3361. }
  3362. else
  3363. {
  3364. if (RTM_LOCK_SUB & mode)
  3365. sub++;
  3366. LockData ld;
  3367. ld.mode = mode;
  3368. ld.sessId = sessId;
  3369. ld.timeLockObtained = msTick();
  3370. connectionInfo.setValue(id, ld);
  3371. }
  3372. return LockSucceeded;
  3373. }
  3374. inline void wakeWaiting()
  3375. {
  3376. if (waiting)
  3377. {
  3378. sem.signal(waiting); // get blocked locks to recheck.
  3379. waiting=0;
  3380. }
  3381. }
  3382. public:
  3383. IMPLEMENT_IINTERFACE;
  3384. CLockInfo(CLockInfoTable &_table, __int64 _treeId, IdPath &_idPath, const char *_xpath, unsigned mode, ConnectionId id, SessionId sessId)
  3385. : table(_table), treeId(_treeId), xpath(_xpath), exclusive(false), sub(0), readLocks(0), holdLocks(0), waiting(0), pending(0)
  3386. {
  3387. INIT_NAMEDCOUNT;
  3388. verifyex(tryLock(mode, id, sessId)==LockSucceeded);
  3389. ForEachItemIn(i, _idPath)
  3390. idPath.append(_idPath.item(i));
  3391. }
  3392. ~CLockInfo()
  3393. {
  3394. if (parent)
  3395. clearLastRef();
  3396. }
  3397. inline void clearLastRef();
  3398. bool querySub() { return (0 != sub); }
  3399. const void *queryFindParam() const
  3400. {
  3401. return (const void *) &treeId;
  3402. }
  3403. bool matchHead(IdPath &_idPath)
  3404. {
  3405. unsigned o = idPath.ordinality();
  3406. ForEachItemIn(i, _idPath)
  3407. {
  3408. if (i>=o) return false;
  3409. else if (idPath.item(i) != _idPath.item(i))
  3410. return false;
  3411. }
  3412. return true;
  3413. }
  3414. bool unlock(ConnectionId id)
  3415. {
  3416. bool ret = false;
  3417. CPendingLockBlock b(*this); // carefully placed, removePending can destroy this, therefore must be destroyed last
  3418. {
  3419. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  3420. LockData *ld = connectionInfo.getValue(id);
  3421. if (ld) // not necessarily any lock info for this connection
  3422. {
  3423. switch (ld->mode & RTM_LOCKBASIC_MASK)
  3424. {
  3425. case RTM_LOCK_READ+RTM_LOCK_HOLD:
  3426. assertex(holdLocks);
  3427. holdLocks--;
  3428. // fall into...
  3429. case RTM_LOCK_READ:
  3430. assertex(readLocks);
  3431. readLocks--;
  3432. break;
  3433. case (RTM_LOCK_WRITE+RTM_LOCK_READ):
  3434. case RTM_LOCK_WRITE:
  3435. assertex(exclusive && 0 == readLocks && 0 == holdLocks);
  3436. exclusive = false;
  3437. #ifdef _DEBUG
  3438. debugInfo.clearExclusive();
  3439. #endif
  3440. break;
  3441. case 0: // no locking
  3442. break;
  3443. default:
  3444. throwUnexpected();
  3445. }
  3446. if (RTM_LOCK_SUB & ld->mode)
  3447. sub--;
  3448. connectionInfo.remove(id);
  3449. if (parent && 0 == connectionInfo.count())
  3450. {
  3451. clearLastRef();
  3452. ret = true;
  3453. }
  3454. }
  3455. wakeWaiting();
  3456. }
  3457. return ret;
  3458. }
  3459. void unlockAll()
  3460. {
  3461. CPendingLockBlock b(*this); // carefully placed, removePending can destroy this.
  3462. { CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  3463. HashIterator iter(connectionInfo);
  3464. while (iter.first())
  3465. {
  3466. IMapping &map = iter.query();
  3467. ConnectionId id = *(ConnectionId *)map.getKey();
  3468. unlock(id);
  3469. }
  3470. }
  3471. }
  3472. inline void addPending()
  3473. {
  3474. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  3475. pending++;
  3476. }
  3477. inline void removePending()
  3478. {
  3479. Linked<CLockInfo> destroy;
  3480. {
  3481. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  3482. pending--;
  3483. if (0 == (lockCount()+pending))
  3484. {
  3485. destroy.set(this);
  3486. table.removeExact(this);
  3487. }
  3488. }
  3489. }
  3490. LockStatus lock(unsigned mode, unsigned timeout, ConnectionId id, SessionId sessionId, IUnlockCallback &callback)
  3491. {
  3492. bool ret = false;
  3493. CPendingLockBlock b(*this); // carefully placed, removePending can destroy this, therefore must be destroyed last
  3494. {
  3495. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  3496. return doLock(mode, timeout, id, sessionId, callback);
  3497. }
  3498. return LockFailed;
  3499. }
  3500. void changeMode(ConnectionId id, SessionId sessionId, unsigned newMode, unsigned timeout, IUnlockCallback &callback)
  3501. {
  3502. CPendingLockBlock b(*this); // carefully placed, removePending can destroy this.
  3503. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  3504. LockStatus result = doLock(newMode, timeout, id, sessionId, callback, true);
  3505. if (result != LockSucceeded)
  3506. {
  3507. StringBuffer s;
  3508. switch (result)
  3509. {
  3510. case LockFailed:
  3511. throw MakeSDSException(SDSExcpt_ConnectionAbsent, "Lost connection performing changeMode on connection to : %s", xpath.get());
  3512. case LockTimedOut:
  3513. throw MakeSDSException(SDSExcpt_LockTimeout, "Lock timeout performing changeMode on connection to : %s, existing lock info: %s", xpath.get(), getLockInfo(s).str());
  3514. case LockHeld:
  3515. throw MakeSDSException(SDSExcpt_LockHeld, "Lock is held performing changeMode on connection to : %s, existing lock info: %s", xpath.get(), getLockInfo(s).str());
  3516. }
  3517. }
  3518. }
  3519. unsigned lockCount()
  3520. {
  3521. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  3522. return connectionInfo.count();
  3523. }
  3524. bool associated(ConnectionId connectionId)
  3525. {
  3526. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  3527. return NULL!=connectionInfo.getValue(connectionId);
  3528. }
  3529. const char *queryXPath() const
  3530. {
  3531. return xpath;
  3532. }
  3533. StringBuffer &getLockInfo(StringBuffer &out)
  3534. {
  3535. unsigned nlocks=0;
  3536. MemoryBuffer locks;
  3537. UInt64Array keys;
  3538. {
  3539. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  3540. HashIterator iter(connectionInfo);
  3541. ForEach(iter)
  3542. {
  3543. IMapping &imap = iter.query();
  3544. LockData *lD = connectionInfo.mapToValue(&imap);
  3545. keys.append(* ((ConnectionId *) imap.getKey()));
  3546. locks.append(sizeof(LockData), lD);
  3547. ++nlocks;
  3548. }
  3549. }
  3550. unsigned msNow = msTick();
  3551. out.append("Locks on path: /").append(xpath).newline();
  3552. out.append("Endpoint |SessionId |ConnectionId |mode |time(duration)]").newline().newline();
  3553. unsigned l = 0;
  3554. if (nlocks)
  3555. {
  3556. loop
  3557. {
  3558. LockData lD;
  3559. memcpy(&lD, ((const byte *)locks.toByteArray())+l*sizeof(LockData), sizeof(LockData));
  3560. ConnectionId connId = keys.item(l);
  3561. StringBuffer sessEpStr;
  3562. unsigned lockedFor = msNow-lD.timeLockObtained;
  3563. CDateTime time;
  3564. time.setNow();
  3565. time_t tt = time.getSimple() - (lockedFor/1000);
  3566. time.set(tt);
  3567. StringBuffer timeStr;
  3568. time.getString(timeStr);
  3569. out.appendf("%-20s|%-16"I64F"x|%-16"I64F"x|%-8x|%s(%d ms)", querySessionManager().getClientProcessEndpoint(lD.sessId, sessEpStr).str(), lD.sessId, connId, lD.mode, timeStr.str(), lockedFor);
  3570. ++l;
  3571. if (l>=nlocks)
  3572. break;
  3573. out.newline();
  3574. }
  3575. }
  3576. out.newline();
  3577. return out;
  3578. }
  3579. void setDROLR(CServerRemoteTree *_parent, CServerRemoteTree *_child)
  3580. {
  3581. CHECKEDCRITICALBLOCK(crit, fakeCritTimeout);
  3582. if (parent)
  3583. {
  3584. assertex(parent.get() == _parent);
  3585. assertex(child.get() == _child);
  3586. return;
  3587. }
  3588. parent.set(_parent);
  3589. child.set(_child);
  3590. }
  3591. };
  3592. CPendingLockBlock::CPendingLockBlock(CLockInfo &_lockInfo) : lockInfo(_lockInfo)
  3593. {
  3594. lockInfo.addPending();
  3595. }
  3596. CPendingLockBlock::~CPendingLockBlock()
  3597. {
  3598. lockInfo.removePending();
  3599. }
  3600. typedef ICopyArrayOf<CLockInfo> CLockInfoArray;
  3601. ///////////
  3602. template <> void CLockInfoTable::onRemove(void *et)
  3603. {
  3604. ((CLockInfo*)et)->Release();
  3605. }
  3606. ///////////////
  3607. CSDSTransactionServer::CSDSTransactionServer(CCovenSDSManager &_manager)
  3608. : Thread("SDS Manager, CSDSTransactionServer"), manager(_manager), CTransactionLogTracker(DAMP_SDSCMD_MAX)
  3609. {
  3610. stopped = true;
  3611. }
  3612. int CSDSTransactionServer::run()
  3613. {
  3614. ICoven &coven=queryCoven();
  3615. CMessageHandler<CSDSTransactionServer> handler("CSDSTransactionServer",this,&CSDSTransactionServer::processMessage, &manager, 100, TIMEOUT_ON_CLOSEDOWN);
  3616. stopped = false;
  3617. CMessageBuffer mb;
  3618. while (!stopped)
  3619. {
  3620. try
  3621. {
  3622. #ifdef TRACE_QWAITING
  3623. unsigned waiting = coven.probe(RANK_ALL,MPTAG_DALI_SDS_REQUEST,NULL);
  3624. static unsigned lastwaiting = 0;
  3625. static unsigned lasttick = 0;
  3626. if ((waiting>lastwaiting+25)||(waiting<lastwaiting/2)||
  3627. ((waiting>100)&&(msTick()-lasttick>1000))) {
  3628. DBGLOG("QPROBE: MPTAG_DALI_SDS_REQUEST has %d waiting",waiting);
  3629. lastwaiting = waiting;
  3630. lasttick = msTick();
  3631. }
  3632. #endif
  3633. mb.clear();
  3634. if (coven.recv(mb, RANK_ALL, MPTAG_DALI_SDS_REQUEST, NULL))
  3635. {
  3636. msgCount++;
  3637. try
  3638. {
  3639. SdsCommand action;
  3640. mb.read((int &)action);
  3641. action = (SdsCommand) (((unsigned)action) & ~DAMP_SDSCMD_LAZYEXT);
  3642. switch (action)
  3643. {
  3644. case DAMP_SDSCMD_CONNECT:
  3645. case DAMP_SDSCMD_MCONNECT:
  3646. case DAMP_SDSCMD_GETCHILDREN:
  3647. case DAMP_SDSCMD_GETCHILDREN2:
  3648. case DAMP_SDSCMD_GET:
  3649. case DAMP_SDSCMD_GET2:
  3650. case DAMP_SDSCMD_GETELEMENTS:
  3651. case DAMP_SDSCMD_DATA:
  3652. case DAMP_SDSCMD_CHANGEMODE:
  3653. case DAMP_SDSCMD_GETXPATHS:
  3654. case DAMP_SDSCMD_GETXPATHSPLUSIDS:
  3655. case DAMP_SDSCMD_GETEXTVALUE:
  3656. case DAMP_SDSCMD_GETELEMENTSRAW:
  3657. case DAMP_SDSCMD_GETCOUNT:
  3658. {
  3659. mb.reset();
  3660. handler.handleMessage(mb);
  3661. mb.clear(); // ^ has copied mb
  3662. break;
  3663. }
  3664. case DAMP_SDSCMD_GETSTORE:
  3665. {
  3666. TimingBlock xactTimingBlock(xactTimingStats);
  3667. CServerRemoteTree *root = manager.queryRoot();
  3668. mb.clear();
  3669. if (root)
  3670. {
  3671. mb.append(DAMP_SDSREPLY_OK);
  3672. root->serializeCutOffRT(mb);
  3673. }
  3674. else
  3675. mb.append(DAMP_SDSREPLY_EMPTY);
  3676. break;
  3677. }
  3678. #ifdef LEGACY_CLIENT_RESPONSE
  3679. // give a re
  3680. case DAMP_SDSCMD_VERSION:
  3681. {
  3682. TimingBlock xactTimingBlock(xactTimingStats);
  3683. mb.clear().append(DAMP_SDSREPLY_ERROR);
  3684. throw MakeStringException(-1, "Client too old to communicate with this dali");
  3685. }
  3686. #endif
  3687. case DAMP_SDSCMD_DIAGNOSTIC:
  3688. {
  3689. TimingBlock xactTimingBlock(xactTimingStats);
  3690. SdsDiagCommand cmd;
  3691. mb.read((int &)cmd);
  3692. switch (cmd)
  3693. {
  3694. case DIAG_CMD_LOCKINFO:
  3695. {
  3696. StringBuffer out;
  3697. SDSManager->getLocks(out);
  3698. mb.clear().append(DAMP_SDSREPLY_OK);
  3699. mb.append(out.length());
  3700. mb.append(out.length(), out.toCharArray());
  3701. break;
  3702. }
  3703. case DIAG_CMD_STATS:
  3704. {
  3705. mb.clear().append(DAMP_SDSREPLY_OK);
  3706. SDSManager->collectUsageStats(mb);
  3707. break;
  3708. }
  3709. case DIAG_CMD_CONNECTIONS:
  3710. {
  3711. mb.clear().append(DAMP_SDSREPLY_OK);
  3712. SDSManager->collectConnections(mb);
  3713. break;
  3714. }
  3715. case DIAG_CMD_SUBSCRIBERS:
  3716. {
  3717. mb.clear().append(DAMP_SDSREPLY_OK);
  3718. SDSManager->collectSubscribers(mb);
  3719. break;
  3720. }
  3721. default:
  3722. assertex(false);
  3723. }
  3724. break;
  3725. }
  3726. case DAMP_SDSCMD_GETPROPS:
  3727. {
  3728. mb.clear().append(DAMP_SDSREPLY_OK);
  3729. manager.queryProperties().serialize(mb);
  3730. break;
  3731. }
  3732. case DAMP_SDSCMD_UPDTENV:
  3733. {
  3734. Owned<IPropertyTree> newEnv = createPTree(mb);
  3735. bool forceGroupUpdate;
  3736. mb.read(forceGroupUpdate);
  3737. StringBuffer response;
  3738. bool result = manager.updateEnvironment(newEnv, forceGroupUpdate, response);
  3739. mb.clear().append(DAMP_SDSREPLY_OK).append(result).append(response);
  3740. break;
  3741. }
  3742. default:
  3743. throw MakeSDSException(SDSExcpt_UnrecognisedCommand, "%d", action);
  3744. }
  3745. }
  3746. catch (IException *e)
  3747. {
  3748. mb.clear();
  3749. mb.append((int) DAMP_SDSREPLY_ERROR);
  3750. mb.append(e->errorCode());
  3751. StringBuffer s;
  3752. mb.append(e->errorMessage(s).str());
  3753. StringBuffer clientUrl("EXCEPTION in reply to client ");
  3754. mb.getSender().getUrlStr(clientUrl);
  3755. EXCLOG(e, clientUrl.str(), MSGCLS_warning);
  3756. e->Release();
  3757. }
  3758. if (mb.length())
  3759. {
  3760. try { coven.reply(mb); }
  3761. catch (IJSOCK_Exception *e)
  3762. {
  3763. LOG(MCwarning, unknownJob, e, "Failed to reply to client (CSDSTransactionServer thread)");
  3764. e->Release();
  3765. }
  3766. catch (IMP_Exception *e)
  3767. {
  3768. LOG(MCwarning, unknownJob, e, "Failed to reply to client (CSDSTransactionServer thread)");
  3769. e->Release();
  3770. }
  3771. }
  3772. }
  3773. else
  3774. stopped = true;
  3775. }
  3776. catch (IException *e)
  3777. {
  3778. StringBuffer s("Failure receiving message from client ");
  3779. mb.getSender().getUrlStr(s);
  3780. LOG(MCwarning, unknownJob, e, s.str());
  3781. e->Release();
  3782. }
  3783. }
  3784. return 0;
  3785. }
  3786. // backward compat.
  3787. bool checkOldFormat(CServerRemoteTree *parentServerTree, IPropertyTree *tree, MemoryBuffer &mb)
  3788. {
  3789. CPState state;
  3790. mb.read((int &)state);
  3791. bool change = false;
  3792. if (state)
  3793. {
  3794. if (CPS_Renames & state)
  3795. {
  3796. loop
  3797. {
  3798. __int64 id;
  3799. mb.read(id);
  3800. if (0 == id)
  3801. break;
  3802. StringAttr newName;
  3803. mb.read(newName);
  3804. IPropertyTree *child = SDSManager->queryRegisteredTree(id);
  3805. if (child)
  3806. {
  3807. assertex(parentServerTree);
  3808. int pos = parentServerTree->findChild(child);
  3809. if (NotFound == pos)
  3810. throw MakeSDSException(SDSExcpt_ClientCacheDirty, "::checkChange - child(%s) not found in parent(%s) at %s(%d)", child->queryName(), parentServerTree->queryName(), __FILE__, __LINE__);
  3811. IPropertyTree *t = createPTree();
  3812. t->setProp("@from", child->queryName());
  3813. t->setProp("@to", newName);
  3814. t->setPropInt64("@id", id);
  3815. #ifdef SIBLING_MOVEMENT_CHECK
  3816. t->setProp("@pos", pos);
  3817. #endif
  3818. tree->addPropTree(RENAME_TAG, t);
  3819. change = true;
  3820. }
  3821. }
  3822. }
  3823. if (CPS_Deletions & state)
  3824. {
  3825. loop
  3826. {
  3827. __int64 id;
  3828. mb.read(id);
  3829. if (0 == id)
  3830. break;
  3831. IPropertyTree *child = SDSManager->queryRegisteredTree(id);
  3832. if (child)
  3833. {
  3834. assertex(parentServerTree);
  3835. int pos = parentServerTree->findChild(child);
  3836. if (NotFound == pos)
  3837. continue;
  3838. IPropertyTree *t = createPTree();
  3839. t->setProp("@name", child->queryName());
  3840. t->setPropInt64("@id", id);
  3841. #ifdef SIBLING_MOVEMENT_CHECK
  3842. t->setPropInt("@pos", pos+1);
  3843. #endif
  3844. tree->addPropTree(DELETE_TAG, t);
  3845. change = true;
  3846. }
  3847. }
  3848. }
  3849. if (CPS_AttrDeletions & state)
  3850. {
  3851. unsigned count, c;
  3852. mb.read(count);
  3853. if (count)
  3854. {
  3855. IPropertyTree *ct = tree->queryPropTree(ATTRCHANGE_TAG);
  3856. IPropertyTree *t = tree->addPropTree(ATTRDELETE_TAG, createPTree());
  3857. for (c=0; c<count; c++)
  3858. {
  3859. StringAttr attr;
  3860. mb.read(attr);
  3861. if (ct) ct->removeProp(attr);
  3862. t->addProp(attr, "");
  3863. }
  3864. change = true;
  3865. }
  3866. }
  3867. if (CPS_Changed & state)
  3868. {
  3869. Owned<PTree> clientTree = new LocalPTree();
  3870. clientTree->deserializeSelf(mb);
  3871. __int64 serverId;
  3872. mb.read(serverId);
  3873. byte STIInfo;
  3874. mb.read(STIInfo);
  3875. tree->setPropBool("@localValue", true);
  3876. if (clientTree->queryValue())
  3877. {
  3878. bool binary = clientTree->isBinary(NULL);
  3879. IPTArrayValue *v = ((PTree *)clientTree)->detachValue();
  3880. ((PTree *)tree)->setValue(v, binary);
  3881. }
  3882. else
  3883. ((PTree *)tree)->setValue(new CPTValue(0, NULL, false, true, false), false);
  3884. Owned<IAttributeIterator> attrs = clientTree->getAttributes();
  3885. IPropertyTree *t = createPTree();
  3886. if (attrs->first())
  3887. {
  3888. do
  3889. {
  3890. t->setProp(attrs->queryName(), clientTree->queryProp(attrs->queryName()));
  3891. }
  3892. while (attrs->next());
  3893. tree->addPropTree(ATTRCHANGE_TAG, t);
  3894. }
  3895. change = true;
  3896. }
  3897. }
  3898. return change;
  3899. }
  3900. bool translateOldFormat(CServerRemoteTree *parentServerTree, IPropertyTree *parentTree, MemoryBuffer &mb)
  3901. {
  3902. bool change = checkOldFormat(parentServerTree, parentTree, mb);
  3903. bool hasChildren;
  3904. mb.read(hasChildren);
  3905. if (hasChildren)
  3906. {
  3907. loop
  3908. {
  3909. __int64 id;
  3910. int pos = -1;
  3911. mb.read(id);
  3912. if (NoMoreChildrenMarker == id)
  3913. break;
  3914. mb.read(pos);
  3915. CServerRemoteTree *serverTree = NULL;
  3916. Owned<IPropertyTree> tree = createPTree(RESERVED_CHANGE_NODE);
  3917. if (0 == id)
  3918. {
  3919. StringAttr childName;
  3920. mb.read(childName);
  3921. tree->setPropBool("@new", true);
  3922. tree->setProp("@name", childName);
  3923. if (-1 != pos)
  3924. tree->setPropInt("@pos", pos+1);
  3925. }
  3926. else
  3927. {
  3928. assertex(parentServerTree);
  3929. serverTree = (CServerRemoteTree *) SDSManager->queryRegisteredTree(id);
  3930. assertex(serverTree);
  3931. pos = parentServerTree->findChild(serverTree);
  3932. if (NotFound == pos)
  3933. throw MakeSDSException(SDSExcpt_ClientCacheDirty, "child(%s) not found in parent(%s) at %s(%d)", serverTree->queryName(), parentServerTree->queryName(), __FILE__, __LINE__);
  3934. tree->setProp("@name", serverTree->queryName());
  3935. tree->setPropInt64("@id", id);
  3936. tree->setPropInt("@pos", pos+1);
  3937. }
  3938. if (translateOldFormat(serverTree, tree, mb))
  3939. {
  3940. parentTree->addPropTree(tree->queryName(), LINK(tree));
  3941. change = true;
  3942. }
  3943. }
  3944. }
  3945. return change;
  3946. }
  3947. ///
  3948. void CSDSTransactionServer::processMessage(CMessageBuffer &mb)
  3949. {
  3950. TimingBlock xactTimingBlock(xactTimingStats);
  3951. ICoven &coven = queryCoven();
  3952. StringAttr xpath;
  3953. ConnectionId connectionId;
  3954. SessionId id;
  3955. unsigned mode;
  3956. unsigned timeout;
  3957. SdsCommand action = (SdsCommand)-1;
  3958. try
  3959. {
  3960. mb.read((int &)action);
  3961. bool getExt = 0 == (action & DAMP_SDSCMD_LAZYEXT);
  3962. action = (SdsCommand) (((unsigned)action) & ~DAMP_SDSCMD_LAZYEXT);
  3963. TransactionLog transactionLog(*this, action, mb.getSender()); // only active if queryTransactionLogging()==true
  3964. switch (action)
  3965. {
  3966. case DAMP_SDSCMD_CONNECT:
  3967. {
  3968. TimingBlock connectTimingBlock(connectTimingStats);
  3969. Owned<CLCLockBlock> lockBlock;
  3970. unsigned startPos = mb.getPos();
  3971. mb.read(id);
  3972. mb.read(mode);
  3973. mb.read(timeout);
  3974. mb.read(xpath);
  3975. if (queryTransactionLogging())
  3976. transactionLog.log("xpath='%s' mode=%d", xpath.get(), (unsigned)mode);
  3977. Owned<LinkingCriticalBlock> connectCritBlock = new LinkingCriticalBlock(manager.connectCrit, __FILE__, __LINE__);
  3978. if (RTM_CREATE == (mode & RTM_CREATE_MASK) || RTM_CREATE_QUERY == (mode & RTM_CREATE_MASK))
  3979. lockBlock.setown(new CLCWriteLockBlock(manager.dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  3980. else
  3981. lockBlock.setown(new CLCReadLockBlock(manager.dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  3982. if (queryTransactionLogging())
  3983. transactionLog.markExtra();
  3984. connectionId = 0;
  3985. CServerRemoteTree *_tree;
  3986. Owned<CServerRemoteTree> tree;
  3987. manager.createConnection(id, mode, timeout, xpath, _tree, connectionId, true, connectCritBlock);
  3988. if (connectionId)
  3989. tree.setown(_tree);
  3990. connectCritBlock.clear();
  3991. if (connectionId)
  3992. {
  3993. if (0 == id)
  3994. {
  3995. StringBuffer str("Dali client passing sessionid=0 to connect (xpath=");
  3996. str.append(xpath).append(", mode=").append(mode).append(", connectionId=").appendf("%"I64F"x", connectionId).append(")");
  3997. WARNLOG("%s", str.str());
  3998. }
  3999. mb.clear();
  4000. mb.append((int)DAMP_SDSREPLY_OK);
  4001. mb.append(connectionId);
  4002. tree->serializeCutOffRT(mb, RTM_SUB & mode?FETCH_ENTIRE:tree->getPropBool("@fetchEntire")?FETCH_ENTIRE_COND : 0, 0, getExt);
  4003. }
  4004. else
  4005. {
  4006. mb.clear();
  4007. mb.append((int)DAMP_SDSREPLY_EMPTY);
  4008. }
  4009. break;
  4010. }
  4011. case DAMP_SDSCMD_MCONNECT:
  4012. {
  4013. TimingBlock connectTimingBlock(connectTimingStats);
  4014. Owned<CLCLockBlock> lockBlock;
  4015. if (queryTransactionLogging())
  4016. transactionLog.log();
  4017. unsigned startPos = mb.getPos();
  4018. mb.read(id);
  4019. mb.read(timeout);
  4020. Owned<IMultipleConnector> mConnect = deserializeIMultipleConnector(mb);
  4021. mb.clear();
  4022. lockBlock.setown(new CLCReadLockBlock(manager.dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  4023. try
  4024. {
  4025. Owned<CRemoteConnections> remoteConnections = new CRemoteConnections;
  4026. unsigned c;
  4027. for (c=0; c<mConnect->queryConnections(); c++)
  4028. {
  4029. StringAttr xpath;
  4030. unsigned mode;
  4031. mConnect->getConnectionDetails(c, xpath, mode);
  4032. if (queryTransactionLogging())
  4033. transactionLog.extra(", xpath='%s', mode=%d", xpath.get(), mode);
  4034. connectionId = 0;
  4035. CServerRemoteTree *_tree;
  4036. Owned<CServerRemoteTree> tree;
  4037. Owned<LinkingCriticalBlock> connectCritBlock = new LinkingCriticalBlock(manager.connectCrit, __FILE__, __LINE__);
  4038. manager.createConnection(id, mode, timeout, xpath, _tree, connectionId, true, connectCritBlock);
  4039. if (connectionId)
  4040. tree.setown(_tree);
  4041. connectCritBlock.clear();
  4042. if (connectionId)
  4043. {
  4044. if (0 == id)
  4045. {
  4046. StringBuffer str("Dali client passing sessionid=0 to multi connect (xpath=");
  4047. str.append(xpath).append(", mode=").append(mode).append(", connectionId=").appendf("%"I64F"x", connectionId).append(")");
  4048. WARNLOG("%s", str.str());
  4049. }
  4050. CRemoteConnection *conn = new CRemoteConnection(*SDSManager, connectionId, xpath, id, mode, timeout);
  4051. assertex(conn);
  4052. remoteConnections->add(conn);
  4053. mb.append((int)DAMP_SDSREPLY_OK);
  4054. mb.append(connectionId);
  4055. tree->serializeCutOffRT(mb, RTM_SUB & mode?FETCH_ENTIRE:tree->getPropBool("@fetchEntire")?FETCH_ENTIRE_COND : 0, 0, getExt);
  4056. }
  4057. else
  4058. {
  4059. mb.append((int)DAMP_SDSREPLY_EMPTY);
  4060. }
  4061. }
  4062. // success detach establish connections from holder (which would otherwise disconnect them)
  4063. remoteConnections->detachConnections();
  4064. }
  4065. catch (IException *e)
  4066. {
  4067. StringBuffer s("Failed to establish locks to multiple paths: ");
  4068. getMConnectString(mConnect, s);
  4069. LOG(MCwarning, unknownJob, e, s.str());
  4070. throw;
  4071. }
  4072. catch (DALI_CATCHALL)
  4073. {
  4074. StringBuffer s("(Unknown exception); Failed to establish locks to multiple paths: ");
  4075. getMConnectString(mConnect, s);
  4076. throw;
  4077. }
  4078. break;
  4079. }
  4080. case DAMP_SDSCMD_GET:
  4081. case DAMP_SDSCMD_GET2:
  4082. {
  4083. mb.read(connectionId);
  4084. if (queryTransactionLogging())
  4085. transactionLog.log();
  4086. __int64 serverId;
  4087. mb.read(serverId);
  4088. CHECKEDDALIREADLOCKBLOCK(manager.dataRWLock, readWriteTimeout);
  4089. CHECKEDCRITICALBLOCK(SDSManager->treeRegCrit, fakeCritTimeout);
  4090. Owned<CServerRemoteTree> tree = manager.getRegisteredTree(serverId);
  4091. if (queryTransactionLogging())
  4092. {
  4093. CServerConnection *conn = manager.queryConnection(connectionId);
  4094. transactionLog.extra(", xpath='%s', node=%s", conn?conn->queryXPath():"???", tree?tree->queryName():"???");
  4095. }
  4096. mb.clear();
  4097. if (!tree)
  4098. {
  4099. if (DAMP_SDSCMD_GET2 == action)
  4100. mb.append((int)DAMP_SDSREPLY_EMPTY);
  4101. else
  4102. {
  4103. CServerConnection *connection = manager.queryConnection(connectionId);
  4104. StringBuffer s;
  4105. if (connection)
  4106. {
  4107. s.append("path=").append(connection->queryXPath());
  4108. s.append(", mode=").append(connection->queryMode());
  4109. }
  4110. else
  4111. s.append("Missing connection!");
  4112. throw MakeSDSException(SDSExcpt_UnknownTreeId, "get: treeId = (%d), connection={ %s }", (unsigned)serverId, s.str());
  4113. }
  4114. }
  4115. else
  4116. {
  4117. mb.append((int)DAMP_SDSREPLY_OK);
  4118. tree->serializeCutOffRT(mb, tree->getPropBool("@fetchEntire")?-1 : 0, 0, getExt);
  4119. }
  4120. break;
  4121. }
  4122. case DAMP_SDSCMD_GETCHILDREN:
  4123. case DAMP_SDSCMD_GETCHILDREN2:
  4124. {
  4125. mb.read(connectionId);
  4126. if (queryTransactionLogging())
  4127. {
  4128. CServerConnection *conn = manager.queryConnection(connectionId);
  4129. transactionLog.log("%s",conn?conn->queryXPath():"???");
  4130. }
  4131. __int64 serverId;
  4132. CHECKEDDALIREADLOCKBLOCK(manager.dataRWLock, readWriteTimeout);
  4133. CHECKEDCRITICALBLOCK(SDSManager->treeRegCrit, fakeCritTimeout);
  4134. CMessageBuffer replyMb;
  4135. replyMb.init(mb.getSender(), mb.getTag(), mb.getReplyTag());
  4136. replyMb.append((int)DAMP_SDSREPLY_OK);
  4137. bool first = true, empty = false;
  4138. loop
  4139. {
  4140. mb.read(serverId);
  4141. if (!serverId) break;
  4142. if (!first && empty) replyMb.clear();
  4143. unsigned levels;
  4144. mb.read(levels);
  4145. Owned<CServerRemoteTree> parent = manager.getRegisteredTree(serverId);
  4146. if (!parent)
  4147. {
  4148. if (DAMP_SDSCMD_GETCHILDREN2 == action)
  4149. replyMb.append(false);
  4150. else
  4151. {
  4152. if (first) // if only one, can acheive without serialization change.
  4153. {
  4154. empty = true;
  4155. replyMb.clear().append((int)DAMP_SDSREPLY_EMPTY);
  4156. }
  4157. else
  4158. {
  4159. CServerConnection *connection = manager.queryConnection(connectionId);
  4160. StringBuffer s;
  4161. if (connection)
  4162. {
  4163. s.append("path=").append(connection->queryXPath());
  4164. s.append(", mode=").append(connection->queryMode());
  4165. }
  4166. else
  4167. s.append("Missing connection!");
  4168. throw MakeSDSException(SDSExcpt_UnknownTreeId, "GETCHILDREN: Failed to locate parent (%d), connection={ %s }", (unsigned)serverId, s.str());
  4169. }
  4170. }
  4171. }
  4172. else
  4173. {
  4174. if (DAMP_SDSCMD_GETCHILDREN2 == action)
  4175. replyMb.append(true);
  4176. parent->serializeCutOffChildrenRT(replyMb, 0==levels ? (unsigned)-1 : levels, 0, getExt);
  4177. if (queryTransactionLogging())
  4178. transactionLog.extra(", node=%s",parent->queryName());
  4179. }
  4180. first = false;
  4181. }
  4182. mb.clear();
  4183. mb.transferFrom(replyMb);
  4184. break;
  4185. }
  4186. case DAMP_SDSCMD_GETELEMENTS:
  4187. {
  4188. mb.read(connectionId);
  4189. if (queryTransactionLogging())
  4190. {
  4191. CServerConnection *conn = manager.queryConnection(connectionId);
  4192. transactionLog.log("%s",conn?conn->queryXPath():"???");
  4193. }
  4194. CHECKEDDALIREADLOCKBLOCK(manager.dataRWLock, readWriteTimeout);
  4195. CHECKEDCRITICALBLOCK(SDSManager->treeRegCrit, fakeCritTimeout);
  4196. CServerConnection *connection = manager.queryConnection(connectionId);
  4197. if (!connection)
  4198. throw MakeSDSException(SDSExcpt_ConnectionAbsent, " [getElements]");
  4199. StringAttr xpath;
  4200. mb.read(xpath);
  4201. if (queryTransactionLogging())
  4202. transactionLog.extra(", xpath='%s'", xpath.get());
  4203. Owned<IPropertyTreeIterator> iter = connection->queryRoot()->getElements(xpath);
  4204. ICopyArrayOf<CServerRemoteTree> arr;
  4205. ForEach (*iter) arr.append((CServerRemoteTree &)iter->query());
  4206. CMessageBuffer replyMb;
  4207. replyMb.init(mb.getSender(), mb.getTag(), mb.getReplyTag());
  4208. replyMb.append((int)DAMP_SDSREPLY_OK);
  4209. replyMb.append(arr.ordinality());
  4210. ForEachItemIn(i, arr)
  4211. arr.item(i).serializeSelfRT(replyMb, getExt);
  4212. mb.clear();
  4213. mb.transferFrom(replyMb);
  4214. break;
  4215. }
  4216. case DAMP_SDSCMD_DATA:
  4217. {
  4218. TimingSizeBlock commitTimingBlock(commitTimingStats);
  4219. CheckTime block0("DAMP_SDSCMD_DATA total");
  4220. unsigned inputStart = mb.getPos();
  4221. mb.read(connectionId);
  4222. byte disconnect; // kludge, high bit to indicate new client format. (for backward compat.)
  4223. bool deleteRoot;
  4224. mb.read(disconnect);
  4225. bool oldFormat = (0 == (0x80 & disconnect));
  4226. disconnect &= ~0x80;
  4227. if (1 == disconnect)
  4228. mb.read(deleteRoot);
  4229. bool data = mb.length() != mb.getPos();
  4230. if (queryTransactionLogging())
  4231. {
  4232. CServerConnection *conn = manager.queryConnection(connectionId);
  4233. transactionLog.log("disconnect=%s, data=%s", disconnect?"true":"false", data?"true":"false");
  4234. }
  4235. Owned<CLCLockBlock> lockBlock;
  4236. {
  4237. CheckTime block1("DAMP_SDSCMD_DATA.1");
  4238. if (data || disconnect)
  4239. lockBlock.setown(new CLCWriteLockBlock(manager.dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  4240. else
  4241. lockBlock.setown(new CLCReadLockBlock(manager.dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  4242. }
  4243. unsigned dataStart = mb.getPos();
  4244. commitTimingBlock.recordSize(mb.length() - dataStart);
  4245. CServerConnection *connection = manager.queryConnection(connectionId);
  4246. if (!connection)
  4247. throw MakeSDSException(SDSExcpt_ConnectionAbsent, " [commit]");
  4248. try
  4249. {
  4250. if (queryTransactionLogging())
  4251. transactionLog.extra(", xpath='%s'", connection->queryXPath());
  4252. CServerRemoteTree *tree = data ? (CServerRemoteTree *)connection->queryRoot() : (CServerRemoteTree *)connection->queryRootUnvalidated();
  4253. MemoryBuffer newIds;
  4254. Owned<IPropertyTree> changeTree;
  4255. if (data)
  4256. {
  4257. if (oldFormat)
  4258. {
  4259. Owned<IPropertyTree> t = createPTree(RESERVED_CHANGE_NODE);
  4260. t->setProp("@name", tree->queryName());
  4261. if (translateOldFormat(tree, t, mb))
  4262. changeTree.setown(LINK(t));
  4263. }
  4264. else
  4265. changeTree.setown(createPTree(mb));
  4266. }
  4267. if (changeTree && tree->processData(*connection, *changeTree, newIds))
  4268. { // something commited, if RTM_Create was used need to remember this.
  4269. CheckTime block6("DAMP_SDSCMD_DATA.6");
  4270. StringBuffer path;
  4271. connection->queryPTreePath().getAbsolutePath(path);
  4272. manager.saveDelta(path.str(), *changeTree);
  4273. }
  4274. mb.clear();
  4275. mb.append((int)DAMP_SDSREPLY_OK);
  4276. mb.append(newIds); // JCSMORE not particularly efficient change later
  4277. if (block0.slow())
  4278. {
  4279. block0.appendMsg(", xpath=").append(connection->queryXPath());
  4280. block0.appendMsg(", block size = ").append(mb.length());
  4281. }
  4282. }
  4283. catch (IException *)
  4284. {
  4285. if (disconnect)
  4286. manager.disconnect(connectionId, deleteRoot, (data || disconnect)?NULL:&lockBlock);
  4287. throw;
  4288. }
  4289. if (disconnect)
  4290. manager.disconnect(connectionId, deleteRoot, (data || disconnect)?NULL:&lockBlock);
  4291. break;
  4292. }
  4293. case DAMP_SDSCMD_CHANGEMODE:
  4294. {
  4295. mb.read(connectionId);
  4296. if (queryTransactionLogging())
  4297. transactionLog.log();
  4298. CHECKEDDALIWRITELOCKBLOCK(manager.dataRWLock, readWriteTimeout);
  4299. Linked<CServerConnection> connection = manager.queryConnection(connectionId);
  4300. if (!connection)
  4301. throw MakeSDSException(SDSExcpt_ConnectionAbsent, " [changeMode]");
  4302. CServerRemoteTree *tree = (CServerRemoteTree *) connection->queryRoot();
  4303. assertex(tree);
  4304. if (queryTransactionLogging())
  4305. transactionLog.extra(", xpath='%s'", connection->queryXPath());
  4306. unsigned newMode;
  4307. unsigned timeout;
  4308. mb.read(newMode);
  4309. mb.read(timeout);
  4310. mb.clear();
  4311. manager.changeLockMode(*connection, newMode, timeout);
  4312. if (!manager.queryConnection(connectionId))
  4313. {
  4314. manager.unlock(tree->queryServerId(), connectionId);
  4315. throw MakeSDSException(SDSExcpt_AbortDuringConnection, " during changeMode");
  4316. }
  4317. mb.append((int) DAMP_SDSREPLY_OK);
  4318. break;
  4319. }
  4320. case DAMP_SDSCMD_GETXPATHS:
  4321. case DAMP_SDSCMD_GETXPATHSPLUSIDS:
  4322. {
  4323. __int64 serverId;
  4324. mb.read(serverId);
  4325. mb.read(xpath);
  4326. if (queryTransactionLogging())
  4327. transactionLog.log("xpath='%s'", xpath.get());
  4328. mb.clear();
  4329. Owned<IPropertyTree> matchTree = SDSManager->getXPaths(serverId, xpath, DAMP_SDSCMD_GETXPATHSPLUSIDS==action);
  4330. if (matchTree)
  4331. {
  4332. mb.append((int) DAMP_SDSREPLY_OK);
  4333. matchTree->serialize(mb);
  4334. }
  4335. else
  4336. mb.append((int) DAMP_SDSREPLY_EMPTY);
  4337. break;
  4338. }
  4339. case DAMP_SDSCMD_GETXPATHSCRITERIA:
  4340. {
  4341. StringAttr matchXPath, sortBy;
  4342. bool caseinsensitive, ascending;
  4343. unsigned from, limit;
  4344. mb.read(xpath);
  4345. mb.read(matchXPath);
  4346. mb.read(sortBy);
  4347. mb.read(caseinsensitive);
  4348. mb.read(ascending);
  4349. mb.read(from);
  4350. mb.read(limit);
  4351. if (queryTransactionLogging())
  4352. {
  4353. transactionLog.log("xpath='%s',matchXPath='%s',sortBy='%s',acscending=%s,from=%d,limit=%d",
  4354. xpath.get(), matchXPath.get(), sortBy.get(),
  4355. ascending?"true":"false", from, limit);
  4356. }
  4357. mb.clear();
  4358. Owned<IPropertyTree> matchTree = SDSManager->getXPathsSortLimitMatchTree(xpath, matchXPath, sortBy, caseinsensitive, ascending, from, limit);
  4359. if (matchTree)
  4360. {
  4361. mb.append((int) DAMP_SDSREPLY_OK);
  4362. matchTree->serialize(mb);
  4363. }
  4364. else
  4365. mb.append((int) DAMP_SDSREPLY_EMPTY);
  4366. break;
  4367. }
  4368. case DAMP_SDSCMD_GETEXTVALUE:
  4369. {
  4370. __int64 serverId;
  4371. mb.read(serverId);
  4372. mb.clear().append((int) DAMP_SDSREPLY_OK);
  4373. if (queryTransactionLogging())
  4374. {
  4375. CServerRemoteTree *idTree = (CServerRemoteTree *) SDSManager->queryRegisteredTree(serverId);
  4376. transactionLog.log("%s", idTree?idTree->queryName():"???");
  4377. }
  4378. SDSManager->getExternalValueFromServerId(serverId, mb);
  4379. break;
  4380. }
  4381. case DAMP_SDSCMD_GETELEMENTSRAW:
  4382. {
  4383. CHECKEDDALIREADLOCKBLOCK(manager.dataRWLock, readWriteTimeout);
  4384. StringAttr _xpath;
  4385. mb.read(_xpath);
  4386. if (queryTransactionLogging())
  4387. transactionLog.log("%s", xpath.get());
  4388. CMessageBuffer replyMb;
  4389. replyMb.init(mb.getSender(), mb.getTag(), mb.getReplyTag());
  4390. replyMb.append((int)DAMP_SDSREPLY_OK);
  4391. unsigned pos = replyMb.length();
  4392. unsigned count = 0;
  4393. replyMb.append(count);
  4394. const char *xpath = _xpath.get();
  4395. if ('/' == *xpath) ++xpath;
  4396. Owned<IPropertyTreeIterator> iter = manager.queryRoot()->getElements(xpath);
  4397. ForEach (*iter)
  4398. {
  4399. ++count;
  4400. IPropertyTree &e = iter->query();
  4401. e.serialize(replyMb);
  4402. }
  4403. replyMb.writeDirect(pos,sizeof(count),&count);
  4404. mb.clear();
  4405. mb.transferFrom(replyMb);
  4406. break;
  4407. }
  4408. case DAMP_SDSCMD_GETCOUNT:
  4409. {
  4410. mb.read(xpath);
  4411. if (queryTransactionLogging())
  4412. transactionLog.log("xpath='%s'", xpath.get());
  4413. CHECKEDDALIREADLOCKBLOCK(manager.dataRWLock, readWriteTimeout);
  4414. mb.clear();
  4415. mb.append((int)DAMP_SDSREPLY_OK);
  4416. mb.append(manager.queryCount(xpath));
  4417. break;
  4418. }
  4419. default:
  4420. throwUnexpected();
  4421. }
  4422. }
  4423. catch (IException *e)
  4424. {
  4425. mb.clear();
  4426. mb.append((int) DAMP_SDSREPLY_ERROR);
  4427. StringBuffer s;
  4428. e->errorMessage(s);
  4429. // NB: wanted to do this in a catch (IPTreeException *) block, but did catch,
  4430. // in spite of being able to query with dynamic cast
  4431. // something to do with rethrow, if I changed to catch early as IPT then it would catch here correctly.
  4432. if (QUERYINTERFACE(e, IPTreeException))
  4433. {
  4434. s.append(" in xpath '").append(xpath).append("'");
  4435. e->Release();
  4436. e = MakeSDSException(SDSExcpt_IPTError, "%s", s.str());
  4437. }
  4438. mb.append(e->errorCode());
  4439. mb.append(e->errorMessage(s.clear()));
  4440. StringBuffer clientUrl("EXCEPTION in reply to client ");
  4441. mb.getSender().getUrlStr(clientUrl);
  4442. EXCLOG(e, clientUrl.str(), MSGCLS_warning);
  4443. e->Release();
  4444. }
  4445. catch (DALI_CATCHALL)
  4446. {
  4447. Owned<IException> e = MakeSDSException(-1, "Unknown server exception processing client action: %d", action);
  4448. mb.clear();
  4449. mb.append((int) DAMP_SDSREPLY_ERROR);
  4450. StringBuffer s;
  4451. mb.append(e->errorCode());
  4452. mb.append(e->errorMessage(s).str());
  4453. StringBuffer clientUrl("EXCEPTION in reply to client ");
  4454. mb.getSender().getUrlStr(clientUrl);
  4455. LOG(MCoperatorError, unknownJob, e);
  4456. }
  4457. try {
  4458. CheckTime block10("DAMP_REQUEST reply");
  4459. coven.reply(mb);
  4460. }
  4461. catch (IMP_Exception *e)
  4462. {
  4463. LOG(MCwarning, unknownJob, e, "Failed to reply to client (processMessage)");
  4464. e->Release();
  4465. }
  4466. catch (IException *e)
  4467. {
  4468. // attempt error reply, on failed initial reply, reply error *might* have been message sensitive, e.g. OOM.
  4469. mb.clear();
  4470. mb.append((int) DAMP_SDSREPLY_ERROR);
  4471. mb.append(e->errorCode());
  4472. StringBuffer s;
  4473. mb.append(e->errorMessage(s).str());
  4474. StringBuffer clientUrl("EXCEPTION in reply to client ");
  4475. mb.getSender().getUrlStr(clientUrl);
  4476. EXCLOG(e, clientUrl.str(), MSGCLS_warning);
  4477. e->Release();
  4478. try
  4479. {
  4480. coven.reply(mb);
  4481. LOG(MCdebugInfo(100), unknownJob, "Failed to reply, but succeeded sending initial reply error to client");
  4482. }
  4483. catch (IException *e)
  4484. {
  4485. LOG(MCwarning, unknownJob, e, "Failed to reply and failed to send reply error to client");
  4486. e->Release();
  4487. }
  4488. }
  4489. }
  4490. void CSDSTransactionServer::stop()
  4491. {
  4492. if (!stopped) {
  4493. stopped = true;
  4494. queryCoven().cancel(RANK_ALL, MPTAG_DALI_SDS_REQUEST);
  4495. }
  4496. PROGLOG("clearing remaining sds locks");
  4497. manager.clearSDSLocks();
  4498. PROGLOG("waiting for transaction server to stop");
  4499. join();
  4500. }
  4501. /////////////////
  4502. // CServerConnection impl.
  4503. IPropertyTree *CServerConnection::queryRoot()
  4504. {
  4505. if (((CServerRemoteTree *)root.get())->isOrphaned())
  4506. throw MakeSDSException(SDSExcpt_OrphanedNode, "%s", queryXPath());
  4507. return root;
  4508. }
  4509. ////////////////
  4510. void CLockInfo::clearLastRef()
  4511. {
  4512. if (parent)
  4513. {
  4514. CPendingLockBlock b(*this); // carefully placed, removePending can destroy this.
  4515. parent->removeTree(child);
  4516. parent.clear();
  4517. child.clear();
  4518. }
  4519. }
  4520. ////////////////
  4521. class ConnectionIdHashTable : public SuperHashTableOf<ConnectionId, ConnectionId>
  4522. {
  4523. public:
  4524. ~ConnectionIdHashTable() { kill(); }
  4525. IMPLEMENT_SUPERHASHTABLEOF_REF_FIND(ConnectionId, ConnectionId);
  4526. virtual void onAdd(void *et) { }
  4527. virtual void onRemove(void *et) { delete (ConnectionId *)et; }
  4528. virtual unsigned getHashFromElement(const void *et) const
  4529. {
  4530. return hashc((const unsigned char *) et, sizeof(ConnectionId), 0);
  4531. }
  4532. virtual unsigned getHashFromFindParam(const void *fp) const
  4533. {
  4534. return hashc((const unsigned char *) fp, sizeof(ConnectionId), 0);
  4535. }
  4536. virtual const void *getFindParam(const void *et) const
  4537. {
  4538. return et;
  4539. }
  4540. virtual bool matchesFindParam(const void *et, const void *fp, unsigned) const
  4541. {
  4542. return *(ConnectionId *)et == *(ConnectionId *)fp;
  4543. }
  4544. };
  4545. static bool retryRename(const char *from, const char *to, unsigned maxAttempts, unsigned delay)
  4546. {
  4547. unsigned attempts=maxAttempts;
  4548. loop
  4549. {
  4550. OwnedIFile iFile = createIFile(from);
  4551. try
  4552. {
  4553. iFile->rename(to);
  4554. break;
  4555. }
  4556. catch (IException *e)
  4557. {
  4558. StringBuffer errTxt("Failed to rename: ");
  4559. EXCLOG(e, errTxt.append(from).append(" to ").append(to).append(", retrying...").str());
  4560. e->Release();
  4561. }
  4562. if (attempts && 0 == --attempts)
  4563. break;
  4564. MilliSleep(delay);
  4565. }
  4566. return (attempts>0);
  4567. }
  4568. #ifdef NODELETE
  4569. static bool retryCopy(const char *from, const char *to, unsigned maxAttempts, unsigned delay)
  4570. {
  4571. unsigned attempts=maxAttempts;
  4572. loop
  4573. {
  4574. StringBuffer _from;
  4575. StringBuffer fname;
  4576. splitFilename(from, &_from, &_from, &fname, &fname);
  4577. _from.append('_').append(fname);
  4578. OwnedIFile iFile = createIFile(from);
  4579. try
  4580. {
  4581. iFile->rename(_from.str());
  4582. copyFile(to, _from.str());
  4583. break;
  4584. }
  4585. catch (IException *e)
  4586. {
  4587. EXCLOG(e, NULL);
  4588. e->Release();
  4589. }
  4590. if (attempts && 0 == --attempts)
  4591. break;
  4592. DBGLOG("Failed to copy: %s to %s, retrying...", from, to);
  4593. MilliSleep(delay);
  4594. }
  4595. return (attempts>0);
  4596. }
  4597. #endif
  4598. inline unsigned nextEditionN(unsigned e, unsigned i=1)
  4599. {
  4600. return e+i;
  4601. }
  4602. inline unsigned prevEditionN(unsigned e, unsigned i=1)
  4603. {
  4604. return e-i;
  4605. }
  4606. void removeDaliFile(const char *path, const char *base, unsigned e)
  4607. {
  4608. StringBuffer filename(path);
  4609. constructStoreName(base, e, filename);
  4610. OwnedIFile iFile = createIFile(filename.str());
  4611. try
  4612. {
  4613. iFile->remove();
  4614. }
  4615. catch (IException *e)
  4616. {
  4617. EXCLOG(e, NULL);
  4618. e->Release();
  4619. }
  4620. }
  4621. // Ensure internally used branches are present
  4622. void initializeInternals(IPropertyTree *root)
  4623. {
  4624. ensurePTree(root, "Files");
  4625. ensurePTree(root, "Queues");
  4626. ensurePTree(root, "Groups");
  4627. ensurePTree(root, "Status");
  4628. ensurePTree(root, "WorkUnits");
  4629. ensurePTree(root, "JobQueues");
  4630. ensurePTree(root, "Environment");
  4631. ensurePTree(root, "Locks");
  4632. ensurePTree(root, "DFU");
  4633. ensurePTree(root, "DFU/RECOVERY");
  4634. ensurePTree(root, "DFU/WorkUnits");
  4635. ensurePTree(root, "Files/Relationships");
  4636. root->removeProp("Status/Servers");
  4637. root->addPropTree("Status/Servers",createPTree());
  4638. }
  4639. IPropertyTree *loadStore(const char *storeFilename, IPTreeMaker *iMaker, unsigned crcValidation, bool logErrorsOnly=false, const bool *abort=NULL)
  4640. {
  4641. CHECKEDCRITICALBLOCK(loadStoreCrit, fakeCritTimeout);
  4642. CHECKEDCRITICALBLOCK(saveStoreCrit, fakeCritTimeout);
  4643. Owned<IPropertyTree> root;
  4644. try
  4645. {
  4646. OwnedIFile iFileStore = createIFile(storeFilename);
  4647. OwnedIFileIO iFileIOStore = iFileStore->open(IFOread);
  4648. if (!iFileIOStore)
  4649. throw MakeSDSException(SDSExcpt_OpenStoreFailed, "%s", storeFilename);
  4650. Owned<IFileIOStream> fstream = createIOStream(iFileIOStore);
  4651. Owned<ICrcIOStream> crcPipeStream = createCrcPipeStream(fstream);
  4652. Owned<IIOStream> ios = createBufferedIOStream(crcPipeStream);
  4653. root.setown((CServerRemoteTree *) createPTree(*ios, ipt_none, ptr_ignoreWhiteSpace, iMaker));
  4654. ios.clear();
  4655. unsigned crc = crcPipeStream->queryCrc();
  4656. if (crcValidation && crc != crcValidation)
  4657. LOG(MCoperatorWarning, unknownJob, "Error processing store %s - CRC ERROR (file size=%"I64F"d, validation crc=%x, calculated crc=%x)", storeFilename, iFileIOStore->size(), crcValidation, crc); // not fatal yet (maybe later)
  4658. }
  4659. catch (IException *e)
  4660. {
  4661. if (!abort)
  4662. {
  4663. StringBuffer s("Exception - loading store file : ");
  4664. s.appendf("%s", storeFilename);
  4665. LOG(MCoperatorError, unknownJob, e, s.str());
  4666. }
  4667. if (SDSExcpt_OpenStoreFailed != e->errorCode())
  4668. if (!logErrorsOnly)
  4669. throw;
  4670. e->Release();
  4671. }
  4672. catch (DALI_CATCHALL)
  4673. {
  4674. IException *e = MakeStringException(0, "Unknown exception - loading store file : %s", storeFilename);
  4675. LOG(MCdisaster, unknownJob, e, "");
  4676. if (!logErrorsOnly)
  4677. throw;
  4678. e->Release();
  4679. }
  4680. return LINK(root);
  4681. }
  4682. // Not really coalescing, blocking transations and saving store (which will delete pending transactions).
  4683. class CLightCoalesceThread : public CInterface, implements ICoalesce
  4684. {
  4685. bool stopped, within24;
  4686. Semaphore sem;
  4687. unsigned writeTransactionsNow, lastSaveWriteTransactions, lastWarning;
  4688. unsigned idlePeriod, minimumTimeBetweenSaves, idleRate;
  4689. Linked<IPropertyTree> config;
  4690. Owned<IJlibDateTime> quietStartTime, quietEndTime;
  4691. CheckedCriticalSection crit;
  4692. IStoreHelper *iStoreHelper;
  4693. class CThreaded : public Thread
  4694. {
  4695. CLightCoalesceThread *coalesce;
  4696. public:
  4697. CThreaded() : Thread("CLightCoalesceThread") { coalesce = NULL; }
  4698. void init(CLightCoalesceThread *_coalesce) { coalesce = _coalesce; start(); }
  4699. virtual int run() { coalesce->main(); return 1; }
  4700. } threaded;
  4701. public:
  4702. IMPLEMENT_IINTERFACE;
  4703. CLightCoalesceThread(IPropertyTree &_config, IStoreHelper *_iStoreHelper) : config(&_config), iStoreHelper(_iStoreHelper)
  4704. {
  4705. stopped = false;
  4706. idlePeriod = config->getPropInt("@lCIdlePeriod", DEFAULT_LCIDLE_PERIOD)*1000;
  4707. minimumTimeBetweenSaves = config->getPropInt("@lCMinTime", DEFAULT_LCMIN_TIME)*1000;
  4708. idleRate = config->getPropInt("@lCIdleRate", DEFAULT_LCIDLE_RATE);
  4709. char const *quietStartTimeStr = config->queryProp("@lCQuietStartTime");
  4710. if (quietStartTimeStr)
  4711. {
  4712. if (*quietStartTimeStr)
  4713. {
  4714. quietStartTime.setown(createDateTime());
  4715. quietStartTime->setLocalTimeString(quietStartTimeStr);
  4716. quietStartTime->setGmtDate(1970, 1, 1);
  4717. }
  4718. else
  4719. quietStartTimeStr = NULL;
  4720. }
  4721. char const *quietEndTimeStr = config->queryProp("@lCQuietEndTime");
  4722. if (quietStartTimeStr && !quietEndTimeStr)
  4723. {
  4724. WARNLOG("Start time for quiet period specified without end time, ignoring times");
  4725. quietStartTime.clear();
  4726. }
  4727. else if (quietEndTimeStr && *quietEndTimeStr)
  4728. {
  4729. if (!quietStartTimeStr)
  4730. WARNLOG("End time for quiet period specified without start time, ignoring times");
  4731. else
  4732. {
  4733. quietEndTime.setown(createDateTime());
  4734. quietEndTime->setLocalTimeString(quietEndTimeStr);
  4735. quietEndTime->setGmtDate(1970, 1, 1);
  4736. within24 = quietStartTime->compare(*quietEndTime) <= 0;
  4737. }
  4738. }
  4739. }
  4740. ~CLightCoalesceThread()
  4741. {
  4742. stop();
  4743. }
  4744. void main()
  4745. {
  4746. unsigned t = 0;
  4747. lastSaveWriteTransactions = SDSManager->writeTransactions;
  4748. lastWarning = 0;
  4749. unsigned lastEdition = iStoreHelper->queryCurrentEdition();
  4750. while (!stopped)
  4751. {
  4752. unsigned writeTransactionsNow = SDSManager->writeTransactions;
  4753. if (!sem.wait(idlePeriod))
  4754. {
  4755. if (writeTransactionsNow != lastSaveWriteTransactions)
  4756. {
  4757. if (quietStartTime)
  4758. {
  4759. Owned<IJlibDateTime> nowTime = createDateTimeNow();
  4760. nowTime->setGmtDate(1970, 1, 1);
  4761. if (within24)
  4762. if (!(nowTime->compare(*quietStartTime) >= 0 && nowTime->compare(*quietEndTime) <= 0))
  4763. continue; // if outside quiet period within 0-24
  4764. else if (nowTime->compare(*quietEndTime) > 0 && nowTime->compare(*quietStartTime) < 0)
  4765. continue; // if inside period excluded by quiet period
  4766. }
  4767. if (lastEdition == iStoreHelper->queryCurrentEdition()) // if not then something else has saved (e.g. probably sasha)
  4768. {
  4769. unsigned transactions = SDSManager->writeTransactions-writeTransactionsNow; // don't care about rollover.
  4770. if (0 == transactions ||
  4771. (0 != idleRate && idlePeriod>=60000 && (transactions/(idlePeriod/60000))<=idleRate))
  4772. {
  4773. StringBuffer filename;
  4774. iStoreHelper->getPrimaryLocation(filename);
  4775. iStoreHelper->getCurrentStoreFilename(filename);
  4776. OwnedIFile iFile = createIFile(filename);
  4777. CDateTime createTime, nowTime;
  4778. nowTime.setNow();
  4779. int diff = 0;
  4780. try
  4781. {
  4782. if (iFile->getTime(&createTime, NULL, NULL))
  4783. diff = ((int)nowTime.getSimple()-(int)createTime.getSimple())*1000;
  4784. }
  4785. catch (IException *e)
  4786. {
  4787. StringBuffer errMsg("failed to get createtime for : ");
  4788. errMsg.append(filename);
  4789. EXCLOG(e, errMsg.str());
  4790. e->Release();
  4791. }
  4792. int period;
  4793. if (diff<=0 || diff > (int)minimumTimeBetweenSaves) // <0 - createTime>nowTime, assume time skew and allow save.
  4794. {
  4795. period = minimumTimeBetweenSaves-idlePeriod;
  4796. if (0 > period) period = 0;
  4797. {
  4798. CHECKEDCRITICALBLOCK(saveStoreCrit, fakeCritTimeout);
  4799. SDSManager->blockingSave(&lastSaveWriteTransactions);
  4800. lastEdition = iStoreHelper->queryCurrentEdition();
  4801. }
  4802. t = lastWarning = 0;
  4803. }
  4804. else
  4805. period = minimumTimeBetweenSaves-diff;
  4806. sem.wait(period);
  4807. }
  4808. else
  4809. {
  4810. t += idlePeriod/1000;
  4811. if (t/3600 >= STORENOTSAVE_WARNING_PERIOD && ((t-lastWarning)/3600>(STORENOTSAVE_WARNING_PERIOD/2)))
  4812. {
  4813. WARNLOG("Store has not been saved for %d hours", t/3600);
  4814. lastWarning = t;
  4815. }
  4816. }
  4817. }
  4818. else
  4819. {
  4820. t = lastWarning = 0;
  4821. lastEdition = iStoreHelper->queryCurrentEdition();
  4822. }
  4823. }
  4824. }
  4825. }
  4826. }
  4827. // implements ICoalsce
  4828. virtual void start()
  4829. {
  4830. threaded.init(this);
  4831. }
  4832. virtual void stop()
  4833. {
  4834. if (!stopped)
  4835. {
  4836. stopped = true;
  4837. sem.signal();
  4838. threaded.join();
  4839. }
  4840. }
  4841. };
  4842. /////////////////
  4843. class CUnlockCallback : implements IUnlockCallback
  4844. { // NB: unblock() always called 1st, then block()
  4845. StringAttr xpath;
  4846. ConnectionId connectionId;
  4847. CServerRemoteTree &tree;
  4848. bool lockedForWrite, unlocked;
  4849. public:
  4850. CUnlockCallback(const char *_xpath, ConnectionId _connectionId, CServerRemoteTree &_tree) : xpath(_xpath), connectionId(_connectionId), tree(_tree), lockedForWrite(false), unlocked(false) { }
  4851. void block()
  4852. {
  4853. assertex(unlocked);
  4854. unsigned got = msTick();
  4855. if (lockedForWrite)
  4856. CHECKEDWRITELOCKENTER(SDSManager->dataRWLock, readWriteTimeout);
  4857. else
  4858. CHECKEDREADLOCKENTER(SDSManager->dataRWLock, readWriteTimeout);
  4859. CHECKEDCRITENTER(SDSManager->lockCrit, fakeCritTimeout);
  4860. unlocked = false;
  4861. unsigned e=msTick()-got;
  4862. if (e>readWriteSlowTracing)
  4863. {
  4864. StringBuffer s("TIME: CUnlockCallback(write=");
  4865. s.append(lockedForWrite).append(",xpath=").append(xpath).append(", connectionId=").appendf("%"I64F"x", connectionId).append(") took ").append(e);
  4866. DBGLOG("%s", s.str());
  4867. if (readWriteStackTracing)
  4868. PrintStackReport();
  4869. }
  4870. if (tree.isOrphaned())
  4871. throw MakeSDSException(SDSExcpt_OrphanedNode, "Whilst completing lock to %s", xpath.get());
  4872. }
  4873. void unblock()
  4874. {
  4875. unlocked = true;
  4876. lockedForWrite = SDSManager->dataRWLock.queryWriteLocked();
  4877. CHECKEDCRITLEAVE(SDSManager->lockCrit);
  4878. if (lockedForWrite)
  4879. SDSManager->dataRWLock.unlockWrite();
  4880. else
  4881. SDSManager->dataRWLock.unlockRead();
  4882. }
  4883. };
  4884. class CStoreHelper : public CInterface, implements IStoreHelper
  4885. {
  4886. StringAttr storeName, location, remoteBackupLocation;
  4887. CStoreInfo storeInfo, deltaInfo;
  4888. unsigned configFlags;
  4889. const bool *abort;
  4890. unsigned delay, keepStores;
  4891. SessionId mySessId;
  4892. void clearStoreInfo(const char *base, const char *location, unsigned edition, CStoreInfo *storeInfo=NULL)
  4893. {
  4894. StringBuffer wcard;
  4895. wcard.append(base).append(".*");
  4896. StringBuffer path, filename;
  4897. filename.append(base).append('.').append(edition);
  4898. if (location) path.append(location);
  4899. path.append(filename);
  4900. if (!storeInfo || !storeInfo->cache)
  4901. {
  4902. Owned<IDirectoryIterator> dIter = createDirectoryIterator(location, wcard.str());
  4903. ForEach (*dIter)
  4904. {
  4905. loop
  4906. {
  4907. try { dIter->query().remove(); break; }
  4908. catch (IException *e)
  4909. {
  4910. e->Release();
  4911. if (abort && *abort)
  4912. return;
  4913. MilliSleep(delay);
  4914. }
  4915. }
  4916. }
  4917. }
  4918. else
  4919. {
  4920. if (0 != stricmp(filename.str(), storeInfo->cache))
  4921. {
  4922. StringBuffer path(location);
  4923. path.append(storeInfo->cache);
  4924. OwnedIFile iFile = createIFile(path.str());
  4925. loop
  4926. {
  4927. try { iFile->remove(); break; }
  4928. catch (IException *e)
  4929. {
  4930. e->Release();
  4931. if (abort && *abort)
  4932. return;
  4933. MilliSleep(delay);
  4934. }
  4935. }
  4936. }
  4937. storeInfo->cache.clear();
  4938. }
  4939. }
  4940. void writeStoreInfo(const char *base, const char *location, unsigned edition, unsigned *crc, CStoreInfo *storeInfo=NULL)
  4941. {
  4942. StringBuffer path, filename;
  4943. filename.append(base).append('.').append(edition);
  4944. if (location) path.append(location);
  4945. path.append(filename);
  4946. OwnedIFile iFile = createIFile(path.str());
  4947. OwnedIFileIO iFileIO = iFile->open(IFOcreate);
  4948. if (crc)
  4949. iFileIO->write(0, sizeof(unsigned), crc);
  4950. if (storeInfo)
  4951. storeInfo->cache.set(filename.str());
  4952. }
  4953. void updateStoreInfo(const char *base, const char *location, unsigned edition, unsigned *crc, CStoreInfo *storeInfo=NULL)
  4954. {
  4955. clearStoreInfo(base, location, edition, storeInfo);
  4956. writeStoreInfo(base, location, edition, crc, storeInfo);
  4957. }
  4958. void refreshInfo(CStoreInfo &info, const char *base)
  4959. {
  4960. OwnedIFile found;
  4961. OwnedIFileIO iFileIO;
  4962. if (info.cache.length()) // avoid directory lookup if poss.
  4963. {
  4964. StringBuffer path(location);
  4965. OwnedIFile iFile = createIFile(path.append(info.cache).str());
  4966. if (iFile->exists())
  4967. {
  4968. found.set(iFile);
  4969. try { iFileIO.setown(found->open(IFOread)); }
  4970. catch (IException *e)
  4971. {
  4972. e->Release();
  4973. }
  4974. }
  4975. }
  4976. if (!iFileIO)
  4977. {
  4978. StringBuffer wcard;
  4979. wcard.append(base).append(".*");
  4980. Owned<IDirectoryIterator> dIter = createDirectoryIterator(location, wcard.str());
  4981. unsigned totalDelays = 0;
  4982. loop
  4983. {
  4984. if (dIter->first())
  4985. {
  4986. const char *name = dIter->query().queryFilename();
  4987. StringBuffer base, ext, fname;
  4988. splitFilename(name, NULL, NULL, &base, &ext);
  4989. fname.append(base).append(ext);
  4990. info.cache.set(fname.str());
  4991. found.set(&dIter->query());
  4992. try { iFileIO.setown(found->open(IFOread)); }
  4993. catch (IException *e)
  4994. {
  4995. e->Release();
  4996. }
  4997. if (iFileIO)
  4998. break;
  4999. }
  5000. totalDelays++;
  5001. if (totalDelays >= MAXDELAYS)
  5002. throw MakeSDSException(SDSExcpt_StoreInfoMissing, "store.<edition> file appears to be missing");
  5003. if (abort && *abort)
  5004. return;
  5005. MilliSleep(delay);
  5006. }
  5007. }
  5008. assertex(iFileIO);
  5009. StringBuffer tail, ext, fname;
  5010. splitFilename(found->queryFilename(), NULL, NULL, &tail, &ext);
  5011. fname.append(tail).append(ext);
  5012. const char *name = fname.str();
  5013. const char *editionBegin = name+strlen(base)+1;
  5014. info.edition = atoi(editionBegin);
  5015. if (iFileIO->size())
  5016. iFileIO->read(0, sizeof(unsigned), &info.crc);
  5017. else
  5018. info.crc = 0;
  5019. }
  5020. void refreshStoreInfo() { refreshInfo(storeInfo, "store"); }
  5021. void refreshDeltaInfo() { refreshInfo(deltaInfo, "store"); }
  5022. void checkInfo(const char *base, CStoreInfo &info)
  5023. {
  5024. StringBuffer wcard;
  5025. wcard.append(base).append(".*");
  5026. Owned<IDirectoryIterator> dIter = createDirectoryIterator(location, wcard.str());
  5027. if (!dIter->first())
  5028. updateStoreInfo(base, location, 0, NULL, &info);
  5029. else if (dIter->next())
  5030. throw MakeStringException(0, "Multiple store.X files - only one corresponding to latest dalisds<X>.xml should exist");
  5031. }
  5032. void renameDelta(unsigned oldEdition, unsigned newEdition, const char *path)
  5033. {
  5034. StringBuffer deltaName(path);
  5035. constructStoreName(DELTANAME, oldEdition, deltaName);
  5036. OwnedIFile oldDelta = createIFile(deltaName.str());
  5037. if (oldDelta->exists())
  5038. {
  5039. deltaName.clear();
  5040. constructStoreName(DELTANAME, newEdition, deltaName);
  5041. oldDelta->rename(deltaName.str());
  5042. }
  5043. }
  5044. struct CheckDeltaBlock
  5045. {
  5046. CheckDeltaBlock(CStoreHelper &_storeHelper) : storeHelper(_storeHelper)
  5047. {
  5048. bool created = false;
  5049. StringBuffer deltaIPStr(storeHelper.location);
  5050. OwnedIFile deltaIPIFile = createIFile(deltaIPStr.append(DELTAINPROGRESS).str());
  5051. activeDetachIPStr.append(DETACHINPROGRESS);
  5052. inactiveDetachIPStr.append(storeHelper.location).append('_').append(DETACHINPROGRESS);
  5053. detachIPIFile.setown(createIFile(inactiveDetachIPStr.str()));
  5054. OwnedIFileIO detachIPIO = detachIPIFile->open(IFOcreate);
  5055. detachIPIO->write(0, sizeof(storeHelper.mySessId), &storeHelper.mySessId);
  5056. detachIPIO.clear();
  5057. detachIPIFile->rename(activeDetachIPStr.str());
  5058. // check often do not wait any longer than necessary
  5059. unsigned d=0;
  5060. while (deltaIPIFile->exists())
  5061. {
  5062. if (0 == d++ % 50)
  5063. PROGLOG("Waiting for a saveDelta in progress");
  5064. MilliSleep(100);
  5065. }
  5066. }
  5067. ~CheckDeltaBlock()
  5068. {
  5069. if (detachIPIFile)
  5070. {
  5071. unsigned a=0;
  5072. loop
  5073. {
  5074. try { detachIPIFile->remove(); break; }
  5075. catch (IException *e)
  5076. {
  5077. EXCLOG(e, "removing detach file marker");
  5078. if (a++ > 10) throw;
  5079. e->Release();
  5080. }
  5081. MilliSleep(500);
  5082. }
  5083. }
  5084. }
  5085. private:
  5086. CStoreHelper &storeHelper;
  5087. OwnedIFile detachIPIFile;
  5088. StringBuffer activeDetachIPStr, inactiveDetachIPStr;
  5089. };
  5090. public:
  5091. IMPLEMENT_IINTERFACE;
  5092. CStoreHelper(const char *_storeName, const char *_location, const char *_remoteBackupLocation, unsigned _configFlags, unsigned _keepStores, unsigned _delay, const bool *_abort) : storeName(_storeName), location(_location), remoteBackupLocation(_remoteBackupLocation), configFlags(_configFlags), keepStores(_keepStores), delay(_delay), abort(_abort)
  5093. {
  5094. mySessId = daliClientActive()?myProcessSession():0;
  5095. if (!keepStores) keepStores = DEFAULT_KEEP_LASTN_STORES;
  5096. checkInfo("store", storeInfo);
  5097. checkInfo("store", deltaInfo);
  5098. if (0 == (SH_External & configFlags))
  5099. {
  5100. refreshStoreInfo();
  5101. unsigned edition = storeInfo.edition;
  5102. Owned<IDirectoryIterator> di = createDirectoryIterator(location, "dali*.xml");
  5103. ForEach (*di)
  5104. {
  5105. StringBuffer fname;
  5106. di->getName(fname);
  5107. if ('_' != fname.charAt(7)) // Unhelpful naming convention to differentiate store files from externals!
  5108. {
  5109. if (0 == memicmp("inc", fname.toCharArray()+4, 3) || 0 == memicmp("sds", fname.toCharArray()+4, 3))
  5110. {
  5111. const char *num = fname.toCharArray()+7;
  5112. const char *dot = (const char *)strchr(num, '.');
  5113. unsigned fileEdition = atoi_l(num, dot-num);
  5114. int d = (int)fileEdition-(int)edition;
  5115. if (edition != fileEdition && (d>=1 || d<(-(int)keepStores)))
  5116. {
  5117. IFile &file = di->query();
  5118. CDateTime dt;
  5119. dt.setNow();
  5120. StringBuffer newName(file.queryFilename());
  5121. newName.append('.');
  5122. unsigned i=newName.length();
  5123. dt.getString(newName); // base on date, incase any old copies.
  5124. for (;i<newName.length();i++)
  5125. if (newName.charAt(i)==':')
  5126. newName.setCharAt(i,'_');
  5127. newName.append(".unused");
  5128. PROGLOG("Detected spurious data file : '%s' - renaming to %s", file.queryFilename(), newName.str());
  5129. try
  5130. {
  5131. file.rename(newName.str());
  5132. }
  5133. catch (IException *e) // safe to ignore these (should e.g. files be in use).
  5134. {
  5135. EXCLOG(e, NULL);
  5136. e->Release();
  5137. }
  5138. }
  5139. }
  5140. }
  5141. }
  5142. StringBuffer dst(location);
  5143. addPathSepChar(dst);
  5144. dst.append(DEBUG_DIR);
  5145. addPathSepChar(dst);
  5146. OwnedIFile dFile = createIFile(dst.str());
  5147. Owned<IDirectoryIterator> dIter = dFile->directoryFiles();
  5148. ForEach(*dIter)
  5149. dIter->query().remove();
  5150. }
  5151. }
  5152. virtual StringBuffer &getDetachedDeltaName(StringBuffer &detachName)
  5153. {
  5154. refreshDeltaInfo();
  5155. constructStoreName(DELTADETACHED, deltaInfo.edition, detachName);
  5156. return detachName;
  5157. }
  5158. virtual bool loadDelta(const char *filename, IFile *iFile, IPropertyTree *root)
  5159. {
  5160. Owned<IFileIO> iFileIO = iFile->open(IFOread);
  5161. if (!iFileIO) // no delta to load
  5162. return true;
  5163. MemoryBuffer tmp;
  5164. char *ptr = (char *) tmp.reserveTruncate(strlen(deltaHeader));
  5165. unsigned embeddedCrc = 0;
  5166. offset_t pos = 0;
  5167. bool hasCrcHeader = false; // check really only needed for deltas proceeding CRC header
  5168. if (strlen(deltaHeader) == iFileIO->read(0, strlen(deltaHeader), ptr))
  5169. {
  5170. if (0 == memicmp(deltaHeader, ptr, 5))
  5171. {
  5172. pos = deltaHeaderSizeStart;
  5173. hasCrcHeader = true;
  5174. embeddedCrc = (unsigned)atoi64_l(ptr+deltaHeaderCrcOff, 10);
  5175. if (0 == memicmp(deltaHeader+deltaHeaderSizeStart, ptr+deltaHeaderSizeStart, 6)) // has <SIZE> too
  5176. {
  5177. pos = strlen(deltaHeader);
  5178. offset_t lastGood;
  5179. if (sscanf(ptr+deltaHeaderSizeOff, "%"I64F"X", &lastGood))
  5180. {
  5181. offset_t fSize = iFileIO->size();
  5182. if (fSize > lastGood)
  5183. {
  5184. size32_t diff = fSize - lastGood;
  5185. LOG(MCoperatorError, unknownJob, "Delta file '%s', has %d bytes of trailing data (possible power loss during save?), file size: %"I64F"d, last committed size: %"I64F"d", filename, diff, fSize, lastGood);
  5186. LOG(MCoperatorError, unknownJob, "Resetting delta file '%s' to size: %"I64F"d", filename, lastGood);
  5187. iFileIO->close();
  5188. backup(filename);
  5189. iFileIO.setown(iFile->open(IFOreadwrite));
  5190. iFileIO->setSize(lastGood);
  5191. iFileIO->close();
  5192. iFileIO.setown(iFile->open(IFOread));
  5193. }
  5194. }
  5195. }
  5196. }
  5197. }
  5198. OwnedIFileIOStream iFileIOStream = createIOStream(iFileIO);
  5199. iFileIOStream->seek(pos, IFSbegin);
  5200. Owned<ICrcIOStream> crcPipeStream = createCrcPipeStream(iFileIOStream); // crc *rest* of stream
  5201. Owned<IIOStream> ios = createBufferedIOStream(crcPipeStream);
  5202. bool noErrors;
  5203. Owned<IException> deltaE;
  5204. noErrors = applyXmlDeltas(*root, *ios, 0 == (SH_RecoverFromIncErrors & configFlags));
  5205. if (noErrors && hasCrcHeader)
  5206. {
  5207. unsigned crc = crcPipeStream->queryCrc();
  5208. if (embeddedCrc != crc)
  5209. {
  5210. noErrors = false;
  5211. StringBuffer s;
  5212. LOG(MCoperatorWarning, unknownJob, "%s", s.append("Delta '").append(filename).append("' crc mismatch").str());
  5213. }
  5214. }
  5215. return noErrors;
  5216. }
  5217. virtual bool loadDeltas(IPropertyTree *root, bool *errors)
  5218. {
  5219. bool res = false;
  5220. if (errors) *errors = false;
  5221. StringBuffer deltaFilename(location);
  5222. constructStoreName(DELTANAME, storeInfo.edition, deltaFilename);
  5223. StringBuffer detachPath(location);
  5224. OwnedIFile detachedDeltaIFile = createIFile(getDetachedDeltaName(detachPath).str());
  5225. bool detached = detachedDeltaIFile->exists();
  5226. OwnedIFile deltaIFile = createIFile(deltaFilename.str());
  5227. loop
  5228. {
  5229. StringAttr filename;
  5230. IFile *iFile;
  5231. if (detached)
  5232. {
  5233. iFile = detachedDeltaIFile;
  5234. filename.set(iFile->queryFilename());
  5235. }
  5236. else
  5237. {
  5238. iFile = deltaIFile;
  5239. filename.set(iFile->queryFilename());
  5240. if (!iFile->exists())
  5241. break;
  5242. }
  5243. PROGLOG("Loading delta: %s", filename.get());
  5244. bool noError;
  5245. Owned<IException> deltaE;
  5246. try { noError = loadDelta(filename, iFile, root); }
  5247. catch (IException *e) { deltaE.setown(e); noError = false; }
  5248. if (!noError)
  5249. {
  5250. backup(filename);
  5251. if (errors) *errors = true;
  5252. if (deltaE)
  5253. throw LINK(deltaE);
  5254. }
  5255. res = true;
  5256. if (detached)
  5257. detached = false;
  5258. else
  5259. break;
  5260. }
  5261. return res;
  5262. }
  5263. virtual bool detachCurrentDelta()
  5264. {
  5265. StringBuffer deltaFilename(location);
  5266. getCurrentDeltaFilename(deltaFilename);
  5267. refreshStoreInfo();
  5268. bool res = false;
  5269. try
  5270. {
  5271. CheckDeltaBlock cD(*this);
  5272. OwnedIFile deltaIFile = createIFile(deltaFilename.str());
  5273. if (deltaIFile->exists())
  5274. {
  5275. #ifdef NODELETE
  5276. StringBuffer detachPath(location);
  5277. getDetachedDeltaName(detachPath);
  5278. if (retryCopy(deltaFilename.str(), detachPath.str(), 5, delay))
  5279. #else
  5280. StringBuffer detachName;
  5281. getDetachedDeltaName(detachName);
  5282. if (retryRename(deltaFilename.str(), detachName.str(), 5, delay))
  5283. #endif
  5284. res = true;
  5285. }
  5286. if (remoteBackupLocation.length())
  5287. {
  5288. deltaFilename.clear().append(remoteBackupLocation);
  5289. getCurrentDeltaFilename(deltaFilename);
  5290. OwnedIFile iFile = createIFile(deltaFilename);
  5291. if (iFile->exists())
  5292. {
  5293. StringBuffer detachName;
  5294. getDetachedDeltaName(detachName);
  5295. iFile->rename(detachName.str());
  5296. }
  5297. }
  5298. }
  5299. catch (IException *e)
  5300. {
  5301. LOG(MCoperatorError, unknownJob, e, "detachCurrentDelta");
  5302. e->Release();
  5303. }
  5304. return res;
  5305. }
  5306. virtual void saveStore(IPropertyTree *root, unsigned *_newEdition, bool currentEdition=false)
  5307. {
  5308. LOG(MCdebugInfo(100), unknownJob, "Saving store");
  5309. refreshStoreInfo();
  5310. unsigned edition = storeInfo.edition;
  5311. unsigned newEdition = currentEdition?edition:nextEditionN(edition);
  5312. bool done = false;
  5313. try
  5314. {
  5315. unsigned crc = 0;
  5316. StringBuffer tmpStoreName;
  5317. OwnedIFileIO iFileIOTmpStore = createUniqueFile(location, TMPSAVENAME, NULL, tmpStoreName);
  5318. OwnedIFile iFileTmpStore = createIFile(tmpStoreName);
  5319. try
  5320. {
  5321. OwnedIFileIOStream fstream = createIOStream(iFileIOTmpStore);
  5322. Owned<ICrcIOStream> crcPipeStream = createCrcPipeStream(fstream);
  5323. Owned<IIOStream> ios = createBufferedIOStream(crcPipeStream);
  5324. #ifdef _DEBUG
  5325. toXML(root, *ios); // formatted (default)
  5326. #else
  5327. toXML(root, *ios, 0, 0);
  5328. #endif
  5329. ios.clear();
  5330. fstream.clear();
  5331. crc = crcPipeStream->queryCrc();
  5332. crcPipeStream.clear();
  5333. iFileIOTmpStore.clear();
  5334. }
  5335. catch (IException *e)
  5336. {
  5337. LOG(MCoperatorError, unknownJob, e, "Exception(1) - Error saving store file");
  5338. iFileIOTmpStore.clear();
  5339. iFileTmpStore->remove();
  5340. throw;
  5341. }
  5342. StringBuffer newStoreName;
  5343. constructStoreName(storeName, newEdition, newStoreName);
  5344. StringBuffer newStoreNamePath(location);
  5345. newStoreNamePath.append(newStoreName);
  5346. refreshStoreInfo();
  5347. if (storeInfo.edition != edition)
  5348. {
  5349. WARNLOG("Another process has updated the edition whilst saving the store: %s", newStoreNamePath.str());
  5350. iFileTmpStore->remove();
  5351. return;
  5352. }
  5353. try
  5354. {
  5355. OwnedIFile newStoreIFile = createIFile(newStoreNamePath.str());
  5356. newStoreIFile->remove();
  5357. iFileTmpStore->rename(newStoreName.str());
  5358. }
  5359. catch (IException *e)
  5360. {
  5361. StringBuffer errMsg;
  5362. EXCLOG(e, errMsg.append("Failed to rename new store to : ").append(newStoreNamePath).append(". Has already been created by another process?").str());
  5363. e->Release();
  5364. iFileTmpStore->remove();
  5365. return;
  5366. }
  5367. if (0 != (SH_CheckNewDelta & configFlags))
  5368. {
  5369. CheckDeltaBlock cD(*this);
  5370. try { renameDelta(edition, newEdition, location); }
  5371. catch (IException *e)
  5372. {
  5373. StringBuffer s("Exception(2) - Error saving store file");
  5374. LOG(MCoperatorError, unknownJob, e, s.str());
  5375. e->Release();
  5376. return;
  5377. }
  5378. if (remoteBackupLocation.length())
  5379. {
  5380. try { renameDelta(edition, newEdition, remoteBackupLocation); }
  5381. catch (IException *e)
  5382. {
  5383. LOG(MCoperatorError, unknownJob, e, "Failure handling backup");
  5384. e->Release();
  5385. }
  5386. }
  5387. clearStoreInfo("store", location, 0, NULL);
  5388. writeStoreInfo("store", location, newEdition, &crc, &storeInfo);
  5389. }
  5390. else
  5391. {
  5392. clearStoreInfo("store", location, 0, NULL);
  5393. writeStoreInfo("store", location, newEdition, &crc, &storeInfo);
  5394. }
  5395. try
  5396. {
  5397. if (remoteBackupLocation.length())
  5398. {
  5399. PROGLOG("Copying store to backup location");
  5400. StringBuffer rL(remoteBackupLocation);
  5401. constructStoreName(storeName, newEdition, rL);
  5402. copyFile(rL.str(), newStoreNamePath.str());
  5403. clearStoreInfo("store", remoteBackupLocation, 0, NULL);
  5404. writeStoreInfo("store", remoteBackupLocation, newEdition, &crc, &storeInfo);
  5405. PROGLOG("Copy done");
  5406. }
  5407. }
  5408. catch (IException *e)
  5409. {
  5410. StringBuffer s;
  5411. LOG(MCoperatorError, unknownJob, e, s.append("Failure to backup dali to remote location: ").append(remoteBackupLocation));
  5412. e->Release();
  5413. }
  5414. if (_newEdition)
  5415. *_newEdition = newEdition;
  5416. done = true;
  5417. LOG(MCdebugInfo(100), unknownJob, "Store saved");
  5418. }
  5419. catch (IException *e)
  5420. {
  5421. StringBuffer s("Exception(3) - Error saving store file");
  5422. LOG(MCoperatorError, unknownJob, e, s.str());
  5423. e->Release();
  5424. }
  5425. if (done)
  5426. {
  5427. #ifndef NODELETE
  5428. unsigned toDeleteEdition = prevEditionN(edition, keepStores+(currentEdition?1:0));
  5429. StringBuffer filename(location);
  5430. constructStoreName(storeName, toDeleteEdition, filename);
  5431. OwnedIFile iFile = createIFile(filename.str());
  5432. if (iFile->exists())
  5433. PROGLOG("Deleting old store: %s", filename.str());
  5434. removeDaliFile(location, storeName, toDeleteEdition);
  5435. removeDaliFile(location, DELTANAME, toDeleteEdition);
  5436. removeDaliFile(location, DELTADETACHED, toDeleteEdition);
  5437. if (remoteBackupLocation)
  5438. {
  5439. removeDaliFile(remoteBackupLocation, storeName, toDeleteEdition);
  5440. removeDaliFile(remoteBackupLocation, DELTANAME, toDeleteEdition);
  5441. removeDaliFile(remoteBackupLocation, DELTADETACHED, toDeleteEdition);
  5442. }
  5443. #endif
  5444. }
  5445. }
  5446. virtual unsigned queryCurrentEdition()
  5447. {
  5448. refreshStoreInfo();
  5449. return storeInfo.edition;
  5450. }
  5451. virtual StringBuffer &getCurrentStoreFilename(StringBuffer &res, unsigned *crc=NULL)
  5452. {
  5453. refreshStoreInfo();
  5454. constructStoreName(storeName, storeInfo.edition, res);
  5455. if (crc)
  5456. * crc = storeInfo.crc;
  5457. return res;
  5458. }
  5459. virtual StringBuffer &getCurrentDeltaFilename(StringBuffer &res, unsigned *crc=NULL)
  5460. {
  5461. refreshDeltaInfo();
  5462. constructStoreName(DELTANAME, deltaInfo.edition, res);
  5463. if (crc)
  5464. * crc = deltaInfo.crc; // TBD, combine into store.<edition>.<store_crc>.<delta_crc>
  5465. return res;
  5466. }
  5467. virtual StringBuffer &getCurrentStoreInfoFilename(StringBuffer &res)
  5468. {
  5469. refreshStoreInfo();
  5470. res.append(storeInfo.cache);
  5471. return res;
  5472. }
  5473. virtual void backup(const char *filename)
  5474. {
  5475. try
  5476. {
  5477. unsigned crc = getFileCRC(filename);
  5478. StringBuffer dst(location);
  5479. if (dst.length())
  5480. addPathSepChar(dst);
  5481. dst.append(DEBUG_DIR);
  5482. addPathSepChar(dst);
  5483. recursiveCreateDirectoryForFile(dst.str());
  5484. OwnedIFile dFile = createIFile(dst.str());
  5485. Owned<IDirectoryIterator> dIter = dFile->directoryFiles();
  5486. unsigned debugFiles = 0;
  5487. ForEach (*dIter) debugFiles++;
  5488. if (debugFiles >= 10) return;
  5489. StringBuffer fname(filename);
  5490. getFileNameOnly(fname);
  5491. dst.append(fname.str()).append('.').append(crc);
  5492. OwnedIFile backupIFile = createIFile(dst.str());
  5493. if (!backupIFile->exists()) // a copy could already have been made
  5494. {
  5495. PROGLOG("Backing up: %s", filename);
  5496. OwnedIFile iFile = createIFile(filename);
  5497. copyFile(backupIFile, iFile);
  5498. PROGLOG("Backup made: %s", dst.str());
  5499. }
  5500. }
  5501. catch (IException *e)
  5502. {
  5503. StringBuffer tmp;
  5504. EXCLOG(e, tmp.append("Failed to take backup of: ").append(filename).str());
  5505. e->Release();
  5506. }
  5507. }
  5508. virtual StringBuffer &getPrimaryLocation(StringBuffer &_location)
  5509. {
  5510. _location.append(location);
  5511. return _location;
  5512. }
  5513. virtual StringBuffer &getBackupLocation(StringBuffer &backupLocation)
  5514. {
  5515. backupLocation.append(remoteBackupLocation);
  5516. return backupLocation;
  5517. }
  5518. friend struct CheckDeltaBlock;
  5519. };
  5520. IStoreHelper *createStoreHelper(const char *storeName, const char *location, const char *remoteBackupLocation, unsigned configFlags, unsigned keepStores, unsigned delay, const bool *abort)
  5521. {
  5522. if (!storeName) storeName = "dalisds";
  5523. return new CStoreHelper(storeName, location, remoteBackupLocation, configFlags, keepStores, delay, abort);
  5524. }
  5525. ///////////////
  5526. #ifdef _MSC_VER
  5527. #pragma warning (push)
  5528. #pragma warning (disable : 4355) // 'this' : used in base member initializer list
  5529. #endif
  5530. CCovenSDSManager::CCovenSDSManager(ICoven &_coven, IPropertyTree &_config, const char *_dataPath)
  5531. : coven(_coven), config(_config), server(*this), dataPath(_dataPath)
  5532. {
  5533. config.Link();
  5534. restartOnError = config.getPropBool("@restartOnUnhandled");
  5535. root = NULL;
  5536. writeTransactions=0;
  5537. externalEnvironment = false;
  5538. ignoreExternals=false;
  5539. unsigned initNodeTableSize = queryCoven().getInitSDSNodes();
  5540. allNodes.ensure(initNodeTableSize?initNodeTableSize:INIT_NODETABLE_SIZE);
  5541. externalSizeThreshold = config.getPropInt("@externalSizeThreshold", DEFAULT_EXTERNAL_SIZE_THRESHOLD);
  5542. remoteBackupLocation.set(config.queryProp("@remoteBackupLocation"));
  5543. nextExternal = 1;
  5544. if (0 == coven.getServerRank())
  5545. {
  5546. if (coven.size() > 1)
  5547. {
  5548. unsigned s;
  5549. for (s=1; s<coven.size(); s++)
  5550. {
  5551. CMessageBuffer mb;
  5552. __int64 dummy=0;
  5553. mb.append(dummy);
  5554. coven.sendRecv(mb, s, MPTAG_DALI_SDS_REQUEST);
  5555. bool success;
  5556. mb.read(success);
  5557. assertex(success);
  5558. }
  5559. }
  5560. }
  5561. else
  5562. {
  5563. CMessageBuffer mb;
  5564. #ifdef TRACE_QWAITING
  5565. unsigned waiting = coven.probe(0,MPTAG_DALI_SDS_REQUEST,NULL);
  5566. if ((waiting!=0)&&(waiting%10==0))
  5567. DBGLOG("QPROBE: MPTAG_DALI_SDS_REQUEST.2 has %d waiting",waiting);
  5568. #endif
  5569. if (coven.recv(mb, 0, MPTAG_DALI_SDS_REQUEST, NULL))
  5570. {
  5571. __int64 dummy;
  5572. mb.read(dummy);
  5573. mb.clear().append(true); // denote success
  5574. coven.reply(mb);
  5575. }
  5576. else
  5577. assertex(false);
  5578. }
  5579. registerSubscriptionManager(SDS_PUBLISHER, this);
  5580. connectionSubscriptionManager.setown(new CConnectionSubscriptionManager());
  5581. nodeSubscriptionManager.setown(new CNodeSubscriptionManager(*this));
  5582. registerSubscriptionManager(SDSCONN_PUBLISHER, connectionSubscriptionManager.get());
  5583. registerSubscriptionManager(SDSNODE_PUBLISHER, nodeSubscriptionManager);
  5584. // add external handlers
  5585. Owned<CXMLFileExternal> xmlExternalHandler = new CXMLFileExternal(dataPath, backupHandler);
  5586. externalHandlers.replace(* new CExternalHandlerMapping(EF_XML, *xmlExternalHandler));
  5587. Owned<CLegacyBinaryFileExternal> legacyBinaryExternalHandler = new CLegacyBinaryFileExternal(dataPath, backupHandler);
  5588. externalHandlers.replace(* new CExternalHandlerMapping(EF_LegacyBinaryValue, *legacyBinaryExternalHandler));
  5589. Owned<CBinaryFileExternal> binaryExternalHandler = new CBinaryFileExternal(dataPath, backupHandler);
  5590. externalHandlers.replace(* new CExternalHandlerMapping(EF_BinaryValue, *binaryExternalHandler));
  5591. properties.setown(createPTree("Properties"));
  5592. IPropertyTree *clientProps = properties->setPropTree("Client", config.hasProp("Client") ? config.getPropTree("Client") : createPTree());
  5593. clientProps->setPropBool("@serverIterAvailable", true);
  5594. clientProps->setPropBool("@useAppendOpt", true);
  5595. clientProps->setPropBool("@serverGetIdsAvailable", true);
  5596. IPropertyTree *throttle = clientProps->setPropTree("Throttle", createPTree());
  5597. throttle->setPropInt("@limit", CLIENT_THROTTLE_LIMIT);
  5598. throttle->setPropInt("@delay", CLIENT_THROTTLE_DELAY);
  5599. // NB: dataPath is assumed to be local
  5600. RemoteFilename rfn;
  5601. if (dataPath.length())
  5602. rfn.setLocalPath(dataPath);
  5603. else
  5604. {
  5605. char cwd[1024];
  5606. if (!GetCurrentDirectory(1024, cwd)) {
  5607. ERRLOG("CCovenSDSManager: Current directory path too big, setting local path to null");
  5608. cwd[0] = 0;
  5609. }
  5610. rfn.setLocalPath(cwd);
  5611. }
  5612. unsigned keepLastN = config.getPropInt("@keepStores", DEFAULT_KEEP_LASTN_STORES);
  5613. StringBuffer path;
  5614. rfn.getRemotePath(path);
  5615. properties->setProp("@dataPathUrl", path.str());
  5616. properties->setPropInt("@keepStores", keepLastN);
  5617. if (remoteBackupLocation.length())
  5618. {
  5619. properties->setProp("@backupPathUrl", remoteBackupLocation.get());
  5620. backupHandler.init(remoteBackupLocation, config.getPropBool("@asyncBackup", true));
  5621. }
  5622. const char *storeName = config.queryProp("@store");
  5623. if (!storeName) storeName = "dalisds";
  5624. #if 1 // legacy
  5625. StringBuffer tail, ext;
  5626. splitFilename(storeName, NULL, NULL, &tail, &ext);
  5627. if (0 == stricmp(".xml", ext.str()))
  5628. {
  5629. config.setProp("@store", tail.str());
  5630. storeName = tail.str();
  5631. }
  5632. #endif
  5633. StringBuffer tmp(dataPath);
  5634. OwnedIFile inProgressIFile = createIFile(tmp.append(DELTAINPROGRESS).str());
  5635. inProgressIFile->remove();
  5636. OwnedIFile detachIPIFile = createIFile(tmp.append(DETACHINPROGRESS).str());
  5637. detachIPIFile->remove();
  5638. unsigned configFlags = config.getPropBool("@recoverFromIncErrors", true) ? SH_RecoverFromIncErrors : 0;
  5639. configFlags |= config.getPropBool("@backupErrorFiles", true) ? SH_BackupErrorFiles : 0;
  5640. iStoreHelper = createStoreHelper(storeName, dataPath, remoteBackupLocation, configFlags, keepLastN, 100, &server.queryStopped());
  5641. doTimeComparison = false;
  5642. if (config.getPropBool("@lightweightCoalesce", true))
  5643. coalesce.setown(new CLightCoalesceThread(config, iStoreHelper));
  5644. }
  5645. #ifdef _MSC_VER
  5646. #pragma warning (pop)
  5647. #endif
  5648. CCovenSDSManager::~CCovenSDSManager()
  5649. {
  5650. backupHandler.stop();
  5651. if (unhandledThread) unhandledThread->join();
  5652. if (coalesce) coalesce->stop();
  5653. scanNotifyPool.clear();
  5654. notifyPool.clear();
  5655. connections.kill();
  5656. ::Release(iStoreHelper);
  5657. if (!config.getPropBool("@leakStore", true)) // intentional default leak of time consuming deconstruction of tree
  5658. ::Release(root);
  5659. else
  5660. enableMemLeakChecking(false);
  5661. config.Release();
  5662. }
  5663. bool compareFiles(IFile *file1, IFile *file2, bool compareTimes=true)
  5664. {
  5665. if (file1->exists())
  5666. {
  5667. if (file2->exists())
  5668. {
  5669. if (file1->size() == file2->size())
  5670. {
  5671. if (!compareTimes) return true;
  5672. CDateTime modifiedTimeBackup;
  5673. file1->getTime(NULL, &modifiedTimeBackup, NULL);
  5674. CDateTime modifiedTime;
  5675. file2->getTime(NULL, &modifiedTime, NULL);
  5676. if (0 == modifiedTimeBackup.compare(modifiedTime, false))
  5677. return true;
  5678. }
  5679. }
  5680. }
  5681. else
  5682. return !file2->exists();
  5683. return false;
  5684. }
  5685. void CCovenSDSManager::validateBackup()
  5686. {
  5687. // check consistency of store info file.
  5688. StringBuffer storeInfoFilename(dataPath);
  5689. iStoreHelper->getCurrentStoreInfoFilename(storeInfoFilename);
  5690. OwnedIFile infoIFile = createIFile(storeInfoFilename.str());
  5691. if (infoIFile->exists())
  5692. {
  5693. StringBuffer rL(remoteBackupLocation);
  5694. iStoreHelper->getCurrentStoreInfoFilename(rL);
  5695. copyFile(rL.str(), storeInfoFilename.str());
  5696. }
  5697. // check consistency of delta
  5698. StringBuffer deltaFilename(dataPath);
  5699. iStoreHelper->getCurrentDeltaFilename(deltaFilename);
  5700. OwnedIFile iFileDelta = createIFile(deltaFilename.str());
  5701. deltaFilename.clear().append(remoteBackupLocation);
  5702. iStoreHelper->getCurrentDeltaFilename(deltaFilename);
  5703. OwnedIFile iFileDeltaBackup = createIFile(deltaFilename.str());
  5704. if (!compareFiles(iFileDeltaBackup, iFileDelta, false))
  5705. WARNLOG("Delta file backup doesn't exist or differs, filename=%s", deltaFilename.str());
  5706. // ensure there's a copy of the primary store present at startup.
  5707. StringBuffer storeFilename(dataPath);
  5708. iStoreHelper->getCurrentStoreFilename(storeFilename);
  5709. OwnedIFile iFileStore = createIFile(storeFilename.str());
  5710. storeFilename.clear().append(remoteBackupLocation);
  5711. iStoreHelper->getCurrentStoreFilename(storeFilename);
  5712. OwnedIFile iFileBackupStore = createIFile(storeFilename.str());
  5713. if (!compareFiles(iFileBackupStore, iFileStore))
  5714. WARNLOG("Store backup file doesn't exist or differs, filename=%s", storeFilename.str());
  5715. }
  5716. static int uint64compare(unsigned __int64 *i1, unsigned __int64 *i2)
  5717. {
  5718. if (*i1==*i2) return 0;
  5719. if (*i1<*i2) return -1;
  5720. return 1;
  5721. }
  5722. class CLegacyFmtItem : public CInterface
  5723. {
  5724. public:
  5725. CLegacyFmtItem(const char *_name, const char *_ext, unsigned __int64 _num) : name(_name), ext(_ext), num(_num) { }
  5726. StringAttr name, ext;
  5727. unsigned __int64 num;
  5728. };
  5729. static int extNcompareFunc(CInterface **_itm1, CInterface **_itm2)
  5730. {
  5731. CLegacyFmtItem *itm1 = *(CLegacyFmtItem **)_itm1;
  5732. CLegacyFmtItem *itm2 = *(CLegacyFmtItem **)_itm2;
  5733. if (itm1->num==itm2->num) return 0;
  5734. if (itm1->num<itm2->num) return -1;
  5735. return 1;
  5736. }
  5737. void CCovenSDSManager::loadStore(const char *storeName, const bool *abort)
  5738. {
  5739. if (root) root->Release();
  5740. class CNodeCreate : public CInterface, implements IPTreeNodeCreator
  5741. {
  5742. public:
  5743. IMPLEMENT_IINTERFACE;
  5744. virtual IPropertyTree *create(const char *tag) { return createServerTree(tag); }
  5745. } nodeCreator;
  5746. class CSDSTreeMaker : public CPTreeMaker
  5747. {
  5748. public:
  5749. CSDSTreeMaker(IPTreeNodeCreator *nodeCreator) : CPTreeMaker(ipt_none, nodeCreator) { }
  5750. virtual void endNode(const char *tag, unsigned length, const void *value, bool binary, offset_t endOffset)
  5751. {
  5752. IPropertyTree *node = queryCurrentNode();
  5753. CPTreeMaker::endNode(tag, length, value, binary, endOffset);
  5754. if (((CServerRemoteTree *)node)->testExternalCandidate())
  5755. convertQueue.append(*(CServerRemoteTree *)node);
  5756. }
  5757. ICopyArrayOf<CServerRemoteTree> convertQueue;
  5758. } treeMaker(&nodeCreator);
  5759. Owned<IPropertyTree> oldEnvironment;
  5760. try
  5761. {
  5762. bool saveNeeded = false;
  5763. if (!storeName)
  5764. storeName = config.queryProp("@store");
  5765. unsigned crc = 0;
  5766. StringBuffer storeFilename(dataPath);
  5767. iStoreHelper->getCurrentStoreFilename(storeFilename, &crc);
  5768. LOG(MCdebugInfo(100), unknownJob, "loading store %d, storedCrc=%x", iStoreHelper->queryCurrentEdition(), crc);
  5769. root = (CServerRemoteTree *)::loadStore(storeFilename.str(), &treeMaker, crc, false, abort);
  5770. if (!root)
  5771. {
  5772. StringBuffer s(storeName);
  5773. LOG(MCdebugInfo(100), unknownJob, "Store %d does not exist, creating new store", iStoreHelper->queryCurrentEdition());
  5774. root = new CServerRemoteTree("SDS");
  5775. }
  5776. bool errors;
  5777. Owned<IException> deltaE;
  5778. try { iStoreHelper->loadDeltas(root, &errors); }
  5779. catch (IException *e) { deltaE.setown(e); errors = true; }
  5780. if (errors && config.getPropBool("@backupErrorFiles", true))
  5781. {
  5782. iStoreHelper->backup(storeFilename.str());
  5783. if (deltaE.get())
  5784. throw LINK(deltaE);
  5785. }
  5786. LOG(MCdebugInfo(100), unknownJob, "store loaded");
  5787. const char *environment = config.queryProp("@environment");
  5788. if (environment && *environment)
  5789. {
  5790. LOG(MCdebugInfo(100), unknownJob, "loading external Environment from: %s", environment);
  5791. Owned<IFile> envFile = createIFile(environment);
  5792. if (!envFile->exists())
  5793. throw MakeStringException(0, "'%s' does not exist", environment);
  5794. OwnedIFileIO iFileIO = envFile->open(IFOread);
  5795. if (!iFileIO)
  5796. throw MakeStringException(0, "Failed to open '%s'", environment);
  5797. Owned<IPropertyTree> envTree = createPTreeFromXMLFile(environment);
  5798. if (0 != stricmp("Environment", envTree->queryName()))
  5799. throw MakeStringException(0, "External environment file '%s', has '%s' as root, expecting a 'Environment' xml node.", environment, envTree->queryName());
  5800. oldEnvironment.setown(root->getPropTree("Environment"));
  5801. root->removeTree(oldEnvironment);
  5802. root->addPropTree("Environment", envTree.getClear());
  5803. externalEnvironment = true;
  5804. }
  5805. UInt64Array refExts;
  5806. PROGLOG("Scanning store for external references");
  5807. Owned<IPropertyTreeIterator> rootIter = root->getElements("//*");
  5808. ForEach (*rootIter)
  5809. {
  5810. IPropertyTree &tree = rootIter->query();
  5811. __int64 index = tree.getPropInt64(EXT_ATTR);
  5812. if (index)
  5813. refExts.append(index);
  5814. }
  5815. PROGLOG("External reference count = %d", refExts.ordinality());
  5816. refExts.sort(uint64compare);
  5817. if (refExts.ordinality())
  5818. nextExternal = refExts.tos()+1; // JCSMORE could keep array and fill gaps
  5819. // build list of primary, backup and legacy type external files
  5820. CIArrayOf<CLegacyFmtItem> legacyFmts;
  5821. UInt64Array primaryExts, backupExts;
  5822. unsigned l = strlen(EXTERNAL_NAME_PREFIX);
  5823. bool primary = true;
  5824. Owned<IDirectoryIterator> di = createDirectoryIterator(dataPath);
  5825. loop
  5826. {
  5827. try
  5828. {
  5829. ForEach(*di)
  5830. {
  5831. StringBuffer fname;
  5832. di->getName(fname);
  5833. if (fname.length() > l && 0 == memicmp(EXTERNAL_NAME_PREFIX, fname.str(), l))
  5834. {
  5835. StringBuffer name, ext;
  5836. splitFilename(fname, NULL, NULL, &name, &ext);
  5837. if (ext.length())
  5838. {
  5839. ext.remove(0, 1); // delete '.'
  5840. if (0 != stricmp(EF_BinaryValue, ext.str()))
  5841. {
  5842. unsigned __int64 num = atoi64(name.str()+l);
  5843. legacyFmts.append(* new CLegacyFmtItem(name.str(), ext.str(), num));
  5844. }
  5845. #ifndef _WIN32 // win32 files are case insensitive, so no point in this step.
  5846. StringBuffer lfName(fname);
  5847. lfName.toLowerCase();
  5848. if (0 != strcmp(fname.str(), lfName.str()))
  5849. di->query().rename(lfName.str());
  5850. #endif
  5851. unsigned __int64 extN = atoi64(name.str()+l);
  5852. if (primary)
  5853. primaryExts.append(extN);
  5854. else
  5855. backupExts.append(extN);
  5856. }
  5857. }
  5858. }
  5859. }
  5860. catch (IException *e)
  5861. {
  5862. if (primary)
  5863. throw;
  5864. EXCLOG(e, NULL);
  5865. e->Release();
  5866. }
  5867. if (!primary || 0 == remoteBackupLocation.length())
  5868. break;
  5869. di.setown(createDirectoryIterator(remoteBackupLocation));
  5870. primary = false;
  5871. }
  5872. primaryExts.sort(uint64compare);
  5873. backupExts.sort(uint64compare);
  5874. // Compare list of primary/backup externals against referenced externals and issue warnings
  5875. // Copy over any if reference and present either only in primary or backup
  5876. IExternalHandler *extHandler = queryExternalHandler(EF_BinaryValue);
  5877. primary = true;
  5878. UInt64Array missingPrimarys;
  5879. loop
  5880. {
  5881. UInt64Array &fileExts = primary ? primaryExts : backupExts;
  5882. unsigned __int64 refN = refExts.ordinality() ? refExts.item(0) : (unsigned __int64)-1;
  5883. unsigned __int64 fileN = fileExts.ordinality() ? fileExts.item(0) : (unsigned __int64)-1;
  5884. unsigned fileP=0;
  5885. unsigned refP=0;
  5886. unsigned missP=0;
  5887. while (fileN != ((unsigned __int64)-1) || refN != ((unsigned __int64)-1))
  5888. {
  5889. while (fileN == refN)
  5890. {
  5891. if (!primary)
  5892. {
  5893. bool found = false;
  5894. while (missP < missingPrimarys.ordinality())
  5895. {
  5896. unsigned __int64 missN = missingPrimarys.item(missP);
  5897. if (refN == missN)
  5898. {
  5899. ++missP;
  5900. found = true;
  5901. break;
  5902. }
  5903. if (missN > refN)
  5904. break;
  5905. ++missP;
  5906. }
  5907. // i.e. found in backup, but was listed missing in primary
  5908. if (found)
  5909. {
  5910. StringBuffer fname;
  5911. StringBuffer name(EXTERNAL_NAME_PREFIX);
  5912. name.append(refN);
  5913. extHandler->getFilename(fname, name.str());
  5914. PROGLOG("Copying missing primary external from backup: %s", fname.str());
  5915. StringBuffer backupFname(remoteBackupLocation);
  5916. extHandler->getName(backupFname, name.str());
  5917. try
  5918. {
  5919. copyFile(fname.str(), backupFname.str());
  5920. }
  5921. catch (IException *e)
  5922. {
  5923. EXCLOG(e, NULL);
  5924. e->Release();
  5925. }
  5926. }
  5927. }
  5928. ++refP;
  5929. ++fileP;
  5930. refN = (refP == refExts.ordinality()) ? (unsigned __int64)-1 : refExts.item(refP);
  5931. fileN = (fileP == fileExts.ordinality()) ? (unsigned __int64)-1 : fileExts.item(fileP);
  5932. if (fileN == ((unsigned __int64)-1) || refN == ((unsigned __int64)-1))
  5933. break;
  5934. }
  5935. while (fileN < refN)
  5936. {
  5937. StringBuffer fname;
  5938. StringBuffer name(EXTERNAL_NAME_PREFIX);
  5939. name.append(fileN);
  5940. extHandler->getName(fname, name.str());
  5941. WARNLOG("Unreferenced %s external %s file", primary?"primary":"backup", fname.str());
  5942. ++fileP;
  5943. if (fileP == fileExts.ordinality())
  5944. {
  5945. fileN = (unsigned __int64)-1;
  5946. break;
  5947. }
  5948. fileN = fileExts.item(fileP);
  5949. }
  5950. while (refN < fileN)
  5951. {
  5952. StringBuffer fname;
  5953. StringBuffer name(EXTERNAL_NAME_PREFIX);
  5954. name.append(refN);
  5955. extHandler->getName(fname, name.str());
  5956. WARNLOG("External %s file reference %s missing", primary?"primary":"backup", fname.str());
  5957. if (primary)
  5958. missingPrimarys.append(refN);
  5959. else
  5960. {
  5961. bool found = false;
  5962. while (missP < missingPrimarys.ordinality())
  5963. {
  5964. unsigned __int64 missN = missingPrimarys.item(missP);
  5965. if (refN == missN)
  5966. {
  5967. ++missP;
  5968. found = true;
  5969. break;
  5970. }
  5971. if (missN > refN)
  5972. break;
  5973. ++missP;
  5974. }
  5975. if (!found)
  5976. {
  5977. // i.e. not missing in primary, but missing in backup
  5978. StringBuffer fname;
  5979. StringBuffer name(EXTERNAL_NAME_PREFIX);
  5980. name.append(refN);
  5981. extHandler->getFilename(fname, name.str());
  5982. PROGLOG("Copying missing backup external from primary: %s", fname.str());
  5983. StringBuffer backupFname(remoteBackupLocation);
  5984. extHandler->getName(backupFname, name.str());
  5985. try
  5986. {
  5987. copyFile(backupFname.str(), fname.str());
  5988. }
  5989. catch (IException *e)
  5990. {
  5991. EXCLOG(e, NULL);
  5992. e->Release();
  5993. }
  5994. }
  5995. }
  5996. ++refP;
  5997. if (refP == refExts.ordinality())
  5998. {
  5999. refN = (unsigned __int64)-1;
  6000. break;
  6001. }
  6002. refN = refExts.item(refP);
  6003. }
  6004. }
  6005. if (!primary || 0 == remoteBackupLocation.length())
  6006. break;
  6007. if (missingPrimarys.ordinality())
  6008. missingPrimarys.sort(uint64compare);
  6009. primary = false;
  6010. }
  6011. // check any marked with legacy formats
  6012. if (legacyFmts.ordinality() && refExts.ordinality())
  6013. {
  6014. legacyFmts.sort(extNcompareFunc);
  6015. unsigned refP = 0;
  6016. unsigned __int64 refN = refExts.item(refP++);
  6017. bool done = false;
  6018. ForEachItemIn(l, legacyFmts)
  6019. {
  6020. CLegacyFmtItem &itm = legacyFmts.item(l);
  6021. while (refN<itm.num)
  6022. {
  6023. if (refP == refExts.ordinality())
  6024. {
  6025. done = true;
  6026. break;
  6027. }
  6028. refN = refExts.item(refP++);
  6029. }
  6030. if (done)
  6031. break;
  6032. if (refN == itm.num)
  6033. {
  6034. IExternalHandler *extHandler = queryExternalHandler(itm.ext);
  6035. if (!extHandler)
  6036. {
  6037. WARNLOG("Unknown external extension, external=%s, extension=%s", itm.name.get(), itm.ext.get());
  6038. continue;
  6039. }
  6040. StringBuffer fname;
  6041. extHandler->getFilename(fname, itm.name);
  6042. PROGLOG("Converting legacy external type(%s) to new, file=%s", itm.ext.get(), fname.str());
  6043. MemoryBuffer mb;
  6044. Owned<IPropertyTree> tree = createPTree("tmp");
  6045. extHandler->read(itm.name, *tree, mb, true);
  6046. mb.append(""); // no children
  6047. tree.setown(createPTree(mb));
  6048. IExternalHandler *extHandlerNew = queryExternalHandler(EF_BinaryValue);
  6049. extHandlerNew->write(itm.name, *tree);
  6050. extHandler->remove(itm.name);
  6051. }
  6052. }
  6053. }
  6054. root->removeProp("External"); // remove legacy /External if present
  6055. unsigned items = treeMaker.convertQueue.ordinality();
  6056. if (items)
  6057. {
  6058. LOG(MCdebugInfo(100), unknownJob, "Converting %d items larger than threshold size %d, to external definitions", items, externalSizeThreshold);
  6059. ForEachItemIn(i, treeMaker.convertQueue)
  6060. SDSManager->writeExternal(treeMaker.convertQueue.item(i), true);
  6061. saveNeeded = true;
  6062. }
  6063. if (saveNeeded)
  6064. {
  6065. LOG(MCdebugInfo(100), unknownJob, "Saving converted store");
  6066. SDSManager->saveStore();
  6067. }
  6068. }
  6069. catch (IException *e)
  6070. {
  6071. LOG(MCoperatorError, unknownJob, e, "Exception - Failed to load main store");
  6072. throw;
  6073. }
  6074. catch (DALI_CATCHALL)
  6075. {
  6076. LOG(MCoperatorError, unknownJob, "Unknown exception - Failed to load main store");
  6077. throw;
  6078. }
  6079. if (!root)
  6080. {
  6081. root = (CServerRemoteTree *) createServerTree();
  6082. root->setName("root");
  6083. }
  6084. if (remoteBackupLocation.length())
  6085. {
  6086. try { validateBackup(); }
  6087. catch (IException *e) { LOG(MCoperatorError, unknownJob, e, "Validating backup"); e->Release(); }
  6088. StringBuffer deltaFilename(dataPath);
  6089. iStoreHelper->getCurrentDeltaFilename(deltaFilename);
  6090. OwnedIFile iFileDelta = createIFile(deltaFilename.str());
  6091. deltaFilename.clear().append(remoteBackupLocation);
  6092. iStoreHelper->getCurrentDeltaFilename(deltaFilename);
  6093. OwnedIFile iFileDeltaBackup = createIFile(deltaFilename.str());
  6094. CDateTime modifiedTime;
  6095. if (!iFileDelta->exists() && !iFileDeltaBackup->exists())
  6096. doTimeComparison = true;
  6097. else if (iFileDelta->getTime(NULL, &modifiedTime, NULL))
  6098. {
  6099. if (iFileDeltaBackup->setTime(NULL, &modifiedTime, NULL))
  6100. doTimeComparison = true;
  6101. }
  6102. if (!doTimeComparison)
  6103. LOG(MCoperatorWarning, unknownJob, "Unable to use time comparison when comparing delta backup file");
  6104. }
  6105. Owned<IRemoteConnection> conn = connect("/", 0, RTM_INTERNAL, INFINITE);
  6106. initializeInternals(conn->queryRoot());
  6107. conn.clear();
  6108. bool forceGroupUpdate = config.getPropBool("DFS/@forceGroupUpdate");
  6109. StringBuffer response;
  6110. initClusterGroups(forceGroupUpdate, response, oldEnvironment);
  6111. if (response.length())
  6112. PROGLOG("DFS group initialization : %s", response.str()); // should this be a syslog?
  6113. }
  6114. void CCovenSDSManager::saveStore(const char *storeName, bool currentEdition)
  6115. {
  6116. struct CIgnore
  6117. {
  6118. CIgnore() { SDSManager->ignoreExternals=true; }
  6119. ~CIgnore() { SDSManager->ignoreExternals=false; }
  6120. } ignore;
  6121. iStoreHelper->saveStore(root, NULL, currentEdition);
  6122. unsigned initNodeTableSize = allNodes.maxElements()+OVERFLOWSIZE;
  6123. queryCoven().setInitSDSNodes(initNodeTableSize>INIT_NODETABLE_SIZE?initNodeTableSize:INIT_NODETABLE_SIZE);
  6124. }
  6125. CServerRemoteTree *CCovenSDSManager::queryRegisteredTree(__int64 uniqId)
  6126. {
  6127. CHECKEDCRITICALBLOCK(treeRegCrit, fakeCritTimeout);
  6128. return (CServerRemoteTree *)allNodes.queryElem(uniqId);
  6129. }
  6130. CServerRemoteTree *CCovenSDSManager::getRegisteredTree(__int64 uniqId)
  6131. {
  6132. CHECKEDCRITICALBLOCK(treeRegCrit, fakeCritTimeout);
  6133. return (CServerRemoteTree *)allNodes.getElem(uniqId);
  6134. }
  6135. CServerRemoteTree *CCovenSDSManager::queryRoot()
  6136. {
  6137. return root;
  6138. }
  6139. StringBuffer &transformToAbsolute(StringBuffer &result, const char *xpath, unsigned index)
  6140. {
  6141. const char *end = xpath+strlen(xpath);
  6142. const char *p = end;
  6143. const char *q = NULL;
  6144. loop
  6145. {
  6146. if (p == xpath)
  6147. {
  6148. p = end;
  6149. break;
  6150. }
  6151. --p;
  6152. if ('/' == *p)
  6153. {
  6154. p = end;
  6155. break;
  6156. }
  6157. else if ('[' == *p)
  6158. {
  6159. q = p;
  6160. break;
  6161. }
  6162. }
  6163. if (q)
  6164. result.append(p-xpath, xpath);
  6165. else
  6166. result.append(xpath);
  6167. result.append('[');
  6168. result.append(index);
  6169. result.append(']');
  6170. return result;
  6171. }
  6172. void cleanChangeTree(IPropertyTree &tree)
  6173. {
  6174. tree.removeProp("@id");
  6175. Owned<IPropertyTreeIterator> iter = tree.getElements(RENAME_TAG);
  6176. ForEach (*iter)
  6177. iter->query().removeProp("@id");
  6178. iter.setown(tree.getElements(DELETE_TAG));
  6179. ForEach (*iter)
  6180. iter->query().removeProp("@id");
  6181. iter.setown(tree.getElements(RESERVED_CHANGE_NODE));
  6182. ForEach (*iter)
  6183. cleanChangeTree(iter->query());
  6184. }
  6185. void CCovenSDSManager::saveDelta(const char *path, IPropertyTree &changeTree)
  6186. {
  6187. CHECKEDCRITICALBLOCK(saveIncCrit, fakeCritTimeout);
  6188. // translate changeTree to inc format (e.g. remove id's)
  6189. if (externalEnvironment)
  6190. {
  6191. // don't save any changed to /Environment if external
  6192. if (0 == strncmp("/Environment", path, strlen("/Environment")))
  6193. {
  6194. WARNLOG("Attempt to change read-only Dali environment, path = %s", path);
  6195. return;
  6196. }
  6197. if (0 == strcmp("/", path) && changeTree.hasProp("*[@name=\"Environment\"]"))
  6198. {
  6199. WARNLOG("Attempt to change read-only Dali environment, path = %s", path);
  6200. return;
  6201. }
  6202. }
  6203. cleanChangeTree(changeTree);
  6204. // write out with header details (e.g. path)
  6205. Owned<IPropertyTree> header = createPTree("Header");
  6206. header->setProp("@path", path);
  6207. IPropertyTree *delta = header->addPropTree("Delta", createPTree());
  6208. delta->addPropTree(changeTree.queryName(), LINK(&changeTree));
  6209. StringBuffer fname(dataPath);
  6210. OwnedIFile deltaIPIFile = createIFile(fname.append(DELTAINPROGRESS).str());
  6211. OwnedIFileIO deltaIPIFileIO = deltaIPIFile->open(IFOcreate);
  6212. deltaIPIFileIO.clear();
  6213. struct RemoveDIPBlock
  6214. {
  6215. IFile &iFile;
  6216. bool done;
  6217. void doit() { done = true; iFile.remove(); }
  6218. RemoveDIPBlock(IFile &_iFile) : iFile(_iFile), done(false) { }
  6219. ~RemoveDIPBlock () { if (!done) doit(); }
  6220. } removeDIP(*deltaIPIFile);
  6221. StringBuffer detachIPStr(dataPath);
  6222. OwnedIFile detachIPIFile = createIFile(detachIPStr.append(DETACHINPROGRESS).str());
  6223. if (detachIPIFile->exists()) // very small window where this can happen.
  6224. {
  6225. // implies other operation about to access current delta
  6226. // CHECK session is really alive, otherwise it has been orphaned, so remove it.
  6227. try
  6228. {
  6229. SessionId sessId = 0;
  6230. OwnedIFileIO detachIPIO = detachIPIFile->open(IFOread);
  6231. if (detachIPIO)
  6232. {
  6233. size_t s = detachIPIO->read(0, sizeof(sessId), &sessId);
  6234. detachIPIO.clear();
  6235. if (sizeof(sessId) == s)
  6236. {
  6237. // double check session is really alive
  6238. if (querySessionManager().sessionStopped(sessId, 0))
  6239. detachIPIFile->remove();
  6240. else
  6241. {
  6242. // *cannot block* because other op (sasha) accessing remote dali files, can access dali.
  6243. removeDIP.doit();
  6244. PROGLOG("blocked");
  6245. toXML(header, blockedDelta);
  6246. return;
  6247. }
  6248. }
  6249. }
  6250. }
  6251. catch (IException *e) { EXCLOG(e, NULL); e->Release(); }
  6252. }
  6253. try
  6254. {
  6255. StringBuffer deltaFilename(dataPath);
  6256. iStoreHelper->getCurrentDeltaFilename(deltaFilename);
  6257. toXML(header, blockedDelta);
  6258. OwnedIFile iFile = createIFile(deltaFilename.str());
  6259. bool first = !iFile->exists() || 0 == iFile->size();
  6260. writeDelta(blockedDelta, *iFile);
  6261. if (remoteBackupLocation.length())
  6262. backupHandler.addDelta(blockedDelta, iStoreHelper->queryCurrentEdition(), first);
  6263. else
  6264. {
  6265. if (blockedDelta.length() > 0x100000)
  6266. blockedDelta.kill();
  6267. else
  6268. blockedDelta.clear();
  6269. }
  6270. }
  6271. catch (IException *e)
  6272. {
  6273. LOG(MCoperatorError, unknownJob, e, "saveDelta");
  6274. e->Release();
  6275. }
  6276. }
  6277. CSubscriberContainerList *CCovenSDSManager::getSubscribers(const char *xpath, CPTStack &stack)
  6278. {
  6279. return subscribers.getQualifiedList(xpath, stack);
  6280. }
  6281. inline void serverToClientTree(CServerRemoteTree &src, CClientRemoteTree &dst)
  6282. {
  6283. if (src.getPropInt64(EXT_ATTR))
  6284. {
  6285. MemoryBuffer mb;
  6286. src.serializeSelfRT(mb, false);
  6287. dst.deserializeSelfRT(mb);
  6288. }
  6289. else
  6290. dst.clone(src, true, false);
  6291. dst.setServerId(src.queryServerId());
  6292. if (src.hasChildren()) dst.addServerTreeInfo(STI_HaveChildren);
  6293. }
  6294. class CMultipleConnector : public CInterface, implements IMultipleConnector
  6295. {
  6296. StringArray xpaths;
  6297. UnsignedArray modes;
  6298. public:
  6299. IMPLEMENT_IINTERFACE;
  6300. CMultipleConnector() { }
  6301. CMultipleConnector(MemoryBuffer &src)
  6302. {
  6303. unsigned c;
  6304. src.read(c);
  6305. xpaths.ensure(c);
  6306. modes.ensure(c);
  6307. while (c--)
  6308. {
  6309. StringAttr xpath;
  6310. unsigned mode;
  6311. src.read(xpath);
  6312. src.read(mode);
  6313. xpaths.append(xpath);
  6314. modes.append(mode);
  6315. }
  6316. }
  6317. // IMultipleConnector impl.
  6318. virtual void addConnection(const char *xpath, unsigned mode)
  6319. {
  6320. if (RTM_CREATE == (mode & RTM_CREATE_MASK) || RTM_CREATE_QUERY == (mode & RTM_CREATE_MASK))
  6321. throw MakeSDSException(SDSExcpt_BadMode, "multiple connections do not support creation modes");
  6322. xpaths.append(xpath);
  6323. modes.append(mode);
  6324. }
  6325. virtual unsigned queryConnections() { return xpaths.ordinality(); }
  6326. virtual void getConnectionDetails(unsigned which, StringAttr &xpath, unsigned &mode)
  6327. {
  6328. xpath.set(xpaths.item(which));
  6329. mode = modes.item(which);
  6330. }
  6331. virtual void serialize(MemoryBuffer &dst)
  6332. {
  6333. unsigned c=xpaths.ordinality();
  6334. dst.append(c);
  6335. while (c--)
  6336. dst.append(xpaths.item(c)).append(modes.item(c));
  6337. }
  6338. };
  6339. IMultipleConnector *deserializeIMultipleConnector(MemoryBuffer &src)
  6340. {
  6341. return new CMultipleConnector(src);
  6342. }
  6343. IMultipleConnector *createIMultipleConnector()
  6344. {
  6345. return new CMultipleConnector();
  6346. }
  6347. StringBuffer &getMConnectString(IMultipleConnector *mConnect, StringBuffer &s)
  6348. {
  6349. unsigned c;
  6350. for (c=0; c<mConnect->queryConnections(); c++)
  6351. {
  6352. StringAttr xpath;
  6353. unsigned mode;
  6354. mConnect->getConnectionDetails(c, xpath, mode);
  6355. s.append("xpath=\"").append(xpath).append("\" [mode=").append(mode).append("]");
  6356. if (c != mConnect->queryConnections()-1)
  6357. s.append(", ");
  6358. }
  6359. return s;
  6360. }
  6361. // ISDSManager impl.
  6362. IRemoteConnections *CCovenSDSManager::connect(IMultipleConnector *mConnect, SessionId id, unsigned timeout)
  6363. {
  6364. Owned<CLCLockBlock> lockBlock;
  6365. lockBlock.setown(new CLCReadLockBlock(dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  6366. Owned<CRemoteConnections> remoteConnections = new CRemoteConnections;
  6367. unsigned c;
  6368. for (c=0; c<mConnect->queryConnections(); c++)
  6369. {
  6370. StringAttr xpath;
  6371. unsigned mode;
  6372. mConnect->getConnectionDetails(c, xpath, mode);
  6373. // connect can return NULL.
  6374. remoteConnections->add(connect(xpath, id, mode, timeout));
  6375. }
  6376. return LINK(remoteConnections);
  6377. }
  6378. IRemoteConnection *CCovenSDSManager::connect(const char *xpath, SessionId id, unsigned mode, unsigned timeout)
  6379. {
  6380. Owned<CLCLockBlock> lockBlock;
  6381. Owned<LinkingCriticalBlock> connectCritBlock;
  6382. if (!RTM_MODE(mode, RTM_INTERNAL))
  6383. {
  6384. connectCritBlock.setown(new LinkingCriticalBlock(connectCrit, __FILE__, __LINE__));
  6385. if (RTM_CREATE == (mode & RTM_CREATE_MASK) || RTM_CREATE_QUERY == (mode & RTM_CREATE_MASK))
  6386. lockBlock.setown(new CLCWriteLockBlock(dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  6387. else
  6388. lockBlock.setown(new CLCReadLockBlock(dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  6389. }
  6390. CServerRemoteTree *_tree;
  6391. Owned<CServerRemoteTree> tree;
  6392. ConnectionId connectionId = 0;
  6393. createConnection(id, mode, timeout, xpath, _tree, connectionId, true, connectCritBlock);
  6394. if (connectionId)
  6395. tree.setown(_tree);
  6396. connectCritBlock.clear();
  6397. if (connectionId)
  6398. {
  6399. CRemoteConnection *conn = new CRemoteConnection(*this, connectionId, xpath, id, mode, timeout);
  6400. assertex(conn);
  6401. CDisableFetchChangeBlock block(*conn);
  6402. CClientRemoteTree *clientTree = new CClientRemoteTree(*conn);
  6403. assertex(clientTree);
  6404. serverToClientTree(*tree, *clientTree);
  6405. conn->setRoot(clientTree);
  6406. return conn;
  6407. }
  6408. return NULL;
  6409. }
  6410. SubscriptionId CCovenSDSManager::subscribe(const char *xpath, ISDSSubscription &notify, bool sub, bool sendValue)
  6411. {
  6412. assertex(xpath);
  6413. if (sub && sendValue)
  6414. throw MakeSDSException(SDSExcpt_Unsupported, "Subscription to sub elements, with sendValue option unsupported");
  6415. StringBuffer s;
  6416. if ('/' != *xpath)
  6417. {
  6418. s.append('/').append(xpath);
  6419. xpath = s.str();
  6420. }
  6421. CSDSSubscriberProxy *subscriber = new CSDSSubscriberProxy(xpath, sub, sendValue, notify);
  6422. querySubscriptionManager(SDS_PUBLISHER)->add(subscriber, subscriber->getId());
  6423. return subscriber->getId();
  6424. }
  6425. SubscriptionId CCovenSDSManager::subscribeExact(const char *xpath, ISDSNodeSubscription &notify, bool sendValue)
  6426. {
  6427. assertex(xpath);
  6428. StringBuffer s;
  6429. if ('/' != *xpath)
  6430. {
  6431. s.append('/').append(xpath);
  6432. xpath = s.str();
  6433. }
  6434. CSDSNodeSubscriberProxy *subscriber = new CSDSNodeSubscriberProxy(xpath, sendValue, notify);
  6435. querySubscriptionManager(SDSNODE_PUBLISHER)->add(subscriber, subscriber->getId());
  6436. return subscriber->getId();
  6437. }
  6438. void CCovenSDSManager::unsubscribe(SubscriptionId id)
  6439. {
  6440. querySubscriptionManager(SDS_PUBLISHER)->remove(id);
  6441. }
  6442. void CCovenSDSManager::unsubscribeExact(SubscriptionId id)
  6443. {
  6444. querySubscriptionManager(SDSNODE_PUBLISHER)->remove(id);
  6445. }
  6446. bool CCovenSDSManager::removeNotifyHandler(const char *handlerKey)
  6447. {
  6448. return nodeNotifyHandlers.remove(handlerKey);
  6449. }
  6450. IPropertyTree *CCovenSDSManager::lockStoreRead() const
  6451. {
  6452. PROGLOG("lockStoreRead() called");
  6453. CHECKEDREADLOCKENTER(dataRWLock, readWriteTimeout);
  6454. return root;
  6455. }
  6456. void CCovenSDSManager::unlockStoreRead() const
  6457. {
  6458. PROGLOG("unlockStoreRead() called");
  6459. dataRWLock.unlockRead();
  6460. }
  6461. bool CCovenSDSManager::setSDSDebug(StringArray &params, StringBuffer &reply)
  6462. {
  6463. if (0 == params.ordinality()) return false;
  6464. else if (0 == stricmp("datalockHoldTiming", params.item(0)))
  6465. {
  6466. if (params.ordinality()<2)
  6467. {
  6468. reply.append("datalockHoldTiming currently = ").append(readWriteSlowTracing);
  6469. return false;
  6470. }
  6471. unsigned ms = atoi(params.item(1));
  6472. readWriteSlowTracing = ms;
  6473. PROGLOG("datalock, readWriteSlowTracing timing set to %d", readWriteSlowTracing);
  6474. }
  6475. else if (0 == stricmp("datalockHoldStack", params.item(0)))
  6476. {
  6477. if (params.ordinality()<2)
  6478. {
  6479. reply.append("datalockHoldStack currently set to '").append(readWriteStackTracing?"on":"off").append("'");
  6480. return false;
  6481. }
  6482. readWriteStackTracing = (0 == stricmp("on", params.item(1)));
  6483. PROGLOG("datalock, held time stacks set to '%s'", readWriteStackTracing?"on":"off");
  6484. }
  6485. else if (0 == stricmp("datalockRetryStackTiming", params.item(0)))
  6486. {
  6487. if (params.ordinality()<2)
  6488. {
  6489. reply.append("datalockRetryStackTiming currently =").append(readWriteTimeout);
  6490. return false;
  6491. }
  6492. unsigned ms = atoi(params.item(1));
  6493. readWriteTimeout = ms;
  6494. PROGLOG("datalock, readWriteTimeout timing set to %s", readWriteStackTracing?"on":"off");
  6495. }
  6496. else if (0 == stricmp("fakecritTiming", params.item(0)))
  6497. {
  6498. if (params.ordinality()<2)
  6499. {
  6500. reply.append("fakeCritTimeout currently =").append(fakeCritTimeout);
  6501. return false;
  6502. }
  6503. unsigned ms = atoi(params.item(1));
  6504. fakeCritTimeout = ms;
  6505. PROGLOG("fakecrit, fakeCritTimeout timing set to %d", fakeCritTimeout);
  6506. }
  6507. else
  6508. {
  6509. reply.append("Unknown command");
  6510. return false;
  6511. }
  6512. return true;
  6513. }
  6514. void CCovenSDSManager::saveRequest()
  6515. {
  6516. blockingSave();
  6517. }
  6518. IPropertyTree &CCovenSDSManager::queryProperties() const
  6519. {
  6520. return *properties;
  6521. }
  6522. void CCovenSDSManager::installNotifyHandler(const char *handlerKey, ISDSNotifyHandler *handler)
  6523. {
  6524. nodeNotifyHandlers.replace(* new CSDSNotifyHandlerMapping(handlerKey, *handler));
  6525. }
  6526. // ISDSConnectionManager impl.
  6527. void CCovenSDSManager::commit(CRemoteConnection &connection, bool *disconnectDeleteRoot)
  6528. {
  6529. Owned<CLCWriteLockBlock> lockBlock;
  6530. if (!RTM_MODE(connection.queryMode(), RTM_INTERNAL))
  6531. lockBlock.setown(new CLCWriteLockBlock(dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  6532. CRemoteTreeBase *tree = (CRemoteTreeBase *) connection.queryRoot();
  6533. bool lazyFetch = connection.setLazyFetch(false);
  6534. Owned<IPropertyTree> changeTree = tree->collateData();
  6535. connection.setLazyFetch(lazyFetch);
  6536. if (NULL == disconnectDeleteRoot && !changeTree) return;
  6537. ConnectionId connectionId = connection.queryConnectionId();
  6538. CServerConnection *serverConnection = queryConnection(connectionId);
  6539. if (!serverConnection)
  6540. throw MakeSDSException(SDSExcpt_ConnectionAbsent, " [commit]");
  6541. try
  6542. {
  6543. CServerRemoteTree *serverTree = (CServerRemoteTree *)serverConnection->queryRoot();
  6544. assertex(serverTree);
  6545. MemoryBuffer newIds, inc;
  6546. if (changeTree && serverTree->processData(*serverConnection, *changeTree, newIds))
  6547. { // something commited, if RTM_Create was used need to remember this.
  6548. StringBuffer path;
  6549. serverConnection->queryPTreePath().getAbsolutePath(path);
  6550. saveDelta(path.str(), *changeTree);
  6551. bool lazyFetch = connection.setLazyFetch(false);
  6552. tree->clearCommitChanges(&newIds);
  6553. assertex(newIds.getPos() == newIds.length()); // must have read it all
  6554. connection.setLazyFetch(lazyFetch);
  6555. }
  6556. }
  6557. catch (IException *)
  6558. {
  6559. if (disconnectDeleteRoot)
  6560. {
  6561. connection.setConnected(false);
  6562. disconnect(connectionId, *disconnectDeleteRoot);
  6563. }
  6564. throw;
  6565. }
  6566. if (disconnectDeleteRoot)
  6567. {
  6568. connection.setConnected(false);
  6569. disconnect(connectionId, *disconnectDeleteRoot);
  6570. }
  6571. }
  6572. CRemoteTreeBase *CCovenSDSManager::get(CRemoteConnection &connection, __int64 serverId)
  6573. {
  6574. Owned<CLCReadLockBlock> lockBlock;
  6575. if (!RTM_MODE(connection.queryMode(), RTM_INTERNAL))
  6576. lockBlock.setown(new CLCReadLockBlock(dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  6577. CDisableFetchChangeBlock block(connection);
  6578. CRemoteTreeBase *connectionRoot = (CRemoteTreeBase *) connection.queryRoot();
  6579. Owned<CServerRemoteTree> tree = getRegisteredTree(connectionRoot->queryServerId());
  6580. if (!tree)
  6581. return NULL;
  6582. CClientRemoteTree *newTree = new CClientRemoteTree(connection);
  6583. serverToClientTree(*tree, *newTree);
  6584. return newTree;
  6585. }
  6586. void CCovenSDSManager::getChildren(CRemoteTreeBase &parent, CRemoteConnection &connection, unsigned levels)
  6587. {
  6588. Owned<CLCReadLockBlock> lockBlock;
  6589. if (!RTM_MODE(connection.queryMode(), RTM_INTERNAL))
  6590. lockBlock.setown(new CLCReadLockBlock(dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  6591. CDisableFetchChangeBlock block(connection);
  6592. Owned<CServerRemoteTree> serverParent = (CServerRemoteTree *)getRegisteredTree(parent.queryServerId());
  6593. if (serverParent)
  6594. _getChildren(parent, *serverParent, connection, levels);
  6595. }
  6596. void CCovenSDSManager::getChildrenFor(CRTArray &childLessList, CRemoteConnection &connection, unsigned levels)
  6597. {
  6598. Owned<CLCReadLockBlock> lockBlock;
  6599. if (!RTM_MODE(connection.queryMode(), RTM_INTERNAL))
  6600. lockBlock.setown(new CLCReadLockBlock(dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  6601. CDisableFetchChangeBlock block(connection);
  6602. ForEachItemIn(f, childLessList)
  6603. {
  6604. CRemoteTreeBase &tree = childLessList.item(f);
  6605. Owned<CServerRemoteTree> serverParent = (CServerRemoteTree *)getRegisteredTree(tree.queryServerId());
  6606. if (serverParent)
  6607. _getChildren(tree, *serverParent, connection, levels);
  6608. }
  6609. }
  6610. static void addServerChildren(CClientRemoteTree &clientParent, CServerRemoteTree &serverParent, bool recurse)
  6611. {
  6612. Owned<IPropertyTreeIterator> iter = serverParent.getElements("*");
  6613. ForEach (*iter)
  6614. {
  6615. CServerRemoteTree &serverChild = (CServerRemoteTree &)iter->query();
  6616. CClientRemoteTree *clientChild = (CClientRemoteTree *)clientParent.create(NULL);
  6617. serverToClientTree(serverChild, *clientChild);
  6618. clientChild = (CClientRemoteTree *)clientParent.addPropTree(clientChild->queryName(), clientChild);
  6619. if (recurse)
  6620. addServerChildren(*clientChild, serverChild, recurse);
  6621. }
  6622. }
  6623. void CCovenSDSManager::matchServerTree(CClientRemoteTree *local, IPropertyTree &matchTree, bool allTail)
  6624. {
  6625. Owned<IPropertyTreeIterator> matchIter = matchTree.getElements("*");
  6626. if (matchIter->first())
  6627. {
  6628. if (local->hasChildren() && NULL == local->queryChildren())
  6629. {
  6630. local->createChildMap();
  6631. Owned<CServerRemoteTree> tree = getRegisteredTree(matchTree.getPropInt64("@serverId"));
  6632. addServerChildren(*local, *tree, false);
  6633. }
  6634. do
  6635. {
  6636. IPropertyTree &elem = matchIter->query();
  6637. StringBuffer path(elem.queryName());
  6638. path.append('[').append(elem.getPropInt("@pos")).append(']');
  6639. CClientRemoteTree *child = (CClientRemoteTree *)local->queryPropTree(path.str());
  6640. if (child) // if not would imply some other thread deleted I think.
  6641. matchServerTree(child, elem, allTail);
  6642. }
  6643. while (matchIter->next());
  6644. }
  6645. else
  6646. {
  6647. if (local->hasChildren() && NULL == local->queryChildren())
  6648. {
  6649. local->createChildMap();
  6650. Owned<CServerRemoteTree> tree = getRegisteredTree(matchTree.getPropInt64("@serverId"));
  6651. addServerChildren(*local, *tree, allTail);
  6652. }
  6653. }
  6654. }
  6655. void CCovenSDSManager::ensureLocal(CRemoteConnection &connection, CRemoteTreeBase &_parent, IPropertyTree *serverMatchTree, IPTIteratorCodes flags)
  6656. {
  6657. CClientRemoteTree &parent = (CClientRemoteTree &)_parent;
  6658. bool getLeaves = iptiter_remotegetbranch == (flags & iptiter_remotegetbranch);
  6659. CDisableFetchChangeBlock block(connection);
  6660. matchServerTree(&parent, *serverMatchTree, getLeaves);
  6661. }
  6662. void CCovenSDSManager::_getChildren(CRemoteTreeBase &parent, CServerRemoteTree &serverParent, CRemoteConnection &connection, unsigned levels)
  6663. {
  6664. Owned<IPropertyTreeIterator> iter = serverParent.getElements("*");
  6665. assertex(iter);
  6666. if (levels && serverParent.getPropBool("@fetchEntire"))
  6667. levels = 0;
  6668. ForEach(*iter)
  6669. {
  6670. CServerRemoteTree &child = (CServerRemoteTree &)iter->query();
  6671. CClientRemoteTree *newChild = new CClientRemoteTree(connection); // clone create
  6672. serverToClientTree(child, *newChild);
  6673. parent.addPropTree(newChild->queryName(), newChild);
  6674. if (0==levels || child.getPropBool("@fetchEntire"))
  6675. _getChildren(*newChild, child, connection, 0);
  6676. }
  6677. }
  6678. IPropertyTreeIterator *CCovenSDSManager::getElements(CRemoteConnection &connection, const char *xpath)
  6679. {
  6680. Owned<CLCReadLockBlock> lockBlock = new CLCReadLockBlock(dataRWLock, readWriteTimeout, __FILE__, __LINE__);
  6681. CDisableFetchChangeBlock block(connection);
  6682. Owned<CServerRemoteTree> serverConnRoot = (CServerRemoteTree *)getRegisteredTree(((CClientRemoteTree *)connection.queryRoot())->queryServerId());
  6683. Owned<CPTArrayIterator> elements = new CPTArrayIterator();
  6684. Owned<IPropertyTreeIterator> iter = serverConnRoot->getElements(xpath);
  6685. ForEach (*iter)
  6686. {
  6687. CServerRemoteTree &child = (CServerRemoteTree &)iter->query();
  6688. Owned<CClientRemoteTree> newChild = new CClientRemoteTree(connection);
  6689. serverToClientTree(child, *newChild);
  6690. elements->array.append(*LINK(newChild));
  6691. }
  6692. return LINK(elements);
  6693. }
  6694. void CCovenSDSManager::changeMode(CRemoteConnection &connection, unsigned mode, unsigned timeout, bool suppressReloads)
  6695. {
  6696. if (mode & RTM_CREATE_MASK)
  6697. throw MakeSDSException(SDSExcpt_BadMode, "calling changeMode");
  6698. ConnectionId connectionId = connection.queryConnectionId();
  6699. Linked<CServerConnection> serverConnection = queryConnection(connectionId);
  6700. if (!serverConnection)
  6701. throw MakeSDSException(SDSExcpt_ConnectionAbsent, " [changeMode]");
  6702. CServerRemoteTree *connectionRoot = (CServerRemoteTree *) serverConnection->queryRoot();
  6703. unsigned prevMode = connection.queryMode();
  6704. if (RTM_MODE(prevMode, RTM_LOCK_WRITE) && !RTM_MODE(mode, RTM_LOCK_WRITE))
  6705. commit(connection, NULL);
  6706. changeLockMode(*serverConnection, mode, timeout);
  6707. if (!suppressReloads)
  6708. {
  6709. if (RTM_MODE(mode, RTM_LOCK_WRITE) && !RTM_MODE(prevMode, RTM_LOCK_WRITE) && !RTM_MODE(prevMode, RTM_LOCK_READ))
  6710. connection.reload();
  6711. }
  6712. }
  6713. IPropertyTree *CCovenSDSManager::getXPaths(__int64 serverId, const char *xpath, bool getServerIds)
  6714. {
  6715. Owned<CServerRemoteTree> tree = getRegisteredTree(serverId);
  6716. if (!tree)
  6717. return NULL;
  6718. IPropertyTree *matchTree = getXPathMatchTree(*tree, xpath);
  6719. if (!matchTree)
  6720. return NULL;
  6721. if (getServerIds)
  6722. populateWithServerIds(matchTree, tree);
  6723. return matchTree;
  6724. }
  6725. IPropertyTreeIterator *CCovenSDSManager::getXPathsSortLimit(const char *baseXPath, const char *matchXPath, const char *sortBy, bool caseinsensitive, bool ascending, unsigned from, unsigned limit)
  6726. {
  6727. Owned<IPropertyTree> matchTree = getXPathsSortLimitMatchTree(baseXPath, matchXPath, sortBy, caseinsensitive, ascending, from, limit);
  6728. if (!matchTree)
  6729. return createNullPTreeIterator();
  6730. IPropertyTree *baseTree = SDSManager->queryRoot()->queryPropTree(baseXPath);
  6731. return new CXPathIterator(baseTree, matchTree, iptiter_null);
  6732. }
  6733. IPropertyTree *CCovenSDSManager::getXPathsSortLimitMatchTree(const char *baseXPath, const char *matchXPath, const char *sortby, bool caseinsensitive, bool ascending, unsigned from, unsigned limit)
  6734. {
  6735. UNIMPLEMENTED;
  6736. return NULL;
  6737. }
  6738. void CCovenSDSManager::getExternalValue(__int64 index, MemoryBuffer &mb)
  6739. {
  6740. IExternalHandler *handler = queryExternalHandler(EF_BinaryValue);
  6741. assertex(handler);
  6742. StringBuffer name(EXTERNAL_NAME_PREFIX);
  6743. name.append(index);
  6744. handler->readValue(name.str(), mb);
  6745. }
  6746. void CCovenSDSManager::getExternalValueFromServerId(__int64 serverId, MemoryBuffer &mb)
  6747. {
  6748. CServerRemoteTree *idTree = (CServerRemoteTree *) SDSManager->queryRegisteredTree(serverId);
  6749. if (idTree)
  6750. {
  6751. CHECKEDCRITICALBLOCK(extCrit, fakeCritTimeout);
  6752. __int64 index = idTree->getPropInt64(EXT_ATTR);
  6753. if (index)
  6754. getExternalValue(index, mb);
  6755. else
  6756. WARNLOG("External file reference missing (node name='%s', id=%"I64F"d)", idTree->queryName(), serverId);
  6757. }
  6758. }
  6759. IPropertyTreeIterator *CCovenSDSManager::getElementsRaw(const char *xpath,INode *remotedali, unsigned timeout)
  6760. {
  6761. assertex(!remotedali); // only client side
  6762. CHECKEDDALIREADLOCKBLOCK(dataRWLock, readWriteTimeout);
  6763. return root->getElements(xpath);
  6764. }
  6765. void CCovenSDSManager::setConfigOpt(const char *opt, const char *value)
  6766. {
  6767. IPropertyTree &props = queryProperties();
  6768. if (props.hasProp(opt) && (0 == strcmp(value, props.queryProp(opt))))
  6769. return;
  6770. ensurePTree(&queryProperties(), opt);
  6771. queryProperties().setProp(opt, value);
  6772. }
  6773. unsigned CCovenSDSManager::queryCount(const char *xpath)
  6774. {
  6775. unsigned count = 0;
  6776. if (xpath && *xpath == '/')
  6777. ++xpath;
  6778. Owned<IPropertyTreeIterator> iter = root->getElements(xpath);
  6779. ForEach(*iter)
  6780. ++count;
  6781. return count;
  6782. }
  6783. void CCovenSDSManager::start()
  6784. {
  6785. server.start();
  6786. if (coalesce) coalesce->start();
  6787. }
  6788. void CCovenSDSManager::stop()
  6789. {
  6790. server.stop();
  6791. PROGLOG("waiting for coalescer to stop");
  6792. if (coalesce) coalesce->stop();
  6793. }
  6794. void CCovenSDSManager::restart(IException * e)
  6795. {
  6796. LOG(MCwarning, unknownJob, "-------: stopping SDS server");
  6797. StringBuffer msg;
  6798. msg.append("Unhandled exception, restarting: ").append(e->errorCode()).append(": ");
  6799. e->errorMessage(msg);
  6800. stop();
  6801. connections.kill();
  6802. LOG(MCwarning, unknownJob, "-------: stopped");
  6803. LOG(MCwarning, unknownJob, "-------: saving current store . . . . . .");
  6804. saveStore();
  6805. LOG(MCwarning, unknownJob, "-------: store saved.");
  6806. LOG(MCwarning, unknownJob, "-------: restarting SDS server restart");
  6807. start();
  6808. LOG(MCwarning, unknownJob, "-------: restarted");
  6809. }
  6810. CServerConnection *CCovenSDSManager::createConnectionInstance(CRemoteTreeBase *root, SessionId sessionId, unsigned mode, unsigned timeout, const char *xpath, CRemoteTreeBase *&tree, ConnectionId _connectionId, StringAttr *deltaPath, Owned<IPropertyTree> &deltaChange, Owned<CBranchChange> &branchChange, unsigned &additions)
  6811. {
  6812. IPropertyTree *parent = NULL;
  6813. ConnInfoFlags connInfoFlags = (ConnInfoFlags)0;
  6814. const char *_xpath = ('/' == *xpath)?xpath+1:xpath;
  6815. StringBuffer tXpath;
  6816. if (!RTM_MODE(mode, RTM_CREATE_UNIQUE))
  6817. {
  6818. unsigned l = strlen(_xpath);
  6819. if (l && '/' == _xpath[l-1])
  6820. {
  6821. tXpath.append(l-1, _xpath);
  6822. _xpath = tXpath.toCharArray();
  6823. }
  6824. }
  6825. bool newNode = false;
  6826. bool replaceNode = false;
  6827. IPropertyTree *created = NULL, *createdParent = NULL;
  6828. StringBuffer head;
  6829. if (mode & RTM_CREATE)
  6830. {
  6831. const char *prop = splitXPath(_xpath, head);
  6832. if (head.length())
  6833. {
  6834. try
  6835. {
  6836. parent = createPropBranch(root, head.str(), true, &created, &createdParent);
  6837. if (created)
  6838. newNode = true;
  6839. }
  6840. catch (IException *) { if (created) createdParent->removeTree(created); throw; }
  6841. catch (DALI_CATCHALL) { if (created) createdParent->removeTree(created); throw; }
  6842. }
  6843. else
  6844. parent = root->splitBranchProp(_xpath, prop);
  6845. if (parent)
  6846. {
  6847. connInfoFlags = ci_newParent;
  6848. StringBuffer uProp;
  6849. if (RTM_MODE(mode, RTM_CREATE_UNIQUE))
  6850. {
  6851. Owned<IPropertyTreeIterator> iter = parent->getElements(prop);
  6852. if (iter->first())
  6853. {
  6854. uProp.append(prop).append('-');
  6855. unsigned l = uProp.length();
  6856. unsigned n=1;
  6857. loop
  6858. {
  6859. n += getRandom() % 5; // better chance of finding a mismatch soon.
  6860. uProp.append(n);
  6861. iter.setown(parent->getElements(uProp.str()));
  6862. if (!iter->first())
  6863. break;
  6864. uProp.setLength(l);
  6865. }
  6866. prop = uProp.str();
  6867. if (head.length())
  6868. tXpath.append(head).append('/');
  6869. _xpath = tXpath.append(prop).str();
  6870. }
  6871. }
  6872. if (RTM_MODE(mode, RTM_CREATE_QUERY))
  6873. tree = (CRemoteTreeBase *) root->queryCreateBranch(parent, prop, &newNode);
  6874. else
  6875. {
  6876. IPropertyTree *newTree = ((CRemoteTreeBase *) parent)->create(NULL);
  6877. if (RTM_MODE(mode, RTM_CREATE_ADD))
  6878. tree = (CRemoteTreeBase *) parent->addPropTree(prop, newTree);
  6879. else // Default - RTM_CREATE - replace existing
  6880. {
  6881. Owned<IPropertyTreeIterator> iter = parent->getElements(prop);
  6882. if (iter->first())
  6883. replaceNode = true;
  6884. tree = (CRemoteTreeBase *) parent->setPropTree(prop, newTree);
  6885. }
  6886. newNode = true;
  6887. }
  6888. }
  6889. else
  6890. tree = NULL;
  6891. }
  6892. else
  6893. {
  6894. if (NULL == _xpath || '\0' == *_xpath)
  6895. tree = root;
  6896. else
  6897. {
  6898. StringBuffer path;
  6899. const char *prop = splitXPath(_xpath, path);
  6900. if (!prop) prop = _xpath;
  6901. // establish parent
  6902. tree = NULL;
  6903. Owned<IPropertyTreeIterator> iter = root->getElements(path.str());
  6904. ForEach (*iter)
  6905. {
  6906. IPropertyTree *_parent = &iter->query();
  6907. IPropertyTree *match = _parent->queryPropTree(prop);
  6908. if (tree)
  6909. {
  6910. if (match)
  6911. throw MakeSDSException(SDSExcpt_AmbiguousXpath, "Ambiguous: %s", _xpath);
  6912. }
  6913. else
  6914. {
  6915. parent = _parent;
  6916. tree = (CRemoteTreeBase *)match;
  6917. }
  6918. }
  6919. }
  6920. }
  6921. if (!tree)
  6922. return NULL;
  6923. assertex(tree->queryServerId());
  6924. ConnectionId connectionId = _connectionId;
  6925. if (!connectionId)
  6926. connectionId = coven.getUniqueId();
  6927. CServerConnection *connection = new CServerConnection(*this, connectionId, _xpath, sessionId, mode, timeout, parent, connInfoFlags);
  6928. Owned<LinkingCriticalBlock> b;
  6929. if (!RTM_MODE(mode, RTM_INTERNAL))
  6930. b.setown(new LinkingCriticalBlock(lockCrit, __FILE__, __LINE__));
  6931. connection->initPTreePath(*root, *tree);
  6932. if (newNode)
  6933. {
  6934. writeTransactions++;
  6935. // add tree into stack temporarily, or add manually at end.
  6936. deltaChange.setown(createPTree(RESERVED_CHANGE_NODE));
  6937. IPropertyTree *tail = deltaChange;
  6938. if (created) // some elems in "head" created
  6939. {
  6940. // iterate stack until createdParent to build up new head path.
  6941. StringBuffer _deltaPath;
  6942. unsigned s = 0;
  6943. StringBuffer headPath;
  6944. connection->queryPTreePath().getAbsolutePath(headPath);
  6945. if (headPath.length() && headPath.charAt(0) == '/')
  6946. headPath.remove(0, 1);
  6947. loop
  6948. {
  6949. _deltaPath.append('/');
  6950. IPropertyTree &tree = connection->queryPTreePath().item(s);
  6951. if (&tree == createdParent)
  6952. {
  6953. ++s;
  6954. break;
  6955. }
  6956. unsigned l = _deltaPath.length();
  6957. const char *t = queryHead(headPath.str(), _deltaPath);
  6958. assertex(l != _deltaPath.length());
  6959. headPath.clear();
  6960. if (t)
  6961. headPath.append(t);
  6962. if (++s>=connection->queryPTreePath().ordinality())
  6963. break;
  6964. }
  6965. additions = connection->queryPTreePath().ordinality()-s;
  6966. deltaPath->set(_deltaPath.str());
  6967. branchChange.setown(new CBranchChange(*(CRemoteTreeBase *)createdParent));
  6968. CBranchChange *topChange = branchChange;
  6969. // iterate remaining stack, iterate marking as 'new'
  6970. for (;s<connection->queryPTreePath().ordinality();s++)
  6971. {
  6972. IPropertyTree &tree = connection->queryPTreePath().item(s);
  6973. IPropertyTree *n = tail->addPropTree(RESERVED_CHANGE_NODE, createPTree());
  6974. n->setProp("@name", tree.queryName());
  6975. n->setPropBool("@new", true);
  6976. tail = n;
  6977. Owned<CBranchChange> childChange = new CBranchChange((CRemoteTreeBase &)tree);
  6978. childChange->noteChange(PDS_Added, PDS_Added);
  6979. topChange->addChildBranch(*LINK(childChange));
  6980. topChange = childChange;
  6981. }
  6982. }
  6983. else
  6984. {
  6985. StringBuffer s, _deltaPath;
  6986. connection->queryPTreePath().getAbsolutePath(s);
  6987. const char *t = splitXPath(s.str(), _deltaPath);
  6988. deltaPath->set(_deltaPath.str());
  6989. IPropertyTree *n = tail->addPropTree(RESERVED_CHANGE_NODE, createPTree());
  6990. n->setProp("@name", tree->queryName());
  6991. if (replaceNode)
  6992. n->setPropBool("@replace", true);
  6993. else
  6994. n->setPropBool("@new", true);
  6995. branchChange.setown(new CBranchChange(*(CRemoteTreeBase *)tree));
  6996. if (replaceNode)
  6997. branchChange->noteChange(PDS_Data, PDS_Data);
  6998. else
  6999. branchChange->noteChange(PDS_Added, PDS_Added);
  7000. additions=1;
  7001. }
  7002. }
  7003. connection->setRoot(LINK(tree));
  7004. return connection;
  7005. }
  7006. void CCovenSDSManager::clearSDSLocks()
  7007. {
  7008. CHECKEDCRITICALBLOCK(lockCrit, fakeCritTimeout);
  7009. SuperHashIteratorOf<CLockInfo> iter(lockTable.queryBaseTable());
  7010. ICopyArrayOf<CLockInfo> locks;
  7011. ForEach(iter)
  7012. locks.append(iter.query());
  7013. ForEachItemIn(l, locks)
  7014. locks.item(l).unlockAll();
  7015. }
  7016. void CCovenSDSManager::changeLockMode(CServerConnection &connection, unsigned newMode, unsigned timeout)
  7017. {
  7018. CServerRemoteTree *tree = (CServerRemoteTree *) connection.queryRoot();
  7019. ConnectionId connectionId = connection.queryConnectionId();
  7020. __int64 treeId = tree->queryServerId();
  7021. newMode = newMode & (RTM_LOCKBASIC_MASK|RTM_LOCK_SUB);
  7022. newMode |= connection.queryMode() & ~(RTM_LOCKBASIC_MASK|RTM_LOCK_SUB);
  7023. CUnlockCallback callback(connection.queryXPath(), connectionId, *tree);
  7024. {
  7025. CHECKEDCRITICALBLOCK(lockCrit, fakeCritTimeout);
  7026. CLockInfo *lockInfo = queryLockInfo(treeId);
  7027. if (lockInfo)
  7028. {
  7029. lockInfo->changeMode(connectionId, connection.querySessionId(), newMode, timeout, callback);
  7030. connection.setMode(newMode);
  7031. return;
  7032. }
  7033. }
  7034. // no existing lock for connection
  7035. lock(*tree, connection.queryXPath(), connectionId, connection.querySessionId(), newMode, timeout, callback);
  7036. connection.setMode(newMode);
  7037. }
  7038. bool CCovenSDSManager::unlock(__int64 connectionId, bool close, StringBuffer &connectionInfo)
  7039. {
  7040. Owned<CServerConnection> connection = getConnection(connectionId);
  7041. if (!connection) return false;
  7042. MemoryBuffer connInfo;
  7043. connection->getInfo(connInfo);
  7044. formatConnectionInfo(connInfo, connectionInfo);
  7045. if (close)
  7046. {
  7047. PROGLOG("forcing unlock & disconnection of connection : %s", connectionInfo.str());
  7048. Owned<CLCLockBlock> lockBlock = new CLCWriteLockBlock(dataRWLock, readWriteTimeout, __FILE__, __LINE__);
  7049. SDSManager->disconnect(connectionId, false);
  7050. }
  7051. else // leave connection open, just unlock
  7052. {
  7053. PROGLOG("forcing unlock for connection : %s", connectionInfo.str());
  7054. __int64 nodeId = ((CRemoteTreeBase *)connection->queryRoot())->queryServerId();
  7055. CHECKEDCRITICALBLOCK(lockCrit, fakeCritTimeout);
  7056. CLockInfo *lockInfo = queryLockInfo(nodeId);
  7057. if (lockInfo)
  7058. lockInfo->unlock(connectionId);
  7059. }
  7060. return true;
  7061. }
  7062. bool CCovenSDSManager::unlock(__int64 treeId, ConnectionId connectionId)
  7063. {
  7064. CHECKEDCRITICALBLOCK(lockCrit, fakeCritTimeout);
  7065. CLockInfo *lockInfo = queryLockInfo(treeId);
  7066. if (lockInfo)
  7067. return lockInfo->unlock(connectionId);
  7068. return false;
  7069. }
  7070. void CCovenSDSManager::unlockAll(__int64 treeId)
  7071. {
  7072. CHECKEDCRITICALBLOCK(lockCrit, fakeCritTimeout);
  7073. CLockInfo *lockInfo = queryLockInfo(treeId);
  7074. if (lockInfo)
  7075. lockInfo->unlockAll();
  7076. }
  7077. LockStatus CCovenSDSManager::establishLock(CLockInfo &lockInfo, __int64 treeId, ConnectionId connectionId, SessionId sessionId, unsigned mode, unsigned timeout, IUnlockCallback &lockCallback)
  7078. {
  7079. LockStatus res = lockInfo.lock(mode, timeout, connectionId, sessionId, lockCallback);
  7080. if (res == LockSucceeded && server.queryStopped())
  7081. {
  7082. lockInfo.unlock(connectionId);
  7083. throw MakeSDSException(SDSExcpt_ServerStoppedLockAborted);
  7084. }
  7085. return res;
  7086. }
  7087. void CCovenSDSManager::lock(CServerRemoteTree &tree, const char *__xpath, ConnectionId connectionId, SessionId sessionId, unsigned mode, unsigned timeout, IUnlockCallback &callback)
  7088. {
  7089. if (0 == ((RTM_LOCK_READ | RTM_LOCK_WRITE) & mode)) // no point in creating lockInfo.
  7090. return;
  7091. CLockInfo *lockInfo = NULL;
  7092. StringAttr sxpath;
  7093. char *_xpath = (char *) (('/' == *__xpath) ? __xpath+1 : __xpath);
  7094. char *xpath;
  7095. if ('/' == _xpath[strlen(_xpath)-1])
  7096. xpath = (char *)_xpath;
  7097. else
  7098. {
  7099. unsigned l = strlen(_xpath);
  7100. xpath = (char *)malloc(l+2);
  7101. memcpy(xpath, _xpath, l);
  7102. xpath[l] = '/';
  7103. xpath[l+1] = '\0';
  7104. sxpath.setown(xpath);
  7105. }
  7106. __int64 treeId = tree.queryServerId();
  7107. CHECKEDCRITICALBLOCK(lockCrit, fakeCritTimeout);
  7108. lockInfo = lockTable.find(&treeId);
  7109. if (!lockInfo)
  7110. {
  7111. IdPath idPath;
  7112. lockInfo = new CLockInfo(lockTable, treeId, idPath, xpath, mode, connectionId, sessionId);
  7113. lockTable.replace(*lockInfo);
  7114. }
  7115. else
  7116. {
  7117. Linked<CLockInfo> tmp = lockInfo; // keep it alive could be destroyed whilst blocked in call below.
  7118. LockStatus result = establishLock(*lockInfo, treeId, connectionId, sessionId, mode, timeout, callback);
  7119. if (result != LockSucceeded)
  7120. {
  7121. if (!queryConnection(connectionId)) return; // connection aborted.
  7122. StringBuffer s;
  7123. switch (result)
  7124. {
  7125. case LockFailed:
  7126. throw MakeSDSException(SDSExcpt_ConnectionAbsent, "Lost connection trying to establish lock on connection to : %s", xpath);
  7127. case LockTimedOut:
  7128. throw MakeSDSException(SDSExcpt_LockTimeout, "Lock timeout trying to establish lock to %s, existing lock info: %s", xpath, lockInfo->getLockInfo(s).str());
  7129. case LockHeld:
  7130. throw MakeSDSException(SDSExcpt_LockHeld, "Lock is held trying to establish lock to %s, existing lock info: %s", xpath, lockInfo->getLockInfo(s).str());
  7131. }
  7132. }
  7133. }
  7134. }
  7135. void CCovenSDSManager::createConnection(SessionId sessionId, unsigned mode, unsigned timeout, const char *xpath, CServerRemoteTree *&tree, ConnectionId &connectionId, bool primary, Owned<LinkingCriticalBlock> &connectCritBlock)
  7136. {
  7137. CRemoteTreeBase *_tree;
  7138. Linked<CRemoteTreeBase> linkedTree;
  7139. Owned<CServerConnection> connection;
  7140. StringBuffer _xpath;
  7141. if (!xpath || '/'!=*xpath)
  7142. xpath = _xpath.append('/').append(xpath).str();
  7143. struct CFreeExistingLocks
  7144. {
  7145. ~CFreeExistingLocks() { clear(); }
  7146. void clear()
  7147. {
  7148. ForEachItemIn(l, existingLockTrees)
  7149. SDSManager->unlock(existingLockTrees.item(l).queryServerId(), connId);
  7150. existingLockTrees.kill();
  7151. }
  7152. void setConnectionId(ConnectionId _connId) { connId = _connId; }
  7153. void add(CServerRemoteTree &tree)
  7154. {
  7155. tree.Link();
  7156. existingLockTrees.append(tree);
  7157. }
  7158. void remove(CServerRemoteTree &tree)
  7159. {
  7160. existingLockTrees.zap(tree);
  7161. }
  7162. bool isExisting(CServerRemoteTree &tree) { return NotFound != existingLockTrees.find(tree); }
  7163. ConnectionId connId;
  7164. IArrayOf<CServerRemoteTree> existingLockTrees;
  7165. } freeExistingLocks;
  7166. StringAttr deltaPath;
  7167. Owned<IPropertyTree> deltaChange;
  7168. Owned<CBranchChange> branchChange;
  7169. unsigned additions = 0;
  7170. try
  7171. {
  7172. struct LockUnblock
  7173. {
  7174. LockUnblock(ReadWriteLock &_rWLock) : rWLock(_rWLock)
  7175. {
  7176. lockedForWrite = rWLock.queryWriteLocked();
  7177. if (lockedForWrite) rWLock.unlockWrite();
  7178. else rWLock.unlockRead();
  7179. }
  7180. ~LockUnblock() { if (lockedForWrite) rWLock.lockWrite(); else rWLock.lockRead(); }
  7181. bool lockedForWrite;
  7182. ReadWriteLock &rWLock;
  7183. };
  7184. bool locked = false;
  7185. class CConnectExistingLockCallback : implements IUnlockCallback
  7186. {
  7187. CUnlockCallback lcb;
  7188. CheckedCriticalSection *connectCrit;
  7189. public:
  7190. CConnectExistingLockCallback(const char *xpath, ConnectionId connectionId, CServerRemoteTree &tree, CheckedCriticalSection *_connectCrit) : lcb(xpath, connectionId, tree), connectCrit(_connectCrit) { }
  7191. virtual void block()
  7192. {
  7193. if (connectCrit)
  7194. CHECKEDCRITENTER(*connectCrit, fakeCritTimeout);
  7195. lcb.block();
  7196. }
  7197. virtual void unblock()
  7198. {
  7199. lcb.unblock();
  7200. if (connectCrit)
  7201. CHECKEDCRITLEAVE(*connectCrit);
  7202. }
  7203. };
  7204. if (!RTM_MODE(mode, RTM_CREATE_ADD) && !RTM_MODE(mode, RTM_CREATE_UNIQUE)) // cannot be pending on existing locked nodes in these cases
  7205. {
  7206. CTimeMon tm(timeout);
  7207. connectionId = coven.getUniqueId();
  7208. Owned<CServerConnection> tmpConn = new CServerConnection(*this, connectionId, xpath, sessionId, mode, timeout, NULL, (ConnInfoFlags)0);
  7209. { CHECKEDCRITICALBLOCK(cTableCrit, fakeCritTimeout);
  7210. connections.replace(*LINK(tmpConn));
  7211. }
  7212. if (sessionId)
  7213. {
  7214. { LockUnblock b(dataRWLock);
  7215. tmpConn->subscribe(sessionId);
  7216. }
  7217. if (!queryConnection(connectionId)) // aborted
  7218. {
  7219. connectionId = 0;
  7220. throw MakeSDSException(SDSExcpt_AbortDuringConnection, " during connect");
  7221. }
  7222. }
  7223. freeExistingLocks.setConnectionId(connectionId);
  7224. try
  7225. {
  7226. loop
  7227. {
  7228. try
  7229. {
  7230. Owned<IPropertyTreeIterator> iter = root->getElements(xpath+1);
  7231. iter->first();
  7232. while (iter->isValid())
  7233. {
  7234. CServerRemoteTree &existing = (CServerRemoteTree &) iter->query();
  7235. if (freeExistingLocks.isExisting(existing))
  7236. iter->next();
  7237. else
  7238. {
  7239. freeExistingLocks.add(existing);
  7240. {
  7241. unsigned remaining;
  7242. if (tm.timedout(&remaining))
  7243. throw MakeSDSException(SDSExcpt_LockTimeout, "Failed to establish lock to %s, timeout whilst retrying connection to orphaned connection path", xpath);
  7244. CConnectExistingLockCallback connectLockCallback(xpath, connectionId, existing, &connectCrit);
  7245. lock(existing, xpath, connectionId, sessionId, mode, remaining, connectLockCallback);
  7246. }
  7247. if (!queryConnection(connectionId)) // aborted
  7248. {
  7249. connectionId = 0;
  7250. throw MakeSDSException(SDSExcpt_AbortDuringConnection, " during connect");
  7251. }
  7252. iter.setown(root->getElements(xpath+1));
  7253. iter->first();
  7254. }
  7255. }
  7256. break;
  7257. }
  7258. catch (ISDSException *e) // don't treat waiting on a now orpahned node an error, since trying to lock to create (retry)
  7259. {
  7260. if (SDSExcpt_OrphanedNode != e->errorCode())
  7261. throw;
  7262. else
  7263. e->Release();
  7264. }
  7265. freeExistingLocks.clear();
  7266. }
  7267. }
  7268. catch (IException *)
  7269. {
  7270. CHECKEDCRITICALBLOCK(cTableCrit, fakeCritTimeout);
  7271. tmpConn->unsubscribeSession();
  7272. connections.removeExact(tmpConn);
  7273. connectionId = 0;
  7274. throw;
  7275. }
  7276. { CHECKEDCRITICALBLOCK(cTableCrit, fakeCritTimeout);
  7277. tmpConn->unsubscribeSession();
  7278. connections.removeExact(tmpConn);
  7279. }
  7280. }
  7281. try
  7282. {
  7283. if (RTM_MODE(mode, RTM_CREATE_ADD) || RTM_MODE(mode, RTM_CREATE_UNIQUE))
  7284. {
  7285. CHECKEDCRITICALBLOCK(blockedSaveCrit, fakeCritTimeout);
  7286. connection.setown(createConnectionInstance(root, sessionId, mode, timeout, xpath, _tree, connectionId, &deltaPath, deltaChange, branchChange, additions));
  7287. }
  7288. else
  7289. connection.setown(createConnectionInstance(root, sessionId, mode, timeout, xpath, _tree, connectionId, &deltaPath, deltaChange, branchChange, additions));
  7290. }
  7291. catch (IException *) // do not want to miss recording change to inc, under any circumstances.
  7292. {
  7293. if (deltaChange.get())
  7294. {
  7295. PROGLOG("Exception on RTM_CREATE caused call to saveDelta, xpath=%s", xpath);
  7296. saveDelta(deltaPath, *deltaChange);
  7297. }
  7298. throw;
  7299. }
  7300. linkedTree.set(_tree);
  7301. if (!connection)
  7302. {
  7303. connectionId = 0;
  7304. return;
  7305. }
  7306. assertex(_tree);
  7307. if (deltaChange.get())
  7308. {
  7309. CPTStack stack = connection->queryPTreePath();
  7310. if (connection->queryRoot() == SDSManager->queryRoot())
  7311. stack.pop();
  7312. stack.popn(additions);
  7313. connection->notify();
  7314. SDSManager->startNotification(*deltaChange, stack, *branchChange);
  7315. saveDelta(deltaPath, *deltaChange);
  7316. }
  7317. connectionId = connection->queryConnectionId();
  7318. if (freeExistingLocks.isExisting(*(CServerRemoteTree *)_tree))
  7319. {
  7320. locked = true;
  7321. freeExistingLocks.remove(*(CServerRemoteTree *)_tree);
  7322. connectCritBlock.clear();
  7323. }
  7324. { CHECKEDCRITICALBLOCK(cTableCrit, fakeCritTimeout);
  7325. connections.replace(*LINK(connection));
  7326. }
  7327. try
  7328. {
  7329. if (!locked)
  7330. {
  7331. CConnectExistingLockCallback connectLockCallback(xpath, connectionId, *(CServerRemoteTree *)_tree, connectCritBlock.get()?&connectCrit:NULL);
  7332. lock(*(CServerRemoteTree *)_tree, xpath, connectionId, sessionId, mode, timeout, connectLockCallback);
  7333. }
  7334. }
  7335. catch (IException *)
  7336. {
  7337. { CHECKEDCRITICALBLOCK(cTableCrit, fakeCritTimeout);
  7338. connections.removeExact(connection);
  7339. }
  7340. throw;
  7341. }
  7342. catch (DALI_CATCHALL)
  7343. {
  7344. { CHECKEDCRITICALBLOCK(cTableCrit, fakeCritTimeout);
  7345. connections.removeExact(connection);
  7346. }
  7347. throw;
  7348. }
  7349. if (sessionId)
  7350. {
  7351. // unlock global lock whilst subscription occurs, incase it calls me back inline (e.g. during an immediate abort)
  7352. {
  7353. LockUnblock b(dataRWLock);
  7354. connection->subscribe(sessionId);
  7355. }
  7356. // subscription may have already disconnected by this stage.
  7357. if (!queryConnection(connectionId))
  7358. {
  7359. connectionId = 0;
  7360. throw MakeSDSException(SDSExcpt_AbortDuringConnection, " during connect");
  7361. }
  7362. }
  7363. }
  7364. catch (IException *e)
  7365. {
  7366. if (SDSExcpt_OrphanedNode != e->errorCode())
  7367. throw;
  7368. e->Release();
  7369. connectionId = 0;
  7370. return;
  7371. }
  7372. // could have been blocked, now freed but in the meantime *this* connection has been aborted.
  7373. if (!queryConnection(connectionId))
  7374. {
  7375. unlock(_tree->queryServerId(), connectionId);
  7376. connectionId = 0;
  7377. throw MakeSDSException(SDSExcpt_AbortDuringConnection, " during connect");
  7378. }
  7379. connection->setEstablished();
  7380. tree = (CServerRemoteTree *) LINK(_tree);
  7381. connectionId = connection->queryConnectionId();
  7382. }
  7383. CServerConnection *CCovenSDSManager::queryConnection(ConnectionId id)
  7384. {
  7385. CHECKEDCRITICALBLOCK(cTableCrit, fakeCritTimeout);
  7386. return (CServerConnection *)connections.find(&id);
  7387. }
  7388. CServerConnection *CCovenSDSManager::getConnection(ConnectionId id)
  7389. {
  7390. CHECKEDCRITICALBLOCK(cTableCrit, fakeCritTimeout);
  7391. CServerConnection *conn = (CServerConnection *)connections.find(&id);
  7392. if (conn) conn->Link();
  7393. return conn;
  7394. }
  7395. void CCovenSDSManager::disconnect(ConnectionId id, bool deleteRoot, Owned<CLCLockBlock> *lockBlock)
  7396. {
  7397. Linked<CServerConnection> connection;
  7398. { CHECKEDCRITICALBLOCK(cTableCrit, fakeCritTimeout);
  7399. connection.set(queryConnection(id));
  7400. if (!connection)
  7401. return;
  7402. connections.removeExact(connection);
  7403. }
  7404. Linked<CServerRemoteTree> tree = (CServerRemoteTree *)connection->queryRootUnvalidated();
  7405. if (!tree) return;
  7406. unsigned index = (unsigned)-1;
  7407. StringBuffer path;
  7408. connection->queryPTreePath().getAbsolutePath(path);
  7409. bool noLockDelete = false;
  7410. if (connection->queryParent())
  7411. {
  7412. if (deleteRoot || RTM_MODE(connection->queryMode(), RTM_DELETE_ON_DISCONNECT))
  7413. {
  7414. CHECKEDCRITICALBLOCK(lockCrit, fakeCritTimeout);
  7415. CLockInfo *lockInfo = queryLockInfo(tree->queryServerId());
  7416. if (lockInfo)
  7417. {
  7418. deleteRoot = false;
  7419. lockInfo->setDROLR((CServerRemoteTree *)connection->queryParent(), tree);
  7420. }
  7421. else
  7422. noLockDelete = deleteRoot = true;
  7423. }
  7424. if (lockBlock)
  7425. {
  7426. lockBlock->clear();
  7427. lockBlock->setown(new CLCWriteLockBlock(dataRWLock, readWriteTimeout, __FILE__, __LINE__));
  7428. }
  7429. if ((unsigned)-1 == index)
  7430. index = connection->queryParent()->queryChildIndex(connection->queryRootUnvalidated());
  7431. }
  7432. else
  7433. deleteRoot = false;
  7434. bool orphaned = ((CServerRemoteTree*)connection->queryRootUnvalidated())->isOrphaned();
  7435. // Still want disconnection to be performed & recorded, if orphaned
  7436. if (noLockDelete)
  7437. connection->queryParent()->removeTree(tree);
  7438. else
  7439. deleteRoot |= unlock(tree->queryServerId(), id);
  7440. if (deleteRoot)
  7441. writeTransactions++;
  7442. if (!orphaned && deleteRoot)
  7443. {
  7444. Owned<IPropertyTree> changeTree = createPTree(RESERVED_CHANGE_NODE);
  7445. IPropertyTree *d = changeTree->setPropTree(DELETE_TAG, createPTree());
  7446. d->setProp("@name", tree->queryName());
  7447. d->setPropInt("@pos", index+1);
  7448. Owned<CBranchChange> branchChange = new CBranchChange(*tree);
  7449. branchChange->noteChange(PDS_Deleted, PDS_Deleted);
  7450. CPTStack stack = connection->queryPTreePath();
  7451. stack.pop();
  7452. if (connection->queryRootUnvalidated() == SDSManager->queryRoot())
  7453. stack.pop();
  7454. if (!RTM_MODE(connection->queryMode(), RTM_INTERNAL))
  7455. {
  7456. connection->notify();
  7457. SDSManager->startNotification(*changeTree, stack, *branchChange);
  7458. }
  7459. StringBuffer head;
  7460. const char *tail = splitXPath(path.str(), head);
  7461. CHECKEDCRITICALBLOCK(blockedSaveCrit, fakeCritTimeout);
  7462. if (NotFound != index)
  7463. saveDelta(head.str(), *changeTree);
  7464. else
  7465. { // NB: don't believe this can happen, but last thing want to do is save duff delete delta.
  7466. WARNLOG("** CCovenSDSManager::disconnect - index position lost ** : noLockDelete=%d", noLockDelete);
  7467. PrintStackReport();
  7468. }
  7469. }
  7470. tree.clear();
  7471. connection->unsubscribeSession();
  7472. }
  7473. StringBuffer &CCovenSDSManager::getLocks(StringBuffer &out)
  7474. {
  7475. CHECKEDCRITICALBLOCK(lockCrit, fakeCritTimeout);
  7476. SuperHashIteratorOf<CLockInfo> iter(lockTable.queryBaseTable());
  7477. iter.first();
  7478. while (iter.isValid())
  7479. {
  7480. CLockInfo &lockInfo = iter.query();
  7481. if (lockInfo.lockCount())
  7482. lockInfo.getLockInfo(out);
  7483. if (!iter.next())
  7484. break;
  7485. if (out.length()) out.newline();
  7486. }
  7487. return out.length() ? out : out.append("No current locks");
  7488. }
  7489. StringBuffer &formatUsageStats(MemoryBuffer &src, StringBuffer &out)
  7490. {
  7491. unsigned c;
  7492. src.read(c);
  7493. out.append("Connections : ").append(c).newline();
  7494. src.read(c);
  7495. out.append("Locks : ").append(c).newline();
  7496. src.read(c);
  7497. out.append("Subscribers : ").append(c).newline();
  7498. src.read(c);
  7499. out.append("Connection subscriptions : ").append(c).newline();
  7500. return out;
  7501. }
  7502. StringBuffer &formatConnectionInfo(MemoryBuffer &src, StringBuffer &out)
  7503. {
  7504. ConnectionId connectionId;
  7505. StringAttr xpath;
  7506. SessionId sessionId;
  7507. unsigned mode;
  7508. unsigned timeout;
  7509. bool established;
  7510. src.read(connectionId).read(xpath).read(sessionId).read(mode).read(timeout).read(established);
  7511. out.append("ConnectionId=").appendf("%"I64F"x", connectionId).append(", xpath=").append(xpath).append(", sessionId=").appendf("%"I64F"x", sessionId).append(", mode=").append(mode).append(", timeout=");
  7512. if (INFINITE == timeout)
  7513. out.append("INFINITE");
  7514. else
  7515. out.append(timeout);
  7516. out.append(established?"":" [BLOCKED]");
  7517. return out;
  7518. }
  7519. StringBuffer &formatSubscriberInfo(MemoryBuffer &src, StringBuffer &out)
  7520. {
  7521. SubscriptionId subscriptionId;
  7522. bool sub;
  7523. StringAttr xpath;
  7524. src.read(subscriptionId).read(sub).read(xpath);
  7525. out.append("SubscriptionId=").appendf("%"I64F"x", subscriptionId).append(", xpath=").append(xpath).append(", sub=").append(sub?"true":"false");
  7526. return out;
  7527. }
  7528. StringBuffer &formatNodeSubscriberInfo(MemoryBuffer &src, StringBuffer &out)
  7529. {
  7530. SubscriptionId subscriptionId;
  7531. StringAttr xpath;
  7532. unsigned nodeCount;
  7533. src.read(subscriptionId).read(xpath).read(nodeCount);
  7534. out.append("SubscriptionId=").appendf("%"I64F"x", subscriptionId).append(", xpath=").append(xpath).append(", nodes=").append(nodeCount);
  7535. return out;
  7536. }
  7537. StringBuffer &formatConnections(MemoryBuffer &src, StringBuffer &out)
  7538. {
  7539. unsigned count;
  7540. src.read(count);
  7541. if (count)
  7542. {
  7543. while (count--)
  7544. {
  7545. formatConnectionInfo(src, out);
  7546. if (count) out.newline();
  7547. }
  7548. }
  7549. else
  7550. out.append("No current connections");
  7551. return out;
  7552. }
  7553. StringBuffer &formatSubscribers(MemoryBuffer &src, StringBuffer &out)
  7554. {
  7555. unsigned sdsSubscribers, sdsNodeSubscribers=0;
  7556. src.read(sdsSubscribers);
  7557. unsigned s = sdsSubscribers;
  7558. while (s--)
  7559. {
  7560. formatSubscriberInfo(src, out);
  7561. if (s) out.newline();
  7562. }
  7563. if (src.remaining())
  7564. {
  7565. src.read(sdsNodeSubscribers);
  7566. s = sdsNodeSubscribers;
  7567. while (s--)
  7568. {
  7569. formatNodeSubscriberInfo(src, out);
  7570. if (s) out.newline();
  7571. }
  7572. }
  7573. out.newline().appendf("%d xpath subscribers, %d node subscribers\n", sdsSubscribers, sdsNodeSubscribers);
  7574. return out;
  7575. }
  7576. unsigned CCovenSDSManager::countConnections()
  7577. {
  7578. CHECKEDCRITICALBLOCK(cTableCrit, fakeCritTimeout);
  7579. return connections.count();
  7580. }
  7581. unsigned CCovenSDSManager::countActiveLocks()
  7582. {
  7583. unsigned activeLocks = 0;
  7584. CHECKEDCRITICALBLOCK(lockCrit, fakeCritTimeout);
  7585. SuperHashIteratorOf<CLockInfo> iter(lockTable.queryBaseTable());
  7586. ForEach(iter) {
  7587. CLockInfo &lockInfo = iter.query();
  7588. if (lockInfo.lockCount()) activeLocks++;
  7589. }
  7590. return activeLocks;
  7591. }
  7592. MemoryBuffer &CCovenSDSManager::collectUsageStats(MemoryBuffer &out)
  7593. {
  7594. { CHECKEDCRITICALBLOCK(cTableCrit, fakeCritTimeout);
  7595. out.append(connections.count());
  7596. }
  7597. unsigned activeLocks = 0;
  7598. { CHECKEDCRITICALBLOCK(lockCrit, fakeCritTimeout);
  7599. SuperHashIteratorOf<CLockInfo> iter(lockTable.queryBaseTable());
  7600. ForEach(iter)
  7601. {
  7602. CLockInfo &lockInfo = iter.query();
  7603. if (lockInfo.lockCount()) activeLocks++;
  7604. }
  7605. }
  7606. out.append(activeLocks);
  7607. out.append(subscribers.count());
  7608. out.append(connectionSubscriptionManager->querySubscribers());
  7609. return out;
  7610. }
  7611. MemoryBuffer &CCovenSDSManager::collectConnections(MemoryBuffer &out)
  7612. {
  7613. CHECKEDCRITICALBLOCK(cTableCrit, fakeCritTimeout);
  7614. out.append(connections.count());
  7615. SuperHashIteratorOf<CServerConnection> iter(connections.queryBaseTable());
  7616. ForEach(iter)
  7617. iter.query().getInfo(out);
  7618. return out;
  7619. }
  7620. MemoryBuffer &CCovenSDSManager::collectSubscribers(MemoryBuffer &out)
  7621. {
  7622. CHECKEDCRITICALBLOCK(sTableCrit, fakeCritTimeout);
  7623. out.append(subscribers.count());
  7624. SuperHashIteratorOf<CSubscriberContainer> sdsIter(subscribers.queryBaseTable());
  7625. ForEach(sdsIter)
  7626. sdsIter.query().getInfo(out);
  7627. nodeSubscriptionManager->collectSubscribers(out);
  7628. return out;
  7629. }
  7630. void CCovenSDSManager::blockingSave(unsigned *writeTransactions)
  7631. {
  7632. CHECKEDDALIREADLOCKBLOCK(SDSManager->dataRWLock, readWriteTimeout); // block all write actions whilst saving
  7633. CHECKEDCRITICALBLOCK(blockedSaveCrit, fakeCritTimeout);
  7634. if (writeTransactions)
  7635. *writeTransactions = SDSManager->writeTransactions;
  7636. // JCS - could in theory, not block, but abort save.
  7637. SDSManager->saveStore();
  7638. }
  7639. StringBuffer &CCovenSDSManager::getUsageStats(StringBuffer &out)
  7640. {
  7641. MemoryBuffer mb;
  7642. formatUsageStats(collectUsageStats(mb), out);
  7643. return out;
  7644. }
  7645. bool CCovenSDSManager::updateEnvironment(IPropertyTree *newEnv, bool forceGroupUpdate, StringBuffer &response)
  7646. {
  7647. Owned<IRemoteConnection> conn = querySDS().connect("/",myProcessSession(),0, INFINITE);
  7648. if (conn)
  7649. {
  7650. Owned<IPropertyTree> root = conn->getRoot();
  7651. Owned<IPropertyTree> oldEnvironment = root->getPropTree("Environment");
  7652. if (oldEnvironment.get())
  7653. {
  7654. StringBuffer bakname;
  7655. Owned<IFileIO> io = createUniqueFile(NULL, "environment", "bak", bakname);
  7656. Owned<IFileIOStream> fstream = createBufferedIOStream(io);
  7657. toXML(oldEnvironment, *fstream); // formatted (default)
  7658. root->removeTree(oldEnvironment);
  7659. }
  7660. root->addPropTree("Environment", LINK(newEnv));
  7661. root.clear();
  7662. conn->commit();
  7663. conn->close();
  7664. StringBuffer messages;
  7665. initClusterGroups(forceGroupUpdate, messages, oldEnvironment);
  7666. response.append(messages);
  7667. PROGLOG("Environment and node groups updated");
  7668. }
  7669. return true;
  7670. }
  7671. // TODO
  7672. StringBuffer &CCovenSDSManager::getExternalReport(StringBuffer &out)
  7673. {
  7674. return out;
  7675. }
  7676. StringBuffer &CCovenSDSManager::getConnections(StringBuffer &out)
  7677. {
  7678. MemoryBuffer mb;
  7679. formatConnections(collectConnections(mb), out);
  7680. return out;
  7681. }
  7682. StringBuffer &CCovenSDSManager::getSubscribers(StringBuffer &out)
  7683. {
  7684. MemoryBuffer mb;
  7685. formatSubscribers(collectSubscribers(mb), out);
  7686. return out;
  7687. }
  7688. void CCovenSDSManager::handleNodeNotify(notifications n, CServerRemoteTree &tree)
  7689. {
  7690. const char *handlerKey = tree.queryProp(NOTIFY_ATTR);
  7691. assertex(handlerKey);
  7692. CSDSNotifyHandlerMapping *m = nodeNotifyHandlers.find(handlerKey);
  7693. if (!m)
  7694. {
  7695. LOG(MCwarning, unknownJob, "Unknown notify handler name \"%s\", handing event %s", handlerKey, notificationStr(n));
  7696. return;
  7697. }
  7698. switch (n)
  7699. {
  7700. case notify_delete:
  7701. try { m->query().removed(tree); }
  7702. catch (IException *e)
  7703. {
  7704. StringBuffer s("Exception calling ISDSNotifyHandler->removed(<tree>), for handler\"");
  7705. s.append(notificationStr(n)).append("\"");
  7706. EXCLOG(e, s.str());
  7707. e->Release();
  7708. }
  7709. break;
  7710. default:
  7711. LOG(MCerror, unknownJob, "Unknown notification type (%d)", n);
  7712. break;
  7713. }
  7714. }
  7715. void CCovenSDSManager::handleNotify(CSubscriberContainerBase &subscriber, MemoryBuffer &notifyData)
  7716. {
  7717. class CNotifyPoolFactory : public CInterface, public IThreadFactory
  7718. {
  7719. class CNotifyHandler : public CInterface, implements IPooledThread
  7720. {
  7721. DECL_NAMEDCOUNT;
  7722. public:
  7723. IMPLEMENT_IINTERFACE;
  7724. CNotifyHandler() { INIT_NAMEDCOUNT; }
  7725. void init(void *startInfo)
  7726. {
  7727. n.set((CSubscriberNotifier *)startInfo);
  7728. }
  7729. void main()
  7730. {
  7731. n->notify();
  7732. n.clear();
  7733. }
  7734. bool canReuse()
  7735. {
  7736. return true;
  7737. }
  7738. bool stop()
  7739. {
  7740. return true;
  7741. }
  7742. private:
  7743. Linked<CSubscriberNotifier> n;
  7744. };
  7745. public:
  7746. IMPLEMENT_IINTERFACE;
  7747. IPooledThread *createNew()
  7748. {
  7749. return new CNotifyHandler();
  7750. }
  7751. };
  7752. if (!notifyPool)
  7753. {
  7754. CNotifyPoolFactory *factory = new CNotifyPoolFactory;
  7755. notifyPool.setown(createThreadPool("SDS Notification Pool", factory, this, SUBNTFY_POOL_SIZE));
  7756. factory->Release();
  7757. }
  7758. Owned<CSubscriberNotifier> _notifier;
  7759. { CHECKEDCRITICALBLOCK(nfyTableCrit, fakeCritTimeout);
  7760. SubscriptionId id = subscriber.queryId();
  7761. CSubscriberNotifier *notifier = subscriberNotificationTable.find(id);
  7762. if (notifier)
  7763. {
  7764. notifier->queueChange(notifyData);
  7765. return;
  7766. }
  7767. else
  7768. {
  7769. _notifier.setown(new CSubscriberNotifier(subscriberNotificationTable, subscriber, notifyData));
  7770. subscriberNotificationTable.replace(*_notifier);
  7771. }
  7772. }
  7773. notifyPool->start(_notifier.get());
  7774. }
  7775. /////////////////
  7776. class CSubscriberNotifyScanner : public CInterface
  7777. {
  7778. DECL_NAMEDCOUNT;
  7779. CPTStack stack;
  7780. Linked<IPropertyTree> changeTree;
  7781. Linked<CBranchChange> rootChanges;
  7782. StringBuffer xpath;
  7783. CSubscriberArray subs;
  7784. public:
  7785. struct PushPop
  7786. {
  7787. PushPop(CPTStack &_stack, CRemoteTreeBase &tree) : stack(_stack) { tree.Link(); stack.append(tree); }
  7788. ~PushPop() { stack.pop(); }
  7789. CPTStack &stack;
  7790. };
  7791. CSubscriberNotifyScanner(IPropertyTree &_changeTree, CPTStack &_stack, CBranchChange &_rootChanges) : changeTree(&_changeTree), rootChanges(&_rootChanges), stack(_stack)
  7792. {
  7793. INIT_NAMEDCOUNT;
  7794. SDSManager->querySubscriberTable().getSubscribers(subs);
  7795. }
  7796. bool match(const char *head, const char *path, bool &sub)
  7797. {
  7798. bool wild = false;
  7799. loop
  7800. {
  7801. if (wild)
  7802. {
  7803. if (*head == *path)
  7804. {
  7805. path++;
  7806. wild = false;
  7807. }
  7808. else if ('/' == *head)
  7809. wild = false;
  7810. }
  7811. else if ('*' == *path)
  7812. {
  7813. path++;
  7814. wild = true;
  7815. }
  7816. else if (*head != *path)
  7817. return false;
  7818. else
  7819. path++;
  7820. head++;
  7821. if ('\0' == *path)
  7822. {
  7823. if (!wild && '/' != *(path-1) && '/' != *head) return false;
  7824. sub = true;
  7825. return true;
  7826. }
  7827. else
  7828. {
  7829. if ('\0' == *head)
  7830. {
  7831. sub = false;
  7832. return true;
  7833. }
  7834. }
  7835. }
  7836. }
  7837. void scan()
  7838. {
  7839. xpath.clear();
  7840. stack.toString(xpath);
  7841. if (stack.ordinality() && (rootChanges->tree == &(stack.tos()))) stack.pop();
  7842. CSubscriberArray pruned;
  7843. scan(*rootChanges, stack, pruned);
  7844. }
  7845. bool prune(const char *xpath, bool &sub, CSubscriberArray &pruned)
  7846. {
  7847. sub = false;
  7848. ForEachItemInRev(s, subs)
  7849. {
  7850. CSubscriberContainer &subscriber = subs.item(s);
  7851. bool _sub; // false = (xpath NOT below subscriber), (true = xpath equals or is below subscriber)
  7852. if (subscriber.isUnsubscribed() || !match(xpath, subscriber.queryXPath(), _sub))
  7853. {
  7854. pruned.append(*LINK(&subscriber));
  7855. subs.remove(s);
  7856. }
  7857. else
  7858. sub |= _sub;
  7859. }
  7860. return (subs.ordinality() > 0);
  7861. }
  7862. // recurse down all matching subscription stubs while qualified
  7863. void scanAll(PDState state, CBranchChange &changes, CPTStack &stack, CSubscriberArray &pruned)
  7864. {
  7865. bool sub;
  7866. if (prune(xpath.str(), sub, pruned))
  7867. {
  7868. MemoryBuffer notifyData;
  7869. if (sub)
  7870. {
  7871. ForEachItemInRev(s, subs)
  7872. {
  7873. CSubscriberContainer &subscriber = subs.item(s);
  7874. if (!subscriber.isUnsubscribed())
  7875. {
  7876. if (subscriber.qualify(stack, true))
  7877. {
  7878. if (0 == notifyData.length())
  7879. buildNotifyData(notifyData, state, &stack, NULL);
  7880. SDSManager->handleNotify(subscriber, notifyData);
  7881. }
  7882. else
  7883. pruned.append(*LINK(&subscriber));
  7884. }
  7885. subs.remove(s);
  7886. }
  7887. }
  7888. else
  7889. {
  7890. if (0 == changes.children.ordinality())
  7891. {
  7892. ForEachItemInRev(s, subs)
  7893. {
  7894. CSubscriberContainer &subscriber = subs.item(s);
  7895. if (!subscriber.isUnsubscribed())
  7896. {
  7897. if (subscriber.qualify(stack, true))
  7898. {
  7899. if (0 == notifyData.length())
  7900. buildNotifyData(notifyData, state, &stack, NULL);
  7901. SDSManager->handleNotify(subscriber, notifyData);
  7902. }
  7903. else
  7904. pruned.append(*LINK(&subscriber));
  7905. }
  7906. subs.remove(s);
  7907. }
  7908. }
  7909. else
  7910. {
  7911. ForEachItemIn (c, changes.children)
  7912. {
  7913. CBranchChange &childChange = changes.children.item(c);
  7914. PushPop pp(stack, *childChange.tree);
  7915. size32_t parentLength = xpath.length();
  7916. xpath.append(childChange.tree->queryName());
  7917. if ('/' != xpath.charAt(xpath.length()-1))
  7918. xpath.append('/');
  7919. CSubscriberArray _pruned;
  7920. scanAll(state, childChange, stack, _pruned);
  7921. ForEachItemIn(i, _pruned) subs.append(*LINK(&_pruned.item(i)));
  7922. if (0 == subs.ordinality())
  7923. break;
  7924. xpath.setLength(parentLength);
  7925. }
  7926. }
  7927. }
  7928. }
  7929. }
  7930. void scan(CBranchChange &changes, CPTStack &stack, CSubscriberArray &pruned)
  7931. {
  7932. bool sub;
  7933. if (!prune(xpath.str(), sub, pruned))
  7934. return;
  7935. PushPop pp(stack, *changes.tree);
  7936. if (PDS_Deleted == (changes.local & PDS_Deleted))
  7937. {
  7938. scanAll(changes.local, changes, stack, pruned);
  7939. return;
  7940. }
  7941. else if (sub) // xpath matched some subscribers, and/or below some, need to check for sub subscribers
  7942. {
  7943. bool ret = false;
  7944. // avoid notifying on PDS_Structure only, which signifies changes deeper down only
  7945. MemoryBuffer notifyData;
  7946. if (changes.state && changes.local && (changes.local != PDS_Structure))
  7947. {
  7948. int lastSendValue = -1;
  7949. ForEachItemInRev(s, subs)
  7950. {
  7951. CSubscriberContainer &subscriber = subs.item(s);
  7952. if (!subscriber.isUnsubscribed())
  7953. {
  7954. if (subscriber.qualify(stack, false))
  7955. {
  7956. if (subscriber.querySendValue())
  7957. {
  7958. if (1 != lastSendValue)
  7959. {
  7960. MemoryBuffer mb;
  7961. changes.tree->getPropBin(NULL, mb);
  7962. buildNotifyData(notifyData.clear(), changes.state, &stack, &mb);
  7963. lastSendValue = 1;
  7964. }
  7965. }
  7966. else
  7967. {
  7968. if (0 != lastSendValue)
  7969. {
  7970. buildNotifyData(notifyData.clear(), changes.state, &stack, NULL);
  7971. lastSendValue = 0;
  7972. }
  7973. }
  7974. SDSManager->handleNotify(subscriber, notifyData);
  7975. }
  7976. else
  7977. pruned.append(*LINK(&subscriber));
  7978. }
  7979. subs.remove(s);
  7980. }
  7981. }
  7982. else
  7983. {
  7984. // remove non-sub subcribers at this level
  7985. ForEachItemInRev(s, subs)
  7986. {
  7987. CSubscriberContainer &subscriber = subs.item(s);
  7988. unsigned subDepth = subscriber.queryDepth();
  7989. unsigned stackDepth = stack.ordinality();
  7990. if ((!subscriber.querySub() && subDepth==stackDepth) || 0 == changes.children.ordinality())
  7991. {
  7992. pruned.append(*LINK(&subscriber));
  7993. subs.remove(s);
  7994. }
  7995. }
  7996. }
  7997. }
  7998. ForEachItemIn(c, changes.children)
  7999. {
  8000. CBranchChange &childChanges = changes.children.item(c);
  8001. size32_t parentLength = xpath.length();
  8002. xpath.append(childChanges.tree->queryName());
  8003. if ('/' != xpath.charAt(xpath.length()-1))
  8004. xpath.append('/');
  8005. CSubscriberArray pruned;
  8006. scan(childChanges, stack, pruned);
  8007. ForEachItemIn(i, pruned) subs.append(*LINK(&pruned.item(i)));
  8008. if (0 == subs.ordinality())
  8009. break;
  8010. xpath.setLength(parentLength);
  8011. }
  8012. }
  8013. };
  8014. void CCovenSDSManager::startNotification(IPropertyTree &changeTree, CPTStack &stack, CBranchChange &changes)
  8015. {
  8016. class CScanNotifyPoolFactory : public CInterface, public IThreadFactory
  8017. {
  8018. class CScanNotifyHandler : public CInterface, implements IPooledThread
  8019. {
  8020. public:
  8021. IMPLEMENT_IINTERFACE;
  8022. void init(void *startInfo)
  8023. {
  8024. n.set((CSubscriberNotifyScanner *)startInfo);
  8025. }
  8026. void main()
  8027. {
  8028. n->scan();
  8029. n.clear();
  8030. }
  8031. bool canReuse()
  8032. {
  8033. return true;
  8034. }
  8035. bool stop()
  8036. {
  8037. return true;
  8038. }
  8039. private:
  8040. Linked<CSubscriberNotifyScanner> n;
  8041. };
  8042. public:
  8043. IMPLEMENT_IINTERFACE;
  8044. IPooledThread *createNew()
  8045. {
  8046. return new CScanNotifyHandler();
  8047. }
  8048. };
  8049. if (!scanNotifyPool)
  8050. {
  8051. CScanNotifyPoolFactory *factory = new CScanNotifyPoolFactory;
  8052. scanNotifyPool.setown(createThreadPool("SDS Scan-Notification Pool", factory, this, SUBSCAN_POOL_SIZE));
  8053. factory->Release();
  8054. }
  8055. Owned<CSubscriberNotifyScanner> scan = new CSubscriberNotifyScanner(changeTree, stack, changes);
  8056. scanNotifyPool->start(scan.get());
  8057. }
  8058. void CCovenSDSManager::deleteExternal(__int64 index)
  8059. {
  8060. if (server.queryStopped()) return;
  8061. CHECKEDCRITICALBLOCK(extCrit, fakeCritTimeout);
  8062. IExternalHandler *handler = queryExternalHandler(EF_BinaryValue);
  8063. assertex(handler);
  8064. StringBuffer name(EXTERNAL_NAME_PREFIX);
  8065. name.append(index);
  8066. handler->remove(name.str());
  8067. }
  8068. void CCovenSDSManager::serializeExternal(__int64 index, IPropertyTree &owner, MemoryBuffer &mb, bool withValue)
  8069. {
  8070. CHECKEDCRITICALBLOCK(extCrit, fakeCritTimeout);
  8071. IExternalHandler *extHandler = queryExternalHandler(EF_BinaryValue);
  8072. assertex(extHandler);
  8073. try
  8074. {
  8075. StringBuffer name(EXTERNAL_NAME_PREFIX);
  8076. name.append(index);
  8077. extHandler->read(name.str(), owner, mb, withValue);
  8078. }
  8079. catch (IException *)
  8080. {
  8081. extHandler->resetAsExternal(owner);
  8082. throw;
  8083. }
  8084. }
  8085. void CCovenSDSManager::writeExternal(CServerRemoteTree &tree, bool direct, __int64 existing)
  8086. {
  8087. CHECKEDCRITICALBLOCK(extCrit, fakeCritTimeout);
  8088. __int64 index;
  8089. if (existing)
  8090. index = existing;
  8091. else
  8092. index = getNextExternal();
  8093. IExternalHandler *extHandler = queryExternalHandler(EF_BinaryValue);
  8094. assertex(extHandler);
  8095. tree.removeProp(EXT_ATTR);
  8096. StringBuffer name(EXTERNAL_NAME_PREFIX);
  8097. extHandler->write(name.append(index).str(), tree);
  8098. tree.setPropInt64(EXT_ATTR, index);
  8099. extHandler->resetAsExternal(tree);
  8100. // setPropInt64(EXT_ATTR, index); // JCSMORE not necessary
  8101. }
  8102. // ISubscriptionManager
  8103. void CCovenSDSManager::add(ISubscription *sub, SubscriptionId id)
  8104. {
  8105. CHECKEDCRITICALBLOCK(sTableCrit, fakeCritTimeout);
  8106. subscribers.replace(* new CSubscriberContainer(sub, id));
  8107. }
  8108. void CCovenSDSManager::remove(SubscriptionId id)
  8109. {
  8110. CHECKEDCRITICALBLOCK(sTableCrit, fakeCritTimeout);
  8111. subscribers.remove(&id);
  8112. }
  8113. // IExceptionHandler
  8114. static bool processingUnhandled = false;
  8115. static bool handled = false;
  8116. static CheckedCriticalSection unhandledCrit;
  8117. bool CCovenSDSManager::fireException(IException *e)
  8118. {
  8119. //This code is rather dodgy (and causes more problems than it solves)
  8120. // so ignore unhandled exceptions for the moment!
  8121. LOG(MCoperatorError, unknownJob, e, "Caught unhandled exception!");
  8122. return true;
  8123. { CHECKEDCRITICALBLOCK(unhandledCrit, fakeCritTimeout);
  8124. if (processingUnhandled)
  8125. {
  8126. if (handled)
  8127. {
  8128. LOG(MCdisaster, unknownJob, e, "FATAL, too many exceptions");
  8129. return false; // did not successfully handle.
  8130. }
  8131. LOG(MCoperatorError, unknownJob, e, "Exception while restarting or shutting down");
  8132. return true;
  8133. }
  8134. handled = false;
  8135. processingUnhandled = true;
  8136. }
  8137. // Handle exception on a separate thread, to avoid complication with joining/restarting deadlocks.
  8138. class CHandleException : public Thread
  8139. {
  8140. CCovenSDSManager &manager;
  8141. Linked<IException> e;
  8142. bool restart;
  8143. public:
  8144. CHandleException(CCovenSDSManager &_manager, IException *_e, bool _restart) : Thread("sds:CHandleException"), manager(_manager), e(_e), restart(_restart)
  8145. {
  8146. start();
  8147. }
  8148. virtual int run()
  8149. {
  8150. handled=true;
  8151. try
  8152. {
  8153. if (restart)
  8154. manager.restart(e);
  8155. else
  8156. {
  8157. StringBuffer msg;
  8158. msg.append("Unhandled exception, shutting down: ").append(e->errorCode()).append(": ");
  8159. e->errorMessage(msg);
  8160. manager.stop();
  8161. manager.saveStore();
  8162. }
  8163. manager.unhandledThread.clear();
  8164. }
  8165. catch (IException *_e) { LOG(MCoperatorError, unknownJob, _e, "Exception while restarting or shutting down"); _e->Release(); }
  8166. catch (DALI_CATCHALL) { LOG(MCoperatorError, unknownJob, "Unknown exception while restarting or shutting down"); }
  8167. if (!restart)
  8168. {
  8169. e->Link();
  8170. throw e.get();
  8171. }
  8172. processingUnhandled = false;
  8173. handled = false;
  8174. return 0;
  8175. }
  8176. };
  8177. unhandledThread.setown(new CHandleException(*this, e, restartOnError));
  8178. return true;
  8179. }
  8180. void CCovenSDSManager::addNodeSubscriber(ISubscription *sub, SubscriptionId id)
  8181. {
  8182. MemoryBuffer mb;
  8183. mb.setBuffer(sub->queryData().length(), (void *)sub->queryData().get());
  8184. StringAttr xpath;
  8185. bool sendValue;
  8186. mb.read(xpath);
  8187. mb.read(sendValue);
  8188. CHECKEDDALIREADLOCKBLOCK(dataRWLock, readWriteTimeout);
  8189. CHECKEDCRITICALBLOCK(treeRegCrit, fakeCritTimeout);
  8190. Owned<IPropertyTreeIterator> iter = root->getElements(xpath+1);
  8191. if (!iter->first())
  8192. throw MakeSDSException(SDSExcpt_SubscriptionNoMatch, "Failed to match any nodes: %s", xpath.get());
  8193. else
  8194. {
  8195. Owned<CNodeSubscriberContainer> subscriber = new CNodeSubscriberContainer(sub, id, sendValue, xpath);
  8196. do
  8197. {
  8198. CServerRemoteTree &node = (CServerRemoteTree &)iter->query();
  8199. node.setSubscribed(true);
  8200. subscriber->add(node);
  8201. }
  8202. while (iter->next());
  8203. nodeSubscriptionManager->associateSubscriber(*subscriber);
  8204. }
  8205. }
  8206. void CCovenSDSManager::removeNodeSubscriber(SubscriptionId id)
  8207. {
  8208. CHECKEDDALIREADLOCKBLOCK(dataRWLock, readWriteTimeout);
  8209. CHECKEDCRITICALBLOCK(treeRegCrit, fakeCritTimeout);
  8210. nodeSubscriptionManager->removeSubscriberAssociation(id);
  8211. }
  8212. void CCovenSDSManager::notifyNodeDelete(CServerRemoteTree &node)
  8213. {
  8214. nodeSubscriptionManager->notifyDelete(node);
  8215. }
  8216. void CCovenSDSManager::notifyNode(CServerRemoteTree &node, PDState state)
  8217. {
  8218. nodeSubscriptionManager->notify(node, state);
  8219. }
  8220. ///////////////////////
  8221. class CDaliSDSServer: public CInterface, public IDaliServer
  8222. {
  8223. public:
  8224. IMPLEMENT_IINTERFACE;
  8225. CDaliSDSServer(IPropertyTree *_config) : config(_config)
  8226. {
  8227. manager = NULL;
  8228. cancelLoad = false;
  8229. storeLoaded = false;
  8230. }
  8231. ~CDaliSDSServer()
  8232. {
  8233. delete manager;
  8234. }
  8235. void start()
  8236. {
  8237. CriticalBlock b(crit);
  8238. ICoven &coven=queryCoven();
  8239. assertex(coven.inCoven()); // must be member of coven
  8240. if (config)
  8241. sdsConfig.setown(config->getPropTree("SDS"));
  8242. if (!sdsConfig)
  8243. sdsConfig.setown(createPTree());
  8244. manager = new CCovenSDSManager(coven, *sdsConfig, config?config->queryProp("@dataPath"):NULL);
  8245. SDSManager = manager;
  8246. addThreadExceptionHandler(manager);
  8247. try { manager->loadStore(NULL, &cancelLoad); }
  8248. catch (IException *)
  8249. {
  8250. LOG(MCdebugInfo(100), unknownJob, "Failed to load main store");
  8251. throw;
  8252. }
  8253. storeLoaded = true;
  8254. manager->start();
  8255. }
  8256. void ready()
  8257. {
  8258. #ifdef TEST_NOTIFY_HANDLER
  8259. class CTestHan : public CInterface, implements ISDSNotifyHandler
  8260. {
  8261. public:
  8262. IMPLEMENT_IINTERFACE;
  8263. virtual void removed(IPropertyTree &tree)
  8264. {
  8265. PrintLog("Hello, tree(%s) handler(%s), being deleted", tree.queryName(), queryNotifyHandlerName(&tree));
  8266. }
  8267. };
  8268. Owned<ISDSNotifyHandler> myHan = new CTestHan();
  8269. ISDSManagerServer &sdsManager = querySDSServer();
  8270. sdsManager.installNotifyHandler("testHandler", myHan);
  8271. Owned<IRemoteConnection> conn = manager->connect("/", 0, 0, 0);
  8272. IPropertyTree *root = conn->queryRoot();
  8273. IPropertyTree *tree = root->setPropTree("test", createPTree());
  8274. setNotifyHandlerName("testHandler", tree);
  8275. conn->commit();
  8276. root->removeProp("test");
  8277. conn->commit();
  8278. sdsManager.removeNotifyHandler("testHandler");
  8279. #endif
  8280. }
  8281. void suspend()
  8282. {
  8283. }
  8284. void stop()
  8285. {
  8286. cancelLoad = true; // if in progress
  8287. CriticalBlock b(crit);
  8288. if (storeLoaded)
  8289. {
  8290. manager->stop();
  8291. manager->saveStore();
  8292. }
  8293. removeThreadExceptionHandler(manager);
  8294. ::Release(manager);
  8295. manager = NULL;
  8296. }
  8297. void nodeDown(rank_t rank)
  8298. {
  8299. TBD;
  8300. }
  8301. private:
  8302. CCovenSDSManager *manager;
  8303. Linked<IPropertyTree> config;
  8304. Owned<IPropertyTree> sdsConfig;
  8305. bool cancelLoad, storeLoaded;
  8306. CriticalSection crit;
  8307. };
  8308. unsigned SDSLockTimeoutCount = 0;
  8309. unsigned querySDSLockTimeoutCount()
  8310. {
  8311. return SDSLockTimeoutCount;
  8312. }
  8313. ISDSException *MakeSDSException(int errorCode)
  8314. {
  8315. ISDSException *ret = new CSDSException(errorCode);
  8316. return ret;
  8317. }
  8318. ISDSException *MakeSDSException(int errorCode, const char *errorMsg, ...)
  8319. {
  8320. if(errorCode == SDSExcpt_LockTimeout)
  8321. SDSLockTimeoutCount++;
  8322. va_list args;
  8323. va_start(args, errorMsg);
  8324. ISDSException *ret = new CSDSException(errorCode, errorMsg, args);
  8325. va_end(args);
  8326. return ret;
  8327. }
  8328. IDaliServer *createDaliSDSServer(IPropertyTree *config)
  8329. {
  8330. return new CDaliSDSServer(config);
  8331. }
  8332. //////////////////////
  8333. bool applyXmlDeltas(IPropertyTree &root, IIOStream &stream, bool stopOnError)
  8334. {
  8335. class CDeltaProcessor : CInterface, implements IPTreeNotifyEvent
  8336. {
  8337. unsigned level;
  8338. IPTreeMaker *maker;
  8339. IPropertyTree &store;
  8340. offset_t sectionEndOffset;
  8341. StringAttr headerPath;
  8342. bool stopOnError;
  8343. public:
  8344. IMPLEMENT_IINTERFACE;
  8345. bool hadError;
  8346. CDeltaProcessor(IPropertyTree &_store, bool _stopOnError) : store(_store), stopOnError(_stopOnError), level(0)
  8347. {
  8348. sectionEndOffset = 0;
  8349. hadError = false;
  8350. maker = createRootLessPTreeMaker();
  8351. }
  8352. ~CDeltaProcessor()
  8353. {
  8354. ::Release(maker);
  8355. }
  8356. void apply(IPropertyTree &change, IPropertyTree &currentBranch)
  8357. {
  8358. if (change.getPropBool("@localValue"))
  8359. {
  8360. bool binary = change.isBinary(NULL);
  8361. if (binary)
  8362. {
  8363. MemoryBuffer mb;
  8364. change.getPropBin(NULL, mb);
  8365. currentBranch.setPropBin(NULL, mb.length(), mb.toByteArray());
  8366. }
  8367. else
  8368. currentBranch.setProp(NULL, change.queryProp(NULL));
  8369. }
  8370. else if (change.getPropBool("@appendValue"))
  8371. {
  8372. if (change.queryProp(NULL))
  8373. {
  8374. bool binary=change.isBinary(NULL);
  8375. __int64 index = currentBranch.getPropInt64(EXT_ATTR);
  8376. MemoryBuffer mb;
  8377. if (index && QUERYINTERFACE(&currentBranch, CServerRemoteTree))
  8378. {
  8379. MemoryBuffer mbv;
  8380. SDSManager->getExternalValue(index, mbv);
  8381. CPTValue v(mbv);
  8382. v.getValue(mb, binary);
  8383. }
  8384. else
  8385. currentBranch.getPropBin(NULL, mb);
  8386. change.getPropBin(NULL, mb);
  8387. if (binary)
  8388. currentBranch.setPropBin(NULL, mb.length(), mb.toByteArray());
  8389. else
  8390. currentBranch.setProp(NULL, (const char *)mb.toByteArray());
  8391. }
  8392. }
  8393. Owned<IPropertyTreeIterator> iter = change.getElements(RENAME_TAG);
  8394. ForEach (*iter)
  8395. {
  8396. IPropertyTree &d = iter->query();
  8397. StringBuffer xpath(d.queryProp("@from"));
  8398. xpath.append('[').append(d.queryProp("@pos")).append(']');
  8399. verifyex(currentBranch.renameProp(xpath.str(), d.queryProp("@to")));
  8400. }
  8401. iter.setown(change.getElements(DELETE_TAG));
  8402. ForEach (*iter)
  8403. {
  8404. IPropertyTree &d = iter->query();
  8405. StringBuffer xpath(d.queryProp("@name"));
  8406. xpath.append('[').append(d.queryProp("@pos")).append(']');
  8407. if (!currentBranch.removeProp(xpath.str()))
  8408. LOG(MCoperatorWarning, unknownJob, "Property '%s' missing, but recorded as being present at time of delete, in section '%s'", xpath.str(), headerPath.get());
  8409. }
  8410. IPropertyTree *ac = change.queryPropTree(ATTRCHANGE_TAG);
  8411. if (ac)
  8412. {
  8413. Owned<IAttributeIterator> aIter = ac->getAttributes();
  8414. ForEach (*aIter)
  8415. currentBranch.setProp(aIter->queryName(), aIter->queryValue());
  8416. }
  8417. IPropertyTree *ad = change.queryPropTree(ATTRDELETE_TAG);
  8418. if (ad)
  8419. {
  8420. Owned<IAttributeIterator> aIter = ad->getAttributes();
  8421. ForEach (*aIter)
  8422. {
  8423. if (!currentBranch.removeProp(aIter->queryName()))
  8424. LOG(MCoperatorWarning, unknownJob, "Property '%s' missing, but recorded as being present at time of delete, in section '%s'", aIter->queryName(), headerPath.get());
  8425. }
  8426. }
  8427. processChildren(change, currentBranch);
  8428. }
  8429. void processChildren(IPropertyTree &change, IPropertyTree &currentBranch)
  8430. {
  8431. // process children
  8432. Owned<IPropertyTreeIterator> iter = change.getElements("T");
  8433. ForEach (*iter)
  8434. {
  8435. try
  8436. {
  8437. IPropertyTree &child = iter->query();
  8438. const char *name = child.queryProp("@name");
  8439. if (child.getPropBool("@new"))
  8440. {
  8441. IPropertyTree *newBranch = currentBranch.addPropTree(name, createPTree());
  8442. apply(child, *newBranch);
  8443. }
  8444. else if (child.getPropBool("@replace"))
  8445. {
  8446. IPropertyTree *newBranch = currentBranch.setPropTree(name, createPTree());
  8447. apply(child, *newBranch);
  8448. }
  8449. else
  8450. {
  8451. const char *pos = child.queryProp("@pos");
  8452. if (!pos)
  8453. throw MakeStringException(0, "Missing position attribute in child reference, section end offset=%"I64F"d", sectionEndOffset);
  8454. StringBuffer xpath(name);
  8455. xpath.append('[').append(pos).append(']');
  8456. IPropertyTree *existingBranch = currentBranch.queryPropTree(xpath.str());
  8457. if (!existingBranch)
  8458. throw MakeStringException(0, "Failed to locate delta change in %s, section end offset=%"I64F"d", xpath.str(), sectionEndOffset);
  8459. apply(child, *existingBranch);
  8460. }
  8461. }
  8462. catch (IException *e)
  8463. {
  8464. StringBuffer s("Error processing delta section: sectionEndOffset=");
  8465. LOG(MCoperatorError, unknownJob, e, s.append(sectionEndOffset).str());
  8466. if (stopOnError) throw;
  8467. hadError = true;
  8468. e->Release();
  8469. }
  8470. }
  8471. }
  8472. void process(IPropertyTree &match, offset_t endOffset)
  8473. {
  8474. sectionEndOffset = endOffset;
  8475. const char *xpath = match.queryProp("@path");
  8476. if (xpath && '/' == *xpath)
  8477. xpath++;
  8478. IPropertyTree *root = store.queryPropTree(xpath);
  8479. if (!root)
  8480. throw MakeStringException(0, "Failed to locate header xpath = %s", xpath);
  8481. IPropertyTree *start = match.queryPropTree("Delta/T");
  8482. if (!start)
  8483. throw MakeStringException(0, "Badly constructed delta format (missing Delta/T) in header path=%s, section end offset=%"I64F"d", xpath, endOffset);
  8484. headerPath.set(xpath);
  8485. apply(*start, *root);
  8486. }
  8487. // IPTreeNotifyEvent
  8488. virtual void beginNode(const char *tag, offset_t startOffset) { maker->beginNode(tag, startOffset); }
  8489. virtual void newAttribute(const char *name, const char *value) { maker->newAttribute(name, value); }
  8490. virtual void beginNodeContent(const char *tag) { level++; }
  8491. virtual void endNode(const char *tag, unsigned length, const void *value, bool binary, offset_t endOffset)
  8492. {
  8493. try
  8494. {
  8495. --level;
  8496. IPropertyTree *match = NULL;
  8497. if (0 == level)
  8498. {
  8499. if (0 == strcmp("Header", tag))
  8500. match = maker->queryCurrentNode();
  8501. }
  8502. maker->endNode(tag, length, value, binary, endOffset);
  8503. if (match)
  8504. {
  8505. process(*match, endOffset);
  8506. verifyex(maker->queryRoot()->removeTree(match)); // no longer needed.
  8507. }
  8508. }
  8509. catch (IException *e)
  8510. {
  8511. StringBuffer s("Error processing delta section: sectionEndOffset=");
  8512. LOG(MCoperatorError, unknownJob, e, s.append(endOffset).str());
  8513. if (stopOnError) throw;
  8514. hadError = true;
  8515. e->Release();
  8516. }
  8517. }
  8518. } deltaProcessor(root, stopOnError);
  8519. Owned<IPullPTreeReader> xmlReader = createPullXMLStreamReader(stream, deltaProcessor, (PTreeReaderOptions)((unsigned)ptr_ignoreWhiteSpace+(unsigned)ptr_noRoot), false);
  8520. try
  8521. {
  8522. xmlReader->load();
  8523. }
  8524. catch (IException *e)
  8525. {
  8526. if (stopOnError)
  8527. throw;
  8528. LOG(MCoperatorError, unknownJob, e, "XML parse error on delta load - load truncated");
  8529. e->Release();
  8530. }
  8531. return !deltaProcessor.hadError;
  8532. }
  8533. void LogRemoteConn(IRemoteConnection *conn)
  8534. {
  8535. CConnectionBase *conbase = QUERYINTERFACE(conn,CConnectionBase);
  8536. if (!conn) {
  8537. PROGLOG("Could not get base for %x",(unsigned)(memsize_t)conn);
  8538. return;
  8539. }
  8540. IPropertyTree *root = conn->queryRoot();
  8541. CRemoteTreeBase *remotetree = root?QUERYINTERFACE(root,CRemoteTreeBase):NULL;
  8542. unsigned rcount = remotetree?remotetree->getLinkCount()-1:((unsigned)-1);
  8543. PROGLOG("CONN(%x,%"I64F"x,%"I64F"x) path = '%s' mode = %x, link %d,%d",
  8544. (unsigned)(memsize_t)conn,
  8545. (__int64)conbase->querySessionId(),
  8546. (__int64)conbase->queryConnectionId(),
  8547. conbase->queryXPath(),
  8548. conbase->queryMode(),
  8549. conbase->getLinkCount()-1,
  8550. rcount);
  8551. }
  8552. #ifdef _POOLED_SERVER_REMOTE_TREE
  8553. MODULE_INIT(INIT_PRIORITY_STANDARD)
  8554. {
  8555. CServerRemoteTree_Allocator = new CFixedSizeAllocator(sizeof(CServerRemoteTree));
  8556. return true;
  8557. }
  8558. MODULE_EXIT()
  8559. {
  8560. delete CServerRemoteTree_Allocator;
  8561. }
  8562. #endif