|
@@ -11,22 +11,36 @@ import (
|
|
|
// WAL (Write-Ahead Log) 实现
|
|
// WAL (Write-Ahead Log) 实现
|
|
|
//
|
|
//
|
|
|
// WAL 页布局 (16KB):
|
|
// WAL 页布局 (16KB):
|
|
|
-// 首页: [PageHdr(20B)] [TxnID(8B)] [TotalEntries(4B)] [Committed(1B)]
|
|
|
|
|
|
|
+// 首页: [PageHdr(20B)] [TxnID(8B)] [TotalEntries(4B)] [State(1B)]
|
|
|
// [NextWalPage(4B)] [EntryCount(2B)] [WALEntry...]
|
|
// [NextWalPage(4B)] [EntryCount(2B)] [WALEntry...]
|
|
|
// 续页: [PageHdr(20B)] [NextWalPage(4B)] [EntryCount(2B)] [WALEntry...]
|
|
// 续页: [PageHdr(20B)] [NextWalPage(4B)] [EntryCount(2B)] [WALEntry...]
|
|
|
//
|
|
//
|
|
|
// WALEntry: [TargetPageID(4B)] [DataLen(4B)] [Checksum(4B)] [Data(DataLen)]
|
|
// WALEntry: [TargetPageID(4B)] [DataLen(4B)] [Checksum(4B)] [Data(DataLen)]
|
|
|
//
|
|
//
|
|
|
|
|
+// WAL 状态机 (State 字段):
|
|
|
|
|
+// 0 = Mem (内存中,未写盘)
|
|
|
|
|
+// 1 = Written (已 write(),未 fsync())
|
|
|
|
|
+// 2 = Persisted (已 fsync(),但未标记提交)
|
|
|
|
|
+// 3 = Committed (已提交,可安全恢复)
|
|
|
|
|
+//
|
|
|
// 每个 WAL 页存 1 条完整 16KB 页镜像 (因为 entry 12B + 16KB > 16KB - 39B)
|
|
// 每个 WAL 页存 1 条完整 16KB 页镜像 (因为 entry 12B + 16KB > 16KB - 39B)
|
|
|
// =============================================================================
|
|
// =============================================================================
|
|
|
|
|
|
|
|
const (
|
|
const (
|
|
|
walPHDR = uint32(unsafe.Sizeof(page.PageHdr{})) // 20
|
|
walPHDR = uint32(unsafe.Sizeof(page.PageHdr{})) // 20
|
|
|
- walFirstHdr = walPHDR + 8 + 4 + 1 + 4 + 2 // 39: PageHdr + TxnID + TotalEntries + Committed + NextWalPage + EntryCount
|
|
|
|
|
|
|
+ walFirstHdr = walPHDR + 8 + 4 + 1 + 4 + 2 // 39: PageHdr + TxnID + TotalEntries + State + NextWalPage + EntryCount
|
|
|
walContHdr = walPHDR + 4 + 2 // 26: PageHdr + NextWalPage + EntryCount
|
|
walContHdr = walPHDR + 4 + 2 // 26: PageHdr + NextWalPage + EntryCount
|
|
|
walEntryMeta = 4 + 4 + 4 // 12: TargetPageID + DataLen + Checksum
|
|
walEntryMeta = 4 + 4 + 4 // 12: TargetPageID + DataLen + Checksum
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+// WAL 状态常量 (对应 State 字段)
|
|
|
|
|
+const (
|
|
|
|
|
+ WALStateMem = 0 // 内存中,未写盘
|
|
|
|
|
+ WALStateWritten = 1 // 已 write(),未 fsync()
|
|
|
|
|
+ WALStatePersisted = 2 // 已 fsync(),但未标记提交
|
|
|
|
|
+ WALStateCommitted = 3 // 已提交,可安全恢复
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
// WALWriter 事务 WAL 写入器
|
|
// WALWriter 事务 WAL 写入器
|
|
|
type WALWriter struct {
|
|
type WALWriter struct {
|
|
|
txnID uint64
|
|
txnID uint64
|
|
@@ -74,23 +88,23 @@ func (w *WALWriter) Rollback() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Commit 原子提交流程:
|
|
// Commit 原子提交流程:
|
|
|
-// 1. 将 entries 写入 WAL 页链 (顺序写盘)
|
|
|
|
|
-// 2. fsync WAL 页 (确保持久化)
|
|
|
|
|
|
|
+// 1. 将 entries 写入 WAL 页链 (State: Mem → Written)
|
|
|
|
|
+// 2. fsync WAL 页 (State: Written → Persisted)
|
|
|
// 3. 回写实际页 (从 WAL 拷贝到真实位置)
|
|
// 3. 回写实际页 (从 WAL 拷贝到真实位置)
|
|
|
-// 4. 标记 WAL 首页 Committed = 1
|
|
|
|
|
|
|
+// 4. 标记 WAL 首页 Committed = 1 (State: Persisted → Committed)
|
|
|
// 5. 回收所有 WAL 页
|
|
// 5. 回收所有 WAL 页
|
|
|
func (w *WALWriter) Commit() error {
|
|
func (w *WALWriter) Commit() error {
|
|
|
if len(w.entries) == 0 {
|
|
if len(w.entries) == 0 {
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // === 步骤 1: 写入 WAL 页链 ===
|
|
|
|
|
|
|
+ // === 步骤 1: 写入 WAL 页链 (State: Mem → Written) ===
|
|
|
walPageIDs, err := w.writeWALPages()
|
|
walPageIDs, err := w.writeWALPages()
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // === 步骤 2: fsync WAL 页 (确保持久化) ===
|
|
|
|
|
|
|
+ // === 步骤 2: fsync WAL 页 (State: Written → Persisted) ===
|
|
|
if err := w.file.sync(); err != nil {
|
|
if err := w.file.sync(); err != nil {
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
@@ -106,7 +120,7 @@ func (w *WALWriter) Commit() error {
|
|
|
}
|
|
}
|
|
|
w.file.ClearCache()
|
|
w.file.ClearCache()
|
|
|
|
|
|
|
|
- // === 步骤 4: 标记 WAL 首页 Committed = 1 ===
|
|
|
|
|
|
|
+ // === 步骤 4: 标记 WAL 首页为已提交 (State: Persisted → Committed) ===
|
|
|
if err := w.markCommitted(walPageIDs[0]); err != nil {
|
|
if err := w.markCommitted(walPageIDs[0]); err != nil {
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
@@ -154,10 +168,10 @@ func (w *WALWriter) writeWALPages() ([]uint32, error) {
|
|
|
off := uint32(0)
|
|
off := uint32(0)
|
|
|
|
|
|
|
|
if entryIdx == 0 {
|
|
if entryIdx == 0 {
|
|
|
- // === 首页: 写入 TxnID + TotalEntries + Committed + NextWalPage + EntryCount ===
|
|
|
|
|
|
|
+ // === 首页: 写入 TxnID + TotalEntries + State + NextWalPage + EntryCount ===
|
|
|
binary.LittleEndian.PutUint64(buf[walPHDR:], w.txnID)
|
|
binary.LittleEndian.PutUint64(buf[walPHDR:], w.txnID)
|
|
|
binary.LittleEndian.PutUint32(buf[walPHDR+8:], uint32(len(w.entries)))
|
|
binary.LittleEndian.PutUint32(buf[walPHDR+8:], uint32(len(w.entries)))
|
|
|
- buf[walPHDR+12] = 0 // Committed = 0 (进行中)
|
|
|
|
|
|
|
+ buf[walPHDR+12] = WALStateWritten // State = Written (已写盘,未 fsync)
|
|
|
binary.LittleEndian.PutUint32(buf[walPHDR+13:], 0) // NextWalPage (稍后填)
|
|
binary.LittleEndian.PutUint32(buf[walPHDR+13:], 0) // NextWalPage (稍后填)
|
|
|
binary.LittleEndian.PutUint16(buf[walPHDR+17:], 0) // EntryCount (稍后填)
|
|
binary.LittleEndian.PutUint16(buf[walPHDR+17:], 0) // EntryCount (稍后填)
|
|
|
|
|
|
|
@@ -236,13 +250,13 @@ func (w *WALWriter) writeWALPages() ([]uint32, error) {
|
|
|
return pageIDs, nil
|
|
return pageIDs, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// markCommitted 标记 WAL 首页为已提交
|
|
|
|
|
|
|
+// markCommitted 标记 WAL 首页为已提交 (State: Persisted → Committed)
|
|
|
func (w *WALWriter) markCommitted(firstPageID uint32) error {
|
|
func (w *WALWriter) markCommitted(firstPageID uint32) error {
|
|
|
buf := make([]byte, PageSize)
|
|
buf := make([]byte, PageSize)
|
|
|
if err := w.file.ReadPage(firstPageID, buf); err != nil {
|
|
if err := w.file.ReadPage(firstPageID, buf); err != nil {
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
|
- buf[walPHDR+12] = 1 // Committed = 1
|
|
|
|
|
|
|
+ buf[walPHDR+12] = WALStateCommitted // State = Committed
|
|
|
return w.file.WritePageDirect(firstPageID, buf)
|
|
return w.file.WritePageDirect(firstPageID, buf)
|
|
|
}
|
|
}
|
|
|
|
|
|