Search in sources :

Example 1 with ReadLock

use of java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock in project zookeeper by apache.

the class LearnerHandler method syncFollower.

/**
     * Determine if we need to sync with follower using DIFF/TRUNC/SNAP
     * and setup follower to receive packets from commit processor
     *
     * @param peerLastZxid
     * @param db
     * @param leader
     * @return true if snapshot transfer is needed.
     */
public boolean syncFollower(long peerLastZxid, ZKDatabase db, Leader leader) {
    /*
         * When leader election is completed, the leader will set its
         * lastProcessedZxid to be (epoch < 32). There will be no txn associated
         * with this zxid.
         *
         * The learner will set its lastProcessedZxid to the same value if
         * it get DIFF or SNAP from the leader. If the same learner come
         * back to sync with leader using this zxid, we will never find this
         * zxid in our history. In this case, we will ignore TRUNC logic and
         * always send DIFF if we have old enough history
         */
    boolean isPeerNewEpochZxid = (peerLastZxid & 0xffffffffL) == 0;
    // Keep track of the latest zxid which already queued
    long currentZxid = peerLastZxid;
    boolean needSnap = true;
    boolean txnLogSyncEnabled = (db.getSnapshotSizeFactor() >= 0);
    ReentrantReadWriteLock lock = db.getLogLock();
    ReadLock rl = lock.readLock();
    try {
        rl.lock();
        long maxCommittedLog = db.getmaxCommittedLog();
        long minCommittedLog = db.getminCommittedLog();
        long lastProcessedZxid = db.getDataTreeLastProcessedZxid();
        LOG.info("Synchronizing with Follower sid: {} maxCommittedLog=0x{}" + " minCommittedLog=0x{} lastProcessedZxid=0x{}" + " peerLastZxid=0x{}", getSid(), Long.toHexString(maxCommittedLog), Long.toHexString(minCommittedLog), Long.toHexString(lastProcessedZxid), Long.toHexString(peerLastZxid));
        if (db.getCommittedLog().isEmpty()) {
            /*
                 * It is possible that commitedLog is empty. In that case
                 * setting these value to the latest txn in leader db
                 * will reduce the case that we need to handle
                 *
                 * Here is how each case handle by the if block below
                 * 1. lastProcessZxid == peerZxid -> Handle by (2)
                 * 2. lastProcessZxid < peerZxid -> Handle by (3)
                 * 3. lastProcessZxid > peerZxid -> Handle by (5)
                 */
            minCommittedLog = lastProcessedZxid;
            maxCommittedLog = lastProcessedZxid;
        }
        if (forceSnapSync) {
            // Force leader to use snapshot to sync with follower
            LOG.warn("Forcing snapshot sync - should not see this in production");
        } else if (lastProcessedZxid == peerLastZxid) {
            // Follower is already sync with us, send empty diff
            LOG.info("Sending DIFF zxid=0x" + Long.toHexString(peerLastZxid) + " for peer sid: " + getSid());
            queueOpPacket(Leader.DIFF, peerLastZxid);
            needOpPacket = false;
            needSnap = false;
        } else if (peerLastZxid > maxCommittedLog && !isPeerNewEpochZxid) {
            // Newer than commitedLog, send trunc and done
            LOG.debug("Sending TRUNC to follower zxidToSend=0x" + Long.toHexString(maxCommittedLog) + " for peer sid:" + getSid());
            queueOpPacket(Leader.TRUNC, maxCommittedLog);
            currentZxid = maxCommittedLog;
            needOpPacket = false;
            needSnap = false;
        } else if ((maxCommittedLog >= peerLastZxid) && (minCommittedLog <= peerLastZxid)) {
            // Follower is within commitLog range
            LOG.info("Using committedLog for peer sid: " + getSid());
            Iterator<Proposal> itr = db.getCommittedLog().iterator();
            currentZxid = queueCommittedProposals(itr, peerLastZxid, null, maxCommittedLog);
            needSnap = false;
        } else if (peerLastZxid < minCommittedLog && txnLogSyncEnabled) {
            // Use txnlog and committedLog to sync
            // Calculate sizeLimit that we allow to retrieve txnlog from disk
            long sizeLimit = db.calculateTxnLogSizeLimit();
            // This method can return empty iterator if the requested zxid
            // is older than on-disk txnlog
            Iterator<Proposal> txnLogItr = db.getProposalsFromTxnLog(peerLastZxid, sizeLimit);
            if (txnLogItr.hasNext()) {
                LOG.info("Use txnlog and committedLog for peer sid: " + getSid());
                currentZxid = queueCommittedProposals(txnLogItr, peerLastZxid, minCommittedLog, maxCommittedLog);
                LOG.debug("Queueing committedLog 0x" + Long.toHexString(currentZxid));
                Iterator<Proposal> committedLogItr = db.getCommittedLog().iterator();
                currentZxid = queueCommittedProposals(committedLogItr, currentZxid, null, maxCommittedLog);
                needSnap = false;
            }
            // closing the resources
            if (txnLogItr instanceof TxnLogProposalIterator) {
                TxnLogProposalIterator txnProposalItr = (TxnLogProposalIterator) txnLogItr;
                txnProposalItr.close();
            }
        } else {
            LOG.warn("Unhandled scenario for peer sid: " + getSid());
        }
        LOG.debug("Start forwarding 0x" + Long.toHexString(currentZxid) + " for peer sid: " + getSid());
        leaderLastZxid = leader.startForwarding(this, currentZxid);
    } finally {
        rl.unlock();
    }
    if (needOpPacket && !needSnap) {
        // This should never happen, but we should fall back to sending
        // snapshot just in case.
        LOG.error("Unhandled scenario for peer sid: " + getSid() + " fall back to use snapshot");
        needSnap = true;
    }
    return needSnap;
}
Also used : ReadLock(java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock) TxnLogProposalIterator(org.apache.zookeeper.server.TxnLogProposalIterator) Iterator(java.util.Iterator) TxnLogProposalIterator(org.apache.zookeeper.server.TxnLogProposalIterator) ReentrantReadWriteLock(java.util.concurrent.locks.ReentrantReadWriteLock) Proposal(org.apache.zookeeper.server.quorum.Leader.Proposal)

Example 2 with ReadLock

use of java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock in project torodb by torodb.

the class SharedWriteInternalTransaction method createSharedWriteTransaction.

static SharedWriteInternalTransaction createSharedWriteTransaction(BackendConnection backendConnection, MetainfoRepository metainfoRepository) {
    ReadLock sharedLock = sharedLock();
    sharedLock.lock();
    try {
        return createWriteTransaction(metainfoRepository, snapshot -> new SharedWriteInternalTransaction(metainfoRepository, snapshot, backendConnection.openSharedWriteTransaction(), sharedLock));
    } catch (Throwable throwable) {
        sharedLock.unlock();
        throw throwable;
    }
}
Also used : ReadLock(java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock)

Example 3 with ReadLock

use of java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock in project zm-mailbox by Zimbra.

the class RedoLogManager method getChangedMailboxesSince.

/**
     * Returns the set of mailboxes that had any committed changes since a
     * particular CommitId in the past, by scanning redologs.  Also returns
     * the last CommitId seen during the scanning process.
     * @param cid
     * @return can be null if server is shutting down
     * @throws IOException
     * @throws MailServiceException
     */
public Pair<Set<Integer>, CommitId> getChangedMailboxesSince(CommitId cid) throws IOException, MailServiceException {
    Set<Integer> mailboxes = new HashSet<Integer>();
    // Grab a read lock to prevent rollover.
    ReadLock readLock = mRWLock.readLock();
    try {
        readLock.lockInterruptibly();
    } catch (InterruptedException e) {
        synchronized (mShuttingDownGuard) {
            if (!mShuttingDown)
                ZimbraLog.redolog.error("InterruptedException during redo log scan for CommitId", e);
            else
                ZimbraLog.redolog.debug("Redo log scan for CommitId interrupted for shutdown");
        }
        return null;
    }
    File linkDir = null;
    File[] logs;
    try {
        try {
            long seq = cid.getRedoSeq();
            File[] archived = getArchivedLogsFromSequence(seq);
            if (archived != null) {
                logs = new File[archived.length + 1];
                System.arraycopy(archived, 0, logs, 0, archived.length);
                logs[archived.length] = mLogFile;
            } else {
                logs = new File[] { mLogFile };
            }
            // Make sure the first log has the sequence in cid.
            FileLogReader firstLog = new FileLogReader(logs[0]);
            if (firstLog.getHeader().getSequence() != seq) {
                // Most likely, the CommitId is too old.
                throw MailServiceException.INVALID_COMMIT_ID(cid.toString());
            }
            // Create a temp directory and make hard links to all redologs.
            // This prevents the logs from disappearing while being scanned.
            String dirName = "tmp-scan-" + System.currentTimeMillis();
            linkDir = new File(mLogFile.getParentFile(), dirName);
            if (linkDir.exists()) {
                int suffix = 1;
                while (linkDir.exists()) {
                    linkDir = new File(mLogFile.getParentFile(), dirName + "-" + suffix);
                }
            }
            if (!linkDir.mkdir())
                throw new IOException("Unable to create temp dir " + linkDir.getAbsolutePath());
            for (int i = 0; i < logs.length; i++) {
                File src = logs[i];
                File dest = new File(linkDir, logs[i].getName());
                IO.link(src.getAbsolutePath(), dest.getAbsolutePath());
                logs[i] = dest;
            }
        } finally {
            // We can let rollover happen now.
            readLock.unlock();
        }
        // Scan redologs to get list with IDs of mailboxes that have
        // committed changes since the given commit id.
        long lastSeq = -1;
        CommitTxn lastCommitTxn = null;
        boolean foundMarker = false;
        for (File logfile : logs) {
            FileLogReader logReader = new FileLogReader(logfile);
            logReader.open();
            lastSeq = logReader.getHeader().getSequence();
            try {
                RedoableOp op = null;
                while ((op = logReader.getNextOp()) != null) {
                    if (ZimbraLog.redolog.isDebugEnabled())
                        ZimbraLog.redolog.debug("Read: " + op);
                    if (!(op instanceof CommitTxn))
                        continue;
                    lastCommitTxn = (CommitTxn) op;
                    if (foundMarker) {
                        int mboxId = op.getMailboxId();
                        if (mboxId > 0)
                            mailboxes.add(mboxId);
                    } else {
                        if (cid.matches(lastCommitTxn))
                            foundMarker = true;
                    }
                }
            } catch (IOException e) {
                ZimbraLog.redolog.warn("IOException while reading redolog file", e);
            } finally {
                logReader.close();
            }
        }
        if (!foundMarker) {
            // Most likely, the CommitId is too old.
            throw MailServiceException.INVALID_COMMIT_ID(cid.toString());
        }
        CommitId lastCommitId = new CommitId(lastSeq, lastCommitTxn);
        return new Pair<Set<Integer>, CommitId>(mailboxes, lastCommitId);
    } finally {
        if (linkDir != null) {
            // Clean up the temp dir with links.
            try {
                if (linkDir.exists())
                    FileUtil.deleteDir(linkDir);
            } catch (IOException e) {
                ZimbraLog.redolog.warn("Unable to delete temporary directory " + linkDir.getAbsolutePath(), e);
            }
        }
    }
}
Also used : ReadLock(java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock) CommitTxn(com.zimbra.cs.redolog.op.CommitTxn) IOException(java.io.IOException) FileLogReader(com.zimbra.cs.redolog.logger.FileLogReader) Checkpoint(com.zimbra.cs.redolog.op.Checkpoint) RedoableOp(com.zimbra.cs.redolog.op.RedoableOp) File(java.io.File) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) Pair(com.zimbra.common.util.Pair)

Example 4 with ReadLock

use of java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock in project zm-mailbox by Zimbra.

the class RedoLogManager method logOnly.

/**
     * Log an operation to the logger.  Only does logging; doesn't
     * bother with checkpoint, rollover, etc.
     * @param op
     * @param synchronous
     */
protected void logOnly(RedoableOp op, boolean synchronous) {
    try {
        // Do the logging while holding a read lock on the RW lock.
        // This prevents checkpoint or rollover from starting when
        // there are any threads in the act of logging.
        ReadLock readLock = mRWLock.readLock();
        readLock.lockInterruptibly();
        try {
            // Update active ops map.
            synchronized (mActiveOps) {
                if (op.isStartMarker()) {
                    mActiveOps.put(op.getTransactionId(), op);
                }
                if (op.isEndMarker())
                    mActiveOps.remove(op.getTransactionId());
            }
            try {
                long start = System.currentTimeMillis();
                mLogWriter.log(op, op.getInputStream(), synchronous);
                long elapsed = System.currentTimeMillis() - start;
                synchronized (mStatGuard) {
                    mElapsed += elapsed;
                    mCounter++;
                }
            } catch (NullPointerException e) {
                StackTraceElement[] stack = e.getStackTrace();
                if (stack == null || stack.length == 0) {
                    ZimbraLog.redolog.warn("Caught NullPointerException during redo logging, but " + "there is no stack trace in the exception.  " + "If you are running Sun server VM, you could be hitting " + "Java bug 4292742.  (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4292742)  " + "Re-run the test case with client VM to see the stack trace.", e);
                }
                // When running with server VM ("java -server" command line) some NPEs
                // will not report the stack trace.  This is Java bug 4292742.
                //
                //   http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4292742
                //
                // There is also this related bug:
                //
                //   http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4761344
                //
                // which says NPE might be thrown when it is impossible to
                // be thrown according to source code.  The bug header says it's fixed
                // in VM 1.4.2, but I'm getting NPE with 1.4.2_05 VM.  Indeed, further
                // reading of the bug page reveals there have been reports of variants
                // of the bug in 1.4.2.
                //
                // Most complaints in the bug page say the problem happens with server
                // VM.  None says it happens with the client VM.
                //
                // The second bug does not imply the first bug.  When you get an NPE
                // with no stack trace, switch to client VM and try to reproduce the
                // bug to get the stack and fix the bug.  Don't automatically assume
                // you're hitting the second bug.
                //
                signalFatalError(e);
            } catch (OutOfMemoryError e) {
                Zimbra.halt("out of memory", e);
            } catch (Throwable e) {
                ZimbraLog.redolog.error("Redo logging to logger " + mLogWriter.getClass().getName() + " failed", e);
                signalFatalError(e);
            }
            if (ZimbraLog.redolog.isDebugEnabled())
                ZimbraLog.redolog.debug(op.toString());
        } finally {
            readLock.unlock();
        }
    } catch (InterruptedException e) {
        synchronized (mShuttingDownGuard) {
            if (!mShuttingDown)
                ZimbraLog.redolog.warn("InterruptedException while logging", e);
            else
                ZimbraLog.redolog.info("Thread interrupted for shutdown");
        }
    }
}
Also used : ReadLock(java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock)

Example 5 with ReadLock

use of java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock in project aries by apache.

the class RWLock method runReadOperation.

public void runReadOperation(Runnable r) {
    ReadLock rl = _lock.readLock();
    rl.lock();
    try {
        r.run();
    } finally {
        rl.unlock();
    }
}
Also used : ReadLock(java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock)

Aggregations

ReadLock (java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock)15 IOException (java.io.IOException)2 HashSet (java.util.HashSet)2 SnapshotStage (com.torodb.core.transaction.metainf.MetainfoRepository.SnapshotStage)1 Pair (com.zimbra.common.util.Pair)1 FileLogReader (com.zimbra.cs.redolog.logger.FileLogReader)1 Checkpoint (com.zimbra.cs.redolog.op.Checkpoint)1 CommitTxn (com.zimbra.cs.redolog.op.CommitTxn)1 RedoableOp (com.zimbra.cs.redolog.op.RedoableOp)1 SuppressFBWarnings (edu.umd.cs.findbugs.annotations.SuppressFBWarnings)1 File (java.io.File)1 BigDecimal (java.math.BigDecimal)1 NumberFormat (java.text.NumberFormat)1 ArrayList (java.util.ArrayList)1 Iterator (java.util.Iterator)1 LinkedHashSet (java.util.LinkedHashSet)1 ExecutionException (java.util.concurrent.ExecutionException)1 ReentrantReadWriteLock (java.util.concurrent.locks.ReentrantReadWriteLock)1 Nonnull (javax.annotation.Nonnull)1 Account (jgnash.engine.Account)1