Search in sources :

Example 1 with RedoCommitCallback

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();
    }
}
Also used : CommitTxn(com.zimbra.cs.redolog.op.CommitTxn) CommitId(com.zimbra.cs.redolog.CommitId) IOException(java.io.IOException) RedoCommitCallback(com.zimbra.cs.redolog.RedoCommitCallback)

Aggregations

CommitId (com.zimbra.cs.redolog.CommitId)1 RedoCommitCallback (com.zimbra.cs.redolog.RedoCommitCallback)1 CommitTxn (com.zimbra.cs.redolog.op.CommitTxn)1 IOException (java.io.IOException)1