env_posix.cc raw

   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 1000 mmap regions for 64-bit binaries; none for 32-bit.
  46  constexpr const int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 1000 : 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  Status PosixError(const std::string& context, int error_number) {
  61    if (error_number == ENOENT) {
  62      return Status::NotFound(context, std::strerror(error_number));
  63    } else {
  64      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    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    bool Acquire() {
  83      int old_acquires_allowed =
  84          acquires_allowed_.fetch_sub(1, std::memory_order_relaxed);
  85  
  86      if (old_acquires_allowed > 0) return true;
  87  
  88      acquires_allowed_.fetch_add(1, std::memory_order_relaxed);
  89      return false;
  90    }
  91  
  92    // Release a resource acquired by a previous call to Acquire() that returned
  93    // true.
  94    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        : fd_(fd), filename_(filename) {}
 112    ~PosixSequentialFile() override { close(fd_); }
 113  
 114    Status Read(size_t n, Slice* result, char* scratch) override {
 115      Status status;
 116      while (true) {
 117        ::ssize_t read_size = ::read(fd_, scratch, n);
 118        if (read_size < 0) {  // Read error.
 119          if (errno == EINTR) {
 120            continue;  // Retry
 121          }
 122          status = PosixError(filename_, errno);
 123          break;
 124        }
 125        *result = Slice(scratch, read_size);
 126        break;
 127      }
 128      return status;
 129    }
 130  
 131    Status Skip(uint64_t n) override {
 132      if (::lseek(fd_, n, SEEK_CUR) == static_cast<off_t>(-1)) {
 133        return PosixError(filename_, errno);
 134      }
 135      return Status::OK();
 136    }
 137  
 138    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          filename_(std::move(filename)) {
 159      if (!has_permanent_fd_) {
 160        assert(fd_ == -1);
 161        ::close(fd);  // The file will be opened on every read.
 162      }
 163    }
 164  
 165    ~PosixRandomAccessFile() override {
 166      if (has_permanent_fd_) {
 167        assert(fd_ != -1);
 168        ::close(fd_);
 169        fd_limiter_->Release();
 170      }
 171    }
 172  
 173    Status Read(uint64_t offset, size_t n, Slice* result,
 174                char* scratch) const override {
 175      int fd = fd_;
 176      if (!has_permanent_fd_) {
 177        fd = ::open(filename_.c_str(), O_RDONLY | kOpenBaseFlags);
 178        if (fd < 0) {
 179          return PosixError(filename_, errno);
 180        }
 181      }
 182  
 183      assert(fd != -1);
 184  
 185      Status status;
 186      ssize_t read_size = ::pread(fd, scratch, n, static_cast<off_t>(offset));
 187      *result = Slice(scratch, (read_size < 0) ? 0 : read_size);
 188      if (read_size < 0) {
 189        // An error: return a non-ok status.
 190        status = PosixError(filename_, errno);
 191      }
 192      if (!has_permanent_fd_) {
 193        // Close the temporary file descriptor opened earlier.
 194        assert(fd != fd_);
 195        ::close(fd);
 196      }
 197      return status;
 198    }
 199  
 200    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    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          filename_(std::move(filename)) {}
 229  
 230    ~PosixMmapReadableFile() override {
 231      ::munmap(static_cast<void*>(mmap_base_), length_);
 232      mmap_limiter_->Release();
 233    }
 234  
 235    Status Read(uint64_t offset, size_t n, Slice* result,
 236                char* scratch) const override {
 237      if (offset + n > length_) {
 238        *result = Slice();
 239        return PosixError(filename_, EINVAL);
 240      }
 241  
 242      *result = Slice(mmap_base_ + offset, n);
 243      return Status::OK();
 244    }
 245  
 246    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          dirname_(Dirname(filename_)) {}
 263  
 264    ~PosixWritableFile() override {
 265      if (fd_ >= 0) {
 266        // Ignoring any potential errors
 267        Close();
 268      }
 269    }
 270  
 271    Status Append(const Slice& data) override {
 272      size_t write_size = data.size();
 273      const char* write_data = data.data();
 274  
 275      // Fit as much as possible into buffer.
 276      size_t copy_size = std::min(write_size, kWritableFileBufferSize - pos_);
 277      std::memcpy(buf_ + pos_, write_data, copy_size);
 278      write_data += copy_size;
 279      write_size -= copy_size;
 280      pos_ += copy_size;
 281      if (write_size == 0) {
 282        return Status::OK();
 283      }
 284  
 285      // Can't fit in buffer, so need to do at least one write.
 286      Status status = FlushBuffer();
 287      if (!status.ok()) {
 288        return status;
 289      }
 290  
 291      // Small writes go to buffer, large writes are written directly.
 292      if (write_size < kWritableFileBufferSize) {
 293        std::memcpy(buf_, write_data, write_size);
 294        pos_ = write_size;
 295        return Status::OK();
 296      }
 297      return WriteUnbuffered(write_data, write_size);
 298    }
 299  
 300    Status Close() override {
 301      Status status = FlushBuffer();
 302      const int close_result = ::close(fd_);
 303      if (close_result < 0 && status.ok()) {
 304        status = PosixError(filename_, errno);
 305      }
 306      fd_ = -1;
 307      return status;
 308    }
 309  
 310    Status Flush() override { return FlushBuffer(); }
 311  
 312    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      Status status = SyncDirIfManifest();
 319      if (!status.ok()) {
 320        return status;
 321      }
 322  
 323      status = FlushBuffer();
 324      if (!status.ok()) {
 325        return status;
 326      }
 327  
 328      return SyncFd(fd_, filename_, false);
 329    }
 330  
 331   private:
 332    Status FlushBuffer() {
 333      Status status = WriteUnbuffered(buf_, pos_);
 334      pos_ = 0;
 335      return status;
 336    }
 337  
 338    Status WriteUnbuffered(const char* data, size_t size) {
 339      while (size > 0) {
 340        ssize_t write_result = ::write(fd_, data, size);
 341        if (write_result < 0) {
 342          if (errno == EINTR) {
 343            continue;  // Retry
 344          }
 345          return PosixError(filename_, errno);
 346        }
 347        data += write_result;
 348        size -= write_result;
 349      }
 350      return Status::OK();
 351    }
 352  
 353    Status SyncDirIfManifest() {
 354      Status status;
 355      if (!is_manifest_) {
 356        return status;
 357      }
 358  
 359      int fd = ::open(dirname_.c_str(), O_RDONLY | kOpenBaseFlags);
 360      if (fd < 0) {
 361        status = PosixError(dirname_, errno);
 362      } else {
 363        status = SyncFd(fd, dirname_, true);
 364        ::close(fd);
 365      }
 366      return status;
 367    }
 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    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      bool sync_success = ::fdatasync(fd) == 0;
 388  #else
 389      bool sync_success = ::fsync(fd) == 0;
 390  #endif  // HAVE_FDATASYNC
 391  
 392      if (sync_success) {
 393        return Status::OK();
 394      }
 395      // Do not crash if filesystem can't fsync directories
 396      // (see https://github.com/bitcoin/bitcoin/pull/10000)
 397      if (syncing_dir && errno == EINVAL) {
 398        return Status::OK();
 399      }
 400      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    static std::string Dirname(const std::string& filename) {
 407      std::string::size_type separator_pos = filename.rfind('/');
 408      if (separator_pos == std::string::npos) {
 409        return std::string(".");
 410      }
 411      // The filename component should not contain a path separator. If it does,
 412      // the splitting was done incorrectly.
 413      assert(filename.find('/', separator_pos + 1) == std::string::npos);
 414  
 415      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    static Slice Basename(const std::string& filename) {
 423      std::string::size_type separator_pos = filename.rfind('/');
 424      if (separator_pos == std::string::npos) {
 425        return Slice(filename);
 426      }
 427      // The filename component should not contain a path separator. If it does,
 428      // the splitting was done incorrectly.
 429      assert(filename.find('/', separator_pos + 1) == std::string::npos);
 430  
 431      return Slice(filename.data() + separator_pos + 1,
 432                   filename.length() - separator_pos - 1);
 433    }
 434  
 435    // True if the given file is a manifest file.
 436    static bool IsManifest(const std::string& filename) {
 437      return Basename(filename).starts_with("MANIFEST");
 438    }
 439  
 440    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  int LockOrUnlock(int fd, bool lock) {
 453    errno = 0;
 454    struct ::flock file_lock_info;
 455    std::memset(&file_lock_info, 0, sizeof(file_lock_info));
 456    file_lock_info.l_type = (lock ? F_WRLCK : F_UNLCK);
 457    file_lock_info.l_whence = SEEK_SET;
 458    file_lock_info.l_start = 0;
 459    file_lock_info.l_len = 0;  // Lock/unlock entire file.
 460    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    PosixFileLock(int fd, std::string filename)
 467        : fd_(fd), filename_(std::move(filename)) {}
 468  
 469    int fd() const { return fd_; }
 470    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    bool Insert(const std::string& fname) LOCKS_EXCLUDED(mu_) {
 487      mu_.Lock();
 488      bool succeeded = locked_files_.insert(fname).second;
 489      mu_.Unlock();
 490      return succeeded;
 491    }
 492    void Remove(const std::string& fname) LOCKS_EXCLUDED(mu_) {
 493      mu_.Lock();
 494      locked_files_.erase(fname);
 495      mu_.Unlock();
 496    }
 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    ~PosixEnv() override {
 507      static const char msg[] =
 508          "PosixEnv singleton destroyed. Unsupported behavior!\n";
 509      std::fwrite(msg, 1, sizeof(msg), stderr);
 510      std::abort();
 511    }
 512  
 513    Status NewSequentialFile(const std::string& filename,
 514                             SequentialFile** result) override {
 515      int fd = ::open(filename.c_str(), O_RDONLY | kOpenBaseFlags);
 516      if (fd < 0) {
 517        *result = nullptr;
 518        return PosixError(filename, errno);
 519      }
 520  
 521      *result = new PosixSequentialFile(filename, fd);
 522      return Status::OK();
 523    }
 524  
 525    Status NewRandomAccessFile(const std::string& filename,
 526                               RandomAccessFile** result) override {
 527      *result = nullptr;
 528      int fd = ::open(filename.c_str(), O_RDONLY | kOpenBaseFlags);
 529      if (fd < 0) {
 530        return PosixError(filename, errno);
 531      }
 532  
 533      if (!mmap_limiter_.Acquire()) {
 534        *result = new PosixRandomAccessFile(filename, fd, &fd_limiter_);
 535        return Status::OK();
 536      }
 537  
 538      uint64_t file_size;
 539      Status status = GetFileSize(filename, &file_size);
 540      if (status.ok()) {
 541        void* mmap_base =
 542            ::mmap(/*addr=*/nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0);
 543        if (mmap_base != MAP_FAILED) {
 544          *result = new PosixMmapReadableFile(filename,
 545                                              reinterpret_cast<char*>(mmap_base),
 546                                              file_size, &mmap_limiter_);
 547        } else {
 548          status = PosixError(filename, errno);
 549        }
 550      }
 551      ::close(fd);
 552      if (!status.ok()) {
 553        mmap_limiter_.Release();
 554      }
 555      return status;
 556    }
 557  
 558    Status NewWritableFile(const std::string& filename,
 559                           WritableFile** result) override {
 560      int fd = ::open(filename.c_str(),
 561                      O_TRUNC | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);
 562      if (fd < 0) {
 563        *result = nullptr;
 564        return PosixError(filename, errno);
 565      }
 566  
 567      *result = new PosixWritableFile(filename, fd);
 568      return Status::OK();
 569    }
 570  
 571    Status NewAppendableFile(const std::string& filename,
 572                             WritableFile** result) override {
 573      int fd = ::open(filename.c_str(),
 574                      O_APPEND | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);
 575      if (fd < 0) {
 576        *result = nullptr;
 577        return PosixError(filename, errno);
 578      }
 579  
 580      *result = new PosixWritableFile(filename, fd);
 581      return Status::OK();
 582    }
 583  
 584    bool FileExists(const std::string& filename) override {
 585      return ::access(filename.c_str(), F_OK) == 0;
 586    }
 587  
 588    Status GetChildren(const std::string& directory_path,
 589                       std::vector<std::string>* result) override {
 590      result->clear();
 591      ::DIR* dir = ::opendir(directory_path.c_str());
 592      if (dir == nullptr) {
 593        return PosixError(directory_path, errno);
 594      }
 595      struct ::dirent* entry;
 596      while ((entry = ::readdir(dir)) != nullptr) {
 597        result->emplace_back(entry->d_name);
 598      }
 599      ::closedir(dir);
 600      return Status::OK();
 601    }
 602  
 603    Status DeleteFile(const std::string& filename) override {
 604      if (::unlink(filename.c_str()) != 0) {
 605        return PosixError(filename, errno);
 606      }
 607      return Status::OK();
 608    }
 609  
 610    Status CreateDir(const std::string& dirname) override {
 611      if (::mkdir(dirname.c_str(), 0755) != 0) {
 612        return PosixError(dirname, errno);
 613      }
 614      return Status::OK();
 615    }
 616  
 617    Status DeleteDir(const std::string& dirname) override {
 618      if (::rmdir(dirname.c_str()) != 0) {
 619        return PosixError(dirname, errno);
 620      }
 621      return Status::OK();
 622    }
 623  
 624    Status GetFileSize(const std::string& filename, uint64_t* size) override {
 625      struct ::stat file_stat;
 626      if (::stat(filename.c_str(), &file_stat) != 0) {
 627        *size = 0;
 628        return PosixError(filename, errno);
 629      }
 630      *size = file_stat.st_size;
 631      return Status::OK();
 632    }
 633  
 634    Status RenameFile(const std::string& from, const std::string& to) override {
 635      if (std::rename(from.c_str(), to.c_str()) != 0) {
 636        return PosixError(from, errno);
 637      }
 638      return Status::OK();
 639    }
 640  
 641    Status LockFile(const std::string& filename, FileLock** lock) override {
 642      *lock = nullptr;
 643  
 644      int fd = ::open(filename.c_str(), O_RDWR | O_CREAT | kOpenBaseFlags, 0644);
 645      if (fd < 0) {
 646        return PosixError(filename, errno);
 647      }
 648  
 649      if (!locks_.Insert(filename)) {
 650        ::close(fd);
 651        return Status::IOError("lock " + filename, "already held by process");
 652      }
 653  
 654      if (LockOrUnlock(fd, true) == -1) {
 655        int lock_errno = errno;
 656        ::close(fd);
 657        locks_.Remove(filename);
 658        return PosixError("lock " + filename, lock_errno);
 659      }
 660  
 661      *lock = new PosixFileLock(fd, filename);
 662      return Status::OK();
 663    }
 664  
 665    Status UnlockFile(FileLock* lock) override {
 666      PosixFileLock* posix_file_lock = static_cast<PosixFileLock*>(lock);
 667      if (LockOrUnlock(posix_file_lock->fd(), false) == -1) {
 668        return PosixError("unlock " + posix_file_lock->filename(), errno);
 669      }
 670      locks_.Remove(posix_file_lock->filename());
 671      ::close(posix_file_lock->fd());
 672      delete posix_file_lock;
 673      return Status::OK();
 674    }
 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                     void* thread_main_arg) override {
 681      std::thread new_thread(thread_main, thread_main_arg);
 682      new_thread.detach();
 683    }
 684  
 685    Status GetTestDirectory(std::string* result) override {
 686      const char* env = std::getenv("TEST_TMPDIR");
 687      if (env && env[0] != '\0') {
 688        *result = env;
 689      } else {
 690        char buf[100];
 691        std::snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d",
 692                      static_cast<int>(::geteuid()));
 693        *result = buf;
 694      }
 695  
 696      // The CreateDir status is ignored because the directory may already exist.
 697      CreateDir(*result);
 698  
 699      return Status::OK();
 700    }
 701  
 702    Status NewLogger(const std::string& filename, Logger** result) override {
 703      int fd = ::open(filename.c_str(),
 704                      O_APPEND | O_WRONLY | O_CREAT | kOpenBaseFlags, 0644);
 705      if (fd < 0) {
 706        *result = nullptr;
 707        return PosixError(filename, errno);
 708      }
 709  
 710      std::FILE* fp = ::fdopen(fd, "w");
 711      if (fp == nullptr) {
 712        ::close(fd);
 713        *result = nullptr;
 714        return PosixError(filename, errno);
 715      } else {
 716        *result = new PosixLogger(fp);
 717        return Status::OK();
 718      }
 719    }
 720  
 721    uint64_t NowMicros() override {
 722      static constexpr uint64_t kUsecondsPerSecond = 1000000;
 723      struct ::timeval tv;
 724      ::gettimeofday(&tv, nullptr);
 725      return static_cast<uint64_t>(tv.tv_sec) * kUsecondsPerSecond + tv.tv_usec;
 726    }
 727  
 728    void SleepForMicroseconds(int micros) override {
 729      std::this_thread::sleep_for(std::chrono::microseconds(micros));
 730    }
 731  
 732   private:
 733    void BackgroundThreadMain();
 734  
 735    static void BackgroundThreadEntryPoint(PosixEnv* env) {
 736      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      explicit BackgroundWorkItem(void (*function)(void* arg), void* arg)
 747          : 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  int MaxMmaps() { return g_mmap_limit; }
 767  
 768  // Return the maximum number of read-only files to keep open.
 769  int MaxOpenFiles() {
 770    if (g_open_read_only_file_limit >= 0) {
 771      return g_open_read_only_file_limit;
 772    }
 773    struct ::rlimit rlim;
 774    if (::getrlimit(RLIMIT_NOFILE, &rlim)) {
 775      // getrlimit failed, fallback to hard-coded default.
 776      g_open_read_only_file_limit = 50;
 777    } else if (rlim.rlim_cur == RLIM_INFINITY) {
 778      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      g_open_read_only_file_limit = rlim.rlim_cur / 5;
 782    }
 783    return g_open_read_only_file_limit;
 784  }
 785  
 786  }  // namespace
 787  
 788  PosixEnv::PosixEnv()
 789      : background_work_cv_(&background_work_mutex_),
 790        started_background_thread_(false),
 791        mmap_limiter_(MaxMmaps()),
 792        fd_limiter_(MaxOpenFiles()) {}
 793  
 794  void PosixEnv::Schedule(
 795      void (*background_work_function)(void* background_work_arg),
 796      void* background_work_arg) {
 797    background_work_mutex_.Lock();
 798  
 799    // Start the background thread, if we haven't done so already.
 800    if (!started_background_thread_) {
 801      started_background_thread_ = true;
 802      std::thread background_thread(PosixEnv::BackgroundThreadEntryPoint, this);
 803      background_thread.detach();
 804    }
 805  
 806    // If the queue is empty, the background thread may be waiting for work.
 807    if (background_work_queue_.empty()) {
 808      background_work_cv_.Signal();
 809    }
 810  
 811    background_work_queue_.emplace(background_work_function, background_work_arg);
 812    background_work_mutex_.Unlock();
 813  }
 814  
 815  void PosixEnv::BackgroundThreadMain() {
 816    while (true) {
 817      background_work_mutex_.Lock();
 818  
 819      // Wait until there is work to be done.
 820      while (background_work_queue_.empty()) {
 821        background_work_cv_.Wait();
 822      }
 823  
 824      assert(!background_work_queue_.empty());
 825      auto background_work_function = background_work_queue_.front().function;
 826      void* background_work_arg = background_work_queue_.front().arg;
 827      background_work_queue_.pop();
 828  
 829      background_work_mutex_.Unlock();
 830      background_work_function(background_work_arg);
 831    }
 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    SingletonEnv() {
 852  #if !defined(NDEBUG)
 853      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      new (env_storage_) EnvType();
 864    }
 865    ~SingletonEnv() = default;
 866  
 867    SingletonEnv(const SingletonEnv&) = delete;
 868    SingletonEnv& operator=(const SingletonEnv&) = delete;
 869  
 870    Env* env() { return reinterpret_cast<Env*>(&env_storage_); }
 871  
 872    static void AssertEnvNotInitialized() {
 873  #if !defined(NDEBUG)
 874      assert(!env_initialized_.load(std::memory_order_relaxed));
 875  #endif  // !defined(NDEBUG)
 876    }
 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  void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) {
 895    PosixDefaultEnv::AssertEnvNotInitialized();
 896    g_open_read_only_file_limit = limit;
 897  }
 898  
 899  void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) {
 900    PosixDefaultEnv::AssertEnvNotInitialized();
 901    g_mmap_limit = limit;
 902  }
 903  
 904  Env* Env::Default() {
 905    static PosixDefaultEnv env_container;
 906    return env_container.env();
 907  }
 908  
 909  }  // namespace leveldb
 910