]> Git Repo - VerusCoin.git/blame - helpers/memenv/memenv.cc
Squashed 'src/leveldb/' changes from 7924331..7d41e6f
[VerusCoin.git] / helpers / memenv / memenv.cc
CommitLineData
c25e9818
VF
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 "helpers/memenv/memenv.h"
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
16namespace leveldb {
17
18namespace {
19
20class 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) {
4b0e2d75 58 n = static_cast<size_t>(available);
c25e9818
VF
59 }
60 if (n == 0) {
61 *result = Slice();
62 return Status::OK();
63 }
64
4b0e2d75
PW
65 assert(offset / kBlockSize <= SIZE_MAX);
66 size_t block = static_cast<size_t>(offset / kBlockSize);
c25e9818
VF
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.
126 ~FileState() {
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
149class SequentialFileImpl : public SequentialFile {
150 public:
151 explicit SequentialFileImpl(FileState* file) : file_(file), pos_(0) {
152 file_->Ref();
153 }
154
155 ~SequentialFileImpl() {
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 }
4b0e2d75 171 const uint64_t available = file_->Size() - pos_;
c25e9818
VF
172 if (n > available) {
173 n = available;
174 }
175 pos_ += n;
176 return Status::OK();
177 }
178
179 private:
180 FileState* file_;
4b0e2d75 181 uint64_t pos_;
c25e9818
VF
182};
183
184class RandomAccessFileImpl : public RandomAccessFile {
185 public:
186 explicit RandomAccessFileImpl(FileState* file) : file_(file) {
187 file_->Ref();
188 }
189
190 ~RandomAccessFileImpl() {
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:
200 FileState* file_;
201};
202
203class WritableFileImpl : public WritableFile {
204 public:
205 WritableFileImpl(FileState* file) : file_(file) {
206 file_->Ref();
207 }
208
209 ~WritableFileImpl() {
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:
222 FileState* file_;
223};
224
225class NoOpLogger : public Logger {
226 public:
227 virtual void Logv(const char* format, va_list ap) { }
228};
229
230class 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 bool FileExists(const std::string& fname) {
281 MutexLock lock(&mutex_);
282 return file_map_.find(fname) != file_map_.end();
283 }
284
285 virtual Status GetChildren(const std::string& dir,
286 std::vector<std::string>* result) {
287 MutexLock lock(&mutex_);
288 result->clear();
289
290 for (FileSystem::iterator i = file_map_.begin(); i != file_map_.end(); ++i){
291 const std::string& filename = i->first;
292
293 if (filename.size() >= dir.size() + 1 && filename[dir.size()] == '/' &&
294 Slice(filename).starts_with(Slice(dir))) {
295 result->push_back(filename.substr(dir.size() + 1));
296 }
297 }
298
299 return Status::OK();
300 }
301
302 void DeleteFileInternal(const std::string& fname) {
303 if (file_map_.find(fname) == file_map_.end()) {
304 return;
305 }
306
307 file_map_[fname]->Unref();
308 file_map_.erase(fname);
309 }
310
311 virtual Status DeleteFile(const std::string& fname) {
312 MutexLock lock(&mutex_);
313 if (file_map_.find(fname) == file_map_.end()) {
314 return Status::IOError(fname, "File not found");
315 }
316
317 DeleteFileInternal(fname);
318 return Status::OK();
319 }
320
321 virtual Status CreateDir(const std::string& dirname) {
322 return Status::OK();
323 }
324
325 virtual Status DeleteDir(const std::string& dirname) {
326 return Status::OK();
327 }
328
329 virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) {
330 MutexLock lock(&mutex_);
331 if (file_map_.find(fname) == file_map_.end()) {
332 return Status::IOError(fname, "File not found");
333 }
334
335 *file_size = file_map_[fname]->Size();
336 return Status::OK();
337 }
338
339 virtual Status RenameFile(const std::string& src,
340 const std::string& target) {
341 MutexLock lock(&mutex_);
342 if (file_map_.find(src) == file_map_.end()) {
343 return Status::IOError(src, "File not found");
344 }
345
346 DeleteFileInternal(target);
347 file_map_[target] = file_map_[src];
348 file_map_.erase(src);
349 return Status::OK();
350 }
351
352 virtual Status LockFile(const std::string& fname, FileLock** lock) {
353 *lock = new FileLock;
354 return Status::OK();
355 }
356
357 virtual Status UnlockFile(FileLock* lock) {
358 delete lock;
359 return Status::OK();
360 }
361
362 virtual Status GetTestDirectory(std::string* path) {
363 *path = "/test";
364 return Status::OK();
365 }
366
367 virtual Status NewLogger(const std::string& fname, Logger** result) {
368 *result = new NoOpLogger;
369 return Status::OK();
370 }
371
372 private:
373 // Map from filenames to FileState objects, representing a simple file system.
374 typedef std::map<std::string, FileState*> FileSystem;
375 port::Mutex mutex_;
376 FileSystem file_map_; // Protected by mutex_.
377};
378
379} // namespace
380
381Env* NewMemEnv(Env* base_env) {
382 return new InMemoryEnv(base_env);
383}
384
385} // namespace leveldb
This page took 0.060654 seconds and 4 git commands to generate.