use of com.zimbra.cs.session.AllAccountsRedoCommitCallback in project zm-mailbox by Zimbra.
the class Mailbox method endTransaction.
/**
* Be very careful when changing code in this method. The order of almost
* every line of code is important to ensure correct redo logging and crash
* recovery.
*
* @param success true to commit the transaction, false to rollback
* @throws ServiceException error
*/
protected void endTransaction(boolean success) throws ServiceException {
assert !Thread.holdsLock(this) : "Use MailboxLock";
if (lock.isUnlocked()) {
ZimbraLog.mailbox.warn("transaction canceled because of lock failure");
assert (!success);
return;
}
// blob and index to delete
PendingDelete deletes = null;
// blob to delete for failure cases
List<Object> rollbackDeletes = null;
try {
if (!currentChange().isActive()) {
// would like to throw here, but it might cover another
// exception...
ZimbraLog.mailbox.warn("cannot end a transaction when not inside a transaction", new Exception());
return;
}
if (!currentChange().endChange()) {
return;
}
ServiceException exception = null;
if (success) {
List<IndexItemEntry> indexItems = currentChange().indexItems;
if (!indexItems.isEmpty()) {
assert (currentChange().writeChange);
//TODO: See bug 15072 - we need to clear mCurrentChange.indexItems (it is stored in a temporary) here,
// just in case item.reindex() recurses into a new transaction...
currentChange().indexItems = new ArrayList<IndexItemEntry>();
index.add(indexItems);
}
// update mailbox size, folder unread/message counts
try {
snapshotCounts();
} catch (ServiceException e) {
exception = e;
success = false;
}
}
DbConnection conn = currentChange().conn;
// transaction, so no redo cleanup is necessary.
if (!success) {
DbPool.quietRollback(conn);
rollbackDeletes = rollbackCache(currentChange());
if (exception != null) {
throw exception;
}
return;
}
RedoableOp redoRecorder = currentChange().recorder;
boolean needRedo = needRedo(currentChange().octxt, redoRecorder);
// Log the change redo record for main transaction.
if (redoRecorder != null && needRedo) {
redoRecorder.log(true);
}
boolean dbCommitSuccess = false;
try {
// Commit the main transaction in database.
if (conn != null) {
try {
conn.commit();
} catch (Throwable t) {
// Any exception during database commit is a disaster
// because we don't know if the change is committed or
// not. Force the server to abort. Next restart will
// redo the operation to ensure the change is made and
// committed. (bug 2121)
Zimbra.halt("Unable to commit database transaction. Forcing server to abort.", t);
}
}
dbCommitSuccess = true;
} finally {
if (!dbCommitSuccess) {
// recovery will try to redo the operation.
if (needRedo) {
if (redoRecorder != null) {
redoRecorder.abort();
}
}
DbPool.quietRollback(conn);
rollbackDeletes = rollbackCache(currentChange());
return;
}
}
if (needRedo) {
// case would result in a redo error, and the second case would index the wrong value.
if (redoRecorder != null) {
if (currentChange().dirty != null && !currentChange().dirty.changedTypes.isEmpty()) {
// if an "all accounts" waitset is active, and this change has an appropriate type,
// then we'll need to set a commit-callback
AllAccountsRedoCommitCallback cb = AllAccountsRedoCommitCallback.getRedoCallbackIfNecessary(getAccountId(), currentChange().dirty.changedTypes);
if (cb != null) {
redoRecorder.setCommitCallback(cb);
}
}
redoRecorder.commit();
}
}
boolean changeMade = currentChange().changeId != MailboxChange.NO_CHANGE;
// keep a reference for cleanup
deletes = currentChange().deletes;
// deletes outside the lock
// We are finally done with database and redo commits. Cache update
// comes last.
commitCache(currentChange());
// down in its call stack.
if (changeMade) {
index.maybeIndexDeferredItems();
}
} finally {
lock.release();
// entail a blocking network operation
if (deletes != null) {
if (!deletes.indexIds.isEmpty()) {
// delete any index entries associated with items deleted from db
index.delete(deletes.indexIds);
}
if (deletes.blobs != null) {
// delete any blobs associated with items deleted from db/index
StoreManager sm = StoreManager.getInstance();
for (MailboxBlob blob : deletes.blobs) {
sm.quietDelete(blob);
}
}
}
if (rollbackDeletes != null) {
StoreManager sm = StoreManager.getInstance();
for (Object obj : rollbackDeletes) {
if (obj instanceof MailboxBlob) {
sm.quietDelete((MailboxBlob) obj);
} else if (obj instanceof Blob) {
sm.quietDelete((Blob) obj);
}
}
}
}
}
Aggregations