From 90d194c9ecef0e9be850132237d88c1805bf138f Mon Sep 17 00:00:00 2001 From: Ludwig Krispenz Date: Thu, 14 Jun 2018 14:44:14 +0200 Subject: [PATCH] Fix for tickest 49507 and 49615 - use correct tombstone rdns The implementation follows the proposal in http://www.port389.org/docs/389ds/design/use-correct-tombstone-rdns.html --- ldap/schema/01core389.ldif | 3 +- ldap/servers/slapd/back-ldbm/ldbm_add.c | 6 +- ldap/servers/slapd/back-ldbm/ldbm_delete.c | 35 ++-- ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c | 228 ++++++++++++++++++++++++- ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 107 +++++------- ldap/servers/slapd/back-ldbm/misc.c | 20 ++- ldap/servers/slapd/back-ldbm/proto-back-ldbm.h | 4 + ldap/servers/slapd/dn.c | 25 ++- ldap/servers/slapd/slapi-plugin.h | 1 + 9 files changed, 346 insertions(+), 83 deletions(-) diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif index 67f5469..1493916 100644 --- a/ldap/schema/01core389.ldif +++ b/ldap/schema/01core389.ldif @@ -310,6 +310,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2339 NAME 'nsslapd-changelogdir' DESC 'T attributeTypes: ( 2.16.840.1.113730.3.1.2340 NAME 'nsslapd-changelogmaxage' DESC 'The changelog5 time where an entry will be retained' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.2341 NAME 'nsslapd-changelogmaxentries' DESC 'The changelog5 max entries limit' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.2344 NAME 'nsslapd-tls-check-crl' DESC 'Check CRL when opening outbound TLS connections. Valid options are none, peer, all.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' ) +attributeTypes: ( 2.16.840.1.113730.3.1.2345 NAME 'tombstoneID' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) # # objectclasses # @@ -320,7 +321,7 @@ objectClasses: ( 2.16.840.1.113730.3.2.109 NAME 'nsBackendInstance' DESC 'Netsca objectClasses: ( 2.16.840.1.113730.3.2.110 NAME 'nsMappingTree' DESC 'Netscape defined objectclass' SUP top MUST ( CN ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.104 NAME 'nsContainer' DESC 'Netscape defined objectclass' SUP top MUST ( CN ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.108 NAME 'nsDS5Replica' DESC 'Replication configuration objectclass' SUP top MUST ( nsDS5ReplicaRoot $ nsDS5ReplicaId ) MAY (cn $ nsds5ReplicaPreciseTombstonePurging $ nsds5ReplicaCleanRUV $ nsds5ReplicaAbortCleanRUV $ nsDS5ReplicaType $ nsDS5ReplicaBindDN $ nsDS5ReplicaBindDNGroup $ nsState $ nsDS5ReplicaName $ nsDS5Flags $ nsDS5Task $ nsDS5ReplicaReferral $ nsDS5ReplicaAutoReferral $ nsds5ReplicaPurgeDelay $ nsds5ReplicaTombstonePurgeInterval $ nsds5ReplicaChangeCount $ nsds5ReplicaLegacyConsumer $ nsds5ReplicaProtocolTimeout $ nsds5ReplicaBackoffMin $ nsds5ReplicaBackoffMax $ nsds5ReplicaReleaseTimeout $ nsDS5ReplicaBindDnGroupCheckInterval ) X-ORIGIN 'Netscape Directory Server' ) -objectClasses: ( 2.16.840.1.113730.3.2.113 NAME 'nsTombstone' DESC 'Netscape defined objectclass' SUP top MAY ( nstombstonecsn $ nsParentUniqueId $ nscpEntryDN ) X-ORIGIN 'Netscape Directory Server' ) +objectClasses: ( 2.16.840.1.113730.3.2.113 NAME 'nsTombstone' DESC 'Netscape defined objectclass' SUP top MAY ( nstombstonecsn $ nsParentUniqueId $ nscpEntryDN $tombstoneID) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.103 NAME 'nsDS5ReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsds5ReplicaCleanRUVNotified $ nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5ReplicaEnabled $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5ReplicaStripAttrs $ nsds5replicaSessionPauseTime $ nsds5ReplicaProtocolTimeout $ nsds5ReplicaFlowControlWindow $ nsds5ReplicaFlowControlPause $ nsDS5ReplicaWaitForAsyncResults $ nsds5ReplicaIgnoreMissingChange) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.39 NAME 'nsslapdConfig' DESC 'Netscape defined objectclass' SUP top MAY ( cn ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.317 NAME 'nsSaslMapping' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSaslMapRegexString $ nsSaslMapBaseDNTemplate $ nsSaslMapFilterTemplate ) MAY ( nsSaslMapPriority ) X-ORIGIN 'Netscape Directory Server' ) diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c index f269115..9fb6dde 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_add.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c @@ -661,7 +661,11 @@ ldbm_back_add(Slapi_PBlock *pb) if (NULL == untombstoned_dn) { untombstoned_dn = ""; } - tombstoned_dn = compute_entry_tombstone_dn(untombstoned_dn, entryuniqueid); + if (is_ruv) { + tombstoned_dn = compute_ruv_tombstone_dn(untombstoned_dn, entryuniqueid); + } else { + tombstoned_dn = compute_entry_tombstone_dn(untombstoned_dn, entryuniqueid); + } slapi_log_err(SLAPI_LOG_DEBUG, "ldbm_back_add", "(tombstone_operation for %s): calculated tombstone_dn " "is (%s) \n", entryuniqueid, tombstoned_dn); diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c index 3a27fd0..07afec8 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c @@ -973,6 +973,26 @@ replace_entry: } #endif retval = entryrdn_index_entry(be, tombstone, BE_INDEX_ADD, &txn); + if (slapi_entry_has_children_ext(tombstone->ep_entry,1)) { + + IDList *children = NULL; + struct backentry **child_entries = NULL; + struct backdn **child_dns = NULL; + Slapi_RDN *sdn = slapi_entry_get_sdn(tombstone->ep_entry); + Slapi_RDN *srdn = slapi_entry_get_srdn(tombstone->ep_entry); + + children = moddn_get_children(&txn, pb, be, tombstone, slapi_entry_get_sdn(e->ep_entry), + &child_entries, &child_dns, 0); + if (children) { + moddn_remove_children_from_cache(inst, child_entries, child_dns, 0); + } + + retval = entryrdn_rename_subtombstones(be, (const Slapi_DN *)sdnp, srdn, + tombstone->ep_id, &txn); + slapi_ch_free((void **)&child_entries); + slapi_ch_free((void **)&child_dns); + idl_free(&children); + } if (DB_LOCK_DEADLOCK == retval) { slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_back_delete", "(adding tombstone entryrdn) DB_LOCK_DEADLOCK\n"); @@ -1452,20 +1472,13 @@ common_return: struct backdn *bdn = dncache_find_id(&inst->inst_dncache, tombstone->ep_id); if (bdn) { /* already in the dncache */ + CACHE_REMOVE(&inst->inst_dncache, bdn); CACHE_RETURN(&inst->inst_dncache, &bdn); - } else { /* not in the dncache yet */ - Slapi_DN *tombstonesdn = slapi_sdn_dup(slapi_entry_get_sdn(tombstone->ep_entry)); - if (tombstonesdn) { - bdn = backdn_init(tombstonesdn, tombstone->ep_id, 0); - if (bdn) { - CACHE_ADD(&inst->inst_dncache, bdn, NULL); - slapi_log_err(SLAPI_LOG_CACHE, "ldbm_back_delete", - "set %s to dn cache\n", slapi_sdn_get_dn(tombstonesdn)); - CACHE_RETURN(&inst->inst_dncache, &bdn); - } - } } } + if (cache_is_in_cache(&inst->inst_cache, tombstone)) { + CACHE_REMOVE(&inst->inst_cache, tombstone); + } CACHE_RETURN(&inst->inst_cache, &tombstone); tombstone = NULL; } diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c index 5797dd7..441839a 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c @@ -638,8 +638,13 @@ entryrdn_rename_subtree(backend *be, } if (mynewsrdn) { + if (flags) { + rc = _entryrdn_index_read(be, cursor, mynewsrdn, &targetelem, + &oldsupelem, &childelems, 0 /*flags*/, db_txn); + } else { rc = _entryrdn_index_read(be, cursor, &oldsrdn, &targetelem, &oldsupelem, &childelems, 0 /*flags*/, db_txn); + } } else { rc = _entryrdn_index_read(be, cursor, &oldsrdn, &targetelem, &oldsupelem, NULL, 0 /*flags*/, db_txn); @@ -911,6 +916,219 @@ bail: return rc; } +int +entryrdn_rename_subtombstones(backend *be, + const Slapi_DN *oldsdn, + Slapi_RDN *newsrdn, /* new rdn */ + ID id, + back_txn *txn) +{ + int rc = -1; + struct attrinfo *ai = NULL; + DB *db = NULL; + DBC *cursor = NULL; + DB_TXN *db_txn = (txn != NULL) ? txn->back_txn_txn : NULL; + Slapi_RDN oldsrdn = {0}; + Slapi_RDN supsrdn = {0}; + Slapi_RDN newsupsrdn = {0}; + const char *nrdn = NULL; /* normalized rdn */ + int rdnidx = -1; + char *keybuf = NULL; + DBT key; + DBT renamedata; + rdn_elem *targetelem = NULL; + rdn_elem *newelem = NULL; + rdn_elem *newsupelem = NULL; + rdn_elem *oldelem = NULL; + rdn_elem **childelems = NULL; + rdn_elem **cep = NULL; + size_t targetelemlen = 0; + size_t newelemlen = 0; + size_t newsupelemlen = 0; + size_t oldelemlen = 0; + const Slapi_DN *mynewsupsdn = NULL; + Slapi_RDN *mynewsrdn = NULL; + ID targetid = 0; + int db_retry = 0; + + slapi_log_err(SLAPI_LOG_TRACE, "entryrdn_rename_subtree", + "--> entryrdn_rename_subtree\n"); + slapi_log_err(SLAPI_LOG_TRACE, "entryrdn_rename_subtombstones", + "--> entryrdn_rename_subtombstones\n"); + + if (NULL == be || NULL == oldsdn || 0 == id) { + slapi_log_err(SLAPI_LOG_ERR, "entryrdn_rename_subtombstones", + "Param error: Empty %s\n", + NULL == be ? "backend" : NULL == oldsdn ? "old dn" : (NULL == newsrdn) ? "new dn" : 0 == id ? "id" : "unknown"); + goto bail; + } + + rc = slapi_rdn_init_all_sdn_ext(&oldsrdn, oldsdn, 0); + if (rc < 0) { + slapi_log_err(SLAPI_LOG_ERR, "entryrdn_rename_subtombstones", + "Failed to convert olddn \"%s\" to Slapi_RDN\n", + slapi_sdn_get_dn(oldsdn)); + rc = LDAP_INVALID_DN_SYNTAX; + goto bail; + } else if (rc > 0) { + slapi_log_err(SLAPI_LOG_TRACE, "entryrdn_rename_subtree", + "%s does not belong to the db\n", slapi_sdn_get_dn(oldsdn)); + rc = DB_NOTFOUND; + goto bail; + } + + if (newsrdn && slapi_rdn_get_rdn(newsrdn) && + strcmp(slapi_rdn_get_rdn(newsrdn), slapi_rdn_get_rdn(&oldsrdn))) { + mynewsrdn = newsrdn; + } else { + goto bail; + } + + /* Open the entryrdn index */ + rc = _entryrdn_open_index(be, &ai, &db); + if (rc || (NULL == db)) { + slapi_log_err(SLAPI_LOG_ERR, "entryrdn_rename_subtree", + "Opening the index failed: %s(%d)\n", + rc < 0 ? dblayer_strerror(rc) : "Invalid parameter", rc); + db = NULL; + return rc; + } + + /* Make a cursor */ + for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) { + rc = db->cursor(db, db_txn, &cursor, 0); + if (rc) { + slapi_log_err(ENTRYRDN_LOGLEVEL(rc), "entryrdn_rename_subtombstones", + "Failed to make a cursor: %s(%d)\n", dblayer_strerror(rc), rc); + if ((DB_LOCK_DEADLOCK == rc) && !db_txn) { + ENTRYRDN_DELAY; + continue; + } + cursor = NULL; + goto bail; + } else { + break; /* success */ + } + } + if (RETRY_TIMES == db_retry) { + slapi_log_err(SLAPI_LOG_ERR, "entryrdn_rename_subtombstones", + "Create cursor failed after [%d] retries\n", + db_retry); + rc = DB_LOCK_DEADLOCK; + goto bail; + } + + /* prepare the element for the newly renamed rdn, if any. */ + oldelem = _entryrdn_new_rdn_elem(be, id, &oldsrdn, &oldelemlen); + if (NULL == oldelem) { + slapi_log_err(SLAPI_LOG_ERR, "entryrdn_rename_subtombstones", + "Failed to generate a new elem: id: %d, rdn: %s\n", + id, slapi_rdn_get_rdn(&oldsrdn)); + goto bail; + } + newelem = _entryrdn_new_rdn_elem(be, id, mynewsrdn, &newelemlen); + if (NULL == newelem) { + slapi_log_err(SLAPI_LOG_ERR, "entryrdn_rename_subtombstones", + "Failed to generate a new elem: id: %d, rdn: %s\n", + id, slapi_rdn_get_rdn(mynewsrdn)); + goto bail; + } + + rc = _entryrdn_index_read(be, cursor, mynewsrdn, &targetelem, + NULL, &childelems, 0 /*flags*/, db_txn); + + if (rc || NULL == targetelem) { + slapi_log_err(SLAPI_LOG_ERR, "entryrdn_rename_subtombstones", + "Failed to read the target element \"%s\" (%d)\n", + slapi_sdn_get_dn(oldsdn), rc); + goto bail; + } + targetid = id_stored_to_internal(targetelem->rdn_elem_id); + targetelemlen = _entryrdn_rdn_elem_size(targetelem); + + /* update targetelem's children's parent link, if renaming the target */ + for (cep = childelems; cep && *cep; cep++) { + /* remove the old elem */ + slapi_ch_free_string(&keybuf); + keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_PARENT, + id_stored_to_internal((*cep)->rdn_elem_id)); + key.data = keybuf; + key.size = key.ulen = strlen(keybuf) + 1; + key.flags = DB_DBT_USERMEM; + + memset(&renamedata, 0, sizeof(renamedata)); + renamedata.ulen = renamedata.size = oldelemlen; + renamedata.data = (void *)oldelem; + renamedata.flags = DB_DBT_USERMEM; + rc = _entryrdn_del_data(cursor, &key, &renamedata, db_txn); + if (rc) { + goto bail; + } + + /* add the new elem */ + memset(&renamedata, 0, sizeof(renamedata)); + renamedata.ulen = renamedata.size = newelemlen; + renamedata.data = (void *)newelem; + renamedata.flags = DB_DBT_USERMEM; + rc = _entryrdn_put_data(cursor, &key, &renamedata, RDN_INDEX_SELF, db_txn); + if (rc && (DB_KEYEXIST != rc)) { /* failed && ignore already exists */ + slapi_log_err(ENTRYRDN_LOGLEVEL(rc), "entryrdn_rename_subtree", + "Adding %s failed; %s(%d)\n", keybuf, dblayer_strerror(rc), rc); + goto bail; + } + } + +bail: + slapi_ch_free_string(&keybuf); + slapi_ch_free((void **)&targetelem); + slapi_ch_free((void **)&newelem); + slapi_ch_free((void **)&newsupelem); + slapi_ch_free((void **)&oldelem); + slapi_rdn_done(&oldsrdn); + slapi_rdn_done(&supsrdn); + slapi_rdn_done(&newsupsrdn); + if (childelems) { + for (cep = childelems; *cep; cep++) { + slapi_ch_free((void **)cep); + } + slapi_ch_free((void **)&childelems); + } + /* Close the cursor */ + if (cursor) { + for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) { + int myrc = cursor->c_close(cursor); + if (0 != myrc) { + slapi_log_err(ENTRYRDN_LOGLEVEL(myrc), "entryrdn_rename_subtombstones", + "Failed to close cursor: %s(%d)\n", dblayer_strerror(myrc), myrc); + if ((DB_LOCK_DEADLOCK == myrc) && !db_txn) { + ENTRYRDN_DELAY; + continue; + } + if (!rc) { + /* if cursor close returns DEADLOCK, we must bubble that up + to the higher layers for retries */ + rc = myrc; + break; + } + } else { + break; /* success */ + } + } + if (RETRY_TIMES == db_retry) { + slapi_log_err(SLAPI_LOG_ERR, "entryrdn_rename_subtombstones", + "Failed to close cursor after [%d] retries.\n", db_retry); + rc = rc ? rc : DB_LOCK_DEADLOCK; + } + } + if (db) { + dblayer_release_index_file(be, ai, db); + } + slapi_log_err(SLAPI_LOG_TRACE, "entryrdn_rename_subtombstones", + "<-- entryrdn_rename_subtree\n"); + + return rc; +} + /* * Get the IDList of direct childen and indirect subordinates * OUTPUT: subordinates @@ -2813,6 +3031,12 @@ _entryrdn_delete_key(backend *be, } do { + /* the verification that the entry has no non-tombstone children + * has already been done. And with the regular tombstone rdn this + * is no longer possible here. Skip check and special tombstone + * handling. + */ +#if 0 rdn_elem *childelem = NULL; DBT dataret; void *ptr; @@ -2830,10 +3054,12 @@ _entryrdn_delete_key(backend *be, slapi_log_err(SLAPI_LOG_ERR, "_entryrdn_delete_key", "Failed to remove %s; has a child %s\n", nrdn, (char *)childelem->rdn_elem_nrdn_rdn); - rc = -1; + /* rc = -1; goto bail; + */ } } while (NULL != dataret.data && NULL != ptr); +#endif retry_get: rc = cursor->c_get(cursor, &key, &data, DB_NEXT_DUP | DB_MULTIPLE); if (DB_LOCK_DEADLOCK == rc) { diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c index 71e2a8f..61b3194 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c @@ -19,7 +19,6 @@ static const char *moddn_get_newdn(Slapi_PBlock *pb, Slapi_DN *dn_olddn, Slapi_DN *dn_newrdn, Slapi_DN *dn_newsuperiordn, int is_tombstone); static void moddn_unlock_and_return_entry(backend *be, struct backentry **targetentry); static int moddn_newrdn_mods(Slapi_PBlock *pb, const char *olddn, struct backentry *ec, Slapi_Mods *smods_wsi, int is_repl_op); -static IDList *moddn_get_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, struct backentry *parententry, Slapi_DN *parentdn, struct backentry ***child_entries, struct backdn ***child_dns, int is_resurect_operation); static int moddn_rename_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, IDList *children, Slapi_DN *dn_parentdn, Slapi_DN *dn_newsuperiordn, struct backentry *child_entries[]); static int modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *e, struct backentry **ec, Slapi_Mods *smods1, Slapi_Mods *smods2, Slapi_Mods *smods3); static void mods_remove_nsuniqueid(Slapi_Mods *smods); @@ -468,6 +467,7 @@ ldbm_back_modrdn(Slapi_PBlock *pb) ldap_result_code = -1; goto error_return; /* error result sent by find_entry2modify() */ } + /* we do want to move tombstones if (slapi_entry_flag_is_set(e->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE) && !is_resurect_operation) { ldap_result_code = LDAP_UNWILLING_TO_PERFORM; @@ -477,6 +477,7 @@ ldbm_back_modrdn(Slapi_PBlock *pb) slapi_sdn_get_dn(slapi_entry_get_sdn_const(e->ep_entry))); goto error_return; } + */ /* Check that an entry with the same DN doesn't already exist. */ { Slapi_Entry *entry; @@ -1228,39 +1229,7 @@ ldbm_back_modrdn(Slapi_PBlock *pb) } if (children) { - int i = 0; - if (child_entries && *child_entries) { - if (entryrdn_get_switch()) /* subtree-rename: on */ - { - /* - * If subtree-rename is on, delete subordinate entries from the - * entry cache. Next time the entries are read from the db, - * "renamed" dn is generated based upon the moved subtree. - */ - for (i = 0; child_entries[i] != NULL; i++) { - if (is_resurect_operation) { - slapi_log_err(SLAPI_LOG_CACHE, "ldbm_back_modrdn", - "Calling cache remove & return %s (refcnt: %d)\n", - slapi_entry_get_dn(child_entries[i]->ep_entry), - child_entries[i]->ep_refcnt); - } - CACHE_REMOVE(&inst->inst_cache, child_entries[i]); - cache_unlock_entry(&inst->inst_cache, child_entries[i]); - CACHE_RETURN(&inst->inst_cache, &child_entries[i]); - } - } else { - for (; child_entries[i] != NULL; i++) { - cache_unlock_entry(&inst->inst_cache, child_entries[i]); - CACHE_RETURN(&inst->inst_cache, &(child_entries[i])); - } - } - } - if (entryrdn_get_switch() && child_dns && *child_dns) { - for (i = 0; child_dns[i] != NULL; i++) { - CACHE_REMOVE(&inst->inst_dncache, child_dns[i]); - CACHE_RETURN(&inst->inst_dncache, &child_dns[i]); - } - } + moddn_remove_children_from_cache(inst, child_entries, child_dns, is_resurect_operation); } if (ruv_c_init) { @@ -1284,32 +1253,7 @@ error_return: slapi_pblock_set(pb, SLAPI_ENTRY_POST_OP, postentry); } if (children) { - int i = 0; - if (child_entries && *child_entries && inst) { - if (entryrdn_get_switch()) /* subtree-rename: on */ - { - /* - * If subtree-rename is on, delete subordinate entries from the - * entry cache even if the procedure was not successful. - */ - for (i = 0; child_entries[i] != NULL; i++) { - CACHE_REMOVE(&inst->inst_cache, child_entries[i]); - cache_unlock_entry(&inst->inst_cache, child_entries[i]); - CACHE_RETURN(&inst->inst_cache, &child_entries[i]); - } - } else { - for (; child_entries[i] != NULL; i++) { - cache_unlock_entry(&inst->inst_cache, child_entries[i]); - CACHE_RETURN(&inst->inst_cache, &(child_entries[i])); - } - } - } - if (entryrdn_get_switch() && child_dns && *child_dns && inst) { - for (i = 0; child_dns[i] != NULL; i++) { - CACHE_REMOVE(&inst->inst_dncache, child_dns[i]); - CACHE_RETURN(&inst->inst_dncache, &child_dns[i]); - } - } + moddn_remove_children_from_cache(inst, child_entries, child_dns, 0); } if (retval == DB_RUNRECOVERY) { @@ -2028,7 +1972,7 @@ moddn_rename_children( /* * Get an IDList of all the children of an entry. */ -static IDList * +IDList * moddn_get_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, @@ -2154,3 +2098,44 @@ moddn_get_children(back_txn *ptxn, bail: return result_idl; } + +void +moddn_remove_children_from_cache(ldbm_instance *inst, + struct backentry **child_entries, + struct backdn **child_dns, + int is_resurect_operation) +{ + int i = 0; + if (child_entries && *child_entries && inst) { + if (entryrdn_get_switch()) /* subtree-rename: on */ + { + /* + * If subtree-rename is on, delete subordinate entries from the + * entry cache. Next time the entries are read from the db, + * "renamed" dn is generated based upon the moved subtree. + */ + for (i = 0; child_entries[i] != NULL; i++) { + if (is_resurect_operation) { + slapi_log_err(SLAPI_LOG_CACHE, "ldbm_back_modrdn", + "Calling cache remove & return %s (refcnt: %d)\n", + slapi_entry_get_dn(child_entries[i]->ep_entry), + child_entries[i]->ep_refcnt); + } + CACHE_REMOVE(&inst->inst_cache, child_entries[i]); + cache_unlock_entry(&inst->inst_cache, child_entries[i]); + CACHE_RETURN(&inst->inst_cache, &child_entries[i]); + } + } else { + for (; child_entries[i] != NULL; i++) { + cache_unlock_entry(&inst->inst_cache, child_entries[i]); + CACHE_RETURN(&inst->inst_cache, &(child_entries[i])); + } + } + } + if (entryrdn_get_switch() && child_dns && *child_dns && inst) { + for (i = 0; child_dns[i] != NULL; i++) { + CACHE_REMOVE(&inst->inst_dncache, child_dns[i]); + CACHE_RETURN(&inst->inst_dncache, &child_dns[i]); + } + } +} diff --git a/ldap/servers/slapd/back-ldbm/misc.c b/ldap/servers/slapd/back-ldbm/misc.c index c52e58a..37a16b9 100644 --- a/ldap/servers/slapd/back-ldbm/misc.c +++ b/ldap/servers/slapd/back-ldbm/misc.c @@ -128,7 +128,7 @@ ldbm_attribute_always_indexed(const char *attrtype) * to an allocated block of memory. */ char * -compute_entry_tombstone_dn(const char *entrydn, const char *uniqueid) +compute_ruv_tombstone_dn(const char *entrydn, const char *uniqueid) { char *tombstone_dn; @@ -141,6 +141,20 @@ compute_entry_tombstone_dn(const char *entrydn, const char *uniqueid) entrydn); return tombstone_dn; } +char * +compute_entry_tombstone_dn(const char *entrydn, const char *uniqueid) +{ + char *tombstone_dn; + + PR_ASSERT(NULL != entrydn); + PR_ASSERT(NULL != uniqueid); + + tombstone_dn = slapi_ch_smprintf("%s=%s+%s", + SLAPI_ATTR_TOMBSTONEID, + uniqueid, + entrydn); + return tombstone_dn; +} char * compute_entry_tombstone_rdn(const char *entryrdn, const char *uniqueid) @@ -150,8 +164,8 @@ compute_entry_tombstone_rdn(const char *entryrdn, const char *uniqueid) PR_ASSERT(NULL != entryrdn); PR_ASSERT(NULL != uniqueid); - tombstone_rdn = slapi_ch_smprintf("%s=%s,%s", - SLAPI_ATTR_UNIQUEID, + tombstone_rdn = slapi_create_dn_string("%s=%s+%s", + SLAPI_ATTR_TOMBSTONEID, uniqueid, entryrdn); return tombstone_rdn; diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h index 6d772cd..4c64bd5 100644 --- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h +++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h @@ -363,6 +363,7 @@ void ldbm_log_access_message(Slapi_PBlock *pblock, char *string); int return_on_disk_full(struct ldbminfo *li); int ldbm_attribute_always_indexed(const char *attrtype); void ldbm_destroy_instance_name(struct ldbminfo *li); +char *compute_ruv_tombstone_dn(const char *entrydn, const char *uniqueid); char *compute_entry_tombstone_dn(const char *entrydn, const char *uniqueid); char *compute_entry_tombstone_rdn(const char *entryrdn, const char *uniqueid); int instance_set_busy(ldbm_instance *inst); @@ -381,6 +382,8 @@ int get_value_from_string(const char *string, char *type, char **value); int get_values_from_string(const char *string, char *type, char ***valuearray); void normalize_dir(char *dir); void ldbm_set_error(Slapi_PBlock *pb, int retval, int *ldap_result_code, char **ldap_result_message); +IDList *moddn_get_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, struct backentry *parententry, Slapi_DN *parentdn, struct backentry ***child_entries, struct backdn ***child_dns, int is_resurect_operation); +void moddn_remove_children_from_cache(ldbm_instance *inst, struct backentry **child_entries, struct backdn **child_dns, int is_resurect_operation); /* * nextid.c @@ -689,6 +692,7 @@ int entryrdn_index_read(backend *be, const Slapi_DN *sdn, ID *id, back_txn *txn) int entryrdn_index_read_ext(backend *be, const Slapi_DN *sdn, ID *id, int flags, back_txn *txn); int entryrdn_rename_subtree(backend *be, const Slapi_DN *oldsdn, Slapi_RDN *newsrdn, const Slapi_DN *newsupsdn, ID id, back_txn *txn, int flags); +int entryrdn_rename_subtombstones(backend *be, const Slapi_DN *oldsdn, Slapi_RDN *newsrdn, ID id, back_txn *txn); int entryrdn_get_subordinates(backend *be, const Slapi_DN *sdn, ID id, IDList **subordinates, back_txn *txn, int flags); int entryrdn_lookup_dn(backend *be, const char *rdn, ID id, char **dn, Slapi_RDN **psrdn, back_txn *txn); int entryrdn_get_parent(backend *be, const char *rdn, ID id, char **prdn, ID *pid, back_txn *txn); diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c index 2af3f38..d8ae9f0 100644 --- a/ldap/servers/slapd/dn.c +++ b/ldap/servers/slapd/dn.c @@ -2646,10 +2646,28 @@ int slapi_sdn_scope_test_ext(const Slapi_DN *dn, const Slapi_DN *base, int scope, int flags) { int rc = 0; + int is_legacy_tombstone = 0; + + if ((flags & SLAPI_ENTRY_FLAG_TOMBSTONE) && + (scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_ONELEVEL)){ + /* the old tombstone format required special handling + * to strip off the first "nsuniqueid=.....," + * For tombstones generated with proper RDN this is + * no longer required + */ +#define RUVRDN SLAPI_ATTR_UNIQUEID "=" RUV_STORAGE_ENTRY_UNIQUEID "," + const char *tombstone_dn = slapi_sdn_get_ndn(dn); + if (strlen(tombstone_dn) > sizeof(RUVRDN) && + 0 == strncmp(tombstone_dn, SLAPI_ATTR_UNIQUEID, sizeof(SLAPI_ATTR_UNIQUEID)-1) && + tombstone_dn[sizeof(RUVRDN)-1] == ',' && + strncmp(tombstone_dn, RUVRDN, sizeof(RUVRDN) - 1)) { + is_legacy_tombstone = 1; + } + } switch (scope) { case LDAP_SCOPE_BASE: - if (flags & SLAPI_ENTRY_FLAG_TOMBSTONE) { + if (is_legacy_tombstone) { Slapi_DN parent; slapi_sdn_init(&parent); slapi_sdn_get_parent(dn, &parent); @@ -2660,10 +2678,7 @@ slapi_sdn_scope_test_ext(const Slapi_DN *dn, const Slapi_DN *base, int scope, in } break; case LDAP_SCOPE_ONELEVEL: -#define RUVRDN SLAPI_ATTR_UNIQUEID "=" RUV_STORAGE_ENTRY_UNIQUEID "," - if ((flags & SLAPI_ENTRY_FLAG_TOMBSTONE) && - (strncmp(slapi_sdn_get_ndn(dn), RUVRDN, sizeof(RUVRDN) - 1))) { - /* tombstones except RUV tombstone */ + if (is_legacy_tombstone) { Slapi_DN parent; slapi_sdn_init(&parent); slapi_sdn_get_parent(dn, &parent); diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index e862382..25314dd 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -483,6 +483,7 @@ PR_fprintf(struct PRFileDesc *fd, const char *fmt, ...) #define SLAPI_ATTR_DN "dn" #define SLAPI_ATTR_RDN "rdn" #define SLAPI_ATTR_PARENTID "parentid" +#define SLAPI_ATTR_TOMBSTONEID "tombstoneID" #define SLAPI_ATTR_UNIQUEID_LENGTH 10 #define SLAPI_ATTR_OBJECTCLASS_LENGTH 11 #define SLAPI_ATTR_VALUE_TOMBSTONE_LENGTH 11 -- 2.9.5