亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Zookeeper事務日志預分配空間源碼分析

發布時間:2023-04-04 11:19:32 來源:億速云 閱讀:165 作者:iii 欄目:開發技術

這篇文章主要介紹“Zookeeper事務日志預分配空間源碼分析”,在日常操作中,相信很多人在Zookeeper事務日志預分配空間源碼分析問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Zookeeper事務日志預分配空間源碼分析”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

1.事務日志的預分配

事務日志的添加,我們需要從FileTxnLog.append()方法看起

public class FileTxnLog implements TxnLog {
    volatile BufferedOutputStream logStream = null;
    volatile OutputArchive oa;
    volatile FileOutputStream fos = null;
    
    // 追加事務日志
    public synchronized boolean append(TxnHeader hdr, Record txn)
        throws IOException
    {
        if (hdr == null) {
            return false;
        }
 
        if (hdr.getZxid() <= lastZxidSeen) {
            LOG.warn("Current zxid " + hdr.getZxid()
                    + " is <= " + lastZxidSeen + " for "
                    + hdr.getType());
        } else {
            lastZxidSeen = hdr.getZxid();
        }
 
        // 默認logStream為空
        if (logStream==null) {
           if(LOG.isInfoEnabled()){
                LOG.info("Creating new log file: " + Util.makeLogName(hdr.getZxid()));
           }
 
            // 以下代碼為創建事務日志文件
            // 根據當前事務ID來創建具體文件名,并寫入文件頭信息
           logFileWrite = new File(logDir, Util.makeLogName(hdr.getZxid()));
           fos = new FileOutputStream(logFileWrite);
           logStream=new BufferedOutputStream(fos);
           oa = BinaryOutputArchive.getArchive(logStream);
           FileHeader fhdr = new FileHeader(TXNLOG_MAGIC,VERSION, dbId);
           fhdr.serialize(oa, "fileheader");
           // Make sure that the magic number is written before padding.
           logStream.flush();
           filePadding.setCurrentSize(fos.getChannel().position());
           streamsToFlush.add(fos);
        }
        // 預分配代碼在這里
        filePadding.padFile(fos.getChannel());
        byte[] buf = Util.marshallTxnEntry(hdr, txn);
        if (buf == null || buf.length == 0) {
            throw new IOException("Faulty serialization for header " +
                    "and txn");
        }
        Checksum crc = makeChecksumAlgorithm();
        crc.update(buf, 0, buf.length);
        oa.writeLong(crc.getValue(), "txnEntryCRC");
        Util.writeTxnBytes(oa, buf);
 
        return true;
    }
}

創建FileTxnLog對象時,其logStream屬性為null,所以當第一次處理事務請求時,會先根據當前事務ID來創建一個文件。

1.1 事務日志預分配

public class FilePadding {
    long padFile(FileChannel fileChannel) throws IOException {
        // 針對新文件而言,newFileSize=64M
        long newFileSize = calculateFileSizeWithPadding(fileChannel.position(), currentSize, preAllocSize);
        if (currentSize != newFileSize) {
            // 將文件擴充到64M,全部用0來填充
            fileChannel.write((ByteBuffer) fill.position(0), newFileSize - fill.remaining());
            currentSize = newFileSize;
        }
        return currentSize;
    }
    
    // size計算
    public static long calculateFileSizeWithPadding(long position, long fileSize, long preAllocSize) {
        // If preAllocSize is positive and we are within 4KB of the known end of the file calculate a new file size
        // 初始時候position=0,fileSize為0,preAllocSize為系統參數執行,默認為64M
        if (preAllocSize > 0 && position + 4096 >= fileSize) {
            // If we have written more than we have previously preallocated we need to make sure the new
            // file size is larger than what we already have
            // Q:這里確實沒看懂...
            if (position > fileSize) {
                fileSize = position + preAllocSize;
                fileSize -= fileSize % preAllocSize;
            } else {
                fileSize += preAllocSize;
            }
        }
 
        return fileSize;
    }
}

預分配的過程比較簡單,就是看下當前文件的剩余空間是否<4096,如果是,則擴容。

Q:

這里有一個不太明白的問題,position > fileSize的場景是怎樣的呢?

2.創建新的事務日志文件時機

通過上述代碼分析我們知道,當logStream=null時,就會創建一個新的事務日志文件,那么logStream對象什么時候為空呢?

搜索代碼,只看到FileTxnLog.rollLog()方法會主動將logStream設置為null

public class FileTxnLog implements TxnLog {
    public synchronized void rollLog() throws IOException {
        if (logStream != null) {
            this.logStream.flush();
            this.logStream = null;
            oa = null;
        }
    }
}

那么根據這個線索,我們來搜索下rollLog的調用鏈

SyncRequestProcessor.run() -> ZKDatabase.rollLog() -> FileTxnSnapLog.rollLog() -> FileTxnLog.rollLog()

最終看到是在SyncRequestProcessor.run()方法中發起調用的,而且只有這一條調用鏈,我們來分析下

2.1 SyncRequestProcessor.run()

public class SyncRequestProcessor extends ZooKeeperCriticalThread implements RequestProcessor {
    public void run() {
        try {
            int logCount = 0;
 
            setRandRoll(r.nextInt(snapCount/2));
            while (true) {
                ...
                if (si != null) {
                    // 追加事務日志
                    if (zks.getZKDatabase().append(si)) {
                        logCount++;
                        if (logCount > (snapCount / 2 + randRoll)) {
                            setRandRoll(r.nextInt(snapCount/2));
                            // 注意:在這里發起了rollLog
                            zks.getZKDatabase().rollLog();
                            ...
                        }
                    } else if (toFlush.isEmpty()) {
                        ...
                    }
                    toFlush.add(si);
                    if (toFlush.size() > 1000) {
                        flush(toFlush);
                    }
                }
            }
        } catch (Throwable t) {
            handleException(this.getName(), t);
            running = false;
        }
        LOG.info("SyncRequestProcessor exited!");
    }
}

需要注意下rollLog()方法執行的條件,就是logCount > (snapCount / 2 + randRoll)

snapCount是一個系統參數,System.getProperty("zookeeper.snapCount"),默認值為100000

randRoll是一個隨機值

那么該條件觸發的時機為:處理的事務請求數至少要大于50000。

這時就出現了一個筆者無法理解的情況:

通過對事務日志的觀察可以看到其都是64M,而至少處理50000次事務請求后,Zookeeper才會分配一個新的事務日志文件,那么這個snapCount是一個經驗值嘛?

如果事務請求的value信息都很大,那么可能到不了50000次,就會超過64M,理論上應該要創建一個新的文件了,但是貌似并沒有,這個該怎么處理呢?

如果事務請求value信息都很小,那么即使到了50000次,也不會超過64M,那么之前預分配的文件大小就浪費了一部分。

到此,關于“Zookeeper事務日志預分配空間源碼分析”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

富川| 寻甸| 黄大仙区| 盐山县| 塘沽区| 兴仁县| 阿荣旗| 秀山| 阿尔山市| 专栏| 达州市| 临海市| 沐川县| 安徽省| 秀山| 分宜县| 吉木乃县| 海南省| 保山市| 秭归县| 临高县| 日照市| 渝北区| 万源市| 普安县| 昆明市| 和田县| 寻甸| 房产| 奇台县| 镇坪县| 体育| 辰溪县| 大方县| 百色市| 突泉县| 高邑县| 富顺县| 东山县| 嘉峪关市| 大渡口区|