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