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