Packages
rocksdb
2.6.0
3.1.1
3.1.0
3.0.0
2.6.2
2.6.1
retired
2.6.0
retired
2.5.0
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.0
1.9.0
1.8.0
1.7.0
1.6.0
1.5.1
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.1
1.1.0
1.0.0
0.26.2
0.26.1
0.26.0
0.25.0
0.24.0
0.23.3
0.23.2
0.23.1
0.23.0
0.22.0
0.21.0
0.20.1
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
RocksDB for Erlang
Retired package: Release invalid - Use 2.6.1 instead
Current section
Files
Jump to
Current section
Files
deps/rocksdb/util/filelock_test.cc
// 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 <fcntl.h>
#include "rocksdb/env.h"
#include "rocksdb/status.h"
#ifdef __FreeBSD__
#include <sys/types.h>
#include <sys/wait.h>
#endif
#ifdef __OpenBSD__
#include <sys/wait.h>
#endif
#include <vector>
#include "test_util/testharness.h"
#include "util/coding.h"
#include "util/string_util.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 = default;
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.
Status s = LockFile(&lock2);
ASSERT_TRUE(s.IsIOError());
#ifndef OS_WIN
// Validate that error message contains current thread ID.
ASSERT_TRUE(s.ToString().find(std::to_string(
Env::Default()->GetThreadID())) != std::string::npos);
#endif
// 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) {
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}