RocketMQ之刷盘策略

1、同步刷盘策略

class GroupCommitService extends FlushCommitLogService {
    private volatile LinkedList<GroupCommitRequest> requestsWrite = new LinkedList<>();
    private volatile LinkedList<GroupCommitRequest> requestsRead = new LinkedList<>();
    private final PutMessageSpinLock lock = new PutMessageSpinLock();

    public void putRequest(final GroupCommitRequest request) {
        lock.lock();//自旋锁
        try {
            this.requestsWrite.add(request);
        } finally {
            lock.unlock();
        }
        this.wakeup();
    }
	/**
    * 读写队列交换操作 & 写操作 通过锁建立了互斥性
     * 1、交换过后的写容器requestsWrite其size为0。
     * 2、刷盘线程刷盘期间也是写容器requestsWrite添加刷盘请求的过程。
     * 3、读容器requestsRead其元素全部完成刷盘完成后,再次尝试获取锁从写容器requestsWrite交换刷盘请求元素。
     */
    private void swapRequests() {
        lock.lock();//自旋锁
        try {
            LinkedList<GroupCommitRequest> tmp = this.requestsWrite;
            this.requestsWrite = this.requestsRead;
            this.requestsRead = tmp;
        } finally {
            lock.unlock();
        }
    }

    private void doCommit() {
        if (!this.requestsRead.isEmpty()) {
            for (GroupCommitRequest req : this.requestsRead) {
                // There may be a message in the next file, so a maximum of
                // two times the flush
                boolean flushOK = CommitLog.this.mappedFileQueue.getFlushedWhere() >= req.getNextOffset();
                for (int i = 0; i < 2 && !flushOK; i++) {
                    CommitLog.this.mappedFileQueue.flush(0);
                    flushOK = CommitLog.this.mappedFileQueue.getFlushedWhere() >= req.getNextOffset();
                }

                req.wakeupCustomer(flushOK ? PutMessageStatus.PUT_OK : PutMessageStatus.FLUSH_DISK_TIMEOUT);
            }

            long storeTimestamp = CommitLog.this.mappedFileQueue.getStoreTimestamp();
            if (storeTimestamp > 0) {
                CommitLog.this.defaultMessageStore.getStoreCheckpoint().setPhysicMsgTimestamp(storeTimestamp);
            }

            this.requestsRead = new LinkedList<>();
        } else {
            // Because of individual messages is set to not sync flush, it
            // will come to this process
            CommitLog.this.mappedFileQueue.flush(0);
        }
    }

    /**
     * 启动同步刷盘的独立线程
     */
    @Override
    public void run() {
        while (!this.isStopped()) {
            try {
                this.waitForRunning(10);
                this.doCommit();
            } catch (Exception e) {
                CommitLog.log.warn(this.getServiceName() + " service has exception. ", e);
            }
        }

        // Under normal circumstances shutdown, wait for the arrival of the
        // request, and then flush
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            CommitLog.log.warn("GroupCommitService Exception, ", e);
        }

        this.swapRequests();
        this.doCommit();

        CommitLog.log.info(this.getServiceName() + " service end");
    }

    @Override
    protected void onWaitEnd() {
        this.swapRequests();
    }

    @Override
    public String getServiceName() {
        if (CommitLog.this.defaultMessageStore.getBrokerConfig().isInBrokerContainer()) {
            return CommitLog.this.defaultMessageStore.getBrokerConfig().getIdentifier() + GroupCommitService.class.getSimpleName();
        }
        return GroupCommitService.class.getSimpleName();
    }

    @Override
    public long getJoinTime() {
        return 1000 * 60 * 5;
    }
}
public abstract class ServiceThread implements Runnable {
	protected final CountDownLatch2 waitPoint = new CountDownLatch2(1);
    protected volatile AtomicBoolean hasNotified = new AtomicBoolean(false);
	/**
	 * 表明已经重放刷盘请求
	 */
	public void wakeup() {
	    if (hasNotified.compareAndSet(false, true)) {// 成立说明 刷盘线程等待 读写容器的交换
	        waitPoint.countDown(); // notify  putRequest时通知线程
	    }
	}
	
	protected void waitForRunning(long interval) {//执行刷盘之前优先执行
	    if (hasNotified.compareAndSet(true, false)) {// 成立说明 写容器可以进一步交换
	        this.onWaitEnd();// 交换读写容器
	        return;
	    }
	    /**
	     * 以下执行表明一直没有 putRequest 操作。刷盘线程等待 interval ms,避免Cpu空轮转,浪费系统资源
	     */
	    //entry to wait
	    waitPoint.reset();
	
	    try {
	        waitPoint.await(interval, TimeUnit.MILLISECONDS);
	    } catch (InterruptedException e) {
	        log.error("Interrupted", e);
	    } finally {
	        hasNotified.set(false);
	        this.onWaitEnd();
	    }
	}
}

你可能感兴趣的:(java-rocketmq,rocketmq,java)