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 }