fdf882ded2
Summary: When dynamically linking two binaries together, different builds of RocksDB from two sources might cause errors. To provide a tool for user to solve the problem, the RocksDB namespace is changed to a flag which can be overridden in build time. Pull Request resolved: https://github.com/facebook/rocksdb/pull/6433 Test Plan: Build release, all and jtest. Try to build with ROCKSDB_NAMESPACE with another flag. Differential Revision: D19977691 fbshipit-source-id: aa7f2d0972e1c31d75339ac48478f34f6cfcfb3e
142 lines
3.4 KiB
C++
142 lines
3.4 KiB
C++
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under both the GPLv2 (found in the
|
|
// COPYING file in the root directory) and Apache 2.0 License
|
|
// (found in the LICENSE.Apache file in the root directory).
|
|
//
|
|
#include "rocksdb/status.h"
|
|
#include "rocksdb/env.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <vector>
|
|
#include "test_util/testharness.h"
|
|
#include "util/coding.h"
|
|
|
|
namespace ROCKSDB_NAMESPACE {
|
|
|
|
class LockTest : public testing::Test {
|
|
public:
|
|
static LockTest* current_;
|
|
std::string file_;
|
|
ROCKSDB_NAMESPACE::Env* env_;
|
|
|
|
LockTest()
|
|
: file_(test::PerThreadDBPath("db_testlock_file")),
|
|
env_(ROCKSDB_NAMESPACE::Env::Default()) {
|
|
current_ = this;
|
|
}
|
|
|
|
~LockTest() override {}
|
|
|
|
Status LockFile(FileLock** db_lock) {
|
|
return env_->LockFile(file_, db_lock);
|
|
}
|
|
|
|
Status UnlockFile(FileLock* db_lock) {
|
|
return env_->UnlockFile(db_lock);
|
|
}
|
|
|
|
bool AssertFileIsLocked(){
|
|
return CheckFileLock( /* lock_expected = */ true);
|
|
}
|
|
|
|
bool AssertFileIsNotLocked(){
|
|
return CheckFileLock( /* lock_expected = */ false);
|
|
}
|
|
|
|
bool CheckFileLock(bool lock_expected){
|
|
// We need to fork to check the fcntl lock as we need
|
|
// to open and close the file from a different process
|
|
// to avoid either releasing the lock on close, or not
|
|
// contending for it when requesting a lock.
|
|
|
|
#ifdef OS_WIN
|
|
|
|
// WaitForSingleObject and GetExitCodeProcess can do what waitpid does.
|
|
// TODO - implement on Windows
|
|
return true;
|
|
|
|
#else
|
|
|
|
pid_t pid = fork();
|
|
if ( 0 == pid ) {
|
|
// child process
|
|
int exit_val = EXIT_FAILURE;
|
|
int fd = open(file_.c_str(), O_RDWR | O_CREAT, 0644);
|
|
if (fd < 0) {
|
|
// could not open file, could not check if it was locked
|
|
fprintf( stderr, "Open on on file %s failed.\n",file_.c_str());
|
|
exit(exit_val);
|
|
}
|
|
|
|
struct flock f;
|
|
memset(&f, 0, sizeof(f));
|
|
f.l_type = (F_WRLCK);
|
|
f.l_whence = SEEK_SET;
|
|
f.l_start = 0;
|
|
f.l_len = 0; // Lock/unlock entire file
|
|
int value = fcntl(fd, F_SETLK, &f);
|
|
if( value == -1 ){
|
|
if( lock_expected ){
|
|
exit_val = EXIT_SUCCESS;
|
|
}
|
|
} else {
|
|
if( ! lock_expected ){
|
|
exit_val = EXIT_SUCCESS;
|
|
}
|
|
}
|
|
close(fd); // lock is released for child process
|
|
exit(exit_val);
|
|
} else if (pid > 0) {
|
|
// parent process
|
|
int status;
|
|
while (-1 == waitpid(pid, &status, 0));
|
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
|
// child process exited with non success status
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
} else {
|
|
fprintf( stderr, "Fork failed\n" );
|
|
return false;
|
|
}
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
};
|
|
LockTest* LockTest::current_;
|
|
|
|
TEST_F(LockTest, LockBySameThread) {
|
|
FileLock* lock1;
|
|
FileLock* lock2;
|
|
|
|
// acquire a lock on a file
|
|
ASSERT_OK(LockFile(&lock1));
|
|
|
|
// check the file is locked
|
|
ASSERT_TRUE( AssertFileIsLocked() );
|
|
|
|
// re-acquire the lock on the same file. This should fail.
|
|
ASSERT_TRUE(LockFile(&lock2).IsIOError());
|
|
|
|
// check the file is locked
|
|
ASSERT_TRUE( AssertFileIsLocked() );
|
|
|
|
// release the lock
|
|
ASSERT_OK(UnlockFile(lock1));
|
|
|
|
// check the file is not locked
|
|
ASSERT_TRUE( AssertFileIsNotLocked() );
|
|
|
|
}
|
|
|
|
} // namespace ROCKSDB_NAMESPACE
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|