| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- // 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();
- }
|