Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Use leveldb 1.9.0 (Jan 2013).

  • Loading branch information...
commit e0e256c30a1b7c0ed3ba546db6b73ffeb6c7b719 1 parent d1ac83b
Linmiao Xu authored February 24, 2013

Showing 33 changed files with 3,536 additions and 104 deletions. Show diff stats Hide diff stats

  1. 3  leveldb/.gitignore
  2. 64  leveldb/Makefile
  3. 1  leveldb/TODO
  4. 70  leveldb/build_detect_platform
  5. 14  leveldb/db/c.cc
  6. 9  leveldb/db/c_test.c
  7. 1  leveldb/db/db_bench.cc
  8. 6  leveldb/db/db_impl.cc
  9. 28  leveldb/db/db_impl.h
  10. 81  leveldb/db/db_test.cc
  11. 238  leveldb/db/leveldb_main.cc
  12. 38  leveldb/db/version_set.cc
  13. 6  leveldb/db/version_set.h
  14. 718  leveldb/doc/bench/db_bench_sqlite3.cc
  15. 528  leveldb/doc/bench/db_bench_tree_db.cc
  16. 459  leveldb/doc/benchmark.html
  17. 89  leveldb/doc/doc.css
  18. 213  leveldb/doc/impl.html
  19. 549  leveldb/doc/index.html
  20. 75  leveldb/doc/log_format.txt
  21. 104  leveldb/doc/table_format.txt
  22. 10  leveldb/helpers/memenv/memenv.cc
  23. 16  leveldb/include/leveldb/c.h
  24. 2  leveldb/include/leveldb/db.h
  25. 10  leveldb/include/leveldb/env.h
  26. 72  leveldb/port/atomic_pointer.h
  27. 19  leveldb/port/port_posix.h
  28. 59  leveldb/port/thread_annotations.h
  29. 4  leveldb/table/block.cc
  30. 5  leveldb/util/bloom_test.cc
  31. 40  leveldb/util/coding.cc
  32. 101  leveldb/util/env_posix.cc
  33. 8  leveldb/util/mutexlock.h
3  leveldb/.gitignore
... ...
@@ -1,5 +1,8 @@
1 1
 build_config.mk
2 2
 *.a
3 3
 *.o
  4
+*.dylib*
  5
+*.so
  6
+*.so.*
4 7
 *_test
5 8
 db_bench
64  leveldb/Makefile
@@ -2,9 +2,6 @@
2 2
 # Use of this source code is governed by a BSD-style license that can be
3 3
 # found in the LICENSE file. See the AUTHORS file for names of contributors.
4 4
 
5  
-# Inherit some settings from environment variables, if available
6  
-INSTALL_PATH ?= $(CURDIR)
7  
-
8 5
 #-----------------------------------------------
9 6
 # Uncomment exactly one of the lines labelled (A), (B), and (C) below
10 7
 # to switch between compilation modes.
@@ -15,7 +12,8 @@ OPT ?= -O2 -DNDEBUG       # (A) Production use (optimized mode)
15 12
 #-----------------------------------------------
16 13
 
17 14
 # detect what platform we're building on
18  
-$(shell ./build_detect_platform build_config.mk)
  15
+$(shell CC=$(CC) CXX=$(CXX) TARGET_OS=$(TARGET_OS) \
  16
+    ./build_detect_platform build_config.mk ./)
19 17
 # this file is generated by the previous line to set build flags and sources
20 18
 include build_config.mk
21 19
 
@@ -23,6 +21,7 @@ CFLAGS += -I. -I./include $(PLATFORM_CCFLAGS) $(OPT)
23 21
 CXXFLAGS += -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT)
24 22
 
25 23
 LDFLAGS += $(PLATFORM_LDFLAGS)
  24
+LIBS += $(PLATFORM_LIBS)
26 25
 
27 26
 LIBOBJECTS = $(SOURCES:.cc=.o)
28 27
 MEMENVOBJECTS = $(MEMENV_SOURCES:.cc=.o)
@@ -51,7 +50,7 @@ TESTS = \
51 50
 	version_set_test \
52 51
 	write_batch_test
53 52
 
54  
-PROGRAMS = db_bench $(TESTS)
  53
+PROGRAMS = db_bench leveldbutil $(TESTS)
55 54
 BENCHMARKS = db_bench_sqlite3 db_bench_tree_db
56 55
 
57 56
 LIBRARY = libleveldb.a
@@ -70,7 +69,7 @@ SHARED = $(SHARED1)
70 69
 else
71 70
 # Update db.h if you change these.
72 71
 SHARED_MAJOR = 1
73  
-SHARED_MINOR = 5
  72
+SHARED_MINOR = 9
74 73
 SHARED1 = libleveldb.$(PLATFORM_SHARED_EXT)
75 74
 SHARED2 = $(SHARED1).$(SHARED_MAJOR)
76 75
 SHARED3 = $(SHARED1).$(SHARED_MAJOR).$(SHARED_MINOR)
@@ -82,7 +81,7 @@ $(SHARED2): $(SHARED3)
82 81
 endif
83 82
 
84 83
 $(SHARED3):
85  
-	$(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) -o $(SHARED3)
  84
+	$(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) -o $(SHARED3) $(LIBS)
86 85
 
87 86
 endif  # PLATFORM_SHARED_EXT
88 87
 
@@ -100,74 +99,77 @@ $(LIBRARY): $(LIBOBJECTS)
100 99
 	$(AR) -rs $@ $(LIBOBJECTS)
101 100
 
102 101
 db_bench: db/db_bench.o $(LIBOBJECTS) $(TESTUTIL)
103  
-	$(CXX) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@  $(LDFLAGS)
  102
+	$(CXX) $(LDFLAGS) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LIBS)
104 103
 
105 104
 db_bench_sqlite3: doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL)
106  
-	$(CXX) doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LDFLAGS) -lsqlite3
  105
+	$(CXX) $(LDFLAGS) doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) -o $@ -lsqlite3 $(LIBS)
107 106
 
108 107
 db_bench_tree_db: doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL)
109  
-	$(CXX) doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LDFLAGS) -lkyotocabinet
  108
+	$(CXX) $(LDFLAGS) doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) -o $@ -lkyotocabinet $(LIBS)
  109
+
  110
+leveldbutil: db/leveldb_main.o $(LIBOBJECTS)
  111
+	$(CXX) $(LDFLAGS) db/leveldb_main.o $(LIBOBJECTS) -o $@ $(LIBS)
110 112
 
111 113
 arena_test: util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS)
112  
-	$(CXX) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  114
+	$(CXX) $(LDFLAGS) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
113 115
 
114 116
 bloom_test: util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS)
115  
-	$(CXX) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  117
+	$(CXX) $(LDFLAGS) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
116 118
 
117 119
 c_test: db/c_test.o $(LIBOBJECTS) $(TESTHARNESS)
118  
-	$(CXX) db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  120
+	$(CXX) $(LDFLAGS) db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
119 121
 
120 122
 cache_test: util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS)
121  
-	$(CXX) util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  123
+	$(CXX) $(LDFLAGS) util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
122 124
 
123 125
 coding_test: util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS)
124  
-	$(CXX) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  126
+	$(CXX) $(LDFLAGS) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
125 127
 
126 128
 corruption_test: db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS)
127  
-	$(CXX) db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  129
+	$(CXX) $(LDFLAGS) db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
128 130
 
129 131
 crc32c_test: util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS)
130  
-	$(CXX) util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  132
+	$(CXX) $(LDFLAGS) util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
131 133
 
132 134
 db_test: db/db_test.o $(LIBOBJECTS) $(TESTHARNESS)
133  
-	$(CXX) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  135
+	$(CXX) $(LDFLAGS) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
134 136
 
135 137
 dbformat_test: db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS)
136  
-	$(CXX) db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  138
+	$(CXX) $(LDFLAGS) db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
137 139
 
138 140
 env_test: util/env_test.o $(LIBOBJECTS) $(TESTHARNESS)
139  
-	$(CXX) util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  141
+	$(CXX) $(LDFLAGS) util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
140 142
 
141 143
 filename_test: db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS)
142  
-	$(CXX) db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  144
+	$(CXX) $(LDFLAGS) db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
143 145
 
144 146
 filter_block_test: table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS)
145  
-	$(CXX) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  147
+	$(CXX) $(LDFLAGS) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
146 148
 
147 149
 log_test: db/log_test.o $(LIBOBJECTS) $(TESTHARNESS)
148  
-	$(CXX) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  150
+	$(CXX) $(LDFLAGS) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
149 151
 
150 152
 table_test: table/table_test.o $(LIBOBJECTS) $(TESTHARNESS)
151  
-	$(CXX) table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  153
+	$(CXX) $(LDFLAGS) table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
152 154
 
153 155
 skiplist_test: db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS)
154  
-	$(CXX) db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  156
+	$(CXX) $(LDFLAGS) db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
155 157
 
156 158
 version_edit_test: db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS)
157  
-	$(CXX) db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  159
+	$(CXX) $(LDFLAGS) db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
158 160
 
159 161
 version_set_test: db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS)
160  
-	$(CXX) db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  162
+	$(CXX) $(LDFLAGS) db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
161 163
 
162 164
 write_batch_test: db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS)
163  
-	$(CXX) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS)
  165
+	$(CXX) $(LDFLAGS) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LIBS)
164 166
 
165 167
 $(MEMENVLIBRARY) : $(MEMENVOBJECTS)
166 168
 	rm -f $@
167 169
 	$(AR) -rs $@ $(MEMENVOBJECTS)
168 170
 
169 171
 memenv_test : helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS)
170  
-	$(CXX) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(LDFLAGS)
  172
+	$(CXX) $(LDFLAGS) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(LIBS)
171 173
 
172 174
 ifeq ($(PLATFORM), IOS)
173 175
 # For iOS, create universal object files to be used on both the simulator and
@@ -179,14 +181,14 @@ IOSVERSION=$(shell defaults read $(PLATFORMSROOT)/iPhoneOS.platform/version CFBu
179 181
 
180 182
 .cc.o:
181 183
 	mkdir -p ios-x86/$(dir $@)
182  
-	$(SIMULATORROOT)/usr/bin/$(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@
  184
+	$(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@
183 185
 	mkdir -p ios-arm/$(dir $@)
184 186
 	$(DEVICEROOT)/usr/bin/$(CXX) $(CXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@
185 187
 	lipo ios-x86/$@ ios-arm/$@ -create -output $@
186 188
 
187 189
 .c.o:
188 190
 	mkdir -p ios-x86/$(dir $@)
189  
-	$(SIMULATORROOT)/usr/bin/$(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@
  191
+	$(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@
190 192
 	mkdir -p ios-arm/$(dir $@)
191 193
 	$(DEVICEROOT)/usr/bin/$(CC) $(CFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@
192 194
 	lipo ios-x86/$@ ios-arm/$@ -create -output $@
1  leveldb/TODO
@@ -7,6 +7,7 @@ db
7 7
   within [start_key..end_key]?  For Chrome, deletion of obsolete
8 8
   object stores, etc. can be done in the background anyway, so
9 9
   probably not that important.
  10
+- There have been requests for MultiGet.
10 11
 
11 12
 After a range is completely deleted, what gets rid of the
12 13
 corresponding files if we do no future changes to that range.  Make
70  leveldb/build_detect_platform
@@ -7,8 +7,11 @@
7 7
 #   CC                          C Compiler path
8 8
 #   CXX                         C++ Compiler path
9 9
 #   PLATFORM_LDFLAGS            Linker flags
  10
+#   PLATFORM_LIBS               Libraries flags
10 11
 #   PLATFORM_SHARED_EXT         Extension for shared libraries
11 12
 #   PLATFORM_SHARED_LDFLAGS     Flags for building shared library
  13
+#                               This flag is embedded just before the name
  14
+#                               of the shared library without intervening spaces
12 15
 #   PLATFORM_SHARED_CFLAGS      Flags for compiling objects for shared library
13 16
 #   PLATFORM_CCFLAGS            C compiler flags
14 17
 #   PLATFORM_CXXFLAGS           C++ compiler flags.  Will contain:
@@ -23,8 +26,9 @@
23 26
 #
24 27
 
25 28
 OUTPUT=$1
26  
-if test -z "$OUTPUT"; then
27  
-  echo "usage: $0 <output-filename>" >&2
  29
+PREFIX=$2
  30
+if test -z "$OUTPUT" || test -z "$PREFIX"; then
  31
+  echo "usage: $0 <output-filename> <directory_prefix>" >&2
28 32
   exit 1
29 33
 fi
30 34
 
@@ -50,63 +54,79 @@ CROSS_COMPILE=
50 54
 PLATFORM_CCFLAGS=
51 55
 PLATFORM_CXXFLAGS=
52 56
 PLATFORM_LDFLAGS=
  57
+PLATFORM_LIBS=
53 58
 PLATFORM_SHARED_EXT="so"
54 59
 PLATFORM_SHARED_LDFLAGS="-shared -Wl,-soname -Wl,"
55 60
 PLATFORM_SHARED_CFLAGS="-fPIC"
56 61
 PLATFORM_SHARED_VERSIONED=true
57 62
 
58  
-# On GCC, we pick libc's memcmp over GCC's memcmp via -fno-builtin-memcmp
  63
+MEMCMP_FLAG=
  64
+if [ "$CXX" = "g++" ]; then
  65
+    # Use libc's memcmp instead of GCC's memcmp.  This results in ~40%
  66
+    # performance improvement on readrandom under gcc 4.4.3 on Linux/x86.
  67
+    MEMCMP_FLAG="-fno-builtin-memcmp"
  68
+fi
  69
+
59 70
 case "$TARGET_OS" in
60 71
     Darwin)
61 72
         PLATFORM=OS_MACOSX
62  
-        COMMON_FLAGS="-fno-builtin-memcmp -DOS_MACOSX"
  73
+        COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX"
63 74
         PLATFORM_SHARED_EXT=dylib
64  
-        PLATFORM_SHARED_LDFLAGS="-dynamiclib -install_name "
  75
+        [ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd`
  76
+        PLATFORM_SHARED_LDFLAGS="-dynamiclib -install_name $INSTALL_PATH/"
65 77
         PORT_FILE=port/port_posix.cc
66 78
         ;;
67 79
     Linux)
68 80
         PLATFORM=OS_LINUX
69  
-        COMMON_FLAGS="-fno-builtin-memcmp -pthread -DOS_LINUX"
  81
+        COMMON_FLAGS="$MEMCMP_FLAG -pthread -DOS_LINUX"
70 82
         PLATFORM_LDFLAGS="-pthread"
71 83
         PORT_FILE=port/port_posix.cc
72 84
         ;;
73 85
     SunOS)
74 86
         PLATFORM=OS_SOLARIS
75  
-        COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_SOLARIS"
76  
-        PLATFORM_LDFLAGS="-lpthread -lrt"
  87
+        COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_SOLARIS"
  88
+        PLATFORM_LIBS="-lpthread -lrt"
77 89
         PORT_FILE=port/port_posix.cc
78 90
         ;;
79 91
     FreeBSD)
80 92
         PLATFORM=OS_FREEBSD
81  
-        COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_FREEBSD"
82  
-        PLATFORM_LDFLAGS="-lpthread"
  93
+        COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_FREEBSD"
  94
+        PLATFORM_LIBS="-lpthread"
83 95
         PORT_FILE=port/port_posix.cc
84 96
         ;;
85 97
     NetBSD)
86 98
         PLATFORM=OS_NETBSD
87  
-        COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_NETBSD"
88  
-        PLATFORM_LDFLAGS="-lpthread -lgcc_s"
  99
+        COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_NETBSD"
  100
+        PLATFORM_LIBS="-lpthread -lgcc_s"
89 101
         PORT_FILE=port/port_posix.cc
90 102
         ;;
91 103
     OpenBSD)
92 104
         PLATFORM=OS_OPENBSD
93  
-        COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_OPENBSD"
  105
+        COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_OPENBSD"
94 106
         PLATFORM_LDFLAGS="-pthread"
95 107
         PORT_FILE=port/port_posix.cc
96 108
         ;;
97 109
     DragonFly)
98 110
         PLATFORM=OS_DRAGONFLYBSD
99  
-        COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_DRAGONFLYBSD"
100  
-        PLATFORM_LDFLAGS="-lpthread"
  111
+        COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_DRAGONFLYBSD"
  112
+        PLATFORM_LIBS="-lpthread"
101 113
         PORT_FILE=port/port_posix.cc
102 114
         ;;
103 115
     OS_ANDROID_CROSSCOMPILE)
104 116
         PLATFORM=OS_ANDROID
105  
-        COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX"
  117
+        COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX"
106 118
         PLATFORM_LDFLAGS=""  # All pthread features are in the Android C library
107 119
         PORT_FILE=port/port_posix.cc
108 120
         CROSS_COMPILE=true
109 121
         ;;
  122
+    HP-UX)
  123
+        PLATFORM=OS_HPUX
  124
+        COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_HPUX"
  125
+        PLATFORM_LDFLAGS="-pthread"
  126
+        PORT_FILE=port/port_posix.cc
  127
+        # man ld: +h internal_name
  128
+        PLATFORM_SHARED_LDFLAGS="-shared -Wl,+h -Wl,"
  129
+        ;;
110 130
     *)
111 131
         echo "Unknown platform!" >&2
112 132
         exit 1
@@ -116,11 +136,14 @@ esac
116 136
 # except for the test and benchmark files. By default, find will output a list
117 137
 # of all files matching either rule, so we need to append -print to make the
118 138
 # prune take effect.
119  
-DIRS="util db table"
  139
+DIRS="$PREFIX/db $PREFIX/util $PREFIX/table"
  140
+
120 141
 set -f # temporarily disable globbing so that our patterns aren't expanded
121 142
 PRUNE_TEST="-name *test*.cc -prune"
122 143
 PRUNE_BENCH="-name *_bench.cc -prune"
123  
-PORTABLE_FILES=`find $DIRS $PRUNE_TEST -o $PRUNE_BENCH -o -name '*.cc' -print | sort | tr "\n" " "`
  144
+PRUNE_TOOL="-name leveldb_main.cc -prune"
  145
+PORTABLE_FILES=`find $DIRS $PRUNE_TEST -o $PRUNE_BENCH -o $PRUNE_TOOL -o -name '*.cc' -print | sort | sed "s,^$PREFIX/,," | tr "\n" " "`
  146
+
124 147
 set +f # re-enable globbing
125 148
 
126 149
 # The sources consist of the portable files, plus the platform-specific port
@@ -133,7 +156,7 @@ if [ "$CROSS_COMPILE" = "true" ]; then
133 156
     true
134 157
 else
135 158
     # If -std=c++0x works, use <cstdatomic>.  Otherwise use port_posix.h.
136  
-    $CXX $CFLAGS -std=c++0x -x c++ - -o /dev/null 2>/dev/null  <<EOF
  159
+    $CXX $CXXFLAGS -std=c++0x -x c++ - -o /dev/null 2>/dev/null  <<EOF
137 160
       #include <cstdatomic>
138 161
       int main() {}
139 162
 EOF
@@ -146,21 +169,21 @@ EOF
146 169
 
147 170
     # Test whether Snappy library is installed
148 171
     # http://code.google.com/p/snappy/
149  
-    $CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null  <<EOF
  172
+    $CXX $CXXFLAGS -x c++ - -o /dev/null 2>/dev/null  <<EOF
150 173
       #include <snappy.h>
151 174
       int main() {}
152 175
 EOF
153 176
     if [ "$?" = 0 ]; then
154 177
         COMMON_FLAGS="$COMMON_FLAGS -DSNAPPY"
155  
-        PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lsnappy"
  178
+        PLATFORM_LIBS="$PLATFORM_LIBS -lsnappy"
156 179
     fi
157 180
 
158 181
     # Test whether tcmalloc is available
159  
-    $CXX $CFLAGS -x c++ - -o /dev/null -ltcmalloc 2>/dev/null  <<EOF
  182
+    $CXX $CXXFLAGS -x c++ - -o /dev/null -ltcmalloc 2>/dev/null  <<EOF
160 183
       int main() {}
161 184
 EOF
162 185
     if [ "$?" = 0 ]; then
163  
-        PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -ltcmalloc"
  186
+        PLATFORM_LIBS="$PLATFORM_LIBS -ltcmalloc"
164 187
     fi
165 188
 fi
166 189
 
@@ -171,6 +194,7 @@ echo "CC=$CC" >> $OUTPUT
171 194
 echo "CXX=$CXX" >> $OUTPUT
172 195
 echo "PLATFORM=$PLATFORM" >> $OUTPUT
173 196
 echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT
  197
+echo "PLATFORM_LIBS=$PLATFORM_LIBS" >> $OUTPUT
174 198
 echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT
175 199
 echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT
176 200
 echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT
14  leveldb/db/c.cc
@@ -24,6 +24,8 @@ using leveldb::Env;
24 24
 using leveldb::FileLock;
25 25
 using leveldb::FilterPolicy;
26 26
 using leveldb::Iterator;
  27
+using leveldb::kMajorVersion;
  28
+using leveldb::kMinorVersion;
27 29
 using leveldb::Logger;
28 30
 using leveldb::NewBloomFilterPolicy;
29 31
 using leveldb::NewLRUCache;
@@ -578,4 +580,16 @@ void leveldb_env_destroy(leveldb_env_t* env) {
578 580
   delete env;
579 581
 }
580 582
 
  583
+void leveldb_free(void* ptr) {
  584
+  free(ptr);
  585
+}
  586
+
  587
+int leveldb_major_version() {
  588
+  return kMajorVersion;
  589
+}
  590
+
  591
+int leveldb_minor_version() {
  592
+  return kMinorVersion;
  593
+}
  594
+
581 595
 }  // end extern "C"
9  leveldb/db/c_test.c
@@ -165,6 +165,9 @@ int main(int argc, char** argv) {
165 165
   char* err = NULL;
166 166
   int run = -1;
167 167
 
  168
+  CheckCondition(leveldb_major_version() >= 1);
  169
+  CheckCondition(leveldb_minor_version() >= 1);
  170
+
168 171
   snprintf(dbname, sizeof(dbname),
169 172
            "%s/leveldb_c_test-%d",
170 173
            GetTempDir(),
@@ -204,6 +207,12 @@ int main(int argc, char** argv) {
204 207
   CheckCondition(err != NULL);
205 208
   Free(&err);
206 209
 
  210
+  StartPhase("leveldb_free");
  211
+  db = leveldb_open(options, dbname, &err);
  212
+  CheckCondition(err != NULL);
  213
+  leveldb_free(err);
  214
+  err = NULL;
  215
+
207 216
   StartPhase("open");
208 217
   leveldb_options_set_create_if_missing(options, 1);
209 218
   db = leveldb_open(options, dbname, &err);
1  leveldb/db/db_bench.cc
@@ -693,6 +693,7 @@ class Benchmark {
693 693
     options.create_if_missing = !FLAGS_use_existing_db;
694 694
     options.block_cache = cache_;
695 695
     options.write_buffer_size = FLAGS_write_buffer_size;
  696
+    options.max_open_files = FLAGS_open_files;
696 697
     options.filter_policy = filter_policy_;
697 698
     Status s = DB::Open(options, FLAGS_db, &db_);
698 699
     if (!s.ok()) {
6  leveldb/db/db_impl.cc
@@ -609,7 +609,11 @@ void DBImpl::BackgroundCall() {
609 609
   assert(bg_compaction_scheduled_);
610 610
   if (!shutting_down_.Acquire_Load()) {
611 611
     Status s = BackgroundCompaction();
612  
-    if (!s.ok()) {
  612
+    if (s.ok()) {
  613
+      // Success
  614
+    } else if (shutting_down_.Acquire_Load()) {
  615
+      // Error most likely due to shutdown; do not wait
  616
+    } else {
613 617
       // Wait a little bit before retrying background compaction in
614 618
       // case this is an environmental problem and we do not want to
615 619
       // chew up resources for failed compactions for the duration of
28  leveldb/db/db_impl.h
@@ -13,6 +13,7 @@
13 13
 #include "leveldb/db.h"
14 14
 #include "leveldb/env.h"
15 15
 #include "port/port.h"
  16
+#include "port/thread_annotations.h"
16 17
 
17 18
 namespace leveldb {
18 19
 
@@ -71,7 +72,7 @@ class DBImpl : public DB {
71 72
   // Recover the descriptor from persistent storage.  May do a significant
72 73
   // amount of work to recover recently logged updates.  Any changes to
73 74
   // be made to the descriptor are added to *edit.
74  
-  Status Recover(VersionEdit* edit);
  75
+  Status Recover(VersionEdit* edit) EXCLUSIVE_LOCKS_REQUIRED(mutex_);
75 76
 
76 77
   void MaybeIgnoreError(Status* s) const;
77 78
 
@@ -80,27 +81,34 @@ class DBImpl : public DB {
80 81
 
81 82
   // Compact the in-memory write buffer to disk.  Switches to a new
82 83
   // log-file/memtable and writes a new descriptor iff successful.
83  
-  Status CompactMemTable();
  84
+  Status CompactMemTable()
  85
+      EXCLUSIVE_LOCKS_REQUIRED(mutex_);
84 86
 
85 87
   Status RecoverLogFile(uint64_t log_number,
86 88
                         VersionEdit* edit,
87  
-                        SequenceNumber* max_sequence);
  89
+                        SequenceNumber* max_sequence)
  90
+      EXCLUSIVE_LOCKS_REQUIRED(mutex_);
88 91
 
89  
-  Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base);
  92
+  Status WriteLevel0Table(MemTable* mem, VersionEdit* edit, Version* base)
  93
+      EXCLUSIVE_LOCKS_REQUIRED(mutex_);
90 94
 
91  
-  Status MakeRoomForWrite(bool force /* compact even if there is room? */);
  95
+  Status MakeRoomForWrite(bool force /* compact even if there is room? */)
  96
+      EXCLUSIVE_LOCKS_REQUIRED(mutex_);
92 97
   WriteBatch* BuildBatchGroup(Writer** last_writer);
93 98
 
94  
-  void MaybeScheduleCompaction();
  99
+  void MaybeScheduleCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_);
95 100
   static void BGWork(void* db);
96 101
   void BackgroundCall();
97  
-  Status BackgroundCompaction();
98  
-  void CleanupCompaction(CompactionState* compact);
99  
-  Status DoCompactionWork(CompactionState* compact);
  102
+  Status BackgroundCompaction() EXCLUSIVE_LOCKS_REQUIRED(mutex_);
  103
+  void CleanupCompaction(CompactionState* compact)
  104
+      EXCLUSIVE_LOCKS_REQUIRED(mutex_);
  105
+  Status DoCompactionWork(CompactionState* compact)
  106
+      EXCLUSIVE_LOCKS_REQUIRED(mutex_);
100 107
 
101 108
   Status OpenCompactionOutputFile(CompactionState* compact);
102 109
   Status FinishCompactionOutputFile(CompactionState* compact, Iterator* input);
103  
-  Status InstallCompactionResults(CompactionState* compact);
  110
+  Status InstallCompactionResults(CompactionState* compact)
  111
+      EXCLUSIVE_LOCKS_REQUIRED(mutex_);
104 112
 
105 113
   // Constant after construction
106 114
   Env* const env_;
81  leveldb/db/db_test.cc
@@ -59,6 +59,12 @@ class SpecialEnv : public EnvWrapper {
59 59
   // Simulate non-writable file system while this pointer is non-NULL
60 60
   port::AtomicPointer non_writable_;
61 61
 
  62
+  // Force sync of manifest files to fail while this pointer is non-NULL
  63
+  port::AtomicPointer manifest_sync_error_;
  64
+
  65
+  // Force write to manifest files to fail while this pointer is non-NULL
  66
+  port::AtomicPointer manifest_write_error_;
  67
+
62 68
   bool count_random_reads_;
63 69
   AtomicCounter random_read_counter_;
64 70
 
@@ -69,6 +75,8 @@ class SpecialEnv : public EnvWrapper {
69 75
     no_space_.Release_Store(NULL);
70 76
     non_writable_.Release_Store(NULL);
71 77
     count_random_reads_ = false;
  78
+    manifest_sync_error_.Release_Store(NULL);
  79
+    manifest_write_error_.Release_Store(NULL);
72 80
   }
73 81
 
74 82
   Status NewWritableFile(const std::string& f, WritableFile** r) {
@@ -100,6 +108,30 @@ class SpecialEnv : public EnvWrapper {
100 108
         return base_->Sync();
101 109
       }
102 110
     };
  111
+    class ManifestFile : public WritableFile {
  112
+     private:
  113
+      SpecialEnv* env_;
  114
+      WritableFile* base_;
  115
+     public:
  116
+      ManifestFile(SpecialEnv* env, WritableFile* b) : env_(env), base_(b) { }
  117
+      ~ManifestFile() { delete base_; }
  118
+      Status Append(const Slice& data) {
  119
+        if (env_->manifest_write_error_.Acquire_Load() != NULL) {
  120
+          return Status::IOError("simulated writer error");
  121
+        } else {
  122
+          return base_->Append(data);
  123
+        }
  124
+      }
  125
+      Status Close() { return base_->Close(); }
  126
+      Status Flush() { return base_->Flush(); }
  127
+      Status Sync() {
  128
+        if (env_->manifest_sync_error_.Acquire_Load() != NULL) {
  129
+          return Status::IOError("simulated sync error");
  130
+        } else {
  131
+          return base_->Sync();
  132
+        }
  133
+      }
  134
+    };
103 135
 
104 136
     if (non_writable_.Acquire_Load() != NULL) {
105 137
       return Status::IOError("simulated write error");
@@ -109,6 +141,8 @@ class SpecialEnv : public EnvWrapper {
109 141
     if (s.ok()) {
110 142
       if (strstr(f.c_str(), ".sst") != NULL) {
111 143
         *r = new SSTableFile(this, *r);
  144
+      } else if (strstr(f.c_str(), "MANIFEST") != NULL) {
  145
+        *r = new ManifestFile(this, *r);
112 146
       }
113 147
     }
114 148
     return s;
@@ -1442,6 +1476,12 @@ TEST(DBTest, DBOpen_Options) {
1442 1476
   db = NULL;
1443 1477
 }
1444 1478
 
  1479
+TEST(DBTest, Locking) {
  1480
+  DB* db2 = NULL;
  1481
+  Status s = DB::Open(CurrentOptions(), dbname_, &db2);
  1482
+  ASSERT_TRUE(!s.ok()) << "Locking did not prevent re-opening db";
  1483
+}
  1484
+
1445 1485
 // Check that number of files does not grow when we are out of space
1446 1486
 TEST(DBTest, NoSpace) {
1447 1487
   Options options = CurrentOptions();
@@ -1486,6 +1526,47 @@ TEST(DBTest, NonWritableFileSystem) {
1486 1526
   env_->non_writable_.Release_Store(NULL);
1487 1527
 }
1488 1528
 
  1529
+TEST(DBTest, ManifestWriteError) {
  1530
+  // Test for the following problem:
  1531
+  // (a) Compaction produces file F
  1532
+  // (b) Log record containing F is written to MANIFEST file, but Sync() fails
  1533
+  // (c) GC deletes F
  1534
+  // (d) After reopening DB, reads fail since deleted F is named in log record
  1535
+
  1536
+  // We iterate twice.  In the second iteration, everything is the
  1537
+  // same except the log record never makes it to the MANIFEST file.
  1538
+  for (int iter = 0; iter < 2; iter++) {
  1539
+    port::AtomicPointer* error_type = (iter == 0)
  1540
+        ? &env_->manifest_sync_error_
  1541
+        : &env_->manifest_write_error_;
  1542
+
  1543
+    // Insert foo=>bar mapping
  1544
+    Options options = CurrentOptions();
  1545
+    options.env = env_;
  1546
+    options.create_if_missing = true;
  1547
+    options.error_if_exists = false;
  1548
+    DestroyAndReopen(&options);
  1549
+    ASSERT_OK(Put("foo", "bar"));
  1550
+    ASSERT_EQ("bar", Get("foo"));
  1551
+
  1552
+    // Memtable compaction (will succeed)
  1553
+    dbfull()->TEST_CompactMemTable();
  1554
+    ASSERT_EQ("bar", Get("foo"));
  1555
+    const int last = config::kMaxMemCompactLevel;
  1556
+    ASSERT_EQ(NumTableFilesAtLevel(last), 1);   // foo=>bar is now in last level
  1557
+
  1558
+    // Merging compaction (will fail)
  1559
+    error_type->Release_Store(env_);
  1560
+    dbfull()->TEST_CompactRange(last, NULL, NULL);  // Should fail
  1561
+    ASSERT_EQ("bar", Get("foo"));
  1562
+
  1563
+    // Recovery: should not lose data
  1564
+    error_type->Release_Store(NULL);
  1565
+    Reopen(&options);
  1566
+    ASSERT_EQ("bar", Get("foo"));
  1567
+  }
  1568
+}
  1569
+
1489 1570
 TEST(DBTest, FilesDeletedAfterCompaction) {
1490 1571
   ASSERT_OK(Put("foo", "v2"));
1491 1572
   Compact("a", "z");
238  leveldb/db/leveldb_main.cc
... ...
@@ -0,0 +1,238 @@
  1
+// Copyright (c) 2012 The LevelDB Authors. All rights reserved.
  2
+// Use of this source code is governed by a BSD-style license that can be
  3
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
  4
+
  5
+#include <stdio.h>
  6
+#include "db/dbformat.h"
  7
+#include "db/filename.h"
  8
+#include "db/log_reader.h"
  9
+#include "db/version_edit.h"
  10
+#include "db/write_batch_internal.h"
  11
+#include "leveldb/env.h"
  12
+#include "leveldb/iterator.h"
  13
+#include "leveldb/options.h"
  14
+#include "leveldb/status.h"
  15
+#include "leveldb/table.h"
  16
+#include "leveldb/write_batch.h"
  17
+#include "util/logging.h"
  18
+
  19
+namespace leveldb {
  20
+
  21
+namespace {
  22
+
  23
+bool GuessType(const std::string& fname, FileType* type) {
  24
+  size_t pos = fname.rfind('/');
  25
+  std::string basename;
  26
+  if (pos == std::string::npos) {
  27
+    basename = fname;
  28
+  } else {
  29
+    basename = std::string(fname.data() + pos + 1, fname.size() - pos - 1);
  30
+  }
  31
+  uint64_t ignored;
  32
+  return ParseFileName(basename, &ignored, type);
  33
+}
  34
+
  35
+// Notified when log reader encounters corruption.
  36
+class CorruptionReporter : public log::Reader::Reporter {
  37
+ public:
  38
+  virtual void Corruption(size_t bytes, const Status& status) {
  39
+    printf("corruption: %d bytes; %s\n",
  40
+            static_cast<int>(bytes),
  41
+            status.ToString().c_str());
  42
+  }
  43
+};
  44
+
  45
+// Print contents of a log file. (*func)() is called on every record.
  46
+bool PrintLogContents(Env* env, const std::string& fname,
  47
+                      void (*func)(Slice)) {
  48
+  SequentialFile* file;
  49
+  Status s = env->NewSequentialFile(fname, &file);
  50
+  if (!s.ok()) {
  51
+    fprintf(stderr, "%s\n", s.ToString().c_str());
  52
+    return false;
  53
+  }
  54
+  CorruptionReporter reporter;
  55
+  log::Reader reader(file, &reporter, true, 0);
  56
+  Slice record;
  57
+  std::string scratch;
  58
+  while (reader.ReadRecord(&record, &scratch)) {
  59
+    printf("--- offset %llu; ",
  60
+           static_cast<unsigned long long>(reader.LastRecordOffset()));
  61
+    (*func)(record);
  62
+  }
  63
+  delete file;
  64
+  return true;
  65
+}
  66
+
  67
+// Called on every item found in a WriteBatch.
  68
+class WriteBatchItemPrinter : public WriteBatch::Handler {
  69
+ public:
  70
+  uint64_t offset_;
  71
+  uint64_t sequence_;
  72
+
  73
+  virtual void Put(const Slice& key, const Slice& value) {
  74
+    printf("  put '%s' '%s'\n",
  75
+           EscapeString(key).c_str(),
  76
+           EscapeString(value).c_str());
  77
+  }
  78
+  virtual void Delete(const Slice& key) {
  79
+    printf("  del '%s'\n",
  80
+           EscapeString(key).c_str());
  81
+  }
  82
+};
  83
+
  84
+
  85
+// Called on every log record (each one of which is a WriteBatch)
  86
+// found in a kLogFile.
  87
+static void WriteBatchPrinter(Slice record) {
  88
+  if (record.size() < 12) {
  89
+    printf("log record length %d is too small\n",
  90
+           static_cast<int>(record.size()));
  91
+    return;
  92
+  }
  93
+  WriteBatch batch;
  94
+  WriteBatchInternal::SetContents(&batch, record);
  95
+  printf("sequence %llu\n",
  96
+         static_cast<unsigned long long>(WriteBatchInternal::Sequence(&batch)));
  97
+  WriteBatchItemPrinter batch_item_printer;
  98
+  Status s = batch.Iterate(&batch_item_printer);
  99
+  if (!s.ok()) {
  100
+    printf("  error: %s\n", s.ToString().c_str());
  101
+  }
  102
+}
  103
+
  104
+bool DumpLog(Env* env, const std::string& fname) {
  105
+  return PrintLogContents(env, fname, WriteBatchPrinter);
  106
+}
  107
+
  108
+// Called on every log record (each one of which is a WriteBatch)
  109
+// found in a kDescriptorFile.
  110
+static void VersionEditPrinter(Slice record) {
  111
+  VersionEdit edit;
  112
+  Status s = edit.DecodeFrom(record);
  113
+  if (!s.ok()) {
  114
+    printf("%s\n", s.ToString().c_str());
  115
+    return;
  116
+  }
  117
+  printf("%s", edit.DebugString().c_str());
  118
+}
  119
+
  120
+bool DumpDescriptor(Env* env, const std::string& fname) {
  121
+  return PrintLogContents(env, fname, VersionEditPrinter);
  122
+}
  123
+
  124
+bool DumpTable(Env* env, const std::string& fname) {
  125
+  uint64_t file_size;
  126
+  RandomAccessFile* file = NULL;
  127
+  Table* table = NULL;
  128
+  Status s = env->GetFileSize(fname, &file_size);
  129
+  if (s.ok()) {
  130
+    s = env->NewRandomAccessFile(fname, &file);
  131
+  }
  132
+  if (s.ok()) {
  133
+    // We use the default comparator, which may or may not match the
  134
+    // comparator used in this database. However this should not cause
  135
+    // problems since we only use Table operations that do not require
  136
+    // any comparisons.  In particular, we do not call Seek or Prev.
  137
+    s = Table::Open(Options(), file, file_size, &table);
  138
+  }
  139
+  if (!s.ok()) {
  140
+    fprintf(stderr, "%s\n", s.ToString().c_str());
  141
+    delete table;
  142
+    delete file;
  143
+    return false;
  144
+  }
  145
+
  146
+  ReadOptions ro;
  147
+  ro.fill_cache = false;
  148
+  Iterator* iter = table->NewIterator(ro);
  149
+  for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
  150
+    ParsedInternalKey key;
  151
+    if (!ParseInternalKey(iter->key(), &key)) {
  152
+      printf("badkey '%s' => '%s'\n",
  153
+             EscapeString(iter->key()).c_str(),
  154
+             EscapeString(iter->value()).c_str());
  155
+    } else {
  156
+      char kbuf[20];
  157
+      const char* type;
  158
+      if (key.type == kTypeDeletion) {
  159
+        type = "del";
  160
+      } else if (key.type == kTypeValue) {
  161
+        type = "val";
  162
+      } else {
  163
+        snprintf(kbuf, sizeof(kbuf), "%d", static_cast<int>(key.type));
  164
+        type = kbuf;
  165
+      }
  166
+      printf("'%s' @ %8llu : %s => '%s'\n",
  167
+             EscapeString(key.user_key).c_str(),
  168
+             static_cast<unsigned long long>(key.sequence),
  169
+             type,
  170
+             EscapeString(iter->value()).c_str());
  171
+    }
  172
+  }
  173
+  s = iter->status();
  174
+  if (!s.ok()) {
  175
+    printf("iterator error: %s\n", s.ToString().c_str());
  176
+  }
  177
+
  178
+  delete iter;
  179
+  delete table;
  180
+  delete file;
  181
+  return true;
  182
+}
  183
+
  184
+bool DumpFile(Env* env, const std::string& fname) {
  185
+  FileType ftype;
  186
+  if (!GuessType(fname, &ftype)) {
  187
+    fprintf(stderr, "%s: unknown file type\n", fname.c_str());
  188
+    return false;
  189
+  }
  190
+  switch (ftype) {
  191
+    case kLogFile:         return DumpLog(env, fname);
  192
+    case kDescriptorFile:  return DumpDescriptor(env, fname);
  193
+    case kTableFile:       return DumpTable(env, fname);
  194
+
  195
+    default: {
  196
+      fprintf(stderr, "%s: not a dump-able file type\n", fname.c_str());
  197
+      break;
  198
+    }
  199
+  }
  200
+  return false;
  201
+}
  202
+
  203
+bool HandleDumpCommand(Env* env, char** files, int num) {
  204
+  bool ok = true;
  205
+  for (int i = 0; i < num; i++) {
  206
+    ok &= DumpFile(env, files[i]);
  207
+  }
  208
+  return ok;
  209
+}
  210
+
  211
+}
  212
+}  // namespace leveldb
  213
+
  214
+static void Usage() {
  215
+  fprintf(
  216
+      stderr,
  217
+      "Usage: leveldbutil command...\n"
  218
+      "   dump files...         -- dump contents of specified files\n"
  219
+      );
  220
+}
  221
+
  222
+int main(int argc, char** argv) {
  223
+  leveldb::Env* env = leveldb::Env::Default();
  224
+  bool ok = true;
  225
+  if (argc < 2) {
  226
+    Usage();
  227
+    ok = false;
  228
+  } else {
  229
+    std::string command = argv[1];
  230
+    if (command == "dump") {
  231
+      ok = leveldb::HandleDumpCommand(env, argv+2, argc-2);
  232
+    } else {
  233
+      Usage();
  234
+      ok = false;
  235
+    }
  236
+  }
  237
+  return (ok ? 0 : 1);
  238
+}
38  leveldb/db/version_set.cc
@@ -786,12 +786,23 @@ Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) {
786 786
       if (s.ok()) {
787 787
         s = descriptor_file_->Sync();
788 788
       }
  789
+      if (!s.ok()) {
  790
+        Log(options_->info_log, "MANIFEST write: %s\n", s.ToString().c_str());
  791
+        if (ManifestContains(record)) {
  792
+          Log(options_->info_log,
  793
+              "MANIFEST contains log record despite error; advancing to new "
  794
+              "version to prevent mismatch between in-memory and logged state");
  795
+          s = Status::OK();
  796
+        }
  797
+      }
789 798
     }
790 799
 
791 800
     // If we just created a new descriptor file, install it by writing a
792 801
     // new CURRENT file that points to it.
793 802
     if (s.ok() && !new_manifest_file.empty()) {
794 803
       s = SetCurrentFile(env_, dbname_, manifest_file_number_);
  804
+      // No need to double-check MANIFEST in case of error since it
  805
+      // will be discarded below.
795 806
     }
796 807
 
797 808
     mu->Lock();
@@ -865,7 +876,7 @@ Status VersionSet::Recover() {
865 876
         if (edit.has_comparator_ &&
866 877
             edit.comparator_ != icmp_.user_comparator()->Name()) {
867 878
           s = Status::InvalidArgument(
868  
-              edit.comparator_ + "does not match existing comparator ",
  879
+              edit.comparator_ + " does not match existing comparator ",
869 880
               icmp_.user_comparator()->Name());
870 881
         }
871 882
       }
@@ -1025,6 +1036,31 @@ const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const {
1025 1036
   return scratch->buffer;
1026 1037
 }
1027 1038
 
  1039
+// Return true iff the manifest contains the specified record.
  1040
+bool VersionSet::ManifestContains(const std::string& record) const {
  1041
+  std::string fname = DescriptorFileName(dbname_, manifest_file_number_);
  1042
+  Log(options_->info_log, "ManifestContains: checking %s\n", fname.c_str());
  1043
+  SequentialFile* file = NULL;
  1044
+  Status s = env_->NewSequentialFile(fname, &file);
  1045
+  if (!s.ok()) {
  1046
+    Log(options_->info_log, "ManifestContains: %s\n", s.ToString().c_str());
  1047
+    return false;
  1048
+  }
  1049
+  log::Reader reader(file, NULL, true/*checksum*/, 0);
  1050
+  Slice r;
  1051
+  std::string scratch;
  1052
+  bool result = false;
  1053
+  while (reader.ReadRecord(&r, &scratch)) {
  1054
+    if (r == Slice(record)) {
  1055
+      result = true;
  1056
+      break;
  1057
+    }
  1058
+  }
  1059
+  delete file;
  1060
+  Log(options_->info_log, "ManifestContains: result = %d\n", result ? 1 : 0);
  1061
+  return result;
  1062
+}
  1063
+
1028 1064
 uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) {
1029 1065
   uint64_t result = 0;
1030 1066
   for (int level = 0; level < config::kNumLevels; level++) {
6  leveldb/db/version_set.h
@@ -21,6 +21,7 @@
21 21
 #include "db/dbformat.h"
22 22
 #include "db/version_edit.h"
23 23
 #include "port/port.h"
  24
+#include "port/thread_annotations.h"
24 25
 
25 26
 namespace leveldb {
26 27
 
@@ -159,7 +160,8 @@ class VersionSet {
159 160
   // current version.  Will release *mu while actually writing to the file.
160 161
   // REQUIRES: *mu is held on entry.
161 162
   // REQUIRES: no other thread concurrently calls LogAndApply()
162  
-  Status LogAndApply(VersionEdit* edit, port::Mutex* mu);
  163
+  Status LogAndApply(VersionEdit* edit, port::Mutex* mu)
  164
+      EXCLUSIVE_LOCKS_REQUIRED(mu);
163 165
 
164 166
   // Recover the last saved descriptor from persistent storage.
165 167
   Status Recover();
@@ -275,6 +277,8 @@ class VersionSet {
275 277
 
276 278
   void AppendVersion(Version* v);
277 279
 
  280
+  bool ManifestContains(const std::string& record) const;
  281
+
278 282
   Env* const env_;
279 283
   const std::string dbname_;
280 284
   const Options* const options_;
718  leveldb/doc/bench/db_bench_sqlite3.cc
... ...
@@ -0,0 +1,718 @@
  1
+// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  2
+// Use of this source code is governed by a BSD-style license that can be
  3
+// found in the LICENSE file. See the AUTHORS file for names of contributors.
  4
+
  5
+#include <stdio.h>
  6
+#include <stdlib.h>
  7
+#include <sqlite3.h>
  8
+#include "util/histogram.h"
  9
+#include "util/random.h"
  10
+#include "util/testutil.h"
  11
+
  12
+// Comma-separated list of operations to run in the specified order
  13
+//   Actual benchmarks:
  14
+//
  15
+//   fillseq       -- write N values in sequential key order in async mode
  16
+//   fillseqsync   -- write N/100 values in sequential key order in sync mode
  17
+//   fillseqbatch  -- batch write N values in sequential key order in async mode
  18
+//   fillrandom    -- write N values in random key order in async mode
  19
+//   fillrandsync  -- write N/100 values in random key order in sync mode
  20
+//   fillrandbatch -- batch write N values in sequential key order in async mode
  21
+//   overwrite     -- overwrite N values in random key order in async mode
  22
+//   fillrand100K  -- write N/1000 100K values in random order in async mode
  23
+//   fillseq100K   -- write N/1000 100K values in sequential order in async mode
  24
+//   readseq       -- read N times sequentially
  25
+//   readrandom    -- read N times in random order
  26
+//   readrand100K  -- read N/1000 100K values in sequential order in async mode
  27
+static const char* FLAGS_benchmarks =
  28
+    "fillseq,"
  29
+    "fillseqsync,"
  30
+    "fillseqbatch,"
  31
+    "fillrandom,"
  32
+    "fillrandsync,"
  33
+    "fillrandbatch,"
  34
+    "overwrite,"
  35
+    "overwritebatch,"
  36
+    "readrandom,"
  37
+    "readseq,"
  38
+    "fillrand100K,"
  39
+    "fillseq100K,"
  40
+    "readseq,"
  41
+    "readrand100K,"
  42
+    ;
  43
+
  44
+// Number of key/values to place in database
  45
+static int FLAGS_num = 1000000;
  46
+
  47
+// Number of read operations to do.  If negative, do FLAGS_num reads.
  48
+static int FLAGS_reads = -1;
  49
+
  50
+// Size of each value
  51
+static int FLAGS_value_size = 100;
  52
+
  53
+// Print histogram of operation timings
  54
+static bool FLAGS_histogram = false;
  55
+
  56
+// Arrange to generate values that shrink to this fraction of
  57
+// their original size after compression
  58
+static double FLAGS_compression_ratio = 0.5;
  59
+
  60
+// Page size. Default 1 KB.
  61
+static int FLAGS_page_size = 1024;
  62
+
  63
+// Number of pages.
  64
+// Default cache size = FLAGS_page_size * FLAGS_num_pages = 4 MB.
  65
+static int FLAGS_num_pages = 4096;
  66
+
  67
+// If true, do not destroy the existing database.  If you set this
  68
+// flag and also specify a benchmark that wants a fresh database, that
  69
+// benchmark will fail.
  70
+static bool FLAGS_use_existing_db = false;
  71
+
  72
+// If true, we allow batch writes to occur
  73
+static bool FLAGS_transaction = true;
  74
+
  75
+// If true, we enable Write-Ahead Logging
  76
+static bool FLAGS_WAL_enabled = true;
  77
+
  78
+// Use the db with the following name.
  79
+static const char* FLAGS_db = NULL;
  80
+
  81
+inline
  82
+static void ExecErrorCheck(int status, char *err_msg) {
  83
+  if (status != SQLITE_OK) {
  84
+    fprintf(stderr, "SQL error: %s\n", err_msg);
  85
+    sqlite3_free(err_msg);
  86
+    exit(1);
  87
+  }
  88
+}
  89
+
  90
+inline
  91
+static void StepErrorCheck(int status) {
  92
+  if (status != SQLITE_DONE) {
  93
+    fprintf(stderr, "SQL step error: status = %d\n", status);
  94
+    exit(1);
  95
+  }
  96
+}
  97
+
  98
+inline
  99
+static void ErrorCheck(int status) {
  100
+  if (status != SQLITE_OK) {
  101
+    fprintf(stderr, "sqlite3 error: status = %d\n", status);
  102
+    exit(1);
  103
+  }
  104
+}
  105
+
  106
+inline
  107
+static void WalCheckpoint(sqlite3* db_) {
  108
+  // Flush all writes to disk
  109
+  if (FLAGS_WAL_enabled) {
  110
+    sqlite3_wal_checkpoint_v2(db_, NULL, SQLITE_CHECKPOINT_FULL, NULL, NULL);
  111
+  }
  112
+}
  113
+
  114
+namespace leveldb {
  115
+
  116
+// Helper for quickly generating random data.
  117
+namespace {
  118
+class RandomGenerator {
  119
+ private:
  120
+  std::string data_;
  121
+  int pos_;
  122
+
  123
+ public:
  124
+  RandomGenerator() {
  125
+    // We use a limited amount of data over and over again and ensure
  126
+    // that it is larger than the compression window (32KB), and also
  127
+    // large enough to serve all typical value sizes we want to write.
  128
+    Random rnd(301);
  129
+    std::string piece;
  130
+    while (data_.size() < 1048576) {
  131
+      // Add a short fragment that is as compressible as specified
  132
+      // by FLAGS_compression_ratio.
  133
+      test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece);
  134
+      data_.append(piece);
  135
+    }
  136
+    pos_ = 0;
  137
+  }
  138
+
  139
+  Slice Generate(int len) {
  140
+    if (pos_ + len > data_.size()) {
  141
+      pos_ = 0;
  142
+      assert(len < data_.size());
  143
+    }
  144
+    pos_ += len;
  145
+    return Slice(data_.data() + pos_ - len, len);
  146
+  }
  147
+};
  148
+
  149
+static Slice TrimSpace(Slice s) {
  150
+  int start = 0;
  151
+  while (start < s.size() && isspace(s[start])) {
  152
+    start++;
  153
+  }
  154
+  int limit = s.size();
  155
+  while (limit > start && isspace(s[limit-1])) {
  156
+    limit--;
  157
+  }
  158
+  return Slice(s.data() + start, limit - start);
  159
+}
  160
+