private void invokeCallbacks(Callback<Void>[] callbacks, Throwable e) { for (Callback<Void> callback : callbacks) { try { callback.onDone(null, e); } catch (Throwable e2) { Log.error("Transaction callback error", e2); } } }
/** * ACID transactional semantics:<br> * - Atomicity with automatic rollback in case of exception,<br> * - Consistency - only with constraints enforced programmatically inside transaction,<br> * - Isolation is serializable (with global lock),<br> * - Durability through on-commit callbacks.<br> */ public void transaction(Runnable transaction, boolean readOnly, Callback<Void> txCallback) { globalLock(); data.txIdCounter.set(data.ids.get()); data.txChanges.clear(); data.txInsertions.clear(); data.txReadonly.set(readOnly); data.insideTx.set(true); boolean success = false; try { transaction.run(); success = true; } catch (Throwable e) { if (SuccessException.isSuccess(e)) { success = true; throw U.rte(e); } else { Log.error("Error in transaction, rolling back", e); txRollback(); if (txCallback != null) { txCallback.onDone(null, e); txCallback = null; } } } finally { data.txChanges.clear(); data.txInsertions.clear(); data.insideTx.set(false); if (persistor != null) { if (success && txCallback != null) { data.txCallbacks.add(txCallback); } } else { if (success && txCallback != null) { txCallback.onDone(null, null); } } globalUnlock(); } }