env_windows.cc raw

   1  // Copyright (c) 2018 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  // Prevent Windows headers from defining min/max macros and instead
   6  // use STL.
   7  #ifndef NOMINMAX
   8  #define NOMINMAX
   9  #endif  // ifndef NOMINMAX
  10  #include <windows.h>
  11  
  12  #include <algorithm>
  13  #include <atomic>
  14  #include <chrono>
  15  #include <condition_variable>
  16  #include <cstddef>
  17  #include <cstdint>
  18  #include <cstdlib>
  19  #include <cstring>
  20  #include <memory>
  21  #include <mutex>
  22  #include <queue>
  23  #include <sstream>
  24  #include <string>
  25  #include <vector>
  26  
  27  #include "leveldb/env.h"
  28  #include "leveldb/slice.h"
  29  #include "port/port.h"
  30  #include "port/thread_annotations.h"
  31  #include "util/env_windows_test_helper.h"
  32  #include "util/logging.h"
  33  #include "util/mutexlock.h"
  34  #include "util/windows_logger.h"
  35  
  36  #if defined(DeleteFile)
  37  #undef DeleteFile
  38  #endif  // defined(DeleteFile)
  39  
  40  namespace leveldb {
  41  
  42  namespace {
  43  
  44  constexpr const size_t kWritableFileBufferSize = 65536;
  45  
  46  // Up to 1000 mmaps for 64-bit binaries; none for 32-bit.
  47  constexpr int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 1000 : 0;
  48  
  49  // Can be set by by EnvWindowsTestHelper::SetReadOnlyMMapLimit().
  50  int g_mmap_limit = kDefaultMmapLimit;
  51  
  52  std::string GetWindowsErrorMessage(DWORD error_code) {
  53    std::string message;
  54    char* error_text = nullptr;
  55    // Use MBCS version of FormatMessage to match return value.
  56    size_t error_text_size = ::FormatMessageA(
  57        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
  58            FORMAT_MESSAGE_IGNORE_INSERTS,
  59        nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  60        reinterpret_cast<char*>(&error_text), 0, nullptr);
  61    if (!error_text) {
  62      return message;
  63    }
  64    message.assign(error_text, error_text_size);
  65    ::LocalFree(error_text);
  66    return message;
  67  }
  68  
  69  Status WindowsError(const std::string& context, DWORD error_code) {
  70    if (error_code == ERROR_FILE_NOT_FOUND || error_code == ERROR_PATH_NOT_FOUND)
  71      return Status::NotFound(context, GetWindowsErrorMessage(error_code));
  72    return Status::IOError(context, GetWindowsErrorMessage(error_code));
  73  }
  74  
  75  class ScopedHandle {
  76   public:
  77    ScopedHandle(HANDLE handle) : handle_(handle) {}
  78    ScopedHandle(const ScopedHandle&) = delete;
  79    ScopedHandle(ScopedHandle&& other) noexcept : handle_(other.Release()) {}
  80    ~ScopedHandle() { Close(); }
  81  
  82    ScopedHandle& operator=(const ScopedHandle&) = delete;
  83  
  84    ScopedHandle& operator=(ScopedHandle&& rhs) = delete;
  85  
  86    bool Close() {
  87      if (!is_valid()) {
  88        return true;
  89      }
  90      HANDLE h = handle_;
  91      handle_ = INVALID_HANDLE_VALUE;
  92      return ::CloseHandle(h);
  93    }
  94  
  95    bool is_valid() const {
  96      return handle_ != INVALID_HANDLE_VALUE && handle_ != nullptr;
  97    }
  98  
  99    HANDLE get() const { return handle_; }
 100  
 101    HANDLE Release() {
 102      HANDLE h = handle_;
 103      handle_ = INVALID_HANDLE_VALUE;
 104      return h;
 105    }
 106  
 107   private:
 108    HANDLE handle_;
 109  };
 110  
 111  // Helper class to limit resource usage to avoid exhaustion.
 112  // Currently used to limit read-only file descriptors and mmap file usage
 113  // so that we do not run out of file descriptors or virtual memory, or run into
 114  // kernel performance problems for very large databases.
 115  class Limiter {
 116   public:
 117    // Limit maximum number of resources to |max_acquires|.
 118    Limiter(int max_acquires) : acquires_allowed_(max_acquires) {}
 119  
 120    Limiter(const Limiter&) = delete;
 121    Limiter operator=(const Limiter&) = delete;
 122  
 123    // If another resource is available, acquire it and return true.
 124    // Else return false.
 125    bool Acquire() {
 126      int old_acquires_allowed =
 127          acquires_allowed_.fetch_sub(1, std::memory_order_relaxed);
 128  
 129      if (old_acquires_allowed > 0) return true;
 130  
 131      acquires_allowed_.fetch_add(1, std::memory_order_relaxed);
 132      return false;
 133    }
 134  
 135    // Release a resource acquired by a previous call to Acquire() that returned
 136    // true.
 137    void Release() { acquires_allowed_.fetch_add(1, std::memory_order_relaxed); }
 138  
 139   private:
 140    // The number of available resources.
 141    //
 142    // This is a counter and is not tied to the invariants of any other class, so
 143    // it can be operated on safely using std::memory_order_relaxed.
 144    std::atomic<int> acquires_allowed_;
 145  };
 146  
 147  class WindowsSequentialFile : public SequentialFile {
 148   public:
 149    WindowsSequentialFile(std::string filename, ScopedHandle handle)
 150        : handle_(std::move(handle)), filename_(std::move(filename)) {}
 151    ~WindowsSequentialFile() override {}
 152  
 153    Status Read(size_t n, Slice* result, char* scratch) override {
 154      DWORD bytes_read;
 155      // DWORD is 32-bit, but size_t could technically be larger. However leveldb
 156      // files are limited to leveldb::Options::max_file_size which is clamped to
 157      // 1<<30 or 1 GiB.
 158      assert(n <= std::numeric_limits<DWORD>::max());
 159      if (!::ReadFile(handle_.get(), scratch, static_cast<DWORD>(n), &bytes_read,
 160                      nullptr)) {
 161        return WindowsError(filename_, ::GetLastError());
 162      }
 163  
 164      *result = Slice(scratch, bytes_read);
 165      return Status::OK();
 166    }
 167  
 168    Status Skip(uint64_t n) override {
 169      LARGE_INTEGER distance;
 170      distance.QuadPart = n;
 171      if (!::SetFilePointerEx(handle_.get(), distance, nullptr, FILE_CURRENT)) {
 172        return WindowsError(filename_, ::GetLastError());
 173      }
 174      return Status::OK();
 175    }
 176  
 177    std::string GetName() const override { return filename_; }
 178  
 179   private:
 180    const ScopedHandle handle_;
 181    const std::string filename_;
 182  };
 183  
 184  class WindowsRandomAccessFile : public RandomAccessFile {
 185   public:
 186    WindowsRandomAccessFile(std::string filename, ScopedHandle handle)
 187        : handle_(std::move(handle)), filename_(std::move(filename)) {}
 188  
 189    ~WindowsRandomAccessFile() override = default;
 190  
 191    Status Read(uint64_t offset, size_t n, Slice* result,
 192                char* scratch) const override {
 193      DWORD bytes_read = 0;
 194      OVERLAPPED overlapped = {};
 195  
 196      overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
 197      overlapped.Offset = static_cast<DWORD>(offset);
 198      if (!::ReadFile(handle_.get(), scratch, static_cast<DWORD>(n), &bytes_read,
 199                      &overlapped)) {
 200        DWORD error_code = ::GetLastError();
 201        if (error_code != ERROR_HANDLE_EOF) {
 202          *result = Slice(scratch, 0);
 203          return Status::IOError(filename_, GetWindowsErrorMessage(error_code));
 204        }
 205      }
 206  
 207      *result = Slice(scratch, bytes_read);
 208      return Status::OK();
 209    }
 210  
 211    std::string GetName() const override { return filename_; }
 212  
 213   private:
 214    const ScopedHandle handle_;
 215    const std::string filename_;
 216  };
 217  
 218  class WindowsMmapReadableFile : public RandomAccessFile {
 219   public:
 220    // base[0,length-1] contains the mmapped contents of the file.
 221    WindowsMmapReadableFile(std::string filename, char* mmap_base, size_t length,
 222                            Limiter* mmap_limiter)
 223        : mmap_base_(mmap_base),
 224          length_(length),
 225          mmap_limiter_(mmap_limiter),
 226          filename_(std::move(filename)) {}
 227  
 228    ~WindowsMmapReadableFile() override {
 229      ::UnmapViewOfFile(mmap_base_);
 230      mmap_limiter_->Release();
 231    }
 232  
 233    Status Read(uint64_t offset, size_t n, Slice* result,
 234                char* scratch) const override {
 235      if (offset + n > length_) {
 236        *result = Slice();
 237        return WindowsError(filename_, ERROR_INVALID_PARAMETER);
 238      }
 239  
 240      *result = Slice(mmap_base_ + offset, n);
 241      return Status::OK();
 242    }
 243  
 244    std::string GetName() const override { return filename_; }
 245  
 246   private:
 247    char* const mmap_base_;
 248    const size_t length_;
 249    Limiter* const mmap_limiter_;
 250    const std::string filename_;
 251  };
 252  
 253  class WindowsWritableFile : public WritableFile {
 254   public:
 255    WindowsWritableFile(std::string filename, ScopedHandle handle)
 256        : pos_(0), handle_(std::move(handle)), filename_(std::move(filename)) {}
 257  
 258    ~WindowsWritableFile() override = default;
 259  
 260    Status Append(const Slice& data) override {
 261      size_t write_size = data.size();
 262      const char* write_data = data.data();
 263  
 264      // Fit as much as possible into buffer.
 265      size_t copy_size = std::min(write_size, kWritableFileBufferSize - pos_);
 266      std::memcpy(buf_ + pos_, write_data, copy_size);
 267      write_data += copy_size;
 268      write_size -= copy_size;
 269      pos_ += copy_size;
 270      if (write_size == 0) {
 271        return Status::OK();
 272      }
 273  
 274      // Can't fit in buffer, so need to do at least one write.
 275      Status status = FlushBuffer();
 276      if (!status.ok()) {
 277        return status;
 278      }
 279  
 280      // Small writes go to buffer, large writes are written directly.
 281      if (write_size < kWritableFileBufferSize) {
 282        std::memcpy(buf_, write_data, write_size);
 283        pos_ = write_size;
 284        return Status::OK();
 285      }
 286      return WriteUnbuffered(write_data, write_size);
 287    }
 288  
 289    Status Close() override {
 290      Status status = FlushBuffer();
 291      if (!handle_.Close() && status.ok()) {
 292        status = WindowsError(filename_, ::GetLastError());
 293      }
 294      return status;
 295    }
 296  
 297    Status Flush() override { return FlushBuffer(); }
 298  
 299    Status Sync() override {
 300      // On Windows no need to sync parent directory. Its metadata will be updated
 301      // via the creation of the new file, without an explicit sync.
 302  
 303      Status status = FlushBuffer();
 304      if (!status.ok()) {
 305        return status;
 306      }
 307  
 308      if (!::FlushFileBuffers(handle_.get())) {
 309        return Status::IOError(filename_,
 310                               GetWindowsErrorMessage(::GetLastError()));
 311      }
 312      return Status::OK();
 313    }
 314  
 315    std::string GetName() const override { return filename_; }
 316  
 317   private:
 318    Status FlushBuffer() {
 319      Status status = WriteUnbuffered(buf_, pos_);
 320      pos_ = 0;
 321      return status;
 322    }
 323  
 324    Status WriteUnbuffered(const char* data, size_t size) {
 325      DWORD bytes_written;
 326      if (!::WriteFile(handle_.get(), data, static_cast<DWORD>(size),
 327                       &bytes_written, nullptr)) {
 328        return Status::IOError(filename_,
 329                               GetWindowsErrorMessage(::GetLastError()));
 330      }
 331      return Status::OK();
 332    }
 333  
 334    // buf_[0, pos_-1] contains data to be written to handle_.
 335    char buf_[kWritableFileBufferSize];
 336    size_t pos_;
 337  
 338    ScopedHandle handle_;
 339    const std::string filename_;
 340  };
 341  
 342  // Lock or unlock the entire file as specified by |lock|. Returns true
 343  // when successful, false upon failure. Caller should call ::GetLastError()
 344  // to determine cause of failure
 345  bool LockOrUnlock(HANDLE handle, bool lock) {
 346    if (lock) {
 347      return ::LockFile(handle,
 348                        /*dwFileOffsetLow=*/0, /*dwFileOffsetHigh=*/0,
 349                        /*nNumberOfBytesToLockLow=*/MAXDWORD,
 350                        /*nNumberOfBytesToLockHigh=*/MAXDWORD);
 351    } else {
 352      return ::UnlockFile(handle,
 353                          /*dwFileOffsetLow=*/0, /*dwFileOffsetHigh=*/0,
 354                          /*nNumberOfBytesToLockLow=*/MAXDWORD,
 355                          /*nNumberOfBytesToLockHigh=*/MAXDWORD);
 356    }
 357  }
 358  
 359  class WindowsFileLock : public FileLock {
 360   public:
 361    WindowsFileLock(ScopedHandle handle, std::string filename)
 362        : handle_(std::move(handle)), filename_(std::move(filename)) {}
 363  
 364    const ScopedHandle& handle() const { return handle_; }
 365    const std::string& filename() const { return filename_; }
 366  
 367   private:
 368    const ScopedHandle handle_;
 369    const std::string filename_;
 370  };
 371  
 372  class WindowsEnv : public Env {
 373   public:
 374    WindowsEnv();
 375    ~WindowsEnv() override {
 376      static const char msg[] =
 377          "WindowsEnv singleton destroyed. Unsupported behavior!\n";
 378      std::fwrite(msg, 1, sizeof(msg), stderr);
 379      std::abort();
 380    }
 381  
 382    Status NewSequentialFile(const std::string& filename,
 383                             SequentialFile** result) override {
 384      *result = nullptr;
 385      DWORD desired_access = GENERIC_READ;
 386      DWORD share_mode = FILE_SHARE_READ;
 387      auto wFilename = toUtf16(filename);
 388      ScopedHandle handle = ::CreateFileW(
 389          wFilename.c_str(), desired_access, share_mode,
 390          /*lpSecurityAttributes=*/nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
 391          /*hTemplateFile=*/nullptr);
 392      if (!handle.is_valid()) {
 393        return WindowsError(filename, ::GetLastError());
 394      }
 395  
 396      *result = new WindowsSequentialFile(filename, std::move(handle));
 397      return Status::OK();
 398    }
 399  
 400    Status NewRandomAccessFile(const std::string& filename,
 401                               RandomAccessFile** result) override {
 402      *result = nullptr;
 403      DWORD desired_access = GENERIC_READ;
 404      DWORD share_mode = FILE_SHARE_READ;
 405      auto wFilename = toUtf16(filename);
 406      ScopedHandle handle =
 407          ::CreateFileW(wFilename.c_str(), desired_access, share_mode,
 408                        /*lpSecurityAttributes=*/nullptr, OPEN_EXISTING,
 409                        FILE_ATTRIBUTE_READONLY,
 410                        /*hTemplateFile=*/nullptr);
 411      if (!handle.is_valid()) {
 412        return WindowsError(filename, ::GetLastError());
 413      }
 414      if (!mmap_limiter_.Acquire()) {
 415        *result = new WindowsRandomAccessFile(filename, std::move(handle));
 416        return Status::OK();
 417      }
 418  
 419      LARGE_INTEGER file_size;
 420      Status status;
 421      if (!::GetFileSizeEx(handle.get(), &file_size)) {
 422        mmap_limiter_.Release();
 423        return WindowsError(filename, ::GetLastError());
 424      }
 425  
 426      ScopedHandle mapping =
 427          ::CreateFileMappingW(handle.get(),
 428                               /*security attributes=*/nullptr, PAGE_READONLY,
 429                               /*dwMaximumSizeHigh=*/0,
 430                               /*dwMaximumSizeLow=*/0,
 431                               /*lpName=*/nullptr);
 432      if (mapping.is_valid()) {
 433        void* mmap_base = ::MapViewOfFile(mapping.get(), FILE_MAP_READ,
 434                                          /*dwFileOffsetHigh=*/0,
 435                                          /*dwFileOffsetLow=*/0,
 436                                          /*dwNumberOfBytesToMap=*/0);
 437        if (mmap_base) {
 438          *result = new WindowsMmapReadableFile(
 439              filename, reinterpret_cast<char*>(mmap_base),
 440              static_cast<size_t>(file_size.QuadPart), &mmap_limiter_);
 441          return Status::OK();
 442        }
 443      }
 444      mmap_limiter_.Release();
 445      return WindowsError(filename, ::GetLastError());
 446    }
 447  
 448    Status NewWritableFile(const std::string& filename,
 449                           WritableFile** result) override {
 450      DWORD desired_access = GENERIC_WRITE;
 451      DWORD share_mode = 0;  // Exclusive access.
 452      auto wFilename = toUtf16(filename);
 453      ScopedHandle handle = ::CreateFileW(
 454          wFilename.c_str(), desired_access, share_mode,
 455          /*lpSecurityAttributes=*/nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
 456          /*hTemplateFile=*/nullptr);
 457      if (!handle.is_valid()) {
 458        *result = nullptr;
 459        return WindowsError(filename, ::GetLastError());
 460      }
 461  
 462      *result = new WindowsWritableFile(filename, std::move(handle));
 463      return Status::OK();
 464    }
 465  
 466    Status NewAppendableFile(const std::string& filename,
 467                             WritableFile** result) override {
 468      DWORD desired_access = FILE_APPEND_DATA;
 469      DWORD share_mode = 0;  // Exclusive access.
 470      auto wFilename = toUtf16(filename);
 471      ScopedHandle handle = ::CreateFileW(
 472          wFilename.c_str(), desired_access, share_mode,
 473          /*lpSecurityAttributes=*/nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
 474          /*hTemplateFile=*/nullptr);
 475      if (!handle.is_valid()) {
 476        *result = nullptr;
 477        return WindowsError(filename, ::GetLastError());
 478      }
 479  
 480      *result = new WindowsWritableFile(filename, std::move(handle));
 481      return Status::OK();
 482    }
 483  
 484    bool FileExists(const std::string& filename) override {
 485      auto wFilename = toUtf16(filename);
 486      return GetFileAttributesW(wFilename.c_str()) != INVALID_FILE_ATTRIBUTES;
 487    }
 488  
 489    Status GetChildren(const std::string& directory_path,
 490                       std::vector<std::string>* result) override {
 491      const std::string find_pattern = directory_path + "\\*";
 492      WIN32_FIND_DATAW find_data;
 493      auto wFind_pattern = toUtf16(find_pattern);
 494      HANDLE dir_handle = ::FindFirstFileW(wFind_pattern.c_str(), &find_data);
 495      if (dir_handle == INVALID_HANDLE_VALUE) {
 496        DWORD last_error = ::GetLastError();
 497        if (last_error == ERROR_FILE_NOT_FOUND) {
 498          return Status::OK();
 499        }
 500        return WindowsError(directory_path, last_error);
 501      }
 502      do {
 503        char base_name[_MAX_FNAME];
 504        char ext[_MAX_EXT];
 505  
 506        auto find_data_filename = toUtf8(find_data.cFileName);
 507        if (!_splitpath_s(find_data_filename.c_str(), nullptr, 0, nullptr, 0,
 508                          base_name, ARRAYSIZE(base_name), ext, ARRAYSIZE(ext))) {
 509          result->emplace_back(std::string(base_name) + ext);
 510        }
 511      } while (::FindNextFileW(dir_handle, &find_data));
 512      DWORD last_error = ::GetLastError();
 513      ::FindClose(dir_handle);
 514      if (last_error != ERROR_NO_MORE_FILES) {
 515        return WindowsError(directory_path, last_error);
 516      }
 517      return Status::OK();
 518    }
 519  
 520    Status DeleteFile(const std::string& filename) override {
 521      auto wFilename = toUtf16(filename);
 522      if (!::DeleteFileW(wFilename.c_str())) {
 523        return WindowsError(filename, ::GetLastError());
 524      }
 525      return Status::OK();
 526    }
 527  
 528    Status CreateDir(const std::string& dirname) override {
 529      auto wDirname = toUtf16(dirname);
 530      if (!::CreateDirectoryW(wDirname.c_str(), nullptr)) {
 531        return WindowsError(dirname, ::GetLastError());
 532      }
 533      return Status::OK();
 534    }
 535  
 536    Status DeleteDir(const std::string& dirname) override {
 537      auto wDirname = toUtf16(dirname);
 538      if (!::RemoveDirectoryW(wDirname.c_str())) {
 539        return WindowsError(dirname, ::GetLastError());
 540      }
 541      return Status::OK();
 542    }
 543  
 544    Status GetFileSize(const std::string& filename, uint64_t* size) override {
 545      WIN32_FILE_ATTRIBUTE_DATA file_attributes;
 546      auto wFilename = toUtf16(filename);
 547      if (!::GetFileAttributesExW(wFilename.c_str(), GetFileExInfoStandard,
 548                                  &file_attributes)) {
 549        return WindowsError(filename, ::GetLastError());
 550      }
 551      ULARGE_INTEGER file_size;
 552      file_size.HighPart = file_attributes.nFileSizeHigh;
 553      file_size.LowPart = file_attributes.nFileSizeLow;
 554      *size = file_size.QuadPart;
 555      return Status::OK();
 556    }
 557  
 558    Status RenameFile(const std::string& from, const std::string& to) override {
 559      // Try a simple move first. It will only succeed when |to| doesn't already
 560      // exist.
 561      auto wFrom = toUtf16(from);
 562      auto wTo = toUtf16(to);
 563      if (::MoveFileW(wFrom.c_str(), wTo.c_str())) {
 564        return Status::OK();
 565      }
 566      DWORD move_error = ::GetLastError();
 567  
 568      // Try the full-blown replace if the move fails, as ReplaceFile will only
 569      // succeed when |to| does exist. When writing to a network share, we may not
 570      // be able to change the ACLs. Ignore ACL errors then
 571      // (REPLACEFILE_IGNORE_MERGE_ERRORS).
 572      if (::ReplaceFileW(wTo.c_str(), wFrom.c_str(), /*lpBackupFileName=*/nullptr,
 573                         REPLACEFILE_IGNORE_MERGE_ERRORS,
 574                         /*lpExclude=*/nullptr, /*lpReserved=*/nullptr)) {
 575        return Status::OK();
 576      }
 577      DWORD replace_error = ::GetLastError();
 578      // In the case of FILE_ERROR_NOT_FOUND from ReplaceFile, it is likely that
 579      // |to| does not exist. In this case, the more relevant error comes from the
 580      // call to MoveFile.
 581      if (replace_error == ERROR_FILE_NOT_FOUND ||
 582          replace_error == ERROR_PATH_NOT_FOUND) {
 583        return WindowsError(from, move_error);
 584      } else {
 585        return WindowsError(from, replace_error);
 586      }
 587    }
 588  
 589    Status LockFile(const std::string& filename, FileLock** lock) override {
 590      *lock = nullptr;
 591      Status result;
 592      auto wFilename = toUtf16(filename);
 593      ScopedHandle handle = ::CreateFileW(
 594          wFilename.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
 595          /*lpSecurityAttributes=*/nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
 596          nullptr);
 597      if (!handle.is_valid()) {
 598        result = WindowsError(filename, ::GetLastError());
 599      } else if (!LockOrUnlock(handle.get(), true)) {
 600        result = WindowsError("lock " + filename, ::GetLastError());
 601      } else {
 602        *lock = new WindowsFileLock(std::move(handle), filename);
 603      }
 604      return result;
 605    }
 606  
 607    Status UnlockFile(FileLock* lock) override {
 608      WindowsFileLock* windows_file_lock =
 609          reinterpret_cast<WindowsFileLock*>(lock);
 610      if (!LockOrUnlock(windows_file_lock->handle().get(), false)) {
 611        return WindowsError("unlock " + windows_file_lock->filename(),
 612                            ::GetLastError());
 613      }
 614      delete windows_file_lock;
 615      return Status::OK();
 616    }
 617  
 618    void Schedule(void (*background_work_function)(void* background_work_arg),
 619                  void* background_work_arg) override;
 620  
 621    void StartThread(void (*thread_main)(void* thread_main_arg),
 622                     void* thread_main_arg) override {
 623      std::thread new_thread(thread_main, thread_main_arg);
 624      new_thread.detach();
 625    }
 626  
 627    Status GetTestDirectory(std::string* result) override {
 628      const char* env = getenv("TEST_TMPDIR");
 629      if (env && env[0] != '\0') {
 630        *result = env;
 631        return Status::OK();
 632      }
 633  
 634      wchar_t wtmp_path[MAX_PATH];
 635      if (!GetTempPathW(ARRAYSIZE(wtmp_path), wtmp_path)) {
 636        return WindowsError("GetTempPath", ::GetLastError());
 637      }
 638      std::string tmp_path = toUtf8(std::wstring(wtmp_path));
 639      std::stringstream ss;
 640      ss << tmp_path << "leveldbtest-" << std::this_thread::get_id();
 641      *result = ss.str();
 642  
 643      // Directory may already exist
 644      CreateDir(*result);
 645      return Status::OK();
 646    }
 647  
 648    Status NewLogger(const std::string& filename, Logger** result) override {
 649      auto wFilename = toUtf16(filename);
 650      std::FILE* fp = _wfopen(wFilename.c_str(), L"w");
 651      if (fp == nullptr) {
 652        *result = nullptr;
 653        return WindowsError(filename, ::GetLastError());
 654      } else {
 655        *result = new WindowsLogger(fp);
 656        return Status::OK();
 657      }
 658    }
 659  
 660    uint64_t NowMicros() override {
 661      // GetSystemTimeAsFileTime typically has a resolution of 10-20 msec.
 662      // TODO(cmumford): Switch to GetSystemTimePreciseAsFileTime which is
 663      // available in Windows 8 and later.
 664      FILETIME ft;
 665      ::GetSystemTimeAsFileTime(&ft);
 666      // Each tick represents a 100-nanosecond intervals since January 1, 1601
 667      // (UTC).
 668      uint64_t num_ticks =
 669          (static_cast<uint64_t>(ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
 670      return num_ticks / 10;
 671    }
 672  
 673    void SleepForMicroseconds(int micros) override {
 674      std::this_thread::sleep_for(std::chrono::microseconds(micros));
 675    }
 676  
 677   private:
 678    void BackgroundThreadMain();
 679  
 680    static void BackgroundThreadEntryPoint(WindowsEnv* env) {
 681      env->BackgroundThreadMain();
 682    }
 683  
 684    // Stores the work item data in a Schedule() call.
 685    //
 686    // Instances are constructed on the thread calling Schedule() and used on the
 687    // background thread.
 688    //
 689    // This structure is thread-safe because it is immutable.
 690    struct BackgroundWorkItem {
 691      explicit BackgroundWorkItem(void (*function)(void* arg), void* arg)
 692          : function(function), arg(arg) {}
 693  
 694      void (*const function)(void*);
 695      void* const arg;
 696    };
 697  
 698    port::Mutex background_work_mutex_;
 699    port::CondVar background_work_cv_ GUARDED_BY(background_work_mutex_);
 700    bool started_background_thread_ GUARDED_BY(background_work_mutex_);
 701  
 702    std::queue<BackgroundWorkItem> background_work_queue_
 703        GUARDED_BY(background_work_mutex_);
 704  
 705    Limiter mmap_limiter_;  // Thread-safe.
 706  
 707    // Converts a Windows wide multi-byte UTF-16 string to a UTF-8 string.
 708    // See http://utf8everywhere.org/#windows
 709    std::string toUtf8(const std::wstring& wstr) {
 710      if (wstr.empty()) return std::string();
 711      int size_needed = WideCharToMultiByte(
 712          CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
 713      std::string strTo(size_needed, 0);
 714      WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0],
 715                          size_needed, NULL, NULL);
 716      return strTo;
 717    }
 718  
 719    // Converts a UTF-8 string to a Windows UTF-16 multi-byte wide character
 720    // string.
 721    // See http://utf8everywhere.org/#windows
 722    std::wstring toUtf16(const std::string& str) {
 723      if (str.empty()) return std::wstring();
 724      int size_needed =
 725          MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
 726      std::wstring strTo(size_needed, 0);
 727      MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &strTo[0],
 728                          size_needed);
 729      return strTo;
 730    }
 731  };
 732  
 733  // Return the maximum number of concurrent mmaps.
 734  int MaxMmaps() { return g_mmap_limit; }
 735  
 736  WindowsEnv::WindowsEnv()
 737      : background_work_cv_(&background_work_mutex_),
 738        started_background_thread_(false),
 739        mmap_limiter_(MaxMmaps()) {}
 740  
 741  void WindowsEnv::Schedule(
 742      void (*background_work_function)(void* background_work_arg),
 743      void* background_work_arg) {
 744    background_work_mutex_.Lock();
 745  
 746    // Start the background thread, if we haven't done so already.
 747    if (!started_background_thread_) {
 748      started_background_thread_ = true;
 749      std::thread background_thread(WindowsEnv::BackgroundThreadEntryPoint, this);
 750      background_thread.detach();
 751    }
 752  
 753    // If the queue is empty, the background thread may be waiting for work.
 754    if (background_work_queue_.empty()) {
 755      background_work_cv_.Signal();
 756    }
 757  
 758    background_work_queue_.emplace(background_work_function, background_work_arg);
 759    background_work_mutex_.Unlock();
 760  }
 761  
 762  void WindowsEnv::BackgroundThreadMain() {
 763    while (true) {
 764      background_work_mutex_.Lock();
 765  
 766      // Wait until there is work to be done.
 767      while (background_work_queue_.empty()) {
 768        background_work_cv_.Wait();
 769      }
 770  
 771      assert(!background_work_queue_.empty());
 772      auto background_work_function = background_work_queue_.front().function;
 773      void* background_work_arg = background_work_queue_.front().arg;
 774      background_work_queue_.pop();
 775  
 776      background_work_mutex_.Unlock();
 777      background_work_function(background_work_arg);
 778    }
 779  }
 780  
 781  // Wraps an Env instance whose destructor is never created.
 782  //
 783  // Intended usage:
 784  //   using PlatformSingletonEnv = SingletonEnv<PlatformEnv>;
 785  //   void ConfigurePosixEnv(int param) {
 786  //     PlatformSingletonEnv::AssertEnvNotInitialized();
 787  //     // set global configuration flags.
 788  //   }
 789  //   Env* Env::Default() {
 790  //     static PlatformSingletonEnv default_env;
 791  //     return default_env.env();
 792  //   }
 793  template <typename EnvType>
 794  class SingletonEnv {
 795   public:
 796    SingletonEnv() {
 797  #if !defined(NDEBUG)
 798      env_initialized_.store(true, std::memory_order_relaxed);
 799  #endif  // !defined(NDEBUG)
 800      static_assert(sizeof(env_storage_) >= sizeof(EnvType),
 801                    "env_storage_ will not fit the Env");
 802      static_assert(std::is_standard_layout_v<SingletonEnv<EnvType>>);
 803      static_assert(
 804          offsetof(SingletonEnv<EnvType>, env_storage_) % alignof(EnvType) == 0,
 805          "env_storage_ does not meet the Env's alignment needs");
 806      static_assert(alignof(SingletonEnv<EnvType>) % alignof(EnvType) == 0,
 807                    "env_storage_ does not meet the Env's alignment needs");
 808      new (env_storage_) EnvType();
 809    }
 810    ~SingletonEnv() = default;
 811  
 812    SingletonEnv(const SingletonEnv&) = delete;
 813    SingletonEnv& operator=(const SingletonEnv&) = delete;
 814  
 815    Env* env() { return reinterpret_cast<Env*>(&env_storage_); }
 816  
 817    static void AssertEnvNotInitialized() {
 818  #if !defined(NDEBUG)
 819      assert(!env_initialized_.load(std::memory_order_relaxed));
 820  #endif  // !defined(NDEBUG)
 821    }
 822  
 823   private:
 824    alignas(EnvType) char env_storage_[sizeof(EnvType)];
 825  #if !defined(NDEBUG)
 826    static std::atomic<bool> env_initialized_;
 827  #endif  // !defined(NDEBUG)
 828  };
 829  
 830  #if !defined(NDEBUG)
 831  template <typename EnvType>
 832  std::atomic<bool> SingletonEnv<EnvType>::env_initialized_;
 833  #endif  // !defined(NDEBUG)
 834  
 835  using WindowsDefaultEnv = SingletonEnv<WindowsEnv>;
 836  
 837  }  // namespace
 838  
 839  void EnvWindowsTestHelper::SetReadOnlyMMapLimit(int limit) {
 840    WindowsDefaultEnv::AssertEnvNotInitialized();
 841    g_mmap_limit = limit;
 842  }
 843  
 844  Env* Env::Default() {
 845    static WindowsDefaultEnv env_container;
 846    return env_container.env();
 847  }
 848  
 849  }  // namespace leveldb
 850