use of com.zimbra.cs.redolog.RedoCommitCallback in project zm-mailbox by Zimbra.
the class FileLogWriter method log.
/**
* Log the supplied bytes. Depending on the value of synchronous argument
* and the setting of fsync interval, this method can do one of 3 things:
*
* case 1: !synchronous
* action: write() only; no flush/fsync
*
* case 2: synchronous && fsyncInterval > 0
* action: write(), then wait() until notified by fsync thread
* Current thread only calls write() on the RandomAccessFile, and blocks to
* wait for the next scheduled fsync. Fsync thread periodically flushes
* the output stream and fsync's the file. After each fsync, all waiting
* logger threads are notified to continue. This method batches multiple
* log items before each fsync, and results in greater throughput than
* calling fsync after each log item because fsync to physical disk is
* a high-latency operation.
*
* case 3: synchronous && fsyncInterval <= 0
* action: write(), then fsync() in the current thread
* Fsync is required, but the sleep interval for fsync thread is 0. We
* special case this condition to mean fsync should be done by the calling
* thread.
*/
@Override
public void log(RedoableOp op, InputStream data, boolean synchronous) throws IOException {
int seq;
boolean sameMboxAsLastOp = false;
synchronized (mLock) {
if (mRAF == null)
throw new IOException("Redolog file closed");
// Record first transaction in header.
long tstamp = op.getTimestamp();
mLastOpTstamp = Math.max(tstamp, mLastOpTstamp);
if (mFirstOpTstamp == 0) {
mFirstOpTstamp = tstamp;
mHeader.setFirstOpTstamp(mFirstOpTstamp);
mHeader.setLastOpTstamp(mLastOpTstamp);
long pos = mRAF.getFilePointer();
mHeader.write(mRAF);
mRAF.seek(pos);
}
mLogSeq++;
mLogCount++;
seq = mLogSeq;
int numRead;
byte[] buf = new byte[1024];
while ((numRead = data.read(buf)) >= 0) {
mRAF.write(buf, 0, numRead);
mFileSize += numRead;
}
data.close();
// callbacks made on their behalf are truly in the correct order.
if (op instanceof CommitTxn) {
CommitTxn cmt = (CommitTxn) op;
RedoCommitCallback cb = cmt.getCallback();
if (cb != null) {
long redoSeq = mRedoLogMgr.getRolloverManager().getCurrentSequence();
CommitId cid = new CommitId(redoSeq, (CommitTxn) op);
Notif notif = new Notif(cb, cid);
// We queue it instead making the callback right away.
// Call it only after the commit record has been fsynced.
mCommitNotifyQueue.push(notif);
}
}
mLastLogTime = System.currentTimeMillis();
sameMboxAsLastOp = mLastOpMboxId == op.getMailboxId();
mLastOpMboxId = op.getMailboxId();
}
// cases 1 above
if (!synchronous)
return;
if (mFsyncIntervalMS > 0) {
if (!sameMboxAsLastOp) {
// case 2
try {
// wait for fsync thread to write this entry to disk
synchronized (mFsyncCond) {
mFsyncCond.wait(10000);
}
} catch (InterruptedException e) {
ZimbraLog.redolog.info("Thread interrupted during fsync");
}
synchronized (mLock) {
// timed out, so fsync in this thread
if (seq > mFsyncSeq)
fsync();
}
} else {
// If this op is on same mailbox as last op, let's assume there's a thread issuing
// many updates on a single mailbox in a loop, such as when importing a large ics file.
// We don't want to pause for mFsyncIntervalMS between every op (because all writes
// to a single mailbox are synchronized), so fsync inline and return immediately.
fsync();
}
} else {
// case 3
fsync();
}
}
Aggregations