]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/util/filelock_test.cc
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / rocksdb / util / filelock_test.cc
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
9 #include <vector>
10 #include <fcntl.h>
11 #include "util/coding.h"
12 #include "util/testharness.h"
13
14 namespace rocksdb {
15
16 class LockTest : public testing::Test {
17 public:
18 static LockTest* current_;
19 std::string file_;
20 rocksdb::Env* env_;
21
22 LockTest()
23 : file_(test::PerThreadDBPath("db_testlock_file")),
24 env_(rocksdb::Env::Default()) {
25 current_ = this;
26 }
27
28 ~LockTest() override {}
29
30 Status LockFile(FileLock** db_lock) {
31 return env_->LockFile(file_, db_lock);
32 }
33
34 Status UnlockFile(FileLock* db_lock) {
35 return env_->UnlockFile(db_lock);
36 }
37
38 bool AssertFileIsLocked(){
39 return CheckFileLock( /* lock_expected = */ true);
40 }
41
42 bool AssertFileIsNotLocked(){
43 return CheckFileLock( /* lock_expected = */ false);
44 }
45
46 bool CheckFileLock(bool lock_expected){
47 // We need to fork to check the fcntl lock as we need
48 // to open and close the file from a different process
49 // to avoid either releasing the lock on close, or not
50 // contending for it when requesting a lock.
51
52 #ifdef OS_WIN
53
54 // WaitForSingleObject and GetExitCodeProcess can do what waitpid does.
55 // TODO - implement on Windows
56 return true;
57
58 #else
59
60 pid_t pid = fork();
61 if ( 0 == pid ) {
62 // child process
63 int exit_val = EXIT_FAILURE;
64 int fd = open(file_.c_str(), O_RDWR | O_CREAT, 0644);
65 if (fd < 0) {
66 // could not open file, could not check if it was locked
67 fprintf( stderr, "Open on on file %s failed.\n",file_.c_str());
68 exit(exit_val);
69 }
70
71 struct flock f;
72 memset(&f, 0, sizeof(f));
73 f.l_type = (F_WRLCK);
74 f.l_whence = SEEK_SET;
75 f.l_start = 0;
76 f.l_len = 0; // Lock/unlock entire file
77 int value = fcntl(fd, F_SETLK, &f);
78 if( value == -1 ){
79 if( lock_expected ){
80 exit_val = EXIT_SUCCESS;
81 }
82 } else {
83 if( ! lock_expected ){
84 exit_val = EXIT_SUCCESS;
85 }
86 }
87 close(fd); // lock is released for child process
88 exit(exit_val);
89 } else if (pid > 0) {
90 // parent process
91 int status;
92 while (-1 == waitpid(pid, &status, 0));
93 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
94 // child process exited with non success status
95 return false;
96 } else {
97 return true;
98 }
99 } else {
100 fprintf( stderr, "Fork failed\n" );
101 return false;
102 }
103 return false;
104
105 #endif
106
107 }
108
109 };
110 LockTest* LockTest::current_;
111
112 TEST_F(LockTest, LockBySameThread) {
113 FileLock* lock1;
114 FileLock* lock2;
115
116 // acquire a lock on a file
117 ASSERT_OK(LockFile(&lock1));
118
119 // check the file is locked
120 ASSERT_TRUE( AssertFileIsLocked() );
121
122 // re-acquire the lock on the same file. This should fail.
123 ASSERT_TRUE(LockFile(&lock2).IsIOError());
124
125 // check the file is locked
126 ASSERT_TRUE( AssertFileIsLocked() );
127
128 // release the lock
129 ASSERT_OK(UnlockFile(lock1));
130
131 // check the file is not locked
132 ASSERT_TRUE( AssertFileIsNotLocked() );
133
134 }
135
136 } // namespace rocksdb
137
138 int main(int argc, char** argv) {
139 ::testing::InitGoogleTest(&argc, argv);
140 return RUN_ALL_TESTS();
141 }