LCOV - code coverage report
Current view: top level - src/leveldb/helpers/memenv - memenv.cc (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 179 242 74.0 %
Date: 2022-04-21 14:51:19 Functions: 33 44 75.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 37 56 66.1 %

           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                 :       3259 :   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                 :       7822 :   void Ref() {
#      36                 :       7822 :     MutexLock lock(&refs_mutex_);
#      37                 :       7822 :     ++refs_;
#      38                 :       7822 :   }
#      39                 :            : 
#      40                 :            :   // Decrease the reference count. Delete if this is the last reference.
#      41                 :       7822 :   void Unref() {
#      42                 :       7822 :     bool do_delete = false;
#      43                 :            : 
#      44                 :       7822 :     {
#      45                 :       7822 :       MutexLock lock(&refs_mutex_);
#      46                 :       7822 :       --refs_;
#      47                 :       7822 :       assert(refs_ >= 0);
#      48         [ +  + ]:       7822 :       if (refs_ <= 0) {
#      49                 :       3259 :         do_delete = true;
#      50                 :       3259 :       }
#      51                 :       7822 :     }
#      52                 :            : 
#      53         [ +  + ]:       7822 :     if (do_delete) {
#      54                 :       3259 :       delete this;
#      55                 :       3259 :     }
#      56                 :       7822 :   }
#      57                 :            : 
#      58                 :          0 :   uint64_t Size() const {
#      59                 :          0 :     MutexLock lock(&blocks_mutex_);
#      60                 :          0 :     return size_;
#      61                 :          0 :   }
#      62                 :            : 
#      63                 :       3259 :   void Truncate() {
#      64                 :       3259 :     MutexLock lock(&blocks_mutex_);
#      65         [ +  + ]:       3641 :     for (char*& block : blocks_) {
#      66                 :       3641 :       delete[] block;
#      67                 :       3641 :     }
#      68                 :       3259 :     blocks_.clear();
#      69                 :       3259 :     size_ = 0;
#      70                 :       3259 :   }
#      71                 :            : 
#      72                 :       2445 :   Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const {
#      73                 :       2445 :     MutexLock lock(&blocks_mutex_);
#      74         [ -  + ]:       2445 :     if (offset > size_) {
#      75                 :          0 :       return Status::IOError("Offset greater than file size.");
#      76                 :          0 :     }
#      77                 :       2445 :     const uint64_t available = size_ - offset;
#      78         [ +  + ]:       2445 :     if (n > available) {
#      79                 :       1953 :       n = static_cast<size_t>(available);
#      80                 :       1953 :     }
#      81         [ +  + ]:       2445 :     if (n == 0) {
#      82                 :        651 :       *result = Slice();
#      83                 :        651 :       return Status::OK();
#      84                 :        651 :     }
#      85                 :            : 
#      86                 :       1794 :     assert(offset / kBlockSize <= std::numeric_limits<size_t>::max());
#      87                 :          0 :     size_t block = static_cast<size_t>(offset / kBlockSize);
#      88                 :       1794 :     size_t block_offset = offset % kBlockSize;
#      89                 :       1794 :     size_t bytes_to_copy = n;
#      90                 :       1794 :     char* dst = scratch;
#      91                 :            : 
#      92         [ +  + ]:       3842 :     while (bytes_to_copy > 0) {
#      93                 :       2048 :       size_t avail = kBlockSize - block_offset;
#      94         [ +  + ]:       2048 :       if (avail > bytes_to_copy) {
#      95                 :       1794 :         avail = bytes_to_copy;
#      96                 :       1794 :       }
#      97                 :       2048 :       memcpy(dst, blocks_[block] + block_offset, avail);
#      98                 :            : 
#      99                 :       2048 :       bytes_to_copy -= avail;
#     100                 :       2048 :       dst += avail;
#     101                 :       2048 :       block++;
#     102                 :       2048 :       block_offset = 0;
#     103                 :       2048 :     }
#     104                 :            : 
#     105                 :       1794 :     *result = Slice(scratch, n);
#     106                 :       1794 :     return Status::OK();
#     107                 :       2445 :   }
#     108                 :            : 
#     109                 :      10384 :   Status Append(const Slice& data) {
#     110                 :      10384 :     const char* src = data.data();
#     111                 :      10384 :     size_t src_len = data.size();
#     112                 :            : 
#     113                 :      10384 :     MutexLock lock(&blocks_mutex_);
#     114         [ +  + ]:      21429 :     while (src_len > 0) {
#     115                 :      11045 :       size_t avail;
#     116                 :      11045 :       size_t offset = size_ % kBlockSize;
#     117                 :            : 
#     118         [ +  + ]:      11045 :       if (offset != 0) {
#     119                 :            :         // There is some room in the last block.
#     120                 :       7404 :         avail = kBlockSize - offset;
#     121                 :       7404 :       } else {
#     122                 :            :         // No room in the last block; push new one.
#     123                 :       3641 :         blocks_.push_back(new char[kBlockSize]);
#     124                 :       3641 :         avail = kBlockSize;
#     125                 :       3641 :       }
#     126                 :            : 
#     127         [ +  + ]:      11045 :       if (avail > src_len) {
#     128                 :      10257 :         avail = src_len;
#     129                 :      10257 :       }
#     130                 :      11045 :       memcpy(blocks_.back() + offset, src, avail);
#     131                 :      11045 :       src_len -= avail;
#     132                 :      11045 :       src += avail;
#     133                 :      11045 :       size_ += avail;
#     134                 :      11045 :     }
#     135                 :            : 
#     136                 :      10384 :     return Status::OK();
#     137                 :      10384 :   }
#     138                 :            : 
#     139                 :            :  private:
#     140                 :            :   enum { kBlockSize = 8 * 1024 };
#     141                 :            : 
#     142                 :            :   // Private since only Unref() should be used to delete it.
#     143                 :       3259 :   ~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                 :       1302 :   explicit SequentialFileImpl(FileState* file) : file_(file), pos_(0) {
#     156                 :       1302 :     file_->Ref();
#     157                 :       1302 :   }
#     158                 :            : 
#     159                 :       1302 :   ~SequentialFileImpl() override { file_->Unref(); }
#     160                 :            : 
#     161                 :       1953 :   Status Read(size_t n, Slice* result, char* scratch) override {
#     162                 :       1953 :     Status s = file_->Read(pos_, n, result, scratch);
#     163         [ +  - ]:       1953 :     if (s.ok()) {
#     164                 :       1953 :       pos_ += result->size();
#     165                 :       1953 :     }
#     166                 :       1953 :     return s;
#     167                 :       1953 :   }
#     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                 :        492 :               char* scratch) const override {
#     195                 :        492 :     return file_->Read(offset, n, result, scratch);
#     196                 :        492 :   }
#     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                 :       3259 :   WritableFileImpl(FileState* file) : file_(file) { file_->Ref(); }
#     206                 :            : 
#     207                 :       3259 :   ~WritableFileImpl() override { file_->Unref(); }
#     208                 :            : 
#     209                 :      10384 :   Status Append(const Slice& data) override { return file_->Append(data); }
#     210                 :            : 
#     211                 :       1955 :   Status Close() override { return Status::OK(); }
#     212                 :       4534 :   Status Flush() override { return Status::OK(); }
#     213                 :       1982 :   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                 :        651 :   explicit InMemoryEnv(Env* base_env) : EnvWrapper(base_env) {}
#     228                 :            : 
#     229                 :        651 :   ~InMemoryEnv() override {
#     230         [ +  + ]:       1955 :     for (const auto& kvp : file_map_) {
#     231                 :       1955 :       kvp.second->Unref();
#     232                 :       1955 :     }
#     233                 :        651 :   }
#     234                 :            : 
#     235                 :            :   // Partial implementation of the Env interface.
#     236                 :            :   Status NewSequentialFile(const std::string& fname,
#     237                 :       1302 :                            SequentialFile** result) override {
#     238                 :       1302 :     MutexLock lock(&mutex_);
#     239         [ -  + ]:       1302 :     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                 :       1302 :     *result = new SequentialFileImpl(file_map_[fname]);
#     245                 :       1302 :     return Status::OK();
#     246                 :       1302 :   }
#     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                 :       3259 :                          WritableFile** result) override {
#     262                 :       3259 :     MutexLock lock(&mutex_);
#     263                 :       3259 :     FileSystem::iterator it = file_map_.find(fname);
#     264                 :            : 
#     265                 :       3259 :     FileState* file;
#     266         [ +  - ]:       3259 :     if (it == file_map_.end()) {
#     267                 :            :       // File is not currently open.
#     268                 :       3259 :       file = new FileState();
#     269                 :       3259 :       file->Ref();
#     270                 :       3259 :       file_map_[fname] = file;
#     271                 :       3259 :     } else {
#     272                 :          0 :       file = it->second;
#     273                 :          0 :       file->Truncate();
#     274                 :          0 :     }
#     275                 :            : 
#     276                 :       3259 :     *result = new WritableFileImpl(file);
#     277                 :       3259 :     return Status::OK();
#     278                 :       3259 :   }
#     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                 :        651 :   bool FileExists(const std::string& fname) override {
#     294                 :        651 :     MutexLock lock(&mutex_);
#     295                 :        651 :     return file_map_.find(fname) != file_map_.end();
#     296                 :        651 :   }
#     297                 :            : 
#     298                 :            :   Status GetChildren(const std::string& dir,
#     299                 :       1304 :                      std::vector<std::string>* result) override {
#     300                 :       1304 :     MutexLock lock(&mutex_);
#     301                 :       1304 :     result->clear();
#     302                 :            : 
#     303         [ +  + ]:       3916 :     for (const auto& kvp : file_map_) {
#     304                 :       3916 :       const std::string& filename = kvp.first;
#     305                 :            : 
#     306 [ +  - ][ +  - ]:       3916 :       if (filename.size() >= dir.size() + 1 && filename[dir.size()] == '/' &&
#                 [ +  - ]
#     307         [ +  - ]:       3916 :           Slice(filename).starts_with(Slice(dir))) {
#     308                 :       3916 :         result->push_back(filename.substr(dir.size() + 1));
#     309                 :       3916 :       }
#     310                 :       3916 :     }
#     311                 :            : 
#     312                 :       1304 :     return Status::OK();
#     313                 :       1304 :   }
#     314                 :            : 
#     315                 :            :   void DeleteFileInternal(const std::string& fname)
#     316                 :       1955 :       EXCLUSIVE_LOCKS_REQUIRED(mutex_) {
#     317         [ +  + ]:       1955 :     if (file_map_.find(fname) == file_map_.end()) {
#     318                 :        651 :       return;
#     319                 :        651 :     }
#     320                 :            : 
#     321                 :       1304 :     file_map_[fname]->Unref();
#     322                 :       1304 :     file_map_.erase(fname);
#     323                 :       1304 :   }
#     324                 :            : 
#     325                 :        653 :   Status DeleteFile(const std::string& fname) override {
#     326                 :        653 :     MutexLock lock(&mutex_);
#     327         [ -  + ]:        653 :     if (file_map_.find(fname) == file_map_.end()) {
#     328                 :          0 :       return Status::IOError(fname, "File not found");
#     329                 :          0 :     }
#     330                 :            : 
#     331                 :        653 :     DeleteFileInternal(fname);
#     332                 :        653 :     return Status::OK();
#     333                 :        653 :   }
#     334                 :            : 
#     335                 :        651 :   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                 :       1302 :                     const std::string& target) override {
#     351                 :       1302 :     MutexLock lock(&mutex_);
#     352         [ -  + ]:       1302 :     if (file_map_.find(src) == file_map_.end()) {
#     353                 :          0 :       return Status::IOError(src, "File not found");
#     354                 :          0 :     }
#     355                 :            : 
#     356                 :       1302 :     DeleteFileInternal(target);
#     357                 :       1302 :     file_map_[target] = file_map_[src];
#     358                 :       1302 :     file_map_.erase(src);
#     359                 :       1302 :     return Status::OK();
#     360                 :       1302 :   }
#     361                 :            : 
#     362                 :        651 :   Status LockFile(const std::string& fname, FileLock** lock) override {
#     363                 :        651 :     *lock = new FileLock;
#     364                 :        651 :     return Status::OK();
#     365                 :        651 :   }
#     366                 :            : 
#     367                 :        651 :   Status UnlockFile(FileLock* lock) override {
#     368                 :        651 :     delete lock;
#     369                 :        651 :     return Status::OK();
#     370                 :        651 :   }
#     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                 :        651 : Env* NewMemEnv(Env* base_env) { return new InMemoryEnv(base_env); }
#     393                 :            : 
#     394                 :            : }  // namespace leveldb

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a