packages feed

leveldb-haskell 0.0.3 → 0.1.0

raw patch · 116 files changed

+793/−25145 lines, 116 filesdep +data-defaultdep +resourcetdep +transformerssetup-changedPVP ok

version bump matches the API change (PVP)

Dependencies added: data-default, resourcet, transformers

API changes (from Hackage documentation)

- Database.LevelDB: BlockRestartInterval :: Int -> Option
- Database.LevelDB: BlockSize :: Int -> Option
- Database.LevelDB: CacheSize :: Int -> Option
- Database.LevelDB: CreateIfMissing :: Option
- Database.LevelDB: ErrorIfExists :: Option
- Database.LevelDB: FillCache :: ReadOption
- Database.LevelDB: MaxOpenFiles :: Int -> Option
- Database.LevelDB: ParanoidChecks :: Option
- Database.LevelDB: Sync :: WriteOption
- Database.LevelDB: UseCompression :: Compression -> Option
- Database.LevelDB: UseSnapshot :: Snapshot -> ReadOption
- Database.LevelDB: VerifyCheckSums :: ReadOption
- Database.LevelDB: WriteBufferSize :: Int -> Option
- Database.LevelDB: data Option
- Database.LevelDB: data ReadOption
- Database.LevelDB: data WriteOption
- Database.LevelDB: instance Eq Option
- Database.LevelDB: instance Eq ReadOption
- Database.LevelDB: instance Eq WriteOption
- Database.LevelDB: instance Show Option
- Database.LevelDB: instance Show WriteOption
- Database.LevelDB: iterClose :: Iterator -> IO ()
- Database.LevelDB: type Options = [Option]
- Database.LevelDB: type ReadOptions = [ReadOption]
- Database.LevelDB: type WriteOptions = [WriteOption]
- Database.LevelDB: withLevelDB :: FilePath -> Options -> (DB -> IO a) -> IO a
+ Database.LevelDB: Comparator :: (ByteString -> ByteString -> Ordering) -> Comparator
+ Database.LevelDB: Options :: !Int -> !Int -> !Int -> !(Maybe Comparator) -> !Compression -> !Bool -> !Bool -> !Int -> !Bool -> !Int -> Options
+ Database.LevelDB: ReadOptions :: !Bool -> !Bool -> !(Maybe Snapshot) -> ReadOptions
+ Database.LevelDB: WriteOptions :: !Bool -> WriteOptions
+ Database.LevelDB: blockRestartInterval :: Options -> !Int
+ Database.LevelDB: blockSize :: Options -> !Int
+ Database.LevelDB: cacheSize :: Options -> !Int
+ Database.LevelDB: class (MonadThrow m, MonadUnsafeIO m, MonadIO m, Applicative m) => MonadResource (m :: * -> *)
+ Database.LevelDB: comparator :: Options -> !(Maybe Comparator)
+ Database.LevelDB: compression :: Options -> !Compression
+ Database.LevelDB: createIfMissing :: Options -> !Bool
+ Database.LevelDB: createSnapshot :: MonadResource m => DB -> m Snapshot
+ Database.LevelDB: createSnapshot' :: MonadResource m => DB -> m (ReleaseKey, Snapshot)
+ Database.LevelDB: data Options
+ Database.LevelDB: data ReadOptions
+ Database.LevelDB: data WriteOptions
+ Database.LevelDB: defaultOptions :: Options
+ Database.LevelDB: defaultReadOptions :: ReadOptions
+ Database.LevelDB: defaultWriteOptions :: WriteOptions
+ Database.LevelDB: errorIfExists :: Options -> !Bool
+ Database.LevelDB: fillCache :: ReadOptions -> !Bool
+ Database.LevelDB: instance Default Options
+ Database.LevelDB: instance Default ReadOptions
+ Database.LevelDB: instance Default WriteOptions
+ Database.LevelDB: instance Eq ReadOptions
+ Database.LevelDB: instance Eq WriteOptions
+ Database.LevelDB: instance Show WriteOptions
+ Database.LevelDB: iterGetError :: MonadResource m => Iterator -> m (Maybe ByteString)
+ Database.LevelDB: iterOpen' :: MonadResource m => DB -> ReadOptions -> m (ReleaseKey, Iterator)
+ Database.LevelDB: liftResourceT :: MonadResource m => ResourceT IO a -> m a
+ Database.LevelDB: maxOpenFiles :: Options -> !Int
+ Database.LevelDB: newtype Comparator
+ Database.LevelDB: open :: MonadResource m => FilePath -> Options -> m DB
+ Database.LevelDB: paranoidChecks :: Options -> !Bool
+ Database.LevelDB: resourceForkIO :: MonadBaseControl IO m => ResourceT m () -> ResourceT m ThreadId
+ Database.LevelDB: runResourceT :: MonadBaseControl IO m => ResourceT m a -> m a
+ Database.LevelDB: sync :: WriteOptions -> !Bool
+ Database.LevelDB: useSnapshot :: ReadOptions -> !(Maybe Snapshot)
+ Database.LevelDB: verifyCheckSums :: ReadOptions -> !Bool
+ Database.LevelDB: writeBufferSize :: Options -> !Int
- Database.LevelDB: approximateSize :: DB -> Range -> IO Int64
+ Database.LevelDB: approximateSize :: MonadResource m => DB -> Range -> m Int64
- Database.LevelDB: delete :: DB -> WriteOptions -> ByteString -> IO ()
+ Database.LevelDB: delete :: MonadResource m => DB -> WriteOptions -> ByteString -> m ()
- Database.LevelDB: destroy :: FilePath -> Options -> IO ()
+ Database.LevelDB: destroy :: MonadResource m => FilePath -> Options -> m ()
- Database.LevelDB: get :: DB -> ReadOptions -> ByteString -> IO (Maybe ByteString)
+ Database.LevelDB: get :: MonadResource m => DB -> ReadOptions -> ByteString -> m (Maybe ByteString)
- Database.LevelDB: getProperty :: DB -> Property -> IO (Maybe ByteString)
+ Database.LevelDB: getProperty :: MonadResource m => DB -> Property -> m (Maybe ByteString)
- Database.LevelDB: iterFirst :: Iterator -> IO ()
+ Database.LevelDB: iterFirst :: MonadResource m => Iterator -> m ()
- Database.LevelDB: iterItems :: Iterator -> IO [(ByteString, ByteString)]
+ Database.LevelDB: iterItems :: MonadResource m => Iterator -> m [(ByteString, ByteString)]
- Database.LevelDB: iterKey :: Iterator -> IO ByteString
+ Database.LevelDB: iterKey :: MonadResource m => Iterator -> m (Maybe ByteString)
- Database.LevelDB: iterKeys :: Iterator -> IO [ByteString]
+ Database.LevelDB: iterKeys :: MonadResource m => Iterator -> m [ByteString]
- Database.LevelDB: iterLast :: Iterator -> IO ()
+ Database.LevelDB: iterLast :: MonadResource m => Iterator -> m ()
- Database.LevelDB: iterNext :: Iterator -> IO ()
+ Database.LevelDB: iterNext :: MonadResource m => Iterator -> m ()
- Database.LevelDB: iterOpen :: DB -> ReadOptions -> IO Iterator
+ Database.LevelDB: iterOpen :: MonadResource m => DB -> ReadOptions -> m Iterator
- Database.LevelDB: iterPrev :: Iterator -> IO ()
+ Database.LevelDB: iterPrev :: MonadResource m => Iterator -> m ()
- Database.LevelDB: iterSeek :: Iterator -> ByteString -> IO ()
+ Database.LevelDB: iterSeek :: MonadResource m => Iterator -> ByteString -> m ()
- Database.LevelDB: iterValid :: Iterator -> IO Bool
+ Database.LevelDB: iterValid :: MonadResource m => Iterator -> m Bool
- Database.LevelDB: iterValue :: Iterator -> IO ByteString
+ Database.LevelDB: iterValue :: MonadResource m => Iterator -> m (Maybe ByteString)
- Database.LevelDB: iterValues :: Iterator -> IO [ByteString]
+ Database.LevelDB: iterValues :: MonadResource m => Iterator -> m [ByteString]
- Database.LevelDB: mapIter :: (Iterator -> IO a) -> Iterator -> IO [a]
+ Database.LevelDB: mapIter :: MonadResource m => (Iterator -> m a) -> Iterator -> m [a]
- Database.LevelDB: put :: DB -> WriteOptions -> ByteString -> ByteString -> IO ()
+ Database.LevelDB: put :: MonadResource m => DB -> WriteOptions -> ByteString -> ByteString -> m ()
- Database.LevelDB: repair :: FilePath -> Options -> IO ()
+ Database.LevelDB: repair :: MonadResource m => FilePath -> Options -> m ()
- Database.LevelDB: withIterator :: DB -> ReadOptions -> (Iterator -> IO a) -> IO a
+ Database.LevelDB: withIterator :: MonadResource m => DB -> ReadOptions -> (Iterator -> m a) -> m a
- Database.LevelDB: withSnapshot :: DB -> (Snapshot -> IO a) -> IO a
+ Database.LevelDB: withSnapshot :: MonadResource m => DB -> (Snapshot -> m a) -> m a
- Database.LevelDB: write :: DB -> WriteOptions -> WriteBatch -> IO ()
+ Database.LevelDB: write :: MonadResource m => DB -> WriteOptions -> WriteBatch -> m ()

Files

Readme.md view
@@ -1,16 +1,36 @@ This library provides Haskell bindings to [LevelDB](http://leveldb.googlecode.com) +## History++Version 0.1.0:++* memory (foreign pointers) is managed through+  [ResourceT](http://hackage.haskell.org/package/resourcet). Note that this+  requires to lift monadic actions inside the `MonadResource` monad, see the+  examples.+* links against shared library (LevelDB v1.3 or higher)+* LevelDB 1.3 API fully supported (including custom comparators, excluding+  custom environments)++Version 0.0.x:++* experimental releases+ ## Installation  Prerequisites:  * [GHC 7.*](http://www.haskell.org/ghc)-* [Cabal](http://www.haskell.org/cabal)+* [Cabal](http://www.haskell.org/cabal), version 1.3 or higher+* [LevelDB](http://code.google.com/p/leveldb) * Optional: [Snappy](http://code.google.com/p/snappy),   if compression support is desired-* Optional: `autoconf` +**Note:** as of version 1.3, LevelDB can be built as a shared library. Thus, as+of version 0.1.0 of this library, LevelDB is no longer bundled and must be+installed on the target system.+ To install the latest version from hackage:  ```shell@@ -20,7 +40,6 @@ To install from checked-out source:  ```shell-$ autoconf $ cabal install ``` 
Setup.hs view
@@ -1,2 +1,2 @@ import Distribution.Simple-main = defaultMainWithHooks autoconfUserHooks+main = defaultMain
− cbits/leveldb/db/builder.cc
@@ -1,88 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/builder.h"--#include "db/filename.h"-#include "db/dbformat.h"-#include "db/table_cache.h"-#include "db/version_edit.h"-#include "leveldb/db.h"-#include "leveldb/env.h"-#include "leveldb/iterator.h"--namespace leveldb {--Status BuildTable(const std::string& dbname,-                  Env* env,-                  const Options& options,-                  TableCache* table_cache,-                  Iterator* iter,-                  FileMetaData* meta) {-  Status s;-  meta->file_size = 0;-  iter->SeekToFirst();--  std::string fname = TableFileName(dbname, meta->number);-  if (iter->Valid()) {-    WritableFile* file;-    s = env->NewWritableFile(fname, &file);-    if (!s.ok()) {-      return s;-    }--    TableBuilder* builder = new TableBuilder(options, file);-    meta->smallest.DecodeFrom(iter->key());-    for (; iter->Valid(); iter->Next()) {-      Slice key = iter->key();-      meta->largest.DecodeFrom(key);-      builder->Add(key, iter->value());-    }--    // Finish and check for builder errors-    if (s.ok()) {-      s = builder->Finish();-      if (s.ok()) {-        meta->file_size = builder->FileSize();-        assert(meta->file_size > 0);-      }-    } else {-      builder->Abandon();-    }-    delete builder;--    // Finish and check for file errors-    if (s.ok()) {-      s = file->Sync();-    }-    if (s.ok()) {-      s = file->Close();-    }-    delete file;-    file = NULL;--    if (s.ok()) {-      // Verify that the table is usable-      Iterator* it = table_cache->NewIterator(ReadOptions(),-                                              meta->number,-                                              meta->file_size);-      s = it->status();-      delete it;-    }-  }--  // Check for input iterator errors-  if (!iter->status().ok()) {-    s = iter->status();-  }--  if (s.ok() && meta->file_size > 0) {-    // Keep it-  } else {-    env->DeleteFile(fname);-  }-  return s;-}--}  // namespace leveldb
− cbits/leveldb/db/builder.h
@@ -1,34 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_DB_BUILDER_H_-#define STORAGE_LEVELDB_DB_BUILDER_H_--#include "leveldb/status.h"--namespace leveldb {--struct Options;-struct FileMetaData;--class Env;-class Iterator;-class TableCache;-class VersionEdit;--// Build a Table file from the contents of *iter.  The generated file-// will be named according to meta->number.  On success, the rest of-// *meta will be filled with metadata about the generated table.-// If no data is present in *iter, meta->file_size will be set to-// zero, and no Table file will be produced.-extern Status BuildTable(const std::string& dbname,-                         Env* env,-                         const Options& options,-                         TableCache* table_cache,-                         Iterator* iter,-                         FileMetaData* meta);--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_BUILDER_H_
− cbits/leveldb/db/c.cc
@@ -1,471 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "leveldb/c.h"--#include <stdlib.h>-#include <unistd.h>-#include "leveldb/cache.h"-#include "leveldb/comparator.h"-#include "leveldb/db.h"-#include "leveldb/env.h"-#include "leveldb/iterator.h"-#include "leveldb/options.h"-#include "leveldb/status.h"-#include "leveldb/write_batch.h"--using leveldb::Cache;-using leveldb::Comparator;-using leveldb::CompressionType;-using leveldb::DB;-using leveldb::Env;-using leveldb::FileLock;-using leveldb::Iterator;-using leveldb::Logger;-using leveldb::NewLRUCache;-using leveldb::Options;-using leveldb::RandomAccessFile;-using leveldb::Range;-using leveldb::ReadOptions;-using leveldb::SequentialFile;-using leveldb::Slice;-using leveldb::Snapshot;-using leveldb::Status;-using leveldb::WritableFile;-using leveldb::WriteBatch;-using leveldb::WriteOptions;--extern "C" {--struct leveldb_t              { DB*               rep; };-struct leveldb_iterator_t     { Iterator*         rep; };-struct leveldb_writebatch_t   { WriteBatch        rep; };-struct leveldb_snapshot_t     { const Snapshot*   rep; };-struct leveldb_readoptions_t  { ReadOptions       rep; };-struct leveldb_writeoptions_t { WriteOptions      rep; };-struct leveldb_options_t      { Options           rep; };-struct leveldb_cache_t        { Cache*            rep; };-struct leveldb_seqfile_t      { SequentialFile*   rep; };-struct leveldb_randomfile_t   { RandomAccessFile* rep; };-struct leveldb_writablefile_t { WritableFile*     rep; };-struct leveldb_logger_t       { Logger*           rep; };-struct leveldb_filelock_t     { FileLock*         rep; };--struct leveldb_comparator_t : public Comparator {-  void* state_;-  void (*destructor_)(void*);-  int (*compare_)(-      void*,-      const char* a, size_t alen,-      const char* b, size_t blen);-  const char* (*name_)(void*);--  virtual ~leveldb_comparator_t() {-    (*destructor_)(state_);-  }--  virtual int Compare(const Slice& a, const Slice& b) const {-    return (*compare_)(state_, a.data(), a.size(), b.data(), b.size());-  }--  virtual const char* Name() const {-    return (*name_)(state_);-  }--  // No-ops since the C binding does not support key shortening methods.-  virtual void FindShortestSeparator(std::string*, const Slice&) const { }-  virtual void FindShortSuccessor(std::string* key) const { }-};--struct leveldb_env_t {-  Env* rep;-  bool is_default;-};--static bool SaveError(char** errptr, const Status& s) {-  assert(errptr != NULL);-  if (s.ok()) {-    return false;-  } else if (*errptr == NULL) {-    *errptr = strdup(s.ToString().c_str());-  } else {-    // TODO(sanjay): Merge with existing error?-    free(*errptr);-    *errptr = strdup(s.ToString().c_str());-  }-  return true;-}--static char* CopyString(const std::string& str) {-  char* result = reinterpret_cast<char*>(malloc(sizeof(char) * str.size()));-  memcpy(result, str.data(), sizeof(char) * str.size());-  return result;-}--leveldb_t* leveldb_open(-    const leveldb_options_t* options,-    const char* name,-    char** errptr) {-  DB* db;-  if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) {-    return NULL;-  }-  leveldb_t* result = new leveldb_t;-  result->rep = db;-  return result;-}--void leveldb_close(leveldb_t* db) {-  delete db->rep;-  delete db;-}--void leveldb_put(-    leveldb_t* db,-    const leveldb_writeoptions_t* options,-    const char* key, size_t keylen,-    const char* val, size_t vallen,-    char** errptr) {-  SaveError(errptr,-            db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen)));-}--void leveldb_delete(-    leveldb_t* db,-    const leveldb_writeoptions_t* options,-    const char* key, size_t keylen,-    char** errptr) {-  SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen)));-}---void leveldb_write(-    leveldb_t* db,-    const leveldb_writeoptions_t* options,-    leveldb_writebatch_t* batch,-    char** errptr) {-  SaveError(errptr, db->rep->Write(options->rep, &batch->rep));-}--char* leveldb_get(-    leveldb_t* db,-    const leveldb_readoptions_t* options,-    const char* key, size_t keylen,-    size_t* vallen,-    char** errptr) {-  char* result = NULL;-  std::string tmp;-  Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp);-  if (s.ok()) {-    *vallen = tmp.size();-    result = CopyString(tmp);-  } else {-    *vallen = 0;-    if (!s.IsNotFound()) {-      SaveError(errptr, s);-    }-  }-  return result;-}--leveldb_iterator_t* leveldb_create_iterator(-    leveldb_t* db,-    const leveldb_readoptions_t* options) {-  leveldb_iterator_t* result = new leveldb_iterator_t;-  result->rep = db->rep->NewIterator(options->rep);-  return result;-}--const leveldb_snapshot_t* leveldb_create_snapshot(-    leveldb_t* db) {-  leveldb_snapshot_t* result = new leveldb_snapshot_t;-  result->rep = db->rep->GetSnapshot();-  return result;-}--void leveldb_release_snapshot(-    leveldb_t* db,-    const leveldb_snapshot_t* snapshot) {-  db->rep->ReleaseSnapshot(snapshot->rep);-  delete snapshot;-}--char* leveldb_property_value(-    leveldb_t* db,-    const char* propname) {-  std::string tmp;-  if (db->rep->GetProperty(Slice(propname), &tmp)) {-    // We use strdup() since we expect human readable output.-    return strdup(tmp.c_str());-  } else {-    return NULL;-  }-}--void leveldb_approximate_sizes(-    leveldb_t* db,-    int num_ranges,-    const char* const* range_start_key, const size_t* range_start_key_len,-    const char* const* range_limit_key, const size_t* range_limit_key_len,-    uint64_t* sizes) {-  Range* ranges = new Range[num_ranges];-  for (int i = 0; i < num_ranges; i++) {-    ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]);-    ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]);-  }-  db->rep->GetApproximateSizes(ranges, num_ranges, sizes);-  delete[] ranges;-}--void leveldb_destroy_db(-    const leveldb_options_t* options,-    const char* name,-    char** errptr) {-  SaveError(errptr, DestroyDB(name, options->rep));-}--void leveldb_repair_db(-    const leveldb_options_t* options,-    const char* name,-    char** errptr) {-  SaveError(errptr, RepairDB(name, options->rep));-}--void leveldb_iter_destroy(leveldb_iterator_t* iter) {-  delete iter->rep;-  delete iter;-}--unsigned char leveldb_iter_valid(const leveldb_iterator_t* iter) {-  return iter->rep->Valid();-}--void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) {-  iter->rep->SeekToFirst();-}--void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) {-  iter->rep->SeekToLast();-}--void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) {-  iter->rep->Seek(Slice(k, klen));-}--void leveldb_iter_next(leveldb_iterator_t* iter) {-  iter->rep->Next();-}--void leveldb_iter_prev(leveldb_iterator_t* iter) {-  iter->rep->Prev();-}--const char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) {-  Slice s = iter->rep->key();-  *klen = s.size();-  return s.data();-}--const char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) {-  Slice s = iter->rep->value();-  *vlen = s.size();-  return s.data();-}--void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) {-  SaveError(errptr, iter->rep->status());-}--leveldb_writebatch_t* leveldb_writebatch_create() {-  return new leveldb_writebatch_t;-}--void leveldb_writebatch_destroy(leveldb_writebatch_t* b) {-  delete b;-}--void leveldb_writebatch_clear(leveldb_writebatch_t* b) {-  b->rep.Clear();-}--void leveldb_writebatch_put(-    leveldb_writebatch_t* b,-    const char* key, size_t klen,-    const char* val, size_t vlen) {-  b->rep.Put(Slice(key, klen), Slice(val, vlen));-}--void leveldb_writebatch_delete(-    leveldb_writebatch_t* b,-    const char* key, size_t klen) {-  b->rep.Delete(Slice(key, klen));-}--void leveldb_writebatch_iterate(-    leveldb_writebatch_t* b,-    void* state,-    void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen),-    void (*deleted)(void*, const char* k, size_t klen)) {-  class H : public WriteBatch::Handler {-   public:-    void* state_;-    void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen);-    void (*deleted_)(void*, const char* k, size_t klen);-    virtual void Put(const Slice& key, const Slice& value) {-      (*put_)(state_, key.data(), key.size(), value.data(), value.size());-    }-    virtual void Delete(const Slice& key) {-      (*deleted_)(state_, key.data(), key.size());-    }-  };-  H handler;-  handler.state_ = state;-  handler.put_ = put;-  handler.deleted_ = deleted;-  b->rep.Iterate(&handler);-}--leveldb_options_t* leveldb_options_create() {-  return new leveldb_options_t;-}--void leveldb_options_destroy(leveldb_options_t* options) {-  delete options;-}--void leveldb_options_set_comparator(-    leveldb_options_t* opt,-    leveldb_comparator_t* cmp) {-  opt->rep.comparator = cmp;-}--void leveldb_options_set_create_if_missing(-    leveldb_options_t* opt, unsigned char v) {-  opt->rep.create_if_missing = v;-}--void leveldb_options_set_error_if_exists(-    leveldb_options_t* opt, unsigned char v) {-  opt->rep.error_if_exists = v;-}--void leveldb_options_set_paranoid_checks(-    leveldb_options_t* opt, unsigned char v) {-  opt->rep.paranoid_checks = v;-}--void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) {-  opt->rep.env = (env ? env->rep : NULL);-}--void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) {-  opt->rep.info_log = (l ? l->rep : NULL);-}--void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) {-  opt->rep.write_buffer_size = s;-}--void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) {-  opt->rep.max_open_files = n;-}--void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) {-  opt->rep.block_cache = c->rep;-}--void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) {-  opt->rep.block_size = s;-}--void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) {-  opt->rep.block_restart_interval = n;-}--void leveldb_options_set_compression(leveldb_options_t* opt, int t) {-  opt->rep.compression = static_cast<CompressionType>(t);-}--leveldb_comparator_t* leveldb_comparator_create(-    void* state,-    void (*destructor)(void*),-    int (*compare)(-        void*,-        const char* a, size_t alen,-        const char* b, size_t blen),-    const char* (*name)(void*)) {-  leveldb_comparator_t* result = new leveldb_comparator_t;-  result->state_ = state;-  result->destructor_ = destructor;-  result->compare_ = compare;-  result->name_ = name;-  return result;-}--void leveldb_comparator_destroy(leveldb_comparator_t* cmp) {-  delete cmp;-}--leveldb_readoptions_t* leveldb_readoptions_create() {-  return new leveldb_readoptions_t;-}--void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) {-  delete opt;-}--void leveldb_readoptions_set_verify_checksums(-    leveldb_readoptions_t* opt,-    unsigned char v) {-  opt->rep.verify_checksums = v;-}--void leveldb_readoptions_set_fill_cache(-    leveldb_readoptions_t* opt, unsigned char v) {-  opt->rep.fill_cache = v;-}--void leveldb_readoptions_set_snapshot(-    leveldb_readoptions_t* opt,-    const leveldb_snapshot_t* snap) {-  opt->rep.snapshot = (snap ? snap->rep : NULL);-}--leveldb_writeoptions_t* leveldb_writeoptions_create() {-  return new leveldb_writeoptions_t;-}--void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) {-  delete opt;-}--void leveldb_writeoptions_set_sync(-    leveldb_writeoptions_t* opt, unsigned char v) {-  opt->rep.sync = v;-}--leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) {-  leveldb_cache_t* c = new leveldb_cache_t;-  c->rep = NewLRUCache(capacity);-  return c;-}--void leveldb_cache_destroy(leveldb_cache_t* cache) {-  delete cache->rep;-  delete cache;-}--leveldb_env_t* leveldb_create_default_env() {-  leveldb_env_t* result = new leveldb_env_t;-  result->rep = Env::Default();-  result->is_default = true;-  return result;-}--void leveldb_env_destroy(leveldb_env_t* env) {-  if (!env->is_default) delete env->rep;-  delete env;-}--}  // end extern "C"
− cbits/leveldb/db/corruption_test.cc
@@ -1,359 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "leveldb/db.h"--#include <errno.h>-#include <fcntl.h>-#include <sys/stat.h>-#include <sys/types.h>-#include "leveldb/cache.h"-#include "leveldb/env.h"-#include "leveldb/table.h"-#include "leveldb/write_batch.h"-#include "db/db_impl.h"-#include "db/filename.h"-#include "db/log_format.h"-#include "db/version_set.h"-#include "util/logging.h"-#include "util/testharness.h"-#include "util/testutil.h"--namespace leveldb {--static const int kValueSize = 1000;--class CorruptionTest {- public:-  test::ErrorEnv env_;-  std::string dbname_;-  Cache* tiny_cache_;-  Options options_;-  DB* db_;--  CorruptionTest() {-    tiny_cache_ = NewLRUCache(100);-    options_.env = &env_;-    dbname_ = test::TmpDir() + "/db_test";-    DestroyDB(dbname_, options_);--    db_ = NULL;-    options_.create_if_missing = true;-    Reopen();-    options_.create_if_missing = false;-  }--  ~CorruptionTest() {-     delete db_;-     DestroyDB(dbname_, Options());-     delete tiny_cache_;-  }--  Status TryReopen(Options* options = NULL) {-    delete db_;-    db_ = NULL;-    Options opt = (options ? *options : options_);-    opt.env = &env_;-    opt.block_cache = tiny_cache_;-    return DB::Open(opt, dbname_, &db_);-  }--  void Reopen(Options* options = NULL) {-    ASSERT_OK(TryReopen(options));-  }--  void RepairDB() {-    delete db_;-    db_ = NULL;-    ASSERT_OK(::leveldb::RepairDB(dbname_, options_));-  }--  void Build(int n) {-    std::string key_space, value_space;-    WriteBatch batch;-    for (int i = 0; i < n; i++) {-      //if ((i % 100) == 0) fprintf(stderr, "@ %d of %d\n", i, n);-      Slice key = Key(i, &key_space);-      batch.Clear();-      batch.Put(key, Value(i, &value_space));-      ASSERT_OK(db_->Write(WriteOptions(), &batch));-    }-  }--  void Check(int min_expected, int max_expected) {-    int next_expected = 0;-    int missed = 0;-    int bad_keys = 0;-    int bad_values = 0;-    int correct = 0;-    std::string value_space;-    Iterator* iter = db_->NewIterator(ReadOptions());-    for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {-      uint64_t key;-      Slice in(iter->key());-      if (!ConsumeDecimalNumber(&in, &key) ||-          !in.empty() ||-          key < next_expected) {-        bad_keys++;-        continue;-      }-      missed += (key - next_expected);-      next_expected = key + 1;-      if (iter->value() != Value(key, &value_space)) {-        bad_values++;-      } else {-        correct++;-      }-    }-    delete iter;--    fprintf(stderr,-            "expected=%d..%d; got=%d; bad_keys=%d; bad_values=%d; missed=%d\n",-            min_expected, max_expected, correct, bad_keys, bad_values, missed);-    ASSERT_LE(min_expected, correct);-    ASSERT_GE(max_expected, correct);-  }--  void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) {-    // Pick file to corrupt-    std::vector<std::string> filenames;-    ASSERT_OK(env_.GetChildren(dbname_, &filenames));-    uint64_t number;-    FileType type;-    std::string fname;-    int picked_number = -1;-    for (int i = 0; i < filenames.size(); i++) {-      if (ParseFileName(filenames[i], &number, &type) &&-          type == filetype &&-          int(number) > picked_number) {  // Pick latest file-        fname = dbname_ + "/" + filenames[i];-        picked_number = number;-      }-    }-    ASSERT_TRUE(!fname.empty()) << filetype;--    struct stat sbuf;-    if (stat(fname.c_str(), &sbuf) != 0) {-      const char* msg = strerror(errno);-      ASSERT_TRUE(false) << fname << ": " << msg;-    }--    if (offset < 0) {-      // Relative to end of file; make it absolute-      if (-offset > sbuf.st_size) {-        offset = 0;-      } else {-        offset = sbuf.st_size + offset;-      }-    }-    if (offset > sbuf.st_size) {-      offset = sbuf.st_size;-    }-    if (offset + bytes_to_corrupt > sbuf.st_size) {-      bytes_to_corrupt = sbuf.st_size - offset;-    }--    // Do it-    std::string contents;-    Status s = ReadFileToString(Env::Default(), fname, &contents);-    ASSERT_TRUE(s.ok()) << s.ToString();-    for (int i = 0; i < bytes_to_corrupt; i++) {-      contents[i + offset] ^= 0x80;-    }-    s = WriteStringToFile(Env::Default(), contents, fname);-    ASSERT_TRUE(s.ok()) << s.ToString();-  }--  int Property(const std::string& name) {-    std::string property;-    int result;-    if (db_->GetProperty(name, &property) &&-        sscanf(property.c_str(), "%d", &result) == 1) {-      return result;-    } else {-      return -1;-    }-  }--  // Return the ith key-  Slice Key(int i, std::string* storage) {-    char buf[100];-    snprintf(buf, sizeof(buf), "%016d", i);-    storage->assign(buf, strlen(buf));-    return Slice(*storage);-  }--  // Return the value to associate with the specified key-  Slice Value(int k, std::string* storage) {-    Random r(k);-    return test::RandomString(&r, kValueSize, storage);-  }-};--TEST(CorruptionTest, Recovery) {-  Build(100);-  Check(100, 100);-  Corrupt(kLogFile, 19, 1);      // WriteBatch tag for first record-  Corrupt(kLogFile, log::kBlockSize + 1000, 1);  // Somewhere in second block-  Reopen();--  // The 64 records in the first two log blocks are completely lost.-  Check(36, 36);-}--TEST(CorruptionTest, RecoverWriteError) {-  env_.writable_file_error_ = true;-  Status s = TryReopen();-  ASSERT_TRUE(!s.ok());-}--TEST(CorruptionTest, NewFileErrorDuringWrite) {-  // Do enough writing to force minor compaction-  env_.writable_file_error_ = true;-  const int num = 3 + (Options().write_buffer_size / kValueSize);-  std::string value_storage;-  Status s;-  for (int i = 0; s.ok() && i < num; i++) {-    WriteBatch batch;-    batch.Put("a", Value(100, &value_storage));-    s = db_->Write(WriteOptions(), &batch);-  }-  ASSERT_TRUE(!s.ok());-  ASSERT_GE(env_.num_writable_file_errors_, 1);-  env_.writable_file_error_ = false;-  Reopen();-}--TEST(CorruptionTest, TableFile) {-  Build(100);-  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);-  dbi->TEST_CompactMemTable();-  dbi->TEST_CompactRange(0, NULL, NULL);-  dbi->TEST_CompactRange(1, NULL, NULL);--  Corrupt(kTableFile, 100, 1);-  Check(99, 99);-}--TEST(CorruptionTest, TableFileIndexData) {-  Build(10000);  // Enough to build multiple Tables-  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);-  dbi->TEST_CompactMemTable();--  Corrupt(kTableFile, -2000, 500);-  Reopen();-  Check(5000, 9999);-}--TEST(CorruptionTest, MissingDescriptor) {-  Build(1000);-  RepairDB();-  Reopen();-  Check(1000, 1000);-}--TEST(CorruptionTest, SequenceNumberRecovery) {-  ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1"));-  ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2"));-  ASSERT_OK(db_->Put(WriteOptions(), "foo", "v3"));-  ASSERT_OK(db_->Put(WriteOptions(), "foo", "v4"));-  ASSERT_OK(db_->Put(WriteOptions(), "foo", "v5"));-  RepairDB();-  Reopen();-  std::string v;-  ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));-  ASSERT_EQ("v5", v);-  // Write something.  If sequence number was not recovered properly,-  // it will be hidden by an earlier write.-  ASSERT_OK(db_->Put(WriteOptions(), "foo", "v6"));-  ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));-  ASSERT_EQ("v6", v);-  Reopen();-  ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));-  ASSERT_EQ("v6", v);-}--TEST(CorruptionTest, CorruptedDescriptor) {-  ASSERT_OK(db_->Put(WriteOptions(), "foo", "hello"));-  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);-  dbi->TEST_CompactMemTable();-  dbi->TEST_CompactRange(0, NULL, NULL);--  Corrupt(kDescriptorFile, 0, 1000);-  Status s = TryReopen();-  ASSERT_TRUE(!s.ok());--  RepairDB();-  Reopen();-  std::string v;-  ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));-  ASSERT_EQ("hello", v);-}--TEST(CorruptionTest, CompactionInputError) {-  Build(10);-  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);-  dbi->TEST_CompactMemTable();-  const int last = config::kMaxMemCompactLevel;-  ASSERT_EQ(1, Property("leveldb.num-files-at-level" + NumberToString(last)));--  Corrupt(kTableFile, 100, 1);-  Check(9, 9);--  // Force compactions by writing lots of values-  Build(10000);-  Check(10000, 10000);-}--TEST(CorruptionTest, CompactionInputErrorParanoid) {-  Options options;-  options.paranoid_checks = true;-  options.write_buffer_size = 1048576;-  Reopen(&options);-  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);--  // Fill levels >= 1 so memtable compaction outputs to level 1-  for (int level = 1; level < config::kNumLevels; level++) {-    dbi->Put(WriteOptions(), "", "begin");-    dbi->Put(WriteOptions(), "~", "end");-    dbi->TEST_CompactMemTable();-  }--  Build(10);-  dbi->TEST_CompactMemTable();-  ASSERT_EQ(1, Property("leveldb.num-files-at-level0"));--  Corrupt(kTableFile, 100, 1);-  Check(9, 9);--  // Write must eventually fail because of corrupted table-  Status s;-  std::string tmp1, tmp2;-  for (int i = 0; i < 10000 && s.ok(); i++) {-    s = db_->Put(WriteOptions(), Key(i, &tmp1), Value(i, &tmp2));-  }-  ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db";-}--TEST(CorruptionTest, UnrelatedKeys) {-  Build(10);-  DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);-  dbi->TEST_CompactMemTable();-  Corrupt(kTableFile, 100, 1);--  std::string tmp1, tmp2;-  ASSERT_OK(db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2)));-  std::string v;-  ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));-  ASSERT_EQ(Value(1000, &tmp2).ToString(), v);-  dbi->TEST_CompactMemTable();-  ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));-  ASSERT_EQ(Value(1000, &tmp2).ToString(), v);-}--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/db/db_bench.cc
@@ -1,877 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include <sys/types.h>-#include <stdio.h>-#include <stdlib.h>-#include "db/db_impl.h"-#include "db/version_set.h"-#include "leveldb/cache.h"-#include "leveldb/db.h"-#include "leveldb/env.h"-#include "leveldb/write_batch.h"-#include "port/port.h"-#include "util/crc32c.h"-#include "util/histogram.h"-#include "util/mutexlock.h"-#include "util/random.h"-#include "util/testutil.h"--// Comma-separated list of operations to run in the specified order-//   Actual benchmarks:-//      fillseq       -- write N values in sequential key order in async mode-//      fillrandom    -- write N values in random key order in async mode-//      overwrite     -- overwrite N values in random key order in async mode-//      fillsync      -- write N/100 values in random key order in sync mode-//      fill100K      -- write N/1000 100K values in random order in async mode-//      readseq       -- read N times sequentially-//      readreverse   -- read N times in reverse order-//      readrandom    -- read N times in random order-//      readhot       -- read N times in random order from 1% section of DB-//      crc32c        -- repeated crc32c of 4K of data-//      acquireload   -- load N*1000 times-//   Meta operations:-//      compact     -- Compact the entire DB-//      stats       -- Print DB stats-//      heapprofile -- Dump a heap profile (if supported by this port)-static const char* FLAGS_benchmarks =-    "fillseq,"-    "fillsync,"-    "fillrandom,"-    "overwrite,"-    "readrandom,"-    "readrandom,"  // Extra run to allow previous compactions to quiesce-    "readseq,"-    "readreverse,"-    "compact,"-    "readrandom,"-    "readseq,"-    "readreverse,"-    "fill100K,"-    "crc32c,"-    "snappycomp,"-    "snappyuncomp,"-    "acquireload,"-    ;--// Number of key/values to place in database-static int FLAGS_num = 1000000;--// Number of read operations to do.  If negative, do FLAGS_num reads.-static int FLAGS_reads = -1;--// Number of concurrent threads to run.-static int FLAGS_threads = 1;--// Size of each value-static int FLAGS_value_size = 100;--// Arrange to generate values that shrink to this fraction of-// their original size after compression-static double FLAGS_compression_ratio = 0.5;--// Print histogram of operation timings-static bool FLAGS_histogram = false;--// Number of bytes to buffer in memtable before compacting-// (initialized to default value by "main")-static int FLAGS_write_buffer_size = 0;--// Number of bytes to use as a cache of uncompressed data.-// Negative means use default settings.-static int FLAGS_cache_size = -1;--// Maximum number of files to keep open at the same time (use default if == 0)-static int FLAGS_open_files = 0;--// If true, do not destroy the existing database.  If you set this-// flag and also specify a benchmark that wants a fresh database, that-// benchmark will fail.-static bool FLAGS_use_existing_db = false;--// Use the db with the following name.-static const char* FLAGS_db = "/tmp/dbbench";--namespace leveldb {--namespace {--// Helper for quickly generating random data.-class RandomGenerator {- private:-  std::string data_;-  int pos_;-- public:-  RandomGenerator() {-    // We use a limited amount of data over and over again and ensure-    // that it is larger than the compression window (32KB), and also-    // large enough to serve all typical value sizes we want to write.-    Random rnd(301);-    std::string piece;-    while (data_.size() < 1048576) {-      // Add a short fragment that is as compressible as specified-      // by FLAGS_compression_ratio.-      test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece);-      data_.append(piece);-    }-    pos_ = 0;-  }--  Slice Generate(int len) {-    if (pos_ + len > data_.size()) {-      pos_ = 0;-      assert(len < data_.size());-    }-    pos_ += len;-    return Slice(data_.data() + pos_ - len, len);-  }-};--static Slice TrimSpace(Slice s) {-  int start = 0;-  while (start < s.size() && isspace(s[start])) {-    start++;-  }-  int limit = s.size();-  while (limit > start && isspace(s[limit-1])) {-    limit--;-  }-  return Slice(s.data() + start, limit - start);-}--static void AppendWithSpace(std::string* str, Slice msg) {-  if (msg.empty()) return;-  if (!str->empty()) {-    str->push_back(' ');-  }-  str->append(msg.data(), msg.size());-}--class Stats {- private:-  double start_;-  double finish_;-  double seconds_;-  int done_;-  int next_report_;-  int64_t bytes_;-  double last_op_finish_;-  Histogram hist_;-  std::string message_;-- public:-  Stats() { Start(); }--  void Start() {-    next_report_ = 100;-    last_op_finish_ = start_;-    hist_.Clear();-    done_ = 0;-    bytes_ = 0;-    seconds_ = 0;-    start_ = Env::Default()->NowMicros();-    finish_ = start_;-    message_.clear();-  }--  void Merge(const Stats& other) {-    hist_.Merge(other.hist_);-    done_ += other.done_;-    bytes_ += other.bytes_;-    seconds_ += other.seconds_;-    if (other.start_ < start_) start_ = other.start_;-    if (other.finish_ > finish_) finish_ = other.finish_;--    // Just keep the messages from one thread-    if (message_.empty()) message_ = other.message_;-  }--  void Stop() {-    finish_ = Env::Default()->NowMicros();-    seconds_ = (finish_ - start_) * 1e-6;-  }--  void AddMessage(Slice msg) {-    AppendWithSpace(&message_, msg);-  }--  void FinishedSingleOp() {-    if (FLAGS_histogram) {-      double now = Env::Default()->NowMicros();-      double micros = now - last_op_finish_;-      hist_.Add(micros);-      if (micros > 20000) {-        fprintf(stderr, "long op: %.1f micros%30s\r", micros, "");-        fflush(stderr);-      }-      last_op_finish_ = now;-    }--    done_++;-    if (done_ >= next_report_) {-      if      (next_report_ < 1000)   next_report_ += 100;-      else if (next_report_ < 5000)   next_report_ += 500;-      else if (next_report_ < 10000)  next_report_ += 1000;-      else if (next_report_ < 50000)  next_report_ += 5000;-      else if (next_report_ < 100000) next_report_ += 10000;-      else if (next_report_ < 500000) next_report_ += 50000;-      else                            next_report_ += 100000;-      fprintf(stderr, "... finished %d ops%30s\r", done_, "");-      fflush(stderr);-    }-  }--  void AddBytes(int64_t n) {-    bytes_ += n;-  }--  void Report(const Slice& name) {-    // Pretend at least one op was done in case we are running a benchmark-    // that does not call FinishedSingleOp().-    if (done_ < 1) done_ = 1;--    std::string extra;-    if (bytes_ > 0) {-      // Rate is computed on actual elapsed time, not the sum of per-thread-      // elapsed times.-      double elapsed = (finish_ - start_) * 1e-6;-      char rate[100];-      snprintf(rate, sizeof(rate), "%6.1f MB/s",-               (bytes_ / 1048576.0) / elapsed);-      extra = rate;-    }-    AppendWithSpace(&extra, message_);--    fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n",-            name.ToString().c_str(),-            seconds_ * 1e6 / done_,-            (extra.empty() ? "" : " "),-            extra.c_str());-    if (FLAGS_histogram) {-      fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str());-    }-    fflush(stdout);-  }-};--// State shared by all concurrent executions of the same benchmark.-struct SharedState {-  port::Mutex mu;-  port::CondVar cv;-  int total;--  // Each thread goes through the following states:-  //    (1) initializing-  //    (2) waiting for others to be initialized-  //    (3) running-  //    (4) done--  int num_initialized;-  int num_done;-  bool start;--  SharedState() : cv(&mu) { }-};--// Per-thread state for concurrent executions of the same benchmark.-struct ThreadState {-  int tid;             // 0..n-1 when running in n threads-  Random rand;         // Has different seeds for different threads-  Stats stats;-  SharedState* shared;--  ThreadState(int index)-      : tid(index),-        rand(1000 + index) {-  }-};--}  // namespace--class Benchmark {- private:-  Cache* cache_;-  DB* db_;-  int num_;-  int value_size_;-  int entries_per_batch_;-  WriteOptions write_options_;-  int reads_;-  int heap_counter_;--  void PrintHeader() {-    const int kKeySize = 16;-    PrintEnvironment();-    fprintf(stdout, "Keys:       %d bytes each\n", kKeySize);-    fprintf(stdout, "Values:     %d bytes each (%d bytes after compression)\n",-            FLAGS_value_size,-            static_cast<int>(FLAGS_value_size * FLAGS_compression_ratio + 0.5));-    fprintf(stdout, "Entries:    %d\n", num_);-    fprintf(stdout, "RawSize:    %.1f MB (estimated)\n",-            ((static_cast<int64_t>(kKeySize + FLAGS_value_size) * num_)-             / 1048576.0));-    fprintf(stdout, "FileSize:   %.1f MB (estimated)\n",-            (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_)-             / 1048576.0));-    PrintWarnings();-    fprintf(stdout, "------------------------------------------------\n");-  }--  void PrintWarnings() {-#if defined(__GNUC__) && !defined(__OPTIMIZE__)-    fprintf(stdout,-            "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n"-            );-#endif-#ifndef NDEBUG-    fprintf(stdout,-            "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");-#endif--    // See if snappy is working by attempting to compress a compressible string-    const char text[] = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";-    std::string compressed;-    if (!port::Snappy_Compress(text, sizeof(text), &compressed)) {-      fprintf(stdout, "WARNING: Snappy compression is not enabled\n");-    } else if (compressed.size() >= sizeof(text)) {-      fprintf(stdout, "WARNING: Snappy compression is not effective\n");-    }-  }--  void PrintEnvironment() {-    fprintf(stderr, "LevelDB:    version %d.%d\n",-            kMajorVersion, kMinorVersion);--#if defined(__linux)-    time_t now = time(NULL);-    fprintf(stderr, "Date:       %s", ctime(&now));  // ctime() adds newline--    FILE* cpuinfo = fopen("/proc/cpuinfo", "r");-    if (cpuinfo != NULL) {-      char line[1000];-      int num_cpus = 0;-      std::string cpu_type;-      std::string cache_size;-      while (fgets(line, sizeof(line), cpuinfo) != NULL) {-        const char* sep = strchr(line, ':');-        if (sep == NULL) {-          continue;-        }-        Slice key = TrimSpace(Slice(line, sep - 1 - line));-        Slice val = TrimSpace(Slice(sep + 1));-        if (key == "model name") {-          ++num_cpus;-          cpu_type = val.ToString();-        } else if (key == "cache size") {-          cache_size = val.ToString();-        }-      }-      fclose(cpuinfo);-      fprintf(stderr, "CPU:        %d * %s\n", num_cpus, cpu_type.c_str());-      fprintf(stderr, "CPUCache:   %s\n", cache_size.c_str());-    }-#endif-  }-- public:-  Benchmark()-  : cache_(FLAGS_cache_size >= 0 ? NewLRUCache(FLAGS_cache_size) : NULL),-    db_(NULL),-    num_(FLAGS_num),-    value_size_(FLAGS_value_size),-    entries_per_batch_(1),-    reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads),-    heap_counter_(0) {-    std::vector<std::string> files;-    Env::Default()->GetChildren(FLAGS_db, &files);-    for (int i = 0; i < files.size(); i++) {-      if (Slice(files[i]).starts_with("heap-")) {-        Env::Default()->DeleteFile(std::string(FLAGS_db) + "/" + files[i]);-      }-    }-    if (!FLAGS_use_existing_db) {-      DestroyDB(FLAGS_db, Options());-    }-  }--  ~Benchmark() {-    delete db_;-    delete cache_;-  }--  void Run() {-    PrintHeader();-    Open();--    const char* benchmarks = FLAGS_benchmarks;-    while (benchmarks != NULL) {-      const char* sep = strchr(benchmarks, ',');-      Slice name;-      if (sep == NULL) {-        name = benchmarks;-        benchmarks = NULL;-      } else {-        name = Slice(benchmarks, sep - benchmarks);-        benchmarks = sep + 1;-      }--      // Reset parameters that may be overriddden bwlow-      num_ = FLAGS_num;-      reads_ = (FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads);-      value_size_ = FLAGS_value_size;-      entries_per_batch_ = 1;-      write_options_ = WriteOptions();--      void (Benchmark::*method)(ThreadState*) = NULL;-      bool fresh_db = false;-      int num_threads = FLAGS_threads;--      if (name == Slice("fillseq")) {-        fresh_db = true;-        method = &Benchmark::WriteSeq;-      } else if (name == Slice("fillbatch")) {-        fresh_db = true;-        entries_per_batch_ = 1000;-        method = &Benchmark::WriteSeq;-      } else if (name == Slice("fillrandom")) {-        fresh_db = true;-        method = &Benchmark::WriteRandom;-      } else if (name == Slice("overwrite")) {-        fresh_db = false;-        method = &Benchmark::WriteRandom;-      } else if (name == Slice("fillsync")) {-        fresh_db = true;-        num_ /= 1000;-        write_options_.sync = true;-        method = &Benchmark::WriteRandom;-      } else if (name == Slice("fill100K")) {-        fresh_db = true;-        num_ /= 1000;-        value_size_ = 100 * 1000;-        method = &Benchmark::WriteRandom;-      } else if (name == Slice("readseq")) {-        method = &Benchmark::ReadSequential;-      } else if (name == Slice("readreverse")) {-        method = &Benchmark::ReadReverse;-      } else if (name == Slice("readrandom")) {-        method = &Benchmark::ReadRandom;-      } else if (name == Slice("readhot")) {-        method = &Benchmark::ReadHot;-      } else if (name == Slice("readrandomsmall")) {-        reads_ /= 1000;-        method = &Benchmark::ReadRandom;-      } else if (name == Slice("readwhilewriting")) {-        num_threads++;  // Add extra thread for writing-        method = &Benchmark::ReadWhileWriting;-      } else if (name == Slice("compact")) {-        method = &Benchmark::Compact;-      } else if (name == Slice("crc32c")) {-        method = &Benchmark::Crc32c;-      } else if (name == Slice("acquireload")) {-        method = &Benchmark::AcquireLoad;-      } else if (name == Slice("snappycomp")) {-        method = &Benchmark::SnappyCompress;-      } else if (name == Slice("snappyuncomp")) {-        method = &Benchmark::SnappyUncompress;-      } else if (name == Slice("heapprofile")) {-        HeapProfile();-      } else if (name == Slice("stats")) {-        PrintStats();-      } else {-        if (name != Slice()) {  // No error message for empty name-          fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str());-        }-      }--      if (fresh_db) {-        if (FLAGS_use_existing_db) {-          fprintf(stdout, "%-12s : skipped (--use_existing_db is true)\n",-                  name.ToString().c_str());-          method = NULL;-        } else {-          delete db_;-          db_ = NULL;-          DestroyDB(FLAGS_db, Options());-          Open();-        }-      }--      if (method != NULL) {-        RunBenchmark(num_threads, name, method);-      }-    }-  }-- private:-  struct ThreadArg {-    Benchmark* bm;-    SharedState* shared;-    ThreadState* thread;-    void (Benchmark::*method)(ThreadState*);-  };--  static void ThreadBody(void* v) {-    ThreadArg* arg = reinterpret_cast<ThreadArg*>(v);-    SharedState* shared = arg->shared;-    ThreadState* thread = arg->thread;-    {-      MutexLock l(&shared->mu);-      shared->num_initialized++;-      if (shared->num_initialized >= shared->total) {-        shared->cv.SignalAll();-      }-      while (!shared->start) {-        shared->cv.Wait();-      }-    }--    thread->stats.Start();-    (arg->bm->*(arg->method))(thread);-    thread->stats.Stop();--    {-      MutexLock l(&shared->mu);-      shared->num_done++;-      if (shared->num_done >= shared->total) {-        shared->cv.SignalAll();-      }-    }-  }--  void RunBenchmark(int n, Slice name,-                    void (Benchmark::*method)(ThreadState*)) {-    SharedState shared;-    shared.total = n;-    shared.num_initialized = 0;-    shared.num_done = 0;-    shared.start = false;--    ThreadArg* arg = new ThreadArg[n];-    for (int i = 0; i < n; i++) {-      arg[i].bm = this;-      arg[i].method = method;-      arg[i].shared = &shared;-      arg[i].thread = new ThreadState(i);-      arg[i].thread->shared = &shared;-      Env::Default()->StartThread(ThreadBody, &arg[i]);-    }--    shared.mu.Lock();-    while (shared.num_initialized < n) {-      shared.cv.Wait();-    }--    shared.start = true;-    shared.cv.SignalAll();-    while (shared.num_done < n) {-      shared.cv.Wait();-    }-    shared.mu.Unlock();--    for (int i = 1; i < n; i++) {-      arg[0].thread->stats.Merge(arg[i].thread->stats);-    }-    arg[0].thread->stats.Report(name);--    for (int i = 0; i < n; i++) {-      delete arg[i].thread;-    }-    delete[] arg;-  }--  void Crc32c(ThreadState* thread) {-    // Checksum about 500MB of data total-    const int size = 4096;-    const char* label = "(4K per op)";-    std::string data(size, 'x');-    int64_t bytes = 0;-    uint32_t crc = 0;-    while (bytes < 500 * 1048576) {-      crc = crc32c::Value(data.data(), size);-      thread->stats.FinishedSingleOp();-      bytes += size;-    }-    // Print so result is not dead-    fprintf(stderr, "... crc=0x%x\r", static_cast<unsigned int>(crc));--    thread->stats.AddBytes(bytes);-    thread->stats.AddMessage(label);-  }--  void AcquireLoad(ThreadState* thread) {-    int dummy;-    port::AtomicPointer ap(&dummy);-    int count = 0;-    void *ptr = NULL;-    thread->stats.AddMessage("(each op is 1000 loads)");-    while (count < 100000) {-      for (int i = 0; i < 1000; i++) {-        ptr = ap.Acquire_Load();-      }-      count++;-      thread->stats.FinishedSingleOp();-    }-    if (ptr == NULL) exit(1); // Disable unused variable warning.-  }--  void SnappyCompress(ThreadState* thread) {-    RandomGenerator gen;-    Slice input = gen.Generate(Options().block_size);-    int64_t bytes = 0;-    int64_t produced = 0;-    bool ok = true;-    std::string compressed;-    while (ok && bytes < 1024 * 1048576) {  // Compress 1G-      ok = port::Snappy_Compress(input.data(), input.size(), &compressed);-      produced += compressed.size();-      bytes += input.size();-      thread->stats.FinishedSingleOp();-    }--    if (!ok) {-      thread->stats.AddMessage("(snappy failure)");-    } else {-      char buf[100];-      snprintf(buf, sizeof(buf), "(output: %.1f%%)",-               (produced * 100.0) / bytes);-      thread->stats.AddMessage(buf);-      thread->stats.AddBytes(bytes);-    }-  }--  void SnappyUncompress(ThreadState* thread) {-    RandomGenerator gen;-    Slice input = gen.Generate(Options().block_size);-    std::string compressed;-    bool ok = port::Snappy_Compress(input.data(), input.size(), &compressed);-    int64_t bytes = 0;-    char* uncompressed = new char[input.size()];-    while (ok && bytes < 1024 * 1048576) {  // Compress 1G-      ok =  port::Snappy_Uncompress(compressed.data(), compressed.size(),-                                    uncompressed);-      bytes += input.size();-      thread->stats.FinishedSingleOp();-    }-    delete[] uncompressed;--    if (!ok) {-      thread->stats.AddMessage("(snappy failure)");-    } else {-      thread->stats.AddBytes(bytes);-    }-  }--  void Open() {-    assert(db_ == NULL);-    Options options;-    options.create_if_missing = !FLAGS_use_existing_db;-    options.block_cache = cache_;-    options.write_buffer_size = FLAGS_write_buffer_size;-    Status s = DB::Open(options, FLAGS_db, &db_);-    if (!s.ok()) {-      fprintf(stderr, "open error: %s\n", s.ToString().c_str());-      exit(1);-    }-  }--  void WriteSeq(ThreadState* thread) {-    DoWrite(thread, true);-  }--  void WriteRandom(ThreadState* thread) {-    DoWrite(thread, false);-  }--  void DoWrite(ThreadState* thread, bool seq) {-    if (num_ != FLAGS_num) {-      char msg[100];-      snprintf(msg, sizeof(msg), "(%d ops)", num_);-      thread->stats.AddMessage(msg);-    }--    RandomGenerator gen;-    WriteBatch batch;-    Status s;-    int64_t bytes = 0;-    for (int i = 0; i < num_; i += entries_per_batch_) {-      batch.Clear();-      for (int j = 0; j < entries_per_batch_; j++) {-        const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num);-        char key[100];-        snprintf(key, sizeof(key), "%016d", k);-        batch.Put(key, gen.Generate(value_size_));-        bytes += value_size_ + strlen(key);-        thread->stats.FinishedSingleOp();-      }-      s = db_->Write(write_options_, &batch);-      if (!s.ok()) {-        fprintf(stderr, "put error: %s\n", s.ToString().c_str());-        exit(1);-      }-    }-    thread->stats.AddBytes(bytes);-  }--  void ReadSequential(ThreadState* thread) {-    Iterator* iter = db_->NewIterator(ReadOptions());-    int i = 0;-    int64_t bytes = 0;-    for (iter->SeekToFirst(); i < reads_ && iter->Valid(); iter->Next()) {-      bytes += iter->key().size() + iter->value().size();-      thread->stats.FinishedSingleOp();-      ++i;-    }-    delete iter;-    thread->stats.AddBytes(bytes);-  }--  void ReadReverse(ThreadState* thread) {-    Iterator* iter = db_->NewIterator(ReadOptions());-    int i = 0;-    int64_t bytes = 0;-    for (iter->SeekToLast(); i < reads_ && iter->Valid(); iter->Prev()) {-      bytes += iter->key().size() + iter->value().size();-      thread->stats.FinishedSingleOp();-      ++i;-    }-    delete iter;-    thread->stats.AddBytes(bytes);-  }--  void ReadRandom(ThreadState* thread) {-    ReadOptions options;-    std::string value;-    for (int i = 0; i < reads_; i++) {-      char key[100];-      const int k = thread->rand.Next() % FLAGS_num;-      snprintf(key, sizeof(key), "%016d", k);-      db_->Get(options, key, &value);-      thread->stats.FinishedSingleOp();-    }-  }--  void ReadHot(ThreadState* thread) {-    ReadOptions options;-    std::string value;-    const int range = (FLAGS_num + 99) / 100;-    for (int i = 0; i < reads_; i++) {-      char key[100];-      const int k = thread->rand.Next() % range;-      snprintf(key, sizeof(key), "%016d", k);-      db_->Get(options, key, &value);-      thread->stats.FinishedSingleOp();-    }-  }--  void ReadWhileWriting(ThreadState* thread) {-    if (thread->tid > 0) {-      ReadRandom(thread);-    } else {-      // Special thread that keeps writing until other threads are done.-      RandomGenerator gen;-      while (true) {-        {-          MutexLock l(&thread->shared->mu);-          if (thread->shared->num_done + 1 >= thread->shared->num_initialized) {-            // Other threads have finished-            break;-          }-        }--        const int k = thread->rand.Next() % FLAGS_num;-        char key[100];-        snprintf(key, sizeof(key), "%016d", k);-        Status s = db_->Put(write_options_, key, gen.Generate(value_size_));-        if (!s.ok()) {-          fprintf(stderr, "put error: %s\n", s.ToString().c_str());-          exit(1);-        }-      }--      // Do not count any of the preceding work/delay in stats.-      thread->stats.Start();-    }-  }--  void Compact(ThreadState* thread) {-    db_->CompactRange(NULL, NULL);-  }--  void PrintStats() {-    std::string stats;-    if (!db_->GetProperty("leveldb.stats", &stats)) {-      stats = "(failed)";-    }-    fprintf(stdout, "\n%s\n", stats.c_str());-  }--  static void WriteToFile(void* arg, const char* buf, int n) {-    reinterpret_cast<WritableFile*>(arg)->Append(Slice(buf, n));-  }--  void HeapProfile() {-    char fname[100];-    snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db, ++heap_counter_);-    WritableFile* file;-    Status s = Env::Default()->NewWritableFile(fname, &file);-    if (!s.ok()) {-      fprintf(stderr, "%s\n", s.ToString().c_str());-      return;-    }-    bool ok = port::GetHeapProfile(WriteToFile, file);-    delete file;-    if (!ok) {-      fprintf(stderr, "heap profiling not supported\n");-      Env::Default()->DeleteFile(fname);-    }-  }-};--}  // namespace leveldb--int main(int argc, char** argv) {-  FLAGS_write_buffer_size = leveldb::Options().write_buffer_size;-  FLAGS_open_files = leveldb::Options().max_open_files;--  for (int i = 1; i < argc; i++) {-    double d;-    int n;-    char junk;-    if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) {-      FLAGS_benchmarks = argv[i] + strlen("--benchmarks=");-    } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) {-      FLAGS_compression_ratio = d;-    } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 &&-               (n == 0 || n == 1)) {-      FLAGS_histogram = n;-    } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 &&-               (n == 0 || n == 1)) {-      FLAGS_use_existing_db = n;-    } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) {-      FLAGS_num = n;-    } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) {-      FLAGS_reads = n;-    } else if (sscanf(argv[i], "--threads=%d%c", &n, &junk) == 1) {-      FLAGS_threads = n;-    } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) {-      FLAGS_value_size = n;-    } else if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) {-      FLAGS_write_buffer_size = n;-    } else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) {-      FLAGS_cache_size = n;-    } else if (sscanf(argv[i], "--open_files=%d%c", &n, &junk) == 1) {-      FLAGS_open_files = n;-    } else if (strncmp(argv[i], "--db=", 5) == 0) {-      FLAGS_db = argv[i] + 5;-    } else {-      fprintf(stderr, "Invalid flag '%s'\n", argv[i]);-      exit(1);-    }-  }--  leveldb::Benchmark benchmark;-  benchmark.Run();-  return 0;-}
− cbits/leveldb/db/db_impl.cc
@@ -1,1444 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/db_impl.h"--#include <algorithm>-#include <set>-#include <string>-#include <stdint.h>-#include <stdio.h>-#include <vector>-#include "db/builder.h"-#include "db/db_iter.h"-#include "db/dbformat.h"-#include "db/filename.h"-#include "db/log_reader.h"-#include "db/log_writer.h"-#include "db/memtable.h"-#include "db/table_cache.h"-#include "db/version_set.h"-#include "db/write_batch_internal.h"-#include "leveldb/db.h"-#include "leveldb/env.h"-#include "leveldb/status.h"-#include "leveldb/table.h"-#include "leveldb/table_builder.h"-#include "port/port.h"-#include "table/block.h"-#include "table/merger.h"-#include "table/two_level_iterator.h"-#include "util/coding.h"-#include "util/logging.h"-#include "util/mutexlock.h"--namespace leveldb {--// Information kept for every waiting writer-struct DBImpl::Writer {-  Status status;-  WriteBatch* batch;-  bool sync;-  bool done;-  port::CondVar cv;--  explicit Writer(port::Mutex* mu) : cv(mu) { }-};--struct DBImpl::CompactionState {-  Compaction* const compaction;--  // Sequence numbers < smallest_snapshot are not significant since we-  // will never have to service a snapshot below smallest_snapshot.-  // Therefore if we have seen a sequence number S <= smallest_snapshot,-  // we can drop all entries for the same key with sequence numbers < S.-  SequenceNumber smallest_snapshot;--  // Files produced by compaction-  struct Output {-    uint64_t number;-    uint64_t file_size;-    InternalKey smallest, largest;-  };-  std::vector<Output> outputs;--  // State kept for output being generated-  WritableFile* outfile;-  TableBuilder* builder;--  uint64_t total_bytes;--  Output* current_output() { return &outputs[outputs.size()-1]; }--  explicit CompactionState(Compaction* c)-      : compaction(c),-        outfile(NULL),-        builder(NULL),-        total_bytes(0) {-  }-};--// Fix user-supplied options to be reasonable-template <class T,class V>-static void ClipToRange(T* ptr, V minvalue, V maxvalue) {-  if (static_cast<V>(*ptr) > maxvalue) *ptr = maxvalue;-  if (static_cast<V>(*ptr) < minvalue) *ptr = minvalue;-}-Options SanitizeOptions(const std::string& dbname,-                        const InternalKeyComparator* icmp,-                        const Options& src) {-  Options result = src;-  result.comparator = icmp;-  ClipToRange(&result.max_open_files,           20,     50000);-  ClipToRange(&result.write_buffer_size,        64<<10, 1<<30);-  ClipToRange(&result.block_size,               1<<10,  4<<20);-  if (result.info_log == NULL) {-    // Open a log file in the same directory as the db-    src.env->CreateDir(dbname);  // In case it does not exist-    src.env->RenameFile(InfoLogFileName(dbname), OldInfoLogFileName(dbname));-    Status s = src.env->NewLogger(InfoLogFileName(dbname), &result.info_log);-    if (!s.ok()) {-      // No place suitable for logging-      result.info_log = NULL;-    }-  }-  if (result.block_cache == NULL) {-    result.block_cache = NewLRUCache(8 << 20);-  }-  return result;-}--DBImpl::DBImpl(const Options& options, const std::string& dbname)-    : env_(options.env),-      internal_comparator_(options.comparator),-      options_(SanitizeOptions(dbname, &internal_comparator_, options)),-      owns_info_log_(options_.info_log != options.info_log),-      owns_cache_(options_.block_cache != options.block_cache),-      dbname_(dbname),-      db_lock_(NULL),-      shutting_down_(NULL),-      bg_cv_(&mutex_),-      mem_(new MemTable(internal_comparator_)),-      imm_(NULL),-      logfile_(NULL),-      logfile_number_(0),-      log_(NULL),-      tmp_batch_(new WriteBatch),-      bg_compaction_scheduled_(false),-      manual_compaction_(NULL) {-  mem_->Ref();-  has_imm_.Release_Store(NULL);--  // Reserve ten files or so for other uses and give the rest to TableCache.-  const int table_cache_size = options.max_open_files - 10;-  table_cache_ = new TableCache(dbname_, &options_, table_cache_size);--  versions_ = new VersionSet(dbname_, &options_, table_cache_,-                             &internal_comparator_);-}--DBImpl::~DBImpl() {-  // Wait for background work to finish-  mutex_.Lock();-  shutting_down_.Release_Store(this);  // Any non-NULL value is ok-  while (bg_compaction_scheduled_) {-    bg_cv_.Wait();-  }-  mutex_.Unlock();--  if (db_lock_ != NULL) {-    env_->UnlockFile(db_lock_);-  }--  delete versions_;-  if (mem_ != NULL) mem_->Unref();-  if (imm_ != NULL) imm_->Unref();-  delete tmp_batch_;-  delete log_;-  delete logfile_;-  delete table_cache_;--  if (owns_info_log_) {-    delete options_.info_log;-  }-  if (owns_cache_) {-    delete options_.block_cache;-  }-}--Status DBImpl::NewDB() {-  VersionEdit new_db;-  new_db.SetComparatorName(user_comparator()->Name());-  new_db.SetLogNumber(0);-  new_db.SetNextFile(2);-  new_db.SetLastSequence(0);--  const std::string manifest = DescriptorFileName(dbname_, 1);-  WritableFile* file;-  Status s = env_->NewWritableFile(manifest, &file);-  if (!s.ok()) {-    return s;-  }-  {-    log::Writer log(file);-    std::string record;-    new_db.EncodeTo(&record);-    s = log.AddRecord(record);-    if (s.ok()) {-      s = file->Close();-    }-  }-  delete file;-  if (s.ok()) {-    // Make "CURRENT" file that points to the new manifest file.-    s = SetCurrentFile(env_, dbname_, 1);-  } else {-    env_->DeleteFile(manifest);-  }-  return s;-}--void DBImpl::MaybeIgnoreError(Status* s) const {-  if (s->ok() || options_.paranoid_checks) {-    // No change needed-  } else {-    Log(options_.info_log, "Ignoring error %s", s->ToString().c_str());-    *s = Status::OK();-  }-}--void DBImpl::DeleteObsoleteFiles() {-  // Make a set of all of the live files-  std::set<uint64_t> live = pending_outputs_;-  versions_->AddLiveFiles(&live);--  std::vector<std::string> filenames;-  env_->GetChildren(dbname_, &filenames); // Ignoring errors on purpose-  uint64_t number;-  FileType type;-  for (size_t i = 0; i < filenames.size(); i++) {-    if (ParseFileName(filenames[i], &number, &type)) {-      bool keep = true;-      switch (type) {-        case kLogFile:-          keep = ((number >= versions_->LogNumber()) ||-                  (number == versions_->PrevLogNumber()));-          break;-        case kDescriptorFile:-          // Keep my manifest file, and any newer incarnations'-          // (in case there is a race that allows other incarnations)-          keep = (number >= versions_->ManifestFileNumber());-          break;-        case kTableFile:-          keep = (live.find(number) != live.end());-          break;-        case kTempFile:-          // Any temp files that are currently being written to must-          // be recorded in pending_outputs_, which is inserted into "live"-          keep = (live.find(number) != live.end());-          break;-        case kCurrentFile:-        case kDBLockFile:-        case kInfoLogFile:-          keep = true;-          break;-      }--      if (!keep) {-        if (type == kTableFile) {-          table_cache_->Evict(number);-        }-        Log(options_.info_log, "Delete type=%d #%lld\n",-            int(type),-            static_cast<unsigned long long>(number));-        env_->DeleteFile(dbname_ + "/" + filenames[i]);-      }-    }-  }-}--Status DBImpl::Recover(VersionEdit* edit) {-  mutex_.AssertHeld();--  // Ignore error from CreateDir since the creation of the DB is-  // committed only when the descriptor is created, and this directory-  // may already exist from a previous failed creation attempt.-  env_->CreateDir(dbname_);-  assert(db_lock_ == NULL);-  Status s = env_->LockFile(LockFileName(dbname_), &db_lock_);-  if (!s.ok()) {-    return s;-  }--  if (!env_->FileExists(CurrentFileName(dbname_))) {-    if (options_.create_if_missing) {-      s = NewDB();-      if (!s.ok()) {-        return s;-      }-    } else {-      return Status::InvalidArgument(-          dbname_, "does not exist (create_if_missing is false)");-    }-  } else {-    if (options_.error_if_exists) {-      return Status::InvalidArgument(-          dbname_, "exists (error_if_exists is true)");-    }-  }--  s = versions_->Recover();-  if (s.ok()) {-    SequenceNumber max_sequence(0);--    // Recover from all newer log files than the ones named in the-    // descriptor (new log files may have been added by the previous-    // incarnation without registering them in the descriptor).-    //-    // Note that PrevLogNumber() is no longer used, but we pay-    // attention to it in case we are recovering a database-    // produced by an older version of leveldb.-    const uint64_t min_log = versions_->LogNumber();-    const uint64_t prev_log = versions_->PrevLogNumber();-    std::vector<std::string> filenames;-    s = env_->GetChildren(dbname_, &filenames);-    if (!s.ok()) {-      return s;-    }-    uint64_t number;-    FileType type;-    std::vector<uint64_t> logs;-    for (size_t i = 0; i < filenames.size(); i++) {-      if (ParseFileName(filenames[i], &number, &type)-          && type == kLogFile-          && ((number >= min_log) || (number == prev_log))) {-        logs.push_back(number);-      }-    }--    // Recover in the order in which the logs were generated-    std::sort(logs.begin(), logs.end());-    for (size_t i = 0; i < logs.size(); i++) {-      s = RecoverLogFile(logs[i], edit, &max_sequence);--      // The previous incarnation may not have written any MANIFEST-      // records after allocating this log number.  So we manually-      // update the file number allocation counter in VersionSet.-      versions_->MarkFileNumberUsed(logs[i]);-    }--    if (s.ok()) {-      if (versions_->LastSequence() < max_sequence) {-        versions_->SetLastSequence(max_sequence);-      }-    }-  }--  return s;-}--Status DBImpl::RecoverLogFile(uint64_t log_number,-                              VersionEdit* edit,-                              SequenceNumber* max_sequence) {-  struct LogReporter : public log::Reader::Reporter {-    Env* env;-    Logger* info_log;-    const char* fname;-    Status* status;  // NULL if options_.paranoid_checks==false-    virtual void Corruption(size_t bytes, const Status& s) {-      Log(info_log, "%s%s: dropping %d bytes; %s",-          (this->status == NULL ? "(ignoring error) " : ""),-          fname, static_cast<int>(bytes), s.ToString().c_str());-      if (this->status != NULL && this->status->ok()) *this->status = s;-    }-  };--  mutex_.AssertHeld();--  // Open the log file-  std::string fname = LogFileName(dbname_, log_number);-  SequentialFile* file;-  Status status = env_->NewSequentialFile(fname, &file);-  if (!status.ok()) {-    MaybeIgnoreError(&status);-    return status;-  }--  // Create the log reader.-  LogReporter reporter;-  reporter.env = env_;-  reporter.info_log = options_.info_log;-  reporter.fname = fname.c_str();-  reporter.status = (options_.paranoid_checks ? &status : NULL);-  // We intentially make log::Reader do checksumming even if-  // paranoid_checks==false so that corruptions cause entire commits-  // to be skipped instead of propagating bad information (like overly-  // large sequence numbers).-  log::Reader reader(file, &reporter, true/*checksum*/,-                     0/*initial_offset*/);-  Log(options_.info_log, "Recovering log #%llu",-      (unsigned long long) log_number);--  // Read all the records and add to a memtable-  std::string scratch;-  Slice record;-  WriteBatch batch;-  MemTable* mem = NULL;-  while (reader.ReadRecord(&record, &scratch) &&-         status.ok()) {-    if (record.size() < 12) {-      reporter.Corruption(-          record.size(), Status::Corruption("log record too small"));-      continue;-    }-    WriteBatchInternal::SetContents(&batch, record);--    if (mem == NULL) {-      mem = new MemTable(internal_comparator_);-      mem->Ref();-    }-    status = WriteBatchInternal::InsertInto(&batch, mem);-    MaybeIgnoreError(&status);-    if (!status.ok()) {-      break;-    }-    const SequenceNumber last_seq =-        WriteBatchInternal::Sequence(&batch) +-        WriteBatchInternal::Count(&batch) - 1;-    if (last_seq > *max_sequence) {-      *max_sequence = last_seq;-    }--    if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) {-      status = WriteLevel0Table(mem, edit, NULL);-      if (!status.ok()) {-        // Reflect errors immediately so that conditions like full-        // file-systems cause the DB::Open() to fail.-        break;-      }-      mem->Unref();-      mem = NULL;-    }-  }--  if (status.ok() && mem != NULL) {-    status = WriteLevel0Table(mem, edit, NULL);-    // Reflect errors immediately so that conditions like full-    // file-systems cause the DB::Open() to fail.-  }--  if (mem != NULL) mem->Unref();-  delete file;-  return status;-}--Status DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit,-                                Version* base) {-  mutex_.AssertHeld();-  const uint64_t start_micros = env_->NowMicros();-  FileMetaData meta;-  meta.number = versions_->NewFileNumber();-  pending_outputs_.insert(meta.number);-  Iterator* iter = mem->NewIterator();-  Log(options_.info_log, "Level-0 table #%llu: started",-      (unsigned long long) meta.number);--  Status s;-  {-    mutex_.Unlock();-    s = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta);-    mutex_.Lock();-  }--  Log(options_.info_log, "Level-0 table #%llu: %lld bytes %s",-      (unsigned long long) meta.number,-      (unsigned long long) meta.file_size,-      s.ToString().c_str());-  delete iter;-  pending_outputs_.erase(meta.number);---  // Note that if file_size is zero, the file has been deleted and-  // should not be added to the manifest.-  int level = 0;-  if (s.ok() && meta.file_size > 0) {-    const Slice min_user_key = meta.smallest.user_key();-    const Slice max_user_key = meta.largest.user_key();-    if (base != NULL) {-      level = base->PickLevelForMemTableOutput(min_user_key, max_user_key);-    }-    edit->AddFile(level, meta.number, meta.file_size,-                  meta.smallest, meta.largest);-  }--  CompactionStats stats;-  stats.micros = env_->NowMicros() - start_micros;-  stats.bytes_written = meta.file_size;-  stats_[level].Add(stats);-  return s;-}--Status DBImpl::CompactMemTable() {-  mutex_.AssertHeld();-  assert(imm_ != NULL);--  // Save the contents of the memtable as a new Table-  VersionEdit edit;-  Version* base = versions_->current();-  base->Ref();-  Status s = WriteLevel0Table(imm_, &edit, base);-  base->Unref();--  if (s.ok() && shutting_down_.Acquire_Load()) {-    s = Status::IOError("Deleting DB during memtable compaction");-  }--  // Replace immutable memtable with the generated Table-  if (s.ok()) {-    edit.SetPrevLogNumber(0);-    edit.SetLogNumber(logfile_number_);  // Earlier logs no longer needed-    s = versions_->LogAndApply(&edit, &mutex_);-  }--  if (s.ok()) {-    // Commit to the new state-    imm_->Unref();-    imm_ = NULL;-    has_imm_.Release_Store(NULL);-    DeleteObsoleteFiles();-  }--  return s;-}--void DBImpl::CompactRange(const Slice* begin, const Slice* end) {-  int max_level_with_files = 1;-  {-    MutexLock l(&mutex_);-    Version* base = versions_->current();-    for (int level = 1; level < config::kNumLevels; level++) {-      if (base->OverlapInLevel(level, begin, end)) {-        max_level_with_files = level;-      }-    }-  }-  TEST_CompactMemTable(); // TODO(sanjay): Skip if memtable does not overlap-  for (int level = 0; level < max_level_with_files; level++) {-    TEST_CompactRange(level, begin, end);-  }-}--void DBImpl::TEST_CompactRange(int level, const Slice* begin,const Slice* end) {-  assert(level >= 0);-  assert(level + 1 < config::kNumLevels);--  InternalKey begin_storage, end_storage;--  ManualCompaction manual;-  manual.level = level;-  manual.done = false;-  if (begin == NULL) {-    manual.begin = NULL;-  } else {-    begin_storage = InternalKey(*begin, kMaxSequenceNumber, kValueTypeForSeek);-    manual.begin = &begin_storage;-  }-  if (end == NULL) {-    manual.end = NULL;-  } else {-    end_storage = InternalKey(*end, 0, static_cast<ValueType>(0));-    manual.end = &end_storage;-  }--  MutexLock l(&mutex_);-  while (!manual.done) {-    while (manual_compaction_ != NULL) {-      bg_cv_.Wait();-    }-    manual_compaction_ = &manual;-    MaybeScheduleCompaction();-    while (manual_compaction_ == &manual) {-      bg_cv_.Wait();-    }-  }-}--Status DBImpl::TEST_CompactMemTable() {-  // NULL batch means just wait for earlier writes to be done-  Status s = Write(WriteOptions(), NULL);-  if (s.ok()) {-    // Wait until the compaction completes-    MutexLock l(&mutex_);-    while (imm_ != NULL && bg_error_.ok()) {-      bg_cv_.Wait();-    }-    if (imm_ != NULL) {-      s = bg_error_;-    }-  }-  return s;-}--void DBImpl::MaybeScheduleCompaction() {-  mutex_.AssertHeld();-  if (bg_compaction_scheduled_) {-    // Already scheduled-  } else if (shutting_down_.Acquire_Load()) {-    // DB is being deleted; no more background compactions-  } else if (imm_ == NULL &&-             manual_compaction_ == NULL &&-             !versions_->NeedsCompaction()) {-    // No work to be done-  } else {-    bg_compaction_scheduled_ = true;-    env_->Schedule(&DBImpl::BGWork, this);-  }-}--void DBImpl::BGWork(void* db) {-  reinterpret_cast<DBImpl*>(db)->BackgroundCall();-}--void DBImpl::BackgroundCall() {-  MutexLock l(&mutex_);-  assert(bg_compaction_scheduled_);-  if (!shutting_down_.Acquire_Load()) {-    BackgroundCompaction();-  }-  bg_compaction_scheduled_ = false;--  // Previous compaction may have produced too many files in a level,-  // so reschedule another compaction if needed.-  MaybeScheduleCompaction();-  bg_cv_.SignalAll();-}--void DBImpl::BackgroundCompaction() {-  mutex_.AssertHeld();--  if (imm_ != NULL) {-    CompactMemTable();-    return;-  }--  Compaction* c;-  bool is_manual = (manual_compaction_ != NULL);-  InternalKey manual_end;-  if (is_manual) {-    ManualCompaction* m = manual_compaction_;-    c = versions_->CompactRange(m->level, m->begin, m->end);-    m->done = (c == NULL);-    if (c != NULL) {-      manual_end = c->input(0, c->num_input_files(0) - 1)->largest;-    }-    Log(options_.info_log,-        "Manual compaction at level-%d from %s .. %s; will stop at %s\n",-        m->level,-        (m->begin ? m->begin->DebugString().c_str() : "(begin)"),-        (m->end ? m->end->DebugString().c_str() : "(end)"),-        (m->done ? "(end)" : manual_end.DebugString().c_str()));-  } else {-    c = versions_->PickCompaction();-  }--  Status status;-  if (c == NULL) {-    // Nothing to do-  } else if (!is_manual && c->IsTrivialMove()) {-    // Move file to next level-    assert(c->num_input_files(0) == 1);-    FileMetaData* f = c->input(0, 0);-    c->edit()->DeleteFile(c->level(), f->number);-    c->edit()->AddFile(c->level() + 1, f->number, f->file_size,-                       f->smallest, f->largest);-    status = versions_->LogAndApply(c->edit(), &mutex_);-    VersionSet::LevelSummaryStorage tmp;-    Log(options_.info_log, "Moved #%lld to level-%d %lld bytes %s: %s\n",-        static_cast<unsigned long long>(f->number),-        c->level() + 1,-        static_cast<unsigned long long>(f->file_size),-        status.ToString().c_str(),-        versions_->LevelSummary(&tmp));-  } else {-    CompactionState* compact = new CompactionState(c);-    status = DoCompactionWork(compact);-    CleanupCompaction(compact);-    c->ReleaseInputs();-    DeleteObsoleteFiles();-  }-  delete c;--  if (status.ok()) {-    // Done-  } else if (shutting_down_.Acquire_Load()) {-    // Ignore compaction errors found during shutting down-  } else {-    Log(options_.info_log,-        "Compaction error: %s", status.ToString().c_str());-    if (options_.paranoid_checks && bg_error_.ok()) {-      bg_error_ = status;-    }-  }--  if (is_manual) {-    ManualCompaction* m = manual_compaction_;-    if (!status.ok()) {-      m->done = true;-    }-    if (!m->done) {-      // We only compacted part of the requested range.  Update *m-      // to the range that is left to be compacted.-      m->tmp_storage = manual_end;-      m->begin = &m->tmp_storage;-    }-    manual_compaction_ = NULL;-  }-}--void DBImpl::CleanupCompaction(CompactionState* compact) {-  mutex_.AssertHeld();-  if (compact->builder != NULL) {-    // May happen if we get a shutdown call in the middle of compaction-    compact->builder->Abandon();-    delete compact->builder;-  } else {-    assert(compact->outfile == NULL);-  }-  delete compact->outfile;-  for (size_t i = 0; i < compact->outputs.size(); i++) {-    const CompactionState::Output& out = compact->outputs[i];-    pending_outputs_.erase(out.number);-  }-  delete compact;-}--Status DBImpl::OpenCompactionOutputFile(CompactionState* compact) {-  assert(compact != NULL);-  assert(compact->builder == NULL);-  uint64_t file_number;-  {-    mutex_.Lock();-    file_number = versions_->NewFileNumber();-    pending_outputs_.insert(file_number);-    CompactionState::Output out;-    out.number = file_number;-    out.smallest.Clear();-    out.largest.Clear();-    compact->outputs.push_back(out);-    mutex_.Unlock();-  }--  // Make the output file-  std::string fname = TableFileName(dbname_, file_number);-  Status s = env_->NewWritableFile(fname, &compact->outfile);-  if (s.ok()) {-    compact->builder = new TableBuilder(options_, compact->outfile);-  }-  return s;-}--Status DBImpl::FinishCompactionOutputFile(CompactionState* compact,-                                          Iterator* input) {-  assert(compact != NULL);-  assert(compact->outfile != NULL);-  assert(compact->builder != NULL);--  const uint64_t output_number = compact->current_output()->number;-  assert(output_number != 0);--  // Check for iterator errors-  Status s = input->status();-  const uint64_t current_entries = compact->builder->NumEntries();-  if (s.ok()) {-    s = compact->builder->Finish();-  } else {-    compact->builder->Abandon();-  }-  const uint64_t current_bytes = compact->builder->FileSize();-  compact->current_output()->file_size = current_bytes;-  compact->total_bytes += current_bytes;-  delete compact->builder;-  compact->builder = NULL;--  // Finish and check for file errors-  if (s.ok()) {-    s = compact->outfile->Sync();-  }-  if (s.ok()) {-    s = compact->outfile->Close();-  }-  delete compact->outfile;-  compact->outfile = NULL;--  if (s.ok() && current_entries > 0) {-    // Verify that the table is usable-    Iterator* iter = table_cache_->NewIterator(ReadOptions(),-                                               output_number,-                                               current_bytes);-    s = iter->status();-    delete iter;-    if (s.ok()) {-      Log(options_.info_log,-          "Generated table #%llu: %lld keys, %lld bytes",-          (unsigned long long) output_number,-          (unsigned long long) current_entries,-          (unsigned long long) current_bytes);-    }-  }-  return s;-}---Status DBImpl::InstallCompactionResults(CompactionState* compact) {-  mutex_.AssertHeld();-  Log(options_.info_log,  "Compacted %d@%d + %d@%d files => %lld bytes",-      compact->compaction->num_input_files(0),-      compact->compaction->level(),-      compact->compaction->num_input_files(1),-      compact->compaction->level() + 1,-      static_cast<long long>(compact->total_bytes));--  // Add compaction outputs-  compact->compaction->AddInputDeletions(compact->compaction->edit());-  const int level = compact->compaction->level();-  for (size_t i = 0; i < compact->outputs.size(); i++) {-    const CompactionState::Output& out = compact->outputs[i];-    compact->compaction->edit()->AddFile(-        level + 1,-        out.number, out.file_size, out.smallest, out.largest);-  }-  return versions_->LogAndApply(compact->compaction->edit(), &mutex_);-}--Status DBImpl::DoCompactionWork(CompactionState* compact) {-  const uint64_t start_micros = env_->NowMicros();-  int64_t imm_micros = 0;  // Micros spent doing imm_ compactions--  Log(options_.info_log,  "Compacting %d@%d + %d@%d files",-      compact->compaction->num_input_files(0),-      compact->compaction->level(),-      compact->compaction->num_input_files(1),-      compact->compaction->level() + 1);--  assert(versions_->NumLevelFiles(compact->compaction->level()) > 0);-  assert(compact->builder == NULL);-  assert(compact->outfile == NULL);-  if (snapshots_.empty()) {-    compact->smallest_snapshot = versions_->LastSequence();-  } else {-    compact->smallest_snapshot = snapshots_.oldest()->number_;-  }--  // Release mutex while we're actually doing the compaction work-  mutex_.Unlock();--  Iterator* input = versions_->MakeInputIterator(compact->compaction);-  input->SeekToFirst();-  Status status;-  ParsedInternalKey ikey;-  std::string current_user_key;-  bool has_current_user_key = false;-  SequenceNumber last_sequence_for_key = kMaxSequenceNumber;-  for (; input->Valid() && !shutting_down_.Acquire_Load(); ) {-    // Prioritize immutable compaction work-    if (has_imm_.NoBarrier_Load() != NULL) {-      const uint64_t imm_start = env_->NowMicros();-      mutex_.Lock();-      if (imm_ != NULL) {-        CompactMemTable();-        bg_cv_.SignalAll();  // Wakeup MakeRoomForWrite() if necessary-      }-      mutex_.Unlock();-      imm_micros += (env_->NowMicros() - imm_start);-    }--    Slice key = input->key();-    if (compact->compaction->ShouldStopBefore(key) &&-        compact->builder != NULL) {-      status = FinishCompactionOutputFile(compact, input);-      if (!status.ok()) {-        break;-      }-    }--    // Handle key/value, add to state, etc.-    bool drop = false;-    if (!ParseInternalKey(key, &ikey)) {-      // Do not hide error keys-      current_user_key.clear();-      has_current_user_key = false;-      last_sequence_for_key = kMaxSequenceNumber;-    } else {-      if (!has_current_user_key ||-          user_comparator()->Compare(ikey.user_key,-                                     Slice(current_user_key)) != 0) {-        // First occurrence of this user key-        current_user_key.assign(ikey.user_key.data(), ikey.user_key.size());-        has_current_user_key = true;-        last_sequence_for_key = kMaxSequenceNumber;-      }--      if (last_sequence_for_key <= compact->smallest_snapshot) {-        // Hidden by an newer entry for same user key-        drop = true;    // (A)-      } else if (ikey.type == kTypeDeletion &&-                 ikey.sequence <= compact->smallest_snapshot &&-                 compact->compaction->IsBaseLevelForKey(ikey.user_key)) {-        // For this user key:-        // (1) there is no data in higher levels-        // (2) data in lower levels will have larger sequence numbers-        // (3) data in layers that are being compacted here and have-        //     smaller sequence numbers will be dropped in the next-        //     few iterations of this loop (by rule (A) above).-        // Therefore this deletion marker is obsolete and can be dropped.-        drop = true;-      }--      last_sequence_for_key = ikey.sequence;-    }-#if 0-    Log(options_.info_log,-        "  Compact: %s, seq %d, type: %d %d, drop: %d, is_base: %d, "-        "%d smallest_snapshot: %d",-        ikey.user_key.ToString().c_str(),-        (int)ikey.sequence, ikey.type, kTypeValue, drop,-        compact->compaction->IsBaseLevelForKey(ikey.user_key),-        (int)last_sequence_for_key, (int)compact->smallest_snapshot);-#endif--    if (!drop) {-      // Open output file if necessary-      if (compact->builder == NULL) {-        status = OpenCompactionOutputFile(compact);-        if (!status.ok()) {-          break;-        }-      }-      if (compact->builder->NumEntries() == 0) {-        compact->current_output()->smallest.DecodeFrom(key);-      }-      compact->current_output()->largest.DecodeFrom(key);-      compact->builder->Add(key, input->value());--      // Close output file if it is big enough-      if (compact->builder->FileSize() >=-          compact->compaction->MaxOutputFileSize()) {-        status = FinishCompactionOutputFile(compact, input);-        if (!status.ok()) {-          break;-        }-      }-    }--    input->Next();-  }--  if (status.ok() && shutting_down_.Acquire_Load()) {-    status = Status::IOError("Deleting DB during compaction");-  }-  if (status.ok() && compact->builder != NULL) {-    status = FinishCompactionOutputFile(compact, input);-  }-  if (status.ok()) {-    status = input->status();-  }-  delete input;-  input = NULL;--  CompactionStats stats;-  stats.micros = env_->NowMicros() - start_micros - imm_micros;-  for (int which = 0; which < 2; which++) {-    for (int i = 0; i < compact->compaction->num_input_files(which); i++) {-      stats.bytes_read += compact->compaction->input(which, i)->file_size;-    }-  }-  for (size_t i = 0; i < compact->outputs.size(); i++) {-    stats.bytes_written += compact->outputs[i].file_size;-  }--  mutex_.Lock();-  stats_[compact->compaction->level() + 1].Add(stats);--  if (status.ok()) {-    status = InstallCompactionResults(compact);-  }-  VersionSet::LevelSummaryStorage tmp;-  Log(options_.info_log,-      "compacted to: %s", versions_->LevelSummary(&tmp));-  return status;-}--namespace {-struct IterState {-  port::Mutex* mu;-  Version* version;-  MemTable* mem;-  MemTable* imm;-};--static void CleanupIteratorState(void* arg1, void* arg2) {-  IterState* state = reinterpret_cast<IterState*>(arg1);-  state->mu->Lock();-  state->mem->Unref();-  if (state->imm != NULL) state->imm->Unref();-  state->version->Unref();-  state->mu->Unlock();-  delete state;-}-}  // namespace--Iterator* DBImpl::NewInternalIterator(const ReadOptions& options,-                                      SequenceNumber* latest_snapshot) {-  IterState* cleanup = new IterState;-  mutex_.Lock();-  *latest_snapshot = versions_->LastSequence();--  // Collect together all needed child iterators-  std::vector<Iterator*> list;-  list.push_back(mem_->NewIterator());-  mem_->Ref();-  if (imm_ != NULL) {-    list.push_back(imm_->NewIterator());-    imm_->Ref();-  }-  versions_->current()->AddIterators(options, &list);-  Iterator* internal_iter =-      NewMergingIterator(&internal_comparator_, &list[0], list.size());-  versions_->current()->Ref();--  cleanup->mu = &mutex_;-  cleanup->mem = mem_;-  cleanup->imm = imm_;-  cleanup->version = versions_->current();-  internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, NULL);--  mutex_.Unlock();-  return internal_iter;-}--Iterator* DBImpl::TEST_NewInternalIterator() {-  SequenceNumber ignored;-  return NewInternalIterator(ReadOptions(), &ignored);-}--int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() {-  MutexLock l(&mutex_);-  return versions_->MaxNextLevelOverlappingBytes();-}--Status DBImpl::Get(const ReadOptions& options,-                   const Slice& key,-                   std::string* value) {-  Status s;-  MutexLock l(&mutex_);-  SequenceNumber snapshot;-  if (options.snapshot != NULL) {-    snapshot = reinterpret_cast<const SnapshotImpl*>(options.snapshot)->number_;-  } else {-    snapshot = versions_->LastSequence();-  }--  MemTable* mem = mem_;-  MemTable* imm = imm_;-  Version* current = versions_->current();-  mem->Ref();-  if (imm != NULL) imm->Ref();-  current->Ref();--  bool have_stat_update = false;-  Version::GetStats stats;--  // Unlock while reading from files and memtables-  {-    mutex_.Unlock();-    // First look in the memtable, then in the immutable memtable (if any).-    LookupKey lkey(key, snapshot);-    if (mem->Get(lkey, value, &s)) {-      // Done-    } else if (imm != NULL && imm->Get(lkey, value, &s)) {-      // Done-    } else {-      s = current->Get(options, lkey, value, &stats);-      have_stat_update = true;-    }-    mutex_.Lock();-  }--  if (have_stat_update && current->UpdateStats(stats)) {-    MaybeScheduleCompaction();-  }-  mem->Unref();-  if (imm != NULL) imm->Unref();-  current->Unref();-  return s;-}--Iterator* DBImpl::NewIterator(const ReadOptions& options) {-  SequenceNumber latest_snapshot;-  Iterator* internal_iter = NewInternalIterator(options, &latest_snapshot);-  return NewDBIterator(-      &dbname_, env_, user_comparator(), internal_iter,-      (options.snapshot != NULL-       ? reinterpret_cast<const SnapshotImpl*>(options.snapshot)->number_-       : latest_snapshot));-}--const Snapshot* DBImpl::GetSnapshot() {-  MutexLock l(&mutex_);-  return snapshots_.New(versions_->LastSequence());-}--void DBImpl::ReleaseSnapshot(const Snapshot* s) {-  MutexLock l(&mutex_);-  snapshots_.Delete(reinterpret_cast<const SnapshotImpl*>(s));-}--// Convenience methods-Status DBImpl::Put(const WriteOptions& o, const Slice& key, const Slice& val) {-  return DB::Put(o, key, val);-}--Status DBImpl::Delete(const WriteOptions& options, const Slice& key) {-  return DB::Delete(options, key);-}--Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) {-  Writer w(&mutex_);-  w.batch = my_batch;-  w.sync = options.sync;-  w.done = false;--  MutexLock l(&mutex_);-  writers_.push_back(&w);-  while (!w.done && &w != writers_.front()) {-    w.cv.Wait();-  }-  if (w.done) {-    return w.status;-  }--  // May temporarily unlock and wait.-  Status status = MakeRoomForWrite(my_batch == NULL);-  uint64_t last_sequence = versions_->LastSequence();-  Writer* last_writer = &w;-  if (status.ok() && my_batch != NULL) {  // NULL batch is for compactions-    WriteBatch* updates = BuildBatchGroup(&last_writer);-    WriteBatchInternal::SetSequence(updates, last_sequence + 1);-    last_sequence += WriteBatchInternal::Count(updates);--    // Add to log and apply to memtable.  We can release the lock-    // during this phase since &w is currently responsible for logging-    // and protects against concurrent loggers and concurrent writes-    // into mem_.-    {-      mutex_.Unlock();-      status = log_->AddRecord(WriteBatchInternal::Contents(updates));-      if (status.ok() && options.sync) {-        status = logfile_->Sync();-      }-      if (status.ok()) {-        status = WriteBatchInternal::InsertInto(updates, mem_);-      }-      mutex_.Lock();-    }-    if (updates == tmp_batch_) tmp_batch_->Clear();--    versions_->SetLastSequence(last_sequence);-  }--  while (true) {-    Writer* ready = writers_.front();-    writers_.pop_front();-    if (ready != &w) {-      ready->status = status;-      ready->done = true;-      ready->cv.Signal();-    }-    if (ready == last_writer) break;-  }--  // Notify new head of write queue-  if (!writers_.empty()) {-    writers_.front()->cv.Signal();-  }--  return status;-}--// REQUIRES: Writer list must be non-empty-// REQUIRES: First writer must have a non-NULL batch-WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) {-  assert(!writers_.empty());-  Writer* first = writers_.front();-  WriteBatch* result = first->batch;-  assert(result != NULL);--  size_t size = WriteBatchInternal::ByteSize(first->batch);--  // Allow the group to grow up to a maximum size, but if the-  // original write is small, limit the growth so we do not slow-  // down the small write too much.-  size_t max_size = 1 << 20;-  if (size <= (128<<10)) {-    max_size = size + (128<<10);-  }--  *last_writer = first;-  std::deque<Writer*>::iterator iter = writers_.begin();-  ++iter;  // Advance past "first"-  for (; iter != writers_.end(); ++iter) {-    Writer* w = *iter;-    if (w->sync && !first->sync) {-      // Do not include a sync write into a batch handled by a non-sync write.-      break;-    }--    if (w->batch != NULL) {-      size += WriteBatchInternal::ByteSize(w->batch);-      if (size > max_size) {-        // Do not make batch too big-        break;-      }--      // Append to *reuslt-      if (result == first->batch) {-        // Switch to temporary batch instead of disturbing caller's batch-        result = tmp_batch_;-        assert(WriteBatchInternal::Count(result) == 0);-        WriteBatchInternal::Append(result, first->batch);-      }-      WriteBatchInternal::Append(result, w->batch);-    }-    *last_writer = w;-  }-  return result;-}--// REQUIRES: mutex_ is held-// REQUIRES: this thread is currently at the front of the writer queue-Status DBImpl::MakeRoomForWrite(bool force) {-  mutex_.AssertHeld();-  assert(!writers_.empty());-  bool allow_delay = !force;-  Status s;-  while (true) {-    if (!bg_error_.ok()) {-      // Yield previous error-      s = bg_error_;-      break;-    } else if (-        allow_delay &&-        versions_->NumLevelFiles(0) >= config::kL0_SlowdownWritesTrigger) {-      // We are getting close to hitting a hard limit on the number of-      // L0 files.  Rather than delaying a single write by several-      // seconds when we hit the hard limit, start delaying each-      // individual write by 1ms to reduce latency variance.  Also,-      // this delay hands over some CPU to the compaction thread in-      // case it is sharing the same core as the writer.-      mutex_.Unlock();-      env_->SleepForMicroseconds(1000);-      allow_delay = false;  // Do not delay a single write more than once-      mutex_.Lock();-    } else if (!force &&-               (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) {-      // There is room in current memtable-      break;-    } else if (imm_ != NULL) {-      // We have filled up the current memtable, but the previous-      // one is still being compacted, so we wait.-      bg_cv_.Wait();-    } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) {-      // There are too many level-0 files.-      Log(options_.info_log, "waiting...\n");-      bg_cv_.Wait();-    } else {-      // Attempt to switch to a new memtable and trigger compaction of old-      assert(versions_->PrevLogNumber() == 0);-      uint64_t new_log_number = versions_->NewFileNumber();-      WritableFile* lfile = NULL;-      s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile);-      if (!s.ok()) {-        break;-      }-      delete log_;-      delete logfile_;-      logfile_ = lfile;-      logfile_number_ = new_log_number;-      log_ = new log::Writer(lfile);-      imm_ = mem_;-      has_imm_.Release_Store(imm_);-      mem_ = new MemTable(internal_comparator_);-      mem_->Ref();-      force = false;   // Do not force another compaction if have room-      MaybeScheduleCompaction();-    }-  }-  return s;-}--bool DBImpl::GetProperty(const Slice& property, std::string* value) {-  value->clear();--  MutexLock l(&mutex_);-  Slice in = property;-  Slice prefix("leveldb.");-  if (!in.starts_with(prefix)) return false;-  in.remove_prefix(prefix.size());--  if (in.starts_with("num-files-at-level")) {-    in.remove_prefix(strlen("num-files-at-level"));-    uint64_t level;-    bool ok = ConsumeDecimalNumber(&in, &level) && in.empty();-    if (!ok || level >= config::kNumLevels) {-      return false;-    } else {-      char buf[100];-      snprintf(buf, sizeof(buf), "%d",-               versions_->NumLevelFiles(static_cast<int>(level)));-      *value = buf;-      return true;-    }-  } else if (in == "stats") {-    char buf[200];-    snprintf(buf, sizeof(buf),-             "                               Compactions\n"-             "Level  Files Size(MB) Time(sec) Read(MB) Write(MB)\n"-             "--------------------------------------------------\n"-             );-    value->append(buf);-    for (int level = 0; level < config::kNumLevels; level++) {-      int files = versions_->NumLevelFiles(level);-      if (stats_[level].micros > 0 || files > 0) {-        snprintf(-            buf, sizeof(buf),-            "%3d %8d %8.0f %9.0f %8.0f %9.0f\n",-            level,-            files,-            versions_->NumLevelBytes(level) / 1048576.0,-            stats_[level].micros / 1e6,-            stats_[level].bytes_read / 1048576.0,-            stats_[level].bytes_written / 1048576.0);-        value->append(buf);-      }-    }-    return true;-  } else if (in == "sstables") {-    *value = versions_->current()->DebugString();-    return true;-  }--  return false;-}--void DBImpl::GetApproximateSizes(-    const Range* range, int n,-    uint64_t* sizes) {-  // TODO(opt): better implementation-  Version* v;-  {-    MutexLock l(&mutex_);-    versions_->current()->Ref();-    v = versions_->current();-  }--  for (int i = 0; i < n; i++) {-    // Convert user_key into a corresponding internal key.-    InternalKey k1(range[i].start, kMaxSequenceNumber, kValueTypeForSeek);-    InternalKey k2(range[i].limit, kMaxSequenceNumber, kValueTypeForSeek);-    uint64_t start = versions_->ApproximateOffsetOf(v, k1);-    uint64_t limit = versions_->ApproximateOffsetOf(v, k2);-    sizes[i] = (limit >= start ? limit - start : 0);-  }--  {-    MutexLock l(&mutex_);-    v->Unref();-  }-}--// Default implementations of convenience methods that subclasses of DB-// can call if they wish-Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) {-  WriteBatch batch;-  batch.Put(key, value);-  return Write(opt, &batch);-}--Status DB::Delete(const WriteOptions& opt, const Slice& key) {-  WriteBatch batch;-  batch.Delete(key);-  return Write(opt, &batch);-}--DB::~DB() { }--Status DB::Open(const Options& options, const std::string& dbname,-                DB** dbptr) {-  *dbptr = NULL;--  DBImpl* impl = new DBImpl(options, dbname);-  impl->mutex_.Lock();-  VersionEdit edit;-  Status s = impl->Recover(&edit); // Handles create_if_missing, error_if_exists-  if (s.ok()) {-    uint64_t new_log_number = impl->versions_->NewFileNumber();-    WritableFile* lfile;-    s = options.env->NewWritableFile(LogFileName(dbname, new_log_number),-                                     &lfile);-    if (s.ok()) {-      edit.SetLogNumber(new_log_number);-      impl->logfile_ = lfile;-      impl->logfile_number_ = new_log_number;-      impl->log_ = new log::Writer(lfile);-      s = impl->versions_->LogAndApply(&edit, &impl->mutex_);-    }-    if (s.ok()) {-      impl->DeleteObsoleteFiles();-      impl->MaybeScheduleCompaction();-    }-  }-  impl->mutex_.Unlock();-  if (s.ok()) {-    *dbptr = impl;-  } else {-    delete impl;-  }-  return s;-}--Snapshot::~Snapshot() {-}--Status DestroyDB(const std::string& dbname, const Options& options) {-  Env* env = options.env;-  std::vector<std::string> filenames;-  // Ignore error in case directory does not exist-  env->GetChildren(dbname, &filenames);-  if (filenames.empty()) {-    return Status::OK();-  }--  FileLock* lock;-  const std::string lockname = LockFileName(dbname);-  Status result = env->LockFile(lockname, &lock);-  if (result.ok()) {-    uint64_t number;-    FileType type;-    for (size_t i = 0; i < filenames.size(); i++) {-      if (ParseFileName(filenames[i], &number, &type) &&-          type != kDBLockFile) {  // Lock file will be deleted at end-        Status del = env->DeleteFile(dbname + "/" + filenames[i]);-        if (result.ok() && !del.ok()) {-          result = del;-        }-      }-    }-    env->UnlockFile(lock);  // Ignore error since state is already gone-    env->DeleteFile(lockname);-    env->DeleteDir(dbname);  // Ignore error in case dir contains other files-  }-  return result;-}--}  // namespace leveldb
− cbits/leveldb/db/db_impl.h
@@ -1,192 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_DB_DB_IMPL_H_-#define STORAGE_LEVELDB_DB_DB_IMPL_H_--#include <deque>-#include <set>-#include "db/dbformat.h"-#include "db/log_writer.h"-#include "db/snapshot.h"-#include "leveldb/db.h"-#include "leveldb/env.h"-#include "port/port.h"--namespace leveldb {--class MemTable;-class TableCache;-class Version;-class VersionEdit;-class VersionSet;--class DBImpl : public DB {- public:-  DBImpl(const Options& options, const std::string& dbname);-  virtual ~DBImpl();--  // Implementations of the DB interface-  virtual Status Put(const WriteOptions&, const Slice& key, const Slice& value);-  virtual Status Delete(const WriteOptions&, const Slice& key);-  virtual Status Write(const WriteOptions& options, WriteBatch* updates);-  virtual Status Get(const ReadOptions& options,-                     const Slice& key,-                     std::string* value);-  virtual Iterator* NewIterator(const ReadOptions&);-  virtual const Snapshot* GetSnapshot();-  virtual void ReleaseSnapshot(const Snapshot* snapshot);-  virtual bool GetProperty(const Slice& property, std::string* value);-  virtual void GetApproximateSizes(const Range* range, int n, uint64_t* sizes);-  virtual void CompactRange(const Slice* begin, const Slice* end);--  // Extra methods (for testing) that are not in the public DB interface--  // Compact any files in the named level that overlap [*begin,*end]-  void TEST_CompactRange(int level, const Slice* begin, const Slice* end);--  // Force current memtable contents to be compacted.-  Status TEST_CompactMemTable();--  // Return an internal iterator over the current state of the database.-  // The keys of this iterator are internal keys (see format.h).-  // The returned iterator should be deleted when no longer needed.-  Iterator* TEST_NewInternalIterator();--  // Return the maximum overlapping data (in bytes) at next level for any-  // file at a level >= 1.-  int64_t TEST_MaxNextLevelOverlappingBytes();-- private:-  friend class DB;-  struct CompactionState;-  struct Writer;--  Iterator* NewInternalIterator(const ReadOptions&,-                                SequenceNumber* latest_snapshot);--  Status NewDB();--  // Recover the descriptor from persistent storage.  May do a significant-  // amount of work to recover recently logged updates.  Any changes to-  // be made to the descriptor are added to *edit.-  Status Recover(VersionEdit* edit);--  void MaybeIgnoreError(Status* s) const;--  // Delete any unneeded files and stale in-memory entries.-  void DeleteObsoleteFiles();--  // Compact the in-memory write buffer to disk.  Switches to a new-  // log-file/memtable and writes a new descriptor iff successful.-  Status CompactMemTable();--  Status RecoverLogFile(uint64_t log_number,-                        VersionEdit* edit,-                        SequenceNumber* max_sequence);--  Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base);--  Status MakeRoomForWrite(bool force /* compact even if there is room? */);-  WriteBatch* BuildBatchGroup(Writer** last_writer);--  void MaybeScheduleCompaction();-  static void BGWork(void* db);-  void BackgroundCall();-  void BackgroundCompaction();-  void CleanupCompaction(CompactionState* compact);-  Status DoCompactionWork(CompactionState* compact);--  Status OpenCompactionOutputFile(CompactionState* compact);-  Status FinishCompactionOutputFile(CompactionState* compact, Iterator* input);-  Status InstallCompactionResults(CompactionState* compact);--  // Constant after construction-  Env* const env_;-  const InternalKeyComparator internal_comparator_;-  const Options options_;  // options_.comparator == &internal_comparator_-  bool owns_info_log_;-  bool owns_cache_;-  const std::string dbname_;--  // table_cache_ provides its own synchronization-  TableCache* table_cache_;--  // Lock over the persistent DB state.  Non-NULL iff successfully acquired.-  FileLock* db_lock_;--  // State below is protected by mutex_-  port::Mutex mutex_;-  port::AtomicPointer shutting_down_;-  port::CondVar bg_cv_;          // Signalled when background work finishes-  MemTable* mem_;-  MemTable* imm_;                // Memtable being compacted-  port::AtomicPointer has_imm_;  // So bg thread can detect non-NULL imm_-  WritableFile* logfile_;-  uint64_t logfile_number_;-  log::Writer* log_;--  // Queue of writers.-  std::deque<Writer*> writers_;-  WriteBatch* tmp_batch_;--  SnapshotList snapshots_;--  // Set of table files to protect from deletion because they are-  // part of ongoing compactions.-  std::set<uint64_t> pending_outputs_;--  // Has a background compaction been scheduled or is running?-  bool bg_compaction_scheduled_;--  // Information for a manual compaction-  struct ManualCompaction {-    int level;-    bool done;-    const InternalKey* begin;   // NULL means beginning of key range-    const InternalKey* end;     // NULL means end of key range-    InternalKey tmp_storage;    // Used to keep track of compaction progress-  };-  ManualCompaction* manual_compaction_;--  VersionSet* versions_;--  // Have we encountered a background error in paranoid mode?-  Status bg_error_;--  // Per level compaction stats.  stats_[level] stores the stats for-  // compactions that produced data for the specified "level".-  struct CompactionStats {-    int64_t micros;-    int64_t bytes_read;-    int64_t bytes_written;--    CompactionStats() : micros(0), bytes_read(0), bytes_written(0) { }--    void Add(const CompactionStats& c) {-      this->micros += c.micros;-      this->bytes_read += c.bytes_read;-      this->bytes_written += c.bytes_written;-    }-  };-  CompactionStats stats_[config::kNumLevels];--  // No copying allowed-  DBImpl(const DBImpl&);-  void operator=(const DBImpl&);--  const Comparator* user_comparator() const {-    return internal_comparator_.user_comparator();-  }-};--// Sanitize db options.  The caller should delete result.info_log if-// it is not equal to src.info_log.-extern Options SanitizeOptions(const std::string& db,-                               const InternalKeyComparator* icmp,-                               const Options& src);--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_DB_IMPL_H_
− cbits/leveldb/db/db_iter.cc
@@ -1,299 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/db_iter.h"--#include "db/filename.h"-#include "db/dbformat.h"-#include "leveldb/env.h"-#include "leveldb/iterator.h"-#include "port/port.h"-#include "util/logging.h"-#include "util/mutexlock.h"--namespace leveldb {--#if 0-static void DumpInternalIter(Iterator* iter) {-  for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {-    ParsedInternalKey k;-    if (!ParseInternalKey(iter->key(), &k)) {-      fprintf(stderr, "Corrupt '%s'\n", EscapeString(iter->key()).c_str());-    } else {-      fprintf(stderr, "@ '%s'\n", k.DebugString().c_str());-    }-  }-}-#endif--namespace {--// Memtables and sstables that make the DB representation contain-// (userkey,seq,type) => uservalue entries.  DBIter-// combines multiple entries for the same userkey found in the DB-// representation into a single entry while accounting for sequence-// numbers, deletion markers, overwrites, etc.-class DBIter: public Iterator {- public:-  // Which direction is the iterator currently moving?-  // (1) When moving forward, the internal iterator is positioned at-  //     the exact entry that yields this->key(), this->value()-  // (2) When moving backwards, the internal iterator is positioned-  //     just before all entries whose user key == this->key().-  enum Direction {-    kForward,-    kReverse-  };--  DBIter(const std::string* dbname, Env* env,-         const Comparator* cmp, Iterator* iter, SequenceNumber s)-      : dbname_(dbname),-        env_(env),-        user_comparator_(cmp),-        iter_(iter),-        sequence_(s),-        direction_(kForward),-        valid_(false) {-  }-  virtual ~DBIter() {-    delete iter_;-  }-  virtual bool Valid() const { return valid_; }-  virtual Slice key() const {-    assert(valid_);-    return (direction_ == kForward) ? ExtractUserKey(iter_->key()) : saved_key_;-  }-  virtual Slice value() const {-    assert(valid_);-    return (direction_ == kForward) ? iter_->value() : saved_value_;-  }-  virtual Status status() const {-    if (status_.ok()) {-      return iter_->status();-    } else {-      return status_;-    }-  }--  virtual void Next();-  virtual void Prev();-  virtual void Seek(const Slice& target);-  virtual void SeekToFirst();-  virtual void SeekToLast();-- private:-  void FindNextUserEntry(bool skipping, std::string* skip);-  void FindPrevUserEntry();-  bool ParseKey(ParsedInternalKey* key);--  inline void SaveKey(const Slice& k, std::string* dst) {-    dst->assign(k.data(), k.size());-  }--  inline void ClearSavedValue() {-    if (saved_value_.capacity() > 1048576) {-      std::string empty;-      swap(empty, saved_value_);-    } else {-      saved_value_.clear();-    }-  }--  const std::string* const dbname_;-  Env* const env_;-  const Comparator* const user_comparator_;-  Iterator* const iter_;-  SequenceNumber const sequence_;--  Status status_;-  std::string saved_key_;     // == current key when direction_==kReverse-  std::string saved_value_;   // == current raw value when direction_==kReverse-  Direction direction_;-  bool valid_;--  // No copying allowed-  DBIter(const DBIter&);-  void operator=(const DBIter&);-};--inline bool DBIter::ParseKey(ParsedInternalKey* ikey) {-  if (!ParseInternalKey(iter_->key(), ikey)) {-    status_ = Status::Corruption("corrupted internal key in DBIter");-    return false;-  } else {-    return true;-  }-}--void DBIter::Next() {-  assert(valid_);--  if (direction_ == kReverse) {  // Switch directions?-    direction_ = kForward;-    // iter_ is pointing just before the entries for this->key(),-    // so advance into the range of entries for this->key() and then-    // use the normal skipping code below.-    if (!iter_->Valid()) {-      iter_->SeekToFirst();-    } else {-      iter_->Next();-    }-    if (!iter_->Valid()) {-      valid_ = false;-      saved_key_.clear();-      return;-    }-  }--  // Temporarily use saved_key_ as storage for key to skip.-  std::string* skip = &saved_key_;-  SaveKey(ExtractUserKey(iter_->key()), skip);-  FindNextUserEntry(true, skip);-}--void DBIter::FindNextUserEntry(bool skipping, std::string* skip) {-  // Loop until we hit an acceptable entry to yield-  assert(iter_->Valid());-  assert(direction_ == kForward);-  do {-    ParsedInternalKey ikey;-    if (ParseKey(&ikey) && ikey.sequence <= sequence_) {-      switch (ikey.type) {-        case kTypeDeletion:-          // Arrange to skip all upcoming entries for this key since-          // they are hidden by this deletion.-          SaveKey(ikey.user_key, skip);-          skipping = true;-          break;-        case kTypeValue:-          if (skipping &&-              user_comparator_->Compare(ikey.user_key, *skip) <= 0) {-            // Entry hidden-          } else {-            valid_ = true;-            saved_key_.clear();-            return;-          }-          break;-      }-    }-    iter_->Next();-  } while (iter_->Valid());-  saved_key_.clear();-  valid_ = false;-}--void DBIter::Prev() {-  assert(valid_);--  if (direction_ == kForward) {  // Switch directions?-    // iter_ is pointing at the current entry.  Scan backwards until-    // the key changes so we can use the normal reverse scanning code.-    assert(iter_->Valid());  // Otherwise valid_ would have been false-    SaveKey(ExtractUserKey(iter_->key()), &saved_key_);-    while (true) {-      iter_->Prev();-      if (!iter_->Valid()) {-        valid_ = false;-        saved_key_.clear();-        ClearSavedValue();-        return;-      }-      if (user_comparator_->Compare(ExtractUserKey(iter_->key()),-                                    saved_key_) < 0) {-        break;-      }-    }-    direction_ = kReverse;-  }--  FindPrevUserEntry();-}--void DBIter::FindPrevUserEntry() {-  assert(direction_ == kReverse);--  ValueType value_type = kTypeDeletion;-  if (iter_->Valid()) {-    do {-      ParsedInternalKey ikey;-      if (ParseKey(&ikey) && ikey.sequence <= sequence_) {-        if ((value_type != kTypeDeletion) &&-            user_comparator_->Compare(ikey.user_key, saved_key_) < 0) {-          // We encountered a non-deleted value in entries for previous keys,-          break;-        }-        value_type = ikey.type;-        if (value_type == kTypeDeletion) {-          saved_key_.clear();-          ClearSavedValue();-        } else {-          Slice raw_value = iter_->value();-          if (saved_value_.capacity() > raw_value.size() + 1048576) {-            std::string empty;-            swap(empty, saved_value_);-          }-          SaveKey(ExtractUserKey(iter_->key()), &saved_key_);-          saved_value_.assign(raw_value.data(), raw_value.size());-        }-      }-      iter_->Prev();-    } while (iter_->Valid());-  }--  if (value_type == kTypeDeletion) {-    // End-    valid_ = false;-    saved_key_.clear();-    ClearSavedValue();-    direction_ = kForward;-  } else {-    valid_ = true;-  }-}--void DBIter::Seek(const Slice& target) {-  direction_ = kForward;-  ClearSavedValue();-  saved_key_.clear();-  AppendInternalKey(-      &saved_key_, ParsedInternalKey(target, sequence_, kValueTypeForSeek));-  iter_->Seek(saved_key_);-  if (iter_->Valid()) {-    FindNextUserEntry(false, &saved_key_ /* temporary storage */);-  } else {-    valid_ = false;-  }-}--void DBIter::SeekToFirst() {-  direction_ = kForward;-  ClearSavedValue();-  iter_->SeekToFirst();-  if (iter_->Valid()) {-    FindNextUserEntry(false, &saved_key_ /* temporary storage */);-  } else {-    valid_ = false;-  }-}--void DBIter::SeekToLast() {-  direction_ = kReverse;-  ClearSavedValue();-  iter_->SeekToLast();-  FindPrevUserEntry();-}--}  // anonymous namespace--Iterator* NewDBIterator(-    const std::string* dbname,-    Env* env,-    const Comparator* user_key_comparator,-    Iterator* internal_iter,-    const SequenceNumber& sequence) {-  return new DBIter(dbname, env, user_key_comparator, internal_iter, sequence);-}--}  // namespace leveldb
− cbits/leveldb/db/db_iter.h
@@ -1,26 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_DB_DB_ITER_H_-#define STORAGE_LEVELDB_DB_DB_ITER_H_--#include <stdint.h>-#include "leveldb/db.h"-#include "db/dbformat.h"--namespace leveldb {--// Return a new iterator that converts internal keys (yielded by-// "*internal_iter") that were live at the specified "sequence" number-// into appropriate user keys.-extern Iterator* NewDBIterator(-    const std::string* dbname,-    Env* env,-    const Comparator* user_key_comparator,-    Iterator* internal_iter,-    const SequenceNumber& sequence);--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_DB_ITER_H_
− cbits/leveldb/db/db_test.cc
@@ -1,1711 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "leveldb/db.h"-#include "db/db_impl.h"-#include "db/filename.h"-#include "db/version_set.h"-#include "db/write_batch_internal.h"-#include "leveldb/env.h"-#include "leveldb/table.h"-#include "util/logging.h"-#include "util/mutexlock.h"-#include "util/testharness.h"-#include "util/testutil.h"--namespace leveldb {--static std::string RandomString(Random* rnd, int len) {-  std::string r;-  test::RandomString(rnd, len, &r);-  return r;-}--// Special Env used to delay background operations-class SpecialEnv : public EnvWrapper {- public:-  // sstable Sync() calls are blocked while this pointer is non-NULL.-  port::AtomicPointer delay_sstable_sync_;--  // Simulate no-space errors while this pointer is non-NULL.-  port::AtomicPointer no_space_;--  explicit SpecialEnv(Env* base) : EnvWrapper(base) {-    delay_sstable_sync_.Release_Store(NULL);-    no_space_.Release_Store(NULL);-  }--  Status NewWritableFile(const std::string& f, WritableFile** r) {-    class SSTableFile : public WritableFile {-     private:-      SpecialEnv* env_;-      WritableFile* base_;--     public:-      SSTableFile(SpecialEnv* env, WritableFile* base)-          : env_(env),-            base_(base) {-      }-      ~SSTableFile() { delete base_; }-      Status Append(const Slice& data) {-        if (env_->no_space_.Acquire_Load() != NULL) {-          // Drop writes on the floor-          return Status::OK();-        } else {-          return base_->Append(data);-        }-      }-      Status Close() { return base_->Close(); }-      Status Flush() { return base_->Flush(); }-      Status Sync() {-        while (env_->delay_sstable_sync_.Acquire_Load() != NULL) {-          env_->SleepForMicroseconds(100000);-        }-        return base_->Sync();-      }-    };--    Status s = target()->NewWritableFile(f, r);-    if (s.ok()) {-      if (strstr(f.c_str(), ".sst") != NULL) {-        *r = new SSTableFile(this, *r);-      }-    }-    return s;-  }-};--class DBTest {- public:-  std::string dbname_;-  SpecialEnv* env_;-  DB* db_;--  Options last_options_;--  DBTest() : env_(new SpecialEnv(Env::Default())) {-    dbname_ = test::TmpDir() + "/db_test";-    DestroyDB(dbname_, Options());-    db_ = NULL;-    Reopen();-  }--  ~DBTest() {-    delete db_;-    DestroyDB(dbname_, Options());-    delete env_;-  }--  DBImpl* dbfull() {-    return reinterpret_cast<DBImpl*>(db_);-  }--  void Reopen(Options* options = NULL) {-    ASSERT_OK(TryReopen(options));-  }--  void DestroyAndReopen(Options* options = NULL) {-    delete db_;-    db_ = NULL;-    DestroyDB(dbname_, Options());-    ASSERT_OK(TryReopen(options));-  }--  Status TryReopen(Options* options) {-    delete db_;-    db_ = NULL;-    Options opts;-    if (options != NULL) {-      opts = *options;-    } else {-      opts.create_if_missing = true;-    }-    last_options_ = opts;--    return DB::Open(opts, dbname_, &db_);-  }--  Status Put(const std::string& k, const std::string& v) {-    return db_->Put(WriteOptions(), k, v);-  }--  Status Delete(const std::string& k) {-    return db_->Delete(WriteOptions(), k);-  }--  std::string Get(const std::string& k, const Snapshot* snapshot = NULL) {-    ReadOptions options;-    options.snapshot = snapshot;-    std::string result;-    Status s = db_->Get(options, k, &result);-    if (s.IsNotFound()) {-      result = "NOT_FOUND";-    } else if (!s.ok()) {-      result = s.ToString();-    }-    return result;-  }--  // Return a string that contains all key,value pairs in order,-  // formatted like "(k1->v1)(k2->v2)".-  std::string Contents() {-    std::vector<std::string> forward;-    std::string result;-    Iterator* iter = db_->NewIterator(ReadOptions());-    for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {-      std::string s = IterStatus(iter);-      result.push_back('(');-      result.append(s);-      result.push_back(')');-      forward.push_back(s);-    }--    // Check reverse iteration results are the reverse of forward results-    int matched = 0;-    for (iter->SeekToLast(); iter->Valid(); iter->Prev()) {-      ASSERT_LT(matched, forward.size());-      ASSERT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]);-      matched++;-    }-    ASSERT_EQ(matched, forward.size());--    delete iter;-    return result;-  }--  std::string AllEntriesFor(const Slice& user_key) {-    Iterator* iter = dbfull()->TEST_NewInternalIterator();-    InternalKey target(user_key, kMaxSequenceNumber, kTypeValue);-    iter->Seek(target.Encode());-    std::string result;-    if (!iter->status().ok()) {-      result = iter->status().ToString();-    } else {-      result = "[ ";-      bool first = true;-      while (iter->Valid()) {-        ParsedInternalKey ikey;-        if (!ParseInternalKey(iter->key(), &ikey)) {-          result += "CORRUPTED";-        } else {-          if (last_options_.comparator->Compare(-                  ikey.user_key, user_key) != 0) {-            break;-          }-          if (!first) {-            result += ", ";-          }-          first = false;-          switch (ikey.type) {-            case kTypeValue:-              result += iter->value().ToString();-              break;-            case kTypeDeletion:-              result += "DEL";-              break;-          }-        }-        iter->Next();-      }-      if (!first) {-        result += " ";-      }-      result += "]";-    }-    delete iter;-    return result;-  }--  int NumTableFilesAtLevel(int level) {-    std::string property;-    ASSERT_TRUE(-        db_->GetProperty("leveldb.num-files-at-level" + NumberToString(level),-                         &property));-    return atoi(property.c_str());-  }--  int TotalTableFiles() {-    int result = 0;-    for (int level = 0; level < config::kNumLevels; level++) {-      result += NumTableFilesAtLevel(level);-    }-    return result;-  }--  // Return spread of files per level-  std::string FilesPerLevel() {-    std::string result;-    int last_non_zero_offset = 0;-    for (int level = 0; level < config::kNumLevels; level++) {-      int f = NumTableFilesAtLevel(level);-      char buf[100];-      snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f);-      result += buf;-      if (f > 0) {-        last_non_zero_offset = result.size();-      }-    }-    result.resize(last_non_zero_offset);-    return result;-  }--  int CountFiles() {-    std::vector<std::string> files;-    env_->GetChildren(dbname_, &files);-    return static_cast<int>(files.size());-  }--  uint64_t Size(const Slice& start, const Slice& limit) {-    Range r(start, limit);-    uint64_t size;-    db_->GetApproximateSizes(&r, 1, &size);-    return size;-  }--  void Compact(const Slice& start, const Slice& limit) {-    db_->CompactRange(&start, &limit);-  }--  // Do n memtable compactions, each of which produces an sstable-  // covering the range [small,large].-  void MakeTables(int n, const std::string& small, const std::string& large) {-    for (int i = 0; i < n; i++) {-      Put(small, "begin");-      Put(large, "end");-      dbfull()->TEST_CompactMemTable();-    }-  }--  // Prevent pushing of new sstables into deeper levels by adding-  // tables that cover a specified range to all levels.-  void FillLevels(const std::string& smallest, const std::string& largest) {-    MakeTables(config::kNumLevels, smallest, largest);-  }--  void DumpFileCounts(const char* label) {-    fprintf(stderr, "---\n%s:\n", label);-    fprintf(stderr, "maxoverlap: %lld\n",-            static_cast<long long>(-                dbfull()->TEST_MaxNextLevelOverlappingBytes()));-    for (int level = 0; level < config::kNumLevels; level++) {-      int num = NumTableFilesAtLevel(level);-      if (num > 0) {-        fprintf(stderr, "  level %3d : %d files\n", level, num);-      }-    }-  }--  std::string DumpSSTableList() {-    std::string property;-    db_->GetProperty("leveldb.sstables", &property);-    return property;-  }--  std::string IterStatus(Iterator* iter) {-    std::string result;-    if (iter->Valid()) {-      result = iter->key().ToString() + "->" + iter->value().ToString();-    } else {-      result = "(invalid)";-    }-    return result;-  }-};--TEST(DBTest, Empty) {-  ASSERT_TRUE(db_ != NULL);-  ASSERT_EQ("NOT_FOUND", Get("foo"));-}--TEST(DBTest, ReadWrite) {-  ASSERT_OK(Put("foo", "v1"));-  ASSERT_EQ("v1", Get("foo"));-  ASSERT_OK(Put("bar", "v2"));-  ASSERT_OK(Put("foo", "v3"));-  ASSERT_EQ("v3", Get("foo"));-  ASSERT_EQ("v2", Get("bar"));-}--TEST(DBTest, PutDeleteGet) {-  ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1"));-  ASSERT_EQ("v1", Get("foo"));-  ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2"));-  ASSERT_EQ("v2", Get("foo"));-  ASSERT_OK(db_->Delete(WriteOptions(), "foo"));-  ASSERT_EQ("NOT_FOUND", Get("foo"));-}--TEST(DBTest, GetFromImmutableLayer) {-  Options options;-  options.env = env_;-  options.write_buffer_size = 100000;  // Small write buffer-  Reopen(&options);--  ASSERT_OK(Put("foo", "v1"));-  ASSERT_EQ("v1", Get("foo"));--  env_->delay_sstable_sync_.Release_Store(env_);   // Block sync calls-  Put("k1", std::string(100000, 'x'));             // Fill memtable-  Put("k2", std::string(100000, 'y'));             // Trigger compaction-  ASSERT_EQ("v1", Get("foo"));-  env_->delay_sstable_sync_.Release_Store(NULL);   // Release sync calls-}--TEST(DBTest, GetFromVersions) {-  ASSERT_OK(Put("foo", "v1"));-  dbfull()->TEST_CompactMemTable();-  ASSERT_EQ("v1", Get("foo"));-}--TEST(DBTest, GetSnapshot) {-  // Try with both a short key and a long key-  for (int i = 0; i < 2; i++) {-    std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x');-    ASSERT_OK(Put(key, "v1"));-    const Snapshot* s1 = db_->GetSnapshot();-    ASSERT_OK(Put(key, "v2"));-    ASSERT_EQ("v2", Get(key));-    ASSERT_EQ("v1", Get(key, s1));-    dbfull()->TEST_CompactMemTable();-    ASSERT_EQ("v2", Get(key));-    ASSERT_EQ("v1", Get(key, s1));-    db_->ReleaseSnapshot(s1);-  }-}--TEST(DBTest, GetLevel0Ordering) {-  // Check that we process level-0 files in correct order.  The code-  // below generates two level-0 files where the earlier one comes-  // before the later one in the level-0 file list since the earlier-  // one has a smaller "smallest" key.-  ASSERT_OK(Put("bar", "b"));-  ASSERT_OK(Put("foo", "v1"));-  dbfull()->TEST_CompactMemTable();-  ASSERT_OK(Put("foo", "v2"));-  dbfull()->TEST_CompactMemTable();-  ASSERT_EQ("v2", Get("foo"));-}--TEST(DBTest, GetOrderedByLevels) {-  ASSERT_OK(Put("foo", "v1"));-  Compact("a", "z");-  ASSERT_EQ("v1", Get("foo"));-  ASSERT_OK(Put("foo", "v2"));-  ASSERT_EQ("v2", Get("foo"));-  dbfull()->TEST_CompactMemTable();-  ASSERT_EQ("v2", Get("foo"));-}--TEST(DBTest, GetPicksCorrectFile) {-  // Arrange to have multiple files in a non-level-0 level.-  ASSERT_OK(Put("a", "va"));-  Compact("a", "b");-  ASSERT_OK(Put("x", "vx"));-  Compact("x", "y");-  ASSERT_OK(Put("f", "vf"));-  Compact("f", "g");-  ASSERT_EQ("va", Get("a"));-  ASSERT_EQ("vf", Get("f"));-  ASSERT_EQ("vx", Get("x"));-}--TEST(DBTest, GetEncountersEmptyLevel) {-  // Arrange for the following to happen:-  //   * sstable A in level 0-  //   * nothing in level 1-  //   * sstable B in level 2-  // Then do enough Get() calls to arrange for an automatic compaction-  // of sstable A.  A bug would cause the compaction to be marked as-  // occuring at level 1 (instead of the correct level 0).--  // Step 1: First place sstables in levels 0 and 2-  int compaction_count = 0;-  while (NumTableFilesAtLevel(0) == 0 ||-         NumTableFilesAtLevel(2) == 0) {-    ASSERT_LE(compaction_count, 100) << "could not fill levels 0 and 2";-    compaction_count++;-    Put("a", "begin");-    Put("z", "end");-    dbfull()->TEST_CompactMemTable();-  }--  // Step 2: clear level 1 if necessary.-  dbfull()->TEST_CompactRange(1, NULL, NULL);-  ASSERT_EQ(NumTableFilesAtLevel(0), 1);-  ASSERT_EQ(NumTableFilesAtLevel(1), 0);-  ASSERT_EQ(NumTableFilesAtLevel(2), 1);--  // Step 3: read until level 0 compaction disappears.-  int read_count = 0;-  while (NumTableFilesAtLevel(0) > 0) {-    ASSERT_LE(read_count, 10000) << "did not trigger level 0 compaction";-    read_count++;-    ASSERT_EQ("NOT_FOUND", Get("missing"));-  }-}--TEST(DBTest, IterEmpty) {-  Iterator* iter = db_->NewIterator(ReadOptions());--  iter->SeekToFirst();-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  iter->SeekToLast();-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  iter->Seek("foo");-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  delete iter;-}--TEST(DBTest, IterSingle) {-  ASSERT_OK(Put("a", "va"));-  Iterator* iter = db_->NewIterator(ReadOptions());--  iter->SeekToFirst();-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "(invalid)");-  iter->SeekToFirst();-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  iter->SeekToLast();-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "(invalid)");-  iter->SeekToLast();-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  iter->Seek("");-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  iter->Seek("a");-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  iter->Seek("b");-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  delete iter;-}--TEST(DBTest, IterMulti) {-  ASSERT_OK(Put("a", "va"));-  ASSERT_OK(Put("b", "vb"));-  ASSERT_OK(Put("c", "vc"));-  Iterator* iter = db_->NewIterator(ReadOptions());--  iter->SeekToFirst();-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "b->vb");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "c->vc");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "(invalid)");-  iter->SeekToFirst();-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  iter->SeekToLast();-  ASSERT_EQ(IterStatus(iter), "c->vc");-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "b->vb");-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "(invalid)");-  iter->SeekToLast();-  ASSERT_EQ(IterStatus(iter), "c->vc");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  iter->Seek("");-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Seek("a");-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Seek("ax");-  ASSERT_EQ(IterStatus(iter), "b->vb");-  iter->Seek("b");-  ASSERT_EQ(IterStatus(iter), "b->vb");-  iter->Seek("z");-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  // Switch from reverse to forward-  iter->SeekToLast();-  iter->Prev();-  iter->Prev();-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "b->vb");--  // Switch from forward to reverse-  iter->SeekToFirst();-  iter->Next();-  iter->Next();-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "b->vb");--  // Make sure iter stays at snapshot-  ASSERT_OK(Put("a",  "va2"));-  ASSERT_OK(Put("a2", "va3"));-  ASSERT_OK(Put("b",  "vb2"));-  ASSERT_OK(Put("c",  "vc2"));-  ASSERT_OK(Delete("b"));-  iter->SeekToFirst();-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "b->vb");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "c->vc");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "(invalid)");-  iter->SeekToLast();-  ASSERT_EQ(IterStatus(iter), "c->vc");-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "b->vb");-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  delete iter;-}--TEST(DBTest, IterSmallAndLargeMix) {-  ASSERT_OK(Put("a", "va"));-  ASSERT_OK(Put("b", std::string(100000, 'b')));-  ASSERT_OK(Put("c", "vc"));-  ASSERT_OK(Put("d", std::string(100000, 'd')));-  ASSERT_OK(Put("e", std::string(100000, 'e')));--  Iterator* iter = db_->NewIterator(ReadOptions());--  iter->SeekToFirst();-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b'));-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "c->vc");-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd'));-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e'));-  iter->Next();-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  iter->SeekToLast();-  ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e'));-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd'));-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "c->vc");-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b'));-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "a->va");-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "(invalid)");--  delete iter;-}--TEST(DBTest, IterMultiWithDelete) {-  ASSERT_OK(Put("a", "va"));-  ASSERT_OK(Put("b", "vb"));-  ASSERT_OK(Put("c", "vc"));-  ASSERT_OK(Delete("b"));-  ASSERT_EQ("NOT_FOUND", Get("b"));--  Iterator* iter = db_->NewIterator(ReadOptions());-  iter->Seek("c");-  ASSERT_EQ(IterStatus(iter), "c->vc");-  iter->Prev();-  ASSERT_EQ(IterStatus(iter), "a->va");-  delete iter;-}--TEST(DBTest, Recover) {-  ASSERT_OK(Put("foo", "v1"));-  ASSERT_OK(Put("baz", "v5"));--  Reopen();-  ASSERT_EQ("v1", Get("foo"));--  ASSERT_EQ("v1", Get("foo"));-  ASSERT_EQ("v5", Get("baz"));-  ASSERT_OK(Put("bar", "v2"));-  ASSERT_OK(Put("foo", "v3"));--  Reopen();-  ASSERT_EQ("v3", Get("foo"));-  ASSERT_OK(Put("foo", "v4"));-  ASSERT_EQ("v4", Get("foo"));-  ASSERT_EQ("v2", Get("bar"));-  ASSERT_EQ("v5", Get("baz"));-}--TEST(DBTest, RecoveryWithEmptyLog) {-  ASSERT_OK(Put("foo", "v1"));-  ASSERT_OK(Put("foo", "v2"));-  Reopen();-  Reopen();-  ASSERT_OK(Put("foo", "v3"));-  Reopen();-  ASSERT_EQ("v3", Get("foo"));-}--// Check that writes done during a memtable compaction are recovered-// if the database is shutdown during the memtable compaction.-TEST(DBTest, RecoverDuringMemtableCompaction) {-  Options options;-  options.env = env_;-  options.write_buffer_size = 1000000;-  Reopen(&options);--  // Trigger a long memtable compaction and reopen the database during it-  ASSERT_OK(Put("foo", "v1"));                         // Goes to 1st log file-  ASSERT_OK(Put("big1", std::string(10000000, 'x')));  // Fills memtable-  ASSERT_OK(Put("big2", std::string(1000, 'y')));      // Triggers compaction-  ASSERT_OK(Put("bar", "v2"));                         // Goes to new log file--  Reopen(&options);-  ASSERT_EQ("v1", Get("foo"));-  ASSERT_EQ("v2", Get("bar"));-  ASSERT_EQ(std::string(10000000, 'x'), Get("big1"));-  ASSERT_EQ(std::string(1000, 'y'), Get("big2"));-}--static std::string Key(int i) {-  char buf[100];-  snprintf(buf, sizeof(buf), "key%06d", i);-  return std::string(buf);-}--TEST(DBTest, MinorCompactionsHappen) {-  Options options;-  options.write_buffer_size = 10000;-  Reopen(&options);--  const int N = 500;--  int starting_num_tables = TotalTableFiles();-  for (int i = 0; i < N; i++) {-    ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v')));-  }-  int ending_num_tables = TotalTableFiles();-  ASSERT_GT(ending_num_tables, starting_num_tables);--  for (int i = 0; i < N; i++) {-    ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));-  }--  Reopen();--  for (int i = 0; i < N; i++) {-    ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));-  }-}--TEST(DBTest, RecoverWithLargeLog) {-  {-    Options options;-    Reopen(&options);-    ASSERT_OK(Put("big1", std::string(200000, '1')));-    ASSERT_OK(Put("big2", std::string(200000, '2')));-    ASSERT_OK(Put("small3", std::string(10, '3')));-    ASSERT_OK(Put("small4", std::string(10, '4')));-    ASSERT_EQ(NumTableFilesAtLevel(0), 0);-  }--  // Make sure that if we re-open with a small write buffer size that-  // we flush table files in the middle of a large log file.-  Options options;-  options.write_buffer_size = 100000;-  Reopen(&options);-  ASSERT_EQ(NumTableFilesAtLevel(0), 3);-  ASSERT_EQ(std::string(200000, '1'), Get("big1"));-  ASSERT_EQ(std::string(200000, '2'), Get("big2"));-  ASSERT_EQ(std::string(10, '3'), Get("small3"));-  ASSERT_EQ(std::string(10, '4'), Get("small4"));-  ASSERT_GT(NumTableFilesAtLevel(0), 1);-}--TEST(DBTest, CompactionsGenerateMultipleFiles) {-  Options options;-  options.write_buffer_size = 100000000;        // Large write buffer-  Reopen(&options);--  Random rnd(301);--  // Write 8MB (80 values, each 100K)-  ASSERT_EQ(NumTableFilesAtLevel(0), 0);-  std::vector<std::string> values;-  for (int i = 0; i < 80; i++) {-    values.push_back(RandomString(&rnd, 100000));-    ASSERT_OK(Put(Key(i), values[i]));-  }--  // Reopening moves updates to level-0-  Reopen(&options);-  dbfull()->TEST_CompactRange(0, NULL, NULL);--  ASSERT_EQ(NumTableFilesAtLevel(0), 0);-  ASSERT_GT(NumTableFilesAtLevel(1), 1);-  for (int i = 0; i < 80; i++) {-    ASSERT_EQ(Get(Key(i)), values[i]);-  }-}--TEST(DBTest, RepeatedWritesToSameKey) {-  Options options;-  options.env = env_;-  options.write_buffer_size = 100000;  // Small write buffer-  Reopen(&options);--  // We must have at most one file per level except for level-0,-  // which may have up to kL0_StopWritesTrigger files.-  const int kMaxFiles = config::kNumLevels + config::kL0_StopWritesTrigger;--  Random rnd(301);-  std::string value = RandomString(&rnd, 2 * options.write_buffer_size);-  for (int i = 0; i < 5 * kMaxFiles; i++) {-    Put("key", value);-    ASSERT_LE(TotalTableFiles(), kMaxFiles);-    fprintf(stderr, "after %d: %d files\n", int(i+1), TotalTableFiles());-  }-}--TEST(DBTest, SparseMerge) {-  Options options;-  options.compression = kNoCompression;-  Reopen(&options);--  FillLevels("A", "Z");--  // Suppose there is:-  //    small amount of data with prefix A-  //    large amount of data with prefix B-  //    small amount of data with prefix C-  // and that recent updates have made small changes to all three prefixes.-  // Check that we do not do a compaction that merges all of B in one shot.-  const std::string value(1000, 'x');-  Put("A", "va");-  // Write approximately 100MB of "B" values-  for (int i = 0; i < 100000; i++) {-    char key[100];-    snprintf(key, sizeof(key), "B%010d", i);-    Put(key, value);-  }-  Put("C", "vc");-  dbfull()->TEST_CompactMemTable();-  dbfull()->TEST_CompactRange(0, NULL, NULL);--  // Make sparse update-  Put("A",    "va2");-  Put("B100", "bvalue2");-  Put("C",    "vc2");-  dbfull()->TEST_CompactMemTable();--  // Compactions should not cause us to create a situation where-  // a file overlaps too much data at the next level.-  ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);-  dbfull()->TEST_CompactRange(0, NULL, NULL);-  ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);-  dbfull()->TEST_CompactRange(1, NULL, NULL);-  ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);-}--static bool Between(uint64_t val, uint64_t low, uint64_t high) {-  bool result = (val >= low) && (val <= high);-  if (!result) {-    fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n",-            (unsigned long long)(val),-            (unsigned long long)(low),-            (unsigned long long)(high));-  }-  return result;-}--TEST(DBTest, ApproximateSizes) {-  Options options;-  options.write_buffer_size = 100000000;        // Large write buffer-  options.compression = kNoCompression;-  DestroyAndReopen();--  ASSERT_TRUE(Between(Size("", "xyz"), 0, 0));-  Reopen(&options);-  ASSERT_TRUE(Between(Size("", "xyz"), 0, 0));--  // Write 8MB (80 values, each 100K)-  ASSERT_EQ(NumTableFilesAtLevel(0), 0);-  const int N = 80;-  Random rnd(301);-  for (int i = 0; i < N; i++) {-    ASSERT_OK(Put(Key(i), RandomString(&rnd, 100000)));-  }--  // 0 because GetApproximateSizes() does not account for memtable space-  ASSERT_TRUE(Between(Size("", Key(50)), 0, 0));--  // Check sizes across recovery by reopening a few times-  for (int run = 0; run < 3; run++) {-    Reopen(&options);--    for (int compact_start = 0; compact_start < N; compact_start += 10) {-      for (int i = 0; i < N; i += 10) {-        ASSERT_TRUE(Between(Size("", Key(i)), 100000*i, 100000*i + 10000));-        ASSERT_TRUE(Between(Size("", Key(i)+".suffix"),-                            100000 * (i+1), 100000 * (i+1) + 10000));-        ASSERT_TRUE(Between(Size(Key(i), Key(i+10)),-                            100000 * 10, 100000 * 10 + 10000));-      }-      ASSERT_TRUE(Between(Size("", Key(50)), 5000000, 5010000));-      ASSERT_TRUE(Between(Size("", Key(50)+".suffix"), 5100000, 5110000));--      std::string cstart_str = Key(compact_start);-      std::string cend_str = Key(compact_start + 9);-      Slice cstart = cstart_str;-      Slice cend = cend_str;-      dbfull()->TEST_CompactRange(0, &cstart, &cend);-    }--    ASSERT_EQ(NumTableFilesAtLevel(0), 0);-    ASSERT_GT(NumTableFilesAtLevel(1), 0);-  }-}--TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) {-  Options options;-  options.compression = kNoCompression;-  Reopen();--  Random rnd(301);-  std::string big1 = RandomString(&rnd, 100000);-  ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000)));-  ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000)));-  ASSERT_OK(Put(Key(2), big1));-  ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000)));-  ASSERT_OK(Put(Key(4), big1));-  ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000)));-  ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000)));-  ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000)));--  // Check sizes across recovery by reopening a few times-  for (int run = 0; run < 3; run++) {-    Reopen(&options);--    ASSERT_TRUE(Between(Size("", Key(0)), 0, 0));-    ASSERT_TRUE(Between(Size("", Key(1)), 10000, 11000));-    ASSERT_TRUE(Between(Size("", Key(2)), 20000, 21000));-    ASSERT_TRUE(Between(Size("", Key(3)), 120000, 121000));-    ASSERT_TRUE(Between(Size("", Key(4)), 130000, 131000));-    ASSERT_TRUE(Between(Size("", Key(5)), 230000, 231000));-    ASSERT_TRUE(Between(Size("", Key(6)), 240000, 241000));-    ASSERT_TRUE(Between(Size("", Key(7)), 540000, 541000));-    ASSERT_TRUE(Between(Size("", Key(8)), 550000, 551000));--    ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000));--    dbfull()->TEST_CompactRange(0, NULL, NULL);-  }-}--TEST(DBTest, IteratorPinsRef) {-  Put("foo", "hello");--  // Get iterator that will yield the current contents of the DB.-  Iterator* iter = db_->NewIterator(ReadOptions());--  // Write to force compactions-  Put("foo", "newvalue1");-  for (int i = 0; i < 100; i++) {-    ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values-  }-  Put("foo", "newvalue2");--  iter->SeekToFirst();-  ASSERT_TRUE(iter->Valid());-  ASSERT_EQ("foo", iter->key().ToString());-  ASSERT_EQ("hello", iter->value().ToString());-  iter->Next();-  ASSERT_TRUE(!iter->Valid());-  delete iter;-}--TEST(DBTest, Snapshot) {-  Put("foo", "v1");-  const Snapshot* s1 = db_->GetSnapshot();-  Put("foo", "v2");-  const Snapshot* s2 = db_->GetSnapshot();-  Put("foo", "v3");-  const Snapshot* s3 = db_->GetSnapshot();--  Put("foo", "v4");-  ASSERT_EQ("v1", Get("foo", s1));-  ASSERT_EQ("v2", Get("foo", s2));-  ASSERT_EQ("v3", Get("foo", s3));-  ASSERT_EQ("v4", Get("foo"));--  db_->ReleaseSnapshot(s3);-  ASSERT_EQ("v1", Get("foo", s1));-  ASSERT_EQ("v2", Get("foo", s2));-  ASSERT_EQ("v4", Get("foo"));--  db_->ReleaseSnapshot(s1);-  ASSERT_EQ("v2", Get("foo", s2));-  ASSERT_EQ("v4", Get("foo"));--  db_->ReleaseSnapshot(s2);-  ASSERT_EQ("v4", Get("foo"));-}--TEST(DBTest, HiddenValuesAreRemoved) {-  Random rnd(301);-  FillLevels("a", "z");--  std::string big = RandomString(&rnd, 50000);-  Put("foo", big);-  Put("pastfoo", "v");-  const Snapshot* snapshot = db_->GetSnapshot();-  Put("foo", "tiny");-  Put("pastfoo2", "v2");        // Advance sequence number one more--  ASSERT_OK(dbfull()->TEST_CompactMemTable());-  ASSERT_GT(NumTableFilesAtLevel(0), 0);--  ASSERT_EQ(big, Get("foo", snapshot));-  ASSERT_TRUE(Between(Size("", "pastfoo"), 50000, 60000));-  db_->ReleaseSnapshot(snapshot);-  ASSERT_EQ(AllEntriesFor("foo"), "[ tiny, " + big + " ]");-  Slice x("x");-  dbfull()->TEST_CompactRange(0, NULL, &x);-  ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]");-  ASSERT_EQ(NumTableFilesAtLevel(0), 0);-  ASSERT_GE(NumTableFilesAtLevel(1), 1);-  dbfull()->TEST_CompactRange(1, NULL, &x);-  ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]");--  ASSERT_TRUE(Between(Size("", "pastfoo"), 0, 1000));-}--TEST(DBTest, DeletionMarkers1) {-  Put("foo", "v1");-  ASSERT_OK(dbfull()->TEST_CompactMemTable());-  const int last = config::kMaxMemCompactLevel;-  ASSERT_EQ(NumTableFilesAtLevel(last), 1);   // foo => v1 is now in last level--  // Place a table at level last-1 to prevent merging with preceding mutation-  Put("a", "begin");-  Put("z", "end");-  dbfull()->TEST_CompactMemTable();-  ASSERT_EQ(NumTableFilesAtLevel(last), 1);-  ASSERT_EQ(NumTableFilesAtLevel(last-1), 1);--  Delete("foo");-  Put("foo", "v2");-  ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");-  ASSERT_OK(dbfull()->TEST_CompactMemTable());  // Moves to level last-2-  ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");-  Slice z("z");-  dbfull()->TEST_CompactRange(last-2, NULL, &z);-  // DEL eliminated, but v1 remains because we aren't compacting that level-  // (DEL can be eliminated because v2 hides v1).-  ASSERT_EQ(AllEntriesFor("foo"), "[ v2, v1 ]");-  dbfull()->TEST_CompactRange(last-1, NULL, NULL);-  // Merging last-1 w/ last, so we are the base level for "foo", so-  // DEL is removed.  (as is v1).-  ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]");-}--TEST(DBTest, DeletionMarkers2) {-  Put("foo", "v1");-  ASSERT_OK(dbfull()->TEST_CompactMemTable());-  const int last = config::kMaxMemCompactLevel;-  ASSERT_EQ(NumTableFilesAtLevel(last), 1);   // foo => v1 is now in last level--  // Place a table at level last-1 to prevent merging with preceding mutation-  Put("a", "begin");-  Put("z", "end");-  dbfull()->TEST_CompactMemTable();-  ASSERT_EQ(NumTableFilesAtLevel(last), 1);-  ASSERT_EQ(NumTableFilesAtLevel(last-1), 1);--  Delete("foo");-  ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");-  ASSERT_OK(dbfull()->TEST_CompactMemTable());  // Moves to level last-2-  ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");-  dbfull()->TEST_CompactRange(last-2, NULL, NULL);-  // DEL kept: "last" file overlaps-  ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");-  dbfull()->TEST_CompactRange(last-1, NULL, NULL);-  // Merging last-1 w/ last, so we are the base level for "foo", so-  // DEL is removed.  (as is v1).-  ASSERT_EQ(AllEntriesFor("foo"), "[ ]");-}--TEST(DBTest, OverlapInLevel0) {-  ASSERT_EQ(config::kMaxMemCompactLevel, 2) << "Fix test to match config";--  // Fill levels 1 and 2 to disable the pushing of new memtables to levels > 0.-  ASSERT_OK(Put("100", "v100"));-  ASSERT_OK(Put("999", "v999"));-  dbfull()->TEST_CompactMemTable();-  ASSERT_OK(Delete("100"));-  ASSERT_OK(Delete("999"));-  dbfull()->TEST_CompactMemTable();-  ASSERT_EQ("0,1,1", FilesPerLevel());--  // Make files spanning the following ranges in level-0:-  //  files[0]  200 .. 900-  //  files[1]  300 .. 500-  // Note that files are sorted by smallest key.-  ASSERT_OK(Put("300", "v300"));-  ASSERT_OK(Put("500", "v500"));-  dbfull()->TEST_CompactMemTable();-  ASSERT_OK(Put("200", "v200"));-  ASSERT_OK(Put("600", "v600"));-  ASSERT_OK(Put("900", "v900"));-  dbfull()->TEST_CompactMemTable();-  ASSERT_EQ("2,1,1", FilesPerLevel());--  // Compact away the placeholder files we created initially-  dbfull()->TEST_CompactRange(1, NULL, NULL);-  dbfull()->TEST_CompactRange(2, NULL, NULL);-  ASSERT_EQ("2", FilesPerLevel());--  // Do a memtable compaction.  Before bug-fix, the compaction would-  // not detect the overlap with level-0 files and would incorrectly place-  // the deletion in a deeper level.-  ASSERT_OK(Delete("600"));-  dbfull()->TEST_CompactMemTable();-  ASSERT_EQ("3", FilesPerLevel());-  ASSERT_EQ("NOT_FOUND", Get("600"));-}--TEST(DBTest, L0_CompactionBug_Issue44_a) {- Reopen();- ASSERT_OK(Put("b", "v"));- Reopen();- ASSERT_OK(Delete("b"));- ASSERT_OK(Delete("a"));- Reopen();- ASSERT_OK(Delete("a"));- Reopen();- ASSERT_OK(Put("a", "v"));- Reopen();- Reopen();- ASSERT_EQ("(a->v)", Contents());- env_->SleepForMicroseconds(1000000);  // Wait for compaction to finish- ASSERT_EQ("(a->v)", Contents());-}--TEST(DBTest, L0_CompactionBug_Issue44_b) {- Reopen();- Put("","");- Reopen();- Delete("e");- Put("","");- Reopen();- Put("c", "cv");- Reopen();- Put("","");- Reopen();- Put("","");- env_->SleepForMicroseconds(1000000);  // Wait for compaction to finish- Reopen();- Put("d","dv");- Reopen();- Put("","");- Reopen();- Delete("d");- Delete("b");- Reopen();- ASSERT_EQ("(->)(c->cv)", Contents());- env_->SleepForMicroseconds(1000000);  // Wait for compaction to finish- ASSERT_EQ("(->)(c->cv)", Contents());-}--TEST(DBTest, ComparatorCheck) {-  class NewComparator : public Comparator {-   public:-    virtual const char* Name() const { return "leveldb.NewComparator"; }-    virtual int Compare(const Slice& a, const Slice& b) const {-      return BytewiseComparator()->Compare(a, b);-    }-    virtual void FindShortestSeparator(std::string* s, const Slice& l) const {-      BytewiseComparator()->FindShortestSeparator(s, l);-    }-    virtual void FindShortSuccessor(std::string* key) const {-      BytewiseComparator()->FindShortSuccessor(key);-    }-  };-  NewComparator cmp;-  Options new_options;-  new_options.comparator = &cmp;-  Status s = TryReopen(&new_options);-  ASSERT_TRUE(!s.ok());-  ASSERT_TRUE(s.ToString().find("comparator") != std::string::npos)-      << s.ToString();-}--TEST(DBTest, CustomComparator) {-  class NumberComparator : public Comparator {-   public:-    virtual const char* Name() const { return "test.NumberComparator"; }-    virtual int Compare(const Slice& a, const Slice& b) const {-      return ToNumber(a) - ToNumber(b);-    }-    virtual void FindShortestSeparator(std::string* s, const Slice& l) const {-      ToNumber(*s);     // Check format-      ToNumber(l);      // Check format-    }-    virtual void FindShortSuccessor(std::string* key) const {-      ToNumber(*key);   // Check format-    }-   private:-    static int ToNumber(const Slice& x) {-      // Check that there are no extra characters.-      ASSERT_TRUE(x.size() >= 2 && x[0] == '[' && x[x.size()-1] == ']')-          << EscapeString(x);-      int val;-      char ignored;-      ASSERT_TRUE(sscanf(x.ToString().c_str(), "[%i]%c", &val, &ignored) == 1)-          << EscapeString(x);-      return val;-    }-  };-  NumberComparator cmp;-  Options new_options;-  new_options.create_if_missing = true;-  new_options.comparator = &cmp;-  new_options.write_buffer_size = 1000;  // Compact more often-  DestroyAndReopen(&new_options);-  ASSERT_OK(Put("[10]", "ten"));-  ASSERT_OK(Put("[0x14]", "twenty"));-  for (int i = 0; i < 2; i++) {-    ASSERT_EQ("ten", Get("[10]"));-    ASSERT_EQ("ten", Get("[0xa]"));-    ASSERT_EQ("twenty", Get("[20]"));-    ASSERT_EQ("twenty", Get("[0x14]"));-    Compact("[0]", "[9999]");-  }--  for (int run = 0; run < 2; run++) {-    for (int i = 0; i < 1000; i++) {-      char buf[100];-      snprintf(buf, sizeof(buf), "[%d]", i*10);-      ASSERT_OK(Put(buf, buf));-    }-    Compact("[0]", "[1000000]");-  }-}--TEST(DBTest, ManualCompaction) {-  ASSERT_EQ(config::kMaxMemCompactLevel, 2)-      << "Need to update this test to match kMaxMemCompactLevel";--  MakeTables(3, "p", "q");-  ASSERT_EQ("1,1,1", FilesPerLevel());--  // Compaction range falls before files-  Compact("", "c");-  ASSERT_EQ("1,1,1", FilesPerLevel());--  // Compaction range falls after files-  Compact("r", "z");-  ASSERT_EQ("1,1,1", FilesPerLevel());--  // Compaction range overlaps files-  Compact("p1", "p9");-  ASSERT_EQ("0,0,1", FilesPerLevel());--  // Populate a different range-  MakeTables(3, "c", "e");-  ASSERT_EQ("1,1,2", FilesPerLevel());--  // Compact just the new range-  Compact("b", "f");-  ASSERT_EQ("0,0,2", FilesPerLevel());--  // Compact all-  MakeTables(1, "a", "z");-  ASSERT_EQ("0,1,2", FilesPerLevel());-  db_->CompactRange(NULL, NULL);-  ASSERT_EQ("0,0,1", FilesPerLevel());-}--TEST(DBTest, DBOpen_Options) {-  std::string dbname = test::TmpDir() + "/db_options_test";-  DestroyDB(dbname, Options());--  // Does not exist, and create_if_missing == false: error-  DB* db = NULL;-  Options opts;-  opts.create_if_missing = false;-  Status s = DB::Open(opts, dbname, &db);-  ASSERT_TRUE(strstr(s.ToString().c_str(), "does not exist") != NULL);-  ASSERT_TRUE(db == NULL);--  // Does not exist, and create_if_missing == true: OK-  opts.create_if_missing = true;-  s = DB::Open(opts, dbname, &db);-  ASSERT_OK(s);-  ASSERT_TRUE(db != NULL);--  delete db;-  db = NULL;--  // Does exist, and error_if_exists == true: error-  opts.create_if_missing = false;-  opts.error_if_exists = true;-  s = DB::Open(opts, dbname, &db);-  ASSERT_TRUE(strstr(s.ToString().c_str(), "exists") != NULL);-  ASSERT_TRUE(db == NULL);--  // Does exist, and error_if_exists == false: OK-  opts.create_if_missing = true;-  opts.error_if_exists = false;-  s = DB::Open(opts, dbname, &db);-  ASSERT_OK(s);-  ASSERT_TRUE(db != NULL);--  delete db;-  db = NULL;-}--// Check that number of files does not grow when we are out of space-TEST(DBTest, NoSpace) {-  Options options;-  options.env = env_;-  Reopen(&options);--  ASSERT_OK(Put("foo", "v1"));-  ASSERT_EQ("v1", Get("foo"));-  Compact("a", "z");-  const int num_files = CountFiles();-  env_->no_space_.Release_Store(env_);   // Force out-of-space errors-  for (int i = 0; i < 10; i++) {-    for (int level = 0; level < config::kNumLevels-1; level++) {-      dbfull()->TEST_CompactRange(level, NULL, NULL);-    }-  }-  env_->no_space_.Release_Store(NULL);-  ASSERT_LT(CountFiles(), num_files + 5);-}--TEST(DBTest, FilesDeletedAfterCompaction) {-  ASSERT_OK(Put("foo", "v2"));-  Compact("a", "z");-  const int num_files = CountFiles();-  for (int i = 0; i < 10; i++) {-    ASSERT_OK(Put("foo", "v2"));-    Compact("a", "z");-  }-  ASSERT_EQ(CountFiles(), num_files);-}--// Multi-threaded test:-namespace {--static const int kNumThreads = 4;-static const int kTestSeconds = 10;-static const int kNumKeys = 1000;--struct MTState {-  DBTest* test;-  port::AtomicPointer stop;-  port::AtomicPointer counter[kNumThreads];-  port::AtomicPointer thread_done[kNumThreads];-};--struct MTThread {-  MTState* state;-  int id;-};--static void MTThreadBody(void* arg) {-  MTThread* t = reinterpret_cast<MTThread*>(arg);-  int id = t->id;-  DB* db = t->state->test->db_;-  uintptr_t counter = 0;-  fprintf(stderr, "... starting thread %d\n", id);-  Random rnd(1000 + id);-  std::string value;-  char valbuf[1500];-  while (t->state->stop.Acquire_Load() == NULL) {-    t->state->counter[id].Release_Store(reinterpret_cast<void*>(counter));--    int key = rnd.Uniform(kNumKeys);-    char keybuf[20];-    snprintf(keybuf, sizeof(keybuf), "%016d", key);--    if (rnd.OneIn(2)) {-      // Write values of the form <key, my id, counter>.-      // We add some padding for force compactions.-      snprintf(valbuf, sizeof(valbuf), "%d.%d.%-1000d",-               key, id, static_cast<int>(counter));-      ASSERT_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf)));-    } else {-      // Read a value and verify that it matches the pattern written above.-      Status s = db->Get(ReadOptions(), Slice(keybuf), &value);-      if (s.IsNotFound()) {-        // Key has not yet been written-      } else {-        // Check that the writer thread counter is >= the counter in the value-        ASSERT_OK(s);-        int k, w, c;-        ASSERT_EQ(3, sscanf(value.c_str(), "%d.%d.%d", &k, &w, &c)) << value;-        ASSERT_EQ(k, key);-        ASSERT_GE(w, 0);-        ASSERT_LT(w, kNumThreads);-        ASSERT_LE(c, reinterpret_cast<uintptr_t>(-            t->state->counter[w].Acquire_Load()));-      }-    }-    counter++;-  }-  t->state->thread_done[id].Release_Store(t);-  fprintf(stderr, "... stopping thread %d after %d ops\n", id, int(counter));-}--}  // namespace--TEST(DBTest, MultiThreaded) {-  // Initialize state-  MTState mt;-  mt.test = this;-  mt.stop.Release_Store(0);-  for (int id = 0; id < kNumThreads; id++) {-    mt.counter[id].Release_Store(0);-    mt.thread_done[id].Release_Store(0);-  }--  // Start threads-  MTThread thread[kNumThreads];-  for (int id = 0; id < kNumThreads; id++) {-    thread[id].state = &mt;-    thread[id].id = id;-    env_->StartThread(MTThreadBody, &thread[id]);-  }--  // Let them run for a while-  env_->SleepForMicroseconds(kTestSeconds * 1000000);--  // Stop the threads and wait for them to finish-  mt.stop.Release_Store(&mt);-  for (int id = 0; id < kNumThreads; id++) {-    while (mt.thread_done[id].Acquire_Load() == NULL) {-      env_->SleepForMicroseconds(100000);-    }-  }-}--namespace {-typedef std::map<std::string, std::string> KVMap;-}--class ModelDB: public DB {- public:-  class ModelSnapshot : public Snapshot {-   public:-    KVMap map_;-  };--  explicit ModelDB(const Options& options): options_(options) { }-  ~ModelDB() { }-  virtual Status Put(const WriteOptions& o, const Slice& k, const Slice& v) {-    return DB::Put(o, k, v);-  }-  virtual Status Delete(const WriteOptions& o, const Slice& key) {-    return DB::Delete(o, key);-  }-  virtual Status Get(const ReadOptions& options,-                     const Slice& key, std::string* value) {-    assert(false);      // Not implemented-    return Status::NotFound(key);-  }-  virtual Iterator* NewIterator(const ReadOptions& options) {-    if (options.snapshot == NULL) {-      KVMap* saved = new KVMap;-      *saved = map_;-      return new ModelIter(saved, true);-    } else {-      const KVMap* snapshot_state =-          &(reinterpret_cast<const ModelSnapshot*>(options.snapshot)->map_);-      return new ModelIter(snapshot_state, false);-    }-  }-  virtual const Snapshot* GetSnapshot() {-    ModelSnapshot* snapshot = new ModelSnapshot;-    snapshot->map_ = map_;-    return snapshot;-  }--  virtual void ReleaseSnapshot(const Snapshot* snapshot) {-    delete reinterpret_cast<const ModelSnapshot*>(snapshot);-  }-  virtual Status Write(const WriteOptions& options, WriteBatch* batch) {-    class Handler : public WriteBatch::Handler {-     public:-      KVMap* map_;-      virtual void Put(const Slice& key, const Slice& value) {-        (*map_)[key.ToString()] = value.ToString();-      }-      virtual void Delete(const Slice& key) {-        map_->erase(key.ToString());-      }-    };-    Handler handler;-    handler.map_ = &map_;-    return batch->Iterate(&handler);-  }--  virtual bool GetProperty(const Slice& property, std::string* value) {-    return false;-  }-  virtual void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) {-    for (int i = 0; i < n; i++) {-      sizes[i] = 0;-    }-  }-  virtual void CompactRange(const Slice* start, const Slice* end) {-  }-- private:-  class ModelIter: public Iterator {-   public:-    ModelIter(const KVMap* map, bool owned)-        : map_(map), owned_(owned), iter_(map_->end()) {-    }-    ~ModelIter() {-      if (owned_) delete map_;-    }-    virtual bool Valid() const { return iter_ != map_->end(); }-    virtual void SeekToFirst() { iter_ = map_->begin(); }-    virtual void SeekToLast() {-      if (map_->empty()) {-        iter_ = map_->end();-      } else {-        iter_ = map_->find(map_->rbegin()->first);-      }-    }-    virtual void Seek(const Slice& k) {-      iter_ = map_->lower_bound(k.ToString());-    }-    virtual void Next() { ++iter_; }-    virtual void Prev() { --iter_; }-    virtual Slice key() const { return iter_->first; }-    virtual Slice value() const { return iter_->second; }-    virtual Status status() const { return Status::OK(); }-   private:-    const KVMap* const map_;-    const bool owned_;  // Do we own map_-    KVMap::const_iterator iter_;-  };-  const Options options_;-  KVMap map_;-};--static std::string RandomKey(Random* rnd) {-  int len = (rnd->OneIn(3)-             ? 1                // Short sometimes to encourage collisions-             : (rnd->OneIn(100) ? rnd->Skewed(10) : rnd->Uniform(10)));-  return test::RandomKey(rnd, len);-}--static bool CompareIterators(int step,-                             DB* model,-                             DB* db,-                             const Snapshot* model_snap,-                             const Snapshot* db_snap) {-  ReadOptions options;-  options.snapshot = model_snap;-  Iterator* miter = model->NewIterator(options);-  options.snapshot = db_snap;-  Iterator* dbiter = db->NewIterator(options);-  bool ok = true;-  int count = 0;-  for (miter->SeekToFirst(), dbiter->SeekToFirst();-       ok && miter->Valid() && dbiter->Valid();-       miter->Next(), dbiter->Next()) {-    count++;-    if (miter->key().compare(dbiter->key()) != 0) {-      fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n",-              step,-              EscapeString(miter->key()).c_str(),-              EscapeString(dbiter->key()).c_str());-      ok = false;-      break;-    }--    if (miter->value().compare(dbiter->value()) != 0) {-      fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n",-              step,-              EscapeString(miter->key()).c_str(),-              EscapeString(miter->value()).c_str(),-              EscapeString(miter->value()).c_str());-      ok = false;-    }-  }--  if (ok) {-    if (miter->Valid() != dbiter->Valid()) {-      fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n",-              step, miter->Valid(), dbiter->Valid());-      ok = false;-    }-  }-  fprintf(stderr, "%d entries compared: ok=%d\n", count, ok);-  delete miter;-  delete dbiter;-  return ok;-}--TEST(DBTest, Randomized) {-  Random rnd(test::RandomSeed());-  ModelDB model(last_options_);-  const int N = 10000;-  const Snapshot* model_snap = NULL;-  const Snapshot* db_snap = NULL;-  std::string k, v;-  for (int step = 0; step < N; step++) {-    if (step % 100 == 0) {-      fprintf(stderr, "Step %d of %d\n", step, N);-    }-    int p = rnd.Uniform(100);-    if (p < 45) {                               // Put-      k = RandomKey(&rnd);-      v = RandomString(&rnd,-                       rnd.OneIn(20)-                       ? 100 + rnd.Uniform(100)-                       : rnd.Uniform(8));-      ASSERT_OK(model.Put(WriteOptions(), k, v));-      ASSERT_OK(db_->Put(WriteOptions(), k, v));--    } else if (p < 90) {                        // Delete-      k = RandomKey(&rnd);-      ASSERT_OK(model.Delete(WriteOptions(), k));-      ASSERT_OK(db_->Delete(WriteOptions(), k));---    } else {                                    // Multi-element batch-      WriteBatch b;-      const int num = rnd.Uniform(8);-      for (int i = 0; i < num; i++) {-        if (i == 0 || !rnd.OneIn(10)) {-          k = RandomKey(&rnd);-        } else {-          // Periodically re-use the same key from the previous iter, so-          // we have multiple entries in the write batch for the same key-        }-        if (rnd.OneIn(2)) {-          v = RandomString(&rnd, rnd.Uniform(10));-          b.Put(k, v);-        } else {-          b.Delete(k);-        }-      }-      ASSERT_OK(model.Write(WriteOptions(), &b));-      ASSERT_OK(db_->Write(WriteOptions(), &b));-    }--    if ((step % 100) == 0) {-      ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL));-      ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap));-      // Save a snapshot from each DB this time that we'll use next-      // time we compare things, to make sure the current state is-      // preserved with the snapshot-      if (model_snap != NULL) model.ReleaseSnapshot(model_snap);-      if (db_snap != NULL) db_->ReleaseSnapshot(db_snap);--      Reopen();-      ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL));--      model_snap = model.GetSnapshot();-      db_snap = db_->GetSnapshot();-    }-  }-  if (model_snap != NULL) model.ReleaseSnapshot(model_snap);-  if (db_snap != NULL) db_->ReleaseSnapshot(db_snap);-}--std::string MakeKey(unsigned int num) {-  char buf[30];-  snprintf(buf, sizeof(buf), "%016u", num);-  return std::string(buf);-}--void BM_LogAndApply(int iters, int num_base_files) {-  std::string dbname = test::TmpDir() + "/leveldb_test_benchmark";-  DestroyDB(dbname, Options());--  DB* db = NULL;-  Options opts;-  opts.create_if_missing = true;-  Status s = DB::Open(opts, dbname, &db);-  ASSERT_OK(s);-  ASSERT_TRUE(db != NULL);--  delete db;-  db = NULL;--  Env* env = Env::Default();--  port::Mutex mu;-  MutexLock l(&mu);--  InternalKeyComparator cmp(BytewiseComparator());-  Options options;-  VersionSet vset(dbname, &options, NULL, &cmp);-  ASSERT_OK(vset.Recover());-  VersionEdit vbase;-  uint64_t fnum = 1;-  for (int i = 0; i < num_base_files; i++) {-    InternalKey start(MakeKey(2*fnum), 1, kTypeValue);-    InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion);-    vbase.AddFile(2, fnum++, 1 /* file size */, start, limit);-  }-  ASSERT_OK(vset.LogAndApply(&vbase, &mu));--  uint64_t start_micros = env->NowMicros();--  for (int i = 0; i < iters; i++) {-    VersionEdit vedit;-    vedit.DeleteFile(2, fnum);-    InternalKey start(MakeKey(2*fnum), 1, kTypeValue);-    InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion);-    vedit.AddFile(2, fnum++, 1 /* file size */, start, limit);-    vset.LogAndApply(&vedit, &mu);-  }-  uint64_t stop_micros = env->NowMicros();-  unsigned int us = stop_micros - start_micros;-  char buf[16];-  snprintf(buf, sizeof(buf), "%d", num_base_files);-  fprintf(stderr,-          "BM_LogAndApply/%-6s   %8d iters : %9u us (%7.0f us / iter)\n",-          buf, iters, us, ((float)us) / iters);-}--}  // namespace leveldb--int main(int argc, char** argv) {-  if (argc > 1 && std::string(argv[1]) == "--benchmark") {-    leveldb::BM_LogAndApply(1000, 1);-    leveldb::BM_LogAndApply(1000, 100);-    leveldb::BM_LogAndApply(1000, 10000);-    leveldb::BM_LogAndApply(100, 100000);-    return 0;-  }--  return leveldb::test::RunAllTests();-}
− cbits/leveldb/db/dbformat.cc
@@ -1,120 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include <stdio.h>-#include "db/dbformat.h"-#include "port/port.h"-#include "util/coding.h"--namespace leveldb {--static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) {-  assert(seq <= kMaxSequenceNumber);-  assert(t <= kValueTypeForSeek);-  return (seq << 8) | t;-}--void AppendInternalKey(std::string* result, const ParsedInternalKey& key) {-  result->append(key.user_key.data(), key.user_key.size());-  PutFixed64(result, PackSequenceAndType(key.sequence, key.type));-}--std::string ParsedInternalKey::DebugString() const {-  char buf[50];-  snprintf(buf, sizeof(buf), "' @ %llu : %d",-           (unsigned long long) sequence,-           int(type));-  std::string result = "'";-  result += user_key.ToString();-  result += buf;-  return result;-}--std::string InternalKey::DebugString() const {-  std::string result;-  ParsedInternalKey parsed;-  if (ParseInternalKey(rep_, &parsed)) {-    result = parsed.DebugString();-  } else {-    result = "(bad)";-    result.append(EscapeString(rep_));-  }-  return result;-}--const char* InternalKeyComparator::Name() const {-  return "leveldb.InternalKeyComparator";-}--int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const {-  // Order by:-  //    increasing user key (according to user-supplied comparator)-  //    decreasing sequence number-  //    decreasing type (though sequence# should be enough to disambiguate)-  int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));-  if (r == 0) {-    const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);-    const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);-    if (anum > bnum) {-      r = -1;-    } else if (anum < bnum) {-      r = +1;-    }-  }-  return r;-}--void InternalKeyComparator::FindShortestSeparator(-      std::string* start,-      const Slice& limit) const {-  // Attempt to shorten the user portion of the key-  Slice user_start = ExtractUserKey(*start);-  Slice user_limit = ExtractUserKey(limit);-  std::string tmp(user_start.data(), user_start.size());-  user_comparator_->FindShortestSeparator(&tmp, user_limit);-  if (tmp.size() < user_start.size() &&-      user_comparator_->Compare(user_start, tmp) < 0) {-    // User key has become shorter physically, but larger logically.-    // Tack on the earliest possible number to the shortened user key.-    PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek));-    assert(this->Compare(*start, tmp) < 0);-    assert(this->Compare(tmp, limit) < 0);-    start->swap(tmp);-  }-}--void InternalKeyComparator::FindShortSuccessor(std::string* key) const {-  Slice user_key = ExtractUserKey(*key);-  std::string tmp(user_key.data(), user_key.size());-  user_comparator_->FindShortSuccessor(&tmp);-  if (tmp.size() < user_key.size() &&-      user_comparator_->Compare(user_key, tmp) < 0) {-    // User key has become shorter physically, but larger logically.-    // Tack on the earliest possible number to the shortened user key.-    PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek));-    assert(this->Compare(*key, tmp) < 0);-    key->swap(tmp);-  }-}--LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) {-  size_t usize = user_key.size();-  size_t needed = usize + 13;  // A conservative estimate-  char* dst;-  if (needed <= sizeof(space_)) {-    dst = space_;-  } else {-    dst = new char[needed];-  }-  start_ = dst;-  dst = EncodeVarint32(dst, usize + 8);-  kstart_ = dst;-  memcpy(dst, user_key.data(), usize);-  dst += usize;-  EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek));-  dst += 8;-  end_ = dst;-}--}  // namespace leveldb
− cbits/leveldb/db/dbformat.h
@@ -1,215 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_DB_FORMAT_H_-#define STORAGE_LEVELDB_DB_FORMAT_H_--#include <stdio.h>-#include "leveldb/comparator.h"-#include "leveldb/db.h"-#include "leveldb/slice.h"-#include "leveldb/table_builder.h"-#include "util/coding.h"-#include "util/logging.h"--namespace leveldb {--// Grouping of constants.  We may want to make some of these-// parameters set via options.-namespace config {-static const int kNumLevels = 7;--// Level-0 compaction is started when we hit this many files.-static const int kL0_CompactionTrigger = 4;--// Soft limit on number of level-0 files.  We slow down writes at this point.-static const int kL0_SlowdownWritesTrigger = 8;--// Maximum number of level-0 files.  We stop writes at this point.-static const int kL0_StopWritesTrigger = 12;--// Maximum level to which a new compacted memtable is pushed if it-// does not create overlap.  We try to push to level 2 to avoid the-// relatively expensive level 0=>1 compactions and to avoid some-// expensive manifest file operations.  We do not push all the way to-// the largest level since that can generate a lot of wasted disk-// space if the same key space is being repeatedly overwritten.-static const int kMaxMemCompactLevel = 2;--}  // namespace config--class InternalKey;--// Value types encoded as the last component of internal keys.-// DO NOT CHANGE THESE ENUM VALUES: they are embedded in the on-disk-// data structures.-enum ValueType {-  kTypeDeletion = 0x0,-  kTypeValue = 0x1-};-// kValueTypeForSeek defines the ValueType that should be passed when-// constructing a ParsedInternalKey object for seeking to a particular-// sequence number (since we sort sequence numbers in decreasing order-// and the value type is embedded as the low 8 bits in the sequence-// number in internal keys, we need to use the highest-numbered-// ValueType, not the lowest).-static const ValueType kValueTypeForSeek = kTypeValue;--typedef uint64_t SequenceNumber;--// We leave eight bits empty at the bottom so a type and sequence#-// can be packed together into 64-bits.-static const SequenceNumber kMaxSequenceNumber =-    ((0x1ull << 56) - 1);--struct ParsedInternalKey {-  Slice user_key;-  SequenceNumber sequence;-  ValueType type;--  ParsedInternalKey() { }  // Intentionally left uninitialized (for speed)-  ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t)-      : user_key(u), sequence(seq), type(t) { }-  std::string DebugString() const;-};--// Return the length of the encoding of "key".-inline size_t InternalKeyEncodingLength(const ParsedInternalKey& key) {-  return key.user_key.size() + 8;-}--// Append the serialization of "key" to *result.-extern void AppendInternalKey(std::string* result,-                              const ParsedInternalKey& key);--// Attempt to parse an internal key from "internal_key".  On success,-// stores the parsed data in "*result", and returns true.-//-// On error, returns false, leaves "*result" in an undefined state.-extern bool ParseInternalKey(const Slice& internal_key,-                             ParsedInternalKey* result);--// Returns the user key portion of an internal key.-inline Slice ExtractUserKey(const Slice& internal_key) {-  assert(internal_key.size() >= 8);-  return Slice(internal_key.data(), internal_key.size() - 8);-}--inline ValueType ExtractValueType(const Slice& internal_key) {-  assert(internal_key.size() >= 8);-  const size_t n = internal_key.size();-  uint64_t num = DecodeFixed64(internal_key.data() + n - 8);-  unsigned char c = num & 0xff;-  return static_cast<ValueType>(c);-}--// A comparator for internal keys that uses a specified comparator for-// the user key portion and breaks ties by decreasing sequence number.-class InternalKeyComparator : public Comparator {- private:-  const Comparator* user_comparator_;- public:-  explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) { }-  virtual const char* Name() const;-  virtual int Compare(const Slice& a, const Slice& b) const;-  virtual void FindShortestSeparator(-      std::string* start,-      const Slice& limit) const;-  virtual void FindShortSuccessor(std::string* key) const;--  const Comparator* user_comparator() const { return user_comparator_; }--  int Compare(const InternalKey& a, const InternalKey& b) const;-};--// Modules in this directory should keep internal keys wrapped inside-// the following class instead of plain strings so that we do not-// incorrectly use string comparisons instead of an InternalKeyComparator.-class InternalKey {- private:-  std::string rep_;- public:-  InternalKey() { }   // Leave rep_ as empty to indicate it is invalid-  InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) {-    AppendInternalKey(&rep_, ParsedInternalKey(user_key, s, t));-  }--  void DecodeFrom(const Slice& s) { rep_.assign(s.data(), s.size()); }-  Slice Encode() const {-    assert(!rep_.empty());-    return rep_;-  }--  Slice user_key() const { return ExtractUserKey(rep_); }--  void SetFrom(const ParsedInternalKey& p) {-    rep_.clear();-    AppendInternalKey(&rep_, p);-  }--  void Clear() { rep_.clear(); }--  std::string DebugString() const;-};--inline int InternalKeyComparator::Compare(-    const InternalKey& a, const InternalKey& b) const {-  return Compare(a.Encode(), b.Encode());-}--inline bool ParseInternalKey(const Slice& internal_key,-                             ParsedInternalKey* result) {-  const size_t n = internal_key.size();-  if (n < 8) return false;-  uint64_t num = DecodeFixed64(internal_key.data() + n - 8);-  unsigned char c = num & 0xff;-  result->sequence = num >> 8;-  result->type = static_cast<ValueType>(c);-  result->user_key = Slice(internal_key.data(), n - 8);-  return (c <= static_cast<unsigned char>(kTypeValue));-}--// A helper class useful for DBImpl::Get()-class LookupKey {- public:-  // Initialize *this for looking up user_key at a snapshot with-  // the specified sequence number.-  LookupKey(const Slice& user_key, SequenceNumber sequence);--  ~LookupKey();--  // Return a key suitable for lookup in a MemTable.-  Slice memtable_key() const { return Slice(start_, end_ - start_); }--  // Return an internal key (suitable for passing to an internal iterator)-  Slice internal_key() const { return Slice(kstart_, end_ - kstart_); }--  // Return the user key-  Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); }-- private:-  // We construct a char array of the form:-  //    klength  varint32               <-- start_-  //    userkey  char[klength]          <-- kstart_-  //    tag      uint64-  //                                    <-- end_-  // The array is a suitable MemTable key.-  // The suffix starting with "userkey" can be used as an InternalKey.-  const char* start_;-  const char* kstart_;-  const char* end_;-  char space_[200];      // Avoid allocation for short keys--  // No copying allowed-  LookupKey(const LookupKey&);-  void operator=(const LookupKey&);-};--inline LookupKey::~LookupKey() {-  if (start_ != space_) delete[] start_;-}--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_FORMAT_H_
− cbits/leveldb/db/dbformat_test.cc
@@ -1,112 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/dbformat.h"-#include "util/logging.h"-#include "util/testharness.h"--namespace leveldb {--static std::string IKey(const std::string& user_key,-                        uint64_t seq,-                        ValueType vt) {-  std::string encoded;-  AppendInternalKey(&encoded, ParsedInternalKey(user_key, seq, vt));-  return encoded;-}--static std::string Shorten(const std::string& s, const std::string& l) {-  std::string result = s;-  InternalKeyComparator(BytewiseComparator()).FindShortestSeparator(&result, l);-  return result;-}--static std::string ShortSuccessor(const std::string& s) {-  std::string result = s;-  InternalKeyComparator(BytewiseComparator()).FindShortSuccessor(&result);-  return result;-}--static void TestKey(const std::string& key,-                    uint64_t seq,-                    ValueType vt) {-  std::string encoded = IKey(key, seq, vt);--  Slice in(encoded);-  ParsedInternalKey decoded("", 0, kTypeValue);--  ASSERT_TRUE(ParseInternalKey(in, &decoded));-  ASSERT_EQ(key, decoded.user_key.ToString());-  ASSERT_EQ(seq, decoded.sequence);-  ASSERT_EQ(vt, decoded.type);--  ASSERT_TRUE(!ParseInternalKey(Slice("bar"), &decoded));-}--class FormatTest { };--TEST(FormatTest, InternalKey_EncodeDecode) {-  const char* keys[] = { "", "k", "hello", "longggggggggggggggggggggg" };-  const uint64_t seq[] = {-    1, 2, 3,-    (1ull << 8) - 1, 1ull << 8, (1ull << 8) + 1,-    (1ull << 16) - 1, 1ull << 16, (1ull << 16) + 1,-    (1ull << 32) - 1, 1ull << 32, (1ull << 32) + 1-  };-  for (int k = 0; k < sizeof(keys) / sizeof(keys[0]); k++) {-    for (int s = 0; s < sizeof(seq) / sizeof(seq[0]); s++) {-      TestKey(keys[k], seq[s], kTypeValue);-      TestKey("hello", 1, kTypeDeletion);-    }-  }-}--TEST(FormatTest, InternalKeyShortSeparator) {-  // When user keys are same-  ASSERT_EQ(IKey("foo", 100, kTypeValue),-            Shorten(IKey("foo", 100, kTypeValue),-                    IKey("foo", 99, kTypeValue)));-  ASSERT_EQ(IKey("foo", 100, kTypeValue),-            Shorten(IKey("foo", 100, kTypeValue),-                    IKey("foo", 101, kTypeValue)));-  ASSERT_EQ(IKey("foo", 100, kTypeValue),-            Shorten(IKey("foo", 100, kTypeValue),-                    IKey("foo", 100, kTypeValue)));-  ASSERT_EQ(IKey("foo", 100, kTypeValue),-            Shorten(IKey("foo", 100, kTypeValue),-                    IKey("foo", 100, kTypeDeletion)));--  // When user keys are misordered-  ASSERT_EQ(IKey("foo", 100, kTypeValue),-            Shorten(IKey("foo", 100, kTypeValue),-                    IKey("bar", 99, kTypeValue)));--  // When user keys are different, but correctly ordered-  ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek),-            Shorten(IKey("foo", 100, kTypeValue),-                    IKey("hello", 200, kTypeValue)));--  // When start user key is prefix of limit user key-  ASSERT_EQ(IKey("foo", 100, kTypeValue),-            Shorten(IKey("foo", 100, kTypeValue),-                    IKey("foobar", 200, kTypeValue)));--  // When limit user key is prefix of start user key-  ASSERT_EQ(IKey("foobar", 100, kTypeValue),-            Shorten(IKey("foobar", 100, kTypeValue),-                    IKey("foo", 200, kTypeValue)));-}--TEST(FormatTest, InternalKeyShortestSuccessor) {-  ASSERT_EQ(IKey("g", kMaxSequenceNumber, kValueTypeForSeek),-            ShortSuccessor(IKey("foo", 100, kTypeValue)));-  ASSERT_EQ(IKey("\xff\xff", 100, kTypeValue),-            ShortSuccessor(IKey("\xff\xff", 100, kTypeValue)));-}--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/db/filename.cc
@@ -1,139 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include <ctype.h>-#include <stdio.h>-#include "db/filename.h"-#include "db/dbformat.h"-#include "leveldb/env.h"-#include "util/logging.h"--namespace leveldb {--// A utility routine: write "data" to the named file and Sync() it.-extern Status WriteStringToFileSync(Env* env, const Slice& data,-                                    const std::string& fname);--static std::string MakeFileName(const std::string& name, uint64_t number,-                                const char* suffix) {-  char buf[100];-  snprintf(buf, sizeof(buf), "/%06llu.%s",-           static_cast<unsigned long long>(number),-           suffix);-  return name + buf;-}--std::string LogFileName(const std::string& name, uint64_t number) {-  assert(number > 0);-  return MakeFileName(name, number, "log");-}--std::string TableFileName(const std::string& name, uint64_t number) {-  assert(number > 0);-  return MakeFileName(name, number, "sst");-}--std::string DescriptorFileName(const std::string& dbname, uint64_t number) {-  assert(number > 0);-  char buf[100];-  snprintf(buf, sizeof(buf), "/MANIFEST-%06llu",-           static_cast<unsigned long long>(number));-  return dbname + buf;-}--std::string CurrentFileName(const std::string& dbname) {-  return dbname + "/CURRENT";-}--std::string LockFileName(const std::string& dbname) {-  return dbname + "/LOCK";-}--std::string TempFileName(const std::string& dbname, uint64_t number) {-  assert(number > 0);-  return MakeFileName(dbname, number, "dbtmp");-}--std::string InfoLogFileName(const std::string& dbname) {-  return dbname + "/LOG";-}--// Return the name of the old info log file for "dbname".-std::string OldInfoLogFileName(const std::string& dbname) {-  return dbname + "/LOG.old";-}---// Owned filenames have the form:-//    dbname/CURRENT-//    dbname/LOCK-//    dbname/LOG-//    dbname/LOG.old-//    dbname/MANIFEST-[0-9]+-//    dbname/[0-9]+.(log|sst)-bool ParseFileName(const std::string& fname,-                   uint64_t* number,-                   FileType* type) {-  Slice rest(fname);-  if (rest == "CURRENT") {-    *number = 0;-    *type = kCurrentFile;-  } else if (rest == "LOCK") {-    *number = 0;-    *type = kDBLockFile;-  } else if (rest == "LOG" || rest == "LOG.old") {-    *number = 0;-    *type = kInfoLogFile;-  } else if (rest.starts_with("MANIFEST-")) {-    rest.remove_prefix(strlen("MANIFEST-"));-    uint64_t num;-    if (!ConsumeDecimalNumber(&rest, &num)) {-      return false;-    }-    if (!rest.empty()) {-      return false;-    }-    *type = kDescriptorFile;-    *number = num;-  } else {-    // Avoid strtoull() to keep filename format independent of the-    // current locale-    uint64_t num;-    if (!ConsumeDecimalNumber(&rest, &num)) {-      return false;-    }-    Slice suffix = rest;-    if (suffix == Slice(".log")) {-      *type = kLogFile;-    } else if (suffix == Slice(".sst")) {-      *type = kTableFile;-    } else if (suffix == Slice(".dbtmp")) {-      *type = kTempFile;-    } else {-      return false;-    }-    *number = num;-  }-  return true;-}--Status SetCurrentFile(Env* env, const std::string& dbname,-                      uint64_t descriptor_number) {-  // Remove leading "dbname/" and add newline to manifest file name-  std::string manifest = DescriptorFileName(dbname, descriptor_number);-  Slice contents = manifest;-  assert(contents.starts_with(dbname + "/"));-  contents.remove_prefix(dbname.size() + 1);-  std::string tmp = TempFileName(dbname, descriptor_number);-  Status s = WriteStringToFileSync(env, contents.ToString() + "\n", tmp);-  if (s.ok()) {-    s = env->RenameFile(tmp, CurrentFileName(dbname));-  }-  if (!s.ok()) {-    env->DeleteFile(tmp);-  }-  return s;-}--}  // namespace leveldb
− cbits/leveldb/db/filename.h
@@ -1,80 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// File names used by DB code--#ifndef STORAGE_LEVELDB_DB_FILENAME_H_-#define STORAGE_LEVELDB_DB_FILENAME_H_--#include <stdint.h>-#include <string>-#include "leveldb/slice.h"-#include "leveldb/status.h"-#include "port/port.h"--namespace leveldb {--class Env;--enum FileType {-  kLogFile,-  kDBLockFile,-  kTableFile,-  kDescriptorFile,-  kCurrentFile,-  kTempFile,-  kInfoLogFile  // Either the current one, or an old one-};--// Return the name of the log file with the specified number-// in the db named by "dbname".  The result will be prefixed with-// "dbname".-extern std::string LogFileName(const std::string& dbname, uint64_t number);--// Return the name of the sstable with the specified number-// in the db named by "dbname".  The result will be prefixed with-// "dbname".-extern std::string TableFileName(const std::string& dbname, uint64_t number);--// Return the name of the descriptor file for the db named by-// "dbname" and the specified incarnation number.  The result will be-// prefixed with "dbname".-extern std::string DescriptorFileName(const std::string& dbname,-                                      uint64_t number);--// Return the name of the current file.  This file contains the name-// of the current manifest file.  The result will be prefixed with-// "dbname".-extern std::string CurrentFileName(const std::string& dbname);--// Return the name of the lock file for the db named by-// "dbname".  The result will be prefixed with "dbname".-extern std::string LockFileName(const std::string& dbname);--// Return the name of a temporary file owned by the db named "dbname".-// The result will be prefixed with "dbname".-extern std::string TempFileName(const std::string& dbname, uint64_t number);--// Return the name of the info log file for "dbname".-extern std::string InfoLogFileName(const std::string& dbname);--// Return the name of the old info log file for "dbname".-extern std::string OldInfoLogFileName(const std::string& dbname);--// If filename is a leveldb file, store the type of the file in *type.-// The number encoded in the filename is stored in *number.  If the-// filename was successfully parsed, returns true.  Else return false.-extern bool ParseFileName(const std::string& filename,-                          uint64_t* number,-                          FileType* type);--// Make the CURRENT file point to the descriptor file with the-// specified number.-extern Status SetCurrentFile(Env* env, const std::string& dbname,-                             uint64_t descriptor_number);---}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_FILENAME_H_
− cbits/leveldb/db/filename_test.cc
@@ -1,122 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/filename.h"--#include "db/dbformat.h"-#include "port/port.h"-#include "util/logging.h"-#include "util/testharness.h"--namespace leveldb {--class FileNameTest { };--TEST(FileNameTest, Parse) {-  Slice db;-  FileType type;-  uint64_t number;--  // Successful parses-  static struct {-    const char* fname;-    uint64_t number;-    FileType type;-  } cases[] = {-    { "100.log",            100,   kLogFile },-    { "0.log",              0,     kLogFile },-    { "0.sst",              0,     kTableFile },-    { "CURRENT",            0,     kCurrentFile },-    { "LOCK",               0,     kDBLockFile },-    { "MANIFEST-2",         2,     kDescriptorFile },-    { "MANIFEST-7",         7,     kDescriptorFile },-    { "LOG",                0,     kInfoLogFile },-    { "LOG.old",            0,     kInfoLogFile },-    { "18446744073709551615.log", 18446744073709551615ull, kLogFile },-  };-  for (int i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {-    std::string f = cases[i].fname;-    ASSERT_TRUE(ParseFileName(f, &number, &type)) << f;-    ASSERT_EQ(cases[i].type, type) << f;-    ASSERT_EQ(cases[i].number, number) << f;-  }--  // Errors-  static const char* errors[] = {-    "",-    "foo",-    "foo-dx-100.log",-    ".log",-    "",-    "manifest",-    "CURREN",-    "CURRENTX",-    "MANIFES",-    "MANIFEST",-    "MANIFEST-",-    "XMANIFEST-3",-    "MANIFEST-3x",-    "LOC",-    "LOCKx",-    "LO",-    "LOGx",-    "18446744073709551616.log",-    "184467440737095516150.log",-    "100",-    "100.",-    "100.lop"-  };-  for (int i = 0; i < sizeof(errors) / sizeof(errors[0]); i++) {-    std::string f = errors[i];-    ASSERT_TRUE(!ParseFileName(f, &number, &type)) << f;-  };-}--TEST(FileNameTest, Construction) {-  uint64_t number;-  FileType type;-  std::string fname;--  fname = CurrentFileName("foo");-  ASSERT_EQ("foo/", std::string(fname.data(), 4));-  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));-  ASSERT_EQ(0, number);-  ASSERT_EQ(kCurrentFile, type);--  fname = LockFileName("foo");-  ASSERT_EQ("foo/", std::string(fname.data(), 4));-  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));-  ASSERT_EQ(0, number);-  ASSERT_EQ(kDBLockFile, type);--  fname = LogFileName("foo", 192);-  ASSERT_EQ("foo/", std::string(fname.data(), 4));-  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));-  ASSERT_EQ(192, number);-  ASSERT_EQ(kLogFile, type);--  fname = TableFileName("bar", 200);-  ASSERT_EQ("bar/", std::string(fname.data(), 4));-  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));-  ASSERT_EQ(200, number);-  ASSERT_EQ(kTableFile, type);--  fname = DescriptorFileName("bar", 100);-  ASSERT_EQ("bar/", std::string(fname.data(), 4));-  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));-  ASSERT_EQ(100, number);-  ASSERT_EQ(kDescriptorFile, type);--  fname = TempFileName("tmp", 999);-  ASSERT_EQ("tmp/", std::string(fname.data(), 4));-  ASSERT_TRUE(ParseFileName(fname.c_str() + 4, &number, &type));-  ASSERT_EQ(999, number);-  ASSERT_EQ(kTempFile, type);-}--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/db/log_format.h
@@ -1,35 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// Log format information shared by reader and writer.-// See ../doc/log_format.txt for more detail.--#ifndef STORAGE_LEVELDB_DB_LOG_FORMAT_H_-#define STORAGE_LEVELDB_DB_LOG_FORMAT_H_--namespace leveldb {-namespace log {--enum RecordType {-  // Zero is reserved for preallocated files-  kZeroType = 0,--  kFullType = 1,--  // For fragments-  kFirstType = 2,-  kMiddleType = 3,-  kLastType = 4-};-static const int kMaxRecordType = kLastType;--static const int kBlockSize = 32768;--// Header is checksum (4 bytes), type (1 byte), length (2 bytes).-static const int kHeaderSize = 4 + 1 + 2;--}  // namespace log-}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_LOG_FORMAT_H_
− cbits/leveldb/db/log_reader.cc
@@ -1,259 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/log_reader.h"--#include <stdio.h>-#include "leveldb/env.h"-#include "util/coding.h"-#include "util/crc32c.h"--namespace leveldb {-namespace log {--Reader::Reporter::~Reporter() {-}--Reader::Reader(SequentialFile* file, Reporter* reporter, bool checksum,-               uint64_t initial_offset)-    : file_(file),-      reporter_(reporter),-      checksum_(checksum),-      backing_store_(new char[kBlockSize]),-      buffer_(),-      eof_(false),-      last_record_offset_(0),-      end_of_buffer_offset_(0),-      initial_offset_(initial_offset) {-}--Reader::~Reader() {-  delete[] backing_store_;-}--bool Reader::SkipToInitialBlock() {-  size_t offset_in_block = initial_offset_ % kBlockSize;-  uint64_t block_start_location = initial_offset_ - offset_in_block;--  // Don't search a block if we'd be in the trailer-  if (offset_in_block > kBlockSize - 6) {-    offset_in_block = 0;-    block_start_location += kBlockSize;-  }--  end_of_buffer_offset_ = block_start_location;--  // Skip to start of first block that can contain the initial record-  if (block_start_location > 0) {-    Status skip_status = file_->Skip(block_start_location);-    if (!skip_status.ok()) {-      ReportDrop(block_start_location, skip_status);-      return false;-    }-  }--  return true;-}--bool Reader::ReadRecord(Slice* record, std::string* scratch) {-  if (last_record_offset_ < initial_offset_) {-    if (!SkipToInitialBlock()) {-      return false;-    }-  }--  scratch->clear();-  record->clear();-  bool in_fragmented_record = false;-  // Record offset of the logical record that we're reading-  // 0 is a dummy value to make compilers happy-  uint64_t prospective_record_offset = 0;--  Slice fragment;-  while (true) {-    uint64_t physical_record_offset = end_of_buffer_offset_ - buffer_.size();-    const unsigned int record_type = ReadPhysicalRecord(&fragment);-    switch (record_type) {-      case kFullType:-        if (in_fragmented_record) {-          // Handle bug in earlier versions of log::Writer where-          // it could emit an empty kFirstType record at the tail end-          // of a block followed by a kFullType or kFirstType record-          // at the beginning of the next block.-          if (scratch->empty()) {-            in_fragmented_record = false;-          } else {-            ReportCorruption(scratch->size(), "partial record without end(1)");-          }-        }-        prospective_record_offset = physical_record_offset;-        scratch->clear();-        *record = fragment;-        last_record_offset_ = prospective_record_offset;-        return true;--      case kFirstType:-        if (in_fragmented_record) {-          // Handle bug in earlier versions of log::Writer where-          // it could emit an empty kFirstType record at the tail end-          // of a block followed by a kFullType or kFirstType record-          // at the beginning of the next block.-          if (scratch->empty()) {-            in_fragmented_record = false;-          } else {-            ReportCorruption(scratch->size(), "partial record without end(2)");-          }-        }-        prospective_record_offset = physical_record_offset;-        scratch->assign(fragment.data(), fragment.size());-        in_fragmented_record = true;-        break;--      case kMiddleType:-        if (!in_fragmented_record) {-          ReportCorruption(fragment.size(),-                           "missing start of fragmented record(1)");-        } else {-          scratch->append(fragment.data(), fragment.size());-        }-        break;--      case kLastType:-        if (!in_fragmented_record) {-          ReportCorruption(fragment.size(),-                           "missing start of fragmented record(2)");-        } else {-          scratch->append(fragment.data(), fragment.size());-          *record = Slice(*scratch);-          last_record_offset_ = prospective_record_offset;-          return true;-        }-        break;--      case kEof:-        if (in_fragmented_record) {-          ReportCorruption(scratch->size(), "partial record without end(3)");-          scratch->clear();-        }-        return false;--      case kBadRecord:-        if (in_fragmented_record) {-          ReportCorruption(scratch->size(), "error in middle of record");-          in_fragmented_record = false;-          scratch->clear();-        }-        break;--      default: {-        char buf[40];-        snprintf(buf, sizeof(buf), "unknown record type %u", record_type);-        ReportCorruption(-            (fragment.size() + (in_fragmented_record ? scratch->size() : 0)),-            buf);-        in_fragmented_record = false;-        scratch->clear();-        break;-      }-    }-  }-  return false;-}--uint64_t Reader::LastRecordOffset() {-  return last_record_offset_;-}--void Reader::ReportCorruption(size_t bytes, const char* reason) {-  ReportDrop(bytes, Status::Corruption(reason));-}--void Reader::ReportDrop(size_t bytes, const Status& reason) {-  if (reporter_ != NULL &&-      end_of_buffer_offset_ - buffer_.size() - bytes >= initial_offset_) {-    reporter_->Corruption(bytes, reason);-  }-}--unsigned int Reader::ReadPhysicalRecord(Slice* result) {-  while (true) {-    if (buffer_.size() < kHeaderSize) {-      if (!eof_) {-        // Last read was a full read, so this is a trailer to skip-        buffer_.clear();-        Status status = file_->Read(kBlockSize, &buffer_, backing_store_);-        end_of_buffer_offset_ += buffer_.size();-        if (!status.ok()) {-          buffer_.clear();-          ReportDrop(kBlockSize, status);-          eof_ = true;-          return kEof;-        } else if (buffer_.size() < kBlockSize) {-          eof_ = true;-        }-        continue;-      } else if (buffer_.size() == 0) {-        // End of file-        return kEof;-      } else {-        size_t drop_size = buffer_.size();-        buffer_.clear();-        ReportCorruption(drop_size, "truncated record at end of file");-        return kEof;-      }-    }--    // Parse the header-    const char* header = buffer_.data();-    const uint32_t a = static_cast<uint32_t>(header[4]) & 0xff;-    const uint32_t b = static_cast<uint32_t>(header[5]) & 0xff;-    const unsigned int type = header[6];-    const uint32_t length = a | (b << 8);-    if (kHeaderSize + length > buffer_.size()) {-      size_t drop_size = buffer_.size();-      buffer_.clear();-      ReportCorruption(drop_size, "bad record length");-      return kBadRecord;-    }--    if (type == kZeroType && length == 0) {-      // Skip zero length record without reporting any drops since-      // such records are produced by the mmap based writing code in-      // env_posix.cc that preallocates file regions.-      buffer_.clear();-      return kBadRecord;-    }--    // Check crc-    if (checksum_) {-      uint32_t expected_crc = crc32c::Unmask(DecodeFixed32(header));-      uint32_t actual_crc = crc32c::Value(header + 6, 1 + length);-      if (actual_crc != expected_crc) {-        // Drop the rest of the buffer since "length" itself may have-        // been corrupted and if we trust it, we could find some-        // fragment of a real log record that just happens to look-        // like a valid log record.-        size_t drop_size = buffer_.size();-        buffer_.clear();-        ReportCorruption(drop_size, "checksum mismatch");-        return kBadRecord;-      }-    }--    buffer_.remove_prefix(kHeaderSize + length);--    // Skip physical record that started before initial_offset_-    if (end_of_buffer_offset_ - buffer_.size() - kHeaderSize - length <-        initial_offset_) {-      result->clear();-      return kBadRecord;-    }--    *result = Slice(header + kHeaderSize, length);-    return type;-  }-}--}  // namespace log-}  // namespace leveldb
− cbits/leveldb/db/log_reader.h
@@ -1,108 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_DB_LOG_READER_H_-#define STORAGE_LEVELDB_DB_LOG_READER_H_--#include <stdint.h>--#include "db/log_format.h"-#include "leveldb/slice.h"-#include "leveldb/status.h"--namespace leveldb {--class SequentialFile;--namespace log {--class Reader {- public:-  // Interface for reporting errors.-  class Reporter {-   public:-    virtual ~Reporter();--    // Some corruption was detected.  "size" is the approximate number-    // of bytes dropped due to the corruption.-    virtual void Corruption(size_t bytes, const Status& status) = 0;-  };--  // Create a reader that will return log records from "*file".-  // "*file" must remain live while this Reader is in use.-  //-  // If "reporter" is non-NULL, it is notified whenever some data is-  // dropped due to a detected corruption.  "*reporter" must remain-  // live while this Reader is in use.-  //-  // If "checksum" is true, verify checksums if available.-  //-  // The Reader will start reading at the first record located at physical-  // position >= initial_offset within the file.-  Reader(SequentialFile* file, Reporter* reporter, bool checksum,-         uint64_t initial_offset);--  ~Reader();--  // Read the next record into *record.  Returns true if read-  // successfully, false if we hit end of the input.  May use-  // "*scratch" as temporary storage.  The contents filled in *record-  // will only be valid until the next mutating operation on this-  // reader or the next mutation to *scratch.-  bool ReadRecord(Slice* record, std::string* scratch);--  // Returns the physical offset of the last record returned by ReadRecord.-  //-  // Undefined before the first call to ReadRecord.-  uint64_t LastRecordOffset();-- private:-  SequentialFile* const file_;-  Reporter* const reporter_;-  bool const checksum_;-  char* const backing_store_;-  Slice buffer_;-  bool eof_;   // Last Read() indicated EOF by returning < kBlockSize--  // Offset of the last record returned by ReadRecord.-  uint64_t last_record_offset_;-  // Offset of the first location past the end of buffer_.-  uint64_t end_of_buffer_offset_;--  // Offset at which to start looking for the first record to return-  uint64_t const initial_offset_;--  // Extend record types with the following special values-  enum {-    kEof = kMaxRecordType + 1,-    // Returned whenever we find an invalid physical record.-    // Currently there are three situations in which this happens:-    // * The record has an invalid CRC (ReadPhysicalRecord reports a drop)-    // * The record is a 0-length record (No drop is reported)-    // * The record is below constructor's initial_offset (No drop is reported)-    kBadRecord = kMaxRecordType + 2-  };--  // Skips all blocks that are completely before "initial_offset_".-  //-  // Returns true on success. Handles reporting.-  bool SkipToInitialBlock();--  // Return type, or one of the preceding special values-  unsigned int ReadPhysicalRecord(Slice* result);--  // Reports dropped bytes to the reporter.-  // buffer_ must be updated to remove the dropped bytes prior to invocation.-  void ReportCorruption(size_t bytes, const char* reason);-  void ReportDrop(size_t bytes, const Status& reason);--  // No copying allowed-  Reader(const Reader&);-  void operator=(const Reader&);-};--}  // namespace log-}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_LOG_READER_H_
− cbits/leveldb/db/log_test.cc
@@ -1,500 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/log_reader.h"-#include "db/log_writer.h"-#include "leveldb/env.h"-#include "util/coding.h"-#include "util/crc32c.h"-#include "util/random.h"-#include "util/testharness.h"--namespace leveldb {-namespace log {--// Construct a string of the specified length made out of the supplied-// partial string.-static std::string BigString(const std::string& partial_string, size_t n) {-  std::string result;-  while (result.size() < n) {-    result.append(partial_string);-  }-  result.resize(n);-  return result;-}--// Construct a string from a number-static std::string NumberString(int n) {-  char buf[50];-  snprintf(buf, sizeof(buf), "%d.", n);-  return std::string(buf);-}--// Return a skewed potentially long string-static std::string RandomSkewedString(int i, Random* rnd) {-  return BigString(NumberString(i), rnd->Skewed(17));-}--class LogTest {- private:-  class StringDest : public WritableFile {-   public:-    std::string contents_;--    virtual Status Close() { return Status::OK(); }-    virtual Status Flush() { return Status::OK(); }-    virtual Status Sync() { return Status::OK(); }-    virtual Status Append(const Slice& slice) {-      contents_.append(slice.data(), slice.size());-      return Status::OK();-    }-  };--  class StringSource : public SequentialFile {-   public:-    Slice contents_;-    bool force_error_;-    bool returned_partial_;-    StringSource() : force_error_(false), returned_partial_(false) { }--    virtual Status Read(size_t n, Slice* result, char* scratch) {-      ASSERT_TRUE(!returned_partial_) << "must not Read() after eof/error";--      if (force_error_) {-        force_error_ = false;-        returned_partial_ = true;-        return Status::Corruption("read error");-      }--      if (contents_.size() < n) {-        n = contents_.size();-        returned_partial_ = true;-      }-      *result = Slice(contents_.data(), n);-      contents_.remove_prefix(n);-      return Status::OK();-    }--    virtual Status Skip(uint64_t n) {-      if (n > contents_.size()) {-        contents_.clear();-        return Status::NotFound("in-memory file skipepd past end");-      }--      contents_.remove_prefix(n);--      return Status::OK();-    }-  };--  class ReportCollector : public Reader::Reporter {-   public:-    size_t dropped_bytes_;-    std::string message_;--    ReportCollector() : dropped_bytes_(0) { }-    virtual void Corruption(size_t bytes, const Status& status) {-      dropped_bytes_ += bytes;-      message_.append(status.ToString());-    }-  };--  StringDest dest_;-  StringSource source_;-  ReportCollector report_;-  bool reading_;-  Writer writer_;-  Reader reader_;--  // Record metadata for testing initial offset functionality-  static size_t initial_offset_record_sizes_[];-  static uint64_t initial_offset_last_record_offsets_[];-- public:-  LogTest() : reading_(false),-              writer_(&dest_),-              reader_(&source_, &report_, true/*checksum*/,-                      0/*initial_offset*/) {-  }--  void Write(const std::string& msg) {-    ASSERT_TRUE(!reading_) << "Write() after starting to read";-    writer_.AddRecord(Slice(msg));-  }--  size_t WrittenBytes() const {-    return dest_.contents_.size();-  }--  std::string Read() {-    if (!reading_) {-      reading_ = true;-      source_.contents_ = Slice(dest_.contents_);-    }-    std::string scratch;-    Slice record;-    if (reader_.ReadRecord(&record, &scratch)) {-      return record.ToString();-    } else {-      return "EOF";-    }-  }--  void IncrementByte(int offset, int delta) {-    dest_.contents_[offset] += delta;-  }--  void SetByte(int offset, char new_byte) {-    dest_.contents_[offset] = new_byte;-  }--  void ShrinkSize(int bytes) {-    dest_.contents_.resize(dest_.contents_.size() - bytes);-  }--  void FixChecksum(int header_offset, int len) {-    // Compute crc of type/len/data-    uint32_t crc = crc32c::Value(&dest_.contents_[header_offset+6], 1 + len);-    crc = crc32c::Mask(crc);-    EncodeFixed32(&dest_.contents_[header_offset], crc);-  }--  void ForceError() {-    source_.force_error_ = true;-  }--  size_t DroppedBytes() const {-    return report_.dropped_bytes_;-  }--  std::string ReportMessage() const {-    return report_.message_;-  }--  // Returns OK iff recorded error message contains "msg"-  std::string MatchError(const std::string& msg) const {-    if (report_.message_.find(msg) == std::string::npos) {-      return report_.message_;-    } else {-      return "OK";-    }-  }--  void WriteInitialOffsetLog() {-    for (int i = 0; i < 4; i++) {-      std::string record(initial_offset_record_sizes_[i],-                         static_cast<char>('a' + i));-      Write(record);-    }-  }--  void CheckOffsetPastEndReturnsNoRecords(uint64_t offset_past_end) {-    WriteInitialOffsetLog();-    reading_ = true;-    source_.contents_ = Slice(dest_.contents_);-    Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/,-                                       WrittenBytes() + offset_past_end);-    Slice record;-    std::string scratch;-    ASSERT_TRUE(!offset_reader->ReadRecord(&record, &scratch));-    delete offset_reader;-  }--  void CheckInitialOffsetRecord(uint64_t initial_offset,-                                int expected_record_offset) {-    WriteInitialOffsetLog();-    reading_ = true;-    source_.contents_ = Slice(dest_.contents_);-    Reader* offset_reader = new Reader(&source_, &report_, true/*checksum*/,-                                       initial_offset);-    Slice record;-    std::string scratch;-    ASSERT_TRUE(offset_reader->ReadRecord(&record, &scratch));-    ASSERT_EQ(initial_offset_record_sizes_[expected_record_offset],-              record.size());-    ASSERT_EQ(initial_offset_last_record_offsets_[expected_record_offset],-              offset_reader->LastRecordOffset());-    ASSERT_EQ((char)('a' + expected_record_offset), record.data()[0]);-    delete offset_reader;-  }--};--size_t LogTest::initial_offset_record_sizes_[] =-    {10000,  // Two sizable records in first block-     10000,-     2 * log::kBlockSize - 1000,  // Span three blocks-     1};--uint64_t LogTest::initial_offset_last_record_offsets_[] =-    {0,-     kHeaderSize + 10000,-     2 * (kHeaderSize + 10000),-     2 * (kHeaderSize + 10000) +-         (2 * log::kBlockSize - 1000) + 3 * kHeaderSize};---TEST(LogTest, Empty) {-  ASSERT_EQ("EOF", Read());-}--TEST(LogTest, ReadWrite) {-  Write("foo");-  Write("bar");-  Write("");-  Write("xxxx");-  ASSERT_EQ("foo", Read());-  ASSERT_EQ("bar", Read());-  ASSERT_EQ("", Read());-  ASSERT_EQ("xxxx", Read());-  ASSERT_EQ("EOF", Read());-  ASSERT_EQ("EOF", Read());  // Make sure reads at eof work-}--TEST(LogTest, ManyBlocks) {-  for (int i = 0; i < 100000; i++) {-    Write(NumberString(i));-  }-  for (int i = 0; i < 100000; i++) {-    ASSERT_EQ(NumberString(i), Read());-  }-  ASSERT_EQ("EOF", Read());-}--TEST(LogTest, Fragmentation) {-  Write("small");-  Write(BigString("medium", 50000));-  Write(BigString("large", 100000));-  ASSERT_EQ("small", Read());-  ASSERT_EQ(BigString("medium", 50000), Read());-  ASSERT_EQ(BigString("large", 100000), Read());-  ASSERT_EQ("EOF", Read());-}--TEST(LogTest, MarginalTrailer) {-  // Make a trailer that is exactly the same length as an empty record.-  const int n = kBlockSize - 2*kHeaderSize;-  Write(BigString("foo", n));-  ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes());-  Write("");-  Write("bar");-  ASSERT_EQ(BigString("foo", n), Read());-  ASSERT_EQ("", Read());-  ASSERT_EQ("bar", Read());-  ASSERT_EQ("EOF", Read());-}--TEST(LogTest, MarginalTrailer2) {-  // Make a trailer that is exactly the same length as an empty record.-  const int n = kBlockSize - 2*kHeaderSize;-  Write(BigString("foo", n));-  ASSERT_EQ(kBlockSize - kHeaderSize, WrittenBytes());-  Write("bar");-  ASSERT_EQ(BigString("foo", n), Read());-  ASSERT_EQ("bar", Read());-  ASSERT_EQ("EOF", Read());-  ASSERT_EQ(0, DroppedBytes());-  ASSERT_EQ("", ReportMessage());-}--TEST(LogTest, ShortTrailer) {-  const int n = kBlockSize - 2*kHeaderSize + 4;-  Write(BigString("foo", n));-  ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes());-  Write("");-  Write("bar");-  ASSERT_EQ(BigString("foo", n), Read());-  ASSERT_EQ("", Read());-  ASSERT_EQ("bar", Read());-  ASSERT_EQ("EOF", Read());-}--TEST(LogTest, AlignedEof) {-  const int n = kBlockSize - 2*kHeaderSize + 4;-  Write(BigString("foo", n));-  ASSERT_EQ(kBlockSize - kHeaderSize + 4, WrittenBytes());-  ASSERT_EQ(BigString("foo", n), Read());-  ASSERT_EQ("EOF", Read());-}--TEST(LogTest, RandomRead) {-  const int N = 500;-  Random write_rnd(301);-  for (int i = 0; i < N; i++) {-    Write(RandomSkewedString(i, &write_rnd));-  }-  Random read_rnd(301);-  for (int i = 0; i < N; i++) {-    ASSERT_EQ(RandomSkewedString(i, &read_rnd), Read());-  }-  ASSERT_EQ("EOF", Read());-}--// Tests of all the error paths in log_reader.cc follow:--TEST(LogTest, ReadError) {-  Write("foo");-  ForceError();-  ASSERT_EQ("EOF", Read());-  ASSERT_EQ(kBlockSize, DroppedBytes());-  ASSERT_EQ("OK", MatchError("read error"));-}--TEST(LogTest, BadRecordType) {-  Write("foo");-  // Type is stored in header[6]-  IncrementByte(6, 100);-  FixChecksum(0, 3);-  ASSERT_EQ("EOF", Read());-  ASSERT_EQ(3, DroppedBytes());-  ASSERT_EQ("OK", MatchError("unknown record type"));-}--TEST(LogTest, TruncatedTrailingRecord) {-  Write("foo");-  ShrinkSize(4);   // Drop all payload as well as a header byte-  ASSERT_EQ("EOF", Read());-  ASSERT_EQ(kHeaderSize - 1, DroppedBytes());-  ASSERT_EQ("OK", MatchError("truncated record at end of file"));-}--TEST(LogTest, BadLength) {-  Write("foo");-  ShrinkSize(1);-  ASSERT_EQ("EOF", Read());-  ASSERT_EQ(kHeaderSize + 2, DroppedBytes());-  ASSERT_EQ("OK", MatchError("bad record length"));-}--TEST(LogTest, ChecksumMismatch) {-  Write("foo");-  IncrementByte(0, 10);-  ASSERT_EQ("EOF", Read());-  ASSERT_EQ(10, DroppedBytes());-  ASSERT_EQ("OK", MatchError("checksum mismatch"));-}--TEST(LogTest, UnexpectedMiddleType) {-  Write("foo");-  SetByte(6, kMiddleType);-  FixChecksum(0, 3);-  ASSERT_EQ("EOF", Read());-  ASSERT_EQ(3, DroppedBytes());-  ASSERT_EQ("OK", MatchError("missing start"));-}--TEST(LogTest, UnexpectedLastType) {-  Write("foo");-  SetByte(6, kLastType);-  FixChecksum(0, 3);-  ASSERT_EQ("EOF", Read());-  ASSERT_EQ(3, DroppedBytes());-  ASSERT_EQ("OK", MatchError("missing start"));-}--TEST(LogTest, UnexpectedFullType) {-  Write("foo");-  Write("bar");-  SetByte(6, kFirstType);-  FixChecksum(0, 3);-  ASSERT_EQ("bar", Read());-  ASSERT_EQ("EOF", Read());-  ASSERT_EQ(3, DroppedBytes());-  ASSERT_EQ("OK", MatchError("partial record without end"));-}--TEST(LogTest, UnexpectedFirstType) {-  Write("foo");-  Write(BigString("bar", 100000));-  SetByte(6, kFirstType);-  FixChecksum(0, 3);-  ASSERT_EQ(BigString("bar", 100000), Read());-  ASSERT_EQ("EOF", Read());-  ASSERT_EQ(3, DroppedBytes());-  ASSERT_EQ("OK", MatchError("partial record without end"));-}--TEST(LogTest, ErrorJoinsRecords) {-  // Consider two fragmented records:-  //    first(R1) last(R1) first(R2) last(R2)-  // where the middle two fragments disappear.  We do not want-  // first(R1),last(R2) to get joined and returned as a valid record.--  // Write records that span two blocks-  Write(BigString("foo", kBlockSize));-  Write(BigString("bar", kBlockSize));-  Write("correct");--  // Wipe the middle block-  for (int offset = kBlockSize; offset < 2*kBlockSize; offset++) {-    SetByte(offset, 'x');-  }--  ASSERT_EQ("correct", Read());-  ASSERT_EQ("EOF", Read());-  const int dropped = DroppedBytes();-  ASSERT_LE(dropped, 2*kBlockSize + 100);-  ASSERT_GE(dropped, 2*kBlockSize);-}--TEST(LogTest, ReadStart) {-  CheckInitialOffsetRecord(0, 0);-}--TEST(LogTest, ReadSecondOneOff) {-  CheckInitialOffsetRecord(1, 1);-}--TEST(LogTest, ReadSecondTenThousand) {-  CheckInitialOffsetRecord(10000, 1);-}--TEST(LogTest, ReadSecondStart) {-  CheckInitialOffsetRecord(10007, 1);-}--TEST(LogTest, ReadThirdOneOff) {-  CheckInitialOffsetRecord(10008, 2);-}--TEST(LogTest, ReadThirdStart) {-  CheckInitialOffsetRecord(20014, 2);-}--TEST(LogTest, ReadFourthOneOff) {-  CheckInitialOffsetRecord(20015, 3);-}--TEST(LogTest, ReadFourthFirstBlockTrailer) {-  CheckInitialOffsetRecord(log::kBlockSize - 4, 3);-}--TEST(LogTest, ReadFourthMiddleBlock) {-  CheckInitialOffsetRecord(log::kBlockSize + 1, 3);-}--TEST(LogTest, ReadFourthLastBlock) {-  CheckInitialOffsetRecord(2 * log::kBlockSize + 1, 3);-}--TEST(LogTest, ReadFourthStart) {-  CheckInitialOffsetRecord(-      2 * (kHeaderSize + 1000) + (2 * log::kBlockSize - 1000) + 3 * kHeaderSize,-      3);-}--TEST(LogTest, ReadEnd) {-  CheckOffsetPastEndReturnsNoRecords(0);-}--TEST(LogTest, ReadPastEnd) {-  CheckOffsetPastEndReturnsNoRecords(5);-}--}  // namespace log-}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/db/log_writer.cc
@@ -1,103 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/log_writer.h"--#include <stdint.h>-#include "leveldb/env.h"-#include "util/coding.h"-#include "util/crc32c.h"--namespace leveldb {-namespace log {--Writer::Writer(WritableFile* dest)-    : dest_(dest),-      block_offset_(0) {-  for (int i = 0; i <= kMaxRecordType; i++) {-    char t = static_cast<char>(i);-    type_crc_[i] = crc32c::Value(&t, 1);-  }-}--Writer::~Writer() {-}--Status Writer::AddRecord(const Slice& slice) {-  const char* ptr = slice.data();-  size_t left = slice.size();--  // Fragment the record if necessary and emit it.  Note that if slice-  // is empty, we still want to iterate once to emit a single-  // zero-length record-  Status s;-  bool begin = true;-  do {-    const int leftover = kBlockSize - block_offset_;-    assert(leftover >= 0);-    if (leftover < kHeaderSize) {-      // Switch to a new block-      if (leftover > 0) {-        // Fill the trailer (literal below relies on kHeaderSize being 7)-        assert(kHeaderSize == 7);-        dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover));-      }-      block_offset_ = 0;-    }--    // Invariant: we never leave < kHeaderSize bytes in a block.-    assert(kBlockSize - block_offset_ - kHeaderSize >= 0);--    const size_t avail = kBlockSize - block_offset_ - kHeaderSize;-    const size_t fragment_length = (left < avail) ? left : avail;--    RecordType type;-    const bool end = (left == fragment_length);-    if (begin && end) {-      type = kFullType;-    } else if (begin) {-      type = kFirstType;-    } else if (end) {-      type = kLastType;-    } else {-      type = kMiddleType;-    }--    s = EmitPhysicalRecord(type, ptr, fragment_length);-    ptr += fragment_length;-    left -= fragment_length;-    begin = false;-  } while (s.ok() && left > 0);-  return s;-}--Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, size_t n) {-  assert(n <= 0xffff);  // Must fit in two bytes-  assert(block_offset_ + kHeaderSize + n <= kBlockSize);--  // Format the header-  char buf[kHeaderSize];-  buf[4] = static_cast<char>(n & 0xff);-  buf[5] = static_cast<char>(n >> 8);-  buf[6] = static_cast<char>(t);--  // Compute the crc of the record type and the payload.-  uint32_t crc = crc32c::Extend(type_crc_[t], ptr, n);-  crc = crc32c::Mask(crc);                 // Adjust for storage-  EncodeFixed32(buf, crc);--  // Write the header and the payload-  Status s = dest_->Append(Slice(buf, kHeaderSize));-  if (s.ok()) {-    s = dest_->Append(Slice(ptr, n));-    if (s.ok()) {-      s = dest_->Flush();-    }-  }-  block_offset_ += kHeaderSize + n;-  return s;-}--}  // namespace log-}  // namespace leveldb
− cbits/leveldb/db/log_writer.h
@@ -1,48 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_DB_LOG_WRITER_H_-#define STORAGE_LEVELDB_DB_LOG_WRITER_H_--#include <stdint.h>-#include "db/log_format.h"-#include "leveldb/slice.h"-#include "leveldb/status.h"--namespace leveldb {--class WritableFile;--namespace log {--class Writer {- public:-  // Create a writer that will append data to "*dest".-  // "*dest" must be initially empty.-  // "*dest" must remain live while this Writer is in use.-  explicit Writer(WritableFile* dest);-  ~Writer();--  Status AddRecord(const Slice& slice);-- private:-  WritableFile* dest_;-  int block_offset_;       // Current offset in block--  // crc32c values for all supported record types.  These are-  // pre-computed to reduce the overhead of computing the crc of the-  // record type stored in the header.-  uint32_t type_crc_[kMaxRecordType + 1];--  Status EmitPhysicalRecord(RecordType type, const char* ptr, size_t length);--  // No copying allowed-  Writer(const Writer&);-  void operator=(const Writer&);-};--}  // namespace log-}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_LOG_WRITER_H_
− cbits/leveldb/db/memtable.cc
@@ -1,145 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/memtable.h"-#include "db/dbformat.h"-#include "leveldb/comparator.h"-#include "leveldb/env.h"-#include "leveldb/iterator.h"-#include "util/coding.h"--namespace leveldb {--static Slice GetLengthPrefixedSlice(const char* data) {-  uint32_t len;-  const char* p = data;-  p = GetVarint32Ptr(p, p + 5, &len);  // +5: we assume "p" is not corrupted-  return Slice(p, len);-}--MemTable::MemTable(const InternalKeyComparator& cmp)-    : comparator_(cmp),-      refs_(0),-      table_(comparator_, &arena_) {-}--MemTable::~MemTable() {-  assert(refs_ == 0);-}--size_t MemTable::ApproximateMemoryUsage() { return arena_.MemoryUsage(); }--int MemTable::KeyComparator::operator()(const char* aptr, const char* bptr)-    const {-  // Internal keys are encoded as length-prefixed strings.-  Slice a = GetLengthPrefixedSlice(aptr);-  Slice b = GetLengthPrefixedSlice(bptr);-  return comparator.Compare(a, b);-}--// Encode a suitable internal key target for "target" and return it.-// Uses *scratch as scratch space, and the returned pointer will point-// into this scratch space.-static const char* EncodeKey(std::string* scratch, const Slice& target) {-  scratch->clear();-  PutVarint32(scratch, target.size());-  scratch->append(target.data(), target.size());-  return scratch->data();-}--class MemTableIterator: public Iterator {- public:-  explicit MemTableIterator(MemTable::Table* table) : iter_(table) { }--  virtual bool Valid() const { return iter_.Valid(); }-  virtual void Seek(const Slice& k) { iter_.Seek(EncodeKey(&tmp_, k)); }-  virtual void SeekToFirst() { iter_.SeekToFirst(); }-  virtual void SeekToLast() { iter_.SeekToLast(); }-  virtual void Next() { iter_.Next(); }-  virtual void Prev() { iter_.Prev(); }-  virtual Slice key() const { return GetLengthPrefixedSlice(iter_.key()); }-  virtual Slice value() const {-    Slice key_slice = GetLengthPrefixedSlice(iter_.key());-    return GetLengthPrefixedSlice(key_slice.data() + key_slice.size());-  }--  virtual Status status() const { return Status::OK(); }-- private:-  MemTable::Table::Iterator iter_;-  std::string tmp_;       // For passing to EncodeKey--  // No copying allowed-  MemTableIterator(const MemTableIterator&);-  void operator=(const MemTableIterator&);-};--Iterator* MemTable::NewIterator() {-  return new MemTableIterator(&table_);-}--void MemTable::Add(SequenceNumber s, ValueType type,-                   const Slice& key,-                   const Slice& value) {-  // Format of an entry is concatenation of:-  //  key_size     : varint32 of internal_key.size()-  //  key bytes    : char[internal_key.size()]-  //  value_size   : varint32 of value.size()-  //  value bytes  : char[value.size()]-  size_t key_size = key.size();-  size_t val_size = value.size();-  size_t internal_key_size = key_size + 8;-  const size_t encoded_len =-      VarintLength(internal_key_size) + internal_key_size +-      VarintLength(val_size) + val_size;-  char* buf = arena_.Allocate(encoded_len);-  char* p = EncodeVarint32(buf, internal_key_size);-  memcpy(p, key.data(), key_size);-  p += key_size;-  EncodeFixed64(p, (s << 8) | type);-  p += 8;-  p = EncodeVarint32(p, val_size);-  memcpy(p, value.data(), val_size);-  assert((p + val_size) - buf == encoded_len);-  table_.Insert(buf);-}--bool MemTable::Get(const LookupKey& key, std::string* value, Status* s) {-  Slice memkey = key.memtable_key();-  Table::Iterator iter(&table_);-  iter.Seek(memkey.data());-  if (iter.Valid()) {-    // entry format is:-    //    klength  varint32-    //    userkey  char[klength]-    //    tag      uint64-    //    vlength  varint32-    //    value    char[vlength]-    // Check that it belongs to same user key.  We do not check the-    // sequence number since the Seek() call above should have skipped-    // all entries with overly large sequence numbers.-    const char* entry = iter.key();-    uint32_t key_length;-    const char* key_ptr = GetVarint32Ptr(entry, entry+5, &key_length);-    if (comparator_.comparator.user_comparator()->Compare(-            Slice(key_ptr, key_length - 8),-            key.user_key()) == 0) {-      // Correct user key-      const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8);-      switch (static_cast<ValueType>(tag & 0xff)) {-        case kTypeValue: {-          Slice v = GetLengthPrefixedSlice(key_ptr + key_length);-          value->assign(v.data(), v.size());-          return true;-        }-        case kTypeDeletion:-          *s = Status::NotFound(Slice());-          return true;-      }-    }-  }-  return false;-}--}  // namespace leveldb
− cbits/leveldb/db/memtable.h
@@ -1,91 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_DB_MEMTABLE_H_-#define STORAGE_LEVELDB_DB_MEMTABLE_H_--#include <string>-#include "leveldb/db.h"-#include "db/dbformat.h"-#include "db/skiplist.h"-#include "util/arena.h"--namespace leveldb {--class InternalKeyComparator;-class Mutex;-class MemTableIterator;--class MemTable {- public:-  // MemTables are reference counted.  The initial reference count-  // is zero and the caller must call Ref() at least once.-  explicit MemTable(const InternalKeyComparator& comparator);--  // Increase reference count.-  void Ref() { ++refs_; }--  // Drop reference count.  Delete if no more references exist.-  void Unref() {-    --refs_;-    assert(refs_ >= 0);-    if (refs_ <= 0) {-      delete this;-    }-  }--  // Returns an estimate of the number of bytes of data in use by this-  // data structure.-  //-  // REQUIRES: external synchronization to prevent simultaneous-  // operations on the same MemTable.-  size_t ApproximateMemoryUsage();--  // Return an iterator that yields the contents of the memtable.-  //-  // The caller must ensure that the underlying MemTable remains live-  // while the returned iterator is live.  The keys returned by this-  // iterator are internal keys encoded by AppendInternalKey in the-  // db/format.{h,cc} module.-  Iterator* NewIterator();--  // Add an entry into memtable that maps key to value at the-  // specified sequence number and with the specified type.-  // Typically value will be empty if type==kTypeDeletion.-  void Add(SequenceNumber seq, ValueType type,-           const Slice& key,-           const Slice& value);--  // If memtable contains a value for key, store it in *value and return true.-  // If memtable contains a deletion for key, store a NotFound() error-  // in *status and return true.-  // Else, return false.-  bool Get(const LookupKey& key, std::string* value, Status* s);-- private:-  ~MemTable();  // Private since only Unref() should be used to delete it--  struct KeyComparator {-    const InternalKeyComparator comparator;-    explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) { }-    int operator()(const char* a, const char* b) const;-  };-  friend class MemTableIterator;-  friend class MemTableBackwardIterator;--  typedef SkipList<const char*, KeyComparator> Table;--  KeyComparator comparator_;-  int refs_;-  Arena arena_;-  Table table_;--  // No copying allowed-  MemTable(const MemTable&);-  void operator=(const MemTable&);-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_MEMTABLE_H_
− cbits/leveldb/db/repair.cc
@@ -1,387 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// We recover the contents of the descriptor from the other files we find.-// (1) Any log files are first converted to tables-// (2) We scan every table to compute-//     (a) smallest/largest for the table-//     (b) largest sequence number in the table-// (3) We generate descriptor contents:-//      - log number is set to zero-//      - next-file-number is set to 1 + largest file number we found-//      - last-sequence-number is set to largest sequence# found across-//        all tables (see 2c)-//      - compaction pointers are cleared-//      - every table file is added at level 0-//-// Possible optimization 1:-//   (a) Compute total size and use to pick appropriate max-level M-//   (b) Sort tables by largest sequence# in the table-//   (c) For each table: if it overlaps earlier table, place in level-0,-//       else place in level-M.-// Possible optimization 2:-//   Store per-table metadata (smallest, largest, largest-seq#, ...)-//   in the table's meta section to speed up ScanTable.--#include "db/builder.h"-#include "db/db_impl.h"-#include "db/dbformat.h"-#include "db/filename.h"-#include "db/log_reader.h"-#include "db/log_writer.h"-#include "db/memtable.h"-#include "db/table_cache.h"-#include "db/version_edit.h"-#include "db/write_batch_internal.h"-#include "leveldb/comparator.h"-#include "leveldb/db.h"-#include "leveldb/env.h"--namespace leveldb {--namespace {--class Repairer {- public:-  Repairer(const std::string& dbname, const Options& options)-      : dbname_(dbname),-        env_(options.env),-        icmp_(options.comparator),-        options_(SanitizeOptions(dbname, &icmp_, options)),-        owns_info_log_(options_.info_log != options.info_log),-        owns_cache_(options_.block_cache != options.block_cache),-        next_file_number_(1) {-    // TableCache can be small since we expect each table to be opened once.-    table_cache_ = new TableCache(dbname_, &options_, 10);-  }--  ~Repairer() {-    delete table_cache_;-    if (owns_info_log_) {-      delete options_.info_log;-    }-    if (owns_cache_) {-      delete options_.block_cache;-    }-  }--  Status Run() {-    Status status = FindFiles();-    if (status.ok()) {-      ConvertLogFilesToTables();-      ExtractMetaData();-      status = WriteDescriptor();-    }-    if (status.ok()) {-      unsigned long long bytes = 0;-      for (size_t i = 0; i < tables_.size(); i++) {-        bytes += tables_[i].meta.file_size;-      }-      Log(options_.info_log,-          "**** Repaired leveldb %s; "-          "recovered %d files; %llu bytes. "-          "Some data may have been lost. "-          "****",-          dbname_.c_str(),-          static_cast<int>(tables_.size()),-          bytes);-    }-    return status;-  }-- private:-  struct TableInfo {-    FileMetaData meta;-    SequenceNumber max_sequence;-  };--  std::string const dbname_;-  Env* const env_;-  InternalKeyComparator const icmp_;-  Options const options_;-  bool owns_info_log_;-  bool owns_cache_;-  TableCache* table_cache_;-  VersionEdit edit_;--  std::vector<std::string> manifests_;-  std::vector<uint64_t> table_numbers_;-  std::vector<uint64_t> logs_;-  std::vector<TableInfo> tables_;-  uint64_t next_file_number_;--  Status FindFiles() {-    std::vector<std::string> filenames;-    Status status = env_->GetChildren(dbname_, &filenames);-    if (!status.ok()) {-      return status;-    }-    if (filenames.empty()) {-      return Status::IOError(dbname_, "repair found no files");-    }--    uint64_t number;-    FileType type;-    for (size_t i = 0; i < filenames.size(); i++) {-      if (ParseFileName(filenames[i], &number, &type)) {-        if (type == kDescriptorFile) {-          manifests_.push_back(filenames[i]);-        } else {-          if (number + 1 > next_file_number_) {-            next_file_number_ = number + 1;-          }-          if (type == kLogFile) {-            logs_.push_back(number);-          } else if (type == kTableFile) {-            table_numbers_.push_back(number);-          } else {-            // Ignore other files-          }-        }-      }-    }-    return status;-  }--  void ConvertLogFilesToTables() {-    for (size_t i = 0; i < logs_.size(); i++) {-      std::string logname = LogFileName(dbname_, logs_[i]);-      Status status = ConvertLogToTable(logs_[i]);-      if (!status.ok()) {-        Log(options_.info_log, "Log #%llu: ignoring conversion error: %s",-            (unsigned long long) logs_[i],-            status.ToString().c_str());-      }-      ArchiveFile(logname);-    }-  }--  Status ConvertLogToTable(uint64_t log) {-    struct LogReporter : public log::Reader::Reporter {-      Env* env;-      Logger* info_log;-      uint64_t lognum;-      virtual void Corruption(size_t bytes, const Status& s) {-        // We print error messages for corruption, but continue repairing.-        Log(info_log, "Log #%llu: dropping %d bytes; %s",-            (unsigned long long) lognum,-            static_cast<int>(bytes),-            s.ToString().c_str());-      }-    };--    // Open the log file-    std::string logname = LogFileName(dbname_, log);-    SequentialFile* lfile;-    Status status = env_->NewSequentialFile(logname, &lfile);-    if (!status.ok()) {-      return status;-    }--    // Create the log reader.-    LogReporter reporter;-    reporter.env = env_;-    reporter.info_log = options_.info_log;-    reporter.lognum = log;-    // We intentially make log::Reader do checksumming so that-    // corruptions cause entire commits to be skipped instead of-    // propagating bad information (like overly large sequence-    // numbers).-    log::Reader reader(lfile, &reporter, false/*do not checksum*/,-                       0/*initial_offset*/);--    // Read all the records and add to a memtable-    std::string scratch;-    Slice record;-    WriteBatch batch;-    MemTable* mem = new MemTable(icmp_);-    mem->Ref();-    int counter = 0;-    while (reader.ReadRecord(&record, &scratch)) {-      if (record.size() < 12) {-        reporter.Corruption(-            record.size(), Status::Corruption("log record too small"));-        continue;-      }-      WriteBatchInternal::SetContents(&batch, record);-      status = WriteBatchInternal::InsertInto(&batch, mem);-      if (status.ok()) {-        counter += WriteBatchInternal::Count(&batch);-      } else {-        Log(options_.info_log, "Log #%llu: ignoring %s",-            (unsigned long long) log,-            status.ToString().c_str());-        status = Status::OK();  // Keep going with rest of file-      }-    }-    delete lfile;--    // Do not record a version edit for this conversion to a Table-    // since ExtractMetaData() will also generate edits.-    FileMetaData meta;-    meta.number = next_file_number_++;-    Iterator* iter = mem->NewIterator();-    status = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta);-    delete iter;-    mem->Unref();-    mem = NULL;-    if (status.ok()) {-      if (meta.file_size > 0) {-        table_numbers_.push_back(meta.number);-      }-    }-    Log(options_.info_log, "Log #%llu: %d ops saved to Table #%llu %s",-        (unsigned long long) log,-        counter,-        (unsigned long long) meta.number,-        status.ToString().c_str());-    return status;-  }--  void ExtractMetaData() {-    std::vector<TableInfo> kept;-    for (size_t i = 0; i < table_numbers_.size(); i++) {-      TableInfo t;-      t.meta.number = table_numbers_[i];-      Status status = ScanTable(&t);-      if (!status.ok()) {-        std::string fname = TableFileName(dbname_, table_numbers_[i]);-        Log(options_.info_log, "Table #%llu: ignoring %s",-            (unsigned long long) table_numbers_[i],-            status.ToString().c_str());-        ArchiveFile(fname);-      } else {-        tables_.push_back(t);-      }-    }-  }--  Status ScanTable(TableInfo* t) {-    std::string fname = TableFileName(dbname_, t->meta.number);-    int counter = 0;-    Status status = env_->GetFileSize(fname, &t->meta.file_size);-    if (status.ok()) {-      Iterator* iter = table_cache_->NewIterator(-          ReadOptions(), t->meta.number, t->meta.file_size);-      bool empty = true;-      ParsedInternalKey parsed;-      t->max_sequence = 0;-      for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {-        Slice key = iter->key();-        if (!ParseInternalKey(key, &parsed)) {-          Log(options_.info_log, "Table #%llu: unparsable key %s",-              (unsigned long long) t->meta.number,-              EscapeString(key).c_str());-          continue;-        }--        counter++;-        if (empty) {-          empty = false;-          t->meta.smallest.DecodeFrom(key);-        }-        t->meta.largest.DecodeFrom(key);-        if (parsed.sequence > t->max_sequence) {-          t->max_sequence = parsed.sequence;-        }-      }-      if (!iter->status().ok()) {-        status = iter->status();-      }-      delete iter;-    }-    Log(options_.info_log, "Table #%llu: %d entries %s",-        (unsigned long long) t->meta.number,-        counter,-        status.ToString().c_str());-    return status;-  }--  Status WriteDescriptor() {-    std::string tmp = TempFileName(dbname_, 1);-    WritableFile* file;-    Status status = env_->NewWritableFile(tmp, &file);-    if (!status.ok()) {-      return status;-    }--    SequenceNumber max_sequence = 0;-    for (size_t i = 0; i < tables_.size(); i++) {-      if (max_sequence < tables_[i].max_sequence) {-        max_sequence = tables_[i].max_sequence;-      }-    }--    edit_.SetComparatorName(icmp_.user_comparator()->Name());-    edit_.SetLogNumber(0);-    edit_.SetNextFile(next_file_number_);-    edit_.SetLastSequence(max_sequence);--    for (size_t i = 0; i < tables_.size(); i++) {-      // TODO(opt): separate out into multiple levels-      const TableInfo& t = tables_[i];-      edit_.AddFile(0, t.meta.number, t.meta.file_size,-                    t.meta.smallest, t.meta.largest);-    }--    //fprintf(stderr, "NewDescriptor:\n%s\n", edit_.DebugString().c_str());-    {-      log::Writer log(file);-      std::string record;-      edit_.EncodeTo(&record);-      status = log.AddRecord(record);-    }-    if (status.ok()) {-      status = file->Close();-    }-    delete file;-    file = NULL;--    if (!status.ok()) {-      env_->DeleteFile(tmp);-    } else {-      // Discard older manifests-      for (size_t i = 0; i < manifests_.size(); i++) {-        ArchiveFile(dbname_ + "/" + manifests_[i]);-      }--      // Install new manifest-      status = env_->RenameFile(tmp, DescriptorFileName(dbname_, 1));-      if (status.ok()) {-        status = SetCurrentFile(env_, dbname_, 1);-      } else {-        env_->DeleteFile(tmp);-      }-    }-    return status;-  }--  void ArchiveFile(const std::string& fname) {-    // Move into another directory.  E.g., for-    //    dir/foo-    // rename to-    //    dir/lost/foo-    const char* slash = strrchr(fname.c_str(), '/');-    std::string new_dir;-    if (slash != NULL) {-      new_dir.assign(fname.data(), slash - fname.data());-    }-    new_dir.append("/lost");-    env_->CreateDir(new_dir);  // Ignore error-    std::string new_file = new_dir;-    new_file.append("/");-    new_file.append((slash == NULL) ? fname.c_str() : slash + 1);-    Status s = env_->RenameFile(fname, new_file);-    Log(options_.info_log, "Archiving %s: %s\n",-        fname.c_str(), s.ToString().c_str());-  }-};-}  // namespace--Status RepairDB(const std::string& dbname, const Options& options) {-  Repairer repairer(dbname, options);-  return repairer.Run();-}--}  // namespace leveldb
− cbits/leveldb/db/skiplist.h
@@ -1,378 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// Thread safety-// --------------//-// Writes require external synchronization, most likely a mutex.-// Reads require a guarantee that the SkipList will not be destroyed-// while the read is in progress.  Apart from that, reads progress-// without any internal locking or synchronization.-//-// Invariants:-//-// (1) Allocated nodes are never deleted until the SkipList is-// destroyed.  This is trivially guaranteed by the code since we-// never delete any skip list nodes.-//-// (2) The contents of a Node except for the next/prev pointers are-// immutable after the Node has been linked into the SkipList.-// Only Insert() modifies the list, and it is careful to initialize-// a node and use release-stores to publish the nodes in one or-// more lists.-//-// ... prev vs. next pointer ordering ...--#include <assert.h>-#include <stdlib.h>-#include "port/port.h"-#include "util/arena.h"-#include "util/random.h"--namespace leveldb {--class Arena;--template<typename Key, class Comparator>-class SkipList {- private:-  struct Node;-- public:-  // Create a new SkipList object that will use "cmp" for comparing keys,-  // and will allocate memory using "*arena".  Objects allocated in the arena-  // must remain allocated for the lifetime of the skiplist object.-  explicit SkipList(Comparator cmp, Arena* arena);--  // Insert key into the list.-  // REQUIRES: nothing that compares equal to key is currently in the list.-  void Insert(const Key& key);--  // Returns true iff an entry that compares equal to key is in the list.-  bool Contains(const Key& key) const;--  // Iteration over the contents of a skip list-  class Iterator {-   public:-    // Initialize an iterator over the specified list.-    // The returned iterator is not valid.-    explicit Iterator(const SkipList* list);--    // Returns true iff the iterator is positioned at a valid node.-    bool Valid() const;--    // Returns the key at the current position.-    // REQUIRES: Valid()-    const Key& key() const;--    // Advances to the next position.-    // REQUIRES: Valid()-    void Next();--    // Advances to the previous position.-    // REQUIRES: Valid()-    void Prev();--    // Advance to the first entry with a key >= target-    void Seek(const Key& target);--    // Position at the first entry in list.-    // Final state of iterator is Valid() iff list is not empty.-    void SeekToFirst();--    // Position at the last entry in list.-    // Final state of iterator is Valid() iff list is not empty.-    void SeekToLast();--   private:-    const SkipList* list_;-    Node* node_;-    // Intentionally copyable-  };-- private:-  enum { kMaxHeight = 12 };--  // Immutable after construction-  Comparator const compare_;-  Arena* const arena_;    // Arena used for allocations of nodes--  Node* const head_;--  // Modified only by Insert().  Read racily by readers, but stale-  // values are ok.-  port::AtomicPointer max_height_;   // Height of the entire list--  inline int GetMaxHeight() const {-    return reinterpret_cast<intptr_t>(max_height_.NoBarrier_Load());-  }--  // Read/written only by Insert().-  Random rnd_;--  Node* NewNode(const Key& key, int height);-  int RandomHeight();-  bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); }--  // Return true if key is greater than the data stored in "n"-  bool KeyIsAfterNode(const Key& key, Node* n) const;--  // Return the earliest node that comes at or after key.-  // Return NULL if there is no such node.-  //-  // If prev is non-NULL, fills prev[level] with pointer to previous-  // node at "level" for every level in [0..max_height_-1].-  Node* FindGreaterOrEqual(const Key& key, Node** prev) const;--  // Return the latest node with a key < key.-  // Return head_ if there is no such node.-  Node* FindLessThan(const Key& key) const;--  // Return the last node in the list.-  // Return head_ if list is empty.-  Node* FindLast() const;--  // No copying allowed-  SkipList(const SkipList&);-  void operator=(const SkipList&);-};--// Implementation details follow-template<typename Key, class Comparator>-struct SkipList<Key,Comparator>::Node {-  explicit Node(const Key& k) : key(k) { }--  Key const key;--  // Accessors/mutators for links.  Wrapped in methods so we can-  // add the appropriate barriers as necessary.-  Node* Next(int n) {-    assert(n >= 0);-    // Use an 'acquire load' so that we observe a fully initialized-    // version of the returned Node.-    return reinterpret_cast<Node*>(next_[n].Acquire_Load());-  }-  void SetNext(int n, Node* x) {-    assert(n >= 0);-    // Use a 'release store' so that anybody who reads through this-    // pointer observes a fully initialized version of the inserted node.-    next_[n].Release_Store(x);-  }--  // No-barrier variants that can be safely used in a few locations.-  Node* NoBarrier_Next(int n) {-    assert(n >= 0);-    return reinterpret_cast<Node*>(next_[n].NoBarrier_Load());-  }-  void NoBarrier_SetNext(int n, Node* x) {-    assert(n >= 0);-    next_[n].NoBarrier_Store(x);-  }-- private:-  // Array of length equal to the node height.  next_[0] is lowest level link.-  port::AtomicPointer next_[1];-};--template<typename Key, class Comparator>-typename SkipList<Key,Comparator>::Node*-SkipList<Key,Comparator>::NewNode(const Key& key, int height) {-  char* mem = arena_->AllocateAligned(-      sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1));-  return new (mem) Node(key);-}--template<typename Key, class Comparator>-inline SkipList<Key,Comparator>::Iterator::Iterator(const SkipList* list) {-  list_ = list;-  node_ = NULL;-}--template<typename Key, class Comparator>-inline bool SkipList<Key,Comparator>::Iterator::Valid() const {-  return node_ != NULL;-}--template<typename Key, class Comparator>-inline const Key& SkipList<Key,Comparator>::Iterator::key() const {-  assert(Valid());-  return node_->key;-}--template<typename Key, class Comparator>-inline void SkipList<Key,Comparator>::Iterator::Next() {-  assert(Valid());-  node_ = node_->Next(0);-}--template<typename Key, class Comparator>-inline void SkipList<Key,Comparator>::Iterator::Prev() {-  // Instead of using explicit "prev" links, we just search for the-  // last node that falls before key.-  assert(Valid());-  node_ = list_->FindLessThan(node_->key);-  if (node_ == list_->head_) {-    node_ = NULL;-  }-}--template<typename Key, class Comparator>-inline void SkipList<Key,Comparator>::Iterator::Seek(const Key& target) {-  node_ = list_->FindGreaterOrEqual(target, NULL);-}--template<typename Key, class Comparator>-inline void SkipList<Key,Comparator>::Iterator::SeekToFirst() {-  node_ = list_->head_->Next(0);-}--template<typename Key, class Comparator>-inline void SkipList<Key,Comparator>::Iterator::SeekToLast() {-  node_ = list_->FindLast();-  if (node_ == list_->head_) {-    node_ = NULL;-  }-}--template<typename Key, class Comparator>-int SkipList<Key,Comparator>::RandomHeight() {-  // Increase height with probability 1 in kBranching-  static const unsigned int kBranching = 4;-  int height = 1;-  while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) {-    height++;-  }-  assert(height > 0);-  assert(height <= kMaxHeight);-  return height;-}--template<typename Key, class Comparator>-bool SkipList<Key,Comparator>::KeyIsAfterNode(const Key& key, Node* n) const {-  // NULL n is considered infinite-  return (n != NULL) && (compare_(n->key, key) < 0);-}--template<typename Key, class Comparator>-typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindGreaterOrEqual(const Key& key, Node** prev)-    const {-  Node* x = head_;-  int level = GetMaxHeight() - 1;-  while (true) {-    Node* next = x->Next(level);-    if (KeyIsAfterNode(key, next)) {-      // Keep searching in this list-      x = next;-    } else {-      if (prev != NULL) prev[level] = x;-      if (level == 0) {-        return next;-      } else {-        // Switch to next list-        level--;-      }-    }-  }-}--template<typename Key, class Comparator>-typename SkipList<Key,Comparator>::Node*-SkipList<Key,Comparator>::FindLessThan(const Key& key) const {-  Node* x = head_;-  int level = GetMaxHeight() - 1;-  while (true) {-    assert(x == head_ || compare_(x->key, key) < 0);-    Node* next = x->Next(level);-    if (next == NULL || compare_(next->key, key) >= 0) {-      if (level == 0) {-        return x;-      } else {-        // Switch to next list-        level--;-      }-    } else {-      x = next;-    }-  }-}--template<typename Key, class Comparator>-typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindLast()-    const {-  Node* x = head_;-  int level = GetMaxHeight() - 1;-  while (true) {-    Node* next = x->Next(level);-    if (next == NULL) {-      if (level == 0) {-        return x;-      } else {-        // Switch to next list-        level--;-      }-    } else {-      x = next;-    }-  }-}--template<typename Key, class Comparator>-SkipList<Key,Comparator>::SkipList(Comparator cmp, Arena* arena)-    : compare_(cmp),-      arena_(arena),-      head_(NewNode(0 /* any key will do */, kMaxHeight)),-      max_height_(reinterpret_cast<void*>(1)),-      rnd_(0xdeadbeef) {-  for (int i = 0; i < kMaxHeight; i++) {-    head_->SetNext(i, NULL);-  }-}--template<typename Key, class Comparator>-void SkipList<Key,Comparator>::Insert(const Key& key) {-  // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual()-  // here since Insert() is externally synchronized.-  Node* prev[kMaxHeight];-  Node* x = FindGreaterOrEqual(key, prev);--  // Our data structure does not allow duplicate insertion-  assert(x == NULL || !Equal(key, x->key));--  int height = RandomHeight();-  if (height > GetMaxHeight()) {-    for (int i = GetMaxHeight(); i < height; i++) {-      prev[i] = head_;-    }-    //fprintf(stderr, "Change height from %d to %d\n", max_height_, height);--    // It is ok to mutate max_height_ without any synchronization-    // with concurrent readers.  A concurrent reader that observes-    // the new value of max_height_ will see either the old value of-    // new level pointers from head_ (NULL), or a new value set in-    // the loop below.  In the former case the reader will-    // immediately drop to the next level since NULL sorts after all-    // keys.  In the latter case the reader will use the new node.-    max_height_.NoBarrier_Store(reinterpret_cast<void*>(height));-  }--  x = NewNode(key, height);-  for (int i = 0; i < height; i++) {-    // NoBarrier_SetNext() suffices since we will add a barrier when-    // we publish a pointer to "x" in prev[i].-    x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));-    prev[i]->SetNext(i, x);-  }-}--template<typename Key, class Comparator>-bool SkipList<Key,Comparator>::Contains(const Key& key) const {-  Node* x = FindGreaterOrEqual(key, NULL);-  if (x != NULL && Equal(key, x->key)) {-    return true;-  } else {-    return false;-  }-}--}  // namespace leveldb
− cbits/leveldb/db/skiplist_test.cc
@@ -1,378 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/skiplist.h"-#include <set>-#include "leveldb/env.h"-#include "util/arena.h"-#include "util/hash.h"-#include "util/random.h"-#include "util/testharness.h"--namespace leveldb {--typedef uint64_t Key;--struct Comparator {-  int operator()(const Key& a, const Key& b) const {-    if (a < b) {-      return -1;-    } else if (a > b) {-      return +1;-    } else {-      return 0;-    }-  }-};--class SkipTest { };--TEST(SkipTest, Empty) {-  Arena arena;-  Comparator cmp;-  SkipList<Key, Comparator> list(cmp, &arena);-  ASSERT_TRUE(!list.Contains(10));--  SkipList<Key, Comparator>::Iterator iter(&list);-  ASSERT_TRUE(!iter.Valid());-  iter.SeekToFirst();-  ASSERT_TRUE(!iter.Valid());-  iter.Seek(100);-  ASSERT_TRUE(!iter.Valid());-  iter.SeekToLast();-  ASSERT_TRUE(!iter.Valid());-}--TEST(SkipTest, InsertAndLookup) {-  const int N = 2000;-  const int R = 5000;-  Random rnd(1000);-  std::set<Key> keys;-  Arena arena;-  Comparator cmp;-  SkipList<Key, Comparator> list(cmp, &arena);-  for (int i = 0; i < N; i++) {-    Key key = rnd.Next() % R;-    if (keys.insert(key).second) {-      list.Insert(key);-    }-  }--  for (int i = 0; i < R; i++) {-    if (list.Contains(i)) {-      ASSERT_EQ(keys.count(i), 1);-    } else {-      ASSERT_EQ(keys.count(i), 0);-    }-  }--  // Simple iterator tests-  {-    SkipList<Key, Comparator>::Iterator iter(&list);-    ASSERT_TRUE(!iter.Valid());--    iter.Seek(0);-    ASSERT_TRUE(iter.Valid());-    ASSERT_EQ(*(keys.begin()), iter.key());--    iter.SeekToFirst();-    ASSERT_TRUE(iter.Valid());-    ASSERT_EQ(*(keys.begin()), iter.key());--    iter.SeekToLast();-    ASSERT_TRUE(iter.Valid());-    ASSERT_EQ(*(keys.rbegin()), iter.key());-  }--  // Forward iteration test-  for (int i = 0; i < R; i++) {-    SkipList<Key, Comparator>::Iterator iter(&list);-    iter.Seek(i);--    // Compare against model iterator-    std::set<Key>::iterator model_iter = keys.lower_bound(i);-    for (int j = 0; j < 3; j++) {-      if (model_iter == keys.end()) {-        ASSERT_TRUE(!iter.Valid());-        break;-      } else {-        ASSERT_TRUE(iter.Valid());-        ASSERT_EQ(*model_iter, iter.key());-        ++model_iter;-        iter.Next();-      }-    }-  }--  // Backward iteration test-  {-    SkipList<Key, Comparator>::Iterator iter(&list);-    iter.SeekToLast();--    // Compare against model iterator-    for (std::set<Key>::reverse_iterator model_iter = keys.rbegin();-         model_iter != keys.rend();-         ++model_iter) {-      ASSERT_TRUE(iter.Valid());-      ASSERT_EQ(*model_iter, iter.key());-      iter.Prev();-    }-    ASSERT_TRUE(!iter.Valid());-  }-}--// We want to make sure that with a single writer and multiple-// concurrent readers (with no synchronization other than when a-// reader's iterator is created), the reader always observes all the-// data that was present in the skip list when the iterator was-// constructor.  Because insertions are happening concurrently, we may-// also observe new values that were inserted since the iterator was-// constructed, but we should never miss any values that were present-// at iterator construction time.-//-// We generate multi-part keys:-//     <key,gen,hash>-// where:-//     key is in range [0..K-1]-//     gen is a generation number for key-//     hash is hash(key,gen)-//-// The insertion code picks a random key, sets gen to be 1 + the last-// generation number inserted for that key, and sets hash to Hash(key,gen).-//-// At the beginning of a read, we snapshot the last inserted-// generation number for each key.  We then iterate, including random-// calls to Next() and Seek().  For every key we encounter, we-// check that it is either expected given the initial snapshot or has-// been concurrently added since the iterator started.-class ConcurrentTest {- private:-  static const uint32_t K = 4;--  static uint64_t key(Key key) { return (key >> 40); }-  static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; }-  static uint64_t hash(Key key) { return key & 0xff; }--  static uint64_t HashNumbers(uint64_t k, uint64_t g) {-    uint64_t data[2] = { k, g };-    return Hash(reinterpret_cast<char*>(data), sizeof(data), 0);-  }--  static Key MakeKey(uint64_t k, uint64_t g) {-    assert(sizeof(Key) == sizeof(uint64_t));-    assert(k <= K);  // We sometimes pass K to seek to the end of the skiplist-    assert(g <= 0xffffffffu);-    return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff));-  }--  static bool IsValidKey(Key k) {-    return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff);-  }--  static Key RandomTarget(Random* rnd) {-    switch (rnd->Next() % 10) {-      case 0:-        // Seek to beginning-        return MakeKey(0, 0);-      case 1:-        // Seek to end-        return MakeKey(K, 0);-      default:-        // Seek to middle-        return MakeKey(rnd->Next() % K, 0);-    }-  }--  // Per-key generation-  struct State {-    port::AtomicPointer generation[K];-    void Set(int k, intptr_t v) {-      generation[k].Release_Store(reinterpret_cast<void*>(v));-    }-    intptr_t Get(int k) {-      return reinterpret_cast<intptr_t>(generation[k].Acquire_Load());-    }--    State() {-      for (int k = 0; k < K; k++) {-        Set(k, 0);-      }-    }-  };--  // Current state of the test-  State current_;--  Arena arena_;--  // SkipList is not protected by mu_.  We just use a single writer-  // thread to modify it.-  SkipList<Key, Comparator> list_;-- public:-  ConcurrentTest() : list_(Comparator(), &arena_) { }--  // REQUIRES: External synchronization-  void WriteStep(Random* rnd) {-    const uint32_t k = rnd->Next() % K;-    const intptr_t g = current_.Get(k) + 1;-    const Key key = MakeKey(k, g);-    list_.Insert(key);-    current_.Set(k, g);-  }--  void ReadStep(Random* rnd) {-    // Remember the initial committed state of the skiplist.-    State initial_state;-    for (int k = 0; k < K; k++) {-      initial_state.Set(k, current_.Get(k));-    }--    Key pos = RandomTarget(rnd);-    SkipList<Key, Comparator>::Iterator iter(&list_);-    iter.Seek(pos);-    while (true) {-      Key current;-      if (!iter.Valid()) {-        current = MakeKey(K, 0);-      } else {-        current = iter.key();-        ASSERT_TRUE(IsValidKey(current)) << current;-      }-      ASSERT_LE(pos, current) << "should not go backwards";--      // Verify that everything in [pos,current) was not present in-      // initial_state.-      while (pos < current) {-        ASSERT_LT(key(pos), K) << pos;--        // Note that generation 0 is never inserted, so it is ok if-        // <*,0,*> is missing.-        ASSERT_TRUE((gen(pos) == 0) ||-                    (gen(pos) > initial_state.Get(key(pos)))-                    ) << "key: " << key(pos)-                      << "; gen: " << gen(pos)-                      << "; initgen: "-                      << initial_state.Get(key(pos));--        // Advance to next key in the valid key space-        if (key(pos) < key(current)) {-          pos = MakeKey(key(pos) + 1, 0);-        } else {-          pos = MakeKey(key(pos), gen(pos) + 1);-        }-      }--      if (!iter.Valid()) {-        break;-      }--      if (rnd->Next() % 2) {-        iter.Next();-        pos = MakeKey(key(pos), gen(pos) + 1);-      } else {-        Key new_target = RandomTarget(rnd);-        if (new_target > pos) {-          pos = new_target;-          iter.Seek(new_target);-        }-      }-    }-  }-};-const uint32_t ConcurrentTest::K;--// Simple test that does single-threaded testing of the ConcurrentTest-// scaffolding.-TEST(SkipTest, ConcurrentWithoutThreads) {-  ConcurrentTest test;-  Random rnd(test::RandomSeed());-  for (int i = 0; i < 10000; i++) {-    test.ReadStep(&rnd);-    test.WriteStep(&rnd);-  }-}--class TestState {- public:-  ConcurrentTest t_;-  int seed_;-  port::AtomicPointer quit_flag_;--  enum ReaderState {-    STARTING,-    RUNNING,-    DONE-  };--  explicit TestState(int s)-      : seed_(s),-        quit_flag_(NULL),-        state_(STARTING),-        state_cv_(&mu_) {}--  void Wait(ReaderState s) {-    mu_.Lock();-    while (state_ != s) {-      state_cv_.Wait();-    }-    mu_.Unlock();-  }--  void Change(ReaderState s) {-    mu_.Lock();-    state_ = s;-    state_cv_.Signal();-    mu_.Unlock();-  }-- private:-  port::Mutex mu_;-  ReaderState state_;-  port::CondVar state_cv_;-};--static void ConcurrentReader(void* arg) {-  TestState* state = reinterpret_cast<TestState*>(arg);-  Random rnd(state->seed_);-  int64_t reads = 0;-  state->Change(TestState::RUNNING);-  while (!state->quit_flag_.Acquire_Load()) {-    state->t_.ReadStep(&rnd);-    ++reads;-  }-  state->Change(TestState::DONE);-}--static void RunConcurrent(int run) {-  const int seed = test::RandomSeed() + (run * 100);-  Random rnd(seed);-  const int N = 1000;-  const int kSize = 1000;-  for (int i = 0; i < N; i++) {-    if ((i % 100) == 0) {-      fprintf(stderr, "Run %d of %d\n", i, N);-    }-    TestState state(seed + 1);-    Env::Default()->Schedule(ConcurrentReader, &state);-    state.Wait(TestState::RUNNING);-    for (int i = 0; i < kSize; i++) {-      state.t_.WriteStep(&rnd);-    }-    state.quit_flag_.Release_Store(&state);  // Any non-NULL arg will do-    state.Wait(TestState::DONE);-  }-}--TEST(SkipTest, Concurrent1) { RunConcurrent(1); }-TEST(SkipTest, Concurrent2) { RunConcurrent(2); }-TEST(SkipTest, Concurrent3) { RunConcurrent(3); }-TEST(SkipTest, Concurrent4) { RunConcurrent(4); }-TEST(SkipTest, Concurrent5) { RunConcurrent(5); }--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/db/snapshot.h
@@ -1,66 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_DB_SNAPSHOT_H_-#define STORAGE_LEVELDB_DB_SNAPSHOT_H_--#include "leveldb/db.h"--namespace leveldb {--class SnapshotList;--// Snapshots are kept in a doubly-linked list in the DB.-// Each SnapshotImpl corresponds to a particular sequence number.-class SnapshotImpl : public Snapshot {- public:-  SequenceNumber number_;  // const after creation-- private:-  friend class SnapshotList;--  // SnapshotImpl is kept in a doubly-linked circular list-  SnapshotImpl* prev_;-  SnapshotImpl* next_;--  SnapshotList* list_;                 // just for sanity checks-};--class SnapshotList {- public:-  SnapshotList() {-    list_.prev_ = &list_;-    list_.next_ = &list_;-  }--  bool empty() const { return list_.next_ == &list_; }-  SnapshotImpl* oldest() const { assert(!empty()); return list_.next_; }-  SnapshotImpl* newest() const { assert(!empty()); return list_.prev_; }--  const SnapshotImpl* New(SequenceNumber seq) {-    SnapshotImpl* s = new SnapshotImpl;-    s->number_ = seq;-    s->list_ = this;-    s->next_ = &list_;-    s->prev_ = list_.prev_;-    s->prev_->next_ = s;-    s->next_->prev_ = s;-    return s;-  }--  void Delete(const SnapshotImpl* s) {-    assert(s->list_ == this);-    s->prev_->next_ = s->next_;-    s->next_->prev_ = s->prev_;-    delete s;-  }-- private:-  // Dummy head of doubly-linked list of snapshots-  SnapshotImpl list_;-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_SNAPSHOT_H_
− cbits/leveldb/db/table_cache.cc
@@ -1,95 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/table_cache.h"--#include "db/filename.h"-#include "leveldb/env.h"-#include "leveldb/table.h"-#include "util/coding.h"--namespace leveldb {--struct TableAndFile {-  RandomAccessFile* file;-  Table* table;-};--static void DeleteEntry(const Slice& key, void* value) {-  TableAndFile* tf = reinterpret_cast<TableAndFile*>(value);-  delete tf->table;-  delete tf->file;-  delete tf;-}--static void UnrefEntry(void* arg1, void* arg2) {-  Cache* cache = reinterpret_cast<Cache*>(arg1);-  Cache::Handle* h = reinterpret_cast<Cache::Handle*>(arg2);-  cache->Release(h);-}--TableCache::TableCache(const std::string& dbname,-                       const Options* options,-                       int entries)-    : env_(options->env),-      dbname_(dbname),-      options_(options),-      cache_(NewLRUCache(entries)) {-}--TableCache::~TableCache() {-  delete cache_;-}--Iterator* TableCache::NewIterator(const ReadOptions& options,-                                  uint64_t file_number,-                                  uint64_t file_size,-                                  Table** tableptr) {-  if (tableptr != NULL) {-    *tableptr = NULL;-  }--  char buf[sizeof(file_number)];-  EncodeFixed64(buf, file_number);-  Slice key(buf, sizeof(buf));-  Cache::Handle* handle = cache_->Lookup(key);-  if (handle == NULL) {-    std::string fname = TableFileName(dbname_, file_number);-    RandomAccessFile* file = NULL;-    Table* table = NULL;-    Status s = env_->NewRandomAccessFile(fname, &file);-    if (s.ok()) {-      s = Table::Open(*options_, file, file_size, &table);-    }--    if (!s.ok()) {-      assert(table == NULL);-      delete file;-      // We do not cache error results so that if the error is transient,-      // or somebody repairs the file, we recover automatically.-      return NewErrorIterator(s);-    }--    TableAndFile* tf = new TableAndFile;-    tf->file = file;-    tf->table = table;-    handle = cache_->Insert(key, tf, 1, &DeleteEntry);-  }--  Table* table = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table;-  Iterator* result = table->NewIterator(options);-  result->RegisterCleanup(&UnrefEntry, cache_, handle);-  if (tableptr != NULL) {-    *tableptr = table;-  }-  return result;-}--void TableCache::Evict(uint64_t file_number) {-  char buf[sizeof(file_number)];-  EncodeFixed64(buf, file_number);-  cache_->Erase(Slice(buf, sizeof(buf)));-}--}  // namespace leveldb
− cbits/leveldb/db/table_cache.h
@@ -1,50 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// Thread-safe (provides internal synchronization)--#ifndef STORAGE_LEVELDB_DB_TABLE_CACHE_H_-#define STORAGE_LEVELDB_DB_TABLE_CACHE_H_--#include <string>-#include <stdint.h>-#include "db/dbformat.h"-#include "leveldb/cache.h"-#include "leveldb/table.h"-#include "port/port.h"--namespace leveldb {--class Env;--class TableCache {- public:-  TableCache(const std::string& dbname, const Options* options, int entries);-  ~TableCache();--  // Return an iterator for the specified file number (the corresponding-  // file length must be exactly "file_size" bytes).  If "tableptr" is-  // non-NULL, also sets "*tableptr" to point to the Table object-  // underlying the returned iterator, or NULL if no Table object underlies-  // the returned iterator.  The returned "*tableptr" object is owned by-  // the cache and should not be deleted, and is valid for as long as the-  // returned iterator is live.-  Iterator* NewIterator(const ReadOptions& options,-                        uint64_t file_number,-                        uint64_t file_size,-                        Table** tableptr = NULL);--  // Evict any entry for the specified file number-  void Evict(uint64_t file_number);-- private:-  Env* const env_;-  const std::string dbname_;-  const Options* options_;-  Cache* cache_;-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_TABLE_CACHE_H_
− cbits/leveldb/db/version_edit.cc
@@ -1,266 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/version_edit.h"--#include "db/version_set.h"-#include "util/coding.h"--namespace leveldb {--// Tag numbers for serialized VersionEdit.  These numbers are written to-// disk and should not be changed.-enum Tag {-  kComparator           = 1,-  kLogNumber            = 2,-  kNextFileNumber       = 3,-  kLastSequence         = 4,-  kCompactPointer       = 5,-  kDeletedFile          = 6,-  kNewFile              = 7,-  // 8 was used for large value refs-  kPrevLogNumber        = 9-};--void VersionEdit::Clear() {-  comparator_.clear();-  log_number_ = 0;-  prev_log_number_ = 0;-  last_sequence_ = 0;-  next_file_number_ = 0;-  has_comparator_ = false;-  has_log_number_ = false;-  has_prev_log_number_ = false;-  has_next_file_number_ = false;-  has_last_sequence_ = false;-  deleted_files_.clear();-  new_files_.clear();-}--void VersionEdit::EncodeTo(std::string* dst) const {-  if (has_comparator_) {-    PutVarint32(dst, kComparator);-    PutLengthPrefixedSlice(dst, comparator_);-  }-  if (has_log_number_) {-    PutVarint32(dst, kLogNumber);-    PutVarint64(dst, log_number_);-  }-  if (has_prev_log_number_) {-    PutVarint32(dst, kPrevLogNumber);-    PutVarint64(dst, prev_log_number_);-  }-  if (has_next_file_number_) {-    PutVarint32(dst, kNextFileNumber);-    PutVarint64(dst, next_file_number_);-  }-  if (has_last_sequence_) {-    PutVarint32(dst, kLastSequence);-    PutVarint64(dst, last_sequence_);-  }--  for (size_t i = 0; i < compact_pointers_.size(); i++) {-    PutVarint32(dst, kCompactPointer);-    PutVarint32(dst, compact_pointers_[i].first);  // level-    PutLengthPrefixedSlice(dst, compact_pointers_[i].second.Encode());-  }--  for (DeletedFileSet::const_iterator iter = deleted_files_.begin();-       iter != deleted_files_.end();-       ++iter) {-    PutVarint32(dst, kDeletedFile);-    PutVarint32(dst, iter->first);   // level-    PutVarint64(dst, iter->second);  // file number-  }--  for (size_t i = 0; i < new_files_.size(); i++) {-    const FileMetaData& f = new_files_[i].second;-    PutVarint32(dst, kNewFile);-    PutVarint32(dst, new_files_[i].first);  // level-    PutVarint64(dst, f.number);-    PutVarint64(dst, f.file_size);-    PutLengthPrefixedSlice(dst, f.smallest.Encode());-    PutLengthPrefixedSlice(dst, f.largest.Encode());-  }-}--static bool GetInternalKey(Slice* input, InternalKey* dst) {-  Slice str;-  if (GetLengthPrefixedSlice(input, &str)) {-    dst->DecodeFrom(str);-    return true;-  } else {-    return false;-  }-}--static bool GetLevel(Slice* input, int* level) {-  uint32_t v;-  if (GetVarint32(input, &v) &&-      v < config::kNumLevels) {-    *level = v;-    return true;-  } else {-    return false;-  }-}--Status VersionEdit::DecodeFrom(const Slice& src) {-  Clear();-  Slice input = src;-  const char* msg = NULL;-  uint32_t tag;--  // Temporary storage for parsing-  int level;-  uint64_t number;-  FileMetaData f;-  Slice str;-  InternalKey key;--  while (msg == NULL && GetVarint32(&input, &tag)) {-    switch (tag) {-      case kComparator:-        if (GetLengthPrefixedSlice(&input, &str)) {-          comparator_ = str.ToString();-          has_comparator_ = true;-        } else {-          msg = "comparator name";-        }-        break;--      case kLogNumber:-        if (GetVarint64(&input, &log_number_)) {-          has_log_number_ = true;-        } else {-          msg = "log number";-        }-        break;--      case kPrevLogNumber:-        if (GetVarint64(&input, &prev_log_number_)) {-          has_prev_log_number_ = true;-        } else {-          msg = "previous log number";-        }-        break;--      case kNextFileNumber:-        if (GetVarint64(&input, &next_file_number_)) {-          has_next_file_number_ = true;-        } else {-          msg = "next file number";-        }-        break;--      case kLastSequence:-        if (GetVarint64(&input, &last_sequence_)) {-          has_last_sequence_ = true;-        } else {-          msg = "last sequence number";-        }-        break;--      case kCompactPointer:-        if (GetLevel(&input, &level) &&-            GetInternalKey(&input, &key)) {-          compact_pointers_.push_back(std::make_pair(level, key));-        } else {-          msg = "compaction pointer";-        }-        break;--      case kDeletedFile:-        if (GetLevel(&input, &level) &&-            GetVarint64(&input, &number)) {-          deleted_files_.insert(std::make_pair(level, number));-        } else {-          msg = "deleted file";-        }-        break;--      case kNewFile:-        if (GetLevel(&input, &level) &&-            GetVarint64(&input, &f.number) &&-            GetVarint64(&input, &f.file_size) &&-            GetInternalKey(&input, &f.smallest) &&-            GetInternalKey(&input, &f.largest)) {-          new_files_.push_back(std::make_pair(level, f));-        } else {-          msg = "new-file entry";-        }-        break;--      default:-        msg = "unknown tag";-        break;-    }-  }--  if (msg == NULL && !input.empty()) {-    msg = "invalid tag";-  }--  Status result;-  if (msg != NULL) {-    result = Status::Corruption("VersionEdit", msg);-  }-  return result;-}--std::string VersionEdit::DebugString() const {-  std::string r;-  r.append("VersionEdit {");-  if (has_comparator_) {-    r.append("\n  Comparator: ");-    r.append(comparator_);-  }-  if (has_log_number_) {-    r.append("\n  LogNumber: ");-    AppendNumberTo(&r, log_number_);-  }-  if (has_prev_log_number_) {-    r.append("\n  PrevLogNumber: ");-    AppendNumberTo(&r, prev_log_number_);-  }-  if (has_next_file_number_) {-    r.append("\n  NextFile: ");-    AppendNumberTo(&r, next_file_number_);-  }-  if (has_last_sequence_) {-    r.append("\n  LastSeq: ");-    AppendNumberTo(&r, last_sequence_);-  }-  for (size_t i = 0; i < compact_pointers_.size(); i++) {-    r.append("\n  CompactPointer: ");-    AppendNumberTo(&r, compact_pointers_[i].first);-    r.append(" ");-    r.append(compact_pointers_[i].second.DebugString());-  }-  for (DeletedFileSet::const_iterator iter = deleted_files_.begin();-       iter != deleted_files_.end();-       ++iter) {-    r.append("\n  DeleteFile: ");-    AppendNumberTo(&r, iter->first);-    r.append(" ");-    AppendNumberTo(&r, iter->second);-  }-  for (size_t i = 0; i < new_files_.size(); i++) {-    const FileMetaData& f = new_files_[i].second;-    r.append("\n  AddFile: ");-    AppendNumberTo(&r, new_files_[i].first);-    r.append(" ");-    AppendNumberTo(&r, f.number);-    r.append(" ");-    AppendNumberTo(&r, f.file_size);-    r.append(" ");-    r.append(f.smallest.DebugString());-    r.append(" .. ");-    r.append(f.largest.DebugString());-  }-  r.append("\n}\n");-  return r;-}--}  // namespace leveldb
− cbits/leveldb/db/version_edit.h
@@ -1,107 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_DB_VERSION_EDIT_H_-#define STORAGE_LEVELDB_DB_VERSION_EDIT_H_--#include <set>-#include <utility>-#include <vector>-#include "db/dbformat.h"--namespace leveldb {--class VersionSet;--struct FileMetaData {-  int refs;-  int allowed_seeks;          // Seeks allowed until compaction-  uint64_t number;-  uint64_t file_size;         // File size in bytes-  InternalKey smallest;       // Smallest internal key served by table-  InternalKey largest;        // Largest internal key served by table--  FileMetaData() : refs(0), allowed_seeks(1 << 30), file_size(0) { }-};--class VersionEdit {- public:-  VersionEdit() { Clear(); }-  ~VersionEdit() { }--  void Clear();--  void SetComparatorName(const Slice& name) {-    has_comparator_ = true;-    comparator_ = name.ToString();-  }-  void SetLogNumber(uint64_t num) {-    has_log_number_ = true;-    log_number_ = num;-  }-  void SetPrevLogNumber(uint64_t num) {-    has_prev_log_number_ = true;-    prev_log_number_ = num;-  }-  void SetNextFile(uint64_t num) {-    has_next_file_number_ = true;-    next_file_number_ = num;-  }-  void SetLastSequence(SequenceNumber seq) {-    has_last_sequence_ = true;-    last_sequence_ = seq;-  }-  void SetCompactPointer(int level, const InternalKey& key) {-    compact_pointers_.push_back(std::make_pair(level, key));-  }--  // Add the specified file at the specified number.-  // REQUIRES: This version has not been saved (see VersionSet::SaveTo)-  // REQUIRES: "smallest" and "largest" are smallest and largest keys in file-  void AddFile(int level, uint64_t file,-               uint64_t file_size,-               const InternalKey& smallest,-               const InternalKey& largest) {-    FileMetaData f;-    f.number = file;-    f.file_size = file_size;-    f.smallest = smallest;-    f.largest = largest;-    new_files_.push_back(std::make_pair(level, f));-  }--  // Delete the specified "file" from the specified "level".-  void DeleteFile(int level, uint64_t file) {-    deleted_files_.insert(std::make_pair(level, file));-  }--  void EncodeTo(std::string* dst) const;-  Status DecodeFrom(const Slice& src);--  std::string DebugString() const;-- private:-  friend class VersionSet;--  typedef std::set< std::pair<int, uint64_t> > DeletedFileSet;--  std::string comparator_;-  uint64_t log_number_;-  uint64_t prev_log_number_;-  uint64_t next_file_number_;-  SequenceNumber last_sequence_;-  bool has_comparator_;-  bool has_log_number_;-  bool has_prev_log_number_;-  bool has_next_file_number_;-  bool has_last_sequence_;--  std::vector< std::pair<int, InternalKey> > compact_pointers_;-  DeletedFileSet deleted_files_;-  std::vector< std::pair<int, FileMetaData> > new_files_;-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_VERSION_EDIT_H_
− cbits/leveldb/db/version_edit_test.cc
@@ -1,46 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/version_edit.h"-#include "util/testharness.h"--namespace leveldb {--static void TestEncodeDecode(const VersionEdit& edit) {-  std::string encoded, encoded2;-  edit.EncodeTo(&encoded);-  VersionEdit parsed;-  Status s = parsed.DecodeFrom(encoded);-  ASSERT_TRUE(s.ok()) << s.ToString();-  parsed.EncodeTo(&encoded2);-  ASSERT_EQ(encoded, encoded2);-}--class VersionEditTest { };--TEST(VersionEditTest, EncodeDecode) {-  static const uint64_t kBig = 1ull << 50;--  VersionEdit edit;-  for (int i = 0; i < 4; i++) {-    TestEncodeDecode(edit);-    edit.AddFile(3, kBig + 300 + i, kBig + 400 + i,-                 InternalKey("foo", kBig + 500 + i, kTypeValue),-                 InternalKey("zoo", kBig + 600 + i, kTypeDeletion));-    edit.DeleteFile(4, kBig + 700 + i);-    edit.SetCompactPointer(i, InternalKey("x", kBig + 900 + i, kTypeValue));-  }--  edit.SetComparatorName("foo");-  edit.SetLogNumber(kBig + 100);-  edit.SetNextFile(kBig + 200);-  edit.SetLastSequence(kBig + 1000);-  TestEncodeDecode(edit);-}--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/db/version_set.cc
@@ -1,1397 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/version_set.h"--#include <algorithm>-#include <stdio.h>-#include "db/filename.h"-#include "db/log_reader.h"-#include "db/log_writer.h"-#include "db/memtable.h"-#include "db/table_cache.h"-#include "leveldb/env.h"-#include "leveldb/table_builder.h"-#include "table/merger.h"-#include "table/two_level_iterator.h"-#include "util/coding.h"-#include "util/logging.h"--namespace leveldb {--static const int kTargetFileSize = 2 * 1048576;--// Maximum bytes of overlaps in grandparent (i.e., level+2) before we-// stop building a single file in a level->level+1 compaction.-static const int64_t kMaxGrandParentOverlapBytes = 10 * kTargetFileSize;--// Maximum number of bytes in all compacted files.  We avoid expanding-// the lower level file set of a compaction if it would make the-// total compaction cover more than this many bytes.-static const int64_t kExpandedCompactionByteSizeLimit = 25 * kTargetFileSize;--static double MaxBytesForLevel(int level) {-  // Note: the result for level zero is not really used since we set-  // the level-0 compaction threshold based on number of files.-  double result = 10 * 1048576.0;  // Result for both level-0 and level-1-  while (level > 1) {-    result *= 10;-    level--;-  }-  return result;-}--static uint64_t MaxFileSizeForLevel(int level) {-  return kTargetFileSize;  // We could vary per level to reduce number of files?-}--static int64_t TotalFileSize(const std::vector<FileMetaData*>& files) {-  int64_t sum = 0;-  for (size_t i = 0; i < files.size(); i++) {-    sum += files[i]->file_size;-  }-  return sum;-}--namespace {-std::string IntSetToString(const std::set<uint64_t>& s) {-  std::string result = "{";-  for (std::set<uint64_t>::const_iterator it = s.begin();-       it != s.end();-       ++it) {-    result += (result.size() > 1) ? "," : "";-    result += NumberToString(*it);-  }-  result += "}";-  return result;-}-}  // namespace--Version::~Version() {-  assert(refs_ == 0);--  // Remove from linked list-  prev_->next_ = next_;-  next_->prev_ = prev_;--  // Drop references to files-  for (int level = 0; level < config::kNumLevels; level++) {-    for (size_t i = 0; i < files_[level].size(); i++) {-      FileMetaData* f = files_[level][i];-      assert(f->refs > 0);-      f->refs--;-      if (f->refs <= 0) {-        delete f;-      }-    }-  }-}--int FindFile(const InternalKeyComparator& icmp,-             const std::vector<FileMetaData*>& files,-             const Slice& key) {-  uint32_t left = 0;-  uint32_t right = files.size();-  while (left < right) {-    uint32_t mid = (left + right) / 2;-    const FileMetaData* f = files[mid];-    if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) {-      // Key at "mid.largest" is < "target".  Therefore all-      // files at or before "mid" are uninteresting.-      left = mid + 1;-    } else {-      // Key at "mid.largest" is >= "target".  Therefore all files-      // after "mid" are uninteresting.-      right = mid;-    }-  }-  return right;-}--static bool AfterFile(const Comparator* ucmp,-                      const Slice* user_key, const FileMetaData* f) {-  // NULL user_key occurs before all keys and is therefore never after *f-  return (user_key != NULL &&-          ucmp->Compare(*user_key, f->largest.user_key()) > 0);-}--static bool BeforeFile(const Comparator* ucmp,-                       const Slice* user_key, const FileMetaData* f) {-  // NULL user_key occurs after all keys and is therefore never before *f-  return (user_key != NULL &&-          ucmp->Compare(*user_key, f->smallest.user_key()) < 0);-}--bool SomeFileOverlapsRange(-    const InternalKeyComparator& icmp,-    bool disjoint_sorted_files,-    const std::vector<FileMetaData*>& files,-    const Slice* smallest_user_key,-    const Slice* largest_user_key) {-  const Comparator* ucmp = icmp.user_comparator();-  if (!disjoint_sorted_files) {-    // Need to check against all files-    for (int i = 0; i < files.size(); i++) {-      const FileMetaData* f = files[i];-      if (AfterFile(ucmp, smallest_user_key, f) ||-          BeforeFile(ucmp, largest_user_key, f)) {-        // No overlap-      } else {-        return true;  // Overlap-      }-    }-    return false;-  }--  // Binary search over file list-  uint32_t index = 0;-  if (smallest_user_key != NULL) {-    // Find the earliest possible internal key for smallest_user_key-    InternalKey small(*smallest_user_key, kMaxSequenceNumber,kValueTypeForSeek);-    index = FindFile(icmp, files, small.Encode());-  }--  if (index >= files.size()) {-    // beginning of range is after all files, so no overlap.-    return false;-  }--  return !BeforeFile(ucmp, largest_user_key, files[index]);-}--// An internal iterator.  For a given version/level pair, yields-// information about the files in the level.  For a given entry, key()-// is the largest key that occurs in the file, and value() is an-// 16-byte value containing the file number and file size, both-// encoded using EncodeFixed64.-class Version::LevelFileNumIterator : public Iterator {- public:-  LevelFileNumIterator(const InternalKeyComparator& icmp,-                       const std::vector<FileMetaData*>* flist)-      : icmp_(icmp),-        flist_(flist),-        index_(flist->size()) {        // Marks as invalid-  }-  virtual bool Valid() const {-    return index_ < flist_->size();-  }-  virtual void Seek(const Slice& target) {-    index_ = FindFile(icmp_, *flist_, target);-  }-  virtual void SeekToFirst() { index_ = 0; }-  virtual void SeekToLast() {-    index_ = flist_->empty() ? 0 : flist_->size() - 1;-  }-  virtual void Next() {-    assert(Valid());-    index_++;-  }-  virtual void Prev() {-    assert(Valid());-    if (index_ == 0) {-      index_ = flist_->size();  // Marks as invalid-    } else {-      index_--;-    }-  }-  Slice key() const {-    assert(Valid());-    return (*flist_)[index_]->largest.Encode();-  }-  Slice value() const {-    assert(Valid());-    EncodeFixed64(value_buf_, (*flist_)[index_]->number);-    EncodeFixed64(value_buf_+8, (*flist_)[index_]->file_size);-    return Slice(value_buf_, sizeof(value_buf_));-  }-  virtual Status status() const { return Status::OK(); }- private:-  const InternalKeyComparator icmp_;-  const std::vector<FileMetaData*>* const flist_;-  uint32_t index_;--  // Backing store for value().  Holds the file number and size.-  mutable char value_buf_[16];-};--static Iterator* GetFileIterator(void* arg,-                                 const ReadOptions& options,-                                 const Slice& file_value) {-  TableCache* cache = reinterpret_cast<TableCache*>(arg);-  if (file_value.size() != 16) {-    return NewErrorIterator(-        Status::Corruption("FileReader invoked with unexpected value"));-  } else {-    return cache->NewIterator(options,-                              DecodeFixed64(file_value.data()),-                              DecodeFixed64(file_value.data() + 8));-  }-}--Iterator* Version::NewConcatenatingIterator(const ReadOptions& options,-                                            int level) const {-  return NewTwoLevelIterator(-      new LevelFileNumIterator(vset_->icmp_, &files_[level]),-      &GetFileIterator, vset_->table_cache_, options);-}--void Version::AddIterators(const ReadOptions& options,-                           std::vector<Iterator*>* iters) {-  // Merge all level zero files together since they may overlap-  for (size_t i = 0; i < files_[0].size(); i++) {-    iters->push_back(-        vset_->table_cache_->NewIterator(-            options, files_[0][i]->number, files_[0][i]->file_size));-  }--  // For levels > 0, we can use a concatenating iterator that sequentially-  // walks through the non-overlapping files in the level, opening them-  // lazily.-  for (int level = 1; level < config::kNumLevels; level++) {-    if (!files_[level].empty()) {-      iters->push_back(NewConcatenatingIterator(options, level));-    }-  }-}--// If "*iter" points at a value or deletion for user_key, store-// either the value, or a NotFound error and return true.-// Else return false.-static bool GetValue(const Comparator* cmp,-                     Iterator* iter, const Slice& user_key,-                     std::string* value,-                     Status* s) {-  if (!iter->Valid()) {-    return false;-  }-  ParsedInternalKey parsed_key;-  if (!ParseInternalKey(iter->key(), &parsed_key)) {-    *s = Status::Corruption("corrupted key for ", user_key);-    return true;-  }-  if (cmp->Compare(parsed_key.user_key, user_key) != 0) {-    return false;-  }-  switch (parsed_key.type) {-    case kTypeDeletion:-      *s = Status::NotFound(Slice());  // Use an empty error message for speed-      break;-    case kTypeValue: {-      Slice v = iter->value();-      value->assign(v.data(), v.size());-      break;-    }-  }-  return true;-}--static bool NewestFirst(FileMetaData* a, FileMetaData* b) {-  return a->number > b->number;-}--Status Version::Get(const ReadOptions& options,-                    const LookupKey& k,-                    std::string* value,-                    GetStats* stats) {-  Slice ikey = k.internal_key();-  Slice user_key = k.user_key();-  const Comparator* ucmp = vset_->icmp_.user_comparator();-  Status s;--  stats->seek_file = NULL;-  stats->seek_file_level = -1;-  FileMetaData* last_file_read = NULL;-  int last_file_read_level = -1;--  // We can search level-by-level since entries never hop across-  // levels.  Therefore we are guaranteed that if we find data-  // in an smaller level, later levels are irrelevant.-  std::vector<FileMetaData*> tmp;-  FileMetaData* tmp2;-  for (int level = 0; level < config::kNumLevels; level++) {-    size_t num_files = files_[level].size();-    if (num_files == 0) continue;--    // Get the list of files to search in this level-    FileMetaData* const* files = &files_[level][0];-    if (level == 0) {-      // Level-0 files may overlap each other.  Find all files that-      // overlap user_key and process them in order from newest to oldest.-      tmp.reserve(num_files);-      for (uint32_t i = 0; i < num_files; i++) {-        FileMetaData* f = files[i];-        if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 &&-            ucmp->Compare(user_key, f->largest.user_key()) <= 0) {-          tmp.push_back(f);-        }-      }-      if (tmp.empty()) continue;--      std::sort(tmp.begin(), tmp.end(), NewestFirst);-      files = &tmp[0];-      num_files = tmp.size();-    } else {-      // Binary search to find earliest index whose largest key >= ikey.-      uint32_t index = FindFile(vset_->icmp_, files_[level], ikey);-      if (index >= num_files) {-        files = NULL;-        num_files = 0;-      } else {-        tmp2 = files[index];-        if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) {-          // All of "tmp2" is past any data for user_key-          files = NULL;-          num_files = 0;-        } else {-          files = &tmp2;-          num_files = 1;-        }-      }-    }--    for (uint32_t i = 0; i < num_files; ++i) {-      if (last_file_read != NULL && stats->seek_file == NULL) {-        // We have had more than one seek for this read.  Charge the 1st file.-        stats->seek_file = last_file_read;-        stats->seek_file_level = last_file_read_level;-      }--      FileMetaData* f = files[i];-      last_file_read = f;-      last_file_read_level = level;--      Iterator* iter = vset_->table_cache_->NewIterator(-          options,-          f->number,-          f->file_size);-      iter->Seek(ikey);-      const bool done = GetValue(ucmp, iter, user_key, value, &s);-      if (!iter->status().ok()) {-        s = iter->status();-        delete iter;-        return s;-      } else {-        delete iter;-        if (done) {-          return s;-        }-      }-    }-  }--  return Status::NotFound(Slice());  // Use an empty error message for speed-}--bool Version::UpdateStats(const GetStats& stats) {-  FileMetaData* f = stats.seek_file;-  if (f != NULL) {-    f->allowed_seeks--;-    if (f->allowed_seeks <= 0 && file_to_compact_ == NULL) {-      file_to_compact_ = f;-      file_to_compact_level_ = stats.seek_file_level;-      return true;-    }-  }-  return false;-}--void Version::Ref() {-  ++refs_;-}--void Version::Unref() {-  assert(this != &vset_->dummy_versions_);-  assert(refs_ >= 1);-  --refs_;-  if (refs_ == 0) {-    delete this;-  }-}--bool Version::OverlapInLevel(int level,-                             const Slice* smallest_user_key,-                             const Slice* largest_user_key) {-  return SomeFileOverlapsRange(vset_->icmp_, (level > 0), files_[level],-                               smallest_user_key, largest_user_key);-}--int Version::PickLevelForMemTableOutput(-    const Slice& smallest_user_key,-    const Slice& largest_user_key) {-  int level = 0;-  if (!OverlapInLevel(0, &smallest_user_key, &largest_user_key)) {-    // Push to next level if there is no overlap in next level,-    // and the #bytes overlapping in the level after that are limited.-    InternalKey start(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek);-    InternalKey limit(largest_user_key, 0, static_cast<ValueType>(0));-    std::vector<FileMetaData*> overlaps;-    while (level < config::kMaxMemCompactLevel) {-      if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) {-        break;-      }-      GetOverlappingInputs(level + 2, &start, &limit, &overlaps);-      const int64_t sum = TotalFileSize(overlaps);-      if (sum > kMaxGrandParentOverlapBytes) {-        break;-      }-      level++;-    }-  }-  return level;-}--// Store in "*inputs" all files in "level" that overlap [begin,end]-void Version::GetOverlappingInputs(-    int level,-    const InternalKey* begin,-    const InternalKey* end,-    std::vector<FileMetaData*>* inputs) {-  inputs->clear();-  Slice user_begin, user_end;-  if (begin != NULL) {-    user_begin = begin->user_key();-  }-  if (end != NULL) {-    user_end = end->user_key();-  }-  const Comparator* user_cmp = vset_->icmp_.user_comparator();-  for (size_t i = 0; i < files_[level].size(); ) {-    FileMetaData* f = files_[level][i++];-    const Slice file_start = f->smallest.user_key();-    const Slice file_limit = f->largest.user_key();-    if (begin != NULL && user_cmp->Compare(file_limit, user_begin) < 0) {-      // "f" is completely before specified range; skip it-    } else if (end != NULL && user_cmp->Compare(file_start, user_end) > 0) {-      // "f" is completely after specified range; skip it-    } else {-      inputs->push_back(f);-      if (level == 0) {-        // Level-0 files may overlap each other.  So check if the newly-        // added file has expanded the range.  If so, restart search.-        if (begin != NULL && user_cmp->Compare(file_start, user_begin) < 0) {-          user_begin = file_start;-          inputs->clear();-          i = 0;-        } else if (end != NULL && user_cmp->Compare(file_limit, user_end) > 0) {-          user_end = file_limit;-          inputs->clear();-          i = 0;-        }-      }-    }-  }-}--std::string Version::DebugString() const {-  std::string r;-  for (int level = 0; level < config::kNumLevels; level++) {-    // E.g.,-    //   --- level 1 ----    //   17:123['a' .. 'd']-    //   20:43['e' .. 'g']-    r.append("--- level ");-    AppendNumberTo(&r, level);-    r.append(" ---\n");-    const std::vector<FileMetaData*>& files = files_[level];-    for (size_t i = 0; i < files.size(); i++) {-      r.push_back(' ');-      AppendNumberTo(&r, files[i]->number);-      r.push_back(':');-      AppendNumberTo(&r, files[i]->file_size);-      r.append("[");-      r.append(files[i]->smallest.DebugString());-      r.append(" .. ");-      r.append(files[i]->largest.DebugString());-      r.append("]\n");-    }-  }-  return r;-}--// A helper class so we can efficiently apply a whole sequence-// of edits to a particular state without creating intermediate-// Versions that contain full copies of the intermediate state.-class VersionSet::Builder {- private:-  // Helper to sort by v->files_[file_number].smallest-  struct BySmallestKey {-    const InternalKeyComparator* internal_comparator;--    bool operator()(FileMetaData* f1, FileMetaData* f2) const {-      int r = internal_comparator->Compare(f1->smallest, f2->smallest);-      if (r != 0) {-        return (r < 0);-      } else {-        // Break ties by file number-        return (f1->number < f2->number);-      }-    }-  };--  typedef std::set<FileMetaData*, BySmallestKey> FileSet;-  struct LevelState {-    std::set<uint64_t> deleted_files;-    FileSet* added_files;-  };--  VersionSet* vset_;-  Version* base_;-  LevelState levels_[config::kNumLevels];-- public:-  // Initialize a builder with the files from *base and other info from *vset-  Builder(VersionSet* vset, Version* base)-      : vset_(vset),-        base_(base) {-    base_->Ref();-    BySmallestKey cmp;-    cmp.internal_comparator = &vset_->icmp_;-    for (int level = 0; level < config::kNumLevels; level++) {-      levels_[level].added_files = new FileSet(cmp);-    }-  }--  ~Builder() {-    for (int level = 0; level < config::kNumLevels; level++) {-      const FileSet* added = levels_[level].added_files;-      std::vector<FileMetaData*> to_unref;-      to_unref.reserve(added->size());-      for (FileSet::const_iterator it = added->begin();-          it != added->end(); ++it) {-        to_unref.push_back(*it);-      }-      delete added;-      for (uint32_t i = 0; i < to_unref.size(); i++) {-        FileMetaData* f = to_unref[i];-        f->refs--;-        if (f->refs <= 0) {-          delete f;-        }-      }-    }-    base_->Unref();-  }--  // Apply all of the edits in *edit to the current state.-  void Apply(VersionEdit* edit) {-    // Update compaction pointers-    for (size_t i = 0; i < edit->compact_pointers_.size(); i++) {-      const int level = edit->compact_pointers_[i].first;-      vset_->compact_pointer_[level] =-          edit->compact_pointers_[i].second.Encode().ToString();-    }--    // Delete files-    const VersionEdit::DeletedFileSet& del = edit->deleted_files_;-    for (VersionEdit::DeletedFileSet::const_iterator iter = del.begin();-         iter != del.end();-         ++iter) {-      const int level = iter->first;-      const uint64_t number = iter->second;-      levels_[level].deleted_files.insert(number);-    }--    // Add new files-    for (size_t i = 0; i < edit->new_files_.size(); i++) {-      const int level = edit->new_files_[i].first;-      FileMetaData* f = new FileMetaData(edit->new_files_[i].second);-      f->refs = 1;--      // We arrange to automatically compact this file after-      // a certain number of seeks.  Let's assume:-      //   (1) One seek costs 10ms-      //   (2) Writing or reading 1MB costs 10ms (100MB/s)-      //   (3) A compaction of 1MB does 25MB of IO:-      //         1MB read from this level-      //         10-12MB read from next level (boundaries may be misaligned)-      //         10-12MB written to next level-      // This implies that 25 seeks cost the same as the compaction-      // of 1MB of data.  I.e., one seek costs approximately the-      // same as the compaction of 40KB of data.  We are a little-      // conservative and allow approximately one seek for every 16KB-      // of data before triggering a compaction.-      f->allowed_seeks = (f->file_size / 16384);-      if (f->allowed_seeks < 100) f->allowed_seeks = 100;--      levels_[level].deleted_files.erase(f->number);-      levels_[level].added_files->insert(f);-    }-  }--  // Save the current state in *v.-  void SaveTo(Version* v) {-    BySmallestKey cmp;-    cmp.internal_comparator = &vset_->icmp_;-    for (int level = 0; level < config::kNumLevels; level++) {-      // Merge the set of added files with the set of pre-existing files.-      // Drop any deleted files.  Store the result in *v.-      const std::vector<FileMetaData*>& base_files = base_->files_[level];-      std::vector<FileMetaData*>::const_iterator base_iter = base_files.begin();-      std::vector<FileMetaData*>::const_iterator base_end = base_files.end();-      const FileSet* added = levels_[level].added_files;-      v->files_[level].reserve(base_files.size() + added->size());-      for (FileSet::const_iterator added_iter = added->begin();-           added_iter != added->end();-           ++added_iter) {-        // Add all smaller files listed in base_-        for (std::vector<FileMetaData*>::const_iterator bpos-                 = std::upper_bound(base_iter, base_end, *added_iter, cmp);-             base_iter != bpos;-             ++base_iter) {-          MaybeAddFile(v, level, *base_iter);-        }--        MaybeAddFile(v, level, *added_iter);-      }--      // Add remaining base files-      for (; base_iter != base_end; ++base_iter) {-        MaybeAddFile(v, level, *base_iter);-      }--#ifndef NDEBUG-      // Make sure there is no overlap in levels > 0-      if (level > 0) {-        for (uint32_t i = 1; i < v->files_[level].size(); i++) {-          const InternalKey& prev_end = v->files_[level][i-1]->largest;-          const InternalKey& this_begin = v->files_[level][i]->smallest;-          if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) {-            fprintf(stderr, "overlapping ranges in same level %s vs. %s\n",-                    prev_end.DebugString().c_str(),-                    this_begin.DebugString().c_str());-            abort();-          }-        }-      }-#endif-    }-  }--  void MaybeAddFile(Version* v, int level, FileMetaData* f) {-    if (levels_[level].deleted_files.count(f->number) > 0) {-      // File is deleted: do nothing-    } else {-      std::vector<FileMetaData*>* files = &v->files_[level];-      if (level > 0 && !files->empty()) {-        // Must not overlap-        assert(vset_->icmp_.Compare((*files)[files->size()-1]->largest,-                                    f->smallest) < 0);-      }-      f->refs++;-      files->push_back(f);-    }-  }-};--VersionSet::VersionSet(const std::string& dbname,-                       const Options* options,-                       TableCache* table_cache,-                       const InternalKeyComparator* cmp)-    : env_(options->env),-      dbname_(dbname),-      options_(options),-      table_cache_(table_cache),-      icmp_(*cmp),-      next_file_number_(2),-      manifest_file_number_(0),  // Filled by Recover()-      last_sequence_(0),-      log_number_(0),-      prev_log_number_(0),-      descriptor_file_(NULL),-      descriptor_log_(NULL),-      dummy_versions_(this),-      current_(NULL) {-  AppendVersion(new Version(this));-}--VersionSet::~VersionSet() {-  current_->Unref();-  assert(dummy_versions_.next_ == &dummy_versions_);  // List must be empty-  delete descriptor_log_;-  delete descriptor_file_;-}--void VersionSet::AppendVersion(Version* v) {-  // Make "v" current-  assert(v->refs_ == 0);-  assert(v != current_);-  if (current_ != NULL) {-    current_->Unref();-  }-  current_ = v;-  v->Ref();--  // Append to linked list-  v->prev_ = dummy_versions_.prev_;-  v->next_ = &dummy_versions_;-  v->prev_->next_ = v;-  v->next_->prev_ = v;-}--Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) {-  if (edit->has_log_number_) {-    assert(edit->log_number_ >= log_number_);-    assert(edit->log_number_ < next_file_number_);-  } else {-    edit->SetLogNumber(log_number_);-  }--  if (!edit->has_prev_log_number_) {-    edit->SetPrevLogNumber(prev_log_number_);-  }--  edit->SetNextFile(next_file_number_);-  edit->SetLastSequence(last_sequence_);--  Version* v = new Version(this);-  {-    Builder builder(this, current_);-    builder.Apply(edit);-    builder.SaveTo(v);-  }-  Finalize(v);--  // Initialize new descriptor log file if necessary by creating-  // a temporary file that contains a snapshot of the current version.-  std::string new_manifest_file;-  Status s;-  if (descriptor_log_ == NULL) {-    // No reason to unlock *mu here since we only hit this path in the-    // first call to LogAndApply (when opening the database).-    assert(descriptor_file_ == NULL);-    new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_);-    edit->SetNextFile(next_file_number_);-    s = env_->NewWritableFile(new_manifest_file, &descriptor_file_);-    if (s.ok()) {-      descriptor_log_ = new log::Writer(descriptor_file_);-      s = WriteSnapshot(descriptor_log_);-    }-  }--  // Unlock during expensive MANIFEST log write-  {-    mu->Unlock();--    // Write new record to MANIFEST log-    if (s.ok()) {-      std::string record;-      edit->EncodeTo(&record);-      s = descriptor_log_->AddRecord(record);-      if (s.ok()) {-        s = descriptor_file_->Sync();-      }-    }--    // If we just created a new descriptor file, install it by writing a-    // new CURRENT file that points to it.-    if (s.ok() && !new_manifest_file.empty()) {-      s = SetCurrentFile(env_, dbname_, manifest_file_number_);-    }--    mu->Lock();-  }--  // Install the new version-  if (s.ok()) {-    AppendVersion(v);-    log_number_ = edit->log_number_;-    prev_log_number_ = edit->prev_log_number_;-  } else {-    delete v;-    if (!new_manifest_file.empty()) {-      delete descriptor_log_;-      delete descriptor_file_;-      descriptor_log_ = NULL;-      descriptor_file_ = NULL;-      env_->DeleteFile(new_manifest_file);-    }-  }--  return s;-}--Status VersionSet::Recover() {-  struct LogReporter : public log::Reader::Reporter {-    Status* status;-    virtual void Corruption(size_t bytes, const Status& s) {-      if (this->status->ok()) *this->status = s;-    }-  };--  // Read "CURRENT" file, which contains a pointer to the current manifest file-  std::string current;-  Status s = ReadFileToString(env_, CurrentFileName(dbname_), &current);-  if (!s.ok()) {-    return s;-  }-  if (current.empty() || current[current.size()-1] != '\n') {-    return Status::Corruption("CURRENT file does not end with newline");-  }-  current.resize(current.size() - 1);--  std::string dscname = dbname_ + "/" + current;-  SequentialFile* file;-  s = env_->NewSequentialFile(dscname, &file);-  if (!s.ok()) {-    return s;-  }--  bool have_log_number = false;-  bool have_prev_log_number = false;-  bool have_next_file = false;-  bool have_last_sequence = false;-  uint64_t next_file = 0;-  uint64_t last_sequence = 0;-  uint64_t log_number = 0;-  uint64_t prev_log_number = 0;-  Builder builder(this, current_);--  {-    LogReporter reporter;-    reporter.status = &s;-    log::Reader reader(file, &reporter, true/*checksum*/, 0/*initial_offset*/);-    Slice record;-    std::string scratch;-    while (reader.ReadRecord(&record, &scratch) && s.ok()) {-      VersionEdit edit;-      s = edit.DecodeFrom(record);-      if (s.ok()) {-        if (edit.has_comparator_ &&-            edit.comparator_ != icmp_.user_comparator()->Name()) {-          s = Status::InvalidArgument(-              edit.comparator_ + "does not match existing comparator ",-              icmp_.user_comparator()->Name());-        }-      }--      if (s.ok()) {-        builder.Apply(&edit);-      }--      if (edit.has_log_number_) {-        log_number = edit.log_number_;-        have_log_number = true;-      }--      if (edit.has_prev_log_number_) {-        prev_log_number = edit.prev_log_number_;-        have_prev_log_number = true;-      }--      if (edit.has_next_file_number_) {-        next_file = edit.next_file_number_;-        have_next_file = true;-      }--      if (edit.has_last_sequence_) {-        last_sequence = edit.last_sequence_;-        have_last_sequence = true;-      }-    }-  }-  delete file;-  file = NULL;--  if (s.ok()) {-    if (!have_next_file) {-      s = Status::Corruption("no meta-nextfile entry in descriptor");-    } else if (!have_log_number) {-      s = Status::Corruption("no meta-lognumber entry in descriptor");-    } else if (!have_last_sequence) {-      s = Status::Corruption("no last-sequence-number entry in descriptor");-    }--    if (!have_prev_log_number) {-      prev_log_number = 0;-    }--    MarkFileNumberUsed(prev_log_number);-    MarkFileNumberUsed(log_number);-  }--  if (s.ok()) {-    Version* v = new Version(this);-    builder.SaveTo(v);-    // Install recovered version-    Finalize(v);-    AppendVersion(v);-    manifest_file_number_ = next_file;-    next_file_number_ = next_file + 1;-    last_sequence_ = last_sequence;-    log_number_ = log_number;-    prev_log_number_ = prev_log_number;-  }--  return s;-}--void VersionSet::MarkFileNumberUsed(uint64_t number) {-  if (next_file_number_ <= number) {-    next_file_number_ = number + 1;-  }-}--void VersionSet::Finalize(Version* v) {-  // Precomputed best level for next compaction-  int best_level = -1;-  double best_score = -1;--  for (int level = 0; level < config::kNumLevels-1; level++) {-    double score;-    if (level == 0) {-      // We treat level-0 specially by bounding the number of files-      // instead of number of bytes for two reasons:-      //-      // (1) With larger write-buffer sizes, it is nice not to do too-      // many level-0 compactions.-      //-      // (2) The files in level-0 are merged on every read and-      // therefore we wish to avoid too many files when the individual-      // file size is small (perhaps because of a small write-buffer-      // setting, or very high compression ratios, or lots of-      // overwrites/deletions).-      score = v->files_[level].size() /-          static_cast<double>(config::kL0_CompactionTrigger);-    } else {-      // Compute the ratio of current size to size limit.-      const uint64_t level_bytes = TotalFileSize(v->files_[level]);-      score = static_cast<double>(level_bytes) / MaxBytesForLevel(level);-    }--    if (score > best_score) {-      best_level = level;-      best_score = score;-    }-  }--  v->compaction_level_ = best_level;-  v->compaction_score_ = best_score;-}--Status VersionSet::WriteSnapshot(log::Writer* log) {-  // TODO: Break up into multiple records to reduce memory usage on recovery?--  // Save metadata-  VersionEdit edit;-  edit.SetComparatorName(icmp_.user_comparator()->Name());--  // Save compaction pointers-  for (int level = 0; level < config::kNumLevels; level++) {-    if (!compact_pointer_[level].empty()) {-      InternalKey key;-      key.DecodeFrom(compact_pointer_[level]);-      edit.SetCompactPointer(level, key);-    }-  }--  // Save files-  for (int level = 0; level < config::kNumLevels; level++) {-    const std::vector<FileMetaData*>& files = current_->files_[level];-    for (size_t i = 0; i < files.size(); i++) {-      const FileMetaData* f = files[i];-      edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest);-    }-  }--  std::string record;-  edit.EncodeTo(&record);-  return log->AddRecord(record);-}--int VersionSet::NumLevelFiles(int level) const {-  assert(level >= 0);-  assert(level < config::kNumLevels);-  return current_->files_[level].size();-}--const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const {-  // Update code if kNumLevels changes-  assert(config::kNumLevels == 7);-  snprintf(scratch->buffer, sizeof(scratch->buffer),-           "files[ %d %d %d %d %d %d %d ]",-           int(current_->files_[0].size()),-           int(current_->files_[1].size()),-           int(current_->files_[2].size()),-           int(current_->files_[3].size()),-           int(current_->files_[4].size()),-           int(current_->files_[5].size()),-           int(current_->files_[6].size()));-  return scratch->buffer;-}--uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) {-  uint64_t result = 0;-  for (int level = 0; level < config::kNumLevels; level++) {-    const std::vector<FileMetaData*>& files = v->files_[level];-    for (size_t i = 0; i < files.size(); i++) {-      if (icmp_.Compare(files[i]->largest, ikey) <= 0) {-        // Entire file is before "ikey", so just add the file size-        result += files[i]->file_size;-      } else if (icmp_.Compare(files[i]->smallest, ikey) > 0) {-        // Entire file is after "ikey", so ignore-        if (level > 0) {-          // Files other than level 0 are sorted by meta->smallest, so-          // no further files in this level will contain data for-          // "ikey".-          break;-        }-      } else {-        // "ikey" falls in the range for this table.  Add the-        // approximate offset of "ikey" within the table.-        Table* tableptr;-        Iterator* iter = table_cache_->NewIterator(-            ReadOptions(), files[i]->number, files[i]->file_size, &tableptr);-        if (tableptr != NULL) {-          result += tableptr->ApproximateOffsetOf(ikey.Encode());-        }-        delete iter;-      }-    }-  }-  return result;-}--void VersionSet::AddLiveFiles(std::set<uint64_t>* live) {-  for (Version* v = dummy_versions_.next_;-       v != &dummy_versions_;-       v = v->next_) {-    for (int level = 0; level < config::kNumLevels; level++) {-      const std::vector<FileMetaData*>& files = v->files_[level];-      for (size_t i = 0; i < files.size(); i++) {-        live->insert(files[i]->number);-      }-    }-  }-}--int64_t VersionSet::NumLevelBytes(int level) const {-  assert(level >= 0);-  assert(level < config::kNumLevels);-  return TotalFileSize(current_->files_[level]);-}--int64_t VersionSet::MaxNextLevelOverlappingBytes() {-  int64_t result = 0;-  std::vector<FileMetaData*> overlaps;-  for (int level = 1; level < config::kNumLevels - 1; level++) {-    for (size_t i = 0; i < current_->files_[level].size(); i++) {-      const FileMetaData* f = current_->files_[level][i];-      current_->GetOverlappingInputs(level+1, &f->smallest, &f->largest,-                                     &overlaps);-      const int64_t sum = TotalFileSize(overlaps);-      if (sum > result) {-        result = sum;-      }-    }-  }-  return result;-}--// Stores the minimal range that covers all entries in inputs in-// *smallest, *largest.-// REQUIRES: inputs is not empty-void VersionSet::GetRange(const std::vector<FileMetaData*>& inputs,-                          InternalKey* smallest,-                          InternalKey* largest) {-  assert(!inputs.empty());-  smallest->Clear();-  largest->Clear();-  for (size_t i = 0; i < inputs.size(); i++) {-    FileMetaData* f = inputs[i];-    if (i == 0) {-      *smallest = f->smallest;-      *largest = f->largest;-    } else {-      if (icmp_.Compare(f->smallest, *smallest) < 0) {-        *smallest = f->smallest;-      }-      if (icmp_.Compare(f->largest, *largest) > 0) {-        *largest = f->largest;-      }-    }-  }-}--// Stores the minimal range that covers all entries in inputs1 and inputs2-// in *smallest, *largest.-// REQUIRES: inputs is not empty-void VersionSet::GetRange2(const std::vector<FileMetaData*>& inputs1,-                           const std::vector<FileMetaData*>& inputs2,-                           InternalKey* smallest,-                           InternalKey* largest) {-  std::vector<FileMetaData*> all = inputs1;-  all.insert(all.end(), inputs2.begin(), inputs2.end());-  GetRange(all, smallest, largest);-}--Iterator* VersionSet::MakeInputIterator(Compaction* c) {-  ReadOptions options;-  options.verify_checksums = options_->paranoid_checks;-  options.fill_cache = false;--  // Level-0 files have to be merged together.  For other levels,-  // we will make a concatenating iterator per level.-  // TODO(opt): use concatenating iterator for level-0 if there is no overlap-  const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2);-  Iterator** list = new Iterator*[space];-  int num = 0;-  for (int which = 0; which < 2; which++) {-    if (!c->inputs_[which].empty()) {-      if (c->level() + which == 0) {-        const std::vector<FileMetaData*>& files = c->inputs_[which];-        for (size_t i = 0; i < files.size(); i++) {-          list[num++] = table_cache_->NewIterator(-              options, files[i]->number, files[i]->file_size);-        }-      } else {-        // Create concatenating iterator for the files from this level-        list[num++] = NewTwoLevelIterator(-            new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]),-            &GetFileIterator, table_cache_, options);-      }-    }-  }-  assert(num <= space);-  Iterator* result = NewMergingIterator(&icmp_, list, num);-  delete[] list;-  return result;-}--Compaction* VersionSet::PickCompaction() {-  Compaction* c;-  int level;--  // We prefer compactions triggered by too much data in a level over-  // the compactions triggered by seeks.-  const bool size_compaction = (current_->compaction_score_ >= 1);-  const bool seek_compaction = (current_->file_to_compact_ != NULL);-  if (size_compaction) {-    level = current_->compaction_level_;-    assert(level >= 0);-    assert(level+1 < config::kNumLevels);-    c = new Compaction(level);--    // Pick the first file that comes after compact_pointer_[level]-    for (size_t i = 0; i < current_->files_[level].size(); i++) {-      FileMetaData* f = current_->files_[level][i];-      if (compact_pointer_[level].empty() ||-          icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) {-        c->inputs_[0].push_back(f);-        break;-      }-    }-    if (c->inputs_[0].empty()) {-      // Wrap-around to the beginning of the key space-      c->inputs_[0].push_back(current_->files_[level][0]);-    }-  } else if (seek_compaction) {-    level = current_->file_to_compact_level_;-    c = new Compaction(level);-    c->inputs_[0].push_back(current_->file_to_compact_);-  } else {-    return NULL;-  }--  c->input_version_ = current_;-  c->input_version_->Ref();--  // Files in level 0 may overlap each other, so pick up all overlapping ones-  if (level == 0) {-    InternalKey smallest, largest;-    GetRange(c->inputs_[0], &smallest, &largest);-    // Note that the next call will discard the file we placed in-    // c->inputs_[0] earlier and replace it with an overlapping set-    // which will include the picked file.-    current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]);-    assert(!c->inputs_[0].empty());-  }--  SetupOtherInputs(c);--  return c;-}--void VersionSet::SetupOtherInputs(Compaction* c) {-  const int level = c->level();-  InternalKey smallest, largest;-  GetRange(c->inputs_[0], &smallest, &largest);--  current_->GetOverlappingInputs(level+1, &smallest, &largest, &c->inputs_[1]);--  // Get entire range covered by compaction-  InternalKey all_start, all_limit;-  GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit);--  // See if we can grow the number of inputs in "level" without-  // changing the number of "level+1" files we pick up.-  if (!c->inputs_[1].empty()) {-    std::vector<FileMetaData*> expanded0;-    current_->GetOverlappingInputs(level, &all_start, &all_limit, &expanded0);-    const int64_t inputs0_size = TotalFileSize(c->inputs_[0]);-    const int64_t inputs1_size = TotalFileSize(c->inputs_[1]);-    const int64_t expanded0_size = TotalFileSize(expanded0);-    if (expanded0.size() > c->inputs_[0].size() &&-        inputs1_size + expanded0_size < kExpandedCompactionByteSizeLimit) {-      InternalKey new_start, new_limit;-      GetRange(expanded0, &new_start, &new_limit);-      std::vector<FileMetaData*> expanded1;-      current_->GetOverlappingInputs(level+1, &new_start, &new_limit,-                                     &expanded1);-      if (expanded1.size() == c->inputs_[1].size()) {-        Log(options_->info_log,-            "Expanding@%d %d+%d (%ld+%ld bytes) to %d+%d (%ld+%ld bytes)\n",-            level,-            int(c->inputs_[0].size()),-            int(c->inputs_[1].size()),-            long(inputs0_size), long(inputs1_size),-            int(expanded0.size()),-            int(expanded1.size()),-            long(expanded0_size), long(inputs1_size));-        smallest = new_start;-        largest = new_limit;-        c->inputs_[0] = expanded0;-        c->inputs_[1] = expanded1;-        GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit);-      }-    }-  }--  // Compute the set of grandparent files that overlap this compaction-  // (parent == level+1; grandparent == level+2)-  if (level + 2 < config::kNumLevels) {-    current_->GetOverlappingInputs(level + 2, &all_start, &all_limit,-                                   &c->grandparents_);-  }--  if (false) {-    Log(options_->info_log, "Compacting %d '%s' .. '%s'",-        level,-        smallest.DebugString().c_str(),-        largest.DebugString().c_str());-  }--  // Update the place where we will do the next compaction for this level.-  // We update this immediately instead of waiting for the VersionEdit-  // to be applied so that if the compaction fails, we will try a different-  // key range next time.-  compact_pointer_[level] = largest.Encode().ToString();-  c->edit_.SetCompactPointer(level, largest);-}--Compaction* VersionSet::CompactRange(-    int level,-    const InternalKey* begin,-    const InternalKey* end) {-  std::vector<FileMetaData*> inputs;-  current_->GetOverlappingInputs(level, begin, end, &inputs);-  if (inputs.empty()) {-    return NULL;-  }--  // Avoid compacting too much in one shot in case the range is large.-  const uint64_t limit = MaxFileSizeForLevel(level);-  uint64_t total = 0;-  for (int i = 0; i < inputs.size(); i++) {-    uint64_t s = inputs[i]->file_size;-    total += s;-    if (total >= limit) {-      inputs.resize(i + 1);-      break;-    }-  }--  Compaction* c = new Compaction(level);-  c->input_version_ = current_;-  c->input_version_->Ref();-  c->inputs_[0] = inputs;-  SetupOtherInputs(c);-  return c;-}--Compaction::Compaction(int level)-    : level_(level),-      max_output_file_size_(MaxFileSizeForLevel(level)),-      input_version_(NULL),-      grandparent_index_(0),-      seen_key_(false),-      overlapped_bytes_(0) {-  for (int i = 0; i < config::kNumLevels; i++) {-    level_ptrs_[i] = 0;-  }-}--Compaction::~Compaction() {-  if (input_version_ != NULL) {-    input_version_->Unref();-  }-}--bool Compaction::IsTrivialMove() const {-  // Avoid a move if there is lots of overlapping grandparent data.-  // Otherwise, the move could create a parent file that will require-  // a very expensive merge later on.-  return (num_input_files(0) == 1 &&-          num_input_files(1) == 0 &&-          TotalFileSize(grandparents_) <= kMaxGrandParentOverlapBytes);-}--void Compaction::AddInputDeletions(VersionEdit* edit) {-  for (int which = 0; which < 2; which++) {-    for (size_t i = 0; i < inputs_[which].size(); i++) {-      edit->DeleteFile(level_ + which, inputs_[which][i]->number);-    }-  }-}--bool Compaction::IsBaseLevelForKey(const Slice& user_key) {-  // Maybe use binary search to find right entry instead of linear search?-  const Comparator* user_cmp = input_version_->vset_->icmp_.user_comparator();-  for (int lvl = level_ + 2; lvl < config::kNumLevels; lvl++) {-    const std::vector<FileMetaData*>& files = input_version_->files_[lvl];-    for (; level_ptrs_[lvl] < files.size(); ) {-      FileMetaData* f = files[level_ptrs_[lvl]];-      if (user_cmp->Compare(user_key, f->largest.user_key()) <= 0) {-        // We've advanced far enough-        if (user_cmp->Compare(user_key, f->smallest.user_key()) >= 0) {-          // Key falls in this file's range, so definitely not base level-          return false;-        }-        break;-      }-      level_ptrs_[lvl]++;-    }-  }-  return true;-}--bool Compaction::ShouldStopBefore(const Slice& internal_key) {-  // Scan to find earliest grandparent file that contains key.-  const InternalKeyComparator* icmp = &input_version_->vset_->icmp_;-  while (grandparent_index_ < grandparents_.size() &&-      icmp->Compare(internal_key,-                    grandparents_[grandparent_index_]->largest.Encode()) > 0) {-    if (seen_key_) {-      overlapped_bytes_ += grandparents_[grandparent_index_]->file_size;-    }-    grandparent_index_++;-  }-  seen_key_ = true;--  if (overlapped_bytes_ > kMaxGrandParentOverlapBytes) {-    // Too much overlap for current output; start new output-    overlapped_bytes_ = 0;-    return true;-  } else {-    return false;-  }-}--void Compaction::ReleaseInputs() {-  if (input_version_ != NULL) {-    input_version_->Unref();-    input_version_ = NULL;-  }-}--}  // namespace leveldb
− cbits/leveldb/db/version_set.h
@@ -1,370 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// The representation of a DBImpl consists of a set of Versions.  The-// newest version is called "current".  Older versions may be kept-// around to provide a consistent view to live iterators.-//-// Each Version keeps track of a set of Table files per level.  The-// entire set of versions is maintained in a VersionSet.-//-// Version,VersionSet are thread-compatible, but require external-// synchronization on all accesses.--#ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_-#define STORAGE_LEVELDB_DB_VERSION_SET_H_--#include <map>-#include <set>-#include <vector>-#include "db/dbformat.h"-#include "db/version_edit.h"-#include "port/port.h"--namespace leveldb {--namespace log { class Writer; }--class Compaction;-class Iterator;-class MemTable;-class TableBuilder;-class TableCache;-class Version;-class VersionSet;-class WritableFile;--// Return the smallest index i such that files[i]->largest >= key.-// Return files.size() if there is no such file.-// REQUIRES: "files" contains a sorted list of non-overlapping files.-extern int FindFile(const InternalKeyComparator& icmp,-                    const std::vector<FileMetaData*>& files,-                    const Slice& key);--// Returns true iff some file in "files" overlaps the user key range-// [*smallest,*largest].-// smallest==NULL represents a key smaller than all keys in the DB.-// largest==NULL represents a key largest than all keys in the DB.-// REQUIRES: If disjoint_sorted_files, files[] contains disjoint ranges-//           in sorted order.-extern bool SomeFileOverlapsRange(-    const InternalKeyComparator& icmp,-    bool disjoint_sorted_files,-    const std::vector<FileMetaData*>& files,-    const Slice* smallest_user_key,-    const Slice* largest_user_key);--class Version {- public:-  // Append to *iters a sequence of iterators that will-  // yield the contents of this Version when merged together.-  // REQUIRES: This version has been saved (see VersionSet::SaveTo)-  void AddIterators(const ReadOptions&, std::vector<Iterator*>* iters);--  // Lookup the value for key.  If found, store it in *val and-  // return OK.  Else return a non-OK status.  Fills *stats.-  // REQUIRES: lock is not held-  struct GetStats {-    FileMetaData* seek_file;-    int seek_file_level;-  };-  Status Get(const ReadOptions&, const LookupKey& key, std::string* val,-             GetStats* stats);--  // Adds "stats" into the current state.  Returns true if a new-  // compaction may need to be triggered, false otherwise.-  // REQUIRES: lock is held-  bool UpdateStats(const GetStats& stats);--  // Reference count management (so Versions do not disappear out from-  // under live iterators)-  void Ref();-  void Unref();--  void GetOverlappingInputs(-      int level,-      const InternalKey* begin,         // NULL means before all keys-      const InternalKey* end,           // NULL means after all keys-      std::vector<FileMetaData*>* inputs);--  // Returns true iff some file in the specified level overlaps-  // some part of [*smallest_user_key,*largest_user_key].-  // smallest_user_key==NULL represents a key smaller than all keys in the DB.-  // largest_user_key==NULL represents a key largest than all keys in the DB.-  bool OverlapInLevel(int level,-                      const Slice* smallest_user_key,-                      const Slice* largest_user_key);--  // Return the level at which we should place a new memtable compaction-  // result that covers the range [smallest_user_key,largest_user_key].-  int PickLevelForMemTableOutput(const Slice& smallest_user_key,-                                 const Slice& largest_user_key);--  int NumFiles(int level) const { return files_[level].size(); }--  // Return a human readable string that describes this version's contents.-  std::string DebugString() const;-- private:-  friend class Compaction;-  friend class VersionSet;--  class LevelFileNumIterator;-  Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const;--  VersionSet* vset_;            // VersionSet to which this Version belongs-  Version* next_;               // Next version in linked list-  Version* prev_;               // Previous version in linked list-  int refs_;                    // Number of live refs to this version--  // List of files per level-  std::vector<FileMetaData*> files_[config::kNumLevels];--  // Next file to compact based on seek stats.-  FileMetaData* file_to_compact_;-  int file_to_compact_level_;--  // Level that should be compacted next and its compaction score.-  // Score < 1 means compaction is not strictly needed.  These fields-  // are initialized by Finalize().-  double compaction_score_;-  int compaction_level_;--  explicit Version(VersionSet* vset)-      : vset_(vset), next_(this), prev_(this), refs_(0),-        file_to_compact_(NULL),-        file_to_compact_level_(-1),-        compaction_score_(-1),-        compaction_level_(-1) {-  }--  ~Version();--  // No copying allowed-  Version(const Version&);-  void operator=(const Version&);-};--class VersionSet {- public:-  VersionSet(const std::string& dbname,-             const Options* options,-             TableCache* table_cache,-             const InternalKeyComparator*);-  ~VersionSet();--  // Apply *edit to the current version to form a new descriptor that-  // is both saved to persistent state and installed as the new-  // current version.  Will release *mu while actually writing to the file.-  // REQUIRES: *mu is held on entry.-  // REQUIRES: no other thread concurrently calls LogAndApply()-  Status LogAndApply(VersionEdit* edit, port::Mutex* mu);--  // Recover the last saved descriptor from persistent storage.-  Status Recover();--  // Return the current version.-  Version* current() const { return current_; }--  // Return the current manifest file number-  uint64_t ManifestFileNumber() const { return manifest_file_number_; }--  // Allocate and return a new file number-  uint64_t NewFileNumber() { return next_file_number_++; }--  // Return the number of Table files at the specified level.-  int NumLevelFiles(int level) const;--  // Return the combined file size of all files at the specified level.-  int64_t NumLevelBytes(int level) const;--  // Return the last sequence number.-  uint64_t LastSequence() const { return last_sequence_; }--  // Set the last sequence number to s.-  void SetLastSequence(uint64_t s) {-    assert(s >= last_sequence_);-    last_sequence_ = s;-  }--  // Mark the specified file number as used.-  void MarkFileNumberUsed(uint64_t number);--  // Return the current log file number.-  uint64_t LogNumber() const { return log_number_; }--  // Return the log file number for the log file that is currently-  // being compacted, or zero if there is no such log file.-  uint64_t PrevLogNumber() const { return prev_log_number_; }--  // Pick level and inputs for a new compaction.-  // Returns NULL if there is no compaction to be done.-  // Otherwise returns a pointer to a heap-allocated object that-  // describes the compaction.  Caller should delete the result.-  Compaction* PickCompaction();--  // Return a compaction object for compacting the range [begin,end] in-  // the specified level.  Returns NULL if there is nothing in that-  // level that overlaps the specified range.  Caller should delete-  // the result.-  Compaction* CompactRange(-      int level,-      const InternalKey* begin,-      const InternalKey* end);--  // Return the maximum overlapping data (in bytes) at next level for any-  // file at a level >= 1.-  int64_t MaxNextLevelOverlappingBytes();--  // Create an iterator that reads over the compaction inputs for "*c".-  // The caller should delete the iterator when no longer needed.-  Iterator* MakeInputIterator(Compaction* c);--  // Returns true iff some level needs a compaction.-  bool NeedsCompaction() const {-    Version* v = current_;-    return (v->compaction_score_ >= 1) || (v->file_to_compact_ != NULL);-  }--  // Add all files listed in any live version to *live.-  // May also mutate some internal state.-  void AddLiveFiles(std::set<uint64_t>* live);--  // Return the approximate offset in the database of the data for-  // "key" as of version "v".-  uint64_t ApproximateOffsetOf(Version* v, const InternalKey& key);--  // Return a human-readable short (single-line) summary of the number-  // of files per level.  Uses *scratch as backing store.-  struct LevelSummaryStorage {-    char buffer[100];-  };-  const char* LevelSummary(LevelSummaryStorage* scratch) const;-- private:-  class Builder;--  friend class Compaction;-  friend class Version;--  void Finalize(Version* v);--  void GetRange(const std::vector<FileMetaData*>& inputs,-                InternalKey* smallest,-                InternalKey* largest);--  void GetRange2(const std::vector<FileMetaData*>& inputs1,-                 const std::vector<FileMetaData*>& inputs2,-                 InternalKey* smallest,-                 InternalKey* largest);--  void SetupOtherInputs(Compaction* c);--  // Save current contents to *log-  Status WriteSnapshot(log::Writer* log);--  void AppendVersion(Version* v);--  Env* const env_;-  const std::string dbname_;-  const Options* const options_;-  TableCache* const table_cache_;-  const InternalKeyComparator icmp_;-  uint64_t next_file_number_;-  uint64_t manifest_file_number_;-  uint64_t last_sequence_;-  uint64_t log_number_;-  uint64_t prev_log_number_;  // 0 or backing store for memtable being compacted--  // Opened lazily-  WritableFile* descriptor_file_;-  log::Writer* descriptor_log_;-  Version dummy_versions_;  // Head of circular doubly-linked list of versions.-  Version* current_;        // == dummy_versions_.prev_--  // Per-level key at which the next compaction at that level should start.-  // Either an empty string, or a valid InternalKey.-  std::string compact_pointer_[config::kNumLevels];--  // No copying allowed-  VersionSet(const VersionSet&);-  void operator=(const VersionSet&);-};--// A Compaction encapsulates information about a compaction.-class Compaction {- public:-  ~Compaction();--  // Return the level that is being compacted.  Inputs from "level"-  // and "level+1" will be merged to produce a set of "level+1" files.-  int level() const { return level_; }--  // Return the object that holds the edits to the descriptor done-  // by this compaction.-  VersionEdit* edit() { return &edit_; }--  // "which" must be either 0 or 1-  int num_input_files(int which) const { return inputs_[which].size(); }--  // Return the ith input file at "level()+which" ("which" must be 0 or 1).-  FileMetaData* input(int which, int i) const { return inputs_[which][i]; }--  // Maximum size of files to build during this compaction.-  uint64_t MaxOutputFileSize() const { return max_output_file_size_; }--  // Is this a trivial compaction that can be implemented by just-  // moving a single input file to the next level (no merging or splitting)-  bool IsTrivialMove() const;--  // Add all inputs to this compaction as delete operations to *edit.-  void AddInputDeletions(VersionEdit* edit);--  // Returns true if the information we have available guarantees that-  // the compaction is producing data in "level+1" for which no data exists-  // in levels greater than "level+1".-  bool IsBaseLevelForKey(const Slice& user_key);--  // Returns true iff we should stop building the current output-  // before processing "internal_key".-  bool ShouldStopBefore(const Slice& internal_key);--  // Release the input version for the compaction, once the compaction-  // is successful.-  void ReleaseInputs();-- private:-  friend class Version;-  friend class VersionSet;--  explicit Compaction(int level);--  int level_;-  uint64_t max_output_file_size_;-  Version* input_version_;-  VersionEdit edit_;--  // Each compaction reads inputs from "level_" and "level_+1"-  std::vector<FileMetaData*> inputs_[2];      // The two sets of inputs--  // State used to check for number of of overlapping grandparent files-  // (parent == level_ + 1, grandparent == level_ + 2)-  std::vector<FileMetaData*> grandparents_;-  size_t grandparent_index_;  // Index in grandparent_starts_-  bool seen_key_;             // Some output key has been seen-  int64_t overlapped_bytes_;  // Bytes of overlap between current output-                              // and grandparent files--  // State for implementing IsBaseLevelForKey--  // level_ptrs_ holds indices into input_version_->levels_: our state-  // is that we are positioned at one of the file ranges for each-  // higher level than the ones involved in this compaction (i.e. for-  // all L >= level_ + 2).-  size_t level_ptrs_[config::kNumLevels];-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_DB_VERSION_SET_H_
− cbits/leveldb/db/version_set_test.cc
@@ -1,179 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "db/version_set.h"-#include "util/logging.h"-#include "util/testharness.h"-#include "util/testutil.h"--namespace leveldb {--class FindFileTest {- public:-  std::vector<FileMetaData*> files_;-  bool disjoint_sorted_files_;--  FindFileTest() : disjoint_sorted_files_(true) { }--  ~FindFileTest() {-    for (int i = 0; i < files_.size(); i++) {-      delete files_[i];-    }-  }--  void Add(const char* smallest, const char* largest,-           SequenceNumber smallest_seq = 100,-           SequenceNumber largest_seq = 100) {-    FileMetaData* f = new FileMetaData;-    f->number = files_.size() + 1;-    f->smallest = InternalKey(smallest, smallest_seq, kTypeValue);-    f->largest = InternalKey(largest, largest_seq, kTypeValue);-    files_.push_back(f);-  }--  int Find(const char* key) {-    InternalKey target(key, 100, kTypeValue);-    InternalKeyComparator cmp(BytewiseComparator());-    return FindFile(cmp, files_, target.Encode());-  }--  bool Overlaps(const char* smallest, const char* largest) {-    InternalKeyComparator cmp(BytewiseComparator());-    Slice s(smallest != NULL ? smallest : "");-    Slice l(largest != NULL ? largest : "");-    return SomeFileOverlapsRange(cmp, disjoint_sorted_files_, files_,-                                 (smallest != NULL ? &s : NULL),-                                 (largest != NULL ? &l : NULL));-  }-};--TEST(FindFileTest, Empty) {-  ASSERT_EQ(0, Find("foo"));-  ASSERT_TRUE(! Overlaps("a", "z"));-  ASSERT_TRUE(! Overlaps(NULL, "z"));-  ASSERT_TRUE(! Overlaps("a", NULL));-  ASSERT_TRUE(! Overlaps(NULL, NULL));-}--TEST(FindFileTest, Single) {-  Add("p", "q");-  ASSERT_EQ(0, Find("a"));-  ASSERT_EQ(0, Find("p"));-  ASSERT_EQ(0, Find("p1"));-  ASSERT_EQ(0, Find("q"));-  ASSERT_EQ(1, Find("q1"));-  ASSERT_EQ(1, Find("z"));--  ASSERT_TRUE(! Overlaps("a", "b"));-  ASSERT_TRUE(! Overlaps("z1", "z2"));-  ASSERT_TRUE(Overlaps("a", "p"));-  ASSERT_TRUE(Overlaps("a", "q"));-  ASSERT_TRUE(Overlaps("a", "z"));-  ASSERT_TRUE(Overlaps("p", "p1"));-  ASSERT_TRUE(Overlaps("p", "q"));-  ASSERT_TRUE(Overlaps("p", "z"));-  ASSERT_TRUE(Overlaps("p1", "p2"));-  ASSERT_TRUE(Overlaps("p1", "z"));-  ASSERT_TRUE(Overlaps("q", "q"));-  ASSERT_TRUE(Overlaps("q", "q1"));--  ASSERT_TRUE(! Overlaps(NULL, "j"));-  ASSERT_TRUE(! Overlaps("r", NULL));-  ASSERT_TRUE(Overlaps(NULL, "p"));-  ASSERT_TRUE(Overlaps(NULL, "p1"));-  ASSERT_TRUE(Overlaps("q", NULL));-  ASSERT_TRUE(Overlaps(NULL, NULL));-}---TEST(FindFileTest, Multiple) {-  Add("150", "200");-  Add("200", "250");-  Add("300", "350");-  Add("400", "450");-  ASSERT_EQ(0, Find("100"));-  ASSERT_EQ(0, Find("150"));-  ASSERT_EQ(0, Find("151"));-  ASSERT_EQ(0, Find("199"));-  ASSERT_EQ(0, Find("200"));-  ASSERT_EQ(1, Find("201"));-  ASSERT_EQ(1, Find("249"));-  ASSERT_EQ(1, Find("250"));-  ASSERT_EQ(2, Find("251"));-  ASSERT_EQ(2, Find("299"));-  ASSERT_EQ(2, Find("300"));-  ASSERT_EQ(2, Find("349"));-  ASSERT_EQ(2, Find("350"));-  ASSERT_EQ(3, Find("351"));-  ASSERT_EQ(3, Find("400"));-  ASSERT_EQ(3, Find("450"));-  ASSERT_EQ(4, Find("451"));--  ASSERT_TRUE(! Overlaps("100", "149"));-  ASSERT_TRUE(! Overlaps("251", "299"));-  ASSERT_TRUE(! Overlaps("451", "500"));-  ASSERT_TRUE(! Overlaps("351", "399"));--  ASSERT_TRUE(Overlaps("100", "150"));-  ASSERT_TRUE(Overlaps("100", "200"));-  ASSERT_TRUE(Overlaps("100", "300"));-  ASSERT_TRUE(Overlaps("100", "400"));-  ASSERT_TRUE(Overlaps("100", "500"));-  ASSERT_TRUE(Overlaps("375", "400"));-  ASSERT_TRUE(Overlaps("450", "450"));-  ASSERT_TRUE(Overlaps("450", "500"));-}--TEST(FindFileTest, MultipleNullBoundaries) {-  Add("150", "200");-  Add("200", "250");-  Add("300", "350");-  Add("400", "450");-  ASSERT_TRUE(! Overlaps(NULL, "149"));-  ASSERT_TRUE(! Overlaps("451", NULL));-  ASSERT_TRUE(Overlaps(NULL, NULL));-  ASSERT_TRUE(Overlaps(NULL, "150"));-  ASSERT_TRUE(Overlaps(NULL, "199"));-  ASSERT_TRUE(Overlaps(NULL, "200"));-  ASSERT_TRUE(Overlaps(NULL, "201"));-  ASSERT_TRUE(Overlaps(NULL, "400"));-  ASSERT_TRUE(Overlaps(NULL, "800"));-  ASSERT_TRUE(Overlaps("100", NULL));-  ASSERT_TRUE(Overlaps("200", NULL));-  ASSERT_TRUE(Overlaps("449", NULL));-  ASSERT_TRUE(Overlaps("450", NULL));-}--TEST(FindFileTest, OverlapSequenceChecks) {-  Add("200", "200", 5000, 3000);-  ASSERT_TRUE(! Overlaps("199", "199"));-  ASSERT_TRUE(! Overlaps("201", "300"));-  ASSERT_TRUE(Overlaps("200", "200"));-  ASSERT_TRUE(Overlaps("190", "200"));-  ASSERT_TRUE(Overlaps("200", "210"));-}--TEST(FindFileTest, OverlappingFiles) {-  Add("150", "600");-  Add("400", "500");-  disjoint_sorted_files_ = false;-  ASSERT_TRUE(! Overlaps("100", "149"));-  ASSERT_TRUE(! Overlaps("601", "700"));-  ASSERT_TRUE(Overlaps("100", "150"));-  ASSERT_TRUE(Overlaps("100", "200"));-  ASSERT_TRUE(Overlaps("100", "300"));-  ASSERT_TRUE(Overlaps("100", "400"));-  ASSERT_TRUE(Overlaps("100", "500"));-  ASSERT_TRUE(Overlaps("375", "400"));-  ASSERT_TRUE(Overlaps("450", "450"));-  ASSERT_TRUE(Overlaps("450", "500"));-  ASSERT_TRUE(Overlaps("450", "700"));-  ASSERT_TRUE(Overlaps("600", "700"));-}--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/db/write_batch.cc
@@ -1,147 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// WriteBatch::rep_ :=-//    sequence: fixed64-//    count: fixed32-//    data: record[count]-// record :=-//    kTypeValue varstring varstring         |-//    kTypeDeletion varstring-// varstring :=-//    len: varint32-//    data: uint8[len]--#include "leveldb/write_batch.h"--#include "leveldb/db.h"-#include "db/dbformat.h"-#include "db/memtable.h"-#include "db/write_batch_internal.h"-#include "util/coding.h"--namespace leveldb {--// WriteBatch header has an 8-byte sequence number followed by a 4-byte count.-static const size_t kHeader = 12;--WriteBatch::WriteBatch() {-  Clear();-}--WriteBatch::~WriteBatch() { }--WriteBatch::Handler::~Handler() { }--void WriteBatch::Clear() {-  rep_.clear();-  rep_.resize(kHeader);-}--Status WriteBatch::Iterate(Handler* handler) const {-  Slice input(rep_);-  if (input.size() < kHeader) {-    return Status::Corruption("malformed WriteBatch (too small)");-  }--  input.remove_prefix(kHeader);-  Slice key, value;-  int found = 0;-  while (!input.empty()) {-    found++;-    char tag = input[0];-    input.remove_prefix(1);-    switch (tag) {-      case kTypeValue:-        if (GetLengthPrefixedSlice(&input, &key) &&-            GetLengthPrefixedSlice(&input, &value)) {-          handler->Put(key, value);-        } else {-          return Status::Corruption("bad WriteBatch Put");-        }-        break;-      case kTypeDeletion:-        if (GetLengthPrefixedSlice(&input, &key)) {-          handler->Delete(key);-        } else {-          return Status::Corruption("bad WriteBatch Delete");-        }-        break;-      default:-        return Status::Corruption("unknown WriteBatch tag");-    }-  }-  if (found != WriteBatchInternal::Count(this)) {-    return Status::Corruption("WriteBatch has wrong count");-  } else {-    return Status::OK();-  }-}--int WriteBatchInternal::Count(const WriteBatch* b) {-  return DecodeFixed32(b->rep_.data() + 8);-}--void WriteBatchInternal::SetCount(WriteBatch* b, int n) {-  EncodeFixed32(&b->rep_[8], n);-}--SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) {-  return SequenceNumber(DecodeFixed64(b->rep_.data()));-}--void WriteBatchInternal::SetSequence(WriteBatch* b, SequenceNumber seq) {-  EncodeFixed64(&b->rep_[0], seq);-}--void WriteBatch::Put(const Slice& key, const Slice& value) {-  WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);-  rep_.push_back(static_cast<char>(kTypeValue));-  PutLengthPrefixedSlice(&rep_, key);-  PutLengthPrefixedSlice(&rep_, value);-}--void WriteBatch::Delete(const Slice& key) {-  WriteBatchInternal::SetCount(this, WriteBatchInternal::Count(this) + 1);-  rep_.push_back(static_cast<char>(kTypeDeletion));-  PutLengthPrefixedSlice(&rep_, key);-}--namespace {-class MemTableInserter : public WriteBatch::Handler {- public:-  SequenceNumber sequence_;-  MemTable* mem_;--  virtual void Put(const Slice& key, const Slice& value) {-    mem_->Add(sequence_, kTypeValue, key, value);-    sequence_++;-  }-  virtual void Delete(const Slice& key) {-    mem_->Add(sequence_, kTypeDeletion, key, Slice());-    sequence_++;-  }-};-}  // namespace--Status WriteBatchInternal::InsertInto(const WriteBatch* b,-                                      MemTable* memtable) {-  MemTableInserter inserter;-  inserter.sequence_ = WriteBatchInternal::Sequence(b);-  inserter.mem_ = memtable;-  return b->Iterate(&inserter);-}--void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) {-  assert(contents.size() >= kHeader);-  b->rep_.assign(contents.data(), contents.size());-}--void WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) {-  SetCount(dst, Count(dst) + Count(src));-  assert(src->rep_.size() >= kHeader);-  dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader);-}--}  // namespace leveldb
− cbits/leveldb/db/write_batch_internal.h
@@ -1,49 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_-#define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_--#include "leveldb/write_batch.h"--namespace leveldb {--class MemTable;--// WriteBatchInternal provides static methods for manipulating a-// WriteBatch that we don't want in the public WriteBatch interface.-class WriteBatchInternal {- public:-  // Return the number of entries in the batch.-  static int Count(const WriteBatch* batch);--  // Set the count for the number of entries in the batch.-  static void SetCount(WriteBatch* batch, int n);--  // Return the seqeunce number for the start of this batch.-  static SequenceNumber Sequence(const WriteBatch* batch);--  // Store the specified number as the seqeunce number for the start of-  // this batch.-  static void SetSequence(WriteBatch* batch, SequenceNumber seq);--  static Slice Contents(const WriteBatch* batch) {-    return Slice(batch->rep_);-  }--  static size_t ByteSize(const WriteBatch* batch) {-    return batch->rep_.size();-  }--  static void SetContents(WriteBatch* batch, const Slice& contents);--  static Status InsertInto(const WriteBatch* batch, MemTable* memtable);--  static void Append(WriteBatch* dst, const WriteBatch* src);-};--}  // namespace leveldb---#endif  // STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_
− cbits/leveldb/db/write_batch_test.cc
@@ -1,120 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "leveldb/db.h"--#include "db/memtable.h"-#include "db/write_batch_internal.h"-#include "leveldb/env.h"-#include "util/logging.h"-#include "util/testharness.h"--namespace leveldb {--static std::string PrintContents(WriteBatch* b) {-  InternalKeyComparator cmp(BytewiseComparator());-  MemTable* mem = new MemTable(cmp);-  mem->Ref();-  std::string state;-  Status s = WriteBatchInternal::InsertInto(b, mem);-  int count = 0;-  Iterator* iter = mem->NewIterator();-  for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {-    ParsedInternalKey ikey;-    ASSERT_TRUE(ParseInternalKey(iter->key(), &ikey));-    switch (ikey.type) {-      case kTypeValue:-        state.append("Put(");-        state.append(ikey.user_key.ToString());-        state.append(", ");-        state.append(iter->value().ToString());-        state.append(")");-        count++;-        break;-      case kTypeDeletion:-        state.append("Delete(");-        state.append(ikey.user_key.ToString());-        state.append(")");-        count++;-        break;-    }-    state.append("@");-    state.append(NumberToString(ikey.sequence));-  }-  delete iter;-  if (!s.ok()) {-    state.append("ParseError()");-  } else if (count != WriteBatchInternal::Count(b)) {-    state.append("CountMismatch()");-  }-  mem->Unref();-  return state;-}--class WriteBatchTest { };--TEST(WriteBatchTest, Empty) {-  WriteBatch batch;-  ASSERT_EQ("", PrintContents(&batch));-  ASSERT_EQ(0, WriteBatchInternal::Count(&batch));-}--TEST(WriteBatchTest, Multiple) {-  WriteBatch batch;-  batch.Put(Slice("foo"), Slice("bar"));-  batch.Delete(Slice("box"));-  batch.Put(Slice("baz"), Slice("boo"));-  WriteBatchInternal::SetSequence(&batch, 100);-  ASSERT_EQ(100, WriteBatchInternal::Sequence(&batch));-  ASSERT_EQ(3, WriteBatchInternal::Count(&batch));-  ASSERT_EQ("Put(baz, boo)@102"-            "Delete(box)@101"-            "Put(foo, bar)@100",-            PrintContents(&batch));-}--TEST(WriteBatchTest, Corruption) {-  WriteBatch batch;-  batch.Put(Slice("foo"), Slice("bar"));-  batch.Delete(Slice("box"));-  WriteBatchInternal::SetSequence(&batch, 200);-  Slice contents = WriteBatchInternal::Contents(&batch);-  WriteBatchInternal::SetContents(&batch,-                                  Slice(contents.data(),contents.size()-1));-  ASSERT_EQ("Put(foo, bar)@200"-            "ParseError()",-            PrintContents(&batch));-}--TEST(WriteBatchTest, Append) {-  WriteBatch b1, b2;-  WriteBatchInternal::SetSequence(&b1, 200);-  WriteBatchInternal::SetSequence(&b2, 300);-  WriteBatchInternal::Append(&b1, &b2);-  ASSERT_EQ("",-            PrintContents(&b1));-  b2.Put("a", "va");-  WriteBatchInternal::Append(&b1, &b2);-  ASSERT_EQ("Put(a, va)@200",-            PrintContents(&b1));-  b2.Clear();-  b2.Put("b", "vb");-  WriteBatchInternal::Append(&b1, &b2);-  ASSERT_EQ("Put(a, va)@200"-            "Put(b, vb)@201",-            PrintContents(&b1));-  b2.Delete("foo");-  WriteBatchInternal::Append(&b1, &b2);-  ASSERT_EQ("Put(a, va)@200"-            "Put(b, vb)@202"-            "Put(b, vb)@201"-            "Delete(foo)@203",-            PrintContents(&b1));-}--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/helpers/memenv/memenv.cc
@@ -1,374 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "helpers/memenv/memenv.h"--#include "leveldb/env.h"-#include "leveldb/status.h"-#include "port/port.h"-#include "util/mutexlock.h"-#include <map>-#include <string.h>-#include <string>-#include <vector>--namespace leveldb {--namespace {--class FileState {- public:-  // FileStates are reference counted. The initial reference count is zero-  // and the caller must call Ref() at least once.-  FileState() : refs_(0), size_(0) {}--  // Increase the reference count.-  void Ref() {-    MutexLock lock(&refs_mutex_);-    ++refs_;-  }--  // Decrease the reference count. Delete if this is the last reference.-  void Unref() {-    bool do_delete = false;--    {-      MutexLock lock(&refs_mutex_);-      --refs_;-      assert(refs_ >= 0);-      if (refs_ <= 0) {-        do_delete = true;-      }-    }--    if (do_delete) {-      delete this;-    }-  }--  uint64_t Size() const { return size_; }--  Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const {-    if (offset > size_) {-      return Status::IOError("Offset greater than file size.");-    }-    const uint64_t available = size_ - offset;-    if (n > available) {-      n = available;-    }-    if (n == 0) {-      *result = Slice();-      return Status::OK();-    }--    size_t block = offset / kBlockSize;-    size_t block_offset = offset % kBlockSize;--    if (n <= kBlockSize - block_offset) {-      // The requested bytes are all in the first block.-      *result = Slice(blocks_[block] + block_offset, n);-      return Status::OK();-    }--    size_t bytes_to_copy = n;-    char* dst = scratch;--    while (bytes_to_copy > 0) {-      size_t avail = kBlockSize - block_offset;-      if (avail > bytes_to_copy) {-        avail = bytes_to_copy;-      }-      memcpy(dst, blocks_[block] + block_offset, avail);--      bytes_to_copy -= avail;-      dst += avail;-      block++;-      block_offset = 0;-    }--    *result = Slice(scratch, n);-    return Status::OK();-  }--  Status Append(const Slice& data) {-    const char* src = data.data();-    size_t src_len = data.size();--    while (src_len > 0) {-      size_t avail;-      size_t offset = size_ % kBlockSize;--      if (offset != 0) {-        // There is some room in the last block.-        avail = kBlockSize - offset;-      } else {-        // No room in the last block; push new one.-        blocks_.push_back(new char[kBlockSize]);-        avail = kBlockSize;-      }--      if (avail > src_len) {-        avail = src_len;-      }-      memcpy(blocks_.back() + offset, src, avail);-      src_len -= avail;-      src += avail;-      size_ += avail;-    }--    return Status::OK();-  }-- private:-  // Private since only Unref() should be used to delete it.-  ~FileState() {-    for (std::vector<char*>::iterator i = blocks_.begin(); i != blocks_.end();-         ++i) {-      delete [] *i;-    }-  }--  // No copying allowed.-  FileState(const FileState&);-  void operator=(const FileState&);--  port::Mutex refs_mutex_;-  int refs_;  // Protected by refs_mutex_;--  // The following fields are not protected by any mutex. They are only mutable-  // while the file is being written, and concurrent access is not allowed-  // to writable files.-  std::vector<char*> blocks_;-  uint64_t size_;--  enum { kBlockSize = 8 * 1024 };-};--class SequentialFileImpl : public SequentialFile {- public:-  explicit SequentialFileImpl(FileState* file) : file_(file), pos_(0) {-    file_->Ref();-  }--  ~SequentialFileImpl() {-    file_->Unref();-  }--  virtual Status Read(size_t n, Slice* result, char* scratch) {-    Status s = file_->Read(pos_, n, result, scratch);-    if (s.ok()) {-      pos_ += result->size();-    }-    return s;-  }--  virtual Status Skip(uint64_t n) {-    if (pos_ > file_->Size()) {-      return Status::IOError("pos_ > file_->Size()");-    }-    const size_t available = file_->Size() - pos_;-    if (n > available) {-      n = available;-    }-    pos_ += n;-    return Status::OK();-  }-- private:-  FileState* file_;-  size_t pos_;-};--class RandomAccessFileImpl : public RandomAccessFile {- public:-  explicit RandomAccessFileImpl(FileState* file) : file_(file) {-    file_->Ref();-  }--  ~RandomAccessFileImpl() {-    file_->Unref();-  }--  virtual Status Read(uint64_t offset, size_t n, Slice* result,-                      char* scratch) const {-    return file_->Read(offset, n, result, scratch);-  }-- private:-  FileState* file_;-};--class WritableFileImpl : public WritableFile {- public:-  WritableFileImpl(FileState* file) : file_(file) {-    file_->Ref();-  }--  ~WritableFileImpl() {-    file_->Unref();-  }--  virtual Status Append(const Slice& data) {-    return file_->Append(data);-  }--  virtual Status Close() { return Status::OK(); }-  virtual Status Flush() { return Status::OK(); }-  virtual Status Sync() { return Status::OK(); }-- private:-  FileState* file_;-};--class InMemoryEnv : public EnvWrapper {- public:-  explicit InMemoryEnv(Env* base_env) : EnvWrapper(base_env) { }--  virtual ~InMemoryEnv() {-    for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){-      i->second->Unref();-    }-  }--  // Partial implementation of the Env interface.-  virtual Status NewSequentialFile(const std::string& fname,-                                   SequentialFile** result) {-    MutexLock lock(&mutex_);-    if (file_map_.find(fname) == file_map_.end()) {-      *result = NULL;-      return Status::IOError(fname, "File not found");-    }--    *result = new SequentialFileImpl(file_map_[fname]);-    return Status::OK();-  }--  virtual Status NewRandomAccessFile(const std::string& fname,-                                     RandomAccessFile** result) {-    MutexLock lock(&mutex_);-    if (file_map_.find(fname) == file_map_.end()) {-      *result = NULL;-      return Status::IOError(fname, "File not found");-    }--    *result = new RandomAccessFileImpl(file_map_[fname]);-    return Status::OK();-  }--  virtual Status NewWritableFile(const std::string& fname,-                                 WritableFile** result) {-    MutexLock lock(&mutex_);-    if (file_map_.find(fname) != file_map_.end()) {-      DeleteFileInternal(fname);-    }--    FileState* file = new FileState();-    file->Ref();-    file_map_[fname] = file;--    *result = new WritableFileImpl(file);-    return Status::OK();-  }--  virtual bool FileExists(const std::string& fname) {-    MutexLock lock(&mutex_);-    return file_map_.find(fname) != file_map_.end();-  }--  virtual Status GetChildren(const std::string& dir,-                             std::vector<std::string>* result) {-    MutexLock lock(&mutex_);-    result->clear();--    for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){-      const std::string& filename = i->first;--      if (filename.size() >= dir.size() + 1 && filename[dir.size()] == '/' &&-          Slice(filename).starts_with(Slice(dir))) {-        result->push_back(filename.substr(dir.size() + 1));-      }-    }--    return Status::OK();-  }--  void DeleteFileInternal(const std::string& fname) {-    if (file_map_.find(fname) == file_map_.end()) {-      return;-    }--    file_map_[fname]->Unref();-    file_map_.erase(fname);-  }--  virtual Status DeleteFile(const std::string& fname) {-    MutexLock lock(&mutex_);-    if (file_map_.find(fname) == file_map_.end()) {-      return Status::IOError(fname, "File not found");-    }--    DeleteFileInternal(fname);-    return Status::OK();-  }--  virtual Status CreateDir(const std::string& dirname) {-    return Status::OK();-  }--  virtual Status DeleteDir(const std::string& dirname) {-    return Status::OK();-  }--  virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) {-    MutexLock lock(&mutex_);-    if (file_map_.find(fname) == file_map_.end()) {-      return Status::IOError(fname, "File not found");-    }--    *file_size = file_map_[fname]->Size();-    return Status::OK();-  }--  virtual Status RenameFile(const std::string& src,-                            const std::string& target) {-    MutexLock lock(&mutex_);-    if (file_map_.find(src) == file_map_.end()) {-      return Status::IOError(src, "File not found");-    }--    DeleteFileInternal(target);-    file_map_[target] = file_map_[src];-    file_map_.erase(src);-    return Status::OK();-  }--  virtual Status LockFile(const std::string& fname, FileLock** lock) {-    *lock = new FileLock;-    return Status::OK();-  }--  virtual Status UnlockFile(FileLock* lock) {-    delete lock;-    return Status::OK();-  }--  virtual Status GetTestDirectory(std::string* path) {-    *path = "/test";-    return Status::OK();-  }-- private:-  // Map from filenames to FileState objects, representing a simple file system.-  typedef std::map<std::string, FileState*> FileSystem;-  port::Mutex mutex_;-  FileSystem file_map_;  // Protected by mutex_.-};--}  // namespace--Env* NewMemEnv(Env* base_env) {-  return new InMemoryEnv(base_env);-}--}  // namespace leveldb
− cbits/leveldb/helpers/memenv/memenv.h
@@ -1,20 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_-#define STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_--namespace leveldb {--class Env;--// Returns a new environment that stores its data in memory and delegates-// all non-file-storage tasks to base_env. The caller must delete the result-// when it is no longer needed.-// *base_env must remain live while the result is in use.-Env* NewMemEnv(Env* base_env);--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_
− cbits/leveldb/helpers/memenv/memenv_test.cc
@@ -1,232 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "helpers/memenv/memenv.h"--#include "db/db_impl.h"-#include "leveldb/db.h"-#include "leveldb/env.h"-#include "util/testharness.h"-#include <string>-#include <vector>--namespace leveldb {--class MemEnvTest {- public:-  Env* env_;--  MemEnvTest()-      : env_(NewMemEnv(Env::Default())) {-  }-  ~MemEnvTest() {-    delete env_;-  }-};--TEST(MemEnvTest, Basics) {-  uint64_t file_size;-  WritableFile* writable_file;-  std::vector<std::string> children;--  ASSERT_OK(env_->CreateDir("/dir"));--  // Check that the directory is empty.-  ASSERT_TRUE(!env_->FileExists("/dir/non_existent"));-  ASSERT_TRUE(!env_->GetFileSize("/dir/non_existent", &file_size).ok());-  ASSERT_OK(env_->GetChildren("/dir", &children));-  ASSERT_EQ(0, children.size());--  // Create a file.-  ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file));-  delete writable_file;--  // Check that the file exists.-  ASSERT_TRUE(env_->FileExists("/dir/f"));-  ASSERT_OK(env_->GetFileSize("/dir/f", &file_size));-  ASSERT_EQ(0, file_size);-  ASSERT_OK(env_->GetChildren("/dir", &children));-  ASSERT_EQ(1, children.size());-  ASSERT_EQ("f", children[0]);--  // Write to the file.-  ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file));-  ASSERT_OK(writable_file->Append("abc"));-  delete writable_file;--  // Check for expected size.-  ASSERT_OK(env_->GetFileSize("/dir/f", &file_size));-  ASSERT_EQ(3, file_size);--  // Check that renaming works.-  ASSERT_TRUE(!env_->RenameFile("/dir/non_existent", "/dir/g").ok());-  ASSERT_OK(env_->RenameFile("/dir/f", "/dir/g"));-  ASSERT_TRUE(!env_->FileExists("/dir/f"));-  ASSERT_TRUE(env_->FileExists("/dir/g"));-  ASSERT_OK(env_->GetFileSize("/dir/g", &file_size));-  ASSERT_EQ(3, file_size);--  // Check that opening non-existent file fails.-  SequentialFile* seq_file;-  RandomAccessFile* rand_file;-  ASSERT_TRUE(!env_->NewSequentialFile("/dir/non_existent", &seq_file).ok());-  ASSERT_TRUE(!seq_file);-  ASSERT_TRUE(!env_->NewRandomAccessFile("/dir/non_existent", &rand_file).ok());-  ASSERT_TRUE(!rand_file);--  // Check that deleting works.-  ASSERT_TRUE(!env_->DeleteFile("/dir/non_existent").ok());-  ASSERT_OK(env_->DeleteFile("/dir/g"));-  ASSERT_TRUE(!env_->FileExists("/dir/g"));-  ASSERT_OK(env_->GetChildren("/dir", &children));-  ASSERT_EQ(0, children.size());-  ASSERT_OK(env_->DeleteDir("/dir"));-}--TEST(MemEnvTest, ReadWrite) {-  WritableFile* writable_file;-  SequentialFile* seq_file;-  RandomAccessFile* rand_file;-  Slice result;-  char scratch[100];--  ASSERT_OK(env_->CreateDir("/dir"));--  ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file));-  ASSERT_OK(writable_file->Append("hello "));-  ASSERT_OK(writable_file->Append("world"));-  delete writable_file;--  // Read sequentially.-  ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file));-  ASSERT_OK(seq_file->Read(5, &result, scratch)); // Read "hello".-  ASSERT_EQ(0, result.compare("hello"));-  ASSERT_OK(seq_file->Skip(1));-  ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Read "world".-  ASSERT_EQ(0, result.compare("world"));-  ASSERT_OK(seq_file->Read(1000, &result, scratch)); // Try reading past EOF.-  ASSERT_EQ(0, result.size());-  ASSERT_OK(seq_file->Skip(100)); // Try to skip past end of file.-  ASSERT_OK(seq_file->Read(1000, &result, scratch));-  ASSERT_EQ(0, result.size());-  delete seq_file;--  // Random reads.-  ASSERT_OK(env_->NewRandomAccessFile("/dir/f", &rand_file));-  ASSERT_OK(rand_file->Read(6, 5, &result, scratch)); // Read "world".-  ASSERT_EQ(0, result.compare("world"));-  ASSERT_OK(rand_file->Read(0, 5, &result, scratch)); // Read "hello".-  ASSERT_EQ(0, result.compare("hello"));-  ASSERT_OK(rand_file->Read(10, 100, &result, scratch)); // Read "d".-  ASSERT_EQ(0, result.compare("d"));--  // Too high offset.-  ASSERT_TRUE(!rand_file->Read(1000, 5, &result, scratch).ok());-  delete rand_file;-}--TEST(MemEnvTest, Locks) {-  FileLock* lock;--  // These are no-ops, but we test they return success.-  ASSERT_OK(env_->LockFile("some file", &lock));-  ASSERT_OK(env_->UnlockFile(lock));-}--TEST(MemEnvTest, Misc) {-  std::string test_dir;-  ASSERT_OK(env_->GetTestDirectory(&test_dir));-  ASSERT_TRUE(!test_dir.empty());--  WritableFile* writable_file;-  ASSERT_OK(env_->NewWritableFile("/a/b", &writable_file));--  // These are no-ops, but we test they return success.-  ASSERT_OK(writable_file->Sync());-  ASSERT_OK(writable_file->Flush());-  ASSERT_OK(writable_file->Close());-  delete writable_file;-}--TEST(MemEnvTest, LargeWrite) {-  const size_t kWriteSize = 300 * 1024;-  char* scratch = new char[kWriteSize * 2];--  std::string write_data;-  for (size_t i = 0; i < kWriteSize; ++i) {-    write_data.append(1, static_cast<char>(i));-  }--  WritableFile* writable_file;-  ASSERT_OK(env_->NewWritableFile("/dir/f", &writable_file));-  ASSERT_OK(writable_file->Append("foo"));-  ASSERT_OK(writable_file->Append(write_data));-  delete writable_file;--  SequentialFile* seq_file;-  Slice result;-  ASSERT_OK(env_->NewSequentialFile("/dir/f", &seq_file));-  ASSERT_OK(seq_file->Read(3, &result, scratch)); // Read "foo".-  ASSERT_EQ(0, result.compare("foo"));--  size_t read = 0;-  std::string read_data;-  while (read < kWriteSize) {-    ASSERT_OK(seq_file->Read(kWriteSize - read, &result, scratch));-    read_data.append(result.data(), result.size());-    read += result.size();-  }-  ASSERT_TRUE(write_data == read_data);-  delete seq_file;-  delete [] scratch;-}--TEST(MemEnvTest, DBTest) {-  Options options;-  options.create_if_missing = true;-  options.env = env_;-  DB* db;--  const Slice keys[] = {Slice("aaa"), Slice("bbb"), Slice("ccc")};-  const Slice vals[] = {Slice("foo"), Slice("bar"), Slice("baz")};--  ASSERT_OK(DB::Open(options, "/dir/db", &db));-  for (size_t i = 0; i < 3; ++i) {-    ASSERT_OK(db->Put(WriteOptions(), keys[i], vals[i]));-  }--  for (size_t i = 0; i < 3; ++i) {-    std::string res;-    ASSERT_OK(db->Get(ReadOptions(), keys[i], &res));-    ASSERT_TRUE(res == vals[i]);-  }--  Iterator* iterator = db->NewIterator(ReadOptions());-  iterator->SeekToFirst();-  for (size_t i = 0; i < 3; ++i) {-    ASSERT_TRUE(iterator->Valid());-    ASSERT_TRUE(keys[i] == iterator->key());-    ASSERT_TRUE(vals[i] == iterator->value());-    iterator->Next();-  }-  ASSERT_TRUE(!iterator->Valid());-  delete iterator;--  DBImpl* dbi = reinterpret_cast<DBImpl*>(db);-  ASSERT_OK(dbi->TEST_CompactMemTable());--  for (size_t i = 0; i < 3; ++i) {-    std::string res;-    ASSERT_OK(db->Get(ReadOptions(), keys[i], &res));-    ASSERT_TRUE(res == vals[i]);-  }--  delete db;-}--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/include/leveldb/c.h
@@ -1,246 +0,0 @@-/* Copyright (c) 2011 The LevelDB Authors. All rights reserved.-  Use of this source code is governed by a BSD-style license that can be-  found in the LICENSE file. See the AUTHORS file for names of contributors.--  C bindings for leveldb.  May be useful as a stable ABI that can be-  used by programs that keep leveldb in a shared library, or for-  a JNI api.--  Does not support:-  . getters for the option types-  . custom comparators that implement key shortening-  . capturing post-write-snapshot-  . custom iter, db, env, cache implementations using just the C bindings--  Some conventions:--  (1) We expose just opaque struct pointers and functions to clients.-  This allows us to change internal representations without having to-  recompile clients.--  (2) For simplicity, there is no equivalent to the Slice type.  Instead,-  the caller has to pass the pointer and length as separate-  arguments.--  (3) Errors are represented by a null-terminated c string.  NULL-  means no error.  All operations that can raise an error are passed-  a "char** errptr" as the last argument.  One of the following must-  be true on entry:-     *errptr == NULL-     *errptr points to a malloc()ed null-terminated error message-  On success, a leveldb routine leaves *errptr unchanged.-  On failure, leveldb frees the old value of *errptr and-  set *errptr to a malloc()ed error message.--  (4) Bools have the type unsigned char (0 == false; rest == true)--  (5) All of the pointer arguments must be non-NULL.-*/--#ifndef STORAGE_LEVELDB_INCLUDE_C_H_-#define STORAGE_LEVELDB_INCLUDE_C_H_--#ifdef __cplusplus-extern "C" {-#endif--#include <stdarg.h>-#include <stddef.h>-#include <stdint.h>--/* Exported types */--typedef struct leveldb_t               leveldb_t;-typedef struct leveldb_cache_t         leveldb_cache_t;-typedef struct leveldb_comparator_t    leveldb_comparator_t;-typedef struct leveldb_env_t           leveldb_env_t;-typedef struct leveldb_filelock_t      leveldb_filelock_t;-typedef struct leveldb_iterator_t      leveldb_iterator_t;-typedef struct leveldb_logger_t        leveldb_logger_t;-typedef struct leveldb_options_t       leveldb_options_t;-typedef struct leveldb_randomfile_t    leveldb_randomfile_t;-typedef struct leveldb_readoptions_t   leveldb_readoptions_t;-typedef struct leveldb_seqfile_t       leveldb_seqfile_t;-typedef struct leveldb_snapshot_t      leveldb_snapshot_t;-typedef struct leveldb_writablefile_t  leveldb_writablefile_t;-typedef struct leveldb_writebatch_t    leveldb_writebatch_t;-typedef struct leveldb_writeoptions_t  leveldb_writeoptions_t;--/* DB operations */--extern leveldb_t* leveldb_open(-    const leveldb_options_t* options,-    const char* name,-    char** errptr);--extern void leveldb_close(leveldb_t* db);--extern void leveldb_put(-    leveldb_t* db,-    const leveldb_writeoptions_t* options,-    const char* key, size_t keylen,-    const char* val, size_t vallen,-    char** errptr);--extern void leveldb_delete(-    leveldb_t* db,-    const leveldb_writeoptions_t* options,-    const char* key, size_t keylen,-    char** errptr);--extern void leveldb_write(-    leveldb_t* db,-    const leveldb_writeoptions_t* options,-    leveldb_writebatch_t* batch,-    char** errptr);--/* Returns NULL if not found.  A malloc()ed array otherwise.-   Stores the length of the array in *vallen. */-extern char* leveldb_get(-    leveldb_t* db,-    const leveldb_readoptions_t* options,-    const char* key, size_t keylen,-    size_t* vallen,-    char** errptr);--extern leveldb_iterator_t* leveldb_create_iterator(-    leveldb_t* db,-    const leveldb_readoptions_t* options);--extern const leveldb_snapshot_t* leveldb_create_snapshot(-    leveldb_t* db);--extern void leveldb_release_snapshot(-    leveldb_t* db,-    const leveldb_snapshot_t* snapshot);--/* Returns NULL if property name is unknown.-   Else returns a pointer to a malloc()-ed null-terminated value. */-extern char* leveldb_property_value(-    leveldb_t* db,-    const char* propname);--extern void leveldb_approximate_sizes(-    leveldb_t* db,-    int num_ranges,-    const char* const* range_start_key, const size_t* range_start_key_len,-    const char* const* range_limit_key, const size_t* range_limit_key_len,-    uint64_t* sizes);--/* Management operations */--extern void leveldb_destroy_db(-    const leveldb_options_t* options,-    const char* name,-    char** errptr);--extern void leveldb_repair_db(-    const leveldb_options_t* options,-    const char* name,-    char** errptr);--/* Iterator */--extern void leveldb_iter_destroy(leveldb_iterator_t*);-extern unsigned char leveldb_iter_valid(const leveldb_iterator_t*);-extern void leveldb_iter_seek_to_first(leveldb_iterator_t*);-extern void leveldb_iter_seek_to_last(leveldb_iterator_t*);-extern void leveldb_iter_seek(leveldb_iterator_t*, const char* k, size_t klen);-extern void leveldb_iter_next(leveldb_iterator_t*);-extern void leveldb_iter_prev(leveldb_iterator_t*);-extern const char* leveldb_iter_key(const leveldb_iterator_t*, size_t* klen);-extern const char* leveldb_iter_value(const leveldb_iterator_t*, size_t* vlen);-extern void leveldb_iter_get_error(const leveldb_iterator_t*, char** errptr);--/* Write batch */--extern leveldb_writebatch_t* leveldb_writebatch_create();-extern void leveldb_writebatch_destroy(leveldb_writebatch_t*);-extern void leveldb_writebatch_clear(leveldb_writebatch_t*);-extern void leveldb_writebatch_put(-    leveldb_writebatch_t*,-    const char* key, size_t klen,-    const char* val, size_t vlen);-extern void leveldb_writebatch_delete(-    leveldb_writebatch_t*,-    const char* key, size_t klen);-extern void leveldb_writebatch_iterate(-    leveldb_writebatch_t*,-    void* state,-    void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen),-    void (*deleted)(void*, const char* k, size_t klen));--/* Options */--extern leveldb_options_t* leveldb_options_create();-extern void leveldb_options_destroy(leveldb_options_t*);-extern void leveldb_options_set_comparator(-    leveldb_options_t*,-    leveldb_comparator_t*);-extern void leveldb_options_set_create_if_missing(-    leveldb_options_t*, unsigned char);-extern void leveldb_options_set_error_if_exists(-    leveldb_options_t*, unsigned char);-extern void leveldb_options_set_paranoid_checks(-    leveldb_options_t*, unsigned char);-extern void leveldb_options_set_env(leveldb_options_t*, leveldb_env_t*);-extern void leveldb_options_set_info_log(leveldb_options_t*, leveldb_logger_t*);-extern void leveldb_options_set_write_buffer_size(leveldb_options_t*, size_t);-extern void leveldb_options_set_max_open_files(leveldb_options_t*, int);-extern void leveldb_options_set_cache(leveldb_options_t*, leveldb_cache_t*);-extern void leveldb_options_set_block_size(leveldb_options_t*, size_t);-extern void leveldb_options_set_block_restart_interval(leveldb_options_t*, int);--enum {-  leveldb_no_compression = 0,-  leveldb_snappy_compression = 1-};-extern void leveldb_options_set_compression(leveldb_options_t*, int);--/* Comparator */--extern leveldb_comparator_t* leveldb_comparator_create(-    void* state,-    void (*destructor)(void*),-    int (*compare)(-        void*,-        const char* a, size_t alen,-        const char* b, size_t blen),-    const char* (*name)(void*));-extern void leveldb_comparator_destroy(leveldb_comparator_t*);--/* Read options */--extern leveldb_readoptions_t* leveldb_readoptions_create();-extern void leveldb_readoptions_destroy(leveldb_readoptions_t*);-extern void leveldb_readoptions_set_verify_checksums(-    leveldb_readoptions_t*,-    unsigned char);-extern void leveldb_readoptions_set_fill_cache(-    leveldb_readoptions_t*, unsigned char);-extern void leveldb_readoptions_set_snapshot(-    leveldb_readoptions_t*,-    const leveldb_snapshot_t*);--/* Write options */--extern leveldb_writeoptions_t* leveldb_writeoptions_create();-extern void leveldb_writeoptions_destroy(leveldb_writeoptions_t*);-extern void leveldb_writeoptions_set_sync(-    leveldb_writeoptions_t*, unsigned char);--/* Cache */--extern leveldb_cache_t* leveldb_cache_create_lru(size_t capacity);-extern void leveldb_cache_destroy(leveldb_cache_t* cache);--/* Env */--extern leveldb_env_t* leveldb_create_default_env();-extern void leveldb_env_destroy(leveldb_env_t*);--#ifdef __cplusplus-}  /* end extern "C" */-#endif--#endif  /* STORAGE_LEVELDB_INCLUDE_C_H_ */
− cbits/leveldb/include/leveldb/cache.h
@@ -1,99 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// A Cache is an interface that maps keys to values.  It has internal-// synchronization and may be safely accessed concurrently from-// multiple threads.  It may automatically evict entries to make room-// for new entries.  Values have a specified charge against the cache-// capacity.  For example, a cache where the values are variable-// length strings, may use the length of the string as the charge for-// the string.-//-// A builtin cache implementation with a least-recently-used eviction-// policy is provided.  Clients may use their own implementations if-// they want something more sophisticated (like scan-resistance, a-// custom eviction policy, variable cache sizing, etc.)--#ifndef STORAGE_LEVELDB_INCLUDE_CACHE_H_-#define STORAGE_LEVELDB_INCLUDE_CACHE_H_--#include <stdint.h>-#include "leveldb/slice.h"--namespace leveldb {--class Cache;--// Create a new cache with a fixed size capacity.  This implementation-// of Cache uses a least-recently-used eviction policy.-extern Cache* NewLRUCache(size_t capacity);--class Cache {- public:-  Cache() { }--  // Destroys all existing entries by calling the "deleter"-  // function that was passed to the constructor.-  virtual ~Cache();--  // Opaque handle to an entry stored in the cache.-  struct Handle { };--  // Insert a mapping from key->value into the cache and assign it-  // the specified charge against the total cache capacity.-  //-  // Returns a handle that corresponds to the mapping.  The caller-  // must call this->Release(handle) when the returned mapping is no-  // longer needed.-  //-  // When the inserted entry is no longer needed, the key and-  // value will be passed to "deleter".-  virtual Handle* Insert(const Slice& key, void* value, size_t charge,-                         void (*deleter)(const Slice& key, void* value)) = 0;--  // If the cache has no mapping for "key", returns NULL.-  //-  // Else return a handle that corresponds to the mapping.  The caller-  // must call this->Release(handle) when the returned mapping is no-  // longer needed.-  virtual Handle* Lookup(const Slice& key) = 0;--  // Release a mapping returned by a previous Lookup().-  // REQUIRES: handle must not have been released yet.-  // REQUIRES: handle must have been returned by a method on *this.-  virtual void Release(Handle* handle) = 0;--  // Return the value encapsulated in a handle returned by a-  // successful Lookup().-  // REQUIRES: handle must not have been released yet.-  // REQUIRES: handle must have been returned by a method on *this.-  virtual void* Value(Handle* handle) = 0;--  // If the cache contains entry for key, erase it.  Note that the-  // underlying entry will be kept around until all existing handles-  // to it have been released.-  virtual void Erase(const Slice& key) = 0;--  // Return a new numeric id.  May be used by multiple clients who are-  // sharing the same cache to partition the key space.  Typically the-  // client will allocate a new id at startup and prepend the id to-  // its cache keys.-  virtual uint64_t NewId() = 0;-- private:-  void LRU_Remove(Handle* e);-  void LRU_Append(Handle* e);-  void Unref(Handle* e);--  struct Rep;-  Rep* rep_;--  // No copying allowed-  Cache(const Cache&);-  void operator=(const Cache&);-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_UTIL_CACHE_H_
− cbits/leveldb/include/leveldb/comparator.h
@@ -1,63 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_-#define STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_--#include <string>--namespace leveldb {--class Slice;--// A Comparator object provides a total order across slices that are-// used as keys in an sstable or a database.  A Comparator implementation-// must be thread-safe since leveldb may invoke its methods concurrently-// from multiple threads.-class Comparator {- public:-  virtual ~Comparator();--  // Three-way comparison.  Returns value:-  //   < 0 iff "a" < "b",-  //   == 0 iff "a" == "b",-  //   > 0 iff "a" > "b"-  virtual int Compare(const Slice& a, const Slice& b) const = 0;--  // The name of the comparator.  Used to check for comparator-  // mismatches (i.e., a DB created with one comparator is-  // accessed using a different comparator.-  //-  // The client of this package should switch to a new name whenever-  // the comparator implementation changes in a way that will cause-  // the relative ordering of any two keys to change.-  //-  // Names starting with "leveldb." are reserved and should not be used-  // by any clients of this package.-  virtual const char* Name() const = 0;--  // Advanced functions: these are used to reduce the space requirements-  // for internal data structures like index blocks.--  // If *start < limit, changes *start to a short string in [start,limit).-  // Simple comparator implementations may return with *start unchanged,-  // i.e., an implementation of this method that does nothing is correct.-  virtual void FindShortestSeparator(-      std::string* start,-      const Slice& limit) const = 0;--  // Changes *key to a short string >= *key.-  // Simple comparator implementations may return with *key unchanged,-  // i.e., an implementation of this method that does nothing is correct.-  virtual void FindShortSuccessor(std::string* key) const = 0;-};--// Return a builtin comparator that uses lexicographic byte-wise-// ordering.  The result remains the property of this module and-// must not be deleted.-extern const Comparator* BytewiseComparator();--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_
− cbits/leveldb/include/leveldb/db.h
@@ -1,160 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_INCLUDE_DB_H_-#define STORAGE_LEVELDB_INCLUDE_DB_H_--#include <stdint.h>-#include <stdio.h>-#include "leveldb/iterator.h"-#include "leveldb/options.h"--namespace leveldb {--static const int kMajorVersion = 1;-static const int kMinorVersion = 2;--struct Options;-struct ReadOptions;-struct WriteOptions;-class WriteBatch;--// Abstract handle to particular state of a DB.-// A Snapshot is an immutable object and can therefore be safely-// accessed from multiple threads without any external synchronization.-class Snapshot {- protected:-  virtual ~Snapshot();-};--// A range of keys-struct Range {-  Slice start;          // Included in the range-  Slice limit;          // Not included in the range--  Range() { }-  Range(const Slice& s, const Slice& l) : start(s), limit(l) { }-};--// A DB is a persistent ordered map from keys to values.-// A DB is safe for concurrent access from multiple threads without-// any external synchronization.-class DB {- public:-  // Open the database with the specified "name".-  // Stores a pointer to a heap-allocated database in *dbptr and returns-  // OK on success.-  // Stores NULL in *dbptr and returns a non-OK status on error.-  // Caller should delete *dbptr when it is no longer needed.-  static Status Open(const Options& options,-                     const std::string& name,-                     DB** dbptr);--  DB() { }-  virtual ~DB();--  // Set the database entry for "key" to "value".  Returns OK on success,-  // and a non-OK status on error.-  // Note: consider setting options.sync = true.-  virtual Status Put(const WriteOptions& options,-                     const Slice& key,-                     const Slice& value) = 0;--  // Remove the database entry (if any) for "key".  Returns OK on-  // success, and a non-OK status on error.  It is not an error if "key"-  // did not exist in the database.-  // Note: consider setting options.sync = true.-  virtual Status Delete(const WriteOptions& options, const Slice& key) = 0;--  // Apply the specified updates to the database.-  // Returns OK on success, non-OK on failure.-  // Note: consider setting options.sync = true.-  virtual Status Write(const WriteOptions& options, WriteBatch* updates) = 0;--  // If the database contains an entry for "key" store the-  // corresponding value in *value and return OK.-  //-  // If there is no entry for "key" leave *value unchanged and return-  // a status for which Status::IsNotFound() returns true.-  //-  // May return some other Status on an error.-  virtual Status Get(const ReadOptions& options,-                     const Slice& key, std::string* value) = 0;--  // Return a heap-allocated iterator over the contents of the database.-  // The result of NewIterator() is initially invalid (caller must-  // call one of the Seek methods on the iterator before using it).-  //-  // Caller should delete the iterator when it is no longer needed.-  // The returned iterator should be deleted before this db is deleted.-  virtual Iterator* NewIterator(const ReadOptions& options) = 0;--  // Return a handle to the current DB state.  Iterators created with-  // this handle will all observe a stable snapshot of the current DB-  // state.  The caller must call ReleaseSnapshot(result) when the-  // snapshot is no longer needed.-  virtual const Snapshot* GetSnapshot() = 0;--  // Release a previously acquired snapshot.  The caller must not-  // use "snapshot" after this call.-  virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0;--  // DB implementations can export properties about their state-  // via this method.  If "property" is a valid property understood by this-  // DB implementation, fills "*value" with its current value and returns-  // true.  Otherwise returns false.-  //-  //-  // Valid property names include:-  //-  //  "leveldb.num-files-at-level<N>" - return the number of files at level <N>,-  //     where <N> is an ASCII representation of a level number (e.g. "0").-  //  "leveldb.stats" - returns a multi-line string that describes statistics-  //     about the internal operation of the DB.-  //  "leveldb.sstables" - returns a multi-line string that describes all-  //     of the sstables that make up the db contents.-  virtual bool GetProperty(const Slice& property, std::string* value) = 0;--  // For each i in [0,n-1], store in "sizes[i]", the approximate-  // file system space used by keys in "[range[i].start .. range[i].limit)".-  //-  // Note that the returned sizes measure file system space usage, so-  // if the user data compresses by a factor of ten, the returned-  // sizes will be one-tenth the size of the corresponding user data size.-  //-  // The results may not include the sizes of recently written data.-  virtual void GetApproximateSizes(const Range* range, int n,-                                   uint64_t* sizes) = 0;--  // Compact the underlying storage for the key range [*begin,*end].-  // In particular, deleted and overwritten versions are discarded,-  // and the data is rearranged to reduce the cost of operations-  // needed to access the data.  This operation should typically only-  // be invoked by users who understand the underlying implementation.-  //-  // begin==NULL is treated as a key before all keys in the database.-  // end==NULL is treated as a key after all keys in the database.-  // Therefore the following call will compact the entire database:-  //    db->CompactRange(NULL, NULL);-  virtual void CompactRange(const Slice* begin, const Slice* end) = 0;-- private:-  // No copying allowed-  DB(const DB&);-  void operator=(const DB&);-};--// Destroy the contents of the specified database.-// Be very careful using this method.-Status DestroyDB(const std::string& name, const Options& options);--// If a DB cannot be opened, you may attempt to call this method to-// resurrect as much of the contents of the database as possible.-// Some data may be lost, so be careful when calling this function-// on a database that contains important information.-Status RepairDB(const std::string& dbname, const Options& options);--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_INCLUDE_DB_H_
− cbits/leveldb/include/leveldb/env.h
@@ -1,323 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// An Env is an interface used by the leveldb implementation to access-// operating system functionality like the filesystem etc.  Callers-// may wish to provide a custom Env object when opening a database to-// get fine gain control; e.g., to rate limit file system operations.-//-// All Env implementations are safe for concurrent access from-// multiple threads without any external synchronization.--#ifndef STORAGE_LEVELDB_INCLUDE_ENV_H_-#define STORAGE_LEVELDB_INCLUDE_ENV_H_--#include <cstdarg>-#include <string>-#include <vector>-#include <stdint.h>-#include "leveldb/status.h"--namespace leveldb {--class FileLock;-class Logger;-class RandomAccessFile;-class SequentialFile;-class Slice;-class WritableFile;--class Env {- public:-  Env() { }-  virtual ~Env();--  // Return a default environment suitable for the current operating-  // system.  Sophisticated users may wish to provide their own Env-  // implementation instead of relying on this default environment.-  //-  // The result of Default() belongs to leveldb and must never be deleted.-  static Env* Default();--  // Create a brand new sequentially-readable file with the specified name.-  // On success, stores a pointer to the new file in *result and returns OK.-  // On failure stores NULL in *result and returns non-OK.  If the file does-  // not exist, returns a non-OK status.-  //-  // The returned file will only be accessed by one thread at a time.-  virtual Status NewSequentialFile(const std::string& fname,-                                   SequentialFile** result) = 0;--  // Create a brand new random access read-only file with the-  // specified name.  On success, stores a pointer to the new file in-  // *result and returns OK.  On failure stores NULL in *result and-  // returns non-OK.  If the file does not exist, returns a non-OK-  // status.-  //-  // The returned file may be concurrently accessed by multiple threads.-  virtual Status NewRandomAccessFile(const std::string& fname,-                                     RandomAccessFile** result) = 0;--  // Create an object that writes to a new file with the specified-  // name.  Deletes any existing file with the same name and creates a-  // new file.  On success, stores a pointer to the new file in-  // *result and returns OK.  On failure stores NULL in *result and-  // returns non-OK.-  //-  // The returned file will only be accessed by one thread at a time.-  virtual Status NewWritableFile(const std::string& fname,-                                 WritableFile** result) = 0;--  // Returns true iff the named file exists.-  virtual bool FileExists(const std::string& fname) = 0;--  // Store in *result the names of the children of the specified directory.-  // The names are relative to "dir".-  // Original contents of *results are dropped.-  virtual Status GetChildren(const std::string& dir,-                             std::vector<std::string>* result) = 0;--  // Delete the named file.-  virtual Status DeleteFile(const std::string& fname) = 0;--  // Create the specified directory.-  virtual Status CreateDir(const std::string& dirname) = 0;--  // Delete the specified directory.-  virtual Status DeleteDir(const std::string& dirname) = 0;--  // Store the size of fname in *file_size.-  virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) = 0;--  // Rename file src to target.-  virtual Status RenameFile(const std::string& src,-                            const std::string& target) = 0;--  // Lock the specified file.  Used to prevent concurrent access to-  // the same db by multiple processes.  On failure, stores NULL in-  // *lock and returns non-OK.-  //-  // On success, stores a pointer to the object that represents the-  // acquired lock in *lock and returns OK.  The caller should call-  // UnlockFile(*lock) to release the lock.  If the process exits,-  // the lock will be automatically released.-  //-  // If somebody else already holds the lock, finishes immediately-  // with a failure.  I.e., this call does not wait for existing locks-  // to go away.-  //-  // May create the named file if it does not already exist.-  virtual Status LockFile(const std::string& fname, FileLock** lock) = 0;--  // Release the lock acquired by a previous successful call to LockFile.-  // REQUIRES: lock was returned by a successful LockFile() call-  // REQUIRES: lock has not already been unlocked.-  virtual Status UnlockFile(FileLock* lock) = 0;--  // Arrange to run "(*function)(arg)" once in a background thread.-  //-  // "function" may run in an unspecified thread.  Multiple functions-  // added to the same Env may run concurrently in different threads.-  // I.e., the caller may not assume that background work items are-  // serialized.-  virtual void Schedule(-      void (*function)(void* arg),-      void* arg) = 0;--  // Start a new thread, invoking "function(arg)" within the new thread.-  // When "function(arg)" returns, the thread will be destroyed.-  virtual void StartThread(void (*function)(void* arg), void* arg) = 0;--  // *path is set to a temporary directory that can be used for testing. It may-  // or many not have just been created. The directory may or may not differ-  // between runs of the same process, but subsequent calls will return the-  // same directory.-  virtual Status GetTestDirectory(std::string* path) = 0;--  // Create and return a log file for storing informational messages.-  virtual Status NewLogger(const std::string& fname, Logger** result) = 0;--  // Returns the number of micro-seconds since some fixed point in time. Only-  // useful for computing deltas of time.-  virtual uint64_t NowMicros() = 0;--  // Sleep/delay the thread for the perscribed number of micro-seconds.-  virtual void SleepForMicroseconds(int micros) = 0;-- private:-  // No copying allowed-  Env(const Env&);-  void operator=(const Env&);-};--// A file abstraction for reading sequentially through a file-class SequentialFile {- public:-  SequentialFile() { }-  virtual ~SequentialFile();--  // Read up to "n" bytes from the file.  "scratch[0..n-1]" may be-  // written by this routine.  Sets "*result" to the data that was-  // read (including if fewer than "n" bytes were successfully read).-  // May set "*result" to point at data in "scratch[0..n-1]", so-  // "scratch[0..n-1]" must be live when "*result" is used.-  // If an error was encountered, returns a non-OK status.-  //-  // REQUIRES: External synchronization-  virtual Status Read(size_t n, Slice* result, char* scratch) = 0;--  // Skip "n" bytes from the file. This is guaranteed to be no-  // slower that reading the same data, but may be faster.-  //-  // If end of file is reached, skipping will stop at the end of the-  // file, and Skip will return OK.-  //-  // REQUIRES: External synchronization-  virtual Status Skip(uint64_t n) = 0;-};--// A file abstraction for randomly reading the contents of a file.-class RandomAccessFile {- public:-  RandomAccessFile() { }-  virtual ~RandomAccessFile();--  // Read up to "n" bytes from the file starting at "offset".-  // "scratch[0..n-1]" may be written by this routine.  Sets "*result"-  // to the data that was read (including if fewer than "n" bytes were-  // successfully read).  May set "*result" to point at data in-  // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when-  // "*result" is used.  If an error was encountered, returns a non-OK-  // status.-  //-  // Safe for concurrent use by multiple threads.-  virtual Status Read(uint64_t offset, size_t n, Slice* result,-                      char* scratch) const = 0;-};--// A file abstraction for sequential writing.  The implementation-// must provide buffering since callers may append small fragments-// at a time to the file.-class WritableFile {- public:-  WritableFile() { }-  virtual ~WritableFile();--  virtual Status Append(const Slice& data) = 0;-  virtual Status Close() = 0;-  virtual Status Flush() = 0;-  virtual Status Sync() = 0;-- private:-  // No copying allowed-  WritableFile(const WritableFile&);-  void operator=(const WritableFile&);-};--// An interface for writing log messages.-class Logger {- public:-  Logger() { }-  virtual ~Logger();--  // Write an entry to the log file with the specified format.-  virtual void Logv(const char* format, va_list ap) = 0;-- private:-  // No copying allowed-  Logger(const Logger&);-  void operator=(const Logger&);-};---// Identifies a locked file.-class FileLock {- public:-  FileLock() { }-  virtual ~FileLock();- private:-  // No copying allowed-  FileLock(const FileLock&);-  void operator=(const FileLock&);-};--// Log the specified data to *info_log if info_log is non-NULL.-extern void Log(Logger* info_log, const char* format, ...)-#   if defined(__GNUC__) || defined(__clang__)-    __attribute__((__format__ (__printf__, 2, 3)))-#   endif-    ;--// A utility routine: write "data" to the named file.-extern Status WriteStringToFile(Env* env, const Slice& data,-                                const std::string& fname);--// A utility routine: read contents of named file into *data-extern Status ReadFileToString(Env* env, const std::string& fname,-                               std::string* data);--// An implementation of Env that forwards all calls to another Env.-// May be useful to clients who wish to override just part of the-// functionality of another Env.-class EnvWrapper : public Env {- public:-  // Initialize an EnvWrapper that delegates all calls to *t-  explicit EnvWrapper(Env* t) : target_(t) { }-  virtual ~EnvWrapper();--  // Return the target to which this Env forwards all calls-  Env* target() const { return target_; }--  // The following text is boilerplate that forwards all methods to target()-  Status NewSequentialFile(const std::string& f, SequentialFile** r) {-    return target_->NewSequentialFile(f, r);-  }-  Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) {-    return target_->NewRandomAccessFile(f, r);-  }-  Status NewWritableFile(const std::string& f, WritableFile** r) {-    return target_->NewWritableFile(f, r);-  }-  bool FileExists(const std::string& f) { return target_->FileExists(f); }-  Status GetChildren(const std::string& dir, std::vector<std::string>* r) {-    return target_->GetChildren(dir, r);-  }-  Status DeleteFile(const std::string& f) { return target_->DeleteFile(f); }-  Status CreateDir(const std::string& d) { return target_->CreateDir(d); }-  Status DeleteDir(const std::string& d) { return target_->DeleteDir(d); }-  Status GetFileSize(const std::string& f, uint64_t* s) {-    return target_->GetFileSize(f, s);-  }-  Status RenameFile(const std::string& s, const std::string& t) {-    return target_->RenameFile(s, t);-  }-  Status LockFile(const std::string& f, FileLock** l) {-    return target_->LockFile(f, l);-  }-  Status UnlockFile(FileLock* l) { return target_->UnlockFile(l); }-  void Schedule(void (*f)(void*), void* a) {-    return target_->Schedule(f, a);-  }-  void StartThread(void (*f)(void*), void* a) {-    return target_->StartThread(f, a);-  }-  virtual Status GetTestDirectory(std::string* path) {-    return target_->GetTestDirectory(path);-  }-  virtual Status NewLogger(const std::string& fname, Logger** result) {-    return target_->NewLogger(fname, result);-  }-  uint64_t NowMicros() {-    return target_->NowMicros();-  }-  void SleepForMicroseconds(int micros) {-    target_->SleepForMicroseconds(micros);-  }- private:-  Env* target_;-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_INCLUDE_ENV_H_
− cbits/leveldb/include/leveldb/iterator.h
@@ -1,100 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// An iterator yields a sequence of key/value pairs from a source.-// The following class defines the interface.  Multiple implementations-// are provided by this library.  In particular, iterators are provided-// to access the contents of a Table or a DB.-//-// Multiple threads can invoke const methods on an Iterator without-// external synchronization, but if any of the threads may call a-// non-const method, all threads accessing the same Iterator must use-// external synchronization.--#ifndef STORAGE_LEVELDB_INCLUDE_ITERATOR_H_-#define STORAGE_LEVELDB_INCLUDE_ITERATOR_H_--#include "leveldb/slice.h"-#include "leveldb/status.h"--namespace leveldb {--class Iterator {- public:-  Iterator();-  virtual ~Iterator();--  // An iterator is either positioned at a key/value pair, or-  // not valid.  This method returns true iff the iterator is valid.-  virtual bool Valid() const = 0;--  // Position at the first key in the source.  The iterator is Valid()-  // after this call iff the source is not empty.-  virtual void SeekToFirst() = 0;--  // Position at the last key in the source.  The iterator is-  // Valid() after this call iff the source is not empty.-  virtual void SeekToLast() = 0;--  // Position at the first key in the source that at or past target-  // The iterator is Valid() after this call iff the source contains-  // an entry that comes at or past target.-  virtual void Seek(const Slice& target) = 0;--  // Moves to the next entry in the source.  After this call, Valid() is-  // true iff the iterator was not positioned at the last entry in the source.-  // REQUIRES: Valid()-  virtual void Next() = 0;--  // Moves to the previous entry in the source.  After this call, Valid() is-  // true iff the iterator was not positioned at the first entry in source.-  // REQUIRES: Valid()-  virtual void Prev() = 0;--  // Return the key for the current entry.  The underlying storage for-  // the returned slice is valid only until the next modification of-  // the iterator.-  // REQUIRES: Valid()-  virtual Slice key() const = 0;--  // Return the value for the current entry.  The underlying storage for-  // the returned slice is valid only until the next modification of-  // the iterator.-  // REQUIRES: !AtEnd() && !AtStart()-  virtual Slice value() const = 0;--  // If an error has occurred, return it.  Else return an ok status.-  virtual Status status() const = 0;--  // Clients are allowed to register function/arg1/arg2 triples that-  // will be invoked when this iterator is destroyed.-  //-  // Note that unlike all of the preceding methods, this method is-  // not abstract and therefore clients should not override it.-  typedef void (*CleanupFunction)(void* arg1, void* arg2);-  void RegisterCleanup(CleanupFunction function, void* arg1, void* arg2);-- private:-  struct Cleanup {-    CleanupFunction function;-    void* arg1;-    void* arg2;-    Cleanup* next;-  };-  Cleanup cleanup_;--  // No copying allowed-  Iterator(const Iterator&);-  void operator=(const Iterator&);-};--// Return an empty iterator (yields nothing).-extern Iterator* NewEmptyIterator();--// Return an empty iterator with the specified status.-extern Iterator* NewErrorIterator(const Status& status);--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_INCLUDE_ITERATOR_H_
− cbits/leveldb/include/leveldb/options.h
@@ -1,187 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_INCLUDE_OPTIONS_H_-#define STORAGE_LEVELDB_INCLUDE_OPTIONS_H_--#include <stddef.h>--namespace leveldb {--class Cache;-class Comparator;-class Env;-class Logger;-class Snapshot;--// DB contents are stored in a set of blocks, each of which holds a-// sequence of key,value pairs.  Each block may be compressed before-// being stored in a file.  The following enum describes which-// compression method (if any) is used to compress a block.-enum CompressionType {-  // NOTE: do not change the values of existing entries, as these are-  // part of the persistent format on disk.-  kNoCompression     = 0x0,-  kSnappyCompression = 0x1-};--// Options to control the behavior of a database (passed to DB::Open)-struct Options {-  // --------------------  // Parameters that affect behavior--  // Comparator used to define the order of keys in the table.-  // Default: a comparator that uses lexicographic byte-wise ordering-  //-  // REQUIRES: The client must ensure that the comparator supplied-  // here has the same name and orders keys *exactly* the same as the-  // comparator provided to previous open calls on the same DB.-  const Comparator* comparator;--  // If true, the database will be created if it is missing.-  // Default: false-  bool create_if_missing;--  // If true, an error is raised if the database already exists.-  // Default: false-  bool error_if_exists;--  // If true, the implementation will do aggressive checking of the-  // data it is processing and will stop early if it detects any-  // errors.  This may have unforeseen ramifications: for example, a-  // corruption of one DB entry may cause a large number of entries to-  // become unreadable or for the entire DB to become unopenable.-  // Default: false-  bool paranoid_checks;--  // Use the specified object to interact with the environment,-  // e.g. to read/write files, schedule background work, etc.-  // Default: Env::Default()-  Env* env;--  // Any internal progress/error information generated by the db will-  // be written to info_log if it is non-NULL, or to a file stored-  // in the same directory as the DB contents if info_log is NULL.-  // Default: NULL-  Logger* info_log;--  // --------------------  // Parameters that affect performance--  // Amount of data to build up in memory (backed by an unsorted log-  // on disk) before converting to a sorted on-disk file.-  //-  // Larger values increase performance, especially during bulk loads.-  // Up to two write buffers may be held in memory at the same time,-  // so you may wish to adjust this parameter to control memory usage.-  // Also, a larger write buffer will result in a longer recovery time-  // the next time the database is opened.-  //-  // Default: 4MB-  size_t write_buffer_size;--  // Number of open files that can be used by the DB.  You may need to-  // increase this if your database has a large working set (budget-  // one open file per 2MB of working set).-  //-  // Default: 1000-  int max_open_files;--  // Control over blocks (user data is stored in a set of blocks, and-  // a block is the unit of reading from disk).--  // If non-NULL, use the specified cache for blocks.-  // If NULL, leveldb will automatically create and use an 8MB internal cache.-  // Default: NULL-  Cache* block_cache;--  // Approximate size of user data packed per block.  Note that the-  // block size specified here corresponds to uncompressed data.  The-  // actual size of the unit read from disk may be smaller if-  // compression is enabled.  This parameter can be changed dynamically.-  //-  // Default: 4K-  size_t block_size;--  // Number of keys between restart points for delta encoding of keys.-  // This parameter can be changed dynamically.  Most clients should-  // leave this parameter alone.-  //-  // Default: 16-  int block_restart_interval;--  // Compress blocks using the specified compression algorithm.  This-  // parameter can be changed dynamically.-  //-  // Default: kSnappyCompression, which gives lightweight but fast-  // compression.-  //-  // Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz:-  //    ~200-500MB/s compression-  //    ~400-800MB/s decompression-  // Note that these speeds are significantly faster than most-  // persistent storage speeds, and therefore it is typically never-  // worth switching to kNoCompression.  Even if the input data is-  // incompressible, the kSnappyCompression implementation will-  // efficiently detect that and will switch to uncompressed mode.-  CompressionType compression;--  // Create an Options object with default values for all fields.-  Options();-};--// Options that control read operations-struct ReadOptions {-  // If true, all data read from underlying storage will be-  // verified against corresponding checksums.-  // Default: false-  bool verify_checksums;--  // Should the data read for this iteration be cached in memory?-  // Callers may wish to set this field to false for bulk scans.-  // Default: true-  bool fill_cache;--  // If "snapshot" is non-NULL, read as of the supplied snapshot-  // (which must belong to the DB that is being read and which must-  // not have been released).  If "snapshot" is NULL, use an impliicit-  // snapshot of the state at the beginning of this read operation.-  // Default: NULL-  const Snapshot* snapshot;--  ReadOptions()-      : verify_checksums(false),-        fill_cache(true),-        snapshot(NULL) {-  }-};--// Options that control write operations-struct WriteOptions {-  // If true, the write will be flushed from the operating system-  // buffer cache (by calling WritableFile::Sync()) before the write-  // is considered complete.  If this flag is true, writes will be-  // slower.-  //-  // If this flag is false, and the machine crashes, some recent-  // writes may be lost.  Note that if it is just the process that-  // crashes (i.e., the machine does not reboot), no writes will be-  // lost even if sync==false.-  //-  // In other words, a DB write with sync==false has similar-  // crash semantics as the "write()" system call.  A DB write-  // with sync==true has similar crash semantics to a "write()"-  // system call followed by "fsync()".-  //-  // Default: false-  bool sync;--  WriteOptions()-      : sync(false) {-  }-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_INCLUDE_OPTIONS_H_
− cbits/leveldb/include/leveldb/slice.h
@@ -1,109 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// Slice is a simple structure containing a pointer into some external-// storage and a size.  The user of a Slice must ensure that the slice-// is not used after the corresponding external storage has been-// deallocated.-//-// Multiple threads can invoke const methods on a Slice without-// external synchronization, but if any of the threads may call a-// non-const method, all threads accessing the same Slice must use-// external synchronization.--#ifndef STORAGE_LEVELDB_INCLUDE_SLICE_H_-#define STORAGE_LEVELDB_INCLUDE_SLICE_H_--#include <assert.h>-#include <stddef.h>-#include <string.h>-#include <string>--namespace leveldb {--class Slice {- public:-  // Create an empty slice.-  Slice() : data_(""), size_(0) { }--  // Create a slice that refers to d[0,n-1].-  Slice(const char* d, size_t n) : data_(d), size_(n) { }--  // Create a slice that refers to the contents of "s"-  Slice(const std::string& s) : data_(s.data()), size_(s.size()) { }--  // Create a slice that refers to s[0,strlen(s)-1]-  Slice(const char* s) : data_(s), size_(strlen(s)) { }--  // Return a pointer to the beginning of the referenced data-  const char* data() const { return data_; }--  // Return the length (in bytes) of the referenced data-  size_t size() const { return size_; }--  // Return true iff the length of the referenced data is zero-  bool empty() const { return size_ == 0; }--  // Return the ith byte in the referenced data.-  // REQUIRES: n < size()-  char operator[](size_t n) const {-    assert(n < size());-    return data_[n];-  }--  // Change this slice to refer to an empty array-  void clear() { data_ = ""; size_ = 0; }--  // Drop the first "n" bytes from this slice.-  void remove_prefix(size_t n) {-    assert(n <= size());-    data_ += n;-    size_ -= n;-  }--  // Return a string that contains the copy of the referenced data.-  std::string ToString() const { return std::string(data_, size_); }--  // Three-way comparison.  Returns value:-  //   <  0 iff "*this" <  "b",-  //   == 0 iff "*this" == "b",-  //   >  0 iff "*this" >  "b"-  int compare(const Slice& b) const;--  // Return true iff "x" is a prefix of "*this"-  bool starts_with(const Slice& x) const {-    return ((size_ >= x.size_) &&-            (memcmp(data_, x.data_, x.size_) == 0));-  }-- private:-  const char* data_;-  size_t size_;--  // Intentionally copyable-};--inline bool operator==(const Slice& x, const Slice& y) {-  return ((x.size() == y.size()) &&-          (memcmp(x.data(), y.data(), x.size()) == 0));-}--inline bool operator!=(const Slice& x, const Slice& y) {-  return !(x == y);-}--inline int Slice::compare(const Slice& b) const {-  const int min_len = (size_ < b.size_) ? size_ : b.size_;-  int r = memcmp(data_, b.data_, min_len);-  if (r == 0) {-    if (size_ < b.size_) r = -1;-    else if (size_ > b.size_) r = +1;-  }-  return r;-}--}  // namespace leveldb---#endif  // STORAGE_LEVELDB_INCLUDE_SLICE_H_
− cbits/leveldb/include/leveldb/status.h
@@ -1,100 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// A Status encapsulates the result of an operation.  It may indicate success,-// or it may indicate an error with an associated error message.-//-// Multiple threads can invoke const methods on a Status without-// external synchronization, but if any of the threads may call a-// non-const method, all threads accessing the same Status must use-// external synchronization.--#ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_-#define STORAGE_LEVELDB_INCLUDE_STATUS_H_--#include <string>-#include "leveldb/slice.h"--namespace leveldb {--class Status {- public:-  // Create a success status.-  Status() : state_(NULL) { }-  ~Status() { delete[] state_; }--  // Copy the specified status.-  Status(const Status& s);-  void operator=(const Status& s);--  // Return a success status.-  static Status OK() { return Status(); }--  // Return error status of an appropriate type.-  static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) {-    return Status(kNotFound, msg, msg2);-  }-  static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) {-    return Status(kCorruption, msg, msg2);-  }-  static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) {-    return Status(kNotSupported, msg, msg2);-  }-  static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) {-    return Status(kInvalidArgument, msg, msg2);-  }-  static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) {-    return Status(kIOError, msg, msg2);-  }--  // Returns true iff the status indicates success.-  bool ok() const { return (state_ == NULL); }--  // Returns true iff the status indicates a NotFound error.-  bool IsNotFound() const { return code() == kNotFound; }--  // Return a string representation of this status suitable for printing.-  // Returns the string "OK" for success.-  std::string ToString() const;-- private:-  // OK status has a NULL state_.  Otherwise, state_ is a new[] array-  // of the following form:-  //    state_[0..3] == length of message-  //    state_[4]    == code-  //    state_[5..]  == message-  const char* state_;--  enum Code {-    kOk = 0,-    kNotFound = 1,-    kCorruption = 2,-    kNotSupported = 3,-    kInvalidArgument = 4,-    kIOError = 5-  };--  Code code() const {-    return (state_ == NULL) ? kOk : static_cast<Code>(state_[4]);-  }--  Status(Code code, const Slice& msg, const Slice& msg2);-  static const char* CopyState(const char* s);-};--inline Status::Status(const Status& s) {-  state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_);-}-inline void Status::operator=(const Status& s) {-  // The following condition catches both aliasing (when this == &s),-  // and the common case where both s and *this are ok.-  if (state_ != s.state_) {-    delete[] state_;-    state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_);-  }-}--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_INCLUDE_STATUS_H_
− cbits/leveldb/include/leveldb/table.h
@@ -1,70 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_H_-#define STORAGE_LEVELDB_INCLUDE_TABLE_H_--#include <stdint.h>-#include "leveldb/iterator.h"--namespace leveldb {--class Block;-class BlockHandle;-struct Options;-class RandomAccessFile;-struct ReadOptions;--// A Table is a sorted map from strings to strings.  Tables are-// immutable and persistent.  A Table may be safely accessed from-// multiple threads without external synchronization.-class Table {- public:-  // 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.-  static Status Open(const Options& options,-                     RandomAccessFile* file,-                     uint64_t file_size,-                     Table** table);--  ~Table();--  // Returns a new iterator over the table contents.-  // The result of NewIterator() is initially invalid (caller must-  // call one of the Seek methods on the iterator before using it).-  Iterator* NewIterator(const ReadOptions&) const;--  // Given a key, return an approximate byte offset in the file where-  // the data for that key begins (or would begin if the key were-  // present in the file).  The returned value is in terms of file-  // bytes, and so includes effects like compression of the underlying data.-  // E.g., the approximate offset of the last key in the table will-  // be close to the file length.-  uint64_t ApproximateOffsetOf(const Slice& key) const;-- private:-  struct Rep;-  Rep* rep_;--  explicit Table(Rep* rep) { rep_ = rep; }-  static Iterator* BlockReader(void*, const ReadOptions&, const Slice&);--  // No copying allowed-  Table(const Table&);-  void operator=(const Table&);-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_INCLUDE_TABLE_H_
− cbits/leveldb/include/leveldb/table_builder.h
@@ -1,91 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// TableBuilder provides the interface used to build a Table-// (an immutable and sorted map from keys to values).-//-// Multiple threads can invoke const methods on a TableBuilder without-// external synchronization, but if any of the threads may call a-// non-const method, all threads accessing the same TableBuilder must use-// external synchronization.--#ifndef STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_-#define STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_--#include <stdint.h>-#include "leveldb/options.h"-#include "leveldb/status.h"--namespace leveldb {--class BlockBuilder;-class BlockHandle;-class WritableFile;--class TableBuilder {- public:-  // Create a builder that will store the contents of the table it is-  // building in *file.  Does not close the file.  It is up to the-  // caller to close the file after calling Finish().-  TableBuilder(const Options& options, WritableFile* file);--  // REQUIRES: Either Finish() or Abandon() has been called.-  ~TableBuilder();--  // Change the options used by this builder.  Note: only some of the-  // option fields can be changed after construction.  If a field is-  // not allowed to change dynamically and its value in the structure-  // passed to the constructor is different from its value in the-  // structure passed to this method, this method will return an error-  // without changing any fields.-  Status ChangeOptions(const Options& options);--  // Add key,value to the table being constructed.-  // REQUIRES: key is after any previously added key according to comparator.-  // REQUIRES: Finish(), Abandon() have not been called-  void Add(const Slice& key, const Slice& value);--  // Advanced operation: flush any buffered key/value pairs to file.-  // Can be used to ensure that two adjacent entries never live in-  // the same data block.  Most clients should not need to use this method.-  // REQUIRES: Finish(), Abandon() have not been called-  void Flush();--  // Return non-ok iff some error has been detected.-  Status status() const;--  // Finish building the table.  Stops using the file passed to the-  // constructor after this function returns.-  // REQUIRES: Finish(), Abandon() have not been called-  Status Finish();--  // Indicate that the contents of this builder should be abandoned.  Stops-  // using the file passed to the constructor after this function returns.-  // If the caller is not going to call Finish(), it must call Abandon()-  // before destroying this builder.-  // REQUIRES: Finish(), Abandon() have not been called-  void Abandon();--  // Number of calls to Add() so far.-  uint64_t NumEntries() const;--  // Size of the file generated so far.  If invoked after a successful-  // Finish() call, returns the size of the final generated file.-  uint64_t FileSize() const;-- private:-  bool ok() const { return status().ok(); }-  void WriteBlock(BlockBuilder* block, BlockHandle* handle);--  struct Rep;-  Rep* rep_;--  // No copying allowed-  TableBuilder(const TableBuilder&);-  void operator=(const TableBuilder&);-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_INCLUDE_TABLE_BUILDER_H_
− cbits/leveldb/include/leveldb/write_batch.h
@@ -1,64 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// WriteBatch holds a collection of updates to apply atomically to a DB.-//-// The updates are applied in the order in which they are added-// to the WriteBatch.  For example, the value of "key" will be "v3"-// after the following batch is written:-//-//    batch.Put("key", "v1");-//    batch.Delete("key");-//    batch.Put("key", "v2");-//    batch.Put("key", "v3");-//-// Multiple threads can invoke const methods on a WriteBatch without-// external synchronization, but if any of the threads may call a-// non-const method, all threads accessing the same WriteBatch must use-// external synchronization.--#ifndef STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_-#define STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_--#include <string>-#include "leveldb/status.h"--namespace leveldb {--class Slice;--class WriteBatch {- public:-  WriteBatch();-  ~WriteBatch();--  // Store the mapping "key->value" in the database.-  void Put(const Slice& key, const Slice& value);--  // If the database contains a mapping for "key", erase it.  Else do nothing.-  void Delete(const Slice& key);--  // Clear all updates buffered in this batch.-  void Clear();--  // Support for iterating over the contents of a batch.-  class Handler {-   public:-    virtual ~Handler();-    virtual void Put(const Slice& key, const Slice& value) = 0;-    virtual void Delete(const Slice& key) = 0;-  };-  Status Iterate(Handler* handler) const;-- private:-  friend class WriteBatchInternal;--  std::string rep_;  // See comment in write_batch.cc for the format of rep_--  // Intentionally copyable-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_INCLUDE_WRITE_BATCH_H_
− cbits/leveldb/port/atomic_pointer.h
@@ -1,144 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--// AtomicPointer provides storage for a lock-free pointer.-// Platform-dependent implementation of AtomicPointer:-// - If the platform provides a cheap barrier, we use it with raw pointers-// - If cstdatomic is present (on newer versions of gcc, it is), we use-//   a cstdatomic-based AtomicPointer.  However we prefer the memory-//   barrier based version, because at least on a gcc 4.4 32-bit build-//   on linux, we have encountered a buggy <cstdatomic>-//   implementation.  Also, some <cstdatomic> implementations are much-//   slower than a memory-barrier based implementation (~16ns for-//   <cstdatomic> based acquire-load vs. ~1ns for a barrier based-//   acquire-load).-// This code is based on atomicops-internals-* in Google's perftools:-// http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase--#ifndef PORT_ATOMIC_POINTER_H_-#define PORT_ATOMIC_POINTER_H_--#include <stdint.h>-#ifdef LEVELDB_CSTDATOMIC_PRESENT-#include <cstdatomic>-#endif-#ifdef OS_WIN-#include <windows.h>-#endif-#ifdef OS_MACOSX-#include <libkern/OSAtomic.h>-#endif--#if defined(_M_X64) || defined(__x86_64__)-#define ARCH_CPU_X86_FAMILY 1-#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)-#define ARCH_CPU_X86_FAMILY 1-#elif defined(__ARMEL__)-#define ARCH_CPU_ARM_FAMILY 1-#endif--namespace leveldb {-namespace port {--// Define MemoryBarrier() if available-// Windows on x86-#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY)-// windows.h already provides a MemoryBarrier(void) macro-// http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx-#define LEVELDB_HAVE_MEMORY_BARRIER--// Gcc on x86-#elif defined(ARCH_CPU_X86_FAMILY) && defined(__GNUC__)-inline void MemoryBarrier() {-  // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on-  // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering.-  __asm__ __volatile__("" : : : "memory");-}-#define LEVELDB_HAVE_MEMORY_BARRIER--// Sun Studio-#elif defined(ARCH_CPU_X86_FAMILY) && defined(__SUNPRO_CC)-inline void MemoryBarrier() {-  // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on-  // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering.-  asm volatile("" : : : "memory");-}-#define LEVELDB_HAVE_MEMORY_BARRIER--// Mac OS-#elif defined(OS_MACOSX)-inline void MemoryBarrier() {-  OSMemoryBarrier();-}-#define LEVELDB_HAVE_MEMORY_BARRIER--// ARM-#elif defined(ARCH_CPU_ARM_FAMILY)-typedef void (*LinuxKernelMemoryBarrierFunc)(void);-LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =-    (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;-inline void MemoryBarrier() {-  pLinuxKernelMemoryBarrier();-}-#define LEVELDB_HAVE_MEMORY_BARRIER--#endif--// AtomicPointer built using platform-specific MemoryBarrier()-#if defined(LEVELDB_HAVE_MEMORY_BARRIER)-class AtomicPointer {- private:-  void* rep_;- public:-  AtomicPointer() { }-  explicit AtomicPointer(void* p) : rep_(p) {}-  inline void* NoBarrier_Load() const { return rep_; }-  inline void NoBarrier_Store(void* v) { rep_ = v; }-  inline void* Acquire_Load() const {-    void* result = rep_;-    MemoryBarrier();-    return result;-  }-  inline void Release_Store(void* v) {-    MemoryBarrier();-    rep_ = v;-  }-};--// AtomicPointer based on <cstdatomic>-#elif defined(LEVELDB_CSTDATOMIC_PRESENT)-class AtomicPointer {- private:-  std::atomic<void*> rep_;- public:-  AtomicPointer() { }-  explicit AtomicPointer(void* v) : rep_(v) { }-  inline void* Acquire_Load() const {-    return rep_.load(std::memory_order_acquire);-  }-  inline void Release_Store(void* v) {-    rep_.store(v, std::memory_order_release);-  }-  inline void* NoBarrier_Load() const {-    return rep_.load(std::memory_order_relaxed);-  }-  inline void NoBarrier_Store(void* v) {-    rep_.store(v, std::memory_order_relaxed);-  }-};--// We have neither MemoryBarrier(), nor <cstdatomic>-#else-#error Please implement AtomicPointer for this platform.--#endif--#undef LEVELDB_HAVE_MEMORY_BARRIER-#undef ARCH_CPU_X86_FAMILY-#undef ARCH_CPU_ARM_FAMILY--}  // namespace port-}  // namespace leveldb--#endif  // PORT_ATOMIC_POINTER_H_
− cbits/leveldb/port/port.h
@@ -1,21 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_PORT_PORT_H_-#define STORAGE_LEVELDB_PORT_PORT_H_--#include <string.h>--// Include the appropriate platform specific file below.  If you are-// porting to a new platform, see "port_example.h" for documentation-// of what the new port_<platform>.h file must provide.-#if defined(LEVELDB_PLATFORM_POSIX)-#  include "port/port_posix.h"-#elif defined(LEVELDB_PLATFORM_CHROMIUM)-#  include "port/port_chromium.h"-#elif defined(LEVELDB_PLATFORM_ANDROID)-#  include "port/port_android.h"-#endif--#endif  // STORAGE_LEVELDB_PORT_PORT_H_
− cbits/leveldb/port/port_android.cc
@@ -1,64 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "port/port_android.h"--#include <cstdlib>--extern "C" {-size_t fread_unlocked(void *a, size_t b, size_t c, FILE *d) {-  return fread(a, b, c, d);-}--size_t fwrite_unlocked(const void *a, size_t b, size_t c, FILE *d) {-  return fwrite(a, b, c, d);-}--int fflush_unlocked(FILE *f) {-  return fflush(f);-}--int fdatasync(int fd) {-  return fsync(fd);-}-}--namespace leveldb {-namespace port {--static void PthreadCall(const char* label, int result) {-  if (result != 0) {-    fprintf(stderr, "pthread %s: %s\n", label, strerror(result));-    abort();-  }-}--Mutex::Mutex() { PthreadCall("init mutex", pthread_mutex_init(&mu_, NULL)); }-Mutex::~Mutex() { PthreadCall("destroy mutex", pthread_mutex_destroy(&mu_)); }-void Mutex::Lock() { PthreadCall("lock", pthread_mutex_lock(&mu_)); }-void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); }--CondVar::CondVar(Mutex* mu)-    : mu_(mu) {-  PthreadCall("init cv", pthread_cond_init(&cv_, NULL));-}--CondVar::~CondVar() { -  PthreadCall("destroy cv", pthread_cond_destroy(&cv_));-}--void CondVar::Wait() {-  PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_));-}--void CondVar::Signal(){-  PthreadCall("signal", pthread_cond_signal(&cv_));-}--void CondVar::SignalAll() {-  PthreadCall("broadcast", pthread_cond_broadcast(&cv_));-}--}  // namespace port-}  // namespace leveldb
− cbits/leveldb/port/port_android.h
@@ -1,156 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// See port_example.h for documentation for the following types/functions.--#ifndef STORAGE_LEVELDB_PORT_PORT_ANDROID_H_-#define STORAGE_LEVELDB_PORT_PORT_ANDROID_H_--#include <endian.h>-#include <pthread.h>-#include <stdint.h>-#include <cstdatomic>-#include <string>-#include <cctype>--// Collapse the plethora of ARM flavors available to an easier to manage set-// Defs reference is at https://wiki.edubuntu.org/ARM/Thumb2PortingHowto-#if defined(__ARM_ARCH_6__) || \-    defined(__ARM_ARCH_6J__) || \-    defined(__ARM_ARCH_6K__) || \-    defined(__ARM_ARCH_6Z__) || \-    defined(__ARM_ARCH_6T2__) || \-    defined(__ARM_ARCH_6ZK__) || \-    defined(__ARM_ARCH_7__) || \-    defined(__ARM_ARCH_7R__) || \-    defined(__ARM_ARCH_7A__)-#define ARMV6_OR_7 1-#endif--extern "C" {-  size_t fread_unlocked(void *a, size_t b, size_t c, FILE *d);-  size_t fwrite_unlocked(const void *a, size_t b, size_t c, FILE *d);-  int fflush_unlocked(FILE *f);-  int fdatasync (int fd);-}--namespace leveldb {-namespace port {--static const bool kLittleEndian = __BYTE_ORDER == __LITTLE_ENDIAN;--class CondVar;--class Mutex {- public:-  Mutex();-  ~Mutex();--  void Lock();-  void Unlock();-  void AssertHeld() {-    //TODO(gabor): How can I implement this?-  }-- private:-  friend class CondVar;-  pthread_mutex_t mu_;--  // No copying-  Mutex(const Mutex&);-  void operator=(const Mutex&);-};--class CondVar {- public:-  explicit CondVar(Mutex* mu);-  ~CondVar();-  void Wait();-  void Signal();-  void SignalAll();- private:-  Mutex* mu_;-  pthread_cond_t cv_;-};--#ifndef ARMV6_OR_7-// On ARM chipsets <V6, 0xffff0fa0 is the hard coded address of a -// memory barrier function provided by the kernel.-typedef void (*LinuxKernelMemoryBarrierFunc)(void);-LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier ATTRIBUTE_WEAK =-    (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;-#endif--// Storage for a lock-free pointer-class AtomicPointer {- private:-  void* rep_;--  inline void MemoryBarrier() const {-    // TODO(gabor): This only works on Android instruction sets >= V6-#ifdef ARMV6_OR_7-    __asm__ __volatile__("dmb" : : : "memory");-#else-    pLinuxKernelMemoryBarrier();-#endif-  }-- public:-  AtomicPointer() { }-  explicit AtomicPointer(void* v) : rep_(v) { }-  inline void* Acquire_Load() const {-    void* r = rep_;-    MemoryBarrier();-    return r;-  }-  inline void Release_Store(void* v) {-    MemoryBarrier();-    rep_ = v;-  }-  inline void* NoBarrier_Load() const {-    void* r = rep_;-    return r;-  }-  inline void NoBarrier_Store(void* v) {-    rep_ = v;-  }-};--// TODO(gabor): Implement compress-inline bool Snappy_Compress(-    const char* input,-    size_t input_length,-    std::string* output) {-  return false;-}--// TODO(gabor): Implement uncompress-inline bool Snappy_GetUncompressedLength(const char* input, size_t length,-                                         size_t* result) {-  return false;-}--// TODO(gabor): Implement uncompress-inline bool Snappy_Uncompress(-    const char* input_data,-    size_t input_length,-    char* output) {-  return false;-}--inline uint64_t ThreadIdentifier() {-  pthread_t tid = pthread_self();-  uint64_t r = 0;-  memcpy(&r, &tid, sizeof(r) < sizeof(tid) ? sizeof(r) : sizeof(tid));-  return r;-}--inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) {-  return false;-}--}  // namespace port-}  // namespace leveldb--#endif  // STORAGE_LEVELDB_PORT_PORT_ANDROID_H_
− cbits/leveldb/port/port_example.h
@@ -1,125 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// This file contains the specification, but not the implementations,-// of the types/operations/etc. that should be defined by a platform-// specific port_<platform>.h file.  Use this file as a reference for-// how to port this package to a new platform.--#ifndef STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_-#define STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_--namespace leveldb {-namespace port {--// TODO(jorlow): Many of these belong more in the environment class rather than-//               here. We should try moving them and see if it affects perf.--// The following boolean constant must be true on a little-endian machine-// and false otherwise.-static const bool kLittleEndian = true /* or some other expression */;--// ------------------ Threading ---------------------// A Mutex represents an exclusive lock.-class Mutex {- public:-  Mutex();-  ~Mutex();--  // Lock the mutex.  Waits until other lockers have exited.-  // Will deadlock if the mutex is already locked by this thread.-  void Lock();--  // Unlock the mutex.-  // REQUIRES: This mutex was locked by this thread.-  void Unlock();--  // Optionally crash if this thread does not hold this mutex.-  // The implementation must be fast, especially if NDEBUG is-  // defined.  The implementation is allowed to skip all checks.-  void AssertHeld();-};--class CondVar {- public:-  explicit CondVar(Mutex* mu);-  ~CondVar();--  // Atomically release *mu and block on this condition variable until-  // either a call to SignalAll(), or a call to Signal() that picks-  // this thread to wakeup.-  // REQUIRES: this thread holds *mu-  void Wait();--  // If there are some threads waiting, wake up at least one of them.-  void Signal();--  // Wake up all waiting threads.-  void SignallAll();-};--// A type that holds a pointer that can be read or written atomically-// (i.e., without word-tearing.)-class AtomicPointer {- private:-  intptr_t rep_;- public:-  // Initialize to arbitrary value-  AtomicPointer();--  // Initialize to hold v-  explicit AtomicPointer(void* v) : rep_(v) { }--  // Read and return the stored pointer with the guarantee that no-  // later memory access (read or write) by this thread can be-  // reordered ahead of this read.-  void* Acquire_Load() const;--  // Set v as the stored pointer with the guarantee that no earlier-  // memory access (read or write) by this thread can be reordered-  // after this store.-  void Release_Store(void* v);--  // Read the stored pointer with no ordering guarantees.-  void* NoBarrier_Load() const;--  // Set va as the stored pointer with no ordering guarantees.-  void NoBarrier_Store(void* v);-};--// ------------------ Compression ---------------------// Store the snappy compression of "input[0,input_length-1]" in *output.-// Returns false if snappy is not supported by this port.-extern bool Snappy_Compress(const char* input, size_t input_length,-                            std::string* output);--// If input[0,input_length-1] looks like a valid snappy compressed-// buffer, store the size of the uncompressed data in *result and-// return true.  Else return false.-extern bool Snappy_GetUncompressedLength(const char* input, size_t length,-                                         size_t* result);--// Attempt to snappy uncompress input[0,input_length-1] into *output.-// Returns true if successful, false if the input is invalid lightweight-// compressed data.-//-// REQUIRES: at least the first "n" bytes of output[] must be writable-// where "n" is the result of a successful call to-// Snappy_GetUncompressedLength.-extern bool Snappy_Uncompress(const char* input_data, size_t input_length,-                              char* output);--// ------------------ Miscellaneous ---------------------// If heap profiling is not supported, returns false.-// Else repeatedly calls (*func)(arg, data, n) and then returns true.-// The concatenation of all "data[0,n-1]" fragments is the heap profile.-extern bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg);--}  // namespace port-}  // namespace leveldb--#endif  // STORAGE_LEVELDB_PORT_PORT_EXAMPLE_H_
− cbits/leveldb/port/port_posix.cc
@@ -1,50 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "port/port_posix.h"--#include <cstdlib>-#include <stdio.h>-#include <string.h>-#include "util/logging.h"--namespace leveldb {-namespace port {--static void PthreadCall(const char* label, int result) {-  if (result != 0) {-    fprintf(stderr, "pthread %s: %s\n", label, strerror(result));-    abort();-  }-}--Mutex::Mutex() { PthreadCall("init mutex", pthread_mutex_init(&mu_, NULL)); }--Mutex::~Mutex() { PthreadCall("destroy mutex", pthread_mutex_destroy(&mu_)); }--void Mutex::Lock() { PthreadCall("lock", pthread_mutex_lock(&mu_)); }--void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); }--CondVar::CondVar(Mutex* mu)-    : mu_(mu) {-    PthreadCall("init cv", pthread_cond_init(&cv_, NULL));-}--CondVar::~CondVar() { PthreadCall("destroy cv", pthread_cond_destroy(&cv_)); }--void CondVar::Wait() {-  PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_));-}--void CondVar::Signal() {-  PthreadCall("signal", pthread_cond_signal(&cv_));-}--void CondVar::SignalAll() {-  PthreadCall("broadcast", pthread_cond_broadcast(&cv_));-}--}  // namespace port-}  // namespace leveldb
− cbits/leveldb/port/port_posix.h
@@ -1,129 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// See port_example.h for documentation for the following types/functions.--#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_-#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_--#if defined(OS_MACOSX)-  #include <machine/endian.h>-#elif defined(OS_SOLARIS)-  #include <sys/isa_defs.h>-  #ifdef _LITTLE_ENDIAN-    #define LITTLE_ENDIAN-  #else-    #define BIG_ENDIAN-  #endif-#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_NETBSD) ||\-      defined(OS_DRAGONFLYBSD)-  #include <sys/types.h>-  #include <sys/endian.h>-#else-  #include <endian.h>-#endif-#include <pthread.h>-#ifdef SNAPPY-#include <snappy.h>-#endif-#include <stdint.h>-#include <string>-#include "port/atomic_pointer.h"--#ifdef LITTLE_ENDIAN-#define IS_LITTLE_ENDIAN true-#else-#define IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)-#endif--#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\-    defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD)-// Use fread/fwrite/fflush on platforms without _unlocked variants-#define fread_unlocked fread-#define fwrite_unlocked fwrite-#define fflush_unlocked fflush-#endif--#if defined(OS_MACOSX) || defined(OS_FREEBSD) ||\-    defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD)-// Use fsync() on platforms without fdatasync()-#define fdatasync fsync-#endif--namespace leveldb {-namespace port {--static const bool kLittleEndian = IS_LITTLE_ENDIAN;--class CondVar;--class Mutex {- public:-  Mutex();-  ~Mutex();--  void Lock();-  void Unlock();-  void AssertHeld() { }-- private:-  friend class CondVar;-  pthread_mutex_t mu_;--  // No copying-  Mutex(const Mutex&);-  void operator=(const Mutex&);-};--class CondVar {- public:-  explicit CondVar(Mutex* mu);-  ~CondVar();-  void Wait();-  void Signal();-  void SignalAll();- private:-  pthread_cond_t cv_;-  Mutex* mu_;-};--inline bool Snappy_Compress(const char* input, size_t length,-                            ::std::string* output) {-#ifdef SNAPPY-  output->resize(snappy::MaxCompressedLength(length));-  size_t outlen;-  snappy::RawCompress(input, length, &(*output)[0], &outlen);-  output->resize(outlen);-  return true;-#endif--  return false;-}--inline bool Snappy_GetUncompressedLength(const char* input, size_t length,-                                         size_t* result) {-#ifdef SNAPPY-  return snappy::GetUncompressedLength(input, length, result);-#else-  return false;-#endif-}--inline bool Snappy_Uncompress(const char* input, size_t length,-                              char* output) {-#ifdef SNAPPY-  return snappy::RawUncompress(input, length, output);-#else-  return false;-#endif-}--inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) {-  return false;-}--} // namespace port-} // namespace leveldb--#endif  // STORAGE_LEVELDB_PORT_PORT_POSIX_H_
− cbits/leveldb/table/block.cc
@@ -1,263 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// Decodes the blocks generated by block_builder.cc.--#include "table/block.h"--#include <vector>-#include <algorithm>-#include "leveldb/comparator.h"-#include "util/coding.h"-#include "util/logging.h"--namespace leveldb {--inline uint32_t Block::NumRestarts() const {-  assert(size_ >= 2*sizeof(uint32_t));-  return DecodeFixed32(data_ + size_ - sizeof(uint32_t));-}--Block::Block(const char* data, size_t size)-    : data_(data),-      size_(size) {-  if (size_ < sizeof(uint32_t)) {-    size_ = 0;  // Error marker-  } else {-    restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t);-    if (restart_offset_ > size_ - sizeof(uint32_t)) {-      // The size is too small for NumRestarts() and therefore-      // restart_offset_ wrapped around.-      size_ = 0;-    }-  }-}--Block::~Block() {-  delete[] data_;-}--// Helper routine: decode the next block entry starting at "p",-// storing the number of shared key bytes, non_shared key bytes,-// and the length of the value in "*shared", "*non_shared", and-// "*value_length", respectively.  Will not derefence past "limit".-//-// If any errors are detected, returns NULL.  Otherwise, returns a-// pointer to the key delta (just past the three decoded values).-static inline const char* DecodeEntry(const char* p, const char* limit,-                                      uint32_t* shared,-                                      uint32_t* non_shared,-                                      uint32_t* value_length) {-  if (limit - p < 3) return NULL;-  *shared = reinterpret_cast<const unsigned char*>(p)[0];-  *non_shared = reinterpret_cast<const unsigned char*>(p)[1];-  *value_length = reinterpret_cast<const unsigned char*>(p)[2];-  if ((*shared | *non_shared | *value_length) < 128) {-    // Fast path: all three values are encoded in one byte each-    p += 3;-  } else {-    if ((p = GetVarint32Ptr(p, limit, shared)) == NULL) return NULL;-    if ((p = GetVarint32Ptr(p, limit, non_shared)) == NULL) return NULL;-    if ((p = GetVarint32Ptr(p, limit, value_length)) == NULL) return NULL;-  }--  if (static_cast<uint32_t>(limit - p) < (*non_shared + *value_length)) {-    return NULL;-  }-  return p;-}--class Block::Iter : public Iterator {- private:-  const Comparator* const comparator_;-  const char* const data_;      // underlying block contents-  uint32_t const restarts_;     // Offset of restart array (list of fixed32)-  uint32_t const num_restarts_; // Number of uint32_t entries in restart array--  // current_ is offset in data_ of current entry.  >= restarts_ if !Valid-  uint32_t current_;-  uint32_t restart_index_;  // Index of restart block in which current_ falls-  std::string key_;-  Slice value_;-  Status status_;--  inline int Compare(const Slice& a, const Slice& b) const {-    return comparator_->Compare(a, b);-  }--  // Return the offset in data_ just past the end of the current entry.-  inline uint32_t NextEntryOffset() const {-    return (value_.data() + value_.size()) - data_;-  }--  uint32_t GetRestartPoint(uint32_t index) {-    assert(index < num_restarts_);-    return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t));-  }--  void SeekToRestartPoint(uint32_t index) {-    key_.clear();-    restart_index_ = index;-    // current_ will be fixed by ParseNextKey();--    // ParseNextKey() starts at the end of value_, so set value_ accordingly-    uint32_t offset = GetRestartPoint(index);-    value_ = Slice(data_ + offset, 0);-  }-- public:-  Iter(const Comparator* comparator,-       const char* data,-       uint32_t restarts,-       uint32_t num_restarts)-      : comparator_(comparator),-        data_(data),-        restarts_(restarts),-        num_restarts_(num_restarts),-        current_(restarts_),-        restart_index_(num_restarts_) {-    assert(num_restarts_ > 0);-  }--  virtual bool Valid() const { return current_ < restarts_; }-  virtual Status status() const { return status_; }-  virtual Slice key() const {-    assert(Valid());-    return key_;-  }-  virtual Slice value() const {-    assert(Valid());-    return value_;-  }--  virtual void Next() {-    assert(Valid());-    ParseNextKey();-  }--  virtual void Prev() {-    assert(Valid());--    // Scan backwards to a restart point before current_-    const uint32_t original = current_;-    while (GetRestartPoint(restart_index_) >= original) {-      if (restart_index_ == 0) {-        // No more entries-        current_ = restarts_;-        restart_index_ = num_restarts_;-        return;-      }-      restart_index_--;-    }--    SeekToRestartPoint(restart_index_);-    do {-      // Loop until end of current entry hits the start of original entry-    } while (ParseNextKey() && NextEntryOffset() < original);-  }--  virtual void Seek(const Slice& target) {-    // Binary search in restart array to find the first restart point-    // with a key >= target-    uint32_t left = 0;-    uint32_t right = num_restarts_ - 1;-    while (left < right) {-      uint32_t mid = (left + right + 1) / 2;-      uint32_t region_offset = GetRestartPoint(mid);-      uint32_t shared, non_shared, value_length;-      const char* key_ptr = DecodeEntry(data_ + region_offset,-                                        data_ + restarts_,-                                        &shared, &non_shared, &value_length);-      if (key_ptr == NULL || (shared != 0)) {-        CorruptionError();-        return;-      }-      Slice mid_key(key_ptr, non_shared);-      if (Compare(mid_key, target) < 0) {-        // Key at "mid" is smaller than "target".  Therefore all-        // blocks before "mid" are uninteresting.-        left = mid;-      } else {-        // Key at "mid" is >= "target".  Therefore all blocks at or-        // after "mid" are uninteresting.-        right = mid - 1;-      }-    }--    // Linear search (within restart block) for first key >= target-    SeekToRestartPoint(left);-    while (true) {-      if (!ParseNextKey()) {-        return;-      }-      if (Compare(key_, target) >= 0) {-        return;-      }-    }-  }--  virtual void SeekToFirst() {-    SeekToRestartPoint(0);-    ParseNextKey();-  }--  virtual void SeekToLast() {-    SeekToRestartPoint(num_restarts_ - 1);-    while (ParseNextKey() && NextEntryOffset() < restarts_) {-      // Keep skipping-    }-  }-- private:-  void CorruptionError() {-    current_ = restarts_;-    restart_index_ = num_restarts_;-    status_ = Status::Corruption("bad entry in block");-    key_.clear();-    value_.clear();-  }--  bool ParseNextKey() {-    current_ = NextEntryOffset();-    const char* p = data_ + current_;-    const char* limit = data_ + restarts_;  // Restarts come right after data-    if (p >= limit) {-      // No more entries to return.  Mark as invalid.-      current_ = restarts_;-      restart_index_ = num_restarts_;-      return false;-    }--    // Decode next entry-    uint32_t shared, non_shared, value_length;-    p = DecodeEntry(p, limit, &shared, &non_shared, &value_length);-    if (p == NULL || key_.size() < shared) {-      CorruptionError();-      return false;-    } else {-      key_.resize(shared);-      key_.append(p, non_shared);-      value_ = Slice(p + non_shared, value_length);-      while (restart_index_ + 1 < num_restarts_ &&-             GetRestartPoint(restart_index_ + 1) < current_) {-        ++restart_index_;-      }-      return true;-    }-  }-};--Iterator* Block::NewIterator(const Comparator* cmp) {-  if (size_ < 2*sizeof(uint32_t)) {-    return NewErrorIterator(Status::Corruption("bad block contents"));-  }-  const uint32_t num_restarts = NumRestarts();-  if (num_restarts == 0) {-    return NewEmptyIterator();-  } else {-    return new Iter(cmp, data_, restart_offset_, num_restarts);-  }-}--}  // namespace leveldb
− cbits/leveldb/table/block.h
@@ -1,43 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_TABLE_BLOCK_H_-#define STORAGE_LEVELDB_TABLE_BLOCK_H_--#include <stddef.h>-#include <stdint.h>-#include "leveldb/iterator.h"--namespace leveldb {--class Comparator;--class Block {- public:-  // Initialize the block with the specified contents.-  // Takes ownership of data[] and will delete[] it when done.-  Block(const char* data, size_t size);--  ~Block();--  size_t size() const { return size_; }-  Iterator* NewIterator(const Comparator* comparator);-- private:-  uint32_t NumRestarts() const;--  const char* data_;-  size_t size_;-  uint32_t restart_offset_;     // Offset in data_ of restart array--  // No copying allowed-  Block(const Block&);-  void operator=(const Block&);--  class Iter;-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_TABLE_BLOCK_H_
− cbits/leveldb/table/block_builder.cc
@@ -1,109 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// BlockBuilder generates blocks where keys are prefix-compressed:-//-// When we store a key, we drop the prefix shared with the previous-// string.  This helps reduce the space requirement significantly.-// Furthermore, once every K keys, we do not apply the prefix-// compression and store the entire key.  We call this a "restart-// point".  The tail end of the block stores the offsets of all of the-// restart points, and can be used to do a binary search when looking-// for a particular key.  Values are stored as-is (without compression)-// immediately following the corresponding key.-//-// An entry for a particular key-value pair has the form:-//     shared_bytes: varint32-//     unshared_bytes: varint32-//     value_length: varint32-//     key_delta: char[unshared_bytes]-//     value: char[value_length]-// shared_bytes == 0 for restart points.-//-// The trailer of the block has the form:-//     restarts: uint32[num_restarts]-//     num_restarts: uint32-// restarts[i] contains the offset within the block of the ith restart point.--#include "table/block_builder.h"--#include <algorithm>-#include <assert.h>-#include "leveldb/comparator.h"-#include "leveldb/table_builder.h"-#include "util/coding.h"--namespace leveldb {--BlockBuilder::BlockBuilder(const Options* options)-    : options_(options),-      restarts_(),-      counter_(0),-      finished_(false) {-  assert(options->block_restart_interval >= 1);-  restarts_.push_back(0);       // First restart point is at offset 0-}--void BlockBuilder::Reset() {-  buffer_.clear();-  restarts_.clear();-  restarts_.push_back(0);       // First restart point is at offset 0-  counter_ = 0;-  finished_ = false;-  last_key_.clear();-}--size_t BlockBuilder::CurrentSizeEstimate() const {-  return (buffer_.size() +                        // Raw data buffer-          restarts_.size() * sizeof(uint32_t) +   // Restart array-          sizeof(uint32_t));                      // Restart array length-}--Slice BlockBuilder::Finish() {-  // Append restart array-  for (size_t i = 0; i < restarts_.size(); i++) {-    PutFixed32(&buffer_, restarts_[i]);-  }-  PutFixed32(&buffer_, restarts_.size());-  finished_ = true;-  return Slice(buffer_);-}--void BlockBuilder::Add(const Slice& key, const Slice& value) {-  Slice last_key_piece(last_key_);-  assert(!finished_);-  assert(counter_ <= options_->block_restart_interval);-  assert(buffer_.empty() // No values yet?-         || options_->comparator->Compare(key, last_key_piece) > 0);-  size_t shared = 0;-  if (counter_ < options_->block_restart_interval) {-    // See how much sharing to do with previous string-    const size_t min_length = std::min(last_key_piece.size(), key.size());-    while ((shared < min_length) && (last_key_piece[shared] == key[shared])) {-      shared++;-    }-  } else {-    // Restart compression-    restarts_.push_back(buffer_.size());-    counter_ = 0;-  }-  const size_t non_shared = key.size() - shared;--  // Add "<shared><non_shared><value_size>" to buffer_-  PutVarint32(&buffer_, shared);-  PutVarint32(&buffer_, non_shared);-  PutVarint32(&buffer_, value.size());--  // Add string delta to buffer_ followed by value-  buffer_.append(key.data() + shared, non_shared);-  buffer_.append(value.data(), value.size());--  // Update state-  last_key_.resize(shared);-  last_key_.append(key.data() + shared, non_shared);-  assert(Slice(last_key_) == key);-  counter_++;-}--}  // namespace leveldb
− cbits/leveldb/table/block_builder.h
@@ -1,57 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_-#define STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_--#include <vector>--#include <stdint.h>-#include "leveldb/slice.h"--namespace leveldb {--struct Options;--class BlockBuilder {- public:-  explicit BlockBuilder(const Options* options);--  // Reset the contents as if the BlockBuilder was just constructed.-  void Reset();--  // REQUIRES: Finish() has not been callled since the last call to Reset().-  // REQUIRES: key is larger than any previously added key-  void Add(const Slice& key, const Slice& value);--  // Finish building the block and return a slice that refers to the-  // block contents.  The returned slice will remain valid for the-  // lifetime of this builder or until Reset() is called.-  Slice Finish();--  // Returns an estimate of the current (uncompressed) size of the block-  // we are building.-  size_t CurrentSizeEstimate() const;--  // Return true iff no entries have been added since the last Reset()-  bool empty() const {-    return buffer_.empty();-  }-- private:-  const Options*        options_;-  std::string           buffer_;      // Destination buffer-  std::vector<uint32_t> restarts_;    // Restart points-  int                   counter_;     // Number of entries emitted since restart-  bool                  finished_;    // Has Finish() been called?-  std::string           last_key_;--  // No copying allowed-  BlockBuilder(const BlockBuilder&);-  void operator=(const BlockBuilder&);-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_TABLE_BLOCK_BUILDER_H_
− cbits/leveldb/table/format.cc
@@ -1,135 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "table/format.h"--#include "leveldb/env.h"-#include "port/port.h"-#include "table/block.h"-#include "util/coding.h"-#include "util/crc32c.h"--namespace leveldb {--void BlockHandle::EncodeTo(std::string* dst) const {-  // Sanity check that all fields have been set-  assert(offset_ != ~static_cast<uint64_t>(0));-  assert(size_ != ~static_cast<uint64_t>(0));-  PutVarint64(dst, offset_);-  PutVarint64(dst, size_);-}--Status BlockHandle::DecodeFrom(Slice* input) {-  if (GetVarint64(input, &offset_) &&-      GetVarint64(input, &size_)) {-    return Status::OK();-  } else {-    return Status::Corruption("bad block handle");-  }-}--void Footer::EncodeTo(std::string* dst) const {-#ifndef NDEBUG-  const size_t original_size = dst->size();-#endif-  metaindex_handle_.EncodeTo(dst);-  index_handle_.EncodeTo(dst);-  dst->resize(2 * BlockHandle::kMaxEncodedLength);  // Padding-  PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber & 0xffffffffu));-  PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber >> 32));-  assert(dst->size() == original_size + kEncodedLength);-}--Status Footer::DecodeFrom(Slice* input) {-  const char* magic_ptr = input->data() + kEncodedLength - 8;-  const uint32_t magic_lo = DecodeFixed32(magic_ptr);-  const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4);-  const uint64_t magic = ((static_cast<uint64_t>(magic_hi) << 32) |-                          (static_cast<uint64_t>(magic_lo)));-  if (magic != kTableMagicNumber) {-    return Status::InvalidArgument("not an sstable (bad magic number)");-  }--  Status result = metaindex_handle_.DecodeFrom(input);-  if (result.ok()) {-    result = index_handle_.DecodeFrom(input);-  }-  if (result.ok()) {-    // We skip over any leftover data (just padding for now) in "input"-    const char* end = magic_ptr + 8;-    *input = Slice(end, input->data() + input->size() - end);-  }-  return result;-}--Status ReadBlock(RandomAccessFile* file,-                 const ReadOptions& options,-                 const BlockHandle& handle,-                 Block** block) {-  *block = NULL;--  // Read the block contents as well as the type/crc footer.-  // See table_builder.cc for the code that built this structure.-  size_t n = static_cast<size_t>(handle.size());-  char* buf = new char[n + kBlockTrailerSize];-  Slice contents;-  Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf);-  if (!s.ok()) {-    delete[] buf;-    return s;-  }-  if (contents.size() != n + kBlockTrailerSize) {-    delete[] buf;-    return Status::Corruption("truncated block read");-  }--  // Check the crc of the type and the block contents-  const char* data = contents.data();    // Pointer to where Read put the data-  if (options.verify_checksums) {-    const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1));-    const uint32_t actual = crc32c::Value(data, n + 1);-    if (actual != crc) {-      delete[] buf;-      s = Status::Corruption("block checksum mismatch");-      return s;-    }-  }--  switch (data[n]) {-    case kNoCompression:-      if (data != buf) {-        // File implementation gave us pointer to some other data.-        // Copy into buf[].-        memcpy(buf, data, n + kBlockTrailerSize);-      }--      // Ok-      break;-    case kSnappyCompression: {-      size_t ulength = 0;-      if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) {-        delete[] buf;-        return Status::Corruption("corrupted compressed block contents");-      }-      char* ubuf = new char[ulength];-      if (!port::Snappy_Uncompress(data, n, ubuf)) {-        delete[] buf;-        delete[] ubuf;-        return Status::Corruption("corrupted compressed block contents");-      }-      delete[] buf;-      buf = ubuf;-      n = ulength;-      break;-    }-    default:-      delete[] buf;-      return Status::Corruption("bad block type");-  }--  *block = new Block(buf, n);  // Block takes ownership of buf[]-  return Status::OK();-}--}  // namespace leveldb
− cbits/leveldb/table/format.h
@@ -1,103 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_TABLE_FORMAT_H_-#define STORAGE_LEVELDB_TABLE_FORMAT_H_--#include <string>-#include <stdint.h>-#include "leveldb/slice.h"-#include "leveldb/status.h"-#include "leveldb/table_builder.h"--namespace leveldb {--class Block;-class RandomAccessFile;-struct ReadOptions;--// BlockHandle is a pointer to the extent of a file that stores a data-// block or a meta block.-class BlockHandle {- public:-  BlockHandle();--  // The offset of the block in the file.-  uint64_t offset() const { return offset_; }-  void set_offset(uint64_t offset) { offset_ = offset; }--  // The size of the stored block-  uint64_t size() const { return size_; }-  void set_size(uint64_t size) { size_ = size; }--  void EncodeTo(std::string* dst) const;-  Status DecodeFrom(Slice* input);--  // Maximum encoding length of a BlockHandle-  enum { kMaxEncodedLength = 10 + 10 };-- private:-  uint64_t offset_;-  uint64_t size_;-};--// Footer encapsulates the fixed information stored at the tail-// end of every table file.-class Footer {- public:-  Footer() { }--  // The block handle for the metaindex block of the table-  const BlockHandle& metaindex_handle() const { return metaindex_handle_; }-  void set_metaindex_handle(const BlockHandle& h) { metaindex_handle_ = h; }--  // The block handle for the index block of the table-  const BlockHandle& index_handle() const {-    return index_handle_;-  }-  void set_index_handle(const BlockHandle& h) {-    index_handle_ = h;-  }--  void EncodeTo(std::string* dst) const;-  Status DecodeFrom(Slice* input);--  // Encoded length of a Footer.  Note that the serialization of a-  // Footer will always occupy exactly this many bytes.  It consists-  // of two block handles and a magic number.-  enum {-    kEncodedLength = 2*BlockHandle::kMaxEncodedLength + 8-  };-- private:-  BlockHandle metaindex_handle_;-  BlockHandle index_handle_;-};--// kTableMagicNumber was picked by running-//    echo http://code.google.com/p/leveldb/ | sha1sum-// and taking the leading 64 bits.-static const uint64_t kTableMagicNumber = 0xdb4775248b80fb57ull;--// 1-byte type + 32-bit crc-static const size_t kBlockTrailerSize = 5;--// Read the block identified by "handle" from "file".  On success,-// store a pointer to the heap-allocated result in *block and return-// OK.  On failure store NULL in *block and return non-OK.-extern Status ReadBlock(RandomAccessFile* file,-                        const ReadOptions& options,-                        const BlockHandle& handle,-                        Block** block);--// Implementation details follow.  Clients should ignore,--inline BlockHandle::BlockHandle()-    : offset_(~static_cast<uint64_t>(0)),-      size_(~static_cast<uint64_t>(0)) {-}--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_TABLE_FORMAT_H_
− cbits/leveldb/table/iterator.cc
@@ -1,67 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "leveldb/iterator.h"--namespace leveldb {--Iterator::Iterator() {-  cleanup_.function = NULL;-  cleanup_.next = NULL;-}--Iterator::~Iterator() {-  if (cleanup_.function != NULL) {-    (*cleanup_.function)(cleanup_.arg1, cleanup_.arg2);-    for (Cleanup* c = cleanup_.next; c != NULL; ) {-      (*c->function)(c->arg1, c->arg2);-      Cleanup* next = c->next;-      delete c;-      c = next;-    }-  }-}--void Iterator::RegisterCleanup(CleanupFunction func, void* arg1, void* arg2) {-  assert(func != NULL);-  Cleanup* c;-  if (cleanup_.function == NULL) {-    c = &cleanup_;-  } else {-    c = new Cleanup;-    c->next = cleanup_.next;-    cleanup_.next = c;-  }-  c->function = func;-  c->arg1 = arg1;-  c->arg2 = arg2;-}--namespace {-class EmptyIterator : public Iterator {- public:-  EmptyIterator(const Status& s) : status_(s) { }-  virtual bool Valid() const { return false; }-  virtual void Seek(const Slice& target) { }-  virtual void SeekToFirst() { }-  virtual void SeekToLast() { }-  virtual void Next() { assert(false); }-  virtual void Prev() { assert(false); }-  Slice key() const { assert(false); return Slice(); }-  Slice value() const { assert(false); return Slice(); }-  virtual Status status() const { return status_; }- private:-  Status status_;-};-}  // namespace--Iterator* NewEmptyIterator() {-  return new EmptyIterator(Status::OK());-}--Iterator* NewErrorIterator(const Status& status) {-  return new EmptyIterator(status);-}--}  // namespace leveldb
− cbits/leveldb/table/iterator_wrapper.h
@@ -1,63 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_-#define STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_--namespace leveldb {--// A internal wrapper class with an interface similar to Iterator that-// caches the valid() and key() results for an underlying iterator.-// This can help avoid virtual function calls and also gives better-// cache locality.-class IteratorWrapper {- public:-  IteratorWrapper(): iter_(NULL), valid_(false) { }-  explicit IteratorWrapper(Iterator* iter): iter_(NULL) {-    Set(iter);-  }-  ~IteratorWrapper() { delete iter_; }-  Iterator* iter() const { return iter_; }--  // Takes ownership of "iter" and will delete it when destroyed, or-  // when Set() is invoked again.-  void Set(Iterator* iter) {-    delete iter_;-    iter_ = iter;-    if (iter_ == NULL) {-      valid_ = false;-    } else {-      Update();-    }-  }---  // Iterator interface methods-  bool Valid() const        { return valid_; }-  Slice key() const         { assert(Valid()); return key_; }-  Slice value() const       { assert(Valid()); return iter_->value(); }-  // Methods below require iter() != NULL-  Status status() const     { assert(iter_); return iter_->status(); }-  void Next()               { assert(iter_); iter_->Next();        Update(); }-  void Prev()               { assert(iter_); iter_->Prev();        Update(); }-  void Seek(const Slice& k) { assert(iter_); iter_->Seek(k);       Update(); }-  void SeekToFirst()        { assert(iter_); iter_->SeekToFirst(); Update(); }-  void SeekToLast()         { assert(iter_); iter_->SeekToLast();  Update(); }-- private:-  void Update() {-    valid_ = iter_->Valid();-    if (valid_) {-      key_ = iter_->key();-    }-  }--  Iterator* iter_;-  bool valid_;-  Slice key_;-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_TABLE_ITERATOR_WRAPPER_H_
− cbits/leveldb/table/merger.cc
@@ -1,197 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "table/merger.h"--#include "leveldb/comparator.h"-#include "leveldb/iterator.h"-#include "table/iterator_wrapper.h"--namespace leveldb {--namespace {-class MergingIterator : public Iterator {- public:-  MergingIterator(const Comparator* comparator, Iterator** children, int n)-      : comparator_(comparator),-        children_(new IteratorWrapper[n]),-        n_(n),-        current_(NULL),-        direction_(kForward) {-    for (int i = 0; i < n; i++) {-      children_[i].Set(children[i]);-    }-  }--  virtual ~MergingIterator() {-    delete[] children_;-  }--  virtual bool Valid() const {-    return (current_ != NULL);-  }--  virtual void SeekToFirst() {-    for (int i = 0; i < n_; i++) {-      children_[i].SeekToFirst();-    }-    FindSmallest();-    direction_ = kForward;-  }--  virtual void SeekToLast() {-    for (int i = 0; i < n_; i++) {-      children_[i].SeekToLast();-    }-    FindLargest();-    direction_ = kReverse;-  }--  virtual void Seek(const Slice& target) {-    for (int i = 0; i < n_; i++) {-      children_[i].Seek(target);-    }-    FindSmallest();-    direction_ = kForward;-  }--  virtual void Next() {-    assert(Valid());--    // Ensure that all children are positioned after key().-    // If we are moving in the forward direction, it is already-    // true for all of the non-current_ children since current_ is-    // the smallest child and key() == current_->key().  Otherwise,-    // we explicitly position the non-current_ children.-    if (direction_ != kForward) {-      for (int i = 0; i < n_; i++) {-        IteratorWrapper* child = &children_[i];-        if (child != current_) {-          child->Seek(key());-          if (child->Valid() &&-              comparator_->Compare(key(), child->key()) == 0) {-            child->Next();-          }-        }-      }-      direction_ = kForward;-    }--    current_->Next();-    FindSmallest();-  }--  virtual void Prev() {-    assert(Valid());--    // Ensure that all children are positioned before key().-    // If we are moving in the reverse direction, it is already-    // true for all of the non-current_ children since current_ is-    // the largest child and key() == current_->key().  Otherwise,-    // we explicitly position the non-current_ children.-    if (direction_ != kReverse) {-      for (int i = 0; i < n_; i++) {-        IteratorWrapper* child = &children_[i];-        if (child != current_) {-          child->Seek(key());-          if (child->Valid()) {-            // Child is at first entry >= key().  Step back one to be < key()-            child->Prev();-          } else {-            // Child has no entries >= key().  Position at last entry.-            child->SeekToLast();-          }-        }-      }-      direction_ = kReverse;-    }--    current_->Prev();-    FindLargest();-  }--  virtual Slice key() const {-    assert(Valid());-    return current_->key();-  }--  virtual Slice value() const {-    assert(Valid());-    return current_->value();-  }--  virtual Status status() const {-    Status status;-    for (int i = 0; i < n_; i++) {-      status = children_[i].status();-      if (!status.ok()) {-        break;-      }-    }-    return status;-  }-- private:-  void FindSmallest();-  void FindLargest();--  // We might want to use a heap in case there are lots of children.-  // For now we use a simple array since we expect a very small number-  // of children in leveldb.-  const Comparator* comparator_;-  IteratorWrapper* children_;-  int n_;-  IteratorWrapper* current_;--  // Which direction is the iterator moving?-  enum Direction {-    kForward,-    kReverse-  };-  Direction direction_;-};--void MergingIterator::FindSmallest() {-  IteratorWrapper* smallest = NULL;-  for (int i = 0; i < n_; i++) {-    IteratorWrapper* child = &children_[i];-    if (child->Valid()) {-      if (smallest == NULL) {-        smallest = child;-      } else if (comparator_->Compare(child->key(), smallest->key()) < 0) {-        smallest = child;-      }-    }-  }-  current_ = smallest;-}--void MergingIterator::FindLargest() {-  IteratorWrapper* largest = NULL;-  for (int i = n_-1; i >= 0; i--) {-    IteratorWrapper* child = &children_[i];-    if (child->Valid()) {-      if (largest == NULL) {-        largest = child;-      } else if (comparator_->Compare(child->key(), largest->key()) > 0) {-        largest = child;-      }-    }-  }-  current_ = largest;-}-}  // namespace--Iterator* NewMergingIterator(const Comparator* cmp, Iterator** list, int n) {-  assert(n >= 0);-  if (n == 0) {-    return NewEmptyIterator();-  } else if (n == 1) {-    return list[0];-  } else {-    return new MergingIterator(cmp, list, n);-  }-}--}  // namespace leveldb
− cbits/leveldb/table/merger.h
@@ -1,26 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_TABLE_MERGER_H_-#define STORAGE_LEVELDB_TABLE_MERGER_H_--namespace leveldb {--class Comparator;-class Iterator;--// Return an iterator that provided the union of the data in-// children[0,n-1].  Takes ownership of the child iterators and-// will delete them when the result iterator is deleted.-//-// The result does no duplicate suppression.  I.e., if a particular-// key is present in K child iterators, it will be yielded K times.-//-// REQUIRES: n >= 0-extern Iterator* NewMergingIterator(-    const Comparator* comparator, Iterator** children, int n);--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_TABLE_MERGER_H_
− cbits/leveldb/table/table.cc
@@ -1,175 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "leveldb/table.h"--#include "leveldb/cache.h"-#include "leveldb/env.h"-#include "table/block.h"-#include "table/format.h"-#include "table/two_level_iterator.h"-#include "util/coding.h"--namespace leveldb {--struct Table::Rep {-  ~Rep() {-    delete index_block;-  }--  Options options;-  Status status;-  RandomAccessFile* file;-  uint64_t cache_id;--  BlockHandle metaindex_handle;  // Handle to metaindex_block: saved from footer-  Block* index_block;-};--Status Table::Open(const Options& options,-                   RandomAccessFile* file,-                   uint64_t size,-                   Table** table) {-  *table = NULL;-  if (size < Footer::kEncodedLength) {-    return Status::InvalidArgument("file is too short to be an sstable");-  }--  char footer_space[Footer::kEncodedLength];-  Slice footer_input;-  Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength,-                        &footer_input, footer_space);-  if (!s.ok()) return s;--  Footer footer;-  s = footer.DecodeFrom(&footer_input);-  if (!s.ok()) return s;--  // Read the index block-  Block* index_block = NULL;-  if (s.ok()) {-    s = ReadBlock(file, ReadOptions(), footer.index_handle(), &index_block);-  }--  if (s.ok()) {-    // We've successfully read the footer and the index block: we're-    // ready to serve requests.-    Rep* rep = new Table::Rep;-    rep->options = options;-    rep->file = file;-    rep->metaindex_handle = footer.metaindex_handle();-    rep->index_block = index_block;-    rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0);-    *table = new Table(rep);-  } else {-    if (index_block) delete index_block;-  }--  return s;-}--Table::~Table() {-  delete rep_;-}--static void DeleteBlock(void* arg, void* ignored) {-  delete reinterpret_cast<Block*>(arg);-}--static void DeleteCachedBlock(const Slice& key, void* value) {-  Block* block = reinterpret_cast<Block*>(value);-  delete block;-}--static void ReleaseBlock(void* arg, void* h) {-  Cache* cache = reinterpret_cast<Cache*>(arg);-  Cache::Handle* handle = reinterpret_cast<Cache::Handle*>(h);-  cache->Release(handle);-}--// Convert an index iterator value (i.e., an encoded BlockHandle)-// into an iterator over the contents of the corresponding block.-Iterator* Table::BlockReader(void* arg,-                             const ReadOptions& options,-                             const Slice& index_value) {-  Table* table = reinterpret_cast<Table*>(arg);-  Cache* block_cache = table->rep_->options.block_cache;-  Block* block = NULL;-  Cache::Handle* cache_handle = NULL;--  BlockHandle handle;-  Slice input = index_value;-  Status s = handle.DecodeFrom(&input);-  // We intentionally allow extra stuff in index_value so that we-  // can add more features in the future.--  if (s.ok()) {-    if (block_cache != NULL) {-      char cache_key_buffer[16];-      EncodeFixed64(cache_key_buffer, table->rep_->cache_id);-      EncodeFixed64(cache_key_buffer+8, handle.offset());-      Slice key(cache_key_buffer, sizeof(cache_key_buffer));-      cache_handle = block_cache->Lookup(key);-      if (cache_handle != NULL) {-        block = reinterpret_cast<Block*>(block_cache->Value(cache_handle));-      } else {-        s = ReadBlock(table->rep_->file, options, handle, &block);-        if (s.ok() && options.fill_cache) {-          cache_handle = block_cache->Insert(-              key, block, block->size(), &DeleteCachedBlock);-        }-      }-    } else {-      s = ReadBlock(table->rep_->file, options, handle, &block);-    }-  }--  Iterator* iter;-  if (block != NULL) {-    iter = block->NewIterator(table->rep_->options.comparator);-    if (cache_handle == NULL) {-      iter->RegisterCleanup(&DeleteBlock, block, NULL);-    } else {-      iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle);-    }-  } else {-    iter = NewErrorIterator(s);-  }-  return iter;-}--Iterator* Table::NewIterator(const ReadOptions& options) const {-  return NewTwoLevelIterator(-      rep_->index_block->NewIterator(rep_->options.comparator),-      &Table::BlockReader, const_cast<Table*>(this), options);-}--uint64_t Table::ApproximateOffsetOf(const Slice& key) const {-  Iterator* index_iter =-      rep_->index_block->NewIterator(rep_->options.comparator);-  index_iter->Seek(key);-  uint64_t result;-  if (index_iter->Valid()) {-    BlockHandle handle;-    Slice input = index_iter->value();-    Status s = handle.DecodeFrom(&input);-    if (s.ok()) {-      result = handle.offset();-    } else {-      // Strange: we can't decode the block handle in the index block.-      // We'll just return the offset of the metaindex block, which is-      // close to the whole file size for this case.-      result = rep_->metaindex_handle.offset();-    }-  } else {-    // key is past the last key in the file.  Approximate the offset-    // by returning the offset of the metaindex block (which is-    // right near the end of the file).-    result = rep_->metaindex_handle.offset();-  }-  delete index_iter;-  return result;-}--}  // namespace leveldb
− cbits/leveldb/table/table_builder.cc
@@ -1,227 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "leveldb/table_builder.h"--#include <assert.h>-#include <stdio.h>-#include "leveldb/comparator.h"-#include "leveldb/env.h"-#include "table/block_builder.h"-#include "table/format.h"-#include "util/coding.h"-#include "util/crc32c.h"-#include "util/logging.h"--namespace leveldb {--struct TableBuilder::Rep {-  Options options;-  Options index_block_options;-  WritableFile* file;-  uint64_t offset;-  Status status;-  BlockBuilder data_block;-  BlockBuilder index_block;-  std::string last_key;-  int64_t num_entries;-  bool closed;          // Either Finish() or Abandon() has been called.--  // We do not emit the index entry for a block until we have seen the-  // first key for the next data block.  This allows us to use shorter-  // keys in the index block.  For example, consider a block boundary-  // between the keys "the quick brown fox" and "the who".  We can use-  // "the r" as the key for the index block entry since it is >= all-  // entries in the first block and < all entries in subsequent-  // blocks.-  //-  // Invariant: r->pending_index_entry is true only if data_block is empty.-  bool pending_index_entry;-  BlockHandle pending_handle;  // Handle to add to index block--  std::string compressed_output;--  Rep(const Options& opt, WritableFile* f)-      : options(opt),-        index_block_options(opt),-        file(f),-        offset(0),-        data_block(&options),-        index_block(&index_block_options),-        num_entries(0),-        closed(false),-        pending_index_entry(false) {-    index_block_options.block_restart_interval = 1;-  }-};--TableBuilder::TableBuilder(const Options& options, WritableFile* file)-    : rep_(new Rep(options, file)) {-}--TableBuilder::~TableBuilder() {-  assert(rep_->closed);  // Catch errors where caller forgot to call Finish()-  delete rep_;-}--Status TableBuilder::ChangeOptions(const Options& options) {-  // Note: if more fields are added to Options, update-  // this function to catch changes that should not be allowed to-  // change in the middle of building a Table.-  if (options.comparator != rep_->options.comparator) {-    return Status::InvalidArgument("changing comparator while building table");-  }--  // Note that any live BlockBuilders point to rep_->options and therefore-  // will automatically pick up the updated options.-  rep_->options = options;-  rep_->index_block_options = options;-  rep_->index_block_options.block_restart_interval = 1;-  return Status::OK();-}--void TableBuilder::Add(const Slice& key, const Slice& value) {-  Rep* r = rep_;-  assert(!r->closed);-  if (!ok()) return;-  if (r->num_entries > 0) {-    assert(r->options.comparator->Compare(key, Slice(r->last_key)) > 0);-  }--  if (r->pending_index_entry) {-    assert(r->data_block.empty());-    r->options.comparator->FindShortestSeparator(&r->last_key, key);-    std::string handle_encoding;-    r->pending_handle.EncodeTo(&handle_encoding);-    r->index_block.Add(r->last_key, Slice(handle_encoding));-    r->pending_index_entry = false;-  }--  r->last_key.assign(key.data(), key.size());-  r->num_entries++;-  r->data_block.Add(key, value);--  const size_t estimated_block_size = r->data_block.CurrentSizeEstimate();-  if (estimated_block_size >= r->options.block_size) {-    Flush();-  }-}--void TableBuilder::Flush() {-  Rep* r = rep_;-  assert(!r->closed);-  if (!ok()) return;-  if (r->data_block.empty()) return;-  assert(!r->pending_index_entry);-  WriteBlock(&r->data_block, &r->pending_handle);-  if (ok()) {-    r->pending_index_entry = true;-    r->status = r->file->Flush();-  }-}--void TableBuilder::WriteBlock(BlockBuilder* block, BlockHandle* handle) {-  // File format contains a sequence of blocks where each block has:-  //    block_data: uint8[n]-  //    type: uint8-  //    crc: uint32-  assert(ok());-  Rep* r = rep_;-  Slice raw = block->Finish();--  Slice block_contents;-  CompressionType type = r->options.compression;-  // TODO(postrelease): Support more compression options: zlib?-  switch (type) {-    case kNoCompression:-      block_contents = raw;-      break;--    case kSnappyCompression: {-      std::string* compressed = &r->compressed_output;-      if (port::Snappy_Compress(raw.data(), raw.size(), compressed) &&-          compressed->size() < raw.size() - (raw.size() / 8u)) {-        block_contents = *compressed;-      } else {-        // Snappy not supported, or compressed less than 12.5%, so just-        // store uncompressed form-        block_contents = raw;-        type = kNoCompression;-      }-      break;-    }-  }-  handle->set_offset(r->offset);-  handle->set_size(block_contents.size());-  r->status = r->file->Append(block_contents);-  if (r->status.ok()) {-    char trailer[kBlockTrailerSize];-    trailer[0] = type;-    uint32_t crc = crc32c::Value(block_contents.data(), block_contents.size());-    crc = crc32c::Extend(crc, trailer, 1);  // Extend crc to cover block type-    EncodeFixed32(trailer+1, crc32c::Mask(crc));-    r->status = r->file->Append(Slice(trailer, kBlockTrailerSize));-    if (r->status.ok()) {-      r->offset += block_contents.size() + kBlockTrailerSize;-    }-  }-  r->compressed_output.clear();-  block->Reset();-}--Status TableBuilder::status() const {-  return rep_->status;-}--Status TableBuilder::Finish() {-  Rep* r = rep_;-  Flush();-  assert(!r->closed);-  r->closed = true;-  BlockHandle metaindex_block_handle;-  BlockHandle index_block_handle;-  if (ok()) {-    BlockBuilder meta_index_block(&r->options);-    // TODO(postrelease): Add stats and other meta blocks-    WriteBlock(&meta_index_block, &metaindex_block_handle);-  }-  if (ok()) {-    if (r->pending_index_entry) {-      r->options.comparator->FindShortSuccessor(&r->last_key);-      std::string handle_encoding;-      r->pending_handle.EncodeTo(&handle_encoding);-      r->index_block.Add(r->last_key, Slice(handle_encoding));-      r->pending_index_entry = false;-    }-    WriteBlock(&r->index_block, &index_block_handle);-  }-  if (ok()) {-    Footer footer;-    footer.set_metaindex_handle(metaindex_block_handle);-    footer.set_index_handle(index_block_handle);-    std::string footer_encoding;-    footer.EncodeTo(&footer_encoding);-    r->status = r->file->Append(footer_encoding);-    if (r->status.ok()) {-      r->offset += footer_encoding.size();-    }-  }-  return r->status;-}--void TableBuilder::Abandon() {-  Rep* r = rep_;-  assert(!r->closed);-  r->closed = true;-}--uint64_t TableBuilder::NumEntries() const {-  return rep_->num_entries;-}--uint64_t TableBuilder::FileSize() const {-  return rep_->offset;-}--}  // namespace leveldb
− cbits/leveldb/table/table_test.cc
@@ -1,854 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "leveldb/table.h"--#include <map>-#include <string>-#include "db/dbformat.h"-#include "db/memtable.h"-#include "db/write_batch_internal.h"-#include "leveldb/db.h"-#include "leveldb/env.h"-#include "leveldb/iterator.h"-#include "leveldb/table_builder.h"-#include "table/block.h"-#include "table/block_builder.h"-#include "table/format.h"-#include "util/random.h"-#include "util/testharness.h"-#include "util/testutil.h"--namespace leveldb {--// Return reverse of "key".-// Used to test non-lexicographic comparators.-static std::string Reverse(const Slice& key) {-  std::string str(key.ToString());-  std::string rev("");-  for (std::string::reverse_iterator rit = str.rbegin();-       rit != str.rend(); ++rit) {-    rev.push_back(*rit);-  }-  return rev;-}--namespace {-class ReverseKeyComparator : public Comparator {- public:-  virtual const char* Name() const {-    return "leveldb.ReverseBytewiseComparator";-  }--  virtual int Compare(const Slice& a, const Slice& b) const {-    return BytewiseComparator()->Compare(Reverse(a), Reverse(b));-  }--  virtual void FindShortestSeparator(-      std::string* start,-      const Slice& limit) const {-    std::string s = Reverse(*start);-    std::string l = Reverse(limit);-    BytewiseComparator()->FindShortestSeparator(&s, l);-    *start = Reverse(s);-  }--  virtual void FindShortSuccessor(std::string* key) const {-    std::string s = Reverse(*key);-    BytewiseComparator()->FindShortSuccessor(&s);-    *key = Reverse(s);-  }-};-}  // namespace-static ReverseKeyComparator reverse_key_comparator;--static void Increment(const Comparator* cmp, std::string* key) {-  if (cmp == BytewiseComparator()) {-    key->push_back('\0');-  } else {-    assert(cmp == &reverse_key_comparator);-    std::string rev = Reverse(*key);-    rev.push_back('\0');-    *key = Reverse(rev);-  }-}--// An STL comparator that uses a Comparator-namespace {-struct STLLessThan {-  const Comparator* cmp;--  STLLessThan() : cmp(BytewiseComparator()) { }-  STLLessThan(const Comparator* c) : cmp(c) { }-  bool operator()(const std::string& a, const std::string& b) const {-    return cmp->Compare(Slice(a), Slice(b)) < 0;-  }-};-}  // namespace--class StringSink: public WritableFile {- public:-  ~StringSink() { }--  const std::string& contents() const { return contents_; }--  virtual Status Close() { return Status::OK(); }-  virtual Status Flush() { return Status::OK(); }-  virtual Status Sync() { return Status::OK(); }--  virtual Status Append(const Slice& data) {-    contents_.append(data.data(), data.size());-    return Status::OK();-  }-- private:-  std::string contents_;-};---class StringSource: public RandomAccessFile {- public:-  StringSource(const Slice& contents)-      : contents_(contents.data(), contents.size()) {-  }--  virtual ~StringSource() { }--  uint64_t Size() const { return contents_.size(); }--  virtual Status Read(uint64_t offset, size_t n, Slice* result,-                       char* scratch) const {-    if (offset > contents_.size()) {-      return Status::InvalidArgument("invalid Read offset");-    }-    if (offset + n > contents_.size()) {-      n = contents_.size() - offset;-    }-    memcpy(scratch, &contents_[offset], n);-    *result = Slice(scratch, n);-    return Status::OK();-  }-- private:-  std::string contents_;-};--typedef std::map<std::string, std::string, STLLessThan> KVMap;--// Helper class for tests to unify the interface between-// BlockBuilder/TableBuilder and Block/Table.-class Constructor {- public:-  explicit Constructor(const Comparator* cmp) : data_(STLLessThan(cmp)) { }-  virtual ~Constructor() { }--  void Add(const std::string& key, const Slice& value) {-    data_[key] = value.ToString();-  }--  // Finish constructing the data structure with all the keys that have-  // been added so far.  Returns the keys in sorted order in "*keys"-  // and stores the key/value pairs in "*kvmap"-  void Finish(const Options& options,-              std::vector<std::string>* keys,-              KVMap* kvmap) {-    *kvmap = data_;-    keys->clear();-    for (KVMap::const_iterator it = data_.begin();-         it != data_.end();-         ++it) {-      keys->push_back(it->first);-    }-    data_.clear();-    Status s = FinishImpl(options, *kvmap);-    ASSERT_TRUE(s.ok()) << s.ToString();-  }--  // Construct the data structure from the data in "data"-  virtual Status FinishImpl(const Options& options, const KVMap& data) = 0;--  virtual size_t NumBytes() const = 0;--  virtual Iterator* NewIterator() const = 0;--  virtual const KVMap& data() { return data_; }--  virtual DB* db() const { return NULL; }  // Overridden in DBConstructor-- private:-  KVMap data_;-};--class BlockConstructor: public Constructor {- public:-  explicit BlockConstructor(const Comparator* cmp)-      : Constructor(cmp),-        comparator_(cmp),-        block_size_(-1),-        block_(NULL) { }-  ~BlockConstructor() {-    delete block_;-  }-  virtual Status FinishImpl(const Options& options, const KVMap& data) {-    delete block_;-    block_ = NULL;-    BlockBuilder builder(&options);--    for (KVMap::const_iterator it = data.begin();-         it != data.end();-         ++it) {-      builder.Add(it->first, it->second);-    }-    // Open the block-    Slice block_data = builder.Finish();-    block_size_ = block_data.size();-    char* block_data_copy = new char[block_size_];-    memcpy(block_data_copy, block_data.data(), block_size_);-    block_ = new Block(block_data_copy, block_size_);-    return Status::OK();-  }-  virtual size_t NumBytes() const { return block_size_; }--  virtual Iterator* NewIterator() const {-    return block_->NewIterator(comparator_);-  }-- private:-  const Comparator* comparator_;-  int block_size_;-  Block* block_;--  BlockConstructor();-};--class TableConstructor: public Constructor {- public:-  TableConstructor(const Comparator* cmp)-      : Constructor(cmp),-        source_(NULL), table_(NULL) {-  }-  ~TableConstructor() {-    Reset();-  }-  virtual Status FinishImpl(const Options& options, const KVMap& data) {-    Reset();-    StringSink sink;-    TableBuilder builder(options, &sink);--    for (KVMap::const_iterator it = data.begin();-         it != data.end();-         ++it) {-      builder.Add(it->first, it->second);-      ASSERT_TRUE(builder.status().ok());-    }-    Status s = builder.Finish();-    ASSERT_TRUE(s.ok()) << s.ToString();--    ASSERT_EQ(sink.contents().size(), builder.FileSize());--    // Open the table-    source_ = new StringSource(sink.contents());-    Options table_options;-    table_options.comparator = options.comparator;-    return Table::Open(table_options, source_, sink.contents().size(), &table_);-  }-  virtual size_t NumBytes() const { return source_->Size(); }--  virtual Iterator* NewIterator() const {-    return table_->NewIterator(ReadOptions());-  }--  uint64_t ApproximateOffsetOf(const Slice& key) const {-    return table_->ApproximateOffsetOf(key);-  }-- private:-  void Reset() {-    delete table_;-    delete source_;-    table_ = NULL;-    source_ = NULL;-  }--  StringSource* source_;-  Table* table_;--  TableConstructor();-};--// A helper class that converts internal format keys into user keys-class KeyConvertingIterator: public Iterator {- public:-  explicit KeyConvertingIterator(Iterator* iter) : iter_(iter) { }-  virtual ~KeyConvertingIterator() { delete iter_; }-  virtual bool Valid() const { return iter_->Valid(); }-  virtual void Seek(const Slice& target) {-    ParsedInternalKey ikey(target, kMaxSequenceNumber, kTypeValue);-    std::string encoded;-    AppendInternalKey(&encoded, ikey);-    iter_->Seek(encoded);-  }-  virtual void SeekToFirst() { iter_->SeekToFirst(); }-  virtual void SeekToLast() { iter_->SeekToLast(); }-  virtual void Next() { iter_->Next(); }-  virtual void Prev() { iter_->Prev(); }--  virtual Slice key() const {-    assert(Valid());-    ParsedInternalKey key;-    if (!ParseInternalKey(iter_->key(), &key)) {-      status_ = Status::Corruption("malformed internal key");-      return Slice("corrupted key");-    }-    return key.user_key;-  }--  virtual Slice value() const { return iter_->value(); }-  virtual Status status() const {-    return status_.ok() ? iter_->status() : status_;-  }-- private:-  mutable Status status_;-  Iterator* iter_;--  // No copying allowed-  KeyConvertingIterator(const KeyConvertingIterator&);-  void operator=(const KeyConvertingIterator&);-};--class MemTableConstructor: public Constructor {- public:-  explicit MemTableConstructor(const Comparator* cmp)-      : Constructor(cmp),-        internal_comparator_(cmp) {-    memtable_ = new MemTable(internal_comparator_);-    memtable_->Ref();-  }-  ~MemTableConstructor() {-    memtable_->Unref();-  }-  virtual Status FinishImpl(const Options& options, const KVMap& data) {-    memtable_->Unref();-    memtable_ = new MemTable(internal_comparator_);-    memtable_->Ref();-    int seq = 1;-    for (KVMap::const_iterator it = data.begin();-         it != data.end();-         ++it) {-      memtable_->Add(seq, kTypeValue, it->first, it->second);-      seq++;-    }-    return Status::OK();-  }-  virtual size_t NumBytes() const {-    return memtable_->ApproximateMemoryUsage();-  }--  virtual Iterator* NewIterator() const {-    return new KeyConvertingIterator(memtable_->NewIterator());-  }-- private:-  InternalKeyComparator internal_comparator_;-  MemTable* memtable_;-};--class DBConstructor: public Constructor {- public:-  explicit DBConstructor(const Comparator* cmp)-      : Constructor(cmp),-        comparator_(cmp) {-    db_ = NULL;-    NewDB();-  }-  ~DBConstructor() {-    delete db_;-  }-  virtual Status FinishImpl(const Options& options, const KVMap& data) {-    delete db_;-    db_ = NULL;-    NewDB();-    for (KVMap::const_iterator it = data.begin();-         it != data.end();-         ++it) {-      WriteBatch batch;-      batch.Put(it->first, it->second);-      ASSERT_TRUE(db_->Write(WriteOptions(), &batch).ok());-    }-    return Status::OK();-  }-  virtual size_t NumBytes() const {-    Range r("", "\xff\xff");-    uint64_t size;-    db_->GetApproximateSizes(&r, 1, &size);-    return size;-  }--  virtual Iterator* NewIterator() const {-    return db_->NewIterator(ReadOptions());-  }--  virtual DB* db() const { return db_; }-- private:-  void NewDB() {-    std::string name = test::TmpDir() + "/table_testdb";--    Options options;-    options.comparator = comparator_;-    Status status = DestroyDB(name, options);-    ASSERT_TRUE(status.ok()) << status.ToString();--    options.create_if_missing = true;-    options.error_if_exists = true;-    options.write_buffer_size = 10000;  // Something small to force merging-    status = DB::Open(options, name, &db_);-    ASSERT_TRUE(status.ok()) << status.ToString();-  }--  const Comparator* comparator_;-  DB* db_;-};--enum TestType {-  TABLE_TEST,-  BLOCK_TEST,-  MEMTABLE_TEST,-  DB_TEST-};--struct TestArgs {-  TestType type;-  bool reverse_compare;-  int restart_interval;-};--static const TestArgs kTestArgList[] = {-  { TABLE_TEST, false, 16 },-  { TABLE_TEST, false, 1 },-  { TABLE_TEST, false, 1024 },-  { TABLE_TEST, true, 16 },-  { TABLE_TEST, true, 1 },-  { TABLE_TEST, true, 1024 },--  { BLOCK_TEST, false, 16 },-  { BLOCK_TEST, false, 1 },-  { BLOCK_TEST, false, 1024 },-  { BLOCK_TEST, true, 16 },-  { BLOCK_TEST, true, 1 },-  { BLOCK_TEST, true, 1024 },--  // Restart interval does not matter for memtables-  { MEMTABLE_TEST, false, 16 },-  { MEMTABLE_TEST, true, 16 },--  // Do not bother with restart interval variations for DB-  { DB_TEST, false, 16 },-  { DB_TEST, true, 16 },-};-static const int kNumTestArgs = sizeof(kTestArgList) / sizeof(kTestArgList[0]);--class Harness {- public:-  Harness() : constructor_(NULL) { }--  void Init(const TestArgs& args) {-    delete constructor_;-    constructor_ = NULL;-    options_ = Options();--    options_.block_restart_interval = args.restart_interval;-    // Use shorter block size for tests to exercise block boundary-    // conditions more.-    options_.block_size = 256;-    if (args.reverse_compare) {-      options_.comparator = &reverse_key_comparator;-    }-    switch (args.type) {-      case TABLE_TEST:-        constructor_ = new TableConstructor(options_.comparator);-        break;-      case BLOCK_TEST:-        constructor_ = new BlockConstructor(options_.comparator);-        break;-      case MEMTABLE_TEST:-        constructor_ = new MemTableConstructor(options_.comparator);-        break;-      case DB_TEST:-        constructor_ = new DBConstructor(options_.comparator);-        break;-    }-  }--  ~Harness() {-    delete constructor_;-  }--  void Add(const std::string& key, const std::string& value) {-    constructor_->Add(key, value);-  }--  void Test(Random* rnd) {-    std::vector<std::string> keys;-    KVMap data;-    constructor_->Finish(options_, &keys, &data);--    TestForwardScan(keys, data);-    TestBackwardScan(keys, data);-    TestRandomAccess(rnd, keys, data);-  }--  void TestForwardScan(const std::vector<std::string>& keys,-                       const KVMap& data) {-    Iterator* iter = constructor_->NewIterator();-    ASSERT_TRUE(!iter->Valid());-    iter->SeekToFirst();-    for (KVMap::const_iterator model_iter = data.begin();-         model_iter != data.end();-         ++model_iter) {-      ASSERT_EQ(ToString(data, model_iter), ToString(iter));-      iter->Next();-    }-    ASSERT_TRUE(!iter->Valid());-    delete iter;-  }--  void TestBackwardScan(const std::vector<std::string>& keys,-                        const KVMap& data) {-    Iterator* iter = constructor_->NewIterator();-    ASSERT_TRUE(!iter->Valid());-    iter->SeekToLast();-    for (KVMap::const_reverse_iterator model_iter = data.rbegin();-         model_iter != data.rend();-         ++model_iter) {-      ASSERT_EQ(ToString(data, model_iter), ToString(iter));-      iter->Prev();-    }-    ASSERT_TRUE(!iter->Valid());-    delete iter;-  }--  void TestRandomAccess(Random* rnd,-                        const std::vector<std::string>& keys,-                        const KVMap& data) {-    static const bool kVerbose = false;-    Iterator* iter = constructor_->NewIterator();-    ASSERT_TRUE(!iter->Valid());-    KVMap::const_iterator model_iter = data.begin();-    if (kVerbose) fprintf(stderr, "---\n");-    for (int i = 0; i < 200; i++) {-      const int toss = rnd->Uniform(5);-      switch (toss) {-        case 0: {-          if (iter->Valid()) {-            if (kVerbose) fprintf(stderr, "Next\n");-            iter->Next();-            ++model_iter;-            ASSERT_EQ(ToString(data, model_iter), ToString(iter));-          }-          break;-        }--        case 1: {-          if (kVerbose) fprintf(stderr, "SeekToFirst\n");-          iter->SeekToFirst();-          model_iter = data.begin();-          ASSERT_EQ(ToString(data, model_iter), ToString(iter));-          break;-        }--        case 2: {-          std::string key = PickRandomKey(rnd, keys);-          model_iter = data.lower_bound(key);-          if (kVerbose) fprintf(stderr, "Seek '%s'\n",-                                EscapeString(key).c_str());-          iter->Seek(Slice(key));-          ASSERT_EQ(ToString(data, model_iter), ToString(iter));-          break;-        }--        case 3: {-          if (iter->Valid()) {-            if (kVerbose) fprintf(stderr, "Prev\n");-            iter->Prev();-            if (model_iter == data.begin()) {-              model_iter = data.end();   // Wrap around to invalid value-            } else {-              --model_iter;-            }-            ASSERT_EQ(ToString(data, model_iter), ToString(iter));-          }-          break;-        }--        case 4: {-          if (kVerbose) fprintf(stderr, "SeekToLast\n");-          iter->SeekToLast();-          if (keys.empty()) {-            model_iter = data.end();-          } else {-            std::string last = data.rbegin()->first;-            model_iter = data.lower_bound(last);-          }-          ASSERT_EQ(ToString(data, model_iter), ToString(iter));-          break;-        }-      }-    }-    delete iter;-  }--  std::string ToString(const KVMap& data, const KVMap::const_iterator& it) {-    if (it == data.end()) {-      return "END";-    } else {-      return "'" + it->first + "->" + it->second + "'";-    }-  }--  std::string ToString(const KVMap& data,-                       const KVMap::const_reverse_iterator& it) {-    if (it == data.rend()) {-      return "END";-    } else {-      return "'" + it->first + "->" + it->second + "'";-    }-  }--  std::string ToString(const Iterator* it) {-    if (!it->Valid()) {-      return "END";-    } else {-      return "'" + it->key().ToString() + "->" + it->value().ToString() + "'";-    }-  }--  std::string PickRandomKey(Random* rnd, const std::vector<std::string>& keys) {-    if (keys.empty()) {-      return "foo";-    } else {-      const int index = rnd->Uniform(keys.size());-      std::string result = keys[index];-      switch (rnd->Uniform(3)) {-        case 0:-          // Return an existing key-          break;-        case 1: {-          // Attempt to return something smaller than an existing key-          if (result.size() > 0 && result[result.size()-1] > '\0') {-            result[result.size()-1]--;-          }-          break;-        }-        case 2: {-          // Return something larger than an existing key-          Increment(options_.comparator, &result);-          break;-        }-      }-      return result;-    }-  }--  // Returns NULL if not running against a DB-  DB* db() const { return constructor_->db(); }-- private:-  Options options_;-  Constructor* constructor_;-};--// Test the empty key-TEST(Harness, SimpleEmptyKey) {-  for (int i = 0; i < kNumTestArgs; i++) {-    Init(kTestArgList[i]);-    Random rnd(test::RandomSeed() + 1);-    Add("", "v");-    Test(&rnd);-  }-}--TEST(Harness, SimpleSingle) {-  for (int i = 0; i < kNumTestArgs; i++) {-    Init(kTestArgList[i]);-    Random rnd(test::RandomSeed() + 2);-    Add("abc", "v");-    Test(&rnd);-  }-}--TEST(Harness, SimpleMulti) {-  for (int i = 0; i < kNumTestArgs; i++) {-    Init(kTestArgList[i]);-    Random rnd(test::RandomSeed() + 3);-    Add("abc", "v");-    Add("abcd", "v");-    Add("ac", "v2");-    Test(&rnd);-  }-}--TEST(Harness, SimpleSpecialKey) {-  for (int i = 0; i < kNumTestArgs; i++) {-    Init(kTestArgList[i]);-    Random rnd(test::RandomSeed() + 4);-    Add("\xff\xff", "v3");-    Test(&rnd);-  }-}--TEST(Harness, Randomized) {-  for (int i = 0; i < kNumTestArgs; i++) {-    Init(kTestArgList[i]);-    Random rnd(test::RandomSeed() + 5);-    for (int num_entries = 0; num_entries < 2000;-         num_entries += (num_entries < 50 ? 1 : 200)) {-      if ((num_entries % 10) == 0) {-        fprintf(stderr, "case %d of %d: num_entries = %d\n",-                (i + 1), int(kNumTestArgs), num_entries);-      }-      for (int e = 0; e < num_entries; e++) {-        std::string v;-        Add(test::RandomKey(&rnd, rnd.Skewed(4)),-            test::RandomString(&rnd, rnd.Skewed(5), &v).ToString());-      }-      Test(&rnd);-    }-  }-}--TEST(Harness, RandomizedLongDB) {-  Random rnd(test::RandomSeed());-  TestArgs args = { DB_TEST, false, 16 };-  Init(args);-  int num_entries = 100000;-  for (int e = 0; e < num_entries; e++) {-    std::string v;-    Add(test::RandomKey(&rnd, rnd.Skewed(4)),-        test::RandomString(&rnd, rnd.Skewed(5), &v).ToString());-  }-  Test(&rnd);--  // We must have created enough data to force merging-  int files = 0;-  for (int level = 0; level < config::kNumLevels; level++) {-    std::string value;-    char name[100];-    snprintf(name, sizeof(name), "leveldb.num-files-at-level%d", level);-    ASSERT_TRUE(db()->GetProperty(name, &value));-    files += atoi(value.c_str());-  }-  ASSERT_GT(files, 0);-}--class MemTableTest { };--TEST(MemTableTest, Simple) {-  InternalKeyComparator cmp(BytewiseComparator());-  MemTable* memtable = new MemTable(cmp);-  memtable->Ref();-  WriteBatch batch;-  WriteBatchInternal::SetSequence(&batch, 100);-  batch.Put(std::string("k1"), std::string("v1"));-  batch.Put(std::string("k2"), std::string("v2"));-  batch.Put(std::string("k3"), std::string("v3"));-  batch.Put(std::string("largekey"), std::string("vlarge"));-  ASSERT_TRUE(WriteBatchInternal::InsertInto(&batch, memtable).ok());--  Iterator* iter = memtable->NewIterator();-  iter->SeekToFirst();-  while (iter->Valid()) {-    fprintf(stderr, "key: '%s' -> '%s'\n",-            iter->key().ToString().c_str(),-            iter->value().ToString().c_str());-    iter->Next();-  }--  delete iter;-  memtable->Unref();-}--static bool Between(uint64_t val, uint64_t low, uint64_t high) {-  bool result = (val >= low) && (val <= high);-  if (!result) {-    fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n",-            (unsigned long long)(val),-            (unsigned long long)(low),-            (unsigned long long)(high));-  }-  return result;-}--class TableTest { };--TEST(TableTest, ApproximateOffsetOfPlain) {-  TableConstructor c(BytewiseComparator());-  c.Add("k01", "hello");-  c.Add("k02", "hello2");-  c.Add("k03", std::string(10000, 'x'));-  c.Add("k04", std::string(200000, 'x'));-  c.Add("k05", std::string(300000, 'x'));-  c.Add("k06", "hello3");-  c.Add("k07", std::string(100000, 'x'));-  std::vector<std::string> keys;-  KVMap kvmap;-  Options options;-  options.block_size = 1024;-  options.compression = kNoCompression;-  c.Finish(options, &keys, &kvmap);--  ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"),       0,      0));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"),       0,      0));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01a"),      0,      0));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"),       0,      0));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"),       0,      0));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"),   10000,  11000));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04a"), 210000, 211000));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k05"),  210000, 211000));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k06"),  510000, 511000));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k07"),  510000, 511000));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"),  610000, 611000));--}--static bool SnappyCompressionSupported() {-  std::string out;-  Slice in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";-  return port::Snappy_Compress(in.data(), in.size(), &out);-}--TEST(TableTest, ApproximateOffsetOfCompressed) {-  if (!SnappyCompressionSupported()) {-    fprintf(stderr, "skipping compression tests\n");-    return;-  }--  Random rnd(301);-  TableConstructor c(BytewiseComparator());-  std::string tmp;-  c.Add("k01", "hello");-  c.Add("k02", test::CompressibleString(&rnd, 0.25, 10000, &tmp));-  c.Add("k03", "hello3");-  c.Add("k04", test::CompressibleString(&rnd, 0.25, 10000, &tmp));-  std::vector<std::string> keys;-  KVMap kvmap;-  Options options;-  options.block_size = 1024;-  options.compression = kSnappyCompression;-  c.Finish(options, &keys, &kvmap);--  ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"),       0,      0));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"),       0,      0));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"),       0,      0));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"),    2000,   3000));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"),    2000,   3000));-  ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"),    4000,   6000));-}--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/table/two_level_iterator.cc
@@ -1,182 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "table/two_level_iterator.h"--#include "leveldb/table.h"-#include "table/block.h"-#include "table/format.h"-#include "table/iterator_wrapper.h"--namespace leveldb {--namespace {--typedef Iterator* (*BlockFunction)(void*, const ReadOptions&, const Slice&);--class TwoLevelIterator: public Iterator {- public:-  TwoLevelIterator(-    Iterator* index_iter,-    BlockFunction block_function,-    void* arg,-    const ReadOptions& options);--  virtual ~TwoLevelIterator();--  virtual void Seek(const Slice& target);-  virtual void SeekToFirst();-  virtual void SeekToLast();-  virtual void Next();-  virtual void Prev();--  virtual bool Valid() const {-    return data_iter_.Valid();-  }-  virtual Slice key() const {-    assert(Valid());-    return data_iter_.key();-  }-  virtual Slice value() const {-    assert(Valid());-    return data_iter_.value();-  }-  virtual Status status() const {-    // It'd be nice if status() returned a const Status& instead of a Status-    if (!index_iter_.status().ok()) {-      return index_iter_.status();-    } else if (data_iter_.iter() != NULL && !data_iter_.status().ok()) {-      return data_iter_.status();-    } else {-      return status_;-    }-  }-- private:-  void SaveError(const Status& s) {-    if (status_.ok() && !s.ok()) status_ = s;-  }-  void SkipEmptyDataBlocksForward();-  void SkipEmptyDataBlocksBackward();-  void SetDataIterator(Iterator* data_iter);-  void InitDataBlock();--  BlockFunction block_function_;-  void* arg_;-  const ReadOptions options_;-  Status status_;-  IteratorWrapper index_iter_;-  IteratorWrapper data_iter_; // May be NULL-  // If data_iter_ is non-NULL, then "data_block_handle_" holds the-  // "index_value" passed to block_function_ to create the data_iter_.-  std::string data_block_handle_;-};--TwoLevelIterator::TwoLevelIterator(-    Iterator* index_iter,-    BlockFunction block_function,-    void* arg,-    const ReadOptions& options)-    : block_function_(block_function),-      arg_(arg),-      options_(options),-      index_iter_(index_iter),-      data_iter_(NULL) {-}--TwoLevelIterator::~TwoLevelIterator() {-}--void TwoLevelIterator::Seek(const Slice& target) {-  index_iter_.Seek(target);-  InitDataBlock();-  if (data_iter_.iter() != NULL) data_iter_.Seek(target);-  SkipEmptyDataBlocksForward();-}--void TwoLevelIterator::SeekToFirst() {-  index_iter_.SeekToFirst();-  InitDataBlock();-  if (data_iter_.iter() != NULL) data_iter_.SeekToFirst();-  SkipEmptyDataBlocksForward();-}--void TwoLevelIterator::SeekToLast() {-  index_iter_.SeekToLast();-  InitDataBlock();-  if (data_iter_.iter() != NULL) data_iter_.SeekToLast();-  SkipEmptyDataBlocksBackward();-}--void TwoLevelIterator::Next() {-  assert(Valid());-  data_iter_.Next();-  SkipEmptyDataBlocksForward();-}--void TwoLevelIterator::Prev() {-  assert(Valid());-  data_iter_.Prev();-  SkipEmptyDataBlocksBackward();-}---void TwoLevelIterator::SkipEmptyDataBlocksForward() {-  while (data_iter_.iter() == NULL || !data_iter_.Valid()) {-    // Move to next block-    if (!index_iter_.Valid()) {-      SetDataIterator(NULL);-      return;-    }-    index_iter_.Next();-    InitDataBlock();-    if (data_iter_.iter() != NULL) data_iter_.SeekToFirst();-  }-}--void TwoLevelIterator::SkipEmptyDataBlocksBackward() {-  while (data_iter_.iter() == NULL || !data_iter_.Valid()) {-    // Move to next block-    if (!index_iter_.Valid()) {-      SetDataIterator(NULL);-      return;-    }-    index_iter_.Prev();-    InitDataBlock();-    if (data_iter_.iter() != NULL) data_iter_.SeekToLast();-  }-}--void TwoLevelIterator::SetDataIterator(Iterator* data_iter) {-  if (data_iter_.iter() != NULL) SaveError(data_iter_.status());-  data_iter_.Set(data_iter);-}--void TwoLevelIterator::InitDataBlock() {-  if (!index_iter_.Valid()) {-    SetDataIterator(NULL);-  } else {-    Slice handle = index_iter_.value();-    if (data_iter_.iter() != NULL && handle.compare(data_block_handle_) == 0) {-      // data_iter_ is already constructed with this iterator, so-      // no need to change anything-    } else {-      Iterator* iter = (*block_function_)(arg_, options_, handle);-      data_block_handle_.assign(handle.data(), handle.size());-      SetDataIterator(iter);-    }-  }-}--}  // namespace--Iterator* NewTwoLevelIterator(-    Iterator* index_iter,-    BlockFunction block_function,-    void* arg,-    const ReadOptions& options) {-  return new TwoLevelIterator(index_iter, block_function, arg, options);-}--}  // namespace leveldb
− cbits/leveldb/table/two_level_iterator.h
@@ -1,34 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_-#define STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_--#include "leveldb/iterator.h"--namespace leveldb {--struct ReadOptions;--// Return a new two level iterator.  A two-level iterator contains an-// index iterator whose values point to a sequence of blocks where-// each block is itself a sequence of key,value pairs.  The returned-// two-level iterator yields the concatenation of all key/value pairs-// in the sequence of blocks.  Takes ownership of "index_iter" and-// will delete it when no longer needed.-//-// Uses a supplied function to convert an index_iter value into-// an iterator over the contents of the corresponding block.-extern Iterator* NewTwoLevelIterator(-    Iterator* index_iter,-    Iterator* (*block_function)(-        void* arg,-        const ReadOptions& options,-        const Slice& index_value),-    void* arg,-    const ReadOptions& options);--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_TABLE_TWO_LEVEL_ITERATOR_H_
− cbits/leveldb/util/arena.cc
@@ -1,68 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "util/arena.h"-#include <assert.h>--namespace leveldb {--static const int kBlockSize = 4096;--Arena::Arena() {-  blocks_memory_ = 0;-  alloc_ptr_ = NULL;  // First allocation will allocate a block-  alloc_bytes_remaining_ = 0;-}--Arena::~Arena() {-  for (size_t i = 0; i < blocks_.size(); i++) {-    delete[] blocks_[i];-  }-}--char* Arena::AllocateFallback(size_t bytes) {-  if (bytes > kBlockSize / 4) {-    // Object is more than a quarter of our block size.  Allocate it separately-    // to avoid wasting too much space in leftover bytes.-    char* result = AllocateNewBlock(bytes);-    return result;-  }--  // We waste the remaining space in the current block.-  alloc_ptr_ = AllocateNewBlock(kBlockSize);-  alloc_bytes_remaining_ = kBlockSize;--  char* result = alloc_ptr_;-  alloc_ptr_ += bytes;-  alloc_bytes_remaining_ -= bytes;-  return result;-}--char* Arena::AllocateAligned(size_t bytes) {-  const int align = sizeof(void*);    // We'll align to pointer size-  assert((align & (align-1)) == 0);   // Pointer size should be a power of 2-  size_t current_mod = reinterpret_cast<uintptr_t>(alloc_ptr_) & (align-1);-  size_t slop = (current_mod == 0 ? 0 : align - current_mod);-  size_t needed = bytes + slop;-  char* result;-  if (needed <= alloc_bytes_remaining_) {-    result = alloc_ptr_ + slop;-    alloc_ptr_ += needed;-    alloc_bytes_remaining_ -= needed;-  } else {-    // AllocateFallback always returned aligned memory-    result = AllocateFallback(bytes);-  }-  assert((reinterpret_cast<uintptr_t>(result) & (align-1)) == 0);-  return result;-}--char* Arena::AllocateNewBlock(size_t block_bytes) {-  char* result = new char[block_bytes];-  blocks_memory_ += block_bytes;-  blocks_.push_back(result);-  return result;-}--}  // namespace leveldb
− cbits/leveldb/util/arena.h
@@ -1,68 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_UTIL_ARENA_H_-#define STORAGE_LEVELDB_UTIL_ARENA_H_--#include <cstddef>-#include <vector>-#include <assert.h>-#include <stdint.h>--namespace leveldb {--class Arena {- public:-  Arena();-  ~Arena();--  // Return a pointer to a newly allocated memory block of "bytes" bytes.-  char* Allocate(size_t bytes);--  // Allocate memory with the normal alignment guarantees provided by malloc-  char* AllocateAligned(size_t bytes);--  // Returns an estimate of the total memory usage of data allocated-  // by the arena (including space allocated but not yet used for user-  // allocations).-  size_t MemoryUsage() const {-    return blocks_memory_ + blocks_.capacity() * sizeof(char*);-  }-- private:-  char* AllocateFallback(size_t bytes);-  char* AllocateNewBlock(size_t block_bytes);--  // Allocation state-  char* alloc_ptr_;-  size_t alloc_bytes_remaining_;--  // Array of new[] allocated memory blocks-  std::vector<char*> blocks_;--  // Bytes of memory in blocks allocated so far-  size_t blocks_memory_;--  // No copying allowed-  Arena(const Arena&);-  void operator=(const Arena&);-};--inline char* Arena::Allocate(size_t bytes) {-  // The semantics of what to return are a bit messy if we allow-  // 0-byte allocations, so we disallow them here (we don't need-  // them for our internal use).-  assert(bytes > 0);-  if (bytes <= alloc_bytes_remaining_) {-    char* result = alloc_ptr_;-    alloc_ptr_ += bytes;-    alloc_bytes_remaining_ -= bytes;-    return result;-  }-  return AllocateFallback(bytes);-}--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_UTIL_ARENA_H_
− cbits/leveldb/util/arena_test.cc
@@ -1,68 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "util/arena.h"--#include "util/random.h"-#include "util/testharness.h"--namespace leveldb {--class ArenaTest { };--TEST(ArenaTest, Empty) {-  Arena arena;-}--TEST(ArenaTest, Simple) {-  std::vector<std::pair<size_t, char*> > allocated;-  Arena arena;-  const int N = 100000;-  size_t bytes = 0;-  Random rnd(301);-  for (int i = 0; i < N; i++) {-    size_t s;-    if (i % (N / 10) == 0) {-      s = i;-    } else {-      s = rnd.OneIn(4000) ? rnd.Uniform(6000) :-          (rnd.OneIn(10) ? rnd.Uniform(100) : rnd.Uniform(20));-    }-    if (s == 0) {-      // Our arena disallows size 0 allocations.-      s = 1;-    }-    char* r;-    if (rnd.OneIn(10)) {-      r = arena.AllocateAligned(s);-    } else {-      r = arena.Allocate(s);-    }--    for (int b = 0; b < s; b++) {-      // Fill the "i"th allocation with a known bit pattern-      r[b] = i % 256;-    }-    bytes += s;-    allocated.push_back(std::make_pair(s, r));-    ASSERT_GE(arena.MemoryUsage(), bytes);-    if (i > N/10) {-      ASSERT_LE(arena.MemoryUsage(), bytes * 1.10);-    }-  }-  for (int i = 0; i < allocated.size(); i++) {-    size_t num_bytes = allocated[i].first;-    const char* p = allocated[i].second;-    for (int b = 0; b < num_bytes; b++) {-      // Check the "i"th allocation for the known bit pattern-      ASSERT_EQ(int(p[b]) & 0xff, i % 256);-    }-  }-}--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/util/cache.cc
@@ -1,328 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include <assert.h>-#include <stdio.h>-#include <stdlib.h>--#include "leveldb/cache.h"-#include "port/port.h"-#include "util/hash.h"-#include "util/mutexlock.h"--namespace leveldb {--Cache::~Cache() {-}--namespace {--// LRU cache implementation--// An entry is a variable length heap-allocated structure.  Entries-// are kept in a circular doubly linked list ordered by access time.-struct LRUHandle {-  void* value;-  void (*deleter)(const Slice&, void* value);-  LRUHandle* next_hash;-  LRUHandle* next;-  LRUHandle* prev;-  size_t charge;      // TODO(opt): Only allow uint32_t?-  size_t key_length;-  uint32_t refs;-  uint32_t hash;      // Hash of key(); used for fast sharding and comparisons-  char key_data[1];   // Beginning of key--  Slice key() const {-    // For cheaper lookups, we allow a temporary Handle object-    // to store a pointer to a key in "value".-    if (next == this) {-      return *(reinterpret_cast<Slice*>(value));-    } else {-      return Slice(key_data, key_length);-    }-  }-};--// We provide our own simple hash table since it removes a whole bunch-// of porting hacks and is also faster than some of the built-in hash-// table implementations in some of the compiler/runtime combinations-// we have tested.  E.g., readrandom speeds up by ~5% over the g++-// 4.4.3's builtin hashtable.-class HandleTable {- public:-  HandleTable() : length_(0), elems_(0), list_(NULL) { Resize(); }-  ~HandleTable() { delete[] list_; }--  LRUHandle* Lookup(const Slice& key, uint32_t hash) {-    return *FindPointer(key, hash);-  }--  LRUHandle* Insert(LRUHandle* h) {-    LRUHandle** ptr = FindPointer(h->key(), h->hash);-    LRUHandle* old = *ptr;-    h->next_hash = (old == NULL ? NULL : old->next_hash);-    *ptr = h;-    if (old == NULL) {-      ++elems_;-      if (elems_ > length_) {-        // Since each cache entry is fairly large, we aim for a small-        // average linked list length (<= 1).-        Resize();-      }-    }-    return old;-  }--  LRUHandle* Remove(const Slice& key, uint32_t hash) {-    LRUHandle** ptr = FindPointer(key, hash);-    LRUHandle* result = *ptr;-    if (result != NULL) {-      *ptr = result->next_hash;-      --elems_;-    }-    return result;-  }-- private:-  // The table consists of an array of buckets where each bucket is-  // a linked list of cache entries that hash into the bucket.-  uint32_t length_;-  uint32_t elems_;-  LRUHandle** list_;--  // Return a pointer to slot that points to a cache entry that-  // matches key/hash.  If there is no such cache entry, return a-  // pointer to the trailing slot in the corresponding linked list.-  LRUHandle** FindPointer(const Slice& key, uint32_t hash) {-    LRUHandle** ptr = &list_[hash & (length_ - 1)];-    while (*ptr != NULL &&-           ((*ptr)->hash != hash || key != (*ptr)->key())) {-      ptr = &(*ptr)->next_hash;-    }-    return ptr;-  }--  void Resize() {-    uint32_t new_length = 4;-    while (new_length < elems_) {-      new_length *= 2;-    }-    LRUHandle** new_list = new LRUHandle*[new_length];-    memset(new_list, 0, sizeof(new_list[0]) * new_length);-    uint32_t count = 0;-    for (uint32_t i = 0; i < length_; i++) {-      LRUHandle* h = list_[i];-      while (h != NULL) {-        LRUHandle* next = h->next_hash;-        Slice key = h->key();-        uint32_t hash = h->hash;-        LRUHandle** ptr = &new_list[hash & (new_length - 1)];-        h->next_hash = *ptr;-        *ptr = h;-        h = next;-        count++;-      }-    }-    assert(elems_ == count);-    delete[] list_;-    list_ = new_list;-    length_ = new_length;-  }-};--// A single shard of sharded cache.-class LRUCache {- public:-  LRUCache();-  ~LRUCache();--  // Separate from constructor so caller can easily make an array of LRUCache-  void SetCapacity(size_t capacity) { capacity_ = capacity; }--  // Like Cache methods, but with an extra "hash" parameter.-  Cache::Handle* Insert(const Slice& key, uint32_t hash,-                        void* value, size_t charge,-                        void (*deleter)(const Slice& key, void* value));-  Cache::Handle* Lookup(const Slice& key, uint32_t hash);-  void Release(Cache::Handle* handle);-  void Erase(const Slice& key, uint32_t hash);-- private:-  void LRU_Remove(LRUHandle* e);-  void LRU_Append(LRUHandle* e);-  void Unref(LRUHandle* e);--  // Initialized before use.-  size_t capacity_;--  // mutex_ protects the following state.-  port::Mutex mutex_;-  size_t usage_;-  uint64_t last_id_;--  // Dummy head of LRU list.-  // lru.prev is newest entry, lru.next is oldest entry.-  LRUHandle lru_;--  HandleTable table_;-};--LRUCache::LRUCache()-    : usage_(0),-      last_id_(0) {-  // Make empty circular linked list-  lru_.next = &lru_;-  lru_.prev = &lru_;-}--LRUCache::~LRUCache() {-  for (LRUHandle* e = lru_.next; e != &lru_; ) {-    LRUHandle* next = e->next;-    assert(e->refs == 1);  // Error if caller has an unreleased handle-    Unref(e);-    e = next;-  }-}--void LRUCache::Unref(LRUHandle* e) {-  assert(e->refs > 0);-  e->refs--;-  if (e->refs <= 0) {-    usage_ -= e->charge;-    (*e->deleter)(e->key(), e->value);-    free(e);-  }-}--void LRUCache::LRU_Remove(LRUHandle* e) {-  e->next->prev = e->prev;-  e->prev->next = e->next;-}--void LRUCache::LRU_Append(LRUHandle* e) {-  // Make "e" newest entry by inserting just before lru_-  e->next = &lru_;-  e->prev = lru_.prev;-  e->prev->next = e;-  e->next->prev = e;-}--Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash) {-  MutexLock l(&mutex_);-  LRUHandle* e = table_.Lookup(key, hash);-  if (e != NULL) {-    e->refs++;-    LRU_Remove(e);-    LRU_Append(e);-  }-  return reinterpret_cast<Cache::Handle*>(e);-}--void LRUCache::Release(Cache::Handle* handle) {-  MutexLock l(&mutex_);-  Unref(reinterpret_cast<LRUHandle*>(handle));-}--Cache::Handle* LRUCache::Insert(-    const Slice& key, uint32_t hash, void* value, size_t charge,-    void (*deleter)(const Slice& key, void* value)) {-  MutexLock l(&mutex_);--  LRUHandle* e = reinterpret_cast<LRUHandle*>(-      malloc(sizeof(LRUHandle)-1 + key.size()));-  e->value = value;-  e->deleter = deleter;-  e->charge = charge;-  e->key_length = key.size();-  e->hash = hash;-  e->refs = 2;  // One from LRUCache, one for the returned handle-  memcpy(e->key_data, key.data(), key.size());-  LRU_Append(e);-  usage_ += charge;--  LRUHandle* old = table_.Insert(e);-  if (old != NULL) {-    LRU_Remove(old);-    Unref(old);-  }--  while (usage_ > capacity_ && lru_.next != &lru_) {-    LRUHandle* old = lru_.next;-    LRU_Remove(old);-    table_.Remove(old->key(), old->hash);-    Unref(old);-  }--  return reinterpret_cast<Cache::Handle*>(e);-}--void LRUCache::Erase(const Slice& key, uint32_t hash) {-  MutexLock l(&mutex_);-  LRUHandle* e = table_.Remove(key, hash);-  if (e != NULL) {-    LRU_Remove(e);-    Unref(e);-  }-}--static const int kNumShardBits = 4;-static const int kNumShards = 1 << kNumShardBits;--class ShardedLRUCache : public Cache {- private:-  LRUCache shard_[kNumShards];-  port::Mutex id_mutex_;-  uint64_t last_id_;--  static inline uint32_t HashSlice(const Slice& s) {-    return Hash(s.data(), s.size(), 0);-  }--  static uint32_t Shard(uint32_t hash) {-    return hash >> (32 - kNumShardBits);-  }-- public:-  explicit ShardedLRUCache(size_t capacity)-      : last_id_(0) {-    const size_t per_shard = (capacity + (kNumShards - 1)) / kNumShards;-    for (int s = 0; s < kNumShards; s++) {-      shard_[s].SetCapacity(per_shard);-    }-  }-  virtual ~ShardedLRUCache() { }-  virtual Handle* Insert(const Slice& key, void* value, size_t charge,-                         void (*deleter)(const Slice& key, void* value)) {-    const uint32_t hash = HashSlice(key);-    return shard_[Shard(hash)].Insert(key, hash, value, charge, deleter);-  }-  virtual Handle* Lookup(const Slice& key) {-    const uint32_t hash = HashSlice(key);-    return shard_[Shard(hash)].Lookup(key, hash);-  }-  virtual void Release(Handle* handle) {-    LRUHandle* h = reinterpret_cast<LRUHandle*>(handle);-    shard_[Shard(h->hash)].Release(handle);-  }-  virtual void Erase(const Slice& key) {-    const uint32_t hash = HashSlice(key);-    shard_[Shard(hash)].Erase(key, hash);-  }-  virtual void* Value(Handle* handle) {-    return reinterpret_cast<LRUHandle*>(handle)->value;-  }-  virtual uint64_t NewId() {-    MutexLock l(&id_mutex_);-    return ++(last_id_);-  }-};--}  // end anonymous namespace--Cache* NewLRUCache(size_t capacity) {-  return new ShardedLRUCache(capacity);-}--}  // namespace leveldb
− cbits/leveldb/util/cache_test.cc
@@ -1,186 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "leveldb/cache.h"--#include <vector>-#include "util/coding.h"-#include "util/testharness.h"--namespace leveldb {--// Conversions between numeric keys/values and the types expected by Cache.-static std::string EncodeKey(int k) {-  std::string result;-  PutFixed32(&result, k);-  return result;-}-static int DecodeKey(const Slice& k) {-  assert(k.size() == 4);-  return DecodeFixed32(k.data());-}-static void* EncodeValue(uintptr_t v) { return reinterpret_cast<void*>(v); }-static int DecodeValue(void* v) { return reinterpret_cast<uintptr_t>(v); }--class CacheTest {- public:-  static CacheTest* current_;--  static void Deleter(const Slice& key, void* v) {-    current_->deleted_keys_.push_back(DecodeKey(key));-    current_->deleted_values_.push_back(DecodeValue(v));-  }--  static const int kCacheSize = 1000;-  std::vector<int> deleted_keys_;-  std::vector<int> deleted_values_;-  Cache* cache_;--  CacheTest() : cache_(NewLRUCache(kCacheSize)) {-    current_ = this;-  }--  ~CacheTest() {-    delete cache_;-  }--  int Lookup(int key) {-    Cache::Handle* handle = cache_->Lookup(EncodeKey(key));-    const int r = (handle == NULL) ? -1 : DecodeValue(cache_->Value(handle));-    if (handle != NULL) {-      cache_->Release(handle);-    }-    return r;-  }--  void Insert(int key, int value, int charge = 1) {-    cache_->Release(cache_->Insert(EncodeKey(key), EncodeValue(value), charge,-                                   &CacheTest::Deleter));-  }--  void Erase(int key) {-    cache_->Erase(EncodeKey(key));-  }-};-CacheTest* CacheTest::current_;--TEST(CacheTest, HitAndMiss) {-  ASSERT_EQ(-1, Lookup(100));--  Insert(100, 101);-  ASSERT_EQ(101, Lookup(100));-  ASSERT_EQ(-1,  Lookup(200));-  ASSERT_EQ(-1,  Lookup(300));--  Insert(200, 201);-  ASSERT_EQ(101, Lookup(100));-  ASSERT_EQ(201, Lookup(200));-  ASSERT_EQ(-1,  Lookup(300));--  Insert(100, 102);-  ASSERT_EQ(102, Lookup(100));-  ASSERT_EQ(201, Lookup(200));-  ASSERT_EQ(-1,  Lookup(300));--  ASSERT_EQ(1, deleted_keys_.size());-  ASSERT_EQ(100, deleted_keys_[0]);-  ASSERT_EQ(101, deleted_values_[0]);-}--TEST(CacheTest, Erase) {-  Erase(200);-  ASSERT_EQ(0, deleted_keys_.size());--  Insert(100, 101);-  Insert(200, 201);-  Erase(100);-  ASSERT_EQ(-1,  Lookup(100));-  ASSERT_EQ(201, Lookup(200));-  ASSERT_EQ(1, deleted_keys_.size());-  ASSERT_EQ(100, deleted_keys_[0]);-  ASSERT_EQ(101, deleted_values_[0]);--  Erase(100);-  ASSERT_EQ(-1,  Lookup(100));-  ASSERT_EQ(201, Lookup(200));-  ASSERT_EQ(1, deleted_keys_.size());-}--TEST(CacheTest, EntriesArePinned) {-  Insert(100, 101);-  Cache::Handle* h1 = cache_->Lookup(EncodeKey(100));-  ASSERT_EQ(101, DecodeValue(cache_->Value(h1)));--  Insert(100, 102);-  Cache::Handle* h2 = cache_->Lookup(EncodeKey(100));-  ASSERT_EQ(102, DecodeValue(cache_->Value(h2)));-  ASSERT_EQ(0, deleted_keys_.size());--  cache_->Release(h1);-  ASSERT_EQ(1, deleted_keys_.size());-  ASSERT_EQ(100, deleted_keys_[0]);-  ASSERT_EQ(101, deleted_values_[0]);--  Erase(100);-  ASSERT_EQ(-1, Lookup(100));-  ASSERT_EQ(1, deleted_keys_.size());--  cache_->Release(h2);-  ASSERT_EQ(2, deleted_keys_.size());-  ASSERT_EQ(100, deleted_keys_[1]);-  ASSERT_EQ(102, deleted_values_[1]);-}--TEST(CacheTest, EvictionPolicy) {-  Insert(100, 101);-  Insert(200, 201);--  // Frequently used entry must be kept around-  for (int i = 0; i < kCacheSize + 100; i++) {-    Insert(1000+i, 2000+i);-    ASSERT_EQ(2000+i, Lookup(1000+i));-    ASSERT_EQ(101, Lookup(100));-  }-  ASSERT_EQ(101, Lookup(100));-  ASSERT_EQ(-1, Lookup(200));-}--TEST(CacheTest, HeavyEntries) {-  // Add a bunch of light and heavy entries and then count the combined-  // size of items still in the cache, which must be approximately the-  // same as the total capacity.-  const int kLight = 1;-  const int kHeavy = 10;-  int added = 0;-  int index = 0;-  while (added < 2*kCacheSize) {-    const int weight = (index & 1) ? kLight : kHeavy;-    Insert(index, 1000+index, weight);-    added += weight;-    index++;-  }--  int cached_weight = 0;-  for (int i = 0; i < index; i++) {-    const int weight = (i & 1 ? kLight : kHeavy);-    int r = Lookup(i);-    if (r >= 0) {-      cached_weight += weight;-      ASSERT_EQ(1000+i, r);-    }-  }-  ASSERT_LE(cached_weight, kCacheSize + kCacheSize/10);-}--TEST(CacheTest, NewId) {-  uint64_t a = cache_->NewId();-  uint64_t b = cache_->NewId();-  ASSERT_NE(a, b);-}--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/util/coding.cc
@@ -1,194 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "util/coding.h"--namespace leveldb {--void EncodeFixed32(char* buf, uint32_t value) {-#if __BYTE_ORDER == __LITTLE_ENDIAN-  memcpy(buf, &value, sizeof(value));-#else-  buf[0] = value & 0xff;-  buf[1] = (value >> 8) & 0xff;-  buf[2] = (value >> 16) & 0xff;-  buf[3] = (value >> 24) & 0xff;-#endif-}--void EncodeFixed64(char* buf, uint64_t value) {-#if __BYTE_ORDER == __LITTLE_ENDIAN-  memcpy(buf, &value, sizeof(value));-#else-  buf[0] = value & 0xff;-  buf[1] = (value >> 8) & 0xff;-  buf[2] = (value >> 16) & 0xff;-  buf[3] = (value >> 24) & 0xff;-  buf[4] = (value >> 32) & 0xff;-  buf[5] = (value >> 40) & 0xff;-  buf[6] = (value >> 48) & 0xff;-  buf[7] = (value >> 56) & 0xff;-#endif-}--void PutFixed32(std::string* dst, uint32_t value) {-  char buf[sizeof(value)];-  EncodeFixed32(buf, value);-  dst->append(buf, sizeof(buf));-}--void PutFixed64(std::string* dst, uint64_t value) {-  char buf[sizeof(value)];-  EncodeFixed64(buf, value);-  dst->append(buf, sizeof(buf));-}--char* EncodeVarint32(char* dst, uint32_t v) {-  // Operate on characters as unsigneds-  unsigned char* ptr = reinterpret_cast<unsigned char*>(dst);-  static const int B = 128;-  if (v < (1<<7)) {-    *(ptr++) = v;-  } else if (v < (1<<14)) {-    *(ptr++) = v | B;-    *(ptr++) = v>>7;-  } else if (v < (1<<21)) {-    *(ptr++) = v | B;-    *(ptr++) = (v>>7) | B;-    *(ptr++) = v>>14;-  } else if (v < (1<<28)) {-    *(ptr++) = v | B;-    *(ptr++) = (v>>7) | B;-    *(ptr++) = (v>>14) | B;-    *(ptr++) = v>>21;-  } else {-    *(ptr++) = v | B;-    *(ptr++) = (v>>7) | B;-    *(ptr++) = (v>>14) | B;-    *(ptr++) = (v>>21) | B;-    *(ptr++) = v>>28;-  }-  return reinterpret_cast<char*>(ptr);-}--void PutVarint32(std::string* dst, uint32_t v) {-  char buf[5];-  char* ptr = EncodeVarint32(buf, v);-  dst->append(buf, ptr - buf);-}--char* EncodeVarint64(char* dst, uint64_t v) {-  static const int B = 128;-  unsigned char* ptr = reinterpret_cast<unsigned char*>(dst);-  while (v >= B) {-    *(ptr++) = (v & (B-1)) | B;-    v >>= 7;-  }-  *(ptr++) = static_cast<unsigned char>(v);-  return reinterpret_cast<char*>(ptr);-}--void PutVarint64(std::string* dst, uint64_t v) {-  char buf[10];-  char* ptr = EncodeVarint64(buf, v);-  dst->append(buf, ptr - buf);-}--void PutLengthPrefixedSlice(std::string* dst, const Slice& value) {-  PutVarint32(dst, value.size());-  dst->append(value.data(), value.size());-}--int VarintLength(uint64_t v) {-  int len = 1;-  while (v >= 128) {-    v >>= 7;-    len++;-  }-  return len;-}--const char* GetVarint32PtrFallback(const char* p,-                                   const char* limit,-                                   uint32_t* value) {-  uint32_t result = 0;-  for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7) {-    uint32_t byte = *(reinterpret_cast<const unsigned char*>(p));-    p++;-    if (byte & 128) {-      // More bytes are present-      result |= ((byte & 127) << shift);-    } else {-      result |= (byte << shift);-      *value = result;-      return reinterpret_cast<const char*>(p);-    }-  }-  return NULL;-}--bool GetVarint32(Slice* input, uint32_t* value) {-  const char* p = input->data();-  const char* limit = p + input->size();-  const char* q = GetVarint32Ptr(p, limit, value);-  if (q == NULL) {-    return false;-  } else {-    *input = Slice(q, limit - q);-    return true;-  }-}--const char* GetVarint64Ptr(const char* p, const char* limit, uint64_t* value) {-  uint64_t result = 0;-  for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7) {-    uint64_t byte = *(reinterpret_cast<const unsigned char*>(p));-    p++;-    if (byte & 128) {-      // More bytes are present-      result |= ((byte & 127) << shift);-    } else {-      result |= (byte << shift);-      *value = result;-      return reinterpret_cast<const char*>(p);-    }-  }-  return NULL;-}--bool GetVarint64(Slice* input, uint64_t* value) {-  const char* p = input->data();-  const char* limit = p + input->size();-  const char* q = GetVarint64Ptr(p, limit, value);-  if (q == NULL) {-    return false;-  } else {-    *input = Slice(q, limit - q);-    return true;-  }-}--const char* GetLengthPrefixedSlice(const char* p, const char* limit,-                                   Slice* result) {-  uint32_t len;-  p = GetVarint32Ptr(p, limit, &len);-  if (p == NULL) return NULL;-  if (p + len > limit) return NULL;-  *result = Slice(p, len);-  return p + len;-}--bool GetLengthPrefixedSlice(Slice* input, Slice* result) {-  uint32_t len;-  if (GetVarint32(input, &len) &&-      input->size() >= len) {-    *result = Slice(input->data(), len);-    input->remove_prefix(len);-    return true;-  } else {-    return false;-  }-}--}  // namespace leveldb
− cbits/leveldb/util/coding.h
@@ -1,104 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// Endian-neutral encoding:-// * Fixed-length numbers are encoded with least-significant byte first-// * In addition we support variable length "varint" encoding-// * Strings are encoded prefixed by their length in varint format--#ifndef STORAGE_LEVELDB_UTIL_CODING_H_-#define STORAGE_LEVELDB_UTIL_CODING_H_--#include <stdint.h>-#include <string.h>-#include <string>-#include "leveldb/slice.h"-#include "port/port.h"--namespace leveldb {--// Standard Put... routines append to a string-extern void PutFixed32(std::string* dst, uint32_t value);-extern void PutFixed64(std::string* dst, uint64_t value);-extern void PutVarint32(std::string* dst, uint32_t value);-extern void PutVarint64(std::string* dst, uint64_t value);-extern void PutLengthPrefixedSlice(std::string* dst, const Slice& value);--// Standard Get... routines parse a value from the beginning of a Slice-// and advance the slice past the parsed value.-extern bool GetVarint32(Slice* input, uint32_t* value);-extern bool GetVarint64(Slice* input, uint64_t* value);-extern bool GetLengthPrefixedSlice(Slice* input, Slice* result);--// Pointer-based variants of GetVarint...  These either store a value-// in *v and return a pointer just past the parsed value, or return-// NULL on error.  These routines only look at bytes in the range-// [p..limit-1]-extern const char* GetVarint32Ptr(const char* p,const char* limit, uint32_t* v);-extern const char* GetVarint64Ptr(const char* p,const char* limit, uint64_t* v);--// Returns the length of the varint32 or varint64 encoding of "v"-extern int VarintLength(uint64_t v);--// Lower-level versions of Put... that write directly into a character buffer-// REQUIRES: dst has enough space for the value being written-extern void EncodeFixed32(char* dst, uint32_t value);-extern void EncodeFixed64(char* dst, uint64_t value);--// Lower-level versions of Put... that write directly into a character buffer-// and return a pointer just past the last byte written.-// REQUIRES: dst has enough space for the value being written-extern char* EncodeVarint32(char* dst, uint32_t value);-extern char* EncodeVarint64(char* dst, uint64_t value);--// Lower-level versions of Get... that read directly from a character buffer-// without any bounds checking.--inline uint32_t DecodeFixed32(const char* ptr) {-  if (port::kLittleEndian) {-    // Load the raw bytes-    uint32_t result;-    memcpy(&result, ptr, sizeof(result));  // gcc optimizes this to a plain load-    return result;-  } else {-    return ((static_cast<uint32_t>(static_cast<unsigned char>(ptr[0])))-        | (static_cast<uint32_t>(static_cast<unsigned char>(ptr[1])) << 8)-        | (static_cast<uint32_t>(static_cast<unsigned char>(ptr[2])) << 16)-        | (static_cast<uint32_t>(static_cast<unsigned char>(ptr[3])) << 24));-  }-}--inline uint64_t DecodeFixed64(const char* ptr) {-  if (port::kLittleEndian) {-    // Load the raw bytes-    uint64_t result;-    memcpy(&result, ptr, sizeof(result));  // gcc optimizes this to a plain load-    return result;-  } else {-    uint64_t lo = DecodeFixed32(ptr);-    uint64_t hi = DecodeFixed32(ptr + 4);-    return (hi << 32) | lo;-  }-}--// Internal routine for use by fallback path of GetVarint32Ptr-extern const char* GetVarint32PtrFallback(const char* p,-                                          const char* limit,-                                          uint32_t* value);-inline const char* GetVarint32Ptr(const char* p,-                                  const char* limit,-                                  uint32_t* value) {-  if (p < limit) {-    uint32_t result = *(reinterpret_cast<const unsigned char*>(p));-    if ((result & 128) == 0) {-      *value = result;-      return p + 1;-    }-  }-  return GetVarint32PtrFallback(p, limit, value);-}--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_UTIL_CODING_H_
− cbits/leveldb/util/coding_test.cc
@@ -1,173 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "util/coding.h"--#include "util/testharness.h"--namespace leveldb {--class Coding { };--TEST(Coding, Fixed32) {-  std::string s;-  for (uint32_t v = 0; v < 100000; v++) {-    PutFixed32(&s, v);-  }--  const char* p = s.data();-  for (uint32_t v = 0; v < 100000; v++) {-    uint32_t actual = DecodeFixed32(p);-    ASSERT_EQ(v, actual);-    p += sizeof(uint32_t);-  }-}--TEST(Coding, Fixed64) {-  std::string s;-  for (int power = 0; power <= 63; power++) {-    uint64_t v = static_cast<uint64_t>(1) << power;-    PutFixed64(&s, v - 1);-    PutFixed64(&s, v + 0);-    PutFixed64(&s, v + 1);-  }--  const char* p = s.data();-  for (int power = 0; power <= 63; power++) {-    uint64_t v = static_cast<uint64_t>(1) << power;-    uint64_t actual;-    actual = DecodeFixed64(p);-    ASSERT_EQ(v-1, actual);-    p += sizeof(uint64_t);--    actual = DecodeFixed64(p);-    ASSERT_EQ(v+0, actual);-    p += sizeof(uint64_t);--    actual = DecodeFixed64(p);-    ASSERT_EQ(v+1, actual);-    p += sizeof(uint64_t);-  }-}--TEST(Coding, Varint32) {-  std::string s;-  for (uint32_t i = 0; i < (32 * 32); i++) {-    uint32_t v = (i / 32) << (i % 32);-    PutVarint32(&s, v);-  }--  const char* p = s.data();-  const char* limit = p + s.size();-  for (uint32_t i = 0; i < (32 * 32); i++) {-    uint32_t expected = (i / 32) << (i % 32);-    uint32_t actual;-    const char* start = p;-    p = GetVarint32Ptr(p, limit, &actual);-    ASSERT_TRUE(p != NULL);-    ASSERT_EQ(expected, actual);-    ASSERT_EQ(VarintLength(actual), p - start);-  }-  ASSERT_EQ(p, s.data() + s.size());-}--TEST(Coding, Varint64) {-  // Construct the list of values to check-  std::vector<uint64_t> values;-  // Some special values-  values.push_back(0);-  values.push_back(100);-  values.push_back(~static_cast<uint64_t>(0));-  values.push_back(~static_cast<uint64_t>(0) - 1);-  for (uint32_t k = 0; k < 64; k++) {-    // Test values near powers of two-    const uint64_t power = 1ull << k;-    values.push_back(power);-    values.push_back(power-1);-    values.push_back(power+1);-  };--  std::string s;-  for (int i = 0; i < values.size(); i++) {-    PutVarint64(&s, values[i]);-  }--  const char* p = s.data();-  const char* limit = p + s.size();-  for (int i = 0; i < values.size(); i++) {-    ASSERT_TRUE(p < limit);-    uint64_t actual;-    const char* start = p;-    p = GetVarint64Ptr(p, limit, &actual);-    ASSERT_TRUE(p != NULL);-    ASSERT_EQ(values[i], actual);-    ASSERT_EQ(VarintLength(actual), p - start);-  }-  ASSERT_EQ(p, limit);--}--TEST(Coding, Varint32Overflow) {-  uint32_t result;-  std::string input("\x81\x82\x83\x84\x85\x11");-  ASSERT_TRUE(GetVarint32Ptr(input.data(), input.data() + input.size(), &result)-              == NULL);-}--TEST(Coding, Varint32Truncation) {-  uint32_t large_value = (1u << 31) + 100;-  std::string s;-  PutVarint32(&s, large_value);-  uint32_t result;-  for (int len = 0; len < s.size() - 1; len++) {-    ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + len, &result) == NULL);-  }-  ASSERT_TRUE(GetVarint32Ptr(s.data(), s.data() + s.size(), &result) != NULL);-  ASSERT_EQ(large_value, result);-}--TEST(Coding, Varint64Overflow) {-  uint64_t result;-  std::string input("\x81\x82\x83\x84\x85\x81\x82\x83\x84\x85\x11");-  ASSERT_TRUE(GetVarint64Ptr(input.data(), input.data() + input.size(), &result)-              == NULL);-}--TEST(Coding, Varint64Truncation) {-  uint64_t large_value = (1ull << 63) + 100ull;-  std::string s;-  PutVarint64(&s, large_value);-  uint64_t result;-  for (int len = 0; len < s.size() - 1; len++) {-    ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + len, &result) == NULL);-  }-  ASSERT_TRUE(GetVarint64Ptr(s.data(), s.data() + s.size(), &result) != NULL);-  ASSERT_EQ(large_value, result);-}--TEST(Coding, Strings) {-  std::string s;-  PutLengthPrefixedSlice(&s, Slice(""));-  PutLengthPrefixedSlice(&s, Slice("foo"));-  PutLengthPrefixedSlice(&s, Slice("bar"));-  PutLengthPrefixedSlice(&s, Slice(std::string(200, 'x')));--  Slice input(s);-  Slice v;-  ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v));-  ASSERT_EQ("", v.ToString());-  ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v));-  ASSERT_EQ("foo", v.ToString());-  ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v));-  ASSERT_EQ("bar", v.ToString());-  ASSERT_TRUE(GetLengthPrefixedSlice(&input, &v));-  ASSERT_EQ(std::string(200, 'x'), v.ToString());-  ASSERT_EQ("", input.ToString());-}--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/util/comparator.cc
@@ -1,76 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include <algorithm>-#include <stdint.h>-#include "leveldb/comparator.h"-#include "leveldb/slice.h"-#include "util/logging.h"--namespace leveldb {--Comparator::~Comparator() { }--namespace {-class BytewiseComparatorImpl : public Comparator {- public:-  BytewiseComparatorImpl() { }--  virtual const char* Name() const {-    return "leveldb.BytewiseComparator";-  }--  virtual int Compare(const Slice& a, const Slice& b) const {-    return a.compare(b);-  }--  virtual void FindShortestSeparator(-      std::string* start,-      const Slice& limit) const {-    // Find length of common prefix-    size_t min_length = std::min(start->size(), limit.size());-    size_t diff_index = 0;-    while ((diff_index < min_length) &&-           ((*start)[diff_index] == limit[diff_index])) {-      diff_index++;-    }--    if (diff_index >= min_length) {-      // Do not shorten if one string is a prefix of the other-    } else {-      uint8_t diff_byte = static_cast<uint8_t>((*start)[diff_index]);-      if (diff_byte < static_cast<uint8_t>(0xff) &&-          diff_byte + 1 < static_cast<uint8_t>(limit[diff_index])) {-        (*start)[diff_index]++;-        start->resize(diff_index + 1);-        assert(Compare(*start, limit) < 0);-      }-    }-  }--  virtual void FindShortSuccessor(std::string* key) const {-    // Find first character that can be incremented-    size_t n = key->size();-    for (size_t i = 0; i < n; i++) {-      const uint8_t byte = (*key)[i];-      if (byte != static_cast<uint8_t>(0xff)) {-        (*key)[i] = byte + 1;-        key->resize(i+1);-        return;-      }-    }-    // *key is a run of 0xffs.  Leave it alone.-  }-};-}  // namespace--// Intentionally not destroyed to prevent destructor racing-// with background threads.-static const Comparator* bytewise = new BytewiseComparatorImpl;--const Comparator* BytewiseComparator() {-  return bytewise;-}--}  // namespace leveldb
− cbits/leveldb/util/crc32c.cc
@@ -1,332 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// A portable implementation of crc32c, optimized to handle-// four bytes at a time.--#include "util/crc32c.h"--#include <stdint.h>-#include "util/coding.h"--namespace leveldb {-namespace crc32c {--static const uint32_t table0_[256] = {-  0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4,-  0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,-  0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,-  0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,-  0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,-  0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,-  0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,-  0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,-  0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,-  0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,-  0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,-  0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,-  0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,-  0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,-  0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,-  0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,-  0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,-  0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,-  0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,-  0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,-  0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,-  0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,-  0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,-  0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,-  0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,-  0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,-  0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,-  0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,-  0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,-  0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,-  0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,-  0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,-  0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,-  0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,-  0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,-  0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,-  0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,-  0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,-  0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,-  0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,-  0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,-  0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,-  0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,-  0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,-  0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,-  0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,-  0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,-  0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,-  0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,-  0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,-  0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,-  0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,-  0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,-  0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,-  0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,-  0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,-  0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,-  0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,-  0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,-  0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,-  0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,-  0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,-  0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,-  0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351-};-static const uint32_t table1_[256] = {-  0x00000000, 0x13a29877, 0x274530ee, 0x34e7a899,-  0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945,-  0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21,-  0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd,-  0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0x0b225918,-  0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4,-  0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0,-  0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c,-  0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b,-  0x310182de, 0x22a31aa9, 0x1644b230, 0x05e62a47,-  0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823,-  0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff,-  0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a,-  0x0ec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6,-  0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2,-  0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e,-  0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d,-  0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41,-  0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25,-  0x2c896460, 0x3f2bfc17, 0x0bcc548e, 0x186eccf9,-  0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c,-  0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0,-  0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4,-  0x134c95e1, 0x00ee0d96, 0x3409a50f, 0x27ab3d78,-  0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f,-  0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43,-  0x1d88e6be, 0x0e2a7ec9, 0x3acdd650, 0x296f4e27,-  0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb,-  0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e,-  0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2,-  0x224d173f, 0x31ef8f48, 0x050827d1, 0x16aabfa6,-  0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a,-  0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260,-  0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc,-  0x66d73941, 0x7575a136, 0x419209af, 0x523091d8,-  0x285d589d, 0x3bffc0ea, 0x0f186873, 0x1cbaf004,-  0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1,-  0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d,-  0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059,-  0x1798a91c, 0x043a316b, 0x30dd99f2, 0x237f0185,-  0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162,-  0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be,-  0x195cda43, 0x0afe4234, 0x3e19eaad, 0x2dbb72da,-  0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306,-  0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3,-  0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f,-  0x26992bc2, 0x353bb3b5, 0x01dc1b2c, 0x127e835b,-  0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287,-  0x04d43cfd, 0x1776a48a, 0x23910c13, 0x30339464,-  0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8,-  0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc,-  0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600,-  0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0x0ff665e5,-  0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439,-  0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d,-  0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781,-  0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766,-  0x35d5be23, 0x26772654, 0x12908ecd, 0x013216ba,-  0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de,-  0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502,-  0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7,-  0x0a104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b,-  0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f,-  0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483-};-static const uint32_t table2_[256] = {-  0x00000000, 0xa541927e, 0x4f6f520d, 0xea2ec073,-  0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469,-  0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6,-  0xa68f9adf, 0x03ce08a1, 0xe9e0c8d2, 0x4ca15aac,-  0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9,-  0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x045219e3,-  0x48f3434f, 0xedb2d131, 0x079c1142, 0xa2dd833c,-  0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726,-  0xe144fb14, 0x4405696a, 0xae2ba919, 0x0b6a3b67,-  0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d,-  0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2,-  0x47cb61cb, 0xe28af3b5, 0x08a433c6, 0xade5a1b8,-  0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed,-  0x0f382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7,-  0xa9b7b85b, 0x0cf62a25, 0xe6d8ea56, 0x43997828,-  0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32,-  0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa,-  0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0,-  0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f,-  0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75,-  0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20,-  0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a,-  0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5,-  0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff,-  0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe,-  0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4,-  0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b,-  0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161,-  0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634,-  0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e,-  0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1,-  0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb,-  0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730,-  0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a,-  0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5,-  0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def,-  0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba,-  0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0,-  0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f,-  0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065,-  0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24,-  0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e,-  0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1,-  0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb,-  0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae,-  0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4,-  0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b,-  0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71,-  0x4c42f79a, 0xe90365e4, 0x032da597, 0xa66c37e9,-  0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3,-  0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c,-  0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0x00e3ad36,-  0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63,-  0xa23e2e0a, 0x077fbc74, 0xed517c07, 0x4810ee79,-  0x04b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6,-  0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc,-  0xad060c8e, 0x08479ef0, 0xe2695e83, 0x4728ccfd,-  0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7,-  0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238,-  0x0b899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622,-  0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177,-  0x437ad51e, 0xe63b4760, 0x0c158713, 0xa954156d,-  0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0x0fdb8fb2,-  0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8-};-static const uint32_t table3_[256] = {-  0x00000000, 0xdd45aab8, 0xbf672381, 0x62228939,-  0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca,-  0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf,-  0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c,-  0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804,-  0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7,-  0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2,-  0x6402e328, 0xb9474990, 0xdb65c0a9, 0x06206a11,-  0xd725148b, 0x0a60be33, 0x6842370a, 0xb5079db2,-  0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41,-  0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54,-  0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7,-  0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f,-  0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c,-  0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69,-  0xb327f7a3, 0x6e625d1b, 0x0c40d422, 0xd1057e9a,-  0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de,-  0xd0846e14, 0x0dc1c4ac, 0x6fe34d95, 0xb2a6e72d,-  0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538,-  0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb,-  0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3,-  0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610,-  0xb4868d3c, 0x69c32784, 0x0be1aebd, 0xd6a40405,-  0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6,-  0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255,-  0x07a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6,-  0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3,-  0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040,-  0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368,-  0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b,-  0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x0181108e,-  0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d,-  0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006,-  0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5,-  0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0,-  0xdfc69b2a, 0x02833192, 0x60a1b8ab, 0xbde41213,-  0xbbc47802, 0x6681d2ba, 0x04a35b83, 0xd9e6f13b,-  0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8,-  0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd,-  0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e,-  0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d,-  0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e,-  0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b,-  0x08e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698,-  0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0x0ec3e5b0,-  0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443,-  0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656,-  0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5,-  0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1,-  0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12,-  0x0f42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07,-  0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4,-  0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc,-  0x6b401616, 0xb605bcae, 0xd4273597, 0x09629f2f,-  0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a,-  0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9,-  0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a,-  0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99,-  0xd867e1b5, 0x05224b0d, 0x6700c234, 0xba45688c,-  0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f,-  0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57,-  0xbc65029d, 0x6120a825, 0x0302211c, 0xde478ba4,-  0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1,-  0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842-};--// Used to fetch a naturally-aligned 32-bit word in little endian byte-order-static inline uint32_t LE_LOAD32(const uint8_t *p) {-  return DecodeFixed32(reinterpret_cast<const char*>(p));-}--uint32_t Extend(uint32_t crc, const char* buf, size_t size) {-  const uint8_t *p = reinterpret_cast<const uint8_t *>(buf);-  const uint8_t *e = p + size;-  uint32_t l = crc ^ 0xffffffffu;--#define STEP1 do {                              \-    int c = (l & 0xff) ^ *p++;                  \-    l = table0_[c] ^ (l >> 8);                  \-} while (0)-#define STEP4 do {                              \-    uint32_t c = l ^ LE_LOAD32(p);              \-    p += 4;                                     \-    l = table3_[c & 0xff] ^                     \-        table2_[(c >> 8) & 0xff] ^              \-        table1_[(c >> 16) & 0xff] ^             \-        table0_[c >> 24];                       \-} while (0)--  // Point x at first 4-byte aligned byte in string.  This might be-  // just past the end of the string.-  const uintptr_t pval = reinterpret_cast<uintptr_t>(p);-  const uint8_t* x = reinterpret_cast<const uint8_t*>(((pval + 3) >> 2) << 2);-  if (x <= e) {-    // Process bytes until finished or p is 4-byte aligned-    while (p != x) {-      STEP1;-    }-  }-  // Process bytes 16 at a time-  while ((e-p) >= 16) {-    STEP4; STEP4; STEP4; STEP4;-  }-  // Process bytes 4 at a time-  while ((e-p) >= 4) {-    STEP4;-  }-  // Process the last few bytes-  while (p != e) {-    STEP1;-  }-#undef STEP4-#undef STEP1-  return l ^ 0xffffffffu;-}--}  // namespace crc32c-}  // namespace leveldb
− cbits/leveldb/util/crc32c.h
@@ -1,45 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_UTIL_CRC32C_H_-#define STORAGE_LEVELDB_UTIL_CRC32C_H_--#include <stddef.h>-#include <stdint.h>--namespace leveldb {-namespace crc32c {--// Return the crc32c of concat(A, data[0,n-1]) where init_crc is the-// crc32c of some string A.  Extend() is often used to maintain the-// crc32c of a stream of data.-extern uint32_t Extend(uint32_t init_crc, const char* data, size_t n);--// Return the crc32c of data[0,n-1]-inline uint32_t Value(const char* data, size_t n) {-  return Extend(0, data, n);-}--static const uint32_t kMaskDelta = 0xa282ead8ul;--// Return a masked representation of crc.-//-// Motivation: it is problematic to compute the CRC of a string that-// contains embedded CRCs.  Therefore we recommend that CRCs stored-// somewhere (e.g., in files) should be masked before being stored.-inline uint32_t Mask(uint32_t crc) {-  // Rotate right by 15 bits and add a constant.-  return ((crc >> 15) | (crc << 17)) + kMaskDelta;-}--// Return the crc whose masked representation is masked_crc.-inline uint32_t Unmask(uint32_t masked_crc) {-  uint32_t rot = masked_crc - kMaskDelta;-  return ((rot >> 17) | (rot << 15));-}--}  // namespace crc32c-}  // namespace leveldb--#endif  // STORAGE_LEVELDB_UTIL_CRC32C_H_
− cbits/leveldb/util/crc32c_test.cc
@@ -1,72 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "util/crc32c.h"-#include "util/testharness.h"--namespace leveldb {-namespace crc32c {--class CRC { };--TEST(CRC, StandardResults) {-  // From rfc3720 section B.4.-  char buf[32];--  memset(buf, 0, sizeof(buf));-  ASSERT_EQ(0x8a9136aa, Value(buf, sizeof(buf)));--  memset(buf, 0xff, sizeof(buf));-  ASSERT_EQ(0x62a8ab43, Value(buf, sizeof(buf)));--  for (int i = 0; i < 32; i++) {-    buf[i] = i;-  }-  ASSERT_EQ(0x46dd794e, Value(buf, sizeof(buf)));--  for (int i = 0; i < 32; i++) {-    buf[i] = 31 - i;-  }-  ASSERT_EQ(0x113fdb5c, Value(buf, sizeof(buf)));--  unsigned char data[48] = {-    0x01, 0xc0, 0x00, 0x00,-    0x00, 0x00, 0x00, 0x00,-    0x00, 0x00, 0x00, 0x00,-    0x00, 0x00, 0x00, 0x00,-    0x14, 0x00, 0x00, 0x00,-    0x00, 0x00, 0x04, 0x00,-    0x00, 0x00, 0x00, 0x14,-    0x00, 0x00, 0x00, 0x18,-    0x28, 0x00, 0x00, 0x00,-    0x00, 0x00, 0x00, 0x00,-    0x02, 0x00, 0x00, 0x00,-    0x00, 0x00, 0x00, 0x00,-  };-  ASSERT_EQ(0xd9963a56, Value(reinterpret_cast<char*>(data), sizeof(data)));-}--TEST(CRC, Values) {-  ASSERT_NE(Value("a", 1), Value("foo", 3));-}--TEST(CRC, Extend) {-  ASSERT_EQ(Value("hello world", 11),-            Extend(Value("hello ", 6), "world", 5));-}--TEST(CRC, Mask) {-  uint32_t crc = Value("foo", 3);-  ASSERT_NE(crc, Mask(crc));-  ASSERT_NE(crc, Mask(Mask(crc)));-  ASSERT_EQ(crc, Unmask(Mask(crc)));-  ASSERT_EQ(crc, Unmask(Unmask(Mask(Mask(crc)))));-}--}  // namespace crc32c-}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/util/env.cc
@@ -1,96 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "leveldb/env.h"--namespace leveldb {--Env::~Env() {-}--SequentialFile::~SequentialFile() {-}--RandomAccessFile::~RandomAccessFile() {-}--WritableFile::~WritableFile() {-}--Logger::~Logger() {-}--FileLock::~FileLock() {-}--void Log(Logger* info_log, const char* format, ...) {-  if (info_log != NULL) {-    va_list ap;-    va_start(ap, format);-    info_log->Logv(format, ap);-    va_end(ap);-  }-}--static Status DoWriteStringToFile(Env* env, const Slice& data,-                                  const std::string& fname,-                                  bool should_sync) {-  WritableFile* file;-  Status s = env->NewWritableFile(fname, &file);-  if (!s.ok()) {-    return s;-  }-  s = file->Append(data);-  if (s.ok() && should_sync) {-    s = file->Sync();-  }-  if (s.ok()) {-    s = file->Close();-  }-  delete file;  // Will auto-close if we did not close above-  if (!s.ok()) {-    env->DeleteFile(fname);-  }-  return s;-}--Status WriteStringToFile(Env* env, const Slice& data,-                         const std::string& fname) {-  return DoWriteStringToFile(env, data, fname, false);-}--Status WriteStringToFileSync(Env* env, const Slice& data,-                             const std::string& fname) {-  return DoWriteStringToFile(env, data, fname, true);-}--Status ReadFileToString(Env* env, const std::string& fname, std::string* data) {-  data->clear();-  SequentialFile* file;-  Status s = env->NewSequentialFile(fname, &file);-  if (!s.ok()) {-    return s;-  }-  static const int kBufferSize = 8192;-  char* space = new char[kBufferSize];-  while (true) {-    Slice fragment;-    s = file->Read(kBufferSize, &fragment, space);-    if (!s.ok()) {-      break;-    }-    data->append(fragment.data(), fragment.size());-    if (fragment.empty()) {-      break;-    }-  }-  delete[] space;-  delete file;-  return s;-}--EnvWrapper::~EnvWrapper() {-}--}  // namespace leveldb
− cbits/leveldb/util/env_posix.cc
@@ -1,567 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include <deque>-#include <dirent.h>-#include <errno.h>-#include <fcntl.h>-#include <pthread.h>-#include <stdio.h>-#include <stdlib.h>-#include <string.h>-#include <sys/mman.h>-#include <sys/stat.h>-#include <sys/time.h>-#include <sys/types.h>-#include <time.h>-#include <unistd.h>-#if defined(LEVELDB_PLATFORM_ANDROID)-#include <sys/stat.h>-#endif-#include "leveldb/env.h"-#include "leveldb/slice.h"-#include "port/port.h"-#include "util/logging.h"-#include "util/posix_logger.h"--namespace leveldb {--namespace {--static Status IOError(const std::string& context, int err_number) {-  return Status::IOError(context, strerror(err_number));-}--class PosixSequentialFile: public SequentialFile {- private:-  std::string filename_;-  FILE* file_;-- public:-  PosixSequentialFile(const std::string& fname, FILE* f)-      : filename_(fname), file_(f) { }-  virtual ~PosixSequentialFile() { fclose(file_); }--  virtual Status Read(size_t n, Slice* result, char* scratch) {-    Status s;-    size_t r = fread_unlocked(scratch, 1, n, file_);-    *result = Slice(scratch, r);-    if (r < n) {-      if (feof(file_)) {-        // We leave status as ok if we hit the end of the file-      } else {-        // A partial read with an error: return a non-ok status-        s = IOError(filename_, errno);-      }-    }-    return s;-  }--  virtual Status Skip(uint64_t n) {-    if (fseek(file_, n, SEEK_CUR)) {-      return IOError(filename_, errno);-    }-    return Status::OK();-  }-};--class PosixRandomAccessFile: public RandomAccessFile {- private:-  std::string filename_;-  int fd_;-- public:-  PosixRandomAccessFile(const std::string& fname, int fd)-      : filename_(fname), fd_(fd) { }-  virtual ~PosixRandomAccessFile() { close(fd_); }--  virtual Status Read(uint64_t offset, size_t n, Slice* result,-                      char* scratch) const {-    Status s;-    ssize_t r = pread(fd_, scratch, n, static_cast<off_t>(offset));-    *result = Slice(scratch, (r < 0) ? 0 : r);-    if (r < 0) {-      // An error: return a non-ok status-      s = IOError(filename_, errno);-    }-    return s;-  }-};--// We preallocate up to an extra megabyte and use memcpy to append new-// data to the file.  This is safe since we either properly close the-// file before reading from it, or for log files, the reading code-// knows enough to skip zero suffixes.-class PosixMmapFile : public WritableFile {- private:-  std::string filename_;-  int fd_;-  size_t page_size_;-  size_t map_size_;       // How much extra memory to map at a time-  char* base_;            // The mapped region-  char* limit_;           // Limit of the mapped region-  char* dst_;             // Where to write next  (in range [base_,limit_])-  char* last_sync_;       // Where have we synced up to-  uint64_t file_offset_;  // Offset of base_ in file--  // Have we done an munmap of unsynced data?-  bool pending_sync_;--  // Roundup x to a multiple of y-  static size_t Roundup(size_t x, size_t y) {-    return ((x + y - 1) / y) * y;-  }--  size_t TruncateToPageBoundary(size_t s) {-    s -= (s & (page_size_ - 1));-    assert((s % page_size_) == 0);-    return s;-  }--  bool UnmapCurrentRegion() {-    bool result = true;-    if (base_ != NULL) {-      if (last_sync_ < limit_) {-        // Defer syncing this data until next Sync() call, if any-        pending_sync_ = true;-      }-      if (munmap(base_, limit_ - base_) != 0) {-        result = false;-      }-      file_offset_ += limit_ - base_;-      base_ = NULL;-      limit_ = NULL;-      last_sync_ = NULL;-      dst_ = NULL;--      // Increase the amount we map the next time, but capped at 1MB-      if (map_size_ < (1<<20)) {-        map_size_ *= 2;-      }-    }-    return result;-  }--  bool MapNewRegion() {-    assert(base_ == NULL);-    if (ftruncate(fd_, file_offset_ + map_size_) < 0) {-      return false;-    }-    void* ptr = mmap(NULL, map_size_, PROT_READ | PROT_WRITE, MAP_SHARED,-                     fd_, file_offset_);-    if (ptr == MAP_FAILED) {-      return false;-    }-    base_ = reinterpret_cast<char*>(ptr);-    limit_ = base_ + map_size_;-    dst_ = base_;-    last_sync_ = base_;-    return true;-  }-- public:-  PosixMmapFile(const std::string& fname, int fd, size_t page_size)-      : filename_(fname),-        fd_(fd),-        page_size_(page_size),-        map_size_(Roundup(65536, page_size)),-        base_(NULL),-        limit_(NULL),-        dst_(NULL),-        last_sync_(NULL),-        file_offset_(0),-        pending_sync_(false) {-    assert((page_size & (page_size - 1)) == 0);-  }---  ~PosixMmapFile() {-    if (fd_ >= 0) {-      PosixMmapFile::Close();-    }-  }--  virtual Status Append(const Slice& data) {-    const char* src = data.data();-    size_t left = data.size();-    while (left > 0) {-      assert(base_ <= dst_);-      assert(dst_ <= limit_);-      size_t avail = limit_ - dst_;-      if (avail == 0) {-        if (!UnmapCurrentRegion() ||-            !MapNewRegion()) {-          return IOError(filename_, errno);-        }-      }--      size_t n = (left <= avail) ? left : avail;-      memcpy(dst_, src, n);-      dst_ += n;-      src += n;-      left -= n;-    }-    return Status::OK();-  }--  virtual Status Close() {-    Status s;-    size_t unused = limit_ - dst_;-    if (!UnmapCurrentRegion()) {-      s = IOError(filename_, errno);-    } else if (unused > 0) {-      // Trim the extra space at the end of the file-      if (ftruncate(fd_, file_offset_ - unused) < 0) {-        s = IOError(filename_, errno);-      }-    }--    if (close(fd_) < 0) {-      if (s.ok()) {-        s = IOError(filename_, errno);-      }-    }--    fd_ = -1;-    base_ = NULL;-    limit_ = NULL;-    return s;-  }--  virtual Status Flush() {-    return Status::OK();-  }--  virtual Status Sync() {-    Status s;--    if (pending_sync_) {-      // Some unmapped data was not synced-      pending_sync_ = false;-      if (fdatasync(fd_) < 0) {-        s = IOError(filename_, errno);-      }-    }--    if (dst_ > last_sync_) {-      // Find the beginnings of the pages that contain the first and last-      // bytes to be synced.-      size_t p1 = TruncateToPageBoundary(last_sync_ - base_);-      size_t p2 = TruncateToPageBoundary(dst_ - base_ - 1);-      last_sync_ = dst_;-      if (msync(base_ + p1, p2 - p1 + page_size_, MS_SYNC) < 0) {-        s = IOError(filename_, errno);-      }-    }--    return s;-  }-};--static int LockOrUnlock(int fd, bool lock) {-  errno = 0;-  struct flock f;-  memset(&f, 0, sizeof(f));-  f.l_type = (lock ? F_WRLCK : F_UNLCK);-  f.l_whence = SEEK_SET;-  f.l_start = 0;-  f.l_len = 0;        // Lock/unlock entire file-  return fcntl(fd, F_SETLK, &f);-}--class PosixFileLock : public FileLock {- public:-  int fd_;-};--class PosixEnv : public Env {- public:-  PosixEnv();-  virtual ~PosixEnv() {-    fprintf(stderr, "Destroying Env::Default()\n");-    exit(1);-  }--  virtual Status NewSequentialFile(const std::string& fname,-                                   SequentialFile** result) {-    FILE* f = fopen(fname.c_str(), "r");-    if (f == NULL) {-      *result = NULL;-      return IOError(fname, errno);-    } else {-      *result = new PosixSequentialFile(fname, f);-      return Status::OK();-    }-  }--  virtual Status NewRandomAccessFile(const std::string& fname,-                                     RandomAccessFile** result) {-    int fd = open(fname.c_str(), O_RDONLY);-    if (fd < 0) {-      *result = NULL;-      return IOError(fname, errno);-    }-    *result = new PosixRandomAccessFile(fname, fd);-    return Status::OK();-  }--  virtual Status NewWritableFile(const std::string& fname,-                                 WritableFile** result) {-    Status s;-    const int fd = open(fname.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0644);-    if (fd < 0) {-      *result = NULL;-      s = IOError(fname, errno);-    } else {-      *result = new PosixMmapFile(fname, fd, page_size_);-    }-    return s;-  }--  virtual bool FileExists(const std::string& fname) {-    return access(fname.c_str(), F_OK) == 0;-  }--  virtual Status GetChildren(const std::string& dir,-                             std::vector<std::string>* result) {-    result->clear();-    DIR* d = opendir(dir.c_str());-    if (d == NULL) {-      return IOError(dir, errno);-    }-    struct dirent* entry;-    while ((entry = readdir(d)) != NULL) {-      result->push_back(entry->d_name);-    }-    closedir(d);-    return Status::OK();-  }--  virtual Status DeleteFile(const std::string& fname) {-    Status result;-    if (unlink(fname.c_str()) != 0) {-      result = IOError(fname, errno);-    }-    return result;-  };--  virtual Status CreateDir(const std::string& name) {-    Status result;-    if (mkdir(name.c_str(), 0755) != 0) {-      result = IOError(name, errno);-    }-    return result;-  };--  virtual Status DeleteDir(const std::string& name) {-    Status result;-    if (rmdir(name.c_str()) != 0) {-      result = IOError(name, errno);-    }-    return result;-  };--  virtual Status GetFileSize(const std::string& fname, uint64_t* size) {-    Status s;-    struct stat sbuf;-    if (stat(fname.c_str(), &sbuf) != 0) {-      *size = 0;-      s = IOError(fname, errno);-    } else {-      *size = sbuf.st_size;-    }-    return s;-  }--  virtual Status RenameFile(const std::string& src, const std::string& target) {-    Status result;-    if (rename(src.c_str(), target.c_str()) != 0) {-      result = IOError(src, errno);-    }-    return result;-  }--  virtual Status LockFile(const std::string& fname, FileLock** lock) {-    *lock = NULL;-    Status result;-    int fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644);-    if (fd < 0) {-      result = IOError(fname, errno);-    } else if (LockOrUnlock(fd, true) == -1) {-      result = IOError("lock " + fname, errno);-      close(fd);-    } else {-      PosixFileLock* my_lock = new PosixFileLock;-      my_lock->fd_ = fd;-      *lock = my_lock;-    }-    return result;-  }--  virtual Status UnlockFile(FileLock* lock) {-    PosixFileLock* my_lock = reinterpret_cast<PosixFileLock*>(lock);-    Status result;-    if (LockOrUnlock(my_lock->fd_, false) == -1) {-      result = IOError("unlock", errno);-    }-    close(my_lock->fd_);-    delete my_lock;-    return result;-  }--  virtual void Schedule(void (*function)(void*), void* arg);--  virtual void StartThread(void (*function)(void* arg), void* arg);--  virtual Status GetTestDirectory(std::string* result) {-    const char* env = getenv("TEST_TMPDIR");-    if (env && env[0] != '\0') {-      *result = env;-    } else {-      char buf[100];-      snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d", int(geteuid()));-      *result = buf;-    }-    // Directory may already exist-    CreateDir(*result);-    return Status::OK();-  }--  static uint64_t gettid() {-    pthread_t tid = pthread_self();-    uint64_t thread_id = 0;-    memcpy(&thread_id, &tid, std::min(sizeof(thread_id), sizeof(tid)));-    return thread_id;-  }--  virtual Status NewLogger(const std::string& fname, Logger** result) {-    FILE* f = fopen(fname.c_str(), "w");-    if (f == NULL) {-      *result = NULL;-      return IOError(fname, errno);-    } else {-      *result = new PosixLogger(f, &PosixEnv::gettid);-      return Status::OK();-    }-  }--  virtual uint64_t NowMicros() {-    struct timeval tv;-    gettimeofday(&tv, NULL);-    return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;-  }--  virtual void SleepForMicroseconds(int micros) {-    usleep(micros);-  }-- private:-  void PthreadCall(const char* label, int result) {-    if (result != 0) {-      fprintf(stderr, "pthread %s: %s\n", label, strerror(result));-      exit(1);-    }-  }--  // BGThread() is the body of the background thread-  void BGThread();-  static void* BGThreadWrapper(void* arg) {-    reinterpret_cast<PosixEnv*>(arg)->BGThread();-    return NULL;-  }--  size_t page_size_;-  pthread_mutex_t mu_;-  pthread_cond_t bgsignal_;-  pthread_t bgthread_;-  bool started_bgthread_;--  // Entry per Schedule() call-  struct BGItem { void* arg; void (*function)(void*); };-  typedef std::deque<BGItem> BGQueue;-  BGQueue queue_;-};--PosixEnv::PosixEnv() : page_size_(getpagesize()),-                       started_bgthread_(false) {-  PthreadCall("mutex_init", pthread_mutex_init(&mu_, NULL));-  PthreadCall("cvar_init", pthread_cond_init(&bgsignal_, NULL));-}--void PosixEnv::Schedule(void (*function)(void*), void* arg) {-  PthreadCall("lock", pthread_mutex_lock(&mu_));--  // Start background thread if necessary-  if (!started_bgthread_) {-    started_bgthread_ = true;-    PthreadCall(-        "create thread",-        pthread_create(&bgthread_, NULL,  &PosixEnv::BGThreadWrapper, this));-  }--  // If the queue is currently empty, the background thread may currently be-  // waiting.-  if (queue_.empty()) {-    PthreadCall("signal", pthread_cond_signal(&bgsignal_));-  }--  // Add to priority queue-  queue_.push_back(BGItem());-  queue_.back().function = function;-  queue_.back().arg = arg;--  PthreadCall("unlock", pthread_mutex_unlock(&mu_));-}--void PosixEnv::BGThread() {-  while (true) {-    // Wait until there is an item that is ready to run-    PthreadCall("lock", pthread_mutex_lock(&mu_));-    while (queue_.empty()) {-      PthreadCall("wait", pthread_cond_wait(&bgsignal_, &mu_));-    }--    void (*function)(void*) = queue_.front().function;-    void* arg = queue_.front().arg;-    queue_.pop_front();--    PthreadCall("unlock", pthread_mutex_unlock(&mu_));-    (*function)(arg);-  }-}--namespace {-struct StartThreadState {-  void (*user_function)(void*);-  void* arg;-};-}-static void* StartThreadWrapper(void* arg) {-  StartThreadState* state = reinterpret_cast<StartThreadState*>(arg);-  state->user_function(state->arg);-  delete state;-  return NULL;-}--void PosixEnv::StartThread(void (*function)(void* arg), void* arg) {-  pthread_t t;-  StartThreadState* state = new StartThreadState;-  state->user_function = function;-  state->arg = arg;-  PthreadCall("start thread",-              pthread_create(&t, NULL,  &StartThreadWrapper, state));-}--}  // namespace--static pthread_once_t once = PTHREAD_ONCE_INIT;-static Env* default_env;-static void InitDefaultEnv() { default_env = new PosixEnv; }--Env* Env::Default() {-  pthread_once(&once, InitDefaultEnv);-  return default_env;-}--}  // namespace leveldb
− cbits/leveldb/util/env_test.cc
@@ -1,104 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "leveldb/env.h"--#include "port/port.h"-#include "util/testharness.h"--namespace leveldb {--static const int kDelayMicros = 100000;--class EnvPosixTest {- private:-  port::Mutex mu_;-  std::string events_;-- public:-  Env* env_;-  EnvPosixTest() : env_(Env::Default()) { }-};--static void SetBool(void* ptr) {-  reinterpret_cast<port::AtomicPointer*>(ptr)->NoBarrier_Store(ptr);-}--TEST(EnvPosixTest, RunImmediately) {-  port::AtomicPointer called (NULL);-  env_->Schedule(&SetBool, &called);-  Env::Default()->SleepForMicroseconds(kDelayMicros);-  ASSERT_TRUE(called.NoBarrier_Load() != NULL);-}--TEST(EnvPosixTest, RunMany) {-  port::AtomicPointer last_id (NULL);--  struct CB {-    port::AtomicPointer* last_id_ptr;   // Pointer to shared slot-    uintptr_t id;             // Order# for the execution of this callback--    CB(port::AtomicPointer* p, int i) : last_id_ptr(p), id(i) { }--    static void Run(void* v) {-      CB* cb = reinterpret_cast<CB*>(v);-      void* cur = cb->last_id_ptr->NoBarrier_Load();-      ASSERT_EQ(cb->id-1, reinterpret_cast<uintptr_t>(cur));-      cb->last_id_ptr->Release_Store(reinterpret_cast<void*>(cb->id));-    }-  };--  // Schedule in different order than start time-  CB cb1(&last_id, 1);-  CB cb2(&last_id, 2);-  CB cb3(&last_id, 3);-  CB cb4(&last_id, 4);-  env_->Schedule(&CB::Run, &cb1);-  env_->Schedule(&CB::Run, &cb2);-  env_->Schedule(&CB::Run, &cb3);-  env_->Schedule(&CB::Run, &cb4);--  Env::Default()->SleepForMicroseconds(kDelayMicros);-  void* cur = last_id.Acquire_Load();-  ASSERT_EQ(4, reinterpret_cast<uintptr_t>(cur));-}--struct State {-  port::Mutex mu;-  int val;-  int num_running;-};--static void ThreadBody(void* arg) {-  State* s = reinterpret_cast<State*>(arg);-  s->mu.Lock();-  s->val += 1;-  s->num_running -= 1;-  s->mu.Unlock();-}--TEST(EnvPosixTest, StartThread) {-  State state;-  state.val = 0;-  state.num_running = 3;-  for (int i = 0; i < 3; i++) {-    env_->StartThread(&ThreadBody, &state);-  }-  while (true) {-    state.mu.Lock();-    int num = state.num_running;-    state.mu.Unlock();-    if (num == 0) {-      break;-    }-    Env::Default()->SleepForMicroseconds(kDelayMicros);-  }-  ASSERT_EQ(state.val, 3);-}--}  // namespace leveldb--int main(int argc, char** argv) {-  return leveldb::test::RunAllTests();-}
− cbits/leveldb/util/hash.cc
@@ -1,45 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include <string.h>-#include "util/coding.h"-#include "util/hash.h"--namespace leveldb {--uint32_t Hash(const char* data, size_t n, uint32_t seed) {-  // Similar to murmur hash-  const uint32_t m = 0xc6a4a793;-  const uint32_t r = 24;-  const char* limit = data + n;-  uint32_t h = seed ^ (n * m);--  // Pick up four bytes at a time-  while (data + 4 <= limit) {-    uint32_t w = DecodeFixed32(data);-    data += 4;-    h += w;-    h *= m;-    h ^= (h >> 16);-  }--  // Pick up remaining bytes-  switch (limit - data) {-    case 3:-      h += data[2] << 16;-      // fall through-    case 2:-      h += data[1] << 8;-      // fall through-    case 1:-      h += data[0];-      h *= m;-      h ^= (h >> r);-      break;-  }-  return h;-}---}  // namespace leveldb
− cbits/leveldb/util/hash.h
@@ -1,19 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// Simple hash function used for internal data structures--#ifndef STORAGE_LEVELDB_UTIL_HASH_H_-#define STORAGE_LEVELDB_UTIL_HASH_H_--#include <stddef.h>-#include <stdint.h>--namespace leveldb {--extern uint32_t Hash(const char* data, size_t n, uint32_t seed);--}--#endif  // STORAGE_LEVELDB_UTIL_HASH_H_
− cbits/leveldb/util/histogram.cc
@@ -1,139 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include <math.h>-#include <stdio.h>-#include "port/port.h"-#include "util/histogram.h"--namespace leveldb {--const double Histogram::kBucketLimit[kNumBuckets] = {-  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 25, 30, 35, 40, 45,-  50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, 250, 300, 350, 400, 450,-  500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000, 2500, 3000,-  3500, 4000, 4500, 5000, 6000, 7000, 8000, 9000, 10000, 12000, 14000,-  16000, 18000, 20000, 25000, 30000, 35000, 40000, 45000, 50000, 60000,-  70000, 80000, 90000, 100000, 120000, 140000, 160000, 180000, 200000,-  250000, 300000, 350000, 400000, 450000, 500000, 600000, 700000, 800000,-  900000, 1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2500000,-  3000000, 3500000, 4000000, 4500000, 5000000, 6000000, 7000000, 8000000,-  9000000, 10000000, 12000000, 14000000, 16000000, 18000000, 20000000,-  25000000, 30000000, 35000000, 40000000, 45000000, 50000000, 60000000,-  70000000, 80000000, 90000000, 100000000, 120000000, 140000000, 160000000,-  180000000, 200000000, 250000000, 300000000, 350000000, 400000000,-  450000000, 500000000, 600000000, 700000000, 800000000, 900000000,-  1000000000, 1200000000, 1400000000, 1600000000, 1800000000, 2000000000,-  2500000000.0, 3000000000.0, 3500000000.0, 4000000000.0, 4500000000.0,-  5000000000.0, 6000000000.0, 7000000000.0, 8000000000.0, 9000000000.0,-  1e200,-};--void Histogram::Clear() {-  min_ = kBucketLimit[kNumBuckets-1];-  max_ = 0;-  num_ = 0;-  sum_ = 0;-  sum_squares_ = 0;-  for (int i = 0; i < kNumBuckets; i++) {-    buckets_[i] = 0;-  }-}--void Histogram::Add(double value) {-  // Linear search is fast enough for our usage in db_bench-  int b = 0;-  while (b < kNumBuckets - 1 && kBucketLimit[b] <= value) {-    b++;-  }-  buckets_[b] += 1.0;-  if (min_ > value) min_ = value;-  if (max_ < value) max_ = value;-  num_++;-  sum_ += value;-  sum_squares_ += (value * value);-}--void Histogram::Merge(const Histogram& other) {-  if (other.min_ < min_) min_ = other.min_;-  if (other.max_ > max_) max_ = other.max_;-  num_ += other.num_;-  sum_ += other.sum_;-  sum_squares_ += other.sum_squares_;-  for (int b = 0; b < kNumBuckets; b++) {-    buckets_[b] += other.buckets_[b];-  }-}--double Histogram::Median() const {-  return Percentile(50.0);-}--double Histogram::Percentile(double p) const {-  double threshold = num_ * (p / 100.0);-  double sum = 0;-  for (int b = 0; b < kNumBuckets; b++) {-    sum += buckets_[b];-    if (sum >= threshold) {-      // Scale linearly within this bucket-      double left_point = (b == 0) ? 0 : kBucketLimit[b-1];-      double right_point = kBucketLimit[b];-      double left_sum = sum - buckets_[b];-      double right_sum = sum;-      double pos = (threshold - left_sum) / (right_sum - left_sum);-      double r = left_point + (right_point - left_point) * pos;-      if (r < min_) r = min_;-      if (r > max_) r = max_;-      return r;-    }-  }-  return max_;-}--double Histogram::Average() const {-  if (num_ == 0.0) return 0;-  return sum_ / num_;-}--double Histogram::StandardDeviation() const {-  if (num_ == 0.0) return 0;-  double variance = (sum_squares_ * num_ - sum_ * sum_) / (num_ * num_);-  return sqrt(variance);-}--std::string Histogram::ToString() const {-  std::string r;-  char buf[200];-  snprintf(buf, sizeof(buf),-           "Count: %.0f  Average: %.4f  StdDev: %.2f\n",-           num_, Average(), StandardDeviation());-  r.append(buf);-  snprintf(buf, sizeof(buf),-           "Min: %.4f  Median: %.4f  Max: %.4f\n",-           (num_ == 0.0 ? 0.0 : min_), Median(), max_);-  r.append(buf);-  r.append("------------------------------------------------------\n");-  const double mult = 100.0 / num_;-  double sum = 0;-  for (int b = 0; b < kNumBuckets; b++) {-    if (buckets_[b] <= 0.0) continue;-    sum += buckets_[b];-    snprintf(buf, sizeof(buf),-             "[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% ",-             ((b == 0) ? 0.0 : kBucketLimit[b-1]),      // left-             kBucketLimit[b],                           // right-             buckets_[b],                               // count-             mult * buckets_[b],                        // percentage-             mult * sum);                               // cumulative percentage-    r.append(buf);--    // Add hash marks based on percentage; 20 marks for 100%.-    int marks = static_cast<int>(20*(buckets_[b] / num_) + 0.5);-    r.append(marks, '#');-    r.push_back('\n');-  }-  return r;-}--}  // namespace leveldb
− cbits/leveldb/util/histogram.h
@@ -1,42 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_UTIL_HISTOGRAM_H_-#define STORAGE_LEVELDB_UTIL_HISTOGRAM_H_--#include <string>--namespace leveldb {--class Histogram {- public:-  Histogram() { }-  ~Histogram() { }--  void Clear();-  void Add(double value);-  void Merge(const Histogram& other);--  std::string ToString() const;-- private:-  double min_;-  double max_;-  double num_;-  double sum_;-  double sum_squares_;--  enum { kNumBuckets = 154 };-  static const double kBucketLimit[kNumBuckets];-  double buckets_[kNumBuckets];--  double Median() const;-  double Percentile(double p) const;-  double Average() const;-  double StandardDeviation() const;-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_UTIL_HISTOGRAM_H_
− cbits/leveldb/util/logging.cc
@@ -1,81 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "util/logging.h"--#include <errno.h>-#include <stdarg.h>-#include <stdio.h>-#include <stdlib.h>-#include "leveldb/env.h"-#include "leveldb/slice.h"--namespace leveldb {--void AppendNumberTo(std::string* str, uint64_t num) {-  char buf[30];-  snprintf(buf, sizeof(buf), "%llu", (unsigned long long) num);-  str->append(buf);-}--void AppendEscapedStringTo(std::string* str, const Slice& value) {-  for (size_t i = 0; i < value.size(); i++) {-    char c = value[i];-    if (c >= ' ' && c <= '~') {-      str->push_back(c);-    } else {-      char buf[10];-      snprintf(buf, sizeof(buf), "\\x%02x",-               static_cast<unsigned int>(c) & 0xff);-      str->append(buf);-    }-  }-}--std::string NumberToString(uint64_t num) {-  std::string r;-  AppendNumberTo(&r, num);-  return r;-}--std::string EscapeString(const Slice& value) {-  std::string r;-  AppendEscapedStringTo(&r, value);-  return r;-}--bool ConsumeChar(Slice* in, char c) {-  if (!in->empty() && (*in)[0] == c) {-    in->remove_prefix(1);-    return true;-  } else {-    return false;-  }-}--bool ConsumeDecimalNumber(Slice* in, uint64_t* val) {-  uint64_t v = 0;-  int digits = 0;-  while (!in->empty()) {-    char c = (*in)[0];-    if (c >= '0' && c <= '9') {-      ++digits;-      const int delta = (c - '0');-      static const uint64_t kMaxUint64 = ~static_cast<uint64_t>(0);-      if (v > kMaxUint64/10 ||-          (v == kMaxUint64/10 && delta > kMaxUint64%10)) {-        // Overflow-        return false;-      }-      v = (v * 10) + delta;-      in->remove_prefix(1);-    } else {-      break;-    }-  }-  *val = v;-  return (digits > 0);-}--}  // namespace leveldb
− cbits/leveldb/util/logging.h
@@ -1,47 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// Must not be included from any .h files to avoid polluting the namespace-// with macros.--#ifndef STORAGE_LEVELDB_UTIL_LOGGING_H_-#define STORAGE_LEVELDB_UTIL_LOGGING_H_--#include <stdio.h>-#include <stdint.h>-#include <string>-#include "port/port.h"--namespace leveldb {--class Slice;-class WritableFile;--// Append a human-readable printout of "num" to *str-extern void AppendNumberTo(std::string* str, uint64_t num);--// Append a human-readable printout of "value" to *str.-// Escapes any non-printable characters found in "value".-extern void AppendEscapedStringTo(std::string* str, const Slice& value);--// Return a human-readable printout of "num"-extern std::string NumberToString(uint64_t num);--// Return a human-readable version of "value".-// Escapes any non-printable characters found in "value".-extern std::string EscapeString(const Slice& value);--// If *in starts with "c", advances *in past the first character and-// returns true.  Otherwise, returns false.-extern bool ConsumeChar(Slice* in, char c);--// Parse a human-readable number from "*in" into *value.  On success,-// advances "*in" past the consumed number and sets "*val" to the-// numeric value.  Otherwise, returns false and leaves *in in an-// unspecified state.-extern bool ConsumeDecimalNumber(Slice* in, uint64_t* val);--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_UTIL_LOGGING_H_
− cbits/leveldb/util/mutexlock.h
@@ -1,39 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_-#define STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_--#include "port/port.h"--namespace leveldb {--// Helper class that locks a mutex on construction and unlocks the mutex when-// the destructor of the MutexLock object is invoked.-//-// Typical usage:-//-//   void MyClass::MyMethod() {-//     MutexLock l(&mu_);       // mu_ is an instance variable-//     ... some complex code, possibly with multiple return paths ...-//   }--class MutexLock {- public:-  explicit MutexLock(port::Mutex *mu) : mu_(mu) {-    this->mu_->Lock();-  }-  ~MutexLock() { this->mu_->Unlock(); }-- private:-  port::Mutex *const mu_;-  // No copying allowed-  MutexLock(const MutexLock&);-  void operator=(const MutexLock&);-};--}  // namespace leveldb---#endif  // STORAGE_LEVELDB_UTIL_MUTEXLOCK_H_
− cbits/leveldb/util/options.cc
@@ -1,28 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "leveldb/options.h"--#include "leveldb/comparator.h"-#include "leveldb/env.h"--namespace leveldb {--Options::Options()-    : comparator(BytewiseComparator()),-      create_if_missing(false),-      error_if_exists(false),-      paranoid_checks(false),-      env(Env::Default()),-      info_log(NULL),-      write_buffer_size(4<<20),-      max_open_files(1000),-      block_cache(NULL),-      block_size(4096),-      block_restart_interval(16),-      compression(kSnappyCompression) {-}---}  // namespace leveldb
− cbits/leveldb/util/posix_logger.h
@@ -1,98 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.-//-// Logger implementation that can be shared by all environments-// where enough posix functionality is available.--#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_-#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_--#include <algorithm>-#include <stdio.h>-#include <sys/time.h>-#include <time.h>-#include "leveldb/env.h"--namespace leveldb {--class PosixLogger : public Logger {- private:-  FILE* file_;-  uint64_t (*gettid_)();  // Return the thread id for the current thread- public:-  PosixLogger(FILE* f, uint64_t (*gettid)()) : file_(f), gettid_(gettid) { }-  virtual ~PosixLogger() {-    fclose(file_);-  }-  virtual void Logv(const char* format, va_list ap) {-    const uint64_t thread_id = (*gettid_)();--    // We try twice: the first time with a fixed-size stack allocated buffer,-    // and the second time with a much larger dynamically allocated buffer.-    char buffer[500];-    for (int iter = 0; iter < 2; iter++) {-      char* base;-      int bufsize;-      if (iter == 0) {-        bufsize = sizeof(buffer);-        base = buffer;-      } else {-        bufsize = 30000;-        base = new char[bufsize];-      }-      char* p = base;-      char* limit = base + bufsize;--      struct timeval now_tv;-      gettimeofday(&now_tv, NULL);-      const time_t seconds = now_tv.tv_sec;-      struct tm t;-      localtime_r(&seconds, &t);-      p += snprintf(p, limit - p,-                    "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",-                    t.tm_year + 1900,-                    t.tm_mon + 1,-                    t.tm_mday,-                    t.tm_hour,-                    t.tm_min,-                    t.tm_sec,-                    static_cast<int>(now_tv.tv_usec),-                    static_cast<long long unsigned int>(thread_id));--      // Print the message-      if (p < limit) {-        va_list backup_ap;-        va_copy(backup_ap, ap);-        p += vsnprintf(p, limit - p, format, backup_ap);-        va_end(backup_ap);-      }--      // Truncate to available space if necessary-      if (p >= limit) {-        if (iter == 0) {-          continue;       // Try again with larger buffer-        } else {-          p = limit - 1;-        }-      }--      // Add newline if necessary-      if (p == base || p[-1] != '\n') {-        *p++ = '\n';-      }--      assert(p <= limit);-      fwrite(base, 1, p - base, file_);-      fflush(file_);-      if (base != buffer) {-        delete[] base;-      }-      break;-    }-  }-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_
− cbits/leveldb/util/random.h
@@ -1,59 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_UTIL_RANDOM_H_-#define STORAGE_LEVELDB_UTIL_RANDOM_H_--#include <stdint.h>--namespace leveldb {--// A very simple random number generator.  Not especially good at-// generating truly random bits, but good enough for our needs in this-// package.-class Random {- private:-  uint32_t seed_;- public:-  explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { }-  uint32_t Next() {-    static const uint32_t M = 2147483647L;   // 2^31-1-    static const uint64_t A = 16807;  // bits 14, 8, 7, 5, 2, 1, 0-    // We are computing-    //       seed_ = (seed_ * A) % M,    where M = 2^31-1-    //-    // seed_ must not be zero or M, or else all subsequent computed values-    // will be zero or M respectively.  For all other values, seed_ will end-    // up cycling through every number in [1,M-1]-    uint64_t product = seed_ * A;--    // Compute (product % M) using the fact that ((x << 31) % M) == x.-    seed_ = static_cast<uint32_t>((product >> 31) + (product & M));-    // The first reduction may overflow by 1 bit, so we may need to-    // repeat.  mod == M is not possible; using > allows the faster-    // sign-bit-based test.-    if (seed_ > M) {-      seed_ -= M;-    }-    return seed_;-  }-  // Returns a uniformly distributed value in the range [0..n-1]-  // REQUIRES: n > 0-  uint32_t Uniform(int n) { return Next() % n; }--  // Randomly returns true ~"1/n" of the time, and false otherwise.-  // REQUIRES: n > 0-  bool OneIn(int n) { return (Next() % n) == 0; }--  // Skewed: pick "base" uniformly from range [0,max_log] and then-  // return "base" random bits.  The effect is to pick a number in the-  // range [0,2^max_log-1] with exponential bias towards smaller numbers.-  uint32_t Skewed(int max_log) {-    return Uniform(1 << Uniform(max_log + 1));-  }-};--}  // namespace leveldb--#endif  // STORAGE_LEVELDB_UTIL_RANDOM_H_
− cbits/leveldb/util/status.cc
@@ -1,75 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include <stdio.h>-#include "port/port.h"-#include "leveldb/status.h"--namespace leveldb {--const char* Status::CopyState(const char* state) {-  uint32_t size;-  memcpy(&size, state, sizeof(size));-  char* result = new char[size + 5];-  memcpy(result, state, size + 5);-  return result;-}--Status::Status(Code code, const Slice& msg, const Slice& msg2) {-  assert(code != kOk);-  const uint32_t len1 = msg.size();-  const uint32_t len2 = msg2.size();-  const uint32_t size = len1 + (len2 ? (2 + len2) : 0);-  char* result = new char[size + 5];-  memcpy(result, &size, sizeof(size));-  result[4] = static_cast<char>(code);-  memcpy(result + 5, msg.data(), len1);-  if (len2) {-    result[5 + len1] = ':';-    result[6 + len1] = ' ';-    memcpy(result + 7 + len1, msg2.data(), len2);-  }-  state_ = result;-}--std::string Status::ToString() const {-  if (state_ == NULL) {-    return "OK";-  } else {-    char tmp[30];-    const char* type;-    switch (code()) {-      case kOk:-        type = "OK";-        break;-      case kNotFound:-        type = "NotFound: ";-        break;-      case kCorruption:-        type = "Corruption: ";-        break;-      case kNotSupported:-        type = "Not implemented: ";-        break;-      case kInvalidArgument:-        type = "Invalid argument: ";-        break;-      case kIOError:-        type = "IO error: ";-        break;-      default:-        snprintf(tmp, sizeof(tmp), "Unknown code(%d): ",-                 static_cast<int>(code()));-        type = tmp;-        break;-    }-    std::string result(type);-    uint32_t length;-    memcpy(&length, state_, sizeof(length));-    result.append(state_ + 5, length);-    return result;-  }-}--}  // namespace leveldb
− cbits/leveldb/util/testharness.cc
@@ -1,77 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "util/testharness.h"--#include <string>-#include <stdlib.h>-#include <sys/stat.h>-#include <sys/types.h>--namespace leveldb {-namespace test {--namespace {-struct Test {-  const char* base;-  const char* name;-  void (*func)();-};-std::vector<Test>* tests;-}--bool RegisterTest(const char* base, const char* name, void (*func)()) {-  if (tests == NULL) {-    tests = new std::vector<Test>;-  }-  Test t;-  t.base = base;-  t.name = name;-  t.func = func;-  tests->push_back(t);-  return true;-}--int RunAllTests() {-  const char* matcher = getenv("LEVELDB_TESTS");--  int num = 0;-  if (tests != NULL) {-    for (int i = 0; i < tests->size(); i++) {-      const Test& t = (*tests)[i];-      if (matcher != NULL) {-        std::string name = t.base;-        name.push_back('.');-        name.append(t.name);-        if (strstr(name.c_str(), matcher) == NULL) {-          continue;-        }-      }-      fprintf(stderr, "==== Test %s.%s\n", t.base, t.name);-      (*t.func)();-      ++num;-    }-  }-  fprintf(stderr, "==== PASSED %d tests\n", num);-  return 0;-}--std::string TmpDir() {-  std::string dir;-  Status s = Env::Default()->GetTestDirectory(&dir);-  ASSERT_TRUE(s.ok()) << s.ToString();-  return dir;-}--int RandomSeed() {-  const char* env = getenv("TEST_RANDOM_SEED");-  int result = (env != NULL ? atoi(env) : 301);-  if (result <= 0) {-    result = 301;-  }-  return result;-}--}  // namespace test-}  // namespace leveldb
− cbits/leveldb/util/testharness.h
@@ -1,138 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_UTIL_TESTHARNESS_H_-#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_--#include <stdio.h>-#include <stdlib.h>-#include <sstream>-#include "leveldb/env.h"-#include "leveldb/slice.h"-#include "util/random.h"--namespace leveldb {-namespace test {--// Run some of the tests registered by the TEST() macro.  If the-// environment variable "LEVELDB_TESTS" is not set, runs all tests.-// Otherwise, runs only the tests whose name contains the value of-// "LEVELDB_TESTS" as a substring.  E.g., suppose the tests are:-//    TEST(Foo, Hello) { ... }-//    TEST(Foo, World) { ... }-// LEVELDB_TESTS=Hello will run the first test-// LEVELDB_TESTS=o     will run both tests-// LEVELDB_TESTS=Junk  will run no tests-//-// Returns 0 if all tests pass.-// Dies or returns a non-zero value if some test fails.-extern int RunAllTests();--// Return the directory to use for temporary storage.-extern std::string TmpDir();--// Return a randomization seed for this run.  Typically returns the-// same number on repeated invocations of this binary, but automated-// runs may be able to vary the seed.-extern int RandomSeed();--// An instance of Tester is allocated to hold temporary state during-// the execution of an assertion.-class Tester {- private:-  bool ok_;-  const char* fname_;-  int line_;-  std::stringstream ss_;-- public:-  Tester(const char* f, int l)-      : ok_(true), fname_(f), line_(l) {-  }--  ~Tester() {-    if (!ok_) {-      fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str());-      exit(1);-    }-  }--  Tester& Is(bool b, const char* msg) {-    if (!b) {-      ss_ << " Assertion failure " << msg;-      ok_ = false;-    }-    return *this;-  }--  Tester& IsOk(const Status& s) {-    if (!s.ok()) {-      ss_ << " " << s.ToString();-      ok_ = false;-    }-    return *this;-  }--#define BINARY_OP(name,op)                              \-  template <class X, class Y>                           \-  Tester& name(const X& x, const Y& y) {                \-    if (! (x op y)) {                                   \-      ss_ << " failed: " << x << (" " #op " ") << y;    \-      ok_ = false;                                      \-    }                                                   \-    return *this;                                       \-  }--  BINARY_OP(IsEq, ==)-  BINARY_OP(IsNe, !=)-  BINARY_OP(IsGe, >=)-  BINARY_OP(IsGt, >)-  BINARY_OP(IsLe, <=)-  BINARY_OP(IsLt, <)-#undef BINARY_OP--  // Attach the specified value to the error message if an error has occurred-  template <class V>-  Tester& operator<<(const V& value) {-    if (!ok_) {-      ss_ << " " << value;-    }-    return *this;-  }-};--#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c)-#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s))-#define ASSERT_EQ(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a),(b))-#define ASSERT_NE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a),(b))-#define ASSERT_GE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a),(b))-#define ASSERT_GT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a),(b))-#define ASSERT_LE(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a),(b))-#define ASSERT_LT(a,b) ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a),(b))--#define TCONCAT(a,b) TCONCAT1(a,b)-#define TCONCAT1(a,b) a##b--#define TEST(base,name)                                                 \-class TCONCAT(_Test_,name) : public base {                              \- public:                                                                \-  void _Run();                                                          \-  static void _RunIt() {                                                \-    TCONCAT(_Test_,name) t;                                             \-    t._Run();                                                           \-  }                                                                     \-};                                                                      \-bool TCONCAT(_Test_ignored_,name) =                                     \-  ::leveldb::test::RegisterTest(#base, #name, &TCONCAT(_Test_,name)::_RunIt); \-void TCONCAT(_Test_,name)::_Run()--// Register the specified test.  Typically not used directly, but-// invoked via the macro expansion of TEST.-extern bool RegisterTest(const char* base, const char* name, void (*func)());---}  // namespace test-}  // namespace leveldb--#endif  // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_
− cbits/leveldb/util/testutil.cc
@@ -1,51 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#include "util/testutil.h"--#include "util/random.h"--namespace leveldb {-namespace test {--Slice RandomString(Random* rnd, int len, std::string* dst) {-  dst->resize(len);-  for (int i = 0; i < len; i++) {-    (*dst)[i] = static_cast<char>(' ' + rnd->Uniform(95));   // ' ' .. '~'-  }-  return Slice(*dst);-}--std::string RandomKey(Random* rnd, int len) {-  // Make sure to generate a wide variety of characters so we-  // test the boundary conditions for short-key optimizations.-  static const char kTestChars[] = {-    '\0', '\1', 'a', 'b', 'c', 'd', 'e', '\xfd', '\xfe', '\xff'-  };-  std::string result;-  for (int i = 0; i < len; i++) {-    result += kTestChars[rnd->Uniform(sizeof(kTestChars))];-  }-  return result;-}---extern Slice CompressibleString(Random* rnd, double compressed_fraction,-                                int len, std::string* dst) {-  int raw = static_cast<int>(len * compressed_fraction);-  if (raw < 1) raw = 1;-  std::string raw_data;-  RandomString(rnd, raw, &raw_data);--  // Duplicate the random data until we have filled "len" bytes-  dst->clear();-  while (dst->size() < len) {-    dst->append(raw_data);-  }-  dst->resize(len);-  return Slice(*dst);-}--}  // namespace test-}  // namespace leveldb
− cbits/leveldb/util/testutil.h
@@ -1,53 +0,0 @@-// Copyright (c) 2011 The LevelDB Authors. All rights reserved.-// Use of this source code is governed by a BSD-style license that can be-// found in the LICENSE file. See the AUTHORS file for names of contributors.--#ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_-#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_--#include "leveldb/env.h"-#include "leveldb/slice.h"-#include "util/random.h"--namespace leveldb {-namespace test {--// Store in *dst a random string of length "len" and return a Slice that-// references the generated data.-extern Slice RandomString(Random* rnd, int len, std::string* dst);--// Return a random key with the specified length that may contain interesting-// characters (e.g. \x00, \xff, etc.).-extern std::string RandomKey(Random* rnd, int len);--// Store in *dst a string of length "len" that will compress to-// "N*compressed_fraction" bytes and return a Slice that references-// the generated data.-extern Slice CompressibleString(Random* rnd, double compressed_fraction,-                                int len, std::string* dst);--// A wrapper that allows injection of errors.-class ErrorEnv : public EnvWrapper {- public:-  bool writable_file_error_;-  int num_writable_file_errors_;--  ErrorEnv() : EnvWrapper(Env::Default()),-               writable_file_error_(false),-               num_writable_file_errors_(0) { }--  virtual Status NewWritableFile(const std::string& fname,-                                 WritableFile** result) {-    if (writable_file_error_) {-      ++num_writable_file_errors_;-      *result = NULL;-      return Status::IOError(fname, "fake error");-    }-    return target()->NewWritableFile(fname, result);-  }-};--}  // namespace test-}  // namespace leveldb--#endif  // STORAGE_LEVELDB_UTIL_TESTUTIL_H_
− configure
@@ -1,4104 +0,0 @@-#! /bin/sh-# Guess values for system-dependent variables and create Makefiles.-# Generated by GNU Autoconf 2.68 for Haskell LevelDB package 0.1.-#-# Report bugs to <mad.one@gmail.com>.-#-#-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,-# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software-# Foundation, Inc.-#-#-# This configure script is free software; the Free Software Foundation-# gives unlimited permission to copy, distribute and modify it.-## -------------------- ##-## M4sh Initialization. ##-## -------------------- ##--# Be more Bourne compatible-DUALCASE=1; export DUALCASE # for MKS sh-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :-  emulate sh-  NULLCMD=:-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which-  # is contrary to our usage.  Disable this feature.-  alias -g '${1+"$@"}'='"$@"'-  setopt NO_GLOB_SUBST-else-  case `(set -o) 2>/dev/null` in #(-  *posix*) :-    set -o posix ;; #(-  *) :-     ;;-esac-fi---as_nl='-'-export as_nl-# Printing a long string crashes Solaris 7 /usr/bin/printf.-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo-# Prefer a ksh shell builtin over an external printf program on Solaris,-# but without wasting forks for bash or zsh.-if test -z "$BASH_VERSION$ZSH_VERSION" \-    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then-  as_echo='print -r --'-  as_echo_n='print -rn --'-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then-  as_echo='printf %s\n'-  as_echo_n='printf %s'-else-  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then-    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'-    as_echo_n='/usr/ucb/echo -n'-  else-    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'-    as_echo_n_body='eval-      arg=$1;-      case $arg in #(-      *"$as_nl"*)-	expr "X$arg" : "X\\(.*\\)$as_nl";-	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;-      esac;-      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"-    '-    export as_echo_n_body-    as_echo_n='sh -c $as_echo_n_body as_echo'-  fi-  export as_echo_body-  as_echo='sh -c $as_echo_body as_echo'-fi--# The user is always right.-if test "${PATH_SEPARATOR+set}" != set; then-  PATH_SEPARATOR=:-  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {-    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||-      PATH_SEPARATOR=';'-  }-fi---# IFS-# We need space, tab and new line, in precisely that order.  Quoting is-# there to prevent editors from complaining about space-tab.-# (If _AS_PATH_WALK were called with IFS unset, it would disable word-# splitting by setting IFS to empty value.)-IFS=" ""	$as_nl"--# Find who we are.  Look in the path if we contain no directory separator.-as_myself=-case $0 in #((-  *[\\/]* ) as_myself=$0 ;;-  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR-for as_dir in $PATH-do-  IFS=$as_save_IFS-  test -z "$as_dir" && as_dir=.-    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break-  done-IFS=$as_save_IFS--     ;;-esac-# We did not find ourselves, most probably we were run as `sh COMMAND'-# in which case we are not to be found in the path.-if test "x$as_myself" = x; then-  as_myself=$0-fi-if test ! -f "$as_myself"; then-  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2-  exit 1-fi--# Unset variables that we do not need and which cause bugs (e.g. in-# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"-# suppresses any "Segmentation fault" message there.  '((' could-# trigger a bug in pdksh 5.2.14.-for as_var in BASH_ENV ENV MAIL MAILPATH-do eval test x\${$as_var+set} = xset \-  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :-done-PS1='$ '-PS2='> '-PS4='+ '--# NLS nuisances.-LC_ALL=C-export LC_ALL-LANGUAGE=C-export LANGUAGE--# CDPATH.-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH--if test "x$CONFIG_SHELL" = x; then-  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :-  emulate sh-  NULLCMD=:-  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which-  # is contrary to our usage.  Disable this feature.-  alias -g '\${1+\"\$@\"}'='\"\$@\"'-  setopt NO_GLOB_SUBST-else-  case \`(set -o) 2>/dev/null\` in #(-  *posix*) :-    set -o posix ;; #(-  *) :-     ;;-esac-fi-"-  as_required="as_fn_return () { (exit \$1); }-as_fn_success () { as_fn_return 0; }-as_fn_failure () { as_fn_return 1; }-as_fn_ret_success () { return 0; }-as_fn_ret_failure () { return 1; }--exitcode=0-as_fn_success || { exitcode=1; echo as_fn_success failed.; }-as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }-as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }-as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }-if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :--else-  exitcode=1; echo positional parameters were not saved.-fi-test x\$exitcode = x0 || exit 1"-  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO-  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO-  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&-  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1-test \$(( 1 + 1 )) = 2 || exit 1"-  if (eval "$as_required") 2>/dev/null; then :-  as_have_required=yes-else-  as_have_required=no-fi-  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :--else-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR-as_found=false-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH-do-  IFS=$as_save_IFS-  test -z "$as_dir" && as_dir=.-  as_found=:-  case $as_dir in #(-	 /*)-	   for as_base in sh bash ksh sh5; do-	     # Try only shells that exist, to save several forks.-	     as_shell=$as_dir/$as_base-	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&-		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :-  CONFIG_SHELL=$as_shell as_have_required=yes-		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :-  break 2-fi-fi-	   done;;-       esac-  as_found=false-done-$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&-	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :-  CONFIG_SHELL=$SHELL as_have_required=yes-fi; }-IFS=$as_save_IFS---      if test "x$CONFIG_SHELL" != x; then :-  # We cannot yet assume a decent shell, so we have to provide a-	# neutralization value for shells without unset; and this also-	# works around shells that cannot unset nonexistent variables.-	# Preserve -v and -x to the replacement shell.-	BASH_ENV=/dev/null-	ENV=/dev/null-	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV-	export CONFIG_SHELL-	case $- in # ((((-	  *v*x* | *x*v* ) as_opts=-vx ;;-	  *v* ) as_opts=-v ;;-	  *x* ) as_opts=-x ;;-	  * ) as_opts= ;;-	esac-	exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}-fi--    if test x$as_have_required = xno; then :-  $as_echo "$0: This script requires a shell more modern than all"-  $as_echo "$0: the shells that I found on your system."-  if test x${ZSH_VERSION+set} = xset ; then-    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"-    $as_echo "$0: be upgraded to zsh 4.3.4 or later."-  else-    $as_echo "$0: Please tell bug-autoconf@gnu.org and mad.one@gmail.com-$0: about your system, including any error possibly output-$0: before this message. Then install a modern shell, or-$0: manually run the script under such a shell if you do-$0: have one."-  fi-  exit 1-fi-fi-fi-SHELL=${CONFIG_SHELL-/bin/sh}-export SHELL-# Unset more variables known to interfere with behavior of common tools.-CLICOLOR_FORCE= GREP_OPTIONS=-unset CLICOLOR_FORCE GREP_OPTIONS--## --------------------- ##-## M4sh Shell Functions. ##-## --------------------- ##-# as_fn_unset VAR-# ----------------# Portably unset VAR.-as_fn_unset ()-{-  { eval $1=; unset $1;}-}-as_unset=as_fn_unset--# as_fn_set_status STATUS-# ------------------------# Set $? to STATUS, without forking.-as_fn_set_status ()-{-  return $1-} # as_fn_set_status--# as_fn_exit STATUS-# ------------------# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.-as_fn_exit ()-{-  set +e-  as_fn_set_status $1-  exit $1-} # as_fn_exit--# as_fn_mkdir_p-# --------------# Create "$as_dir" as a directory, including parents if necessary.-as_fn_mkdir_p ()-{--  case $as_dir in #(-  -*) as_dir=./$as_dir;;-  esac-  test -d "$as_dir" || eval $as_mkdir_p || {-    as_dirs=-    while :; do-      case $as_dir in #(-      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(-      *) as_qdir=$as_dir;;-      esac-      as_dirs="'$as_qdir' $as_dirs"-      as_dir=`$as_dirname -- "$as_dir" ||-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \-	 X"$as_dir" : 'X\(//\)[^/]' \| \-	 X"$as_dir" : 'X\(//\)$' \| \-	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||-$as_echo X"$as_dir" |-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{-	    s//\1/-	    q-	  }-	  /^X\(\/\/\)[^/].*/{-	    s//\1/-	    q-	  }-	  /^X\(\/\/\)$/{-	    s//\1/-	    q-	  }-	  /^X\(\/\).*/{-	    s//\1/-	    q-	  }-	  s/.*/./; q'`-      test -d "$as_dir" && break-    done-    test -z "$as_dirs" || eval "mkdir $as_dirs"-  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"---} # as_fn_mkdir_p-# as_fn_append VAR VALUE-# -----------------------# Append the text in VALUE to the end of the definition contained in VAR. Take-# advantage of any shell optimizations that allow amortized linear growth over-# repeated appends, instead of the typical quadratic growth present in naive-# implementations.-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :-  eval 'as_fn_append ()-  {-    eval $1+=\$2-  }'-else-  as_fn_append ()-  {-    eval $1=\$$1\$2-  }-fi # as_fn_append--# as_fn_arith ARG...-# -------------------# Perform arithmetic evaluation on the ARGs, and store the result in the-# global $as_val. Take advantage of shells that can avoid forks. The arguments-# must be portable across $(()) and expr.-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :-  eval 'as_fn_arith ()-  {-    as_val=$(( $* ))-  }'-else-  as_fn_arith ()-  {-    as_val=`expr "$@" || test $? -eq 1`-  }-fi # as_fn_arith---# as_fn_error STATUS ERROR [LINENO LOG_FD]-# -----------------------------------------# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the-# script with STATUS, using 1 if that was 0.-as_fn_error ()-{-  as_status=$1; test $as_status -eq 0 && as_status=1-  if test "$4"; then-    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack-    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4-  fi-  $as_echo "$as_me: error: $2" >&2-  as_fn_exit $as_status-} # as_fn_error--if expr a : '\(a\)' >/dev/null 2>&1 &&-   test "X`expr 00001 : '.*\(...\)'`" = X001; then-  as_expr=expr-else-  as_expr=false-fi--if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then-  as_basename=basename-else-  as_basename=false-fi--if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then-  as_dirname=dirname-else-  as_dirname=false-fi--as_me=`$as_basename -- "$0" ||-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \-	 X"$0" : 'X\(//\)$' \| \-	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||-$as_echo X/"$0" |-    sed '/^.*\/\([^/][^/]*\)\/*$/{-	    s//\1/-	    q-	  }-	  /^X\/\(\/\/\)$/{-	    s//\1/-	    q-	  }-	  /^X\/\(\/\).*/{-	    s//\1/-	    q-	  }-	  s/.*/./; q'`--# Avoid depending upon Character Ranges.-as_cr_letters='abcdefghijklmnopqrstuvwxyz'-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'-as_cr_Letters=$as_cr_letters$as_cr_LETTERS-as_cr_digits='0123456789'-as_cr_alnum=$as_cr_Letters$as_cr_digits---  as_lineno_1=$LINENO as_lineno_1a=$LINENO-  as_lineno_2=$LINENO as_lineno_2a=$LINENO-  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&-  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {-  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)-  sed -n '-    p-    /[$]LINENO/=-  ' <$as_myself |-    sed '-      s/[$]LINENO.*/&-/-      t lineno-      b-      :lineno-      N-      :loop-      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/-      t loop-      s/-\n.*//-    ' >$as_me.lineno &&-  chmod +x "$as_me.lineno" ||-    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }--  # Don't try to exec as it changes $[0], causing all sort of problems-  # (the dirname of $[0] is not the place where we might find the-  # original and so on.  Autoconf is especially sensitive to this).-  . "./$as_me.lineno"-  # Exit status is that of the last command.-  exit-}--ECHO_C= ECHO_N= ECHO_T=-case `echo -n x` in #(((((--n*)-  case `echo 'xy\c'` in-  *c*) ECHO_T='	';;	# ECHO_T is single tab character.-  xy)  ECHO_C='\c';;-  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null-       ECHO_T='	';;-  esac;;-*)-  ECHO_N='-n';;-esac--rm -f conf$$ conf$$.exe conf$$.file-if test -d conf$$.dir; then-  rm -f conf$$.dir/conf$$.file-else-  rm -f conf$$.dir-  mkdir conf$$.dir 2>/dev/null-fi-if (echo >conf$$.file) 2>/dev/null; then-  if ln -s conf$$.file conf$$ 2>/dev/null; then-    as_ln_s='ln -s'-    # ... but there are two gotchas:-    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.-    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.-    # In both cases, we have to default to `cp -p'.-    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||-      as_ln_s='cp -p'-  elif ln conf$$.file conf$$ 2>/dev/null; then-    as_ln_s=ln-  else-    as_ln_s='cp -p'-  fi-else-  as_ln_s='cp -p'-fi-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file-rmdir conf$$.dir 2>/dev/null--if mkdir -p . 2>/dev/null; then-  as_mkdir_p='mkdir -p "$as_dir"'-else-  test -d ./-p && rmdir ./-p-  as_mkdir_p=false-fi--if test -x / >/dev/null 2>&1; then-  as_test_x='test -x'-else-  if ls -dL / >/dev/null 2>&1; then-    as_ls_L_option=L-  else-    as_ls_L_option=-  fi-  as_test_x='-    eval sh -c '\''-      if test -d "$1"; then-	test -d "$1/.";-      else-	case $1 in #(-	-*)set "./$1";;-	esac;-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((-	???[sx]*):;;*)false;;esac;fi-    '\'' sh-  '-fi-as_executable_p=$as_test_x--# Sed expression to map a string onto a valid CPP name.-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"--# Sed expression to map a string onto a valid variable name.-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"---test -n "$DJDIR" || exec 7<&0 </dev/null-exec 6>&1--# Name of the host.-# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,-# so uname gets run too.-ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`--#-# Initializations.-#-ac_default_prefix=/usr/local-ac_clean_files=-ac_config_libobj_dir=.-LIBOBJS=-cross_compiling=no-subdirs=-MFLAGS=-MAKEFLAGS=--# Identity of this package.-PACKAGE_NAME='Haskell LevelDB package'-PACKAGE_TARNAME='leveldb'-PACKAGE_VERSION='0.1'-PACKAGE_STRING='Haskell LevelDB package 0.1'-PACKAGE_BUGREPORT='mad.one@gmail.com'-PACKAGE_URL='http://thoughtpolice.github.com/hs-leveldb'--# Factoring default headers for most tests.-ac_includes_default="\-#include <stdio.h>-#ifdef HAVE_SYS_TYPES_H-# include <sys/types.h>-#endif-#ifdef HAVE_SYS_STAT_H-# include <sys/stat.h>-#endif-#ifdef STDC_HEADERS-# include <stdlib.h>-# include <stddef.h>-#else-# ifdef HAVE_STDLIB_H-#  include <stdlib.h>-# endif-#endif-#ifdef HAVE_STRING_H-# if !defined STDC_HEADERS && defined HAVE_MEMORY_H-#  include <memory.h>-# endif-# include <string.h>-#endif-#ifdef HAVE_STRINGS_H-# include <strings.h>-#endif-#ifdef HAVE_INTTYPES_H-# include <inttypes.h>-#endif-#ifdef HAVE_STDINT_H-# include <stdint.h>-#endif-#ifdef HAVE_UNISTD_H-# include <unistd.h>-#endif"--ac_subst_vars='LTLIBOBJS-LIBOBJS-CSTDATOMIC-SNAPPYLIB-SNAPPY-EGREP-GREP-CXXCPP-OBJEXT-EXEEXT-ac_ct_CXX-CPPFLAGS-LDFLAGS-CXXFLAGS-CXX-target_alias-host_alias-build_alias-LIBS-ECHO_T-ECHO_N-ECHO_C-DEFS-mandir-localedir-libdir-psdir-pdfdir-dvidir-htmldir-infodir-docdir-oldincludedir-includedir-localstatedir-sharedstatedir-sysconfdir-datadir-datarootdir-libexecdir-sbindir-bindir-program_transform_name-prefix-exec_prefix-PACKAGE_URL-PACKAGE_BUGREPORT-PACKAGE_STRING-PACKAGE_VERSION-PACKAGE_TARNAME-PACKAGE_NAME-PATH_SEPARATOR-SHELL'-ac_subst_files=''-ac_user_opts='-enable_option_checking-'-      ac_precious_vars='build_alias-host_alias-target_alias-CXX-CXXFLAGS-LDFLAGS-LIBS-CPPFLAGS-CCC-CXXCPP'---# Initialize some variables set by options.-ac_init_help=-ac_init_version=false-ac_unrecognized_opts=-ac_unrecognized_sep=-# The variables have the same names as the options, with-# dashes changed to underlines.-cache_file=/dev/null-exec_prefix=NONE-no_create=-no_recursion=-prefix=NONE-program_prefix=NONE-program_suffix=NONE-program_transform_name=s,x,x,-silent=-site=-srcdir=-verbose=-x_includes=NONE-x_libraries=NONE--# Installation directory options.-# These are left unexpanded so users can "make install exec_prefix=/foo"-# and all the variables that are supposed to be based on exec_prefix-# by default will actually change.-# Use braces instead of parens because sh, perl, etc. also accept them.-# (The list follows the same order as the GNU Coding Standards.)-bindir='${exec_prefix}/bin'-sbindir='${exec_prefix}/sbin'-libexecdir='${exec_prefix}/libexec'-datarootdir='${prefix}/share'-datadir='${datarootdir}'-sysconfdir='${prefix}/etc'-sharedstatedir='${prefix}/com'-localstatedir='${prefix}/var'-includedir='${prefix}/include'-oldincludedir='/usr/include'-docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'-infodir='${datarootdir}/info'-htmldir='${docdir}'-dvidir='${docdir}'-pdfdir='${docdir}'-psdir='${docdir}'-libdir='${exec_prefix}/lib'-localedir='${datarootdir}/locale'-mandir='${datarootdir}/man'--ac_prev=-ac_dashdash=-for ac_option-do-  # If the previous option needs an argument, assign it.-  if test -n "$ac_prev"; then-    eval $ac_prev=\$ac_option-    ac_prev=-    continue-  fi--  case $ac_option in-  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;-  *=)   ac_optarg= ;;-  *)    ac_optarg=yes ;;-  esac--  # Accept the important Cygnus configure options, so we can diagnose typos.--  case $ac_dashdash$ac_option in-  --)-    ac_dashdash=yes ;;--  -bindir | --bindir | --bindi | --bind | --bin | --bi)-    ac_prev=bindir ;;-  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)-    bindir=$ac_optarg ;;--  -build | --build | --buil | --bui | --bu)-    ac_prev=build_alias ;;-  -build=* | --build=* | --buil=* | --bui=* | --bu=*)-    build_alias=$ac_optarg ;;--  -cache-file | --cache-file | --cache-fil | --cache-fi \-  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)-    ac_prev=cache_file ;;-  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \-  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)-    cache_file=$ac_optarg ;;--  --config-cache | -C)-    cache_file=config.cache ;;--  -datadir | --datadir | --datadi | --datad)-    ac_prev=datadir ;;-  -datadir=* | --datadir=* | --datadi=* | --datad=*)-    datadir=$ac_optarg ;;--  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \-  | --dataroo | --dataro | --datar)-    ac_prev=datarootdir ;;-  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \-  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)-    datarootdir=$ac_optarg ;;--  -disable-* | --disable-*)-    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`-    # Reject names that are not valid shell variable names.-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&-      as_fn_error $? "invalid feature name: $ac_useropt"-    ac_useropt_orig=$ac_useropt-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`-    case $ac_user_opts in-      *"-"enable_$ac_useropt"-"*) ;;-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"-	 ac_unrecognized_sep=', ';;-    esac-    eval enable_$ac_useropt=no ;;--  -docdir | --docdir | --docdi | --doc | --do)-    ac_prev=docdir ;;-  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)-    docdir=$ac_optarg ;;--  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)-    ac_prev=dvidir ;;-  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)-    dvidir=$ac_optarg ;;--  -enable-* | --enable-*)-    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`-    # Reject names that are not valid shell variable names.-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&-      as_fn_error $? "invalid feature name: $ac_useropt"-    ac_useropt_orig=$ac_useropt-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`-    case $ac_user_opts in-      *"-"enable_$ac_useropt"-"*) ;;-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"-	 ac_unrecognized_sep=', ';;-    esac-    eval enable_$ac_useropt=\$ac_optarg ;;--  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \-  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \-  | --exec | --exe | --ex)-    ac_prev=exec_prefix ;;-  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \-  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \-  | --exec=* | --exe=* | --ex=*)-    exec_prefix=$ac_optarg ;;--  -gas | --gas | --ga | --g)-    # Obsolete; use --with-gas.-    with_gas=yes ;;--  -help | --help | --hel | --he | -h)-    ac_init_help=long ;;-  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)-    ac_init_help=recursive ;;-  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)-    ac_init_help=short ;;--  -host | --host | --hos | --ho)-    ac_prev=host_alias ;;-  -host=* | --host=* | --hos=* | --ho=*)-    host_alias=$ac_optarg ;;--  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)-    ac_prev=htmldir ;;-  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \-  | --ht=*)-    htmldir=$ac_optarg ;;--  -includedir | --includedir | --includedi | --included | --include \-  | --includ | --inclu | --incl | --inc)-    ac_prev=includedir ;;-  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \-  | --includ=* | --inclu=* | --incl=* | --inc=*)-    includedir=$ac_optarg ;;--  -infodir | --infodir | --infodi | --infod | --info | --inf)-    ac_prev=infodir ;;-  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)-    infodir=$ac_optarg ;;--  -libdir | --libdir | --libdi | --libd)-    ac_prev=libdir ;;-  -libdir=* | --libdir=* | --libdi=* | --libd=*)-    libdir=$ac_optarg ;;--  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \-  | --libexe | --libex | --libe)-    ac_prev=libexecdir ;;-  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \-  | --libexe=* | --libex=* | --libe=*)-    libexecdir=$ac_optarg ;;--  -localedir | --localedir | --localedi | --localed | --locale)-    ac_prev=localedir ;;-  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)-    localedir=$ac_optarg ;;--  -localstatedir | --localstatedir | --localstatedi | --localstated \-  | --localstate | --localstat | --localsta | --localst | --locals)-    ac_prev=localstatedir ;;-  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \-  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)-    localstatedir=$ac_optarg ;;--  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)-    ac_prev=mandir ;;-  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)-    mandir=$ac_optarg ;;--  -nfp | --nfp | --nf)-    # Obsolete; use --without-fp.-    with_fp=no ;;--  -no-create | --no-create | --no-creat | --no-crea | --no-cre \-  | --no-cr | --no-c | -n)-    no_create=yes ;;--  -no-recursion | --no-recursion | --no-recursio | --no-recursi \-  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)-    no_recursion=yes ;;--  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \-  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \-  | --oldin | --oldi | --old | --ol | --o)-    ac_prev=oldincludedir ;;-  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \-  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \-  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)-    oldincludedir=$ac_optarg ;;--  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)-    ac_prev=prefix ;;-  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)-    prefix=$ac_optarg ;;--  -program-prefix | --program-prefix | --program-prefi | --program-pref \-  | --program-pre | --program-pr | --program-p)-    ac_prev=program_prefix ;;-  -program-prefix=* | --program-prefix=* | --program-prefi=* \-  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)-    program_prefix=$ac_optarg ;;--  -program-suffix | --program-suffix | --program-suffi | --program-suff \-  | --program-suf | --program-su | --program-s)-    ac_prev=program_suffix ;;-  -program-suffix=* | --program-suffix=* | --program-suffi=* \-  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)-    program_suffix=$ac_optarg ;;--  -program-transform-name | --program-transform-name \-  | --program-transform-nam | --program-transform-na \-  | --program-transform-n | --program-transform- \-  | --program-transform | --program-transfor \-  | --program-transfo | --program-transf \-  | --program-trans | --program-tran \-  | --progr-tra | --program-tr | --program-t)-    ac_prev=program_transform_name ;;-  -program-transform-name=* | --program-transform-name=* \-  | --program-transform-nam=* | --program-transform-na=* \-  | --program-transform-n=* | --program-transform-=* \-  | --program-transform=* | --program-transfor=* \-  | --program-transfo=* | --program-transf=* \-  | --program-trans=* | --program-tran=* \-  | --progr-tra=* | --program-tr=* | --program-t=*)-    program_transform_name=$ac_optarg ;;--  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)-    ac_prev=pdfdir ;;-  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)-    pdfdir=$ac_optarg ;;--  -psdir | --psdir | --psdi | --psd | --ps)-    ac_prev=psdir ;;-  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)-    psdir=$ac_optarg ;;--  -q | -quiet | --quiet | --quie | --qui | --qu | --q \-  | -silent | --silent | --silen | --sile | --sil)-    silent=yes ;;--  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)-    ac_prev=sbindir ;;-  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \-  | --sbi=* | --sb=*)-    sbindir=$ac_optarg ;;--  -sharedstatedir | --sharedstatedir | --sharedstatedi \-  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \-  | --sharedst | --shareds | --shared | --share | --shar \-  | --sha | --sh)-    ac_prev=sharedstatedir ;;-  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \-  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \-  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \-  | --sha=* | --sh=*)-    sharedstatedir=$ac_optarg ;;--  -site | --site | --sit)-    ac_prev=site ;;-  -site=* | --site=* | --sit=*)-    site=$ac_optarg ;;--  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)-    ac_prev=srcdir ;;-  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)-    srcdir=$ac_optarg ;;--  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \-  | --syscon | --sysco | --sysc | --sys | --sy)-    ac_prev=sysconfdir ;;-  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \-  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)-    sysconfdir=$ac_optarg ;;--  -target | --target | --targe | --targ | --tar | --ta | --t)-    ac_prev=target_alias ;;-  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)-    target_alias=$ac_optarg ;;--  -v | -verbose | --verbose | --verbos | --verbo | --verb)-    verbose=yes ;;--  -version | --version | --versio | --versi | --vers | -V)-    ac_init_version=: ;;--  -with-* | --with-*)-    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`-    # Reject names that are not valid shell variable names.-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&-      as_fn_error $? "invalid package name: $ac_useropt"-    ac_useropt_orig=$ac_useropt-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`-    case $ac_user_opts in-      *"-"with_$ac_useropt"-"*) ;;-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"-	 ac_unrecognized_sep=', ';;-    esac-    eval with_$ac_useropt=\$ac_optarg ;;--  -without-* | --without-*)-    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`-    # Reject names that are not valid shell variable names.-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&-      as_fn_error $? "invalid package name: $ac_useropt"-    ac_useropt_orig=$ac_useropt-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`-    case $ac_user_opts in-      *"-"with_$ac_useropt"-"*) ;;-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"-	 ac_unrecognized_sep=', ';;-    esac-    eval with_$ac_useropt=no ;;--  --x)-    # Obsolete; use --with-x.-    with_x=yes ;;--  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \-  | --x-incl | --x-inc | --x-in | --x-i)-    ac_prev=x_includes ;;-  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \-  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)-    x_includes=$ac_optarg ;;--  -x-libraries | --x-libraries | --x-librarie | --x-librari \-  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)-    ac_prev=x_libraries ;;-  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \-  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)-    x_libraries=$ac_optarg ;;--  -*) as_fn_error $? "unrecognized option: \`$ac_option'-Try \`$0 --help' for more information"-    ;;--  *=*)-    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`-    # Reject names that are not valid shell variable names.-    case $ac_envvar in #(-      '' | [0-9]* | *[!_$as_cr_alnum]* )-      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;-    esac-    eval $ac_envvar=\$ac_optarg-    export $ac_envvar ;;--  *)-    # FIXME: should be removed in autoconf 3.0.-    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2-    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&-      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2-    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"-    ;;--  esac-done--if test -n "$ac_prev"; then-  ac_option=--`echo $ac_prev | sed 's/_/-/g'`-  as_fn_error $? "missing argument to $ac_option"-fi--if test -n "$ac_unrecognized_opts"; then-  case $enable_option_checking in-    no) ;;-    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;-    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;-  esac-fi--# Check all directory arguments for consistency.-for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \-		datadir sysconfdir sharedstatedir localstatedir includedir \-		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \-		libdir localedir mandir-do-  eval ac_val=\$$ac_var-  # Remove trailing slashes.-  case $ac_val in-    */ )-      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`-      eval $ac_var=\$ac_val;;-  esac-  # Be sure to have absolute directory names.-  case $ac_val in-    [\\/$]* | ?:[\\/]* )  continue;;-    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;-  esac-  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"-done--# There might be people who depend on the old broken behavior: `$host'-# used to hold the argument of --host etc.-# FIXME: To remove some day.-build=$build_alias-host=$host_alias-target=$target_alias--# FIXME: To remove some day.-if test "x$host_alias" != x; then-  if test "x$build_alias" = x; then-    cross_compiling=maybe-    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.-    If a cross compiler is detected then cross compile mode will be used" >&2-  elif test "x$build_alias" != "x$host_alias"; then-    cross_compiling=yes-  fi-fi--ac_tool_prefix=-test -n "$host_alias" && ac_tool_prefix=$host_alias---test "$silent" = yes && exec 6>/dev/null---ac_pwd=`pwd` && test -n "$ac_pwd" &&-ac_ls_di=`ls -di .` &&-ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||-  as_fn_error $? "working directory cannot be determined"-test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||-  as_fn_error $? "pwd does not report name of working directory"---# Find the source files, if location was not specified.-if test -z "$srcdir"; then-  ac_srcdir_defaulted=yes-  # Try the directory containing this script, then the parent directory.-  ac_confdir=`$as_dirname -- "$as_myself" ||-$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \-	 X"$as_myself" : 'X\(//\)[^/]' \| \-	 X"$as_myself" : 'X\(//\)$' \| \-	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||-$as_echo X"$as_myself" |-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{-	    s//\1/-	    q-	  }-	  /^X\(\/\/\)[^/].*/{-	    s//\1/-	    q-	  }-	  /^X\(\/\/\)$/{-	    s//\1/-	    q-	  }-	  /^X\(\/\).*/{-	    s//\1/-	    q-	  }-	  s/.*/./; q'`-  srcdir=$ac_confdir-  if test ! -r "$srcdir/$ac_unique_file"; then-    srcdir=..-  fi-else-  ac_srcdir_defaulted=no-fi-if test ! -r "$srcdir/$ac_unique_file"; then-  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."-  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"-fi-ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"-ac_abs_confdir=`(-	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"-	pwd)`-# When building in place, set srcdir=.-if test "$ac_abs_confdir" = "$ac_pwd"; then-  srcdir=.-fi-# Remove unnecessary trailing slashes from srcdir.-# Double slashes in file names in object file debugging info-# mess up M-x gdb in Emacs.-case $srcdir in-*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;-esac-for ac_var in $ac_precious_vars; do-  eval ac_env_${ac_var}_set=\${${ac_var}+set}-  eval ac_env_${ac_var}_value=\$${ac_var}-  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}-  eval ac_cv_env_${ac_var}_value=\$${ac_var}-done--#-# Report the --help message.-#-if test "$ac_init_help" = "long"; then-  # Omit some internal or obsolete options to make the list less imposing.-  # This message is too long to be a string in the A/UX 3.1 sh.-  cat <<_ACEOF-\`configure' configures Haskell LevelDB package 0.1 to adapt to many kinds of systems.--Usage: $0 [OPTION]... [VAR=VALUE]...--To assign environment variables (e.g., CC, CFLAGS...), specify them as-VAR=VALUE.  See below for descriptions of some of the useful variables.--Defaults for the options are specified in brackets.--Configuration:-  -h, --help              display this help and exit-      --help=short        display options specific to this package-      --help=recursive    display the short help of all the included packages-  -V, --version           display version information and exit-  -q, --quiet, --silent   do not print \`checking ...' messages-      --cache-file=FILE   cache test results in FILE [disabled]-  -C, --config-cache      alias for \`--cache-file=config.cache'-  -n, --no-create         do not create output files-      --srcdir=DIR        find the sources in DIR [configure dir or \`..']--Installation directories:-  --prefix=PREFIX         install architecture-independent files in PREFIX-                          [$ac_default_prefix]-  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX-                          [PREFIX]--By default, \`make install' will install all the files in-\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify-an installation prefix other than \`$ac_default_prefix' using \`--prefix',-for instance \`--prefix=\$HOME'.--For better control, use the options below.--Fine tuning of the installation directories:-  --bindir=DIR            user executables [EPREFIX/bin]-  --sbindir=DIR           system admin executables [EPREFIX/sbin]-  --libexecdir=DIR        program executables [EPREFIX/libexec]-  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]-  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]-  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]-  --libdir=DIR            object code libraries [EPREFIX/lib]-  --includedir=DIR        C header files [PREFIX/include]-  --oldincludedir=DIR     C header files for non-gcc [/usr/include]-  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]-  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]-  --infodir=DIR           info documentation [DATAROOTDIR/info]-  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]-  --mandir=DIR            man documentation [DATAROOTDIR/man]-  --docdir=DIR            documentation root [DATAROOTDIR/doc/leveldb]-  --htmldir=DIR           html documentation [DOCDIR]-  --dvidir=DIR            dvi documentation [DOCDIR]-  --pdfdir=DIR            pdf documentation [DOCDIR]-  --psdir=DIR             ps documentation [DOCDIR]-_ACEOF--  cat <<\_ACEOF-_ACEOF-fi--if test -n "$ac_init_help"; then-  case $ac_init_help in-     short | recursive ) echo "Configuration of Haskell LevelDB package 0.1:";;-   esac-  cat <<\_ACEOF--Some influential environment variables:-  CXX         C++ compiler command-  CXXFLAGS    C++ compiler flags-  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a-              nonstandard directory <lib dir>-  LIBS        libraries to pass to the linker, e.g. -l<library>-  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if-              you have headers in a nonstandard directory <include dir>-  CXXCPP      C++ preprocessor--Use these variables to override the choices made by `configure' or to help-it to find libraries and programs with nonstandard names/locations.--Report bugs to <mad.one@gmail.com>.-Haskell LevelDB package home page: <http://thoughtpolice.github.com/hs-leveldb>.-_ACEOF-ac_status=$?-fi--if test "$ac_init_help" = "recursive"; then-  # If there are subdirs, report their specific --help.-  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue-    test -d "$ac_dir" ||-      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||-      continue-    ac_builddir=.--case "$ac_dir" in-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;-*)-  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`-  # A ".." for each directory in $ac_dir_suffix.-  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`-  case $ac_top_builddir_sub in-  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;-  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;-  esac ;;-esac-ac_abs_top_builddir=$ac_pwd-ac_abs_builddir=$ac_pwd$ac_dir_suffix-# for backward compatibility:-ac_top_builddir=$ac_top_build_prefix--case $srcdir in-  .)  # We are building in place.-    ac_srcdir=.-    ac_top_srcdir=$ac_top_builddir_sub-    ac_abs_top_srcdir=$ac_pwd ;;-  [\\/]* | ?:[\\/]* )  # Absolute name.-    ac_srcdir=$srcdir$ac_dir_suffix;-    ac_top_srcdir=$srcdir-    ac_abs_top_srcdir=$srcdir ;;-  *) # Relative name.-    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix-    ac_top_srcdir=$ac_top_build_prefix$srcdir-    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;-esac-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix--    cd "$ac_dir" || { ac_status=$?; continue; }-    # Check for guested configure.-    if test -f "$ac_srcdir/configure.gnu"; then-      echo &&-      $SHELL "$ac_srcdir/configure.gnu" --help=recursive-    elif test -f "$ac_srcdir/configure"; then-      echo &&-      $SHELL "$ac_srcdir/configure" --help=recursive-    else-      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2-    fi || ac_status=$?-    cd "$ac_pwd" || { ac_status=$?; break; }-  done-fi--test -n "$ac_init_help" && exit $ac_status-if $ac_init_version; then-  cat <<\_ACEOF-Haskell LevelDB package configure 0.1-generated by GNU Autoconf 2.68--Copyright (C) 2010 Free Software Foundation, Inc.-This configure script is free software; the Free Software Foundation-gives unlimited permission to copy, distribute and modify it.-_ACEOF-  exit-fi--## ------------------------ ##-## Autoconf initialization. ##-## ------------------------ ##--# ac_fn_cxx_try_compile LINENO-# -----------------------------# Try to compile conftest.$ac_ext, and return whether this succeeded.-ac_fn_cxx_try_compile ()-{-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack-  rm -f conftest.$ac_objext-  if { { ac_try="$ac_compile"-case "(($ac_try" in-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;-  *) ac_try_echo=$ac_try;;-esac-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""-$as_echo "$ac_try_echo"; } >&5-  (eval "$ac_compile") 2>conftest.err-  ac_status=$?-  if test -s conftest.err; then-    grep -v '^ *+' conftest.err >conftest.er1-    cat conftest.er1 >&5-    mv -f conftest.er1 conftest.err-  fi-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5-  test $ac_status = 0; } && {-	 test -z "$ac_cxx_werror_flag" ||-	 test ! -s conftest.err-       } && test -s conftest.$ac_objext; then :-  ac_retval=0-else-  $as_echo "$as_me: failed program was:" >&5-sed 's/^/| /' conftest.$ac_ext >&5--	ac_retval=1-fi-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno-  as_fn_set_status $ac_retval--} # ac_fn_cxx_try_compile--# ac_fn_cxx_try_cpp LINENO-# -------------------------# Try to preprocess conftest.$ac_ext, and return whether this succeeded.-ac_fn_cxx_try_cpp ()-{-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack-  if { { ac_try="$ac_cpp conftest.$ac_ext"-case "(($ac_try" in-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;-  *) ac_try_echo=$ac_try;;-esac-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""-$as_echo "$ac_try_echo"; } >&5-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err-  ac_status=$?-  if test -s conftest.err; then-    grep -v '^ *+' conftest.err >conftest.er1-    cat conftest.er1 >&5-    mv -f conftest.er1 conftest.err-  fi-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5-  test $ac_status = 0; } > conftest.i && {-	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||-	 test ! -s conftest.err-       }; then :-  ac_retval=0-else-  $as_echo "$as_me: failed program was:" >&5-sed 's/^/| /' conftest.$ac_ext >&5--    ac_retval=1-fi-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno-  as_fn_set_status $ac_retval--} # ac_fn_cxx_try_cpp--# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES-# ----------------------------------------------------------# Tests whether HEADER exists, giving a warning if it cannot be compiled using-# the include files in INCLUDES and setting the cache variable VAR-# accordingly.-ac_fn_cxx_check_header_mongrel ()-{-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack-  if eval \${$3+:} false; then :-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5-$as_echo_n "checking for $2... " >&6; }-if eval \${$3+:} false; then :-  $as_echo_n "(cached) " >&6-fi-eval ac_res=\$$3-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5-$as_echo "$ac_res" >&6; }-else-  # Is the header compilable?-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5-$as_echo_n "checking $2 usability... " >&6; }-cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-$4-#include <$2>-_ACEOF-if ac_fn_cxx_try_compile "$LINENO"; then :-  ac_header_compiler=yes-else-  ac_header_compiler=no-fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5-$as_echo "$ac_header_compiler" >&6; }--# Is the header present?-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5-$as_echo_n "checking $2 presence... " >&6; }-cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <$2>-_ACEOF-if ac_fn_cxx_try_cpp "$LINENO"; then :-  ac_header_preproc=yes-else-  ac_header_preproc=no-fi-rm -f conftest.err conftest.i conftest.$ac_ext-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5-$as_echo "$ac_header_preproc" >&6; }--# So?  What about this header?-case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #((-  yes:no: )-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5-$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}-    ;;-  no:yes:* )-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5-$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5-$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5-$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5-$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}-( $as_echo "## -------------------------------- ##-## Report this to mad.one@gmail.com ##-## -------------------------------- ##"-     ) | sed "s/^/$as_me: WARNING:     /" >&2-    ;;-esac-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5-$as_echo_n "checking for $2... " >&6; }-if eval \${$3+:} false; then :-  $as_echo_n "(cached) " >&6-else-  eval "$3=\$ac_header_compiler"-fi-eval ac_res=\$$3-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5-$as_echo "$ac_res" >&6; }-fi-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno--} # ac_fn_cxx_check_header_mongrel--# ac_fn_cxx_try_run LINENO-# -------------------------# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes-# that executables *can* be run.-ac_fn_cxx_try_run ()-{-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack-  if { { ac_try="$ac_link"-case "(($ac_try" in-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;-  *) ac_try_echo=$ac_try;;-esac-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""-$as_echo "$ac_try_echo"; } >&5-  (eval "$ac_link") 2>&5-  ac_status=$?-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5-  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'-  { { case "(($ac_try" in-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;-  *) ac_try_echo=$ac_try;;-esac-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""-$as_echo "$ac_try_echo"; } >&5-  (eval "$ac_try") 2>&5-  ac_status=$?-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5-  test $ac_status = 0; }; }; then :-  ac_retval=0-else-  $as_echo "$as_me: program exited with status $ac_status" >&5-       $as_echo "$as_me: failed program was:" >&5-sed 's/^/| /' conftest.$ac_ext >&5--       ac_retval=$ac_status-fi-  rm -rf conftest.dSYM conftest_ipa8_conftest.oo-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno-  as_fn_set_status $ac_retval--} # ac_fn_cxx_try_run--# ac_fn_cxx_check_header_compile LINENO HEADER VAR INCLUDES-# ----------------------------------------------------------# Tests whether HEADER exists and can be compiled using the include files in-# INCLUDES, setting the cache variable VAR accordingly.-ac_fn_cxx_check_header_compile ()-{-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5-$as_echo_n "checking for $2... " >&6; }-if eval \${$3+:} false; then :-  $as_echo_n "(cached) " >&6-else-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-$4-#include <$2>-_ACEOF-if ac_fn_cxx_try_compile "$LINENO"; then :-  eval "$3=yes"-else-  eval "$3=no"-fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext-fi-eval ac_res=\$$3-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5-$as_echo "$ac_res" >&6; }-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno--} # ac_fn_cxx_check_header_compile-cat >config.log <<_ACEOF-This file contains any messages produced by compilers while-running configure, to aid debugging if configure makes a mistake.--It was created by Haskell LevelDB package $as_me 0.1, which was-generated by GNU Autoconf 2.68.  Invocation command line was--  $ $0 $@--_ACEOF-exec 5>>config.log-{-cat <<_ASUNAME-## --------- ##-## Platform. ##-## --------- ##--hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`-uname -m = `(uname -m) 2>/dev/null || echo unknown`-uname -r = `(uname -r) 2>/dev/null || echo unknown`-uname -s = `(uname -s) 2>/dev/null || echo unknown`-uname -v = `(uname -v) 2>/dev/null || echo unknown`--/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`-/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`--/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`-/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`-/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`-/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`-/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`-/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`--_ASUNAME--as_save_IFS=$IFS; IFS=$PATH_SEPARATOR-for as_dir in $PATH-do-  IFS=$as_save_IFS-  test -z "$as_dir" && as_dir=.-    $as_echo "PATH: $as_dir"-  done-IFS=$as_save_IFS--} >&5--cat >&5 <<_ACEOF---## ----------- ##-## Core tests. ##-## ----------- ##--_ACEOF---# Keep a trace of the command line.-# Strip out --no-create and --no-recursion so they do not pile up.-# Strip out --silent because we don't want to record it for future runs.-# Also quote any args containing shell meta-characters.-# Make two passes to allow for proper duplicate-argument suppression.-ac_configure_args=-ac_configure_args0=-ac_configure_args1=-ac_must_keep_next=false-for ac_pass in 1 2-do-  for ac_arg-  do-    case $ac_arg in-    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;-    -q | -quiet | --quiet | --quie | --qui | --qu | --q \-    | -silent | --silent | --silen | --sile | --sil)-      continue ;;-    *\'*)-      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;-    esac-    case $ac_pass in-    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;-    2)-      as_fn_append ac_configure_args1 " '$ac_arg'"-      if test $ac_must_keep_next = true; then-	ac_must_keep_next=false # Got value, back to normal.-      else-	case $ac_arg in-	  *=* | --config-cache | -C | -disable-* | --disable-* \-	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \-	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \-	  | -with-* | --with-* | -without-* | --without-* | --x)-	    case "$ac_configure_args0 " in-	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;-	    esac-	    ;;-	  -* ) ac_must_keep_next=true ;;-	esac-      fi-      as_fn_append ac_configure_args " '$ac_arg'"-      ;;-    esac-  done-done-{ ac_configure_args0=; unset ac_configure_args0;}-{ ac_configure_args1=; unset ac_configure_args1;}--# When interrupted or exit'd, cleanup temporary files, and complete-# config.log.  We remove comments because anyway the quotes in there-# would cause problems or look ugly.-# WARNING: Use '\'' to represent an apostrophe within the trap.-# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.-trap 'exit_status=$?-  # Save into config.log some information that might help in debugging.-  {-    echo--    $as_echo "## ---------------- ##-## Cache variables. ##-## ---------------- ##"-    echo-    # The following way of writing the cache mishandles newlines in values,-(-  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do-    eval ac_val=\$$ac_var-    case $ac_val in #(-    *${as_nl}*)-      case $ac_var in #(-      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;-      esac-      case $ac_var in #(-      _ | IFS | as_nl) ;; #(-      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(-      *) { eval $ac_var=; unset $ac_var;} ;;-      esac ;;-    esac-  done-  (set) 2>&1 |-    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(-    *${as_nl}ac_space=\ *)-      sed -n \-	"s/'\''/'\''\\\\'\'''\''/g;-	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"-      ;; #(-    *)-      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"-      ;;-    esac |-    sort-)-    echo--    $as_echo "## ----------------- ##-## Output variables. ##-## ----------------- ##"-    echo-    for ac_var in $ac_subst_vars-    do-      eval ac_val=\$$ac_var-      case $ac_val in-      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;-      esac-      $as_echo "$ac_var='\''$ac_val'\''"-    done | sort-    echo--    if test -n "$ac_subst_files"; then-      $as_echo "## ------------------- ##-## File substitutions. ##-## ------------------- ##"-      echo-      for ac_var in $ac_subst_files-      do-	eval ac_val=\$$ac_var-	case $ac_val in-	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;-	esac-	$as_echo "$ac_var='\''$ac_val'\''"-      done | sort-      echo-    fi--    if test -s confdefs.h; then-      $as_echo "## ----------- ##-## confdefs.h. ##-## ----------- ##"-      echo-      cat confdefs.h-      echo-    fi-    test "$ac_signal" != 0 &&-      $as_echo "$as_me: caught signal $ac_signal"-    $as_echo "$as_me: exit $exit_status"-  } >&5-  rm -f core *.core core.conftest.* &&-    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&-    exit $exit_status-' 0-for ac_signal in 1 2 13 15; do-  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal-done-ac_signal=0--# confdefs.h avoids OS command line length limits that DEFS can exceed.-rm -f -r conftest* confdefs.h--$as_echo "/* confdefs.h */" > confdefs.h--# Predefined preprocessor variables.--cat >>confdefs.h <<_ACEOF-#define PACKAGE_NAME "$PACKAGE_NAME"-_ACEOF--cat >>confdefs.h <<_ACEOF-#define PACKAGE_TARNAME "$PACKAGE_TARNAME"-_ACEOF--cat >>confdefs.h <<_ACEOF-#define PACKAGE_VERSION "$PACKAGE_VERSION"-_ACEOF--cat >>confdefs.h <<_ACEOF-#define PACKAGE_STRING "$PACKAGE_STRING"-_ACEOF--cat >>confdefs.h <<_ACEOF-#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"-_ACEOF--cat >>confdefs.h <<_ACEOF-#define PACKAGE_URL "$PACKAGE_URL"-_ACEOF---# Let the site file select an alternate cache file if it wants to.-# Prefer an explicitly selected file to automatically selected ones.-ac_site_file1=NONE-ac_site_file2=NONE-if test -n "$CONFIG_SITE"; then-  # We do not want a PATH search for config.site.-  case $CONFIG_SITE in #((-    -*)  ac_site_file1=./$CONFIG_SITE;;-    */*) ac_site_file1=$CONFIG_SITE;;-    *)   ac_site_file1=./$CONFIG_SITE;;-  esac-elif test "x$prefix" != xNONE; then-  ac_site_file1=$prefix/share/config.site-  ac_site_file2=$prefix/etc/config.site-else-  ac_site_file1=$ac_default_prefix/share/config.site-  ac_site_file2=$ac_default_prefix/etc/config.site-fi-for ac_site_file in "$ac_site_file1" "$ac_site_file2"-do-  test "x$ac_site_file" = xNONE && continue-  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then-    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5-$as_echo "$as_me: loading site script $ac_site_file" >&6;}-    sed 's/^/| /' "$ac_site_file" >&5-    . "$ac_site_file" \-      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}-as_fn_error $? "failed to load site script $ac_site_file-See \`config.log' for more details" "$LINENO" 5; }-  fi-done--if test -r "$cache_file"; then-  # Some versions of bash will fail to source /dev/null (special files-  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.-  if test /dev/null != "$cache_file" && test -f "$cache_file"; then-    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5-$as_echo "$as_me: loading cache $cache_file" >&6;}-    case $cache_file in-      [\\/]* | ?:[\\/]* ) . "$cache_file";;-      *)                      . "./$cache_file";;-    esac-  fi-else-  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5-$as_echo "$as_me: creating cache $cache_file" >&6;}-  >$cache_file-fi--# Check that the precious variables saved in the cache have kept the same-# value.-ac_cache_corrupted=false-for ac_var in $ac_precious_vars; do-  eval ac_old_set=\$ac_cv_env_${ac_var}_set-  eval ac_new_set=\$ac_env_${ac_var}_set-  eval ac_old_val=\$ac_cv_env_${ac_var}_value-  eval ac_new_val=\$ac_env_${ac_var}_value-  case $ac_old_set,$ac_new_set in-    set,)-      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5-$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}-      ac_cache_corrupted=: ;;-    ,set)-      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5-$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}-      ac_cache_corrupted=: ;;-    ,);;-    *)-      if test "x$ac_old_val" != "x$ac_new_val"; then-	# differences in whitespace do not lead to failure.-	ac_old_val_w=`echo x $ac_old_val`-	ac_new_val_w=`echo x $ac_new_val`-	if test "$ac_old_val_w" != "$ac_new_val_w"; then-	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5-$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}-	  ac_cache_corrupted=:-	else-	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5-$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}-	  eval $ac_var=\$ac_old_val-	fi-	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5-$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}-	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5-$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}-      fi;;-  esac-  # Pass precious variables to config.status.-  if test "$ac_new_set" = set; then-    case $ac_new_val in-    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;-    *) ac_arg=$ac_var=$ac_new_val ;;-    esac-    case " $ac_configure_args " in-      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.-      *) as_fn_append ac_configure_args " '$ac_arg'" ;;-    esac-  fi-done-if $ac_cache_corrupted; then-  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}-  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5-$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}-  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5-fi-## -------------------- ##-## Main body of script. ##-## -------------------- ##--ac_ext=c-ac_cpp='$CPP $CPPFLAGS'-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'-ac_compiler_gnu=$ac_cv_c_compiler_gnu----ac_ext=cpp-ac_cpp='$CXXCPP $CPPFLAGS'-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu----ac_ext=cpp-ac_cpp='$CXXCPP $CPPFLAGS'-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu-if test -z "$CXX"; then-  if test -n "$CCC"; then-    CXX=$CCC-  else-    if test -n "$ac_tool_prefix"; then-  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC-  do-    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.-set dummy $ac_tool_prefix$ac_prog; ac_word=$2-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5-$as_echo_n "checking for $ac_word... " >&6; }-if ${ac_cv_prog_CXX+:} false; then :-  $as_echo_n "(cached) " >&6-else-  if test -n "$CXX"; then-  ac_cv_prog_CXX="$CXX" # Let the user override the test.-else-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR-for as_dir in $PATH-do-  IFS=$as_save_IFS-  test -z "$as_dir" && as_dir=.-    for ac_exec_ext in '' $ac_executable_extensions; do-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then-    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5-    break 2-  fi-done-  done-IFS=$as_save_IFS--fi-fi-CXX=$ac_cv_prog_CXX-if test -n "$CXX"; then-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5-$as_echo "$CXX" >&6; }-else-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5-$as_echo "no" >&6; }-fi---    test -n "$CXX" && break-  done-fi-if test -z "$CXX"; then-  ac_ct_CXX=$CXX-  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC-do-  # Extract the first word of "$ac_prog", so it can be a program name with args.-set dummy $ac_prog; ac_word=$2-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5-$as_echo_n "checking for $ac_word... " >&6; }-if ${ac_cv_prog_ac_ct_CXX+:} false; then :-  $as_echo_n "(cached) " >&6-else-  if test -n "$ac_ct_CXX"; then-  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.-else-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR-for as_dir in $PATH-do-  IFS=$as_save_IFS-  test -z "$as_dir" && as_dir=.-    for ac_exec_ext in '' $ac_executable_extensions; do-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then-    ac_cv_prog_ac_ct_CXX="$ac_prog"-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5-    break 2-  fi-done-  done-IFS=$as_save_IFS--fi-fi-ac_ct_CXX=$ac_cv_prog_ac_ct_CXX-if test -n "$ac_ct_CXX"; then-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5-$as_echo "$ac_ct_CXX" >&6; }-else-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5-$as_echo "no" >&6; }-fi---  test -n "$ac_ct_CXX" && break-done--  if test "x$ac_ct_CXX" = x; then-    CXX="g++"-  else-    case $cross_compiling:$ac_tool_warned in-yes:)-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}-ac_tool_warned=yes ;;-esac-    CXX=$ac_ct_CXX-  fi-fi--  fi-fi-# Provide some information about the compiler.-$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5-set X $ac_compile-ac_compiler=$2-for ac_option in --version -v -V -qversion; do-  { { ac_try="$ac_compiler $ac_option >&5"-case "(($ac_try" in-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;-  *) ac_try_echo=$ac_try;;-esac-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""-$as_echo "$ac_try_echo"; } >&5-  (eval "$ac_compiler $ac_option >&5") 2>conftest.err-  ac_status=$?-  if test -s conftest.err; then-    sed '10a\-... rest of stderr output deleted ...-         10q' conftest.err >conftest.er1-    cat conftest.er1 >&5-  fi-  rm -f conftest.er1 conftest.err-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5-  test $ac_status = 0; }-done--cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */--int-main ()-{--  ;-  return 0;-}-_ACEOF-ac_clean_files_save=$ac_clean_files-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"-# Try to create an executable without -o first, disregard a.out.-# It will help us diagnose broken compilers, and finding out an intuition-# of exeext.-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5-$as_echo_n "checking whether the C++ compiler works... " >&6; }-ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`--# The possible output files:-ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"--ac_rmfiles=-for ac_file in $ac_files-do-  case $ac_file in-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;-    * ) ac_rmfiles="$ac_rmfiles $ac_file";;-  esac-done-rm -f $ac_rmfiles--if { { ac_try="$ac_link_default"-case "(($ac_try" in-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;-  *) ac_try_echo=$ac_try;;-esac-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""-$as_echo "$ac_try_echo"; } >&5-  (eval "$ac_link_default") 2>&5-  ac_status=$?-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5-  test $ac_status = 0; }; then :-  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.-# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'-# in a Makefile.  We should not override ac_cv_exeext if it was cached,-# so that the user can short-circuit this test for compilers unknown to-# Autoconf.-for ac_file in $ac_files ''-do-  test -f "$ac_file" || continue-  case $ac_file in-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )-	;;-    [ab].out )-	# We found the default executable, but exeext='' is most-	# certainly right.-	break;;-    *.* )-	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;-	then :; else-	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`-	fi-	# We set ac_cv_exeext here because the later test for it is not-	# safe: cross compilers may not add the suffix if given an `-o'-	# argument, so we may need to know it at that point already.-	# Even if this section looks crufty: it has the advantage of-	# actually working.-	break;;-    * )-	break;;-  esac-done-test "$ac_cv_exeext" = no && ac_cv_exeext=--else-  ac_file=''-fi-if test -z "$ac_file"; then :-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5-$as_echo "no" >&6; }-$as_echo "$as_me: failed program was:" >&5-sed 's/^/| /' conftest.$ac_ext >&5--{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}-as_fn_error 77 "C++ compiler cannot create executables-See \`config.log' for more details" "$LINENO" 5; }-else-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5-$as_echo "yes" >&6; }-fi-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5-$as_echo_n "checking for C++ compiler default output file name... " >&6; }-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5-$as_echo "$ac_file" >&6; }-ac_exeext=$ac_cv_exeext--rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out-ac_clean_files=$ac_clean_files_save-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5-$as_echo_n "checking for suffix of executables... " >&6; }-if { { ac_try="$ac_link"-case "(($ac_try" in-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;-  *) ac_try_echo=$ac_try;;-esac-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""-$as_echo "$ac_try_echo"; } >&5-  (eval "$ac_link") 2>&5-  ac_status=$?-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5-  test $ac_status = 0; }; then :-  # If both `conftest.exe' and `conftest' are `present' (well, observable)-# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will-# work properly (i.e., refer to `conftest.exe'), while it won't with-# `rm'.-for ac_file in conftest.exe conftest conftest.*; do-  test -f "$ac_file" || continue-  case $ac_file in-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;-    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`-	  break;;-    * ) break;;-  esac-done-else-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}-as_fn_error $? "cannot compute suffix of executables: cannot compile and link-See \`config.log' for more details" "$LINENO" 5; }-fi-rm -f conftest conftest$ac_cv_exeext-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5-$as_echo "$ac_cv_exeext" >&6; }--rm -f conftest.$ac_ext-EXEEXT=$ac_cv_exeext-ac_exeext=$EXEEXT-cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <stdio.h>-int-main ()-{-FILE *f = fopen ("conftest.out", "w");- return ferror (f) || fclose (f) != 0;--  ;-  return 0;-}-_ACEOF-ac_clean_files="$ac_clean_files conftest.out"-# Check that the compiler produces executables we can run.  If not, either-# the compiler is broken, or we cross compile.-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5-$as_echo_n "checking whether we are cross compiling... " >&6; }-if test "$cross_compiling" != yes; then-  { { ac_try="$ac_link"-case "(($ac_try" in-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;-  *) ac_try_echo=$ac_try;;-esac-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""-$as_echo "$ac_try_echo"; } >&5-  (eval "$ac_link") 2>&5-  ac_status=$?-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5-  test $ac_status = 0; }-  if { ac_try='./conftest$ac_cv_exeext'-  { { case "(($ac_try" in-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;-  *) ac_try_echo=$ac_try;;-esac-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""-$as_echo "$ac_try_echo"; } >&5-  (eval "$ac_try") 2>&5-  ac_status=$?-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5-  test $ac_status = 0; }; }; then-    cross_compiling=no-  else-    if test "$cross_compiling" = maybe; then-	cross_compiling=yes-    else-	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}-as_fn_error $? "cannot run C++ compiled programs.-If you meant to cross compile, use \`--host'.-See \`config.log' for more details" "$LINENO" 5; }-    fi-  fi-fi-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5-$as_echo "$cross_compiling" >&6; }--rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out-ac_clean_files=$ac_clean_files_save-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5-$as_echo_n "checking for suffix of object files... " >&6; }-if ${ac_cv_objext+:} false; then :-  $as_echo_n "(cached) " >&6-else-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */--int-main ()-{--  ;-  return 0;-}-_ACEOF-rm -f conftest.o conftest.obj-if { { ac_try="$ac_compile"-case "(($ac_try" in-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;-  *) ac_try_echo=$ac_try;;-esac-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""-$as_echo "$ac_try_echo"; } >&5-  (eval "$ac_compile") 2>&5-  ac_status=$?-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5-  test $ac_status = 0; }; then :-  for ac_file in conftest.o conftest.obj conftest.*; do-  test -f "$ac_file" || continue;-  case $ac_file in-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;-    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`-       break;;-  esac-done-else-  $as_echo "$as_me: failed program was:" >&5-sed 's/^/| /' conftest.$ac_ext >&5--{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}-as_fn_error $? "cannot compute suffix of object files: cannot compile-See \`config.log' for more details" "$LINENO" 5; }-fi-rm -f conftest.$ac_cv_objext conftest.$ac_ext-fi-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5-$as_echo "$ac_cv_objext" >&6; }-OBJEXT=$ac_cv_objext-ac_objext=$OBJEXT-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5-$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }-if ${ac_cv_cxx_compiler_gnu+:} false; then :-  $as_echo_n "(cached) " >&6-else-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */--int-main ()-{-#ifndef __GNUC__-       choke me-#endif--  ;-  return 0;-}-_ACEOF-if ac_fn_cxx_try_compile "$LINENO"; then :-  ac_compiler_gnu=yes-else-  ac_compiler_gnu=no-fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext-ac_cv_cxx_compiler_gnu=$ac_compiler_gnu--fi-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5-$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }-if test $ac_compiler_gnu = yes; then-  GXX=yes-else-  GXX=-fi-ac_test_CXXFLAGS=${CXXFLAGS+set}-ac_save_CXXFLAGS=$CXXFLAGS-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5-$as_echo_n "checking whether $CXX accepts -g... " >&6; }-if ${ac_cv_prog_cxx_g+:} false; then :-  $as_echo_n "(cached) " >&6-else-  ac_save_cxx_werror_flag=$ac_cxx_werror_flag-   ac_cxx_werror_flag=yes-   ac_cv_prog_cxx_g=no-   CXXFLAGS="-g"-   cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */--int-main ()-{--  ;-  return 0;-}-_ACEOF-if ac_fn_cxx_try_compile "$LINENO"; then :-  ac_cv_prog_cxx_g=yes-else-  CXXFLAGS=""-      cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */--int-main ()-{--  ;-  return 0;-}-_ACEOF-if ac_fn_cxx_try_compile "$LINENO"; then :--else-  ac_cxx_werror_flag=$ac_save_cxx_werror_flag-	 CXXFLAGS="-g"-	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */--int-main ()-{--  ;-  return 0;-}-_ACEOF-if ac_fn_cxx_try_compile "$LINENO"; then :-  ac_cv_prog_cxx_g=yes-fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext-fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext-fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext-   ac_cxx_werror_flag=$ac_save_cxx_werror_flag-fi-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5-$as_echo "$ac_cv_prog_cxx_g" >&6; }-if test "$ac_test_CXXFLAGS" = set; then-  CXXFLAGS=$ac_save_CXXFLAGS-elif test $ac_cv_prog_cxx_g = yes; then-  if test "$GXX" = yes; then-    CXXFLAGS="-g -O2"-  else-    CXXFLAGS="-g"-  fi-else-  if test "$GXX" = yes; then-    CXXFLAGS="-O2"-  else-    CXXFLAGS=-  fi-fi-ac_ext=cpp-ac_cpp='$CXXCPP $CPPFLAGS'-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu---ac_ext=cpp-ac_cpp='$CXXCPP $CPPFLAGS'-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5-$as_echo_n "checking how to run the C++ preprocessor... " >&6; }-if test -z "$CXXCPP"; then-  if ${ac_cv_prog_CXXCPP+:} false; then :-  $as_echo_n "(cached) " >&6-else-      # Double quotes because CXXCPP needs to be expanded-    for CXXCPP in "$CXX -E" "/lib/cpp"-    do-      ac_preproc_ok=false-for ac_cxx_preproc_warn_flag in '' yes-do-  # Use a header file that comes with gcc, so configuring glibc-  # with a fresh cross-compiler works.-  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since-  # <limits.h> exists even on freestanding compilers.-  # On the NeXT, cc -E runs the code through the compiler's parser,-  # not just through cpp. "Syntax error" is here to catch this case.-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#ifdef __STDC__-# include <limits.h>-#else-# include <assert.h>-#endif-		     Syntax error-_ACEOF-if ac_fn_cxx_try_cpp "$LINENO"; then :--else-  # Broken: fails on valid input.-continue-fi-rm -f conftest.err conftest.i conftest.$ac_ext--  # OK, works on sane cases.  Now check whether nonexistent headers-  # can be detected and how.-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <ac_nonexistent.h>-_ACEOF-if ac_fn_cxx_try_cpp "$LINENO"; then :-  # Broken: success on invalid input.-continue-else-  # Passes both tests.-ac_preproc_ok=:-break-fi-rm -f conftest.err conftest.i conftest.$ac_ext--done-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.-rm -f conftest.i conftest.err conftest.$ac_ext-if $ac_preproc_ok; then :-  break-fi--    done-    ac_cv_prog_CXXCPP=$CXXCPP--fi-  CXXCPP=$ac_cv_prog_CXXCPP-else-  ac_cv_prog_CXXCPP=$CXXCPP-fi-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5-$as_echo "$CXXCPP" >&6; }-ac_preproc_ok=false-for ac_cxx_preproc_warn_flag in '' yes-do-  # Use a header file that comes with gcc, so configuring glibc-  # with a fresh cross-compiler works.-  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since-  # <limits.h> exists even on freestanding compilers.-  # On the NeXT, cc -E runs the code through the compiler's parser,-  # not just through cpp. "Syntax error" is here to catch this case.-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#ifdef __STDC__-# include <limits.h>-#else-# include <assert.h>-#endif-		     Syntax error-_ACEOF-if ac_fn_cxx_try_cpp "$LINENO"; then :--else-  # Broken: fails on valid input.-continue-fi-rm -f conftest.err conftest.i conftest.$ac_ext--  # OK, works on sane cases.  Now check whether nonexistent headers-  # can be detected and how.-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <ac_nonexistent.h>-_ACEOF-if ac_fn_cxx_try_cpp "$LINENO"; then :-  # Broken: success on invalid input.-continue-else-  # Passes both tests.-ac_preproc_ok=:-break-fi-rm -f conftest.err conftest.i conftest.$ac_ext--done-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.-rm -f conftest.i conftest.err conftest.$ac_ext-if $ac_preproc_ok; then :--else-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}-as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check-See \`config.log' for more details" "$LINENO" 5; }-fi--ac_ext=cpp-ac_cpp='$CXXCPP $CPPFLAGS'-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu---{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5-$as_echo_n "checking for grep that handles long lines and -e... " >&6; }-if ${ac_cv_path_GREP+:} false; then :-  $as_echo_n "(cached) " >&6-else-  if test -z "$GREP"; then-  ac_path_GREP_found=false-  # Loop through the user's path and test for each of PROGNAME-LIST-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin-do-  IFS=$as_save_IFS-  test -z "$as_dir" && as_dir=.-    for ac_prog in grep ggrep; do-    for ac_exec_ext in '' $ac_executable_extensions; do-      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"-      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue-# Check for GNU ac_path_GREP and select it if it is found.-  # Check for GNU $ac_path_GREP-case `"$ac_path_GREP" --version 2>&1` in-*GNU*)-  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;-*)-  ac_count=0-  $as_echo_n 0123456789 >"conftest.in"-  while :-  do-    cat "conftest.in" "conftest.in" >"conftest.tmp"-    mv "conftest.tmp" "conftest.in"-    cp "conftest.in" "conftest.nl"-    $as_echo 'GREP' >> "conftest.nl"-    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break-    as_fn_arith $ac_count + 1 && ac_count=$as_val-    if test $ac_count -gt ${ac_path_GREP_max-0}; then-      # Best one so far, save it but keep looking for a better one-      ac_cv_path_GREP="$ac_path_GREP"-      ac_path_GREP_max=$ac_count-    fi-    # 10*(2^10) chars as input seems more than enough-    test $ac_count -gt 10 && break-  done-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;-esac--      $ac_path_GREP_found && break 3-    done-  done-  done-IFS=$as_save_IFS-  if test -z "$ac_cv_path_GREP"; then-    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5-  fi-else-  ac_cv_path_GREP=$GREP-fi--fi-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5-$as_echo "$ac_cv_path_GREP" >&6; }- GREP="$ac_cv_path_GREP"---{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5-$as_echo_n "checking for egrep... " >&6; }-if ${ac_cv_path_EGREP+:} false; then :-  $as_echo_n "(cached) " >&6-else-  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1-   then ac_cv_path_EGREP="$GREP -E"-   else-     if test -z "$EGREP"; then-  ac_path_EGREP_found=false-  # Loop through the user's path and test for each of PROGNAME-LIST-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin-do-  IFS=$as_save_IFS-  test -z "$as_dir" && as_dir=.-    for ac_prog in egrep; do-    for ac_exec_ext in '' $ac_executable_extensions; do-      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"-      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue-# Check for GNU ac_path_EGREP and select it if it is found.-  # Check for GNU $ac_path_EGREP-case `"$ac_path_EGREP" --version 2>&1` in-*GNU*)-  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;-*)-  ac_count=0-  $as_echo_n 0123456789 >"conftest.in"-  while :-  do-    cat "conftest.in" "conftest.in" >"conftest.tmp"-    mv "conftest.tmp" "conftest.in"-    cp "conftest.in" "conftest.nl"-    $as_echo 'EGREP' >> "conftest.nl"-    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break-    as_fn_arith $ac_count + 1 && ac_count=$as_val-    if test $ac_count -gt ${ac_path_EGREP_max-0}; then-      # Best one so far, save it but keep looking for a better one-      ac_cv_path_EGREP="$ac_path_EGREP"-      ac_path_EGREP_max=$ac_count-    fi-    # 10*(2^10) chars as input seems more than enough-    test $ac_count -gt 10 && break-  done-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;-esac--      $ac_path_EGREP_found && break 3-    done-  done-  done-IFS=$as_save_IFS-  if test -z "$ac_cv_path_EGREP"; then-    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5-  fi-else-  ac_cv_path_EGREP=$EGREP-fi--   fi-fi-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5-$as_echo "$ac_cv_path_EGREP" >&6; }- EGREP="$ac_cv_path_EGREP"---{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5-$as_echo_n "checking for ANSI C header files... " >&6; }-if ${ac_cv_header_stdc+:} false; then :-  $as_echo_n "(cached) " >&6-else-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <stdlib.h>-#include <stdarg.h>-#include <string.h>-#include <float.h>--int-main ()-{--  ;-  return 0;-}-_ACEOF-if ac_fn_cxx_try_compile "$LINENO"; then :-  ac_cv_header_stdc=yes-else-  ac_cv_header_stdc=no-fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext--if test $ac_cv_header_stdc = yes; then-  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <string.h>--_ACEOF-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |-  $EGREP "memchr" >/dev/null 2>&1; then :--else-  ac_cv_header_stdc=no-fi-rm -f conftest*--fi--if test $ac_cv_header_stdc = yes; then-  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <stdlib.h>--_ACEOF-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |-  $EGREP "free" >/dev/null 2>&1; then :--else-  ac_cv_header_stdc=no-fi-rm -f conftest*--fi--if test $ac_cv_header_stdc = yes; then-  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.-  if test "$cross_compiling" = yes; then :-  :-else-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <ctype.h>-#include <stdlib.h>-#if ((' ' & 0x0FF) == 0x020)-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))-#else-# define ISLOWER(c) \-		   (('a' <= (c) && (c) <= 'i') \-		     || ('j' <= (c) && (c) <= 'r') \-		     || ('s' <= (c) && (c) <= 'z'))-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))-#endif--#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))-int-main ()-{-  int i;-  for (i = 0; i < 256; i++)-    if (XOR (islower (i), ISLOWER (i))-	|| toupper (i) != TOUPPER (i))-      return 2;-  return 0;-}-_ACEOF-if ac_fn_cxx_try_run "$LINENO"; then :--else-  ac_cv_header_stdc=no-fi-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \-  conftest.$ac_objext conftest.beam conftest.$ac_ext-fi--fi-fi-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5-$as_echo "$ac_cv_header_stdc" >&6; }-if test $ac_cv_header_stdc = yes; then--$as_echo "#define STDC_HEADERS 1" >>confdefs.h--fi--# On IRIX 5.3, sys/types and inttypes.h are conflicting.-for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \-		  inttypes.h stdint.h unistd.h-do :-  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`-ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default-"-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :-  cat >>confdefs.h <<_ACEOF-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1-_ACEOF--fi--done---for ac_header in snappy.h-do :-  ac_fn_cxx_check_header_mongrel "$LINENO" "snappy.h" "ac_cv_header_snappy_h" "$ac_includes_default"-if test "x$ac_cv_header_snappy_h" = xyes; then :-  cat >>confdefs.h <<_ACEOF-#define HAVE_SNAPPY_H 1-_ACEOF- snappy=yes-else-  snappy=no-fi--done---if test "x$snappy" = "xyes"-then-  SNAPPY="-DSNAPPY"-  SNAPPYLIB="snappy"-else-  SNAPPY=""-  SNAPPYLIB=""-fi---{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports C++11 cstdatomic" >&5-$as_echo_n "checking whether compiler supports C++11 cstdatomic... " >&6; }--OLD_CXXFLAGS="$CXXFLAGS"-CXXFLAGS="$CXXFLAGS -std=c++0x"-cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */--#include <cstdatomic>-int main() {}--_ACEOF-if ac_fn_cxx_try_compile "$LINENO"; then :--     { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5-$as_echo "yes" >&6; }-     has_cstdatomic=yes--else--     { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5-$as_echo "no" >&6; }-     has_cstdatomic=no--fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext-CXXFLAGS="$OLD_CXXFLAGS"--if test "x$has_cstdatomic" = "xyes"-then-  CSTDATOMIC="-DLEVELDB_CSTDATOMIC_PRESENT -std=c++0x"-else-  CSTDATOMIC=""-fi--------ac_config_files="$ac_config_files leveldb-haskell.buildinfo"--cat >confcache <<\_ACEOF-# This file is a shell script that caches the results of configure-# tests run on this system so they can be shared between configure-# scripts and configure runs, see configure's option --config-cache.-# It is not useful on other systems.  If it contains results you don't-# want to keep, you may remove or edit it.-#-# config.status only pays attention to the cache file if you give it-# the --recheck option to rerun configure.-#-# `ac_cv_env_foo' variables (set or unset) will be overridden when-# loading this file, other *unset* `ac_cv_foo' will be assigned the-# following values.--_ACEOF--# The following way of writing the cache mishandles newlines in values,-# but we know of no workaround that is simple, portable, and efficient.-# So, we kill variables containing newlines.-# Ultrix sh set writes to stderr and can't be redirected directly,-# and sets the high bit in the cache file unless we assign to the vars.-(-  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do-    eval ac_val=\$$ac_var-    case $ac_val in #(-    *${as_nl}*)-      case $ac_var in #(-      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;-      esac-      case $ac_var in #(-      _ | IFS | as_nl) ;; #(-      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(-      *) { eval $ac_var=; unset $ac_var;} ;;-      esac ;;-    esac-  done--  (set) 2>&1 |-    case $as_nl`(ac_space=' '; set) 2>&1` in #(-    *${as_nl}ac_space=\ *)-      # `set' does not quote correctly, so add quotes: double-quote-      # substitution turns \\\\ into \\, and sed turns \\ into \.-      sed -n \-	"s/'/'\\\\''/g;-	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"-      ;; #(-    *)-      # `set' quotes correctly as required by POSIX, so do not add quotes.-      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"-      ;;-    esac |-    sort-) |-  sed '-     /^ac_cv_env_/b end-     t clear-     :clear-     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/-     t end-     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/-     :end' >>confcache-if diff "$cache_file" confcache >/dev/null 2>&1; then :; else-  if test -w "$cache_file"; then-    if test "x$cache_file" != "x/dev/null"; then-      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5-$as_echo "$as_me: updating cache $cache_file" >&6;}-      if test ! -f "$cache_file" || test -h "$cache_file"; then-	cat confcache >"$cache_file"-      else-        case $cache_file in #(-        */* | ?:*)-	  mv -f confcache "$cache_file"$$ &&-	  mv -f "$cache_file"$$ "$cache_file" ;; #(-        *)-	  mv -f confcache "$cache_file" ;;-	esac-      fi-    fi-  else-    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5-$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}-  fi-fi-rm -f confcache--test "x$prefix" = xNONE && prefix=$ac_default_prefix-# Let make expand exec_prefix.-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'--# Transform confdefs.h into DEFS.-# Protect against shell expansion while executing Makefile rules.-# Protect against Makefile macro expansion.-#-# If the first sed substitution is executed (which looks for macros that-# take arguments), then branch to the quote section.  Otherwise,-# look for a macro that doesn't take arguments.-ac_script='-:mline-/\\$/{- N- s,\\\n,,- b mline-}-t clear-:clear-s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*([^)]*)\)[	 ]*\(.*\)/-D\1=\2/g-t quote-s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)/-D\1=\2/g-t quote-b any-:quote-s/[	 `~#$^&*(){}\\|;'\''"<>?]/\\&/g-s/\[/\\&/g-s/\]/\\&/g-s/\$/$$/g-H-:any-${-	g-	s/^\n//-	s/\n/ /g-	p-}-'-DEFS=`sed -n "$ac_script" confdefs.h`---ac_libobjs=-ac_ltlibobjs=-U=-for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue-  # 1. Remove the extension, and $U if already installed.-  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'-  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`-  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR-  #    will be set to the directory where LIBOBJS objects are built.-  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"-  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'-done-LIBOBJS=$ac_libobjs--LTLIBOBJS=$ac_ltlibobjs----: "${CONFIG_STATUS=./config.status}"-ac_write_fail=0-ac_clean_files_save=$ac_clean_files-ac_clean_files="$ac_clean_files $CONFIG_STATUS"-{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5-$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}-as_write_fail=0-cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1-#! $SHELL-# Generated by $as_me.-# Run this file to recreate the current configuration.-# Compiler output produced by configure, useful for debugging-# configure, is in config.log if it exists.--debug=false-ac_cs_recheck=false-ac_cs_silent=false--SHELL=\${CONFIG_SHELL-$SHELL}-export SHELL-_ASEOF-cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1-## -------------------- ##-## M4sh Initialization. ##-## -------------------- ##--# Be more Bourne compatible-DUALCASE=1; export DUALCASE # for MKS sh-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :-  emulate sh-  NULLCMD=:-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which-  # is contrary to our usage.  Disable this feature.-  alias -g '${1+"$@"}'='"$@"'-  setopt NO_GLOB_SUBST-else-  case `(set -o) 2>/dev/null` in #(-  *posix*) :-    set -o posix ;; #(-  *) :-     ;;-esac-fi---as_nl='-'-export as_nl-# Printing a long string crashes Solaris 7 /usr/bin/printf.-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo-# Prefer a ksh shell builtin over an external printf program on Solaris,-# but without wasting forks for bash or zsh.-if test -z "$BASH_VERSION$ZSH_VERSION" \-    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then-  as_echo='print -r --'-  as_echo_n='print -rn --'-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then-  as_echo='printf %s\n'-  as_echo_n='printf %s'-else-  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then-    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'-    as_echo_n='/usr/ucb/echo -n'-  else-    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'-    as_echo_n_body='eval-      arg=$1;-      case $arg in #(-      *"$as_nl"*)-	expr "X$arg" : "X\\(.*\\)$as_nl";-	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;-      esac;-      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"-    '-    export as_echo_n_body-    as_echo_n='sh -c $as_echo_n_body as_echo'-  fi-  export as_echo_body-  as_echo='sh -c $as_echo_body as_echo'-fi--# The user is always right.-if test "${PATH_SEPARATOR+set}" != set; then-  PATH_SEPARATOR=:-  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {-    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||-      PATH_SEPARATOR=';'-  }-fi---# IFS-# We need space, tab and new line, in precisely that order.  Quoting is-# there to prevent editors from complaining about space-tab.-# (If _AS_PATH_WALK were called with IFS unset, it would disable word-# splitting by setting IFS to empty value.)-IFS=" ""	$as_nl"--# Find who we are.  Look in the path if we contain no directory separator.-as_myself=-case $0 in #((-  *[\\/]* ) as_myself=$0 ;;-  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR-for as_dir in $PATH-do-  IFS=$as_save_IFS-  test -z "$as_dir" && as_dir=.-    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break-  done-IFS=$as_save_IFS--     ;;-esac-# We did not find ourselves, most probably we were run as `sh COMMAND'-# in which case we are not to be found in the path.-if test "x$as_myself" = x; then-  as_myself=$0-fi-if test ! -f "$as_myself"; then-  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2-  exit 1-fi--# Unset variables that we do not need and which cause bugs (e.g. in-# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"-# suppresses any "Segmentation fault" message there.  '((' could-# trigger a bug in pdksh 5.2.14.-for as_var in BASH_ENV ENV MAIL MAILPATH-do eval test x\${$as_var+set} = xset \-  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :-done-PS1='$ '-PS2='> '-PS4='+ '--# NLS nuisances.-LC_ALL=C-export LC_ALL-LANGUAGE=C-export LANGUAGE--# CDPATH.-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH---# as_fn_error STATUS ERROR [LINENO LOG_FD]-# -----------------------------------------# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the-# script with STATUS, using 1 if that was 0.-as_fn_error ()-{-  as_status=$1; test $as_status -eq 0 && as_status=1-  if test "$4"; then-    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack-    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4-  fi-  $as_echo "$as_me: error: $2" >&2-  as_fn_exit $as_status-} # as_fn_error---# as_fn_set_status STATUS-# ------------------------# Set $? to STATUS, without forking.-as_fn_set_status ()-{-  return $1-} # as_fn_set_status--# as_fn_exit STATUS-# ------------------# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.-as_fn_exit ()-{-  set +e-  as_fn_set_status $1-  exit $1-} # as_fn_exit--# as_fn_unset VAR-# ----------------# Portably unset VAR.-as_fn_unset ()-{-  { eval $1=; unset $1;}-}-as_unset=as_fn_unset-# as_fn_append VAR VALUE-# -----------------------# Append the text in VALUE to the end of the definition contained in VAR. Take-# advantage of any shell optimizations that allow amortized linear growth over-# repeated appends, instead of the typical quadratic growth present in naive-# implementations.-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :-  eval 'as_fn_append ()-  {-    eval $1+=\$2-  }'-else-  as_fn_append ()-  {-    eval $1=\$$1\$2-  }-fi # as_fn_append--# as_fn_arith ARG...-# -------------------# Perform arithmetic evaluation on the ARGs, and store the result in the-# global $as_val. Take advantage of shells that can avoid forks. The arguments-# must be portable across $(()) and expr.-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :-  eval 'as_fn_arith ()-  {-    as_val=$(( $* ))-  }'-else-  as_fn_arith ()-  {-    as_val=`expr "$@" || test $? -eq 1`-  }-fi # as_fn_arith---if expr a : '\(a\)' >/dev/null 2>&1 &&-   test "X`expr 00001 : '.*\(...\)'`" = X001; then-  as_expr=expr-else-  as_expr=false-fi--if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then-  as_basename=basename-else-  as_basename=false-fi--if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then-  as_dirname=dirname-else-  as_dirname=false-fi--as_me=`$as_basename -- "$0" ||-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \-	 X"$0" : 'X\(//\)$' \| \-	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||-$as_echo X/"$0" |-    sed '/^.*\/\([^/][^/]*\)\/*$/{-	    s//\1/-	    q-	  }-	  /^X\/\(\/\/\)$/{-	    s//\1/-	    q-	  }-	  /^X\/\(\/\).*/{-	    s//\1/-	    q-	  }-	  s/.*/./; q'`--# Avoid depending upon Character Ranges.-as_cr_letters='abcdefghijklmnopqrstuvwxyz'-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'-as_cr_Letters=$as_cr_letters$as_cr_LETTERS-as_cr_digits='0123456789'-as_cr_alnum=$as_cr_Letters$as_cr_digits--ECHO_C= ECHO_N= ECHO_T=-case `echo -n x` in #(((((--n*)-  case `echo 'xy\c'` in-  *c*) ECHO_T='	';;	# ECHO_T is single tab character.-  xy)  ECHO_C='\c';;-  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null-       ECHO_T='	';;-  esac;;-*)-  ECHO_N='-n';;-esac--rm -f conf$$ conf$$.exe conf$$.file-if test -d conf$$.dir; then-  rm -f conf$$.dir/conf$$.file-else-  rm -f conf$$.dir-  mkdir conf$$.dir 2>/dev/null-fi-if (echo >conf$$.file) 2>/dev/null; then-  if ln -s conf$$.file conf$$ 2>/dev/null; then-    as_ln_s='ln -s'-    # ... but there are two gotchas:-    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.-    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.-    # In both cases, we have to default to `cp -p'.-    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||-      as_ln_s='cp -p'-  elif ln conf$$.file conf$$ 2>/dev/null; then-    as_ln_s=ln-  else-    as_ln_s='cp -p'-  fi-else-  as_ln_s='cp -p'-fi-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file-rmdir conf$$.dir 2>/dev/null---# as_fn_mkdir_p-# --------------# Create "$as_dir" as a directory, including parents if necessary.-as_fn_mkdir_p ()-{--  case $as_dir in #(-  -*) as_dir=./$as_dir;;-  esac-  test -d "$as_dir" || eval $as_mkdir_p || {-    as_dirs=-    while :; do-      case $as_dir in #(-      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(-      *) as_qdir=$as_dir;;-      esac-      as_dirs="'$as_qdir' $as_dirs"-      as_dir=`$as_dirname -- "$as_dir" ||-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \-	 X"$as_dir" : 'X\(//\)[^/]' \| \-	 X"$as_dir" : 'X\(//\)$' \| \-	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||-$as_echo X"$as_dir" |-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{-	    s//\1/-	    q-	  }-	  /^X\(\/\/\)[^/].*/{-	    s//\1/-	    q-	  }-	  /^X\(\/\/\)$/{-	    s//\1/-	    q-	  }-	  /^X\(\/\).*/{-	    s//\1/-	    q-	  }-	  s/.*/./; q'`-      test -d "$as_dir" && break-    done-    test -z "$as_dirs" || eval "mkdir $as_dirs"-  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"---} # as_fn_mkdir_p-if mkdir -p . 2>/dev/null; then-  as_mkdir_p='mkdir -p "$as_dir"'-else-  test -d ./-p && rmdir ./-p-  as_mkdir_p=false-fi--if test -x / >/dev/null 2>&1; then-  as_test_x='test -x'-else-  if ls -dL / >/dev/null 2>&1; then-    as_ls_L_option=L-  else-    as_ls_L_option=-  fi-  as_test_x='-    eval sh -c '\''-      if test -d "$1"; then-	test -d "$1/.";-      else-	case $1 in #(-	-*)set "./$1";;-	esac;-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((-	???[sx]*):;;*)false;;esac;fi-    '\'' sh-  '-fi-as_executable_p=$as_test_x--# Sed expression to map a string onto a valid CPP name.-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"--# Sed expression to map a string onto a valid variable name.-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"---exec 6>&1-## ----------------------------------- ##-## Main body of $CONFIG_STATUS script. ##-## ----------------------------------- ##-_ASEOF-test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1--cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1-# Save the log message, to keep $0 and so on meaningful, and to-# report actual input values of CONFIG_FILES etc. instead of their-# values after options handling.-ac_log="-This file was extended by Haskell LevelDB package $as_me 0.1, which was-generated by GNU Autoconf 2.68.  Invocation command line was--  CONFIG_FILES    = $CONFIG_FILES-  CONFIG_HEADERS  = $CONFIG_HEADERS-  CONFIG_LINKS    = $CONFIG_LINKS-  CONFIG_COMMANDS = $CONFIG_COMMANDS-  $ $0 $@--on `(hostname || uname -n) 2>/dev/null | sed 1q`-"--_ACEOF--case $ac_config_files in *"-"*) set x $ac_config_files; shift; ac_config_files=$*;;-esac----cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1-# Files that config.status was made for.-config_files="$ac_config_files"--_ACEOF--cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1-ac_cs_usage="\-\`$as_me' instantiates files and other configuration actions-from templates according to the current configuration.  Unless the files-and actions are specified as TAGs, all are instantiated by default.--Usage: $0 [OPTION]... [TAG]...--  -h, --help       print this help, then exit-  -V, --version    print version number and configuration settings, then exit-      --config     print configuration, then exit-  -q, --quiet, --silent-                   do not print progress messages-  -d, --debug      don't remove temporary files-      --recheck    update $as_me by reconfiguring in the same conditions-      --file=FILE[:TEMPLATE]-                   instantiate the configuration file FILE--Configuration files:-$config_files--Report bugs to <mad.one@gmail.com>.-Haskell LevelDB package home page: <http://thoughtpolice.github.com/hs-leveldb>."--_ACEOF-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1-ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"-ac_cs_version="\\-Haskell LevelDB package config.status 0.1-configured by $0, generated by GNU Autoconf 2.68,-  with options \\"\$ac_cs_config\\"--Copyright (C) 2010 Free Software Foundation, Inc.-This config.status script is free software; the Free Software Foundation-gives unlimited permission to copy, distribute and modify it."--ac_pwd='$ac_pwd'-srcdir='$srcdir'-test -n "\$AWK" || AWK=awk-_ACEOF--cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1-# The default lists apply if the user does not specify any file.-ac_need_defaults=:-while test $# != 0-do-  case $1 in-  --*=?*)-    ac_option=`expr "X$1" : 'X\([^=]*\)='`-    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`-    ac_shift=:-    ;;-  --*=)-    ac_option=`expr "X$1" : 'X\([^=]*\)='`-    ac_optarg=-    ac_shift=:-    ;;-  *)-    ac_option=$1-    ac_optarg=$2-    ac_shift=shift-    ;;-  esac--  case $ac_option in-  # Handling of the options.-  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)-    ac_cs_recheck=: ;;-  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )-    $as_echo "$ac_cs_version"; exit ;;-  --config | --confi | --conf | --con | --co | --c )-    $as_echo "$ac_cs_config"; exit ;;-  --debug | --debu | --deb | --de | --d | -d )-    debug=: ;;-  --file | --fil | --fi | --f )-    $ac_shift-    case $ac_optarg in-    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;-    '') as_fn_error $? "missing file argument" ;;-    esac-    as_fn_append CONFIG_FILES " '$ac_optarg'"-    ac_need_defaults=false;;-  --he | --h |  --help | --hel | -h )-    $as_echo "$ac_cs_usage"; exit ;;-  -q | -quiet | --quiet | --quie | --qui | --qu | --q \-  | -silent | --silent | --silen | --sile | --sil | --si | --s)-    ac_cs_silent=: ;;--  # This is an error.-  -*) as_fn_error $? "unrecognized option: \`$1'-Try \`$0 --help' for more information." ;;--  *) as_fn_append ac_config_targets " $1"-     ac_need_defaults=false ;;--  esac-  shift-done--ac_configure_extra_args=--if $ac_cs_silent; then-  exec 6>/dev/null-  ac_configure_extra_args="$ac_configure_extra_args --silent"-fi--_ACEOF-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1-if \$ac_cs_recheck; then-  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion-  shift-  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6-  CONFIG_SHELL='$SHELL'-  export CONFIG_SHELL-  exec "\$@"-fi--_ACEOF-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1-exec 5>>config.log-{-  echo-  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX-## Running $as_me. ##-_ASBOX-  $as_echo "$ac_log"-} >&5--_ACEOF-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1-_ACEOF--cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1--# Handling of arguments.-for ac_config_target in $ac_config_targets-do-  case $ac_config_target in-    "leveldb-haskell.buildinfo") CONFIG_FILES="$CONFIG_FILES leveldb-haskell.buildinfo" ;;--  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;-  esac-done---# If the user did not use the arguments to specify the items to instantiate,-# then the envvar interface is used.  Set only those that are not.-# We use the long form for the default assignment because of an extremely-# bizarre bug on SunOS 4.1.3.-if $ac_need_defaults; then-  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files-fi--# Have a temporary directory for convenience.  Make it in the build tree-# simply because there is no reason against having it here, and in addition,-# creating and moving files from /tmp can sometimes cause problems.-# Hook for its removal unless debugging.-# Note that there is a small window in which the directory will not be cleaned:-# after its creation but before its name has been assigned to `$tmp'.-$debug ||-{-  tmp= ac_tmp=-  trap 'exit_status=$?-  : "${ac_tmp:=$tmp}"-  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status-' 0-  trap 'as_fn_exit 1' 1 2 13 15-}-# Create a (secure) tmp directory for tmp files.--{-  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&-  test -d "$tmp"-}  ||-{-  tmp=./conf$$-$RANDOM-  (umask 077 && mkdir "$tmp")-} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5-ac_tmp=$tmp--# Set up the scripts for CONFIG_FILES section.-# No need to generate them if there are no CONFIG_FILES.-# This happens for instance with `./config.status config.h'.-if test -n "$CONFIG_FILES"; then---ac_cr=`echo X | tr X '\015'`-# On cygwin, bash can eat \r inside `` if the user requested igncr.-# But we know of no other shell where ac_cr would be empty at this-# point, so we can use a bashism as a fallback.-if test "x$ac_cr" = x; then-  eval ac_cr=\$\'\\r\'-fi-ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`-if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then-  ac_cs_awk_cr='\\r'-else-  ac_cs_awk_cr=$ac_cr-fi--echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&-_ACEOF---{-  echo "cat >conf$$subs.awk <<_ACEOF" &&-  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&-  echo "_ACEOF"-} >conf$$subs.sh ||-  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5-ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`-ac_delim='%!_!# '-for ac_last_try in false false false false false :; do-  . ./conf$$subs.sh ||-    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5--  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`-  if test $ac_delim_n = $ac_delim_num; then-    break-  elif $ac_last_try; then-    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5-  else-    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "-  fi-done-rm -f conf$$subs.sh--cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1-cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&-_ACEOF-sed -n '-h-s/^/S["/; s/!.*/"]=/-p-g-s/^[^!]*!//-:repl-t repl-s/'"$ac_delim"'$//-t delim-:nl-h-s/\(.\{148\}\)..*/\1/-t more1-s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/-p-n-b repl-:more1-s/["\\]/\\&/g; s/^/"/; s/$/"\\/-p-g-s/.\{148\}//-t nl-:delim-h-s/\(.\{148\}\)..*/\1/-t more2-s/["\\]/\\&/g; s/^/"/; s/$/"/-p-b-:more2-s/["\\]/\\&/g; s/^/"/; s/$/"\\/-p-g-s/.\{148\}//-t delim-' <conf$$subs.awk | sed '-/^[^""]/{-  N-  s/\n//-}-' >>$CONFIG_STATUS || ac_write_fail=1-rm -f conf$$subs.awk-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1-_ACAWK-cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&-  for (key in S) S_is_set[key] = 1-  FS = ""--}-{-  line = $ 0-  nfields = split(line, field, "@")-  substed = 0-  len = length(field[1])-  for (i = 2; i < nfields; i++) {-    key = field[i]-    keylen = length(key)-    if (S_is_set[key]) {-      value = S[key]-      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)-      len += length(value) + length(field[++i])-      substed = 1-    } else-      len += 1 + keylen-  }--  print line-}--_ACAWK-_ACEOF-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1-if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then-  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"-else-  cat-fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \-  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5-_ACEOF--# VPATH may cause trouble with some makes, so we remove sole $(srcdir),-# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and-# trailing colons and then remove the whole line if VPATH becomes empty-# (actually we leave an empty line to preserve line numbers).-if test "x$srcdir" = x.; then-  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{-h-s///-s/^/:/-s/[	 ]*$/:/-s/:\$(srcdir):/:/g-s/:\${srcdir}:/:/g-s/:@srcdir@:/:/g-s/^:*//-s/:*$//-x-s/\(=[	 ]*\).*/\1/-G-s/\n//-s/^[^=]*=[	 ]*$//-}'-fi--cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1-fi # test -n "$CONFIG_FILES"---eval set X "  :F $CONFIG_FILES      "-shift-for ac_tag-do-  case $ac_tag in-  :[FHLC]) ac_mode=$ac_tag; continue;;-  esac-  case $ac_mode$ac_tag in-  :[FHL]*:*);;-  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;-  :[FH]-) ac_tag=-:-;;-  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;-  esac-  ac_save_IFS=$IFS-  IFS=:-  set x $ac_tag-  IFS=$ac_save_IFS-  shift-  ac_file=$1-  shift--  case $ac_mode in-  :L) ac_source=$1;;-  :[FH])-    ac_file_inputs=-    for ac_f-    do-      case $ac_f in-      -) ac_f="$ac_tmp/stdin";;-      *) # Look for the file first in the build tree, then in the source tree-	 # (if the path is not absolute).  The absolute path cannot be DOS-style,-	 # because $ac_f cannot contain `:'.-	 test -f "$ac_f" ||-	   case $ac_f in-	   [\\/$]*) false;;-	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;-	   esac ||-	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;-      esac-      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac-      as_fn_append ac_file_inputs " '$ac_f'"-    done--    # Let's still pretend it is `configure' which instantiates (i.e., don't-    # use $as_me), people would be surprised to read:-    #    /* config.h.  Generated by config.status.  */-    configure_input='Generated from '`-	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'-	`' by configure.'-    if test x"$ac_file" != x-; then-      configure_input="$ac_file.  $configure_input"-      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5-$as_echo "$as_me: creating $ac_file" >&6;}-    fi-    # Neutralize special characters interpreted by sed in replacement strings.-    case $configure_input in #(-    *\&* | *\|* | *\\* )-       ac_sed_conf_input=`$as_echo "$configure_input" |-       sed 's/[\\\\&|]/\\\\&/g'`;; #(-    *) ac_sed_conf_input=$configure_input;;-    esac--    case $ac_tag in-    *:-:* | *:-) cat >"$ac_tmp/stdin" \-      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;-    esac-    ;;-  esac--  ac_dir=`$as_dirname -- "$ac_file" ||-$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \-	 X"$ac_file" : 'X\(//\)[^/]' \| \-	 X"$ac_file" : 'X\(//\)$' \| \-	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||-$as_echo X"$ac_file" |-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{-	    s//\1/-	    q-	  }-	  /^X\(\/\/\)[^/].*/{-	    s//\1/-	    q-	  }-	  /^X\(\/\/\)$/{-	    s//\1/-	    q-	  }-	  /^X\(\/\).*/{-	    s//\1/-	    q-	  }-	  s/.*/./; q'`-  as_dir="$ac_dir"; as_fn_mkdir_p-  ac_builddir=.--case "$ac_dir" in-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;-*)-  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`-  # A ".." for each directory in $ac_dir_suffix.-  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`-  case $ac_top_builddir_sub in-  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;-  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;-  esac ;;-esac-ac_abs_top_builddir=$ac_pwd-ac_abs_builddir=$ac_pwd$ac_dir_suffix-# for backward compatibility:-ac_top_builddir=$ac_top_build_prefix--case $srcdir in-  .)  # We are building in place.-    ac_srcdir=.-    ac_top_srcdir=$ac_top_builddir_sub-    ac_abs_top_srcdir=$ac_pwd ;;-  [\\/]* | ?:[\\/]* )  # Absolute name.-    ac_srcdir=$srcdir$ac_dir_suffix;-    ac_top_srcdir=$srcdir-    ac_abs_top_srcdir=$srcdir ;;-  *) # Relative name.-    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix-    ac_top_srcdir=$ac_top_build_prefix$srcdir-    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;-esac-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix---  case $ac_mode in-  :F)-  #-  # CONFIG_FILE-  #--_ACEOF--cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1-# If the template does not know about datarootdir, expand it.-# FIXME: This hack should be removed a few years after 2.60.-ac_datarootdir_hack=; ac_datarootdir_seen=-ac_sed_dataroot='-/datarootdir/ {-  p-  q-}-/@datadir@/p-/@docdir@/p-/@infodir@/p-/@localedir@/p-/@mandir@/p'-case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in-*datarootdir*) ac_datarootdir_seen=yes;;-*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5-$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}-_ACEOF-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1-  ac_datarootdir_hack='-  s&@datadir@&$datadir&g-  s&@docdir@&$docdir&g-  s&@infodir@&$infodir&g-  s&@localedir@&$localedir&g-  s&@mandir@&$mandir&g-  s&\\\${datarootdir}&$datarootdir&g' ;;-esac-_ACEOF--# Neutralize VPATH when `$srcdir' = `.'.-# Shell code in configure.ac might set extrasub.-# FIXME: do we really want to maintain this feature?-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1-ac_sed_extra="$ac_vpsub-$extrasub-_ACEOF-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1-:t-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b-s|@configure_input@|$ac_sed_conf_input|;t t-s&@top_builddir@&$ac_top_builddir_sub&;t t-s&@top_build_prefix@&$ac_top_build_prefix&;t t-s&@srcdir@&$ac_srcdir&;t t-s&@abs_srcdir@&$ac_abs_srcdir&;t t-s&@top_srcdir@&$ac_top_srcdir&;t t-s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t-s&@builddir@&$ac_builddir&;t t-s&@abs_builddir@&$ac_abs_builddir&;t t-s&@abs_top_builddir@&$ac_abs_top_builddir&;t t-$ac_datarootdir_hack-"-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \-  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5--test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&-  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&-  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \-      "$ac_tmp/out"`; test -z "$ac_out"; } &&-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'-which seems to be undefined.  Please make sure it is defined" >&5-$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'-which seems to be undefined.  Please make sure it is defined" >&2;}--  rm -f "$ac_tmp/stdin"-  case $ac_file in-  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;-  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;-  esac \-  || as_fn_error $? "could not create $ac_file" "$LINENO" 5- ;;----  esac--done # for ac_tag---as_fn_exit 0-_ACEOF-ac_clean_files=$ac_clean_files_save--test $ac_write_fail = 0 ||-  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5---# configure is writing to config.log, and then calls config.status.-# config.status does its own redirection, appending to config.log.-# Unfortunately, on DOS this fails, as config.log is still kept open-# by configure, so config.status won't be able to write to it; its-# output is simply discarded.  So we exec the FD to /dev/null,-# effectively closing config.log, so it can be properly (re)opened and-# appended to by config.status.  When coming back to configure, we-# need to make the FD available again.-if test "$no_create" != yes; then-  ac_cs_success=:-  ac_config_status_args=-  test "$silent" = yes &&-    ac_config_status_args="$ac_config_status_args --quiet"-  exec 5>/dev/null-  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false-  exec 5>>config.log-  # Use ||, not &&, to avoid exiting from the if with $? = 1, which-  # would make configure fail if this is the last instruction.-  $ac_cs_success || as_fn_exit 1-fi-if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5-$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}-fi-
− configure.ac
@@ -1,64 +0,0 @@-AC_INIT([Haskell LevelDB package],-        [0.1],-        [mad.one@gmail.com],-        [leveldb],-        [http://thoughtpolice.github.com/hs-leveldb])--AC_LANG_CPLUSPLUS--dnl ****************-dnl Check for snappy-dnl ****************--AC_CHECK_HEADERS([snappy.h],-    [snappy=yes],-    [snappy=no])--if test "x$snappy" = "xyes"-then-  SNAPPY="-DSNAPPY"-  SNAPPYLIB="snappy"-else-  SNAPPY=""-  SNAPPYLIB=""-fi--dnl ********************-dnl Check for cstdatomic-dnl ********************--AC_MSG_CHECKING(whether compiler supports C++11 cstdatomic)--OLD_CXXFLAGS="$CXXFLAGS"-CXXFLAGS="$CXXFLAGS -std=c++0x"-AC_COMPILE_IFELSE([AC_LANG_SOURCE([-#include <cstdatomic>-int main() {}-])], [-     AC_MSG_RESULT(yes)-     has_cstdatomic=yes-   ],-   [-     AC_MSG_RESULT(no)-     has_cstdatomic=no-   ])-CXXFLAGS="$OLD_CXXFLAGS"--if test "x$has_cstdatomic" = "xyes"-then-  CSTDATOMIC="-DLEVELDB_CSTDATOMIC_PRESENT -std=c++0x"-else-  CSTDATOMIC=""-fi--dnl *****************-dnl Substitute output-dnl *****************--AC_SUBST([SNAPPY])-AC_SUBST([SNAPPYLIB])--AC_SUBST([CSTDATOMIC])--AC_CONFIG_FILES([leveldb-haskell.buildinfo])-AC_OUTPUT
+ examples/comparator.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE OverloadedStrings #-}++-- | Demo custom comparator++module Main where++import Control.Monad.IO.Class (liftIO)+import Data.ByteString.Char8  (take)+import Data.Default++import Database.LevelDB+++customComparator :: Comparator+customComparator = Comparator compare++main :: IO ()+main = runResourceT $ do+    db <- open "/tmp/lvlcmptest"+               defaultOptions{ createIfMissing = True+                             , comparator = Just customComparator+                             }++    put db def "zzz" ""+    put db def "yyy" ""+    put db def "xxx" ""++    withIterator db def $ \iter -> do+        iterFirst iter+        iterItems iter >>= liftIO . print++    return ()
examples/features.hs view
@@ -5,43 +5,63 @@ module Main where  import Control.Monad+import Control.Monad.IO.Class       (liftIO) import Data.ByteString.Char8 hiding (take)-import Prelude hiding (putStrLn)+import Data.Default+import Prelude               hiding (putStrLn) import System.FilePath  import Database.LevelDB   main :: IO ()-main = withLevelDB dbdir [ CreateIfMissing, CacheSize 2048 ] $ \db -> do-         put db [] "foo" "bar"-         get db [ FillCache ] "foo" >>= print-         delete db [] "foo"-         get db [ FillCache ] "foo" >>= print+main = runResourceT $ do+    db <- open "/tmp/leveltest"+               defaultOptions{ createIfMissing = True+                             , cacheSize= 2048+                             }+    put db def "foo" "bar"+    get db def "foo" >>= liftIO . print+    delete db def "foo"+    get db def "foo" >>= liftIO . print -         withSnapshot db $ \snap -> do-             write db [ Sync ] [ Put "a" "one"-                               , Put "b" "two"-                               , Put "c" "three" ]-             dumpEntries db [ UseSnapshot snap, FillCache ]-             dumpEntries db [ FillCache ]+    (releaseSnap, snap) <- createSnapshot' db+    write db def{sync = True} [ Put "a" "one"+                              , Put "b" "two"+                              , Put "c" "three"+                              ] -         approximateSize db ("a", "z") >>= print-         getProperty db SSTables >>= printProperty "sstables"-         getProperty db Stats    >>= printProperty "stats"-         getProperty db (NumFilesAtLevel 1) >>= printProperty "num files at level"+    withIterator db def{useSnapshot = Just snap} $ \iter ->+      dumpEntries iter -         write db [ Sync ] [ Del "a", Del "b", Del "c" ]-         dumpEntries db [ FillCache ]+    -- early release snapshot+    release releaseSnap -    where-         dbdir = "/" </> "tmp" </> "leveltest"+    -- here, we keep the iterator around for later reuse.+    -- Note that we don't explicitly release it (and thus don't keep the release+    -- key). The iterator will be released when runResourceT terminates.+    iter <- iterOpen db def+    dumpEntries iter -         dumpEntries db opts =-             withIterator db opts $ \iter -> do-                 iterFirst iter-                 iterItems iter >>= print+    approximateSize db ("a", "z") >>= liftIO . print -         printProperty l p = do-             putStrLn l-             maybe (putStrLn "n/a") putStrLn $ p+    getProperty db SSTables >>= printProperty "sstables"+    getProperty db Stats >>= printProperty "stats"+    getProperty db (NumFilesAtLevel 1) >>= printProperty "num files at level"++    write db def [ Del "a"+                 , Del "b"+                 , Del "c"+                 ]+    dumpEntries iter++    return ()++    where+        dumpEntries iter = do+            iterFirst iter+            iterItems iter >>= liftIO . print++        printProperty l p = liftIO $ do+            putStrLn l+            maybe (putStrLn "n/a") putStrLn $ p
− leveldb-haskell.buildinfo.in
@@ -1,2 +0,0 @@-cc-options: @SNAPPY@ @CSTDATOMIC@-extra-libraries: @SNAPPYLIB@
leveldb-haskell.cabal view
@@ -1,5 +1,5 @@ name:                leveldb-haskell-version:             0.0.3+version:             0.1.0 synopsis:            Haskell bindings to LevelDB homepage:            http://github.com/kim/leveldb-haskell bug-reports:         http://github.com/kim/leveldb-haskell/issues@@ -13,7 +13,7 @@ copyright:           Copyright (c) 2012 The leveldb-haskell Authors category:            Database, FFI stability:           Experimental-build-type:          Configure+build-type:          Simple cabal-version:       >=1.10 tested-with:         GHC == 7.2.2, GHC == 7.4.1 description:@@ -26,26 +26,11 @@     This library provides a Haskell language binding to LeveldDB. It is in very     early stage and has seen very limited testing.     .-    Note: the LevelDB source code is bundled with this package and built as-    part of the installation. To enable compression, the snappy library needs to-    be installed on the target system.+    Note: as of v1.3, LevelDB can be built as a shared library. Thus, as of+    v0.1.0 of this library, LevelDB is no longer bundled and must be installed+    on the target system (version 1.3 or greater). -extra-source-files:  Readme.md-                   , configure-                   , configure.ac-                   , leveldb-haskell.buildinfo.in-                   , cbits/leveldb/include/leveldb/*.h-                   , cbits/leveldb/db/*.h-                   , cbits/leveldb/db/*.cc-                   , cbits/leveldb/table/*.h-                   , cbits/leveldb/table/*.cc-                   , cbits/leveldb/port/*.h-                   , cbits/leveldb/port/*.cc-                   , cbits/leveldb/util/*.h-                   , cbits/leveldb/util/*.cc-                   , cbits/leveldb/helpers/memenv/*.h-                   , cbits/leveldb/helpers/memenv/*.cc-                   , examples/*.hs+extra-source-files:  Readme.md, examples/*.hs  source-repository head   type:     git@@ -60,65 +45,19 @@                     CPP                   , ForeignFunctionInterface                   , EmptyDataDecls+                  , RecordWildCards    build-depends:    base >= 3 && < 5                   , bytestring                   , filepath+                  , transformers+                  , resourcet > 0.3.2+                  , data-default -  ghc-options:      -Wall -O2-                    -static -optl-static -rtsopts+  ghc-options:      -Wall -O2 -rtsopts                     -funbox-strict-fields   ghc-prof-options: -prof -auto-all    hs-source-dirs:   src-  extra-libraries:  stdc++-  include-dirs:     cbits/leveldb-                    cbits/leveldb/include -  cc-options:       -fno-builtin-memcmp -DLEVELDB_PLATFORM_POSIX--  if os(linux)-    cc-options:     -DOS_LINUX-  if os(darwin)-    cc-options:     -DOS_MACOSX-  if os(solaris)-    cc-options:     -D_REENTRANT -DOS_SOLARIS-  if os(freebsd)-    cc-options:     -D_REENTRANT -DOS_FREEBSD--  c-sources:        cbits/leveldb/db/builder.cc-                    cbits/leveldb/db/c.cc-                    cbits/leveldb/db/db_impl.cc-                    cbits/leveldb/db/db_iter.cc-                    cbits/leveldb/db/dbformat.cc-                    cbits/leveldb/db/filename.cc-                    cbits/leveldb/db/log_reader.cc-                    cbits/leveldb/db/log_writer.cc-                    cbits/leveldb/db/memtable.cc-                    cbits/leveldb/db/repair.cc-                    cbits/leveldb/db/table_cache.cc-                    cbits/leveldb/db/version_edit.cc-                    cbits/leveldb/db/version_set.cc-                    cbits/leveldb/db/write_batch.cc-                    cbits/leveldb/helpers/memenv/memenv.cc-                    cbits/leveldb/port/port_posix.cc-                    cbits/leveldb/table/block.cc-                    cbits/leveldb/table/block_builder.cc-                    cbits/leveldb/table/format.cc-                    cbits/leveldb/table/iterator.cc-                    cbits/leveldb/table/merger.cc-                    cbits/leveldb/table/table.cc-                    cbits/leveldb/table/table_builder.cc-                    cbits/leveldb/table/two_level_iterator.cc-                    cbits/leveldb/util/arena.cc-                    cbits/leveldb/util/cache.cc-                    cbits/leveldb/util/coding.cc-                    cbits/leveldb/util/comparator.cc-                    cbits/leveldb/util/crc32c.cc-                    cbits/leveldb/util/env.cc-                    cbits/leveldb/util/env_posix.cc-                    cbits/leveldb/util/hash.cc-                    cbits/leveldb/util/histogram.cc-                    cbits/leveldb/util/logging.cc-                    cbits/leveldb/util/options.cc-                    cbits/leveldb/util/status.cc+  extra-libraries:  leveldb
src/Database/LevelDB.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE RecordWildCards #-} -- | -- Module      : Database.LevelDB -- Copyright   : (c) 2012 Kim Altintop@@ -10,52 +11,34 @@ -- -- The API closely follows the C-API of LevelDB. -- For more information, see: <http://leveldb.googlecode.com>--------- Basic example:------ > withLevelDB "/tmp/leveldbtest" [CreateIfMissing, CacheSize 1024] $ \db -> do--- >     put db [] "foo" "bar"--- >     get db [] "foo" >>= print--- >     delete db [] "foo"--- >     get db [] "foo" >>= print------ Batch write and iterating:------ > withLevelDB "/tmp/leveldbtest" [CreateIfMissing, CacheSize 1024] $ \db -> do--- >     write db [Sync] [ Put "a" "one"--- >                     , Put "b" "two"--- >                     , Put "c" "three" ]--- >     dumpEntries db []--- >--- >     where--- >         dumpEntries db opts =--- >             withIterator db opts $ \iter -> do--- >                 iterFirst iter--- >                 iterItems iter >>= print  module Database.LevelDB (   -- * Exported Types     DB   , BatchOp(..)+  , Comparator(..)   , Compression(..)-  , Option(..)-  , Options-  , ReadOption(..)-  , ReadOptions+  , Options(..)+  , ReadOptions(..)   , Snapshot   , WriteBatch-  , WriteOption(..)-  , WriteOptions+  , WriteOptions(..)   , Range +  -- * Defaults+  , defaultOptions+  , defaultWriteOptions+  , defaultReadOptions+   -- * Basic Database Manipulation-  , withLevelDB   , withSnapshot+  , open   , put   , delete   , write   , get+  , createSnapshot+  , createSnapshot'    -- * Administrative Functions   , Property(..), getProperty@@ -67,7 +50,7 @@   , Iterator   , withIterator   , iterOpen-  , iterClose+  , iterOpen'   , iterValid   , iterSeek   , iterFirst@@ -76,26 +59,36 @@   , iterPrev   , iterKey   , iterValue+  , iterGetError   , mapIter   , iterItems   , iterKeys   , iterValues++  -- * Re-exports+  , MonadResource(..)+  , runResourceT+  , resourceForkIO ) where -import Control.Exception         (bracket, throwIO)-import Control.Applicative       ((<$>), (<*>))-import Control.Monad             (liftM, when)-import Data.ByteString           (ByteString)-import Data.List                 (find)-import Data.Maybe+import Control.Applicative          ((<$>), (<*>))+import Control.Concurrent           (MVar, withMVar, newMVar)+import Control.Exception            (throwIO)+import Control.Monad                (liftM, when)+import Control.Monad.IO.Class       (liftIO)+import Control.Monad.Trans.Resource+import Data.ByteString              (ByteString)+import Data.Default+import Data.Maybe                   (catMaybes) import Foreign-import Foreign.C.Error           (throwErrnoIfNull)-import Foreign.C.String          (withCString, peekCString)-import Foreign.C.Types           (CSize, CInt)+import Foreign.C.Error              (throwErrnoIfNull)+import Foreign.C.String             (withCString, peekCString)+import Foreign.C.Types              (CSize, CInt)  import Database.LevelDB.Base -import qualified Data.ByteString as SB+import qualified Data.ByteString        as SB+import qualified Data.ByteString.Char8  as BC import qualified Data.ByteString.Unsafe as UB  -- import Debug.Trace@@ -104,7 +97,10 @@ newtype DB = DB LevelDBPtr deriving (Eq)  -- | Iterator handle-newtype Iterator = Iterator IteratorPtr deriving (Eq)+data Iterator = Iterator+    { _iterPtr  :: !IteratorPtr+    , _iterLock :: !(MVar ())+    } deriving (Eq)  -- | Snapshot handle newtype Snapshot = Snapshot SnapshotPtr deriving (Eq)@@ -112,31 +108,173 @@ -- | Compression setting data Compression = NoCompression | Snappy deriving (Eq, Show) -type Options = [Option]+-- | User-defined comparator+newtype Comparator = Comparator (ByteString -> ByteString -> Ordering)++data Comparator' = Comparator' (FunPtr CompareFun)+                               (FunPtr Destructor)+                               (FunPtr NameFun)+                               ComparatorPtr+ -- | Options when opening a database-data Option = CreateIfMissing-            | ErrorIfExists-            | ParanoidChecks-            | WriteBufferSize Int-            | MaxOpenFiles Int-            | BlockSize Int-            | BlockRestartInterval Int-            | UseCompression Compression-            | CacheSize Int-            deriving (Eq, Show)+data Options = Options+    { blockRestartInterval :: !Int+      -- ^ Number of keys between restart points for delta encoding of keys.+      --+      -- This parameter can be changed dynamically. Most clients should leave+      -- this parameter alone.+      --+      -- Default: 16+    , blockSize            :: !Int+      -- ^ Approximate size of user data packed per block.+      --+      -- Note that the block size specified here corresponds to uncompressed+      -- data. The actual size of the unit read from disk may be smaller if+      -- compression is enabled.+      --+      -- This parameter can be changed dynamically.+      --+      -- Default: 4k+    , cacheSize            :: !Int+      -- ^ Control over blocks (user data is stored in a set of blocks, and a+      -- block is the unit of reading from disk).+      --+      -- If > 0, use the specified cache (in bytes) for blocks. If 0, leveldb+      -- will automatically create and use an 8MB internal cache.+      --+      -- Default: 0+    , comparator           :: !(Maybe Comparator)+      -- ^ Comparator used to defined the order of keys in the table.+      --+      -- If 'Nothing', the default comparator is used, which uses lexicographic+      -- bytes-wise ordering.+      --+      -- NOTE: the client must ensure that the comparator supplied here has the+      -- same name and orders keys /exactly/ the same as the comparator provided+      -- to previous open calls on the same DB.+      --+      -- Default: Nothing+    , compression          :: !Compression+      -- ^ Compress blocks using the specified compression algorithm.+      --+      -- This parameter can be changed dynamically.+      --+      -- Default: 'Snappy'+    , createIfMissing      :: !Bool+      -- ^ If true, the database will be created if it is missing.+      --+      -- Default: False+    , errorIfExists        :: !Bool+      -- ^ It true, an error is raised if the database already exists.+      --+      -- Default: False+    , maxOpenFiles         :: !Int+      -- ^ Number of open files that can be used by the DB.+      --+      -- You may need to increase this if your database has a large working set+      -- (budget one open file per 2MB of working set).+      --+      -- Default: 1000+    , paranoidChecks       :: !Bool+      -- ^ If true, the implementation will do aggressive checking of the data+      -- it is processing and will stop early if it detects any errors.+      --+      -- This may have unforeseen ramifications: for example, a corruption of+      -- one DB entry may cause a large number of entries to become unreadable+      -- or for the entire DB to become unopenable.+      --+      -- Default: False+    , writeBufferSize      :: !Int+      -- ^ Amount of data to build up in memory (backed by an unsorted log on+      -- disk) before converting to a sorted on-disk file.+      --+      -- Larger values increase performance, especially during bulk loads. Up to+      -- to write buffers may be held in memory at the same time, so you may+      -- with to adjust this parameter to control memory usage. Also, a larger+      -- write buffer will result in a longer recovery time the next time the+      -- database is opened.+      --+      -- Default: 4MB+    } -type WriteOptions = [WriteOption]+defaultOptions :: Options+defaultOptions = Options+    { blockRestartInterval = 16+    , blockSize            = 4096+    , cacheSize            = 0+    , comparator           = Nothing+    , compression          = Snappy+    , createIfMissing      = False+    , errorIfExists        = False+    , maxOpenFiles         = 1000+    , paranoidChecks       = False+    , writeBufferSize      = 4 `shift` 20+    }++instance Default Options where+    def = defaultOptions++data Options' = Options'+    { _optsPtr  :: !OptionsPtr+    , _cachePtr :: !(Maybe CachePtr)+    , _comp     :: !(Maybe Comparator')+    }+ -- | Options for write operations-data WriteOption  = Sync -- ^ fsync the rows written immediately-                  deriving (Eq, Show)+data WriteOptions = WriteOptions+    { sync :: !Bool+      -- ^ If true, the write will be flushed from the operating system buffer+      -- cache (by calling WritableFile::Sync()) before the write is considered+      -- complete. If this flag is true, writes will be slower.+      --+      -- If this flag is false, and the machine crashes, some recent writes may+      -- be lost. Note that if it is just the process that crashes (i.e., the+      -- machine does not reboot), no writes will be lost even if sync==false.+      --+      -- In other words, a DB write with sync==false has similar crash semantics+      -- as the "write()" system call. A DB write with sync==true has similar+      -- crash semantics to a "write()" system call followed by "fsync()".+      --+      -- Default: False+    } deriving (Eq, Show) -type ReadOptions = [ReadOption]+defaultWriteOptions :: WriteOptions+defaultWriteOptions = WriteOptions { sync = False }++instance Default WriteOptions where+    def = defaultWriteOptions+ -- | Options for read operations-data ReadOption  = VerifyCheckSums-                 | FillCache-                 | UseSnapshot Snapshot-                 deriving (Eq)+data ReadOptions = ReadOptions+    { verifyCheckSums :: !Bool+      -- ^ If true, all data read from underlying storage will be verified+      -- against corresponding checksuyms.+      --+      -- Default: False+    , fillCache       :: !Bool+      -- ^ Should the data read for this iteration be cached in memory? Callers+      -- may with to set this field to false for bulk scans.+      --+      -- Default: True+    , useSnapshot     :: !(Maybe Snapshot)+      -- ^ If 'Just', read as of the supplied snapshot (which must belong to the+      -- DB that is being read and which must not have been released). If+      -- 'Nothing', use an implicit snapshot of the state at the beginning of+      -- this read operation.+      --+      -- Default: Nothing+    } deriving (Eq) +defaultReadOptions :: ReadOptions+defaultReadOptions = ReadOptions+    { verifyCheckSums = False+    , fillCache       = True+    , useSnapshot     = Nothing+    }++instance Default ReadOptions where+    def = defaultReadOptions+ type WriteBatch = [BatchOp] -- | Batch operation data BatchOp = Put ByteString ByteString | Del ByteString@@ -147,34 +285,67 @@               deriving (Eq, Show)  --- | Run an action on a database-withLevelDB :: FilePath -> Options -> (DB -> IO a) -> IO a-withLevelDB path opts act =-    withCString path    $ \path_ptr ->-    withCOptions opts   $ \opts_ptr ->-        bracket (open path_ptr opts_ptr) close act+-- | Open a database+--+-- The returned handle will automatically be released when the enclosing+-- 'runResourceT' terminates.+open :: MonadResource m => FilePath -> Options -> m DB+open path opts = snd <$> open' path opts++open' :: MonadResource m => FilePath -> Options -> m (ReleaseKey, DB)+open' path opts = do+    opts' <- snd <$> allocate (mkOpts opts) freeOpts+    allocate (mkDB opts') freeDB+     where-        open path_ptr opts_ptr = do-            p <- throwIfErr "open" $ c_leveldb_open opts_ptr path_ptr-            return . DB $ p+        mkDB (Options' opts_ptr _ _) =+            withCString path $ \path_ptr ->+                liftM DB+                $ throwIfErr "open"+                $ c_leveldb_open opts_ptr path_ptr -        close (DB db) = c_leveldb_close db+        freeDB (DB db_ptr) = c_leveldb_close db_ptr+{-# INLINE open' #-}  -- | Run an action with a snapshot of the database.-withSnapshot :: DB -> (Snapshot -> IO a) -> IO a-withSnapshot (DB db) = bracket (create db) (release db)+--+-- The snapshot will be released when the action terminates or throws an+-- exception. Note that this function is provided for convenience and does not+-- prevent the 'Snapshot' handle to escape. It will, however, be invalid after+-- this function returns and should not be used anymore.+withSnapshot :: MonadResource m => DB -> (Snapshot -> m a) -> m a+withSnapshot db f = do+    (rk, snap) <- createSnapshot' db+    res <- f snap+    release rk+    return res++-- | Create a snapshot of the database.+--+-- The returned 'Snapshot' will be released automatically when the enclosing+-- 'runResourceT' terminates. It is recommended to use 'createSnapshot'' instead+-- and release the resource manually as soon as possible.+createSnapshot :: MonadResource m => DB -> m Snapshot+createSnapshot db = snd <$> createSnapshot' db++-- | Create a snapshot of the database which can (and should) be released early.+createSnapshot' :: MonadResource m => DB -> m (ReleaseKey, Snapshot)+createSnapshot' db = allocate (mkSnap db) (freeSnap db)     where-        create  db_ptr = liftM Snapshot $ c_leveldb_create_snapshot db_ptr-        release db_ptr (Snapshot snap) = c_leveldb_release_snapshot db_ptr snap+        mkSnap (DB db_ptr) =+            Snapshot <$> c_leveldb_create_snapshot db_ptr +        freeSnap (DB db_ptr) (Snapshot snap) =+            c_leveldb_release_snapshot db_ptr snap+ -- | Get a DB property-getProperty :: DB -> Property -> IO (Maybe ByteString)-getProperty (DB db) p =+getProperty :: MonadResource m => DB -> Property -> m (Maybe ByteString)+getProperty (DB db_ptr) p = liftIO $     withCString (prop p) $ \prop_ptr -> do-        val_ptr <- c_leveldb_property_value db prop_ptr+        val_ptr <- c_leveldb_property_value db_ptr prop_ptr         if val_ptr == nullPtr             then return Nothing-            else do res <- liftM Just $ SB.packCString val_ptr+            else do res <- Just <$> SB.packCString val_ptr                     free val_ptr                     return res @@ -184,273 +355,421 @@         prop SSTables = "leveldb.sstables"  -- | Destroy the given leveldb database.-destroy :: FilePath -> Options -> IO ()-destroy path opts =-    withCString path    $ \path_ptr ->-    withCOptions opts   $ \opts_ptr ->-        throwIfErr "destroy" $ c_leveldb_destroy_db opts_ptr path_ptr+destroy :: MonadResource m => FilePath -> Options -> m ()+destroy path opts = do+    (rk, opts') <- allocate (mkOpts opts) freeOpts+    liftIO $ destroy' opts'+    release rk +    where+        destroy' (Options' opts_ptr _ _) =+            withCString path $ \path_ptr ->+                throwIfErr "destroy" $ c_leveldb_destroy_db opts_ptr path_ptr+ -- | Repair the given leveldb database.-repair :: FilePath -> Options -> IO ()-repair path opts =-    withCString path    $ \path_ptr ->-    withCOptions opts   $ \opts_ptr ->-        throwIfErr "repair" $ c_leveldb_repair_db opts_ptr path_ptr+repair :: MonadResource m => FilePath -> Options -> m ()+repair path opts = do+    (rk, opts') <- allocate (mkOpts opts) freeOpts+    liftIO $ repair' opts'+    release rk +    where+        repair' (Options' opts_ptr _ _) =+            withCString path $ \path_ptr ->+                throwIfErr "repair" $ c_leveldb_repair_db opts_ptr path_ptr+ -- TODO: support [Range], like C API does type Range  = (ByteString, ByteString)  -- | Inspect the approximate sizes of the different levels-approximateSize :: DB -> Range -> IO Int64-approximateSize (DB db) (from, to) =+approximateSize :: MonadResource m => DB -> Range -> m Int64+approximateSize (DB db_ptr) (from, to) = liftIO $     UB.unsafeUseAsCStringLen from $ \(from_ptr, flen) ->     UB.unsafeUseAsCStringLen to   $ \(to_ptr, tlen)   ->     withArray [from_ptr]          $ \from_ptrs        ->-    withArray [i2s flen]          $ \flen_ptrs        ->+    withArray [intToCSize flen]          $ \flen_ptrs        ->     withArray [to_ptr]            $ \to_ptrs          ->-    withArray [i2s tlen]          $ \tlen_ptrs        ->+    withArray [intToCSize tlen]          $ \tlen_ptrs        ->     allocaArray 1                 $ \size_ptrs        -> do-        c_leveldb_approximate_sizes db 1 from_ptrs flen_ptrs to_ptrs tlen_ptrs size_ptrs+        c_leveldb_approximate_sizes db_ptr 1+                                    from_ptrs flen_ptrs+                                    to_ptrs tlen_ptrs+                                    size_ptrs         liftM head $ peekArray 1 size_ptrs >>= mapM toInt64      where         toInt64 = return . fromIntegral  -- | Write a key/value pair-put :: DB -> WriteOptions -> ByteString -> ByteString -> IO ()-put (DB db) opts key value =-    UB.unsafeUseAsCStringLen key   $ \(key_ptr, klen) ->-    UB.unsafeUseAsCStringLen value $ \(val_ptr, vlen) ->-    withCWriteOptions opts         $ \opts_ptr        ->-        throwIfErr "put" $ c_leveldb_put db opts_ptr-                                         key_ptr (i2s klen)-                                         val_ptr (i2s vlen)+put :: MonadResource m => DB -> WriteOptions -> ByteString -> ByteString -> m ()+put (DB db_ptr) opts key value =  do+    (rk, opts_ptr) <- mkCWriteOpts opts +    liftIO $+        UB.unsafeUseAsCStringLen key   $ \(key_ptr, klen) ->+        UB.unsafeUseAsCStringLen value $ \(val_ptr, vlen) ->+            throwIfErr "put"+                $ c_leveldb_put db_ptr opts_ptr+                                key_ptr (intToCSize klen)+                                val_ptr (intToCSize vlen)++    release rk+ -- | Read a value by key-get :: DB -> ReadOptions -> ByteString -> IO (Maybe ByteString)-get (DB db) opts key =-    UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->-    withCReadOptions opts        $ \opts_ptr        ->-    alloca                       $ \vlen_ptr        -> do-        val_ptr <- throwIfErr "get"-                   $ c_leveldb_get db opts_ptr key_ptr (i2s klen) vlen_ptr-        vlen <- peek vlen_ptr-        if val_ptr /= nullPtr-            then do-                res <- liftM Just $ SB.packCStringLen (val_ptr, s2i vlen)-                free val_ptr-                return res-            else return Nothing+get :: MonadResource m => DB -> ReadOptions -> ByteString -> m (Maybe ByteString)+get (DB db_ptr) opts key = do+    (rk, opts_ptr) <- mkCReadOptions opts +    res <- liftIO $+        UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->+        alloca                       $ \vlen_ptr        -> do+            val_ptr <- throwIfErr "get" $+                c_leveldb_get db_ptr opts_ptr key_ptr (intToCSize klen) vlen_ptr+            vlen <- peek vlen_ptr+            if val_ptr == nullPtr+                then return Nothing+                else do+                    res' <- Just <$> SB.packCStringLen (val_ptr, cSizeToInt vlen)+                    free val_ptr+                    return res'++    release rk+    return res+ -- | Delete a key/value pair-delete :: DB -> WriteOptions -> ByteString -> IO ()-delete (DB db) opts key =-    UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->-    withCWriteOptions opts       $ \opts_ptr        ->-        throwIfErr "delete" $ c_leveldb_delete db opts_ptr key_ptr (i2s klen)+delete :: MonadResource m => DB -> WriteOptions -> ByteString -> m ()+delete (DB db_ptr) opts key = do+    (rk, opts_ptr) <- mkCWriteOpts opts +    liftIO $ UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->+        throwIfErr "delete"+            $ c_leveldb_delete db_ptr opts_ptr key_ptr (intToCSize klen)++    release rk+ -- | Perform a batch mutation-write :: DB -> WriteOptions -> WriteBatch -> IO ()-write (DB db) opts batch =-    withCWriteOptions opts $ \opts_ptr  ->-    withCWriteBatch batch  $ \batch_ptr ->-        throwIfErr "write"-        $ c_leveldb_write db opts_ptr batch_ptr+write :: MonadResource m => DB -> WriteOptions -> WriteBatch -> m ()+write (DB db_ptr) opts batch = do+    (rk_opts, opts_ptr)   <- mkCWriteOpts opts+    (rk_batch, batch_ptr) <- allocate c_leveldb_writebatch_create+                                      c_leveldb_writebatch_destroy -    where-        withCWriteBatch b f = do-            batch_ptr <- c_leveldb_writebatch_create-            mapM_ (batchAdd batch_ptr) b-            res <- f batch_ptr-            c_leveldb_writebatch_destroy batch_ptr-            return res+    mapM_ (liftIO . batchAdd batch_ptr) batch +    liftIO+        $ throwIfErr "write"+        $ c_leveldb_write db_ptr opts_ptr batch_ptr++    release rk_opts+    release rk_batch++    where         batchAdd batch_ptr (Put key val) =             UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->             UB.unsafeUseAsCStringLen val $ \(val_ptr, vlen) ->                 c_leveldb_writebatch_put batch_ptr-                                         key_ptr (i2s klen)-                                         val_ptr (i2s vlen)+                                         key_ptr (intToCSize klen)+                                         val_ptr (intToCSize vlen)          batchAdd batch_ptr (Del key) =             UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->-                c_leveldb_writebatch_delete batch_ptr key_ptr (i2s klen)+                c_leveldb_writebatch_delete batch_ptr key_ptr (intToCSize klen)  -- | Run an action with an Iterator. The iterator will be closed after the -- action returns or an error is thrown. Thus, the iterator will /not/ be valid -- after this function terminates.-withIterator :: DB -> ReadOptions -> (Iterator -> IO a) -> IO a-withIterator db opts = bracket (iterOpen db opts) iterClose+withIterator :: MonadResource m => DB -> ReadOptions -> (Iterator -> m a) -> m a+withIterator db opts f = do+    (rk, iter) <- iterOpen' db opts+    res <- f iter+    release rk+    return res --- | Create an Iterator. Consider using withIterator.-iterOpen :: DB -> ReadOptions -> IO Iterator-iterOpen (DB db) opts =-    withCReadOptions opts $ \opts_ptr ->-        liftM Iterator-        $ throwErrnoIfNull "create_iterator"-        $ c_leveldb_create_iterator db opts_ptr+-- | Create an 'Iterator'.+--+-- The iterator will be released when the enclosing 'runResourceT' terminates.+-- You may consider to use 'iterOpen'' instead and manually release the iterator+-- as soon as it is no longer needed (alternatively, use 'withIterator').+--+-- Note that an 'Iterator' creates a snapshot of the database implicitly, so+-- updates written after the iterator was created are not visible. You may,+-- however, specify an older 'Snapshot' in the 'ReadOptions'.+iterOpen :: MonadResource m => DB -> ReadOptions -> m Iterator+iterOpen db opts = snd <$> iterOpen' db opts --- | Release an Iterator. Consider using withIterator.-iterClose :: Iterator -> IO ()-iterClose (Iterator iter) = c_leveldb_iter_destroy iter+-- | Create an 'Iterator' which can be released early.+iterOpen' :: MonadResource m => DB -> ReadOptions -> m (ReleaseKey, Iterator)+iterOpen' db opts = do+    (rk, opts_ptr) <- mkCReadOptions opts+    iter <- allocate (mkIter db opts_ptr) freeIter +    release rk+    return iter++    where+        mkIter (DB db_ptr) opts_ptr = do+            lock   <- liftIO $ newMVar ()+            it_ptr <- liftIO+                          $ throwErrnoIfNull "create_iterator"+                          $ c_leveldb_create_iterator db_ptr opts_ptr+            return $ Iterator it_ptr lock++        freeIter (Iterator iter lck) =+            withMVar lck (\_ -> c_leveldb_iter_destroy iter)+ -- | An iterator is either positioned at a key/value pair, or not valid. This -- function returns /true/ iff the iterator is valid.-iterValid :: Iterator -> IO Bool-iterValid (Iterator iter) = do-    x <- c_leveldb_iter_valid iter+iterValid :: MonadResource m => Iterator -> m Bool+iterValid (Iterator iter _) = do+    x <- liftIO $ c_leveldb_iter_valid iter     return (x /= 0)  -- | Position at the first key in the source that is at or past target. The -- iterator is /valid/ after this call iff the source contains an entry that -- comes at or past target.-iterSeek :: Iterator -> ByteString -> IO ()-iterSeek (Iterator iter) key =-    UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->-        c_leveldb_iter_seek iter key_ptr (i2s klen)+iterSeek :: MonadResource m => Iterator -> ByteString -> m ()+iterSeek (Iterator iter lck) key = liftIO $ withMVar lck go+    where+        go _ = UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->+                   c_leveldb_iter_seek iter key_ptr (intToCSize klen)  -- | Position at the first key in the source. The iterator is /valid/ after this -- call iff the source is not empty.-iterFirst :: Iterator -> IO ()-iterFirst (Iterator iter) = c_leveldb_iter_seek_to_first iter+iterFirst :: MonadResource m => Iterator -> m ()+iterFirst (Iterator iter lck) = liftIO $ withMVar lck go+    where+        go _ = c_leveldb_iter_seek_to_first iter  -- | Position at the last key in the source. The iterator is /valid/ after this -- call iff the source is not empty.-iterLast :: Iterator -> IO ()-iterLast (Iterator iter) = c_leveldb_iter_seek_to_last iter+iterLast :: MonadResource m => Iterator -> m ()+iterLast (Iterator iter lck) = liftIO $ withMVar lck go+    where+        go _ = c_leveldb_iter_seek_to_last iter  -- | Moves to the next entry in the source. After this call, 'iterValid' is--- /true/ iff the iterator was not positioned the last entry in the source.-iterNext :: Iterator -> IO ()-iterNext (Iterator iter) = c_leveldb_iter_next iter+-- /true/ iff the iterator was not positioned at the last entry in the source.+--+-- If the iterator is not valid, this function does nothing. Note that this is a+-- shortcoming of the C API: an 'iterPrev' might still be possible, but we can't+-- determine if we're at the last or first entry.+iterNext :: MonadResource m => Iterator -> m ()+iterNext iter@(Iterator iter_ptr lck) = do+    valid <- iterValid iter+    when valid $ liftIO $ withMVar lck go +    where+        go _ = c_leveldb_iter_next iter_ptr+ -- | Moves to the previous entry in the source. After this call, 'iterValid' is -- /true/ iff the iterator was not positioned at the first entry in the source.-iterPrev :: Iterator -> IO ()-iterPrev (Iterator iter) = c_leveldb_iter_prev iter+--+-- If the iterator is not valid, this function does nothing. Note that this is a+-- shortcoming of the C API: an 'iterNext' might still be possible, but we can't+-- determine if we're at the last or first entry.+iterPrev :: MonadResource m => Iterator -> m ()+iterPrev iter@(Iterator iter_ptr lck) = do+    valid <- iterValid iter+    when valid $ liftIO $ withMVar lck go --- | Return the key for the current entry. The underlying storage for the--- returned slice is valid only until the next modification of the iterator.-iterKey :: Iterator -> IO ByteString-iterKey (Iterator iter) =-    alloca $ \len_ptr -> do-        key_ptr <- c_leveldb_iter_key iter len_ptr-        klen <- peek len_ptr-        if key_ptr /= nullPtr-            then SB.packCStringLen (key_ptr, s2i klen)-            else ioError $ userError "null key"+    where+        go _ = c_leveldb_iter_prev iter_ptr --- | Return the value for the current entry. The underlying storage for the--- returned slice is valid only until the next modification of the iterator.-iterValue :: Iterator -> IO ByteString-iterValue (Iterator iter) =-    alloca $ \len_ptr -> do-        val_ptr <- c_leveldb_iter_value iter len_ptr-        vlen <- peek len_ptr-        if val_ptr /= nullPtr-            then SB.packCStringLen (val_ptr, s2i vlen)-            else ioError $ userError "null value"+-- | Return the key for the current entry if the iterator is currently+-- positioned at an entry, ie. 'iterValid'.+iterKey :: MonadResource m => Iterator -> m (Maybe ByteString)+iterKey iter = do+    valid <- iterValid iter+    if not valid+        then return Nothing+        else iterKey' iter --- | Map a function over an iterator, returning the value. The iterator--- should be put in the right position prior to calling this with the iterator.-mapIter :: (Iterator -> IO a) -> Iterator -> IO [a]-mapIter f iter = do+    where+        iterKey' (Iterator iter_ptr _) = liftIO $+            alloca $ \len_ptr -> do+                key_ptr <- c_leveldb_iter_key iter_ptr len_ptr+                if key_ptr == nullPtr+                    then return Nothing+                    else do+                        klen <- peek len_ptr+                        Just <$> SB.packCStringLen (key_ptr, cSizeToInt klen)++-- | Return the value for the current entry if the iterator is currently+-- positioned at an entry, ie. 'iterValid'.+iterValue :: MonadResource m => Iterator -> m (Maybe ByteString)+iterValue iter = do     valid <- iterValid iter-    case valid of-        False -> return []-        True -> do-            val <- f iter-            _ <- iterNext iter-            fmap (val :) $ mapIter f iter+    if not valid+        then return Nothing+        else iterValue' iter +    where+        iterValue' (Iterator iter_ptr _) = liftIO $+            alloca $ \len_ptr -> do+                val_ptr <- c_leveldb_iter_value iter_ptr len_ptr+                if val_ptr == nullPtr+                    then return Nothing+                    else do+                        vlen <- peek len_ptr+                        Just <$> SB.packCStringLen (val_ptr, cSizeToInt vlen)++-- | Check for errors+--+-- Note that this captures somewhat severe errors such as a corrupted database.+iterGetError :: MonadResource m => Iterator -> m (Maybe ByteString)+iterGetError (Iterator iter_ptr _) = liftIO $+    alloca $ \err_ptr -> do+        poke err_ptr nullPtr+        c_leveldb_iter_get_error iter_ptr err_ptr+        erra <- peek err_ptr+        if erra == nullPtr+            then return Nothing+            else do+                err <- peekCString erra+                return . Just . BC.pack $ err++-- | Map a function over an iterator, advancing the iterator forward and+-- returning the value. The iterator should be put in the right position prior+-- to calling the function.+--+-- Note that this function accumulates the result strictly, ie. it reads all+-- values into memory until the iterator is exhausted. This is most likely not+-- what you want for large ranges. You may consider using conduits instead, for+-- an example see: <https://gist.github.com/adc8ec348f03483446a5>+mapIter :: MonadResource m => (Iterator -> m a) -> Iterator -> m [a]+mapIter = go []++    where+        go acc f iter = do+            valid <- iterValid iter+            if not valid+                then return acc+                else do+                    val <- f iter+                    _   <- iterNext iter+                    go (val : acc) f iter+ -- | Return a list of key and value tuples from an iterator. The iterator -- should be put in the right position prior to calling this with the iterator.-iterItems :: Iterator -> IO [(ByteString, ByteString)]-iterItems = mapIter $ \iter -> (,) <$> iterKey iter <*> iterValue iter+--+-- See strictness remarks on 'mapIter'.+iterItems :: MonadResource m => Iterator -> m [(ByteString, ByteString)]+iterItems iter = catMaybes <$> mapIter iterItems' iter +    where+        iterItems' iter' = do+            mkey <- iterKey iter'+            mval <- iterValue iter'+            return $ (,) <$> mkey <*> mval+ -- | Return a list of key from an iterator. The iterator should be put -- in the right position prior to calling this with the iterator.-iterKeys :: Iterator -> IO [ByteString]-iterKeys = mapIter iterKey+--+-- See strictness remarks on 'mapIter'+iterKeys :: MonadResource m => Iterator -> m [ByteString]+iterKeys iter = catMaybes <$> mapIter iterKey iter  -- | Return a list of values from an iterator. The iterator should be put -- in the right position prior to calling this with the iterator.-iterValues :: Iterator -> IO [ByteString]-iterValues = mapIter iterValue+--+-- See strictness remarks on 'mapIter'+iterValues :: MonadResource m => Iterator -> m [ByteString]+iterValues iter = catMaybes <$> mapIter iterValue iter --- | Internal+--+-- Internal+-- -withCOptions :: Options -> (OptionsPtr -> IO a) -> IO a-withCOptions opts f = do+mkOpts :: Options -> IO Options'+mkOpts Options{..} = do     opts_ptr <- c_leveldb_options_create-    mapM_ (setopt opts_ptr) opts-    if isJust $ maybeCacheSize opts-        then withCache (fromJust $ maybeCacheSize opts) $ \cache_ptr -> do-                 c_leveldb_options_set_cache opts_ptr cache_ptr-                 run opts_ptr-        else run opts_ptr +    c_leveldb_options_set_block_restart_interval opts_ptr+        $ intToCInt blockRestartInterval+    c_leveldb_options_set_block_size opts_ptr+        $ intToCSize blockSize+    c_leveldb_options_set_compression opts_ptr+        $ ccompression compression+    c_leveldb_options_set_create_if_missing opts_ptr+        $ boolToNum createIfMissing+    c_leveldb_options_set_error_if_exists opts_ptr+        $ boolToNum errorIfExists+    c_leveldb_options_set_max_open_files opts_ptr+        $ intToCInt maxOpenFiles+    c_leveldb_options_set_paranoid_checks opts_ptr+        $ boolToNum paranoidChecks+    c_leveldb_options_set_write_buffer_size opts_ptr+        $ intToCSize writeBufferSize++    cache <- maybeSetCache opts_ptr cacheSize+    cmp   <- maybeSetCmp opts_ptr comparator++    return (Options' opts_ptr cache cmp)+     where-        run opts_ptr = do-            res <- f opts_ptr-            c_leveldb_options_destroy opts_ptr-            return res+        ccompression NoCompression = noCompression+        ccompression Snappy        = snappyCompression -        maybeCacheSize os = find isCs os >>= \(CacheSize s) -> return s+        maybeSetCache :: OptionsPtr -> Int -> IO (Maybe CachePtr)+        maybeSetCache opts_ptr size =+            if size <= 0+                then return Nothing+                else do+                    cache_ptr <- c_leveldb_cache_create_lru $ intToCSize size+                    c_leveldb_options_set_cache opts_ptr cache_ptr+                    return . Just $ cache_ptr -        isCs (CacheSize _) = True-        isCs _             = False+        maybeSetCmp :: OptionsPtr -> Maybe Comparator -> IO (Maybe Comparator')+        maybeSetCmp opts_ptr (Just mcmp) = Just <$> setcmp opts_ptr mcmp+        maybeSetCmp _ Nothing = return Nothing -        withCache s = bracket (c_leveldb_cache_create_lru $ i2s s)-                              c_leveldb_cache_destroy+        setcmp :: OptionsPtr -> Comparator -> IO Comparator'+        setcmp opts_ptr (Comparator cmp) = do+            cmp'@(Comparator' _ _ _ cmp_ptr) <- mkComparator "user-defined" cmp+            c_leveldb_options_set_comparator opts_ptr cmp_ptr+            return cmp' -        setopt opts_ptr CreateIfMissing =-            c_leveldb_options_set_create_if_missing opts_ptr 1-        setopt opts_ptr ErrorIfExists =-            c_leveldb_options_set_error_if_exists opts_ptr 1-        setopt opts_ptr ParanoidChecks =-            c_leveldb_options_set_paranoid_checks opts_ptr 1-        setopt opts_ptr (WriteBufferSize s) =-            c_leveldb_options_set_write_buffer_size opts_ptr $ i2s s-        setopt opts_ptr (MaxOpenFiles n) =-            c_leveldb_options_set_max_open_files opts_ptr $ i2ci n-        setopt opts_ptr (BlockSize s) =-            c_leveldb_options_set_block_size opts_ptr $ i2s s-        setopt opts_ptr (BlockRestartInterval i) =-            c_leveldb_options_set_block_restart_interval opts_ptr $ i2ci i-        setopt opts_ptr (UseCompression NoCompression) =-            c_leveldb_options_set_compression opts_ptr noCompression-        setopt opts_ptr (UseCompression Snappy) =-            c_leveldb_options_set_compression opts_ptr snappyCompression-        setopt _ (CacheSize _) = return ()+freeOpts :: Options' -> IO ()+freeOpts (Options' opts_ptr mcache_ptr mcmp_ptr) = do+    c_leveldb_options_destroy opts_ptr+    maybe (return ()) c_leveldb_cache_destroy mcache_ptr+    maybe (return ()) freeComparator mcmp_ptr+    return () -withCWriteOptions :: WriteOptions -> (WriteOptionsPtr -> IO a) -> IO a-withCWriteOptions opts f = do-    opts_ptr <- c_leveldb_writeoptions_create-    mapM_ (setopt opts_ptr) opts-    res <- f opts_ptr-    c_leveldb_writeoptions_destroy opts_ptr-    return res+mkCWriteOpts :: MonadResource m => WriteOptions -> m (ReleaseKey, WriteOptionsPtr)+mkCWriteOpts WriteOptions{..} = do+    (rk, opts_ptr) <- allocate c_leveldb_writeoptions_create+                               c_leveldb_writeoptions_destroy -    where-        setopt opts_ptr Sync = c_leveldb_writeoptions_set_sync opts_ptr 1+    liftIO+        $ c_leveldb_writeoptions_set_sync opts_ptr+        $ boolToNum sync -withCReadOptions :: ReadOptions -> (ReadOptionsPtr -> IO a) -> IO a-withCReadOptions opts f = do-    opts_ptr <- c_leveldb_readoptions_create-    mapM_ (setopt opts_ptr) opts-    res <- f opts_ptr-    c_leveldb_readoptions_destroy opts_ptr-    return res+    return (rk, opts_ptr) +mkCReadOptions:: MonadResource m => ReadOptions -> m (ReleaseKey, ReadOptionsPtr)+mkCReadOptions ReadOptions{..} = do+    (rk, opts_ptr) <- allocate c_leveldb_readoptions_create+                               c_leveldb_readoptions_destroy++    liftIO+        $ c_leveldb_readoptions_set_verify_checksums opts_ptr+        $ boolToNum verifyCheckSums++    liftIO+        $ c_leveldb_readoptions_set_verify_checksums opts_ptr+        $ boolToNum fillCache++    maybeSetSnapshot opts_ptr useSnapshot++    return (rk, opts_ptr)+     where-        setopt opts_ptr VerifyCheckSums =-            c_leveldb_readoptions_set_verify_checksums opts_ptr 1-        setopt opts_ptr FillCache =-            c_leveldb_readoptions_set_fill_cache opts_ptr 1-        setopt opts_ptr (UseSnapshot (Snapshot snap)) =-            c_leveldb_readoptions_set_snapshot opts_ptr snap+        maybeSetSnapshot opts_ptr (Just (Snapshot snap_ptr)) =+            liftIO $ c_leveldb_readoptions_set_snapshot opts_ptr snap_ptr +        maybeSetSnapshot _ Nothing = return ()+ throwIfErr :: String -> (ErrPtr -> IO a) -> IO a throwIfErr s f = alloca $ \err_ptr -> do     poke err_ptr nullPtr@@ -461,11 +780,47 @@         throwIO $ userError $ s ++ ": " ++ err     return res -s2i :: CSize -> Int-s2i = fromIntegral+cSizeToInt :: CSize -> Int+cSizeToInt = fromIntegral+{-# INLINE cSizeToInt #-} -i2s :: Int -> CSize-i2s = fromIntegral+intToCSize :: Int -> CSize+intToCSize = fromIntegral+{-# INLINE intToCSize #-} -i2ci :: Int -> CInt-i2ci = fromIntegral+intToCInt :: Int -> CInt+intToCInt = fromIntegral+{-# INLINE intToCInt #-}++boolToNum :: Num b => Bool -> b+boolToNum True  = fromIntegral (1 :: Int)+boolToNum False = fromIntegral (0 :: Int)+{-# INLINE boolToNum #-}++mkCompareFun :: (ByteString -> ByteString -> Ordering) -> CompareFun+mkCompareFun cmp = cmp'+    where+        cmp' _ a alen b blen = do+            a' <- SB.packCStringLen (a, fromInteger . toInteger $ alen)+            b' <- SB.packCStringLen (b, fromInteger . toInteger $ blen)+            return $ case cmp a' b' of+                         EQ ->  0+                         GT ->  1+                         LT -> -1++mkComparator :: String -> (ByteString -> ByteString -> Ordering) -> IO Comparator'+mkComparator name f =+    withCString name $ \cs -> do+        ccmpfun <- mkCmp  $ mkCompareFun f+        cdest   <- mkDest $ \_ -> ()+        cname   <- mkName $ \_ -> cs+        ccmp    <- c_leveldb_comparator_create nullPtr cdest ccmpfun cname+        return $ Comparator' ccmpfun cdest cname ccmp+++freeComparator :: Comparator' -> IO ()+freeComparator (Comparator' ccmpfun cdest cname ccmp) = do+    c_leveldb_comparator_destroy ccmp+    freeHaskellFunPtr ccmpfun+    freeHaskellFunPtr cdest+    freeHaskellFunPtr cname
src/Database/LevelDB/Base.hsc view
@@ -63,14 +63,14 @@  }  -foreign import ccall unsafe "leveldb/c.h leveldb_open"+foreign import ccall safe "leveldb/c.h leveldb_open"   c_leveldb_open :: OptionsPtr -> DBName -> ErrPtr -> IO LevelDBPtr -foreign import ccall unsafe "leveldb/c.h leveldb_close"+foreign import ccall safe "leveldb/c.h leveldb_close"   c_leveldb_close :: LevelDBPtr -> IO ()  -foreign import ccall unsafe "leveldb/c.h leveldb_put"+foreign import ccall safe "leveldb/c.h leveldb_put"   c_leveldb_put :: LevelDBPtr                 -> WriteOptionsPtr                 -> Key -> CSize@@ -78,14 +78,14 @@                 -> ErrPtr                 -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_delete"+foreign import ccall safe "leveldb/c.h leveldb_delete"   c_leveldb_delete :: LevelDBPtr                    -> WriteOptionsPtr                    -> Key -> CSize                    -> ErrPtr                    -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_write"+foreign import ccall safe "leveldb/c.h leveldb_write"   c_leveldb_write :: LevelDBPtr                   -> WriteOptionsPtr                   -> WriteBatchPtr@@ -94,7 +94,7 @@  -- | Returns NULL if not found. A malloc()ed array otherwise. Stores the length -- of the array in *vallen.-foreign import ccall unsafe "leveldb/c.h leveldb_get"+foreign import ccall safe "leveldb/c.h leveldb_get"   c_leveldb_get :: LevelDBPtr                 -> ReadOptionsPtr                 -> Key -> CSize@@ -102,19 +102,19 @@                 -> ErrPtr                 -> IO CString -foreign import ccall unsafe "leveldb/c.h leveldb_create_snapshot"+foreign import ccall safe "leveldb/c.h leveldb_create_snapshot"   c_leveldb_create_snapshot :: LevelDBPtr -> IO SnapshotPtr -foreign import ccall unsafe "leveldb/c.h leveldb_release_snapshot"+foreign import ccall safe "leveldb/c.h leveldb_release_snapshot"   c_leveldb_release_snapshot :: LevelDBPtr -> SnapshotPtr -> IO ()  -- | Returns NULL if property name is unknown. Else returns a pointer to a -- malloc()-ed null-terminated value.-foreign import ccall unsafe "leveldb/c.h leveldb_property_value"+foreign import ccall safe "leveldb/c.h leveldb_property_value"   c_leveldb_property_value :: LevelDBPtr -> CString -> IO CString --- not sure why this needs to be imported unsafe-foreign import ccall unsafe "leveldb/c.h leveldb_approximate_sizes"+-- not sure why this needs to be imported safe+foreign import ccall safe "leveldb/c.h leveldb_approximate_sizes"   c_leveldb_approximate_sizes :: LevelDBPtr                               -> CInt                     -- ^ num ranges                               -> Ptr CString -> Ptr CSize -- ^ range start keys (array)@@ -122,68 +122,68 @@                               -> Ptr Word64               -- ^ array of approx. sizes of ranges                               -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_destroy_db"+foreign import ccall safe "leveldb/c.h leveldb_destroy_db"   c_leveldb_destroy_db :: OptionsPtr -> DBName -> ErrPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_repair_db"+foreign import ccall safe "leveldb/c.h leveldb_repair_db"   c_leveldb_repair_db :: OptionsPtr -> DBName -> ErrPtr -> IO ()  -- ^ Iterator -foreign import ccall unsafe "leveldb/c.h leveldb_create_iterator"+foreign import ccall safe "leveldb/c.h leveldb_create_iterator"   c_leveldb_create_iterator :: LevelDBPtr -> ReadOptionsPtr -> IO IteratorPtr -foreign import ccall unsafe "leveldb/c.h leveldb_iter_destroy"+foreign import ccall safe "leveldb/c.h leveldb_iter_destroy"   c_leveldb_iter_destroy :: IteratorPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_iter_valid"+foreign import ccall safe "leveldb/c.h leveldb_iter_valid"   c_leveldb_iter_valid :: IteratorPtr -> IO CUChar -foreign import ccall unsafe "leveldb/c.h leveldb_iter_seek_to_first"+foreign import ccall safe "leveldb/c.h leveldb_iter_seek_to_first"   c_leveldb_iter_seek_to_first :: IteratorPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_iter_seek_to_last"+foreign import ccall safe "leveldb/c.h leveldb_iter_seek_to_last"   c_leveldb_iter_seek_to_last :: IteratorPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_iter_seek"+foreign import ccall safe "leveldb/c.h leveldb_iter_seek"   c_leveldb_iter_seek :: IteratorPtr -> Key -> CSize -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_iter_next"+foreign import ccall safe "leveldb/c.h leveldb_iter_next"   c_leveldb_iter_next :: IteratorPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_iter_prev"+foreign import ccall safe "leveldb/c.h leveldb_iter_prev"   c_leveldb_iter_prev :: IteratorPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_iter_key"+foreign import ccall safe "leveldb/c.h leveldb_iter_key"   c_leveldb_iter_key :: IteratorPtr -> Ptr CSize -> IO Key -foreign import ccall unsafe "leveldb/c.h leveldb_iter_value"+foreign import ccall safe "leveldb/c.h leveldb_iter_value"   c_leveldb_iter_value :: IteratorPtr -> Ptr CSize -> IO Val -foreign import ccall unsafe "leveldb/c.h leveldb_iter_get_error"+foreign import ccall safe "leveldb/c.h leveldb_iter_get_error"   c_leveldb_iter_get_error :: IteratorPtr -> ErrPtr -> IO ()  -- ^ Write batch -foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_create"+foreign import ccall safe "leveldb/c.h leveldb_writebatch_create"   c_leveldb_writebatch_create :: IO WriteBatchPtr -foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_destroy"+foreign import ccall safe "leveldb/c.h leveldb_writebatch_destroy"   c_leveldb_writebatch_destroy :: WriteBatchPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_clear"+foreign import ccall safe "leveldb/c.h leveldb_writebatch_clear"   c_leveldb_writebatch_clear :: WriteBatchPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_put"+foreign import ccall safe "leveldb/c.h leveldb_writebatch_put"   c_leveldb_writebatch_put :: WriteBatchPtr                            -> Key -> CSize                            -> Val -> CSize                            -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_delete"+foreign import ccall safe "leveldb/c.h leveldb_writebatch_delete"   c_leveldb_writebatch_delete :: WriteBatchPtr -> Key -> CSize -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_iterate"+foreign import ccall safe "leveldb/c.h leveldb_writebatch_iterate"   c_leveldb_writebatch_iterate :: WriteBatchPtr                                -> Ptr ()                            -- ^ state                                -> FunPtr (Ptr () -> Key -> CSize -> Val -> CSize) -- ^ put@@ -192,46 +192,46 @@  -- ^ Options -foreign import ccall unsafe "leveldb/c.h leveldb_options_create"+foreign import ccall safe "leveldb/c.h leveldb_options_create"   c_leveldb_options_create :: IO OptionsPtr -foreign import ccall unsafe "leveldb/c.h leveldb_options_destroy"+foreign import ccall safe "leveldb/c.h leveldb_options_destroy"   c_leveldb_options_destroy :: OptionsPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_options_set_comparator"+foreign import ccall safe "leveldb/c.h leveldb_options_set_comparator"   c_leveldb_options_set_comparator :: OptionsPtr -> ComparatorPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_options_set_create_if_missing"+foreign import ccall safe "leveldb/c.h leveldb_options_set_create_if_missing"   c_leveldb_options_set_create_if_missing :: OptionsPtr -> CUChar -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_options_set_error_if_exists"+foreign import ccall safe "leveldb/c.h leveldb_options_set_error_if_exists"   c_leveldb_options_set_error_if_exists :: OptionsPtr -> CUChar -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_options_set_paranoid_checks"+foreign import ccall safe "leveldb/c.h leveldb_options_set_paranoid_checks"   c_leveldb_options_set_paranoid_checks :: OptionsPtr -> CUChar -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_options_set_env"+foreign import ccall safe "leveldb/c.h leveldb_options_set_env"   c_leveldb_options_set_env :: OptionsPtr -> EnvPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_options_set_info_log"+foreign import ccall safe "leveldb/c.h leveldb_options_set_info_log"   c_leveldb_options_set_info_log :: OptionsPtr -> LoggerPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_options_set_write_buffer_size"+foreign import ccall safe "leveldb/c.h leveldb_options_set_write_buffer_size"   c_leveldb_options_set_write_buffer_size :: OptionsPtr -> CSize -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_options_set_max_open_files"+foreign import ccall safe "leveldb/c.h leveldb_options_set_max_open_files"   c_leveldb_options_set_max_open_files :: OptionsPtr -> CInt -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_options_set_block_size"+foreign import ccall safe "leveldb/c.h leveldb_options_set_block_size"   c_leveldb_options_set_block_size :: OptionsPtr -> CSize -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_options_set_block_restart_interval"+foreign import ccall safe "leveldb/c.h leveldb_options_set_block_restart_interval"   c_leveldb_options_set_block_restart_interval :: OptionsPtr -> CInt -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_options_set_compression"+foreign import ccall safe "leveldb/c.h leveldb_options_set_compression"   c_leveldb_options_set_compression :: OptionsPtr -> CompressionOpt -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_options_set_cache"+foreign import ccall safe "leveldb/c.h leveldb_options_set_cache"   c_leveldb_options_set_cache :: OptionsPtr -> CachePtr -> IO ()  --@@ -251,56 +251,56 @@ -- | Make a name FunPtr foreign import ccall "wrapper" mkName :: NameFun -> IO (FunPtr NameFun) -foreign import ccall unsafe "leveldb/c.h leveldb_comparator_create"+foreign import ccall safe "leveldb/c.h leveldb_comparator_create"   c_leveldb_comparator_create :: StatePtr                               -> FunPtr Destructor                               -> FunPtr CompareFun                               -> FunPtr NameFun                               -> IO ComparatorPtr -foreign import ccall unsafe "leveldb/c.h leveldb_comparator_destroy"+foreign import ccall safe "leveldb/c.h leveldb_comparator_destroy"   c_leveldb_comparator_destroy :: ComparatorPtr -> IO ()  -- ^ Read options -foreign import ccall unsafe "leveldb/c.h leveldb_readoptions_create"+foreign import ccall safe "leveldb/c.h leveldb_readoptions_create"   c_leveldb_readoptions_create :: IO ReadOptionsPtr -foreign import ccall unsafe "leveldb/c.h leveldb_readoptions_destroy"+foreign import ccall safe "leveldb/c.h leveldb_readoptions_destroy"   c_leveldb_readoptions_destroy :: ReadOptionsPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_readoptions_set_verify_checksums"+foreign import ccall safe "leveldb/c.h leveldb_readoptions_set_verify_checksums"   c_leveldb_readoptions_set_verify_checksums :: ReadOptionsPtr -> CUChar -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_readoptions_set_fill_cache"+foreign import ccall safe "leveldb/c.h leveldb_readoptions_set_fill_cache"   c_leveldb_readoptions_set_fill_cache :: ReadOptionsPtr -> CUChar -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_readoptions_set_snapshot"+foreign import ccall safe "leveldb/c.h leveldb_readoptions_set_snapshot"   c_leveldb_readoptions_set_snapshot :: ReadOptionsPtr -> SnapshotPtr -> IO ()  -- ^ Write options -foreign import ccall unsafe "leveldb/c.h leveldb_writeoptions_create"+foreign import ccall safe "leveldb/c.h leveldb_writeoptions_create"   c_leveldb_writeoptions_create :: IO WriteOptionsPtr -foreign import ccall unsafe "leveldb/c.h leveldb_writeoptions_destroy"+foreign import ccall safe "leveldb/c.h leveldb_writeoptions_destroy"   c_leveldb_writeoptions_destroy :: WriteOptionsPtr -> IO () -foreign import ccall unsafe "leveldb/c.h leveldb_writeoptions_set_sync"+foreign import ccall safe "leveldb/c.h leveldb_writeoptions_set_sync"   c_leveldb_writeoptions_set_sync :: WriteOptionsPtr -> CUChar -> IO ()  -- ^ Cache -foreign import ccall unsafe "leveldb/c.h leveldb_cache_create_lru"+foreign import ccall safe "leveldb/c.h leveldb_cache_create_lru"   c_leveldb_cache_create_lru :: CSize -> IO CachePtr -foreign import ccall unsafe "leveldb/c.h leveldb_cache_destroy"+foreign import ccall safe "leveldb/c.h leveldb_cache_destroy"   c_leveldb_cache_destroy :: CachePtr -> IO ()  -- ^ Env -foreign import ccall unsafe "leveldb/c.h leveldb_create_default_env"+foreign import ccall safe "leveldb/c.h leveldb_create_default_env"   c_leveldb_create_default_env :: IO EnvPtr -foreign import ccall unsafe "leveldb/c.h leveldb_env_destroy"+foreign import ccall safe "leveldb/c.h leveldb_env_destroy"   c_leveldb_env_destroy :: EnvPtr -> IO ()