leveldb
memenv.cc
Go to the documentation of this file.
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 
6 
7 #include "leveldb/env.h"
8 #include "leveldb/status.h"
9 #include "port/port.h"
10 #include "util/mutexlock.h"
11 #include <map>
12 #include <string.h>
13 #include <string>
14 #include <vector>
15 
16 namespace leveldb {
17 
18 namespace {
19 
20 class FileState {
21  public:
22  // FileStates are reference counted. The initial reference count is zero
23  // and the caller must call Ref() at least once.
24  FileState() : refs_(0), size_(0) {}
25 
26  // Increase the reference count.
27  void Ref() {
28  MutexLock lock(&refs_mutex_);
29  ++refs_;
30  }
31 
32  // Decrease the reference count. Delete if this is the last reference.
33  void Unref() {
34  bool do_delete = false;
35 
36  {
37  MutexLock lock(&refs_mutex_);
38  --refs_;
39  assert(refs_ >= 0);
40  if (refs_ <= 0) {
41  do_delete = true;
42  }
43  }
44 
45  if (do_delete) {
46  delete this;
47  }
48  }
49 
50  uint64_t Size() const { return size_; }
51 
52  Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const {
53  if (offset > size_) {
54  return Status::IOError("Offset greater than file size.");
55  }
56  const uint64_t available = size_ - offset;
57  if (n > available) {
58  n = static_cast<size_t>(available);
59  }
60  if (n == 0) {
61  *result = Slice();
62  return Status::OK();
63  }
64 
65  assert(offset / kBlockSize <= SIZE_MAX);
66  size_t block = static_cast<size_t>(offset / kBlockSize);
67  size_t block_offset = offset % kBlockSize;
68 
69  if (n <= kBlockSize - block_offset) {
70  // The requested bytes are all in the first block.
71  *result = Slice(blocks_[block] + block_offset, n);
72  return Status::OK();
73  }
74 
75  size_t bytes_to_copy = n;
76  char* dst = scratch;
77 
78  while (bytes_to_copy > 0) {
79  size_t avail = kBlockSize - block_offset;
80  if (avail > bytes_to_copy) {
81  avail = bytes_to_copy;
82  }
83  memcpy(dst, blocks_[block] + block_offset, avail);
84 
85  bytes_to_copy -= avail;
86  dst += avail;
87  block++;
88  block_offset = 0;
89  }
90 
91  *result = Slice(scratch, n);
92  return Status::OK();
93  }
94 
95  Status Append(const Slice& data) {
96  const char* src = data.data();
97  size_t src_len = data.size();
98 
99  while (src_len > 0) {
100  size_t avail;
101  size_t offset = size_ % kBlockSize;
102 
103  if (offset != 0) {
104  // There is some room in the last block.
105  avail = kBlockSize - offset;
106  } else {
107  // No room in the last block; push new one.
108  blocks_.push_back(new char[kBlockSize]);
109  avail = kBlockSize;
110  }
111 
112  if (avail > src_len) {
113  avail = src_len;
114  }
115  memcpy(blocks_.back() + offset, src, avail);
116  src_len -= avail;
117  src += avail;
118  size_ += avail;
119  }
120 
121  return Status::OK();
122  }
123 
124  private:
125  // Private since only Unref() should be used to delete it.
127  for (std::vector<char*>::iterator i = blocks_.begin(); i != blocks_.end();
128  ++i) {
129  delete [] *i;
130  }
131  }
132 
133  // No copying allowed.
134  FileState(const FileState&);
135  void operator=(const FileState&);
136 
137  port::Mutex refs_mutex_;
138  int refs_; // Protected by refs_mutex_;
139 
140  // The following fields are not protected by any mutex. They are only mutable
141  // while the file is being written, and concurrent access is not allowed
142  // to writable files.
143  std::vector<char*> blocks_;
144  uint64_t size_;
145 
146  enum { kBlockSize = 8 * 1024 };
147 };
148 
150  public:
151  explicit SequentialFileImpl(FileState* file) : file_(file), pos_(0) {
152  file_->Ref();
153  }
154 
156  file_->Unref();
157  }
158 
159  virtual Status Read(size_t n, Slice* result, char* scratch) {
160  Status s = file_->Read(pos_, n, result, scratch);
161  if (s.ok()) {
162  pos_ += result->size();
163  }
164  return s;
165  }
166 
167  virtual Status Skip(uint64_t n) {
168  if (pos_ > file_->Size()) {
169  return Status::IOError("pos_ > file_->Size()");
170  }
171  const uint64_t available = file_->Size() - pos_;
172  if (n > available) {
173  n = available;
174  }
175  pos_ += n;
176  return Status::OK();
177  }
178 
179  private:
181  uint64_t pos_;
182 };
183 
185  public:
186  explicit RandomAccessFileImpl(FileState* file) : file_(file) {
187  file_->Ref();
188  }
189 
191  file_->Unref();
192  }
193 
194  virtual Status Read(uint64_t offset, size_t n, Slice* result,
195  char* scratch) const {
196  return file_->Read(offset, n, result, scratch);
197  }
198 
199  private:
201 };
202 
204  public:
205  WritableFileImpl(FileState* file) : file_(file) {
206  file_->Ref();
207  }
208 
210  file_->Unref();
211  }
212 
213  virtual Status Append(const Slice& data) {
214  return file_->Append(data);
215  }
216 
217  virtual Status Close() { return Status::OK(); }
218  virtual Status Flush() { return Status::OK(); }
219  virtual Status Sync() { return Status::OK(); }
220 
221  private:
223 };
224 
225 class NoOpLogger : public Logger {
226  public:
227  virtual void Logv(const char* format, va_list ap) { }
228 };
229 
230 class InMemoryEnv : public EnvWrapper {
231  public:
232  explicit InMemoryEnv(Env* base_env) : EnvWrapper(base_env) { }
233 
234  virtual ~InMemoryEnv() {
235  for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){
236  i->second->Unref();
237  }
238  }
239 
240  // Partial implementation of the Env interface.
241  virtual Status NewSequentialFile(const std::string& fname,
242  SequentialFile** result) {
243  MutexLock lock(&mutex_);
244  if (file_map_.find(fname) == file_map_.end()) {
245  *result = NULL;
246  return Status::IOError(fname, "File not found");
247  }
248 
249  *result = new SequentialFileImpl(file_map_[fname]);
250  return Status::OK();
251  }
252 
253  virtual Status NewRandomAccessFile(const std::string& fname,
254  RandomAccessFile** result) {
255  MutexLock lock(&mutex_);
256  if (file_map_.find(fname) == file_map_.end()) {
257  *result = NULL;
258  return Status::IOError(fname, "File not found");
259  }
260 
261  *result = new RandomAccessFileImpl(file_map_[fname]);
262  return Status::OK();
263  }
264 
265  virtual Status NewWritableFile(const std::string& fname,
266  WritableFile** result) {
267  MutexLock lock(&mutex_);
268  if (file_map_.find(fname) != file_map_.end()) {
269  DeleteFileInternal(fname);
270  }
271 
272  FileState* file = new FileState();
273  file->Ref();
274  file_map_[fname] = file;
275 
276  *result = new WritableFileImpl(file);
277  return Status::OK();
278  }
279 
280  virtual Status NewAppendableFile(const std::string& fname,
281  WritableFile** result) {
282  MutexLock lock(&mutex_);
283  FileState** sptr = &file_map_[fname];
284  FileState* file = *sptr;
285  if (file == NULL) {
286  file = new FileState();
287  file->Ref();
288  }
289  *result = new WritableFileImpl(file);
290  return Status::OK();
291  }
292 
293  virtual bool FileExists(const std::string& fname) {
294  MutexLock lock(&mutex_);
295  return file_map_.find(fname) != file_map_.end();
296  }
297 
298  virtual Status GetChildren(const std::string& dir,
299  std::vector<std::string>* result) {
300  MutexLock lock(&mutex_);
301  result->clear();
302 
303  for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){
304  const std::string& filename = i->first;
305 
306  if (filename.size() >= dir.size() + 1 && filename[dir.size()] == '/' &&
307  Slice(filename).starts_with(Slice(dir))) {
308  result->push_back(filename.substr(dir.size() + 1));
309  }
310  }
311 
312  return Status::OK();
313  }
314 
315  void DeleteFileInternal(const std::string& fname) {
316  if (file_map_.find(fname) == file_map_.end()) {
317  return;
318  }
319 
320  file_map_[fname]->Unref();
321  file_map_.erase(fname);
322  }
323 
324  virtual Status DeleteFile(const std::string& fname) {
325  MutexLock lock(&mutex_);
326  if (file_map_.find(fname) == file_map_.end()) {
327  return Status::IOError(fname, "File not found");
328  }
329 
330  DeleteFileInternal(fname);
331  return Status::OK();
332  }
333 
334  virtual Status CreateDir(const std::string& dirname) {
335  return Status::OK();
336  }
337 
338  virtual Status DeleteDir(const std::string& dirname) {
339  return Status::OK();
340  }
341 
342  virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) {
343  MutexLock lock(&mutex_);
344  if (file_map_.find(fname) == file_map_.end()) {
345  return Status::IOError(fname, "File not found");
346  }
347 
348  *file_size = file_map_[fname]->Size();
349  return Status::OK();
350  }
351 
352  virtual Status RenameFile(const std::string& src,
353  const std::string& target) {
354  MutexLock lock(&mutex_);
355  if (file_map_.find(src) == file_map_.end()) {
356  return Status::IOError(src, "File not found");
357  }
358 
359  DeleteFileInternal(target);
360  file_map_[target] = file_map_[src];
361  file_map_.erase(src);
362  return Status::OK();
363  }
364 
365  virtual Status LockFile(const std::string& fname, FileLock** lock) {
366  *lock = new FileLock;
367  return Status::OK();
368  }
369 
370  virtual Status UnlockFile(FileLock* lock) {
371  delete lock;
372  return Status::OK();
373  }
374 
375  virtual Status GetTestDirectory(std::string* path) {
376  *path = "/test";
377  return Status::OK();
378  }
379 
380  virtual Status NewLogger(const std::string& fname, Logger** result) {
381  *result = new NoOpLogger;
382  return Status::OK();
383  }
384 
385  private:
386  // Map from filenames to FileState objects, representing a simple file system.
387  typedef std::map<std::string, FileState*> FileSystem;
388  port::Mutex mutex_;
389  FileSystem file_map_; // Protected by mutex_.
390 };
391 
392 } // namespace
393 
394 Env* NewMemEnv(Env* base_env) {
395  return new InMemoryEnv(base_env);
396 }
397 
398 } // namespace leveldb
virtual Status Append(const Slice &data)
Definition: memenv.cc:213
virtual Status LockFile(const std::string &fname, FileLock **lock)
Definition: memenv.cc:365
virtual Status NewLogger(const std::string &fname, Logger **result)
Definition: memenv.cc:380
virtual Status DeleteFile(const std::string &fname)
Definition: memenv.cc:324
virtual Status GetFileSize(const std::string &fname, uint64_t *file_size)
Definition: memenv.cc:342
void DeleteFileInternal(const std::string &fname)
Definition: memenv.cc:315
virtual bool FileExists(const std::string &fname)
Definition: memenv.cc:293
virtual Status GetTestDirectory(std::string *path)
Definition: memenv.cc:375
virtual Status Read(size_t n, Slice *result, char *scratch)
Definition: memenv.cc:159
static Status OK()
Definition: status.h:32
virtual Status GetChildren(const std::string &dir, std::vector< std::string > *result)
Definition: memenv.cc:298
virtual Status CreateDir(const std::string &dirname)
Definition: memenv.cc:334
static const int kBlockSize
Definition: arena.cc:10
virtual Status NewSequentialFile(const std::string &fname, SequentialFile **result)
Definition: memenv.cc:241
virtual Status UnlockFile(FileLock *lock)
Definition: memenv.cc:370
virtual Status NewWritableFile(const std::string &fname, WritableFile **result)
Definition: memenv.cc:265
virtual Status RenameFile(const std::string &src, const std::string &target)
Definition: memenv.cc:352
virtual Status NewRandomAccessFile(const std::string &fname, RandomAccessFile **result)
Definition: memenv.cc:253
bool ok() const
Definition: status.h:52
std::map< std::string, FileState * > FileSystem
Definition: memenv.cc:387
virtual void Logv(const char *format, va_list ap)
Definition: memenv.cc:227
virtual Status Read(uint64_t offset, size_t n, Slice *result, char *scratch) const
Definition: memenv.cc:194
virtual Status NewAppendableFile(const std::string &fname, WritableFile **result)
Definition: memenv.cc:280
bool starts_with(const Slice &x) const
Definition: slice.h:75
virtual Status DeleteDir(const std::string &dirname)
Definition: memenv.cc:338
const char * data() const
Definition: slice.h:40
static Status IOError(const Slice &msg, const Slice &msg2=Slice())
Definition: status.h:47
size_t size() const
Definition: slice.h:43
Status Read(uint64_t offset, size_t n, Slice *result, char *scratch) const
Definition: memenv.cc:52
Env * NewMemEnv(Env *base_env)
Definition: memenv.cc:394