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