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:
EnvTest()21   EnvTest() : env_(Env::Default()) {}
22 
23   Env* env_;
24 };
25 
TEST(EnvTest,ReadWrite)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 
TEST(EnvTest,RunImmediately)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 
TEST(EnvTest,RunMany)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 
Stateleveldb::State144   State(int val, int num_running) : val(val), num_running(num_running) {}
145 };
146 
ThreadBody(void * arg)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 
TEST(EnvTest,StartThread)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 
TEST(EnvTest,TestOpenNonExistentFile)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 
TEST(EnvTest,ReopenWritableFile)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 
TEST(EnvTest,ReopenAppendableFile)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 
main(int argc,char ** argv)237 int main(int argc, char** argv) { return leveldb::test::RunAllTests(); }
238