diff options
Diffstat (limited to 'ldap/servers/plugins/replication/urp_tombstone.c')
-rw-r--r-- | ldap/servers/plugins/replication/urp_tombstone.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/ldap/servers/plugins/replication/urp_tombstone.c b/ldap/servers/plugins/replication/urp_tombstone.c new file mode 100644 index 00000000..3b24b928 --- /dev/null +++ b/ldap/servers/plugins/replication/urp_tombstone.c @@ -0,0 +1,210 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +/* + * urp_tombstone.c - Update Resolution Procedures - Tombstones + */ + +#include "slapi-plugin.h" +#include "repl5.h" +#include "urp.h" + +extern int slapi_log_urp; + +/* + * Check if the entry is a tombstone. + */ +int +is_tombstone_entry(const Slapi_Entry* entry) +{ + int flag; + + /* LP: This doesn't work very well with entries that we tombstone ourself */ + flag = slapi_entry_flag_is_set (entry, SLAPI_ENTRY_FLAG_TOMBSTONE); + if (flag == 0) + { + /* This is slow */ + flag = slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE); + } + return flag; +} + +PRBool +get_tombstone_csn(const Slapi_Entry *entry, const CSN **delcsn) +{ + PRBool ists = PR_FALSE; + if (is_tombstone_entry(entry)) { + ists = PR_TRUE; + *delcsn = _get_deletion_csn((Slapi_Entry *)entry); /* cast away const */ + } + + return ists; +} + +static int +tombstone_to_glue_resolve_parent ( + Slapi_PBlock *pb, + const char *sessionid, + const Slapi_DN *parentdn, + const char *parentuniqueid, + CSN *opcsn) +{ + /* Let's have a look at the parent of this entry... */ + if(!slapi_sdn_isempty(parentdn) && parentuniqueid!=NULL) + { + int op_result; + Slapi_PBlock *newpb= slapi_pblock_new(); + slapi_search_internal_set_pb( + newpb, + slapi_sdn_get_dn(parentdn), /* JCM - This DN just identifies the backend to be searched. */ + LDAP_SCOPE_BASE, + "objectclass=*", + NULL, /*attrs*/ + 0, /*attrsonly*/ + NULL, /*Controls*/ + parentuniqueid, /*uniqueid*/ + repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), + 0); + slapi_search_internal_pb(newpb); + slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result); + switch(op_result) + { + case LDAP_SUCCESS: + { + Slapi_Entry **entries= NULL; + /* OK, the tombstone entry parent exists. Is it also a tombstone? */ + slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); + if(entries!=NULL && entries[0]!=NULL) + { + if(is_tombstone_entry(entries[0])) + { + tombstone_to_glue (pb, sessionid, entries[0], parentdn, REASON_RESURRECT_ENTRY, opcsn); + } + } + else + { + /* JCM - Couldn't find the entry! */ + } + } + break; + default: + /* So, the tombstone entry had a parent... but it's gone. */ + /* That's probably a bad thing. */ + break; + } + slapi_free_search_results_internal (newpb); + slapi_pblock_destroy(newpb); + } + return 0; +} + +/* + * Convert a tombstone into a glue entry. + */ +int +tombstone_to_glue ( + Slapi_PBlock *pb, + const char *sessionid, + Slapi_Entry *tombstoneentry, + const Slapi_DN *tombstonedn, + const char *reason, + CSN *opcsn) +{ + Slapi_DN *parentdn; + char *parentuniqueid; + const char *tombstoneuniqueid; + Slapi_Entry *addingentry; + const char *addingdn; + int op_result; + + /* JCMREPL + * Nothing logged to the 5.0 Change Log + * Add is logged to the 4.0 Change Log - Core server Add code + * must attach the entry to the Operation + */ + + + /* Resurrect the parent entry first */ + + /* JCM - This DN calculation is odd. It could resolve to NULL + * which won't help us identify the correct backend to search. + */ + is_suffix_dn (pb, tombstonedn, &parentdn); + parentuniqueid= slapi_entry_attr_get_charptr (tombstoneentry, + SLAPI_ATTR_VALUE_PARENT_UNIQUEID); /* Allocated */ + tombstone_to_glue_resolve_parent (pb, sessionid, parentdn, parentuniqueid, opcsn); + slapi_sdn_free(&parentdn); + + /* Submit an Add operation to turn the tombstone entry into glue. */ + /* + * The tombstone is stored with an invalid DN, we must fix this. + */ + addingentry = slapi_entry_dup(tombstoneentry); + addingdn = slapi_sdn_get_dn(tombstonedn); + slapi_entry_set_dn(addingentry,slapi_ch_strdup(addingdn)); /* consumes DN */ + + if (!slapi_entry_attr_hasvalue(addingentry, ATTR_NSDS5_REPLCONFLICT, reason)) + { + /* Add the reason of turning it to glue - The backend code will use it*/ + slapi_entry_add_string(addingentry, ATTR_NSDS5_REPLCONFLICT, reason); + } + tombstoneuniqueid= slapi_entry_get_uniqueid(tombstoneentry); + op_result = urp_fixup_add_entry (addingentry, tombstoneuniqueid, parentuniqueid, opcsn, OP_FLAG_RESURECT_ENTRY); + if (op_result == LDAP_SUCCESS) + { + slapi_log_error (slapi_log_urp, repl_plugin_name, + "%s: Resurrected tombstone %s to glue reason '%s'\n", sessionid, addingdn, reason); + } + else + { + slapi_log_error (SLAPI_LOG_FATAL, repl_plugin_name, + "%s: Can't resurrect tombstone %s to glue reason '%s', error=%d\n", + sessionid, addingdn, reason, op_result); + } + slapi_entry_free (addingentry); + return op_result; +} + +int +entry_to_tombstone ( Slapi_PBlock *pb, Slapi_Entry *entry ) +{ + Slapi_Operation *op; + Slapi_Mods smods; + CSN *opcsn; + const char *uniqueid; + int op_result = LDAP_SUCCESS; + + slapi_pblock_get ( pb, SLAPI_OPERATION, &op ); + opcsn = operation_get_csn ( op ); + uniqueid = slapi_entry_get_uniqueid ( entry ); + + + slapi_mods_init ( &smods, 2 ); + /* Remove objectclass=glue */ + slapi_mods_add ( &smods, LDAP_MOD_DELETE, SLAPI_ATTR_OBJECTCLASS, strlen("glue"), "glue"); + /* Remove any URP conflict since a tombstone shouldn't + * be retrieved later for conflict removal. + */ + slapi_mods_add ( &smods, LDAP_MOD_DELETE, ATTR_NSDS5_REPLCONFLICT, 0, NULL ); + + op_result = urp_fixup_modify_entry (uniqueid, slapi_entry_get_dn_const (entry), opcsn, &smods, 0); + slapi_mods_done ( &smods ); + + /* + * Delete the entry. + */ + if ( op_result == LDAP_SUCCESS ) + { + /* + * Using internal delete operation since it would go + * through the urp operations and trigger the recursive + * fixup if applicable. + */ + op_result = urp_fixup_delete_entry (uniqueid, slapi_entry_get_dn_const (entry), opcsn, 0); + } + + return op_result; +} |