ldbm_delete.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* delete.c - ldbm backend delete routine */
  42. #include "back-ldbm.h"
  43. int
  44. ldbm_back_delete( Slapi_PBlock *pb )
  45. {
  46. backend *be;
  47. ldbm_instance *inst;
  48. struct ldbminfo *li = NULL;
  49. struct backentry *e = NULL;
  50. struct backentry *tombstone = NULL;
  51. char *dn = NULL;
  52. back_txn txn;
  53. back_txnid parent_txn;
  54. int retval = -1;
  55. char *msg;
  56. char *errbuf = NULL;
  57. int retry_count = 0;
  58. int disk_full = 0;
  59. int parent_found = 0;
  60. modify_context parent_modify_c = {0};
  61. int rc;
  62. int ldap_result_code= LDAP_SUCCESS;
  63. char *ldap_result_message= NULL;
  64. Slapi_DN sdn;
  65. char *e_uniqueid = NULL;
  66. Slapi_DN *nscpEntrySDN = NULL;
  67. int dblock_acquired= 0;
  68. Slapi_Operation *operation;
  69. CSN *opcsn = NULL;
  70. int is_fixup_operation = 0;
  71. int is_ruv = 0; /* True if the current entry is RUV */
  72. int is_replicated_operation= 0;
  73. int is_tombstone_entry = 0; /* True if the current entry is alreday a tombstone */
  74. int delete_tombstone_entry = 0; /* We must remove the given tombstone entry from the DB */
  75. int create_tombstone_entry = 0; /* We perform a "regular" LDAP delete but since we use */
  76. /* replication, we must create a new tombstone entry */
  77. int tombstone_in_cache = 0;
  78. entry_address *addr;
  79. int addordel_flags = 0; /* passed to index_addordel */
  80. char *entryusn_str = NULL;
  81. char *prev_entryusn_str = NULL;
  82. Slapi_Entry *orig_entry = NULL;
  83. slapi_pblock_get( pb, SLAPI_BACKEND, &be);
  84. slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
  85. slapi_pblock_get( pb, SLAPI_DELETE_TARGET, &dn );
  86. slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr);
  87. slapi_pblock_get( pb, SLAPI_PARENT_TXN, (void**)&parent_txn );
  88. slapi_pblock_get( pb, SLAPI_OPERATION, &operation );
  89. slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation );
  90. if (pb->pb_conn)
  91. {
  92. slapi_log_error (SLAPI_LOG_TRACE, "ldbm_back_delete", "enter conn=%" NSPRIu64 " op=%d\n", pb->pb_conn->c_connid, operation->o_opid);
  93. }
  94. is_fixup_operation = operation_is_flag_set(operation, OP_FLAG_REPL_FIXUP);
  95. is_ruv = operation_is_flag_set(operation, OP_FLAG_REPL_RUV);
  96. delete_tombstone_entry = operation_is_flag_set(operation, OP_FLAG_TOMBSTONE_ENTRY);
  97. inst = (ldbm_instance *) be->be_instance_info;
  98. slapi_sdn_init_dn_byref(&sdn,dn);
  99. dblayer_txn_init(li,&txn);
  100. /* The dblock serializes writes to the database,
  101. * which reduces deadlocking in the db code,
  102. * which means that we run faster.
  103. *
  104. * But, this lock is re-enterant for the fixup
  105. * operations that the URP code in the Replication
  106. * plugin generates.
  107. */
  108. if(SERIALLOCK(li) && !operation_is_flag_set(operation,OP_FLAG_REPL_FIXUP))
  109. {
  110. dblayer_lock_backend(be);
  111. dblock_acquired= 1;
  112. }
  113. /*
  114. * We are about to pass the last abandon test, so from now on we are
  115. * committed to finish this operation. Set status to "will complete"
  116. * before we make our last abandon check to avoid race conditions in
  117. * the code that processes abandon operations.
  118. */
  119. if (operation) {
  120. operation->o_status = SLAPI_OP_STATUS_WILL_COMPLETE;
  121. }
  122. if ( slapi_op_abandoned( pb ) ) {
  123. goto error_return;
  124. }
  125. /* find and lock the entry we are about to modify */
  126. if ( (e = find_entry2modify( pb, be, addr, NULL )) == NULL )
  127. {
  128. ldap_result_code= -1;
  129. goto error_return; /* error result sent by find_entry2modify() */
  130. }
  131. if ( slapi_entry_has_children( e->ep_entry ) )
  132. {
  133. ldap_result_code= LDAP_NOT_ALLOWED_ON_NONLEAF;
  134. goto error_return;
  135. }
  136. /* set entry in case be-preop plugins need to work on it (e.g., USN) */
  137. slapi_pblock_get( pb, SLAPI_DELETE_BEPREOP_ENTRY, &orig_entry );
  138. slapi_pblock_set( pb, SLAPI_DELETE_BEPREOP_ENTRY, e->ep_entry );
  139. /* Don't call pre-op for Tombstone entries */
  140. if (!delete_tombstone_entry)
  141. {
  142. /*
  143. * Some present state information is passed through the PBlock to the
  144. * backend pre-op plugin. To ensure a consistent snapshot of this state
  145. * we wrap the reading of the entry with the dblock.
  146. */
  147. ldap_result_code= get_copy_of_entry(pb, addr, &txn,
  148. SLAPI_DELETE_EXISTING_ENTRY, !is_replicated_operation);
  149. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
  150. if(plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_DELETE_FN)==-1)
  151. {
  152. /*
  153. * Plugin indicated some kind of failure,
  154. * or that this Operation became a No-Op.
  155. */
  156. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
  157. goto error_return;
  158. }
  159. /* the flag could be set in a preop plugin (e.g., USN) */
  160. delete_tombstone_entry = operation_is_flag_set(operation,
  161. OP_FLAG_TOMBSTONE_ENTRY);
  162. }
  163. slapi_pblock_set( pb, SLAPI_DELETE_BEPREOP_ENTRY, orig_entry );
  164. /*
  165. * Sanity check to avoid to delete a non-tombstone or to tombstone again
  166. * a tombstone entry. This should not happen (see bug 561003).
  167. */
  168. is_tombstone_entry = slapi_entry_flag_is_set(e->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE);
  169. if (delete_tombstone_entry) {
  170. PR_ASSERT(is_tombstone_entry);
  171. if (!is_tombstone_entry) {
  172. slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
  173. "Attempt to delete a non-tombstone entry %s\n", dn);
  174. delete_tombstone_entry = 0;
  175. }
  176. } else {
  177. PR_ASSERT(!is_tombstone_entry);
  178. if (is_tombstone_entry) {
  179. slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
  180. "Attempt to Tombstone again a tombstone entry %s\n", dn);
  181. delete_tombstone_entry = 1;
  182. }
  183. }
  184. /*
  185. * If a CSN is set, we need to tombstone the entry,
  186. * rather than deleting it outright.
  187. */
  188. opcsn = operation_get_csn (operation);
  189. if (!delete_tombstone_entry)
  190. {
  191. /* If both USN and replication is enabled, csn set by replication
  192. * should be honored. */
  193. if ((opcsn == NULL || ldbm_usn_enabled(be)) &&
  194. !is_fixup_operation && operation->o_csngen_handler)
  195. {
  196. csn_free(&opcsn); /* free opcsn set by USN plugin, if any */
  197. /*
  198. * Current op is a user request. Opcsn will be assigned
  199. * by entry_assign_operation_csn() if the dn is in an
  200. * updatable replica.
  201. */
  202. opcsn = entry_assign_operation_csn ( pb, e->ep_entry, NULL );
  203. }
  204. if (opcsn != NULL)
  205. {
  206. if (!is_fixup_operation)
  207. {
  208. entry_set_maxcsn (e->ep_entry, opcsn);
  209. }
  210. /*
  211. * We are dealing with replication and if we haven't been called to
  212. * remove a tombstone, then it's because we want to create a new one.
  213. */
  214. if ( slapi_operation_get_replica_attr (pb, operation, "nsds5ReplicaTombstonePurgeInterval", &create_tombstone_entry) == 0)
  215. {
  216. create_tombstone_entry = (create_tombstone_entry < 0) ? 0 : 1;
  217. }
  218. }
  219. }
  220. #if DEBUG
  221. slapi_log_error(SLAPI_LOG_REPL, "ldbm_back_delete",
  222. "entry: %s - flags: delete %d is_tombstone_entry %d create %d \n",
  223. dn, delete_tombstone_entry, is_tombstone_entry, create_tombstone_entry);
  224. #endif
  225. /* Save away a copy of the entry, before modifications */
  226. slapi_pblock_set( pb, SLAPI_ENTRY_PRE_OP, slapi_entry_dup( e->ep_entry ));
  227. /* JCMACL - Shouldn't the access check be before the has children check...
  228. * otherwise we're revealing the fact that an entry exists and has children */
  229. ldap_result_code = plugin_call_acl_plugin (pb, e->ep_entry, NULL, NULL, SLAPI_ACL_DELETE,
  230. ACLPLUGIN_ACCESS_DEFAULT, &errbuf );
  231. if ( ldap_result_code != LDAP_SUCCESS )
  232. {
  233. ldap_result_message= errbuf;
  234. goto error_return;
  235. }
  236. /*
  237. * Get the entry's parent. We do this here because index_read
  238. * seems to deadlock the database when dblayer_txn_begin is
  239. * called.
  240. */
  241. if (!delete_tombstone_entry)
  242. {
  243. Slapi_DN parentsdn;
  244. slapi_sdn_init(&parentsdn);
  245. slapi_sdn_get_backend_parent(&sdn,&parentsdn,pb->pb_backend);
  246. if ( !slapi_sdn_isempty(&parentsdn) )
  247. {
  248. struct backentry *parent = NULL;
  249. entry_address parent_addr;
  250. parent_addr.dn = (char*)slapi_sdn_get_dn (&parentsdn);
  251. parent_addr.uniqueid = NULL;
  252. parent = find_entry2modify_only(pb,be,&parent_addr,&txn);
  253. if (NULL != parent) {
  254. int isglue;
  255. size_t haschildren = 0;
  256. /* Unfortunately findentry doesn't tell us whether it just didn't find the entry, or if
  257. there was an error, so we have to assume that the parent wasn't found */
  258. parent_found = 1;
  259. /* Modify the parent in memory */
  260. modify_init(&parent_modify_c,parent);
  261. retval = parent_update_on_childchange(&parent_modify_c,2,&haschildren); /* 2==delete */\
  262. /* The modify context now contains info needed later */
  263. if (0 != retval) {
  264. ldap_result_code= LDAP_OPERATIONS_ERROR;
  265. goto error_return;
  266. }
  267. /*
  268. * Replication urp_post_delete will delete the parent entry
  269. * if it is a glue entry without any more children.
  270. * Those urp condition checkings are done here to
  271. * save unnecessary entry dup.
  272. */
  273. isglue = slapi_entry_attr_hasvalue (parent_modify_c.new_entry->ep_entry,
  274. SLAPI_ATTR_OBJECTCLASS, "glue");
  275. if ( opcsn && parent_modify_c.new_entry && !haschildren && isglue)
  276. {
  277. slapi_pblock_set ( pb, SLAPI_DELETE_GLUE_PARENT_ENTRY,
  278. slapi_entry_dup (parent_modify_c.new_entry->ep_entry) );
  279. }
  280. }
  281. }
  282. slapi_sdn_done(&parentsdn);
  283. }
  284. if(create_tombstone_entry)
  285. {
  286. /*
  287. * The entry is not removed from the disk when we tombstone an
  288. * entry. We change the DN, add objectclass=tombstone, and record
  289. * the UniqueID of the parent entry.
  290. */
  291. const char *childuniqueid= slapi_entry_get_uniqueid(e->ep_entry);
  292. const char *parentuniqueid= NULL;
  293. char *tombstone_dn = compute_entry_tombstone_dn(slapi_entry_get_dn(e->ep_entry),
  294. childuniqueid);
  295. Slapi_Value *tomb_value;
  296. nscpEntrySDN = slapi_entry_get_sdn(e->ep_entry);
  297. /* Copy the entry unique_id for URP conflict checking */
  298. e_uniqueid = slapi_ch_strdup(childuniqueid);
  299. if(parent_modify_c.old_entry!=NULL)
  300. {
  301. /* The suffix entry has no parent */
  302. parentuniqueid= slapi_entry_get_uniqueid(parent_modify_c.old_entry->ep_entry);
  303. }
  304. tombstone = backentry_dup( e );
  305. slapi_entry_set_dn(tombstone->ep_entry,tombstone_dn); /* Consumes DN */
  306. /* Set tombstone flag on ep_entry */
  307. slapi_entry_set_flag(tombstone->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE);
  308. if(parentuniqueid!=NULL)
  309. {
  310. /* The suffix entry has no parent */
  311. slapi_entry_add_string(tombstone->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID, parentuniqueid);
  312. }
  313. if(nscpEntrySDN!=NULL)
  314. {
  315. slapi_entry_add_string(tombstone->ep_entry, SLAPI_ATTR_NSCP_ENTRYDN, slapi_sdn_get_ndn(nscpEntrySDN));
  316. }
  317. tomb_value = slapi_value_new_string(SLAPI_ATTR_VALUE_TOMBSTONE);
  318. value_update_csn(tomb_value, CSN_TYPE_VALUE_UPDATED,
  319. operation_get_csn(operation));
  320. slapi_entry_add_value(tombstone->ep_entry, SLAPI_ATTR_OBJECTCLASS, tomb_value);
  321. slapi_value_free(&tomb_value);
  322. /* retrieve previous entry usn value, if any */
  323. prev_entryusn_str = slapi_entry_attr_get_charptr(tombstone->ep_entry,
  324. SLAPI_ATTR_ENTRYUSN_PREV);
  325. if (prev_entryusn_str) {
  326. /* discard the previous value from the tombstone entry */
  327. retval = slapi_entry_delete_string(tombstone->ep_entry,
  328. SLAPI_ATTR_ENTRYUSN_PREV, prev_entryusn_str);
  329. if (0 != retval) {
  330. LDAPDebug( LDAP_DEBUG_TRACE,
  331. "delete (deleting %s) failed, err=%d\n",
  332. SLAPI_ATTR_ENTRYUSN, retval, 0) ;
  333. }
  334. }
  335. /* XXXggood above used to be: slapi_entry_add_string(tombstone->ep_entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE); */
  336. /* JCMREPL - Add a description of what's going on? */
  337. }
  338. /*
  339. * So, we believe that no code up till here actually added anything
  340. * to the persistent store. From now on, we're transacted
  341. */
  342. for (retry_count = 0; retry_count < RETRY_TIMES; retry_count++) {
  343. if (retry_count > 0) {
  344. dblayer_txn_abort(li,&txn);
  345. /* We're re-trying */
  346. LDAPDebug( LDAP_DEBUG_TRACE, "Delete Retrying Transaction\n", 0, 0, 0 );
  347. #ifndef LDBM_NO_BACKOFF_DELAY
  348. {
  349. PRIntervalTime interval;
  350. interval = PR_MillisecondsToInterval(slapi_rand() % 100);
  351. DS_Sleep(interval);
  352. }
  353. #endif
  354. }
  355. retval = dblayer_txn_begin(li,parent_txn,&txn);
  356. if (0 != retval) {
  357. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  358. ldap_result_code= LDAP_OPERATIONS_ERROR;
  359. goto error_return;
  360. }
  361. if(create_tombstone_entry)
  362. {
  363. /*
  364. * The entry is not removed from the disk when we tombstone an
  365. * entry. We change the DN, add objectclass=tombstone, and record
  366. * the UniqueID of the parent entry.
  367. */
  368. retval = id2entry_add( be, tombstone, &txn );
  369. if (DB_LOCK_DEADLOCK == retval) {
  370. LDAPDebug( LDAP_DEBUG_ARGS, "delete 1 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
  371. /* Abort and re-try */
  372. continue;
  373. }
  374. if (0 != retval) {
  375. LDAPDebug( LDAP_DEBUG_ANY, "id2entry_add failed, err=%d %s\n",
  376. retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
  377. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  378. ldap_result_code= LDAP_OPERATIONS_ERROR;
  379. goto error_return;
  380. }
  381. tombstone_in_cache = 1;
  382. }
  383. else
  384. {
  385. /* delete the entry from disk */
  386. retval = id2entry_delete( be, e, &txn );
  387. if (DB_LOCK_DEADLOCK == retval)
  388. {
  389. LDAPDebug( LDAP_DEBUG_ARGS, "delete 2 DEADLOCK\n", 0, 0, 0 );
  390. /* Retry txn */
  391. continue;
  392. }
  393. if (retval != 0 ) {
  394. if (retval == DB_RUNRECOVERY ||
  395. LDBM_OS_ERR_IS_DISKFULL(retval)) {
  396. disk_full = 1;
  397. }
  398. ldap_result_code= LDAP_OPERATIONS_ERROR;
  399. goto error_return;
  400. }
  401. }
  402. /* delete from attribute indexes */
  403. addordel_flags = BE_INDEX_DEL|BE_INDEX_PRESENCE|BE_INDEX_EQUALITY;
  404. if (delete_tombstone_entry)
  405. {
  406. addordel_flags |= BE_INDEX_TOMBSTONE; /* tell index code we are deleting a tombstone */
  407. }
  408. retval = index_addordel_entry( be, e, addordel_flags, &txn );
  409. if (DB_LOCK_DEADLOCK == retval)
  410. {
  411. LDAPDebug( LDAP_DEBUG_ARGS, "delete 1 DEADLOCK\n", 0, 0, 0 );
  412. /* Retry txn */
  413. continue;
  414. }
  415. if (retval != 0) {
  416. LDAPDebug( LDAP_DEBUG_TRACE, "index_del_entry failed\n", 0, 0, 0 );
  417. ldap_result_code= LDAP_OPERATIONS_ERROR;
  418. goto error_return;
  419. }
  420. if(create_tombstone_entry)
  421. {
  422. /*
  423. * The tombstone entry is removed from all attribute indexes
  424. * above, but we want it to remain in the nsUniqueID and nscpEntryDN indexes
  425. * and for objectclass=tombstone.
  426. */
  427. retval = index_addordel_string(be, SLAPI_ATTR_OBJECTCLASS,
  428. SLAPI_ATTR_VALUE_TOMBSTONE,
  429. tombstone->ep_id,BE_INDEX_ADD, &txn);
  430. if (DB_LOCK_DEADLOCK == retval) {
  431. LDAPDebug( LDAP_DEBUG_ARGS,
  432. "delete (adding %s) DB_LOCK_DEADLOCK\n",
  433. SLAPI_ATTR_VALUE_TOMBSTONE, 0, 0 );
  434. /* Retry txn */
  435. continue;
  436. }
  437. if (0 != retval) {
  438. LDAPDebug( LDAP_DEBUG_TRACE,
  439. "delete (adding %s) failed, err=%d %s\n",
  440. SLAPI_ATTR_VALUE_TOMBSTONE, retval,
  441. (msg = dblayer_strerror( retval )) ? msg : "" );
  442. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  443. ldap_result_code= LDAP_OPERATIONS_ERROR;
  444. goto error_return;
  445. }
  446. retval = index_addordel_string(be, SLAPI_ATTR_UNIQUEID,
  447. slapi_entry_get_uniqueid(tombstone->ep_entry),
  448. tombstone->ep_id,BE_INDEX_ADD,&txn);
  449. if (DB_LOCK_DEADLOCK == retval) {
  450. LDAPDebug( LDAP_DEBUG_ARGS,
  451. "delete (adding %s) DB_LOCK_DEADLOCK\n",
  452. SLAPI_ATTR_UNIQUEID, 0, 0 );
  453. /* Retry txn */
  454. continue;
  455. }
  456. if (0 != retval) {
  457. LDAPDebug( LDAP_DEBUG_TRACE,
  458. "delete (adding %s) failed, err=%d %s\n",
  459. SLAPI_ATTR_UNIQUEID, retval,
  460. (msg = dblayer_strerror( retval )) ? msg : "" );
  461. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  462. ldap_result_code= LDAP_OPERATIONS_ERROR;
  463. goto error_return;
  464. }
  465. retval = index_addordel_string(be, SLAPI_ATTR_NSCP_ENTRYDN,
  466. slapi_sdn_get_ndn(nscpEntrySDN),
  467. tombstone->ep_id, BE_INDEX_ADD, &txn);
  468. if (DB_LOCK_DEADLOCK == retval) {
  469. LDAPDebug( LDAP_DEBUG_ARGS,
  470. "delete (adding %s) DB_LOCK_DEADLOCK\n",
  471. SLAPI_ATTR_NSCP_ENTRYDN, 0, 0 );
  472. /* Retry txn */
  473. continue;
  474. }
  475. if (0 != retval) {
  476. LDAPDebug( LDAP_DEBUG_TRACE,
  477. "delete (adding %s) failed, err=%d %s\n",
  478. SLAPI_ATTR_NSCP_ENTRYDN, retval,
  479. (msg = dblayer_strerror( retval )) ? msg : "" );
  480. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  481. ldap_result_code= LDAP_OPERATIONS_ERROR;
  482. goto error_return;
  483. }
  484. /* add a new usn to the entryusn index */
  485. entryusn_str = slapi_entry_attr_get_charptr(tombstone->ep_entry,
  486. SLAPI_ATTR_ENTRYUSN);
  487. if (entryusn_str) {
  488. retval = index_addordel_string(be, SLAPI_ATTR_ENTRYUSN,
  489. entryusn_str, tombstone->ep_id, BE_INDEX_ADD, &txn);
  490. slapi_ch_free_string(&entryusn_str);
  491. if (DB_LOCK_DEADLOCK == retval) {
  492. LDAPDebug( LDAP_DEBUG_ARGS,
  493. "delete (adding %s) DB_LOCK_DEADLOCK\n",
  494. SLAPI_ATTR_ENTRYUSN, 0, 0 );
  495. /* Retry txn */
  496. continue;
  497. }
  498. if (0 != retval) {
  499. LDAPDebug( LDAP_DEBUG_TRACE,
  500. "delete (adding %s) failed, err=%d %s\n",
  501. SLAPI_ATTR_ENTRYUSN, retval,
  502. (msg = dblayer_strerror( retval )) ? msg : "" );
  503. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  504. ldap_result_code= LDAP_OPERATIONS_ERROR;
  505. goto error_return;
  506. }
  507. }
  508. /* delete a previous value (if it exists) from the entryusn index */
  509. if (prev_entryusn_str) {
  510. retval = index_addordel_string(be, SLAPI_ATTR_ENTRYUSN,
  511. prev_entryusn_str, tombstone->ep_id,
  512. BE_INDEX_DEL|BE_INDEX_EQUALITY, &txn);
  513. slapi_ch_free_string(&prev_entryusn_str);
  514. if (DB_LOCK_DEADLOCK == retval) {
  515. LDAPDebug( LDAP_DEBUG_ARGS,
  516. "delete (deleting %s) DB_LOCK_DEADLOCK\n",
  517. SLAPI_ATTR_ENTRYUSN, 0, 0 );
  518. /* Retry txn */
  519. continue;
  520. }
  521. if (0 != retval) {
  522. LDAPDebug( LDAP_DEBUG_TRACE,
  523. "delete (deleting %s) failed, err=%d %s\n",
  524. SLAPI_ATTR_ENTRYUSN, retval,
  525. (msg = dblayer_strerror( retval )) ? msg : "" );
  526. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  527. ldap_result_code= LDAP_OPERATIONS_ERROR;
  528. goto error_return;
  529. }
  530. }
  531. } /* create_tombstone_entry */
  532. else if (delete_tombstone_entry)
  533. {
  534. /*
  535. * We need to remove the Tombstone entry from the remaining indexes:
  536. * objectclass=nsTombstone, nsUniqueID, nscpEntryDN
  537. */
  538. char *nscpedn = NULL;
  539. retval = index_addordel_string(be, SLAPI_ATTR_OBJECTCLASS,
  540. SLAPI_ATTR_VALUE_TOMBSTONE, e->ep_id,
  541. BE_INDEX_DEL, &txn);
  542. if (DB_LOCK_DEADLOCK == retval) {
  543. LDAPDebug( LDAP_DEBUG_ARGS,
  544. "delete (deleting %s) DB_LOCK_DEADLOCK\n",
  545. SLAPI_ATTR_VALUE_TOMBSTONE, 0, 0 );
  546. /* Retry txn */
  547. continue;
  548. }
  549. if (0 != retval) {
  550. LDAPDebug( LDAP_DEBUG_TRACE,
  551. "delete (deleting %s) failed, err=%d %s\n",
  552. SLAPI_ATTR_VALUE_TOMBSTONE, retval,
  553. (msg = dblayer_strerror( retval )) ? msg : "" );
  554. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  555. ldap_result_code= LDAP_OPERATIONS_ERROR;
  556. goto error_return;
  557. }
  558. retval = index_addordel_string(be, SLAPI_ATTR_UNIQUEID,
  559. slapi_entry_get_uniqueid(e->ep_entry),
  560. e->ep_id, BE_INDEX_DEL, &txn);
  561. if (DB_LOCK_DEADLOCK == retval) {
  562. LDAPDebug( LDAP_DEBUG_ARGS,
  563. "delete (deleting %s) DB_LOCK_DEADLOCK\n",
  564. SLAPI_ATTR_UNIQUEID, 0, 0 );
  565. /* Retry txn */
  566. continue;
  567. }
  568. if (0 != retval) {
  569. LDAPDebug( LDAP_DEBUG_TRACE,
  570. "delete (deleting %s) failed, err=%d %s\n",
  571. SLAPI_ATTR_UNIQUEID, retval,
  572. (msg = dblayer_strerror( retval )) ? msg : "" );
  573. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  574. ldap_result_code= LDAP_OPERATIONS_ERROR;
  575. goto error_return;
  576. }
  577. nscpedn = slapi_entry_attr_get_charptr(e->ep_entry,
  578. SLAPI_ATTR_NSCP_ENTRYDN);
  579. if (nscpedn) {
  580. retval = index_addordel_string(be, SLAPI_ATTR_NSCP_ENTRYDN,
  581. nscpedn, e->ep_id, BE_INDEX_DEL, &txn);
  582. slapi_ch_free((void **)&nscpedn);
  583. if (DB_LOCK_DEADLOCK == retval) {
  584. LDAPDebug( LDAP_DEBUG_ARGS,
  585. "delete (deleting %s) DB_LOCK_DEADLOCK\n",
  586. SLAPI_ATTR_NSCP_ENTRYDN, 0, 0 );
  587. /* Retry txn */
  588. continue;
  589. }
  590. if (0 != retval) {
  591. LDAPDebug( LDAP_DEBUG_TRACE,
  592. "delete (deleting %s) failed, err=%d %s\n",
  593. SLAPI_ATTR_NSCP_ENTRYDN, retval,
  594. (msg = dblayer_strerror( retval )) ? msg : "" );
  595. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  596. ldap_result_code= LDAP_OPERATIONS_ERROR;
  597. goto error_return;
  598. }
  599. }
  600. /* delete usn from the entryusn index */
  601. entryusn_str = slapi_entry_attr_get_charptr(e->ep_entry,
  602. SLAPI_ATTR_ENTRYUSN);
  603. if (entryusn_str) {
  604. retval = index_addordel_string(be, SLAPI_ATTR_ENTRYUSN,
  605. entryusn_str, e->ep_id,
  606. BE_INDEX_DEL|BE_INDEX_EQUALITY, &txn);
  607. slapi_ch_free_string(&entryusn_str);
  608. if (DB_LOCK_DEADLOCK == retval) {
  609. LDAPDebug( LDAP_DEBUG_ARGS,
  610. "delete (deleting %s) DB_LOCK_DEADLOCK\n",
  611. SLAPI_ATTR_ENTRYUSN, 0, 0 );
  612. /* Retry txn */
  613. continue;
  614. }
  615. if (0 != retval) {
  616. LDAPDebug( LDAP_DEBUG_TRACE,
  617. "delete (deleting %s) failed, err=%d %s\n",
  618. SLAPI_ATTR_ENTRYUSN, retval,
  619. (msg = dblayer_strerror( retval )) ? msg : "" );
  620. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  621. ldap_result_code= LDAP_OPERATIONS_ERROR;
  622. goto error_return;
  623. }
  624. }
  625. } /* delete_tombstone_entry */
  626. if (parent_found) {
  627. /* Push out the db modifications from the parent entry */
  628. retval = modify_update_all(be,pb,&parent_modify_c,&txn);
  629. if (DB_LOCK_DEADLOCK == retval)
  630. {
  631. LDAPDebug( LDAP_DEBUG_ARGS, "del 4 DEADLOCK\n", 0, 0, 0 );
  632. /* Retry txn */
  633. continue;
  634. }
  635. if (0 != retval) {
  636. LDAPDebug( LDAP_DEBUG_TRACE, "delete 3 BAD, err=%d %s\n",
  637. retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
  638. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  639. ldap_result_code= LDAP_OPERATIONS_ERROR;
  640. goto error_return;
  641. }
  642. }
  643. /*
  644. * first check if searchentry needs to be removed
  645. * Remove the entry from the Virtual List View indexes.
  646. */
  647. if (!delete_tombstone_entry && !is_ruv &&
  648. !vlv_delete_search_entry(pb,e->ep_entry,inst)) {
  649. retval = vlv_update_all_indexes(&txn, be, pb, e, NULL);
  650. if (DB_LOCK_DEADLOCK == retval)
  651. {
  652. LDAPDebug( LDAP_DEBUG_ARGS, "delete DEADLOCK vlv_update_index\n", 0, 0, 0 );
  653. /* Retry txn */
  654. continue;
  655. }
  656. if (retval != 0 ) {
  657. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  658. ldap_result_code= LDAP_OPERATIONS_ERROR;
  659. goto error_return;
  660. }
  661. }
  662. if (retval == 0 ) {
  663. break;
  664. }
  665. }
  666. if (retry_count == RETRY_TIMES) {
  667. /* Failed */
  668. LDAPDebug( LDAP_DEBUG_ANY, "Retry count exceeded in delete\n", 0, 0, 0 );
  669. ldap_result_code= LDAP_OPERATIONS_ERROR;
  670. goto error_return;
  671. }
  672. retval = dblayer_txn_commit(li,&txn);
  673. if (0 != retval)
  674. {
  675. if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
  676. ldap_result_code= LDAP_OPERATIONS_ERROR;
  677. goto error_return;
  678. }
  679. /* delete from cache and clean up */
  680. cache_remove(&inst->inst_cache, e);
  681. cache_unlock_entry( &inst->inst_cache, e );
  682. cache_return( &inst->inst_cache, &e );
  683. if (parent_found)
  684. {
  685. /* Replace the old parent entry with the newly modified one */
  686. modify_switch_entries( &parent_modify_c,be);
  687. }
  688. rc= 0;
  689. goto common_return;
  690. error_return:
  691. if (e!=NULL) {
  692. cache_unlock_entry( &inst->inst_cache, e );
  693. cache_return( &inst->inst_cache, &e );
  694. }
  695. if (tombstone_in_cache)
  696. {
  697. cache_remove( &inst->inst_cache, tombstone );
  698. }
  699. else
  700. {
  701. backentry_free( &tombstone );
  702. }
  703. if (retval == DB_RUNRECOVERY) {
  704. dblayer_remember_disk_filled(li);
  705. ldbm_nasty("Delete",79,retval);
  706. disk_full = 1;
  707. }
  708. if (disk_full) {
  709. rc= return_on_disk_full(li);
  710. goto diskfull_return;
  711. }
  712. else
  713. rc= SLAPI_FAIL_GENERAL;
  714. /* It is specifically OK to make this call even when no transaction was in progress */
  715. dblayer_txn_abort(li,&txn); /* abort crashes in case disk full */
  716. common_return:
  717. if (tombstone_in_cache)
  718. {
  719. cache_return( &inst->inst_cache, &tombstone );
  720. }
  721. /*
  722. * The bepostop is called even if the operation fails,
  723. * but not if the operation is purging tombstones.
  724. */
  725. if (!delete_tombstone_entry) {
  726. plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_DELETE_FN);
  727. }
  728. diskfull_return:
  729. if(ldap_result_code!=-1)
  730. {
  731. slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
  732. }
  733. modify_term(&parent_modify_c,be);
  734. if(dblock_acquired)
  735. {
  736. dblayer_unlock_backend(be);
  737. }
  738. if (rc == 0 && opcsn && !is_fixup_operation && !delete_tombstone_entry)
  739. {
  740. /* URP Naming Collision
  741. * When an entry is deleted by a replicated delete operation
  742. * we must check for entries that have had a naming collision
  743. * with this entry. Now that this name has been given up, one
  744. * of those entries can take over the name.
  745. */
  746. slapi_pblock_set(pb, SLAPI_URP_NAMING_COLLISION_DN, slapi_ch_strdup (dn));
  747. }
  748. done_with_pblock_entry(pb, SLAPI_DELETE_EXISTING_ENTRY);
  749. slapi_ch_free((void**)&errbuf);
  750. slapi_sdn_done(&sdn);
  751. slapi_ch_free_string(&e_uniqueid);
  752. if (pb->pb_conn)
  753. {
  754. slapi_log_error (SLAPI_LOG_TRACE, "ldbm_back_delete", "leave conn=%" NSPRIu64 " op=%d\n", pb->pb_conn->c_connid, operation->o_opid);
  755. }
  756. return rc;
  757. }