LCOV - code coverage report
Current view: top level - src/leveldb/util - env_posix.cc (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 62.6 % 401 251
Test Date: 2026-02-04 04:43:42 Functions: 70.8 % 65 46
Branches: 33.7 % 270 91

             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 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                 :         118 : Status PosixError(const std::string& context, int error_number) {
      61         [ +  + ]:         118 :   if (error_number == ENOENT) {
      62         [ -  + ]:           3 :     return Status::NotFound(context, std::strerror(error_number));
      63                 :             :   } else {
      64         [ -  + ]:         115 :     return Status::IOError(context, std::strerror(error_number));
      65                 :             :   }
      66                 :             : }
      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                 :         100 :   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                 :         154 :   bool Acquire() {
      83                 :         154 :     int old_acquires_allowed =
      84         [ -  + ]:         154 :         acquires_allowed_.fetch_sub(1, std::memory_order_relaxed);
      85                 :             : 
      86         [ -  + ]:         154 :     if (old_acquires_allowed > 0) return true;
      87                 :             : 
      88                 :           0 :     acquires_allowed_.fetch_add(1, std::memory_order_relaxed);
      89                 :           0 :     return false;
      90                 :             :   }
      91                 :             : 
      92                 :             :   // Release a resource acquired by a previous call to Acquire() that returned
      93                 :             :   // true.
      94                 :         154 :   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                 :         298 :   PosixSequentialFile(std::string filename, int fd)
     111         [ -  + ]:         596 :       : fd_(fd), filename_(filename) {}
     112                 :         596 :   ~PosixSequentialFile() override { close(fd_); }
     113                 :             : 
     114                 :         416 :   Status Read(size_t n, Slice* result, char* scratch) override {
     115                 :         416 :     Status status;
     116                 :         416 :     while (true) {
     117         [ +  - ]:         416 :       ::ssize_t read_size = ::read(fd_, scratch, n);
     118         [ -  + ]:         416 :       if (read_size < 0) {  // Read error.
     119         [ #  # ]:           0 :         if (errno == EINTR) {
     120                 :           0 :           continue;  // Retry
     121                 :             :         }
     122   [ #  #  #  # ]:           0 :         status = PosixError(filename_, errno);
     123                 :           0 :         break;
     124                 :             :       }
     125                 :         416 :       *result = Slice(scratch, read_size);
     126                 :         416 :       break;
     127                 :           0 :     }
     128                 :         416 :     return status;
     129                 :           0 :   }
     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                 :             :     }
     135                 :           0 :     return Status::OK();
     136                 :             :   }
     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                 :           0 :   PosixRandomAccessFile(std::string filename, int fd, Limiter* fd_limiter)
     155                 :           0 :       : has_permanent_fd_(fd_limiter->Acquire()),
     156         [ #  # ]:           0 :         fd_(has_permanent_fd_ ? fd : -1),
     157                 :           0 :         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                 :             :     }
     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                 :             :     }
     171                 :           0 :   }
     172                 :             : 
     173                 :           0 :   Status Read(uint64_t offset, size_t n, Slice* result,
     174                 :             :               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                 :             :       }
     181                 :             :     }
     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                 :             :     }
     192         [ #  # ]:           0 :     if (!has_permanent_fd_) {
     193                 :             :       // Close the temporary file descriptor opened earlier.
     194         [ #  # ]:           0 :       assert(fd != fd_);
     195         [ #  # ]:           0 :       ::close(fd);
     196                 :             :     }
     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                 :             :   // acquired the right to use one mmap region, which will be released when this
     222                 :             :   // instance is destroyed.
     223                 :         154 :   PosixMmapReadableFile(std::string filename, char* mmap_base, size_t length,
     224                 :             :                         Limiter* mmap_limiter)
     225                 :         154 :       : mmap_base_(mmap_base),
     226                 :         154 :         length_(length),
     227                 :         154 :         mmap_limiter_(mmap_limiter),
     228                 :         154 :         filename_(std::move(filename)) {}
     229                 :             : 
     230                 :         308 :   ~PosixMmapReadableFile() override {
     231                 :         154 :     ::munmap(static_cast<void*>(mmap_base_), length_);
     232                 :         154 :     mmap_limiter_->Release();
     233                 :         308 :   }
     234                 :             : 
     235                 :        2105 :   Status Read(uint64_t offset, size_t n, Slice* result,
     236                 :             :               char* scratch) const override {
     237         [ -  + ]:        2105 :     if (offset + n > length_) {
     238                 :           0 :       *result = Slice();
     239                 :           0 :       return PosixError(filename_, EINVAL);
     240                 :             :     }
     241                 :             : 
     242                 :        2105 :     *result = Slice(mmap_base_ + offset, n);
     243                 :        2105 :     return Status::OK();
     244                 :             :   }
     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                 :         512 :   PosixWritableFile(std::string filename, int fd)
     258                 :         512 :       : pos_(0),
     259                 :         512 :         fd_(fd),
     260                 :         512 :         is_manifest_(IsManifest(filename)),
     261                 :         512 :         filename_(std::move(filename)),
     262         [ +  - ]:        1024 :         dirname_(Dirname(filename_)) {}
     263                 :             : 
     264                 :        1024 :   ~PosixWritableFile() override {
     265         [ +  + ]:         512 :     if (fd_ >= 0) {
     266                 :             :       // Ignoring any potential errors
     267         [ -  + ]:         231 :       Close();
     268                 :             :     }
     269                 :        1024 :   }
     270                 :             : 
     271                 :        2236 :   Status Append(const Slice& data) override {
     272         [ +  - ]:        2236 :     size_t write_size = data.size();
     273         [ +  - ]:        2236 :     const char* write_data = data.data();
     274                 :             : 
     275                 :             :     // Fit as much as possible into buffer.
     276         [ +  - ]:        2236 :     size_t copy_size = std::min(write_size, kWritableFileBufferSize - pos_);
     277         [ +  - ]:        2236 :     std::memcpy(buf_ + pos_, write_data, copy_size);
     278                 :        2236 :     write_data += copy_size;
     279                 :        2236 :     write_size -= copy_size;
     280                 :        2236 :     pos_ += copy_size;
     281         [ +  - ]:        2236 :     if (write_size == 0) {
     282                 :        2236 :       return Status::OK();
     283                 :             :     }
     284                 :             : 
     285                 :             :     // Can't fit in buffer, so need to do at least one write.
     286                 :           0 :     Status status = FlushBuffer();
     287                 :           0 :     if (!status.ok()) {
     288                 :           0 :       return status;
     289                 :             :     }
     290                 :             : 
     291                 :             :     // Small writes go to buffer, large writes are written directly.
     292         [ #  # ]:           0 :     if (write_size < kWritableFileBufferSize) {
     293                 :           0 :       std::memcpy(buf_, write_data, write_size);
     294                 :           0 :       pos_ = write_size;
     295                 :           0 :       return Status::OK();
     296                 :             :     }
     297         [ #  # ]:           0 :     return WriteUnbuffered(write_data, write_size);
     298                 :           0 :   }
     299                 :             : 
     300                 :         512 :   Status Close() override {
     301                 :        1024 :     Status status = FlushBuffer();
     302                 :        1024 :     const int close_result = ::close(fd_);
     303   [ -  +  -  - ]:         512 :     if (close_result < 0 && status.ok()) {
     304   [ #  #  #  # ]:           0 :       status = PosixError(filename_, errno);
     305                 :             :     }
     306                 :         512 :     fd_ = -1;
     307                 :         512 :     return status;
     308                 :           0 :   }
     309                 :             : 
     310                 :        1570 :   Status Flush() override { return FlushBuffer(); }
     311                 :             : 
     312                 :         434 :   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                 :         434 :     Status status = SyncDirIfManifest();
     319         [ -  + ]:         434 :     if (!status.ok()) {
     320                 :           0 :       return status;
     321                 :             :     }
     322                 :             : 
     323                 :        1302 :     status = FlushBuffer();
     324         [ -  + ]:         434 :     if (!status.ok()) {
     325                 :           0 :       return status;
     326                 :             :     }
     327                 :             : 
     328         [ +  - ]:         434 :     return SyncFd(fd_, filename_, false);
     329                 :         434 :   }
     330                 :             : 
     331                 :             :  private:
     332                 :        1731 :   Status FlushBuffer() {
     333         [ +  - ]:        1731 :     Status status = WriteUnbuffered(buf_, pos_);
     334                 :        1731 :     pos_ = 0;
     335   [ -  +  +  -  :         946 :     return status;
                   -  - ]
     336                 :             :   }
     337                 :             : 
     338                 :        1731 :   Status WriteUnbuffered(const char* data, size_t size) {
     339         [ +  + ]:        2750 :     while (size > 0) {
     340                 :        1019 :       ssize_t write_result = ::write(fd_, data, size);
     341         [ -  + ]:        1019 :       if (write_result < 0) {
     342         [ #  # ]:           0 :         if (errno == EINTR) {
     343                 :           0 :           continue;  // Retry
     344                 :             :         }
     345                 :           0 :         return PosixError(filename_, errno);
     346                 :             :       }
     347                 :        1019 :       data += write_result;
     348                 :        1019 :       size -= write_result;
     349                 :             :     }
     350                 :        1731 :     return Status::OK();
     351                 :             :   }
     352                 :             : 
     353                 :         434 :   Status SyncDirIfManifest() {
     354         [ +  + ]:         434 :     Status status;
     355         [ +  + ]:         434 :     if (!is_manifest_) {
     356                 :             :       return status;
     357                 :             :     }
     358                 :             : 
     359         [ +  - ]:         126 :     int fd = ::open(dirname_.c_str(), O_RDONLY | kOpenBaseFlags);
     360         [ -  + ]:         126 :     if (fd < 0) {
     361   [ #  #  #  # ]:           0 :       status = PosixError(dirname_, errno);
     362                 :             :     } else {
     363   [ +  -  -  + ]:         126 :       status = SyncFd(fd, dirname_, true);
     364         [ +  - ]:         126 :       ::close(fd);
     365                 :             :     }
     366                 :             :     return status;
     367                 :           0 :   }
     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                 :         560 :   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                 :             : #if HAVE_FDATASYNC
     387                 :         560 :     bool sync_success = ::fdatasync(fd) == 0;
     388                 :             : #else
     389                 :             :     bool sync_success = ::fsync(fd) == 0;
     390                 :             : #endif  // HAVE_FDATASYNC
     391                 :             : 
     392         [ +  - ]:         560 :     if (sync_success) {
     393                 :         560 :       return Status::OK();
     394                 :             :     }
     395                 :             :     // Do not crash if filesystem can't fsync directories
     396                 :             :     // (see https://github.com/bitcoin/bitcoin/pull/10000)
     397   [ #  #  #  # ]:           0 :     if (syncing_dir && errno == EINVAL) {
     398                 :           0 :       return Status::OK();
     399                 :             :     }
     400                 :           0 :     return PosixError(fd_path, errno);
     401                 :             :   }
     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                 :         512 :   static std::string Dirname(const std::string& filename) {
     407                 :         512 :     std::string::size_type separator_pos = filename.rfind('/');
     408         [ -  + ]:         512 :     if (separator_pos == std::string::npos) {
     409                 :           0 :       return std::string(".");
     410                 :             :     }
     411                 :             :     // The filename component should not contain a path separator. If it does,
     412                 :             :     // the splitting was done incorrectly.
     413         [ -  + ]:         512 :     assert(filename.find('/', separator_pos + 1) == std::string::npos);
     414                 :             : 
     415                 :         512 :     return filename.substr(0, separator_pos);
     416                 :             :   }
     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                 :         512 :   static Slice Basename(const std::string& filename) {
     423                 :         512 :     std::string::size_type separator_pos = filename.rfind('/');
     424         [ -  + ]:         512 :     if (separator_pos == std::string::npos) {
     425         [ #  # ]:           0 :       return Slice(filename);
     426                 :             :     }
     427                 :             :     // The filename component should not contain a path separator. If it does,
     428                 :             :     // the splitting was done incorrectly.
     429         [ -  + ]:         512 :     assert(filename.find('/', separator_pos + 1) == std::string::npos);
     430                 :             : 
     431         [ -  + ]:         512 :     return Slice(filename.data() + separator_pos + 1,
     432                 :         512 :                  filename.length() - separator_pos - 1);
     433                 :             :   }
     434                 :             : 
     435                 :             :   // True if the given file is a manifest file.
     436                 :         512 :   static bool IsManifest(const std::string& filename) {
     437                 :         512 :     return Basename(filename).starts_with("MANIFEST");
     438                 :             :   }
     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                 :         266 : int LockOrUnlock(int fd, bool lock) {
     453                 :         266 :   errno = 0;
     454                 :         266 :   struct ::flock file_lock_info;
     455         [ +  + ]:         266 :   std::memset(&file_lock_info, 0, sizeof(file_lock_info));
     456         [ +  + ]:         266 :   file_lock_info.l_type = (lock ? F_WRLCK : F_UNLCK);
     457                 :         266 :   file_lock_info.l_whence = SEEK_SET;
     458                 :         266 :   file_lock_info.l_start = 0;
     459                 :         266 :   file_lock_info.l_len = 0;  // Lock/unlock entire file.
     460                 :         266 :   return ::fcntl(fd, F_SETLK, &file_lock_info);
     461                 :             : }
     462                 :             : 
     463                 :             : // Instances are thread-safe because they are immutable.
     464                 :             : class PosixFileLock : public FileLock {
     465                 :             :  public:
     466                 :         133 :   PosixFileLock(int fd, std::string filename)
     467                 :         133 :       : fd_(fd), filename_(std::move(filename)) {}
     468                 :             : 
     469                 :         266 :   int fd() const { return fd_; }
     470                 :         133 :   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                 :          50 : class PosixLockTable {
     485                 :             :  public:
     486                 :         133 :   bool Insert(const std::string& fname) LOCKS_EXCLUDED(mu_) {
     487                 :         133 :     mu_.Lock();
     488                 :         133 :     bool succeeded = locked_files_.insert(fname).second;
     489                 :         133 :     mu_.Unlock();
     490                 :         133 :     return succeeded;
     491                 :             :   }
     492                 :         133 :   void Remove(const std::string& fname) LOCKS_EXCLUDED(mu_) {
     493                 :         133 :     mu_.Lock();
     494                 :         133 :     locked_files_.erase(fname);
     495                 :         133 :     mu_.Unlock();
     496                 :         133 :   }
     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                 :             :         "PosixEnv singleton destroyed. Unsupported behavior!\n";
     509                 :           0 :     std::fwrite(msg, 1, sizeof(msg), stderr);
     510                 :           0 :     std::abort();
     511                 :           0 :   }
     512                 :             : 
     513                 :         298 :   Status NewSequentialFile(const std::string& filename,
     514                 :             :                            SequentialFile** result) override {
     515                 :         298 :     int fd = ::open(filename.c_str(), O_RDONLY | kOpenBaseFlags);
     516         [ -  + ]:         298 :     if (fd < 0) {
     517                 :           0 :       *result = nullptr;
     518                 :           0 :       return PosixError(filename, errno);
     519                 :             :     }
     520                 :             : 
     521   [ -  +  +  - ]:         596 :     *result = new PosixSequentialFile(filename, fd);
     522                 :         298 :     return Status::OK();
     523                 :             :   }
     524                 :             : 
     525                 :         154 :   Status NewRandomAccessFile(const std::string& filename,
     526                 :             :                              RandomAccessFile** result) override {
     527                 :         154 :     *result = nullptr;
     528                 :         154 :     int fd = ::open(filename.c_str(), O_RDONLY | kOpenBaseFlags);
     529         [ -  + ]:         154 :     if (fd < 0) {
     530                 :           0 :       return PosixError(filename, errno);
     531                 :             :     }
     532                 :             : 
     533         [ -  + ]:         154 :     if (!mmap_limiter_.Acquire()) {
     534   [ #  #  #  # ]:           0 :       *result = new PosixRandomAccessFile(filename, fd, &fd_limiter_);
     535                 :           0 :       return Status::OK();
     536                 :             :     }
     537                 :             : 
     538                 :         154 :     uint64_t file_size;
     539                 :         154 :     Status status = GetFileSize(filename, &file_size);
     540         [ +  - ]:         154 :     if (status.ok()) {
     541                 :         154 :       void* mmap_base =
     542                 :         154 :           ::mmap(/*addr=*/nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0);
     543         [ +  - ]:         154 :       if (mmap_base != MAP_FAILED) {
     544                 :         308 :         *result = new PosixMmapReadableFile(filename,
     545                 :             :                                             reinterpret_cast<char*>(mmap_base),
     546   [ +  -  -  + ]:         462 :                                             file_size, &mmap_limiter_);
     547                 :             :       } else {
     548   [ #  #  #  # ]:           0 :         status = PosixError(filename, errno);
     549                 :             :       }
     550                 :             :     }
     551         [ +  - ]:         154 :     ::close(fd);
     552         [ -  + ]:         154 :     if (!status.ok()) {
     553                 :           0 :       mmap_limiter_.Release();
     554                 :             :     }
     555                 :         154 :     return status;
     556                 :         154 :   }
     557                 :             : 
     558                 :         512 :   Status NewWritableFile(const std::string& filename,
     559                 :             :                          WritableFile** result) override {
     560                 :         512 :     int fd = ::open(filename.c_str(),
     561                 :             :                     O_TRUNC | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);
     562         [ -  + ]:         512 :     if (fd < 0) {
     563                 :           0 :       *result = nullptr;
     564                 :           0 :       return PosixError(filename, errno);
     565                 :             :     }
     566                 :             : 
     567   [ -  +  +  - ]:        1024 :     *result = new PosixWritableFile(filename, fd);
     568                 :         512 :     return Status::OK();
     569                 :             :   }
     570                 :             : 
     571                 :           0 :   Status NewAppendableFile(const std::string& filename,
     572                 :             :                            WritableFile** result) override {
     573                 :           0 :     int fd = ::open(filename.c_str(),
     574                 :             :                     O_APPEND | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);
     575         [ #  # ]:           0 :     if (fd < 0) {
     576                 :           0 :       *result = nullptr;
     577                 :           0 :       return PosixError(filename, errno);
     578                 :             :     }
     579                 :             : 
     580   [ #  #  #  # ]:           0 :     *result = new PosixWritableFile(filename, fd);
     581                 :           0 :     return Status::OK();
     582                 :             :   }
     583                 :             : 
     584                 :         115 :   bool FileExists(const std::string& filename) override {
     585                 :         115 :     return ::access(filename.c_str(), F_OK) == 0;
     586                 :             :   }
     587                 :             : 
     588                 :         262 :   Status GetChildren(const std::string& directory_path,
     589                 :             :                      std::vector<std::string>* result) override {
     590                 :         262 :     result->clear();
     591                 :         262 :     ::DIR* dir = ::opendir(directory_path.c_str());
     592         [ +  + ]:         262 :     if (dir == nullptr) {
     593                 :           3 :       return PosixError(directory_path, errno);
     594                 :             :     }
     595                 :             :     struct ::dirent* entry;
     596         [ +  + ]:        2287 :     while ((entry = ::readdir(dir)) != nullptr) {
     597                 :        2028 :       result->emplace_back(entry->d_name);
     598                 :             :     }
     599                 :         259 :     ::closedir(dir);
     600                 :         259 :     return Status::OK();
     601                 :             :   }
     602                 :             : 
     603                 :         303 :   Status DeleteFile(const std::string& filename) override {
     604         [ -  + ]:         303 :     if (::unlink(filename.c_str()) != 0) {
     605                 :           0 :       return PosixError(filename, errno);
     606                 :             :     }
     607                 :         303 :     return Status::OK();
     608                 :             :   }
     609                 :             : 
     610                 :         115 :   Status CreateDir(const std::string& dirname) override {
     611         [ +  - ]:         115 :     if (::mkdir(dirname.c_str(), 0755) != 0) {
     612                 :         115 :       return PosixError(dirname, errno);
     613                 :             :     }
     614                 :           0 :     return Status::OK();
     615                 :             :   }
     616                 :             : 
     617                 :          18 :   Status DeleteDir(const std::string& dirname) override {
     618         [ -  + ]:          18 :     if (::rmdir(dirname.c_str()) != 0) {
     619                 :           0 :       return PosixError(dirname, errno);
     620                 :             :     }
     621                 :          18 :     return Status::OK();
     622                 :             :   }
     623                 :             : 
     624                 :         154 :   Status GetFileSize(const std::string& filename, uint64_t* size) override {
     625                 :         154 :     struct ::stat file_stat;
     626         [ -  + ]:         154 :     if (::stat(filename.c_str(), &file_stat) != 0) {
     627                 :           0 :       *size = 0;
     628                 :           0 :       return PosixError(filename, errno);
     629                 :             :     }
     630                 :         154 :     *size = file_stat.st_size;
     631                 :         154 :     return Status::OK();
     632                 :             :   }
     633                 :             : 
     634                 :         162 :   Status RenameFile(const std::string& from, const std::string& to) override {
     635         [ -  + ]:         162 :     if (std::rename(from.c_str(), to.c_str()) != 0) {
     636                 :           0 :       return PosixError(from, errno);
     637                 :             :     }
     638                 :         162 :     return Status::OK();
     639                 :             :   }
     640                 :             : 
     641                 :         133 :   Status LockFile(const std::string& filename, FileLock** lock) override {
     642                 :         133 :     *lock = nullptr;
     643                 :             : 
     644                 :         133 :     int fd = ::open(filename.c_str(), O_RDWR | O_CREAT | kOpenBaseFlags, 0644);
     645         [ -  + ]:         133 :     if (fd < 0) {
     646                 :           0 :       return PosixError(filename, errno);
     647                 :             :     }
     648                 :             : 
     649         [ -  + ]:         133 :     if (!locks_.Insert(filename)) {
     650                 :           0 :       ::close(fd);
     651   [ #  #  #  # ]:           0 :       return Status::IOError("lock " + filename, "already held by process");
     652                 :             :     }
     653                 :             : 
     654         [ -  + ]:         133 :     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                 :             :     }
     660                 :             : 
     661         [ -  + ]:         266 :     *lock = new PosixFileLock(fd, filename);
     662                 :         133 :     return Status::OK();
     663                 :             :   }
     664                 :             : 
     665                 :         133 :   Status UnlockFile(FileLock* lock) override {
     666                 :         133 :     PosixFileLock* posix_file_lock = static_cast<PosixFileLock*>(lock);
     667         [ -  + ]:         133 :     if (LockOrUnlock(posix_file_lock->fd(), false) == -1) {
     668         [ #  # ]:           0 :       return PosixError("unlock " + posix_file_lock->filename(), errno);
     669                 :             :     }
     670                 :         133 :     locks_.Remove(posix_file_lock->filename());
     671                 :         133 :     ::close(posix_file_lock->fd());
     672         [ +  - ]:         133 :     delete posix_file_lock;
     673                 :         133 :     return Status::OK();
     674                 :             :   }
     675                 :             : 
     676                 :             :   void Schedule(void (*background_work_function)(void* background_work_arg),
     677                 :             :                 void* background_work_arg) override;
     678                 :             : 
     679                 :           0 :   void StartThread(void (*thread_main)(void* thread_main_arg),
     680                 :             :                    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                 :             :     } 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                 :             :     }
     695                 :             : 
     696                 :             :     // The CreateDir status is ignored because the directory may already exist.
     697         [ #  # ]:           0 :     CreateDir(*result);
     698                 :             : 
     699                 :           0 :     return Status::OK();
     700                 :             :   }
     701                 :             : 
     702                 :           0 :   Status NewLogger(const std::string& filename, Logger** result) override {
     703                 :           0 :     int fd = ::open(filename.c_str(),
     704                 :             :                     O_APPEND | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);
     705         [ #  # ]:           0 :     if (fd < 0) {
     706                 :           0 :       *result = nullptr;
     707                 :           0 :       return PosixError(filename, errno);
     708                 :             :     }
     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                 :             :     } else {
     716                 :           0 :       *result = new PosixLogger(fp);
     717                 :           0 :       return Status::OK();
     718                 :             :     }
     719                 :             :   }
     720                 :             : 
     721                 :         148 :   uint64_t NowMicros() override {
     722                 :         148 :     static constexpr uint64_t kUsecondsPerSecond = 1000000;
     723                 :         148 :     struct ::timeval tv;
     724                 :         148 :     ::gettimeofday(&tv, nullptr);
     725                 :         148 :     return static_cast<uint64_t>(tv.tv_sec) * kUsecondsPerSecond + tv.tv_usec;
     726                 :             :   }
     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                 :           3 :   static void BackgroundThreadEntryPoint(PosixEnv* env) {
     736                 :           3 :     env->BackgroundThreadMain();
     737                 :             :   }
     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 because it is immutable.
     745                 :             :   struct BackgroundWorkItem {
     746                 :          13 :     explicit BackgroundWorkItem(void (*function)(void* arg), void* arg)
     747                 :          13 :         : 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                 :          50 : int MaxMmaps() { return g_mmap_limit; }
     767                 :             : 
     768                 :             : // Return the maximum number of read-only files to keep open.
     769                 :          50 : int MaxOpenFiles() {
     770         [ +  - ]:          50 :   if (g_open_read_only_file_limit >= 0) {
     771                 :             :     return g_open_read_only_file_limit;
     772                 :             :   }
     773                 :          50 :   struct ::rlimit rlim;
     774         [ -  + ]:          50 :   if (::getrlimit(RLIMIT_NOFILE, &rlim)) {
     775                 :             :     // getrlimit failed, fallback to hard-coded default.
     776                 :           0 :     g_open_read_only_file_limit = 50;
     777         [ -  + ]:          50 :   } else if (rlim.rlim_cur == RLIM_INFINITY) {
     778                 :           0 :     g_open_read_only_file_limit = std::numeric_limits<int>::max();
     779                 :             :   } else {
     780                 :             :     // Allow use of 20% of available file descriptors for read-only files.
     781                 :          50 :     g_open_read_only_file_limit = rlim.rlim_cur / 5;
     782                 :             :   }
     783                 :          50 :   return g_open_read_only_file_limit;
     784                 :             : }
     785                 :             : 
     786                 :             : }  // namespace
     787                 :             : 
     788                 :          50 : PosixEnv::PosixEnv()
     789                 :          50 :     : background_work_cv_(&background_work_mutex_),
     790                 :          50 :       started_background_thread_(false),
     791                 :          50 :       mmap_limiter_(MaxMmaps()),
     792         [ +  - ]:          50 :       fd_limiter_(MaxOpenFiles()) {}
     793                 :             : 
     794                 :          13 : void PosixEnv::Schedule(
     795                 :             :     void (*background_work_function)(void* background_work_arg),
     796                 :             :     void* background_work_arg) {
     797                 :          13 :   background_work_mutex_.Lock();
     798                 :             : 
     799                 :             :   // Start the background thread, if we haven't done so already.
     800         [ +  + ]:          13 :   if (!started_background_thread_) {
     801                 :           3 :     started_background_thread_ = true;
     802                 :           3 :     std::thread background_thread(PosixEnv::BackgroundThreadEntryPoint, this);
     803         [ +  - ]:           3 :     background_thread.detach();
     804                 :           3 :   }
     805                 :             : 
     806                 :             :   // If the queue is empty, the background thread may be waiting for work.
     807         [ +  - ]:          13 :   if (background_work_queue_.empty()) {
     808                 :          13 :     background_work_cv_.Signal();
     809                 :             :   }
     810                 :             : 
     811                 :          13 :   background_work_queue_.emplace(background_work_function, background_work_arg);
     812                 :          13 :   background_work_mutex_.Unlock();
     813                 :          13 : }
     814                 :             : 
     815                 :           3 : void PosixEnv::BackgroundThreadMain() {
     816                 :          29 :   while (true) {
     817                 :          16 :     background_work_mutex_.Lock();
     818                 :             : 
     819                 :             :     // Wait until there is work to be done.
     820         [ +  + ]:          26 :     while (background_work_queue_.empty()) {
     821                 :          13 :       background_work_cv_.Wait();
     822                 :             :     }
     823                 :             : 
     824                 :          13 :     assert(!background_work_queue_.empty());
     825                 :          13 :     auto background_work_function = background_work_queue_.front().function;
     826                 :          13 :     void* background_work_arg = background_work_queue_.front().arg;
     827                 :          13 :     background_work_queue_.pop();
     828                 :             : 
     829                 :          13 :     background_work_mutex_.Unlock();
     830                 :          13 :     background_work_function(background_work_arg);
     831                 :          13 :   }
     832                 :             : }
     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                 :          50 :   SingletonEnv() {
     852                 :             : #if !defined(NDEBUG)
     853                 :          50 :     env_initialized_.store(true, std::memory_order_relaxed);
     854                 :             : #endif  // !defined(NDEBUG)
     855                 :             :     static_assert(sizeof(env_storage_) >= sizeof(EnvType),
     856                 :             :                   "env_storage_ will not fit the Env");
     857                 :             :     static_assert(std::is_standard_layout_v<SingletonEnv<EnvType>>);
     858                 :             :     static_assert(
     859                 :             :         offsetof(SingletonEnv<EnvType>, env_storage_) % alignof(EnvType) == 0,
     860                 :             :         "env_storage_ does not meet the Env's alignment needs");
     861                 :             :     static_assert(alignof(SingletonEnv<EnvType>) % alignof(EnvType) == 0,
     862                 :             :                   "env_storage_ does not meet the Env's alignment needs");
     863                 :          50 :     new (env_storage_) EnvType();
     864                 :          50 :   }
     865                 :             :   ~SingletonEnv() = default;
     866                 :             : 
     867                 :             :   SingletonEnv(const SingletonEnv&) = delete;
     868                 :             :   SingletonEnv& operator=(const SingletonEnv&) = delete;
     869                 :             : 
     870                 :        1520 :   Env* env() { return reinterpret_cast<Env*>(&env_storage_); }
     871                 :             : 
     872         [ #  # ]:           0 :   static void AssertEnvNotInitialized() {
     873                 :             : #if !defined(NDEBUG)
     874         [ #  # ]:           0 :     assert(!env_initialized_.load(std::memory_order_relaxed));
     875                 :             : #endif  // !defined(NDEBUG)
     876                 :           0 :   }
     877                 :             : 
     878                 :             :  private:
     879                 :             :   alignas(EnvType) char env_storage_[sizeof(EnvType)];
     880                 :             : #if !defined(NDEBUG)
     881                 :             :   static std::atomic<bool> env_initialized_;
     882                 :             : #endif  // !defined(NDEBUG)
     883                 :             : };
     884                 :             : 
     885                 :             : #if !defined(NDEBUG)
     886                 :             : template <typename EnvType>
     887                 :             : std::atomic<bool> SingletonEnv<EnvType>::env_initialized_;
     888                 :             : #endif  // !defined(NDEBUG)
     889                 :             : 
     890                 :             : using PosixDefaultEnv = SingletonEnv<PosixEnv>;
     891                 :             : 
     892                 :             : }  // namespace
     893                 :             : 
     894                 :           0 : void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) {
     895                 :           0 :   PosixDefaultEnv::AssertEnvNotInitialized();
     896                 :           0 :   g_open_read_only_file_limit = limit;
     897                 :           0 : }
     898                 :             : 
     899                 :           0 : void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) {
     900                 :           0 :   PosixDefaultEnv::AssertEnvNotInitialized();
     901                 :           0 :   g_mmap_limit = limit;
     902                 :           0 : }
     903                 :             : 
     904                 :        1520 : Env* Env::Default() {
     905   [ +  +  +  -  :        1520 :   static PosixDefaultEnv env_container;
                   +  - ]
     906                 :        1520 :   return env_container.env();
     907                 :             : }
     908                 :             : 
     909                 :             : }  // namespace leveldb
        

Generated by: LCOV version 2.0-1