urp_tombstone.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /*
  13. * urp_tombstone.c - Update Resolution Procedures - Tombstones
  14. */
  15. #include "slapi-plugin.h"
  16. #include "repl5.h"
  17. #include "urp.h"
  18. extern int slapi_log_urp;
  19. /*
  20. * Check if the entry is a tombstone.
  21. */
  22. int
  23. is_tombstone_entry(const Slapi_Entry* entry)
  24. {
  25. int flag;
  26. /* LP: This doesn't work very well with entries that we tombstone ourself */
  27. flag = slapi_entry_flag_is_set (entry, SLAPI_ENTRY_FLAG_TOMBSTONE);
  28. if (flag == 0)
  29. {
  30. /* This is slow */
  31. flag = slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE);
  32. }
  33. return flag;
  34. }
  35. PRBool
  36. get_tombstone_csn(const Slapi_Entry *entry, const CSN **delcsn)
  37. {
  38. PRBool ists = PR_FALSE;
  39. if (is_tombstone_entry(entry)) {
  40. ists = PR_TRUE;
  41. *delcsn = entry_get_deletion_csn((Slapi_Entry *)entry); /* cast away const */
  42. }
  43. return ists;
  44. }
  45. static int
  46. tombstone_to_glue_resolve_parent (
  47. Slapi_PBlock *pb,
  48. char *sessionid,
  49. const Slapi_DN *parentdn,
  50. const char *parentuniqueid,
  51. CSN *opcsn,
  52. Slapi_DN **newparentdn)
  53. {
  54. /* Let's have a look at the parent of this entry... */
  55. if(!slapi_sdn_isempty(parentdn) && parentuniqueid!=NULL)
  56. {
  57. int op_result;
  58. Slapi_PBlock *newpb= slapi_pblock_new();
  59. slapi_search_internal_set_pb(
  60. newpb,
  61. slapi_sdn_get_dn(parentdn), /* JCM - This DN just identifies the backend to be searched. */
  62. LDAP_SCOPE_BASE,
  63. "objectclass=*",
  64. NULL, /*attrs*/
  65. 0, /*attrsonly*/
  66. NULL, /*Controls*/
  67. parentuniqueid, /*uniqueid*/
  68. repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
  69. 0);
  70. slapi_search_internal_pb(newpb);
  71. slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);
  72. switch(op_result)
  73. {
  74. case LDAP_SUCCESS:
  75. {
  76. Slapi_Entry **entries= NULL;
  77. /* OK, the tombstone entry parent exists. Is it also a tombstone? */
  78. slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  79. if(entries!=NULL && entries[0]!=NULL)
  80. {
  81. if(is_tombstone_entry(entries[0]))
  82. {
  83. tombstone_to_glue(pb, sessionid, entries[0], parentdn,
  84. REASON_RESURRECT_ENTRY, opcsn, newparentdn);
  85. }
  86. }
  87. else
  88. {
  89. /* JCM - Couldn't find the entry! */
  90. }
  91. }
  92. break;
  93. default:
  94. /* So, the tombstone entry had a parent... but it's gone. */
  95. /* That's probably a bad thing. */
  96. break;
  97. }
  98. slapi_free_search_results_internal (newpb);
  99. slapi_pblock_destroy(newpb);
  100. }
  101. return 0;
  102. }
  103. /*
  104. * Convert a tombstone into a glue entry.
  105. */
  106. int
  107. tombstone_to_glue (
  108. Slapi_PBlock *pb,
  109. char *sessionid,
  110. Slapi_Entry *tombstoneentry,
  111. const Slapi_DN *gluedn, /* does not start with uniqueid= */
  112. const char *reason,
  113. CSN *opcsn,
  114. Slapi_DN **newparentdn)
  115. {
  116. Slapi_DN *parentdn;
  117. char *parentuniqueid;
  118. const char *tombstoneuniqueid;
  119. Slapi_Entry *addingentry = NULL;
  120. Slapi_Entry *addingentry_bakup = NULL;
  121. const char *addingdn;
  122. int op_result;
  123. int rdn_is_conflict = 0;
  124. /* JCMREPL
  125. * Nothing logged to the 5.0 Change Log
  126. * Add is logged to the 4.0 Change Log - Core server Add code
  127. * must attach the entry to the Operation
  128. */
  129. /* Resurrect the parent entry first */
  130. /* JCM - This DN calculation is odd. It could resolve to NULL
  131. * which won't help us identify the correct backend to search.
  132. */
  133. is_suffix_dn_ext (pb, gluedn, &parentdn, 1 /* is_tombstone */);
  134. parentuniqueid = slapi_entry_attr_get_charptr (tombstoneentry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID); /* Allocated */
  135. tombstone_to_glue_resolve_parent (pb, sessionid, parentdn, parentuniqueid, opcsn, newparentdn);
  136. /* Submit an Add operation to turn the tombstone entry into glue. */
  137. /*
  138. * The tombstone is stored with an invalid DN, we must fix this.
  139. */
  140. addingentry = slapi_entry_dup(tombstoneentry);
  141. if (newparentdn && *newparentdn && slapi_sdn_compare(parentdn, *newparentdn)) {
  142. /* If the parents are resolved, the tombstone's DN is going to be different... */
  143. /* Update DN in addingentry */
  144. Slapi_RDN *rdn = slapi_rdn_new();
  145. slapi_rdn_set_dn_ext(rdn, slapi_sdn_get_dn(gluedn), SLAPI_RDN_SET_DN_INCLUDE_UNIQUEID);
  146. addingdn = slapi_moddn_get_newdn(slapi_entry_get_sdn(addingentry), slapi_rdn_get_rdn(rdn),
  147. slapi_sdn_get_dn(*newparentdn));
  148. slapi_rdn_free(&rdn);
  149. slapi_sdn_init_normdn_passin(*newparentdn, addingdn); /* to return the new parentdn to the caller */
  150. } else {
  151. slapi_sdn_free(newparentdn); /* no change in parentdn; returning NULL */
  152. addingdn = slapi_sdn_get_dn(gluedn);
  153. }
  154. slapi_sdn_set_normdn_byval(slapi_entry_get_sdn(addingentry), addingdn);
  155. /* not just e_sdn, e_rsdn needs to be updated. */
  156. slapi_rdn_set_all_dn(slapi_entry_get_srdn(addingentry), slapi_entry_get_dn_const(addingentry));
  157. rdn_is_conflict = slapi_rdn_is_conflict(slapi_entry_get_srdn(addingentry));
  158. if (!slapi_entry_attr_hasvalue(addingentry, ATTR_NSDS5_REPLCONFLICT, reason))
  159. {
  160. /* Add the reason of turning it to glue - The backend code will use it*/
  161. slapi_entry_add_string(addingentry, ATTR_NSDS5_REPLCONFLICT, reason);
  162. }
  163. tombstoneuniqueid= slapi_entry_get_uniqueid(tombstoneentry);
  164. /*
  165. * addingentry and parentuniqueid are consumed in urp_fixup_add_entry,
  166. * regardless of the result.
  167. * Note: addingentry is not really consumed in ldbm_back_add.
  168. * tombstoneentry from DB/entry cache is duplicated and turned to be a glue.
  169. * This addingentry is freed in op_shared_add.
  170. */
  171. addingentry_bakup = slapi_entry_dup(addingentry);
  172. op_result = urp_fixup_add_entry (addingentry, tombstoneuniqueid, slapi_ch_strdup(parentuniqueid), opcsn, OP_FLAG_RESURECT_ENTRY);
  173. if ((LDAP_ALREADY_EXISTS == op_result) && !rdn_is_conflict) {
  174. /* conflict -- there's already the same named entry added.
  175. * But this to-be-glued entry needs to be added since this is a parent of child entries...
  176. * So, rename this tombstone parententry a conflict, glue entry.
  177. * Instead of "fixup_add", we have to "fixup_rename"...
  178. * */
  179. char *conflictrdn = get_rdn_plus_uniqueid(sessionid, addingdn, tombstoneuniqueid);
  180. if (conflictrdn) {
  181. addingentry = addingentry_bakup;
  182. addingentry_bakup = NULL;
  183. if (!slapi_entry_attr_hasvalue(addingentry, ATTR_NSDS5_REPLCONFLICT, reason)) {
  184. /* Add the reason of turning it to glue - The backend code will use it*/
  185. slapi_entry_add_string(addingentry, ATTR_NSDS5_REPLCONFLICT, reason);
  186. }
  187. slapi_log_error (SLAPI_LOG_FATAL, repl_plugin_name,
  188. "%s: Can't resurrect tombstone to glue reason '%s'. "
  189. "Try with conflict dn %s, error=%d\n",
  190. sessionid, reason, addingdn, op_result);
  191. op_result = urp_fixup_rename_entry(addingentry, (const char *)conflictrdn, parentuniqueid,
  192. OP_FLAG_RESURECT_ENTRY|OP_FLAG_TOMBSTONE_ENTRY);
  193. slapi_ch_free_string(&conflictrdn);
  194. slapi_entry_free(addingentry);
  195. addingentry = NULL;
  196. }
  197. }
  198. slapi_entry_free(addingentry_bakup);
  199. slapi_ch_free_string(&parentuniqueid);
  200. if (op_result == LDAP_SUCCESS)
  201. {
  202. slapi_log_error (/*slapi_log_urp*/SLAPI_LOG_FATAL, repl_plugin_name,
  203. "%s: Resurrected tombstone %s to glue reason '%s'\n", sessionid, addingdn, reason);
  204. }
  205. else if (LDAP_ALREADY_EXISTS == op_result)
  206. {
  207. slapi_log_error(/*slapi_log_urp*/SLAPI_LOG_FATAL, repl_plugin_name,
  208. "%s: No need to turn tombstone %s to glue; it was already resurrected.\n",
  209. sessionid, addingdn);
  210. op_result = LDAP_SUCCESS;
  211. }
  212. else
  213. {
  214. slapi_log_error (SLAPI_LOG_FATAL, repl_plugin_name,
  215. "%s: Can't resurrect tombstone %s to glue reason '%s', error=%d\n",
  216. sessionid, addingdn, reason, op_result);
  217. }
  218. slapi_sdn_free(&parentdn);
  219. return op_result;
  220. }
  221. int
  222. entry_to_tombstone ( Slapi_PBlock *pb, Slapi_Entry *entry )
  223. {
  224. Slapi_Operation *op;
  225. Slapi_Mods smods;
  226. CSN *opcsn;
  227. const char *uniqueid;
  228. int op_result = LDAP_SUCCESS;
  229. slapi_pblock_get ( pb, SLAPI_OPERATION, &op );
  230. opcsn = operation_get_csn ( op );
  231. uniqueid = slapi_entry_get_uniqueid ( entry );
  232. slapi_mods_init ( &smods, 2 );
  233. /* Remove objectclass=glue */
  234. slapi_mods_add ( &smods, LDAP_MOD_DELETE, SLAPI_ATTR_OBJECTCLASS, strlen("glue"), "glue");
  235. /* Remove any URP conflict since a tombstone shouldn't
  236. * be retrieved later for conflict removal.
  237. */
  238. slapi_mods_add ( &smods, LDAP_MOD_DELETE, ATTR_NSDS5_REPLCONFLICT, 0, NULL );
  239. op_result = urp_fixup_modify_entry (uniqueid,
  240. slapi_entry_get_sdn_const (entry),
  241. opcsn, &smods, 0);
  242. slapi_mods_done ( &smods );
  243. /*
  244. * Delete the entry.
  245. */
  246. if ( op_result == LDAP_SUCCESS )
  247. {
  248. /*
  249. * Using internal delete operation since it would go
  250. * through the urp operations and trigger the recursive
  251. * fixup if applicable.
  252. */
  253. op_result = urp_fixup_delete_entry (uniqueid, slapi_entry_get_dn_const (entry), opcsn, 0);
  254. }
  255. return op_result;
  256. }