#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( true);
}
bool AssertFileIsNotLocked() {
return CheckFileLock( false);
}
bool CheckFileLock(bool lock_expected) {
#ifdef OS_WIN
return true;
#else
pid_t pid = fork();
if (0 == pid) {
int exit_val = EXIT_FAILURE;
int fd = open(file_.c_str(), O_RDWR | O_CREAT, 0644);
if (fd < 0) {
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; 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); exit(exit_val);
} else if (pid > 0) {
int status;
while (-1 == waitpid(pid, &status, 0)) {
}
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
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;
ASSERT_OK(LockFile(&lock1));
ASSERT_TRUE(AssertFileIsLocked());
Status s = LockFile(&lock2);
ASSERT_TRUE(s.IsIOError());
#ifndef OS_WIN
ASSERT_TRUE(s.ToString().find(std::to_string(
Env::Default()->GetThreadID())) != std::string::npos);
#endif
ASSERT_TRUE(AssertFileIsLocked());
ASSERT_OK(UnlockFile(lock1));
ASSERT_TRUE(AssertFileIsNotLocked());
}
}
int main(int argc, char** argv) {
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}