func (s *session) setOptions(o *opt.Options) { s.o = &opt.Options{} if o != nil { *s.o = *o } // Alternative filters. if filters := o.GetAltFilters(); len(filters) > 0 { s.o.AltFilters = make([]filter.Filter, len(filters)) for i, filter := range filters { s.o.AltFilters[i] = &iFilter{filter} } } // Block cache. switch o.GetBlockCache() { case nil: s.o.BlockCache = cache.NewLRUCache(opt.DefaultBlockCacheSize) case opt.NoCache: s.o.BlockCache = nil } // Comparer. s.icmp = &iComparer{o.GetComparer()} s.o.Comparer = s.icmp // Filter. if filter := o.GetFilter(); filter != nil { s.o.Filter = &iFilter{filter} } }
// NewWriter creates a new initialized table writer for the file. // // Table writer is not goroutine-safe. func NewWriter(f io.Writer, o *opt.Options) *Writer { w := &Writer{ writer: f, cmp: o.GetComparer(), filter: o.GetFilter(), compression: o.GetCompression(), blockSize: o.GetBlockSize(), comparerScratch: make([]byte, 0), } // data block w.dataBlock.restartInterval = o.GetBlockRestartInterval() // The first 20-bytes are used for encoding block handle. w.dataBlock.scratch = w.scratch[20:] // index block w.indexBlock.restartInterval = 1 w.indexBlock.scratch = w.scratch[20:] // filter block if w.filter != nil { w.filterBlock.generator = w.filter.NewGenerator() w.filterBlock.flush(0) } return w }
// NewReader creates a new initialized table reader for the file. // The cache and bpool is optional and can be nil. // // The returned table reader instance is goroutine-safe. func NewReader(f io.ReaderAt, size int64, cache cache.Namespace, bpool *util.BufferPool, o *opt.Options) *Reader { if bpool == nil { bpool = util.NewBufferPool(o.GetBlockSize() + blockTrailerLen) } r := &Reader{ reader: f, cache: cache, bpool: bpool, cmp: o.GetComparer(), checksum: o.GetStrict(opt.StrictBlockChecksum), strictIter: o.GetStrict(opt.StrictIterator), } if f == nil { r.err = errors.New("leveldb/table: Reader: nil file") return r } if size < footerLen { r.err = errors.New("leveldb/table: Reader: invalid table (file size is too small)") return r } var footer [footerLen]byte if _, err := r.reader.ReadAt(footer[:], size-footerLen); err != nil && err != io.EOF { r.err = fmt.Errorf("leveldb/table: Reader: invalid table (could not read footer): %v", err) } if string(footer[footerLen-len(magic):footerLen]) != magic { r.err = errors.New("leveldb/table: Reader: invalid table (bad magic number)") return r } // Decode the metaindex block handle. metaBH, n := decodeBlockHandle(footer[:]) if n == 0 { r.err = errors.New("leveldb/table: Reader: invalid table (bad metaindex block handle)") return r } // Decode the index block handle. r.indexBH, n = decodeBlockHandle(footer[n:]) if n == 0 { r.err = errors.New("leveldb/table: Reader: invalid table (bad index block handle)") return r } // Read metaindex block. metaBlock, err := r.readBlock(metaBH, true) if err != nil { r.err = err return r } // Set data end. r.dataEnd = int64(metaBH.offset) metaIter := metaBlock.newIterator(nil, false, nil) for metaIter.Next() { key := string(metaIter.Key()) if !strings.HasPrefix(key, "filter.") { continue } fn := key[7:] if f0 := o.GetFilter(); f0 != nil && f0.Name() == fn { r.filter = f0 } else { for _, f0 := range o.GetAltFilters() { if f0.Name() == fn { r.filter = f0 break } } } if r.filter != nil { filterBH, n := decodeBlockHandle(metaIter.Value()) if n == 0 { continue } r.filterBH = filterBH // Update data end. r.dataEnd = int64(filterBH.offset) break } } metaIter.Release() metaBlock.Release() return r }