LCOV - code coverage report
Current view: top level - src/leveldb/util - env_posix.cc (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 299 488 61.3 %
Date: 2022-04-21 14:51:19 Functions: 52 69 75.4 %
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: 55 122 45.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 <dirent.h>
#       6                 :            : #include <fcntl.h>
#       7                 :            : #include <pthread.h>
#       8                 :            : #include <sys/mman.h>
#       9                 :            : #include <sys/resource.h>
#      10                 :            : #include <sys/stat.h>
#      11                 :            : #include <sys/time.h>
#      12                 :            : #include <sys/types.h>
#      13                 :            : #include <unistd.h>
#      14                 :            : 
#      15                 :            : #include <atomic>
#      16                 :            : #include <cerrno>
#      17                 :            : #include <cstddef>
#      18                 :            : #include <cstdint>
#      19                 :            : #include <cstdio>
#      20                 :            : #include <cstdlib>
#      21                 :            : #include <cstring>
#      22                 :            : #include <limits>
#      23                 :            : #include <queue>
#      24                 :            : #include <set>
#      25                 :            : #include <string>
#      26                 :            : #include <thread>
#      27                 :            : #include <type_traits>
#      28                 :            : #include <utility>
#      29                 :            : 
#      30                 :            : #include "leveldb/env.h"
#      31                 :            : #include "leveldb/slice.h"
#      32                 :            : #include "leveldb/status.h"
#      33                 :            : #include "port/port.h"
#      34                 :            : #include "port/thread_annotations.h"
#      35                 :            : #include "util/env_posix_test_helper.h"
#      36                 :            : #include "util/posix_logger.h"
#      37                 :            : 
#      38                 :            : namespace leveldb {
#      39                 :            : 
#      40                 :            : namespace {
#      41                 :            : 
#      42                 :            : // Set by EnvPosixTestHelper::SetReadOnlyMMapLimit() and MaxOpenFiles().
#      43                 :            : int g_open_read_only_file_limit = -1;
#      44                 :            : 
#      45                 :            : // Up to 4096 mmap regions for 64-bit binaries; none for 32-bit.
#      46                 :            : constexpr const int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 4096 : 0;
#      47                 :            : 
#      48                 :            : // Can be set using EnvPosixTestHelper::SetReadOnlyMMapLimit().
#      49                 :            : int g_mmap_limit = kDefaultMmapLimit;
#      50                 :            : 
#      51                 :            : // Common flags defined for all posix open operations
#      52                 :            : #if defined(HAVE_O_CLOEXEC)
#      53                 :            : constexpr const int kOpenBaseFlags = O_CLOEXEC;
#      54                 :            : #else
#      55                 :            : constexpr const int kOpenBaseFlags = 0;
#      56                 :            : #endif  // defined(HAVE_O_CLOEXEC)
#      57                 :            : 
#      58                 :            : constexpr const size_t kWritableFileBufferSize = 65536;
#      59                 :            : 
#      60                 :       1546 : Status PosixError(const std::string& context, int error_number) {
#      61         [ +  + ]:       1546 :   if (error_number == ENOENT) {
#      62                 :          4 :     return Status::NotFound(context, std::strerror(error_number));
#      63                 :       1542 :   } else {
#      64                 :       1542 :     return Status::IOError(context, std::strerror(error_number));
#      65                 :       1542 :   }
#      66                 :       1546 : }
#      67                 :            : 
#      68                 :            : // Helper class to limit resource usage to avoid exhaustion.
#      69                 :            : // Currently used to limit read-only file descriptors and mmap file usage
#      70                 :            : // so that we do not run out of file descriptors or virtual memory, or run into
#      71                 :            : // kernel performance problems for very large databases.
#      72                 :            : class Limiter {
#      73                 :            :  public:
#      74                 :            :   // Limit maximum number of resources to |max_acquires|.
#      75                 :       1482 :   Limiter(int max_acquires) : acquires_allowed_(max_acquires) {}
#      76                 :            : 
#      77                 :            :   Limiter(const Limiter&) = delete;
#      78                 :            :   Limiter operator=(const Limiter&) = delete;
#      79                 :            : 
#      80                 :            :   // If another resource is available, acquire it and return true.
#      81                 :            :   // Else return false.
#      82                 :       1921 :   bool Acquire() {
#      83                 :       1921 :     int old_acquires_allowed =
#      84                 :       1921 :         acquires_allowed_.fetch_sub(1, std::memory_order_relaxed);
#      85                 :            : 
#      86         [ +  - ]:       1921 :     if (old_acquires_allowed > 0) return true;
#      87                 :            : 
#      88                 :          0 :     acquires_allowed_.fetch_add(1, std::memory_order_relaxed);
#      89                 :          0 :     return false;
#      90                 :       1921 :   }
#      91                 :            : 
#      92                 :            :   // Release a resource acquired by a previous call to Acquire() that returned
#      93                 :            :   // true.
#      94                 :       1921 :   void Release() { acquires_allowed_.fetch_add(1, std::memory_order_relaxed); }
#      95                 :            : 
#      96                 :            :  private:
#      97                 :            :   // The number of available resources.
#      98                 :            :   //
#      99                 :            :   // This is a counter and is not tied to the invariants of any other class, so
#     100                 :            :   // it can be operated on safely using std::memory_order_relaxed.
#     101                 :            :   std::atomic<int> acquires_allowed_;
#     102                 :            : };
#     103                 :            : 
#     104                 :            : // Implements sequential read access in a file using read().
#     105                 :            : //
#     106                 :            : // Instances of this class are thread-friendly but not thread-safe, as required
#     107                 :            : // by the SequentialFile API.
#     108                 :            : class PosixSequentialFile final : public SequentialFile {
#     109                 :            :  public:
#     110                 :            :   PosixSequentialFile(std::string filename, int fd)
#     111                 :       4055 :       : fd_(fd), filename_(filename) {}
#     112                 :       4055 :   ~PosixSequentialFile() override { close(fd_); }
#     113                 :            : 
#     114                 :       5649 :   Status Read(size_t n, Slice* result, char* scratch) override {
#     115                 :       5649 :     Status status;
#     116                 :       5649 :     while (true) {
#     117                 :       5649 :       ::ssize_t read_size = ::read(fd_, scratch, n);
#     118         [ -  + ]:       5649 :       if (read_size < 0) {  // Read error.
#     119         [ #  # ]:          0 :         if (errno == EINTR) {
#     120                 :          0 :           continue;  // Retry
#     121                 :          0 :         }
#     122                 :          0 :         status = PosixError(filename_, errno);
#     123                 :          0 :         break;
#     124                 :          0 :       }
#     125                 :       5649 :       *result = Slice(scratch, read_size);
#     126                 :       5649 :       break;
#     127                 :       5649 :     }
#     128                 :       5649 :     return status;
#     129                 :       5649 :   }
#     130                 :            : 
#     131                 :          0 :   Status Skip(uint64_t n) override {
#     132         [ #  # ]:          0 :     if (::lseek(fd_, n, SEEK_CUR) == static_cast<off_t>(-1)) {
#     133                 :          0 :       return PosixError(filename_, errno);
#     134                 :          0 :     }
#     135                 :          0 :     return Status::OK();
#     136                 :          0 :   }
#     137                 :            : 
#     138                 :          0 :   virtual std::string GetName() const override { return filename_; }
#     139                 :            : 
#     140                 :            :  private:
#     141                 :            :   const int fd_;
#     142                 :            :   const std::string filename_;
#     143                 :            : };
#     144                 :            : 
#     145                 :            : // Implements random read access in a file using pread().
#     146                 :            : //
#     147                 :            : // Instances of this class are thread-safe, as required by the RandomAccessFile
#     148                 :            : // API. Instances are immutable and Read() only calls thread-safe library
#     149                 :            : // functions.
#     150                 :            : class PosixRandomAccessFile final : public RandomAccessFile {
#     151                 :            :  public:
#     152                 :            :   // The new instance takes ownership of |fd|. |fd_limiter| must outlive this
#     153                 :            :   // instance, and will be used to determine if .
#     154                 :            :   PosixRandomAccessFile(std::string filename, int fd, Limiter* fd_limiter)
#     155                 :            :       : has_permanent_fd_(fd_limiter->Acquire()),
#     156                 :            :         fd_(has_permanent_fd_ ? fd : -1),
#     157                 :            :         fd_limiter_(fd_limiter),
#     158                 :          0 :         filename_(std::move(filename)) {
#     159         [ #  # ]:          0 :     if (!has_permanent_fd_) {
#     160                 :          0 :       assert(fd_ == -1);
#     161                 :          0 :       ::close(fd);  // The file will be opened on every read.
#     162                 :          0 :     }
#     163                 :          0 :   }
#     164                 :            : 
#     165                 :          0 :   ~PosixRandomAccessFile() override {
#     166         [ #  # ]:          0 :     if (has_permanent_fd_) {
#     167                 :          0 :       assert(fd_ != -1);
#     168                 :          0 :       ::close(fd_);
#     169                 :          0 :       fd_limiter_->Release();
#     170                 :          0 :     }
#     171                 :          0 :   }
#     172                 :            : 
#     173                 :            :   Status Read(uint64_t offset, size_t n, Slice* result,
#     174                 :          0 :               char* scratch) const override {
#     175                 :          0 :     int fd = fd_;
#     176         [ #  # ]:          0 :     if (!has_permanent_fd_) {
#     177                 :          0 :       fd = ::open(filename_.c_str(), O_RDONLY | kOpenBaseFlags);
#     178         [ #  # ]:          0 :       if (fd < 0) {
#     179                 :          0 :         return PosixError(filename_, errno);
#     180                 :          0 :       }
#     181                 :          0 :     }
#     182                 :            : 
#     183                 :          0 :     assert(fd != -1);
#     184                 :            : 
#     185                 :          0 :     Status status;
#     186                 :          0 :     ssize_t read_size = ::pread(fd, scratch, n, static_cast<off_t>(offset));
#     187         [ #  # ]:          0 :     *result = Slice(scratch, (read_size < 0) ? 0 : read_size);
#     188         [ #  # ]:          0 :     if (read_size < 0) {
#     189                 :            :       // An error: return a non-ok status.
#     190                 :          0 :       status = PosixError(filename_, errno);
#     191                 :          0 :     }
#     192         [ #  # ]:          0 :     if (!has_permanent_fd_) {
#     193                 :            :       // Close the temporary file descriptor opened earlier.
#     194                 :          0 :       assert(fd != fd_);
#     195                 :          0 :       ::close(fd);
#     196                 :          0 :     }
#     197                 :          0 :     return status;
#     198                 :          0 :   }
#     199                 :            : 
#     200                 :          0 :   virtual std::string GetName() const override { return filename_; }
#     201                 :            : 
#     202                 :            :  private:
#     203                 :            :   const bool has_permanent_fd_;  // If false, the file is opened on every read.
#     204                 :            :   const int fd_;                 // -1 if has_permanent_fd_ is false.
#     205                 :            :   Limiter* const fd_limiter_;
#     206                 :            :   const std::string filename_;
#     207                 :            : };
#     208                 :            : 
#     209                 :            : // Implements random read access in a file using mmap().
#     210                 :            : //
#     211                 :            : // Instances of this class are thread-safe, as required by the RandomAccessFile
#     212                 :            : // API. Instances are immutable and Read() only calls thread-safe library
#     213                 :            : // functions.
#     214                 :            : class PosixMmapReadableFile final : public RandomAccessFile {
#     215                 :            :  public:
#     216                 :            :   // mmap_base[0, length-1] points to the memory-mapped contents of the file. It
#     217                 :            :   // must be the result of a successful call to mmap(). This instances takes
#     218                 :            :   // over the ownership of the region.
#     219                 :            :   //
#     220                 :            :   // |mmap_limiter| must outlive this instance. The caller must have already
#     221                 :            :   // aquired the right to use one mmap region, which will be released when this
#     222                 :            :   // instance is destroyed.
#     223                 :            :   PosixMmapReadableFile(std::string filename, char* mmap_base, size_t length,
#     224                 :            :                         Limiter* mmap_limiter)
#     225                 :            :       : mmap_base_(mmap_base),
#     226                 :            :         length_(length),
#     227                 :            :         mmap_limiter_(mmap_limiter),
#     228                 :       1921 :         filename_(std::move(filename)) {}
#     229                 :            : 
#     230                 :       1921 :   ~PosixMmapReadableFile() override {
#     231                 :       1921 :     ::munmap(static_cast<void*>(mmap_base_), length_);
#     232                 :       1921 :     mmap_limiter_->Release();
#     233                 :       1921 :   }
#     234                 :            : 
#     235                 :            :   Status Read(uint64_t offset, size_t n, Slice* result,
#     236                 :      28606 :               char* scratch) const override {
#     237         [ -  + ]:      28606 :     if (offset + n > length_) {
#     238                 :          0 :       *result = Slice();
#     239                 :          0 :       return PosixError(filename_, EINVAL);
#     240                 :          0 :     }
#     241                 :            : 
#     242                 :      28606 :     *result = Slice(mmap_base_ + offset, n);
#     243                 :      28606 :     return Status::OK();
#     244                 :      28606 :   }
#     245                 :            : 
#     246                 :          0 :   virtual std::string GetName() const override { return filename_; }
#     247                 :            : 
#     248                 :            :  private:
#     249                 :            :   char* const mmap_base_;
#     250                 :            :   const size_t length_;
#     251                 :            :   Limiter* const mmap_limiter_;
#     252                 :            :   const std::string filename_;
#     253                 :            : };
#     254                 :            : 
#     255                 :            : class PosixWritableFile final : public WritableFile {
#     256                 :            :  public:
#     257                 :            :   PosixWritableFile(std::string filename, int fd)
#     258                 :            :       : pos_(0),
#     259                 :            :         fd_(fd),
#     260                 :            :         is_manifest_(IsManifest(filename)),
#     261                 :            :         filename_(std::move(filename)),
#     262                 :       6834 :         dirname_(Dirname(filename_)) {}
#     263                 :            : 
#     264                 :       6834 :   ~PosixWritableFile() override {
#     265         [ +  + ]:       6834 :     if (fd_ >= 0) {
#     266                 :            :       // Ignoring any potential errors
#     267                 :       3081 :       Close();
#     268                 :       3081 :     }
#     269                 :       6834 :   }
#     270                 :            : 
#     271                 :      49773 :   Status Append(const Slice& data) override {
#     272                 :      49773 :     size_t write_size = data.size();
#     273                 :      49773 :     const char* write_data = data.data();
#     274                 :            : 
#     275                 :            :     // Fit as much as possible into buffer.
#     276                 :      49773 :     size_t copy_size = std::min(write_size, kWritableFileBufferSize - pos_);
#     277                 :      49773 :     std::memcpy(buf_ + pos_, write_data, copy_size);
#     278                 :      49773 :     write_data += copy_size;
#     279                 :      49773 :     write_size -= copy_size;
#     280                 :      49773 :     pos_ += copy_size;
#     281         [ +  + ]:      49774 :     if (write_size == 0) {
#     282                 :      49774 :       return Status::OK();
#     283                 :      49774 :     }
#     284                 :            : 
#     285                 :            :     // Can't fit in buffer, so need to do at least one write.
#     286                 :>1844*10^16 :     Status status = FlushBuffer();
#     287         [ -  + ]:>1844*10^16 :     if (!status.ok()) {
#     288                 :          0 :       return status;
#     289                 :          0 :     }
#     290                 :            : 
#     291                 :            :     // Small writes go to buffer, large writes are written directly.
#     292         [ -  + ]:>1844*10^16 :     if (write_size < kWritableFileBufferSize) {
#     293                 :          0 :       std::memcpy(buf_, write_data, write_size);
#     294                 :          0 :       pos_ = write_size;
#     295                 :          0 :       return Status::OK();
#     296                 :          0 :     }
#     297                 :>1844*10^16 :     return WriteUnbuffered(write_data, write_size);
#     298                 :>1844*10^16 :   }
#     299                 :            : 
#     300                 :       6834 :   Status Close() override {
#     301                 :       6834 :     Status status = FlushBuffer();
#     302                 :       6834 :     const int close_result = ::close(fd_);
#     303 [ -  + ][ #  # ]:       6834 :     if (close_result < 0 && status.ok()) {
#     304                 :          0 :       status = PosixError(filename_, errno);
#     305                 :          0 :     }
#     306                 :       6834 :     fd_ = -1;
#     307                 :       6834 :     return status;
#     308                 :       6834 :   }
#     309                 :            : 
#     310                 :      20068 :   Status Flush() override { return FlushBuffer(); }
#     311                 :            : 
#     312                 :       6431 :   Status Sync() override {
#     313                 :            :     // Ensure new files referred to by the manifest are in the filesystem.
#     314                 :            :     //
#     315                 :            :     // This needs to happen before the manifest file is flushed to disk, to
#     316                 :            :     // avoid crashing in a state where the manifest refers to files that are not
#     317                 :            :     // yet on disk.
#     318                 :       6431 :     Status status = SyncDirIfManifest();
#     319         [ -  + ]:       6431 :     if (!status.ok()) {
#     320                 :          0 :       return status;
#     321                 :          0 :     }
#     322                 :            : 
#     323                 :       6431 :     status = FlushBuffer();
#     324         [ -  + ]:       6431 :     if (!status.ok()) {
#     325                 :          0 :       return status;
#     326                 :          0 :     }
#     327                 :            : 
#     328                 :       6431 :     return SyncFd(fd_, filename_, false);
#     329                 :       6431 :   }
#     330                 :            : 
#     331                 :            :  private:
#     332                 :      33332 :   Status FlushBuffer() {
#     333                 :      33332 :     Status status = WriteUnbuffered(buf_, pos_);
#     334                 :      33332 :     pos_ = 0;
#     335                 :      33332 :     return status;
#     336                 :      33332 :   }
#     337                 :            : 
#     338                 :      33333 :   Status WriteUnbuffered(const char* data, size_t size) {
#     339         [ +  + ]:      56585 :     while (size > 0) {
#     340                 :      23252 :       ssize_t write_result = ::write(fd_, data, size);
#     341         [ -  + ]:      23252 :       if (write_result < 0) {
#     342         [ #  # ]:          0 :         if (errno == EINTR) {
#     343                 :          0 :           continue;  // Retry
#     344                 :          0 :         }
#     345                 :          0 :         return PosixError(filename_, errno);
#     346                 :          0 :       }
#     347                 :      23252 :       data += write_result;
#     348                 :      23252 :       size -= write_result;
#     349                 :      23252 :     }
#     350                 :      33333 :     return Status::OK();
#     351                 :      33333 :   }
#     352                 :            : 
#     353                 :       6431 :   Status SyncDirIfManifest() {
#     354                 :       6431 :     Status status;
#     355         [ +  + ]:       6431 :     if (!is_manifest_) {
#     356                 :       4782 :       return status;
#     357                 :       4782 :     }
#     358                 :            : 
#     359                 :       1649 :     int fd = ::open(dirname_.c_str(), O_RDONLY | kOpenBaseFlags);
#     360         [ -  + ]:       1649 :     if (fd < 0) {
#     361                 :          0 :       status = PosixError(dirname_, errno);
#     362                 :       1649 :     } else {
#     363                 :       1649 :       status = SyncFd(fd, dirname_, true);
#     364                 :       1649 :       ::close(fd);
#     365                 :       1649 :     }
#     366                 :       1649 :     return status;
#     367                 :       6431 :   }
#     368                 :            : 
#     369                 :            :   // Ensures that all the caches associated with the given file descriptor's
#     370                 :            :   // data are flushed all the way to durable media, and can withstand power
#     371                 :            :   // failures.
#     372                 :            :   //
#     373                 :            :   // The path argument is only used to populate the description string in the
#     374                 :            :   // returned Status if an error occurs.
#     375                 :       8080 :   static Status SyncFd(int fd, const std::string& fd_path, bool syncing_dir) {
#     376                 :            : #if HAVE_FULLFSYNC
#     377                 :            :     // On macOS and iOS, fsync() doesn't guarantee durability past power
#     378                 :            :     // failures. fcntl(F_FULLFSYNC) is required for that purpose. Some
#     379                 :            :     // filesystems don't support fcntl(F_FULLFSYNC), and require a fallback to
#     380                 :            :     // fsync().
#     381                 :            :     if (::fcntl(fd, F_FULLFSYNC) == 0) {
#     382                 :            :       return Status::OK();
#     383                 :            :     }
#     384                 :            : #endif  // HAVE_FULLFSYNC
#     385                 :            : 
#     386                 :       8080 : #if HAVE_FDATASYNC
#     387                 :       8080 :     bool sync_success = ::fdatasync(fd) == 0;
#     388                 :            : #else
#     389                 :            :     bool sync_success = ::fsync(fd) == 0;
#     390                 :            : #endif  // HAVE_FDATASYNC
#     391                 :            : 
#     392         [ +  + ]:       8080 :     if (sync_success) {
#     393                 :       8079 :       return Status::OK();
#     394                 :       8079 :     }
#     395                 :            :     // Do not crash if filesystem can't fsync directories
#     396                 :            :     // (see https://github.com/bitcoin/bitcoin/pull/10000)
#     397 [ -  + ][ #  # ]:          1 :     if (syncing_dir && errno == EINVAL) {
#     398                 :          0 :       return Status::OK();
#     399                 :          0 :     }
#     400                 :          1 :     return PosixError(fd_path, errno);
#     401                 :          1 :   }
#     402                 :            : 
#     403                 :            :   // Returns the directory name in a path pointing to a file.
#     404                 :            :   //
#     405                 :            :   // Returns "." if the path does not contain any directory separator.
#     406                 :       6834 :   static std::string Dirname(const std::string& filename) {
#     407                 :       6834 :     std::string::size_type separator_pos = filename.rfind('/');
#     408         [ -  + ]:       6834 :     if (separator_pos == std::string::npos) {
#     409                 :          0 :       return std::string(".");
#     410                 :          0 :     }
#     411                 :            :     // The filename component should not contain a path separator. If it does,
#     412                 :            :     // the splitting was done incorrectly.
#     413                 :       6834 :     assert(filename.find('/', separator_pos + 1) == std::string::npos);
#     414                 :            : 
#     415                 :          0 :     return filename.substr(0, separator_pos);
#     416                 :       6834 :   }
#     417                 :            : 
#     418                 :            :   // Extracts the file name from a path pointing to a file.
#     419                 :            :   //
#     420                 :            :   // The returned Slice points to |filename|'s data buffer, so it is only valid
#     421                 :            :   // while |filename| is alive and unchanged.
#     422                 :       6834 :   static Slice Basename(const std::string& filename) {
#     423                 :       6834 :     std::string::size_type separator_pos = filename.rfind('/');
#     424         [ -  + ]:       6834 :     if (separator_pos == std::string::npos) {
#     425                 :          0 :       return Slice(filename);
#     426                 :          0 :     }
#     427                 :            :     // The filename component should not contain a path separator. If it does,
#     428                 :            :     // the splitting was done incorrectly.
#     429                 :       6834 :     assert(filename.find('/', separator_pos + 1) == std::string::npos);
#     430                 :            : 
#     431                 :          0 :     return Slice(filename.data() + separator_pos + 1,
#     432                 :       6834 :                  filename.length() - separator_pos - 1);
#     433                 :       6834 :   }
#     434                 :            : 
#     435                 :            :   // True if the given file is a manifest file.
#     436                 :       6834 :   static bool IsManifest(const std::string& filename) {
#     437                 :       6834 :     return Basename(filename).starts_with("MANIFEST");
#     438                 :       6834 :   }
#     439                 :            : 
#     440                 :          0 :   virtual std::string GetName() const override { return filename_; }
#     441                 :            : 
#     442                 :            :   // buf_[0, pos_ - 1] contains data to be written to fd_.
#     443                 :            :   char buf_[kWritableFileBufferSize];
#     444                 :            :   size_t pos_;
#     445                 :            :   int fd_;
#     446                 :            : 
#     447                 :            :   const bool is_manifest_;  // True if the file's name starts with MANIFEST.
#     448                 :            :   const std::string filename_;
#     449                 :            :   const std::string dirname_;  // The directory of filename_.
#     450                 :            : };
#     451                 :            : 
#     452                 :       3134 : int LockOrUnlock(int fd, bool lock) {
#     453                 :       3134 :   errno = 0;
#     454                 :       3134 :   struct ::flock file_lock_info;
#     455                 :       3134 :   std::memset(&file_lock_info, 0, sizeof(file_lock_info));
#     456         [ +  + ]:       3134 :   file_lock_info.l_type = (lock ? F_WRLCK : F_UNLCK);
#     457                 :       3134 :   file_lock_info.l_whence = SEEK_SET;
#     458                 :       3134 :   file_lock_info.l_start = 0;
#     459                 :       3134 :   file_lock_info.l_len = 0;  // Lock/unlock entire file.
#     460                 :       3134 :   return ::fcntl(fd, F_SETLK, &file_lock_info);
#     461                 :       3134 : }
#     462                 :            : 
#     463                 :            : // Instances are thread-safe because they are immutable.
#     464                 :            : class PosixFileLock : public FileLock {
#     465                 :            :  public:
#     466                 :            :   PosixFileLock(int fd, std::string filename)
#     467                 :       1567 :       : fd_(fd), filename_(std::move(filename)) {}
#     468                 :            : 
#     469                 :       3134 :   int fd() const { return fd_; }
#     470                 :       1567 :   const std::string& filename() const { return filename_; }
#     471                 :            : 
#     472                 :            :  private:
#     473                 :            :   const int fd_;
#     474                 :            :   const std::string filename_;
#     475                 :            : };
#     476                 :            : 
#     477                 :            : // Tracks the files locked by PosixEnv::LockFile().
#     478                 :            : //
#     479                 :            : // We maintain a separate set instead of relying on fcntl(F_SETLK) because
#     480                 :            : // fcntl(F_SETLK) does not provide any protection against multiple uses from the
#     481                 :            : // same process.
#     482                 :            : //
#     483                 :            : // Instances are thread-safe because all member data is guarded by a mutex.
#     484                 :            : class PosixLockTable {
#     485                 :            :  public:
#     486                 :       1567 :   bool Insert(const std::string& fname) LOCKS_EXCLUDED(mu_) {
#     487                 :       1567 :     mu_.Lock();
#     488                 :       1567 :     bool succeeded = locked_files_.insert(fname).second;
#     489                 :       1567 :     mu_.Unlock();
#     490                 :       1567 :     return succeeded;
#     491                 :       1567 :   }
#     492                 :       1567 :   void Remove(const std::string& fname) LOCKS_EXCLUDED(mu_) {
#     493                 :       1567 :     mu_.Lock();
#     494                 :       1567 :     locked_files_.erase(fname);
#     495                 :       1567 :     mu_.Unlock();
#     496                 :       1567 :   }
#     497                 :            : 
#     498                 :            :  private:
#     499                 :            :   port::Mutex mu_;
#     500                 :            :   std::set<std::string> locked_files_ GUARDED_BY(mu_);
#     501                 :            : };
#     502                 :            : 
#     503                 :            : class PosixEnv : public Env {
#     504                 :            :  public:
#     505                 :            :   PosixEnv();
#     506                 :          0 :   ~PosixEnv() override {
#     507                 :          0 :     static const char msg[] =
#     508                 :          0 :         "PosixEnv singleton destroyed. Unsupported behavior!\n";
#     509                 :          0 :     std::fwrite(msg, 1, sizeof(msg), stderr);
#     510                 :          0 :     std::abort();
#     511                 :          0 :   }
#     512                 :            : 
#     513                 :            :   Status NewSequentialFile(const std::string& filename,
#     514                 :       4055 :                            SequentialFile** result) override {
#     515                 :       4055 :     int fd = ::open(filename.c_str(), O_RDONLY | kOpenBaseFlags);
#     516         [ -  + ]:       4055 :     if (fd < 0) {
#     517                 :          0 :       *result = nullptr;
#     518                 :          0 :       return PosixError(filename, errno);
#     519                 :          0 :     }
#     520                 :            : 
#     521                 :       4055 :     *result = new PosixSequentialFile(filename, fd);
#     522                 :       4055 :     return Status::OK();
#     523                 :       4055 :   }
#     524                 :            : 
#     525                 :            :   Status NewRandomAccessFile(const std::string& filename,
#     526                 :       1921 :                              RandomAccessFile** result) override {
#     527                 :       1921 :     *result = nullptr;
#     528                 :       1921 :     int fd = ::open(filename.c_str(), O_RDONLY | kOpenBaseFlags);
#     529         [ -  + ]:       1921 :     if (fd < 0) {
#     530                 :          0 :       return PosixError(filename, errno);
#     531                 :          0 :     }
#     532                 :            : 
#     533         [ -  + ]:       1921 :     if (!mmap_limiter_.Acquire()) {
#     534                 :          0 :       *result = new PosixRandomAccessFile(filename, fd, &fd_limiter_);
#     535                 :          0 :       return Status::OK();
#     536                 :          0 :     }
#     537                 :            : 
#     538                 :       1921 :     uint64_t file_size;
#     539                 :       1921 :     Status status = GetFileSize(filename, &file_size);
#     540         [ +  - ]:       1921 :     if (status.ok()) {
#     541                 :       1921 :       void* mmap_base =
#     542                 :       1921 :           ::mmap(/*addr=*/nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0);
#     543         [ +  - ]:       1921 :       if (mmap_base != MAP_FAILED) {
#     544                 :       1921 :         *result = new PosixMmapReadableFile(filename,
#     545                 :       1921 :                                             reinterpret_cast<char*>(mmap_base),
#     546                 :       1921 :                                             file_size, &mmap_limiter_);
#     547                 :       1921 :       } else {
#     548                 :          0 :         status = PosixError(filename, errno);
#     549                 :          0 :       }
#     550                 :       1921 :     }
#     551                 :       1921 :     ::close(fd);
#     552         [ -  + ]:       1921 :     if (!status.ok()) {
#     553                 :          0 :       mmap_limiter_.Release();
#     554                 :          0 :     }
#     555                 :       1921 :     return status;
#     556                 :       1921 :   }
#     557                 :            : 
#     558                 :            :   Status NewWritableFile(const std::string& filename,
#     559                 :       6834 :                          WritableFile** result) override {
#     560                 :       6834 :     int fd = ::open(filename.c_str(),
#     561                 :       6834 :                     O_TRUNC | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);
#     562         [ -  + ]:       6834 :     if (fd < 0) {
#     563                 :          0 :       *result = nullptr;
#     564                 :          0 :       return PosixError(filename, errno);
#     565                 :          0 :     }
#     566                 :            : 
#     567                 :       6834 :     *result = new PosixWritableFile(filename, fd);
#     568                 :       6834 :     return Status::OK();
#     569                 :       6834 :   }
#     570                 :            : 
#     571                 :            :   Status NewAppendableFile(const std::string& filename,
#     572                 :          0 :                            WritableFile** result) override {
#     573                 :          0 :     int fd = ::open(filename.c_str(),
#     574                 :          0 :                     O_APPEND | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);
#     575         [ #  # ]:          0 :     if (fd < 0) {
#     576                 :          0 :       *result = nullptr;
#     577                 :          0 :       return PosixError(filename, errno);
#     578                 :          0 :     }
#     579                 :            : 
#     580                 :          0 :     *result = new PosixWritableFile(filename, fd);
#     581                 :          0 :     return Status::OK();
#     582                 :          0 :   }
#     583                 :            : 
#     584                 :       1542 :   bool FileExists(const std::string& filename) override {
#     585                 :       1542 :     return ::access(filename.c_str(), F_OK) == 0;
#     586                 :       1542 :   }
#     587                 :            : 
#     588                 :            :   Status GetChildren(const std::string& directory_path,
#     589                 :       3220 :                      std::vector<std::string>* result) override {
#     590                 :       3220 :     result->clear();
#     591                 :       3220 :     ::DIR* dir = ::opendir(directory_path.c_str());
#     592         [ +  + ]:       3220 :     if (dir == nullptr) {
#     593                 :          4 :       return PosixError(directory_path, errno);
#     594                 :          4 :     }
#     595                 :       3216 :     struct ::dirent* entry;
#     596         [ +  + ]:      27747 :     while ((entry = ::readdir(dir)) != nullptr) {
#     597                 :      24531 :       result->emplace_back(entry->d_name);
#     598                 :      24531 :     }
#     599                 :       3216 :     ::closedir(dir);
#     600                 :       3216 :     return Status::OK();
#     601                 :       3220 :   }
#     602                 :            : 
#     603                 :       3050 :   Status DeleteFile(const std::string& filename) override {
#     604         [ -  + ]:       3050 :     if (::unlink(filename.c_str()) != 0) {
#     605                 :          0 :       return PosixError(filename, errno);
#     606                 :          0 :     }
#     607                 :       3050 :     return Status::OK();
#     608                 :       3050 :   }
#     609                 :            : 
#     610                 :       1542 :   Status CreateDir(const std::string& dirname) override {
#     611         [ +  - ]:       1542 :     if (::mkdir(dirname.c_str(), 0755) != 0) {
#     612                 :       1542 :       return PosixError(dirname, errno);
#     613                 :       1542 :     }
#     614                 :          0 :     return Status::OK();
#     615                 :       1542 :   }
#     616                 :            : 
#     617                 :         25 :   Status DeleteDir(const std::string& dirname) override {
#     618         [ -  + ]:         25 :     if (::rmdir(dirname.c_str()) != 0) {
#     619                 :          0 :       return PosixError(dirname, errno);
#     620                 :          0 :     }
#     621                 :         25 :     return Status::OK();
#     622                 :         25 :   }
#     623                 :            : 
#     624                 :       1921 :   Status GetFileSize(const std::string& filename, uint64_t* size) override {
#     625                 :       1921 :     struct ::stat file_stat;
#     626         [ -  + ]:       1921 :     if (::stat(filename.c_str(), &file_stat) != 0) {
#     627                 :          0 :       *size = 0;
#     628                 :          0 :       return PosixError(filename, errno);
#     629                 :          0 :     }
#     630                 :       1921 :     *size = file_stat.st_size;
#     631                 :       1921 :     return Status::OK();
#     632                 :       1921 :   }
#     633                 :            : 
#     634                 :       2109 :   Status RenameFile(const std::string& from, const std::string& to) override {
#     635         [ -  + ]:       2109 :     if (std::rename(from.c_str(), to.c_str()) != 0) {
#     636                 :          0 :       return PosixError(from, errno);
#     637                 :          0 :     }
#     638                 :       2109 :     return Status::OK();
#     639                 :       2109 :   }
#     640                 :            : 
#     641                 :       1567 :   Status LockFile(const std::string& filename, FileLock** lock) override {
#     642                 :       1567 :     *lock = nullptr;
#     643                 :            : 
#     644                 :       1567 :     int fd = ::open(filename.c_str(), O_RDWR | O_CREAT | kOpenBaseFlags, 0644);
#     645         [ -  + ]:       1567 :     if (fd < 0) {
#     646                 :          0 :       return PosixError(filename, errno);
#     647                 :          0 :     }
#     648                 :            : 
#     649         [ -  + ]:       1567 :     if (!locks_.Insert(filename)) {
#     650                 :          0 :       ::close(fd);
#     651                 :          0 :       return Status::IOError("lock " + filename, "already held by process");
#     652                 :          0 :     }
#     653                 :            : 
#     654         [ -  + ]:       1567 :     if (LockOrUnlock(fd, true) == -1) {
#     655                 :          0 :       int lock_errno = errno;
#     656                 :          0 :       ::close(fd);
#     657                 :          0 :       locks_.Remove(filename);
#     658                 :          0 :       return PosixError("lock " + filename, lock_errno);
#     659                 :          0 :     }
#     660                 :            : 
#     661                 :       1567 :     *lock = new PosixFileLock(fd, filename);
#     662                 :       1567 :     return Status::OK();
#     663                 :       1567 :   }
#     664                 :            : 
#     665                 :       1567 :   Status UnlockFile(FileLock* lock) override {
#     666                 :       1567 :     PosixFileLock* posix_file_lock = static_cast<PosixFileLock*>(lock);
#     667         [ -  + ]:       1567 :     if (LockOrUnlock(posix_file_lock->fd(), false) == -1) {
#     668                 :          0 :       return PosixError("unlock " + posix_file_lock->filename(), errno);
#     669                 :          0 :     }
#     670                 :       1567 :     locks_.Remove(posix_file_lock->filename());
#     671                 :       1567 :     ::close(posix_file_lock->fd());
#     672                 :       1567 :     delete posix_file_lock;
#     673                 :       1567 :     return Status::OK();
#     674                 :       1567 :   }
#     675                 :            : 
#     676                 :            :   void Schedule(void (*background_work_function)(void* background_work_arg),
#     677                 :            :                 void* background_work_arg) override;
#     678                 :            : 
#     679                 :            :   void StartThread(void (*thread_main)(void* thread_main_arg),
#     680                 :          0 :                    void* thread_main_arg) override {
#     681                 :          0 :     std::thread new_thread(thread_main, thread_main_arg);
#     682                 :          0 :     new_thread.detach();
#     683                 :          0 :   }
#     684                 :            : 
#     685                 :          0 :   Status GetTestDirectory(std::string* result) override {
#     686                 :          0 :     const char* env = std::getenv("TEST_TMPDIR");
#     687 [ #  # ][ #  # ]:          0 :     if (env && env[0] != '\0') {
#     688                 :          0 :       *result = env;
#     689                 :          0 :     } else {
#     690                 :          0 :       char buf[100];
#     691                 :          0 :       std::snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d",
#     692                 :          0 :                     static_cast<int>(::geteuid()));
#     693                 :          0 :       *result = buf;
#     694                 :          0 :     }
#     695                 :            : 
#     696                 :            :     // The CreateDir status is ignored because the directory may already exist.
#     697                 :          0 :     CreateDir(*result);
#     698                 :            : 
#     699                 :          0 :     return Status::OK();
#     700                 :          0 :   }
#     701                 :            : 
#     702                 :          0 :   Status NewLogger(const std::string& filename, Logger** result) override {
#     703                 :          0 :     int fd = ::open(filename.c_str(),
#     704                 :          0 :                     O_APPEND | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);
#     705         [ #  # ]:          0 :     if (fd < 0) {
#     706                 :          0 :       *result = nullptr;
#     707                 :          0 :       return PosixError(filename, errno);
#     708                 :          0 :     }
#     709                 :            : 
#     710                 :          0 :     std::FILE* fp = ::fdopen(fd, "w");
#     711         [ #  # ]:          0 :     if (fp == nullptr) {
#     712                 :          0 :       ::close(fd);
#     713                 :          0 :       *result = nullptr;
#     714                 :          0 :       return PosixError(filename, errno);
#     715                 :          0 :     } else {
#     716                 :          0 :       *result = new PosixLogger(fp);
#     717                 :          0 :       return Status::OK();
#     718                 :          0 :     }
#     719                 :          0 :   }
#     720                 :            : 
#     721                 :       2154 :   uint64_t NowMicros() override {
#     722                 :       2154 :     static constexpr uint64_t kUsecondsPerSecond = 1000000;
#     723                 :       2154 :     struct ::timeval tv;
#     724                 :       2154 :     ::gettimeofday(&tv, nullptr);
#     725                 :       2154 :     return static_cast<uint64_t>(tv.tv_sec) * kUsecondsPerSecond + tv.tv_usec;
#     726                 :       2154 :   }
#     727                 :            : 
#     728                 :          0 :   void SleepForMicroseconds(int micros) override {
#     729                 :          0 :     std::this_thread::sleep_for(std::chrono::microseconds(micros));
#     730                 :          0 :   }
#     731                 :            : 
#     732                 :            :  private:
#     733                 :            :   void BackgroundThreadMain();
#     734                 :            : 
#     735                 :         69 :   static void BackgroundThreadEntryPoint(PosixEnv* env) {
#     736                 :         69 :     env->BackgroundThreadMain();
#     737                 :         69 :   }
#     738                 :            : 
#     739                 :            :   // Stores the work item data in a Schedule() call.
#     740                 :            :   //
#     741                 :            :   // Instances are constructed on the thread calling Schedule() and used on the
#     742                 :            :   // background thread.
#     743                 :            :   //
#     744                 :            :   // This structure is thread-safe beacuse it is immutable.
#     745                 :            :   struct BackgroundWorkItem {
#     746                 :            :     explicit BackgroundWorkItem(void (*function)(void* arg), void* arg)
#     747                 :        111 :         : function(function), arg(arg) {}
#     748                 :            : 
#     749                 :            :     void (*const function)(void*);
#     750                 :            :     void* const arg;
#     751                 :            :   };
#     752                 :            : 
#     753                 :            :   port::Mutex background_work_mutex_;
#     754                 :            :   port::CondVar background_work_cv_ GUARDED_BY(background_work_mutex_);
#     755                 :            :   bool started_background_thread_ GUARDED_BY(background_work_mutex_);
#     756                 :            : 
#     757                 :            :   std::queue<BackgroundWorkItem> background_work_queue_
#     758                 :            :       GUARDED_BY(background_work_mutex_);
#     759                 :            : 
#     760                 :            :   PosixLockTable locks_;  // Thread-safe.
#     761                 :            :   Limiter mmap_limiter_;  // Thread-safe.
#     762                 :            :   Limiter fd_limiter_;    // Thread-safe.
#     763                 :            : };
#     764                 :            : 
#     765                 :            : // Return the maximum number of concurrent mmaps.
#     766                 :        741 : int MaxMmaps() { return g_mmap_limit; }
#     767                 :            : 
#     768                 :            : // Return the maximum number of read-only files to keep open.
#     769                 :        741 : int MaxOpenFiles() {
#     770         [ -  + ]:        741 :   if (g_open_read_only_file_limit >= 0) {
#     771                 :          0 :     return g_open_read_only_file_limit;
#     772                 :          0 :   }
#     773                 :        741 :   struct ::rlimit rlim;
#     774         [ -  + ]:        741 :   if (::getrlimit(RLIMIT_NOFILE, &rlim)) {
#     775                 :            :     // getrlimit failed, fallback to hard-coded default.
#     776                 :          0 :     g_open_read_only_file_limit = 50;
#     777         [ -  + ]:        741 :   } else if (rlim.rlim_cur == RLIM_INFINITY) {
#     778                 :          0 :     g_open_read_only_file_limit = std::numeric_limits<int>::max();
#     779                 :        741 :   } else {
#     780                 :            :     // Allow use of 20% of available file descriptors for read-only files.
#     781                 :        741 :     g_open_read_only_file_limit = rlim.rlim_cur / 5;
#     782                 :        741 :   }
#     783                 :        741 :   return g_open_read_only_file_limit;
#     784                 :        741 : }
#     785                 :            : 
#     786                 :            : }  // namespace
#     787                 :            : 
#     788                 :            : PosixEnv::PosixEnv()
#     789                 :            :     : background_work_cv_(&background_work_mutex_),
#     790                 :            :       started_background_thread_(false),
#     791                 :            :       mmap_limiter_(MaxMmaps()),
#     792                 :        741 :       fd_limiter_(MaxOpenFiles()) {}
#     793                 :            : 
#     794                 :            : void PosixEnv::Schedule(
#     795                 :            :     void (*background_work_function)(void* background_work_arg),
#     796                 :        111 :     void* background_work_arg) {
#     797                 :        111 :   background_work_mutex_.Lock();
#     798                 :            : 
#     799                 :            :   // Start the background thread, if we haven't done so already.
#     800         [ +  + ]:        111 :   if (!started_background_thread_) {
#     801                 :         69 :     started_background_thread_ = true;
#     802                 :         69 :     std::thread background_thread(PosixEnv::BackgroundThreadEntryPoint, this);
#     803                 :         69 :     background_thread.detach();
#     804                 :         69 :   }
#     805                 :            : 
#     806                 :            :   // If the queue is empty, the background thread may be waiting for work.
#     807         [ +  - ]:        111 :   if (background_work_queue_.empty()) {
#     808                 :        111 :     background_work_cv_.Signal();
#     809                 :        111 :   }
#     810                 :            : 
#     811                 :        111 :   background_work_queue_.emplace(background_work_function, background_work_arg);
#     812                 :        111 :   background_work_mutex_.Unlock();
#     813                 :        111 : }
#     814                 :            : 
#     815                 :         69 : void PosixEnv::BackgroundThreadMain() {
#     816                 :        249 :   while (true) {
#     817                 :        180 :     background_work_mutex_.Lock();
#     818                 :            : 
#     819                 :            :     // Wait until there is work to be done.
#     820         [ +  + ]:        291 :     while (background_work_queue_.empty()) {
#     821                 :        111 :       background_work_cv_.Wait();
#     822                 :        111 :     }
#     823                 :            : 
#     824                 :        180 :     assert(!background_work_queue_.empty());
#     825                 :          0 :     auto background_work_function = background_work_queue_.front().function;
#     826                 :        180 :     void* background_work_arg = background_work_queue_.front().arg;
#     827                 :        180 :     background_work_queue_.pop();
#     828                 :            : 
#     829                 :        180 :     background_work_mutex_.Unlock();
#     830                 :        180 :     background_work_function(background_work_arg);
#     831                 :        180 :   }
#     832                 :         69 : }
#     833                 :            : 
#     834                 :            : namespace {
#     835                 :            : 
#     836                 :            : // Wraps an Env instance whose destructor is never created.
#     837                 :            : //
#     838                 :            : // Intended usage:
#     839                 :            : //   using PlatformSingletonEnv = SingletonEnv<PlatformEnv>;
#     840                 :            : //   void ConfigurePosixEnv(int param) {
#     841                 :            : //     PlatformSingletonEnv::AssertEnvNotInitialized();
#     842                 :            : //     // set global configuration flags.
#     843                 :            : //   }
#     844                 :            : //   Env* Env::Default() {
#     845                 :            : //     static PlatformSingletonEnv default_env;
#     846                 :            : //     return default_env.env();
#     847                 :            : //   }
#     848                 :            : template <typename EnvType>
#     849                 :            : class SingletonEnv {
#     850                 :            :  public:
#     851                 :        741 :   SingletonEnv() {
#     852                 :        741 : #if !defined(NDEBUG)
#     853                 :        741 :     env_initialized_.store(true, std::memory_order_relaxed);
#     854                 :        741 : #endif  // !defined(NDEBUG)
#     855                 :        741 :     static_assert(sizeof(env_storage_) >= sizeof(EnvType),
#     856                 :        741 :                   "env_storage_ will not fit the Env");
#     857                 :        741 :     static_assert(alignof(decltype(env_storage_)) >= alignof(EnvType),
#     858                 :        741 :                   "env_storage_ does not meet the Env's alignment needs");
#     859                 :        741 :     new (&env_storage_) EnvType();
#     860                 :        741 :   }
#     861                 :            :   ~SingletonEnv() = default;
#     862                 :            : 
#     863                 :            :   SingletonEnv(const SingletonEnv&) = delete;
#     864                 :            :   SingletonEnv& operator=(const SingletonEnv&) = delete;
#     865                 :            : 
#     866                 :       6960 :   Env* env() { return reinterpret_cast<Env*>(&env_storage_); }
#     867                 :            : 
#     868                 :          0 :   static void AssertEnvNotInitialized() {
#     869                 :          0 : #if !defined(NDEBUG)
#     870                 :          0 :     assert(!env_initialized_.load(std::memory_order_relaxed));
#     871                 :          0 : #endif  // !defined(NDEBUG)
#     872                 :          0 :   }
#     873                 :            : 
#     874                 :            :  private:
#     875                 :            :   typename std::aligned_storage<sizeof(EnvType), alignof(EnvType)>::type
#     876                 :            :       env_storage_;
#     877                 :            : #if !defined(NDEBUG)
#     878                 :            :   static std::atomic<bool> env_initialized_;
#     879                 :            : #endif  // !defined(NDEBUG)
#     880                 :            : };
#     881                 :            : 
#     882                 :            : #if !defined(NDEBUG)
#     883                 :            : template <typename EnvType>
#     884                 :            : std::atomic<bool> SingletonEnv<EnvType>::env_initialized_;
#     885                 :            : #endif  // !defined(NDEBUG)
#     886                 :            : 
#     887                 :            : using PosixDefaultEnv = SingletonEnv<PosixEnv>;
#     888                 :            : 
#     889                 :            : }  // namespace
#     890                 :            : 
#     891                 :          0 : void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) {
#     892                 :          0 :   PosixDefaultEnv::AssertEnvNotInitialized();
#     893                 :          0 :   g_open_read_only_file_limit = limit;
#     894                 :          0 : }
#     895                 :            : 
#     896                 :          0 : void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) {
#     897                 :          0 :   PosixDefaultEnv::AssertEnvNotInitialized();
#     898                 :          0 :   g_mmap_limit = limit;
#     899                 :          0 : }
#     900                 :            : 
#     901                 :       6960 : Env* Env::Default() {
#     902                 :       6960 :   static PosixDefaultEnv env_container;
#     903                 :       6960 :   return env_container.env();
#     904                 :       6960 : }
#     905                 :            : 
#     906                 :            : }  // namespace leveldb

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