git / moonbite-core / src/leveldb/util/env_windows.cc · raw

// Copyright (c) 2018 The LevelDB Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file. See the AUTHORS file for names of contributors.// Prevent Windows headers from defining min/max macros and instead// use STL.#ifndef NOMINMAX#define NOMINMAX#endif  // ifndef NOMINMAX#include <windows.h>#include <algorithm>#include <atomic>#include <chrono>#include <condition_variable>#include <cstddef>#include <cstdint>#include <cstdlib>#include <cstring>#include <memory>#include <mutex>#include <queue>#include <sstream>#include <string>#include <vector>#include "leveldb/env.h"#include "leveldb/slice.h"#include "port/port.h"#include "port/thread_annotations.h"#include "util/env_windows_test_helper.h"#include "util/logging.h"#include "util/mutexlock.h"#include "util/windows_logger.h"#if defined(DeleteFile)#undef DeleteFile#endif  // defined(DeleteFile)namespace leveldb {namespace {constexpr const size_t kWritableFileBufferSize = 65536;// Up to 1000 mmaps for 64-bit binaries; none for 32-bit.constexpr int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 1000 : 0;// Can be set by by EnvWindowsTestHelper::SetReadOnlyMMapLimit().int g_mmap_limit = kDefaultMmapLimit;std::string GetWindowsErrorMessage(DWORD error_code) {  std::string message;  char* error_text = nullptr;  // Use MBCS version of FormatMessage to match return value.  size_t error_text_size = ::FormatMessageA(      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |          FORMAT_MESSAGE_IGNORE_INSERTS,      nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),      reinterpret_cast<char*>(&error_text), 0, nullptr);  if (!error_text) {    return message;  }  message.assign(error_text, error_text_size);  ::LocalFree(error_text);  return message;}Status WindowsError(const std::string& context, DWORD error_code) {  if (error_code == ERROR_FILE_NOT_FOUND || error_code == ERROR_PATH_NOT_FOUND)    return Status::NotFound(context, GetWindowsErrorMessage(error_code));  return Status::IOError(context, GetWindowsErrorMessage(error_code));}class ScopedHandle { public:  ScopedHandle(HANDLE handle) : handle_(handle) {}  ScopedHandle(const ScopedHandle&) = delete;  ScopedHandle(ScopedHandle&& other) noexcept : handle_(other.Release()) {}  ~ScopedHandle() { Close(); }  ScopedHandle& operator=(const ScopedHandle&) = delete;  ScopedHandle& operator=(ScopedHandle&& rhs) noexcept {    if (this != &rhs) handle_ = rhs.Release();    return *this;  }  bool Close() {    if (!is_valid()) {      return true;    }    HANDLE h = handle_;    handle_ = INVALID_HANDLE_VALUE;    return ::CloseHandle(h);  }  bool is_valid() const {    return handle_ != INVALID_HANDLE_VALUE && handle_ != nullptr;  }  HANDLE get() const { return handle_; }  HANDLE Release() {    HANDLE h = handle_;    handle_ = INVALID_HANDLE_VALUE;    return h;  } private:  HANDLE handle_;};// Helper class to limit resource usage to avoid exhaustion.// Currently used to limit read-only file descriptors and mmap file usage// so that we do not run out of file descriptors or virtual memory, or run into// kernel performance problems for very large databases.class Limiter { public:  // Limit maximum number of resources to |max_acquires|.  Limiter(int max_acquires) : acquires_allowed_(max_acquires) {}  Limiter(const Limiter&) = delete;  Limiter operator=(const Limiter&) = delete;  // If another resource is available, acquire it and return true.  // Else return false.  bool Acquire() {    int old_acquires_allowed =        acquires_allowed_.fetch_sub(1, std::memory_order_relaxed);    if (old_acquires_allowed > 0) return true;    acquires_allowed_.fetch_add(1, std::memory_order_relaxed);    return false;  }  // Release a resource acquired by a previous call to Acquire() that returned  // true.  void Release() { acquires_allowed_.fetch_add(1, std::memory_order_relaxed); } private:  // The number of available resources.  //  // This is a counter and is not tied to the invariants of any other class, so  // it can be operated on safely using std::memory_order_relaxed.  std::atomic<int> acquires_allowed_;};class WindowsSequentialFile : public SequentialFile { public:  WindowsSequentialFile(std::string filename, ScopedHandle handle)      : handle_(std::move(handle)), filename_(std::move(filename)) {}  ~WindowsSequentialFile() override {}  Status Read(size_t n, Slice* result, char* scratch) override {    DWORD bytes_read;    // DWORD is 32-bit, but size_t could technically be larger. However leveldb    // files are limited to leveldb::Options::max_file_size which is clamped to    // 1<<30 or 1 GiB.    assert(n <= std::numeric_limits<DWORD>::max());    if (!::ReadFile(handle_.get(), scratch, static_cast<DWORD>(n), &bytes_read,                    nullptr)) {      return WindowsError(filename_, ::GetLastError());    }    *result = Slice(scratch, bytes_read);    return Status::OK();  }  Status Skip(uint64_t n) override {    LARGE_INTEGER distance;    distance.QuadPart = n;    if (!::SetFilePointerEx(handle_.get(), distance, nullptr, FILE_CURRENT)) {      return WindowsError(filename_, ::GetLastError());    }    return Status::OK();  }  std::string GetName() const override { return filename_; } private:  const ScopedHandle handle_;  const std::string filename_;};class WindowsRandomAccessFile : public RandomAccessFile { public:  WindowsRandomAccessFile(std::string filename, ScopedHandle handle)      : handle_(std::move(handle)), filename_(std::move(filename)) {}  ~WindowsRandomAccessFile() override = default;  Status Read(uint64_t offset, size_t n, Slice* result,              char* scratch) const override {    DWORD bytes_read = 0;    OVERLAPPED overlapped = {0};    overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);    overlapped.Offset = static_cast<DWORD>(offset);    if (!::ReadFile(handle_.get(), scratch, static_cast<DWORD>(n), &bytes_read,                    &overlapped)) {      DWORD error_code = ::GetLastError();      if (error_code != ERROR_HANDLE_EOF) {        *result = Slice(scratch, 0);        return Status::IOError(filename_, GetWindowsErrorMessage(error_code));      }    }    *result = Slice(scratch, bytes_read);    return Status::OK();  }  std::string GetName() const override { return filename_; } private:  const ScopedHandle handle_;  const std::string filename_;};class WindowsMmapReadableFile : public RandomAccessFile { public:  // base[0,length-1] contains the mmapped contents of the file.  WindowsMmapReadableFile(std::string filename, char* mmap_base, size_t length,                          Limiter* mmap_limiter)      : mmap_base_(mmap_base),        length_(length),        mmap_limiter_(mmap_limiter),        filename_(std::move(filename)) {}  ~WindowsMmapReadableFile() override {    ::UnmapViewOfFile(mmap_base_);    mmap_limiter_->Release();  }  Status Read(uint64_t offset, size_t n, Slice* result,              char* scratch) const override {    if (offset + n > length_) {      *result = Slice();      return WindowsError(filename_, ERROR_INVALID_PARAMETER);    }    *result = Slice(mmap_base_ + offset, n);    return Status::OK();  }  std::string GetName() const override { return filename_; } private:  char* const mmap_base_;  const size_t length_;  Limiter* const mmap_limiter_;  const std::string filename_;};class WindowsWritableFile : public WritableFile { public:  WindowsWritableFile(std::string filename, ScopedHandle handle)      : pos_(0), handle_(std::move(handle)), filename_(std::move(filename)) {}  ~WindowsWritableFile() override = default;  Status Append(const Slice& data) override {    size_t write_size = data.size();    const char* write_data = data.data();    // Fit as much as possible into buffer.    size_t copy_size = std::min(write_size, kWritableFileBufferSize - pos_);    std::memcpy(buf_ + pos_, write_data, copy_size);    write_data += copy_size;    write_size -= copy_size;    pos_ += copy_size;    if (write_size == 0) {      return Status::OK();    }    // Can't fit in buffer, so need to do at least one write.    Status status = FlushBuffer();    if (!status.ok()) {      return status;    }    // Small writes go to buffer, large writes are written directly.    if (write_size < kWritableFileBufferSize) {      std::memcpy(buf_, write_data, write_size);      pos_ = write_size;      return Status::OK();    }    return WriteUnbuffered(write_data, write_size);  }  Status Close() override {    Status status = FlushBuffer();    if (!handle_.Close() && status.ok()) {      status = WindowsError(filename_, ::GetLastError());    }    return status;  }  Status Flush() override { return FlushBuffer(); }  Status Sync() override {    // On Windows no need to sync parent directory. Its metadata will be updated    // via the creation of the new file, without an explicit sync.    Status status = FlushBuffer();    if (!status.ok()) {      return status;    }    if (!::FlushFileBuffers(handle_.get())) {      return Status::IOError(filename_,                             GetWindowsErrorMessage(::GetLastError()));    }    return Status::OK();  }  std::string GetName() const override { return filename_; } private:  Status FlushBuffer() {    Status status = WriteUnbuffered(buf_, pos_);    pos_ = 0;    return status;  }  Status WriteUnbuffered(const char* data, size_t size) {    DWORD bytes_written;    if (!::WriteFile(handle_.get(), data, static_cast<DWORD>(size),                     &bytes_written, nullptr)) {      return Status::IOError(filename_,                             GetWindowsErrorMessage(::GetLastError()));    }    return Status::OK();  }  // buf_[0, pos_-1] contains data to be written to handle_.  char buf_[kWritableFileBufferSize];  size_t pos_;  ScopedHandle handle_;  const std::string filename_;};// Lock or unlock the entire file as specified by |lock|. Returns true// when successful, false upon failure. Caller should call ::GetLastError()// to determine cause of failurebool LockOrUnlock(HANDLE handle, bool lock) {  if (lock) {    return ::LockFile(handle,                      /*dwFileOffsetLow=*/0, /*dwFileOffsetHigh=*/0,                      /*nNumberOfBytesToLockLow=*/MAXDWORD,                      /*nNumberOfBytesToLockHigh=*/MAXDWORD);  } else {    return ::UnlockFile(handle,                        /*dwFileOffsetLow=*/0, /*dwFileOffsetHigh=*/0,                        /*nNumberOfBytesToLockLow=*/MAXDWORD,                        /*nNumberOfBytesToLockHigh=*/MAXDWORD);  }}class WindowsFileLock : public FileLock { public:  WindowsFileLock(ScopedHandle handle, std::string filename)      : handle_(std::move(handle)), filename_(std::move(filename)) {}  const ScopedHandle& handle() const { return handle_; }  const std::string& filename() const { return filename_; } private:  const ScopedHandle handle_;  const std::string filename_;};class WindowsEnv : public Env { public:  WindowsEnv();  ~WindowsEnv() override {    static const char msg[] =        "WindowsEnv singleton destroyed. Unsupported behavior!\n";    std::fwrite(msg, 1, sizeof(msg), stderr);    std::abort();  }  Status NewSequentialFile(const std::string& filename,                           SequentialFile** result) override {    *result = nullptr;    DWORD desired_access = GENERIC_READ;    DWORD share_mode = FILE_SHARE_READ;    auto wFilename = toUtf16(filename);    ScopedHandle handle = ::CreateFileW(        wFilename.c_str(), desired_access, share_mode,        /*lpSecurityAttributes=*/nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,        /*hTemplateFile=*/nullptr);    if (!handle.is_valid()) {      return WindowsError(filename, ::GetLastError());    }    *result = new WindowsSequentialFile(filename, std::move(handle));    return Status::OK();  }  Status NewRandomAccessFile(const std::string& filename,                             RandomAccessFile** result) override {    *result = nullptr;    DWORD desired_access = GENERIC_READ;    DWORD share_mode = FILE_SHARE_READ;    auto wFilename = toUtf16(filename);    ScopedHandle handle =        ::CreateFileW(wFilename.c_str(), desired_access, share_mode,                      /*lpSecurityAttributes=*/nullptr, OPEN_EXISTING,                      FILE_ATTRIBUTE_READONLY,                      /*hTemplateFile=*/nullptr);    if (!handle.is_valid()) {      return WindowsError(filename, ::GetLastError());    }    if (!mmap_limiter_.Acquire()) {      *result = new WindowsRandomAccessFile(filename, std::move(handle));      return Status::OK();    }    LARGE_INTEGER file_size;    Status status;    if (!::GetFileSizeEx(handle.get(), &file_size)) {      mmap_limiter_.Release();      return WindowsError(filename, ::GetLastError());    }    ScopedHandle mapping =        ::CreateFileMappingW(handle.get(),                             /*security attributes=*/nullptr, PAGE_READONLY,                             /*dwMaximumSizeHigh=*/0,                             /*dwMaximumSizeLow=*/0,                             /*lpName=*/nullptr);    if (mapping.is_valid()) {      void* mmap_base = ::MapViewOfFile(mapping.get(), FILE_MAP_READ,                                        /*dwFileOffsetHigh=*/0,                                        /*dwFileOffsetLow=*/0,                                        /*dwNumberOfBytesToMap=*/0);      if (mmap_base) {        *result = new WindowsMmapReadableFile(            filename, reinterpret_cast<char*>(mmap_base),            static_cast<size_t>(file_size.QuadPart), &mmap_limiter_);        return Status::OK();      }    }    mmap_limiter_.Release();    return WindowsError(filename, ::GetLastError());  }  Status NewWritableFile(const std::string& filename,                         WritableFile** result) override {    DWORD desired_access = GENERIC_WRITE;    DWORD share_mode = 0;  // Exclusive access.    auto wFilename = toUtf16(filename);    ScopedHandle handle = ::CreateFileW(        wFilename.c_str(), desired_access, share_mode,        /*lpSecurityAttributes=*/nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,        /*hTemplateFile=*/nullptr);    if (!handle.is_valid()) {      *result = nullptr;      return WindowsError(filename, ::GetLastError());    }    *result = new WindowsWritableFile(filename, std::move(handle));    return Status::OK();  }  Status NewAppendableFile(const std::string& filename,                           WritableFile** result) override {    DWORD desired_access = FILE_APPEND_DATA;    DWORD share_mode = 0;  // Exclusive access.    auto wFilename = toUtf16(filename);    ScopedHandle handle = ::CreateFileW(        wFilename.c_str(), desired_access, share_mode,        /*lpSecurityAttributes=*/nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,        /*hTemplateFile=*/nullptr);    if (!handle.is_valid()) {      *result = nullptr;      return WindowsError(filename, ::GetLastError());    }    *result = new WindowsWritableFile(filename, std::move(handle));    return Status::OK();  }  bool FileExists(const std::string& filename) override {    auto wFilename = toUtf16(filename);    return GetFileAttributesW(wFilename.c_str()) != INVALID_FILE_ATTRIBUTES;  }  Status GetChildren(const std::string& directory_path,                     std::vector<std::string>* result) override {    const std::string find_pattern = directory_path + "\\*";    WIN32_FIND_DATAW find_data;    auto wFind_pattern = toUtf16(find_pattern);    HANDLE dir_handle = ::FindFirstFileW(wFind_pattern.c_str(), &find_data);    if (dir_handle == INVALID_HANDLE_VALUE) {      DWORD last_error = ::GetLastError();      if (last_error == ERROR_FILE_NOT_FOUND) {        return Status::OK();      }      return WindowsError(directory_path, last_error);    }    do {      char base_name[_MAX_FNAME];      char ext[_MAX_EXT];      auto find_data_filename = toUtf8(find_data.cFileName);      if (!_splitpath_s(find_data_filename.c_str(), nullptr, 0, nullptr, 0,                        base_name, ARRAYSIZE(base_name), ext, ARRAYSIZE(ext))) {        result->emplace_back(std::string(base_name) + ext);      }    } while (::FindNextFileW(dir_handle, &find_data));    DWORD last_error = ::GetLastError();    ::FindClose(dir_handle);    if (last_error != ERROR_NO_MORE_FILES) {      return WindowsError(directory_path, last_error);    }    return Status::OK();  }  Status DeleteFile(const std::string& filename) override {    auto wFilename = toUtf16(filename);    if (!::DeleteFileW(wFilename.c_str())) {      return WindowsError(filename, ::GetLastError());    }    return Status::OK();  }  Status CreateDir(const std::string& dirname) override {    auto wDirname = toUtf16(dirname);    if (!::CreateDirectoryW(wDirname.c_str(), nullptr)) {      return WindowsError(dirname, ::GetLastError());    }    return Status::OK();  }  Status DeleteDir(const std::string& dirname) override {    auto wDirname = toUtf16(dirname);    if (!::RemoveDirectoryW(wDirname.c_str())) {      return WindowsError(dirname, ::GetLastError());    }    return Status::OK();  }  Status GetFileSize(const std::string& filename, uint64_t* size) override {    WIN32_FILE_ATTRIBUTE_DATA file_attributes;    auto wFilename = toUtf16(filename);    if (!::GetFileAttributesExW(wFilename.c_str(), GetFileExInfoStandard,                                &file_attributes)) {      return WindowsError(filename, ::GetLastError());    }    ULARGE_INTEGER file_size;    file_size.HighPart = file_attributes.nFileSizeHigh;    file_size.LowPart = file_attributes.nFileSizeLow;    *size = file_size.QuadPart;    return Status::OK();  }  Status RenameFile(const std::string& from, const std::string& to) override {    // Try a simple move first. It will only succeed when |to| doesn't already    // exist.    auto wFrom = toUtf16(from);    auto wTo = toUtf16(to);    if (::MoveFileW(wFrom.c_str(), wTo.c_str())) {      return Status::OK();    }    DWORD move_error = ::GetLastError();    // Try the full-blown replace if the move fails, as ReplaceFile will only    // succeed when |to| does exist. When writing to a network share, we may not    // be able to change the ACLs. Ignore ACL errors then    // (REPLACEFILE_IGNORE_MERGE_ERRORS).    if (::ReplaceFileW(wTo.c_str(), wFrom.c_str(), /*lpBackupFileName=*/nullptr,                       REPLACEFILE_IGNORE_MERGE_ERRORS,                       /*lpExclude=*/nullptr, /*lpReserved=*/nullptr)) {      return Status::OK();    }    DWORD replace_error = ::GetLastError();    // In the case of FILE_ERROR_NOT_FOUND from ReplaceFile, it is likely that    // |to| does not exist. In this case, the more relevant error comes from the    // call to MoveFile.    if (replace_error == ERROR_FILE_NOT_FOUND ||        replace_error == ERROR_PATH_NOT_FOUND) {      return WindowsError(from, move_error);    } else {      return WindowsError(from, replace_error);    }  }  Status LockFile(const std::string& filename, FileLock** lock) override {    *lock = nullptr;    Status result;    auto wFilename = toUtf16(filename);    ScopedHandle handle = ::CreateFileW(        wFilename.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,        /*lpSecurityAttributes=*/nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,        nullptr);    if (!handle.is_valid()) {      result = WindowsError(filename, ::GetLastError());    } else if (!LockOrUnlock(handle.get(), true)) {      result = WindowsError("lock " + filename, ::GetLastError());    } else {      *lock = new WindowsFileLock(std::move(handle), filename);    }    return result;  }  Status UnlockFile(FileLock* lock) override {    WindowsFileLock* windows_file_lock =        reinterpret_cast<WindowsFileLock*>(lock);    if (!LockOrUnlock(windows_file_lock->handle().get(), false)) {      return WindowsError("unlock " + windows_file_lock->filename(),                          ::GetLastError());    }    delete windows_file_lock;    return Status::OK();  }  void Schedule(void (*background_work_function)(void* background_work_arg),                void* background_work_arg) override;  void StartThread(void (*thread_main)(void* thread_main_arg),                   void* thread_main_arg) override {    std::thread new_thread(thread_main, thread_main_arg);    new_thread.detach();  }  Status GetTestDirectory(std::string* result) override {    const char* env = getenv("TEST_TMPDIR");    if (env && env[0] != '\0') {      *result = env;      return Status::OK();    }    wchar_t wtmp_path[MAX_PATH];    if (!GetTempPathW(ARRAYSIZE(wtmp_path), wtmp_path)) {      return WindowsError("GetTempPath", ::GetLastError());    }    std::string tmp_path = toUtf8(std::wstring(wtmp_path));    std::stringstream ss;    ss << tmp_path << "leveldbtest-" << std::this_thread::get_id();    *result = ss.str();    // Directory may already exist    CreateDir(*result);    return Status::OK();  }  Status NewLogger(const std::string& filename, Logger** result) override {    auto wFilename = toUtf16(filename);    std::FILE* fp = _wfopen(wFilename.c_str(), L"w");    if (fp == nullptr) {      *result = nullptr;      return WindowsError(filename, ::GetLastError());    } else {      *result = new WindowsLogger(fp);      return Status::OK();    }  }  uint64_t NowMicros() override {    // GetSystemTimeAsFileTime typically has a resolution of 10-20 msec.    // TODO(cmumford): Switch to GetSystemTimePreciseAsFileTime which is    // available in Windows 8 and later.    FILETIME ft;    ::GetSystemTimeAsFileTime(&ft);    // Each tick represents a 100-nanosecond intervals since January 1, 1601    // (UTC).    uint64_t num_ticks =        (static_cast<uint64_t>(ft.dwHighDateTime) << 32) + ft.dwLowDateTime;    return num_ticks / 10;  }  void SleepForMicroseconds(int micros) override {    std::this_thread::sleep_for(std::chrono::microseconds(micros));  } private:  void BackgroundThreadMain();  static void BackgroundThreadEntryPoint(WindowsEnv* env) {    env->BackgroundThreadMain();  }  // Stores the work item data in a Schedule() call.  //  // Instances are constructed on the thread calling Schedule() and used on the  // background thread.  //  // This structure is thread-safe beacuse it is immutable.  struct BackgroundWorkItem {    explicit BackgroundWorkItem(void (*function)(void* arg), void* arg)        : function(function), arg(arg) {}    void (*const function)(void*);    void* const arg;  };  port::Mutex background_work_mutex_;  port::CondVar background_work_cv_ GUARDED_BY(background_work_mutex_);  bool started_background_thread_ GUARDED_BY(background_work_mutex_);  std::queue<BackgroundWorkItem> background_work_queue_      GUARDED_BY(background_work_mutex_);  Limiter mmap_limiter_;  // Thread-safe.  // Converts a Windows wide multi-byte UTF-16 string to a UTF-8 string.  // See http://utf8everywhere.org/#windows  std::string toUtf8(const std::wstring& wstr) {    if (wstr.empty()) return std::string();    int size_needed = WideCharToMultiByte(        CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);    std::string strTo(size_needed, 0);    WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0],                        size_needed, NULL, NULL);    return strTo;  }  // Converts a UTF-8 string to a Windows UTF-16 multi-byte wide character  // string.  // See http://utf8everywhere.org/#windows  std::wstring toUtf16(const std::string& str) {    if (str.empty()) return std::wstring();    int size_needed =        MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);    std::wstring strTo(size_needed, 0);    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &strTo[0],                        size_needed);    return strTo;  }};// Return the maximum number of concurrent mmaps.int MaxMmaps() { return g_mmap_limit; }WindowsEnv::WindowsEnv()    : background_work_cv_(&background_work_mutex_),      started_background_thread_(false),      mmap_limiter_(MaxMmaps()) {}void WindowsEnv::Schedule(    void (*background_work_function)(void* background_work_arg),    void* background_work_arg) {  background_work_mutex_.Lock();  // Start the background thread, if we haven't done so already.  if (!started_background_thread_) {    started_background_thread_ = true;    std::thread background_thread(WindowsEnv::BackgroundThreadEntryPoint, this);    background_thread.detach();  }  // If the queue is empty, the background thread may be waiting for work.  if (background_work_queue_.empty()) {    background_work_cv_.Signal();  }  background_work_queue_.emplace(background_work_function, background_work_arg);  background_work_mutex_.Unlock();}void WindowsEnv::BackgroundThreadMain() {  while (true) {    background_work_mutex_.Lock();    // Wait until there is work to be done.    while (background_work_queue_.empty()) {      background_work_cv_.Wait();    }    assert(!background_work_queue_.empty());    auto background_work_function = background_work_queue_.front().function;    void* background_work_arg = background_work_queue_.front().arg;    background_work_queue_.pop();    background_work_mutex_.Unlock();    background_work_function(background_work_arg);  }}// Wraps an Env instance whose destructor is never created.//// Intended usage://   using PlatformSingletonEnv = SingletonEnv<PlatformEnv>;//   void ConfigurePosixEnv(int param) {//     PlatformSingletonEnv::AssertEnvNotInitialized();//     // set global configuration flags.//   }//   Env* Env::Default() {//     static PlatformSingletonEnv default_env;//     return default_env.env();//   }template <typename EnvType>class SingletonEnv { public:  SingletonEnv() {#if !defined(NDEBUG)    env_initialized_.store(true, std::memory_order::memory_order_relaxed);#endif  // !defined(NDEBUG)    static_assert(sizeof(env_storage_) >= sizeof(EnvType),                  "env_storage_ will not fit the Env");    static_assert(alignof(decltype(env_storage_)) >= alignof(EnvType),                  "env_storage_ does not meet the Env's alignment needs");    new (&env_storage_) EnvType();  }  ~SingletonEnv() = default;  SingletonEnv(const SingletonEnv&) = delete;  SingletonEnv& operator=(const SingletonEnv&) = delete;  Env* env() { return reinterpret_cast<Env*>(&env_storage_); }  static void AssertEnvNotInitialized() {#if !defined(NDEBUG)    assert(!env_initialized_.load(std::memory_order::memory_order_relaxed));#endif  // !defined(NDEBUG)  } private:  typename std::aligned_storage<sizeof(EnvType), alignof(EnvType)>::type      env_storage_;#if !defined(NDEBUG)  static std::atomic<bool> env_initialized_;#endif  // !defined(NDEBUG)};#if !defined(NDEBUG)template <typename EnvType>std::atomic<bool> SingletonEnv<EnvType>::env_initialized_;#endif  // !defined(NDEBUG)using WindowsDefaultEnv = SingletonEnv<WindowsEnv>;}  // namespacevoid EnvWindowsTestHelper::SetReadOnlyMMapLimit(int limit) {  WindowsDefaultEnv::AssertEnvNotInitialized();  g_mmap_limit = limit;}Env* Env::Default() {  static WindowsDefaultEnv env_container;  return env_container.env();}}  // namespace leveldb