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