packages feed

leveldb-haskell (empty) → 0.0.1

raw patch · 20 files changed

+2563/−0 lines, 20 filesdep +basedep +bytestringdep +filepathsetup-changed

Dependencies added: base, bytestring, filepath, leveldb-haskell

Files

+ Example.lhs view
@@ -0,0 +1,86 @@+Comprehensive walkthough of the functionality provided by this library.++> {-# LANGUAGE OverloadedStrings #-}+> module Main where+>+> import Control.Monad+> import Data.ByteString.Char8 hiding (take)+> import Prelude hiding (putStrLn)+> import System.FilePath+>+> import Database.LevelDB+>+> import Debug.Trace+>+>+> main :: IO ()+> main =++Almost all operations on a leveldb database occur within the @withLevelDB@+bracket, to ensure proper resource de-/allocation.++>     withLevelDB dbdir [ CreateIfMissing, CacheSize 2048 ] $ \db -> do++The basic operations are @put@, @get@ and @delete@, straightforwardly:++>         put db [] "foo" "bar"+>         get db [ FillCache ] "foo" >>= print+>         delete db [] "foo"+>         get db [ FillCache ] "foo" >>= print++Additionally, we can write several key/value pairs in a batch, which is+guaranteed to be atomic. Note the use of the @Sync@ option here: it tells+leveldb to flush the data to disk before returning. While syncing may have a+considerable performance impact, it is most useful with batch operations.++Also note that we're taking a snapshot of the database before issueing the+write.++>         withSnapshot db $ \snap -> do+>             write db [ Sync ] [ Put "a" "one"+>                               , Put "b" "two"+>                               , Put "c" "three" ]++Now, we can perform a snapshot read. As expected, this will output nothing,+since we took the snapshot before writing.++>             dumpEntries db [ UseSnapshot snap, FillCache ]++Conversely, we should see the values just written in a "dirty" read:++>             dumpEntries db [ FillCache ]+++Let's inspect the state of our database, just for the fun of it.++>         approximateSize db ("a", "z") >>= print+>         getProperty db SSTables >>= printProperty "sstables"+>         getProperty db Stats    >>= printProperty "stats"+>         getProperty db (NumFilesAtLevel 1) >>= printProperty "num files at level"++Similar to the batch write above, we can also use @write@ to delete key/value+pairs:++>         write db [ Sync ] [ Del "a", Del "b", Del "c" ]+>         dumpEntries db [ FillCache ]+>+>     where+>         dbdir = "/" </> "tmp" </> "leveltest"+>+>         dumpEntries db opts =+>             withIterator db opts $ \iter -> do+>                 iterFirst iter+>                 iterEntries iter print+>+>         iterEntries iter f = do+>             valid <- iterValid iter+>             when valid $ do+>                 key <- iterKey iter+>                 val <- iterValue iter+>                 _   <- f (key, val)+>                 _   <- iterNext iter+>                 iterEntries iter f+>+>         printProperty l p = do+>             putStrLn l+>             maybe (putStrLn "n/a") putStrLn $ p
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2011, Kim Altintop++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Kim Altintop nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Readme.md view
@@ -0,0 +1,28 @@+This library provides Haskell bindings to+[LevelDB](http://leveldb.googlecode.com)++## Installation++Prerequisites:++* GHC 7.* (http://www.haskell.org/ghc)+* Cabal (http://www.haskell.org/cabal)+* `make` and a working C++ compiler++`cabal install` will build and install the package, including the bundled+LevelDB sources.++## Notes++This library is in very early stage and has seen very limited testing. Comments+and contributions are welcome.++## Bugs and Contributing++Please report issues via http://github.com/kim/leveldb-haskell/issues.<br />+Patches are best submitted as pull requests, or via email+(kim.altintop@gmail.com).++## License++BSD 3, see LICENSE file.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cbits/leveldb/include/leveldb/c.h view
@@ -0,0 +1,246 @@+/* 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 view
@@ -0,0 +1,99 @@+// 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 view
@@ -0,0 +1,63 @@+// 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 view
@@ -0,0 +1,160 @@+// 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 view
@@ -0,0 +1,323 @@+// 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 view
@@ -0,0 +1,100 @@+// 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 view
@@ -0,0 +1,187 @@+// 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 view
@@ -0,0 +1,109 @@+// 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 view
@@ -0,0 +1,100 @@+// 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 view
@@ -0,0 +1,70 @@+// 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 view
@@ -0,0 +1,91 @@+// 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 view
@@ -0,0 +1,64 @@+// 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_
+ configure view
@@ -0,0 +1,4 @@+#!/bin/sh++make --directory=cbits/leveldb libleveldb.a+echo extra-lib-dirs: `pwd`/cbits/leveldb > leveldb-haskell.buildinfo
+ leveldb-haskell.cabal view
@@ -0,0 +1,57 @@+name:                leveldb-haskell+version:             0.0.1+synopsis:            Haskell bindings to LevelDB+homepage:            http://github.com/kim/leveldb-haskell+license:             BSD3+license-file:        LICENSE+author:              Kim Altintop+maintainer:          kim.altintop@gmail.com+category:            Database+stability:           Experimental+build-type:          Configure+cabal-version:       >=1.8+tested-with:         GHC == 7.2.2, GHC == 7.4.1+description:+    From <http://leveldb.googlecode.com>:+    .+    LevelDB is a fast key-value storage library written at Google that provides+    an ordered mapping from string keys to string values.+    .+    .+    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, assuming that a working C++ compiler is installed+    on the target system and the @make@ command can invoke it.++extra-source-files:  Example.lhs+                   , Readme.md+                   , configure+                   , cbits/leveldb/include/leveldb/*.h++source-repository head+  type:     git+  location: git://github.com/kim/leveldb-haskell.git++library+  exposed-modules:  Database.LevelDB+  other-modules:    Database.LevelDB.Base+  extensions:       CPP+                  , ForeignFunctionInterface+  build-depends:    base >= 3 && < 5+                  , bytestring+  ghc-options:      -Wall -O2 -static -optl-static -rtsopts+  ghc-prof-options: -prof -auto-all+  hs-source-dirs:   src+  includes:         leveldb/c.h+  extra-libraries:  leveldb, snappy, stdc+++  include-dirs:     cbits/leveldb/include++executable hsleveldb-example+  main-is:          Example.lhs+  build-depends:    base+                  , leveldb-haskell+                  , bytestring+                  , filepath+  ghc-options:      -rtsopts -threaded
+ src/Database/LevelDB.hs view
@@ -0,0 +1,446 @@+-- |+-- LevelDB Haskell binding.+--+-- 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+-- >                 iterEntries iter print+-- >+-- >         iterEntries iter f = do+-- >             valid <- iterValid iter+-- >             when valid $ do+-- >                 key <- iterKey iter+-- >                 val <- iterValue iter+-- >                 _   <- f (key, val)+-- >                 _   <- iterNext iter+-- >                 iterEntries iter f++module Database.LevelDB (+  -- * Exported Types+    DB+  , BatchOp(..)+  , Compression(..)+  , Option(..)+  , Options+  , ReadOption(..)+  , ReadOptions+  , Snapshot+  , WriteBatch+  , WriteOption(..)+  , WriteOptions+  , Range++  -- * Basic Database Manipulation+  , withLevelDB+  , withSnapshot+  , put+  , delete+  , write+  , get++  -- * Administrative Functions+  , Property(..), getProperty+  , destroy+  , repair+  , approximateSize++  -- * Iteration+  , Iterator+  , withIterator+  , iterOpen+  , iterClose+  , iterValid+  , iterSeek+  , iterFirst+  , iterLast+  , iterNext+  , iterPrev+  , iterKey+  , iterValue+) where++import Control.Exception  (bracket)+import Control.Monad      (liftM, when)+import Data.ByteString    (ByteString)+import Data.List          (find)+import Data.Maybe+import Foreign+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.Unsafe as UB++-- import Debug.Trace++-- | Database handle+newtype DB = DB LevelDBPtr++-- | Iterator handle+newtype Iterator = Iterator IteratorPtr++-- | Snapshot handle+newtype Snapshot = Snapshot SnapshotPtr++-- | Compression setting+data Compression = NoCompression | Snappy deriving (Eq, Show)++type Options = [Option]+-- | 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)++type WriteOptions = [WriteOption]+-- | Options for write operations+data WriteOption  = Sync -- ^ fsync the rows written immediately+                  deriving (Show)++type ReadOptions = [ReadOption]+-- | Options for read operations+data ReadOption  = VerifyCheckSums+                 | FillCache+                 | UseSnapshot Snapshot++type WriteBatch = [BatchOp]+-- | Batch operation+data BatchOp = Put ByteString ByteString | Del ByteString deriving (Show)++-- | Properties exposed by LevelDB+data Property = NumFilesAtLevel Int | Stats | SSTables 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 ->+    alloca              $ \err_ptr  ->+        bracket (open path_ptr opts_ptr err_ptr) close act+    where+        open path_ptr opts_ptr err_ptr = do+            p <- throwIfErr "open" err_ptr $ c_leveldb_open opts_ptr path_ptr+            return . DB $ p++        close (DB db) = c_leveldb_close db++-- | Run an action with a snapshot of the database.+withSnapshot :: DB -> (Snapshot -> IO a) -> IO a+withSnapshot (DB db) = bracket (create db) (release 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++-- | Get a DB property+getProperty :: DB -> Property -> IO (Maybe ByteString)+getProperty (DB db) p =+    withCString (prop p) $ \prop_ptr -> do+        val_ptr <- c_leveldb_property_value db prop_ptr+        if val_ptr == nullPtr+            then return Nothing+            else do res <- liftM Just $ SB.packCString val_ptr+                    free val_ptr+                    return res++    where+        prop (NumFilesAtLevel i) = "leveldb.num-files-at-level" ++ show i+        prop Stats    = "leveldb.stats"+        prop SSTables = "leveldb.sstables"++-- | Destroy the given leveldb database.+destroy :: FilePath -> Options -> IO ()+destroy path opts =+    withCString path    $ \path_ptr ->+    withCOptions opts   $ \opts_ptr ->+    alloca              $ \err_ptr  ->+        throwIfErr "destroy" err_ptr $ 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 ->+    alloca              $ \err_ptr  ->+        throwIfErr "repair" err_ptr $ 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) =+    UB.unsafeUseAsCStringLen from $ \(from_ptr, flen) ->+    UB.unsafeUseAsCStringLen to   $ \(to_ptr, tlen)   ->+    withArray [from_ptr]          $ \from_ptrs        ->+    withArray [i2s flen]          $ \flen_ptrs        ->+    withArray [to_ptr]            $ \to_ptrs          ->+    withArray [i2s tlen]          $ \tlen_ptrs        ->+    allocaArray 1                 $ \size_ptrs        -> do+        c_leveldb_approximate_sizes db 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        ->+    alloca                         $ \err_ptr         ->+        throwIfErr "put" err_ptr+        $ c_leveldb_put db opts_ptr+                        key_ptr (i2s klen)+                        val_ptr (i2s vlen)++-- | 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                       $ \err_ptr         ->+    alloca                       $ \vlen_ptr        -> do+        val_ptr <- throwIfErr "get" err_ptr+                   $ 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++-- | 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        ->+    alloca                       $ \err_ptr         ->+        throwIfErr "delete" err_ptr+        $ c_leveldb_delete db opts_ptr key_ptr (i2s klen)++-- | Perform a batch mutation+write :: DB -> WriteOptions -> WriteBatch -> IO ()+write (DB db) opts batch =+    withCWriteOptions opts $ \opts_ptr  ->+    withCWriteBatch batch  $ \batch_ptr ->+    alloca                 $ \err_ptr   ->+        throwIfErr "write" err_ptr+        $ c_leveldb_write db opts_ptr batch_ptr++    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++        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)++        batchAdd batch_ptr (Del key) =+            UB.unsafeUseAsCStringLen key $ \(key_ptr, klen) ->+                c_leveldb_writebatch_delete batch_ptr key_ptr (i2s 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++-- | 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++-- | Release an Iterator. Consider using withIterator.+iterClose :: Iterator -> IO ()+iterClose (Iterator iter) = 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+    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)++-- | 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++-- | 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++-- | 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++-- | 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++-- | 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"++-- | 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"++-- | Internal++withCOptions :: Options -> (OptionsPtr -> IO a) -> IO a+withCOptions opts f = 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++    where+        run opts_ptr = do+            res <- f opts_ptr+            c_leveldb_options_destroy opts_ptr+            return res++        maybeCacheSize os = find isCs os >>= \(CacheSize s) -> return s++        isCs (CacheSize _) = True+        isCs _             = False++        withCache s = bracket (c_leveldb_cache_create_lru $ i2s s)+                              c_leveldb_cache_destroy++        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 ()++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++    where+        setopt opts_ptr Sync = c_leveldb_writeoptions_set_sync opts_ptr 1++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++    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++throwIfErr :: String -> ErrPtr -> (ErrPtr -> IO a) -> IO a+throwIfErr s err_ptr f = do+    res  <- f err_ptr+    erra <- peek err_ptr+    when (erra /= nullPtr) $ do+        err <- peekCString erra+        ioError $ userError $ s ++ ": " ++ err+    return res++s2i :: CSize -> Int+s2i = fromIntegral++i2s :: Int -> CSize+i2s = fromIntegral++i2ci :: Int -> CInt+i2ci = fromIntegral
+ src/Database/LevelDB/Base.hsc view
@@ -0,0 +1,298 @@+{-# LANGUAGE CPP, ForeignFunctionInterface, EmptyDataDecls #-}++module Database.LevelDB.Base where++import Foreign+import Foreign.C.Types+import Foreign.C.String++#include <leveldb/c.h>++data LevelDB+data LCache+data LComparator+data LIterator+data LLogger+data LOptions+data LReadOptions+data LSnapshot+data LWriteBatch+data LWriteOptions++type LevelDBPtr      = Ptr LevelDB+type CachePtr        = Ptr LCache+type ComparatorPtr   = Ptr LComparator+type IteratorPtr     = Ptr LIterator+type LoggerPtr       = Ptr LLogger+type OptionsPtr      = Ptr LOptions+type ReadOptionsPtr  = Ptr LReadOptions+type SnapshotPtr     = Ptr LSnapshot+type WriteBatchPtr   = Ptr LWriteBatch+type WriteOptionsPtr = Ptr LWriteOptions++-- custom env from haskell doesn't make too much sense+data LEnv+data LFileLock+data LRandomFile+data LSeqfile+data LWritableFile+type EnvPtr          = Ptr LEnv+type FileLockPtr     = Ptr LFileLock+type RandomFilePtr   = Ptr LRandomFile+type WritableFilePtr = Ptr LWritableFile+type SeqfilePtr      = Ptr LSeqfile++type DBName = CString+type ErrPtr = Ptr CString+type Key    = CString+type Val    = CString++newtype CompressionOpt = CompressionOpt { compressionOpt :: CInt }+  deriving (Eq, Show)+#{enum CompressionOpt, CompressionOpt+ , noCompression     = 0+ , snappyCompression = 1+ }+++foreign import ccall unsafe "leveldb/c.h leveldb_open"+  c_leveldb_open :: OptionsPtr -> DBName -> ErrPtr -> IO LevelDBPtr++foreign import ccall unsafe "leveldb/c.h leveldb_close"+  c_leveldb_close :: LevelDBPtr -> IO ()+++foreign import ccall unsafe "leveldb/c.h leveldb_put"+  c_leveldb_put :: LevelDBPtr+                -> WriteOptionsPtr+                -> Key -> CSize+                -> Val -> CSize+                -> ErrPtr+                -> IO ()++foreign import ccall unsafe "leveldb/c.h leveldb_delete"+  c_leveldb_delete :: LevelDBPtr+                   -> WriteOptionsPtr+                   -> Key -> CSize+                   -> ErrPtr+                   -> IO ()++foreign import ccall unsafe "leveldb/c.h leveldb_write"+  c_leveldb_write :: LevelDBPtr+                  -> WriteOptionsPtr+                  -> WriteBatchPtr+                  -> ErrPtr+                  -> IO ()++-- | 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"+  c_leveldb_get :: LevelDBPtr+                -> ReadOptionsPtr+                -> Key -> CSize+                -> Ptr CSize        -- ^ value length+                -> ErrPtr+                -> IO CString++foreign import ccall unsafe "leveldb/c.h leveldb_create_snapshot"+  c_leveldb_create_snapshot :: LevelDBPtr -> IO SnapshotPtr++foreign import ccall unsafe "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"+  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"+  c_leveldb_approximate_sizes :: LevelDBPtr+                              -> CInt                     -- ^ num ranges+                              -> Ptr CString -> Ptr CSize -- ^ range start keys (array)+                              -> Ptr CString -> Ptr CSize -- ^ range limit keys (array)+                              -> Ptr Word64               -- ^ array of approx. sizes of ranges+                              -> IO ()++foreign import ccall unsafe "leveldb/c.h leveldb_destroy_db"+  c_leveldb_destroy_db :: OptionsPtr -> DBName -> ErrPtr -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_create_iterator :: LevelDBPtr -> ReadOptionsPtr -> IO IteratorPtr++foreign import ccall unsafe "leveldb/c.h leveldb_iter_destroy"+  c_leveldb_iter_destroy :: IteratorPtr -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_iter_seek_to_first :: IteratorPtr -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_iter_seek :: IteratorPtr -> Key -> CSize -> IO ()++foreign import ccall unsafe "leveldb/c.h leveldb_iter_next"+  c_leveldb_iter_next :: IteratorPtr -> IO ()++foreign import ccall unsafe "leveldb/c.h leveldb_iter_prev"+  c_leveldb_iter_prev :: IteratorPtr -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_iter_value :: IteratorPtr -> Ptr CSize -> IO Val++foreign import ccall unsafe "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"+  c_leveldb_writebatch_create :: IO WriteBatchPtr++foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_destroy"+  c_leveldb_writebatch_destroy :: WriteBatchPtr -> IO ()++foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_clear"+  c_leveldb_writebatch_clear :: WriteBatchPtr -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_writebatch_delete :: WriteBatchPtr -> Key -> CSize -> IO ()++foreign import ccall unsafe "leveldb/c.h leveldb_writebatch_iterate"+  c_leveldb_writebatch_iterate :: WriteBatchPtr+                               -> Ptr ()                            -- ^ state+                               -> FunPtr (Ptr () -> Key -> CSize -> Val -> CSize) -- ^ put+                               -> FunPtr (Ptr () -> Key -> CSize)     -- ^ delete+                               -> IO ()++-- ^ Options++foreign import ccall unsafe "leveldb/c.h leveldb_options_create"+  c_leveldb_options_create :: IO OptionsPtr++foreign import ccall unsafe "leveldb/c.h leveldb_options_destroy"+  c_leveldb_options_destroy :: OptionsPtr -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_options_set_create_if_missing :: OptionsPtr -> CUChar -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_options_set_paranoid_checks :: OptionsPtr -> CUChar -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_options_set_info_log :: OptionsPtr -> LoggerPtr -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_options_set_max_open_files :: OptionsPtr -> CInt -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_options_set_block_restart_interval :: OptionsPtr -> CInt -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_options_set_cache :: OptionsPtr -> CachePtr -> IO ()++--+-- Comparator+--+type StatePtr   = Ptr ()+type Destructor = StatePtr -> ()+type CompareFun = StatePtr -> CString -> CSize -> CString -> CSize -> IO CInt+type NameFun    = StatePtr -> CString++-- | Make a FunPtr to a user-defined comparator function+foreign import ccall "wrapper" mkCmp :: CompareFun -> IO (FunPtr CompareFun)++-- | Make a destructor FunPtr+foreign import ccall "wrapper" mkDest :: Destructor -> IO (FunPtr Destructor)++-- | Make a name FunPtr+foreign import ccall "wrapper" mkName :: NameFun -> IO (FunPtr NameFun)++foreign import ccall unsafe "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"+  c_leveldb_comparator_destroy :: ComparatorPtr -> IO ()++-- ^ Read options++foreign import ccall unsafe "leveldb/c.h leveldb_readoptions_create"+  c_leveldb_readoptions_create :: IO ReadOptionsPtr++foreign import ccall unsafe "leveldb/c.h leveldb_readoptions_destroy"+  c_leveldb_readoptions_destroy :: ReadOptionsPtr -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_readoptions_set_fill_cache :: ReadOptionsPtr -> CUChar -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_writeoptions_create :: IO WriteOptionsPtr++foreign import ccall unsafe "leveldb/c.h leveldb_writeoptions_destroy"+  c_leveldb_writeoptions_destroy :: WriteOptionsPtr -> IO ()++foreign import ccall unsafe "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"+  c_leveldb_cache_create_lru :: CSize -> IO CachePtr++foreign import ccall unsafe "leveldb/c.h leveldb_cache_destroy"+  c_leveldb_cache_destroy :: CachePtr -> IO ()++-- ^ Env++foreign import ccall unsafe "leveldb/c.h leveldb_create_default_env"+  c_leveldb_create_default_env :: IO EnvPtr++foreign import ccall unsafe "leveldb/c.h leveldb_env_destroy"+  c_leveldb_env_destroy :: EnvPtr -> IO ()