repl5_replica_config.c 90 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* repl5_replica_config.c - replica configuration over ldap */
  42. #include <ctype.h> /* for isdigit() */
  43. #include "repl.h" /* ONREPL - this is bad */
  44. #include "repl5.h"
  45. #include "cl5_api.h"
  46. #include "cl5.h"
  47. /* CONFIG_BASE: no need to optimize */
  48. #define CONFIG_BASE "cn=mapping tree,cn=config"
  49. #define CONFIG_FILTER "(objectclass=nsDS5Replica)"
  50. #define TASK_ATTR "nsds5Task"
  51. #define CL2LDIF_TASK "CL2LDIF"
  52. #define LDIF2CL_TASK "LDIF2CL"
  53. #define CLEANRUV "CLEANRUV"
  54. #define CLEANRUVLEN 8
  55. #define CLEANALLRUV "CLEANALLRUV"
  56. #define CLEANALLRUVLEN 11
  57. #define REPLICA_RDN "cn=replica"
  58. #define CLEANALLRUV_ID "CleanAllRUV Task"
  59. #define ABORT_CLEANALLRUV_ID "Abort CleanAllRUV Task"
  60. int slapi_log_urp = SLAPI_LOG_REPL;
  61. static ReplicaId cleaned_rids[CLEANRIDSIZ + 1] = {0};
  62. static ReplicaId aborted_rids[CLEANRIDSIZ + 1] = {0};
  63. static Slapi_RWLock *rid_lock = NULL;
  64. static Slapi_RWLock *abort_rid_lock = NULL;
  65. static PRLock *notify_lock = NULL;
  66. static PRCondVar *notify_cvar = NULL;
  67. /* Forward Declartions */
  68. static int replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  69. static int replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  70. static int replica_config_post_modify (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  71. static int replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  72. static int replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  73. static int replica_cleanall_ruv_task(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg);
  74. static int replica_config_change_type_and_id (Replica *r, const char *new_type, const char *new_id, char *returntext, int apply_mods);
  75. static int replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char *returntext, int apply_mods);
  76. static int replica_config_change_flags (Replica *r, const char *new_flags, char *returntext, int apply_mods);
  77. static int replica_execute_task (Object *r, const char *task_name, char *returntext, int apply_mods);
  78. static int replica_execute_cl2ldif_task (Object *r, char *returntext);
  79. static int replica_execute_ldif2cl_task (Object *r, char *returntext);
  80. static int replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext);
  81. static int replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, char *returntext);
  82. static void replica_cleanallruv_thread(void *arg);
  83. static void replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task);
  84. static int check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task);
  85. static int check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_Task *task);
  86. static int replica_cleanallruv_send_extop(Repl_Agmt *ra, ReplicaId rid, Slapi_Task *task, struct berval *payload, int check_result);
  87. static int replica_cleanallruv_send_abort_extop(Repl_Agmt *ra, Slapi_Task *task, struct berval *payload);
  88. static int replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *rid_text, char *maxcsn, Slapi_Task *task);
  89. static int replica_cleanallruv_replica_alive(Repl_Agmt *agmt);
  90. static int replica_cleanallruv_check_ruv(Repl_Agmt *ra, char *rid_text, Slapi_Task *task);
  91. static int get_cleanruv_task_count();
  92. static int get_abort_cleanruv_task_count();
  93. static int replica_cleanup_task (Object *r, const char *task_name, char *returntext, int apply_mods);
  94. static int replica_task_done(Replica *replica);
  95. static multimaster_mtnode_extension * _replica_config_get_mtnode_ext (const Slapi_Entry *e);
  96. /*
  97. * Note: internal add/modify/delete operations should not be run while
  98. * s_configLock is held. E.g., slapi_modify_internal_pb via replica_task_done
  99. * in replica_config_post_modify.
  100. */
  101. static PRLock *s_configLock;
  102. static int
  103. dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
  104. {
  105. *returncode = LDAP_UNWILLING_TO_PERFORM;
  106. return SLAPI_DSE_CALLBACK_ERROR;
  107. }
  108. int
  109. replica_config_init()
  110. {
  111. s_configLock = PR_NewLock ();
  112. if (s_configLock == NULL)
  113. {
  114. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
  115. "failed to create configuration lock; NSPR error - %d\n",
  116. PR_GetError ());
  117. return -1;
  118. }
  119. rid_lock = slapi_new_rwlock();
  120. if(rid_lock == NULL)
  121. {
  122. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
  123. "failed to create rid_lock; NSPR error - %d\n", PR_GetError ());
  124. return -1;
  125. }
  126. abort_rid_lock = slapi_new_rwlock();
  127. if(abort_rid_lock == NULL)
  128. {
  129. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
  130. "failed to create abort_rid_lock; NSPR error - %d\n", PR_GetError ());
  131. return -1;
  132. }
  133. if ( ( notify_lock = PR_NewLock()) == NULL ) {
  134. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
  135. "failed to create notify lock; NSPR error - %d\n", PR_GetError ());
  136. return -1;
  137. }
  138. if ( ( notify_cvar = PR_NewCondVar( notify_lock )) == NULL ) {
  139. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
  140. "failed to create notify cond var; NSPR error - %d\n", PR_GetError ());
  141. return -1;
  142. }
  143. /* config DSE must be initialized before we get here */
  144. slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  145. CONFIG_FILTER, replica_config_add, NULL);
  146. slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  147. CONFIG_FILTER, replica_config_modify,NULL);
  148. slapi_config_register_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  149. CONFIG_FILTER, dont_allow_that, NULL);
  150. slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  151. CONFIG_FILTER, replica_config_delete,NULL);
  152. slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  153. CONFIG_FILTER, replica_config_search,NULL);
  154. slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP,
  155. CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  156. CONFIG_FILTER, replica_config_post_modify,
  157. NULL);
  158. /* register the CLEANALLRUV & ABORT task */
  159. slapi_task_register_handler("cleanallruv", replica_cleanall_ruv_task);
  160. slapi_task_register_handler("abort cleanallruv", replica_cleanall_ruv_abort);
  161. return 0;
  162. }
  163. void
  164. replica_config_destroy ()
  165. {
  166. if (s_configLock)
  167. {
  168. PR_DestroyLock (s_configLock);
  169. s_configLock = NULL;
  170. }
  171. /* config DSE must be initialized before we get here */
  172. slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  173. CONFIG_FILTER, replica_config_add);
  174. slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  175. CONFIG_FILTER, replica_config_modify);
  176. slapi_config_remove_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  177. CONFIG_FILTER, dont_allow_that);
  178. slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  179. CONFIG_FILTER, replica_config_delete);
  180. slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  181. CONFIG_FILTER, replica_config_search);
  182. slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP,
  183. CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  184. CONFIG_FILTER, replica_config_post_modify);
  185. }
  186. static int
  187. replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
  188. int *returncode, char *errorbuf, void *arg)
  189. {
  190. Replica *r = NULL;
  191. multimaster_mtnode_extension *mtnode_ext;
  192. char *replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
  193. char buf [SLAPI_DSE_RETURNTEXT_SIZE];
  194. char *errortext = errorbuf ? errorbuf : buf;
  195. if (errorbuf)
  196. {
  197. errorbuf[0] = '\0';
  198. }
  199. *returncode = LDAP_SUCCESS;
  200. PR_Lock (s_configLock);
  201. /* add the dn to the dn hash so we can tell this replica is being configured */
  202. replica_add_by_dn(replica_root);
  203. mtnode_ext = _replica_config_get_mtnode_ext (e);
  204. PR_ASSERT (mtnode_ext);
  205. if (mtnode_ext->replica)
  206. {
  207. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "replica already configured for %s", replica_root);
  208. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: %s\n", errortext);
  209. *returncode = LDAP_UNWILLING_TO_PERFORM;
  210. goto done;
  211. }
  212. /* create replica object */
  213. r = replica_new_from_entry (e, errortext, PR_TRUE /* is a newly added entry */);
  214. if (r == NULL)
  215. {
  216. *returncode = LDAP_OPERATIONS_ERROR;
  217. goto done;
  218. }
  219. /* Set the mapping tree node state, and the referrals from the RUV */
  220. /* if this server is a 4.0 consumer the referrals are set by legacy plugin */
  221. if (!replica_is_legacy_consumer (r))
  222. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  223. /* ONREPL if replica is added as writable we need to execute protocol that
  224. introduces new writable replica to the topology */
  225. mtnode_ext->replica = object_new (r, replica_destroy); /* Refcnt is 1 */
  226. /* add replica object to the hash */
  227. *returncode = replica_add_by_name (replica_get_name (r), mtnode_ext->replica); /* Increments object refcnt */
  228. /* delete the dn from the dn hash - done with configuration */
  229. replica_delete_by_dn(replica_root);
  230. done:
  231. PR_Unlock (s_configLock);
  232. /* slapi_ch_free accepts NULL pointer */
  233. slapi_ch_free ((void**)&replica_root);
  234. if (*returncode != LDAP_SUCCESS)
  235. {
  236. if (mtnode_ext->replica)
  237. object_release (mtnode_ext->replica);
  238. return SLAPI_DSE_CALLBACK_ERROR;
  239. }
  240. else
  241. return SLAPI_DSE_CALLBACK_OK;
  242. }
  243. static int
  244. replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
  245. int *returncode, char *returntext, void *arg)
  246. {
  247. int rc= 0;
  248. LDAPMod **mods;
  249. int i, apply_mods;
  250. multimaster_mtnode_extension *mtnode_ext;
  251. Replica *r = NULL;
  252. char *replica_root = NULL;
  253. char buf [SLAPI_DSE_RETURNTEXT_SIZE];
  254. char *errortext = returntext ? returntext : buf;
  255. char *config_attr, *config_attr_value;
  256. Slapi_Operation *op;
  257. void *identity;
  258. if (returntext)
  259. {
  260. returntext[0] = '\0';
  261. }
  262. *returncode = LDAP_SUCCESS;
  263. /* just let internal operations originated from replication plugin to go through */
  264. slapi_pblock_get (pb, SLAPI_OPERATION, &op);
  265. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
  266. if (operation_is_flag_set(op, OP_FLAG_INTERNAL) &&
  267. (identity == repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)))
  268. {
  269. *returncode = LDAP_SUCCESS;
  270. return SLAPI_DSE_CALLBACK_OK;
  271. }
  272. replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
  273. PR_Lock (s_configLock);
  274. mtnode_ext = _replica_config_get_mtnode_ext (e);
  275. PR_ASSERT (mtnode_ext);
  276. if (mtnode_ext->replica)
  277. object_acquire (mtnode_ext->replica);
  278. if (mtnode_ext->replica == NULL)
  279. {
  280. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "replica does not exist for %s", replica_root);
  281. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
  282. errortext);
  283. *returncode = LDAP_OPERATIONS_ERROR;
  284. goto done;
  285. }
  286. r = object_get_data (mtnode_ext->replica);
  287. PR_ASSERT (r);
  288. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  289. for (apply_mods = 0; apply_mods <= 1; apply_mods++)
  290. {
  291. /* we only allow the replica ID and type to be modified together e.g.
  292. if converting a read only replica to a master or vice versa -
  293. we will need to change both the replica ID and the type at the same
  294. time - we must disallow changing the replica ID if the type is not
  295. being changed and vice versa
  296. */
  297. char *new_repl_id = NULL;
  298. char *new_repl_type = NULL;
  299. if (*returncode != LDAP_SUCCESS)
  300. break;
  301. for (i = 0; (mods[i] && (LDAP_SUCCESS == rc)); i++)
  302. {
  303. if (*returncode != LDAP_SUCCESS)
  304. break;
  305. config_attr = (char *) mods[i]->mod_type;
  306. PR_ASSERT (config_attr);
  307. /* disallow modifications or removal of replica root,
  308. replica name and replica state attributes */
  309. if (strcasecmp (config_attr, attr_replicaRoot) == 0 ||
  310. strcasecmp (config_attr, attr_replicaName) == 0 ||
  311. strcasecmp (config_attr, attr_state) == 0)
  312. {
  313. *returncode = LDAP_UNWILLING_TO_PERFORM;
  314. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "modification of %s attribute is not allowed",
  315. config_attr);
  316. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
  317. errortext);
  318. }
  319. /* this is a request to delete an attribute */
  320. else if ((mods[i]->mod_op & LDAP_MOD_DELETE) || mods[i]->mod_bvalues == NULL
  321. || mods[i]->mod_bvalues[0]->bv_val == NULL)
  322. {
  323. /* currently, you can only remove referral,
  324. legacy consumer or bind dn attribute */
  325. if (strcasecmp (config_attr, attr_replicaBindDn) == 0)
  326. {
  327. *returncode = replica_config_change_updatedn (r, mods[i], errortext, apply_mods);
  328. }
  329. else if (strcasecmp (config_attr, attr_replicaReferral) == 0)
  330. {
  331. if (apply_mods) {
  332. replica_set_referrals(r, NULL);
  333. if (!replica_is_legacy_consumer (r)) {
  334. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  335. }
  336. }
  337. }
  338. else if (strcasecmp (config_attr, type_replicaLegacyConsumer) == 0)
  339. {
  340. if (apply_mods)
  341. replica_set_legacy_consumer (r, PR_FALSE);
  342. }
  343. else
  344. {
  345. *returncode = LDAP_UNWILLING_TO_PERFORM;
  346. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "deletion of %s attribute is not allowed", config_attr);
  347. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n", errortext);
  348. }
  349. }
  350. else /* modify an attribute */
  351. {
  352. config_attr_value = (char *) mods[i]->mod_bvalues[0]->bv_val;
  353. if (strcasecmp (config_attr, attr_replicaBindDn) == 0)
  354. {
  355. *returncode = replica_config_change_updatedn (r, mods[i], errortext, apply_mods);
  356. }
  357. else if (strcasecmp (config_attr, attr_replicaType) == 0)
  358. {
  359. new_repl_type = slapi_ch_strdup(config_attr_value);
  360. }
  361. else if (strcasecmp (config_attr, attr_replicaId) == 0)
  362. {
  363. new_repl_id = slapi_ch_strdup(config_attr_value);
  364. }
  365. else if (strcasecmp (config_attr, attr_flags) == 0)
  366. {
  367. *returncode = replica_config_change_flags (r, config_attr_value, errortext, apply_mods);
  368. }
  369. else if (strcasecmp (config_attr, TASK_ATTR) == 0)
  370. {
  371. *returncode = replica_execute_task (mtnode_ext->replica, config_attr_value, errortext, apply_mods);
  372. }
  373. else if (strcasecmp (config_attr, attr_replicaReferral) == 0)
  374. {
  375. if (apply_mods)
  376. {
  377. Slapi_Mod smod;
  378. Slapi_ValueSet *vs= slapi_valueset_new();
  379. slapi_mod_init_byref(&smod,mods[i]);
  380. slapi_valueset_set_from_smod(vs, &smod);
  381. replica_set_referrals (r, vs);
  382. slapi_mod_done(&smod);
  383. slapi_valueset_free(vs);
  384. if (!replica_is_legacy_consumer (r)) {
  385. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  386. }
  387. }
  388. }
  389. else if (strcasecmp (config_attr, type_replicaPurgeDelay) == 0)
  390. {
  391. if (apply_mods && config_attr_value && config_attr_value[0])
  392. {
  393. PRUint32 delay;
  394. if (isdigit (config_attr_value[0]))
  395. {
  396. delay = (unsigned int)atoi(config_attr_value);
  397. replica_set_purge_delay(r, delay);
  398. }
  399. else
  400. *returncode = LDAP_OPERATIONS_ERROR;
  401. }
  402. }
  403. else if (strcasecmp (config_attr, type_replicaTombstonePurgeInterval) == 0)
  404. {
  405. if (apply_mods && config_attr_value && config_attr_value[0])
  406. {
  407. long interval;
  408. interval = atol (config_attr_value);
  409. replica_set_tombstone_reap_interval (r, interval);
  410. }
  411. }
  412. else if (strcasecmp (config_attr, type_replicaLegacyConsumer) == 0)
  413. {
  414. if (apply_mods)
  415. {
  416. PRBool legacy = (strcasecmp (config_attr_value, "on") == 0) ||
  417. (strcasecmp (config_attr_value, "true") == 0) ||
  418. (strcasecmp (config_attr_value, "yes") == 0) ||
  419. (strcasecmp (config_attr_value, "1") == 0);
  420. replica_set_legacy_consumer (r, legacy);
  421. }
  422. }
  423. /* ignore modifiers attributes added by the server */
  424. else if (strcasecmp (config_attr, "modifytimestamp") == 0 ||
  425. strcasecmp (config_attr, "modifiersname") == 0)
  426. {
  427. *returncode = LDAP_SUCCESS;
  428. }
  429. else
  430. {
  431. *returncode = LDAP_UNWILLING_TO_PERFORM;
  432. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
  433. "modification of attribute %s is not allowed in replica entry", config_attr);
  434. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n", errortext);
  435. }
  436. }
  437. }
  438. if (new_repl_id || new_repl_type)
  439. {
  440. *returncode = replica_config_change_type_and_id(r, new_repl_type, new_repl_id, errortext, apply_mods);
  441. slapi_ch_free_string(&new_repl_id);
  442. slapi_ch_free_string(&new_repl_type);
  443. }
  444. }
  445. done:
  446. if (mtnode_ext->replica)
  447. object_release (mtnode_ext->replica);
  448. /* slapi_ch_free accepts NULL pointer */
  449. slapi_ch_free_string(&replica_root);
  450. PR_Unlock (s_configLock);
  451. if (*returncode != LDAP_SUCCESS)
  452. {
  453. return SLAPI_DSE_CALLBACK_ERROR;
  454. }
  455. else
  456. {
  457. return SLAPI_DSE_CALLBACK_OK;
  458. }
  459. }
  460. static int
  461. replica_config_post_modify(Slapi_PBlock *pb,
  462. Slapi_Entry* entryBefore,
  463. Slapi_Entry* e,
  464. int *returncode,
  465. char *returntext,
  466. void *arg)
  467. {
  468. int rc= 0;
  469. LDAPMod **mods;
  470. int i, apply_mods;
  471. multimaster_mtnode_extension *mtnode_ext;
  472. Replica *r = NULL;
  473. char *replica_root = NULL;
  474. char buf [SLAPI_DSE_RETURNTEXT_SIZE];
  475. char *errortext = returntext ? returntext : buf;
  476. char *config_attr, *config_attr_value;
  477. Slapi_Operation *op;
  478. void *identity;
  479. int flag_need_cleanup = 0;
  480. if (returntext)
  481. {
  482. returntext[0] = '\0';
  483. }
  484. *returncode = LDAP_SUCCESS;
  485. /* just let internal operations originated from replication plugin to go through */
  486. slapi_pblock_get (pb, SLAPI_OPERATION, &op);
  487. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
  488. if (operation_is_flag_set(op, OP_FLAG_INTERNAL) &&
  489. (identity == repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)))
  490. {
  491. *returncode = LDAP_SUCCESS;
  492. return SLAPI_DSE_CALLBACK_OK;
  493. }
  494. replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
  495. PR_Lock (s_configLock);
  496. mtnode_ext = _replica_config_get_mtnode_ext (e);
  497. PR_ASSERT (mtnode_ext);
  498. if (mtnode_ext->replica)
  499. object_acquire (mtnode_ext->replica);
  500. if (mtnode_ext->replica == NULL)
  501. {
  502. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
  503. "replica does not exist for %s", replica_root);
  504. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  505. "replica_config_post_modify: %s\n",
  506. errortext);
  507. *returncode = LDAP_OPERATIONS_ERROR;
  508. goto done;
  509. }
  510. r = object_get_data (mtnode_ext->replica);
  511. PR_ASSERT (r);
  512. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  513. for (apply_mods = 0; apply_mods <= 1; apply_mods++)
  514. {
  515. /* we only allow the replica ID and type to be modified together e.g.
  516. if converting a read only replica to a master or vice versa -
  517. we will need to change both the replica ID and the type at the same
  518. time - we must disallow changing the replica ID if the type is not
  519. being changed and vice versa
  520. */
  521. if (*returncode != LDAP_SUCCESS)
  522. break;
  523. for (i = 0; (mods[i] && (LDAP_SUCCESS == rc)); i++)
  524. {
  525. if (*returncode != LDAP_SUCCESS)
  526. break;
  527. config_attr = (char *) mods[i]->mod_type;
  528. PR_ASSERT (config_attr);
  529. /* disallow modifications or removal of replica root,
  530. replica name and replica state attributes */
  531. if (strcasecmp (config_attr, attr_replicaRoot) == 0 ||
  532. strcasecmp (config_attr, attr_replicaName) == 0 ||
  533. strcasecmp (config_attr, attr_state) == 0)
  534. {
  535. *returncode = LDAP_UNWILLING_TO_PERFORM;
  536. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
  537. "modification of %s attribute is not allowed",
  538. config_attr);
  539. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  540. "replica_config_post_modify: %s\n",
  541. errortext);
  542. }
  543. /* this is a request to delete an attribute */
  544. else if ((mods[i]->mod_op & LDAP_MOD_DELETE) ||
  545. mods[i]->mod_bvalues == NULL ||
  546. mods[i]->mod_bvalues[0]->bv_val == NULL)
  547. {
  548. ;
  549. }
  550. else /* modify an attribute */
  551. {
  552. config_attr_value = (char *) mods[i]->mod_bvalues[0]->bv_val;
  553. if (strcasecmp (config_attr, TASK_ATTR) == 0)
  554. {
  555. flag_need_cleanup = 1;
  556. }
  557. }
  558. }
  559. }
  560. done:
  561. PR_Unlock (s_configLock);
  562. /* slapi_ch_free accepts NULL pointer */
  563. slapi_ch_free_string (&replica_root);
  564. /* Call replica_cleanup_task after s_configLock is reliesed */
  565. if (flag_need_cleanup)
  566. {
  567. *returncode = replica_cleanup_task(mtnode_ext->replica,
  568. config_attr_value,
  569. errortext, apply_mods);
  570. }
  571. if (mtnode_ext->replica)
  572. object_release (mtnode_ext->replica);
  573. if (*returncode != LDAP_SUCCESS)
  574. {
  575. return SLAPI_DSE_CALLBACK_ERROR;
  576. }
  577. else
  578. {
  579. return SLAPI_DSE_CALLBACK_OK;
  580. }
  581. }
  582. static int
  583. replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
  584. int *returncode, char *returntext, void *arg)
  585. {
  586. multimaster_mtnode_extension *mtnode_ext;
  587. Replica *r;
  588. PR_Lock (s_configLock);
  589. mtnode_ext = _replica_config_get_mtnode_ext (e);
  590. PR_ASSERT (mtnode_ext);
  591. if (mtnode_ext->replica)
  592. {
  593. /* remove object from the hash */
  594. r = (Replica*)object_get_data (mtnode_ext->replica);
  595. PR_ASSERT (r);
  596. /* The changelog for this replica is no longer valid, so we should remove it. */
  597. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_delete: "
  598. "Warning: The changelog for replica %s is no longer valid since "
  599. "the replica config is being deleted. Removing the changelog.\n",
  600. slapi_sdn_get_dn(replica_get_root(r)));
  601. cl5DeleteDBSync(mtnode_ext->replica);
  602. replica_delete_by_name (replica_get_name (r));
  603. object_release (mtnode_ext->replica);
  604. mtnode_ext->replica = NULL;
  605. }
  606. PR_Unlock (s_configLock);
  607. *returncode = LDAP_SUCCESS;
  608. return SLAPI_DSE_CALLBACK_OK;
  609. }
  610. static int
  611. replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode,
  612. char *returntext, void *arg)
  613. {
  614. multimaster_mtnode_extension *mtnode_ext;
  615. int changeCount = 0;
  616. PRBool reapActive = PR_FALSE;
  617. char val [64];
  618. /* add attribute that contains number of entries in the changelog for this replica */
  619. PR_Lock (s_configLock);
  620. mtnode_ext = _replica_config_get_mtnode_ext (e);
  621. PR_ASSERT (mtnode_ext);
  622. if (mtnode_ext->replica) {
  623. Replica *replica;
  624. object_acquire (mtnode_ext->replica);
  625. if (cl5GetState () == CL5_STATE_OPEN) {
  626. changeCount = cl5GetOperationCount (mtnode_ext->replica);
  627. }
  628. replica = (Replica*)object_get_data (mtnode_ext->replica);
  629. if (replica) {
  630. reapActive = replica_get_tombstone_reap_active(replica);
  631. }
  632. object_release (mtnode_ext->replica);
  633. }
  634. sprintf (val, "%d", changeCount);
  635. slapi_entry_add_string (e, type_replicaChangeCount, val);
  636. slapi_entry_attr_set_int(e, "nsds5replicaReapActive", (int)reapActive);
  637. PR_Unlock (s_configLock);
  638. return SLAPI_DSE_CALLBACK_OK;
  639. }
  640. static int
  641. replica_config_change_type_and_id (Replica *r, const char *new_type,
  642. const char *new_id, char *returntext,
  643. int apply_mods)
  644. {
  645. int type;
  646. ReplicaType oldtype;
  647. ReplicaId rid;
  648. ReplicaId oldrid;
  649. PR_ASSERT (r);
  650. oldtype = replica_get_type(r);
  651. oldrid = replica_get_rid(r);
  652. if (new_type == NULL) /* by default - replica is read-only */
  653. {
  654. type = REPLICA_TYPE_READONLY;
  655. }
  656. else
  657. {
  658. type = atoi (new_type);
  659. if (type <= REPLICA_TYPE_UNKNOWN || type >= REPLICA_TYPE_END)
  660. {
  661. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "invalid replica type %d", type);
  662. return LDAP_OPERATIONS_ERROR;
  663. }
  664. }
  665. /* disallow changing type to itself just to permit a replica ID change */
  666. if (oldtype == type)
  667. {
  668. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "replica type is already %d - not changing", type);
  669. return LDAP_OPERATIONS_ERROR;
  670. }
  671. if (type == REPLICA_TYPE_READONLY)
  672. {
  673. rid = READ_ONLY_REPLICA_ID; /* default rid for read only */
  674. }
  675. else if (!new_id)
  676. {
  677. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "a replica ID is required when changing replica type to read-write");
  678. return LDAP_UNWILLING_TO_PERFORM;
  679. }
  680. else
  681. {
  682. int temprid = atoi (new_id);
  683. if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID)
  684. {
  685. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  686. "attribute %s must have a value greater than 0 "
  687. "and less than %d",
  688. attr_replicaId, READ_ONLY_REPLICA_ID);
  689. return LDAP_UNWILLING_TO_PERFORM;
  690. }
  691. else
  692. {
  693. rid = (ReplicaId)temprid;
  694. }
  695. }
  696. /* error if old rid == new rid */
  697. if (oldrid == rid)
  698. {
  699. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "replica ID is already %d - not changing", rid);
  700. return LDAP_OPERATIONS_ERROR;
  701. }
  702. if (apply_mods)
  703. {
  704. replica_set_type (r, type);
  705. replica_set_rid(r, rid);
  706. /* Set the mapping tree node, and the list of referrals */
  707. /* if this server is a 4.0 consumer the referrals are set by legacy plugin */
  708. if (!replica_is_legacy_consumer(r))
  709. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  710. }
  711. return LDAP_SUCCESS;
  712. }
  713. static int
  714. replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char *returntext,
  715. int apply_mods)
  716. {
  717. PR_ASSERT (r);
  718. if (apply_mods)
  719. {
  720. Slapi_Mod smod;
  721. Slapi_ValueSet *vs= slapi_valueset_new();
  722. slapi_mod_init_byref(&smod, (LDAPMod *)mod); /* cast away const */
  723. slapi_valueset_set_from_smod(vs, &smod);
  724. replica_set_updatedn(r, vs, mod->mod_op);
  725. slapi_mod_done(&smod);
  726. slapi_valueset_free(vs);
  727. }
  728. return LDAP_SUCCESS;
  729. }
  730. static int replica_config_change_flags (Replica *r, const char *new_flags,
  731. char *returntext, int apply_mods)
  732. {
  733. PR_ASSERT (r);
  734. if (apply_mods)
  735. {
  736. PRUint32 flags;
  737. flags = atol (new_flags);
  738. replica_replace_flags (r, flags);
  739. }
  740. return LDAP_SUCCESS;
  741. }
  742. static int replica_execute_task (Object *r, const char *task_name, char *returntext,
  743. int apply_mods)
  744. {
  745. if (strcasecmp (task_name, CL2LDIF_TASK) == 0)
  746. {
  747. if (apply_mods)
  748. {
  749. return replica_execute_cl2ldif_task (r, returntext);
  750. }
  751. else
  752. return LDAP_SUCCESS;
  753. }
  754. else if (strcasecmp (task_name, LDIF2CL_TASK) == 0)
  755. {
  756. if (apply_mods)
  757. {
  758. return replica_execute_ldif2cl_task (r, returntext);
  759. }
  760. else
  761. return LDAP_SUCCESS;
  762. }
  763. else if (strncasecmp (task_name, CLEANRUV, CLEANRUVLEN) == 0)
  764. {
  765. int temprid = atoi(&(task_name[CLEANRUVLEN]));
  766. if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID){
  767. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid replica id (%d) for task - %s", temprid, task_name);
  768. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_execute_task: %s\n", returntext);
  769. return LDAP_OPERATIONS_ERROR;
  770. }
  771. if (apply_mods)
  772. {
  773. return replica_execute_cleanruv_task (r, (ReplicaId)temprid, returntext);
  774. }
  775. else
  776. return LDAP_SUCCESS;
  777. }
  778. else if (strncasecmp (task_name, CLEANALLRUV, CLEANALLRUVLEN) == 0)
  779. {
  780. int temprid = atoi(&(task_name[CLEANALLRUVLEN]));
  781. if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID){
  782. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid replica id (%d) for task - (%s)", temprid, task_name);
  783. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_execute_task: %s\n", returntext);
  784. return LDAP_OPERATIONS_ERROR;
  785. }
  786. if (apply_mods)
  787. {
  788. Slapi_Task *empty_task = NULL;
  789. return replica_execute_cleanall_ruv_task(r, (ReplicaId)temprid, empty_task, returntext);
  790. }
  791. else
  792. return LDAP_SUCCESS;
  793. }
  794. else
  795. {
  796. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "unsupported replica task - %s", task_name);
  797. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  798. "replica_execute_task: %s\n", returntext);
  799. return LDAP_OPERATIONS_ERROR;
  800. }
  801. }
  802. static int
  803. replica_cleanup_task (Object *r, const char *task_name, char *returntext,
  804. int apply_mods)
  805. {
  806. int rc = LDAP_SUCCESS;
  807. if (apply_mods) {
  808. Replica *replica = (Replica*)object_get_data (r);
  809. if (NULL == replica) {
  810. rc = LDAP_OPERATIONS_ERROR;
  811. } else {
  812. rc = replica_task_done(replica);
  813. }
  814. }
  815. return rc;
  816. }
  817. static int
  818. replica_task_done(Replica *replica)
  819. {
  820. int rc = LDAP_OPERATIONS_ERROR;
  821. char *replica_dn = NULL;
  822. Slapi_DN *replica_sdn = NULL;
  823. Slapi_PBlock *pb = NULL;
  824. LDAPMod *mods [2];
  825. LDAPMod mod;
  826. if (NULL == replica) {
  827. return rc;
  828. }
  829. /* dn: cn=replica,cn=dc\3Dexample\2Cdc\3Dcom,cn=mapping tree,cn=config */
  830. replica_dn = slapi_ch_smprintf("%s,cn=\"%s\",%s",
  831. REPLICA_RDN,
  832. slapi_sdn_get_dn(replica_get_root(replica)),
  833. CONFIG_BASE);
  834. if (NULL == replica_dn) {
  835. return rc;
  836. }
  837. replica_sdn = slapi_sdn_new_dn_passin(replica_dn);
  838. pb = slapi_pblock_new();
  839. mods[0] = &mod;
  840. mods[1] = NULL;
  841. mod.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
  842. mod.mod_type = (char *)TASK_ATTR;
  843. mod.mod_bvalues = NULL;
  844. slapi_modify_internal_set_pb_ext(pb, replica_sdn, mods, NULL/* controls */,
  845. NULL/* uniqueid */,
  846. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
  847. 0/* flags */);
  848. slapi_modify_internal_pb (pb);
  849. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  850. if ((rc != LDAP_SUCCESS) && (rc != LDAP_NO_SUCH_ATTRIBUTE)) {
  851. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  852. "replica_task_done: "
  853. "failed to remove (%s) attribute from (%s) entry; "
  854. "LDAP error - %d\n",
  855. TASK_ATTR, replica_dn, rc);
  856. }
  857. slapi_pblock_destroy (pb);
  858. slapi_sdn_free(&replica_sdn);
  859. return rc;
  860. }
  861. static int replica_execute_cl2ldif_task (Object *r, char *returntext)
  862. {
  863. int rc;
  864. Object *rlist [2];
  865. Replica *replica;
  866. char fName [MAXPATHLEN];
  867. char *clDir = NULL;
  868. if (cl5GetState () != CL5_STATE_OPEN)
  869. {
  870. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "changelog is not open");
  871. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  872. "replica_execute_cl2ldif_task: %s\n", returntext);
  873. rc = LDAP_OPERATIONS_ERROR;
  874. goto bail;
  875. }
  876. rlist[0] = r;
  877. rlist[1] = NULL;
  878. /* file is stored in the changelog directory and is named
  879. <replica name>.ldif */
  880. clDir = cl5GetDir ();
  881. if (NULL == clDir) {
  882. rc = LDAP_OPERATIONS_ERROR;
  883. goto bail;
  884. }
  885. replica = (Replica*)object_get_data (r);
  886. if (NULL == replica) {
  887. rc = LDAP_OPERATIONS_ERROR;
  888. goto bail;
  889. }
  890. PR_snprintf (fName, MAXPATHLEN, "%s/%s.ldif", clDir, replica_get_name (replica));
  891. slapi_ch_free_string (&clDir);
  892. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  893. "Beginning changelog export of replica \"%s\"\n",
  894. replica_get_name(replica));
  895. rc = cl5ExportLDIF (fName, rlist);
  896. if (rc == CL5_SUCCESS) {
  897. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  898. "Finished changelog export of replica \"%s\"\n",
  899. replica_get_name(replica));
  900. rc = LDAP_SUCCESS;
  901. } else {
  902. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  903. "Failed changelog export replica %s; "
  904. "changelog error - %d", replica_get_name(replica), rc);
  905. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  906. "replica_execute_cl2ldif_task: %s\n", returntext);
  907. rc = LDAP_OPERATIONS_ERROR;
  908. }
  909. bail:
  910. return rc;
  911. }
  912. static int replica_execute_ldif2cl_task (Object *r, char *returntext)
  913. {
  914. int rc, imprc = 0;
  915. Object *rlist [2];
  916. Replica *replica;
  917. char fName [MAXPATHLEN];
  918. char *clDir = NULL;
  919. changelog5Config config;
  920. if (cl5GetState () != CL5_STATE_OPEN)
  921. {
  922. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "changelog is not open");
  923. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  924. "replica_execute_ldif2cl_task: %s\n", returntext);
  925. rc = LDAP_OPERATIONS_ERROR;
  926. goto bail;
  927. }
  928. rlist[0] = r;
  929. rlist[1] = NULL;
  930. /* file is stored in the changelog directory and is named
  931. <replica name>.ldif */
  932. clDir = cl5GetDir ();
  933. if (NULL == clDir) {
  934. rc = LDAP_OPERATIONS_ERROR;
  935. goto bail;
  936. }
  937. replica = (Replica*)object_get_data (r);
  938. if (NULL == replica) {
  939. rc = LDAP_OPERATIONS_ERROR;
  940. goto bail;
  941. }
  942. PR_snprintf (fName, MAXPATHLEN, "%s/%s.ldif", clDir, replica_get_name (replica));
  943. rc = cl5Close();
  944. if (rc != CL5_SUCCESS)
  945. {
  946. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  947. "failed to close changelog to import changelog data; "
  948. "changelog error - %d", rc);
  949. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  950. "replica_execute_ldif2cl_task: %s\n", returntext);
  951. rc = LDAP_OPERATIONS_ERROR;
  952. goto bail;
  953. }
  954. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  955. "Beginning changelog import of replica \"%s\"\n",
  956. replica_get_name(replica));
  957. imprc = cl5ImportLDIF (clDir, fName, rlist);
  958. slapi_ch_free_string (&clDir);
  959. if (CL5_SUCCESS == imprc)
  960. {
  961. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  962. "Finished changelog import of replica \"%s\"\n",
  963. replica_get_name(replica));
  964. }
  965. else
  966. {
  967. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  968. "Failed changelog import replica %s; "
  969. "changelog error - %d", replica_get_name(replica), rc);
  970. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  971. "replica_execute_ldif2cl_task: %s\n", returntext);
  972. imprc = LDAP_OPERATIONS_ERROR;
  973. }
  974. changelog5_read_config (&config);
  975. /* restart changelog */
  976. rc = cl5Open (config.dir, &config.dbconfig);
  977. if (CL5_SUCCESS == rc)
  978. {
  979. rc = LDAP_SUCCESS;
  980. }
  981. else
  982. {
  983. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  984. "replica_execute_ldif2cl_task: failed to start changelog at %s\n",
  985. config.dir?config.dir:"null config dir");
  986. rc = LDAP_OPERATIONS_ERROR;
  987. }
  988. bail:
  989. changelog5_config_done(&config);
  990. /* if cl5ImportLDIF returned an error, report it first. */
  991. return imprc?imprc:rc;
  992. }
  993. static multimaster_mtnode_extension *
  994. _replica_config_get_mtnode_ext (const Slapi_Entry *e)
  995. {
  996. const char *replica_root;
  997. Slapi_DN *sdn = NULL;
  998. mapping_tree_node *mtnode;
  999. multimaster_mtnode_extension *ext = NULL;
  1000. /* retirve root of the tree for which replica is configured */
  1001. replica_root = slapi_entry_attr_get_charptr (e, attr_replicaRoot);
  1002. if (replica_root == NULL)
  1003. {
  1004. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: "
  1005. "configuration entry %s missing %s attribute\n",
  1006. slapi_entry_get_dn((Slapi_Entry *)e),
  1007. attr_replicaRoot);
  1008. return NULL;
  1009. }
  1010. sdn = slapi_sdn_new_dn_passin (replica_root);
  1011. /* locate mapping tree node for the specified subtree */
  1012. mtnode = slapi_get_mapping_tree_node_by_dn (sdn);
  1013. if (mtnode == NULL)
  1014. {
  1015. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: "
  1016. "failed to locate mapping tree node for dn %s\n",
  1017. slapi_sdn_get_dn(sdn));
  1018. }
  1019. else
  1020. {
  1021. /* check if replica object already exists for the specified subtree */
  1022. ext = (multimaster_mtnode_extension *)repl_con_get_ext (REPL_CON_EXT_MTNODE, mtnode);
  1023. }
  1024. slapi_sdn_free (&sdn);
  1025. return ext;
  1026. }
  1027. int
  1028. replica_execute_cleanruv_task_ext(Object *r, ReplicaId rid)
  1029. {
  1030. return replica_execute_cleanruv_task(r, rid, NULL);
  1031. }
  1032. static int
  1033. replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext /* not used */)
  1034. {
  1035. Object *RUVObj;
  1036. RUV *local_ruv = NULL;
  1037. Replica *replica = (Replica*)object_get_data (r);
  1038. int rc = 0;
  1039. PR_ASSERT (replica);
  1040. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanruv_task: cleaning rid (%d)...\n",(int)rid);
  1041. RUVObj = replica_get_ruv(replica);
  1042. PR_ASSERT(RUVObj);
  1043. local_ruv = (RUV*)object_get_data (RUVObj);
  1044. /* Need to check that :
  1045. * - rid is not the local one
  1046. * - rid is not the last one
  1047. */
  1048. if ((replica_get_rid(replica) == rid) ||
  1049. (ruv_replica_count(local_ruv) <= 1)) {
  1050. return LDAP_UNWILLING_TO_PERFORM;
  1051. }
  1052. rc = ruv_delete_replica(local_ruv, rid);
  1053. replica_set_ruv_dirty(replica);
  1054. replica_write_ruv(replica);
  1055. object_release(RUVObj);
  1056. /* Update Mapping Tree to reflect RUV changes */
  1057. consumer5_set_mapping_tree_state_for_replica(replica, NULL);
  1058. /*
  1059. * Clean the changelog RUV's
  1060. */
  1061. cl5CleanRUV(rid);
  1062. if (rc != RUV_SUCCESS){
  1063. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanruv_task: task failed(%d)\n",rc);
  1064. return LDAP_OPERATIONS_ERROR;
  1065. }
  1066. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanruv_task: finished successfully\n");
  1067. return LDAP_SUCCESS;
  1068. }
  1069. const char *
  1070. fetch_attr(Slapi_Entry *e, const char *attrname, const char *default_val)
  1071. {
  1072. Slapi_Attr *attr;
  1073. Slapi_Value *val = NULL;
  1074. if (slapi_entry_attr_find(e, attrname, &attr) != 0)
  1075. return default_val;
  1076. slapi_attr_first_value(attr, &val);
  1077. return slapi_value_get_string(val);
  1078. }
  1079. static int
  1080. replica_cleanall_ruv_task(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
  1081. int *returncode, char *returntext, void *arg)
  1082. {
  1083. Slapi_Task *task = NULL;
  1084. const Slapi_DN *task_dn;
  1085. Slapi_DN *dn = NULL;
  1086. Object *r;
  1087. const char *base_dn;
  1088. const char *rid_str;
  1089. ReplicaId rid;
  1090. int rc = SLAPI_DSE_CALLBACK_OK;
  1091. /* allocate new task now */
  1092. task = slapi_new_task(slapi_entry_get_ndn(e));
  1093. if(task == NULL){
  1094. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_task: Failed to create new task\n");
  1095. rc = SLAPI_DSE_CALLBACK_ERROR;
  1096. goto out;
  1097. }
  1098. /*
  1099. * Get our task settings
  1100. */
  1101. if ((base_dn = fetch_attr(e, "replica-base-dn", 0)) == NULL){
  1102. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  1103. rc = SLAPI_DSE_CALLBACK_ERROR;
  1104. goto out;
  1105. }
  1106. if ((rid_str = fetch_attr(e, "replica-id", 0)) == NULL){
  1107. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  1108. rc = SLAPI_DSE_CALLBACK_ERROR;
  1109. goto out;
  1110. }
  1111. task_dn = slapi_entry_get_sdn(e);
  1112. /*
  1113. * Check the rid
  1114. */
  1115. rid = atoi(rid_str);
  1116. if (rid <= 0 || rid >= READ_ONLY_REPLICA_ID){
  1117. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid replica id (%d) for task - (%s)",
  1118. rid, slapi_sdn_get_dn(task_dn));
  1119. cleanruv_log(task, CLEANALLRUV_ID, "%s", returntext);
  1120. rc = LDAP_OPERATIONS_ERROR;
  1121. goto out;
  1122. }
  1123. /*
  1124. * Get the replica object
  1125. */
  1126. dn = slapi_sdn_new_dn_byval(base_dn);
  1127. if((r = replica_get_replica_from_dn(dn)) == NULL){
  1128. *returncode = LDAP_OPERATIONS_ERROR ;
  1129. rc = SLAPI_DSE_CALLBACK_ERROR;
  1130. goto out;
  1131. }
  1132. /* clean the RUV's */
  1133. rc = replica_execute_cleanall_ruv_task (r, rid, task, returntext);
  1134. out:
  1135. if(rc){
  1136. cleanruv_log(task, CLEANALLRUV_ID, "Task failed...(%d)", rc);
  1137. *returncode = rc;
  1138. slapi_task_finish(task, *returncode);
  1139. rc = SLAPI_DSE_CALLBACK_ERROR;
  1140. } else {
  1141. rc = SLAPI_DSE_CALLBACK_OK;
  1142. }
  1143. slapi_sdn_free(&dn);
  1144. return rc;
  1145. }
  1146. /*
  1147. * CLEANALLRUV task
  1148. *
  1149. * [1] Get the maxcsn from the RUV of the rid we want to clean
  1150. * [2] Create the payload for the "cleanallruv" extended ops
  1151. * [3] Create "monitor" thread to do the real work.
  1152. *
  1153. */
  1154. static int
  1155. replica_execute_cleanall_ruv_task (Object *r, ReplicaId rid, Slapi_Task *task, char *returntext)
  1156. {
  1157. PRThread *thread = NULL;
  1158. Slapi_Task *pre_task = NULL; /* this is supposed to be null for logging */
  1159. Replica *replica;
  1160. Object *ruv_obj;
  1161. cleanruv_data *data = NULL;
  1162. CSN *maxcsn = NULL;
  1163. const RUV *ruv;
  1164. struct berval *payload = NULL;
  1165. char *ridstr = NULL;
  1166. char csnstr[CSN_STRSIZE];
  1167. int rc = 0;
  1168. if(get_cleanruv_task_count() >= CLEANRIDSIZ){
  1169. /* we are already running the maximum number of tasks */
  1170. cleanruv_log(pre_task, CLEANALLRUV_ID,
  1171. "Exceeded maximum number of active CLEANALLRUV tasks(%d)",CLEANRIDSIZ);
  1172. return LDAP_UNWILLING_TO_PERFORM;
  1173. }
  1174. /*
  1175. * Grab the replica
  1176. */
  1177. replica = (Replica*)object_get_data (r);
  1178. /*
  1179. * Check if this is a consumer
  1180. */
  1181. if(replica_get_type(replica) == REPLICA_TYPE_READONLY){
  1182. /* this is a consumer, send error */
  1183. cleanruv_log(pre_task, CLEANALLRUV_ID, "Failed to clean rid (%d), task can not be run on a consumer",rid);
  1184. if(task){
  1185. rc = -1;
  1186. slapi_task_finish(task, rc);
  1187. }
  1188. return -1;
  1189. }
  1190. /*
  1191. * Grab the max csn of the deleted replica
  1192. */
  1193. ruv_obj = replica_get_ruv(replica);
  1194. ruv = object_get_data (ruv_obj);
  1195. if(ruv_get_rid_max_csn(ruv, &maxcsn, rid) == RUV_BAD_DATA){
  1196. /* no maxcsn, can not proceed */
  1197. cleanruv_log(pre_task, CLEANALLRUV_ID, "Could not find maxcsn for rid (%d)", rid);
  1198. rc = -1;
  1199. object_release(ruv_obj);
  1200. goto fail;
  1201. } else {
  1202. object_release(ruv_obj);
  1203. if(maxcsn == NULL || csn_get_replicaid(maxcsn) == 0){
  1204. /*
  1205. * This is for consistency with extop csn creation, where
  1206. * we want the csn string to be "0000000000000000000" not ""
  1207. */
  1208. csn_free(&maxcsn);
  1209. maxcsn = csn_new();
  1210. csn_init_by_string(maxcsn, "");
  1211. }
  1212. csn_as_string(maxcsn, PR_FALSE, csnstr);
  1213. }
  1214. /*
  1215. * Create payload
  1216. */
  1217. ridstr = slapi_ch_smprintf("%d:%s:%s", rid, slapi_sdn_get_dn(replica_get_root(replica)), csnstr);
  1218. payload = create_ruv_payload(ridstr);
  1219. slapi_ch_free_string(&ridstr);
  1220. if(payload == NULL){
  1221. cleanruv_log(pre_task, CLEANALLRUV_ID, "Failed to create extended op payload, aborting task");
  1222. rc = -1;
  1223. goto fail;
  1224. }
  1225. /*
  1226. * Launch the cleanallruv thread. Once all the replicas are cleaned it will release the rid
  1227. */
  1228. data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
  1229. if (data == NULL) {
  1230. cleanruv_log(pre_task, CLEANALLRUV_ID, "Failed to allocate cleanruv_data. Aborting task.");
  1231. rc = -1;
  1232. goto fail;
  1233. }
  1234. data->repl_obj = r;
  1235. data->replica = replica;
  1236. data->rid = rid;
  1237. data->task = task;
  1238. data->maxcsn = maxcsn;
  1239. data->payload = payload;
  1240. data->sdn = NULL;
  1241. thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread,
  1242. (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  1243. PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
  1244. if (thread == NULL) {
  1245. rc = -1;
  1246. goto fail;
  1247. } else {
  1248. goto done;
  1249. }
  1250. fail:
  1251. cleanruv_log(pre_task, CLEANALLRUV_ID, "Failed to clean rid (%d)",rid);
  1252. if(task){
  1253. slapi_task_finish(task, rc);
  1254. }
  1255. if(payload){
  1256. ber_bvfree(payload);
  1257. }
  1258. csn_free(&maxcsn);
  1259. if(task) /* only the task acquires the r obj */
  1260. object_release (r);
  1261. done:
  1262. return rc;
  1263. }
  1264. void
  1265. replica_cleanallruv_thread_ext(void *arg)
  1266. {
  1267. replica_cleanallruv_thread(arg);
  1268. }
  1269. /*
  1270. * CLEANALLRUV Thread
  1271. *
  1272. * [1] Wait for the maxcsn to be covered
  1273. * [2] Make sure all the replicas are alive
  1274. * [3] Set the cleaned rid
  1275. * [4] Send the cleanAllRUV extop to all the replicas
  1276. * [5] Manually send the CLEANRUV task to replicas that do not support CLEANALLRUV
  1277. * [6] Wait for all the replicas to be cleaned.
  1278. * [7] Trigger cl trimming, release the rid, and remove all the "cleanallruv" attributes
  1279. * from the config.
  1280. */
  1281. static void
  1282. replica_cleanallruv_thread(void *arg)
  1283. {
  1284. Object *ruv_obj = NULL;
  1285. Object *agmt_obj = NULL;
  1286. Repl_Agmt *agmt = NULL;
  1287. RUV *ruv = NULL;
  1288. cleanruv_data *data = arg;
  1289. char csnstr[CSN_STRSIZE];
  1290. char *returntext = NULL;
  1291. char *rid_text = NULL;
  1292. int agmt_not_notified = 1;
  1293. int found_dirty_rid = 1;
  1294. int interval = 10;
  1295. int free_obj = 0;
  1296. int aborted = 0;
  1297. int rc = 0;
  1298. /*
  1299. * Initialize our settings
  1300. */
  1301. if(data->replica == NULL && data->repl_obj == NULL){
  1302. /*
  1303. * This thread was initiated at startup because the process did not finish. Due
  1304. * to startup timing issues, we need to wait before grabbing the replica obj, as
  1305. * the backends might not be online yet.
  1306. */
  1307. PR_Lock( notify_lock );
  1308. PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(5) );
  1309. PR_Unlock( notify_lock );
  1310. data->repl_obj = replica_get_replica_from_dn(data->sdn);
  1311. if(data->repl_obj == NULL){
  1312. cleanruv_log(data->task, CLEANALLRUV_ID, "Unable to retrieve repl object from dn(%s).", data->sdn);
  1313. aborted = 1;
  1314. goto done;
  1315. }
  1316. data->replica = (Replica*)object_get_data(data->repl_obj);
  1317. free_obj = 1;
  1318. } else if(data->replica == NULL && data->repl_obj){
  1319. data->replica = (Replica*)object_get_data(data->repl_obj);
  1320. } else if( data->repl_obj == NULL && data->replica){
  1321. data->repl_obj = object_new(data->replica, NULL);
  1322. free_obj = 1;
  1323. }
  1324. /* verify we have set our repl objects */
  1325. if(data->repl_obj == NULL || data->replica == NULL){
  1326. cleanruv_log(data->task, CLEANALLRUV_ID, "Unable to set the replica objects.");
  1327. aborted = 1;
  1328. goto done;
  1329. }
  1330. if(data->task){
  1331. slapi_task_begin(data->task, 1);
  1332. }
  1333. rid_text = slapi_ch_smprintf("{replica %d ldap", data->rid);
  1334. csn_as_string(data->maxcsn, PR_FALSE, csnstr);
  1335. /*
  1336. * Add the cleanallruv task to the repl config - so we can handle restarts
  1337. */
  1338. cleanruv_log(data->task, CLEANALLRUV_ID, "Cleaning rid (%d)...", data->rid);
  1339. add_cleaned_rid(data->rid, data->replica, csnstr); /* marks config that we started cleaning a rid */
  1340. /*
  1341. * First, wait for the maxcsn to be covered
  1342. */
  1343. cleanruv_log(data->task, CLEANALLRUV_ID, "Waiting to process all the updates from the deleted replica...");
  1344. ruv_obj = replica_get_ruv(data->replica);
  1345. ruv = object_get_data (ruv_obj);
  1346. while(data->maxcsn && !is_task_aborted(data->rid) && !is_cleaned_rid(data->rid) && !slapi_is_shutting_down()){
  1347. if(csn_get_replicaid(data->maxcsn) == 0 || ruv_covers_csn_cleanallruv(ruv,data->maxcsn)){
  1348. /* We are caught up, now we can clean the ruv's */
  1349. break;
  1350. }
  1351. PR_Lock( notify_lock );
  1352. PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(5) );
  1353. PR_Unlock( notify_lock );
  1354. }
  1355. object_release(ruv_obj);
  1356. /*
  1357. * Next, make sure all the replicas are up and running before sending off the clean ruv tasks
  1358. */
  1359. cleanruv_log(data->task, CLEANALLRUV_ID,"Waiting for all the replicas to be online...");
  1360. if(check_agmts_are_alive(data->replica, data->rid, data->task)){
  1361. /* error, aborted or shutdown */
  1362. aborted = 1;
  1363. goto done;
  1364. }
  1365. /*
  1366. * Make sure all the replicas have seen the max csn
  1367. */
  1368. cleanruv_log(data->task, CLEANALLRUV_ID,"Waiting for all the replicas to receive all the deleted replica updates...");
  1369. if(check_agmts_are_caught_up(data->replica, data->rid, csnstr, data->task)){
  1370. /* error, aborted or shutdown */
  1371. aborted = 1;
  1372. goto done;
  1373. }
  1374. /*
  1375. * Set the rid as notified - this blocks the changelog from sending out updates
  1376. * during this process, as well as prevents the db ruv from getting polluted.
  1377. */
  1378. set_cleaned_rid(data->rid);
  1379. /*
  1380. * Now send the cleanruv extended op to all the agreements
  1381. */
  1382. cleanruv_log(data->task, CLEANALLRUV_ID, "Sending cleanAllRUV task to all the replicas...");
  1383. while(agmt_not_notified && !is_task_aborted(data->rid) && !slapi_is_shutting_down()){
  1384. agmt_obj = agmtlist_get_first_agreement_for_replica (data->replica);
  1385. if(agmt_obj == NULL){
  1386. /* no agmts, just clean this replica */
  1387. break;
  1388. }
  1389. while (agmt_obj){
  1390. agmt = (Repl_Agmt*)object_get_data (agmt_obj);
  1391. if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
  1392. agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
  1393. continue;
  1394. }
  1395. if(replica_cleanallruv_send_extop(agmt, data->rid, data->task, data->payload, 1) == 0){
  1396. agmt_not_notified = 0;
  1397. } else {
  1398. agmt_not_notified = 1;
  1399. break;
  1400. }
  1401. agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
  1402. }
  1403. if(is_task_aborted(data->rid)){
  1404. aborted = 1;
  1405. goto done;
  1406. }
  1407. if(agmt_not_notified == 0){
  1408. break;
  1409. }
  1410. /*
  1411. * need to sleep between passes
  1412. */
  1413. cleanruv_log(data->task, CLEANALLRUV_ID, "Not all replicas have received the "
  1414. "cleanallruv extended op, retrying in %d seconds",interval);
  1415. PR_Lock( notify_lock );
  1416. PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
  1417. PR_Unlock( notify_lock );
  1418. if(interval < 14400){ /* 4 hour max */
  1419. interval = interval * 2;
  1420. } else {
  1421. interval = 14400;
  1422. }
  1423. }
  1424. /*
  1425. * Run the CLEANRUV task
  1426. */
  1427. cleanruv_log(data->task, CLEANALLRUV_ID,"Cleaning local ruv's...");
  1428. replica_execute_cleanruv_task (data->repl_obj, data->rid, returntext);
  1429. /*
  1430. * Wait for all the replicas to be cleaned
  1431. */
  1432. cleanruv_log(data->task, CLEANALLRUV_ID,"Waiting for all the replicas to be cleaned...");
  1433. interval = 10;
  1434. while(found_dirty_rid && !is_task_aborted(data->rid) && !slapi_is_shutting_down()){
  1435. agmt_obj = agmtlist_get_first_agreement_for_replica (data->replica);
  1436. if(agmt_obj == NULL){
  1437. break;
  1438. }
  1439. while (agmt_obj && !slapi_is_shutting_down()){
  1440. agmt = (Repl_Agmt*)object_get_data (agmt_obj);
  1441. if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
  1442. agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
  1443. continue;
  1444. }
  1445. if(replica_cleanallruv_check_ruv(agmt, rid_text, data->task) == 0){
  1446. found_dirty_rid = 0;
  1447. } else {
  1448. found_dirty_rid = 1;
  1449. break;
  1450. }
  1451. agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
  1452. }
  1453. /* If the task is abort or everyone is cleaned, break out */
  1454. if(is_task_aborted(data->rid)){
  1455. aborted = 1;
  1456. goto done;
  1457. }
  1458. if(found_dirty_rid == 0){
  1459. break;
  1460. }
  1461. /*
  1462. * need to sleep between passes
  1463. */
  1464. cleanruv_log(data->task, CLEANALLRUV_ID, "Replicas have not been cleaned yet, "
  1465. "retrying in %d seconds", interval);
  1466. PR_Lock( notify_lock );
  1467. PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
  1468. PR_Unlock( notify_lock );
  1469. if(interval < 14400){ /* 4 hour max */
  1470. interval = interval * 2;
  1471. } else {
  1472. interval = 14400;
  1473. }
  1474. } /* while */
  1475. done:
  1476. /*
  1477. * If the replicas are cleaned, release the rid, and trim the changelog
  1478. */
  1479. if(!aborted){
  1480. trigger_cl_trimming(data->rid);
  1481. delete_cleaned_rid(data->replica, data->rid, data->maxcsn);
  1482. cleanruv_log(data->task, CLEANALLRUV_ID, "Successfully cleaned rid(%d).", data->rid);
  1483. slapi_task_finish(data->task, rc);
  1484. } else {
  1485. /*
  1486. * Shutdown or abort
  1487. */
  1488. if(!is_task_aborted(data->rid)){
  1489. cleanruv_log(data->task, CLEANALLRUV_ID,"Server shutting down. Process will resume at server startup");
  1490. } else {
  1491. cleanruv_log(data->task, CLEANALLRUV_ID,"Task aborted for rid(%d).",data->rid);
  1492. }
  1493. if(data->task){
  1494. slapi_task_finish(data->task, rc);
  1495. }
  1496. }
  1497. if(data->payload){
  1498. ber_bvfree(data->payload);
  1499. }
  1500. if(data->repl_obj && free_obj){
  1501. object_release(data->repl_obj);
  1502. }
  1503. slapi_sdn_free(&data->sdn);
  1504. slapi_ch_free_string(&rid_text);
  1505. csn_free(&data->maxcsn);
  1506. slapi_ch_free((void **)&data);
  1507. }
  1508. /*
  1509. * Waits for all the repl agmts to be have have the maxcsn. Returns error only on abort or shutdown
  1510. */
  1511. static int
  1512. check_agmts_are_caught_up(Replica *replica, ReplicaId rid, char *maxcsn, Slapi_Task *task)
  1513. {
  1514. Object *agmt_obj;
  1515. Repl_Agmt *agmt;
  1516. char *rid_text;
  1517. int not_all_caughtup = 1;
  1518. int interval = 10;
  1519. rid_text = slapi_ch_smprintf("{replica %d ldap", rid);
  1520. while(not_all_caughtup && !is_task_aborted(rid) && !slapi_is_shutting_down()){
  1521. agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
  1522. if(agmt_obj == NULL){
  1523. not_all_caughtup = 0;
  1524. break;
  1525. }
  1526. while (agmt_obj){
  1527. agmt = (Repl_Agmt*)object_get_data (agmt_obj);
  1528. if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
  1529. agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
  1530. continue;
  1531. }
  1532. if(replica_cleanallruv_check_maxcsn(agmt, rid_text, maxcsn, task) == 0){
  1533. not_all_caughtup = 0;
  1534. } else {
  1535. not_all_caughtup = 1;
  1536. break;
  1537. }
  1538. agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
  1539. } /* agmt while */
  1540. if(not_all_caughtup == 0 || is_task_aborted(rid) ){
  1541. break;
  1542. }
  1543. cleanruv_log(task, CLEANALLRUV_ID, "Not all replicas caught up, retrying in %d seconds",interval);
  1544. PR_Lock( notify_lock );
  1545. PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
  1546. PR_Unlock( notify_lock );
  1547. if(interval < 14400){ /* 4 hour max */
  1548. interval = interval * 2;
  1549. } else {
  1550. interval = 14400;
  1551. }
  1552. }
  1553. slapi_ch_free_string(&rid_text);
  1554. if(is_task_aborted(rid)){
  1555. return -1;
  1556. }
  1557. return not_all_caughtup;
  1558. }
  1559. /*
  1560. * Waits for all the repl agmts to be online. Returns error only on abort or shutdown
  1561. */
  1562. static int
  1563. check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task)
  1564. {
  1565. Object *agmt_obj;
  1566. Repl_Agmt *agmt;
  1567. int not_all_alive = 1;
  1568. int interval = 10;
  1569. while(not_all_alive && is_task_aborted(rid) == 0 && !slapi_is_shutting_down()){
  1570. agmt_obj = agmtlist_get_first_agreement_for_replica (replica);
  1571. if(agmt_obj == NULL){
  1572. not_all_alive = 0;
  1573. break;
  1574. }
  1575. while (agmt_obj){
  1576. agmt = (Repl_Agmt*)object_get_data (agmt_obj);
  1577. if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
  1578. agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
  1579. continue;
  1580. }
  1581. if(replica_cleanallruv_replica_alive(agmt) == 0){
  1582. not_all_alive = 0;
  1583. } else {
  1584. not_all_alive = 1;
  1585. break;
  1586. }
  1587. agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
  1588. }
  1589. if(not_all_alive == 0 || is_task_aborted(rid)){
  1590. break;
  1591. }
  1592. cleanruv_log(task, CLEANALLRUV_ID, "Not all replicas online, retrying in %d seconds...",interval);
  1593. PR_Lock( notify_lock );
  1594. PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
  1595. PR_Unlock( notify_lock );
  1596. if(interval < 14400){ /* 4 hour max */
  1597. interval = interval * 2;
  1598. } else {
  1599. interval = 14400;
  1600. }
  1601. }
  1602. if(is_task_aborted(rid)){
  1603. return -1;
  1604. }
  1605. return not_all_alive;
  1606. }
  1607. /*
  1608. * Create the CLEANALLRUV extended op payload
  1609. */
  1610. struct berval *
  1611. create_ruv_payload(char *value)
  1612. {
  1613. struct berval *req_data = NULL;
  1614. BerElement *tmp_bere = NULL;
  1615. if ((tmp_bere = der_alloc()) == NULL){
  1616. goto error;
  1617. }
  1618. if (ber_printf(tmp_bere, "{s", value) == -1){
  1619. goto error;
  1620. }
  1621. if (ber_printf(tmp_bere, "}") == -1){
  1622. goto error;
  1623. }
  1624. if (ber_flatten(tmp_bere, &req_data) == -1){
  1625. goto error;
  1626. }
  1627. goto done;
  1628. error:
  1629. if (NULL != req_data){
  1630. ber_bvfree(req_data);
  1631. req_data = NULL;
  1632. }
  1633. done:
  1634. if (NULL != tmp_bere){
  1635. ber_free(tmp_bere, 1);
  1636. tmp_bere = NULL;
  1637. }
  1638. return req_data;
  1639. }
  1640. /*
  1641. * Manually add the CLEANRUV task to replicas that do not support
  1642. * the CLEANALLRUV task.
  1643. */
  1644. static void
  1645. replica_send_cleanruv_task(Repl_Agmt *agmt, ReplicaId rid, Slapi_Task *task)
  1646. {
  1647. Repl_Connection *conn;
  1648. ConnResult crc = 0;
  1649. LDAP *ld;
  1650. Slapi_DN *sdn;
  1651. struct berval *vals[2];
  1652. struct berval val;
  1653. LDAPMod *mods[2];
  1654. LDAPMod mod;
  1655. char *repl_dn = NULL;
  1656. char data[15];
  1657. int rc;
  1658. if((conn = conn_new(agmt)) == NULL){
  1659. return;
  1660. }
  1661. crc = conn_connect(conn);
  1662. if (CONN_OPERATION_SUCCESS != crc){
  1663. conn_delete_internal_ext(conn);
  1664. return;
  1665. }
  1666. ld = conn_get_ldap(conn);
  1667. if(ld == NULL){
  1668. conn_delete_internal_ext(conn);
  1669. return;
  1670. }
  1671. val.bv_len = PR_snprintf(data, sizeof(data), "CLEANRUV%d", rid);
  1672. sdn = agmt_get_replarea(agmt);
  1673. mod.mod_op = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
  1674. mod.mod_type = "nsds5task";
  1675. mod.mod_bvalues = vals;
  1676. vals [0] = &val;
  1677. vals [1] = NULL;
  1678. val.bv_val = data;
  1679. mods[0] = &mod;
  1680. mods[1] = NULL;
  1681. repl_dn = slapi_create_dn_string("cn=replica,cn=%s,cn=mapping tree,cn=config", slapi_sdn_get_dn(sdn));
  1682. /*
  1683. * Add task to remote replica
  1684. */
  1685. rc = ldap_modify_ext_s( ld, repl_dn, mods, NULL, NULL);
  1686. if(rc != LDAP_SUCCESS){
  1687. cleanruv_log(task, CLEANALLRUV_ID, "Failed to add CLEANRUV task replica "
  1688. "(%s). You will need to manually run the CLEANRUV task on this replica (%s) error (%d)",
  1689. agmt_get_long_name(agmt), agmt_get_hostname(agmt), rc);
  1690. }
  1691. slapi_ch_free_string(&repl_dn);
  1692. slapi_sdn_free(&sdn);
  1693. conn_delete_internal_ext(conn);
  1694. }
  1695. /*
  1696. * Check if the rid is in our list of "cleaned" rids
  1697. */
  1698. int
  1699. is_cleaned_rid(ReplicaId rid)
  1700. {
  1701. int i;
  1702. slapi_rwlock_rdlock(rid_lock);
  1703. for(i = 0; i < CLEANRIDSIZ && cleaned_rids[i] != 0; i++){
  1704. if(rid == cleaned_rids[i]){
  1705. slapi_rwlock_unlock(rid_lock);
  1706. return 1;
  1707. }
  1708. }
  1709. slapi_rwlock_unlock(rid_lock);
  1710. return 0;
  1711. }
  1712. int
  1713. is_task_aborted(ReplicaId rid)
  1714. {
  1715. int i;
  1716. if(rid == 0){
  1717. return 0;
  1718. }
  1719. slapi_rwlock_rdlock(abort_rid_lock);
  1720. for(i = 0; i < CLEANRIDSIZ && aborted_rids[i] != 0; i++){
  1721. if(rid == aborted_rids[i]){
  1722. slapi_rwlock_unlock(abort_rid_lock);
  1723. return 1;
  1724. }
  1725. }
  1726. slapi_rwlock_unlock(abort_rid_lock);
  1727. return 0;
  1728. }
  1729. /*
  1730. * Just add the rid to the in memory, as we don't want it to survive after a restart,
  1731. * This prevent the changelog from sending updates from this rid, and the local ruv
  1732. * will not be updated either.
  1733. */
  1734. void
  1735. set_cleaned_rid(ReplicaId rid)
  1736. {
  1737. int i;
  1738. slapi_rwlock_wrlock(rid_lock);
  1739. for(i = 0; i < CLEANRIDSIZ; i++){
  1740. if(cleaned_rids[i] == 0){
  1741. cleaned_rids[i] = rid;
  1742. cleaned_rids[i + 1] = 0;
  1743. }
  1744. }
  1745. slapi_rwlock_unlock(rid_lock);
  1746. }
  1747. /*
  1748. * Add the rid and maxcsn to the repl config (so we can resume after a server restart)
  1749. */
  1750. void
  1751. add_cleaned_rid(ReplicaId rid, Replica *r, char *maxcsn)
  1752. {
  1753. Slapi_PBlock *pb;
  1754. struct berval *vals[2];
  1755. struct berval val;
  1756. LDAPMod *mods[2];
  1757. LDAPMod mod;
  1758. char data[CSN_STRSIZE + 10];
  1759. char *dn;
  1760. int rc;
  1761. if(r == NULL || maxcsn == NULL){
  1762. return;
  1763. }
  1764. /*
  1765. * Write the rid & maxcsn to the config entry
  1766. */
  1767. val.bv_len = PR_snprintf(data, sizeof(data),"%d:%s", rid, maxcsn);
  1768. dn = replica_get_dn(r);
  1769. pb = slapi_pblock_new();
  1770. mod.mod_op = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
  1771. mod.mod_type = (char *)type_replicaCleanRUV;
  1772. mod.mod_bvalues = vals;
  1773. vals [0] = &val;
  1774. vals [1] = NULL;
  1775. val.bv_val = data;
  1776. mods[0] = &mod;
  1777. mods[1] = NULL;
  1778. replica_add_cleanruv_data(r, val.bv_val);
  1779. slapi_modify_internal_set_pb (pb, dn, mods, NULL, NULL,
  1780. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
  1781. slapi_modify_internal_pb (pb);
  1782. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1783. if (rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS){
  1784. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to update replica "
  1785. "config (%d), rid (%d)\n", rc, rid);
  1786. }
  1787. slapi_ch_free_string(&dn);
  1788. slapi_pblock_destroy(pb);
  1789. }
  1790. /*
  1791. * Add aborted rid and repl root to config in case of a server restart
  1792. */
  1793. void
  1794. add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root)
  1795. {
  1796. Slapi_PBlock *pb;
  1797. struct berval *vals[2];
  1798. struct berval val;
  1799. LDAPMod *mods[2];
  1800. LDAPMod mod;
  1801. char *data;
  1802. char *dn;
  1803. int rc;
  1804. int i;
  1805. slapi_rwlock_wrlock(abort_rid_lock);
  1806. for(i = 0; i < CLEANRIDSIZ; i++){
  1807. if(aborted_rids[i] == 0){
  1808. aborted_rids[i] = rid;
  1809. aborted_rids[i + 1] = 0;
  1810. break;
  1811. }
  1812. }
  1813. slapi_rwlock_unlock(abort_rid_lock);
  1814. /*
  1815. * Write the rid to the config entry
  1816. */
  1817. dn = replica_get_dn(r);
  1818. pb = slapi_pblock_new();
  1819. data = PR_smprintf("%d:%s", rid, repl_root);
  1820. mod.mod_op = LDAP_MOD_ADD|LDAP_MOD_BVALUES;
  1821. mod.mod_type = (char *)type_replicaAbortCleanRUV;
  1822. mod.mod_bvalues = vals;
  1823. vals [0] = &val;
  1824. vals [1] = NULL;
  1825. val.bv_val = data;
  1826. val.bv_len = strlen (data);
  1827. mods[0] = &mod;
  1828. mods[1] = NULL;
  1829. slapi_modify_internal_set_pb (pb, dn, mods, NULL, NULL,
  1830. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
  1831. slapi_modify_internal_pb (pb);
  1832. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1833. if (rc != LDAP_SUCCESS){
  1834. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to update "
  1835. "replica config (%d), rid (%d)\n", rc, rid);
  1836. }
  1837. slapi_ch_free_string(&dn);
  1838. slapi_ch_free_string(&data);
  1839. slapi_pblock_destroy(pb);
  1840. }
  1841. void
  1842. delete_aborted_rid(Replica *r, ReplicaId rid, char *repl_root){
  1843. Slapi_PBlock *pb;
  1844. LDAPMod *mods[2];
  1845. LDAPMod mod;
  1846. struct berval *vals[2];
  1847. struct berval val;
  1848. char *data;
  1849. char *dn;
  1850. int rc;
  1851. int i;
  1852. if(r == NULL)
  1853. return;
  1854. /*
  1855. * Remove this rid, and optimize the array
  1856. */
  1857. slapi_rwlock_wrlock(abort_rid_lock);
  1858. for(i = 0; i < CLEANRIDSIZ && aborted_rids[i] != rid; i++); /* found rid, stop */
  1859. for(; i < CLEANRIDSIZ; i++){
  1860. /* rewrite entire array */
  1861. aborted_rids[i] = aborted_rids[i + 1];
  1862. }
  1863. slapi_rwlock_unlock(abort_rid_lock);
  1864. /*
  1865. * Prepare the mods for the config entry
  1866. */
  1867. dn = replica_get_dn(r);
  1868. pb = slapi_pblock_new();
  1869. data = PR_smprintf("%d:%s", (int)rid, repl_root);
  1870. mod.mod_op = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
  1871. mod.mod_type = (char *)type_replicaAbortCleanRUV;
  1872. mod.mod_bvalues = vals;
  1873. vals [0] = &val;
  1874. vals [1] = NULL;
  1875. val.bv_val = data;
  1876. val.bv_len = strlen (data);
  1877. mods[0] = &mod;
  1878. mods[1] = NULL;
  1879. slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
  1880. slapi_modify_internal_pb (pb);
  1881. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1882. if (rc != LDAP_SUCCESS){
  1883. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Abort CleanAllRUV Task: failed to remove replica "
  1884. "config (%d), rid (%d)\n", rc, rid);
  1885. }
  1886. slapi_pblock_destroy (pb);
  1887. slapi_ch_free_string(&dn);
  1888. slapi_ch_free_string(&data);
  1889. }
  1890. /*
  1891. * Remove the rid from our list, and the config
  1892. */
  1893. void
  1894. delete_cleaned_rid(Replica *r, ReplicaId rid, CSN *maxcsn)
  1895. {
  1896. Slapi_PBlock *pb;
  1897. Object *agmt_obj;
  1898. Repl_Agmt *agmt;
  1899. LDAPMod *mods[2];
  1900. LDAPMod mod;
  1901. struct berval *vals[2];
  1902. struct berval val;
  1903. char *dn;
  1904. char data[CSN_STRSIZE + 10];
  1905. char csnstr[CSN_STRSIZE];
  1906. int rc;
  1907. int i;
  1908. if(r == NULL || maxcsn == NULL)
  1909. return;
  1910. /*
  1911. * Remove this rid, and optimize the array
  1912. */
  1913. slapi_rwlock_wrlock(rid_lock);
  1914. for(i = 0; i < CLEANRIDSIZ && cleaned_rids[i] != rid; i++); /* found rid, stop */
  1915. for(; i < CLEANRIDSIZ; i++){
  1916. /* rewrite entire array */
  1917. cleaned_rids[i] = cleaned_rids[i + 1];
  1918. }
  1919. slapi_rwlock_unlock(rid_lock);
  1920. /*
  1921. * Prepare the mods for the config entry
  1922. */
  1923. csn_as_string(maxcsn, PR_FALSE, csnstr);
  1924. val.bv_len = PR_snprintf(data, sizeof(data), "%d:%s", (int)rid, csnstr);
  1925. dn = replica_get_dn(r);
  1926. pb = slapi_pblock_new();
  1927. mod.mod_op = LDAP_MOD_DELETE|LDAP_MOD_BVALUES;
  1928. mod.mod_type = (char *)type_replicaCleanRUV;
  1929. mod.mod_bvalues = vals;
  1930. vals [0] = &val;
  1931. vals [1] = NULL;
  1932. val.bv_val = data;
  1933. mods[0] = &mod;
  1934. mods[1] = NULL;
  1935. replica_remove_cleanruv_data(r, data);
  1936. slapi_modify_internal_set_pb(pb, dn, mods, NULL, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
  1937. slapi_modify_internal_pb (pb);
  1938. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1939. if (rc != LDAP_SUCCESS){
  1940. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "CleanAllRUV Task: failed to remove replica config "
  1941. "(%d), rid (%d)\n", rc, rid);
  1942. }
  1943. slapi_pblock_destroy (pb);
  1944. slapi_ch_free_string(&dn);
  1945. /*
  1946. * Now release the cleaned rid from the repl agmts
  1947. */
  1948. agmt_obj = agmtlist_get_first_agreement_for_replica (r);
  1949. while (agmt_obj){
  1950. agmt = (Repl_Agmt*)object_get_data (agmt_obj);
  1951. if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
  1952. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  1953. continue;
  1954. }
  1955. agmt_set_cleanruv_data(agmt, rid, CLEANRUV_RELEASED);
  1956. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  1957. }
  1958. }
  1959. /*
  1960. * Abort the CLEANALLRUV task
  1961. */
  1962. int
  1963. replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
  1964. int *returncode, char *returntext, void *arg)
  1965. {
  1966. PRThread *thread = NULL;
  1967. struct berval *payload = NULL;
  1968. Slapi_Task *task = NULL;
  1969. Replica *replica;
  1970. ReplicaId rid;
  1971. cleanruv_data *data = NULL;
  1972. Slapi_DN *sdn;
  1973. Object *r;
  1974. CSN *maxcsn;
  1975. const char *base_dn;
  1976. const char *rid_str;
  1977. char *ridstr;
  1978. int rc = SLAPI_DSE_CALLBACK_OK;
  1979. if(get_abort_cleanruv_task_count() >= CLEANRIDSIZ){
  1980. /* we are already running the maximum number of tasks */
  1981. cleanruv_log(task, ABORT_CLEANALLRUV_ID,
  1982. "Exceeded maximum number of active ABORT CLEANALLRUV tasks(%d)",CLEANRIDSIZ);
  1983. *returncode = LDAP_OPERATIONS_ERROR;
  1984. return SLAPI_DSE_CALLBACK_ERROR;
  1985. }
  1986. /* allocate new task now */
  1987. task = slapi_new_task(slapi_entry_get_ndn(e));
  1988. /*
  1989. * Get our task settings
  1990. */
  1991. if ((rid_str = fetch_attr(e, "replica-id", 0)) == NULL){
  1992. cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Missing required attr \"replica-id\"");
  1993. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  1994. rc = SLAPI_DSE_CALLBACK_ERROR;
  1995. goto out;
  1996. }
  1997. if ((base_dn = fetch_attr(e, "replica-base-dn", 0)) == NULL){
  1998. cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Missing required attr \"replica-base-dn\"");
  1999. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  2000. rc = SLAPI_DSE_CALLBACK_ERROR;
  2001. goto out;
  2002. }
  2003. /*
  2004. * Check the rid
  2005. */
  2006. rid = atoi(rid_str);
  2007. if (rid <= 0 || rid >= READ_ONLY_REPLICA_ID){
  2008. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid replica id (%d) for task - (%s)",
  2009. rid, slapi_sdn_get_dn(slapi_entry_get_sdn(e)));
  2010. cleanruv_log(task, ABORT_CLEANALLRUV_ID,"%s", returntext);
  2011. *returncode = LDAP_OPERATIONS_ERROR;
  2012. rc = SLAPI_DSE_CALLBACK_ERROR;
  2013. goto out;
  2014. }
  2015. /*
  2016. * Get the replica object
  2017. */
  2018. sdn = slapi_sdn_new_dn_byval(base_dn);
  2019. if((r = replica_get_replica_from_dn(sdn)) == NULL){
  2020. cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Failed to find replica from dn(%s)", base_dn);
  2021. *returncode = LDAP_OPERATIONS_ERROR;
  2022. rc = SLAPI_DSE_CALLBACK_ERROR;
  2023. goto out;
  2024. }
  2025. /*
  2026. * Create payload
  2027. */
  2028. ridstr = slapi_ch_smprintf("%d:%s", rid, base_dn);
  2029. payload = create_ruv_payload(ridstr);
  2030. if(payload == NULL){
  2031. cleanruv_log(task, ABORT_CLEANALLRUV_ID, "Failed to create extended op payload, aborting task");
  2032. *returncode = LDAP_OPERATIONS_ERROR;
  2033. rc = SLAPI_DSE_CALLBACK_ERROR;
  2034. goto out;
  2035. }
  2036. /*
  2037. * Stop the cleaning, and delete the rid
  2038. */
  2039. replica = (Replica*)object_get_data (r);
  2040. maxcsn = replica_get_cleanruv_maxcsn(replica, rid);
  2041. delete_cleaned_rid(replica, rid, maxcsn);
  2042. add_aborted_rid(rid, replica, (char *)base_dn);
  2043. stop_ruv_cleaning();
  2044. /*
  2045. * Prepare the abort struct and fire off the thread
  2046. */
  2047. data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
  2048. if (data == NULL) {
  2049. cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Failed to allocate abort_cleanruv_data. Aborting task.");
  2050. *returncode = LDAP_OPERATIONS_ERROR;
  2051. rc = SLAPI_DSE_CALLBACK_ERROR;
  2052. goto out;
  2053. }
  2054. data->repl_obj = r; /* released in replica_abort_task_thread() */
  2055. data->replica = replica;
  2056. data->task = task;
  2057. data->payload = payload;
  2058. data->rid = rid;
  2059. data->repl_root = slapi_ch_strdup(base_dn);
  2060. data->sdn = NULL;
  2061. thread = PR_CreateThread(PR_USER_THREAD, replica_abort_task_thread,
  2062. (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  2063. PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
  2064. if (thread == NULL) {
  2065. object_release(r);
  2066. cleanruv_log(task, ABORT_CLEANALLRUV_ID,"Unable to create abort thread. Aborting task.");
  2067. *returncode = LDAP_OPERATIONS_ERROR;
  2068. rc = SLAPI_DSE_CALLBACK_ERROR;
  2069. }
  2070. out:
  2071. csn_free(&maxcsn);
  2072. slapi_ch_free_string(&ridstr);
  2073. slapi_sdn_free(&sdn);
  2074. if(rc != SLAPI_DSE_CALLBACK_OK){
  2075. cleanruv_log(task, ABORT_CLEANALLRUV_ID, "Abort Task failed (%d)", rc);
  2076. slapi_task_finish(task, rc);
  2077. }
  2078. return rc;
  2079. }
  2080. /*
  2081. * Abort CLEANALLRUV task thread
  2082. */
  2083. void
  2084. replica_abort_task_thread(void *arg)
  2085. {
  2086. cleanruv_data *data = (cleanruv_data *)arg;
  2087. Repl_Agmt *agmt;
  2088. Object *agmt_obj;
  2089. int agmt_not_notified = 1;
  2090. int interval = 10;
  2091. int release_it = 0;
  2092. /*
  2093. * Need to build the replica from the dn
  2094. */
  2095. if(data->replica == NULL && data->repl_obj == NULL){
  2096. /*
  2097. * This thread was initiated at startup because the process did not finish. Due
  2098. * to timing issues, we need to wait to grab the replica obj until we get here.
  2099. */
  2100. if((data->repl_obj = replica_get_replica_from_dn(data->sdn)) == NULL){
  2101. cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Failed to get replica from dn (%s).", slapi_sdn_get_dn(data->sdn));
  2102. goto done;
  2103. }
  2104. if(data->replica == NULL && data->repl_obj){
  2105. data->replica = (Replica*)object_get_data(data->repl_obj);
  2106. }
  2107. release_it = 1;
  2108. }
  2109. /*
  2110. * Now send the cleanruv extended op to all the agreements
  2111. */
  2112. while(agmt_not_notified && !slapi_is_shutting_down()){
  2113. agmt_obj = agmtlist_get_first_agreement_for_replica (data->replica);
  2114. while (agmt_obj){
  2115. agmt = (Repl_Agmt*)object_get_data (agmt_obj);
  2116. if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
  2117. agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
  2118. continue;
  2119. }
  2120. if(replica_cleanallruv_send_abort_extop(agmt, data->task, data->payload)){
  2121. agmt_not_notified = 1;
  2122. break;
  2123. } else {
  2124. /* success */
  2125. agmt_not_notified = 0;
  2126. }
  2127. agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
  2128. } /* while loop for agmts */
  2129. if(agmt_not_notified == 0){
  2130. /* everybody has been contacted */
  2131. break;
  2132. }
  2133. /*
  2134. * need to sleep between passes
  2135. */
  2136. cleanruv_log(data->task, ABORT_CLEANALLRUV_ID,"Retrying in %d seconds",interval);
  2137. PR_Lock( notify_lock );
  2138. PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
  2139. PR_Unlock( notify_lock );
  2140. if(interval < 14400){ /* 4 hour max */
  2141. interval = interval * 2;
  2142. } else {
  2143. interval = 14400;
  2144. }
  2145. } /* while */
  2146. done:
  2147. if(agmt_not_notified){
  2148. /* failure */
  2149. cleanruv_log(data->task, ABORT_CLEANALLRUV_ID,"Abort task failed, will resume the task at the next server startup.");
  2150. } else {
  2151. /*
  2152. * Clean up the config
  2153. */
  2154. delete_aborted_rid(data->replica, data->rid, data->repl_root);
  2155. cleanruv_log(data->task, ABORT_CLEANALLRUV_ID, "Successfully aborted cleanAllRUV task for rid(%d)", data->rid);
  2156. }
  2157. if(data->task){
  2158. slapi_task_finish(data->task, agmt_not_notified);
  2159. }
  2160. if(data->repl_obj && release_it)
  2161. object_release(data->repl_obj);
  2162. if(data->payload){
  2163. ber_bvfree(data->payload);
  2164. }
  2165. slapi_ch_free_string(&data->repl_root);
  2166. slapi_sdn_free(&data->sdn);
  2167. slapi_ch_free((void **)&data);
  2168. }
  2169. static int
  2170. replica_cleanallruv_send_abort_extop(Repl_Agmt *ra, Slapi_Task *task, struct berval *payload)
  2171. {
  2172. Repl_Connection *conn = NULL;
  2173. ConnResult crc = 0;
  2174. int msgid = 0;
  2175. int rc = 0;
  2176. if((conn = conn_new(ra)) == NULL){
  2177. return -1;
  2178. }
  2179. if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
  2180. crc = conn_send_extended_operation(conn, REPL_ABORT_CLEANRUV_OID, payload, NULL, &msgid);
  2181. /*
  2182. * success or failure, just return the error code
  2183. */
  2184. rc = crc;
  2185. if(rc){
  2186. cleanruv_log(task, ABORT_CLEANALLRUV_ID, "Failed to send extop to replica(%s).", agmt_get_long_name(ra));
  2187. }
  2188. } else {
  2189. cleanruv_log(task, ABORT_CLEANALLRUV_ID, "Failed to connect to replica(%s).", agmt_get_long_name(ra));
  2190. rc = -1;
  2191. }
  2192. conn_delete_internal_ext(conn);
  2193. return rc;
  2194. }
  2195. static int
  2196. replica_cleanallruv_send_extop(Repl_Agmt *ra, ReplicaId rid, Slapi_Task *task, struct berval *payload, int check_result)
  2197. {
  2198. Repl_Connection *conn = NULL;
  2199. ConnResult crc = 0;
  2200. int msgid = 0;
  2201. int rc = 0;
  2202. if((conn = conn_new(ra)) == NULL){
  2203. return -1;
  2204. }
  2205. if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
  2206. crc = conn_send_extended_operation(conn, REPL_CLEANRUV_OID, payload, NULL, &msgid);
  2207. if(crc == CONN_OPERATION_SUCCESS && check_result){
  2208. struct berval *retsdata = NULL;
  2209. char *retoid = NULL;
  2210. crc = conn_read_result_ex(conn, &retoid, &retsdata, NULL, msgid, NULL, 1);
  2211. if (CONN_OPERATION_SUCCESS == crc ){
  2212. struct berval **ruv_bervals = NULL;
  2213. struct berval *data = NULL;
  2214. char *data_guid = NULL;
  2215. decode_repl_ext_response(retsdata, &rc, &ruv_bervals, &data_guid, &data);
  2216. /* just free everything, we only wanted "rc" */
  2217. slapi_ch_free_string(&data_guid);
  2218. if(data)
  2219. ber_bvfree(data);
  2220. if (ruv_bervals)
  2221. ber_bvecfree(ruv_bervals);
  2222. if(rc == 0 ){ /* rc == 1 is success */
  2223. cleanruv_log(task, CLEANALLRUV_ID,"Replica %s does not support the CLEANALLRUV task. Sending replica CLEANRUV task...",
  2224. slapi_sdn_get_dn(agmt_get_dn_byref(ra)));
  2225. /*
  2226. * Ok, this replica doesn't know about CLEANALLRUV, so just manually
  2227. * add the CLEANRUV task to the replica.
  2228. */
  2229. replica_send_cleanruv_task(ra, rid, task);
  2230. } else {
  2231. /* extop was accepted */
  2232. rc = 0;
  2233. }
  2234. if (NULL != retoid)
  2235. ldap_memfree(retoid);
  2236. if (NULL != retsdata)
  2237. ber_bvfree(retsdata);
  2238. }
  2239. agmt_set_cleanruv_data(ra, rid, CLEANRUV_NOTIFIED);
  2240. } else {
  2241. /*
  2242. * success or failure, just return the error code
  2243. */
  2244. rc = crc;
  2245. }
  2246. } else {
  2247. rc =-1;
  2248. }
  2249. conn_delete_internal_ext(conn);
  2250. return rc;
  2251. }
  2252. static int
  2253. replica_cleanallruv_check_maxcsn(Repl_Agmt *agmt, char *rid_text, char *maxcsn, Slapi_Task *task)
  2254. {
  2255. Repl_Connection *conn = NULL;
  2256. LDAP *ld;
  2257. Slapi_DN *sdn;
  2258. struct berval **vals;
  2259. LDAPMessage *result = NULL, *entry = NULL;
  2260. BerElement *ber;
  2261. char *attrs[2];
  2262. char *attr = NULL;
  2263. char *iter = NULL;
  2264. char *ruv_part = NULL;
  2265. int found_rid = 0;
  2266. int part_count = 0;
  2267. int rc = 0, i;
  2268. if((conn = conn_new(agmt)) == NULL){
  2269. return -1;
  2270. }
  2271. if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
  2272. attrs[0] = "nsds50ruv";
  2273. attrs[1] = NULL;
  2274. ld = conn_get_ldap(conn);
  2275. if(ld == NULL){
  2276. conn_delete_internal_ext(conn);
  2277. return -1;
  2278. }
  2279. sdn = agmt_get_replarea(agmt);
  2280. rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(sdn), LDAP_SCOPE_SUBTREE,
  2281. "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))",
  2282. attrs, 0, NULL, NULL, NULL, 0, &result);
  2283. slapi_sdn_free(&sdn);
  2284. if(rc != LDAP_SUCCESS){
  2285. cleanruv_log(task, CLEANALLRUV_ID,"Failed to contact "
  2286. "agmt (%s) error (%d), will retry later.", agmt_get_long_name(agmt), rc);
  2287. conn_delete_internal_ext(conn);
  2288. return -1;
  2289. }
  2290. entry = ldap_first_entry( ld, result );
  2291. if ( entry != NULL ) {
  2292. for ( attr = ldap_first_attribute( ld, entry, &ber ); attr != NULL; attr = ldap_next_attribute( ld, entry, ber ) ){
  2293. /* make sure the attribute is nsds50ruv */
  2294. if(strcasecmp(attr,"nsds50ruv") != 0){
  2295. ldap_memfree( attr );
  2296. continue;
  2297. }
  2298. found_rid = 0;
  2299. if ((vals = ldap_get_values_len( ld, entry, attr)) != NULL ) {
  2300. for ( i = 0; vals[i] && vals[i]->bv_val; i++ ) {
  2301. /* look for this replica */
  2302. if(strstr(vals[i]->bv_val, rid_text)){
  2303. found_rid = 1;
  2304. /* get the max csn compare it to our known max csn */
  2305. ruv_part = ldap_utf8strtok_r(vals[i]->bv_val, " ", &iter);
  2306. for(part_count = 1; ruv_part && part_count < 5; part_count++){
  2307. ruv_part = ldap_utf8strtok_r(iter, " ", &iter);
  2308. }
  2309. if(part_count == 5 && ruv_part){
  2310. /* we have the maxcsn */
  2311. if(strcmp(ruv_part, maxcsn)){
  2312. /* we are not caught up yet, free, and return */
  2313. ldap_value_free_len(vals);
  2314. ldap_memfree( attr );
  2315. ldap_msgfree( result );
  2316. if(ber){
  2317. ber_free( ber, 0 );
  2318. }
  2319. conn_delete_internal_ext(conn);
  2320. return -1;
  2321. } else {
  2322. /* ok this replica has all the updates from the deleted replica */
  2323. rc = 0;
  2324. }
  2325. } else {
  2326. /* there is no maxcsn for this rid - treat it as caught up */
  2327. rc = 0;
  2328. }
  2329. }
  2330. }
  2331. if(!found_rid){
  2332. /* must have been cleaned already */
  2333. rc = 0;
  2334. }
  2335. ldap_value_free_len(vals);
  2336. }
  2337. ldap_memfree( attr );
  2338. }
  2339. if ( ber != NULL ) {
  2340. ber_free( ber, 0 );
  2341. }
  2342. }
  2343. if(result)
  2344. ldap_msgfree( result );
  2345. } else {
  2346. rc = -1;
  2347. }
  2348. conn_delete_internal_ext(conn);
  2349. return rc;
  2350. }
  2351. static int
  2352. replica_cleanallruv_replica_alive(Repl_Agmt *agmt)
  2353. {
  2354. Repl_Connection *conn = NULL;
  2355. LDAP *ld = NULL;
  2356. LDAPMessage *result = NULL;
  2357. int rc = 0;
  2358. if((conn = conn_new(agmt)) == NULL){
  2359. return -1;
  2360. }
  2361. if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
  2362. ld = conn_get_ldap(conn);
  2363. if(ld == NULL){
  2364. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanAllRUV_task: failed to get LDAP "
  2365. "handle from the replication agmt (%s). Moving on to the next agmt.\n",agmt_get_long_name(agmt));
  2366. conn_delete_internal_ext(conn);
  2367. return -1;
  2368. }
  2369. if(ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, "objectclass=top",
  2370. NULL, 0, NULL, NULL, NULL, 0, &result) == LDAP_SUCCESS)
  2371. {
  2372. rc = 0;
  2373. } else {
  2374. rc = -1;
  2375. }
  2376. if(result)
  2377. ldap_msgfree( result );
  2378. } else {
  2379. rc = -1;
  2380. }
  2381. conn_delete_internal_ext(conn);
  2382. return rc;
  2383. }
  2384. static int
  2385. replica_cleanallruv_check_ruv(Repl_Agmt *ra, char *rid_text, Slapi_Task *task)
  2386. {
  2387. Repl_Connection *conn = NULL;
  2388. BerElement *ber = NULL;
  2389. struct berval **vals = NULL;
  2390. LDAPMessage *result = NULL, *entry = NULL;
  2391. LDAP *ld = NULL;
  2392. Slapi_DN *sdn;
  2393. char *attrs[2];
  2394. char *attr = NULL;
  2395. int rc = 0, i;
  2396. if((conn = conn_new(ra)) == NULL){
  2397. return -1;
  2398. }
  2399. if(conn_connect(conn) == CONN_OPERATION_SUCCESS){
  2400. attrs[0] = "nsds50ruv";
  2401. attrs[1] = NULL;
  2402. ld = conn_get_ldap(conn);
  2403. if(ld == NULL){
  2404. cleanruv_log(task, CLEANALLRUV_ID,"Failed to get LDAP handle from "
  2405. "the replication agmt (%s). Moving on to the next agmt.",agmt_get_long_name(ra));
  2406. rc = -1;
  2407. goto done;
  2408. }
  2409. sdn = agmt_get_replarea(ra);
  2410. rc = ldap_search_ext_s(ld, slapi_sdn_get_dn(sdn), LDAP_SCOPE_SUBTREE,
  2411. "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))",
  2412. attrs, 0, NULL, NULL, NULL, 0, &result);
  2413. slapi_sdn_free(&sdn);
  2414. if(rc != LDAP_SUCCESS){
  2415. cleanruv_log(task, CLEANALLRUV_ID,"Failed to contact "
  2416. "agmt (%s) error (%d), will retry later.", agmt_get_long_name(ra), rc);
  2417. rc = -1;
  2418. goto done;
  2419. }
  2420. entry = ldap_first_entry( ld, result );
  2421. if ( entry != NULL ) {
  2422. for ( attr = ldap_first_attribute( ld, entry, &ber ); attr != NULL; attr = ldap_next_attribute( ld, entry, ber ) ){
  2423. /* make sure the attribute is nsds50ruv */
  2424. if(strcasecmp(attr,"nsds50ruv") != 0){
  2425. ldap_memfree( attr );
  2426. continue;
  2427. }
  2428. if ((vals = ldap_get_values_len( ld, entry, attr)) != NULL ) {
  2429. for ( i = 0; vals[i] && vals[i]->bv_val; i++ ) {
  2430. /* look for this replica */
  2431. if(strstr(vals[i]->bv_val, rid_text)){
  2432. /* rid has not been cleaned yet, free and return */
  2433. rc = -1;
  2434. ldap_value_free_len(vals);
  2435. ldap_memfree( attr );
  2436. if ( ber != NULL ) {
  2437. ber_free( ber, 0 );
  2438. ber = NULL;
  2439. }
  2440. goto done;
  2441. } else {
  2442. rc = 0;
  2443. }
  2444. }
  2445. ldap_value_free_len(vals);
  2446. }
  2447. ldap_memfree( attr );
  2448. } /* for loop */
  2449. if ( ber != NULL ) {
  2450. ber_free( ber, 0 );
  2451. }
  2452. }
  2453. done:
  2454. if(result)
  2455. ldap_msgfree( result );
  2456. } else {
  2457. return -1;
  2458. }
  2459. conn_delete_internal_ext(conn);
  2460. return rc;
  2461. }
  2462. static int
  2463. get_cleanruv_task_count()
  2464. {
  2465. int i, count = 0;
  2466. slapi_rwlock_wrlock(rid_lock);
  2467. for(i = 0; i < CLEANRIDSIZ; i++){
  2468. if(cleaned_rids[i] != 0){
  2469. count++;
  2470. }
  2471. }
  2472. slapi_rwlock_unlock(rid_lock);
  2473. return count;
  2474. }
  2475. static int
  2476. get_abort_cleanruv_task_count()
  2477. {
  2478. int i, count = 0;
  2479. slapi_rwlock_wrlock(rid_lock);
  2480. for(i = 0; i < CLEANRIDSIZ; i++){
  2481. if(aborted_rids[i] != 0){
  2482. count++;
  2483. }
  2484. }
  2485. slapi_rwlock_unlock(rid_lock);
  2486. return count;
  2487. }
  2488. /*
  2489. * Notify sleeping CLEANALLRUV threads to stop
  2490. */
  2491. void
  2492. stop_ruv_cleaning()
  2493. {
  2494. if(notify_lock){
  2495. PR_Lock( notify_lock );
  2496. PR_NotifyCondVar( notify_cvar );
  2497. PR_Unlock( notify_lock );
  2498. }
  2499. }
  2500. /*
  2501. * Write our logging to the task and error log
  2502. */
  2503. void
  2504. cleanruv_log(Slapi_Task *task, char *task_type, char *fmt, ...)
  2505. {
  2506. va_list ap1;
  2507. va_list ap2;
  2508. va_list ap3;
  2509. va_list ap4;
  2510. char *errlog_fmt;
  2511. va_start(ap1, fmt);
  2512. va_start(ap2, fmt);
  2513. va_start(ap3, fmt);
  2514. va_start(ap4, fmt);
  2515. if(task){
  2516. slapi_task_log_notice_ext(task, fmt, ap1);
  2517. slapi_task_log_status_ext(task, fmt, ap2);
  2518. slapi_task_inc_progress(task);
  2519. }
  2520. errlog_fmt = PR_smprintf("%s: %s\n",task_type, fmt);
  2521. slapi_log_error_ext(SLAPI_LOG_FATAL, repl_plugin_name, errlog_fmt, ap3, ap4);
  2522. slapi_ch_free_string(&errlog_fmt);
  2523. va_end(ap1);
  2524. va_end(ap2);
  2525. va_end(ap3);
  2526. va_end(ap4);
  2527. }