// LoadSegs laods all existing segment files available // matching provided base path. The base path should contain // the path to the segment file and the segment file prefix. // example: "/path/to/segment/files/prefix_" func LoadSegs(base string, size int64, lock bool) (segs []*Segment, err error) { segs = []*Segment{} for i := 0; true; i++ { path := base + strconv.Itoa(i) file, err := os.OpenFile(path, os.O_RDWR, 0644) if err != nil { break } // don't need this defer file.Close() seg, err := memmap.MapFile(file, size) if err != nil { return nil, err } if lock { if err := seg.Lock(); err != nil { go seg.Close() return nil, err } } segs = append(segs, &Segment{seg, 0}) } return segs, nil }
// ensure makes sure that segments upto given index exists and are valid. // This will check from current segment length upto given position. // This will also pre allocate an additional segment file/mmap. func (s *Store) ensure(n int64) (err error) { // +1 preallocate num := int(n) + 1 // fast path s.segmx.RLock() if num < len(s.segs) { s.segmx.RUnlock() return nil } s.segmx.RUnlock() // slow path s.segmx.Lock() defer s.segmx.Unlock() available := len(s.segs) if num < available { return nil } for i := available; i <= num; i++ { path := s.base + strconv.Itoa(i) file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644) if err != nil { return err } // don't need this defer file.Close() seg, err := memmap.MapFile(file, s.size) if err != nil { return err } if err := seg.Lock(); err != nil { go seg.Close() return err } s.segs = append(s.segs, &Segment{seg, 0}) } return nil }