Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for loading dynamic libraries into the RocksDB environment #5281

Closed
wants to merge 43 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
6b6e221
Test
mrambacher Oct 24, 2018
c804c5c
Add DynamicLibrary to environment object
mrambacher Oct 24, 2018
8fec86f
Add Exension and ExtensionFactory classes
mrambacher Oct 24, 2018
89ab886
Add Extension and ExtensionFactory
mrambacher Nov 1, 2018
25aca89
disabling hanging tests
Nov 1, 2018
eb6472b
one more file with disabled tests
Nov 2, 2018
fc8652e
yet one more file to disable a test
Nov 2, 2018
cb3b805
Merge branch 'master' of https://github.com/facebook/rocksdb
mrambacher Jan 14, 2019
acba221
dl library on LINUX
Feb 12, 2019
f174e6e
Merge branch 'master' of https://github.ooa.sttgts.com/STTOOA/rocksdb
mrambacher Feb 13, 2019
68c839b
Test
mrambacher Oct 24, 2018
c6ced75
Add DynamicLibrary to environment object
mrambacher Oct 24, 2018
c2c8aaa
Add Exension and ExtensionFactory classes
mrambacher Oct 24, 2018
d5e13f1
Add Extension and ExtensionFactory
mrambacher Nov 1, 2018
48d5eb9
disabling hanging tests
Nov 1, 2018
739534e
one more file with disabled tests
Nov 2, 2018
a7385a9
yet one more file to disable a test
Nov 2, 2018
5f550b9
dl library on LINUX
Feb 12, 2019
65bda3f
Undo unintended changes made by SST to master
mrambacher Apr 18, 2019
6080376
Fix undo of SST changes
mrambacher Apr 18, 2019
410c22e
Mark the .DS_Store files as ignore
mrambacher Apr 18, 2019
59c2623
Merge branch 'master' of https://github.ooa.sttgts.com/STTOOA/rocksdb
mrambacher Apr 18, 2019
388cfc2
Revert "Merge branch 'master' of https://github.ooa.sttgts.com/STTOOA…
mrambacher Apr 19, 2019
aef1c55
Add Dynamic Library Support to the RocksDB Environment object
mrambacher Apr 19, 2019
2cf624a
Attempt to remove Extensions from Master
mrambacher Apr 19, 2019
c769f07
Revert "Add Exension and ExtensionFactory classes"
mrambacher Apr 19, 2019
22d2c18
Revert "Test"
mrambacher Apr 19, 2019
8f02905
Revert "disabling hanging tests"
mrambacher Apr 19, 2019
91c38f8
Revert "one more file with disabled tests"
mrambacher Apr 19, 2019
732e63b
Revert "yet one more file to disable a test"
mrambacher Apr 19, 2019
5e76fd8
Fix merge issuers
mrambacher Apr 19, 2019
480e8f3
Merge branch 'master' into dynamic-library
mrambacher Apr 19, 2019
0f5205f
Fix missing std:: for namespace
mrambacher Apr 19, 2019
6b97cc8
Add a search path option to the LoadLibrary API.
mrambacher May 6, 2019
0e65163
Fix DynamicLibrary based on review comments
mrambacher May 7, 2019
2e4bfd0
Add an assert to verify result is valid in LoadLibrary per review com…
mrambacher May 8, 2019
c002441
Changed the dynamic library test to use the RocksDB Library if found
mrambacher May 16, 2019
b172de5
Check whether to add -dl in build_detect_platform
riversand963 May 22, 2019
eeebf4f
Remove undesired virtual keyword
riversand963 May 22, 2019
2257aec
Adjust format with `make format`
riversand963 May 22, 2019
af80f43
Add glibc as an external dep of RocksDB in buck
riversand963 May 22, 2019
f99fe2a
Commit changes after run buckifier
riversand963 May 23, 2019
38b01d3
Remove glibc from external deps
riversand963 May 24, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -47,6 +47,7 @@ rocksdb_undump
db_test2
trace_analyzer
trace_analyzer_test
.DS_Store

java/out
java/target
Expand Down
1 change: 1 addition & 0 deletions TARGETS
Expand Up @@ -30,6 +30,7 @@ ROCKSDB_COMPILER_FLAGS = [
"-DROCKSDB_PTHREAD_ADAPTIVE_MUTEX",
"-DROCKSDB_BACKTRACE",
"-Wnarrowing",
"-DROCKSDB_NO_DYNAMIC_EXTENSION",
]

ROCKSDB_EXTERNAL_DEPS = [
Expand Down
1 change: 1 addition & 0 deletions buckifier/targets_cfg.py
Expand Up @@ -35,6 +35,7 @@
"-DROCKSDB_PTHREAD_ADAPTIVE_MUTEX",
"-DROCKSDB_BACKTRACE",
"-Wnarrowing",
"-DROCKSDB_NO_DYNAMIC_EXTENSION",
]

ROCKSDB_EXTERNAL_DEPS = [
Expand Down
13 changes: 13 additions & 0 deletions build_tools/build_detect_platform
Expand Up @@ -596,6 +596,19 @@ EOF
fi
fi

if [ "$FBCODE_BUILD" != "true" -a "$PLATFORM" = OS_LINUX ]; then
$CXX $COMMON_FLAGS $PLATFORM_SHARED_CFLAGS -x c++ -c - -o test_dl.o 2>/dev/null <<EOF
void dummy_func() {}
EOF
if [ "$?" = 0 ]; then
$CXX $COMMON_FLAGS $PLATFORM_SHARED_LDFLAGS test_dl.o -o /dev/null 2>/dev/null
if [ "$?" = 0 ]; then
EXEC_LDFLAGS+="-ldl"
rm -f test_dl.o
fi
fi
fi

PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS"
PLATFORM_CXXFLAGS="$PLATFORM_CXXFLAGS $COMMON_FLAGS"

Expand Down
99 changes: 99 additions & 0 deletions env/env_posix.cc
Expand Up @@ -7,8 +7,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors
#include <dirent.h>
#ifndef ROCKSDB_NO_DYNAMIC_EXTENSION
#include <dlfcn.h>
#endif
#include <errno.h>
#include <fcntl.h>

#if defined(OS_LINUX)
#include <linux/fs.h>
#endif
Expand Down Expand Up @@ -69,6 +73,17 @@
#endif

namespace rocksdb {
#if defined(OS_WIN)
static const std::string kSharedLibExt = ".dll";
static const char kPathSeparator = ';';
#else
static const char kPathSeparator = ':';
#if defined(OS_MACOSX)
static const std::string kSharedLibExt = ".dylib";
#else
static const std::string kSharedLibExt = ".so";
#endif
#endif

namespace {

Expand Down Expand Up @@ -115,6 +130,32 @@ int cloexec_flags(int flags, const EnvOptions* options) {
return flags;
}

#ifndef ROCKSDB_NO_DYNAMIC_EXTENSION
class PosixDynamicLibrary : public DynamicLibrary {
public:
PosixDynamicLibrary(const std::string& name, void* handle)
: name_(name), handle_(handle) {}
~PosixDynamicLibrary() override { dlclose(handle_); }

Status LoadSymbol(const std::string& sym_name, FunctionPtr* func) override {
char* err = dlerror(); // Clear any old error
*func = (FunctionPtr)dlsym(handle_, sym_name.c_str());
if (*func != nullptr) {
return Status::OK();
} else {
err = dlerror();
return Status::NotFound("Error finding symbol: " + sym_name, err);
}
}

const char* Name() const override { return name_.c_str(); }

private:
std::string name_;
void* handle_;
};
#endif // !ROCKSDB_NO_DYNAMIC_EXTENSION

class PosixEnv : public Env {
public:
PosixEnv();
Expand Down Expand Up @@ -729,6 +770,64 @@ class PosixEnv : public Env {
return result;
}

#ifndef ROCKSDB_NO_DYNAMIC_EXTENSION
/**
* Loads the named library into the result.
* If the input name is empty, the current executable is loaded
* On *nix systems, a "lib" prefix is added to the name if one is not supplied
* Comparably, the appropriate shared library extension is added to the name
* if not supplied. If search_path is not specified, the shared library will
* be loaded using the default path (LD_LIBRARY_PATH) If search_path is
* specified, the shared library will be searched for in the directories
* provided by the search path
*/
Status LoadLibrary(const std::string& name, const std::string& path,
std::shared_ptr<DynamicLibrary>* result) override {
Status status;
assert(result != nullptr);
if (name.empty()) {
void* hndl = dlopen(NULL, RTLD_NOW);
if (hndl != nullptr) {
result->reset(new PosixDynamicLibrary(name, hndl));
return Status::OK();
}
} else {
std::string library_name = name;
riversand963 marked this conversation as resolved.
Show resolved Hide resolved
if (library_name.find(kSharedLibExt) == std::string::npos) {
library_name = library_name + kSharedLibExt;
}
#if !defined(OS_WIN)
if (library_name.find('/') == std::string::npos &&
library_name.compare(0, 3, "lib") != 0) {
library_name = "lib" + library_name;
}
#endif
if (path.empty()) {
void* hndl = dlopen(library_name.c_str(), RTLD_NOW);
if (hndl != nullptr) {
result->reset(new PosixDynamicLibrary(library_name, hndl));
return Status::OK();
}
} else {
std::string local_path;
std::stringstream ss(path);
while (getline(ss, local_path, kPathSeparator)) {
if (!path.empty()) {
std::string full_name = local_path + "/" + library_name;
void* hndl = dlopen(full_name.c_str(), RTLD_NOW);
if (hndl != nullptr) {
result->reset(new PosixDynamicLibrary(full_name, hndl));
return Status::OK();
}
}
}
}
}
return Status::IOError(
IOErrorMsg("Failed to open shared library: xs", name), dlerror());
}
#endif // !ROCKSDB_NO_DYNAMIC_EXTENSION

void Schedule(void (*function)(void* arg1), void* arg, Priority pri = LOW,
void* tag = nullptr,
void (*unschedFunction)(void* arg) = nullptr) override;
Expand Down
46 changes: 46 additions & 0 deletions env/env_test.cc
Expand Up @@ -247,6 +247,52 @@ TEST_F(EnvPosixTest, MemoryMappedFileBuffer) {
ASSERT_EQ(expected_data, actual_data);
}

#ifndef ROCKSDB_NO_DYNAMIC_EXTENSION
TEST_F(EnvPosixTest, LoadRocksDBLibrary) {
std::shared_ptr<DynamicLibrary> library;
std::function<void*(void*, const char*)> function;
Status status = env_->LoadLibrary("no-such-library", "", &library);
ASSERT_NOK(status);
ASSERT_EQ(nullptr, library.get());
status = env_->LoadLibrary("rocksdb", "", &library);
if (status.ok()) { // If we have can find a rocksdb shared library
ASSERT_NE(nullptr, library.get());
ASSERT_OK(library->LoadFunction("rocksdb_create_default_env",
&function)); // from C definition
ASSERT_NE(nullptr, function);
ASSERT_NOK(library->LoadFunction("no-such-method", &function));
ASSERT_EQ(nullptr, function);
ASSERT_OK(env_->LoadLibrary(library->Name(), "", &library));
} else {
ASSERT_EQ(nullptr, library.get());
}
}
#endif // !ROCKSDB_NO_DYNAMIC_EXTENSION

#if !defined(OS_WIN) && !defined(ROCKSDB_NO_DYNAMIC_EXTENSION)
TEST_F(EnvPosixTest, LoadRocksDBLibraryWithSearchPath) {
std::shared_ptr<DynamicLibrary> library;
std::function<void*(void*, const char*)> function;
ASSERT_NOK(env_->LoadLibrary("no-such-library", "/tmp", &library));
ASSERT_EQ(nullptr, library.get());
ASSERT_NOK(env_->LoadLibrary("dl", "/tmp", &library));
ASSERT_EQ(nullptr, library.get());
Status status = env_->LoadLibrary("rocksdb", "/tmp:./", &library);
if (status.ok()) {
ASSERT_NE(nullptr, library.get());
ASSERT_OK(env_->LoadLibrary(library->Name(), "", &library));
}
char buff[1024];
std::string cwd = getcwd(buff, sizeof(buff));

status = env_->LoadLibrary("rocksdb", "/tmp:" + cwd, &library);
if (status.ok()) {
ASSERT_NE(nullptr, library.get());
ASSERT_OK(env_->LoadLibrary(library->Name(), "", &library));
}
}
#endif // !OS_WIN && !ROCKSDB_NO_DYNAMIC_EXTENSION

TEST_P(EnvPosixTestWithParam, UnSchedule) {
std::atomic<bool> called(false);
env_->SetBackgroundThreads(1, Env::LOW);
Expand Down
42 changes: 42 additions & 0 deletions include/rocksdb/env.h
Expand Up @@ -41,6 +41,7 @@

namespace rocksdb {

class DynamicLibrary;
class FileLock;
class Logger;
class RandomAccessFile;
Expand Down Expand Up @@ -321,6 +322,18 @@ class Env {
// REQUIRES: lock has not already been unlocked.
virtual Status UnlockFile(FileLock* lock) = 0;

// Opens `lib_name` as a dynamic library.
// If the 'search_path' is specified, breaks the path into its components
// based on the appropriate platform separator (";" or ";") and looks for the
// library in those directories. If 'search path is not specified, uses the
// default library path search mechanism (such as LD_LIBRARY_PATH). On
// success, stores a dynamic library in `*result`.
virtual Status LoadLibrary(const std::string& /*lib_name*/,
const std::string& /*search_path */,
std::shared_ptr<DynamicLibrary>* /*result*/) {
return Status::NotSupported("LoadLibrary is not implemented in this Env");
}

// Priority for scheduling job in thread pool
enum Priority { BOTTOM, LOW, HIGH, USER, TOTAL };

Expand Down Expand Up @@ -948,6 +961,29 @@ class FileLock {
void operator=(const FileLock&);
};

class DynamicLibrary {
public:
typedef void* (*FunctionPtr)();
virtual ~DynamicLibrary() {}

/** Returns the name of the dynamic library */
virtual const char* Name() const = 0;

/**
* Loads the symbol for sym_name from the library and updates the input
* function. Returns the loaded symbol
*/
template <typename T>
Status LoadFunction(const std::string& sym_name, std::function<T>* function) {
FunctionPtr ptr;
Status s = LoadSymbol(sym_name, &ptr);
*function = reinterpret_cast<T*>(ptr);
return s;
}
/** Loads and returns the symbol for sym_name from the library */
virtual Status LoadSymbol(const std::string& sym_name, FunctionPtr* func) = 0;
};

extern void LogFlush(const std::shared_ptr<Logger>& info_log);

extern void Log(const InfoLogLevel log_level,
Expand Down Expand Up @@ -1138,6 +1174,12 @@ class EnvWrapper : public Env {

Status UnlockFile(FileLock* l) override { return target_->UnlockFile(l); }

Status LoadLibrary(const std::string& lib_name,
const std::string& search_path,
std::shared_ptr<DynamicLibrary>* result) override {
return target_->LoadLibrary(lib_name, search_path, result);
}

void Schedule(void (*f)(void* arg), void* a, Priority pri,
void* tag = nullptr, void (*u)(void* arg) = nullptr) override {
return target_->Schedule(f, a, pri, tag, u);
Expand Down