Skip to content

Commit

Permalink
add segment file ext
Browse files Browse the repository at this point in the history
  • Loading branch information
roseduan committed Jun 16, 2023
1 parent f577e14 commit 7b8e448
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 27 deletions.
18 changes: 13 additions & 5 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ type Options struct {
// SegmentSize specifies the maximum size of each segment file in bytes.
SegmentSize int64

// SegmentFileExt specifies the file extension of the segment files.
// The file extension must start with a dot ".", default value is ".SEG".
// It is used to identify the different types of files in the directory.
// Now it is used by rosedb to identify the segment files and hint files.
// Not a common usage for most users.
SementFileExt string

// BlockCache specifies the size of the block cache in number of bytes.
// A block cache is used to store recently accessed data blocks, improving read performance.
// If BlockCache is set to 0, no block cache will be used.
Expand Down Expand Up @@ -37,9 +44,10 @@ const (
)

var DefaultOptions = Options{
DirPath: os.TempDir(),
SegmentSize: GB,
BlockCache: 32 * KB * 10,
Sync: false,
BytesPerSync: 0,
DirPath: os.TempDir(),
SegmentSize: GB,
SementFileExt: ".SEG",
BlockCache: 32 * KB * 10,
Sync: false,
BytesPerSync: 0,
}
8 changes: 3 additions & 5 deletions segment.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ const (
blockSize = 32 * KB

fileModePerm = 0644

segmentFileSuffix = ".SEG"
)

// Segment represents a single segment file in WAL.
Expand Down Expand Up @@ -75,8 +73,8 @@ type ChunkPosition struct {
}

// openSegmentFile a new segment file.
func openSegmentFile(dirPath string, id uint32, cache *lru.Cache[uint64, []byte]) (*segment, error) {
fileName := fmt.Sprintf("%09d"+segmentFileSuffix, id)
func openSegmentFile(dirPath, extName string, id uint32, cache *lru.Cache[uint64, []byte]) (*segment, error) {
fileName := fmt.Sprintf("%09d"+extName, id)
fd, err := os.OpenFile(
filepath.Join(dirPath, fileName),
os.O_CREATE|os.O_RDWR|os.O_APPEND,
Expand All @@ -90,7 +88,7 @@ func openSegmentFile(dirPath string, id uint32, cache *lru.Cache[uint64, []byte]
// set the current block number and block size.
offset, err := fd.Seek(0, io.SeekEnd)
if err != nil {
panic(fmt.Errorf("seek to the end of segment file %d%s failed: %v", id, segmentFileSuffix, err))
panic(fmt.Errorf("seek to the end of segment file %d%s failed: %v", id, extName, err))
}

return &segment{
Expand Down
18 changes: 9 additions & 9 deletions segment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

func TestSegment_Write_FULL1(t *testing.T) {
dir, _ := os.MkdirTemp("", "seg-test-full1")
seg, err := openSegmentFile(dir, 1, nil)
seg, err := openSegmentFile(dir, ".SEG", 1, nil)
assert.Nil(t, err)
defer func() {
_ = seg.Remove()
Expand Down Expand Up @@ -46,7 +46,7 @@ func TestSegment_Write_FULL1(t *testing.T) {

func TestSegment_Write_FULL2(t *testing.T) {
dir, _ := os.MkdirTemp("", "seg-test-full2")
seg, err := openSegmentFile(dir, 1, nil)
seg, err := openSegmentFile(dir, ".SEG", 1, nil)
assert.Nil(t, err)
defer func() {
_ = seg.Remove()
Expand Down Expand Up @@ -74,7 +74,7 @@ func TestSegment_Write_FULL2(t *testing.T) {

func TestSegment_Write_Padding(t *testing.T) {
dir, _ := os.MkdirTemp("", "seg-test-padding")
seg, err := openSegmentFile(dir, 1, nil)
seg, err := openSegmentFile(dir, ".SEG", 1, nil)
assert.Nil(t, err)
defer func() {
_ = seg.Remove()
Expand All @@ -97,7 +97,7 @@ func TestSegment_Write_Padding(t *testing.T) {

func TestSegment_Write_NOT_FULL(t *testing.T) {
dir, _ := os.MkdirTemp("", "seg-test-not-full")
seg, err := openSegmentFile(dir, 1, nil)
seg, err := openSegmentFile(dir, ".SEG", 1, nil)
assert.Nil(t, err)
defer func() {
_ = seg.Remove()
Expand Down Expand Up @@ -135,7 +135,7 @@ func TestSegment_Write_NOT_FULL(t *testing.T) {

func TestSegment_Reader_FULL(t *testing.T) {
dir, _ := os.MkdirTemp("", "seg-test-reader-full")
seg, err := openSegmentFile(dir, 1, nil)
seg, err := openSegmentFile(dir, ".SEG", 1, nil)
assert.Nil(t, err)
defer func() {
_ = seg.Remove()
Expand Down Expand Up @@ -167,7 +167,7 @@ func TestSegment_Reader_FULL(t *testing.T) {

func TestSegment_Reader_Padding(t *testing.T) {
dir, _ := os.MkdirTemp("", "seg-test-reader-padding")
seg, err := openSegmentFile(dir, 1, nil)
seg, err := openSegmentFile(dir, ".SEG", 1, nil)
assert.Nil(t, err)
defer func() {
_ = seg.Remove()
Expand Down Expand Up @@ -201,7 +201,7 @@ func TestSegment_Reader_Padding(t *testing.T) {

func TestSegment_Reader_NOT_FULL(t *testing.T) {
dir, _ := os.MkdirTemp("", "seg-test-reader-not-full")
seg, err := openSegmentFile(dir, 1, nil)
seg, err := openSegmentFile(dir, ".SEG", 1, nil)
assert.Nil(t, err)
defer func() {
_ = seg.Remove()
Expand Down Expand Up @@ -248,7 +248,7 @@ func TestSegment_Reader_NOT_FULL(t *testing.T) {
func TestSegment_Reader_ManyChunks_FULL(t *testing.T) {
dir, _ := os.MkdirTemp("", "seg-test-reader-ManyChunks_FULL")
cache, _ := lru.New[uint64, []byte](5)
seg, err := openSegmentFile(dir, 1, cache)
seg, err := openSegmentFile(dir, ".SEG", 1, cache)
assert.Nil(t, err)
defer func() {
_ = seg.Remove()
Expand Down Expand Up @@ -286,7 +286,7 @@ func TestSegment_Reader_ManyChunks_FULL(t *testing.T) {
func TestSegment_Reader_ManyChunks_NOT_FULL(t *testing.T) {
dir, _ := os.MkdirTemp("", "seg-test-reader-ManyChunks_NOT_FULL")
cache, _ := lru.New[uint64, []byte](5)
seg, err := openSegmentFile(dir, 1, cache)
seg, err := openSegmentFile(dir, ".SEG", 1, cache)
assert.Nil(t, err)
defer func() {
_ = seg.Remove()
Expand Down
20 changes: 14 additions & 6 deletions wal.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io"
"os"
"sort"
"strings"
"sync"

lru "github.com/hashicorp/golang-lru/v2"
Expand Down Expand Up @@ -49,6 +50,9 @@ type Reader struct {
}

func Open(options Options) (*WAL, error) {
if !strings.HasPrefix(options.SementFileExt, ".") {
return nil, fmt.Errorf("segment file extension must start with '.'")
}
wal := &WAL{
options: options,
olderSegments: make(map[SegmentID]*segment),
Expand Down Expand Up @@ -85,7 +89,7 @@ func Open(options Options) (*WAL, error) {
continue
}
var id int
_, err := fmt.Sscanf(entry.Name(), "%d"+segmentFileSuffix, &id)
_, err := fmt.Sscanf(entry.Name(), "%d"+options.SementFileExt, &id)
if err != nil {
continue
}
Expand All @@ -94,7 +98,8 @@ func Open(options Options) (*WAL, error) {

// empty directory, just initialize a new segment file.
if len(segmengIDs) == 0 {
segment, err := openSegmentFile(options.DirPath, initialSegmentFileID, wal.blockCache)
segment, err := openSegmentFile(options.DirPath, options.SementFileExt,
initialSegmentFileID, wal.blockCache)
if err != nil {
return nil, err
}
Expand All @@ -104,7 +109,8 @@ func Open(options Options) (*WAL, error) {
sort.Ints(segmengIDs)

for i, segId := range segmengIDs {
segment, err := openSegmentFile(options.DirPath, uint32(segId), wal.blockCache)
segment, err := openSegmentFile(options.DirPath, options.SementFileExt,
uint32(segId), wal.blockCache)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -133,7 +139,8 @@ func (wal *WAL) OpenNewActiveSegment() error {
return err
}
// create a new segment file and set it as the active one.
segment, err := openSegmentFile(wal.options.DirPath, wal.activeSegment.id+1, wal.blockCache)
segment, err := openSegmentFile(wal.options.DirPath, wal.options.SementFileExt,
wal.activeSegment.id+1, wal.blockCache)
if err != nil {
return err
}
Expand Down Expand Up @@ -215,7 +222,8 @@ func (wal *WAL) Write(data []byte) (*ChunkPosition, error) {
return nil, err
}

segment, err := openSegmentFile(wal.options.DirPath, wal.activeSegment.id+1, wal.blockCache)
segment, err := openSegmentFile(wal.options.DirPath, wal.options.SementFileExt,
wal.activeSegment.id+1, wal.blockCache)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -260,7 +268,7 @@ func (wal *WAL) Read(pos *ChunkPosition) ([]byte, error) {
}

if segment == nil {
return nil, fmt.Errorf("segment file %d%s not found", pos.SegmentId, segmentFileSuffix)
return nil, fmt.Errorf("segment file %d%s not found", pos.SegmentId, wal.options.SementFileExt)
}

// read the data from the segment file.
Expand Down
8 changes: 6 additions & 2 deletions wal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ func destroyWAL(wal *WAL) {
func TestWAL_Write(t *testing.T) {
dir, _ := os.MkdirTemp("", "wal-test-write1")
opts := Options{
DirPath: dir,
SegmentSize: 32 * 1024 * 1024,
DirPath: dir,
SementFileExt: ".SEG",
SegmentSize: 32 * 1024 * 1024,
}
wal, err := Open(opts)
assert.Nil(t, err)
Expand Down Expand Up @@ -51,6 +52,7 @@ func TestWAL_Write_large(t *testing.T) {
dir, _ := os.MkdirTemp("", "wal-test-write2")
opts := Options{
DirPath: dir,
SementFileExt: ".SEG",
SegmentSize: 32 * 1024 * 1024,
}
wal, err := Open(opts)
Expand All @@ -64,6 +66,7 @@ func TestWAL_Write_large2(t *testing.T) {
dir, _ := os.MkdirTemp("", "wal-test-write3")
opts := Options{
DirPath: dir,
SementFileExt: ".SEG",
SegmentSize: 32 * 1024 * 1024,
}
wal, err := Open(opts)
Expand All @@ -77,6 +80,7 @@ func TestWAL_OpenNewActiveSegment(t *testing.T) {
dir, _ := os.MkdirTemp("", "wal-test-new-active-segment")
opts := Options{
DirPath: dir,
SementFileExt: ".SEG",
SegmentSize: 32 * 1024 * 1024,
}
wal, err := Open(opts)
Expand Down

0 comments on commit 7b8e448

Please sign in to comment.