use of com.zimbra.cs.redolog.op.Checkpoint in project zm-mailbox by Zimbra.
the class RedoLogManager method checkpoint.
/**
* Should be called with write lock on mRWLock held.
*/
private void checkpoint() {
LinkedHashSet<TransactionId> txns = null;
synchronized (mActiveOps) {
if (mActiveOps.size() == 0)
return;
// Create an empty LinkedHashSet and insert keys from mActiveOps
// by iterating the keyset.
txns = new LinkedHashSet<TransactionId>();
for (Iterator<Map.Entry<TransactionId, RedoableOp>> it = mActiveOps.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<TransactionId, RedoableOp> entry = it.next();
txns.add(entry.getKey());
}
}
Checkpoint ckpt = new Checkpoint(txns);
logOnly(ckpt, true);
}
use of com.zimbra.cs.redolog.op.Checkpoint in project zm-mailbox by Zimbra.
the class RedoPlayer method processOp.
private final void processOp(RedoableOp op, boolean redoCommitted, Map<Integer, Integer> mboxIDsMap, long startTime, long endTime, long ignoreCommitsAtOrAfter) throws ServiceException {
if (op.isStartMarker()) {
synchronized (mOpsMapGuard) {
mOpsMap.put(op.getTransactionId(), op);
if (mHasOrphanOps) {
RedoableOp x = mOrphanOps.remove(op.getTransactionId());
if (x != null)
ZimbraLog.redolog.error("Detected out-of-order insertion of change record for orphans commit/abort: change=" + op + ", orphan=" + x);
}
}
} else {
// those listed in the checkpoint.
if (op instanceof Checkpoint) {
Checkpoint ckpt = (Checkpoint) op;
Set txns = ckpt.getActiveTxns();
if (txns.size() > 0) {
synchronized (mOpsMapGuard) {
if (mOpsMap.size() != txns.size()) {
// Unexpected discrepancy
if (ZimbraLog.redolog.isDebugEnabled()) {
StringBuffer sb1 = new StringBuffer("Current Uncommitted Ops: ");
StringBuffer sb2 = new StringBuffer("Checkpoint Uncommitted Ops: ");
int i = 0;
for (Iterator it = mOpsMap.keySet().iterator(); it.hasNext(); i++) {
TransactionId id = (TransactionId) it.next();
if (i > 0)
sb1.append(", ");
sb1.append(id);
}
i = 0;
for (Iterator it = txns.iterator(); it.hasNext(); i++) {
TransactionId id = (TransactionId) it.next();
if (i > 0)
sb2.append(", ");
sb2.append(id);
}
ZimbraLog.redolog.info("Checkpoint discrepancy: # current uncommitted ops = " + mOpsMap.size() + ", # checkpoint uncommitted ops = " + txns.size() + "\nMAP DUMP:\n" + sb1.toString() + "\n" + sb2.toString());
}
}
}
} else {
synchronized (mOpsMapGuard) {
if (mOpsMap.size() != 0) {
// Unexpected discrepancy
if (ZimbraLog.redolog.isDebugEnabled()) {
StringBuffer sb1 = new StringBuffer("Current Uncommitted Ops: ");
int i = 0;
for (Iterator it = mOpsMap.keySet().iterator(); it.hasNext(); i++) {
TransactionId id = (TransactionId) it.next();
if (i > 0)
sb1.append(", ");
sb1.append(id);
}
ZimbraLog.redolog.info("Checkpoint discrepancy: # current uncommitted ops = " + mOpsMap.size() + " instead of 0\nMAP DUMP:\n" + sb1.toString());
}
}
}
}
} else if (op.isEndMarker()) {
// Ignore if op is a commit and its timestamp is at or after ignoreCommitsAtOrAfter.
// In other words, don't ignore if op is a rollback OR its timestamp is before ignoreCommitsAtOrAfter.
boolean isCommitOp = op instanceof CommitTxn;
long opTstamp = op.getTimestamp();
if (!isCommitOp || opTstamp < ignoreCommitsAtOrAfter) {
// Encountered COMMIT or ABORT. Discard the
// corresponding op from map, and optionally execute the committed op.
RedoableOp prepareOp;
synchronized (mOpsMapGuard) {
prepareOp = (RedoableOp) mOpsMap.remove(op.getTransactionId());
if (prepareOp == null) {
mHasOrphanOps = true;
ZimbraLog.redolog.error("Commit/abort record encountered before corresponding change record (" + op + ")");
TransactionId tid = op.getTransactionId();
RedoableOp x = (RedoableOp) mOrphanOps.get(tid);
if (x != null)
ZimbraLog.redolog.error("Op [" + op + "] is already in orphans map: value=" + x);
mOrphanOps.put(tid, op);
}
}
if (redoCommitted && prepareOp != null && isCommitOp && (startTime == -1 || prepareOp.getTimestamp() >= startTime) && opTstamp < endTime) {
boolean allowRedo = false;
if (mboxIDsMap == null) {
// Caller doesn't care which mailbox(es) the op is for.
allowRedo = true;
} else {
int opMailboxId = prepareOp.getMailboxId();
if (prepareOp instanceof StoreIncomingBlob) {
assert (opMailboxId == RedoableOp.MAILBOX_ID_ALL);
// special case for StoreIncomingBlob op that has
// a list of mailbox IDs.
StoreIncomingBlob storeOp = (StoreIncomingBlob) prepareOp;
List<Integer> list = storeOp.getMailboxIdList();
if (list != null) {
Set<Integer> opMboxIds = new HashSet<Integer>(list);
for (Map.Entry<Integer, Integer> entry : mboxIDsMap.entrySet()) {
if (opMboxIds.contains(entry.getKey())) {
allowRedo = true;
// Replace the mailbox ID list in the op. We're
// replaying it only for the target mailbox ID we're
// interested in.
List<Integer> newList = new ArrayList<Integer>(mboxIDsMap.values());
storeOp.setMailboxIdList(newList);
break;
}
}
} else {
// Prior to redolog version 1.0 StoreIncomingBlob
// didn't keep track of mailbox list. Always recreate
// the blob since we don't know which mailboxes will
// need it.
allowRedo = true;
}
} else if (opMailboxId == RedoableOp.MAILBOX_ID_ALL) {
// This case should be checked after StoreIncomingBlob
// case because StoreIncomingBlob has mailbox ID of
// MAILBOX_ID_ALL.
allowRedo = true;
} else {
for (Map.Entry<Integer, Integer> entry : mboxIDsMap.entrySet()) {
if (opMailboxId == entry.getKey().intValue()) {
if (entry.getValue() != null) {
// restore to a different mailbox
prepareOp.setMailboxId(entry.getValue().intValue());
}
allowRedo = true;
break;
}
}
}
}
if (allowRedo) {
if (mSkipDeleteOps && prepareOp.isDeleteOp()) {
ZimbraLog.redolog.info("Skipping delete op: " + prepareOp.toString());
} else {
try {
if (ZimbraLog.redolog.isDebugEnabled())
ZimbraLog.redolog.debug("Redoing: " + prepareOp.toString());
prepareOp.setUnloggedReplay(mUnloggedReplay);
playOp(prepareOp);
} catch (Exception e) {
if (!ignoreReplayErrors())
throw ServiceException.FAILURE("Error executing redoOp", e);
else
ZimbraLog.redolog.warn("Ignoring error during redo log replay: " + e.getMessage(), e);
}
}
}
}
}
}
}
}
Aggregations