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() }