env_test.cc raw

   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(); }
 238