WAL模塊主要方法簡述

来源:https://www.cnblogs.com/lt6668964/archive/2023/04/07/17297095.html
-Advertisement-
Play Games

簡介 ChatGPT Java版SDK開源地址:https://github.com/Grt1228/chatgpt-java ,目前收穫將近1000個star。 有bug歡迎朋友們指出,互相學習,所有咨詢全部免費。 最新版:1.0.10 <dependency> <groupId>com.unfb ...


Method---wal.go Description
func Create(lg *zap.Logger, dirpath string, metadata []byte) (*WAL, error) 初次啟動raftNode時調用WAL.Create方法。創建WAL對象用於記錄追加 :判斷是否存在dirpath路徑,如果已存在則不是初次啟動raftNode,返回os.ErrExist。創建臨時目錄和初始上鎖的wal文件—walName(seq=0 & index=0),seek到文件末尾(why?),預分配該wal文件大小(SegmentSizeBytes=64MB,優化追加速度),創建WAL對象並設定路徑、 metadata(NodeID和ClusterID)、編碼器,將上鎖的WAL文件追加到鎖表內,然後依次寫入crc、metadata和空snapshot,重命名臨時目錄,同步臨時目錄的父目錄(fsync)使得重命名持久化。
func (w *WAL) renameWAL(tmpdirpath string) (*WAL, error) 移除w.dir目錄及目錄下所有文件和文件夾,調用os.Rename(tmpdirpath, w.dir)將Create方法內創建的臨時目錄重命名,創建FilePipeline和dirFile *os.File,dirFile is a fd for the wal directory for syncing on Rename
func (w *WAL) SaveSnapshot(e walpb.Snapshot) error 檢驗snapshot是否合法(Since etcd>=3.5.0),pb序列化snapshot得到data欄位,加鎖,調用w.encoder.encode方法寫入record,更新w.enti如果snapshot index > 原w.enti,解鎖。
func (w *WAL) saveCrc(prevCrc uint32) error 寫入crcType的記錄
func (w *WAL) Save(st raftpb.HardState, ents []raftpb.Entry) error 加鎖,如果hardstate和entries為空,返回。判斷是否需要sync(entries長度不為0||vote改變||term改變),寫入entries和hardstate,判斷文件當前位置是否小於SegmentSizeBytes(預設64M),如果小於判斷是否需要sync數據,如果不小於,返回cut操作結果,解鎖。
func (w *WAL) saveEntry(e *raftpb.Entry) error 寫入一條entry記錄並更新WAL對象的enti值
func (w *WAL) saveState(s *raftpb.HardState) error 判斷是否為空,不為空寫入HardState並更新WAL對象的state值
func (w *WAL) cut() error 關閉當前文件並創建一個新的文件用於追加記錄:首先移動到鎖表最後一個wal文件的當前位置截斷文件然後執行sync,調用FilePipeline對象的Open方法創建一個新文件並加入鎖表,首先保存舊的encoder的crc,然後創建新的encoder對象替換舊的encoder對象,保存頭信息crc、metadata和hardstate,原子重命名文件之前先執行sync和保存當前位置偏移,重命名後對WAL對象的dirFile執行fsync持久化wal目錄的變化。關閉文件重新以LockFile方式打開文件並seek到文件末尾,替換鎖表尾文件,再次進行新舊encoder替換。
func (w *WAL) tail() *fileutil.LockedFile WAL對象的鎖表如果不為空,返回最後一個上鎖文件,否則返回空。
func (w *WAL) sync() error 如果encoder存在,則將encoder pageWriter緩衝區的數據寫入,鎖表尾文件執行fdatasync,將fdatasync延時上報監控prometheus。
func ValidSnapshotEntries(lg *zap.Logger, walDir string) ([]walpb.Snapshot, error) 尋找所有wal文件中snapshot條目,有效的snapshot條目index必須小於等於最新的hardstate。步驟:找到目錄下所有帶有合法名稱的wal文件名,以只讀模式打開這些wal文件,根據以讀模式打開的這些wal文件創建decoder,迴圈解碼每個文件的record:若為snapshotType,追加到snaps中;若為stateType,更新hardstate;若為crcType(wal文件開頭),驗證是否和decoder.crc相同(上一個文件末尾的crc)。返回所有index小於最新hardstate.Commit的walpb.snap條目。
func readWALNames(lg *zap.Logger, dirpath string) ([]string, error) 從指定目錄讀取所有wal文件name,並檢查name合法性(.wal結尾)
func openWALFiles(lg *zap.Logger, dirpath string, names []string, nameIndex int, write bool) ([]fileutil.FileReader, []*fileutil.LockedFile, func() error, error) 根據write標誌選擇以讀模式還是寫模式打開文件,步驟:從nameIndex指定的索引開始打開文件。若寫模式:打開上鎖的wal文件,將該文件添加到鎖表、文件關閉表、讀文件表;若讀模式:以os.O_RDONLY打開文件,將該文件添加到文件關閉表、讀文件表,添加nil到鎖表(鎖表只在寫模式下用到)。
func Open(lg zap.Logger, dirpath string, snap walpb.Snapshot) (WAL, error) 寫模式調用openAtIndex。Open opens the WAL at the given snap,The returned WAL is ready to read and the first record will be the one after the given snap. The WAL cannot be appended to before reading out all of its previous records.
func OpenForRead(lg zap.Logger, dirpath string, snap walpb.Snapshot) (WAL, error) 讀模式調用openAtIndex。
func openAtIndex(lg zap.Logger, dirpath string, snap walpb.Snapshot, write bool) (WAL, error) 遍歷wal目錄,找到snap所在位置index,依次打開index後續所有的wal文件並加鎖(調用openWALFiles),創建WAL對象並設定解碼器、readClose(調用closeAll關閉已打開文件)和鎖表,若寫模式:readClose置空(寫模式下還要繼續對wal文件進行append操作,等到讀完後不用進行關閉操作),測試鎖表最後一個上鎖文件是否是合法wal文件(通過是否符合命名規範判斷),如果不合法,關閉所有文件返回錯誤,否則,設定FilePipeline對象(大小超過64M時用於截斷並切換到新文件),返回WAL對象 。
func (w *WAL) ReadAll() (metadata []byte, state raftpb.HardState, ents []raftpb.Entry, err error) 讀取WAL對象的所有記錄 ,對於不同類型記錄做不同處理: 判斷鎖表尾文件如為空(讀模式):如果不是讀到EOF或ErrUnexpectedEOF則重置state返回;對於寫模式,如果err不是EOF,重置狀態返回,然後鎖表尾文件Seek到lastOffset位置, 將後續內容清零(目的是處理遇到0記錄後接非0記錄時,非0記錄又沒有被全部重寫,再次打開的時候會出現 CRC錯誤,由於數據從不會一開始就完全同步到磁碟,因此進行清零操作是安全的 ?暫時沒懂),然後判斷snapshot是否匹配,關閉decoder實現禁讀,重置WAL對象的start為一個空snapshot對象,創建encoder並將decoder設空,返回metadata,state,ents和err。



Method---encoder.go Description
func (e *encoder) encode(rec *walpb.Record) error 加鎖,根據record.data計算crc,序列化record得data,根據len(data)計算出lenField和padBytes(需要填充位元組數使得8位元組對齊),寫入lenField到文件,如果padBytes!=0,則給data填充padBytes位元組,寫入到pageWriter緩衝區。
func encodeFrameSize(dataBytes int) (lenField uint64, padBytes int) 計算出lenField, padBytes
func (e *encoder) flush() error 加鎖,將pageWriter緩衝區內數據寫入文件,解鎖
func writeUint64(w io.Writer, n uint64, buf []byte) error 將uint64類型n寫入到[]byte內,再寫入文件



Method---pagewriter.go Description
func (pw *PageWriter) Write(p []byte) (n int, err error) 若未超出緩衝區最大容量,則將數據複製到緩衝區並更新當前緩衝位元組數返回。若超出,計算出一頁還空閑多少位元組數slack,若還有空閑:
func (pw *PageWriter) flush() (int, error) 將緩衝區內的所有數據寫入文件,重新計算頁內偏移量(pageBytes=4KB),將已緩存位元組數重置為0



Method---decoder.go Description
func (d *decoder) decodeRecord(rec *walpb.Record) error 首先讀取一個int64變數,算出recBytes,和padBytes,讀取recBytes+padBytes大小的數據,將前recBytes大小的數據反序列化,如果不是crcType,驗證crc是否一致,更新lastOffset = 8 + recBytes + padBytes。
func decodeFrameSize(lenField int64) (recBytes int64, padBytes int64) 根據lenField,算出實際數據大小和填充數據大小
func (d *decoder) isTornEntry(data []byte) bool 還沒看
func readInt64(r io.Reader) (int64, error) 從文件中讀取一個int64變數

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 簡介 外觀模式(Facade Pattern),也叫門面模式,是一種結構型設計模式。它向現有的系統添加一個高層介面,隱藏子系統的複雜性,這個介面使得子系統更加容易使用。 如果你需要一個指向複雜子系統的直接介面,且該介面的功能有限,則可以使用外觀模式。或者需要將子系統組織為多層結構,可以使用外觀。 作 ...
  • 一個非常簡單的小項目。 看到了楊旭大佬的教學視頻,自己跟著實現了一下,完善了一下游戲邏輯。 通過空格鍵進行控制。 游戲中可按 P 鍵 暫停/恢復 游戲 項目結構 · ├── Cargo.lock ├── Cargo.toml ├── src/ │ ├── main.rs │ ├──bird/ │ │ ...
  • 本文介紹了學習Spring源碼前需要掌握的核心知識點,包括IOC、AOP、Bean生命周期、初始化和Transaction事務。通過Hello World示例,講解瞭如何使用Spring,並指出了深入瞭解Spring內部機制的方向。 ...
  • 約束(Constraints) 上一章介紹了向模型中添加一些業務邏輯的能力。我們現在可以將按鈕鏈接到業務代碼,但如何防止用戶輸入錯誤的數據?例如,在我們的房地產模塊中,沒有什麼可以阻止用戶設置負預期價格。 odoo提供了兩種設置自動驗證恆定式的方法:Python約束 and SQL約束。 SQL 參 ...
  • Mybatis常見問題 1,大於號、小於號在sql語句中的轉換 使用 mybatis 時 sql 語句是寫在 xml 文件中,如果 sql 中有一些特殊的字元的話,比如< ,<=,>,>=等符號,會引起 xml 格式的錯誤,需要替換掉,或者不被轉義。 有兩種方法可以解決:轉義字元和標記 CDATA ...
  • SpringCloud Eureka-服務註冊與發現02 3.搭建EurekaServer集群-實現負載均衡&故障容錯 3.1為什麼需要集群EurekaServer? 微服務RPC遠程服務調用最核心的是高可用 如果註冊中心只有1個,如果出現故障,會導致整個服務環境不可用 解決辦法就是搭建Eureka ...
  • ps 命令速查備忘清單 Linux我們提供了一個名為 ps 的實用程式,用於查看與系統上的進程相關的信息,它是 Process Status 的縮寫這份 ps 命令備忘清單的快速參考列表,包含常用選項和示例。入門,為開發人員分享快速參考備忘單。 開發速查表大綱 入門 語法 示例 查看系統上的每個進程 ...
  • Perl語言線上運行編譯,是一款可線上編程編輯器,在編輯器上輸入Perl語言代碼,點擊運行,可線上編譯運行Perl語言,Perl語言代碼線上運行調試,Perl語言線上編譯,可快速線上測試您的Perl語言代碼,線上編譯Perl語言代碼發現是否存在錯誤,如果代碼測試通過,將會輸出編譯後的結果。 該線上工 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...