repl5_plugins.c 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
  5. * All rights reserved.
  6. *
  7. * License: GPL (version 3 or any later version).
  8. * See LICENSE for details.
  9. * END COPYRIGHT BLOCK **/
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. /*
  14. * repl5_consumer.c - consumer plugin functions
  15. */
  16. /*
  17. * LDAP Data Model Constraints...
  18. *
  19. * 1) Parent entry must exist.
  20. * 2) RDN must be unique.
  21. * 3) RDN components must be attribute values.
  22. * 4) Must conform to the schema constraints - Single Valued Attributes.
  23. * 5) Must conform to the schema constraints - Required Attributes.
  24. * 6) Must conform to the schema constraints - No Extra Attributes.
  25. * 7) Duplicate attribute values are not permited.
  26. * 8) Cycle in the ancestry graph not permitted.
  27. *
  28. * Update Resolution Procedures...
  29. * 1) ...
  30. * 2) Add the UniqueID to the RDN.
  31. * 3) Remove the not present RDN component.
  32. * Use the UniqueID if the RDN becomes empty.
  33. * 4) Keep the most recent value.
  34. * 5) Ignore.
  35. * 6) Ignore.
  36. * 7) Keep the largest CSN for the duplicate value.
  37. * 8) Don't check for this.
  38. */
  39. #include "repl5.h"
  40. #include "cl5_api.h"
  41. #include "urp.h"
  42. #include "csnpl.h"
  43. static char *local_purl = NULL;
  44. static char *purl_attrs[] = {"nsslapd-localhost", "nsslapd-port", "nsslapd-secureport", NULL};
  45. /* Forward declarations */
  46. static void copy_operation_parameters(Slapi_PBlock *pb);
  47. static int write_changelog_and_ruv(Slapi_PBlock *pb);
  48. static int process_postop(Slapi_PBlock *pb);
  49. static int cancel_opcsn(Slapi_PBlock *pb);
  50. static int ruv_tombstone_op(Slapi_PBlock *pb);
  51. static PRBool process_operation(Slapi_PBlock *pb, const CSN *csn);
  52. static PRBool is_mmr_replica(Slapi_PBlock *pb);
  53. static const char *replica_get_purl_for_op(const Replica *r, Slapi_PBlock *pb, const CSN *opcsn);
  54. /*
  55. * XXXggood - what to do if both ssl and non-ssl ports available? How
  56. * do you know which to use? Offer a choice in replication config?
  57. */
  58. int
  59. multimaster_set_local_purl()
  60. {
  61. int rc = 0;
  62. Slapi_Entry **entries;
  63. Slapi_PBlock *pb = NULL;
  64. pb = slapi_pblock_new();
  65. slapi_search_internal_set_pb(pb, "cn=config", LDAP_SCOPE_BASE,
  66. "objectclass=*", purl_attrs, 0, NULL, NULL,
  67. repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
  68. slapi_search_internal_pb(pb);
  69. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  70. if (rc != 0) {
  71. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "multimaster_set_local_purl - "
  72. "unable to read server configuration: error %d\n",
  73. rc);
  74. } else {
  75. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  76. if (NULL == entries || NULL == entries[0]) {
  77. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "multimaster_set_local_purl - "
  78. "Server configuration missing\n");
  79. rc = -1;
  80. } else {
  81. char *host = slapi_entry_attr_get_charptr(entries[0], "nsslapd-localhost");
  82. char *port = slapi_entry_attr_get_charptr(entries[0], "nsslapd-port");
  83. char *sslport = slapi_entry_attr_get_charptr(entries[0], "nsslapd-secureport");
  84. if (host == NULL || ((port == NULL && sslport == NULL))) {
  85. slapi_log_err(SLAPI_LOG_WARNING, repl_plugin_name,
  86. "multimaster_set_local_purl - Invalid server "
  87. "configuration\n");
  88. } else {
  89. if (slapi_is_ipv6_addr(host)) {
  90. /* need to put brackets around the ipv6 address */
  91. local_purl = slapi_ch_smprintf("ldap://[%s]:%s", host, port);
  92. } else {
  93. local_purl = slapi_ch_smprintf("ldap://%s:%s", host, port);
  94. }
  95. }
  96. /* slapi_ch_free acceptS NULL pointer */
  97. slapi_ch_free((void **)&host);
  98. slapi_ch_free((void **)&port);
  99. slapi_ch_free((void **)&sslport);
  100. }
  101. }
  102. slapi_free_search_results_internal(pb);
  103. slapi_pblock_destroy(pb);
  104. return rc;
  105. }
  106. const char *
  107. multimaster_get_local_purl()
  108. {
  109. return local_purl;
  110. }
  111. /* ================= Multimaster Pre-Op Plugin Points ================== */
  112. int
  113. multimaster_preop_bind(Slapi_PBlock *pb __attribute__((unused)))
  114. {
  115. return 0;
  116. }
  117. int
  118. multimaster_preop_add(Slapi_PBlock *pb)
  119. {
  120. Slapi_Operation *op;
  121. int is_replicated_operation;
  122. int is_fixup_operation;
  123. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  124. if (!is_mmr_replica(pb)) {
  125. copy_operation_parameters(pb);
  126. return SLAPI_PLUGIN_SUCCESS;
  127. }
  128. is_replicated_operation = operation_is_flag_set(op, OP_FLAG_REPLICATED);
  129. is_fixup_operation = operation_is_flag_set(op, OP_FLAG_REPL_FIXUP);
  130. if (is_replicated_operation) {
  131. if (!is_fixup_operation) {
  132. LDAPControl **ctrlp;
  133. char sessionid[REPL_SESSION_ID_SIZE];
  134. get_repl_session_id(pb, sessionid, NULL);
  135. slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
  136. if (NULL != ctrlp) {
  137. CSN *csn = NULL;
  138. char *target_uuid = NULL;
  139. char *superior_uuid = NULL;
  140. int drc = decode_NSDS50ReplUpdateInfoControl(ctrlp, &target_uuid, &superior_uuid, &csn, NULL /* modrdn_mods */);
  141. if (-1 == drc) {
  142. slapi_log_err(SLAPI_LOG_ERR, REPLICATION_SUBSYSTEM,
  143. "multimaster_preop_add - %s An error occurred while decoding the replication update "
  144. "control - Add\n",
  145. sessionid);
  146. } else if (1 == drc) {
  147. /*
  148. * For add operations, we just set the operation csn. The entry's
  149. * uniqueid should already be an attribute of the replicated entry.
  150. */
  151. struct slapi_operation_parameters *op_params;
  152. /* we don't want to process replicated operations with csn smaller
  153. than the corresponding csn in the consumer's ruv */
  154. if (!process_operation(pb, csn)) {
  155. slapi_send_ldap_result(pb, LDAP_SUCCESS, 0,
  156. "replication operation not processed, replica unavailable "
  157. "or csn ignored",
  158. 0, 0);
  159. csn_free(&csn);
  160. slapi_ch_free((void **)&target_uuid);
  161. slapi_ch_free((void **)&superior_uuid);
  162. return SLAPI_PLUGIN_FAILURE;
  163. }
  164. operation_set_csn(op, csn);
  165. slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, target_uuid);
  166. slapi_pblock_get(pb, SLAPI_OPERATION_PARAMETERS, &op_params);
  167. /* JCMREPL - Complain if there's no superior uuid */
  168. op_params->p.p_add.parentuniqueid = superior_uuid; /* JCMREPL - Not very elegant */
  169. /* JCMREPL - When do these things get free'd? */
  170. if (target_uuid != NULL) {
  171. /*
  172. * Make sure that the Unique Identifier in the Control is the
  173. * same as the one in the entry.
  174. */
  175. Slapi_Entry *addentry;
  176. char *entry_uuid;
  177. slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &addentry);
  178. entry_uuid = slapi_entry_attr_get_charptr(addentry, SLAPI_ATTR_UNIQUEID);
  179. if (entry_uuid == NULL) {
  180. /* Odd that the entry doesn't have a Unique Identifier. But, we can fix it. */
  181. slapi_entry_set_uniqueid(addentry, slapi_ch_strdup(target_uuid)); /* JCMREPL - strdup EVIL! There should be a uuid dup function. */
  182. } else {
  183. if (strcasecmp(entry_uuid, target_uuid) != 0) {
  184. slapi_log_err(SLAPI_LOG_WARNING, REPLICATION_SUBSYSTEM,
  185. "multimaster_preop_add - %s Replicated Add received with Control_UUID=%s and Entry_UUID=%s.\n",
  186. sessionid, target_uuid, entry_uuid);
  187. }
  188. slapi_ch_free((void **)&entry_uuid);
  189. }
  190. }
  191. }
  192. } else {
  193. PR_ASSERT(0); /* JCMREPL - A Replicated Operation with no Repl Baggage control... What does that mean? */
  194. }
  195. } else {
  196. /* Replicated & Fixup Operation */
  197. }
  198. } else {
  199. slapi_operation_set_csngen_handler(op, (void *)replica_generate_next_csn);
  200. }
  201. copy_operation_parameters(pb);
  202. return SLAPI_PLUGIN_SUCCESS;
  203. }
  204. int
  205. multimaster_preop_delete(Slapi_PBlock *pb)
  206. {
  207. Slapi_Operation *op;
  208. int is_replicated_operation;
  209. int is_fixup_operation;
  210. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  211. if (!is_mmr_replica(pb)) {
  212. copy_operation_parameters(pb);
  213. return SLAPI_PLUGIN_SUCCESS;
  214. }
  215. is_replicated_operation = operation_is_flag_set(op, OP_FLAG_REPLICATED);
  216. is_fixup_operation = operation_is_flag_set(op, OP_FLAG_REPL_FIXUP);
  217. if (is_replicated_operation) {
  218. if (!is_fixup_operation) {
  219. LDAPControl **ctrlp;
  220. char sessionid[REPL_SESSION_ID_SIZE];
  221. get_repl_session_id(pb, sessionid, NULL);
  222. slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
  223. if (NULL != ctrlp) {
  224. CSN *csn = NULL;
  225. char *target_uuid = NULL;
  226. int drc = decode_NSDS50ReplUpdateInfoControl(ctrlp, &target_uuid, NULL, &csn, NULL /* modrdn_mods */);
  227. if (-1 == drc) {
  228. slapi_log_err(SLAPI_LOG_ERR, REPLICATION_SUBSYSTEM,
  229. "multimaster_preop_delete - %s An error occurred while decoding the replication update "
  230. "control - Delete\n",
  231. sessionid);
  232. } else if (1 == drc) {
  233. /* we don't want to process replicated operations with csn smaller
  234. than the corresponding csn in the consumer's ruv */
  235. if (!process_operation(pb, csn)) {
  236. slapi_send_ldap_result(pb, LDAP_SUCCESS, 0,
  237. "replication operation not processed, replica unavailable "
  238. "or csn ignored",
  239. 0, 0);
  240. slapi_log_err(SLAPI_LOG_REPL, REPLICATION_SUBSYSTEM,
  241. "multimaster_preop_delete - %s replication operation not processed, replica unavailable "
  242. "or csn ignored\n",
  243. sessionid);
  244. csn_free(&csn);
  245. slapi_ch_free((void **)&target_uuid);
  246. return SLAPI_PLUGIN_FAILURE;
  247. }
  248. /*
  249. * For delete operations, we pass the uniqueid of the deleted entry
  250. * to the backend and let it sort out which entry to really delete.
  251. * We also set the operation csn.
  252. */
  253. operation_set_csn(op, csn);
  254. slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, target_uuid);
  255. }
  256. } else {
  257. PR_ASSERT(0); /* JCMREPL - A Replicated Operation with no Repl Baggage control... What does that mean? */
  258. }
  259. } else {
  260. /* Replicated & Fixup Operation */
  261. }
  262. } else {
  263. slapi_operation_set_csngen_handler(op, (void *)replica_generate_next_csn);
  264. }
  265. copy_operation_parameters(pb);
  266. slapi_operation_set_replica_attr_handler(op, (void *)replica_get_attr);
  267. return SLAPI_PLUGIN_SUCCESS;
  268. }
  269. int
  270. multimaster_preop_modify(Slapi_PBlock *pb)
  271. {
  272. Slapi_Operation *op;
  273. int is_replicated_operation;
  274. int is_fixup_operation;
  275. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  276. if (!is_mmr_replica(pb)) {
  277. copy_operation_parameters(pb);
  278. return SLAPI_PLUGIN_SUCCESS;
  279. }
  280. is_replicated_operation = operation_is_flag_set(op, OP_FLAG_REPLICATED);
  281. is_fixup_operation = operation_is_flag_set(op, OP_FLAG_REPL_FIXUP);
  282. if (is_replicated_operation) {
  283. if (!is_fixup_operation) {
  284. LDAPControl **ctrlp;
  285. char sessionid[REPL_SESSION_ID_SIZE];
  286. get_repl_session_id(pb, sessionid, NULL);
  287. slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
  288. if (NULL != ctrlp) {
  289. CSN *csn = NULL;
  290. char *target_uuid = NULL;
  291. int drc = decode_NSDS50ReplUpdateInfoControl(ctrlp, &target_uuid, NULL, &csn, NULL /* modrdn_mods */);
  292. if (-1 == drc) {
  293. slapi_log_err(SLAPI_LOG_ERR, REPLICATION_SUBSYSTEM,
  294. "multimaster_preop_modify - %s An error occurred while decoding the replication update "
  295. "control- Modify\n",
  296. sessionid);
  297. } else if (1 == drc) {
  298. /* we don't want to process replicated operations with csn smaller
  299. than the corresponding csn in the consumer's ruv */
  300. if (!process_operation(pb, csn)) {
  301. slapi_send_ldap_result(pb, LDAP_SUCCESS, 0,
  302. "replication operation not processed, replica unavailable "
  303. "or csn ignored",
  304. 0, 0);
  305. slapi_log_err(SLAPI_LOG_REPL, REPLICATION_SUBSYSTEM,
  306. "multimaster_preop_modify - %s replication operation not processed, replica unavailable "
  307. "or csn ignored\n",
  308. sessionid);
  309. csn_free(&csn);
  310. slapi_ch_free((void **)&target_uuid);
  311. return SLAPI_PLUGIN_FAILURE;
  312. }
  313. /*
  314. * For modify operations, we pass the uniqueid of the modified entry
  315. * to the backend and let it sort out which entry to really modify.
  316. * We also set the operation csn.
  317. */
  318. operation_set_csn(op, csn);
  319. slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, target_uuid);
  320. }
  321. } else {
  322. /* PR_ASSERT(0); JCMREPL - A Replicated Operation with no Repl Baggage control... What does that mean? */
  323. /*
  324. * This could be RI plugin responding to a replicated update from AD or some other master that is not
  325. * using the RI plugin, so don't PR_ASSERT here. This only happens if we configure the RI plugin with
  326. * "nsslapd-pluginAllowReplUpdates: on", also the RI plugin only issues "modifies".
  327. */
  328. }
  329. } else {
  330. /* Replicated & Fixup Operation */
  331. }
  332. } else {
  333. slapi_operation_set_csngen_handler(op, (void *)replica_generate_next_csn);
  334. }
  335. copy_operation_parameters(pb);
  336. return SLAPI_PLUGIN_SUCCESS;
  337. }
  338. int
  339. multimaster_preop_modrdn(Slapi_PBlock *pb)
  340. {
  341. Slapi_Operation *op;
  342. int is_replicated_operation;
  343. int is_fixup_operation;
  344. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  345. if (!is_mmr_replica(pb)) {
  346. copy_operation_parameters(pb);
  347. return SLAPI_PLUGIN_SUCCESS;
  348. }
  349. is_replicated_operation = operation_is_flag_set(op, OP_FLAG_REPLICATED);
  350. is_fixup_operation = operation_is_flag_set(op, OP_FLAG_REPL_FIXUP);
  351. if (is_replicated_operation) {
  352. if (!is_fixup_operation) {
  353. LDAPControl **ctrlp;
  354. char sessionid[REPL_SESSION_ID_SIZE];
  355. get_repl_session_id(pb, sessionid, NULL);
  356. slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
  357. if (NULL != ctrlp) {
  358. CSN *csn = NULL;
  359. char *target_uuid = NULL;
  360. char *newsuperior_uuid = NULL;
  361. LDAPMod **modrdn_mods = NULL;
  362. int drc = decode_NSDS50ReplUpdateInfoControl(ctrlp, &target_uuid, &newsuperior_uuid,
  363. &csn, &modrdn_mods);
  364. if (-1 == drc) {
  365. slapi_log_err(SLAPI_LOG_ERR, REPLICATION_SUBSYSTEM,
  366. "multimaster_preop_modrdn - %s An error occurred while decoding the replication update "
  367. "control - ModRDN\n",
  368. sessionid);
  369. } else if (1 == drc) {
  370. /*
  371. * For modrdn operations, we pass the uniqueid of the entry being
  372. * renamed to the backend and let it sort out which entry to really
  373. * rename. We also set the operation csn, and if the newsuperior_uuid
  374. * was sent, we decode that as well.
  375. */
  376. struct slapi_operation_parameters *op_params;
  377. /* we don't want to process replicated operations with csn smaller
  378. than the corresponding csn in the consumer's ruv */
  379. if (!process_operation(pb, csn)) {
  380. slapi_send_ldap_result(pb, LDAP_SUCCESS, 0,
  381. "replication operation not processed, replica unavailable "
  382. "or csn ignored",
  383. 0, 0);
  384. csn_free(&csn);
  385. slapi_ch_free((void **)&target_uuid);
  386. slapi_ch_free((void **)&newsuperior_uuid);
  387. ldap_mods_free(modrdn_mods, 1);
  388. return SLAPI_PLUGIN_FAILURE;
  389. }
  390. operation_set_csn(op, csn);
  391. slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, target_uuid);
  392. slapi_pblock_get(pb, SLAPI_OPERATION_PARAMETERS, &op_params);
  393. op_params->p.p_modrdn.modrdn_newsuperior_address.uniqueid = newsuperior_uuid; /* JCMREPL - Not very elegant */
  394. }
  395. /*
  396. * The replicated modrdn operation may also contain a sequence
  397. * that contains side effects of the modrdn operation, e.g. the
  398. * modifiersname and modifytimestamp are updated.
  399. */
  400. if (NULL != modrdn_mods) {
  401. LDAPMod **mods;
  402. Slapi_Mods smods;
  403. int i;
  404. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  405. slapi_mods_init_passin(&smods, mods);
  406. for (i = 0; NULL != modrdn_mods[i]; i++) {
  407. slapi_mods_add_ldapmod(&smods, modrdn_mods[i]); /* Does not copy mod */
  408. }
  409. mods = slapi_mods_get_ldapmods_passout(&smods);
  410. slapi_pblock_set(pb, SLAPI_MODIFY_MODS, mods);
  411. slapi_mods_done(&smods);
  412. slapi_ch_free((void **)&modrdn_mods); /* Free container only - contents are referred to by array "mods" */
  413. }
  414. } else {
  415. PR_ASSERT(0); /* JCMREPL - A Replicated Operation with no Repl Baggage control... What does that mean? */
  416. }
  417. } else {
  418. /* Replicated & Fixup Operation */
  419. }
  420. } else {
  421. slapi_operation_set_csngen_handler(op, (void *)replica_generate_next_csn);
  422. }
  423. copy_operation_parameters(pb);
  424. return SLAPI_PLUGIN_SUCCESS;
  425. }
  426. int
  427. multimaster_preop_search(Slapi_PBlock *pb __attribute__((unused)))
  428. {
  429. return SLAPI_PLUGIN_SUCCESS;
  430. }
  431. int
  432. multimaster_preop_compare(Slapi_PBlock *pb __attribute__((unused)))
  433. {
  434. return SLAPI_PLUGIN_SUCCESS;
  435. }
  436. int
  437. multimaster_ruv_search(Slapi_PBlock *pb)
  438. {
  439. Slapi_Entry *e, *e_alt;
  440. Slapi_DN *suffix_sdn;
  441. Slapi_Operation *operation;
  442. slapi_pblock_get(pb, SLAPI_SEARCH_ENTRY_ORIG, &e);
  443. slapi_pblock_get(pb, SLAPI_OPERATION, &operation);
  444. if ((e == NULL) || (operation == NULL))
  445. return SLAPI_PLUGIN_SUCCESS;
  446. if (!operation_is_flag_set(operation, OP_FLAG_INTERNAL) && is_ruv_tombstone_entry(e)) {
  447. /* We are about to send back the database RUV, we need to return
  448. * in memory RUV instead
  449. */
  450. /* Retrieve the suffix DN from the RUV entry */
  451. suffix_sdn = slapi_sdn_new();
  452. slapi_sdn_get_parent(slapi_entry_get_sdn(e), suffix_sdn);
  453. /* Now set the in memory RUV into the pblock */
  454. if ((e_alt = get_in_memory_ruv(suffix_sdn)) != NULL) {
  455. slapi_pblock_set(pb, SLAPI_SEARCH_ENTRY_COPY, e_alt);
  456. }
  457. slapi_sdn_free(&suffix_sdn);
  458. }
  459. return SLAPI_PLUGIN_SUCCESS;
  460. }
  461. static void
  462. purge_entry_state_information(Slapi_PBlock *pb)
  463. {
  464. CSN *purge_csn = NULL;
  465. Object *repl_obj;
  466. Replica *replica;
  467. /* we don't want to trim RUV tombstone because we will
  468. deadlock with ourself */
  469. if (ruv_tombstone_op(pb))
  470. return;
  471. repl_obj = replica_get_replica_for_op(pb);
  472. if (NULL != repl_obj) {
  473. replica = object_get_data(repl_obj);
  474. if (NULL != replica) {
  475. purge_csn = replica_get_purge_csn(replica);
  476. }
  477. if (NULL != purge_csn) {
  478. Slapi_Entry *e;
  479. int optype;
  480. slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &optype);
  481. switch (optype) {
  482. case SLAPI_OPERATION_MODIFY:
  483. slapi_pblock_get(pb, SLAPI_MODIFY_EXISTING_ENTRY, &e);
  484. break;
  485. case SLAPI_OPERATION_MODRDN:
  486. /* XXXggood - the following always gives a NULL entry - why? */
  487. slapi_pblock_get(pb, SLAPI_MODRDN_EXISTING_ENTRY, &e);
  488. break;
  489. case SLAPI_OPERATION_DELETE:
  490. slapi_pblock_get(pb, SLAPI_DELETE_EXISTING_ENTRY, &e);
  491. break;
  492. default:
  493. e = NULL; /* Don't purge on ADD - not needed */
  494. break;
  495. }
  496. if (NULL != e) {
  497. entry_purge_state_information(e, purge_csn);
  498. /* conntion is always null */
  499. if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
  500. char csn_str[CSN_STRSIZE];
  501. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  502. "purge_entry_state_information - From entry %s up to "
  503. "CSN %s\n",
  504. slapi_entry_get_dn(e),
  505. csn_as_string(purge_csn, PR_FALSE, csn_str));
  506. }
  507. }
  508. csn_free(&purge_csn);
  509. }
  510. object_release(repl_obj);
  511. }
  512. }
  513. int
  514. multimaster_mmr_preop (Slapi_PBlock *pb, int flags)
  515. {
  516. int rc= SLAPI_PLUGIN_SUCCESS;
  517. switch (flags)
  518. {
  519. case SLAPI_PLUGIN_BE_PRE_ADD_FN:
  520. rc = multimaster_bepreop_add(pb);
  521. break;
  522. case SLAPI_PLUGIN_BE_PRE_MODIFY_FN:
  523. rc = multimaster_bepreop_modify(pb);
  524. break;
  525. case SLAPI_PLUGIN_BE_PRE_MODRDN_FN:
  526. rc = multimaster_bepreop_modrdn(pb);
  527. break;
  528. case SLAPI_PLUGIN_BE_PRE_DELETE_FN:
  529. rc = multimaster_bepreop_delete(pb);
  530. break;
  531. }
  532. return rc;
  533. }
  534. int
  535. multimaster_mmr_postop (Slapi_PBlock *pb, int flags)
  536. {
  537. int rc= SLAPI_PLUGIN_SUCCESS;
  538. switch (flags)
  539. {
  540. case SLAPI_PLUGIN_BE_TXN_POST_ADD_FN:
  541. rc = multimaster_be_betxnpostop_add(pb);
  542. break;
  543. case SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN:
  544. rc = multimaster_be_betxnpostop_delete(pb);
  545. break;
  546. case SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN:
  547. rc = multimaster_be_betxnpostop_modify(pb);
  548. break;
  549. case SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN:
  550. rc = multimaster_be_betxnpostop_modrdn(pb);
  551. break;
  552. }
  553. slapi_log_err(SLAPI_LOG_REPL, REPLICATION_SUBSYSTEM,
  554. "multimaster_mmr_postop - error %d for oparation %d.\n", rc, flags);
  555. return rc;
  556. }
  557. /* pure bepreop's -- should be done before transaction starts */
  558. int
  559. multimaster_bepreop_add(Slapi_PBlock *pb)
  560. {
  561. int rc = SLAPI_PLUGIN_SUCCESS;
  562. Slapi_Operation *op;
  563. int is_replicated_operation;
  564. int is_fixup_operation;
  565. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  566. is_replicated_operation = operation_is_flag_set(op, OP_FLAG_REPLICATED);
  567. is_fixup_operation = operation_is_flag_set(op, OP_FLAG_REPL_FIXUP);
  568. /* For replicated operations, apply URP algorithm */
  569. if (!is_fixup_operation) {
  570. slapi_pblock_set(pb, SLAPI_TXN_RUV_MODS_FN,
  571. (void *)replica_ruv_smods_for_op);
  572. if (is_replicated_operation) {
  573. rc = urp_add_operation(pb);
  574. }
  575. }
  576. return rc;
  577. }
  578. int
  579. multimaster_bepreop_delete(Slapi_PBlock *pb)
  580. {
  581. int rc = SLAPI_PLUGIN_SUCCESS;
  582. Slapi_Operation *op;
  583. int is_replicated_operation;
  584. int is_fixup_operation;
  585. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  586. is_replicated_operation = operation_is_flag_set(op, OP_FLAG_REPLICATED);
  587. is_fixup_operation = operation_is_flag_set(op, OP_FLAG_REPL_FIXUP);
  588. /* For replicated operations, apply URP algorithm */
  589. if (!is_fixup_operation) {
  590. slapi_pblock_set(pb, SLAPI_TXN_RUV_MODS_FN,
  591. (void *)replica_ruv_smods_for_op);
  592. if (is_replicated_operation) {
  593. rc = urp_delete_operation(pb);
  594. }
  595. }
  596. return rc;
  597. }
  598. int
  599. multimaster_bepreop_modify(Slapi_PBlock *pb)
  600. {
  601. int rc = SLAPI_PLUGIN_SUCCESS;
  602. Slapi_Operation *op;
  603. int is_replicated_operation;
  604. int is_fixup_operation;
  605. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  606. is_replicated_operation = operation_is_flag_set(op, OP_FLAG_REPLICATED);
  607. is_fixup_operation = operation_is_flag_set(op, OP_FLAG_REPL_FIXUP);
  608. /* For replicated operations, apply URP algorithm */
  609. if (!is_fixup_operation) {
  610. slapi_pblock_set(pb, SLAPI_TXN_RUV_MODS_FN,
  611. (void *)replica_ruv_smods_for_op);
  612. if (is_replicated_operation) {
  613. rc = urp_modify_operation(pb);
  614. }
  615. }
  616. /* Clean up old state information */
  617. purge_entry_state_information(pb);
  618. return rc;
  619. }
  620. int
  621. multimaster_bepreop_modrdn(Slapi_PBlock *pb)
  622. {
  623. int rc = SLAPI_PLUGIN_SUCCESS;
  624. Slapi_Operation *op;
  625. int is_replicated_operation;
  626. int is_fixup_operation;
  627. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  628. is_replicated_operation = operation_is_flag_set(op, OP_FLAG_REPLICATED);
  629. is_fixup_operation = operation_is_flag_set(op, OP_FLAG_REPL_FIXUP);
  630. /* For replicated operations, apply URP algorithm */
  631. if (!is_fixup_operation) {
  632. slapi_pblock_set(pb, SLAPI_TXN_RUV_MODS_FN,
  633. (void *)replica_ruv_smods_for_op);
  634. if (is_replicated_operation) {
  635. rc = urp_modrdn_operation(pb);
  636. }
  637. }
  638. /* Clean up old state information */
  639. purge_entry_state_information(pb);
  640. return rc;
  641. }
  642. int
  643. multimaster_bepostop_add(Slapi_PBlock *pb)
  644. {
  645. Slapi_Operation *op;
  646. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  647. if ( ! operation_is_flag_set (op, OP_FLAG_REPL_FIXUP) ) {
  648. urp_post_add_operation (pb);
  649. }
  650. return SLAPI_PLUGIN_SUCCESS;
  651. }
  652. int
  653. multimaster_bepostop_modrdn(Slapi_PBlock *pb)
  654. {
  655. Slapi_Operation *op;
  656. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  657. if (!operation_is_flag_set(op, OP_FLAG_REPL_FIXUP)) {
  658. urp_post_modrdn_operation(pb);
  659. }
  660. return SLAPI_PLUGIN_SUCCESS;
  661. }
  662. int
  663. multimaster_bepostop_delete(Slapi_PBlock *pb)
  664. {
  665. Slapi_Operation *op;
  666. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  667. if (!operation_is_flag_set(op, OP_FLAG_REPL_FIXUP)) {
  668. urp_post_delete_operation(pb);
  669. }
  670. return SLAPI_PLUGIN_SUCCESS;
  671. }
  672. /* postop - write to changelog */
  673. int
  674. multimaster_postop_bind(Slapi_PBlock *pb __attribute__((unused)))
  675. {
  676. return SLAPI_PLUGIN_SUCCESS;
  677. }
  678. int
  679. multimaster_postop_add(Slapi_PBlock *pb)
  680. {
  681. return process_postop(pb);
  682. }
  683. int
  684. multimaster_postop_delete(Slapi_PBlock *pb)
  685. {
  686. return process_postop(pb);
  687. }
  688. int
  689. multimaster_postop_modify(Slapi_PBlock *pb)
  690. {
  691. return process_postop(pb);
  692. }
  693. int
  694. multimaster_postop_modrdn(Slapi_PBlock *pb)
  695. {
  696. return process_postop(pb);
  697. }
  698. int
  699. multimaster_betxnpostop_delete(Slapi_PBlock *pb)
  700. {
  701. return write_changelog_and_ruv(pb);
  702. }
  703. int
  704. multimaster_betxnpostop_modrdn(Slapi_PBlock *pb)
  705. {
  706. return write_changelog_and_ruv(pb);
  707. }
  708. int
  709. multimaster_betxnpostop_add(Slapi_PBlock *pb)
  710. {
  711. return write_changelog_and_ruv(pb);
  712. }
  713. int
  714. multimaster_betxnpostop_modify(Slapi_PBlock *pb)
  715. {
  716. return write_changelog_and_ruv(pb);
  717. }
  718. /* If nsslapd-pluginbetxn is on */
  719. int
  720. multimaster_be_betxnpostop_delete(Slapi_PBlock *pb)
  721. {
  722. int rc = SLAPI_PLUGIN_SUCCESS;
  723. /* original betxnpost */
  724. rc = write_changelog_and_ruv(pb);
  725. /* original bepost */
  726. rc |= multimaster_bepostop_delete(pb);
  727. return rc;
  728. }
  729. int
  730. multimaster_be_betxnpostop_modrdn(Slapi_PBlock *pb)
  731. {
  732. int rc = 0;
  733. /* original betxnpost */
  734. rc = write_changelog_and_ruv(pb);
  735. /* original bepost */
  736. rc |= multimaster_bepostop_modrdn(pb);
  737. return rc;
  738. }
  739. int
  740. multimaster_be_betxnpostop_add(Slapi_PBlock *pb)
  741. {
  742. int rc = 0;
  743. /* original betxnpost */
  744. rc = write_changelog_and_ruv(pb);
  745. rc |= multimaster_bepostop_add(pb);
  746. return rc;
  747. }
  748. int
  749. multimaster_be_betxnpostop_modify(Slapi_PBlock *pb)
  750. {
  751. int rc = 0;
  752. /* original betxnpost */
  753. rc = write_changelog_and_ruv(pb);
  754. return rc;
  755. }
  756. /* Helper functions */
  757. /*
  758. * This function makes a copy of the operation parameters
  759. * and stashes them in the consumer operation extension.
  760. * This is where the 5.0 Change Log will get the operation
  761. * details from.
  762. */
  763. static void
  764. copy_operation_parameters(Slapi_PBlock *pb)
  765. {
  766. Slapi_Operation *op = NULL;
  767. struct slapi_operation_parameters *op_params;
  768. supplier_operation_extension *opext;
  769. Object *repl_obj;
  770. Replica *replica;
  771. repl_obj = replica_get_replica_for_op(pb);
  772. /* we are only interested in the updates to replicas */
  773. if (repl_obj) {
  774. /* we only save the original operation parameters for replicated operations
  775. since client operations don't go through urp engine and pblock data can be logged */
  776. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  777. if (NULL == op) {
  778. slapi_log_err(SLAPI_LOG_REPL, REPLICATION_SUBSYSTEM,
  779. "copy_operation_parameters - operation is null.\n");
  780. return;
  781. }
  782. replica = (Replica *)object_get_data(repl_obj);
  783. if (NULL == replica) {
  784. slapi_log_err(SLAPI_LOG_REPL, REPLICATION_SUBSYSTEM,
  785. "copy_operation_parameters - replica is null.\n");
  786. return;
  787. }
  788. opext = (supplier_operation_extension *)repl_sup_get_ext(REPL_SUP_EXT_OP, op);
  789. if (operation_is_flag_set(op, OP_FLAG_REPLICATED) &&
  790. !operation_is_flag_set(op, OP_FLAG_REPL_FIXUP)) {
  791. slapi_pblock_get(pb, SLAPI_OPERATION_PARAMETERS, &op_params);
  792. opext->operation_parameters = operation_parameters_dup(op_params);
  793. }
  794. /* this condition is needed to avoid re-entering backend serial lock
  795. when ruv state is updated */
  796. if (!operation_is_flag_set(op, OP_FLAG_REPL_FIXUP)) {
  797. /* save replica generation in case it changes */
  798. opext->repl_gen = replica_get_generation(replica);
  799. }
  800. object_release(repl_obj);
  801. }
  802. }
  803. /*
  804. * Helper function: update the RUV so that it reflects the
  805. * locally-processed update. This is called for both replicated
  806. * and non-replicated operations.
  807. */
  808. static int
  809. update_ruv_component(Replica *replica, CSN *opcsn, Slapi_PBlock *pb)
  810. {
  811. char *purl;
  812. int rc = RUV_NOTFOUND;
  813. if (!replica || !opcsn)
  814. return rc;
  815. /* Replica configured, so update its ruv */
  816. purl = (char *)replica_get_purl_for_op(replica, pb, opcsn);
  817. rc = replica_update_ruv(replica, opcsn, purl);
  818. return rc;
  819. }
  820. /*
  821. * Write the changelog. Note: it is an error to call write_changelog_and_ruv() for fixup
  822. * operations. The caller should avoid calling this function if the operation is
  823. * a fixup op.
  824. * Also update the ruv - we need to do this while we have the replica lock acquired
  825. * so that the csn is written to the changelog and the ruv is updated with the csn
  826. * in one atomic operation - if there is no changelog, we still need to update
  827. * the ruv (e.g. for consumers)
  828. */
  829. static int
  830. write_changelog_and_ruv(Slapi_PBlock *pb)
  831. {
  832. Slapi_Operation *op = NULL;
  833. CSN *opcsn;
  834. CSNPL_CTX *prim_csn;
  835. int rc;
  836. slapi_operation_parameters *op_params = NULL;
  837. Object *repl_obj = NULL;
  838. int return_value = SLAPI_PLUGIN_SUCCESS;
  839. Replica *r;
  840. Slapi_Backend *be;
  841. int is_replicated_operation = 0;
  842. /* we just let fixup operations through */
  843. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  844. if (NULL == op) {
  845. return return_value;
  846. }
  847. if ((operation_is_flag_set(op, OP_FLAG_REPL_FIXUP)) ||
  848. (operation_is_flag_set(op, OP_FLAG_TOMBSTONE_ENTRY))) {
  849. return return_value;
  850. }
  851. /* ignore operations intended for chaining backends - they will be
  852. replicated back to us or should be ignored anyway
  853. replicated operations should be processed normally, as they should
  854. be going to a local backend */
  855. is_replicated_operation = operation_is_flag_set(op, OP_FLAG_REPLICATED);
  856. slapi_pblock_get(pb, SLAPI_BACKEND, &be);
  857. if (!is_replicated_operation &&
  858. slapi_be_is_flag_set(be, SLAPI_BE_FLAG_REMOTE_DATA)) {
  859. return return_value;
  860. }
  861. /* we only log changes for operations applied to a replica */
  862. repl_obj = replica_get_replica_for_op(pb);
  863. if (repl_obj == NULL)
  864. return return_value;
  865. r = (Replica *)object_get_data(repl_obj);
  866. PR_ASSERT(r);
  867. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc);
  868. if (rc) { /* op failed - just return */
  869. cancel_opcsn(pb);
  870. goto common_return;
  871. }
  872. replica_check_release_timeout(r, pb);
  873. if (replica_is_flag_set(r, REPLICA_LOG_CHANGES) &&
  874. (cl5GetState() == CL5_STATE_OPEN)) {
  875. supplier_operation_extension *opext = NULL;
  876. const char *repl_name;
  877. char *repl_gen;
  878. opext = (supplier_operation_extension *)repl_sup_get_ext(REPL_SUP_EXT_OP, op);
  879. PR_ASSERT(opext);
  880. /* get replica generation and replica name to pass to the write function */
  881. repl_name = replica_get_name(r);
  882. repl_gen = opext->repl_gen;
  883. PR_ASSERT(repl_name && repl_gen);
  884. /* for replicated operations, we log the original, non-urp data which is
  885. saved in the operation extension */
  886. if (operation_is_flag_set(op, OP_FLAG_REPLICATED)) {
  887. PR_ASSERT(opext->operation_parameters);
  888. op_params = opext->operation_parameters;
  889. } else /* since client operations don't go through urp, we log the operation data in pblock */
  890. {
  891. Slapi_Entry *e = NULL;
  892. const char *uniqueid = NULL;
  893. slapi_pblock_get(pb, SLAPI_OPERATION_PARAMETERS, &op_params);
  894. if (NULL == op_params) {
  895. goto common_return;
  896. }
  897. /* need to set uniqueid operation parameter */
  898. /* we try to use the appropriate entry (pre op or post op)
  899. depending on the type of operation (add, delete, modify)
  900. However, in some cases, the backend operation may fail in
  901. a non fatal way (e.g. attempt to remove an attribute value
  902. that does not exist) but we still need to log the change.
  903. So, the POST_OP entry may not have been set in the FE modify
  904. code. In that case, we use the PRE_OP entry.
  905. */
  906. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
  907. if ((e == NULL) ||
  908. (op_params->operation_type == SLAPI_OPERATION_DELETE)) {
  909. slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e);
  910. }
  911. if (NULL == e) {
  912. goto common_return;
  913. }
  914. uniqueid = slapi_entry_get_uniqueid(e);
  915. if (NULL == uniqueid) {
  916. goto common_return;
  917. }
  918. op_params->target_address.uniqueid = slapi_ch_strdup(uniqueid);
  919. }
  920. if (op_params->csn && is_cleaned_rid(csn_get_replicaid(op_params->csn))) {
  921. /* this RID has been cleaned */
  922. goto common_return;
  923. }
  924. /* we might have stripped all the mods - in that case we do not
  925. log the operation */
  926. if (op_params->operation_type != SLAPI_OPERATION_MODIFY ||
  927. op_params->p.p_modify.modify_mods != NULL) {
  928. void *txn = NULL;
  929. char csn_str[CSN_STRSIZE];
  930. if (cl5_is_diskfull() && !cl5_diskspace_is_available()) {
  931. slapi_log_err(SLAPI_LOG_CRIT, repl_plugin_name,
  932. "write_changelog_and_ruv - Skipped due to DISKFULL\n");
  933. goto common_return;
  934. }
  935. slapi_pblock_get(pb, SLAPI_TXN, &txn);
  936. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  937. "write_changelog_and_ruv - Writing change for "
  938. "%s (uniqid: %s, optype: %lu) to changelog csn %s\n",
  939. REPL_GET_DN(&op_params->target_address),
  940. op_params->target_address.uniqueid,
  941. op_params->operation_type,
  942. csn_as_string(op_params->csn, PR_FALSE, csn_str));
  943. rc = cl5WriteOperationTxn(repl_name, repl_gen, op_params,
  944. !operation_is_flag_set(op, OP_FLAG_REPLICATED), txn);
  945. if (rc != CL5_SUCCESS) {
  946. /* ONREPL - log error */
  947. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
  948. "write_changelog_and_ruv - Can't add a change for "
  949. "%s (uniqid: %s, optype: %lu) to changelog csn %s\n",
  950. REPL_GET_DN(&op_params->target_address),
  951. op_params->target_address.uniqueid,
  952. op_params->operation_type,
  953. csn_as_string(op_params->csn, PR_FALSE, csn_str));
  954. return_value = SLAPI_PLUGIN_FAILURE;
  955. }
  956. }
  957. if (!operation_is_flag_set(op, OP_FLAG_REPLICATED)) {
  958. slapi_ch_free((void **)&op_params->target_address.uniqueid);
  959. }
  960. }
  961. /*
  962. This was moved because we need to write the changelog and update
  963. the ruv in one atomic operation - I have seen cases where the inc
  964. protocol thread interrupts this thread between the time the changelog
  965. is written and the ruv is updated - this causes confusion in several
  966. places, especially in _cl5SkipReplayEntry since it cannot find the csn it
  967. just read from the changelog in either the supplier or consumer ruv
  968. */
  969. if (0 == return_value) {
  970. char csn_str[CSN_STRSIZE] = {'\0'};
  971. int rc;
  972. const char *dn = op_params ? REPL_GET_DN(&op_params->target_address) : "unknown";
  973. Slapi_DN *sdn = op_params ? (&op_params->target_address)->sdn : NULL;
  974. char *uniqueid = op_params ? op_params->target_address.uniqueid : "unknown";
  975. unsigned long optype = op_params ? op_params->operation_type : 0;
  976. CSN *oppcsn = op_params ? op_params->csn : NULL;
  977. LDAPMod **mods = op_params ? op_params->p.p_modify.modify_mods : NULL;
  978. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  979. opcsn = operation_get_csn(op);
  980. /* Update each agmt's maxcsn */
  981. if (op_params && sdn) {
  982. agmt_update_maxcsn(r, sdn, op_params->operation_type, mods, opcsn);
  983. }
  984. rc = update_ruv_component(r, opcsn, pb);
  985. if (RUV_COVERS_CSN == rc) {
  986. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  987. "write_changelog_and_ruv - RUV already covers csn for "
  988. "%s (uniqid: %s, optype: %lu) csn %s\n",
  989. dn, uniqueid, optype,
  990. csn_as_string(oppcsn, PR_FALSE, csn_str));
  991. } else if ((rc != RUV_SUCCESS) && (rc != RUV_NOTFOUND)) {
  992. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
  993. "write_changelog_and_ruv - Failed to update RUV for "
  994. "%s (uniqid: %s, optype: %lu) to changelog csn %s - rc %d\n",
  995. dn, uniqueid, optype,
  996. csn_as_string(oppcsn, PR_FALSE, csn_str), rc);
  997. }
  998. }
  999. common_return:
  1000. opcsn = operation_get_csn(op);
  1001. prim_csn = get_thread_primary_csn();
  1002. if (csn_primary(r, opcsn, prim_csn)) {
  1003. if (return_value == 0) {
  1004. /* the primary csn was succesfully committed
  1005. * unset it in the thread local data
  1006. */
  1007. set_thread_primary_csn(NULL, NULL);
  1008. }
  1009. }
  1010. if (repl_obj) {
  1011. object_release(repl_obj);
  1012. }
  1013. return return_value;
  1014. }
  1015. /*
  1016. * Postop processing - write the changelog if the operation resulted in
  1017. * an LDAP_SUCCESS result code, update the RUV, and notify the replication
  1018. * agreements about the change.
  1019. * If the result code is not LDAP_SUCCESS, then cancel the operation CSN.
  1020. */
  1021. static int
  1022. process_postop(Slapi_PBlock *pb)
  1023. {
  1024. Slapi_Operation *op;
  1025. Slapi_Backend *be;
  1026. int is_replicated_operation = 0;
  1027. CSN *opcsn = NULL;
  1028. char sessionid[REPL_SESSION_ID_SIZE];
  1029. int retval = LDAP_SUCCESS;
  1030. int rc = 0;
  1031. /* we just let fixup operations through */
  1032. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  1033. if ((operation_is_flag_set(op, OP_FLAG_REPL_FIXUP)) ||
  1034. (operation_is_flag_set(op, OP_FLAG_TOMBSTONE_ENTRY))) {
  1035. return SLAPI_PLUGIN_SUCCESS;
  1036. }
  1037. /* ignore operations intended for chaining backends - they will be
  1038. replicated back to us or should be ignored anyway
  1039. replicated operations should be processed normally, as they should
  1040. be going to a local backend */
  1041. is_replicated_operation = operation_is_flag_set(op, OP_FLAG_REPLICATED);
  1042. slapi_pblock_get(pb, SLAPI_BACKEND, &be);
  1043. if (!is_replicated_operation &&
  1044. slapi_be_is_flag_set(be, SLAPI_BE_FLAG_REMOTE_DATA)) {
  1045. return SLAPI_PLUGIN_SUCCESS;
  1046. }
  1047. get_repl_session_id(pb, sessionid, &opcsn);
  1048. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &retval);
  1049. if (retval == LDAP_SUCCESS) {
  1050. agmtlist_notify_all(pb);
  1051. rc = SLAPI_PLUGIN_SUCCESS;
  1052. } else if (opcsn) {
  1053. rc = cancel_opcsn(pb);
  1054. /* Don't try to get session id since conn is always null */
  1055. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  1056. "process postop - %s canceling operation csn\n", sessionid);
  1057. } else {
  1058. rc = SLAPI_PLUGIN_FAILURE;
  1059. }
  1060. /* the target unique id is set in the modify_preop above, so
  1061. we need to free it */
  1062. /* The following bunch of frees code does not belong to this place
  1063. * but rather to operation_free who should be responsible for calling
  1064. * operation_parameters_free and it doesn't. I guess this is like this
  1065. * because several crashes happened in the past regarding some opparams
  1066. * that were getting individually freed before they should. Whatever
  1067. * the case, this is not the place and we should make sure that this
  1068. * code gets removed for 5.next and substituted by the strategy (operation_free).
  1069. * For 5.0, such change is too risky, so this will be done here */
  1070. if (is_replicated_operation) {
  1071. slapi_operation_parameters *op_params = NULL;
  1072. int optype = 0;
  1073. /* target uid and csn are set for all repl operations. Free them */
  1074. char *target_uuid = NULL;
  1075. slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &optype);
  1076. slapi_pblock_get(pb, SLAPI_TARGET_UNIQUEID, &target_uuid);
  1077. slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, NULL);
  1078. slapi_ch_free((void **)&target_uuid);
  1079. if (optype == SLAPI_OPERATION_ADD) {
  1080. slapi_pblock_get(pb, SLAPI_OPERATION_PARAMETERS, &op_params);
  1081. slapi_ch_free((void **)&op_params->p.p_add.parentuniqueid);
  1082. }
  1083. if (optype == SLAPI_OPERATION_MODRDN) {
  1084. slapi_pblock_get(pb, SLAPI_OPERATION_PARAMETERS, &op_params);
  1085. slapi_ch_free((void **)&op_params->p.p_modrdn.modrdn_newsuperior_address.uniqueid);
  1086. }
  1087. if (!ignore_error_and_keep_going(retval)) {
  1088. /*
  1089. * We have an error we can't ignore. Release the replica and close
  1090. * the connection to stop the replication session.
  1091. */
  1092. consumer_connection_extension *connext = NULL;
  1093. Slapi_Connection *conn = NULL;
  1094. char csn_str[CSN_STRSIZE] = {'\0'};
  1095. PRUint64 connid = 0;
  1096. int opid = 0;
  1097. slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
  1098. slapi_pblock_get(pb, SLAPI_OPERATION_ID, &opid);
  1099. slapi_pblock_get(pb, SLAPI_CONN_ID, &connid);
  1100. if (conn) {
  1101. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
  1102. "process_postop - Failed to apply update (%s) error (%d). "
  1103. "Aborting replication session(conn=%" PRIu64 " op=%d)\n",
  1104. csn_as_string(opcsn, PR_FALSE, csn_str), retval,
  1105. connid, opid);
  1106. /*
  1107. * Release this replica so new sessions can begin
  1108. */
  1109. connext = consumer_connection_extension_acquire_exclusive_access(conn, connid, opid);
  1110. if (connext && connext->replica_acquired) {
  1111. int zero = 0;
  1112. Replica *r = (Replica *)object_get_data((Object *)connext->replica_acquired);
  1113. replica_relinquish_exclusive_access(r, connid, opid);
  1114. object_release((Object *)connext->replica_acquired);
  1115. connext->replica_acquired = NULL;
  1116. connext->isreplicationsession = 0;
  1117. slapi_pblock_set(pb, SLAPI_CONN_IS_REPLICATION_SESSION, &zero);
  1118. }
  1119. if (connext) {
  1120. consumer_connection_extension_relinquish_exclusive_access(conn, connid, opid, PR_FALSE);
  1121. }
  1122. /*
  1123. * Close the connection to end the current session with the
  1124. * supplier. This prevents new updates from coming in and
  1125. * updating the consumer RUV - which would cause this failed
  1126. * update to be never be replayed.
  1127. */
  1128. slapi_disconnect_server(conn);
  1129. }
  1130. }
  1131. }
  1132. if (NULL == opcsn)
  1133. opcsn = operation_get_csn(op);
  1134. if (opcsn)
  1135. csn_free(&opcsn);
  1136. return rc;
  1137. }
  1138. /*
  1139. * Cancel an operation CSN. This removes it from any CSN pending lists.
  1140. * This function is called when a previously-generated CSN will not
  1141. * be needed, e.g. if the update operation produced an error.
  1142. */
  1143. static int
  1144. cancel_opcsn(Slapi_PBlock *pb)
  1145. {
  1146. Object *repl_obj;
  1147. Slapi_Operation *op = NULL;
  1148. if (NULL == pb) {
  1149. return SLAPI_PLUGIN_SUCCESS;
  1150. }
  1151. repl_obj = replica_get_replica_for_op(pb);
  1152. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  1153. if (NULL == op) {
  1154. return SLAPI_PLUGIN_SUCCESS;
  1155. }
  1156. if (repl_obj) {
  1157. Replica *r;
  1158. Object *gen_obj;
  1159. CSNGen *gen;
  1160. CSN *opcsn;
  1161. r = (Replica *)object_get_data(repl_obj);
  1162. PR_ASSERT(r);
  1163. opcsn = operation_get_csn(op);
  1164. if (!operation_is_flag_set(op, OP_FLAG_REPLICATED)) {
  1165. /* get csn generator for the replica */
  1166. gen_obj = replica_get_csngen(r);
  1167. PR_ASSERT(gen_obj);
  1168. gen = (CSNGen *)object_get_data(gen_obj);
  1169. if (NULL != opcsn) {
  1170. csngen_abort_csn(gen, operation_get_csn(op));
  1171. }
  1172. object_release(gen_obj);
  1173. } else if (!operation_is_flag_set(op, OP_FLAG_REPL_FIXUP)) {
  1174. Object *ruv_obj;
  1175. ruv_obj = replica_get_ruv(r);
  1176. PR_ASSERT(ruv_obj);
  1177. ruv_cancel_csn_inprogress(r, (RUV *)object_get_data(ruv_obj), opcsn, replica_get_rid(r));
  1178. object_release(ruv_obj);
  1179. }
  1180. object_release(repl_obj);
  1181. }
  1182. return SLAPI_PLUGIN_SUCCESS;
  1183. }
  1184. /*
  1185. * Return non-zero if the target entry DN is the DN of the RUV tombstone
  1186. * entry.
  1187. * The entry has rdn of nsuniqueid = ffffffff-ffffffff-ffffffff-ffffffff
  1188. */
  1189. static int
  1190. ruv_tombstone_op(Slapi_PBlock *pb)
  1191. {
  1192. char *uniqueid;
  1193. int rc;
  1194. slapi_pblock_get(pb, SLAPI_TARGET_UNIQUEID, &uniqueid);
  1195. rc = uniqueid && strcasecmp(uniqueid, RUV_STORAGE_ENTRY_UNIQUEID) == 0;
  1196. return rc;
  1197. }
  1198. /* we don't want to process replicated operations with csn smaller
  1199. than the corresponding csn in the consumer's ruv */
  1200. static PRBool
  1201. process_operation(Slapi_PBlock *pb, const CSN *csn)
  1202. {
  1203. Object *r_obj;
  1204. Replica *r;
  1205. Object *ruv_obj;
  1206. RUV *ruv;
  1207. int rc;
  1208. r_obj = replica_get_replica_for_op(pb);
  1209. if (r_obj == NULL) {
  1210. char sessionid[REPL_SESSION_ID_SIZE];
  1211. get_repl_session_id(pb, sessionid, NULL);
  1212. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "process_operation - "
  1213. "%s - Can't locate replica for the replicated operation\n",
  1214. sessionid);
  1215. return PR_FALSE;
  1216. }
  1217. r = (Replica *)object_get_data(r_obj);
  1218. PR_ASSERT(r);
  1219. ruv_obj = replica_get_ruv(r);
  1220. PR_ASSERT(ruv_obj);
  1221. ruv = (RUV *)object_get_data(ruv_obj);
  1222. PR_ASSERT(ruv);
  1223. rc = ruv_add_csn_inprogress(r, ruv, csn);
  1224. object_release(ruv_obj);
  1225. object_release(r_obj);
  1226. return (rc == RUV_SUCCESS);
  1227. }
  1228. static PRBool
  1229. is_mmr_replica(Slapi_PBlock *pb)
  1230. {
  1231. Object *r_obj;
  1232. r_obj = replica_get_replica_for_op(pb);
  1233. if (r_obj == NULL) {
  1234. return PR_FALSE;
  1235. }
  1236. object_release(r_obj);
  1237. return PR_TRUE;
  1238. }
  1239. static const char *
  1240. replica_get_purl_for_op(const Replica *r __attribute__((unused)), Slapi_PBlock *pb, const CSN *opcsn)
  1241. {
  1242. int is_replicated_op;
  1243. const char *purl = NULL;
  1244. slapi_pblock_get(pb, SLAPI_IS_MMR_REPLICATED_OPERATION, &is_replicated_op);
  1245. if (!is_replicated_op) {
  1246. purl = multimaster_get_local_purl();
  1247. } else {
  1248. /* Get the appropriate partial URL from the supplier RUV */
  1249. Slapi_Connection *conn;
  1250. consumer_connection_extension *connext;
  1251. slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
  1252. /* TEL 20120531: There is a slim chance we want to take exclusive access
  1253. * to this instead. However, it isn't clear to me that it is worth the
  1254. * risk of changing this working code. */
  1255. connext = (consumer_connection_extension *)repl_con_get_ext(
  1256. REPL_CON_EXT_CONN, conn);
  1257. if (NULL == connext || NULL == connext->supplier_ruv) {
  1258. char sessionid[REPL_SESSION_ID_SIZE];
  1259. get_repl_session_id(pb, sessionid, NULL);
  1260. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "replica_get_purl_for_op - "
  1261. "%s - Cannot obtain consumer connection extension or supplier_ruv.\n",
  1262. sessionid);
  1263. } else {
  1264. purl = ruv_get_purl_for_replica(connext->supplier_ruv,
  1265. csn_get_replicaid(opcsn));
  1266. }
  1267. }
  1268. return purl;
  1269. }
  1270. /* this function is called when state of a backend changes */
  1271. void
  1272. multimaster_be_state_change(void *handle __attribute__((unused)), char *be_name, int old_be_state, int new_be_state)
  1273. {
  1274. Object *r_obj;
  1275. Replica *r;
  1276. /* check if we have replica associated with the backend */
  1277. r_obj = replica_get_for_backend(be_name);
  1278. if (r_obj == NULL)
  1279. return;
  1280. r = (Replica *)object_get_data(r_obj);
  1281. PR_ASSERT(r);
  1282. if (new_be_state == SLAPI_BE_STATE_ON) {
  1283. /* backend came back online - restart replication */
  1284. slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name, "multimaster_be_state_change - "
  1285. "Replica %s is coming online; enabling replication\n",
  1286. slapi_sdn_get_ndn(replica_get_root(r)));
  1287. replica_enable_replication(r);
  1288. } else if (new_be_state == SLAPI_BE_STATE_OFFLINE) {
  1289. /* backend is about to be taken down - disable replication */
  1290. slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name, "multimaster_be_state_change - "
  1291. "Replica %s is going offline; disabling replication\n",
  1292. slapi_sdn_get_ndn(replica_get_root(r)));
  1293. replica_disable_replication(r, r_obj);
  1294. } else if (new_be_state == SLAPI_BE_STATE_DELETE) {
  1295. /* backend is about to be removed - disable replication */
  1296. if (old_be_state == SLAPI_BE_STATE_ON) {
  1297. slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name, "multimaster_be_state_change - "
  1298. "Replica %s is about to be deleted; disabling replication\n",
  1299. slapi_sdn_get_ndn(replica_get_root(r)));
  1300. replica_disable_replication(r, r_obj);
  1301. }
  1302. }
  1303. object_release(r_obj);
  1304. }