130 changed files with 25488 additions and 4 deletions
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
build_config.mk |
||||
*.a |
||||
*.o |
||||
*.dylib* |
||||
*.so |
||||
*.so.* |
||||
*_test |
||||
db_bench |
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
# Names should be added to this file like so: |
||||
# Name or Organization <email address> |
||||
|
||||
Google Inc. |
||||
|
||||
# Initial version authors: |
||||
Jeffrey Dean <jeff@google.com> |
||||
Sanjay Ghemawat <sanjay@google.com> |
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2011 The LevelDB Authors. 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 Google Inc. nor the names of its |
||||
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. |
@ -0,0 +1,200 @@
@@ -0,0 +1,200 @@
|
||||
# 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.
|
||||
|
||||
# Inherit some settings from environment variables, if available
|
||||
INSTALL_PATH ?= $(CURDIR) |
||||
|
||||
#-----------------------------------------------
|
||||
# Uncomment exactly one of the lines labelled (A), (B), and (C) below
|
||||
# to switch between compilation modes.
|
||||
|
||||
OPT ?= -O2 -DNDEBUG # (A) Production use (optimized mode) |
||||
# OPT ?= -g2 # (B) Debug mode, w/ full line-level debugging symbols
|
||||
# OPT ?= -O2 -g2 -DNDEBUG # (C) Profiling mode: opt, but w/debugging symbols
|
||||
#-----------------------------------------------
|
||||
|
||||
# detect what platform we're building on
|
||||
$(shell ./build_detect_platform build_config.mk) |
||||
# this file is generated by the previous line to set build flags and sources
|
||||
include build_config.mk |
||||
|
||||
CFLAGS += -I. -I./include $(PLATFORM_CCFLAGS) $(OPT) |
||||
CXXFLAGS += -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) |
||||
|
||||
LDFLAGS += $(PLATFORM_LDFLAGS) |
||||
|
||||
LIBOBJECTS = $(SOURCES:.cc=.o) |
||||
MEMENVOBJECTS = $(MEMENV_SOURCES:.cc=.o) |
||||
|
||||
TESTUTIL = ./util/testutil.o |
||||
TESTHARNESS = ./util/testharness.o $(TESTUTIL) |
||||
|
||||
TESTS = \
|
||||
arena_test \
|
||||
bloom_test \
|
||||
c_test \
|
||||
cache_test \
|
||||
coding_test \
|
||||
corruption_test \
|
||||
crc32c_test \
|
||||
db_test \
|
||||
dbformat_test \
|
||||
env_test \
|
||||
filename_test \
|
||||
filter_block_test \
|
||||
log_test \
|
||||
memenv_test \
|
||||
skiplist_test \
|
||||
table_test \
|
||||
version_edit_test \
|
||||
version_set_test \
|
||||
write_batch_test |
||||
|
||||
PROGRAMS = db_bench $(TESTS) |
||||
BENCHMARKS = db_bench_sqlite3 db_bench_tree_db |
||||
|
||||
LIBRARY = libleveldb.a |
||||
MEMENVLIBRARY = libmemenv.a |
||||
|
||||
default: all |
||||
|
||||
# Should we build shared libraries?
|
||||
ifneq ($(PLATFORM_SHARED_EXT),) |
||||
|
||||
ifneq ($(PLATFORM_SHARED_VERSIONED),true) |
||||
SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) |
||||
SHARED2 = $(SHARED1) |
||||
SHARED3 = $(SHARED1) |
||||
SHARED = $(SHARED1) |
||||
else |
||||
# Update db.h if you change these.
|
||||
SHARED_MAJOR = 1 |
||||
SHARED_MINOR = 5 |
||||
SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT) |
||||
SHARED2 = $(SHARED1).$(SHARED_MAJOR) |
||||
SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR) |
||||
SHARED = $(SHARED1) $(SHARED2) $(SHARED3) |
||||
$(SHARED1): $(SHARED3) |
||||
ln -fs $(SHARED3) $(SHARED1) |
||||
$(SHARED2): $(SHARED3) |
||||
ln -fs $(SHARED3) $(SHARED2) |
||||
endif |
||||
|
||||
$(SHARED3): |
||||
$(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) -o $(SHARED3) |
||||
|
||||
endif # PLATFORM_SHARED_EXT
|
||||
|
||||
all: $(SHARED) $(LIBRARY) |
||||
|
||||
check: all $(PROGRAMS) $(TESTS) |
||||
for t in $(TESTS); do echo "***** Running $$t"; ./$$t || exit 1; done |
||||
|
||||
clean: |
||||
-rm -f $(PROGRAMS) $(BENCHMARKS) $(LIBRARY) $(SHARED) $(MEMENVLIBRARY) */*.o */*/*.o ios-x86/*/*.o ios-arm/*/*.o build_config.mk |
||||
-rm -rf ios-x86/* ios-arm/* |
||||
|
||||
$(LIBRARY): $(LIBOBJECTS) |
||||
rm -f $@ |
||||
$(AR) -rs $@ $(LIBOBJECTS) |
||||
|
||||
db_bench: db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) |
||||
$(CXX) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LDFLAGS) |
||||
|
||||
db_bench_sqlite3: doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) |
||||
$(CXX) doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LDFLAGS) -lsqlite3 |
||||
|
||||
db_bench_tree_db: doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) |
||||
$(CXX) doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LDFLAGS) -lkyotocabinet |
||||
|
||||
arena_test: util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
bloom_test: util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
c_test: db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
cache_test: util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
coding_test: util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
corruption_test: db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
crc32c_test: util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
db_test: db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
dbformat_test: db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
env_test: util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
filename_test: db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
filter_block_test: table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
log_test: db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
table_test: table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
skiplist_test: db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
version_edit_test: db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
version_set_test: db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
write_batch_test: db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) |
||||
$(CXX) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
$(MEMENVLIBRARY) : $(MEMENVOBJECTS) |
||||
rm -f $@ |
||||
$(AR) -rs $@ $(MEMENVOBJECTS) |
||||
|
||||
memenv_test : helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) |
||||
$(CXX) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(LDFLAGS) |
||||
|
||||
ifeq ($(PLATFORM), IOS) |
||||
# For iOS, create universal object files to be used on both the simulator and
|
||||
# a device.
|
||||
PLATFORMSROOT=/Applications/Xcode.app/Contents/Developer/Platforms |
||||
SIMULATORROOT=$(PLATFORMSROOT)/iPhoneSimulator.platform/Developer |
||||
DEVICEROOT=$(PLATFORMSROOT)/iPhoneOS.platform/Developer |
||||
IOSVERSION=$(shell defaults read $(PLATFORMSROOT)/iPhoneOS.platform/version CFBundleShortVersionString) |
||||
|
||||
.cc.o: |
||||
mkdir -p ios-x86/$(dir $@) |
||||
$(SIMULATORROOT)/usr/bin/$(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@ |
||||
mkdir -p ios-arm/$(dir $@) |
||||
$(DEVICEROOT)/usr/bin/$(CXX) $(CXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@ |
||||
lipo ios-x86/$@ ios-arm/$@ -create -output $@ |
||||
|
||||
.c.o: |
||||
mkdir -p ios-x86/$(dir $@) |
||||
$(SIMULATORROOT)/usr/bin/$(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@ |
||||
mkdir -p ios-arm/$(dir $@) |
||||
$(DEVICEROOT)/usr/bin/$(CC) $(CFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@ |
||||
lipo ios-x86/$@ ios-arm/$@ -create -output $@ |
||||
|
||||
else |
||||
.cc.o: |
||||
$(CXX) $(CXXFLAGS) -c $< -o $@ |
||||
|
||||
.c.o: |
||||
$(CC) $(CFLAGS) -c $< -o $@ |
||||
endif |
@ -0,0 +1,59 @@
@@ -0,0 +1,59 @@
|
||||
LevelDB is a third party library used for the transaction database. |
||||
It is imported into the Bitcoin codebase due to being relatively new |
||||
and not widely packaged. |
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------- |
||||
|
||||
leveldb: A key-value store |
||||
Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com) |
||||
|
||||
The code under this directory implements a system for maintaining a |
||||
persistent key/value store. |
||||
|
||||
See doc/index.html for more explanation. |
||||
See doc/impl.html for a brief overview of the implementation. |
||||
|
||||
The public interface is in include/*.h. Callers should not include or |
||||
rely on the details of any other header files in this package. Those |
||||
internal APIs may be changed without warning. |
||||
|
||||
Guide to header files: |
||||
|
||||
include/db.h |
||||
Main interface to the DB: Start here |
||||
|
||||
include/options.h |
||||
Control over the behavior of an entire database, and also |
||||
control over the behavior of individual reads and writes. |
||||
|
||||
include/comparator.h |
||||
Abstraction for user-specified comparison function. If you want |
||||
just bytewise comparison of keys, you can use the default comparator, |
||||
but clients can write their own comparator implementations if they |
||||
want custom ordering (e.g. to handle different character |
||||
encodings, etc.) |
||||
|
||||
include/iterator.h |
||||
Interface for iterating over data. You can get an iterator |
||||
from a DB object. |
||||
|
||||
include/write_batch.h |
||||
Interface for atomically applying multiple updates to a database. |
||||
|
||||
include/slice.h |
||||
A simple module for maintaining a pointer and a length into some |
||||
other byte array. |
||||
|
||||
include/status.h |
||||
Status is returned from many of the public interfaces and is used |
||||
to report success and various kinds of errors. |
||||
|
||||
include/env.h |
||||
Abstraction of the OS environment. A posix implementation of |
||||
this interface is in util/env_posix.cc |
||||
|
||||
include/table.h |
||||
include/table_builder.h |
||||
Lower-level modules that most clients probably won't use directly |
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
ss |
||||
- Stats |
||||
|
||||
db |
||||
- Maybe implement DB::BulkDeleteForRange(start_key, end_key) |
||||
that would blow away files whose ranges are entirely contained |
||||
within [start_key..end_key]? For Chrome, deletion of obsolete |
||||
object stores, etc. can be done in the background anyway, so |
||||
probably not that important. |
||||
|
||||
After a range is completely deleted, what gets rid of the |
||||
corresponding files if we do no future changes to that range. Make |
||||
the conditions for triggering compactions fire in more situations? |
@ -0,0 +1,179 @@
@@ -0,0 +1,179 @@
|
||||
#!/bin/sh |
||||
# |
||||
# Detects OS we're compiling on and outputs a file specified by the first |
||||
# argument, which in turn gets read while processing Makefile. |
||||
# |
||||
# The output will set the following variables: |
||||
# CC C Compiler path |
||||
# CXX C++ Compiler path |
||||
# PLATFORM_LDFLAGS Linker flags |
||||
# PLATFORM_SHARED_EXT Extension for shared libraries |
||||
# PLATFORM_SHARED_LDFLAGS Flags for building shared library |
||||
# PLATFORM_SHARED_CFLAGS Flags for compiling objects for shared library |
||||
# PLATFORM_CCFLAGS C compiler flags |
||||
# PLATFORM_CXXFLAGS C++ compiler flags. Will contain: |
||||
# PLATFORM_SHARED_VERSIONED Set to 'true' if platform supports versioned |
||||
# shared libraries, empty otherwise. |
||||
# |
||||
# The PLATFORM_CCFLAGS and PLATFORM_CXXFLAGS might include the following: |
||||
# |
||||
# -DLEVELDB_CSTDATOMIC_PRESENT if <cstdatomic> is present |
||||
# -DLEVELDB_PLATFORM_POSIX for Posix-based platforms |
||||
# -DSNAPPY if the Snappy library is present |
||||
# |
||||
|
||||
OUTPUT=$1 |
||||
if test -z "$OUTPUT"; then |
||||
echo "usage: $0 <output-filename>" >&2 |
||||
exit 1 |
||||
fi |
||||
|
||||
# Delete existing output, if it exists |
||||
rm -f $OUTPUT |
||||
touch $OUTPUT |
||||
|
||||
if test -z "$CC"; then |
||||
CC=cc |
||||
fi |
||||
|
||||
if test -z "$CXX"; then |
||||
CXX=g++ |
||||
fi |
||||
|
||||
# Detect OS |
||||
if test -z "$TARGET_OS"; then |
||||
TARGET_OS=`uname -s` |
||||
fi |
||||
|
||||
COMMON_FLAGS= |
||||
CROSS_COMPILE= |
||||
PLATFORM_CCFLAGS= |
||||
PLATFORM_CXXFLAGS= |
||||
PLATFORM_LDFLAGS= |
||||
PLATFORM_SHARED_EXT="so" |
||||
PLATFORM_SHARED_LDFLAGS="-shared -Wl,-soname -Wl," |
||||
PLATFORM_SHARED_CFLAGS="-fPIC" |
||||
PLATFORM_SHARED_VERSIONED=true |
||||
|
||||
# On GCC, we pick libc's memcmp over GCC's memcmp via -fno-builtin-memcmp |
||||
case "$TARGET_OS" in |
||||
Darwin) |
||||
PLATFORM=OS_MACOSX |
||||
COMMON_FLAGS="-fno-builtin-memcmp -DOS_MACOSX" |
||||
PLATFORM_SHARED_EXT=dylib |
||||
PLATFORM_SHARED_LDFLAGS="-dynamiclib -install_name " |
||||
PORT_FILE=port/port_posix.cc |
||||
;; |
||||
Linux) |
||||
PLATFORM=OS_LINUX |
||||
COMMON_FLAGS="-fno-builtin-memcmp -pthread -DOS_LINUX" |
||||
PLATFORM_LDFLAGS="-pthread" |
||||
PORT_FILE=port/port_posix.cc |
||||
;; |
||||
SunOS) |
||||
PLATFORM=OS_SOLARIS |
||||
COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_SOLARIS" |
||||
PLATFORM_LDFLAGS="-lpthread -lrt" |
||||
PORT_FILE=port/port_posix.cc |
||||
;; |
||||
FreeBSD) |
||||
PLATFORM=OS_FREEBSD |
||||
COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_FREEBSD" |
||||
PLATFORM_LDFLAGS="-lpthread" |
||||
PORT_FILE=port/port_posix.cc |
||||
;; |
||||
NetBSD) |
||||
PLATFORM=OS_NETBSD |
||||
COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_NETBSD" |
||||
PLATFORM_LDFLAGS="-lpthread -lgcc_s" |
||||
PORT_FILE=port/port_posix.cc |
||||
;; |
||||
OpenBSD) |
||||
PLATFORM=OS_OPENBSD |
||||
COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_OPENBSD" |
||||
PLATFORM_LDFLAGS="-pthread" |
||||
PORT_FILE=port/port_posix.cc |
||||
;; |
||||
DragonFly) |
||||
PLATFORM=OS_DRAGONFLYBSD |
||||
COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_DRAGONFLYBSD" |
||||
PLATFORM_LDFLAGS="-lpthread" |
||||
PORT_FILE=port/port_posix.cc |
||||
;; |
||||
OS_ANDROID_CROSSCOMPILE) |
||||
PLATFORM=OS_ANDROID |
||||
COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX" |
||||
PLATFORM_LDFLAGS="" # All pthread features are in the Android C library |
||||
PORT_FILE=port/port_posix.cc |
||||
CROSS_COMPILE=true |
||||
;; |
||||
*) |
||||
echo "Unknown platform!" >&2 |
||||
exit 1 |
||||
esac |
||||
|
||||
# We want to make a list of all cc files within util, db, table, and helpers |
||||
# except for the test and benchmark files. By default, find will output a list |
||||
# of all files matching either rule, so we need to append -print to make the |
||||
# prune take effect. |
||||
DIRS="util db table" |
||||
set -f # temporarily disable globbing so that our patterns aren't expanded |
||||
PRUNE_TEST="-name *test*.cc -prune" |
||||
PRUNE_BENCH="-name *_bench.cc -prune" |
||||
PORTABLE_FILES=`find $DIRS $PRUNE_TEST -o $PRUNE_BENCH -o -name '*.cc' -print | sort | tr "\n" " "` |
||||
set +f # re-enable globbing |
||||
|
||||
# The sources consist of the portable files, plus the platform-specific port |
||||
# file. |
||||
echo "SOURCES=$PORTABLE_FILES $PORT_FILE" >> $OUTPUT |
||||
echo "MEMENV_SOURCES=helpers/memenv/memenv.cc" >> $OUTPUT |
||||
|
||||
if [ "$CROSS_COMPILE" = "true" ]; then |
||||
# Cross-compiling; do not try any compilation tests. |
||||
true |
||||
else |
||||
# If -std=c++0x works, use <cstdatomic>. Otherwise use port_posix.h. |
||||
$CXX $CFLAGS -std=c++0x -x c++ - -o /dev/null 2>/dev/null <<EOF |
||||
#include <cstdatomic> |
||||
int main() {} |
||||
EOF |
||||
if [ "$?" = 0 ]; then |
||||
COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX -DLEVELDB_CSTDATOMIC_PRESENT" |
||||
PLATFORM_CXXFLAGS="-std=c++0x" |
||||
else |
||||
COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX" |
||||
fi |
||||
|
||||
# Test whether Snappy library is installed |
||||
# http://code.google.com/p/snappy/ |
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF |
||||
#include <snappy.h> |
||||
int main() {} |
||||
EOF |
||||
if [ "$?" = 0 ]; then |
||||
COMMON_FLAGS="$COMMON_FLAGS -DSNAPPY" |
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lsnappy" |
||||
fi |
||||
|
||||
# Test whether tcmalloc is available |
||||
$CXX $CFLAGS -x c++ - -o /dev/null -ltcmalloc 2>/dev/null <<EOF |
||||
int main() {} |
||||
EOF |
||||
if [ "$?" = 0 ]; then |
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -ltcmalloc" |
||||
fi |
||||
fi |
||||
|
||||
PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS" |
||||
PLATFORM_CXXFLAGS="$PLATFORM_CXXFLAGS $COMMON_FLAGS" |
||||
|
||||
echo "CC=$CC" >> $OUTPUT |
||||
echo "CXX=$CXX" >> $OUTPUT |
||||
echo "PLATFORM=$PLATFORM" >> $OUTPUT |
||||
echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT |
||||
echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT |
||||
echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT |
||||
echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT |
||||
echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT |
||||
echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT |
||||
echo "PLATFORM_SHARED_VERSIONED=$PLATFORM_SHARED_VERSIONED" >> $OUTPUT |
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "db/builder.h" |
||||
|
||||
#include "db/filename.h" |
||||
#include "db/dbformat.h" |
||||
#include "db/table_cache.h" |
||||
#include "db/version_edit.h" |
||||
#include "leveldb/db.h" |
||||
#include "leveldb/env.h" |
||||
#include "leveldb/iterator.h" |
||||
|
||||
namespace leveldb { |
||||
|
||||
Status BuildTable(const std::string& dbname, |
||||
Env* env, |
||||
const Options& options, |
||||
TableCache* table_cache, |
||||
Iterator* iter, |
||||
FileMetaData* meta) { |
||||
Status s; |
||||
meta->file_size = 0; |
||||
iter->SeekToFirst(); |
||||
|
||||
std::string fname = TableFileName(dbname, meta->number); |
||||
if (iter->Valid()) { |
||||
WritableFile* file; |
||||
s = env->NewWritableFile(fname, &file); |
||||
if (!s.ok()) { |
||||
return s; |
||||
} |
||||
|
||||
TableBuilder* builder = new TableBuilder(options, file); |
||||
meta->smallest.DecodeFrom(iter->key()); |
||||
for (; iter->Valid(); iter->Next()) { |
||||
Slice key = iter->key(); |
||||
meta->largest.DecodeFrom(key); |
||||
builder->Add(key, iter->value()); |
||||
} |
||||
|
||||
// Finish and check for builder errors
|
||||
if (s.ok()) { |
||||
s = builder->Finish(); |
||||
if (s.ok()) { |
||||
meta->file_size = builder->FileSize(); |
||||
assert(meta->file_size > 0); |
||||
} |
||||
} else { |
||||
builder->Abandon(); |
||||
} |
||||
delete builder; |
||||
|
||||
// Finish and check for file errors
|
||||
if (s.ok()) { |
||||
s = file->Sync(); |
||||
} |
||||
if (s.ok()) { |
||||
s = file->Close(); |
||||
} |
||||
delete file; |
||||
file = NULL; |
||||
|
||||
if (s.ok()) { |
||||
// Verify that the table is usable
|
||||
Iterator* it = table_cache->NewIterator(ReadOptions(), |
||||
meta->number, |
||||
meta->file_size); |
||||
s = it->status(); |
||||
delete it; |
||||
} |
||||
} |
||||
|
||||
// Check for input iterator errors
|
||||
if (!iter->status().ok()) { |
||||
s = iter->status(); |
||||
} |
||||
|
||||
if (s.ok() && meta->file_size > 0) { |
||||
// Keep it
|
||||
} else { |
||||
env->DeleteFile(fname); |
||||
} |
||||
return s; |
||||
} |
||||
|
||||
} // namespace leveldb
|
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_BUILDER_H_ |
||||
#define STORAGE_LEVELDB_DB_BUILDER_H_ |
||||
|
||||
#include "leveldb/status.h" |
||||
|
||||
namespace leveldb { |
||||
|
||||
struct Options; |
||||
struct FileMetaData; |
||||
|
||||
class Env; |
||||
class Iterator; |
||||
class TableCache; |
||||
class VersionEdit; |
||||
|
||||
// Build a Table file from the contents of *iter. The generated file
|
||||
// will be named according to meta->number. On success, the rest of
|
||||
// *meta will be filled with metadata about the generated table.
|
||||
// If no data is present in *iter, meta->file_size will be set to
|
||||
// zero, and no Table file will be produced.
|
||||
extern Status BuildTable(const std::string& dbname, |
||||
Env* env, |
||||
const Options& options, |
||||
TableCache* table_cache, |
||||
Iterator* iter, |
||||
FileMetaData* meta); |
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_BUILDER_H_
|
@ -0,0 +1,581 @@
@@ -0,0 +1,581 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "leveldb/c.h" |
||||
|
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include "leveldb/cache.h" |
||||
#include "leveldb/comparator.h" |
||||
#include "leveldb/db.h" |
||||
#include "leveldb/env.h" |
||||
#include "leveldb/filter_policy.h" |
||||
#include "leveldb/iterator.h" |
||||
#include "leveldb/options.h" |
||||
#include "leveldb/status.h" |
||||
#include "leveldb/write_batch.h" |
||||
|
||||
using leveldb::Cache; |
||||
using leveldb::Comparator; |
||||
using leveldb::CompressionType; |
||||
using leveldb::DB; |
||||
using leveldb::Env; |
||||
using leveldb::FileLock; |
||||
using leveldb::FilterPolicy; |
||||
using leveldb::Iterator; |
||||
using leveldb::Logger; |
||||
using leveldb::NewBloomFilterPolicy; |
||||
using leveldb::NewLRUCache; |
||||
using leveldb::Options; |
||||
using leveldb::RandomAccessFile; |
||||
using leveldb::Range; |
||||
using leveldb::ReadOptions; |
||||
using leveldb::SequentialFile; |
||||
using leveldb::Slice; |
||||
using leveldb::Snapshot; |
||||
using leveldb::Status; |
||||
using leveldb::WritableFile; |
||||
using leveldb::WriteBatch; |
||||
using leveldb::WriteOptions; |
||||
|
||||
extern "C" { |
||||
|
||||
struct leveldb_t { DB* rep; }; |
||||
struct leveldb_iterator_t { Iterator* rep; }; |
||||
struct leveldb_writebatch_t { WriteBatch rep; }; |
||||
struct leveldb_snapshot_t { const Snapshot* rep; }; |
||||
struct leveldb_readoptions_t { ReadOptions rep; }; |
||||
struct leveldb_writeoptions_t { WriteOptions rep; }; |
||||
struct leveldb_options_t { Options rep; }; |
||||
struct leveldb_cache_t { Cache* rep; }; |
||||
struct leveldb_seqfile_t { SequentialFile* rep; }; |
||||
struct leveldb_randomfile_t { RandomAccessFile* rep; }; |
||||
struct leveldb_writablefile_t { WritableFile* rep; }; |
||||
struct leveldb_logger_t { Logger* rep; }; |
||||
struct leveldb_filelock_t { FileLock* rep; }; |
||||
|
||||
struct leveldb_comparator_t : public Comparator { |
||||
void* state_; |
||||
void (*destructor_)(void*); |
||||
int (*compare_)( |
||||
void*, |
||||
const char* a, size_t alen, |
||||
const char* b, size_t blen); |
||||
const char* (*name_)(void*); |
||||
|
||||
virtual ~leveldb_comparator_t() { |
||||
(*destructor_)(state_); |
||||
} |
||||
|
||||
virtual int Compare(const Slice& a, const Slice& b) const { |
||||
return (*compare_)(state_, a.data(), a.size(), b.data(), b.size()); |
||||
} |
||||
|
||||
virtual const char* Name() const { |
||||
return (*name_)(state_); |
||||
} |
||||
|
||||
// No-ops since the C binding does not support key shortening methods.
|
||||
virtual void FindShortestSeparator(std::string*, const Slice&) const { } |
||||
virtual void FindShortSuccessor(std::string* key) const { } |
||||
}; |
||||
|
||||
struct leveldb_filterpolicy_t : public FilterPolicy { |
||||
void* state_; |
||||
void (*destructor_)(void*); |
||||
const char* (*name_)(void*); |
||||
char* (*create_)( |
||||
void*, |
||||
const char* const* key_array, const size_t* key_length_array, |
||||
int num_keys, |
||||
size_t* filter_length); |
||||
unsigned char (*key_match_)( |
||||
void*, |
||||
const char* key, size_t length, |
||||
const char* filter, size_t filter_length); |
||||
|
||||
virtual ~leveldb_filterpolicy_t() { |
||||
(*destructor_)(state_); |
||||
} |
||||
|
||||
virtual const char* Name() const { |
||||
return (*name_)(state_); |
||||
} |
||||
|
||||
virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { |
||||
std::vector<const char*> key_pointers(n); |
||||
std::vector<size_t> key_sizes(n); |
||||
for (int i = 0; i < n; i++) { |
||||
key_pointers[i] = keys[i].data(); |
||||
key_sizes[i] = keys[i].size(); |
||||
} |
||||
size_t len; |
||||
char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len); |
||||
dst->append(filter, len); |
||||
free(filter); |
||||
} |
||||
|
||||
virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { |
||||
return (*key_match_)(state_, key.data(), key.size(), |
||||
filter.data(), filter.size()); |
||||
} |
||||
}; |
||||
|
||||
struct leveldb_env_t { |
||||
Env* rep; |
||||
bool is_default; |
||||
}; |
||||
|
||||
static bool SaveError(char** errptr, const Status& s) { |
||||
assert(errptr != NULL); |
||||
if (s.ok()) { |
||||
return false; |
||||
} else if (*errptr == NULL) { |
||||
*errptr = strdup(s.ToString().c_str()); |
||||
} else { |
||||
// TODO(sanjay): Merge with existing error?
|
||||
free(*errptr); |
||||
*errptr = strdup(s.ToString().c_str()); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
static char* CopyString(const std::string& str) { |
||||
char* result = reinterpret_cast<char*>(malloc(sizeof(char) * str.size())); |
||||
memcpy(result, str.data(), sizeof(char) * str.size()); |
||||
return result; |
||||
} |
||||
|
||||
leveldb_t* leveldb_open( |
||||
const leveldb_options_t* options, |
||||
const char* name, |
||||
char** errptr) { |
||||
DB* db; |
||||
if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) { |
||||
return NULL; |
||||
} |
||||
leveldb_t* result = new leveldb_t; |
||||
result->rep = db; |
||||
return result; |
||||
} |
||||
|
||||
void leveldb_close(leveldb_t* db) { |
||||
delete db->rep; |
||||
delete db; |
||||
} |
||||
|
||||
void leveldb_put( |
||||
leveldb_t* db, |
||||
const leveldb_writeoptions_t* options, |
||||
const char* key, size_t keylen, |
||||
const char* val, size_t vallen, |
||||
char** errptr) { |
||||
SaveError(errptr, |
||||
db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen))); |
||||
} |
||||
|
||||
void leveldb_delete( |
||||
leveldb_t* db, |
||||
const leveldb_writeoptions_t* options, |
||||
const char* key, size_t keylen, |
||||
char** errptr) { |
||||
SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen))); |
||||
} |
||||
|
||||
|
||||
void leveldb_write( |
||||
leveldb_t* db, |
||||
const leveldb_writeoptions_t* options, |
||||
leveldb_writebatch_t* batch, |
||||
char** errptr) { |
||||
SaveError(errptr, db->rep->Write(options->rep, &batch->rep)); |
||||
} |
||||
|
||||
char* leveldb_get( |
||||
leveldb_t* db, |
||||
const leveldb_readoptions_t* options, |
||||
const char* key, size_t keylen, |
||||
size_t* vallen, |
||||
char** errptr) { |
||||
char* result = NULL; |
||||
std::string tmp; |
||||
Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp); |
||||
if (s.ok()) { |
||||
*vallen = tmp.size(); |
||||
result = CopyString(tmp); |
||||
} else { |
||||
*vallen = 0; |
||||
if (!s.IsNotFound()) { |
||||
SaveError(errptr, s); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
leveldb_iterator_t* leveldb_create_iterator( |
||||
leveldb_t* db, |
||||
const leveldb_readoptions_t* options) { |
||||
leveldb_iterator_t* result = new leveldb_iterator_t; |
||||
result->rep = db->rep->NewIterator(options->rep); |
||||
return result; |
||||
} |
||||
|
||||
const leveldb_snapshot_t* leveldb_create_snapshot( |
||||
leveldb_t* db) { |
||||
leveldb_snapshot_t* result = new leveldb_snapshot_t; |
||||
result->rep = db->rep->GetSnapshot(); |
||||
return result; |
||||
} |
||||
|
||||
void leveldb_release_snapshot( |
||||
leveldb_t* db, |
||||
const leveldb_snapshot_t* snapshot) { |
||||
db->rep->ReleaseSnapshot(snapshot->rep); |
||||
delete snapshot; |
||||
} |
||||
|
||||
char* leveldb_property_value( |
||||
leveldb_t* db, |
||||
const char* propname) { |
||||
std::string tmp; |
||||
if (db->rep->GetProperty(Slice(propname), &tmp)) { |
||||
// We use strdup() since we expect human readable output.
|
||||
return strdup(tmp.c_str()); |
||||
} else { |
||||
return NULL; |
||||
} |
||||
} |
||||
|
||||
void leveldb_approximate_sizes( |
||||
leveldb_t* db, |
||||
int num_ranges, |
||||
const char* const* range_start_key, const size_t* range_start_key_len, |
||||
const char* const* range_limit_key, const size_t* range_limit_key_len, |
||||
uint64_t* sizes) { |
||||
Range* ranges = new Range[num_ranges]; |
||||
for (int i = 0; i < num_ranges; i++) { |
||||
ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]); |
||||
ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]); |
||||
} |
||||
db->rep->GetApproximateSizes(ranges, num_ranges, sizes); |
||||
delete[] ranges; |
||||
} |
||||
|
||||
void leveldb_compact_range( |
||||
leveldb_t* db, |
||||
const char* start_key, size_t start_key_len, |
||||
const char* limit_key, size_t limit_key_len) { |
||||
Slice a, b; |
||||
db->rep->CompactRange( |
||||
// Pass NULL Slice if corresponding "const char*" is NULL
|
||||
(start_key ? (a = Slice(start_key, start_key_len), &a) : NULL), |
||||
(limit_key ? (b = Slice(limit_key, limit_key_len), &b) : NULL)); |
||||
} |
||||
|
||||
void leveldb_destroy_db( |
||||
const leveldb_options_t* options, |
||||
const char* name, |
||||
char** errptr) { |
||||
SaveError(errptr, DestroyDB(name, options->rep)); |
||||
} |
||||
|
||||
void leveldb_repair_db( |
||||
const leveldb_options_t* options, |
||||
const char* name, |
||||
char** errptr) { |
||||
SaveError(errptr, RepairDB(name, options->rep)); |
||||
} |
||||
|
||||
void leveldb_iter_destroy(leveldb_iterator_t* iter) { |
||||
delete iter->rep; |
||||
delete iter; |
||||
} |
||||
|
||||
unsigned char leveldb_iter_valid(const leveldb_iterator_t* iter) { |
||||
return iter->rep->Valid(); |
||||
} |
||||
|
||||
void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) { |
||||
iter->rep->SeekToFirst(); |
||||
} |
||||
|
||||
void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) { |
||||
iter->rep->SeekToLast(); |
||||
} |
||||
|
||||
void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) { |
||||
iter->rep->Seek(Slice(k, klen)); |
||||
} |
||||
|
||||
void leveldb_iter_next(leveldb_iterator_t* iter) { |
||||
iter->rep->Next(); |
||||
} |
||||
|
||||
void leveldb_iter_prev(leveldb_iterator_t* iter) { |
||||
iter->rep->Prev(); |
||||
} |
||||
|
||||
const char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) { |
||||
Slice s = iter->rep->key(); |
||||
*klen = s.size(); |
||||
return s.data(); |
||||
} |
||||
|
||||
const char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) { |
||||
Slice s = iter->rep->value(); |
||||
*vlen = s.size(); |
||||
return s.data(); |
||||
} |
||||
|
||||
void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) { |
||||
SaveError(errptr, iter->rep->status()); |
||||
} |
||||
|
||||
leveldb_writebatch_t* leveldb_writebatch_create() { |
||||
return new leveldb_writebatch_t; |
||||
} |
||||
|
||||
void leveldb_writebatch_destroy(leveldb_writebatch_t* b) { |
||||
delete b; |
||||
} |
||||
|
||||
void leveldb_writebatch_clear(leveldb_writebatch_t* b) { |
||||
b->rep.Clear(); |
||||
} |
||||
|
||||
void leveldb_writebatch_put( |
||||
leveldb_writebatch_t* b, |
||||
const char* key, size_t klen, |
||||
const char* val, size_t vlen) { |
||||
b->rep.Put(Slice(key, klen), Slice(val, vlen)); |
||||
} |
||||
|
||||
void leveldb_writebatch_delete( |
||||
leveldb_writebatch_t* b, |
||||
const char* key, size_t klen) { |
||||
b->rep.Delete(Slice(key, klen)); |
||||
} |
||||
|
||||
void leveldb_writebatch_iterate( |
||||
leveldb_writebatch_t* b, |
||||
void* state, |
||||
void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), |
||||
void (*deleted)(void*, const char* k, size_t klen)) { |
||||
class H : public WriteBatch::Handler { |
||||
public: |
||||
void* state_; |
||||
void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen); |
||||
void (*deleted_)(void*, const char* k, size_t klen); |
||||
virtual void Put(const Slice& key, const Slice& value) { |
||||
(*put_)(state_, key.data(), key.size(), value.data(), value.size()); |
||||
} |
||||
virtual void Delete(const Slice& key) { |
||||
(*deleted_)(state_, key.data(), key.size()); |
||||
} |
||||
}; |
||||
H handler; |
||||
handler.state_ = state; |
||||
handler.put_ = put; |
||||
handler.deleted_ = deleted; |
||||
b->rep.Iterate(&handler); |
||||
} |
||||
|
||||
leveldb_options_t* leveldb_options_create() { |
||||
return new leveldb_options_t; |
||||
} |
||||
|
||||
void leveldb_options_destroy(leveldb_options_t* options) { |
||||
delete options; |
||||
} |
||||
|
||||
void leveldb_options_set_comparator( |
||||
leveldb_options_t* opt, |
||||
leveldb_comparator_t* cmp) { |
||||
opt->rep.comparator = cmp; |
||||
} |
||||
|
||||
void leveldb_options_set_filter_policy( |
||||
leveldb_options_t* opt, |
||||
leveldb_filterpolicy_t* policy) { |
||||
opt->rep.filter_policy = policy; |
||||
} |
||||
|
||||
void leveldb_options_set_create_if_missing( |
||||
leveldb_options_t* opt, unsigned char v) { |
||||
opt->rep.create_if_missing = v; |
||||
} |
||||
|
||||
void leveldb_options_set_error_if_exists( |
||||
leveldb_options_t* opt, unsigned char v) { |
||||
opt->rep.error_if_exists = v; |
||||
} |
||||
|
||||
void leveldb_options_set_paranoid_checks( |
||||
leveldb_options_t* opt, unsigned char v) { |
||||
opt->rep.paranoid_checks = v; |
||||
} |
||||
|
||||
void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) { |
||||
opt->rep.env = (env ? env->rep : NULL); |
||||
} |
||||
|
||||
void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) { |
||||
opt->rep.info_log = (l ? l->rep : NULL); |
||||
} |
||||
|
||||
void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) { |
||||
opt->rep.write_buffer_size = s; |
||||
} |
||||
|
||||
void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) { |
||||
opt->rep.max_open_files = n; |
||||
} |
||||
|
||||
void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) { |
||||
opt->rep.block_cache = c->rep; |
||||
} |
||||
|
||||
void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) { |
||||
opt->rep.block_size = s; |
||||
} |
||||
|
||||
void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) { |
||||
opt->rep.block_restart_interval = n; |
||||
} |
||||
|
||||
void leveldb_options_set_compression(leveldb_options_t* opt, int t) { |
||||
opt->rep.compression = static_cast<CompressionType>(t); |
||||
} |
||||
|
||||
leveldb_comparator_t* leveldb_comparator_create( |
||||
void* state, |
||||
void (*destructor)(void*), |
||||
int (*compare)( |
||||
void*, |
||||
const char* a, size_t alen, |
||||
const char* b, size_t blen), |
||||
const char* (*name)(void*)) { |
||||
leveldb_comparator_t* result = new leveldb_comparator_t; |
||||
result->state_ = state; |
||||
result->destructor_ = destructor; |
||||
result->compare_ = compare; |
||||
result->name_ = name; |
||||
return result; |
||||
} |
||||
|
||||
void leveldb_comparator_destroy(leveldb_comparator_t* cmp) { |
||||
delete cmp; |
||||
} |
||||
|
||||
leveldb_filterpolicy_t* leveldb_filterpolicy_create( |
||||
void* state, |
||||
void (*destructor)(void*), |
||||
char* (*create_filter)( |
||||
void*, |
||||
const char* const* key_array, const size_t* key_length_array, |
||||
int num_keys, |
||||
size_t* filter_length), |
||||
unsigned char (*key_may_match)( |
||||
void*, |
||||
const char* key, size_t length, |
||||
const char* filter, size_t filter_length), |
||||
const char* (*name)(void*)) { |
||||
leveldb_filterpolicy_t* result = new leveldb_filterpolicy_t; |
||||
result->state_ = state; |
||||
result->destructor_ = destructor; |
||||
result->create_ = create_filter; |
||||
result->key_match_ = key_may_match; |
||||
result->name_ = name; |
||||
return result; |
||||
} |
||||
|
||||
void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) { |
||||
delete filter; |
||||
} |
||||
|
||||
leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_key) { |
||||
// Make a leveldb_filterpolicy_t, but override all of its methods so
|
||||
// they delegate to a NewBloomFilterPolicy() instead of user
|
||||
// supplied C functions.
|
||||
struct Wrapper : public leveldb_filterpolicy_t { |
||||
const FilterPolicy* rep_; |
||||
~Wrapper() { delete rep_; } |
||||
const char* Name() const { return rep_->Name(); } |
||||
void CreateFilter(const Slice* keys, int n, std::string* dst) const { |
||||
return rep_->CreateFilter(keys, n, dst); |
||||
} |
||||
bool KeyMayMatch(const Slice& key, const Slice& filter) const { |
||||
return rep_->KeyMayMatch(key, filter); |
||||
} |
||||
static void DoNothing(void*) { } |
||||
}; |
||||
Wrapper* wrapper = new Wrapper; |
||||
wrapper->rep_ = NewBloomFilterPolicy(bits_per_key); |
||||
wrapper->state_ = NULL; |
||||
wrapper->destructor_ = &Wrapper::DoNothing; |
||||
return wrapper; |
||||
} |
||||
|
||||
leveldb_readoptions_t* leveldb_readoptions_create() { |
||||
return new leveldb_readoptions_t; |
||||
} |
||||
|
||||
void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { |
||||
delete opt; |
||||
} |
||||
|
||||
void leveldb_readoptions_set_verify_checksums( |
||||
leveldb_readoptions_t* opt, |
||||
unsigned char v) { |
||||
opt->rep.verify_checksums = v; |
||||
} |
||||
|
||||
void leveldb_readoptions_set_fill_cache( |
||||
leveldb_readoptions_t* opt, unsigned char v) { |
||||
opt->rep.fill_cache = v; |
||||
} |
||||
|
||||
void leveldb_readoptions_set_snapshot( |
||||
leveldb_readoptions_t* opt, |
||||
const leveldb_snapshot_t* snap) { |
||||
opt->rep.snapshot = (snap ? snap->rep : NULL); |
||||
} |
||||
|
||||
leveldb_writeoptions_t* leveldb_writeoptions_create() { |
||||
return new leveldb_writeoptions_t; |
||||
} |
||||
|
||||
void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { |
||||
delete opt; |
||||
} |
||||
|
||||
void leveldb_writeoptions_set_sync( |
||||
leveldb_writeoptions_t* opt, unsigned char v) { |
||||
opt->rep.sync = v; |
||||
} |
||||
|
||||
leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) { |
||||
leveldb_cache_t* c = new leveldb_cache_t; |
||||
c->rep = NewLRUCache(capacity); |
||||
return c; |
||||
} |
||||
|
||||
void leveldb_cache_destroy(leveldb_cache_t* cache) { |
||||
delete cache->rep; |
||||
delete cache; |
||||
} |
||||
|
||||
leveldb_env_t* leveldb_create_default_env() { |
||||
leveldb_env_t* result = new leveldb_env_t; |
||||
result->rep = Env::Default(); |
||||
result->is_default = true; |
||||
return result; |
||||
} |
||||
|
||||
void leveldb_env_destroy(leveldb_env_t* env) { |
||||
if (!env->is_default) delete env->rep; |
||||
delete env; |
||||
} |
||||
|
||||
} // end extern "C"
|
@ -0,0 +1,381 @@
@@ -0,0 +1,381 @@
|
||||
/* Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style license that can be |
||||
found in the LICENSE file. See the AUTHORS file for names of contributors. */ |
||||
|
||||
#include "leveldb/c.h" |
||||
|
||||
#include <stddef.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <sys/types.h> |
||||
#include <unistd.h> |
||||
|
||||
const char* phase = ""; |
||||
static char dbname[200]; |
||||
|
||||
static void StartPhase(const char* name) { |
||||
fprintf(stderr, "=== Test %s\n", name); |
||||
phase = name; |
||||
} |
||||
|
||||
static const char* GetTempDir(void) { |
||||
const char* ret = getenv("TEST_TMPDIR"); |
||||
if (ret == NULL || ret[0] == '\0') |
||||
ret = "/tmp"; |
||||
return ret; |
||||
} |
||||
|
||||
#define CheckNoError(err) \ |
||||
if ((err) != NULL) { \ |
||||
fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \ |
||||
abort(); \ |
||||
} |
||||
|
||||
#define CheckCondition(cond) \ |
||||
if (!(cond)) { \ |
||||
fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, #cond); \ |
||||
abort(); \ |
||||
} |
||||
|
||||
static void CheckEqual(const char* expected, const char* v, size_t n) { |
||||
if (expected == NULL && v == NULL) { |
||||
// ok
|
||||
} else if (expected != NULL && v != NULL && n == strlen(expected) && |
||||
memcmp(expected, v, n) == 0) { |
||||
// ok
|
||||
return; |
||||
} else { |
||||
fprintf(stderr, "%s: expected '%s', got '%s'\n", |
||||
phase, |
||||
(expected ? expected : "(null)"), |
||||
(v ? v : "(null")); |
||||
abort(); |
||||
} |
||||
} |
||||
|
||||
static void Free(char** ptr) { |
||||
if (*ptr) { |
||||
free(*ptr); |
||||
*ptr = NULL; |
||||
} |
||||
} |
||||
|
||||
static void CheckGet( |
||||
leveldb_t* db, |
||||
const leveldb_readoptions_t* options, |
||||
const char* key, |
||||
const char* expected) { |
||||
char* err = NULL; |
||||
size_t val_len; |
||||
char* val; |
||||
val = leveldb_get(db, options, key, strlen(key), &val_len, &err); |
||||
CheckNoError(err); |
||||
CheckEqual(expected, val, val_len); |
||||
Free(&val); |
||||
} |
||||
|
||||
static void CheckIter(leveldb_iterator_t* iter, |
||||
const char* key, const char* val) { |
||||
size_t len; |
||||
const char* str; |
||||
str = leveldb_iter_key(iter, &len); |
||||
CheckEqual(key, str, len); |
||||
str = leveldb_iter_value(iter, &len); |
||||
CheckEqual(val, str, len); |
||||
} |
||||
|
||||
// Callback from leveldb_writebatch_iterate()
|
||||
static void CheckPut(void* ptr, |
||||
const char* k, size_t klen, |
||||
const char* v, size_t vlen) { |
||||
int* state = (int*) ptr; |
||||
CheckCondition(*state < 2); |
||||
switch (*state) { |
||||
case 0: |
||||
CheckEqual("bar", k, klen); |
||||
CheckEqual("b", v, vlen); |
||||
break; |
||||
case 1: |
||||
CheckEqual("box", k, klen); |
||||
CheckEqual("c", v, vlen); |
||||
break; |
||||
} |
||||
(*state)++; |
||||
} |
||||
|
||||
// Callback from leveldb_writebatch_iterate()
|
||||
static void CheckDel(void* ptr, const char* k, size_t klen) { |
||||
int* state = (int*) ptr; |
||||
CheckCondition(*state == 2); |
||||
CheckEqual("bar", k, klen); |
||||
(*state)++; |
||||
} |
||||
|
||||
static void CmpDestroy(void* arg) { } |
||||
|
||||
static int CmpCompare(void* arg, const char* a, size_t alen, |
||||
const char* b, size_t blen) { |
||||
int n = (alen < blen) ? alen : blen; |
||||
int r = memcmp(a, b, n); |
||||
if (r == 0) { |
||||
if (alen < blen) r = -1; |
||||
else if (alen > blen) r = +1; |
||||
} |
||||
return r; |
||||
} |
||||
|
||||
static const char* CmpName(void* arg) { |
||||
return "foo"; |
||||
} |
||||
|
||||
// Custom filter policy
|
||||
static unsigned char fake_filter_result = 1; |
||||
static void FilterDestroy(void* arg) { } |
||||
static const char* FilterName(void* arg) { |
||||
return "TestFilter"; |
||||
} |
||||
static char* FilterCreate( |
||||
void* arg, |
||||
const char* const* key_array, const size_t* key_length_array, |
||||
int num_keys, |
||||
size_t* filter_length) { |
||||
*filter_length = 4; |
||||
char* result = malloc(4); |
||||
memcpy(result, "fake", 4); |
||||
return result; |
||||
} |
||||
unsigned char FilterKeyMatch( |
||||
void* arg, |
||||
const char* key, size_t length, |
||||
const char* filter, size_t filter_length) { |
||||
CheckCondition(filter_length == 4); |
||||
CheckCondition(memcmp(filter, "fake", 4) == 0); |
||||
return fake_filter_result; |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
leveldb_t* db; |
||||
leveldb_comparator_t* cmp; |
||||
leveldb_cache_t* cache; |
||||
leveldb_env_t* env; |
||||
leveldb_options_t* options; |
||||
leveldb_readoptions_t* roptions; |
||||
leveldb_writeoptions_t* woptions; |
||||
char* err = NULL; |
||||
int run = -1; |
||||
|
||||
snprintf(dbname, sizeof(dbname), |
||||
"%s/leveldb_c_test-%d", |
||||
GetTempDir(), |
||||
((int) geteuid())); |
||||
|
||||
StartPhase("create_objects"); |
||||
cmp = leveldb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName); |
||||
env = leveldb_create_default_env(); |
||||
cache = leveldb_cache_create_lru(100000); |
||||
|
||||
options = leveldb_options_create(); |
||||
leveldb_options_set_comparator(options, cmp); |
||||
leveldb_options_set_error_if_exists(options, 1); |
||||
leveldb_options_set_cache(options, cache); |
||||
leveldb_options_set_env(options, env); |
||||
leveldb_options_set_info_log(options, NULL); |
||||
leveldb_options_set_write_buffer_size(options, 100000); |
||||
leveldb_options_set_paranoid_checks(options, 1); |
||||
leveldb_options_set_max_open_files(options, 10); |
||||
leveldb_options_set_block_size(options, 1024); |
||||
leveldb_options_set_block_restart_interval(options, 8); |
||||
leveldb_options_set_compression(options, leveldb_no_compression); |
||||
|
||||
roptions = leveldb_readoptions_create(); |
||||
leveldb_readoptions_set_verify_checksums(roptions, 1); |
||||
leveldb_readoptions_set_fill_cache(roptions, 0); |
||||
|
||||
woptions = leveldb_writeoptions_create(); |
||||
leveldb_writeoptions_set_sync(woptions, 1); |
||||
|
||||
StartPhase("destroy"); |
||||
leveldb_destroy_db(options, dbname, &err); |
||||
Free(&err); |
||||
|
||||
StartPhase("open_error"); |
||||
db = leveldb_open(options, dbname, &err); |
||||
CheckCondition(err != NULL); |
||||
Free(&err); |
||||
|
||||
StartPhase("open"); |
||||
leveldb_options_set_create_if_missing(options, 1); |
||||
db = leveldb_open(options, dbname, &err); |
||||
CheckNoError(err); |
||||
CheckGet(db, roptions, "foo", NULL); |
||||
|
||||
StartPhase("put"); |
||||
leveldb_put(db, woptions, "foo", 3, "hello", 5, &err); |
||||
CheckNoError(err); |
||||
CheckGet(db, roptions, "foo", "hello"); |
||||
|
||||
StartPhase("compactall"); |
||||
leveldb_compact_range(db, NULL, 0, NULL, 0); |
||||
CheckGet(db, roptions, "foo", "hello"); |
||||
|
||||
StartPhase("compactrange"); |
||||
leveldb_compact_range(db, "a", 1, "z", 1); |
||||
CheckGet(db, roptions, "foo", "hello"); |
||||
|
||||
StartPhase("writebatch"); |
||||
{ |
||||
leveldb_writebatch_t* wb = leveldb_writebatch_create(); |
||||
leveldb_writebatch_put(wb, "foo", 3, "a", 1); |
||||
leveldb_writebatch_clear(wb); |
||||
leveldb_writebatch_put(wb, "bar", 3, "b", 1); |
||||
leveldb_writebatch_put(wb, "box", 3, "c", 1); |
||||
leveldb_writebatch_delete(wb, "bar", 3); |
||||
leveldb_write(db, woptions, wb, &err); |
||||
CheckNoError(err); |
||||
CheckGet(db, roptions, "foo", "hello"); |
||||
CheckGet(db, roptions, "bar", NULL); |
||||
CheckGet(db, roptions, "box", "c"); |
||||
int pos = 0; |
||||
leveldb_writebatch_iterate(wb, &pos, CheckPut, CheckDel); |
||||
CheckCondition(pos == 3); |
||||
leveldb_writebatch_destroy(wb); |
||||
} |
||||
|
||||
StartPhase("iter"); |
||||