小组成员:谢瑞阳、徐翔宇
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
5.2 KiB

  1. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  4. #include <sys/wait.h>
  5. #include <unistd.h>
  6. #include "leveldb/env.h"
  7. #include "port/port.h"
  8. #include "util/env_posix_test_helper.h"
  9. #include "util/testharness.h"
  10. namespace leveldb {
  11. static const int kReadOnlyFileLimit = 4;
  12. static const int kMMapLimit = 4;
  13. class EnvPosixTest {
  14. public:
  15. static void SetFileLimits(int read_only_file_limit, int mmap_limit) {
  16. EnvPosixTestHelper::SetReadOnlyFDLimit(read_only_file_limit);
  17. EnvPosixTestHelper::SetReadOnlyMMapLimit(mmap_limit);
  18. }
  19. EnvPosixTest() : env_(Env::Default()) {}
  20. Env* env_;
  21. };
  22. TEST(EnvPosixTest, TestOpenOnRead) {
  23. // Write some test data to a single file that will be opened |n| times.
  24. std::string test_dir;
  25. ASSERT_OK(env_->GetTestDirectory(&test_dir));
  26. std::string test_file = test_dir + "/open_on_read.txt";
  27. FILE* f = fopen(test_file.c_str(), "we");
  28. ASSERT_TRUE(f != nullptr);
  29. const char kFileData[] = "abcdefghijklmnopqrstuvwxyz";
  30. fputs(kFileData, f);
  31. fclose(f);
  32. // Open test file some number above the sum of the two limits to force
  33. // open-on-read behavior of POSIX Env leveldb::RandomAccessFile.
  34. const int kNumFiles = kReadOnlyFileLimit + kMMapLimit + 5;
  35. leveldb::RandomAccessFile* files[kNumFiles] = {0};
  36. for (int i = 0; i < kNumFiles; i++) {
  37. ASSERT_OK(env_->NewRandomAccessFile(test_file, &files[i]));
  38. }
  39. char scratch;
  40. Slice read_result;
  41. for (int i = 0; i < kNumFiles; i++) {
  42. ASSERT_OK(files[i]->Read(i, 1, &read_result, &scratch));
  43. ASSERT_EQ(kFileData[i], read_result[0]);
  44. }
  45. for (int i = 0; i < kNumFiles; i++) {
  46. delete files[i];
  47. }
  48. ASSERT_OK(env_->DeleteFile(test_file));
  49. }
  50. #if defined(HAVE_O_CLOEXEC)
  51. TEST(EnvPosixTest, TestCloseOnExec) {
  52. // Test that file handles are not inherited by child processes.
  53. // Open file handles with each of the open methods.
  54. std::string test_dir;
  55. ASSERT_OK(env_->GetTestDirectory(&test_dir));
  56. std::vector<std::string> test_files = {
  57. test_dir + "/close_on_exec_seq.txt",
  58. test_dir + "/close_on_exec_rand.txt",
  59. test_dir + "/close_on_exec_write.txt",
  60. test_dir + "/close_on_exec_append.txt",
  61. test_dir + "/close_on_exec_lock.txt",
  62. test_dir + "/close_on_exec_log.txt",
  63. };
  64. for (const std::string& test_file : test_files) {
  65. const char kFileData[] = "0123456789";
  66. ASSERT_OK(WriteStringToFile(env_, kFileData, test_file));
  67. }
  68. leveldb::SequentialFile* seqFile = nullptr;
  69. leveldb::RandomAccessFile* randFile = nullptr;
  70. leveldb::WritableFile* writeFile = nullptr;
  71. leveldb::WritableFile* appendFile = nullptr;
  72. leveldb::FileLock* lockFile = nullptr;
  73. leveldb::Logger* logFile = nullptr;
  74. ASSERT_OK(env_->NewSequentialFile(test_files[0], &seqFile));
  75. ASSERT_OK(env_->NewRandomAccessFile(test_files[1], &randFile));
  76. ASSERT_OK(env_->NewWritableFile(test_files[2], &writeFile));
  77. ASSERT_OK(env_->NewAppendableFile(test_files[3], &appendFile));
  78. ASSERT_OK(env_->LockFile(test_files[4], &lockFile));
  79. ASSERT_OK(env_->NewLogger(test_files[5], &logFile));
  80. // Fork a child process and wait for it to complete.
  81. int pid = fork();
  82. if (pid == 0) {
  83. const char* const child[] = {"/proc/self/exe", "-cloexec-child", nullptr};
  84. execv(child[0], const_cast<char* const*>(child));
  85. printf("Error spawning child process: %s\n", strerror(errno));
  86. exit(6);
  87. }
  88. int status;
  89. waitpid(pid, &status, 0);
  90. ASSERT_EQ(0, WEXITSTATUS(status));
  91. // cleanup
  92. ASSERT_OK(env_->UnlockFile(lockFile));
  93. delete seqFile;
  94. delete randFile;
  95. delete writeFile;
  96. delete appendFile;
  97. delete logFile;
  98. for (const std::string& test_file : test_files) {
  99. ASSERT_OK(env_->DeleteFile(test_file));
  100. }
  101. }
  102. #endif // defined(HAVE_O_CLOEXEC)
  103. int cloexecChild() {
  104. // Checks for open file descriptors in the range 3..FD_SETSIZE.
  105. for (int i = 3; i < FD_SETSIZE; i++) {
  106. int dup_result = dup2(i, i);
  107. if (dup_result != -1) {
  108. printf("Unexpected open file %d\n", i);
  109. char nbuf[28];
  110. snprintf(nbuf, 28, "/proc/self/fd/%d", i);
  111. char dbuf[1024];
  112. int result = readlink(nbuf, dbuf, 1024);
  113. if (0 < result && result < 1024) {
  114. dbuf[result] = 0;
  115. printf("File descriptor %d is %s\n", i, dbuf);
  116. if (strstr(dbuf, "close_on_exec_") == nullptr) {
  117. continue;
  118. }
  119. } else if (result >= 1024) {
  120. printf("(file name length is too long)\n");
  121. } else {
  122. printf("Couldn't get file name: %s\n", strerror(errno));
  123. }
  124. return 3;
  125. } else {
  126. int e = errno;
  127. if (e != EBADF) {
  128. printf("Unexpected result reading file handle %d: %s\n", i,
  129. strerror(errno));
  130. return 4;
  131. }
  132. }
  133. }
  134. return 0;
  135. }
  136. } // namespace leveldb
  137. int main(int argc, char** argv) {
  138. // Check if this is the child process for TestCloseOnExec
  139. if (argc > 1 && strcmp(argv[1], "-cloexec-child") == 0) {
  140. return leveldb::cloexecChild();
  141. }
  142. // All tests currently run with the same read-only file limits.
  143. leveldb::EnvPosixTest::SetFileLimits(leveldb::kReadOnlyFileLimit,
  144. leveldb::kMMapLimit);
  145. return leveldb::test::RunAllTests();
  146. }