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;
}
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;
}
}
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);
}
}
}
}
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");
}
}
}
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();
}
}
Aggregations