filelock_test.cc 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. #include "rocksdb/status.h"
  7. #include "rocksdb/env.h"
  8. #include <fcntl.h>
  9. #include <vector>
  10. #include "test_util/testharness.h"
  11. #include "util/coding.h"
  12. namespace ROCKSDB_NAMESPACE {
  13. class LockTest : public testing::Test {
  14. public:
  15. static LockTest* current_;
  16. std::string file_;
  17. ROCKSDB_NAMESPACE::Env* env_;
  18. LockTest()
  19. : file_(test::PerThreadDBPath("db_testlock_file")),
  20. env_(ROCKSDB_NAMESPACE::Env::Default()) {
  21. current_ = this;
  22. }
  23. ~LockTest() override {}
  24. Status LockFile(FileLock** db_lock) {
  25. return env_->LockFile(file_, db_lock);
  26. }
  27. Status UnlockFile(FileLock* db_lock) {
  28. return env_->UnlockFile(db_lock);
  29. }
  30. bool AssertFileIsLocked(){
  31. return CheckFileLock( /* lock_expected = */ true);
  32. }
  33. bool AssertFileIsNotLocked(){
  34. return CheckFileLock( /* lock_expected = */ false);
  35. }
  36. bool CheckFileLock(bool lock_expected){
  37. // We need to fork to check the fcntl lock as we need
  38. // to open and close the file from a different process
  39. // to avoid either releasing the lock on close, or not
  40. // contending for it when requesting a lock.
  41. #ifdef OS_WIN
  42. // WaitForSingleObject and GetExitCodeProcess can do what waitpid does.
  43. // TODO - implement on Windows
  44. return true;
  45. #else
  46. pid_t pid = fork();
  47. if ( 0 == pid ) {
  48. // child process
  49. int exit_val = EXIT_FAILURE;
  50. int fd = open(file_.c_str(), O_RDWR | O_CREAT, 0644);
  51. if (fd < 0) {
  52. // could not open file, could not check if it was locked
  53. fprintf( stderr, "Open on on file %s failed.\n",file_.c_str());
  54. exit(exit_val);
  55. }
  56. struct flock f;
  57. memset(&f, 0, sizeof(f));
  58. f.l_type = (F_WRLCK);
  59. f.l_whence = SEEK_SET;
  60. f.l_start = 0;
  61. f.l_len = 0; // Lock/unlock entire file
  62. int value = fcntl(fd, F_SETLK, &f);
  63. if( value == -1 ){
  64. if( lock_expected ){
  65. exit_val = EXIT_SUCCESS;
  66. }
  67. } else {
  68. if( ! lock_expected ){
  69. exit_val = EXIT_SUCCESS;
  70. }
  71. }
  72. close(fd); // lock is released for child process
  73. exit(exit_val);
  74. } else if (pid > 0) {
  75. // parent process
  76. int status;
  77. while (-1 == waitpid(pid, &status, 0));
  78. if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
  79. // child process exited with non success status
  80. return false;
  81. } else {
  82. return true;
  83. }
  84. } else {
  85. fprintf( stderr, "Fork failed\n" );
  86. return false;
  87. }
  88. return false;
  89. #endif
  90. }
  91. };
  92. LockTest* LockTest::current_;
  93. TEST_F(LockTest, LockBySameThread) {
  94. FileLock* lock1;
  95. FileLock* lock2;
  96. // acquire a lock on a file
  97. ASSERT_OK(LockFile(&lock1));
  98. // check the file is locked
  99. ASSERT_TRUE( AssertFileIsLocked() );
  100. // re-acquire the lock on the same file. This should fail.
  101. ASSERT_TRUE(LockFile(&lock2).IsIOError());
  102. // check the file is locked
  103. ASSERT_TRUE( AssertFileIsLocked() );
  104. // release the lock
  105. ASSERT_OK(UnlockFile(lock1));
  106. // check the file is not locked
  107. ASSERT_TRUE( AssertFileIsNotLocked() );
  108. }
  109. } // namespace ROCKSDB_NAMESPACE
  110. int main(int argc, char** argv) {
  111. ::testing::InitGoogleTest(&argc, argv);
  112. return RUN_ALL_TESTS();
  113. }