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