High-performance disk-based log storage implementation using memory mapping
The local file system storage implements a disk-based log storage system using memory mapping (mmap) to provide efficient read and write performance. Although the local file system supports append operations, we maintain the Fragment concept to ensure consistency with the object storage implementation.
FragmentFile is the basic storage unit responsible for read and write operations of individual log fragment files.
File Layout:
[Header (4K)] + [Data Area (grows forward)] + [...Free Space...] + [Index Area (grows backward)] + [Footer (fixed size)]
- Header (4K): Stores magic string and version information
- Data Area: Stores actual log entries, growing forward from 4K position
- Free Space: Unused space between data area and index area
- Index Area: Stores offset of each entry, growing backward from file end
- Footer: Stores metadata information
Data Entry Format:
[Payload Size (4 bytes)] + [CRC (4 bytes)] + [Actual Data (variable length)]
DiskLogFile manages multiple Fragment files, providing a unified read/write interface.
Directory Structure:
/basePath/
└── log_[logID]/
├── fragment_[startOffset1]
├── fragment_[startOffset2]
└── ...
Although local file system supports append, maintaining the Fragment concept provides several benefits:
Parameter | Description |
---|---|
File Size Limit | Maximum size of a fragment file |
Maximum Entries | Maximum number of entries per fragment |
Pre-allocated Space | Amount of space to pre-allocate |
Memory Mapping Options | Configuration for memory mapping behavior |
Parameter | Description |
---|---|
Base Path | Root directory for log files |
Fragment Size | Size of individual fragments |
Async Write Buffer Size | Size of asynchronous write buffer |
Cleanup Policy | Strategy for cleaning up old fragments |
// Create LogFile
logFile, err := NewDiskLogFile(1, "/path/to/logs", WithFragmentSize(4*1024*1024))
// Write data
err = logFile.Append(ctx, []byte("log entry"))
// Async write
entryID, resultCh, err := logFile.AppendAsync(ctx, 0, []byte("async log entry"))
// Read data
reader, err := logFile.NewReader(ctx, storage.ReaderOpt{
StartSequenceNum: 0,
EndSequenceNum: 100,
})