/ src / leveldb / util / env_test.cc
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(); }