Merge branch 'master' of https://github.com/facebook/rocksdb
This commit is contained in:
commit
611e286b9d
@ -8,6 +8,7 @@
|
|||||||
* We have refactored our system of stalling writes. Any stall-related statistics' meanings are changed. Instead of per-write stall counts, we now count stalls per-epoch, where epochs are periods between flushes and compactions. You'll find more information in our Tuning Perf Guide once we release RocksDB 3.6.
|
* We have refactored our system of stalling writes. Any stall-related statistics' meanings are changed. Instead of per-write stall counts, we now count stalls per-epoch, where epochs are periods between flushes and compactions. You'll find more information in our Tuning Perf Guide once we release RocksDB 3.6.
|
||||||
* When disableDataSync=true, we no longer sync the MANIFEST file.
|
* When disableDataSync=true, we no longer sync the MANIFEST file.
|
||||||
* Add identity_as_first_hash property to CuckooTable. SST file needs to be rebuilt to be opened by reader properly.
|
* Add identity_as_first_hash property to CuckooTable. SST file needs to be rebuilt to be opened by reader properly.
|
||||||
|
* Change target_file_size_base type to uint64_t from int.
|
||||||
|
|
||||||
----- Past Releases -----
|
----- Past Releases -----
|
||||||
|
|
||||||
|
35
Makefile
35
Makefile
@ -198,7 +198,7 @@ endif # PLATFORM_SHARED_EXT
|
|||||||
|
|
||||||
.PHONY: blackbox_crash_test check clean coverage crash_test ldb_tests \
|
.PHONY: blackbox_crash_test check clean coverage crash_test ldb_tests \
|
||||||
release tags valgrind_check whitebox_crash_test format static_lib shared_lib all \
|
release tags valgrind_check whitebox_crash_test format static_lib shared_lib all \
|
||||||
dbg install uninstall
|
dbg rocksdbjavastatic rocksdbjava install uninstall
|
||||||
|
|
||||||
all: $(LIBRARY) $(PROGRAMS) $(TESTS)
|
all: $(LIBRARY) $(PROGRAMS) $(TESTS)
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ unity: unity.cc unity.o
|
|||||||
clean:
|
clean:
|
||||||
-rm -f $(PROGRAMS) $(TESTS) $(LIBRARY) $(SHARED) $(MEMENVLIBRARY) build_config.mk unity.cc
|
-rm -f $(PROGRAMS) $(TESTS) $(LIBRARY) $(SHARED) $(MEMENVLIBRARY) build_config.mk unity.cc
|
||||||
-rm -rf ios-x86/* ios-arm/*
|
-rm -rf ios-x86/* ios-arm/*
|
||||||
-find . -name "*.[od]" -exec rm {} \;
|
-find . -name "*.[oda]" -exec rm {} \;
|
||||||
-find . -type f -regex ".*\.\(\(gcda\)\|\(gcno\)\)" -exec rm {} \;
|
-find . -type f -regex ".*\.\(\(gcda\)\|\(gcno\)\)" -exec rm {} \;
|
||||||
tags:
|
tags:
|
||||||
ctags * -R
|
ctags * -R
|
||||||
@ -518,6 +518,37 @@ ROCKSDBJNILIB = librocksdbjni.jnilib
|
|||||||
JAVA_INCLUDE = -I/System/Library/Frameworks/JavaVM.framework/Headers/
|
JAVA_INCLUDE = -I/System/Library/Frameworks/JavaVM.framework/Headers/
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
libz.a:
|
||||||
|
-rm -rf zlib-1.2.8
|
||||||
|
curl -O http://zlib.net/zlib-1.2.8.tar.gz
|
||||||
|
tar xvzf zlib-1.2.8.tar.gz
|
||||||
|
cd zlib-1.2.8 && CFLAGS='-fPIC' ./configure --static && make
|
||||||
|
cp zlib-1.2.8/libz.a .
|
||||||
|
|
||||||
|
libbz2.a:
|
||||||
|
-rm -rf bzip2-1.0.6
|
||||||
|
curl -O http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz
|
||||||
|
tar xvzf bzip2-1.0.6.tar.gz
|
||||||
|
cd bzip2-1.0.6 && make CFLAGS='-fPIC -Wall -Winline -O2 -g -D_FILE_OFFSET_BITS=64'
|
||||||
|
cp bzip2-1.0.6/libbz2.a .
|
||||||
|
|
||||||
|
libsnappy.a:
|
||||||
|
-rm -rf snappy-1.1.1
|
||||||
|
curl -O https://snappy.googlecode.com/files/snappy-1.1.1.tar.gz
|
||||||
|
tar xvzf snappy-1.1.1.tar.gz
|
||||||
|
cd snappy-1.1.1 && ./configure --with-pic --enable-static
|
||||||
|
cd snappy-1.1.1 && make
|
||||||
|
cp snappy-1.1.1/.libs/libsnappy.a .
|
||||||
|
|
||||||
|
|
||||||
|
rocksdbjavastatic: libz.a libbz2.a libsnappy.a
|
||||||
|
OPT="-fPIC -DNDEBUG -O2" $(MAKE) $(LIBRARY) -j
|
||||||
|
cd java;$(MAKE) java;
|
||||||
|
rm -f ./java/$(ROCKSDBJNILIB)
|
||||||
|
$(CXX) $(CXXFLAGS) -I./java/. $(JAVA_INCLUDE) -shared -fPIC -o ./java/$(ROCKSDBJNILIB) $(JNI_NATIVE_SOURCES) $(LIBOBJECTS) $(COVERAGEFLAGS) libz.a libbz2.a libsnappy.a
|
||||||
|
cd java;jar -cf $(ROCKSDB_JAR) org/rocksdb/*.class org/rocksdb/util/*.class HISTORY*.md $(ROCKSDBJNILIB)
|
||||||
|
|
||||||
|
|
||||||
rocksdbjava:
|
rocksdbjava:
|
||||||
OPT="-fPIC -DNDEBUG -O2" $(MAKE) $(LIBRARY) -j32
|
OPT="-fPIC -DNDEBUG -O2" $(MAKE) $(LIBRARY) -j32
|
||||||
cd java;$(MAKE) java;
|
cd java;$(MAKE) java;
|
||||||
|
@ -86,6 +86,10 @@ ColumnFamilyHandleImpl::~ColumnFamilyHandleImpl() {
|
|||||||
|
|
||||||
uint32_t ColumnFamilyHandleImpl::GetID() const { return cfd()->GetID(); }
|
uint32_t ColumnFamilyHandleImpl::GetID() const { return cfd()->GetID(); }
|
||||||
|
|
||||||
|
const Comparator* ColumnFamilyHandleImpl::user_comparator() const {
|
||||||
|
return cfd()->user_comparator();
|
||||||
|
}
|
||||||
|
|
||||||
ColumnFamilyOptions SanitizeOptions(const InternalKeyComparator* icmp,
|
ColumnFamilyOptions SanitizeOptions(const InternalKeyComparator* icmp,
|
||||||
const ColumnFamilyOptions& src) {
|
const ColumnFamilyOptions& src) {
|
||||||
ColumnFamilyOptions result = src;
|
ColumnFamilyOptions result = src;
|
||||||
@ -726,4 +730,13 @@ uint32_t GetColumnFamilyID(ColumnFamilyHandle* column_family) {
|
|||||||
return column_family_id;
|
return column_family_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Comparator* GetColumnFamilyUserComparator(
|
||||||
|
ColumnFamilyHandle* column_family) {
|
||||||
|
if (column_family != nullptr) {
|
||||||
|
auto cfh = reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
|
||||||
|
return cfh->user_comparator();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace rocksdb
|
} // namespace rocksdb
|
||||||
|
@ -49,6 +49,7 @@ class ColumnFamilyHandleImpl : public ColumnFamilyHandle {
|
|||||||
// destroy without mutex
|
// destroy without mutex
|
||||||
virtual ~ColumnFamilyHandleImpl();
|
virtual ~ColumnFamilyHandleImpl();
|
||||||
virtual ColumnFamilyData* cfd() const { return cfd_; }
|
virtual ColumnFamilyData* cfd() const { return cfd_; }
|
||||||
|
virtual const Comparator* user_comparator() const;
|
||||||
|
|
||||||
virtual uint32_t GetID() const;
|
virtual uint32_t GetID() const;
|
||||||
|
|
||||||
@ -448,4 +449,7 @@ class ColumnFamilyMemTablesImpl : public ColumnFamilyMemTables {
|
|||||||
|
|
||||||
extern uint32_t GetColumnFamilyID(ColumnFamilyHandle* column_family);
|
extern uint32_t GetColumnFamilyID(ColumnFamilyHandle* column_family);
|
||||||
|
|
||||||
|
extern const Comparator* GetColumnFamilyUserComparator(
|
||||||
|
ColumnFamilyHandle* column_family);
|
||||||
|
|
||||||
} // namespace rocksdb
|
} // namespace rocksdb
|
||||||
|
@ -575,7 +575,7 @@ Compaction* UniversalCompactionPicker::PickCompaction(Version* version,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
Version::FileSummaryStorage tmp;
|
Version::FileSummaryStorage tmp;
|
||||||
LogToBuffer(log_buffer, "[%s] Universal: candidate files(%zu): %s\n",
|
LogToBuffer(log_buffer, 3072, "[%s] Universal: candidate files(%zu): %s\n",
|
||||||
version->cfd_->GetName().c_str(), version->files_[level].size(),
|
version->cfd_->GetName().c_str(), version->files_[level].size(),
|
||||||
version->LevelFileSummary(&tmp, 0));
|
version->LevelFileSummary(&tmp, 0));
|
||||||
|
|
||||||
|
@ -307,7 +307,7 @@ DEFINE_string(wal_dir, "", "If not empty, use the given dir for WAL");
|
|||||||
|
|
||||||
DEFINE_int32(num_levels, 7, "The total number of levels");
|
DEFINE_int32(num_levels, 7, "The total number of levels");
|
||||||
|
|
||||||
DEFINE_int32(target_file_size_base, 2 * 1048576, "Target file size at level-1");
|
DEFINE_int64(target_file_size_base, 2 * 1048576, "Target file size at level-1");
|
||||||
|
|
||||||
DEFINE_int32(target_file_size_multiplier, 1,
|
DEFINE_int32(target_file_size_multiplier, 1,
|
||||||
"A multiplier to compute target level-N file size (N >= 2)");
|
"A multiplier to compute target level-N file size (N >= 2)");
|
||||||
|
@ -3117,9 +3117,6 @@ Status DBImpl::DoCompactionWork(CompactionState* compact,
|
|||||||
const uint64_t start_micros = env_->NowMicros();
|
const uint64_t start_micros = env_->NowMicros();
|
||||||
unique_ptr<Iterator> input(versions_->MakeInputIterator(compact->compaction));
|
unique_ptr<Iterator> input(versions_->MakeInputIterator(compact->compaction));
|
||||||
input->SeekToFirst();
|
input->SeekToFirst();
|
||||||
shared_ptr<Iterator> backup_input(
|
|
||||||
versions_->MakeInputIterator(compact->compaction));
|
|
||||||
backup_input->SeekToFirst();
|
|
||||||
|
|
||||||
Status status;
|
Status status;
|
||||||
ParsedInternalKey ikey;
|
ParsedInternalKey ikey;
|
||||||
@ -3132,14 +3129,30 @@ Status DBImpl::DoCompactionWork(CompactionState* compact,
|
|||||||
auto compaction_filter_v2 =
|
auto compaction_filter_v2 =
|
||||||
compaction_filter_from_factory_v2.get();
|
compaction_filter_from_factory_v2.get();
|
||||||
|
|
||||||
// temp_backup_input always point to the start of the current buffer
|
if (!compaction_filter_v2) {
|
||||||
// temp_backup_input = backup_input;
|
status = ProcessKeyValueCompaction(
|
||||||
// iterate through input,
|
is_snapshot_supported,
|
||||||
// 1) buffer ineligible keys and value keys into 2 separate buffers;
|
visible_at_tip,
|
||||||
// 2) send value_buffer to compaction filter and alternate the values;
|
earliest_snapshot,
|
||||||
// 3) merge value_buffer with ineligible_value_buffer;
|
latest_snapshot,
|
||||||
// 4) run the modified "compaction" using the old for loop.
|
deletion_state,
|
||||||
if (compaction_filter_v2) {
|
bottommost_level,
|
||||||
|
imm_micros,
|
||||||
|
input.get(),
|
||||||
|
compact,
|
||||||
|
false,
|
||||||
|
log_buffer);
|
||||||
|
} else {
|
||||||
|
// temp_backup_input always point to the start of the current buffer
|
||||||
|
// temp_backup_input = backup_input;
|
||||||
|
// iterate through input,
|
||||||
|
// 1) buffer ineligible keys and value keys into 2 separate buffers;
|
||||||
|
// 2) send value_buffer to compaction filter and alternate the values;
|
||||||
|
// 3) merge value_buffer with ineligible_value_buffer;
|
||||||
|
// 4) run the modified "compaction" using the old for loop.
|
||||||
|
shared_ptr<Iterator> backup_input(
|
||||||
|
versions_->MakeInputIterator(compact->compaction));
|
||||||
|
backup_input->SeekToFirst();
|
||||||
while (backup_input->Valid() && !shutting_down_.Acquire_Load() &&
|
while (backup_input->Valid() && !shutting_down_.Acquire_Load() &&
|
||||||
!cfd->IsDropped()) {
|
!cfd->IsDropped()) {
|
||||||
// FLUSH preempts compaction
|
// FLUSH preempts compaction
|
||||||
@ -3267,21 +3280,6 @@ Status DBImpl::DoCompactionWork(CompactionState* compact,
|
|||||||
log_buffer);
|
log_buffer);
|
||||||
} // checking for compaction filter v2
|
} // checking for compaction filter v2
|
||||||
|
|
||||||
if (!compaction_filter_v2) {
|
|
||||||
status = ProcessKeyValueCompaction(
|
|
||||||
is_snapshot_supported,
|
|
||||||
visible_at_tip,
|
|
||||||
earliest_snapshot,
|
|
||||||
latest_snapshot,
|
|
||||||
deletion_state,
|
|
||||||
bottommost_level,
|
|
||||||
imm_micros,
|
|
||||||
input.get(),
|
|
||||||
compact,
|
|
||||||
false,
|
|
||||||
log_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status.ok() && (shutting_down_.Acquire_Load() || cfd->IsDropped())) {
|
if (status.ok() && (shutting_down_.Acquire_Load() || cfd->IsDropped())) {
|
||||||
status = Status::ShutdownInProgress(
|
status = Status::ShutdownInProgress(
|
||||||
"Database shutdown or Column family drop during compaction");
|
"Database shutdown or Column family drop during compaction");
|
||||||
|
@ -183,10 +183,10 @@ class Version {
|
|||||||
// Return a human-readable short (single-line) summary of the number
|
// Return a human-readable short (single-line) summary of the number
|
||||||
// of files per level. Uses *scratch as backing store.
|
// of files per level. Uses *scratch as backing store.
|
||||||
struct LevelSummaryStorage {
|
struct LevelSummaryStorage {
|
||||||
char buffer[100];
|
char buffer[1000];
|
||||||
};
|
};
|
||||||
struct FileSummaryStorage {
|
struct FileSummaryStorage {
|
||||||
char buffer[1000];
|
char buffer[3000];
|
||||||
};
|
};
|
||||||
const char* LevelSummary(LevelSummaryStorage* scratch) const;
|
const char* LevelSummary(LevelSummaryStorage* scratch) const;
|
||||||
// Return a human-readable short (single-line) summary of files
|
// Return a human-readable short (single-line) summary of files
|
||||||
|
@ -289,6 +289,9 @@ class ColumnFamilyHandleImplDummy : public ColumnFamilyHandleImpl {
|
|||||||
explicit ColumnFamilyHandleImplDummy(int id)
|
explicit ColumnFamilyHandleImplDummy(int id)
|
||||||
: ColumnFamilyHandleImpl(nullptr, nullptr, nullptr), id_(id) {}
|
: ColumnFamilyHandleImpl(nullptr, nullptr, nullptr), id_(id) {}
|
||||||
uint32_t GetID() const override { return id_; }
|
uint32_t GetID() const override { return id_; }
|
||||||
|
const Comparator* user_comparator() const override {
|
||||||
|
return BytewiseComparator();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t id_;
|
uint32_t id_;
|
||||||
@ -320,7 +323,7 @@ TEST(WriteBatchTest, ColumnFamiliesBatchTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(WriteBatchTest, ColumnFamiliesBatchWithIndexTest) {
|
TEST(WriteBatchTest, ColumnFamiliesBatchWithIndexTest) {
|
||||||
WriteBatchWithIndex batch(BytewiseComparator(), 20);
|
WriteBatchWithIndex batch;
|
||||||
ColumnFamilyHandleImplDummy zero(0), two(2), three(3), eight(8);
|
ColumnFamilyHandleImplDummy zero(0), two(2), three(3), eight(8);
|
||||||
batch.Put(&zero, Slice("foo"), Slice("bar"));
|
batch.Put(&zero, Slice("foo"), Slice("bar"));
|
||||||
batch.Put(&two, Slice("twofoo"), Slice("bar2"));
|
batch.Put(&two, Slice("twofoo"), Slice("bar2"));
|
||||||
|
@ -77,6 +77,8 @@ struct ImmutableCFOptions {
|
|||||||
std::vector<CompressionType> compression_per_level;
|
std::vector<CompressionType> compression_per_level;
|
||||||
|
|
||||||
CompressionOptions compression_opts;
|
CompressionOptions compression_opts;
|
||||||
|
|
||||||
|
Options::AccessHint access_hint_on_compaction_start;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace rocksdb
|
} // namespace rocksdb
|
||||||
|
@ -58,6 +58,7 @@ enum CompactionStyle : char {
|
|||||||
kCompactionStyleFIFO = 0x2, // FIFO compaction style
|
kCompactionStyleFIFO = 0x2, // FIFO compaction style
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct CompactionOptionsFIFO {
|
struct CompactionOptionsFIFO {
|
||||||
// once the total sum of table files reaches this, we will delete the oldest
|
// once the total sum of table files reaches this, we will delete the oldest
|
||||||
// table file
|
// table file
|
||||||
@ -287,7 +288,7 @@ struct ColumnFamilyOptions {
|
|||||||
// and each file on level-3 will be 200MB.
|
// and each file on level-3 will be 200MB.
|
||||||
|
|
||||||
// by default target_file_size_base is 2MB.
|
// by default target_file_size_base is 2MB.
|
||||||
int target_file_size_base;
|
uint64_t target_file_size_base;
|
||||||
// by default target_file_size_multiplier is 1, which means
|
// by default target_file_size_multiplier is 1, which means
|
||||||
// by default files in different levels will have similar size.
|
// by default files in different levels will have similar size.
|
||||||
int target_file_size_multiplier;
|
int target_file_size_multiplier;
|
||||||
@ -783,12 +784,13 @@ struct DBOptions {
|
|||||||
// Specify the file access pattern once a compaction is started.
|
// Specify the file access pattern once a compaction is started.
|
||||||
// It will be applied to all input files of a compaction.
|
// It will be applied to all input files of a compaction.
|
||||||
// Default: NORMAL
|
// Default: NORMAL
|
||||||
enum {
|
enum AccessHint {
|
||||||
NONE,
|
NONE,
|
||||||
NORMAL,
|
NORMAL,
|
||||||
SEQUENTIAL,
|
SEQUENTIAL,
|
||||||
WILLNEED
|
WILLNEED
|
||||||
} access_hint_on_compaction_start;
|
};
|
||||||
|
AccessHint access_hint_on_compaction_start;
|
||||||
|
|
||||||
// Use adaptive mutex, which spins in the user space before resorting
|
// Use adaptive mutex, which spins in the user space before resorting
|
||||||
// to kernel. This could reduce context switch when the mutex is not
|
// to kernel. This could reduce context switch when the mutex is not
|
||||||
|
@ -11,8 +11,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "rocksdb/status.h"
|
#include "rocksdb/comparator.h"
|
||||||
#include "rocksdb/slice.h"
|
#include "rocksdb/slice.h"
|
||||||
|
#include "rocksdb/status.h"
|
||||||
#include "rocksdb/write_batch.h"
|
#include "rocksdb/write_batch.h"
|
||||||
|
|
||||||
namespace rocksdb {
|
namespace rocksdb {
|
||||||
@ -56,12 +57,14 @@ class WBWIIterator {
|
|||||||
// A user can call NewIterator() to create an iterator.
|
// A user can call NewIterator() to create an iterator.
|
||||||
class WriteBatchWithIndex {
|
class WriteBatchWithIndex {
|
||||||
public:
|
public:
|
||||||
// index_comparator indicates the order when iterating data in the write
|
// backup_index_comparator: the backup comparator used to compare keys
|
||||||
// batch. Technically, it doesn't have to be the same as the one used in
|
// within the same column family, if column family is not given in the
|
||||||
// the DB.
|
// interface, or we can't find a column family from the column family handle
|
||||||
|
// passed in, backup_index_comparator will be used for the column family.
|
||||||
// reserved_bytes: reserved bytes in underlying WriteBatch
|
// reserved_bytes: reserved bytes in underlying WriteBatch
|
||||||
explicit WriteBatchWithIndex(const Comparator* index_comparator,
|
explicit WriteBatchWithIndex(
|
||||||
size_t reserved_bytes = 0);
|
const Comparator* backup_index_comparator = BytewiseComparator(),
|
||||||
|
size_t reserved_bytes = 0);
|
||||||
virtual ~WriteBatchWithIndex();
|
virtual ~WriteBatchWithIndex();
|
||||||
|
|
||||||
WriteBatch* GetWriteBatch();
|
WriteBatch* GetWriteBatch();
|
||||||
|
58
java/org/rocksdb/NativeLibraryLoader.java
Normal file
58
java/org/rocksdb/NativeLibraryLoader.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package org.rocksdb;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to load the RocksDB shared library from within the jar.
|
||||||
|
* The shared library is extracted to a temp folder and loaded from there.
|
||||||
|
*/
|
||||||
|
public class NativeLibraryLoader {
|
||||||
|
private static String sharedLibraryName = "librocksdbjni.so";
|
||||||
|
private static String tempFilePrefix = "librocksdbjni";
|
||||||
|
private static String tempFileSuffix = ".so";
|
||||||
|
|
||||||
|
public static void loadLibraryFromJar(String tmpDir)
|
||||||
|
throws IOException {
|
||||||
|
File temp;
|
||||||
|
if(tmpDir == null || tmpDir.equals(""))
|
||||||
|
temp = File.createTempFile(tempFilePrefix, tempFileSuffix);
|
||||||
|
else
|
||||||
|
temp = new File(tmpDir + "/" + sharedLibraryName);
|
||||||
|
|
||||||
|
temp.deleteOnExit();
|
||||||
|
|
||||||
|
if (!temp.exists()) {
|
||||||
|
throw new RuntimeException("File " + temp.getAbsolutePath() + " does not exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] buffer = new byte[102400];
|
||||||
|
int readBytes;
|
||||||
|
|
||||||
|
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(sharedLibraryName);
|
||||||
|
if (is == null) {
|
||||||
|
throw new RuntimeException(sharedLibraryName + " was not found inside JAR.");
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputStream os = null;
|
||||||
|
try {
|
||||||
|
os = new FileOutputStream(temp);
|
||||||
|
while ((readBytes = is.read(buffer)) != -1) {
|
||||||
|
os.write(buffer, 0, readBytes);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if(os != null)
|
||||||
|
os.close();
|
||||||
|
|
||||||
|
if(is != null)
|
||||||
|
is.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.load(temp.getAbsolutePath());
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Private constructor to disallow instantiation
|
||||||
|
*/
|
||||||
|
private NativeLibraryLoader() {
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,9 @@ package org.rocksdb;
|
|||||||
* native resources will be released as part of the process.
|
* native resources will be released as part of the process.
|
||||||
*/
|
*/
|
||||||
public class Options extends RocksObject {
|
public class Options extends RocksObject {
|
||||||
|
static {
|
||||||
|
RocksDB.loadLibrary();
|
||||||
|
}
|
||||||
static final long DEFAULT_CACHE_SIZE = 8 << 20;
|
static final long DEFAULT_CACHE_SIZE = 8 << 20;
|
||||||
static final int DEFAULT_NUM_SHARD_BITS = -1;
|
static final int DEFAULT_NUM_SHARD_BITS = -1;
|
||||||
/**
|
/**
|
||||||
|
@ -11,6 +11,7 @@ import java.util.HashMap;
|
|||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.rocksdb.util.Environment;
|
import org.rocksdb.util.Environment;
|
||||||
|
import org.rocksdb.NativeLibraryLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A RocksDB is a persistent ordered map from keys to values. It is safe for
|
* A RocksDB is a persistent ordered map from keys to values. It is safe for
|
||||||
@ -23,11 +24,19 @@ public class RocksDB extends RocksObject {
|
|||||||
private static final String[] compressionLibs_ = {
|
private static final String[] compressionLibs_ = {
|
||||||
"snappy", "z", "bzip2", "lz4", "lz4hc"};
|
"snappy", "z", "bzip2", "lz4", "lz4hc"};
|
||||||
|
|
||||||
|
static {
|
||||||
|
RocksDB.loadLibrary();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the necessary library files.
|
* Loads the necessary library files.
|
||||||
* Calling this method twice will have no effect.
|
* Calling this method twice will have no effect.
|
||||||
|
* By default the method extracts the shared library for loading at
|
||||||
|
* java.io.tmpdir, however, you can override this temporary location by
|
||||||
|
* setting the environment variable ROCKSDB_SHAREDLIB_DIR.
|
||||||
*/
|
*/
|
||||||
public static synchronized void loadLibrary() {
|
public static synchronized void loadLibrary() {
|
||||||
|
String tmpDir = System.getenv("ROCKSDB_SHAREDLIB_DIR");
|
||||||
// loading possibly necessary libraries.
|
// loading possibly necessary libraries.
|
||||||
for (String lib : compressionLibs_) {
|
for (String lib : compressionLibs_) {
|
||||||
try {
|
try {
|
||||||
@ -36,8 +45,14 @@ public class RocksDB extends RocksObject {
|
|||||||
// since it may be optional, we ignore its loading failure here.
|
// since it may be optional, we ignore its loading failure here.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// However, if any of them is required. We will see error here.
|
try
|
||||||
System.loadLibrary("rocksdbjni");
|
{
|
||||||
|
NativeLibraryLoader.loadLibraryFromJar(tmpDir);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Unable to load the RocksDB shared library" + e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -498,7 +498,6 @@ Status BlockBasedTable::Open(const ImmutableCFOptions& ioptions,
|
|||||||
// pre-load these blocks, which will kept in member variables in Rep
|
// pre-load these blocks, which will kept in member variables in Rep
|
||||||
// and with a same life-time as this table object.
|
// and with a same life-time as this table object.
|
||||||
IndexReader* index_reader = nullptr;
|
IndexReader* index_reader = nullptr;
|
||||||
// TODO: we never really verify check sum for index block
|
|
||||||
s = new_table->CreateIndexReader(&index_reader, meta_iter.get());
|
s = new_table->CreateIndexReader(&index_reader, meta_iter.get());
|
||||||
|
|
||||||
if (s.ok()) {
|
if (s.ok()) {
|
||||||
@ -533,8 +532,7 @@ Status BlockBasedTable::Open(const ImmutableCFOptions& ioptions,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BlockBasedTable::SetupForCompaction() {
|
void BlockBasedTable::SetupForCompaction() {
|
||||||
/*
|
switch (rep_->ioptions.access_hint_on_compaction_start) {
|
||||||
switch (.access_hint_on_compaction_start) {
|
|
||||||
case Options::NONE:
|
case Options::NONE:
|
||||||
break;
|
break;
|
||||||
case Options::NORMAL:
|
case Options::NORMAL:
|
||||||
@ -550,7 +548,6 @@ void BlockBasedTable::SetupForCompaction() {
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
compaction_optimized_ = true;
|
compaction_optimized_ = true;
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const TableProperties> BlockBasedTable::GetTableProperties()
|
std::shared_ptr<const TableProperties> BlockBasedTable::GetTableProperties()
|
||||||
|
@ -522,7 +522,7 @@ void ReadKeys(uint64_t num, uint32_t batch_size) {
|
|||||||
float time_per_op = (env->NowMicros() - start_time) * 1.0 / num;
|
float time_per_op = (env->NowMicros() - start_time) * 1.0 / num;
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Time taken per op is %.3fus (%.1f Mqps) with batch size of %u, "
|
"Time taken per op is %.3fus (%.1f Mqps) with batch size of %u, "
|
||||||
"# of found keys %ld\n",
|
"# of found keys %" PRId64 "\n",
|
||||||
time_per_op, 1.0 / time_per_op, batch_size, found_count);
|
time_per_op, 1.0 / time_per_op, batch_size, found_count);
|
||||||
}
|
}
|
||||||
} // namespace.
|
} // namespace.
|
||||||
|
@ -30,7 +30,8 @@ class TestFilterBitsBuilder : public FilterBitsBuilder {
|
|||||||
for (size_t i = 0; i < hash_entries_.size(); i++) {
|
for (size_t i = 0; i < hash_entries_.size(); i++) {
|
||||||
EncodeFixed32(data + i * 4, hash_entries_[i]);
|
EncodeFixed32(data + i * 4, hash_entries_[i]);
|
||||||
}
|
}
|
||||||
buf->reset(data);
|
const char* const_data = data;
|
||||||
|
buf->reset(const_data);
|
||||||
return Slice(data, len);
|
return Slice(data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -768,6 +768,41 @@ TEST(EnvPosixTest, LogBufferTest) {
|
|||||||
ASSERT_EQ(10, test_logger.char_x_count);
|
ASSERT_EQ(10, test_logger.char_x_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TestLogger2 : public Logger {
|
||||||
|
public:
|
||||||
|
explicit TestLogger2(size_t max_log_size) : max_log_size_(max_log_size) {}
|
||||||
|
virtual void Logv(const char* format, va_list ap) override {
|
||||||
|
char new_format[2000];
|
||||||
|
std::fill_n(new_format, sizeof(new_format), '2');
|
||||||
|
{
|
||||||
|
va_list backup_ap;
|
||||||
|
va_copy(backup_ap, ap);
|
||||||
|
int n = vsnprintf(new_format, sizeof(new_format) - 1, format, backup_ap);
|
||||||
|
// 48 bytes for extra information + bytes allocated
|
||||||
|
ASSERT_TRUE(
|
||||||
|
n <= 48 + static_cast<int>(max_log_size_ - sizeof(struct timeval)));
|
||||||
|
ASSERT_TRUE(n > static_cast<int>(max_log_size_ - sizeof(struct timeval)));
|
||||||
|
va_end(backup_ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size_t max_log_size_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(EnvPosixTest, LogBufferMaxSizeTest) {
|
||||||
|
char bytes9000[9000];
|
||||||
|
std::fill_n(bytes9000, sizeof(bytes9000), '1');
|
||||||
|
bytes9000[sizeof(bytes9000) - 1] = '\0';
|
||||||
|
|
||||||
|
for (size_t max_log_size = 256; max_log_size <= 1024;
|
||||||
|
max_log_size += 1024 - 256) {
|
||||||
|
TestLogger2 test_logger(max_log_size);
|
||||||
|
test_logger.SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);
|
||||||
|
LogBuffer log_buffer(InfoLogLevel::INFO_LEVEL, &test_logger);
|
||||||
|
LogToBuffer(&log_buffer, max_log_size, "%s", bytes9000);
|
||||||
|
log_buffer.FlushBufferToLog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace rocksdb
|
} // namespace rocksdb
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
@ -13,17 +13,17 @@ LogBuffer::LogBuffer(const InfoLogLevel log_level,
|
|||||||
Logger*info_log)
|
Logger*info_log)
|
||||||
: log_level_(log_level), info_log_(info_log) {}
|
: log_level_(log_level), info_log_(info_log) {}
|
||||||
|
|
||||||
void LogBuffer::AddLogToBuffer(const char* format, va_list ap) {
|
void LogBuffer::AddLogToBuffer(size_t max_log_size, const char* format,
|
||||||
|
va_list ap) {
|
||||||
if (!info_log_ || log_level_ < info_log_->GetInfoLogLevel()) {
|
if (!info_log_ || log_level_ < info_log_->GetInfoLogLevel()) {
|
||||||
// Skip the level because of its level.
|
// Skip the level because of its level.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t kLogSizeLimit = 512;
|
char* alloc_mem = arena_.AllocateAligned(max_log_size);
|
||||||
char* alloc_mem = arena_.AllocateAligned(kLogSizeLimit);
|
|
||||||
BufferedLog* buffered_log = new (alloc_mem) BufferedLog();
|
BufferedLog* buffered_log = new (alloc_mem) BufferedLog();
|
||||||
char* p = buffered_log->message;
|
char* p = buffered_log->message;
|
||||||
char* limit = alloc_mem + kLogSizeLimit - 1;
|
char* limit = alloc_mem + max_log_size - 1;
|
||||||
|
|
||||||
// store the time
|
// store the time
|
||||||
gettimeofday(&(buffered_log->now_tv), nullptr);
|
gettimeofday(&(buffered_log->now_tv), nullptr);
|
||||||
@ -61,11 +61,22 @@ void LogBuffer::FlushBufferToLog() {
|
|||||||
logs_.clear();
|
logs_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogToBuffer(LogBuffer* log_buffer, const char* format, ...) {
|
void LogToBuffer(LogBuffer* log_buffer, size_t max_log_size, const char* format,
|
||||||
|
...) {
|
||||||
if (log_buffer != nullptr) {
|
if (log_buffer != nullptr) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
log_buffer->AddLogToBuffer(format, ap);
|
log_buffer->AddLogToBuffer(max_log_size, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogToBuffer(LogBuffer* log_buffer, const char* format, ...) {
|
||||||
|
const size_t kDefaultMaxLogSize = 512;
|
||||||
|
if (log_buffer != nullptr) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
log_buffer->AddLogToBuffer(kDefaultMaxLogSize, format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,9 @@ class LogBuffer {
|
|||||||
// info_log: logger to write the logs to
|
// info_log: logger to write the logs to
|
||||||
LogBuffer(const InfoLogLevel log_level, Logger* info_log);
|
LogBuffer(const InfoLogLevel log_level, Logger* info_log);
|
||||||
|
|
||||||
// Add a log entry to the buffer.
|
// Add a log entry to the buffer. Use default max_log_size.
|
||||||
void AddLogToBuffer(const char* format, va_list ap);
|
// max_log_size indicates maximize log size, including some metadata.
|
||||||
|
void AddLogToBuffer(size_t max_log_size, const char* format, va_list ap);
|
||||||
|
|
||||||
size_t IsEmpty() const { return logs_.empty(); }
|
size_t IsEmpty() const { return logs_.empty(); }
|
||||||
|
|
||||||
@ -44,6 +45,10 @@ class LogBuffer {
|
|||||||
|
|
||||||
// Add log to the LogBuffer for a delayed info logging. It can be used when
|
// Add log to the LogBuffer for a delayed info logging. It can be used when
|
||||||
// we want to add some logs inside a mutex.
|
// we want to add some logs inside a mutex.
|
||||||
|
// max_log_size indicates maximize log size, including some metadata.
|
||||||
|
extern void LogToBuffer(LogBuffer* log_buffer, size_t max_log_size,
|
||||||
|
const char* format, ...);
|
||||||
|
// Same as previous function, but with default max log size.
|
||||||
extern void LogToBuffer(LogBuffer* log_buffer, const char* format, ...);
|
extern void LogToBuffer(LogBuffer* log_buffer, const char* format, ...);
|
||||||
|
|
||||||
} // namespace rocksdb
|
} // namespace rocksdb
|
||||||
|
@ -45,7 +45,7 @@ int AppendHumanBytes(uint64_t bytes, char* output, int len) {
|
|||||||
|
|
||||||
void AppendNumberTo(std::string* str, uint64_t num) {
|
void AppendNumberTo(std::string* str, uint64_t num) {
|
||||||
char buf[30];
|
char buf[30];
|
||||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long) num);
|
snprintf(buf, sizeof(buf), "%" PRIu64, num);
|
||||||
str->append(buf);
|
str->append(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
namespace rocksdb {
|
namespace rocksdb {
|
||||||
|
|
||||||
class Slice;
|
class Slice;
|
||||||
class WritableFile;
|
|
||||||
|
|
||||||
// Append a human-readable size in bytes
|
// Append a human-readable size in bytes
|
||||||
int AppendHumanBytes(uint64_t bytes, char* output, int len);
|
int AppendHumanBytes(uint64_t bytes, char* output, int len);
|
||||||
|
@ -59,7 +59,8 @@ ImmutableCFOptions::ImmutableCFOptions(const Options& options)
|
|||||||
use_fsync(options.use_fsync),
|
use_fsync(options.use_fsync),
|
||||||
compression(options.compression),
|
compression(options.compression),
|
||||||
compression_per_level(options.compression_per_level),
|
compression_per_level(options.compression_per_level),
|
||||||
compression_opts(options.compression_opts) {}
|
compression_opts(options.compression_opts),
|
||||||
|
access_hint_on_compaction_start(options.access_hint_on_compaction_start) {}
|
||||||
|
|
||||||
ColumnFamilyOptions::ColumnFamilyOptions()
|
ColumnFamilyOptions::ColumnFamilyOptions()
|
||||||
: comparator(BytewiseComparator()),
|
: comparator(BytewiseComparator()),
|
||||||
@ -273,8 +274,8 @@ void DBOptions::Dump(Logger* log) const {
|
|||||||
Log(log, " Options.disableDataSync: %d", disableDataSync);
|
Log(log, " Options.disableDataSync: %d", disableDataSync);
|
||||||
Log(log, " Options.use_fsync: %d", use_fsync);
|
Log(log, " Options.use_fsync: %d", use_fsync);
|
||||||
Log(log, " Options.max_log_file_size: %zu", max_log_file_size);
|
Log(log, " Options.max_log_file_size: %zu", max_log_file_size);
|
||||||
Log(log, "Options.max_manifest_file_size: %lu",
|
Log(log, "Options.max_manifest_file_size: %" PRIu64,
|
||||||
(unsigned long)max_manifest_file_size);
|
max_manifest_file_size);
|
||||||
Log(log, " Options.log_file_time_to_roll: %zu", log_file_time_to_roll);
|
Log(log, " Options.log_file_time_to_roll: %zu", log_file_time_to_roll);
|
||||||
Log(log, " Options.keep_log_file_num: %zu", keep_log_file_num);
|
Log(log, " Options.keep_log_file_num: %zu", keep_log_file_num);
|
||||||
Log(log, " Options.allow_os_buffer: %d", allow_os_buffer);
|
Log(log, " Options.allow_os_buffer: %d", allow_os_buffer);
|
||||||
@ -290,16 +291,16 @@ void DBOptions::Dump(Logger* log) const {
|
|||||||
table_cache_numshardbits);
|
table_cache_numshardbits);
|
||||||
Log(log, " Options.table_cache_remove_scan_count_limit: %d",
|
Log(log, " Options.table_cache_remove_scan_count_limit: %d",
|
||||||
table_cache_remove_scan_count_limit);
|
table_cache_remove_scan_count_limit);
|
||||||
Log(log, " Options.delete_obsolete_files_period_micros: %lu",
|
Log(log, " Options.delete_obsolete_files_period_micros: %" PRIu64,
|
||||||
(unsigned long)delete_obsolete_files_period_micros);
|
delete_obsolete_files_period_micros);
|
||||||
Log(log, " Options.max_background_compactions: %d",
|
Log(log, " Options.max_background_compactions: %d",
|
||||||
max_background_compactions);
|
max_background_compactions);
|
||||||
Log(log, " Options.max_background_flushes: %d",
|
Log(log, " Options.max_background_flushes: %d",
|
||||||
max_background_flushes);
|
max_background_flushes);
|
||||||
Log(log, " Options.WAL_ttl_seconds: %lu",
|
Log(log, " Options.WAL_ttl_seconds: %" PRIu64,
|
||||||
(unsigned long)WAL_ttl_seconds);
|
WAL_ttl_seconds);
|
||||||
Log(log, " Options.WAL_size_limit_MB: %lu",
|
Log(log, " Options.WAL_size_limit_MB: %" PRIu64,
|
||||||
(unsigned long)WAL_size_limit_MB);
|
WAL_size_limit_MB);
|
||||||
Log(log, " Options.manifest_preallocation_size: %zu",
|
Log(log, " Options.manifest_preallocation_size: %zu",
|
||||||
manifest_preallocation_size);
|
manifest_preallocation_size);
|
||||||
Log(log, " Options.allow_os_buffer: %d",
|
Log(log, " Options.allow_os_buffer: %d",
|
||||||
@ -322,8 +323,8 @@ void DBOptions::Dump(Logger* log) const {
|
|||||||
use_adaptive_mutex);
|
use_adaptive_mutex);
|
||||||
Log(log, " Options.rate_limiter: %p",
|
Log(log, " Options.rate_limiter: %p",
|
||||||
rate_limiter.get());
|
rate_limiter.get());
|
||||||
Log(log, " Options.bytes_per_sync: %lu",
|
Log(log, " Options.bytes_per_sync: %" PRIu64,
|
||||||
(unsigned long)bytes_per_sync);
|
bytes_per_sync);
|
||||||
} // DBOptions::Dump
|
} // DBOptions::Dump
|
||||||
|
|
||||||
void ColumnFamilyOptions::Dump(Logger* log) const {
|
void ColumnFamilyOptions::Dump(Logger* log) const {
|
||||||
@ -371,20 +372,20 @@ void ColumnFamilyOptions::Dump(Logger* log) const {
|
|||||||
level0_stop_writes_trigger);
|
level0_stop_writes_trigger);
|
||||||
Log(log," Options.max_mem_compaction_level: %d",
|
Log(log," Options.max_mem_compaction_level: %d",
|
||||||
max_mem_compaction_level);
|
max_mem_compaction_level);
|
||||||
Log(log," Options.target_file_size_base: %d",
|
Log(log," Options.target_file_size_base: %" PRIu64,
|
||||||
target_file_size_base);
|
target_file_size_base);
|
||||||
Log(log," Options.target_file_size_multiplier: %d",
|
Log(log," Options.target_file_size_multiplier: %d",
|
||||||
target_file_size_multiplier);
|
target_file_size_multiplier);
|
||||||
Log(log," Options.max_bytes_for_level_base: %lu",
|
Log(log," Options.max_bytes_for_level_base: %" PRIu64,
|
||||||
(unsigned long)max_bytes_for_level_base);
|
max_bytes_for_level_base);
|
||||||
Log(log," Options.max_bytes_for_level_multiplier: %d",
|
Log(log," Options.max_bytes_for_level_multiplier: %d",
|
||||||
max_bytes_for_level_multiplier);
|
max_bytes_for_level_multiplier);
|
||||||
for (int i = 0; i < num_levels; i++) {
|
for (int i = 0; i < num_levels; i++) {
|
||||||
Log(log,"Options.max_bytes_for_level_multiplier_addtl[%d]: %d",
|
Log(log,"Options.max_bytes_for_level_multiplier_addtl[%d]: %d",
|
||||||
i, max_bytes_for_level_multiplier_additional[i]);
|
i, max_bytes_for_level_multiplier_additional[i]);
|
||||||
}
|
}
|
||||||
Log(log," Options.max_sequential_skip_in_iterations: %lu",
|
Log(log," Options.max_sequential_skip_in_iterations: %" PRIu64,
|
||||||
(unsigned long)max_sequential_skip_in_iterations);
|
max_sequential_skip_in_iterations);
|
||||||
Log(log," Options.expanded_compaction_factor: %d",
|
Log(log," Options.expanded_compaction_factor: %d",
|
||||||
expanded_compaction_factor);
|
expanded_compaction_factor);
|
||||||
Log(log," Options.source_compaction_factor: %d",
|
Log(log," Options.source_compaction_factor: %d",
|
||||||
|
@ -177,7 +177,7 @@ bool GetOptionsFromStrings(
|
|||||||
} else if (o.first == "max_mem_compaction_level") {
|
} else if (o.first == "max_mem_compaction_level") {
|
||||||
new_options->max_mem_compaction_level = ParseInt(o.second);
|
new_options->max_mem_compaction_level = ParseInt(o.second);
|
||||||
} else if (o.first == "target_file_size_base") {
|
} else if (o.first == "target_file_size_base") {
|
||||||
new_options->target_file_size_base = ParseInt(o.second);
|
new_options->target_file_size_base = ParseUint64(o.second);
|
||||||
} else if (o.first == "target_file_size_multiplier") {
|
} else if (o.first == "target_file_size_multiplier") {
|
||||||
new_options->target_file_size_multiplier = ParseInt(o.second);
|
new_options->target_file_size_multiplier = ParseInt(o.second);
|
||||||
} else if (o.first == "max_bytes_for_level_base") {
|
} else if (o.first == "max_bytes_for_level_base") {
|
||||||
|
@ -177,7 +177,7 @@ TEST(OptionsTest, GetOptionsFromStringsTest) {
|
|||||||
ASSERT_EQ(new_opt.level0_slowdown_writes_trigger, 9);
|
ASSERT_EQ(new_opt.level0_slowdown_writes_trigger, 9);
|
||||||
ASSERT_EQ(new_opt.level0_stop_writes_trigger, 10);
|
ASSERT_EQ(new_opt.level0_stop_writes_trigger, 10);
|
||||||
ASSERT_EQ(new_opt.max_mem_compaction_level, 11);
|
ASSERT_EQ(new_opt.max_mem_compaction_level, 11);
|
||||||
ASSERT_EQ(new_opt.target_file_size_base, 12);
|
ASSERT_EQ(new_opt.target_file_size_base, static_cast<uint64_t>(12));
|
||||||
ASSERT_EQ(new_opt.target_file_size_multiplier, 13);
|
ASSERT_EQ(new_opt.target_file_size_multiplier, 13);
|
||||||
ASSERT_EQ(new_opt.max_bytes_for_level_base, 14U);
|
ASSERT_EQ(new_opt.max_bytes_for_level_base, 14U);
|
||||||
ASSERT_EQ(new_opt.max_bytes_for_level_multiplier, 15);
|
ASSERT_EQ(new_opt.max_bytes_for_level_multiplier, 15);
|
||||||
|
@ -20,7 +20,6 @@ class ReadableWriteBatch : public WriteBatch {
|
|||||||
Status GetEntryFromDataOffset(size_t data_offset, WriteType* type, Slice* Key,
|
Status GetEntryFromDataOffset(size_t data_offset, WriteType* type, Slice* Key,
|
||||||
Slice* value, Slice* blob) const;
|
Slice* value, Slice* blob) const;
|
||||||
};
|
};
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// Key used by skip list, as the binary searchable index of WriteBatchWithIndex.
|
// Key used by skip list, as the binary searchable index of WriteBatchWithIndex.
|
||||||
struct WriteBatchIndexEntry {
|
struct WriteBatchIndexEntry {
|
||||||
@ -38,44 +37,28 @@ struct WriteBatchIndexEntry {
|
|||||||
|
|
||||||
class WriteBatchEntryComparator {
|
class WriteBatchEntryComparator {
|
||||||
public:
|
public:
|
||||||
WriteBatchEntryComparator(const Comparator* comparator,
|
WriteBatchEntryComparator(const Comparator* default_comparator,
|
||||||
const ReadableWriteBatch* write_batch)
|
const ReadableWriteBatch* write_batch)
|
||||||
: comparator_(comparator), write_batch_(write_batch) {}
|
: default_comparator_(default_comparator), write_batch_(write_batch) {}
|
||||||
// Compare a and b. Return a negative value if a is less than b, 0 if they
|
// Compare a and b. Return a negative value if a is less than b, 0 if they
|
||||||
// are equal, and a positive value if a is greater than b
|
// are equal, and a positive value if a is greater than b
|
||||||
int operator()(const WriteBatchIndexEntry* entry1,
|
int operator()(const WriteBatchIndexEntry* entry1,
|
||||||
const WriteBatchIndexEntry* entry2) const;
|
const WriteBatchIndexEntry* entry2) const;
|
||||||
|
|
||||||
|
void SetComparatorForCF(uint32_t column_family_id,
|
||||||
|
const Comparator* comparator) {
|
||||||
|
cf_comparator_map_[column_family_id] = comparator;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Comparator* comparator_;
|
const Comparator* default_comparator_;
|
||||||
|
std::unordered_map<uint32_t, const Comparator*> cf_comparator_map_;
|
||||||
const ReadableWriteBatch* write_batch_;
|
const ReadableWriteBatch* write_batch_;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef SkipList<WriteBatchIndexEntry*, const WriteBatchEntryComparator&>
|
typedef SkipList<WriteBatchIndexEntry*, const WriteBatchEntryComparator&>
|
||||||
WriteBatchEntrySkipList;
|
WriteBatchEntrySkipList;
|
||||||
|
|
||||||
struct WriteBatchWithIndex::Rep {
|
|
||||||
Rep(const Comparator* index_comparator, size_t reserved_bytes = 0)
|
|
||||||
: write_batch(reserved_bytes),
|
|
||||||
comparator(index_comparator, &write_batch),
|
|
||||||
skip_list(comparator, &arena) {}
|
|
||||||
ReadableWriteBatch write_batch;
|
|
||||||
WriteBatchEntryComparator comparator;
|
|
||||||
Arena arena;
|
|
||||||
WriteBatchEntrySkipList skip_list;
|
|
||||||
|
|
||||||
WriteBatchIndexEntry* GetEntry(ColumnFamilyHandle* column_family) {
|
|
||||||
return GetEntryWithCfId(GetColumnFamilyID(column_family));
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteBatchIndexEntry* GetEntryWithCfId(uint32_t column_family_id) {
|
|
||||||
auto* mem = arena.Allocate(sizeof(WriteBatchIndexEntry));
|
|
||||||
auto* index_entry = new (mem)
|
|
||||||
WriteBatchIndexEntry(write_batch.GetDataSize(), column_family_id);
|
|
||||||
return index_entry;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class WBWIIteratorImpl : public WBWIIterator {
|
class WBWIIteratorImpl : public WBWIIterator {
|
||||||
public:
|
public:
|
||||||
WBWIIteratorImpl(uint32_t column_family_id,
|
WBWIIteratorImpl(uint32_t column_family_id,
|
||||||
@ -138,6 +121,35 @@ class WBWIIteratorImpl : public WBWIIterator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
struct WriteBatchWithIndex::Rep {
|
||||||
|
Rep(const Comparator* index_comparator, size_t reserved_bytes = 0)
|
||||||
|
: write_batch(reserved_bytes),
|
||||||
|
comparator(index_comparator, &write_batch),
|
||||||
|
skip_list(comparator, &arena) {}
|
||||||
|
ReadableWriteBatch write_batch;
|
||||||
|
WriteBatchEntryComparator comparator;
|
||||||
|
Arena arena;
|
||||||
|
WriteBatchEntrySkipList skip_list;
|
||||||
|
|
||||||
|
WriteBatchIndexEntry* GetEntry(ColumnFamilyHandle* column_family) {
|
||||||
|
uint32_t cf_id = GetColumnFamilyID(column_family);
|
||||||
|
const auto* cf_cmp = GetColumnFamilyUserComparator(column_family);
|
||||||
|
if (cf_cmp != nullptr) {
|
||||||
|
comparator.SetComparatorForCF(cf_id, cf_cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetEntryWithCfId(cf_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteBatchIndexEntry* GetEntryWithCfId(uint32_t column_family_id) {
|
||||||
|
auto* mem = arena.Allocate(sizeof(WriteBatchIndexEntry));
|
||||||
|
auto* index_entry = new (mem)
|
||||||
|
WriteBatchIndexEntry(write_batch.GetDataSize(), column_family_id);
|
||||||
|
return index_entry;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Status ReadableWriteBatch::GetEntryFromDataOffset(size_t data_offset,
|
Status ReadableWriteBatch::GetEntryFromDataOffset(size_t data_offset,
|
||||||
WriteType* type, Slice* Key,
|
WriteType* type, Slice* Key,
|
||||||
@ -179,9 +191,9 @@ Status ReadableWriteBatch::GetEntryFromDataOffset(size_t data_offset,
|
|||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteBatchWithIndex::WriteBatchWithIndex(const Comparator* index_comparator,
|
WriteBatchWithIndex::WriteBatchWithIndex(
|
||||||
size_t reserved_bytes)
|
const Comparator* default_index_comparator, size_t reserved_bytes)
|
||||||
: rep(new Rep(index_comparator, reserved_bytes)) {}
|
: rep(new Rep(default_index_comparator, reserved_bytes)) {}
|
||||||
|
|
||||||
WriteBatchWithIndex::~WriteBatchWithIndex() { delete rep; }
|
WriteBatchWithIndex::~WriteBatchWithIndex() { delete rep; }
|
||||||
|
|
||||||
@ -287,7 +299,14 @@ int WriteBatchEntryComparator::operator()(
|
|||||||
key2 = *(entry2->search_key);
|
key2 = *(entry2->search_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmp = comparator_->Compare(key1, key2);
|
int cmp;
|
||||||
|
auto comparator_for_cf = cf_comparator_map_.find(entry1->column_family);
|
||||||
|
if (comparator_for_cf != cf_comparator_map_.end()) {
|
||||||
|
cmp = comparator_for_cf->second->Compare(key1, key2);
|
||||||
|
} else {
|
||||||
|
cmp = default_comparator_->Compare(key1, key2);
|
||||||
|
}
|
||||||
|
|
||||||
if (cmp != 0) {
|
if (cmp != 0) {
|
||||||
return cmp;
|
return cmp;
|
||||||
} else if (entry1->offset > entry2->offset) {
|
} else if (entry1->offset > entry2->offset) {
|
||||||
|
@ -19,12 +19,16 @@ namespace rocksdb {
|
|||||||
namespace {
|
namespace {
|
||||||
class ColumnFamilyHandleImplDummy : public ColumnFamilyHandleImpl {
|
class ColumnFamilyHandleImplDummy : public ColumnFamilyHandleImpl {
|
||||||
public:
|
public:
|
||||||
explicit ColumnFamilyHandleImplDummy(int id)
|
explicit ColumnFamilyHandleImplDummy(int id, const Comparator* comparator)
|
||||||
: ColumnFamilyHandleImpl(nullptr, nullptr, nullptr), id_(id) {}
|
: ColumnFamilyHandleImpl(nullptr, nullptr, nullptr),
|
||||||
|
id_(id),
|
||||||
|
comparator_(comparator) {}
|
||||||
uint32_t GetID() const override { return id_; }
|
uint32_t GetID() const override { return id_; }
|
||||||
|
const Comparator* user_comparator() const override { return comparator_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t id_;
|
uint32_t id_;
|
||||||
|
const Comparator* comparator_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
@ -90,8 +94,9 @@ TEST(WriteBatchWithIndexTest, TestValueAsSecondaryIndex) {
|
|||||||
index_map[e.value].push_back(&e);
|
index_map[e.value].push_back(&e);
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteBatchWithIndex batch(BytewiseComparator(), 20);
|
WriteBatchWithIndex batch(nullptr, 20);
|
||||||
ColumnFamilyHandleImplDummy data(6), index(8);
|
ColumnFamilyHandleImplDummy data(6, BytewiseComparator());
|
||||||
|
ColumnFamilyHandleImplDummy index(8, BytewiseComparator());
|
||||||
for (auto& e : entries) {
|
for (auto& e : entries) {
|
||||||
if (e.type == kPutRecord) {
|
if (e.type == kPutRecord) {
|
||||||
batch.Put(&data, e.key, e.value);
|
batch.Put(&data, e.key, e.value);
|
||||||
@ -230,6 +235,107 @@ TEST(WriteBatchWithIndexTest, TestValueAsSecondaryIndex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ReverseComparator : public Comparator {
|
||||||
|
public:
|
||||||
|
ReverseComparator() {}
|
||||||
|
|
||||||
|
virtual const char* Name() const override {
|
||||||
|
return "rocksdb.ReverseComparator";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int Compare(const Slice& a, const Slice& b) const override {
|
||||||
|
return 0 - BytewiseComparator()->Compare(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void FindShortestSeparator(std::string* start,
|
||||||
|
const Slice& limit) const {}
|
||||||
|
virtual void FindShortSuccessor(std::string* key) const {}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(WriteBatchWithIndexTest, TestComparatorForCF) {
|
||||||
|
ReverseComparator reverse_cmp;
|
||||||
|
ColumnFamilyHandleImplDummy cf1(6, nullptr);
|
||||||
|
ColumnFamilyHandleImplDummy reverse_cf(66, &reverse_cmp);
|
||||||
|
ColumnFamilyHandleImplDummy cf2(88, BytewiseComparator());
|
||||||
|
WriteBatchWithIndex batch(BytewiseComparator(), 20);
|
||||||
|
|
||||||
|
batch.Put(&cf1, "ddd", "");
|
||||||
|
batch.Put(&cf2, "aaa", "");
|
||||||
|
batch.Put(&cf2, "eee", "");
|
||||||
|
batch.Put(&cf1, "ccc", "");
|
||||||
|
batch.Put(&reverse_cf, "a11", "");
|
||||||
|
batch.Put(&cf1, "bbb", "");
|
||||||
|
batch.Put(&reverse_cf, "a33", "");
|
||||||
|
batch.Put(&reverse_cf, "a22", "");
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&cf1));
|
||||||
|
iter->Seek("");
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(iter->Valid());
|
||||||
|
ASSERT_EQ("bbb", iter->Entry().key.ToString());
|
||||||
|
iter->Next();
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(iter->Valid());
|
||||||
|
ASSERT_EQ("ccc", iter->Entry().key.ToString());
|
||||||
|
iter->Next();
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(iter->Valid());
|
||||||
|
ASSERT_EQ("ddd", iter->Entry().key.ToString());
|
||||||
|
iter->Next();
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(!iter->Valid());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&cf2));
|
||||||
|
iter->Seek("");
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(iter->Valid());
|
||||||
|
ASSERT_EQ("aaa", iter->Entry().key.ToString());
|
||||||
|
iter->Next();
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(iter->Valid());
|
||||||
|
ASSERT_EQ("eee", iter->Entry().key.ToString());
|
||||||
|
iter->Next();
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(!iter->Valid());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_ptr<WBWIIterator> iter(batch.NewIterator(&reverse_cf));
|
||||||
|
iter->Seek("");
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(!iter->Valid());
|
||||||
|
|
||||||
|
iter->Seek("z");
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(iter->Valid());
|
||||||
|
ASSERT_EQ("a33", iter->Entry().key.ToString());
|
||||||
|
iter->Next();
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(iter->Valid());
|
||||||
|
ASSERT_EQ("a22", iter->Entry().key.ToString());
|
||||||
|
iter->Next();
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(iter->Valid());
|
||||||
|
ASSERT_EQ("a11", iter->Entry().key.ToString());
|
||||||
|
iter->Next();
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(!iter->Valid());
|
||||||
|
|
||||||
|
iter->Seek("a22");
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(iter->Valid());
|
||||||
|
ASSERT_EQ("a22", iter->Entry().key.ToString());
|
||||||
|
|
||||||
|
iter->Seek("a13");
|
||||||
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_TRUE(iter->Valid());
|
||||||
|
ASSERT_EQ("a11", iter->Entry().key.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char** argv) { return rocksdb::test::RunAllTests(); }
|
int main(int argc, char** argv) { return rocksdb::test::RunAllTests(); }
|
||||||
|
Loading…
Reference in New Issue
Block a user