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 +86/−0
- LICENSE +30/−0
- Readme.md +28/−0
- Setup.hs +2/−0
- cbits/leveldb/include/leveldb/c.h +246/−0
- cbits/leveldb/include/leveldb/cache.h +99/−0
- cbits/leveldb/include/leveldb/comparator.h +63/−0
- cbits/leveldb/include/leveldb/db.h +160/−0
- cbits/leveldb/include/leveldb/env.h +323/−0
- cbits/leveldb/include/leveldb/iterator.h +100/−0
- cbits/leveldb/include/leveldb/options.h +187/−0
- cbits/leveldb/include/leveldb/slice.h +109/−0
- cbits/leveldb/include/leveldb/status.h +100/−0
- cbits/leveldb/include/leveldb/table.h +70/−0
- cbits/leveldb/include/leveldb/table_builder.h +91/−0
- cbits/leveldb/include/leveldb/write_batch.h +64/−0
- configure +4/−0
- leveldb-haskell.cabal +57/−0
- src/Database/LevelDB.hs +446/−0
- src/Database/LevelDB/Base.hsc +298/−0
+ 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 ()