Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

248 righe
7.0 KiB

1 mese fa
  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 "leveldb/env.h"
  5. #include <algorithm>
  6. #include "gtest/gtest.h"
  7. #include "port/port.h"
  8. #include "port/thread_annotations.h"
  9. #include "util/mutexlock.h"
  10. #include "util/testutil.h"
  11. namespace leveldb {
  12. class EnvTest : public testing::Test {
  13. public:
  14. EnvTest() : env_(Env::Default()) {}
  15. Env* env_;
  16. };
  17. TEST_F(EnvTest, ReadWrite) {
  18. Random rnd(test::RandomSeed());
  19. // Get file to use for testing.
  20. std::string test_dir;
  21. ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir));
  22. std::string test_file_name = test_dir + "/open_on_read.txt";
  23. WritableFile* writable_file;
  24. ASSERT_LEVELDB_OK(env_->NewWritableFile(test_file_name, &writable_file));
  25. // Fill a file with data generated via a sequence of randomly sized writes.
  26. static const size_t kDataSize = 10 * 1048576;
  27. std::string data;
  28. while (data.size() < kDataSize) {
  29. int len = rnd.Skewed(18); // Up to 2^18 - 1, but typically much smaller
  30. std::string r;
  31. test::RandomString(&rnd, len, &r);
  32. ASSERT_LEVELDB_OK(writable_file->Append(r));
  33. data += r;
  34. if (rnd.OneIn(10)) {
  35. ASSERT_LEVELDB_OK(writable_file->Flush());
  36. }
  37. }
  38. ASSERT_LEVELDB_OK(writable_file->Sync());
  39. ASSERT_LEVELDB_OK(writable_file->Close());
  40. delete writable_file;
  41. // Read all data using a sequence of randomly sized reads.
  42. SequentialFile* sequential_file;
  43. ASSERT_LEVELDB_OK(env_->NewSequentialFile(test_file_name, &sequential_file));
  44. std::string read_result;
  45. std::string scratch;
  46. while (read_result.size() < data.size()) {
  47. int len = std::min<int>(rnd.Skewed(18), data.size() - read_result.size());
  48. scratch.resize(std::max(len, 1)); // at least 1 so &scratch[0] is legal
  49. Slice read;
  50. ASSERT_LEVELDB_OK(sequential_file->Read(len, &read, &scratch[0]));
  51. if (len > 0) {
  52. ASSERT_GT(read.size(), 0);
  53. }
  54. ASSERT_LE(read.size(), len);
  55. read_result.append(read.data(), read.size());
  56. }
  57. ASSERT_EQ(read_result, data);
  58. delete sequential_file;
  59. }
  60. TEST_F(EnvTest, RunImmediately) {
  61. struct RunState {
  62. port::Mutex mu;
  63. port::CondVar cvar{&mu};
  64. bool called = false;
  65. static void Run(void* arg) {
  66. RunState* state = reinterpret_cast<RunState*>(arg);
  67. MutexLock l(&state->mu);
  68. ASSERT_EQ(state->called, false);
  69. state->called = true;
  70. state->cvar.Signal();
  71. }
  72. };
  73. RunState state;
  74. env_->Schedule(&RunState::Run, &state);
  75. MutexLock l(&state.mu);
  76. while (!state.called) {
  77. state.cvar.Wait();
  78. }
  79. }
  80. TEST_F(EnvTest, RunMany) {
  81. struct RunState {
  82. port::Mutex mu;
  83. port::CondVar cvar{&mu};
  84. int run_count = 0;
  85. };
  86. struct Callback {
  87. RunState* const state_; // Pointer to shared state.
  88. bool run = false;
  89. Callback(RunState* s) : state_(s) {}
  90. static void Run(void* arg) {
  91. Callback* callback = reinterpret_cast<Callback*>(arg);
  92. RunState* state = callback->state_;
  93. MutexLock l(&state->mu);
  94. state->run_count++;
  95. callback->run = true;
  96. state->cvar.Signal();
  97. }
  98. };
  99. RunState state;
  100. Callback callback1(&state);
  101. Callback callback2(&state);
  102. Callback callback3(&state);
  103. Callback callback4(&state);
  104. env_->Schedule(&Callback::Run, &callback1);
  105. env_->Schedule(&Callback::Run, &callback2);
  106. env_->Schedule(&Callback::Run, &callback3);
  107. env_->Schedule(&Callback::Run, &callback4);
  108. MutexLock l(&state.mu);
  109. while (state.run_count != 4) {
  110. state.cvar.Wait();
  111. }
  112. ASSERT_TRUE(callback1.run);
  113. ASSERT_TRUE(callback2.run);
  114. ASSERT_TRUE(callback3.run);
  115. ASSERT_TRUE(callback4.run);
  116. }
  117. struct State {
  118. port::Mutex mu;
  119. port::CondVar cvar{&mu};
  120. int val GUARDED_BY(mu);
  121. int num_running GUARDED_BY(mu);
  122. State(int val, int num_running) : val(val), num_running(num_running) {}
  123. };
  124. static void ThreadBody(void* arg) {
  125. State* s = reinterpret_cast<State*>(arg);
  126. s->mu.Lock();
  127. s->val += 1;
  128. s->num_running -= 1;
  129. s->cvar.Signal();
  130. s->mu.Unlock();
  131. }
  132. TEST_F(EnvTest, StartThread) {
  133. State state(0, 3);
  134. for (int i = 0; i < 3; i++) {
  135. env_->StartThread(&ThreadBody, &state);
  136. }
  137. MutexLock l(&state.mu);
  138. while (state.num_running != 0) {
  139. state.cvar.Wait();
  140. }
  141. ASSERT_EQ(state.val, 3);
  142. }
  143. TEST_F(EnvTest, TestOpenNonExistentFile) {
  144. // Write some test data to a single file that will be opened |n| times.
  145. std::string test_dir;
  146. ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir));
  147. std::string non_existent_file = test_dir + "/non_existent_file";
  148. ASSERT_TRUE(!env_->FileExists(non_existent_file));
  149. RandomAccessFile* random_access_file;
  150. Status status =
  151. env_->NewRandomAccessFile(non_existent_file, &random_access_file);
  152. #if defined(LEVELDB_PLATFORM_CHROMIUM)
  153. // TODO(crbug.com/760362): See comment in MakeIOError() from env_chromium.cc.
  154. ASSERT_TRUE(status.IsIOError());
  155. #else
  156. ASSERT_TRUE(status.IsNotFound());
  157. #endif // defined(LEVELDB_PLATFORM_CHROMIUM)
  158. SequentialFile* sequential_file;
  159. status = env_->NewSequentialFile(non_existent_file, &sequential_file);
  160. #if defined(LEVELDB_PLATFORM_CHROMIUM)
  161. // TODO(crbug.com/760362): See comment in MakeIOError() from env_chromium.cc.
  162. ASSERT_TRUE(status.IsIOError());
  163. #else
  164. ASSERT_TRUE(status.IsNotFound());
  165. #endif // defined(LEVELDB_PLATFORM_CHROMIUM)
  166. }
  167. TEST_F(EnvTest, ReopenWritableFile) {
  168. std::string test_dir;
  169. ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir));
  170. std::string test_file_name = test_dir + "/reopen_writable_file.txt";
  171. env_->RemoveFile(test_file_name);
  172. WritableFile* writable_file;
  173. ASSERT_LEVELDB_OK(env_->NewWritableFile(test_file_name, &writable_file));
  174. std::string data("hello world!");
  175. ASSERT_LEVELDB_OK(writable_file->Append(data));
  176. ASSERT_LEVELDB_OK(writable_file->Close());
  177. delete writable_file;
  178. ASSERT_LEVELDB_OK(env_->NewWritableFile(test_file_name, &writable_file));
  179. data = "42";
  180. ASSERT_LEVELDB_OK(writable_file->Append(data));
  181. ASSERT_LEVELDB_OK(writable_file->Close());
  182. delete writable_file;
  183. ASSERT_LEVELDB_OK(ReadFileToString(env_, test_file_name, &data));
  184. ASSERT_EQ(std::string("42"), data);
  185. env_->RemoveFile(test_file_name);
  186. }
  187. TEST_F(EnvTest, ReopenAppendableFile) {
  188. std::string test_dir;
  189. ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir));
  190. std::string test_file_name = test_dir + "/reopen_appendable_file.txt";
  191. env_->RemoveFile(test_file_name);
  192. WritableFile* appendable_file;
  193. ASSERT_LEVELDB_OK(env_->NewAppendableFile(test_file_name, &appendable_file));
  194. std::string data("hello world!");
  195. ASSERT_LEVELDB_OK(appendable_file->Append(data));
  196. ASSERT_LEVELDB_OK(appendable_file->Close());
  197. delete appendable_file;
  198. ASSERT_LEVELDB_OK(env_->NewAppendableFile(test_file_name, &appendable_file));
  199. data = "42";
  200. ASSERT_LEVELDB_OK(appendable_file->Append(data));
  201. ASSERT_LEVELDB_OK(appendable_file->Close());
  202. delete appendable_file;
  203. ASSERT_LEVELDB_OK(ReadFileToString(env_, test_file_name, &data));
  204. ASSERT_EQ(std::string("hello world!42"), data);
  205. env_->RemoveFile(test_file_name);
  206. }
  207. } // namespace leveldb