openreplay/backend/services/sink/writer.go
2021-05-03 17:53:25 +02:00

99 lines
1.7 KiB
Go

package main
import (
"math"
"os"
"strconv"
"time"
)
type Writer struct {
ulimit int
dir string
files map[uint64]*os.File
atimes map[uint64]int64
}
func NewWriter(ulimit uint16, dir string) *Writer {
return &Writer{
ulimit: int(ulimit),
dir: dir + "/",
files: make(map[uint64]*os.File),
atimes: make(map[uint64]int64),
}
}
func (w *Writer) open(key uint64) (*os.File, error) {
file, ok := w.files[key]
if ok {
return file, nil
}
if len(w.atimes) == w.ulimit {
var m_k uint64
var m_t int64 = math.MaxInt64
for k, t := range w.atimes {
if t < m_t {
m_k = k
m_t = t
}
}
if err := w.Close(m_k); err != nil {
return nil, err
}
}
file, err := os.OpenFile(w.dir+strconv.FormatUint(key, 10), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
return nil, err
}
w.files[key] = file
w.atimes[key] = time.Now().Unix()
return file, nil
}
func (w *Writer) Close(key uint64) error {
file := w.files[key]
if file == nil {
return nil
}
if err := file.Sync(); err != nil {
return err
}
if err := file.Close(); err != nil {
return err
}
delete(w.files, key)
delete(w.atimes, key)
return nil
}
func (w *Writer) Write(key uint64, data []byte) error {
file, err := w.open(key)
if err != nil {
return err
}
_, err = file.Write(data)
return err
}
func (w *Writer) SyncAll() error {
for _, file := range w.files {
if err := file.Sync(); err != nil {
return err
}
}
return nil
}
func (w *Writer) CloseAll() error {
for _, file := range w.files {
if err := file.Sync(); err != nil {
return err
}
if err := file.Close(); err != nil {
return err
}
}
w.files = nil
w.atimes = nil
return nil
}