diff --git a/arangod/Replication/Syncer.cpp b/arangod/Replication/Syncer.cpp index 0395ae1f29..12f2f2277f 100644 --- a/arangod/Replication/Syncer.cpp +++ b/arangod/Replication/Syncer.cpp @@ -406,13 +406,15 @@ int Syncer::applyCollectionDumpMarker( res = opRes.code; } catch (arangodb::basics::Exception const& ex) { res = ex.code(); - } catch (...) { - res = TRI_ERROR_INTERNAL; - } - - if (res != TRI_ERROR_NO_ERROR) { errorMsg = "document insert/replace operation failed: " + std::string(TRI_errno_string(res)); + } catch (std::exception const& ex) { + res = TRI_ERROR_INTERNAL; + errorMsg = "document insert/replace operation failed: " + + std::string(ex.what()); + } catch (...) { + res = TRI_ERROR_INTERNAL; + errorMsg = "document insert/replace operation failed: unknown exception"; } return res; @@ -436,15 +438,16 @@ int Syncer::applyCollectionDumpMarker( res = opRes.code; } catch (arangodb::basics::Exception const& ex) { res = ex.code(); - } catch (...) { - res = TRI_ERROR_INTERNAL; - } - - if (res != TRI_ERROR_NO_ERROR) { errorMsg = "document remove operation failed: " + std::string(TRI_errno_string(res)); + } catch (std::exception const& ex) { + errorMsg = "document remove operation failed: " + + std::string(ex.what()); + } catch (...) { + res = TRI_ERROR_INTERNAL; + errorMsg = "document remove operation failed: unknown exception"; } - + return res; } diff --git a/arangod/VocBase/transaction.cpp b/arangod/VocBase/transaction.cpp index 2045083fa2..ea48271175 100644 --- a/arangod/VocBase/transaction.cpp +++ b/arangod/VocBase/transaction.cpp @@ -610,18 +610,25 @@ static int WriteBeginMarker(TRI_transaction_t* trx) { try { arangodb::wal::TransactionMarker marker(TRI_DF_MARKER_VPACK_BEGIN_TRANSACTION, trx->_vocbase->id(), trx->_id); res = GetLogfileManager()->allocateAndWrite(marker, false).errorCode; + + TRI_IF_FAILURE("TransactionWriteBeginMarkerThrow") { + throw std::bad_alloc(); + } if (res == TRI_ERROR_NO_ERROR) { trx->_beginWritten = true; + } else { + THROW_ARANGO_EXCEPTION(res); } } catch (arangodb::basics::Exception const& ex) { res = ex.code(); + LOG(WARN) << "could not save transaction begin marker in log: " << ex.what(); + } catch (std::exception const& ex) { + res = TRI_ERROR_INTERNAL; + LOG(WARN) << "could not save transaction begin marker in log: " << ex.what(); } catch (...) { res = TRI_ERROR_INTERNAL; - } - - if (res != TRI_ERROR_NO_ERROR) { - LOG(WARN) << "could not save transaction begin marker in log: " << TRI_errno_string(res); + LOG(WARN) << "could not save transaction begin marker in log: unknown exception"; } return res; @@ -649,14 +656,23 @@ static int WriteAbortMarker(TRI_transaction_t* trx) { try { arangodb::wal::TransactionMarker marker(TRI_DF_MARKER_VPACK_ABORT_TRANSACTION, trx->_vocbase->id(), trx->_id); res = GetLogfileManager()->allocateAndWrite(marker, false).errorCode; + + TRI_IF_FAILURE("TransactionWriteAbortMarkerThrow") { + throw std::bad_alloc(); + } + + if (res != TRI_ERROR_NO_ERROR) { + THROW_ARANGO_EXCEPTION(res); + } } catch (arangodb::basics::Exception const& ex) { res = ex.code(); + LOG(WARN) << "could not save transaction abort marker in log: " << ex.what(); + } catch (std::exception const& ex) { + res = TRI_ERROR_INTERNAL; + LOG(WARN) << "could not save transaction abort marker in log: " << ex.what(); } catch (...) { res = TRI_ERROR_INTERNAL; - } - - if (res != TRI_ERROR_NO_ERROR) { - LOG(WARN) << "could not save transaction abort marker in log: " << TRI_errno_string(res); + LOG(WARN) << "could not save transaction abort marker in log: unknown exception"; } return res; @@ -692,15 +708,24 @@ static int WriteCommitMarker(TRI_transaction_t* trx) { // also sync RocksDB WAL RocksDBFeature::syncWal(); } + + TRI_IF_FAILURE("TransactionWriteCommitMarkerThrow") { + throw std::bad_alloc(); + } + + if (res != TRI_ERROR_NO_ERROR) { + THROW_ARANGO_EXCEPTION(res); + } #endif } catch (arangodb::basics::Exception const& ex) { res = ex.code(); + LOG(WARN) << "could not save transaction commit marker in log: " << ex.what(); + } catch (std::exception const& ex) { + res = TRI_ERROR_INTERNAL; + LOG(WARN) << "could not save transaction commit marker in log: " << ex.what(); } catch (...) { res = TRI_ERROR_INTERNAL; - } - - if (res != TRI_ERROR_NO_ERROR) { - LOG(WARN) << "could not save transaction commit marker in log: " << TRI_errno_string(res); + LOG(WARN) << "could not save transaction commit marker in log: unknown exception"; } return res; diff --git a/js/server/tests/shell/shell-transactions-noncluster.js b/js/server/tests/shell/shell-transactions-noncluster.js index e36a97f2e7..edfb37e140 100644 --- a/js/server/tests/shell/shell-transactions-noncluster.js +++ b/js/server/tests/shell/shell-transactions-noncluster.js @@ -5017,6 +5017,135 @@ function transactionServerFailuresSuite () { testHelper.waitUnload(c); + assertEqual(100, c.count()); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test: cannot write begin marker for trx +//////////////////////////////////////////////////////////////////////////////// + + testNoBeginMarkerThrow : function () { + internal.debugClearFailAt(); + + db._drop(cn); + c = db._create(cn); + + var i; + for (i = 0; i < 100; ++i) { + c.save({ _key: "test" + i, a: i }); + } + assertEqual(100, c.count()); + + internal.wal.flush(true, true); + internal.debugSetFailAt("TransactionWriteBeginMarkerThrow"); + + try { + TRANSACTION({ + collections: { + write: [ cn ], + }, + action: function () { + c.save({ _key: "test100" }); + fail(); + } + }); + fail(); + } + catch (err) { + assertEqual(internal.errors.ERROR_INTERNAL.code, err.errorNum); + } + + assertEqual(100, c.count()); + internal.debugClearFailAt(); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test: cannot write commit marker for trx +//////////////////////////////////////////////////////////////////////////////// + + testNoCommitMarkerThrow : function () { + internal.debugClearFailAt(); + + db._drop(cn); + c = db._create(cn); + + var i; + for (i = 0; i < 100; ++i) { + c.save({ _key: "test" + i, a: i }); + } + assertEqual(100, c.count()); + + internal.wal.flush(true, true); + internal.debugSetFailAt("TransactionWriteCommitMarkerThrow"); + + try { + TRANSACTION({ + collections: { + write: [ cn ], + }, + action: function () { + var i; + for (i = 100; i < 1000; ++i) { + c.save({ _key: "test" + i, a: i }); + } + + assertEqual(1000, c.count()); + } + }); + fail(); + } + catch (err) { + assertEqual(internal.errors.ERROR_INTERNAL.code, err.errorNum); + } + + assertEqual(100, c.count()); + internal.debugClearFailAt(); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test: cannot write abort marker for trx +//////////////////////////////////////////////////////////////////////////////// + + testNoAbortMarkerThrow : function () { + internal.debugClearFailAt(); + + db._drop(cn); + c = db._create(cn); + + var i; + for (i = 0; i < 100; ++i) { + c.save({ _key: "test" + i, a: i }); + } + assertEqual(100, c.count()); + + internal.wal.flush(true, true); + internal.debugSetFailAt("TransactionWriteAbortMarkerThrow"); + + try { + TRANSACTION({ + collections: { + write: [ cn ], + }, + action: function () { + var i; + for (i = 100; i < 1000; ++i) { + c.save({ _key: "test" + i, a: i }); + } + + assertEqual(1000, c.count()); + + throw "rollback!"; + } + }); + } + catch (err) { + // ignore the intentional error + } + + internal.debugClearFailAt(); + + testHelper.waitUnload(c); + assertEqual(100, c.count()); }