179 lines
3.9 KiB
Go
179 lines
3.9 KiB
Go
package store
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"git.gammaspectra.live/S.O.N.G/Hibiki/panako"
|
|
"log"
|
|
"os"
|
|
"sort"
|
|
"syscall"
|
|
)
|
|
|
|
type AppendStore struct {
|
|
f *os.File
|
|
//writeMutex sync.RWMutex
|
|
useCompactHashes bool
|
|
usePackedValues bool
|
|
}
|
|
|
|
func NewAppendStore(pathName string, useCompactHashes, usePackedValues bool) (*AppendStore, error) {
|
|
f, err := os.OpenFile(pathName, os.O_WRONLY|os.O_CREATE|os.O_APPEND|syscall.O_DSYNC, 0666)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &AppendStore{
|
|
f: f,
|
|
useCompactHashes: useCompactHashes,
|
|
usePackedValues: usePackedValues,
|
|
}, nil
|
|
}
|
|
|
|
func (s *AppendStore) GetPanakoRecords(resourceId panako.ResourceId) []panako.StoreRecord {
|
|
return nil
|
|
}
|
|
|
|
func (s *AppendStore) GetPanakoMatch(record panako.StoreRecord, lookupRange int) chan *panako.MatchedRecord {
|
|
|
|
channel := make(chan *panako.MatchedRecord)
|
|
|
|
close(channel)
|
|
|
|
return channel
|
|
}
|
|
|
|
func (s *AppendStore) GetPanakoMatches(records []panako.StoreRecord, lookupRange int) chan *panako.MatchedRecord {
|
|
|
|
channel := make(chan *panako.MatchedRecord)
|
|
|
|
close(channel)
|
|
|
|
return channel
|
|
}
|
|
|
|
func (s *AppendStore) encodeRecord(record *panako.StoreRecord, buf *bytes.Buffer) {
|
|
|
|
if s.useCompactHashes {
|
|
binary.Write(buf, binary.LittleEndian, uint32(record.Hash))
|
|
} else {
|
|
binary.Write(buf, binary.LittleEndian, record.Hash)
|
|
}
|
|
if s.usePackedValues {
|
|
_, v := record.GetCompactPackedPrint()
|
|
binary.Write(buf, binary.LittleEndian, v)
|
|
} else {
|
|
binary.Write(buf, binary.LittleEndian, record.Time)
|
|
binary.Write(buf, binary.LittleEndian, record.Frequency)
|
|
}
|
|
|
|
}
|
|
|
|
type AppendStoreControlData struct {
|
|
resourceId panako.ResourceId
|
|
length uint32
|
|
}
|
|
|
|
func (s *AppendStore) encodeControl(d AppendStoreControlData, buf *bytes.Buffer) {
|
|
|
|
//Reset record mode
|
|
if s.useCompactHashes {
|
|
binary.Write(buf, binary.LittleEndian, uint32(0))
|
|
} else {
|
|
binary.Write(buf, binary.LittleEndian, uint64(0))
|
|
}
|
|
if s.usePackedValues {
|
|
binary.Write(buf, binary.LittleEndian, uint32(0))
|
|
} else {
|
|
binary.Write(buf, binary.LittleEndian, uint32(0))
|
|
binary.Write(buf, binary.LittleEndian, uint32(0))
|
|
}
|
|
|
|
//Write value
|
|
if s.useCompactHashes {
|
|
binary.Write(buf, binary.LittleEndian, uint64(d.resourceId))
|
|
binary.Write(buf, binary.LittleEndian, uint32(d.length))
|
|
if s.usePackedValues {
|
|
binary.Write(buf, binary.LittleEndian, uint32(0))
|
|
}
|
|
|
|
} else {
|
|
binary.Write(buf, binary.LittleEndian, uint64(d.resourceId))
|
|
binary.Write(buf, binary.LittleEndian, uint32(d.length))
|
|
if !s.usePackedValues {
|
|
binary.Write(buf, binary.LittleEndian, uint32(0))
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func (s *AppendStore) GetEntrySize() int {
|
|
if s.useCompactHashes && s.usePackedValues {
|
|
return 4 + 4
|
|
} else if !s.useCompactHashes && s.usePackedValues {
|
|
return 8 + 4
|
|
} else if s.useCompactHashes && !s.usePackedValues {
|
|
return 4 + 8
|
|
} else {
|
|
log.Panic()
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func (s *AppendStore) StorePanakoPrint(record panako.StoreRecord) {
|
|
buf := new(bytes.Buffer)
|
|
s.encodeControl(AppendStoreControlData{
|
|
resourceId: record.ResourceId,
|
|
length: 1,
|
|
}, buf)
|
|
s.encodeRecord(&record, buf)
|
|
//s.writeMutex.Lock()
|
|
//defer s.writeMutex.Unlock()
|
|
_, err := s.f.Write(buf.Bytes())
|
|
|
|
if err != nil {
|
|
log.Panic(err)
|
|
}
|
|
}
|
|
|
|
func (s *AppendStore) StorePanakoPrints(records []panako.StoreRecord) {
|
|
m := make(map[panako.ResourceId][]*panako.StoreRecord)
|
|
for i := range records {
|
|
m[records[i].ResourceId] = append(m[records[i].ResourceId], &records[i])
|
|
}
|
|
|
|
//s.writeMutex.Lock()
|
|
//defer s.writeMutex.Unlock()
|
|
|
|
buf := new(bytes.Buffer)
|
|
for k, l := range m {
|
|
s.encodeControl(AppendStoreControlData{
|
|
resourceId: k,
|
|
length: uint32(len(l)),
|
|
}, buf)
|
|
|
|
//sort entries to allow easier lookups on scan
|
|
sort.Slice(l, func(i, j int) bool {
|
|
return l[i].Hash < l[j].Hash
|
|
})
|
|
|
|
for _, v := range l {
|
|
s.encodeRecord(v, buf)
|
|
}
|
|
}
|
|
|
|
_, err := s.f.Write(buf.Bytes())
|
|
|
|
if err != nil {
|
|
log.Panic(err)
|
|
}
|
|
}
|
|
|
|
func (s *AppendStore) Sync() error {
|
|
return s.f.Sync()
|
|
}
|
|
|
|
func (s *AppendStore) Close() error {
|
|
return s.f.Close()
|
|
}
|