repl5_replica.c 125 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  5. * All rights reserved.
  6. *
  7. * License: GPL (version 3 or any later version).
  8. * See LICENSE for details.
  9. * END COPYRIGHT BLOCK **/
  10. #ifdef HAVE_CONFIG_H
  11. # include <config.h>
  12. #endif
  13. /* repl5_replica.c */
  14. #include "slapi-plugin.h"
  15. #include "repl.h" /* ONREPL - this is bad */
  16. #include "repl5.h"
  17. #include "repl_shared.h"
  18. #include "csnpl.h"
  19. #include "cl5_api.h"
  20. #define RUV_SAVE_INTERVAL (30 * 1000) /* 30 seconds */
  21. #define REPLICA_RDN "cn=replica"
  22. #define CHANGELOG_RDN "cn=legacy changelog"
  23. /*
  24. * A replica is a locally-held copy of a portion of the DIT.
  25. */
  26. struct replica {
  27. Slapi_DN *repl_root; /* top of the replicated are */
  28. char *repl_name; /* unique replica name */
  29. PRBool new_name; /* new name was generated - need to be saved */
  30. ReplicaUpdateDNList updatedn_list; /* list of dns with which a supplier should bind
  31. to update this replica */
  32. Slapi_ValueSet *updatedn_groups; /* set of groups whose memebers are
  33. * allowed to update replica */
  34. ReplicaUpdateDNList groupdn_list; /* exploded listof dns from update group */
  35. PRUint32 updatedn_group_last_check;
  36. int updatedn_group_check_interval;
  37. ReplicaType repl_type; /* is this replica read-only ? */
  38. PRBool legacy_consumer; /* if true, this replica is supplied by 4.0 consumer */
  39. char* legacy_purl; /* partial url of the legacy supplier */
  40. ReplicaId repl_rid; /* replicaID */
  41. Object *repl_ruv; /* replica update vector */
  42. PRBool repl_ruv_dirty; /* Dirty flag for ruv */
  43. CSNPL *min_csn_pl; /* Pending list for minimal CSN */
  44. void *csn_pl_reg_id; /* registration assignment for csn callbacks */
  45. unsigned long repl_state_flags; /* state flags */
  46. PRUint32 repl_flags; /* persistent, externally visible flags */
  47. PRMonitor *repl_lock; /* protects entire structure */
  48. Slapi_Eq_Context repl_eqcxt_rs; /* context to cancel event that saves ruv */
  49. Slapi_Eq_Context repl_eqcxt_tr; /* context to cancel event that reaps tombstones */
  50. Object *repl_csngen; /* CSN generator for this replica */
  51. PRBool repl_csn_assigned; /* Flag set when new csn is assigned. */
  52. PRUint32 repl_purge_delay; /* When purgeable, CSNs are held on to for this many extra seconds */
  53. PRBool tombstone_reap_stop; /* TRUE when the tombstone reaper should stop */
  54. PRBool tombstone_reap_active; /* TRUE when the tombstone reaper is running */
  55. long tombstone_reap_interval; /* Time in seconds between tombstone reaping */
  56. Slapi_ValueSet *repl_referral; /* A list of administrator provided referral URLs */
  57. PRBool state_update_inprogress; /* replica state is being updated */
  58. PRLock *agmt_lock; /* protects agreement creation, start and stop */
  59. char *locking_purl; /* supplier who has exclusive access */
  60. Slapi_Counter *protocol_timeout;/* protocol shutdown timeout */
  61. Slapi_Counter *backoff_min; /* backoff retry minimum */
  62. Slapi_Counter *backoff_max; /* backoff retry maximum */
  63. Slapi_Counter *precise_purging; /* Enable precise tombstone purging */
  64. PRUint64 agmt_count; /* Number of agmts */
  65. };
  66. typedef struct reap_callback_data
  67. {
  68. int rc;
  69. unsigned long num_entries;
  70. unsigned long num_purged_entries;
  71. CSN *purge_csn;
  72. PRBool *tombstone_reap_stop;
  73. } reap_callback_data;
  74. /* Forward declarations of helper functions*/
  75. static Slapi_Entry* _replica_get_config_entry (const Slapi_DN *root, const char **attrs);
  76. static int _replica_check_validity (const Replica *r);
  77. static int _replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext);
  78. static int _replica_update_entry (Replica *r, Slapi_Entry *e, char *errortext);
  79. static int _replica_configure_ruv (Replica *r, PRBool isLocked);
  80. static char * _replica_get_config_dn (const Slapi_DN *root);
  81. static char * _replica_type_as_string (const Replica *r);
  82. /* DBDB, I think this is probably bogus : */
  83. static int replica_create_ruv_tombstone(Replica *r);
  84. static void assign_csn_callback(const CSN *csn, void *data);
  85. static void abort_csn_callback(const CSN *csn, void *data);
  86. static void eq_cb_reap_tombstones(time_t when, void *arg);
  87. static CSN *_replica_get_purge_csn_nolock (const Replica *r);
  88. static void replica_get_referrals_nolock (const Replica *r, char ***referrals);
  89. static void replica_clear_legacy_referrals (const Slapi_DN *repl_root_sdn, char **referrals, const char *state);
  90. static void replica_remove_legacy_attr (const Slapi_DN *repl_root_sdn, const char *attr);
  91. static int replica_log_ruv_elements_nolock (const Replica *r);
  92. static void replica_replace_ruv_tombstone(Replica *r);
  93. static void start_agreements_for_replica (Replica *r, PRBool start);
  94. static void _delete_tombstone(const char *tombstone_dn, const char *uniqueid, int ext_op_flags);
  95. static void replica_strip_cleaned_rids(Replica *r);
  96. static void
  97. replica_lock(PRMonitor *lock)
  98. {
  99. PR_EnterMonitor(lock);
  100. }
  101. static void
  102. replica_unlock(PRMonitor *lock)
  103. {
  104. PR_ExitMonitor(lock);
  105. }
  106. /*
  107. * Allocates new replica and reads its state and state of its component from
  108. * various parts of the DIT.
  109. */
  110. Replica *
  111. replica_new(const Slapi_DN *root)
  112. {
  113. Replica *r = NULL;
  114. Slapi_Entry *e = NULL;
  115. char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];
  116. PR_ASSERT (root);
  117. /* check if there is a replica associated with the tree */
  118. e = _replica_get_config_entry (root, NULL);
  119. if (e)
  120. {
  121. errorbuf[0] = '\0';
  122. r = replica_new_from_entry(e, errorbuf,
  123. PR_FALSE /* not a newly added entry */);
  124. if (NULL == r)
  125. {
  126. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Unable to "
  127. "configure replica %s: %s\n",
  128. slapi_sdn_get_dn(root),
  129. errorbuf);
  130. }
  131. slapi_entry_free (e);
  132. }
  133. return r;
  134. }
  135. /* constructs the replica object from the newly added entry */
  136. Replica *
  137. replica_new_from_entry (Slapi_Entry *e, char *errortext, PRBool is_add_operation)
  138. {
  139. int rc = 0;
  140. Replica *r;
  141. char *repl_name = NULL;
  142. if (e == NULL)
  143. {
  144. if (NULL != errortext)
  145. {
  146. PR_snprintf(errortext, SLAPI_DSE_RETURNTEXT_SIZE, "NULL entry");
  147. }
  148. return NULL;
  149. }
  150. r = (Replica *)slapi_ch_calloc(1, sizeof(Replica));
  151. if (!r)
  152. {
  153. if (NULL != errortext)
  154. {
  155. PR_snprintf(errortext, SLAPI_DSE_RETURNTEXT_SIZE, "Out of memory");
  156. }
  157. rc = -1;
  158. goto done;
  159. }
  160. if ((r->repl_lock = PR_NewMonitor()) == NULL)
  161. {
  162. if (NULL != errortext)
  163. {
  164. PR_snprintf(errortext, SLAPI_DSE_RETURNTEXT_SIZE, "failed to create replica lock");
  165. }
  166. rc = -1;
  167. goto done;
  168. }
  169. if ((r->agmt_lock = PR_NewLock()) == NULL)
  170. {
  171. if (NULL != errortext)
  172. {
  173. PR_snprintf(errortext, SLAPI_DSE_RETURNTEXT_SIZE, "failed to create replica lock");
  174. }
  175. rc = -1;
  176. goto done;
  177. }
  178. /* init the slapi_counter/atomic settings */
  179. r->protocol_timeout = slapi_counter_new();
  180. r->backoff_min = slapi_counter_new();
  181. r->backoff_max = slapi_counter_new();
  182. /* read parameters from the replica config entry */
  183. rc = _replica_init_from_config (r, e, errortext);
  184. if (rc != 0)
  185. {
  186. goto done;
  187. }
  188. /* configure ruv */
  189. rc = _replica_configure_ruv (r, PR_FALSE);
  190. if (rc != 0)
  191. {
  192. goto done;
  193. }
  194. /* If smallest csn exists in RUV for our local replica, it's ok to begin iteration */
  195. PR_ASSERT (object_get_data (r->repl_ruv));
  196. if (is_add_operation)
  197. {
  198. /*
  199. * This is called by an ldap add operation.
  200. * Update the entry to contain information generated
  201. * during replica initialization
  202. */
  203. rc = _replica_update_entry (r, e, errortext);
  204. }
  205. else
  206. {
  207. /*
  208. * Entry is already in dse.ldif - update it on the disk
  209. * (done by the update state event scheduled below)
  210. */
  211. }
  212. if (rc != 0)
  213. goto done;
  214. /* ONREPL - the state update can occur before the entry is added to the DIT.
  215. In that case the updated would fail but nothing bad would happen. The next
  216. scheduled update would save the state */
  217. repl_name = slapi_ch_strdup (r->repl_name);
  218. r->repl_eqcxt_rs = slapi_eq_repeat(replica_update_state, repl_name,
  219. current_time () + START_UPDATE_DELAY, RUV_SAVE_INTERVAL);
  220. if (r->tombstone_reap_interval > 0)
  221. {
  222. /*
  223. * Reap Tombstone should be started some time after the plugin started.
  224. * This will allow the server to fully start before consuming resources.
  225. */
  226. repl_name = slapi_ch_strdup (r->repl_name);
  227. r->repl_eqcxt_tr = slapi_eq_repeat(eq_cb_reap_tombstones, repl_name,
  228. current_time() + r->tombstone_reap_interval,
  229. 1000 * r->tombstone_reap_interval);
  230. }
  231. if (r->legacy_consumer)
  232. {
  233. legacy_consumer_init_referrals (r);
  234. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_new_from_entry: "
  235. "replica for %s was configured as legacy consumer\n",
  236. slapi_sdn_get_dn(r->repl_root));
  237. }
  238. replica_check_for_tasks(r, e);
  239. done:
  240. if (rc != 0 && r)
  241. {
  242. replica_destroy ((void**)&r);
  243. }
  244. return r;
  245. }
  246. void
  247. replica_flush(Replica *r)
  248. {
  249. PR_ASSERT(NULL != r);
  250. if (NULL != r)
  251. {
  252. replica_lock(r->repl_lock);
  253. /* Make sure we dump the CSNGen state */
  254. r->repl_csn_assigned = PR_TRUE;
  255. replica_unlock(r->repl_lock);
  256. /* This function take the Lock Inside */
  257. /* And also write the RUV */
  258. replica_update_state((time_t)0, r->repl_name);
  259. }
  260. }
  261. void
  262. replica_set_csn_assigned(Replica *r)
  263. {
  264. replica_lock(r->repl_lock);
  265. r->repl_csn_assigned = PR_TRUE;
  266. replica_unlock(r->repl_lock);
  267. }
  268. /*
  269. * Deallocate a replica. arg should point to the address of a
  270. * pointer that points to a replica structure.
  271. */
  272. void
  273. replica_destroy(void **arg)
  274. {
  275. Replica *r;
  276. void *repl_name;
  277. if (arg == NULL)
  278. return;
  279. r = *((Replica **)arg);
  280. PR_ASSERT(r);
  281. slapi_log_error (SLAPI_LOG_REPL, NULL, "replica_destroy\n");
  282. /*
  283. * The function will not be called unless the refcnt of its
  284. * wrapper object is 0. Hopefully this refcnt could sync up
  285. * this destruction and the events such as tombstone reap
  286. * and ruv updates.
  287. */
  288. if (r->repl_eqcxt_rs)
  289. {
  290. repl_name = slapi_eq_get_arg (r->repl_eqcxt_rs);
  291. slapi_ch_free (&repl_name);
  292. slapi_eq_cancel(r->repl_eqcxt_rs);
  293. r->repl_eqcxt_rs = NULL;
  294. }
  295. if (r->repl_eqcxt_tr)
  296. {
  297. repl_name = slapi_eq_get_arg (r->repl_eqcxt_tr);
  298. slapi_ch_free (&repl_name);
  299. slapi_eq_cancel(r->repl_eqcxt_tr);
  300. r->repl_eqcxt_tr = NULL;
  301. }
  302. if (r->repl_root)
  303. {
  304. slapi_sdn_free(&r->repl_root);
  305. }
  306. slapi_ch_free_string(&r->locking_purl);
  307. if (r->updatedn_list)
  308. {
  309. replica_updatedn_list_free(r->updatedn_list);
  310. r->updatedn_list = NULL;
  311. }
  312. if (r->groupdn_list)
  313. {
  314. replica_updatedn_list_free(r->groupdn_list);
  315. r->groupdn_list = NULL;
  316. }
  317. if (r->updatedn_groups) {
  318. slapi_valueset_free(r->updatedn_groups);
  319. }
  320. /* slapi_ch_free accepts NULL pointer */
  321. slapi_ch_free ((void**)&r->repl_name);
  322. slapi_ch_free ((void**)&r->legacy_purl);
  323. if (r->repl_lock)
  324. {
  325. PR_DestroyMonitor(r->repl_lock);
  326. r->repl_lock = NULL;
  327. }
  328. if (r->agmt_lock)
  329. {
  330. PR_DestroyLock(r->agmt_lock);
  331. r->agmt_lock = NULL;
  332. }
  333. if(NULL != r->repl_ruv)
  334. {
  335. object_release(r->repl_ruv);
  336. }
  337. if(NULL != r->repl_csngen)
  338. {
  339. if (r->csn_pl_reg_id)
  340. {
  341. csngen_unregister_callbacks((CSNGen *)object_get_data (r->repl_csngen), r->csn_pl_reg_id);
  342. }
  343. object_release(r->repl_csngen);
  344. }
  345. if (NULL != r->repl_referral)
  346. {
  347. slapi_valueset_free(r->repl_referral);
  348. }
  349. if (NULL != r->min_csn_pl)
  350. {
  351. csnplFree(&r->min_csn_pl);;
  352. }
  353. slapi_counter_destroy(&r->protocol_timeout);
  354. slapi_counter_destroy(&r->backoff_min);
  355. slapi_counter_destroy(&r->backoff_max);
  356. slapi_ch_free((void **)arg);
  357. }
  358. #define KEEP_ALIVE_ATTR "keepalivetimestamp"
  359. #define KEEP_ALIVE_ENTRY "repl keep alive"
  360. #define KEEP_ALIVE_DN_FORMAT "cn=%s %d,%s"
  361. static int
  362. replica_subentry_create(Slapi_DN *repl_root, ReplicaId rid)
  363. {
  364. char *entry_string = NULL;
  365. Slapi_Entry *e = NULL;
  366. Slapi_PBlock *pb = NULL;
  367. int return_value;
  368. int rc = 0;
  369. entry_string = slapi_ch_smprintf("dn: cn=%s %d,%s\nobjectclass: top\nobjectclass: ldapsubentry\nobjectclass: extensibleObject\ncn: %s %d",
  370. KEEP_ALIVE_ENTRY, rid, slapi_sdn_get_dn(repl_root), KEEP_ALIVE_ENTRY, rid);
  371. if (entry_string == NULL) {
  372. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  373. "replica_subentry_create add failed in slapi_ch_smprintf\n");
  374. rc = -1;
  375. goto done;
  376. }
  377. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "add %s\n", entry_string);
  378. e = slapi_str2entry(entry_string, 0);
  379. /* create the entry */
  380. pb = slapi_pblock_new();
  381. slapi_add_entry_internal_set_pb(pb, e, NULL, /* controls */
  382. repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0 /* flags */);
  383. slapi_add_internal_pb(pb);
  384. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &return_value);
  385. if (return_value != LDAP_SUCCESS &&
  386. return_value != LDAP_ALREADY_EXISTS &&
  387. return_value != LDAP_REFERRAL /* CONSUMER */)
  388. {
  389. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Warning: unable to "
  390. "create replication keep alive entry %s: %s\n", slapi_entry_get_dn_const(e),
  391. ldap_err2string(return_value));
  392. rc = -1;
  393. goto done;
  394. }
  395. done:
  396. slapi_pblock_destroy(pb);
  397. slapi_ch_free_string(&entry_string);
  398. return rc;
  399. }
  400. int
  401. replica_subentry_check(Slapi_DN *repl_root, ReplicaId rid)
  402. {
  403. Slapi_PBlock *pb;
  404. char *filter = NULL;
  405. Slapi_Entry **entries = NULL;
  406. int res;
  407. int rc = 0;
  408. pb = slapi_pblock_new();
  409. filter = slapi_ch_smprintf("(&(objectclass=ldapsubentry)(cn=%s %d))", KEEP_ALIVE_ENTRY, rid);
  410. slapi_search_internal_set_pb(pb, slapi_sdn_get_dn(repl_root), LDAP_SCOPE_ONELEVEL,
  411. filter, NULL, 0, NULL, NULL,
  412. repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
  413. slapi_search_internal_pb(pb);
  414. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
  415. if (res == LDAP_SUCCESS)
  416. {
  417. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  418. if (entries && (entries[0] == NULL))
  419. {
  420. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  421. "Need to create replication keep alive entry <cn=%s %d,%s>\n", KEEP_ALIVE_ENTRY, rid, slapi_sdn_get_dn(repl_root));
  422. rc = replica_subentry_create(repl_root, rid);
  423. } else {
  424. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  425. "replication keep alive entry <cn=%s %d,%s> already exists\n", KEEP_ALIVE_ENTRY, rid, slapi_sdn_get_dn(repl_root));
  426. rc = 0;
  427. }
  428. } else {
  429. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  430. "Error accessing replication keep alive entry <cn=%s %d,%s> res=%d\n",
  431. KEEP_ALIVE_ENTRY, rid, slapi_sdn_get_dn(repl_root), res);
  432. /* The status of the entry is not clear, do not attempt to create it */
  433. rc = 1;
  434. }
  435. slapi_free_search_results_internal(pb);
  436. slapi_pblock_destroy(pb);
  437. slapi_ch_free_string(&filter);
  438. return rc;
  439. }
  440. int
  441. replica_subentry_update(Slapi_DN *repl_root, ReplicaId rid)
  442. {
  443. int ldrc;
  444. int rc = LDAP_SUCCESS; /* Optimistic default */
  445. LDAPMod * mods[2];
  446. LDAPMod mod;
  447. struct berval * vals[2];
  448. char buf[20];
  449. time_t curtime;
  450. struct tm ltm;
  451. struct berval val;
  452. Slapi_PBlock *modpb = NULL;
  453. char *dn;
  454. replica_subentry_check(repl_root, rid);
  455. curtime = current_time();
  456. gmtime_r(&curtime, &ltm);
  457. strftime(buf, sizeof (buf), "%Y%m%d%H%M%SZ", &ltm);
  458. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "subentry_update called at %s\n", buf);
  459. val.bv_val = buf;
  460. val.bv_len = strlen(val.bv_val);
  461. vals [0] = &val;
  462. vals [1] = NULL;
  463. mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  464. mod.mod_type = KEEP_ALIVE_ATTR;
  465. mod.mod_bvalues = vals;
  466. mods[0] = &mod;
  467. mods[1] = NULL;
  468. modpb = slapi_pblock_new();
  469. dn = slapi_ch_smprintf(KEEP_ALIVE_DN_FORMAT, KEEP_ALIVE_ENTRY, rid, slapi_sdn_get_dn(repl_root));
  470. slapi_modify_internal_set_pb(modpb, dn, mods, NULL, NULL,
  471. repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
  472. slapi_modify_internal_pb(modpb);
  473. slapi_pblock_get(modpb, SLAPI_PLUGIN_INTOP_RESULT, &ldrc);
  474. if (ldrc != LDAP_SUCCESS)
  475. {
  476. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  477. "Failure (%d) to update replication keep alive entry \"%s: %s\"\n", ldrc, KEEP_ALIVE_ATTR, buf);
  478. rc = ldrc;
  479. } else {
  480. slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name,
  481. "Successful update of replication keep alive entry \"%s: %s\"\n", KEEP_ALIVE_ATTR, buf);
  482. }
  483. slapi_pblock_destroy(modpb);
  484. slapi_ch_free_string(&dn);
  485. return rc;
  486. }
  487. /*
  488. * Attempt to obtain exclusive access to replica (advisory only)
  489. *
  490. * Returns PR_TRUE if exclusive access was granted,
  491. * PR_FALSE otherwise
  492. * The parameter isInc tells whether or not the replica is being
  493. * locked for an incremental update session - if the replica is
  494. * successfully locked, this value is used - if the replica is already
  495. * in use, this value will be set to TRUE or FALSE, depending on what
  496. * type of update session has the replica in use currently
  497. * locking_purl is the supplier who is attempting to acquire access
  498. * current_purl is the supplier who already has access, if any
  499. */
  500. PRBool
  501. replica_get_exclusive_access(Replica *r, PRBool *isInc, PRUint64 connid, int opid,
  502. const char *locking_purl,
  503. char **current_purl)
  504. {
  505. PRBool rval = PR_TRUE;
  506. PR_ASSERT(r);
  507. replica_lock(r->repl_lock);
  508. if (r->repl_state_flags & REPLICA_IN_USE)
  509. {
  510. if (isInc)
  511. *isInc = (r->repl_state_flags & REPLICA_INCREMENTAL_IN_PROGRESS);
  512. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  513. "conn=%" NSPRIu64 " op=%d repl=\"%s\": "
  514. "Replica in use locking_purl=%s\n",
  515. connid, opid,
  516. slapi_sdn_get_dn(r->repl_root),
  517. r->locking_purl ? r->locking_purl : "unknown");
  518. rval = PR_FALSE;
  519. if (current_purl)
  520. {
  521. *current_purl = slapi_ch_strdup(r->locking_purl);
  522. }
  523. }
  524. else
  525. {
  526. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  527. "conn=%" NSPRIu64 " op=%d repl=\"%s\": Acquired replica\n",
  528. connid, opid,
  529. slapi_sdn_get_dn(r->repl_root));
  530. r->repl_state_flags |= REPLICA_IN_USE;
  531. if (isInc && *isInc)
  532. {
  533. r->repl_state_flags |= REPLICA_INCREMENTAL_IN_PROGRESS;
  534. }
  535. else
  536. {
  537. /* if connid or opid != 0, it's a total update */
  538. /* Both set to 0 means we're disabling replication */
  539. if (connid || opid)
  540. {
  541. r->repl_state_flags |= REPLICA_TOTAL_IN_PROGRESS;
  542. }
  543. }
  544. slapi_ch_free_string(&r->locking_purl);
  545. r->locking_purl = slapi_ch_strdup(locking_purl);
  546. }
  547. replica_unlock(r->repl_lock);
  548. return rval;
  549. }
  550. /*
  551. * Relinquish exclusive access to the replica
  552. */
  553. void
  554. replica_relinquish_exclusive_access(Replica *r, PRUint64 connid, int opid)
  555. {
  556. PRBool isInc;
  557. PR_ASSERT(r);
  558. replica_lock(r->repl_lock);
  559. isInc = (r->repl_state_flags & REPLICA_INCREMENTAL_IN_PROGRESS);
  560. /* check to see if the replica is in use and log a warning if not */
  561. if (!(r->repl_state_flags & REPLICA_IN_USE))
  562. {
  563. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  564. "conn=%" NSPRIu64 " op=%d repl=\"%s\": "
  565. "Replica not in use\n",
  566. connid, opid,
  567. slapi_sdn_get_dn(r->repl_root));
  568. } else {
  569. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  570. "conn=%" NSPRIu64 " op=%d repl=\"%s\": "
  571. "Released replica held by locking_purl=%s\n",
  572. connid, opid,
  573. slapi_sdn_get_dn(r->repl_root),
  574. r->locking_purl);
  575. slapi_ch_free_string(&r->locking_purl);
  576. r->repl_state_flags &= ~(REPLICA_IN_USE);
  577. if (isInc)
  578. r->repl_state_flags &= ~(REPLICA_INCREMENTAL_IN_PROGRESS);
  579. else
  580. r->repl_state_flags &= ~(REPLICA_TOTAL_IN_PROGRESS);
  581. }
  582. replica_unlock(r->repl_lock);
  583. }
  584. /*
  585. * Returns root of the replicated area
  586. */
  587. PRBool
  588. replica_get_tombstone_reap_active(const Replica *r)
  589. {
  590. PR_ASSERT(r);
  591. return(r->tombstone_reap_active);
  592. }
  593. /*
  594. * Returns root of the replicated area
  595. */
  596. const Slapi_DN *
  597. replica_get_root(const Replica *r) /* ONREPL - should we return copy instead? */
  598. {
  599. PR_ASSERT(r);
  600. /* replica root never changes so we don't have to lock */
  601. return(r->repl_root);
  602. }
  603. /*
  604. * Returns normalized dn of the root of the replicated area
  605. */
  606. const char *
  607. replica_get_name(const Replica *r) /* ONREPL - should we return copy instead? */
  608. {
  609. PR_ASSERT(r);
  610. /* replica name never changes so we don't have to lock */
  611. return(r->repl_name);
  612. }
  613. /*
  614. * Returns replicaid of this replica
  615. */
  616. ReplicaId
  617. replica_get_rid (const Replica *r)
  618. {
  619. ReplicaId rid;
  620. PR_ASSERT(r);
  621. replica_lock(r->repl_lock);
  622. rid = r->repl_rid;
  623. replica_unlock(r->repl_lock);
  624. return rid;
  625. }
  626. /*
  627. * Sets replicaid of this replica - should only be used when also changing the type
  628. */
  629. void
  630. replica_set_rid (Replica *r, ReplicaId rid)
  631. {
  632. PR_ASSERT(r);
  633. replica_lock(r->repl_lock);
  634. r->repl_rid = rid;
  635. replica_unlock(r->repl_lock);
  636. }
  637. /* Returns true if replica was initialized through ORC or import;
  638. * otherwise, false. An uninitialized replica should return
  639. * LDAP_UNWILLING_TO_PERFORM to all client requests
  640. */
  641. PRBool
  642. replica_is_initialized (const Replica *r)
  643. {
  644. PR_ASSERT(r);
  645. return (r->repl_ruv != NULL);
  646. }
  647. /*
  648. * Returns refcounted object that contains RUV. The caller should release the
  649. * object once it is no longer used. To release, call object_release
  650. */
  651. Object *
  652. replica_get_ruv (const Replica *r)
  653. {
  654. Object *ruv = NULL;
  655. PR_ASSERT(r);
  656. replica_lock(r->repl_lock);
  657. PR_ASSERT (r->repl_ruv);
  658. object_acquire (r->repl_ruv);
  659. ruv = r->repl_ruv;
  660. replica_unlock(r->repl_lock);
  661. return ruv;
  662. }
  663. /*
  664. * Sets RUV vector. This function should be called during replica
  665. * (re)initialization. During normal operation, the RUV is read from
  666. * the root of the replicated in the replica_new call
  667. */
  668. void
  669. replica_set_ruv (Replica *r, RUV *ruv)
  670. {
  671. PR_ASSERT(r && ruv);
  672. replica_lock(r->repl_lock);
  673. if(NULL != r->repl_ruv)
  674. {
  675. object_release(r->repl_ruv);
  676. }
  677. /* if the local replica is not in the RUV and it is writable - add it
  678. and reinitialize min_csn pending list */
  679. if (r->repl_type == REPLICA_TYPE_UPDATABLE)
  680. {
  681. CSN *csn = NULL;
  682. if (r->min_csn_pl)
  683. csnplFree (&r->min_csn_pl);
  684. if (ruv_contains_replica (ruv, r->repl_rid))
  685. {
  686. ruv_get_smallest_csn_for_replica(ruv, r->repl_rid, &csn);
  687. if (csn)
  688. csn_free (&csn);
  689. else
  690. r->min_csn_pl = csnplNew ();
  691. /* We need to make sure the local ruv element is the 1st. */
  692. ruv_move_local_supplier_to_first(ruv, r->repl_rid);
  693. }
  694. else
  695. {
  696. r->min_csn_pl = csnplNew ();
  697. /* To be sure that the local is in first */
  698. ruv_add_index_replica(ruv, r->repl_rid, multimaster_get_local_purl(), 1);
  699. }
  700. }
  701. r->repl_ruv = object_new((void*)ruv, (FNFree)ruv_destroy);
  702. r->repl_ruv_dirty = PR_TRUE;
  703. replica_unlock(r->repl_lock);
  704. }
  705. /*
  706. * Update one particular CSN in an RUV. This is meant to be called
  707. * whenever (a) the server has processed a client operation and
  708. * needs to update its CSN, or (b) the server is completing an
  709. * inbound replication session operation, and needs to update its
  710. * local RUV.
  711. */
  712. int
  713. replica_update_ruv(Replica *r, const CSN *updated_csn, const char *replica_purl)
  714. {
  715. char csn_str[CSN_STRSIZE];
  716. int rc = RUV_SUCCESS;
  717. PR_ASSERT(NULL != r);
  718. PR_ASSERT(NULL != updated_csn);
  719. #ifdef DEBUG
  720. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  721. "replica_update_ruv: csn %s\n",
  722. csn_as_string(updated_csn, PR_FALSE, csn_str)); /* XXXggood remove debugging */
  723. #endif
  724. if (NULL == r)
  725. {
  726. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_update_ruv: replica "
  727. "is NULL\n");
  728. rc = RUV_BAD_DATA;
  729. }
  730. else if (NULL == updated_csn)
  731. {
  732. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_update_ruv: csn "
  733. "is NULL when updating replica %s\n", slapi_sdn_get_dn(r->repl_root));
  734. rc = RUV_BAD_DATA;
  735. }
  736. else
  737. {
  738. RUV *ruv;
  739. replica_lock(r->repl_lock);
  740. if (r->repl_ruv != NULL)
  741. {
  742. ruv = object_get_data(r->repl_ruv);
  743. if (NULL != ruv)
  744. {
  745. ReplicaId rid = csn_get_replicaid(updated_csn);
  746. if (rid == r->repl_rid)
  747. {
  748. if (NULL != r->min_csn_pl)
  749. {
  750. CSN *min_csn;
  751. PRBool committed;
  752. (void)csnplCommit(r->min_csn_pl, updated_csn);
  753. min_csn = csnplGetMinCSN(r->min_csn_pl, &committed);
  754. if (NULL != min_csn)
  755. {
  756. if (committed)
  757. {
  758. ruv_set_min_csn(ruv, min_csn, replica_purl);
  759. csnplFree(&r->min_csn_pl);
  760. }
  761. csn_free(&min_csn);
  762. }
  763. }
  764. }
  765. /* Update max csn for local and remote replicas */
  766. rc = ruv_update_ruv (ruv, updated_csn, replica_purl, rid == r->repl_rid);
  767. if (RUV_COVERS_CSN == rc)
  768. {
  769. slapi_log_error(SLAPI_LOG_REPL,
  770. repl_plugin_name, "replica_update_ruv: RUV "
  771. "for replica %s already covers max_csn = %s\n",
  772. slapi_sdn_get_dn(r->repl_root),
  773. csn_as_string(updated_csn, PR_FALSE, csn_str));
  774. /* RUV is not dirty - no write needed */
  775. }
  776. else if (RUV_SUCCESS != rc)
  777. {
  778. slapi_log_error(SLAPI_LOG_FATAL,
  779. repl_plugin_name, "replica_update_ruv: unable "
  780. "to update RUV for replica %s, csn = %s\n",
  781. slapi_sdn_get_dn(r->repl_root),
  782. csn_as_string(updated_csn, PR_FALSE, csn_str));
  783. }
  784. else
  785. {
  786. /* RUV updated - mark as dirty */
  787. r->repl_ruv_dirty = PR_TRUE;
  788. }
  789. }
  790. else
  791. {
  792. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  793. "replica_update_ruv: unable to get RUV object for replica "
  794. "%s\n", slapi_sdn_get_dn(r->repl_root));
  795. rc = RUV_NOTFOUND;
  796. }
  797. }
  798. else
  799. {
  800. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_update_ruv: "
  801. "unable to initialize RUV for replica %s\n",
  802. slapi_sdn_get_dn(r->repl_root));
  803. rc = RUV_NOTFOUND;
  804. }
  805. replica_unlock(r->repl_lock);
  806. }
  807. return rc;
  808. }
  809. /*
  810. * Returns refcounted object that contains csn generator. The caller should release the
  811. * object once it is no longer used. To release, call object_release
  812. */
  813. Object *
  814. replica_get_csngen (const Replica *r)
  815. {
  816. Object *csngen;
  817. PR_ASSERT(r);
  818. replica_lock(r->repl_lock);
  819. object_acquire (r->repl_csngen);
  820. csngen = r->repl_csngen;
  821. replica_unlock(r->repl_lock);
  822. return csngen;
  823. }
  824. /*
  825. * Returns the replica type.
  826. */
  827. ReplicaType
  828. replica_get_type (const Replica *r)
  829. {
  830. PR_ASSERT(r);
  831. return r->repl_type;
  832. }
  833. PRUint64
  834. replica_get_protocol_timeout(Replica *r)
  835. {
  836. if(r){
  837. return slapi_counter_get_value(r->protocol_timeout);
  838. } else {
  839. return 0;
  840. }
  841. }
  842. void
  843. replica_set_protocol_timeout(Replica *r, PRUint64 timeout)
  844. {
  845. if(r){
  846. slapi_counter_set_value(r->protocol_timeout, timeout);
  847. }
  848. }
  849. void
  850. replica_set_groupdn_checkinterval(Replica *r, int interval)
  851. {
  852. if(r){
  853. r->updatedn_group_check_interval = interval ;
  854. }
  855. }
  856. /*
  857. * Sets the replica type.
  858. */
  859. void
  860. replica_set_type (Replica *r, ReplicaType type)
  861. {
  862. PR_ASSERT(r);
  863. replica_lock(r->repl_lock);
  864. r->repl_type = type;
  865. replica_unlock(r->repl_lock);
  866. }
  867. /*
  868. * Returns PR_TRUE if this replica is a consumer of 4.0 server
  869. * and PR_FALSE otherwise
  870. */
  871. PRBool
  872. replica_is_legacy_consumer (const Replica *r)
  873. {
  874. PR_ASSERT(r);
  875. return r->legacy_consumer;
  876. }
  877. /*
  878. * Sets the replica type.
  879. */
  880. void
  881. replica_set_legacy_consumer (Replica *r, PRBool legacy_consumer)
  882. {
  883. int legacy2mmr;
  884. Slapi_DN *repl_root_sdn = NULL;
  885. char **referrals = NULL;
  886. char *replstate = NULL;
  887. PR_ASSERT(r);
  888. replica_lock(r->repl_lock);
  889. legacy2mmr = r->legacy_consumer && !legacy_consumer;
  890. /* making the server a regular 5.0 replica */
  891. if (legacy2mmr)
  892. {
  893. slapi_ch_free ((void**)&r->legacy_purl);
  894. /* Remove copiedFrom/copyingFrom attributes from the root entry */
  895. /* set the right state in the mapping tree */
  896. if (r->repl_type == REPLICA_TYPE_READONLY)
  897. {
  898. replica_get_referrals_nolock (r, &referrals);
  899. replstate = STATE_UPDATE_REFERRAL;
  900. }
  901. else /* updateable */
  902. {
  903. replstate = STATE_BACKEND;
  904. }
  905. }
  906. r->legacy_consumer = legacy_consumer;
  907. repl_root_sdn = slapi_sdn_dup(r->repl_root);
  908. replica_unlock(r->repl_lock);
  909. if (legacy2mmr)
  910. {
  911. replica_clear_legacy_referrals(repl_root_sdn, referrals, replstate);
  912. /* Also change state of the mapping tree node and/or referrals */
  913. replica_remove_legacy_attr (repl_root_sdn, type_copiedFrom);
  914. replica_remove_legacy_attr (repl_root_sdn, type_copyingFrom);
  915. }
  916. charray_free(referrals);
  917. slapi_sdn_free(&repl_root_sdn);
  918. }
  919. /* Gets partial url of the legacy supplier - applicable for legacy consumer only */
  920. char *
  921. replica_get_legacy_purl (const Replica *r)
  922. {
  923. char *purl;
  924. replica_lock(r->repl_lock);
  925. PR_ASSERT (r->legacy_consumer);
  926. purl = slapi_ch_strdup(r->legacy_purl);
  927. replica_unlock(r->repl_lock);
  928. return purl;
  929. }
  930. void
  931. replica_set_legacy_purl (Replica *r, const char *purl)
  932. {
  933. replica_lock(r->repl_lock);
  934. PR_ASSERT (r->legacy_consumer);
  935. /* slapi_ch_free accepts NULL pointer */
  936. slapi_ch_free ((void**)&r->legacy_purl);
  937. r->legacy_purl = slapi_ch_strdup (purl);
  938. replica_unlock(r->repl_lock);
  939. }
  940. /*
  941. * Returns true if sdn is the same as updatedn and false otherwise
  942. */
  943. PRBool
  944. replica_is_updatedn (Replica *r, const Slapi_DN *sdn)
  945. {
  946. PRBool result;
  947. PR_ASSERT (r);
  948. replica_lock(r->repl_lock);
  949. if ((r->updatedn_list == NULL) && (r->groupdn_list == NULL)) {
  950. if (sdn == NULL) {
  951. result = PR_TRUE;
  952. } else {
  953. result = PR_FALSE;
  954. }
  955. } else {
  956. result = PR_FALSE;
  957. if (r->updatedn_list ) {
  958. result = replica_updatedn_list_ismember(r->updatedn_list, sdn);
  959. }
  960. if ((result == PR_FALSE) && r->groupdn_list ) {
  961. /* check and rebuild groupdns */
  962. if (r->updatedn_group_check_interval > -1) {
  963. time_t now = time(NULL);
  964. if (now - r->updatedn_group_last_check > r->updatedn_group_check_interval) {
  965. replica_updatedn_list_group_replace( r->groupdn_list, r->updatedn_groups);
  966. r->updatedn_group_last_check = now;
  967. }
  968. }
  969. result = replica_updatedn_list_ismember(r->groupdn_list, sdn);
  970. }
  971. }
  972. replica_unlock(r->repl_lock);
  973. return result;
  974. }
  975. /*
  976. * Sets updatedn list for this replica
  977. */
  978. void
  979. replica_set_updatedn (Replica *r, const Slapi_ValueSet *vs, int mod_op)
  980. {
  981. PR_ASSERT (r);
  982. replica_lock(r->repl_lock);
  983. if (!r->updatedn_list)
  984. r->updatedn_list = replica_updatedn_list_new(NULL);
  985. if (SLAPI_IS_MOD_DELETE(mod_op) || vs == NULL ||
  986. (0 == slapi_valueset_count(vs))) /* null value also causes list deletion */
  987. replica_updatedn_list_delete(r->updatedn_list, vs);
  988. else if (SLAPI_IS_MOD_REPLACE(mod_op))
  989. replica_updatedn_list_replace(r->updatedn_list, vs);
  990. else if (SLAPI_IS_MOD_ADD(mod_op))
  991. replica_updatedn_list_add(r->updatedn_list, vs);
  992. replica_unlock(r->repl_lock);
  993. }
  994. /*
  995. * Sets updatedn list for this replica
  996. */
  997. void
  998. replica_set_groupdn (Replica *r, const Slapi_ValueSet *vs, int mod_op)
  999. {
  1000. PR_ASSERT (r);
  1001. replica_lock(r->repl_lock);
  1002. if (!r->groupdn_list)
  1003. r->groupdn_list = replica_updatedn_list_new(NULL);
  1004. if (!r->updatedn_groups)
  1005. r->updatedn_groups = slapi_valueset_new();
  1006. if (SLAPI_IS_MOD_DELETE(mod_op) || vs == NULL ||
  1007. (0 == slapi_valueset_count(vs))) {
  1008. /* null value also causes list deletion */
  1009. slapi_valueset_free (r->updatedn_groups);
  1010. r->updatedn_groups = NULL;
  1011. replica_updatedn_list_delete(r->groupdn_list, vs);
  1012. } else if (SLAPI_IS_MOD_REPLACE(mod_op)) {
  1013. if (r->updatedn_groups) {
  1014. slapi_valueset_done(r->updatedn_groups);
  1015. } else {
  1016. r->updatedn_groups = slapi_valueset_new();
  1017. }
  1018. slapi_valueset_set_valueset(r->updatedn_groups, vs);
  1019. replica_updatedn_list_group_replace(r->groupdn_list, vs);
  1020. } else if (SLAPI_IS_MOD_ADD(mod_op)) {
  1021. if (!r->updatedn_groups) {
  1022. r->updatedn_groups = slapi_valueset_new();
  1023. }
  1024. slapi_valueset_join_attr_valueset(NULL, r->updatedn_groups, vs);
  1025. replica_updatedn_list_add_ext(r->groupdn_list, vs, 1);
  1026. }
  1027. replica_unlock(r->repl_lock);
  1028. }
  1029. void
  1030. replica_reset_csn_pl(Replica *r)
  1031. {
  1032. replica_lock(r->repl_lock);
  1033. if (NULL != r->min_csn_pl){
  1034. csnplFree (&r->min_csn_pl);
  1035. }
  1036. r->min_csn_pl = csnplNew();
  1037. replica_unlock(r->repl_lock);
  1038. }
  1039. /* gets current replica generation for this replica */
  1040. char *replica_get_generation (const Replica *r)
  1041. {
  1042. int rc = 0;
  1043. char *gen = NULL;
  1044. if (r && r->repl_ruv)
  1045. {
  1046. replica_lock(r->repl_lock);
  1047. if (rc == 0)
  1048. gen = ruv_get_replica_generation ((RUV*)object_get_data (r->repl_ruv));
  1049. replica_unlock(r->repl_lock);
  1050. }
  1051. return gen;
  1052. }
  1053. PRBool replica_is_flag_set (const Replica *r, PRUint32 flag)
  1054. {
  1055. if (r)
  1056. return (r->repl_flags & flag);
  1057. else
  1058. return PR_FALSE;
  1059. }
  1060. void replica_set_flag (Replica *r, PRUint32 flag, PRBool clear)
  1061. {
  1062. if (r == NULL)
  1063. return;
  1064. replica_lock(r->repl_lock);
  1065. if (clear)
  1066. {
  1067. r->repl_flags &= ~flag;
  1068. }
  1069. else
  1070. {
  1071. r->repl_flags |= flag;
  1072. }
  1073. replica_unlock(r->repl_lock);
  1074. }
  1075. void replica_replace_flags (Replica *r, PRUint32 flags)
  1076. {
  1077. if (r)
  1078. {
  1079. replica_lock(r->repl_lock);
  1080. r->repl_flags = flags;
  1081. replica_unlock(r->repl_lock);
  1082. }
  1083. }
  1084. void
  1085. replica_get_referrals(const Replica *r, char ***referrals)
  1086. {
  1087. replica_lock(r->repl_lock);
  1088. replica_get_referrals_nolock (r, referrals);
  1089. replica_unlock(r->repl_lock);
  1090. }
  1091. void
  1092. replica_set_referrals(Replica *r,const Slapi_ValueSet *vs)
  1093. {
  1094. int ii = 0;
  1095. Slapi_Value *vv = NULL;
  1096. if (r->repl_referral == NULL)
  1097. {
  1098. r->repl_referral = slapi_valueset_new();
  1099. }
  1100. else
  1101. {
  1102. slapi_valueset_done(r->repl_referral);
  1103. }
  1104. slapi_valueset_set_valueset(r->repl_referral, vs);
  1105. /* make sure the DN is included in the referral LDAP URL */
  1106. if (r->repl_referral)
  1107. {
  1108. Slapi_ValueSet *newvs = slapi_valueset_new();
  1109. const char *repl_root = slapi_sdn_get_dn(r->repl_root);
  1110. ii = slapi_valueset_first_value(r->repl_referral, &vv);
  1111. while (vv)
  1112. {
  1113. const char *ref = slapi_value_get_string(vv);
  1114. LDAPURLDesc *lud = NULL;
  1115. (void)slapi_ldap_url_parse(ref, &lud, 0, NULL);
  1116. /* see if the dn is already in the referral URL */
  1117. if (!lud || !lud->lud_dn) {
  1118. /* add the dn */
  1119. Slapi_Value *newval = NULL;
  1120. int len = strlen(ref);
  1121. char *tmpref = NULL;
  1122. int need_slash = 0;
  1123. if (ref[len-1] != '/') {
  1124. need_slash = 1;
  1125. }
  1126. tmpref = slapi_ch_smprintf("%s%s%s", ref, (need_slash ? "/" : ""),
  1127. repl_root);
  1128. newval = slapi_value_new_string(tmpref);
  1129. slapi_ch_free_string(&tmpref); /* sv_new_string makes a copy */
  1130. slapi_valueset_add_value(newvs, newval);
  1131. slapi_value_free(&newval); /* s_vs_add_value makes a copy */
  1132. }
  1133. if (lud)
  1134. ldap_free_urldesc(lud);
  1135. ii = slapi_valueset_next_value(r->repl_referral, ii, &vv);
  1136. }
  1137. if (slapi_valueset_count(newvs) > 0) {
  1138. slapi_valueset_done(r->repl_referral);
  1139. slapi_valueset_set_valueset(r->repl_referral, newvs);
  1140. }
  1141. slapi_valueset_free(newvs); /* s_vs_set_vs makes a copy */
  1142. }
  1143. }
  1144. int
  1145. replica_update_csngen_state_ext (Replica *r, const RUV *ruv, const CSN *extracsn)
  1146. {
  1147. int rc = 0;
  1148. CSNGen *gen;
  1149. CSN *csn = NULL;
  1150. PR_ASSERT (r && ruv);
  1151. rc = ruv_get_max_csn(ruv, &csn);
  1152. if (rc != RUV_SUCCESS)
  1153. {
  1154. return -1;
  1155. }
  1156. if ((csn == NULL) && (extracsn == NULL)) /* ruv contains no csn and no extra - we are done */
  1157. {
  1158. return 0;
  1159. }
  1160. if (csn_compare(extracsn, csn) > 0) /* extracsn > csn */
  1161. {
  1162. csn_free (&csn); /* free */
  1163. csn = (CSN*)extracsn; /* use this csn to do the update */
  1164. }
  1165. replica_lock(r->repl_lock);
  1166. gen = (CSNGen *)object_get_data (r->repl_csngen);
  1167. PR_ASSERT (gen);
  1168. rc = csngen_adjust_time (gen, csn);
  1169. /* rc will be either CSN_SUCCESS (0) or clock skew */
  1170. /* done: */
  1171. replica_unlock(r->repl_lock);
  1172. if (csn != extracsn) /* do not free the given csn */
  1173. {
  1174. csn_free (&csn);
  1175. }
  1176. return rc;
  1177. }
  1178. int
  1179. replica_update_csngen_state (Replica *r, const RUV *ruv)
  1180. {
  1181. return replica_update_csngen_state_ext(r, ruv, NULL);
  1182. }
  1183. /*
  1184. * dumps replica state for debugging purpose
  1185. */
  1186. void
  1187. replica_dump(Replica *r)
  1188. {
  1189. char *updatedn_list = NULL;
  1190. PR_ASSERT (r);
  1191. replica_lock(r->repl_lock);
  1192. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "Replica state:\n");
  1193. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\treplica root: %s\n",
  1194. slapi_sdn_get_ndn (r->repl_root));
  1195. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\treplica type: %s\n",
  1196. _replica_type_as_string (r));
  1197. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\treplica id: %d\n", r->repl_rid);
  1198. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\tflags: %d\n", r->repl_flags);
  1199. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\tstate flags: %lu\n", r->repl_state_flags);
  1200. if (r->updatedn_list)
  1201. updatedn_list = replica_updatedn_list_to_string(r->updatedn_list, "\n\t\t");
  1202. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\tupdate dn: %s\n",
  1203. updatedn_list? updatedn_list : "not configured");
  1204. slapi_ch_free_string(&updatedn_list);
  1205. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\truv: %s configured and is %sdirty\n",
  1206. r->repl_ruv ? "" : "not", r->repl_ruv_dirty ? "" : "not ");
  1207. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\tCSN generator: %s configured\n",
  1208. r->repl_csngen ? "" : "not");
  1209. /* JCMREPL - Dump Referrals */
  1210. replica_unlock(r->repl_lock);
  1211. }
  1212. /*
  1213. * Return the CSN of the purge point. Any CSNs smaller than the
  1214. * purge point can be safely removed from entries within this
  1215. * this replica. Returns an allocated CSN that must be freed by
  1216. * the caller, or NULL if purging is disabled.
  1217. */
  1218. CSN *
  1219. replica_get_purge_csn(const Replica *r)
  1220. {
  1221. CSN *csn;
  1222. replica_lock(r->repl_lock);
  1223. csn= _replica_get_purge_csn_nolock(r);
  1224. replica_unlock(r->repl_lock);
  1225. return csn;
  1226. }
  1227. /*
  1228. * This function logs a dummy entry for the smallest csn in the RUV.
  1229. * This is necessary because, to get the next change, we need to position
  1230. * changelog on the previous change. So this function insures that we always have one.
  1231. */
  1232. /* ONREPL we will need to change this function to log all the
  1233. * ruv elements not just the smallest when changelog iteration
  1234. * algoritm changes to iterate replica by replica
  1235. */
  1236. int
  1237. replica_log_ruv_elements (const Replica *r)
  1238. {
  1239. int rc = 0;
  1240. PR_ASSERT (r);
  1241. replica_lock(r->repl_lock);
  1242. rc = replica_log_ruv_elements_nolock (r);
  1243. replica_unlock(r->repl_lock);
  1244. return rc;
  1245. }
  1246. void
  1247. consumer5_set_mapping_tree_state_for_replica(const Replica *r, RUV *supplierRuv)
  1248. {
  1249. const Slapi_DN *repl_root_sdn= replica_get_root(r);
  1250. char **ruv_referrals= NULL;
  1251. char **replica_referrals= NULL;
  1252. RUV *ruv;
  1253. int state_backend = -1;
  1254. const char *mtn_state = NULL;
  1255. replica_lock(r->repl_lock);
  1256. if ( supplierRuv == NULL )
  1257. {
  1258. ruv = (RUV*)object_get_data (r->repl_ruv);
  1259. PR_ASSERT (ruv);
  1260. ruv_referrals= ruv_get_referrals(ruv); /* ruv_referrals has to be free'd */
  1261. }
  1262. else
  1263. {
  1264. ruv_referrals = ruv_get_referrals(supplierRuv);
  1265. }
  1266. replica_get_referrals_nolock (r, &replica_referrals); /* replica_referrals has to be free'd */
  1267. /* JCMREPL - What if there's a Total update in progress? */
  1268. if( (r->repl_type==REPLICA_TYPE_READONLY) || (r->legacy_consumer) )
  1269. {
  1270. state_backend = 0;
  1271. }
  1272. else if (r->repl_type==REPLICA_TYPE_UPDATABLE)
  1273. {
  1274. state_backend = 1;
  1275. }
  1276. /* Unlock to avoid changing MTN state under repl lock */
  1277. replica_unlock(r->repl_lock);
  1278. if(state_backend == 0 )
  1279. {
  1280. /* Read-Only - The mapping tree should be refering all update operations. */
  1281. mtn_state = STATE_UPDATE_REFERRAL;
  1282. }
  1283. else if (state_backend == 1)
  1284. {
  1285. /* Updatable - The mapping tree should be accepting all update operations. */
  1286. mtn_state = STATE_BACKEND;
  1287. }
  1288. /* JCMREPL - Check the return code. */
  1289. repl_set_mtn_state_and_referrals(repl_root_sdn, mtn_state, NULL,
  1290. ruv_referrals, replica_referrals);
  1291. charray_free(ruv_referrals);
  1292. charray_free(replica_referrals);
  1293. }
  1294. void
  1295. replica_set_enabled (Replica *r, PRBool enable)
  1296. {
  1297. char *repl_name = NULL;
  1298. PR_ASSERT (r);
  1299. replica_lock(r->repl_lock);
  1300. if (enable)
  1301. {
  1302. if (r->repl_eqcxt_rs == NULL) /* event is not already registered */
  1303. {
  1304. repl_name = slapi_ch_strdup (r->repl_name);
  1305. r->repl_eqcxt_rs = slapi_eq_repeat(replica_update_state, repl_name,
  1306. current_time() + START_UPDATE_DELAY, RUV_SAVE_INTERVAL);
  1307. }
  1308. }
  1309. else /* disable */
  1310. {
  1311. if (r->repl_eqcxt_rs) /* event is still registerd */
  1312. {
  1313. repl_name = slapi_eq_get_arg (r->repl_eqcxt_rs);
  1314. slapi_ch_free ((void**)&repl_name);
  1315. slapi_eq_cancel(r->repl_eqcxt_rs);
  1316. r->repl_eqcxt_rs = NULL;
  1317. }
  1318. }
  1319. replica_unlock(r->repl_lock);
  1320. }
  1321. /* This function is generally called when replica's data store
  1322. is reloaded. It retrieves new RUV from the datastore. If new
  1323. RUV does not exist or if it is not as up to date as the purge RUV
  1324. of the corresponding changelog file, we need to remove */
  1325. /* the function minimizes the use of replica lock where ever possible.
  1326. Locking replica lock while calling changelog functions
  1327. causes a deadlock because changelog calls replica functions that
  1328. that lock the same lock */
  1329. int
  1330. replica_reload_ruv (Replica *r)
  1331. {
  1332. int rc = 0;
  1333. Object *old_ruv_obj = NULL, *new_ruv_obj = NULL;
  1334. RUV *upper_bound_ruv = NULL;
  1335. RUV *new_ruv = NULL;
  1336. Object *r_obj;
  1337. PR_ASSERT (r);
  1338. replica_lock(r->repl_lock);
  1339. old_ruv_obj = r->repl_ruv;
  1340. r->repl_ruv = NULL;
  1341. rc = _replica_configure_ruv (r, PR_TRUE);
  1342. replica_unlock(r->repl_lock);
  1343. if (rc != 0)
  1344. {
  1345. return rc;
  1346. }
  1347. /* check if there is a changelog and whether this replica logs changes */
  1348. if (cl5GetState () == CL5_STATE_OPEN && (r->repl_flags & REPLICA_LOG_CHANGES))
  1349. {
  1350. /* Compare new ruv to the changelog's upper bound ruv. We could only keep
  1351. the existing changelog if its upper bound is the same as replica's RUV.
  1352. This is because if changelog has changes not in RUV, they will be
  1353. eventually sent to the consumer's which will cause a state mismatch
  1354. (because the supplier does not actually contain the changes in its data store.
  1355. If, on the other hand, the changelog is not as up to date as the supplier,
  1356. it is not really useful since out of sync consumer's can't be brought
  1357. up to date using this changelog and hence will need to be reinitialized */
  1358. /* replace ruv to make sure we work with the correct changelog file */
  1359. replica_lock(r->repl_lock);
  1360. new_ruv_obj = r->repl_ruv;
  1361. r->repl_ruv = old_ruv_obj;
  1362. replica_unlock(r->repl_lock);
  1363. rc = cl5GetUpperBoundRUV (r, &upper_bound_ruv);
  1364. if (rc != CL5_SUCCESS && rc != CL5_NOTFOUND)
  1365. {
  1366. return -1;
  1367. }
  1368. if (upper_bound_ruv)
  1369. {
  1370. new_ruv = object_get_data (new_ruv_obj);
  1371. PR_ASSERT (new_ruv);
  1372. /* ONREPL - there are more efficient ways to establish RUV equality.
  1373. However, because this is not in the critical path and we at most
  1374. have 2 elements in the RUV, this will not effect performance */
  1375. if (!ruv_covers_ruv (new_ruv, upper_bound_ruv) ||
  1376. !ruv_covers_ruv (upper_bound_ruv, new_ruv))
  1377. {
  1378. /* create a temporary replica object to conform to the interface */
  1379. r_obj = object_new (r, NULL);
  1380. /* We can't use existing changelog - remove existing file */
  1381. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_reload_ruv: "
  1382. "Warning: new data for replica %s does not match the data in the changelog.\n"
  1383. " Recreating the changelog file. This could affect replication with replica's "
  1384. " consumers in which case the consumers should be reinitialized.\n",
  1385. slapi_sdn_get_dn(r->repl_root));
  1386. rc = cl5DeleteDBSync (r_obj);
  1387. /* reinstate new ruv */
  1388. replica_lock(r->repl_lock);
  1389. r->repl_ruv = new_ruv_obj;
  1390. object_release (r_obj);
  1391. if (rc == CL5_SUCCESS)
  1392. {
  1393. /* log changes to mark starting point for replication */
  1394. rc = replica_log_ruv_elements_nolock (r);
  1395. }
  1396. replica_unlock(r->repl_lock);
  1397. }
  1398. else
  1399. {
  1400. /* we just need to reinstate new ruv */
  1401. replica_lock(r->repl_lock);
  1402. r->repl_ruv = new_ruv_obj;
  1403. replica_unlock(r->repl_lock);
  1404. }
  1405. }
  1406. else /* upper bound vector is not there - we have no changes logged */
  1407. {
  1408. /* reinstate new ruv */
  1409. replica_lock(r->repl_lock);
  1410. r->repl_ruv = new_ruv_obj;
  1411. /* just log elements of the current RUV. This is to have
  1412. a starting point for iteration through the changes */
  1413. rc = replica_log_ruv_elements_nolock (r);
  1414. replica_unlock(r->repl_lock);
  1415. }
  1416. }
  1417. if (rc == 0)
  1418. {
  1419. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  1420. /* reset mapping tree referrals based on new local RUV */
  1421. }
  1422. if (old_ruv_obj)
  1423. object_release (old_ruv_obj);
  1424. if (upper_bound_ruv)
  1425. ruv_destroy (&upper_bound_ruv);
  1426. return rc;
  1427. }
  1428. /* this function is called during server startup for each replica
  1429. to check whether the replica's data was reloaded offline and
  1430. whether replica's changelog needs to be reinitialized */
  1431. /* the function does not use replica lock but all functions it calls are
  1432. thread safe. Locking replica lock while calling changelog functions
  1433. causes a deadlock because changelog calls replica functions that
  1434. that lock the same lock */
  1435. int replica_check_for_data_reload (Replica *r, void *arg)
  1436. {
  1437. int rc = 0;
  1438. RUV *upper_bound_ruv = NULL;
  1439. RUV *r_ruv = NULL;
  1440. Object *r_obj, *ruv_obj;
  1441. PR_ASSERT (r);
  1442. /* check that we have a changelog and if this replica logs changes */
  1443. if (cl5GetState () == CL5_STATE_OPEN && (r->repl_flags & REPLICA_LOG_CHANGES))
  1444. {
  1445. /* Compare new ruv to the purge ruv. If the new contains csns which
  1446. are smaller than those in purge ruv, we need to remove old and
  1447. create new changelog file for this replica. This is because we
  1448. will not have sufficient changes to incrementally update a consumer
  1449. to the current state of the supplier. */
  1450. rc = cl5GetUpperBoundRUV (r, &upper_bound_ruv);
  1451. if (rc != CL5_SUCCESS && rc != CL5_NOTFOUND)
  1452. {
  1453. return -1;
  1454. }
  1455. if (upper_bound_ruv)
  1456. {
  1457. ruv_obj = replica_get_ruv (r);
  1458. r_ruv = object_get_data (ruv_obj);
  1459. PR_ASSERT (r_ruv);
  1460. /* Compare new ruv to the changelog's upper bound ruv. We could only keep
  1461. the existing changelog if its upper bound is the same as replica's RUV.
  1462. This is because if changelog has changes not in RUV, they will be
  1463. eventually sent to the consumer's which will cause a state mismatch
  1464. (because the supplier does not actually contain the changes in its data store.
  1465. If, on the other hand, the changelog is not as up to date as the supplier,
  1466. it is not really useful since out of sync consumer's can't be brought
  1467. up to date using this changelog and hence will need to be reinitialized */
  1468. /*
  1469. * Actually we can ignore the scenario that the changelog's upper
  1470. * bound ruv covers data store's ruv for two reasons: (1) a change
  1471. * is always written to the changelog after it is committed to the
  1472. * data store; (2) a change will be ignored if the server has seen
  1473. * it before - this happens frequently at the beginning of replication
  1474. * sessions.
  1475. */
  1476. if (slapi_disordely_shutdown(PR_FALSE)) {
  1477. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_check_for_data_reload: "
  1478. "Warning: disordely shutdown for replica %s. Check if DB RUV needs to be updated\n",
  1479. slapi_sdn_get_dn(r->repl_root));
  1480. if (ruv_covers_ruv(upper_bound_ruv, r_ruv) && !ruv_covers_ruv(r_ruv, upper_bound_ruv)) {
  1481. /*
  1482. * The Changelog RUV is ahead of the RUV in the DB.
  1483. * RUV DB was likely not flushed on disk.
  1484. */
  1485. ruv_force_csn_update_from_ruv(upper_bound_ruv, r_ruv,
  1486. "Force update of database RUV (from CL RUV) -> ", SLAPI_LOG_FATAL);
  1487. replica_set_ruv_dirty(r);
  1488. }
  1489. } else {
  1490. rc = ruv_compare_ruv(upper_bound_ruv, "changelog max RUV", r_ruv, "database RUV", 0, SLAPI_LOG_FATAL);
  1491. if (RUV_COMP_IS_FATAL(rc)) {
  1492. /* create a temporary replica object to conform to the interface */
  1493. r_obj = object_new(r, NULL);
  1494. /* We can't use existing changelog - remove existing file */
  1495. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_check_for_data_reload: "
  1496. "Warning: data for replica %s does not match the data in the changelog. "
  1497. "Recreating the changelog file. "
  1498. "This could affect replication with replica's consumers in which case the "
  1499. "consumers should be reinitialized.\n",
  1500. slapi_sdn_get_dn(r->repl_root));
  1501. rc = cl5DeleteDBSync(r_obj);
  1502. object_release(r_obj);
  1503. if (rc == CL5_SUCCESS) {
  1504. /* log changes to mark starting point for replication */
  1505. rc = replica_log_ruv_elements(r);
  1506. }
  1507. } else if (rc) {
  1508. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_check_for_data_reload: "
  1509. "Warning: for replica %s there were some differences between the changelog max RUV and the "
  1510. "database RUV. If there are obsolete elements in the database RUV, you "
  1511. "should remove them using the CLEANALLRUV task. If they are not obsolete, "
  1512. "you should check their status to see why there are no changes from those "
  1513. "servers in the changelog.\n",
  1514. slapi_sdn_get_dn(r->repl_root));
  1515. rc = 0;
  1516. }
  1517. } // slapi_disordely_shutdown
  1518. object_release (ruv_obj);
  1519. }
  1520. else /* we have no changes currently logged for this replica */
  1521. {
  1522. /* log changes to mark starting point for replication */
  1523. rc = replica_log_ruv_elements (r);
  1524. }
  1525. }
  1526. if (rc == 0)
  1527. {
  1528. /* reset mapping tree referrals based on new local RUV */
  1529. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  1530. }
  1531. if (upper_bound_ruv)
  1532. ruv_destroy (&upper_bound_ruv);
  1533. return rc;
  1534. }
  1535. /* Helper functions */
  1536. /* reads replica configuration entry. The entry is the child of the
  1537. mapping tree node for the replica's backend */
  1538. static Slapi_Entry*
  1539. _replica_get_config_entry (const Slapi_DN *root, const char **attrs)
  1540. {
  1541. int rc = 0;
  1542. char *dn = NULL;
  1543. Slapi_Entry **entries;
  1544. Slapi_Entry *e = NULL;
  1545. Slapi_PBlock *pb = NULL;
  1546. dn = _replica_get_config_dn (root);
  1547. if (NULL == dn) {
  1548. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  1549. "_replica_get_config_entry: failed to get the config dn for %s\n",
  1550. slapi_sdn_get_dn (root));
  1551. return NULL;
  1552. }
  1553. pb = slapi_pblock_new ();
  1554. slapi_search_internal_set_pb (pb, dn, LDAP_SCOPE_BASE, "objectclass=*", (char **)attrs, 0, NULL,
  1555. NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
  1556. slapi_search_internal_pb (pb);
  1557. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1558. if (rc == 0)
  1559. {
  1560. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  1561. e = slapi_entry_dup (entries [0]);
  1562. }
  1563. slapi_free_search_results_internal(pb);
  1564. slapi_pblock_destroy (pb);
  1565. slapi_ch_free_string(&dn);
  1566. return e;
  1567. }
  1568. /* It does an internal search to read the in memory RUV
  1569. * of the provided suffix
  1570. */
  1571. Slapi_Entry *
  1572. get_in_memory_ruv(Slapi_DN *suffix_sdn)
  1573. {
  1574. const char *attrs[4];
  1575. /* these two attributes needs to be asked when reading the RUV */
  1576. attrs[0] = type_ruvElement;
  1577. attrs[1] = type_ruvElementUpdatetime;
  1578. attrs[2] = type_agmtMaxCSN;
  1579. attrs[3] = NULL;
  1580. return(_replica_get_config_entry(suffix_sdn, attrs));
  1581. }
  1582. char *
  1583. replica_get_dn(Replica *r)
  1584. {
  1585. return _replica_get_config_dn (r->repl_root);
  1586. }
  1587. static int
  1588. _replica_check_validity (const Replica *r)
  1589. {
  1590. PR_ASSERT (r);
  1591. if (r->repl_root == NULL || r->repl_type == 0 || r->repl_rid == 0 ||
  1592. r->repl_csngen == NULL || r->repl_name == NULL)
  1593. {
  1594. return -1;
  1595. }
  1596. else
  1597. {
  1598. return 0;
  1599. }
  1600. }
  1601. /* replica configuration entry has the following format:
  1602. dn: cn=replica,<mapping tree node dn>
  1603. objectclass: top
  1604. objectclass: nsds5Replica
  1605. objectclass: extensibleObject
  1606. nsds5ReplicaRoot: <root of the replica>
  1607. nsds5ReplicaId: <replica id>
  1608. nsds5ReplicaType: <type of the replica: primary, read-write or read-only>
  1609. nsState: <state of the csn generator> missing the first time replica is started
  1610. nsds5ReplicaBindDN: <supplier update dn> consumers only
  1611. nsds5ReplicaBindDNGroup: group, containing replicaBindDNs
  1612. nsds5ReplicaBindDNGroupCheckInterval: defines how frequently to check for update of bindGroup
  1613. nsds5ReplicaReferral: <referral URL to updatable replica> consumers only
  1614. nsds5ReplicaPurgeDelay: <time, in seconds, to keep purgeable CSNs, 0 == keep forever>
  1615. nsds5ReplicaTombstonePurgeInterval: <time, in seconds, between tombstone purge runs, 0 == don't reap>
  1616. nsds5ReplicaLegacyConsumer: <TRUE | FALSE>
  1617. richm: changed slapi entry from const to editable - if the replica id is supplied for a read
  1618. only replica, we ignore it and replace the value with the READ_ONLY_REPLICA_ID
  1619. */
  1620. static int
  1621. _replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext)
  1622. {
  1623. Slapi_Attr *a = NULL;
  1624. Slapi_Attr *attr;
  1625. CSNGen *gen;
  1626. char *precise_purging = NULL;
  1627. char buf [SLAPI_DSE_RETURNTEXT_SIZE];
  1628. char *errormsg = errortext? errortext : buf;
  1629. char *val;
  1630. int backoff_min;
  1631. int backoff_max;
  1632. int ptimeout = 0;
  1633. int rc;
  1634. PR_ASSERT (r && e);
  1635. /* get replica root */
  1636. val = slapi_entry_attr_get_charptr (e, attr_replicaRoot);
  1637. if (val == NULL){
  1638. PR_snprintf (errormsg, SLAPI_DSE_RETURNTEXT_SIZE, "failed to retrieve %s attribute from (%s)\n",
  1639. attr_replicaRoot,
  1640. (char*)slapi_entry_get_dn ((Slapi_Entry*)e));
  1641. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_replica_init_from_config: %s\n",
  1642. errormsg);
  1643. return -1;
  1644. }
  1645. r->repl_root = slapi_sdn_new_dn_passin (val);
  1646. /* get replica type */
  1647. val = slapi_entry_attr_get_charptr (e, attr_replicaType);
  1648. if (val){
  1649. r->repl_type = atoi(val);
  1650. slapi_ch_free ((void**)&val);
  1651. } else {
  1652. r->repl_type = REPLICA_TYPE_READONLY;
  1653. }
  1654. /* get legacy consumer flag */
  1655. val = slapi_entry_attr_get_charptr (e, type_replicaLegacyConsumer);
  1656. if (val){
  1657. if (strcasecmp (val, "on") == 0 || strcasecmp (val, "yes") == 0 ||
  1658. strcasecmp (val, "true") == 0 || strcasecmp (val, "1") == 0)
  1659. {
  1660. r->legacy_consumer = PR_TRUE;
  1661. } else {
  1662. r->legacy_consumer = PR_FALSE;
  1663. }
  1664. slapi_ch_free ((void**)&val);
  1665. } else {
  1666. r->legacy_consumer = PR_FALSE;
  1667. }
  1668. /* grab and validate the backoff retry settings */
  1669. if(slapi_entry_attr_exists(e, type_replicaBackoffMin)){
  1670. backoff_min = slapi_entry_attr_get_int(e, type_replicaBackoffMin);
  1671. if(backoff_min <= 0){
  1672. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Invalid value for %s: %d Using default value (%d)\n",
  1673. type_replicaBackoffMin, backoff_min, PROTOCOL_BACKOFF_MINIMUM );
  1674. backoff_min = PROTOCOL_BACKOFF_MINIMUM;
  1675. }
  1676. } else {
  1677. backoff_min = PROTOCOL_BACKOFF_MINIMUM;
  1678. }
  1679. if(slapi_entry_attr_exists(e, type_replicaBackoffMax)){
  1680. backoff_max = slapi_entry_attr_get_int(e, type_replicaBackoffMax);
  1681. if(backoff_max <= 0){
  1682. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Invalid value for %s: %d Using default value (%d)\n",
  1683. type_replicaBackoffMax, backoff_max, PROTOCOL_BACKOFF_MAXIMUM );
  1684. backoff_max = PROTOCOL_BACKOFF_MAXIMUM;
  1685. }
  1686. } else {
  1687. backoff_max = PROTOCOL_BACKOFF_MAXIMUM;
  1688. }
  1689. if(backoff_min > backoff_max){
  1690. /* Ok these values are invalid, reset back the defaults */
  1691. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Backoff minimum (%d) can not be greater than "
  1692. "the backoff maximum (%d). Using default values: min (%d) max (%d)\n", backoff_min, backoff_max,
  1693. PROTOCOL_BACKOFF_MINIMUM, PROTOCOL_BACKOFF_MAXIMUM);
  1694. slapi_counter_set_value(r->backoff_min, PROTOCOL_BACKOFF_MINIMUM);
  1695. slapi_counter_set_value(r->backoff_max, PROTOCOL_BACKOFF_MAXIMUM);
  1696. } else {
  1697. slapi_counter_set_value(r->backoff_min, backoff_min);
  1698. slapi_counter_set_value(r->backoff_max, backoff_max);
  1699. }
  1700. /* get the protocol timeout */
  1701. ptimeout = slapi_entry_attr_get_int(e, type_replicaProtocolTimeout);
  1702. if(ptimeout <= 0){
  1703. slapi_counter_set_value(r->protocol_timeout, DEFAULT_PROTOCOL_TIMEOUT);
  1704. } else {
  1705. slapi_counter_set_value(r->protocol_timeout, ptimeout);
  1706. }
  1707. /* check for precise tombstone purging */
  1708. precise_purging = slapi_entry_attr_get_charptr(e, type_replicaPrecisePurge);
  1709. if(precise_purging){
  1710. if (strcasecmp(precise_purging, "on") == 0){
  1711. slapi_counter_set_value(r->precise_purging, 1);
  1712. } else if (strcasecmp(precise_purging, "off") == 0){
  1713. slapi_counter_set_value(r->precise_purging, 0);
  1714. } else{
  1715. /* Invalid value */
  1716. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  1717. "Invalid value for %s: %s Using default value (off)\n",
  1718. type_replicaPrecisePurge, precise_purging);
  1719. slapi_counter_set_value(r->precise_purging, 0);
  1720. }
  1721. slapi_ch_free_string(&precise_purging);
  1722. } else {
  1723. slapi_counter_set_value(r->precise_purging, 0);
  1724. }
  1725. /* get replica flags */
  1726. r->repl_flags = slapi_entry_attr_get_ulong(e, attr_flags);
  1727. /*
  1728. * Get replicaid
  1729. * The replica id is ignored for read only replicas and is set to the
  1730. * special value READ_ONLY_REPLICA_ID
  1731. */
  1732. if (r->repl_type == REPLICA_TYPE_READONLY){
  1733. r->repl_rid = READ_ONLY_REPLICA_ID;
  1734. slapi_entry_attr_set_uint(e, attr_replicaId, (unsigned int)READ_ONLY_REPLICA_ID);
  1735. }
  1736. /* a replica id is required for updatable and primary replicas */
  1737. else if (r->repl_type == REPLICA_TYPE_UPDATABLE ||
  1738. r->repl_type == REPLICA_TYPE_PRIMARY)
  1739. {
  1740. if ((val = slapi_entry_attr_get_charptr (e, attr_replicaId))){
  1741. int temprid = atoi (val);
  1742. slapi_ch_free ((void**)&val);
  1743. if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID){
  1744. PR_snprintf (errormsg, SLAPI_DSE_RETURNTEXT_SIZE,
  1745. "attribute %s must have a value greater than 0 "
  1746. "and less than %d: entry %s",
  1747. attr_replicaId, READ_ONLY_REPLICA_ID,
  1748. (char*)slapi_entry_get_dn ((Slapi_Entry*)e));
  1749. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  1750. "_replica_init_from_config: %s\n", errormsg);
  1751. return -1;
  1752. } else {
  1753. r->repl_rid = (ReplicaId)temprid;
  1754. }
  1755. } else {
  1756. PR_snprintf (errormsg, SLAPI_DSE_RETURNTEXT_SIZE,
  1757. "failed to retrieve required %s attribute from %s",
  1758. attr_replicaId,(char*)slapi_entry_get_dn ((Slapi_Entry*)e));
  1759. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  1760. "_replica_init_from_config: %s\n", errormsg);
  1761. return -1;
  1762. }
  1763. }
  1764. attr = NULL;
  1765. rc = slapi_entry_attr_find(e, attr_state, &attr);
  1766. gen = csngen_new (r->repl_rid, attr);
  1767. if (gen == NULL){
  1768. PR_snprintf (errormsg, SLAPI_DSE_RETURNTEXT_SIZE,
  1769. "failed to create csn generator for replica (%s)",
  1770. (char*)slapi_entry_get_dn ((Slapi_Entry*)e));
  1771. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  1772. "_replica_init_from_config: %s\n", errormsg);
  1773. return -1;
  1774. }
  1775. r->repl_csngen = object_new((void*)gen, (FNFree)csngen_free);
  1776. /* Hook generator so we can maintain min/max CSN info */
  1777. r->csn_pl_reg_id = csngen_register_callbacks(gen, assign_csn_callback, r, abort_csn_callback, r);
  1778. /* get replication bind dn */
  1779. r->updatedn_list = replica_updatedn_list_new(e);
  1780. /* get replication bind dn groups */
  1781. r->updatedn_groups = replica_updatedn_group_new(e);
  1782. r->groupdn_list = replica_groupdn_list_new(r->updatedn_groups);
  1783. r->updatedn_group_last_check = time(NULL);
  1784. /* get groupdn check interval */
  1785. val = slapi_entry_attr_get_charptr (e, attr_replicaBindDnGroupCheckInterval);
  1786. if (val) {
  1787. r->updatedn_group_check_interval = atoi(val);
  1788. slapi_ch_free ((void**)&val);
  1789. } else {
  1790. r->updatedn_group_check_interval = -1;
  1791. }
  1792. /* get replica name */
  1793. val = slapi_entry_attr_get_charptr (e, attr_replicaName);
  1794. if (val) {
  1795. r->repl_name = val;
  1796. } else {
  1797. rc = slapi_uniqueIDGenerateString (&r->repl_name);
  1798. if (rc != UID_SUCCESS){
  1799. PR_snprintf (errormsg, SLAPI_DSE_RETURNTEXT_SIZE,
  1800. "failed to assign replica name for replica (%s); uuid generator error - %d ",
  1801. (char*)slapi_entry_get_dn ((Slapi_Entry*)e), rc);
  1802. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_replica_init_from_config: %s\n",
  1803. errormsg);
  1804. return -1;
  1805. } else
  1806. r->new_name = PR_TRUE;
  1807. }
  1808. /* get the list of referrals */
  1809. slapi_entry_attr_find( e, attr_replicaReferral, &attr );
  1810. if(attr!=NULL){
  1811. slapi_attr_get_valueset(attr, &r->repl_referral);
  1812. }
  1813. /*
  1814. * Set the purge offset (default 7 days). This is the extra
  1815. * time we allow purgeable CSNs to stick around, in case a
  1816. * replica regresses. Could also be useful when LCUP happens,
  1817. * since we don't know about LCUP replicas, and they can just
  1818. * turn up whenever they want to.
  1819. */
  1820. if (slapi_entry_attr_find(e, type_replicaPurgeDelay, &a) == -1){
  1821. /* No purge delay provided, so use default */
  1822. r->repl_purge_delay = 60 * 60 * 24 * 7; /* One week, in seconds */
  1823. } else {
  1824. r->repl_purge_delay = slapi_entry_attr_get_uint(e, type_replicaPurgeDelay);
  1825. }
  1826. if (slapi_entry_attr_find(e, type_replicaTombstonePurgeInterval, &a) == -1){
  1827. /* No reap interval provided, so use default */
  1828. r->tombstone_reap_interval = 3600 * 24; /* One day */
  1829. } else {
  1830. r->tombstone_reap_interval = slapi_entry_attr_get_int(e, type_replicaTombstonePurgeInterval);
  1831. }
  1832. r->tombstone_reap_stop = r->tombstone_reap_active = PR_FALSE;
  1833. return (_replica_check_validity (r));
  1834. }
  1835. void
  1836. replica_check_for_tasks(Replica *r, Slapi_Entry *e)
  1837. {
  1838. char **clean_vals;
  1839. if(e == NULL || ldif_dump_is_running() == PR_TRUE){
  1840. /* If db2ldif is being run, do not check if there are incomplete tasks */
  1841. return;
  1842. }
  1843. /*
  1844. * check if we are in the middle of a CLEANALLRUV task,
  1845. * if so set the cleaned rid, and fire off the thread
  1846. */
  1847. if ((clean_vals = slapi_entry_attr_get_charray(e, type_replicaCleanRUV)) != NULL)
  1848. {
  1849. PRThread *thread = NULL;
  1850. struct berval *payload = NULL;
  1851. CSN *maxcsn = NULL;
  1852. ReplicaId rid;
  1853. char csnstr[CSN_STRSIZE];
  1854. char *token = NULL;
  1855. char *forcing;
  1856. char *csnpart;
  1857. char *ridstr;
  1858. char *iter = NULL;
  1859. int i;
  1860. for(i = 0; i < CLEANRIDSIZ && clean_vals[i]; i++){
  1861. cleanruv_data *data = NULL;
  1862. /*
  1863. * Set the cleanruv data, and add the cleaned rid
  1864. */
  1865. token = ldap_utf8strtok_r(clean_vals[i], ":", &iter);
  1866. if(token){
  1867. rid = atoi(token);
  1868. if(rid <= 0 || rid >= READ_ONLY_REPLICA_ID){
  1869. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: invalid replica id(%d) "
  1870. "aborting task.\n", rid);
  1871. goto done;
  1872. }
  1873. } else {
  1874. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: unable to parse cleanallruv "
  1875. "data (%s), aborting task.\n",clean_vals[i]);
  1876. goto done;
  1877. }
  1878. csnpart = ldap_utf8strtok_r(iter, ":", &iter);
  1879. maxcsn = csn_new();
  1880. csn_init_by_string(maxcsn, csnpart);
  1881. csn_as_string(maxcsn, PR_FALSE, csnstr);
  1882. forcing = ldap_utf8strtok_r(iter, ":", &iter);
  1883. if(forcing == NULL){
  1884. forcing = "no";
  1885. }
  1886. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: cleanAllRUV task found, "
  1887. "resuming the cleaning of rid(%d)...\n", rid);
  1888. /*
  1889. * Create payload
  1890. */
  1891. ridstr = slapi_ch_smprintf("%d:%s:%s:%s", rid, slapi_sdn_get_dn(replica_get_root(r)), csnstr, forcing);
  1892. payload = create_cleanruv_payload(ridstr);
  1893. slapi_ch_free_string(&ridstr);
  1894. if(payload == NULL){
  1895. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: Startup: Failed to "
  1896. "create extended op payload, aborting task");
  1897. csn_free(&maxcsn);
  1898. goto done;
  1899. }
  1900. /*
  1901. * Setup the data struct, and fire off the thread.
  1902. */
  1903. data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
  1904. if (data == NULL) {
  1905. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV: failed to allocate cleanruv_data.\n");
  1906. csn_free(&maxcsn);
  1907. } else {
  1908. /* setup our data */
  1909. data->repl_obj = NULL;
  1910. data->replica = NULL;
  1911. data->rid = rid;
  1912. data->task = NULL;
  1913. data->maxcsn = maxcsn;
  1914. data->payload = payload;
  1915. data->sdn = slapi_sdn_dup(r->repl_root);
  1916. data->force = slapi_ch_strdup(forcing);
  1917. data->repl_root = NULL;
  1918. thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread_ext,
  1919. (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  1920. PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
  1921. if (thread == NULL) {
  1922. /* log an error and free everything */
  1923. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV: unable to create cleanAllRUV "
  1924. "thread for rid(%d)\n", (int)data->rid);
  1925. csn_free(&maxcsn);
  1926. slapi_sdn_free(&data->sdn);
  1927. ber_bvfree(data->payload);
  1928. slapi_ch_free_string(&data->force);
  1929. slapi_ch_free((void **)&data);
  1930. }
  1931. }
  1932. }
  1933. done:
  1934. slapi_ch_array_free(clean_vals);
  1935. }
  1936. if ((clean_vals = slapi_entry_attr_get_charray(e, type_replicaAbortCleanRUV)) != NULL)
  1937. {
  1938. PRThread *thread = NULL;
  1939. struct berval *payload;
  1940. ReplicaId rid;
  1941. char *certify = NULL;
  1942. char *ridstr = NULL;
  1943. char *token = NULL;
  1944. char *repl_root;
  1945. char *iter = NULL;
  1946. int i;
  1947. for(i = 0; clean_vals[i]; i++){
  1948. cleanruv_data *data = NULL;
  1949. token = ldap_utf8strtok_r(clean_vals[i], ":", &iter);
  1950. if(token){
  1951. rid = atoi(token);
  1952. if(rid <= 0 || rid >= READ_ONLY_REPLICA_ID){
  1953. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: invalid replica id(%d) "
  1954. "aborting abort task.\n", rid);
  1955. goto done2;
  1956. }
  1957. } else {
  1958. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: unable to parse cleanallruv "
  1959. "data (%s), aborting abort task.\n",clean_vals[i]);
  1960. goto done2;
  1961. }
  1962. repl_root = ldap_utf8strtok_r(iter, ":", &iter);
  1963. certify = ldap_utf8strtok_r(iter, ":", &iter);
  1964. if(!is_cleaned_rid(rid)){
  1965. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: replica id(%d) is not "
  1966. "being cleaned, nothing to abort. Aborting abort task.\n", rid);
  1967. delete_aborted_rid(r, rid, repl_root, 0);
  1968. goto done2;
  1969. }
  1970. add_aborted_rid(rid, r, repl_root);
  1971. stop_ruv_cleaning();
  1972. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: abort task found, "
  1973. "resuming abort of rid(%d).\n", rid);
  1974. /*
  1975. * Setup the data struct, and fire off the abort thread.
  1976. */
  1977. data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
  1978. if (data == NULL) {
  1979. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to allocate cleanruv_data.\n");
  1980. } else {
  1981. ridstr = slapi_ch_smprintf("%d:%s:%s", rid, repl_root, certify);
  1982. payload = create_cleanruv_payload(ridstr);
  1983. slapi_ch_free_string(&ridstr);
  1984. if(payload == NULL){
  1985. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to create extended "
  1986. "op payload\n");
  1987. slapi_ch_free((void **)&data);
  1988. } else {
  1989. /* setup the data */
  1990. data->repl_obj = NULL;
  1991. data->replica = NULL;
  1992. data->rid = rid;
  1993. data->task = NULL;
  1994. data->payload = payload;
  1995. data->repl_root = slapi_ch_strdup(repl_root);
  1996. data->sdn = slapi_sdn_dup(r->repl_root);
  1997. data->certify = slapi_ch_strdup(certify);
  1998. thread = PR_CreateThread(PR_USER_THREAD, replica_abort_task_thread,
  1999. (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  2000. PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
  2001. if (thread == NULL) {
  2002. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: unable to create abort cleanAllRUV "
  2003. "thread for rid(%d)\n", (int)data->rid);
  2004. slapi_sdn_free(&data->sdn);
  2005. ber_bvfree(data->payload);
  2006. slapi_ch_free_string(&data->repl_root);
  2007. slapi_ch_free_string(&data->certify);
  2008. slapi_ch_free((void **)&data);
  2009. }
  2010. }
  2011. }
  2012. }
  2013. done2:
  2014. slapi_ch_array_free(clean_vals);
  2015. }
  2016. }
  2017. /* This function updates the entry to contain information generated
  2018. during replica initialization.
  2019. Returns 0 if successful and -1 otherwise */
  2020. static int
  2021. _replica_update_entry (Replica *r, Slapi_Entry *e, char *errortext)
  2022. {
  2023. int rc;
  2024. Slapi_Mod smod;
  2025. Slapi_Value *val;
  2026. PR_ASSERT (r);
  2027. /* add attribute that stores state of csn generator */
  2028. rc = csngen_get_state ((CSNGen*)object_get_data (r->repl_csngen), &smod);
  2029. if (rc != CSN_SUCCESS)
  2030. {
  2031. PR_snprintf(errortext, SLAPI_DSE_RETURNTEXT_SIZE, "failed to get csn generator's state; csn error - %d", rc);
  2032. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2033. "_replica_update_entry: %s\n", errortext);
  2034. return -1;
  2035. }
  2036. val = slapi_value_new_berval(slapi_mod_get_first_value(&smod));
  2037. rc = slapi_entry_add_value (e, slapi_mod_get_type (&smod), val);
  2038. slapi_value_free(&val);
  2039. slapi_mod_done (&smod);
  2040. if (rc != 0)
  2041. {
  2042. PR_snprintf(errortext, SLAPI_DSE_RETURNTEXT_SIZE, "failed to update replica entry");
  2043. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2044. "_replica_update_entry: %s\n", errortext);
  2045. return -1;
  2046. }
  2047. /* add attribute that stores replica name */
  2048. rc = slapi_entry_add_string (e, attr_replicaName, r->repl_name);
  2049. if (rc != 0)
  2050. {
  2051. PR_snprintf(errortext, SLAPI_DSE_RETURNTEXT_SIZE, "failed to update replica entry");
  2052. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2053. "_replica_update_entry: %s\n", errortext);
  2054. return -1;
  2055. }
  2056. else
  2057. r->new_name = PR_FALSE;
  2058. return 0;
  2059. }
  2060. /* DN format: cn=replica,cn=\"<root>\",cn=mapping tree,cn=config */
  2061. static char*
  2062. _replica_get_config_dn (const Slapi_DN *root)
  2063. {
  2064. char *dn;
  2065. /* "cn=mapping tree,cn=config" */
  2066. const char *mp_base = slapi_get_mapping_tree_config_root ();
  2067. PR_ASSERT (root);
  2068. /* This function converts the old style DN to the new style. */
  2069. dn = slapi_ch_smprintf("%s,cn=\"%s\",%s",
  2070. REPLICA_RDN, slapi_sdn_get_dn (root), mp_base);
  2071. return dn;
  2072. }
  2073. /* This function retrieves RUV from the root of the replicated tree.
  2074. * The attribute can be missing if
  2075. * (1) this replica is the first supplier and replica generation has not been assigned
  2076. * or
  2077. * (2) this is a consumer that has not been yet initialized
  2078. * In either case, replica_set_ruv should be used to further initialize the replica.
  2079. * Returns 0 on success, -1 on failure. If 0 is returned, the RUV is present in the replica.
  2080. */
  2081. static int
  2082. _replica_configure_ruv (Replica *r, PRBool isLocked)
  2083. {
  2084. Slapi_PBlock *pb = NULL;
  2085. char *attrs[2];
  2086. int rc;
  2087. int return_value = -1;
  2088. Slapi_Entry **entries = NULL;
  2089. Slapi_Attr *attr;
  2090. RUV *ruv = NULL;
  2091. CSN *csn = NULL;
  2092. ReplicaId rid = 0;
  2093. /* read ruv state from the ruv tombstone entry */
  2094. pb = slapi_pblock_new();
  2095. if (!pb) {
  2096. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2097. "_replica_configure_ruv: Out of memory\n");
  2098. goto done;
  2099. }
  2100. attrs[0] = (char*)type_ruvElement;
  2101. attrs[1] = NULL;
  2102. slapi_search_internal_set_pb(
  2103. pb,
  2104. slapi_sdn_get_dn(r->repl_root),
  2105. LDAP_SCOPE_BASE,
  2106. "objectclass=*",
  2107. attrs,
  2108. 0, /* attrsonly */
  2109. NULL, /* controls */
  2110. RUV_STORAGE_ENTRY_UNIQUEID,
  2111. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
  2112. OP_FLAG_REPLICATED); /* flags */
  2113. slapi_search_internal_pb (pb);
  2114. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  2115. if (rc == LDAP_SUCCESS)
  2116. {
  2117. /* get RUV attributes and construct the RUV */
  2118. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  2119. if (NULL == entries || NULL == entries[0])
  2120. {
  2121. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2122. "_replica_configure_ruv: replica ruv tombstone entry for "
  2123. "replica %s not found\n",
  2124. slapi_sdn_get_dn(r->repl_root));
  2125. goto done;
  2126. }
  2127. rc = slapi_entry_attr_find(entries[0], type_ruvElement, &attr);
  2128. if (rc != 0) /* ruv attribute is missing - this not allowed */
  2129. {
  2130. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2131. "_replica_configure_ruv: replica ruv tombstone entry for "
  2132. "replica %s does not contain %s\n",
  2133. slapi_sdn_get_dn(r->repl_root), type_ruvElement);
  2134. goto done;
  2135. }
  2136. /* Check in the tombstone we have retrieved if the local purl is
  2137. already present:
  2138. rid == 0: the local purl is not present
  2139. rid != 0: the local purl is present ==> nothing to do
  2140. */
  2141. ruv_init_from_slapi_attr_and_check_purl (attr, &ruv, &rid);
  2142. if (ruv)
  2143. {
  2144. char *generation = NULL;
  2145. generation = ruv_get_replica_generation(ruv);
  2146. if (NULL != generation)
  2147. {
  2148. r->repl_ruv = object_new((void*)ruv, (FNFree)ruv_destroy);
  2149. /* Is the local purl in the ruv? (the port or the host could have
  2150. changed)
  2151. */
  2152. /* A consumer only doesn't have its purl in its ruv */
  2153. if (r->repl_type == REPLICA_TYPE_UPDATABLE)
  2154. {
  2155. int need_update = 0;
  2156. #define RUV_UPDATE_PARTIAL 1
  2157. #define RUV_UPDATE_FULL 2
  2158. if (rid == 0)
  2159. {
  2160. /* We can not have more than 1 ruv with the same rid
  2161. so we replace it */
  2162. const char *purl = NULL;
  2163. purl = multimaster_get_local_purl();
  2164. ruv_delete_replica(ruv, r->repl_rid);
  2165. ruv_add_index_replica(ruv, r->repl_rid, purl, 1);
  2166. need_update = RUV_UPDATE_PARTIAL; /* ruv changed, so write tombstone */
  2167. }
  2168. else /* bug 540844: make sure the local supplier rid is first in the ruv */
  2169. {
  2170. /* make sure local supplier is first in list */
  2171. ReplicaId first_rid = 0;
  2172. char *first_purl = NULL;
  2173. ruv_get_first_id_and_purl(ruv, &first_rid, &first_purl);
  2174. /* if the local supplier is not first in the list . . . */
  2175. /* rid is from changelog; first_rid is from backend */
  2176. if (rid != first_rid)
  2177. {
  2178. /* . . . move the local supplier to the beginning of the list */
  2179. ruv_move_local_supplier_to_first(ruv, rid);
  2180. need_update = RUV_UPDATE_PARTIAL; /* must update tombstone also */
  2181. }
  2182. /* r->repl_rid is from config; rid is from changelog */
  2183. if (r->repl_rid != rid)
  2184. {
  2185. /* Most likely, the replica was once deleted
  2186. * and recreated with a different rid from the
  2187. * previous. */
  2188. /* must recreate ruv tombstone */
  2189. need_update = RUV_UPDATE_FULL;
  2190. if(NULL != r->repl_ruv)
  2191. {
  2192. object_release(r->repl_ruv);
  2193. r->repl_ruv = NULL;
  2194. }
  2195. }
  2196. }
  2197. /* Update also the directory entry */
  2198. if (RUV_UPDATE_PARTIAL == need_update) {
  2199. replica_replace_ruv_tombstone(r);
  2200. } else if (RUV_UPDATE_FULL == need_update) {
  2201. _delete_tombstone(slapi_sdn_get_dn(r->repl_root),
  2202. RUV_STORAGE_ENTRY_UNIQUEID,
  2203. OP_FLAG_REPL_RUV);
  2204. rc = replica_create_ruv_tombstone(r);
  2205. if (rc) {
  2206. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2207. "_replica_configure_ruv: "
  2208. "failed to recreate replica ruv tombstone entry"
  2209. " (%s); LDAP error - %d\n",
  2210. slapi_sdn_get_dn(r->repl_root), rc);
  2211. slapi_ch_free_string(&generation);
  2212. goto done;
  2213. }
  2214. }
  2215. #undef RUV_UPDATE_PARTIAL
  2216. #undef RUV_UPDATE_FULL
  2217. }
  2218. slapi_ch_free_string(&generation);
  2219. return_value = 0;
  2220. }
  2221. else
  2222. {
  2223. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2224. "RUV for replica %s is missing replica generation\n",
  2225. slapi_sdn_get_dn(r->repl_root));
  2226. goto done;
  2227. }
  2228. }
  2229. else
  2230. {
  2231. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2232. "Unable to convert %s attribute in entry %s to a replica update vector.\n",
  2233. type_ruvElement, slapi_sdn_get_dn(r->repl_root));
  2234. goto done;
  2235. }
  2236. }
  2237. else /* search failed */
  2238. {
  2239. if (LDAP_NO_SUCH_OBJECT == rc)
  2240. {
  2241. /* The entry doesn't exist: create it */
  2242. rc = replica_create_ruv_tombstone(r);
  2243. if (LDAP_SUCCESS != rc)
  2244. {
  2245. /*
  2246. * XXXggood - the following error appears on startup if we try
  2247. * to initialize replica RUVs before the backend instance is up.
  2248. * It's alarming to see this error, and we should suppress it
  2249. * (or avoid trying to configure it) if the backend instance is
  2250. * not yet online.
  2251. */
  2252. /*
  2253. * XXXrichm - you can also get this error when the backend is in
  2254. * read only mode c.f. bug 539782
  2255. */
  2256. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2257. "_replica_configure_ruv: failed to create replica ruv tombstone "
  2258. "entry (%s); LDAP error - %d\n",
  2259. slapi_sdn_get_dn(r->repl_root), rc);
  2260. goto done;
  2261. }
  2262. else
  2263. {
  2264. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2265. "_replica_configure_ruv: No ruv tombstone found for replica %s. "
  2266. "Created a new one\n",
  2267. slapi_sdn_get_dn(r->repl_root));
  2268. return_value = 0;
  2269. }
  2270. }
  2271. else
  2272. {
  2273. /* see if the suffix is disabled */
  2274. char *state = slapi_mtn_get_state(r->repl_root);
  2275. if (state && !strcasecmp(state, "disabled"))
  2276. {
  2277. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2278. "_replica_configure_ruv: replication disabled for "
  2279. "entry (%s); LDAP error - %d\n",
  2280. slapi_sdn_get_dn(r->repl_root), rc);
  2281. slapi_ch_free_string(&state);
  2282. goto done;
  2283. }
  2284. else if (!r->repl_ruv) /* other error */
  2285. {
  2286. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2287. "_replica_configure_ruv: replication broken for "
  2288. "entry (%s); LDAP error - %d\n",
  2289. slapi_sdn_get_dn(r->repl_root), rc);
  2290. slapi_ch_free_string(&state);
  2291. goto done;
  2292. }
  2293. else /* some error but continue anyway? */
  2294. {
  2295. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2296. "_replica_configure_ruv: Error %d reading tombstone for replica %s.\n",
  2297. rc, slapi_sdn_get_dn(r->repl_root));
  2298. return_value = 0;
  2299. }
  2300. slapi_ch_free_string(&state);
  2301. }
  2302. }
  2303. if (NULL != r->min_csn_pl)
  2304. {
  2305. csnplFree (&r->min_csn_pl);
  2306. }
  2307. /* create pending list for min csn if necessary */
  2308. if (ruv_get_smallest_csn_for_replica ((RUV*)object_get_data (r->repl_ruv),
  2309. r->repl_rid, &csn) == RUV_SUCCESS)
  2310. {
  2311. csn_free (&csn);
  2312. r->min_csn_pl = NULL;
  2313. }
  2314. else
  2315. {
  2316. /*
  2317. * The local replica has not generated any of its own CSNs yet.
  2318. * We need to watch CSNs being generated and note the first
  2319. * locally-generated CSN that's committed. Once that event occurs,
  2320. * the RUV is suitable for iteration over locally generated
  2321. * changes.
  2322. */
  2323. r->min_csn_pl = csnplNew();
  2324. }
  2325. done:
  2326. if (NULL != pb)
  2327. {
  2328. slapi_free_search_results_internal(pb);
  2329. slapi_pblock_destroy (pb);
  2330. }
  2331. if (return_value != 0)
  2332. {
  2333. if (ruv)
  2334. ruv_destroy (&ruv);
  2335. }
  2336. return return_value;
  2337. }
  2338. /* NOTE - this is the only non-api function that performs locking because
  2339. it is called by the event queue */
  2340. void
  2341. replica_update_state (time_t when, void *arg)
  2342. {
  2343. int rc;
  2344. const char *replica_name = (const char *)arg;
  2345. Object *replica_object = NULL;
  2346. Replica *r;
  2347. Slapi_Mod smod;
  2348. LDAPMod *mods[3];
  2349. Slapi_PBlock *pb = NULL;
  2350. char *dn = NULL;
  2351. struct berval *vals[2];
  2352. struct berval val;
  2353. LDAPMod mod;
  2354. if (NULL == replica_name)
  2355. return;
  2356. /*
  2357. * replica_get_by_name() will acquire the replica object
  2358. * and that could prevent the replica from being destroyed
  2359. * until the object_release is called.
  2360. */
  2361. replica_object = replica_get_by_name(replica_name);
  2362. if (NULL == replica_object)
  2363. {
  2364. return;
  2365. }
  2366. /* We have a reference, so replica won't vanish on us. */
  2367. r = (Replica *)object_get_data(replica_object);
  2368. if (NULL == r)
  2369. {
  2370. goto done;
  2371. }
  2372. replica_lock(r->repl_lock);
  2373. /* replica state is currently being updated
  2374. or no CSN was assigned - bail out */
  2375. if (r->state_update_inprogress)
  2376. {
  2377. replica_unlock(r->repl_lock);
  2378. goto done;
  2379. }
  2380. /* This might be a consumer */
  2381. if (!r->repl_csn_assigned)
  2382. {
  2383. /* EY: the consumer needs to flush ruv to disk. */
  2384. replica_unlock(r->repl_lock);
  2385. if (replica_write_ruv(r)) {
  2386. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2387. "_replica_update_state: failed write RUV for %s\n",
  2388. slapi_sdn_get_dn (r->repl_root));
  2389. }
  2390. goto done;
  2391. }
  2392. /* ONREPL update csn generator state of an updatable replica only */
  2393. /* ONREPL state always changes because we update time every second and
  2394. we write state to the disk less frequently */
  2395. rc = csngen_get_state ((CSNGen*)object_get_data (r->repl_csngen), &smod);
  2396. if (rc != 0)
  2397. {
  2398. replica_unlock(r->repl_lock);
  2399. goto done;
  2400. }
  2401. r->state_update_inprogress = PR_TRUE;
  2402. r->repl_csn_assigned = PR_FALSE;
  2403. dn = _replica_get_config_dn (r->repl_root);
  2404. if (NULL == dn) {
  2405. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2406. "replica_update_state: failed to get the config dn for %s\n",
  2407. slapi_sdn_get_dn (r->repl_root));
  2408. replica_unlock(r->repl_lock);
  2409. goto done;
  2410. }
  2411. pb = slapi_pblock_new();
  2412. mods[0] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod);
  2413. /* we don't want to held lock during operations since it causes lock contention
  2414. and sometimes deadlock. So releasing lock here */
  2415. replica_unlock(r->repl_lock);
  2416. /* replica repl_name and new_name attributes do not get changed once
  2417. the replica is configured - so it is ok that they are outside replica lock */
  2418. /* write replica name if it has not been written before */
  2419. if (r->new_name)
  2420. {
  2421. mods[1] = &mod;
  2422. mod.mod_op = LDAP_MOD_REPLACE|LDAP_MOD_BVALUES;
  2423. mod.mod_type = (char*)attr_replicaName;
  2424. mod.mod_bvalues = vals;
  2425. vals [0] = &val;
  2426. vals [1] = NULL;
  2427. val.bv_val = r->repl_name;
  2428. val.bv_len = strlen (val.bv_val);
  2429. mods[2] = NULL;
  2430. }
  2431. else
  2432. {
  2433. mods[1] = NULL;
  2434. }
  2435. slapi_modify_internal_set_pb (pb, dn, mods, NULL, NULL,
  2436. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
  2437. slapi_modify_internal_pb (pb);
  2438. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  2439. if (rc != LDAP_SUCCESS)
  2440. {
  2441. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_update_state: "
  2442. "failed to update state of csn generator for replica %s: LDAP "
  2443. "error - %d\n", slapi_sdn_get_dn(r->repl_root), rc);
  2444. }
  2445. else
  2446. {
  2447. r->new_name = PR_FALSE;
  2448. }
  2449. /* update RUV - performs its own locking */
  2450. if (replica_write_ruv(r)) {
  2451. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2452. "_replica_update_state: failed write RUV for %s\n",
  2453. slapi_sdn_get_dn (r->repl_root));
  2454. }
  2455. /* since this is the only place this value is changed and we are
  2456. guaranteed that only one thread enters the function, its ok
  2457. to change it outside replica lock */
  2458. r->state_update_inprogress = PR_FALSE;
  2459. slapi_ch_free ((void**)&dn);
  2460. slapi_pblock_destroy (pb);
  2461. slapi_mod_done (&smod);
  2462. done:
  2463. if (replica_object)
  2464. object_release (replica_object);
  2465. }
  2466. int
  2467. replica_write_ruv (Replica *r)
  2468. {
  2469. int rc = LDAP_SUCCESS;
  2470. Slapi_Mod smod, rmod;
  2471. Slapi_Mod smod_last_modified;
  2472. LDAPMod *mods [4];
  2473. Slapi_PBlock *pb;
  2474. PR_ASSERT(r);
  2475. replica_lock(r->repl_lock);
  2476. if (!r->repl_ruv_dirty)
  2477. {
  2478. replica_unlock(r->repl_lock);
  2479. return rc;
  2480. }
  2481. PR_ASSERT (r->repl_ruv);
  2482. ruv_to_smod ((RUV*)object_get_data(r->repl_ruv), &smod);
  2483. ruv_last_modified_to_smod ((RUV*)object_get_data(r->repl_ruv), &smod_last_modified);
  2484. replica_unlock (r->repl_lock);
  2485. mods [0] = (LDAPMod *)slapi_mod_get_ldapmod_byref(&smod);
  2486. mods [1] = (LDAPMod *)slapi_mod_get_ldapmod_byref(&smod_last_modified);
  2487. if(agmt_maxcsn_to_smod(r,&rmod) == LDAP_SUCCESS){
  2488. mods [2] = (LDAPMod *)slapi_mod_get_ldapmod_byref(&rmod);
  2489. } else {
  2490. mods [2] = NULL;
  2491. }
  2492. mods [3] = NULL;
  2493. pb = slapi_pblock_new();
  2494. /* replica name never changes so it is ok to reference it outside the lock */
  2495. slapi_modify_internal_set_pb_ext(
  2496. pb,
  2497. r->repl_root, /* only used to select be */
  2498. mods,
  2499. NULL, /* controls */
  2500. RUV_STORAGE_ENTRY_UNIQUEID,
  2501. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
  2502. /* Add OP_FLAG_TOMBSTONE_ENTRY so that this doesn't get logged in the Retro ChangeLog */
  2503. OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP | OP_FLAG_TOMBSTONE_ENTRY |
  2504. OP_FLAG_REPL_RUV );
  2505. slapi_modify_internal_pb (pb);
  2506. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  2507. /* ruv does not exist - create one */
  2508. replica_lock(r->repl_lock);
  2509. if (rc == LDAP_SUCCESS)
  2510. {
  2511. r->repl_ruv_dirty = PR_FALSE;
  2512. }
  2513. else if (rc == LDAP_NO_SUCH_OBJECT)
  2514. {
  2515. /* this includes an internal operation - but since this only happens
  2516. during server startup - its ok that we have lock around it */
  2517. rc = _replica_configure_ruv (r, PR_TRUE);
  2518. if (rc == 0)
  2519. r->repl_ruv_dirty = PR_FALSE;
  2520. }
  2521. else /* error */
  2522. {
  2523. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2524. "replica_write_ruv: failed to update RUV tombstone for %s; "
  2525. "LDAP error - %d\n",
  2526. slapi_sdn_get_dn(r->repl_root), rc);
  2527. }
  2528. replica_unlock(r->repl_lock);
  2529. slapi_mod_done (&smod);
  2530. slapi_mod_done (&rmod);
  2531. slapi_mod_done (&smod_last_modified);
  2532. slapi_pblock_destroy (pb);
  2533. return rc;
  2534. }
  2535. /* This routine figures out if an operation is for a replicated area and if so,
  2536. * pulls out the operation CSN and returns it through the smods parameter.
  2537. * It also informs the caller of the RUV entry's unique ID, since the caller
  2538. * may not have access to the macro in repl5.h. */
  2539. int
  2540. replica_ruv_smods_for_op( Slapi_PBlock *pb, char **uniqueid, Slapi_Mods **smods )
  2541. {
  2542. Object *replica_obj;
  2543. Object *ruv_obj;
  2544. Replica *replica;
  2545. RUV *ruv;
  2546. RUV *ruv_copy;
  2547. CSN *opcsn = NULL;
  2548. Slapi_Mod smod;
  2549. Slapi_Mod smod_last_modified;
  2550. Slapi_Operation *op;
  2551. Slapi_Entry *target_entry = NULL;
  2552. int rc = 0;
  2553. slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &target_entry);
  2554. if (target_entry && is_ruv_tombstone_entry(target_entry)) {
  2555. /* disallow direct modification of the RUV tombstone entry
  2556. must use the CLEANRUV task instead */
  2557. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2558. "replica_ruv_smods_for_op: attempted to directly modify the tombstone RUV "
  2559. "entry [%s] - use the CLEANALLRUV task instead\n",
  2560. slapi_entry_get_dn_const(target_entry));
  2561. return (-1);
  2562. }
  2563. replica_obj = replica_get_replica_for_op (pb);
  2564. slapi_pblock_get( pb, SLAPI_OPERATION, &op );
  2565. if (NULL != replica_obj && NULL != op) {
  2566. opcsn = operation_get_csn( op );
  2567. }
  2568. /* If the op has no CSN then it's not in a replicated area, so we're done */
  2569. if (NULL == opcsn) {
  2570. return (0);
  2571. }
  2572. replica = (Replica*)object_get_data(replica_obj);
  2573. PR_ASSERT (replica);
  2574. ruv_obj = replica_get_ruv(replica);
  2575. PR_ASSERT (ruv_obj);
  2576. ruv = (RUV*)object_get_data(ruv_obj);
  2577. PR_ASSERT (ruv);
  2578. ruv_copy = ruv_dup( ruv );
  2579. object_release (ruv_obj);
  2580. object_release (replica_obj);
  2581. rc = ruv_set_max_csn_ext( ruv_copy, opcsn, NULL, PR_TRUE );
  2582. if (rc == RUV_COVERS_CSN) { /* change would "revert" RUV - ignored */
  2583. rc = 0; /* tell caller to ignore */
  2584. } else if (rc == RUV_SUCCESS) {
  2585. rc = 1; /* tell caller success */
  2586. } else { /* error */
  2587. rc = -1; /* tell caller error */
  2588. }
  2589. if (rc == 1) {
  2590. ruv_to_smod( ruv_copy, &smod );
  2591. ruv_last_modified_to_smod( ruv_copy, &smod_last_modified );
  2592. }
  2593. ruv_destroy( &ruv_copy );
  2594. if (rc == 1) {
  2595. *smods = slapi_mods_new();
  2596. slapi_mods_add_smod(*smods, &smod);
  2597. slapi_mods_add_smod(*smods, &smod_last_modified);
  2598. *uniqueid = slapi_ch_strdup( RUV_STORAGE_ENTRY_UNIQUEID );
  2599. } else {
  2600. *smods = NULL;
  2601. *uniqueid = NULL;
  2602. }
  2603. return rc;
  2604. }
  2605. const CSN *
  2606. entry_get_deletion_csn(Slapi_Entry *e)
  2607. {
  2608. const CSN *deletion_csn = NULL;
  2609. PR_ASSERT(NULL != e);
  2610. if (NULL != e)
  2611. {
  2612. Slapi_Attr *oc_attr = NULL;
  2613. if (entry_attr_find_wsi(e, SLAPI_ATTR_OBJECTCLASS, &oc_attr) == ATTRIBUTE_PRESENT)
  2614. {
  2615. Slapi_Value *tombstone_value = NULL;
  2616. struct berval v;
  2617. v.bv_val = SLAPI_ATTR_VALUE_TOMBSTONE;
  2618. v.bv_len = strlen(SLAPI_ATTR_VALUE_TOMBSTONE);
  2619. if (attr_value_find_wsi(oc_attr, &v, &tombstone_value) == VALUE_PRESENT)
  2620. {
  2621. deletion_csn = value_get_csn(tombstone_value, CSN_TYPE_VALUE_UPDATED);
  2622. }
  2623. }
  2624. }
  2625. return deletion_csn;
  2626. }
  2627. static void
  2628. _delete_tombstone(const char *tombstone_dn, const char *uniqueid, int ext_op_flags)
  2629. {
  2630. PR_ASSERT(NULL != tombstone_dn && NULL != uniqueid);
  2631. if (NULL == tombstone_dn || NULL == uniqueid)
  2632. {
  2633. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_delete_tombstone: "
  2634. "NULL tombstone_dn or uniqueid provided.\n");
  2635. }
  2636. else
  2637. {
  2638. int ldaprc;
  2639. Slapi_PBlock *pb = slapi_pblock_new();
  2640. slapi_delete_internal_set_pb(pb, tombstone_dn, NULL, /* controls */
  2641. uniqueid, repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
  2642. OP_FLAG_TOMBSTONE_ENTRY | ext_op_flags);
  2643. slapi_delete_internal_pb(pb);
  2644. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ldaprc);
  2645. if (LDAP_SUCCESS != ldaprc)
  2646. {
  2647. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2648. "_delete_tombstone: unable to delete tombstone %s, "
  2649. "uniqueid %s: %s.\n", tombstone_dn, uniqueid,
  2650. ldap_err2string(ldaprc));
  2651. }
  2652. slapi_pblock_destroy(pb);
  2653. }
  2654. }
  2655. static
  2656. void get_reap_result (int rc, void *cb_data)
  2657. {
  2658. PR_ASSERT (cb_data);
  2659. ((reap_callback_data*)cb_data)->rc = rc;
  2660. }
  2661. static int
  2662. process_reap_entry (Slapi_Entry *entry, void *cb_data)
  2663. {
  2664. char deletion_csn_str[CSN_STRSIZE];
  2665. char purge_csn_str[CSN_STRSIZE];
  2666. unsigned long *num_entriesp = &((reap_callback_data *)cb_data)->num_entries;
  2667. unsigned long *num_purged_entriesp = &((reap_callback_data *)cb_data)->num_purged_entries;
  2668. CSN *purge_csn = ((reap_callback_data *)cb_data)->purge_csn;
  2669. /* this is a pointer into the actual value in the Replica object - so that
  2670. if the value is set in the replica, we will know about it immediately */
  2671. PRBool *tombstone_reap_stop = ((reap_callback_data *)cb_data)->tombstone_reap_stop;
  2672. const CSN *deletion_csn = NULL;
  2673. int rc = -1;
  2674. /* abort reaping if we've been told to stop or we're shutting down */
  2675. if (*tombstone_reap_stop || slapi_is_shutting_down()) {
  2676. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2677. "process_reap_entry: the tombstone reap process "
  2678. " has been stopped\n");
  2679. return rc;
  2680. }
  2681. /* we only ask for the objectclass in the search - the deletion csn is in the
  2682. objectclass attribute values - if we need more attributes returned by the
  2683. search in the future, see _replica_reap_tombstones below and add more to the
  2684. attrs array */
  2685. deletion_csn = entry_get_deletion_csn(entry);
  2686. if ((NULL == deletion_csn || csn_compare(deletion_csn, purge_csn) < 0) &&
  2687. (!is_ruv_tombstone_entry(entry))) {
  2688. if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
  2689. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2690. "process_reap_entry: removing tombstone %s "
  2691. "because its deletion csn (%s) is less than the "
  2692. "purge csn (%s).\n",
  2693. slapi_entry_get_dn(entry),
  2694. csn_as_string(deletion_csn, PR_FALSE, deletion_csn_str),
  2695. csn_as_string(purge_csn, PR_FALSE, purge_csn_str));
  2696. }
  2697. if (slapi_entry_attr_get_ulong(entry, "tombstonenumsubordinates") < 1) {
  2698. _delete_tombstone(slapi_entry_get_dn(entry),
  2699. slapi_entry_get_uniqueid(entry), 0);
  2700. (*num_purged_entriesp)++;
  2701. }
  2702. }
  2703. else {
  2704. if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
  2705. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2706. "process_reap_entry: NOT removing tombstone "
  2707. "%s\n", slapi_entry_get_dn(entry));
  2708. }
  2709. }
  2710. if(!is_ruv_tombstone_entry(entry)){
  2711. /* Don't update the count for the database tombstone entry */
  2712. (*num_entriesp)++;
  2713. }
  2714. return 0;
  2715. }
  2716. /* This does the actual work of searching for tombstones and deleting them.
  2717. This must be called in a separate thread because it may take a long time.
  2718. */
  2719. static void
  2720. _replica_reap_tombstones(void *arg)
  2721. {
  2722. const char *replica_name = (const char *)arg;
  2723. Slapi_PBlock *pb = NULL;
  2724. Object *replica_object = NULL;
  2725. Replica *replica = NULL;
  2726. CSN *purge_csn = NULL;
  2727. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2728. "Info: Beginning tombstone reap for replica %s.\n",
  2729. replica_name ? replica_name : "(null)");
  2730. if (NULL == replica_name)
  2731. {
  2732. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2733. "Warning: Replica name is null in tombstone reap\n");
  2734. goto done;
  2735. }
  2736. /*
  2737. * replica_get_by_name() will acquire the replica object
  2738. * and that could prevent the replica from being destroyed
  2739. * until the object_release is called.
  2740. */
  2741. replica_object = replica_get_by_name(replica_name);
  2742. if (NULL == replica_object)
  2743. {
  2744. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2745. "Warning: Replica object %s is null in tombstone reap\n", replica_name);
  2746. goto done;
  2747. }
  2748. /* We have a reference, so replica won't vanish on us. */
  2749. replica = (Replica *)object_get_data(replica_object);
  2750. if (NULL == replica)
  2751. {
  2752. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2753. "Warning: Replica %s is null in tombstone reap\n", replica_name);
  2754. goto done;
  2755. }
  2756. if (replica->tombstone_reap_stop)
  2757. {
  2758. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2759. "Info: Replica %s reap stop flag is set for tombstone reap\n", replica_name);
  2760. goto done;
  2761. }
  2762. purge_csn = replica_get_purge_csn(replica);
  2763. if (NULL != purge_csn)
  2764. {
  2765. LDAPControl **ctrls;
  2766. reap_callback_data cb_data;
  2767. char deletion_csn_str[CSN_STRSIZE];
  2768. char tombstone_filter[128];
  2769. char **attrs = NULL;
  2770. int oprc;
  2771. if (replica_get_precise_purging(replica)){
  2772. /*
  2773. * Using precise tombstone purging. Create filter to lookup the exact
  2774. * entries that need to be purged by using a range search on the new
  2775. * tombstone csn index.
  2776. */
  2777. csn_as_string(purge_csn, PR_FALSE, deletion_csn_str);
  2778. PR_snprintf(tombstone_filter, 128,
  2779. "(&(%s<=%s)(objectclass=nsTombstone))", SLAPI_ATTR_TOMBSTONE_CSN,
  2780. csn_as_string(purge_csn, PR_FALSE, deletion_csn_str));
  2781. } else {
  2782. /* Use the old inefficient filter */
  2783. PR_snprintf(tombstone_filter, 128, "(objectclass=nsTombstone)");
  2784. }
  2785. /* we just need the objectclass - for the deletion csn
  2786. and the dn and nsuniqueid - for possible deletion
  2787. and tombstonenumsubordinates to check if it has numsubordinates
  2788. saves time to return only 3 attrs
  2789. */
  2790. charray_add(&attrs, slapi_ch_strdup("objectclass"));
  2791. charray_add(&attrs, slapi_ch_strdup("nsuniqueid"));
  2792. charray_add(&attrs, slapi_ch_strdup("tombstonenumsubordinates"));
  2793. charray_add(&attrs, slapi_ch_strdup(SLAPI_ATTR_TOMBSTONE_CSN));
  2794. ctrls = (LDAPControl **)slapi_ch_calloc (3, sizeof (LDAPControl *));
  2795. ctrls[0] = create_managedsait_control();
  2796. ctrls[1] = create_backend_control(replica->repl_root);
  2797. ctrls[2] = NULL;
  2798. pb = slapi_pblock_new();
  2799. slapi_search_internal_set_pb(pb, slapi_sdn_get_dn(replica->repl_root),
  2800. LDAP_SCOPE_SUBTREE, tombstone_filter,
  2801. attrs, 0, ctrls, NULL,
  2802. repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
  2803. OP_FLAG_REVERSE_CANDIDATE_ORDER);
  2804. cb_data.rc = 0;
  2805. cb_data.num_entries = 0UL;
  2806. cb_data.num_purged_entries = 0UL;
  2807. cb_data.purge_csn = purge_csn;
  2808. /* set the cb data pointer to point to the actual memory address in
  2809. the actual Replica object - so that when the value in the Replica
  2810. is set, the reap process will know about it immediately */
  2811. cb_data.tombstone_reap_stop = &(replica->tombstone_reap_stop);
  2812. slapi_search_internal_callback_pb(pb, &cb_data /* callback data */,
  2813. get_reap_result /* result callback */,
  2814. process_reap_entry /* entry callback */,
  2815. NULL /* referral callback*/);
  2816. charray_free(attrs);
  2817. oprc = cb_data.rc;
  2818. if (LDAP_SUCCESS != oprc)
  2819. {
  2820. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2821. "_replica_reap_tombstones: failed when searching for "
  2822. "tombstones in replica %s: %s. Will try again in %ld "
  2823. "seconds.\n", slapi_sdn_get_dn(replica->repl_root),
  2824. ldap_err2string(oprc), replica->tombstone_reap_interval);
  2825. }
  2826. else
  2827. {
  2828. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2829. "_replica_reap_tombstones: purged %ld of %ld tombstones "
  2830. "in replica %s. Will try again in %ld "
  2831. "seconds.\n", cb_data.num_purged_entries, cb_data.num_entries,
  2832. slapi_sdn_get_dn(replica->repl_root),
  2833. replica->tombstone_reap_interval);
  2834. }
  2835. }
  2836. else
  2837. {
  2838. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2839. "Info: No purge CSN for tombstone reap for replica %s.\n",
  2840. replica_name);
  2841. }
  2842. done:
  2843. if (replica)
  2844. {
  2845. replica_lock(replica->repl_lock);
  2846. replica->tombstone_reap_active = PR_FALSE;
  2847. replica_unlock(replica->repl_lock);
  2848. }
  2849. if (NULL != purge_csn)
  2850. {
  2851. csn_free(&purge_csn);
  2852. }
  2853. if (NULL != pb)
  2854. {
  2855. slapi_free_search_results_internal(pb);
  2856. slapi_pblock_destroy(pb);
  2857. }
  2858. if (NULL != replica_object)
  2859. {
  2860. object_release(replica_object);
  2861. replica_object = NULL;
  2862. replica = NULL;
  2863. }
  2864. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2865. "Info: Finished tombstone reap for replica %s.\n",
  2866. replica_name ? replica_name : "(null)");
  2867. }
  2868. /*
  2869. We don't want to run the reaper function directly from the event
  2870. queue since it may hog the event queue, starving other events.
  2871. See bug 604441
  2872. The function eq_cb_reap_tombstones will fire off the actual thread
  2873. that does the real work.
  2874. */
  2875. static void
  2876. eq_cb_reap_tombstones(time_t when, void *arg)
  2877. {
  2878. const char *replica_name = (const char *)arg;
  2879. Object *replica_object = NULL;
  2880. Replica *replica = NULL;
  2881. if (NULL != replica_name)
  2882. {
  2883. /*
  2884. * replica_get_by_name() will acquire the replica object
  2885. * and that could prevent the replica from being destroyed
  2886. * until the object_release is called.
  2887. */
  2888. replica_object = replica_get_by_name(replica_name);
  2889. if (NULL != replica_object)
  2890. {
  2891. /* We have a reference, so replica won't vanish on us. */
  2892. replica = (Replica *)object_get_data(replica_object);
  2893. if (replica)
  2894. {
  2895. replica_lock(replica->repl_lock);
  2896. /* No action if purge is disabled or the previous purge is not done yet */
  2897. if (replica->tombstone_reap_interval != 0 &&
  2898. replica->tombstone_reap_active == PR_FALSE)
  2899. {
  2900. /* set the flag here to minimize race conditions */
  2901. replica->tombstone_reap_active = PR_TRUE;
  2902. if (PR_CreateThread(PR_USER_THREAD,
  2903. _replica_reap_tombstones, (void *)replica_name,
  2904. PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
  2905. SLAPD_DEFAULT_THREAD_STACKSIZE) == NULL)
  2906. {
  2907. replica->tombstone_reap_active = PR_FALSE;
  2908. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2909. "Error: unable to create the tombstone reap thread for replica %s. "
  2910. "Possible system resources problem\n",
  2911. replica_name);
  2912. }
  2913. }
  2914. /* reap thread will wait until this lock is released */
  2915. replica_unlock(replica->repl_lock);
  2916. }
  2917. object_release(replica_object);
  2918. replica_object = NULL;
  2919. replica = NULL;
  2920. }
  2921. }
  2922. }
  2923. static char *
  2924. _replica_type_as_string (const Replica *r)
  2925. {
  2926. switch (r->repl_type)
  2927. {
  2928. case REPLICA_TYPE_PRIMARY: return "primary";
  2929. case REPLICA_TYPE_READONLY: return "read-only";
  2930. case REPLICA_TYPE_UPDATABLE: return "updatable";
  2931. default: return "unknown";
  2932. }
  2933. }
  2934. static const char *root_glue =
  2935. "dn: %s\n"
  2936. "objectclass: top\n"
  2937. "objectclass: nsTombstone\n"
  2938. "objectclass: extensibleobject\n"
  2939. "nsuniqueid: %s\n";
  2940. static int
  2941. replica_create_ruv_tombstone(Replica *r)
  2942. {
  2943. int return_value = LDAP_LOCAL_ERROR;
  2944. char *root_entry_str;
  2945. Slapi_Entry *e = NULL;
  2946. const char *purl = NULL;
  2947. RUV *ruv;
  2948. struct berval **bvals = NULL;
  2949. Slapi_PBlock *pb = NULL;
  2950. int rc;
  2951. PR_ASSERT(NULL != r && NULL != r->repl_root);
  2952. root_entry_str = slapi_ch_smprintf(root_glue, slapi_sdn_get_ndn(r->repl_root), RUV_STORAGE_ENTRY_UNIQUEID);
  2953. e = slapi_str2entry(root_entry_str, SLAPI_STR2ENTRY_TOMBSTONE_CHECK);
  2954. if (e == NULL)
  2955. goto done;
  2956. /* Add ruv */
  2957. if (r->repl_ruv == NULL){
  2958. CSNGen *gen;
  2959. CSN *csn;
  2960. char csnstr [CSN_STRSIZE];
  2961. /* first attempt to write RUV tombstone - need to create RUV */
  2962. gen = (CSNGen *)object_get_data(r->repl_csngen);
  2963. PR_ASSERT (gen);
  2964. if (csngen_new_csn(gen, &csn, PR_FALSE /* notify */) == CSN_SUCCESS){
  2965. (void)csn_as_string(csn, PR_FALSE, csnstr);
  2966. csn_free(&csn);
  2967. /*
  2968. * if this is an updateable replica - add its own
  2969. * element to the RUV so that referrals work correctly
  2970. */
  2971. if (r->repl_type == REPLICA_TYPE_UPDATABLE)
  2972. purl = multimaster_get_local_purl();
  2973. if (ruv_init_new(csnstr, r->repl_rid, purl, &ruv) == RUV_SUCCESS){
  2974. r->repl_ruv = object_new((void*)ruv, (FNFree)ruv_destroy);
  2975. r->repl_ruv_dirty = PR_TRUE;
  2976. return_value = LDAP_SUCCESS;
  2977. } else {
  2978. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Cannot create new replica update vector for %s\n",
  2979. slapi_sdn_get_dn(r->repl_root));
  2980. ruv_destroy(&ruv);
  2981. goto done;
  2982. }
  2983. } else {
  2984. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Cannot obtain CSN for new replica update vector for %s\n",
  2985. slapi_sdn_get_dn(r->repl_root));
  2986. csn_free(&csn);
  2987. goto done;
  2988. }
  2989. } else { /* failed to write the entry because DB was not initialized - retry */
  2990. ruv = (RUV*) object_get_data (r->repl_ruv);
  2991. PR_ASSERT (ruv);
  2992. }
  2993. PR_ASSERT (r->repl_ruv);
  2994. rc = ruv_to_bervals(ruv, &bvals);
  2995. if (rc != RUV_SUCCESS){
  2996. goto done;
  2997. }
  2998. /* ONREPL this is depricated function but there is currently no better API to use */
  2999. rc = slapi_entry_add_values(e, type_ruvElement, bvals);
  3000. if (rc != 0){
  3001. goto done;
  3002. }
  3003. pb = slapi_pblock_new();
  3004. slapi_add_entry_internal_set_pb(pb, e, NULL /* controls */, repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
  3005. OP_FLAG_TOMBSTONE_ENTRY | OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP | OP_FLAG_REPL_RUV);
  3006. slapi_add_internal_pb(pb);
  3007. e = NULL; /* add consumes e, upon success or failure */
  3008. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &return_value);
  3009. if (return_value == LDAP_SUCCESS)
  3010. r->repl_ruv_dirty = PR_FALSE;
  3011. done:
  3012. slapi_entry_free (e);
  3013. if (bvals)
  3014. ber_bvecfree(bvals);
  3015. if (pb)
  3016. slapi_pblock_destroy(pb);
  3017. slapi_ch_free_string(&root_entry_str);
  3018. return return_value;
  3019. }
  3020. static void
  3021. assign_csn_callback(const CSN *csn, void *data)
  3022. {
  3023. Replica *r = (Replica *)data;
  3024. Object *ruv_obj;
  3025. RUV *ruv;
  3026. PR_ASSERT(NULL != csn);
  3027. PR_ASSERT(NULL != r);
  3028. ruv_obj = replica_get_ruv (r);
  3029. PR_ASSERT (ruv_obj);
  3030. ruv = (RUV*)object_get_data (ruv_obj);
  3031. PR_ASSERT (ruv);
  3032. replica_lock(r->repl_lock);
  3033. r->repl_csn_assigned = PR_TRUE;
  3034. if (NULL != r->min_csn_pl)
  3035. {
  3036. if (csnplInsert(r->min_csn_pl, csn) != 0)
  3037. {
  3038. char csn_str[CSN_STRSIZE]; /* For logging only */
  3039. /* Ack, we can't keep track of min csn. Punt. */
  3040. if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
  3041. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "assign_csn_callback: "
  3042. "failed to insert csn %s for replica %s\n",
  3043. csn_as_string(csn, PR_FALSE, csn_str),
  3044. slapi_sdn_get_dn(r->repl_root));
  3045. }
  3046. csnplFree(&r->min_csn_pl);
  3047. }
  3048. }
  3049. ruv_add_csn_inprogress (ruv, csn);
  3050. replica_unlock(r->repl_lock);
  3051. object_release (ruv_obj);
  3052. }
  3053. static void
  3054. abort_csn_callback(const CSN *csn, void *data)
  3055. {
  3056. Replica *r = (Replica *)data;
  3057. Object *ruv_obj;
  3058. RUV *ruv;
  3059. PR_ASSERT(NULL != csn);
  3060. PR_ASSERT(NULL != data);
  3061. ruv_obj = replica_get_ruv (r);
  3062. PR_ASSERT (ruv_obj);
  3063. ruv = (RUV*)object_get_data (ruv_obj);
  3064. PR_ASSERT (ruv);
  3065. replica_lock(r->repl_lock);
  3066. if (NULL != r->min_csn_pl)
  3067. {
  3068. int rc = csnplRemove(r->min_csn_pl, csn);
  3069. if (rc) {
  3070. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "csnplRemove failed");
  3071. return;
  3072. }
  3073. }
  3074. ruv_cancel_csn_inprogress (ruv, csn);
  3075. replica_unlock(r->repl_lock);
  3076. object_release (ruv_obj);
  3077. }
  3078. static CSN *
  3079. _replica_get_purge_csn_nolock(const Replica *r)
  3080. {
  3081. CSN *purge_csn = NULL;
  3082. CSN **csns = NULL;
  3083. RUV *ruv;
  3084. int i;
  3085. if (r->repl_purge_delay > 0)
  3086. {
  3087. /* get a sorted list of all maxcsns in ruv in ascend order */
  3088. object_acquire(r->repl_ruv);
  3089. ruv = object_get_data(r->repl_ruv);
  3090. csns = cl5BuildCSNList (ruv, NULL);
  3091. object_release(r->repl_ruv);
  3092. if (csns == NULL)
  3093. return NULL;
  3094. /* locate the most recent maxcsn in the csn list */
  3095. for (i = 0; csns[i]; i++);
  3096. purge_csn = csn_dup (csns[i-1]);
  3097. /* set purge_csn to the most recent maxcsn - purge_delay */
  3098. if ((csn_get_time(purge_csn) - r->repl_purge_delay) > 0)
  3099. csn_set_time(purge_csn, csn_get_time(purge_csn) - r->repl_purge_delay);
  3100. }
  3101. if (csns)
  3102. cl5DestroyCSNList (&csns);
  3103. return purge_csn;
  3104. }
  3105. static void
  3106. replica_get_referrals_nolock (const Replica *r, char ***referrals)
  3107. {
  3108. if(referrals!=NULL)
  3109. {
  3110. int hint;
  3111. int i= 0;
  3112. Slapi_Value *v= NULL;
  3113. if (NULL == r->repl_referral)
  3114. {
  3115. *referrals = NULL;
  3116. }
  3117. else
  3118. {
  3119. /* richm: +1 for trailing NULL */
  3120. *referrals= (char**)slapi_ch_calloc(sizeof(char*),1+slapi_valueset_count(r->repl_referral));
  3121. hint= slapi_valueset_first_value( r->repl_referral, &v );
  3122. while(v!=NULL)
  3123. {
  3124. const char *s= slapi_value_get_string(v);
  3125. if(s!=NULL && s[0]!='\0')
  3126. {
  3127. (*referrals)[i]= slapi_ch_strdup(s);
  3128. i++;
  3129. }
  3130. hint= slapi_valueset_next_value( r->repl_referral, hint, &v);
  3131. }
  3132. (*referrals)[i] = NULL;
  3133. }
  3134. }
  3135. }
  3136. static void
  3137. replica_clear_legacy_referrals(const Slapi_DN *repl_root_sdn,
  3138. char **referrals, const char *state)
  3139. {
  3140. repl_set_mtn_state_and_referrals(repl_root_sdn, state, NULL, NULL, referrals);
  3141. }
  3142. static void
  3143. replica_remove_legacy_attr (const Slapi_DN *repl_root_sdn, const char *attr)
  3144. {
  3145. Slapi_PBlock *pb;
  3146. Slapi_Mods smods;
  3147. LDAPControl **ctrls;
  3148. int rc;
  3149. pb = slapi_pblock_new ();
  3150. slapi_mods_init(&smods, 1);
  3151. slapi_mods_add(&smods, LDAP_MOD_DELETE, attr, 0, NULL);
  3152. ctrls = (LDAPControl**)slapi_ch_malloc (2 * sizeof (LDAPControl*));
  3153. ctrls[0] = create_managedsait_control ();
  3154. ctrls[1] = NULL;
  3155. /* remove copiedFrom/copyingFrom first */
  3156. slapi_modify_internal_set_pb_ext (pb, repl_root_sdn,
  3157. slapi_mods_get_ldapmods_passout (&smods),
  3158. ctrls, NULL /*uniqueid */,
  3159. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION) ,
  3160. 0 /* operation_flags */);
  3161. slapi_modify_internal_pb (pb);
  3162. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  3163. if (rc != LDAP_SUCCESS)
  3164. {
  3165. /* this is not a fatal error because the attribute may not be there */
  3166. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_remove_legacy_attr: "
  3167. "failed to remove legacy attribute %s for replica %s; LDAP error - %d\n",
  3168. attr, slapi_sdn_get_dn(repl_root_sdn), rc);
  3169. }
  3170. slapi_mods_done (&smods);
  3171. slapi_pblock_destroy (pb);
  3172. }
  3173. static int
  3174. replica_log_ruv_elements_nolock (const Replica *r)
  3175. {
  3176. int rc = 0;
  3177. slapi_operation_parameters op_params;
  3178. RUV *ruv;
  3179. char *repl_gen;
  3180. CSN *csn = NULL;
  3181. ruv = (RUV*) object_get_data (r->repl_ruv);
  3182. PR_ASSERT (ruv);
  3183. if ((ruv_get_min_csn(ruv, &csn) == RUV_SUCCESS) && csn)
  3184. {
  3185. /* we log it as a delete operation to have the least number of fields
  3186. to set. the entry can be identified by a special target uniqueid and
  3187. special target dn */
  3188. memset (&op_params, 0, sizeof (op_params));
  3189. op_params.operation_type = SLAPI_OPERATION_DELETE;
  3190. op_params.target_address.sdn = slapi_sdn_new_ndn_byval(START_ITERATION_ENTRY_DN);
  3191. op_params.target_address.uniqueid = START_ITERATION_ENTRY_UNIQUEID;
  3192. op_params.csn = csn;
  3193. repl_gen = ruv_get_replica_generation (ruv);
  3194. rc = cl5WriteOperation(r->repl_name, repl_gen, &op_params, PR_FALSE);
  3195. if (rc == CL5_SUCCESS)
  3196. rc = 0;
  3197. else
  3198. rc = -1;
  3199. slapi_ch_free ((void**)&repl_gen);
  3200. slapi_sdn_free(&op_params.target_address.sdn);
  3201. csn_free (&csn);
  3202. }
  3203. return rc;
  3204. }
  3205. void
  3206. replica_set_purge_delay(Replica *r, PRUint32 purge_delay)
  3207. {
  3208. PR_ASSERT(r);
  3209. replica_lock(r->repl_lock);
  3210. r->repl_purge_delay = purge_delay;
  3211. replica_unlock(r->repl_lock);
  3212. }
  3213. void
  3214. replica_set_tombstone_reap_interval (Replica *r, long interval)
  3215. {
  3216. char *repl_name;
  3217. replica_lock(r->repl_lock);
  3218. /*
  3219. * Leave the event there to purge the existing tombstones
  3220. * if we are about to turn off tombstone creation
  3221. */
  3222. if (interval > 0 && r->repl_eqcxt_tr && r->tombstone_reap_interval != interval)
  3223. {
  3224. int found;
  3225. repl_name = slapi_eq_get_arg (r->repl_eqcxt_tr);
  3226. slapi_ch_free ((void**)&repl_name);
  3227. found = slapi_eq_cancel (r->repl_eqcxt_tr);
  3228. slapi_log_error (SLAPI_LOG_REPL, NULL,
  3229. "tombstone_reap event (interval=%ld) was %s\n",
  3230. r->tombstone_reap_interval, (found ? "cancelled" : "not found"));
  3231. r->repl_eqcxt_tr = NULL;
  3232. }
  3233. r->tombstone_reap_interval = interval;
  3234. if ( interval > 0 && r->repl_eqcxt_tr == NULL )
  3235. {
  3236. repl_name = slapi_ch_strdup (r->repl_name);
  3237. r->repl_eqcxt_tr = slapi_eq_repeat (eq_cb_reap_tombstones, repl_name,
  3238. current_time() + r->tombstone_reap_interval,
  3239. 1000 * r->tombstone_reap_interval);
  3240. slapi_log_error (SLAPI_LOG_REPL, NULL,
  3241. "tombstone_reap event (interval=%ld) was %s\n",
  3242. r->tombstone_reap_interval, (r->repl_eqcxt_tr ? "scheduled" : "not scheduled successfully"));
  3243. }
  3244. replica_unlock(r->repl_lock);
  3245. }
  3246. static void
  3247. replica_strip_cleaned_rids(Replica *r)
  3248. {
  3249. Object *RUVObj;
  3250. RUV *ruv = NULL;
  3251. ReplicaId rid[32] = {0};
  3252. int i = 0;
  3253. RUVObj = replica_get_ruv(r);
  3254. ruv = (RUV*)object_get_data (RUVObj);
  3255. ruv_get_cleaned_rids(ruv, rid);
  3256. while(rid[i] != 0){
  3257. ruv_delete_replica(ruv, rid[i]);
  3258. replica_set_ruv_dirty(r);
  3259. if (replica_write_ruv(r)) {
  3260. slapi_log_error (SLAPI_LOG_REPL, "replica_strip_cleaned_rids", "failed to write RUV\n");
  3261. }
  3262. i++;
  3263. }
  3264. object_release(RUVObj);
  3265. }
  3266. /* Update the tombstone entry to reflect the content of the ruv */
  3267. static void
  3268. replica_replace_ruv_tombstone(Replica *r)
  3269. {
  3270. Slapi_PBlock *pb = NULL;
  3271. Slapi_Mod smod;
  3272. Slapi_Mod smod_last_modified;
  3273. LDAPMod *mods [3];
  3274. char *dn;
  3275. int rc;
  3276. PR_ASSERT(NULL != r && NULL != r->repl_root);
  3277. replica_strip_cleaned_rids(r);
  3278. replica_lock(r->repl_lock);
  3279. PR_ASSERT (r->repl_ruv);
  3280. ruv_to_smod ((RUV*)object_get_data(r->repl_ruv), &smod);
  3281. ruv_last_modified_to_smod ((RUV*)object_get_data(r->repl_ruv), &smod_last_modified);
  3282. dn = _replica_get_config_dn (r->repl_root);
  3283. if (NULL == dn) {
  3284. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  3285. "replica_replace_ruv_tombstone: "
  3286. "failed to get the config dn for %s\n",
  3287. slapi_sdn_get_dn (r->repl_root));
  3288. replica_unlock(r->repl_lock);
  3289. goto bail;
  3290. }
  3291. mods[0] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod);
  3292. mods[1] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod_last_modified);
  3293. replica_unlock(r->repl_lock);
  3294. mods [2] = NULL;
  3295. pb = slapi_pblock_new();
  3296. slapi_modify_internal_set_pb_ext(
  3297. pb,
  3298. r->repl_root, /* only used to select be */
  3299. mods,
  3300. NULL, /* controls */
  3301. RUV_STORAGE_ENTRY_UNIQUEID,
  3302. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
  3303. OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP | OP_FLAG_REPL_RUV | OP_FLAG_TOMBSTONE_ENTRY);
  3304. slapi_modify_internal_pb (pb);
  3305. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  3306. if (rc != LDAP_SUCCESS)
  3307. {
  3308. if ((rc != LDAP_NO_SUCH_OBJECT && rc != LDAP_TYPE_OR_VALUE_EXISTS) || !replica_is_state_flag_set(r, REPLICA_IN_USE))
  3309. {
  3310. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_replace_ruv_tombstone: "
  3311. "failed to update replication update vector for replica %s: LDAP "
  3312. "error - %d\n", (char*)slapi_sdn_get_dn (r->repl_root), rc);
  3313. }
  3314. }
  3315. slapi_ch_free ((void**)&dn);
  3316. slapi_pblock_destroy (pb);
  3317. bail:
  3318. slapi_mod_done (&smod);
  3319. slapi_mod_done (&smod_last_modified);
  3320. }
  3321. void
  3322. replica_update_ruv_consumer(Replica *r, RUV *supplier_ruv)
  3323. {
  3324. ReplicaId supplier_id = 0;
  3325. char *supplier_purl = NULL;
  3326. if ( ruv_get_first_id_and_purl(supplier_ruv, &supplier_id, &supplier_purl) == RUV_SUCCESS)
  3327. {
  3328. RUV *local_ruv = NULL;
  3329. replica_lock(r->repl_lock);
  3330. local_ruv = (RUV*)object_get_data (r->repl_ruv);
  3331. if(is_cleaned_rid(supplier_id) || local_ruv == NULL){
  3332. replica_unlock(r->repl_lock);
  3333. return;
  3334. }
  3335. if ( ruv_local_contains_supplier(local_ruv, supplier_id) == 0 )
  3336. {
  3337. if ( r->repl_type == REPLICA_TYPE_UPDATABLE )
  3338. {
  3339. /* Add the new ruv right after the consumer own purl */
  3340. ruv_add_index_replica(local_ruv, supplier_id, supplier_purl, 2);
  3341. }
  3342. else
  3343. {
  3344. /* This is a consumer only, add it first */
  3345. ruv_add_index_replica(local_ruv, supplier_id, supplier_purl, 1);
  3346. }
  3347. }
  3348. else
  3349. {
  3350. /* Replace it */
  3351. ruv_replace_replica_purl(local_ruv, supplier_id, supplier_purl);
  3352. }
  3353. replica_unlock(r->repl_lock);
  3354. /* Update also the directory entry */
  3355. replica_replace_ruv_tombstone(r);
  3356. }
  3357. }
  3358. void
  3359. replica_set_ruv_dirty(Replica *r)
  3360. {
  3361. PR_ASSERT(r);
  3362. replica_lock(r->repl_lock);
  3363. r->repl_ruv_dirty = PR_TRUE;
  3364. replica_unlock(r->repl_lock);
  3365. }
  3366. PRBool
  3367. replica_is_state_flag_set(Replica *r, PRInt32 flag)
  3368. {
  3369. PR_ASSERT(r);
  3370. if (r)
  3371. return (r->repl_state_flags & flag);
  3372. else
  3373. return PR_FALSE;
  3374. }
  3375. void
  3376. replica_set_state_flag (Replica *r, PRUint32 flag, PRBool clear)
  3377. {
  3378. if (r == NULL)
  3379. return;
  3380. replica_lock(r->repl_lock);
  3381. if (clear)
  3382. {
  3383. r->repl_state_flags &= ~flag;
  3384. }
  3385. else
  3386. {
  3387. r->repl_state_flags |= flag;
  3388. }
  3389. replica_unlock(r->repl_lock);
  3390. }
  3391. /**
  3392. * Use this to tell the tombstone reap process to stop. This will
  3393. * typically be used when we (consumer) get a request to do a
  3394. * total update.
  3395. */
  3396. void
  3397. replica_set_tombstone_reap_stop(Replica *r, PRBool val)
  3398. {
  3399. if (r == NULL)
  3400. return;
  3401. replica_lock(r->repl_lock);
  3402. r->tombstone_reap_stop = val;
  3403. replica_unlock(r->repl_lock);
  3404. }
  3405. /* replica just came back online, probably after data was reloaded */
  3406. void
  3407. replica_enable_replication (Replica *r)
  3408. {
  3409. int rc;
  3410. PR_ASSERT(r);
  3411. /* prevent creation of new agreements until the replica is enabled */
  3412. PR_Lock(r->agmt_lock);
  3413. /* retrieve new ruv */
  3414. rc = replica_reload_ruv (r);
  3415. if (rc) {
  3416. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_enable_replication: "
  3417. "reloading ruv failed\n");
  3418. /* What to do ? */
  3419. }
  3420. /* Replica came back online, Check if the total update was terminated.
  3421. If flag is still set, it was not terminated, therefore the data is
  3422. very likely to be incorrect, and we should not restart Replication threads...
  3423. */
  3424. if (!replica_is_state_flag_set(r, REPLICA_TOTAL_IN_PROGRESS)){
  3425. /* restart outbound replication */
  3426. start_agreements_for_replica (r, PR_TRUE);
  3427. /* enable ruv state update */
  3428. replica_set_enabled (r, PR_TRUE);
  3429. }
  3430. /* mark the replica as being available for updates */
  3431. replica_relinquish_exclusive_access(r, 0, 0);
  3432. replica_set_state_flag(r, REPLICA_AGREEMENTS_DISABLED, PR_TRUE /* clear */);
  3433. PR_Unlock(r->agmt_lock);
  3434. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_enable_replication: "
  3435. "replica %s is relinquished\n",
  3436. slapi_sdn_get_ndn (replica_get_root (r)));
  3437. }
  3438. /* replica is about to be taken offline */
  3439. void
  3440. replica_disable_replication (Replica *r, Object *r_obj)
  3441. {
  3442. char *current_purl = NULL;
  3443. char *p_locking_purl = NULL;
  3444. char *locking_purl = NULL;
  3445. ReplicaId junkrid;
  3446. PRBool isInc = PR_FALSE; /* get exclusive access, but not for inc update */
  3447. RUV *repl_ruv = NULL;
  3448. /* prevent creation of new agreements until the replica is disabled */
  3449. PR_Lock(r->agmt_lock);
  3450. /* stop ruv update */
  3451. replica_set_enabled (r, PR_FALSE);
  3452. /* disable outbound replication */
  3453. start_agreements_for_replica (r, PR_FALSE);
  3454. /* close the corresponding changelog file */
  3455. /* close_changelog_for_replica (r_obj); */
  3456. /* mark the replica as being unavailable for updates */
  3457. /* If an incremental update is in progress, we want to wait until it is
  3458. finished until we get exclusive access to the replica, because we have
  3459. to make sure no operations are in progress - it messes up replication
  3460. when a restore is in progress but we are still adding replicated entries
  3461. from a supplier
  3462. */
  3463. repl_ruv = (RUV*) object_get_data (r->repl_ruv);
  3464. ruv_get_first_id_and_purl(repl_ruv, &junkrid, &p_locking_purl);
  3465. locking_purl = slapi_ch_strdup(p_locking_purl);
  3466. p_locking_purl = NULL;
  3467. repl_ruv = NULL;
  3468. while (!replica_get_exclusive_access(r, &isInc, 0, 0, "replica_disable_replication",
  3469. &current_purl)) {
  3470. if (!isInc) /* already locked, but not by inc update - break */
  3471. break;
  3472. isInc = PR_FALSE;
  3473. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  3474. "replica_disable_replication: "
  3475. "replica %s is already locked by (%s) for incoming "
  3476. "incremental update; sleeping 100ms\n",
  3477. slapi_sdn_get_ndn (replica_get_root (r)),
  3478. current_purl ? current_purl : "unknown");
  3479. slapi_ch_free_string(&current_purl);
  3480. DS_Sleep(PR_MillisecondsToInterval(100));
  3481. }
  3482. slapi_ch_free_string(&current_purl);
  3483. slapi_ch_free_string(&locking_purl);
  3484. replica_set_state_flag(r, REPLICA_AGREEMENTS_DISABLED, PR_FALSE);
  3485. PR_Unlock(r->agmt_lock);
  3486. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_disable_replication: "
  3487. "replica %s is acquired\n",
  3488. slapi_sdn_get_ndn (replica_get_root (r)));
  3489. }
  3490. static void
  3491. start_agreements_for_replica (Replica *r, PRBool start)
  3492. {
  3493. Object *agmt_obj;
  3494. Repl_Agmt *agmt;
  3495. agmt_obj = agmtlist_get_first_agreement_for_replica (r);
  3496. while (agmt_obj)
  3497. {
  3498. agmt = (Repl_Agmt*)object_get_data (agmt_obj);
  3499. PR_ASSERT (agmt);
  3500. if(agmt_is_enabled(agmt)){
  3501. if (start)
  3502. agmt_start (agmt);
  3503. else /* stop */
  3504. agmt_stop (agmt);
  3505. }
  3506. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  3507. }
  3508. }
  3509. int replica_start_agreement(Replica *r, Repl_Agmt *ra)
  3510. {
  3511. int ret = 0;
  3512. if (r == NULL) return -1;
  3513. PR_Lock(r->agmt_lock);
  3514. if (!replica_is_state_flag_set(r, REPLICA_AGREEMENTS_DISABLED) && agmt_is_enabled(ra)) {
  3515. ret = agmt_start(ra); /* Start the replication agreement */
  3516. }
  3517. PR_Unlock(r->agmt_lock);
  3518. return ret;
  3519. }
  3520. int windows_replica_start_agreement(Replica *r, Repl_Agmt *ra)
  3521. {
  3522. int ret = 0;
  3523. if (r == NULL) return -1;
  3524. PR_Lock(r->agmt_lock);
  3525. if (!replica_is_state_flag_set(r, REPLICA_AGREEMENTS_DISABLED)) {
  3526. ret = windows_agmt_start(ra); /* Start the replication agreement */
  3527. /* ret = windows_agmt_start(ra); Start the replication agreement */
  3528. }
  3529. PR_Unlock(r->agmt_lock);
  3530. return ret;
  3531. }
  3532. /*
  3533. * A callback function registed as op->o_csngen_handler and
  3534. * called by backend ops to generate opcsn.
  3535. */
  3536. CSN *
  3537. replica_generate_next_csn ( Slapi_PBlock *pb, const CSN *basecsn )
  3538. {
  3539. CSN *opcsn = NULL;
  3540. Object *replica_obj;
  3541. replica_obj = replica_get_replica_for_op (pb);
  3542. if (NULL != replica_obj)
  3543. {
  3544. Replica *replica = (Replica*) object_get_data (replica_obj);
  3545. if ( NULL != replica )
  3546. {
  3547. Slapi_Operation *op;
  3548. slapi_pblock_get (pb, SLAPI_OPERATION, &op);
  3549. if ( replica->repl_type != REPLICA_TYPE_READONLY ||
  3550. operation_is_flag_set (op, OP_FLAG_LEGACY_REPLICATION_DN ))
  3551. {
  3552. Object *gen_obj = replica_get_csngen (replica);
  3553. if (NULL != gen_obj)
  3554. {
  3555. CSNGen *gen = (CSNGen*) object_get_data (gen_obj);
  3556. if (NULL != gen)
  3557. {
  3558. /* The new CSN should be greater than the base CSN */
  3559. csngen_new_csn (gen, &opcsn, PR_FALSE /* don't notify */);
  3560. if (csn_compare (opcsn, basecsn) <= 0)
  3561. {
  3562. char opcsnstr[CSN_STRSIZE], basecsnstr[CSN_STRSIZE];
  3563. char opcsn2str[CSN_STRSIZE];
  3564. csn_as_string (opcsn, PR_FALSE, opcsnstr);
  3565. csn_as_string (basecsn, PR_FALSE, basecsnstr);
  3566. csn_free ( &opcsn );
  3567. csngen_adjust_time (gen, basecsn);
  3568. csngen_new_csn (gen, &opcsn, PR_FALSE /* don't notify */);
  3569. csn_as_string (opcsn, PR_FALSE, opcsn2str);
  3570. slapi_log_error (SLAPI_LOG_FATAL, NULL,
  3571. "replica_generate_next_csn: "
  3572. "opcsn=%s <= basecsn=%s, adjusted opcsn=%s\n",
  3573. opcsnstr, basecsnstr, opcsn2str);
  3574. }
  3575. /*
  3576. * Insert opcsn into the csn pending list.
  3577. * This is the notify effect in csngen_new_csn().
  3578. */
  3579. assign_csn_callback (opcsn, (void *)replica);
  3580. }
  3581. object_release (gen_obj);
  3582. }
  3583. }
  3584. }
  3585. object_release (replica_obj);
  3586. }
  3587. return opcsn;
  3588. }
  3589. /*
  3590. * A callback function registed as op->o_replica_attr_handler and
  3591. * called by backend ops to get replica attributes.
  3592. */
  3593. int
  3594. replica_get_attr ( Slapi_PBlock *pb, const char* type, void *value )
  3595. {
  3596. int rc = -1;
  3597. Object *replica_obj;
  3598. replica_obj = replica_get_replica_for_op (pb);
  3599. if (NULL != replica_obj)
  3600. {
  3601. Replica *replica = (Replica*) object_get_data (replica_obj);
  3602. if ( NULL != replica )
  3603. {
  3604. if (strcasecmp (type, type_replicaTombstonePurgeInterval) == 0)
  3605. {
  3606. *((int*)value) = replica->tombstone_reap_interval;
  3607. rc = 0;
  3608. }
  3609. else if (strcasecmp (type, type_replicaPurgeDelay) == 0)
  3610. {
  3611. *((int*)value) = replica->repl_purge_delay;
  3612. rc = 0;
  3613. }
  3614. }
  3615. object_release (replica_obj);
  3616. }
  3617. return rc;
  3618. }
  3619. PRUint64
  3620. replica_get_backoff_min(Replica *r)
  3621. {
  3622. if(r){
  3623. return slapi_counter_get_value(r->backoff_min);
  3624. } else {
  3625. return PROTOCOL_BACKOFF_MINIMUM;
  3626. }
  3627. }
  3628. PRUint64
  3629. replica_get_backoff_max(Replica *r)
  3630. {
  3631. if(r){
  3632. return slapi_counter_get_value(r->backoff_max);
  3633. } else {
  3634. return PROTOCOL_BACKOFF_MAXIMUM;
  3635. }
  3636. }
  3637. void
  3638. replica_set_backoff_min(Replica *r, PRUint64 min)
  3639. {
  3640. if(r){
  3641. slapi_counter_set_value(r->backoff_min, min);
  3642. }
  3643. }
  3644. void
  3645. replica_set_backoff_max(Replica *r, PRUint64 max)
  3646. {
  3647. if(r){
  3648. slapi_counter_set_value(r->backoff_max, max);
  3649. }
  3650. }
  3651. void
  3652. replica_set_precise_purging(Replica *r, PRUint64 on_off)
  3653. {
  3654. if(r){
  3655. slapi_counter_set_value(r->precise_purging, on_off);
  3656. }
  3657. }
  3658. PRUint64
  3659. replica_get_precise_purging(Replica *r)
  3660. {
  3661. if(r){
  3662. return slapi_counter_get_value(r->precise_purging);
  3663. } else {
  3664. return 0;
  3665. }
  3666. }
  3667. int
  3668. replica_get_agmt_count(Replica *r)
  3669. {
  3670. return r->agmt_count;
  3671. }
  3672. void
  3673. replica_incr_agmt_count(Replica *r)
  3674. {
  3675. if(r){
  3676. r->agmt_count++;
  3677. }
  3678. }
  3679. void
  3680. replica_decr_agmt_count(Replica *r)
  3681. {
  3682. if(r){
  3683. if(r->agmt_count > 0){
  3684. r->agmt_count--;
  3685. }
  3686. }
  3687. }