/ src / leveldb / util / env_windows.cc
env_windows.cc
  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 because 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(std::is_standard_layout_v<SingletonEnv<EnvType>>);
806      static_assert(
807          offsetof(SingletonEnv<EnvType>, env_storage_) % alignof(EnvType) == 0,
808          "env_storage_ does not meet the Env's alignment needs");
809      static_assert(alignof(SingletonEnv<EnvType>) % alignof(EnvType) == 0,
810                    "env_storage_ does not meet the Env's alignment needs");
811      new (env_storage_) EnvType();
812    }
813    ~SingletonEnv() = default;
814  
815    SingletonEnv(const SingletonEnv&) = delete;
816    SingletonEnv& operator=(const SingletonEnv&) = delete;
817  
818    Env* env() { return reinterpret_cast<Env*>(&env_storage_); }
819  
820    static void AssertEnvNotInitialized() {
821  #if !defined(NDEBUG)
822      assert(!env_initialized_.load(std::memory_order_relaxed));
823  #endif  // !defined(NDEBUG)
824    }
825  
826   private:
827    alignas(EnvType) char env_storage_[sizeof(EnvType)];
828  #if !defined(NDEBUG)
829    static std::atomic<bool> env_initialized_;
830  #endif  // !defined(NDEBUG)
831  };
832  
833  #if !defined(NDEBUG)
834  template <typename EnvType>
835  std::atomic<bool> SingletonEnv<EnvType>::env_initialized_;
836  #endif  // !defined(NDEBUG)
837  
838  using WindowsDefaultEnv = SingletonEnv<WindowsEnv>;
839  
840  }  // namespace
841  
842  void EnvWindowsTestHelper::SetReadOnlyMMapLimit(int limit) {
843    WindowsDefaultEnv::AssertEnvNotInitialized();
844    g_mmap_limit = limit;
845  }
846  
847  Env* Env::Default() {
848    static WindowsDefaultEnv env_container;
849    return env_container.env();
850  }
851  
852  }  // namespace leveldb