diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c index 3a97f2f..b8e9503 100644 --- a/ldap/servers/slapd/back-ldbm/dblayer.c +++ b/ldap/servers/slapd/back-ldbm/dblayer.c @@ -3323,10 +3323,29 @@ int dblayer_txn_init(struct ldbminfo *li __attribute__((unused)), back_txn *txn) return 0; } - int dblayer_txn_begin_ext(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn, PRBool use_lock) { + dblayer_private *priv = NULL; + int txn_begin_flags = 0; + PR_ASSERT(NULL != li); + + if ( g_get_shutdown() == SLAPI_SHUTDOWN_DISKFULL ) { + return -1; + } + + priv = (dblayer_private*)li->li_dblayer_private; + PR_ASSERT(NULL != priv); + + if (!priv->dblayer_txn_wait) { + txn_begin_flags = DB_TXN_NOWAIT; + } + return dblayer_txn_begin_ext_txnflags(li, parent_txn, txn, use_lock, txn_begin_flags); +} + +int +dblayer_txn_begin_ext_txnflags(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn, PRBool use_lock, int txn_begin_flags) +{ int return_value = -1; dblayer_private *priv = NULL; back_txn new_txn = {NULL}; @@ -3349,8 +3368,6 @@ dblayer_txn_begin_ext(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn, if (priv->dblayer_enable_transactions) { - int txn_begin_flags; - dblayer_private_env *pEnv = priv->dblayer_env; if(use_lock) slapi_rwlock_rdlock(pEnv->dblayer_env_lock); if (!parent_txn) @@ -3360,11 +3377,6 @@ dblayer_txn_begin_ext(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn, if (par_txn_txn) { parent_txn = par_txn_txn->back_txn_txn; } - } - if (priv->dblayer_txn_wait) { - txn_begin_flags = 0; - } else { - txn_begin_flags = DB_TXN_NOWAIT; } return_value = TXN_BEGIN(pEnv->dblayer_DB_ENV, (DB_TXN*)parent_txn, @@ -3406,6 +3418,13 @@ dblayer_txn_begin_ext(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn, } int +dblayer_export_txn_begin(backend *be, back_txnid parent_txn, back_txn *txn) +{ + struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private; + return (dblayer_txn_begin_ext_txnflags(li,parent_txn,txn,PR_FALSE,DB_READ_COMMITTED|DB_TXN_NOWAIT)); +} + +int dblayer_read_txn_begin(backend *be, back_txnid parent_txn, back_txn *txn) { struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private; @@ -3534,6 +3553,12 @@ int dblayer_txn_commit_ext(struct ldbminfo *li, back_txn *txn, PRBool use_lock) } int +dblayer_export_txn_commit(backend *be, back_txn *txn) +{ + return dblayer_read_txn_commit(be, txn); +} + +int dblayer_read_txn_commit(backend *be, back_txn *txn) { struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private; @@ -3626,6 +3651,12 @@ int dblayer_txn_abort_ext(struct ldbminfo *li, back_txn *txn, PRBool use_lock) } int +dblayer_export_txn_abort(backend *be, back_txn *txn) +{ + return dblayer_read_txn_abort(be, txn); +} + +int dblayer_read_txn_abort(backend *be, back_txn *txn) { struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private; diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c index 6d897ed..ec87d16 100644 --- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c +++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c @@ -1079,6 +1079,7 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb ) struct ldbminfo *li = NULL; DB *db = NULL; DBC *dbc = NULL; + back_txn s_txn = {NULL}; struct backentry *ep; DBT key = {0}; DBT data = {0}; @@ -1115,9 +1116,9 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb ) static int load_dse = 1; /* We'd like to load dse just once. */ int server_running; export_args eargs = {0}; - + slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_ldbm2ldif", "=>\n"); - + slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li ); slapi_pblock_get( pb, SLAPI_TASK_FLAGS, &task_flags ); slapi_pblock_get( pb, SLAPI_DB2LDIF_DECRYPT, &decrypt ); @@ -1284,8 +1285,9 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb ) } /* idl manipulation requires nextid to be init'd now */ - if (include_suffix && ok_index) + if (include_suffix && ok_index) { get_ids_from_disk(be); + } if ((( dblayer_get_id2entry( be, &db )) != 0) || (db == NULL)) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "Could not open/create id2entry\n"); @@ -1293,6 +1295,21 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb ) goto bye; } + /* Open a TXN so that all our actions across id2entry and entryrdn can be + * correlated by the BDB layer. If we don't group them in a transaction, + * we risk deadlocking ourself as we hop around to fill in parents, turn + * RDNs into DNs, etc. if it happens that we need to access a page which + * has already been locked. (TEL 20180626) */ + slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_ldbm2ldif", "Beginning transaction for LDIF export.\n"); + dblayer_txn_init(li, &s_txn); + rc = dblayer_export_txn_begin(be, NULL, &s_txn); + if (rc) { + slapi_log_err(SLAPI_LOG_ERR, + "ldbm_back_ldbm2ldif", "Transaction error: %s (%d)\n", + dblayer_strerror(return_value), return_value); + goto bye; + } + /* if an include_suffix was given (and we're pretty sure the * entrydn and ancestorid indexes are valid), we try to * assemble an id-list of candidates instead of plowing thru @@ -1306,7 +1323,7 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb ) * which it is ! */ /* get a cursor to we can walk over the table */ - return_value = db->cursor(db,NULL,&dbc,0); + return_value = db->cursor(db, s_txn.back_txn_txn, &dbc, 0); if (0 != return_value || NULL == dbc) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "Failed to get cursor for db2ldif; %s (%d)\n", @@ -1400,7 +1417,7 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb ) data.flags = DB_DBT_MALLOC; for (retry = 0; retry < RETRY_TIMES; retry++) { - return_value = db->get(db, NULL, &key, &data, 0); + return_value = db->get(db, s_txn.back_txn_txn, &key, &data, 0); if (return_value != DB_LOCK_DEADLOCK) break; } if (return_value) { @@ -1481,7 +1498,7 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb ) eargs.cnt = &cnt; eargs.lastcnt = &lastcnt; - rc = _export_or_index_parents(inst, db, NULL, temp_id, + rc = _export_or_index_parents(inst, db, &s_txn, temp_id, rdn, temp_id, pid, run_from_cmdline, &eargs, DB2LDIF_ENTRYRDN, &psrdn); if (rc) { @@ -1501,7 +1518,7 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb ) } else { int myrc = 0; Slapi_DN *sdn = NULL; - rc = entryrdn_lookup_dn(be, rdn, temp_id, &dn, NULL, NULL); + rc = entryrdn_lookup_dn(be, rdn, temp_id, &dn, NULL, &s_txn); if (rc) { /* We cannot use the entryrdn index; * Compose dn from the entries in id2entry */ @@ -1513,7 +1530,7 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb ) if (NULL == slapi_rdn_get_rdn(&psrdn)) { /* This time just to get the parents' rdn * most likely from dn cache. */ - rc = _get_and_add_parent_rdns(be, db, NULL, pid, + rc = _get_and_add_parent_rdns(be, db, &s_txn, pid, &psrdn, NULL, 0, run_from_cmdline, NULL); if (rc) { @@ -1611,6 +1628,13 @@ bye: if (dbc) { dbc->c_close(dbc); } + if (s_txn.back_txn_txn) { + /* Abort rather than commit the transaction, since we should not be + * making any changes to the DB during an export, which this more or + * less guarantees. (TEL 20180626) */ + slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_ldbm2ldif", "Aborting LDIF export transaction (this is normal).\n"); + dblayer_export_txn_abort(be, &s_txn); + } dblayer_release_id2entry( be, db ); @@ -3283,6 +3307,7 @@ _get_and_add_parent_rdns(backend *be, char *pid_str = NULL; ID storedid; ID temp_pid = NOID; + DB_TXN *db_txn = (NULL != txn) ? txn->back_txn_txn : NULL; if (!entryrdn_get_switch()) { /* entryrdn specific code */ return rc; @@ -3347,7 +3372,7 @@ _get_and_add_parent_rdns(backend *be, memset(&data, 0, sizeof(data)); data.flags = DB_DBT_MALLOC; - rc = db->get(db, NULL, &key, &data, 0); + rc = db->get(db, db_txn, &key, &data, 0); if (rc) { slapi_log_err(SLAPI_LOG_ERR, "_get_and_add_parent_rdns", "Failed to position cursor at ID " ID_FMT "\n", id); @@ -3511,7 +3536,7 @@ _export_or_index_parents(ldbm_instance *inst, } /* in case the parent is not already exported */ - rc = entryrdn_get_parent(be, rdn, id, &prdn, &temp_pid, NULL); + rc = entryrdn_get_parent(be, rdn, id, &prdn, &temp_pid, txn); if (rc) { /* entryrdn is not available. */ /* get the parent info from the id2entry (no add) */ rc = _get_and_add_parent_rdns(be, db, txn, pid, psrdn, &ppid, 0, @@ -3537,7 +3562,7 @@ _export_or_index_parents(ldbm_instance *inst, if (!bdn) { /* we put pdn to dn cache, which could be used * in _get_and_add_parent_rdns */ - rc = entryrdn_lookup_dn(be, prdn, pid, &pdn, NULL, NULL); + rc = entryrdn_lookup_dn(be, prdn, pid, &pdn, NULL, txn); if (0 == rc) { int myrc = 0; /* pdn is put in DN cache. No need to free it here, @@ -3565,7 +3590,7 @@ _export_or_index_parents(ldbm_instance *inst, /* check one more upper level */ if (0 == ppid) { - rc = entryrdn_get_parent(be, prdn, pid, &pprdn, &ppid, NULL); + rc = entryrdn_get_parent(be, prdn, pid, &pprdn, &ppid, txn); slapi_ch_free_string(&pprdn); if (rc) { /* entryrdn is not available */ slapi_log_err(SLAPI_LOG_ERR, "_export_or_index_parents", diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h index 86ef5cb..d37737d 100644 --- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h +++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h @@ -98,6 +98,7 @@ int dblayer_release_aux_id2entry(backend *be, DB *pDB, DB_ENV *pEnv); int dblayer_txn_init(struct ldbminfo *li, back_txn *txn); int dblayer_txn_begin(backend *be,back_txnid parent_txn, back_txn *txn); int dblayer_txn_begin_ext(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn, PRBool use_lock); +int dblayer_txn_begin_ext_txnflags(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn, PRBool use_lock, int txn_begin_flags); int dblayer_txn_commit(backend *be, back_txn *txn); int dblayer_txn_commit_ext(struct ldbminfo *li, back_txn *txn, PRBool use_lock); int dblayer_txn_abort(backend *be, back_txn *txn); @@ -105,6 +106,9 @@ int dblayer_txn_abort_ext(struct ldbminfo *li, back_txn *txn, PRBool use_lock); int dblayer_read_txn_abort(backend *be, back_txn *txn); int dblayer_read_txn_begin(backend *be,back_txnid parent_txn, back_txn *txn); int dblayer_read_txn_commit(backend *be, back_txn *txn); +int dblayer_export_txn_abort(backend *be, back_txn *txn); +int dblayer_export_txn_begin(backend *be,back_txnid parent_txn, back_txn *txn); +int dblayer_export_txn_commit(backend *be, back_txn *txn); int dblayer_txn_begin_all(struct ldbminfo *li,back_txnid parent_txn, back_txn *txn); int dblayer_txn_commit_all(struct ldbminfo *li, back_txn *txn); int dblayer_txn_abort_all(struct ldbminfo *li, back_txn *txn);