Search in sources :

Example 1 with Checkpoint

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);
}
Also used : Checkpoint(com.zimbra.cs.redolog.op.Checkpoint) RedoableOp(com.zimbra.cs.redolog.op.RedoableOp) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 2 with Checkpoint

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);
                            }
                        }
                    }
                }
            }
        }
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) CommitTxn(com.zimbra.cs.redolog.op.CommitTxn) Checkpoint(com.zimbra.cs.redolog.op.Checkpoint) IOException(java.io.IOException) ServiceException(com.zimbra.common.service.ServiceException) Checkpoint(com.zimbra.cs.redolog.op.Checkpoint) Entry(java.util.Map.Entry) RedoableOp(com.zimbra.cs.redolog.op.RedoableOp) StoreIncomingBlob(com.zimbra.cs.redolog.op.StoreIncomingBlob) Iterator(java.util.Iterator) ArrayList(java.util.ArrayList) List(java.util.List) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Aggregations

Checkpoint (com.zimbra.cs.redolog.op.Checkpoint)2 RedoableOp (com.zimbra.cs.redolog.op.RedoableOp)2 LinkedHashMap (java.util.LinkedHashMap)2 Map (java.util.Map)2 ServiceException (com.zimbra.common.service.ServiceException)1 CommitTxn (com.zimbra.cs.redolog.op.CommitTxn)1 StoreIncomingBlob (com.zimbra.cs.redolog.op.StoreIncomingBlob)1 IOException (java.io.IOException)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Iterator (java.util.Iterator)1 List (java.util.List)1 Entry (java.util.Map.Entry)1 Set (java.util.Set)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 ConcurrentMap (java.util.concurrent.ConcurrentMap)1