/// <summary> /// Attempt to open the table that is stored in bytes [0..file_size) /// of "file", and read the metadata entries necessary to allow /// retrieving data from the table. /// /// If successful, returns ok and sets "*table" to the newly opened /// table. The client should delete "*table" when no longer needed. /// If there was an error while initializing the table, sets "*table" /// to NULL and returns a non-ok status. Does not take ownership of /// "*source", but the client must ensure that "source" remains live /// for the duration of the returned table's lifetime. /// /// *file must remain live while this Table is in use. /// </summary> public static Status Open(Options options, RandomAccessFile file, UInt64 size, out Table table) { table = null; if (size < Footer.kEncodedLength) { return Status.InvalidArgument("file is too short to be an sstable"); } ByteArrayPointer footerSpace = new ByteArrayPointer(Footer.kEncodedLength); Slice footerInput; Status s = file.Read(size - Footer.kEncodedLength, Footer.kEncodedLength, out footerInput, footerSpace); if (!s.IsOk) return s; Footer footer = new Footer(); s = footer.DecodeFrom(ref footerInput); if (!s.IsOk) return s; // Read the index block BlockContents contents; Block indexBlock = null; if (s.IsOk) { s = FormatHelper.ReadBlock(file, ReadOptions.Default, footer.IndexHandle, out contents); if (s.IsOk) { indexBlock = new Block(contents); } } if (s.IsOk) { // We've successfully read the footer and the index block: we're // ready to serve requests. Rep rep = new Rep(); rep.Options = options; rep.File = file; rep.MetaindexHandle = footer.MetaindexHandle; rep.IndexBlock = indexBlock; rep.CacheId = (options.BlockCache != null ? options.BlockCache.NewId() : 0); rep.FilterData = ByteArrayPointer.Null; rep.Filter = null; table = new Table(rep); table.ReadMeta(footer); } return s; }
void ReadMeta(Footer footer) { if (rep_.Options.FilterPolicy == null) { // Do not need any metadata return; } // TODO(sanjay): Skip this if footer.metaindex_handle() size indicates // it is an empty block. ReadOptions opt = ReadOptions.Default; BlockContents contents; if (!FormatHelper.ReadBlock(rep_.File, opt, footer.MetaindexHandle, out contents).IsOk) { // Do not propagate errors since meta info is not needed for operation return; } Block meta = new Block(contents); Iterator iter = meta.NewIterator(Comparator.BytewiseComparator); string key = "filter." + rep_.Options.FilterPolicy.Name; iter.Seek(key); if (iter.Valid && iter.Key == key) { ReadFilter(iter.Value); } }
private static Iterator BlockReader(object arg, ReadOptions options, Slice indexValue) { Table table = (Table)arg; Cache blockCache = table.rep_.Options.BlockCache; Block block = null; Cache.Handle cacheHandle = null; BlockHandle handle = new BlockHandle(); Slice input = indexValue; Status s = handle.DecodeFrom(ref input); // We intentionally allow extra stuff in index_value so that we // can add more features in the future. if (s.IsOk) { BlockContents contents; if (blockCache != null) { ByteArrayPointer cacheKeyBuffer = new ByteArrayPointer(16); Coding.EncodeFixed64(cacheKeyBuffer, table.rep_.CacheId); Coding.EncodeFixed64(cacheKeyBuffer + 8, handle.Offset); Slice key = new Slice(cacheKeyBuffer, cacheKeyBuffer.Length); cacheHandle = blockCache.Lookup(key); if (cacheHandle != null) { block = (Block)(blockCache.Value(cacheHandle)); } else { s = FormatHelper.ReadBlock(table.rep_.File, options, handle, out contents); if (s.IsOk) { block = new Block(contents); if (contents.Cachable && options.FillCache) { cacheHandle = blockCache.Insert(key, block, block.Size); } } } } else { s = FormatHelper.ReadBlock(table.rep_.File, options, handle, out contents); if (s.IsOk) { block = new Block(contents); } } } Iterator iter; if (block != null) { iter = block.NewIterator(table.rep_.Options.Comparator); if (cacheHandle != null) { iter.RegisterCleanup(ReleaseBlock, blockCache, cacheHandle); } } else { iter = Iterator.NewErrorIterator(s); } return iter; }