|
|
@ -1,32 +1,6 @@ |
|
|
|
package fsstorage |
|
|
|
|
|
|
|
import ( |
|
|
|
"encoding/binary" |
|
|
|
"io/ioutil" |
|
|
|
"os" |
|
|
|
"path/filepath" |
|
|
|
"sync" |
|
|
|
"syscall" |
|
|
|
"time" |
|
|
|
"unsafe" |
|
|
|
|
|
|
|
"git.crumpington.com/public/toolbox/fsutil" |
|
|
|
"git.crumpington.com/public/toolbox/mmap" |
|
|
|
) |
|
|
|
|
|
|
|
const fixedDataSize = 32 |
|
|
|
|
|
|
|
type walEntry struct { |
|
|
|
offset uint64 |
|
|
|
prevOffset uint64 |
|
|
|
cmdDataSize uint32 |
|
|
|
|
|
|
|
WALID uint64 |
|
|
|
TS uint64 // Unix timestamp in seconds.
|
|
|
|
CmdID uint32 |
|
|
|
CmdData []byte |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
type segment struct { |
|
|
|
dataPath string |
|
|
|
tailOffsetPath string |
|
|
@ -36,23 +10,22 @@ type segment struct { |
|
|
|
nextWALID uint64 |
|
|
|
firstWALID uint64 |
|
|
|
|
|
|
|
lock sync.Mutex // Protects tailOffset.
|
|
|
|
tailOffset uint64 |
|
|
|
|
|
|
|
f *os.File |
|
|
|
mapped []byte |
|
|
|
|
|
|
|
// TODO: Append lock?
|
|
|
|
} |
|
|
|
|
|
|
|
func (seg *segment) getTailOffset() uint64 { |
|
|
|
seg.lock.Lock() |
|
|
|
defer seg.lock.Unlock() |
|
|
|
// TODO
|
|
|
|
return seg.tailOffset |
|
|
|
} |
|
|
|
|
|
|
|
func (seg *segment) setTailOffset(offset uint64) { |
|
|
|
seg.lock.Lock() |
|
|
|
// TODO
|
|
|
|
seg.tailOffset = offset |
|
|
|
seg.lock.Unlock() |
|
|
|
} |
|
|
|
|
|
|
|
// Given a directory and file size in bytes, create a new segment. The actual
|
|
|
@ -165,11 +138,13 @@ func openSegment(dir string) (*segment, error) { |
|
|
|
|
|
|
|
// Set insertion point.
|
|
|
|
seg.nextWALID = seg.firstWALID |
|
|
|
seg.insertAt = 1 |
|
|
|
if tail := seg.Tail(); tail != nil { |
|
|
|
seg.nextWALID = tail.WALID + 1 |
|
|
|
seg.insertAt = int(tail.offset + fixedDataSize + uint64(len(tail.CmdData))) |
|
|
|
} |
|
|
|
|
|
|
|
seg.insertAt = 1 |
|
|
|
if walID, tail := seg.Tail(); tail != nil { |
|
|
|
seg.nextWALID = walID + 1 |
|
|
|
seg.insertAt = int(tail.offset + offsetData + uint64(len(tail.CmdData))) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return seg, nil |
|
|
|
} |
|
|
@ -204,40 +179,36 @@ func (seg *segment) Close() error { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
func (seg *segment) Head() *walEntry { |
|
|
|
func (seg *segment) Head() (WALEntry, bool) { |
|
|
|
if seg.getTailOffset() == 0 { |
|
|
|
return nil |
|
|
|
return WALEntry{}, false |
|
|
|
|
|
|
|
} |
|
|
|
return seg.loadEntry(1) |
|
|
|
return seg.loadEntry(1), true |
|
|
|
} |
|
|
|
|
|
|
|
func (seg *segment) Tail() *walEntry { |
|
|
|
func (seg *segment) Tail() (walID uint64, data []byte) { |
|
|
|
offset := seg.getTailOffset() |
|
|
|
if offset == 0 { |
|
|
|
return nil |
|
|
|
return 0, nil |
|
|
|
} |
|
|
|
return seg.loadEntry(offset) |
|
|
|
} |
|
|
|
|
|
|
|
func (seg *segment) loadEntry(offset uint64) *walEntry { |
|
|
|
entry := &walEntry{ |
|
|
|
offset: offset, |
|
|
|
prevOffset: *(*uint64)(unsafe.Pointer(&seg.mapped[offset])), |
|
|
|
WALID: *(*uint64)(unsafe.Pointer(&seg.mapped[offset+8])), |
|
|
|
TS: *(*uint64)(unsafe.Pointer(&seg.mapped[offset+16])), |
|
|
|
CmdID: *(*uint32)(unsafe.Pointer(&seg.mapped[offset+24])), |
|
|
|
cmdDataSize: *(*uint32)(unsafe.Pointer(&seg.mapped[offset+28])), |
|
|
|
} |
|
|
|
func (seg *segment) loadEntry(offset uint64) WALEntry { |
|
|
|
return loadWALEntry(seg.mapped[offset:]) |
|
|
|
|
|
|
|
dataStart := offset + fixedDataSize |
|
|
|
dataEnd := dataStart + uint64(entry.cmdDataSize) |
|
|
|
entry.CmdData = seg.mapped[dataStart:dataEnd] |
|
|
|
return entry |
|
|
|
} |
|
|
|
walID = *(*uint64)(unsafe.Pointer(&seg.mapped[offset+offsetWALID])) |
|
|
|
size := *(*uint32)(unsafe.Pointer(&seg.mapped[offset+offsetDataLen])) |
|
|
|
|
|
|
|
func (seg *segment) Next(entry *walEntry) *walEntry { |
|
|
|
offset := entry.offset + fixedDataSize + uint64(entry.cmdDataSize) |
|
|
|
dataStart := offset + offsetData |
|
|
|
dataEnd := dataStart + uint64(size) |
|
|
|
data = seg.mapped[dataStart:dataEnd] |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
func (seg *segment) Next(data []byte) (walID uint64, data []byte) { |
|
|
|
offset := *(*uint64)(unsafe.Add(unsafe.Pointer(&data[0]), len(data))) |
|
|
|
if offset > seg.getTailOffset() { |
|
|
|
return nil |
|
|
|
} |
|
|
@ -245,19 +216,20 @@ func (seg *segment) Next(entry *walEntry) *walEntry { |
|
|
|
return seg.loadEntry(offset) |
|
|
|
} |
|
|
|
|
|
|
|
func (seg *segment) Prev(entry *walEntry) *walEntry { |
|
|
|
func (seg *segment) Prev(entry *walEntry) (walID uint64, data []byte) { |
|
|
|
prevOffset := *(*uint64)(unsafe.Add(unsafe.Pointer(&data[0]), -offsetData)) |
|
|
|
if entry.prevOffset == 0 { |
|
|
|
return nil |
|
|
|
} |
|
|
|
return seg.loadEntry(entry.prevOffset) |
|
|
|
} |
|
|
|
|
|
|
|
func (seg *segment) Append(walID uint64, cmdID uint32, data []byte) error { |
|
|
|
func (seg *segment) Append(walID uint64, data []byte) error { |
|
|
|
if walID != seg.nextWALID { |
|
|
|
return ErrInvalidWALID |
|
|
|
} |
|
|
|
|
|
|
|
needed := fixedDataSize + len(data) |
|
|
|
needed := offsetData + len(data) |
|
|
|
if len(seg.mapped)-seg.insertAt < needed { |
|
|
|
return ErrSegmentFull |
|
|
|
} |
|
|
@ -265,15 +237,15 @@ func (seg *segment) Append(walID uint64, cmdID uint32, data []byte) error { |
|
|
|
*(*uint64)(unsafe.Pointer(&seg.mapped[seg.insertAt])) = seg.getTailOffset() |
|
|
|
seg.setTailOffset(uint64(seg.insertAt)) |
|
|
|
|
|
|
|
*(*uint64)(unsafe.Pointer(&seg.mapped[seg.insertAt+8])) = walID |
|
|
|
*(*uint64)(unsafe.Pointer(&seg.mapped[seg.insertAt+16])) = uint64(time.Now().Unix()) |
|
|
|
*(*uint32)(unsafe.Pointer(&seg.mapped[seg.insertAt+24])) = cmdID |
|
|
|
*(*uint32)(unsafe.Pointer(&seg.mapped[seg.insertAt+28])) = uint32(len(data)) |
|
|
|
*(*uint64)(unsafe.Pointer(&seg.mapped[seg.insertAt+offsetWALID])) = walID |
|
|
|
*(*uint64)(unsafe.Pointer(&seg.mapped[seg.insertAt+offsetTS])) = uint64(time.Now().Unix()) |
|
|
|
*(*uint32)(unsafe.Pointer(&seg.mapped[seg.insertAt+offsetDataLen])) = uint32(len(data)) |
|
|
|
|
|
|
|
seg.insertAt += fixedDataSize |
|
|
|
seg.insertAt += offsetData |
|
|
|
seg.insertAt += copy(seg.mapped[seg.insertAt:], data) |
|
|
|
|
|
|
|
seg.nextWALID++ |
|
|
|
|
|
|
|
return nil |
|
|
|
} |
|
|
|
*/ |