作者: 韩晨旭 10225101440 李畅 10225102463
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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