class PeriodicLogSyncService extends LogSyncService {

    private final long blockWhenSyncLagsMillis;

    PeriodicLogSyncService(Map<String, String> config) {
        super(config);
        syncIntervalMillis = MapUtils.getLong(config, "log_sync_period", 500);
        blockWhenSyncLagsMillis = (long) (syncIntervalMillis * 1.5);
    }

    @Override
    public boolean isPeriodic() {
        return true;
    }

    private boolean waitForSyncToCatchUp() {
        // 如果当前时间是第10毫秒，上次同步时间是在第5毫秒，同步间隔是10毫秒，说时当前时间还是同步周期内，就不用阻塞了
        // 如果当前时间是第16毫秒，超过了同步周期，需要阻塞
        return System.currentTimeMillis() > lastSyncedAt + blockWhenSyncLagsMillis;
    }

    @Override
    public void asyncWrite(AOTransaction t, RedoLogRecord r, long logId) {<FILL_FUNCTION_BODY>}

    @Override
    public void syncWrite(AOTransaction t, RedoLogRecord r, long logId) {
        // 如果在同步周期内，不用等
        if (!waitForSyncToCatchUp()) {
            PendingTransaction pt = new PendingTransaction(t, r, logId);
            t.onSynced();
            pt.setCompleted(true);
            // 同步调用无需t.asyncCommitComplete();
            asyncWrite(pt);
        } else {
            super.syncWrite(t, r, logId);
        }
    }
}

        PendingTransaction pt = new PendingTransaction(t, r, logId);
        // 如果在同步周期内，可以提前通知异步提交完成了
        if (!waitForSyncToCatchUp()) {
            t.onSynced(); // 不能直接pt.setSynced(true);
            pt.setCompleted(true);
            asyncWrite(pt);
            t.asyncCommitComplete();
        } else {
            asyncWrite(pt);
        }
    
<methods>public void <init>(Map<java.lang.String,java.lang.String>) ,public void addRedoLogRecord(com.lealone.transaction.aote.AOTransaction, com.lealone.transaction.aote.log.RedoLogRecord, long) ,public void asyncWakeUp() ,public void asyncWrite(com.lealone.transaction.aote.AOTransaction, com.lealone.transaction.aote.log.RedoLogRecord, long) ,public void close() ,public static com.lealone.transaction.aote.log.LogSyncService create(Map<java.lang.String,java.lang.String>) ,public java.util.concurrent.atomic.AtomicLong getAsyncLogQueueSize() ,public com.lealone.transaction.aote.log.RedoLog getRedoLog() ,public com.lealone.db.scheduler.Scheduler[] getWaitingSchedulers() ,public boolean isPeriodic() ,public boolean isRunning() ,public boolean needSync() ,public long nextLogId() ,public void run() ,public void syncWrite(com.lealone.transaction.aote.AOTransaction, com.lealone.transaction.aote.log.RedoLogRecord, long) ,public void wakeUp() <variables>public static final java.lang.String LOG_SYNC_TYPE_INSTANT,public static final java.lang.String LOG_SYNC_TYPE_NO_SYNC,public static final java.lang.String LOG_SYNC_TYPE_PERIODIC,private final java.util.concurrent.atomic.AtomicLong asyncLogQueueSize,private final com.lealone.common.util.Awaiter awaiter,private final java.util.concurrent.atomic.AtomicLong lastLogId,protected volatile long lastSyncedAt,private volatile java.util.concurrent.CountDownLatch latchOnClose,private static final com.lealone.common.logging.Logger logger,private final non-sealed com.lealone.transaction.aote.log.RedoLog redoLog,private final non-sealed int redoLogRecordSyncThreshold,private volatile boolean running,protected long syncIntervalMillis,private final non-sealed com.lealone.db.scheduler.Scheduler[] waitingSchedulers