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