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