-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwal.go
More file actions
83 lines (67 loc) · 1.38 KB
/
wal.go
File metadata and controls
83 lines (67 loc) · 1.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package fossil
import (
"encoding/binary"
"fmt"
"os"
"path/filepath"
"sync"
)
const (
// safe value is used to compare buf size
// only reuse the buffer if within range
//
// otherwise force buffer pool to reallocate
safeValue = 64 * 1024 // 64KB
)
type wal struct {
f *os.File
mu sync.Mutex
p *sync.Pool
}
func newWal(path string) (*wal, error) {
clean := filepath.Clean(path)
f, err := os.OpenFile(clean, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
if err != nil {
return nil, fmt.Errorf("os.OpenFile: %w", err)
}
bufPool := &sync.Pool{
New: func() any {
b := make([]byte, 1024)
return &b
},
}
return &wal{
f: f,
mu: sync.Mutex{},
p: bufPool,
}, nil
}
func (w *wal) append(key, value []byte) error {
w.mu.Lock()
defer w.mu.Unlock()
s := 8 + len(key) + len(value)
bptr := w.p.Get().(*[]byte)
buf := *bptr
// grow buf if needed
if cap(buf) < s {
buf = make([]byte, s)
} else {
buf = buf[:s]
}
binary.BigEndian.PutUint32(buf[0:4], uint32(len(key)))
binary.BigEndian.PutUint32(buf[4:8], uint32(len(value)))
copy(buf[8:], key)
copy(buf[8+len(key):], value)
_, err := w.f.Write(buf)
if err != nil {
return fmt.Errorf("failed to write buf to file: %w", err)
}
// only return the buf to the pool if
// buffer did not grow above safe value
if cap(buf) <= safeValue {
*bptr = buf
w.p.Put(bptr)
}
// force os write
return w.f.Sync()
}