25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

816 lines
26 KiB

1 개월 전
  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. // Prevent Windows headers from defining min/max macros and instead
  5. // use STL.
  6. #ifndef NOMINMAX
  7. #define NOMINMAX
  8. #endif // ifndef NOMINMAX
  9. #include <windows.h>
  10. #include <algorithm>
  11. #include <atomic>
  12. #include <chrono>
  13. #include <condition_variable>
  14. #include <cstddef>
  15. #include <cstdint>
  16. #include <cstdlib>
  17. #include <cstring>
  18. #include <memory>
  19. #include <mutex>
  20. #include <queue>
  21. #include <sstream>
  22. #include <string>
  23. #include <vector>
  24. #include "leveldb/env.h"
  25. #include "leveldb/slice.h"
  26. #include "port/port.h"
  27. #include "port/thread_annotations.h"
  28. #include "util/env_windows_test_helper.h"
  29. #include "util/logging.h"
  30. #include "util/mutexlock.h"
  31. #include "util/windows_logger.h"
  32. namespace leveldb {
  33. namespace {
  34. constexpr const size_t kWritableFileBufferSize = 65536;
  35. // Up to 1000 mmaps for 64-bit binaries; none for 32-bit.
  36. constexpr int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 1000 : 0;
  37. // Can be set by by EnvWindowsTestHelper::SetReadOnlyMMapLimit().
  38. int g_mmap_limit = kDefaultMmapLimit;
  39. std::string GetWindowsErrorMessage(DWORD error_code) {
  40. std::string message;
  41. char* error_text = nullptr;
  42. // Use MBCS version of FormatMessage to match return value.
  43. size_t error_text_size = ::FormatMessageA(
  44. FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
  45. FORMAT_MESSAGE_IGNORE_INSERTS,
  46. nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  47. reinterpret_cast<char*>(&error_text), 0, nullptr);
  48. if (!error_text) {
  49. return message;
  50. }
  51. message.assign(error_text, error_text_size);
  52. ::LocalFree(error_text);
  53. return message;
  54. }
  55. Status WindowsError(const std::string& context, DWORD error_code) {
  56. if (error_code == ERROR_FILE_NOT_FOUND || error_code == ERROR_PATH_NOT_FOUND)
  57. return Status::NotFound(context, GetWindowsErrorMessage(error_code));
  58. return Status::IOError(context, GetWindowsErrorMessage(error_code));
  59. }
  60. class ScopedHandle {
  61. public:
  62. ScopedHandle(HANDLE handle) : handle_(handle) {}
  63. ScopedHandle(const ScopedHandle&) = delete;
  64. ScopedHandle(ScopedHandle&& other) noexcept : handle_(other.Release()) {}
  65. ~ScopedHandle() { Close(); }
  66. ScopedHandle& operator=(const ScopedHandle&) = delete;
  67. ScopedHandle& operator=(ScopedHandle&& rhs) noexcept {
  68. if (this != &rhs) handle_ = rhs.Release();
  69. return *this;
  70. }
  71. bool Close() {
  72. if (!is_valid()) {
  73. return true;
  74. }
  75. HANDLE h = handle_;
  76. handle_ = INVALID_HANDLE_VALUE;
  77. return ::CloseHandle(h);
  78. }
  79. bool is_valid() const {
  80. return handle_ != INVALID_HANDLE_VALUE && handle_ != nullptr;
  81. }
  82. HANDLE get() const { return handle_; }
  83. HANDLE Release() {
  84. HANDLE h = handle_;
  85. handle_ = INVALID_HANDLE_VALUE;
  86. return h;
  87. }
  88. private:
  89. HANDLE handle_;
  90. };
  91. // Helper class to limit resource usage to avoid exhaustion.
  92. // Currently used to limit read-only file descriptors and mmap file usage
  93. // so that we do not run out of file descriptors or virtual memory, or run into
  94. // kernel performance problems for very large databases.
  95. class Limiter {
  96. public:
  97. // Limit maximum number of resources to |max_acquires|.
  98. Limiter(int max_acquires)
  99. :
  100. #if !defined(NDEBUG)
  101. max_acquires_(max_acquires),
  102. #endif // !defined(NDEBUG)
  103. acquires_allowed_(max_acquires) {
  104. assert(max_acquires >= 0);
  105. }
  106. Limiter(const Limiter&) = delete;
  107. Limiter operator=(const Limiter&) = delete;
  108. // If another resource is available, acquire it and return true.
  109. // Else return false.
  110. bool Acquire() {
  111. int old_acquires_allowed =
  112. acquires_allowed_.fetch_sub(1, std::memory_order_relaxed);
  113. if (old_acquires_allowed > 0) return true;
  114. acquires_allowed_.fetch_add(1, std::memory_order_relaxed);
  115. return false;
  116. }
  117. // Release a resource acquired by a previous call to Acquire() that returned
  118. // true.
  119. void Release() {
  120. int old_acquires_allowed =
  121. acquires_allowed_.fetch_add(1, std::memory_order_relaxed);
  122. // Silence compiler warnings about unused arguments when NDEBUG is defined.
  123. (void)old_acquires_allowed;
  124. // If the check below fails, Release() was called more times than acquire.
  125. assert(old_acquires_allowed < max_acquires_);
  126. }
  127. private:
  128. #if !defined(NDEBUG)
  129. // Catches an excessive number of Release() calls.
  130. const int max_acquires_;
  131. #endif // !defined(NDEBUG)
  132. // The number of available resources.
  133. //
  134. // This is a counter and is not tied to the invariants of any other class, so
  135. // it can be operated on safely using std::memory_order_relaxed.
  136. std::atomic<int> acquires_allowed_;
  137. };
  138. class WindowsSequentialFile : public SequentialFile {
  139. public:
  140. WindowsSequentialFile(std::string filename, ScopedHandle handle)
  141. : handle_(std::move(handle)), filename_(std::move(filename)) {}
  142. ~WindowsSequentialFile() override {}
  143. Status Read(size_t n, Slice* result, char* scratch) override {
  144. DWORD bytes_read;
  145. // DWORD is 32-bit, but size_t could technically be larger. However leveldb
  146. // files are limited to leveldb::Options::max_file_size which is clamped to
  147. // 1<<30 or 1 GiB.
  148. assert(n <= std::numeric_limits<DWORD>::max());
  149. if (!::ReadFile(handle_.get(), scratch, static_cast<DWORD>(n), &bytes_read,
  150. nullptr)) {
  151. return WindowsError(filename_, ::GetLastError());
  152. }
  153. *result = Slice(scratch, bytes_read);
  154. return Status::OK();
  155. }
  156. Status Skip(uint64_t n) override {
  157. LARGE_INTEGER distance;
  158. distance.QuadPart = n;
  159. if (!::SetFilePointerEx(handle_.get(), distance, nullptr, FILE_CURRENT)) {
  160. return WindowsError(filename_, ::GetLastError());
  161. }
  162. return Status::OK();
  163. }
  164. private:
  165. const ScopedHandle handle_;
  166. const std::string filename_;
  167. };
  168. class WindowsRandomAccessFile : public RandomAccessFile {
  169. public:
  170. WindowsRandomAccessFile(std::string filename, ScopedHandle handle)
  171. : handle_(std::move(handle)), filename_(std::move(filename)) {}
  172. ~WindowsRandomAccessFile() override = default;
  173. Status Read(uint64_t offset, size_t n, Slice* result,
  174. char* scratch) const override {
  175. DWORD bytes_read = 0;
  176. OVERLAPPED overlapped = {0};
  177. overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
  178. overlapped.Offset = static_cast<DWORD>(offset);
  179. if (!::ReadFile(handle_.get(), scratch, static_cast<DWORD>(n), &bytes_read,
  180. &overlapped)) {
  181. DWORD error_code = ::GetLastError();
  182. if (error_code != ERROR_HANDLE_EOF) {
  183. *result = Slice(scratch, 0);
  184. return Status::IOError(filename_, GetWindowsErrorMessage(error_code));
  185. }
  186. }
  187. *result = Slice(scratch, bytes_read);
  188. return Status::OK();
  189. }
  190. private:
  191. const ScopedHandle handle_;
  192. const std::string filename_;
  193. };
  194. class WindowsMmapReadableFile : public RandomAccessFile {
  195. public:
  196. // base[0,length-1] contains the mmapped contents of the file.
  197. WindowsMmapReadableFile(std::string filename, char* mmap_base, size_t length,
  198. Limiter* mmap_limiter)
  199. : mmap_base_(mmap_base),
  200. length_(length),
  201. mmap_limiter_(mmap_limiter),
  202. filename_(std::move(filename)) {}
  203. ~WindowsMmapReadableFile() override {
  204. ::UnmapViewOfFile(mmap_base_);
  205. mmap_limiter_->Release();
  206. }
  207. Status Read(uint64_t offset, size_t n, Slice* result,
  208. char* scratch) const override {
  209. if (offset + n > length_) {
  210. *result = Slice();
  211. return WindowsError(filename_, ERROR_INVALID_PARAMETER);
  212. }
  213. *result = Slice(mmap_base_ + offset, n);
  214. return Status::OK();
  215. }
  216. private:
  217. char* const mmap_base_;
  218. const size_t length_;
  219. Limiter* const mmap_limiter_;
  220. const std::string filename_;
  221. };
  222. class WindowsWritableFile : public WritableFile {
  223. public:
  224. WindowsWritableFile(std::string filename, ScopedHandle handle)
  225. : pos_(0), handle_(std::move(handle)), filename_(std::move(filename)) {}
  226. ~WindowsWritableFile() override = default;
  227. Status Append(const Slice& data) override {
  228. size_t write_size = data.size();
  229. const char* write_data = data.data();
  230. // Fit as much as possible into buffer.
  231. size_t copy_size = std::min(write_size, kWritableFileBufferSize - pos_);
  232. std::memcpy(buf_ + pos_, write_data, copy_size);
  233. write_data += copy_size;
  234. write_size -= copy_size;
  235. pos_ += copy_size;
  236. if (write_size == 0) {
  237. return Status::OK();
  238. }
  239. // Can't fit in buffer, so need to do at least one write.
  240. Status status = FlushBuffer();
  241. if (!status.ok()) {
  242. return status;
  243. }
  244. // Small writes go to buffer, large writes are written directly.
  245. if (write_size < kWritableFileBufferSize) {
  246. std::memcpy(buf_, write_data, write_size);
  247. pos_ = write_size;
  248. return Status::OK();
  249. }
  250. return WriteUnbuffered(write_data, write_size);
  251. }
  252. Status Close() override {
  253. Status status = FlushBuffer();
  254. if (!handle_.Close() && status.ok()) {
  255. status = WindowsError(filename_, ::GetLastError());
  256. }
  257. return status;
  258. }
  259. Status Flush() override { return FlushBuffer(); }
  260. Status Sync() override {
  261. // On Windows no need to sync parent directory. Its metadata will be updated
  262. // via the creation of the new file, without an explicit sync.
  263. Status status = FlushBuffer();
  264. if (!status.ok()) {
  265. return status;
  266. }
  267. if (!::FlushFileBuffers(handle_.get())) {
  268. return Status::IOError(filename_,
  269. GetWindowsErrorMessage(::GetLastError()));
  270. }
  271. return Status::OK();
  272. }
  273. private:
  274. Status FlushBuffer() {
  275. Status status = WriteUnbuffered(buf_, pos_);
  276. pos_ = 0;
  277. return status;
  278. }
  279. Status WriteUnbuffered(const char* data, size_t size) {
  280. DWORD bytes_written;
  281. if (!::WriteFile(handle_.get(), data, static_cast<DWORD>(size),
  282. &bytes_written, nullptr)) {
  283. return Status::IOError(filename_,
  284. GetWindowsErrorMessage(::GetLastError()));
  285. }
  286. return Status::OK();
  287. }
  288. // buf_[0, pos_-1] contains data to be written to handle_.
  289. char buf_[kWritableFileBufferSize];
  290. size_t pos_;
  291. ScopedHandle handle_;
  292. const std::string filename_;
  293. };
  294. // Lock or unlock the entire file as specified by |lock|. Returns true
  295. // when successful, false upon failure. Caller should call ::GetLastError()
  296. // to determine cause of failure
  297. bool LockOrUnlock(HANDLE handle, bool lock) {
  298. if (lock) {
  299. return ::LockFile(handle,
  300. /*dwFileOffsetLow=*/0, /*dwFileOffsetHigh=*/0,
  301. /*nNumberOfBytesToLockLow=*/MAXDWORD,
  302. /*nNumberOfBytesToLockHigh=*/MAXDWORD);
  303. } else {
  304. return ::UnlockFile(handle,
  305. /*dwFileOffsetLow=*/0, /*dwFileOffsetHigh=*/0,
  306. /*nNumberOfBytesToLockLow=*/MAXDWORD,
  307. /*nNumberOfBytesToLockHigh=*/MAXDWORD);
  308. }
  309. }
  310. class WindowsFileLock : public FileLock {
  311. public:
  312. WindowsFileLock(ScopedHandle handle, std::string filename)
  313. : handle_(std::move(handle)), filename_(std::move(filename)) {}
  314. const ScopedHandle& handle() const { return handle_; }
  315. const std::string& filename() const { return filename_; }
  316. private:
  317. const ScopedHandle handle_;
  318. const std::string filename_;
  319. };
  320. class WindowsEnv : public Env {
  321. public:
  322. WindowsEnv();
  323. ~WindowsEnv() override {
  324. static const char msg[] =
  325. "WindowsEnv singleton destroyed. Unsupported behavior!\n";
  326. std::fwrite(msg, 1, sizeof(msg), stderr);
  327. std::abort();
  328. }
  329. Status NewSequentialFile(const std::string& filename,
  330. SequentialFile** result) override {
  331. *result = nullptr;
  332. DWORD desired_access = GENERIC_READ;
  333. DWORD share_mode = FILE_SHARE_READ;
  334. ScopedHandle handle = ::CreateFileA(
  335. filename.c_str(), desired_access, share_mode,
  336. /*lpSecurityAttributes=*/nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  337. /*hTemplateFile=*/nullptr);
  338. if (!handle.is_valid()) {
  339. return WindowsError(filename, ::GetLastError());
  340. }
  341. *result = new WindowsSequentialFile(filename, std::move(handle));
  342. return Status::OK();
  343. }
  344. Status NewRandomAccessFile(const std::string& filename,
  345. RandomAccessFile** result) override {
  346. *result = nullptr;
  347. DWORD desired_access = GENERIC_READ;
  348. DWORD share_mode = FILE_SHARE_READ;
  349. ScopedHandle handle =
  350. ::CreateFileA(filename.c_str(), desired_access, share_mode,
  351. /*lpSecurityAttributes=*/nullptr, OPEN_EXISTING,
  352. FILE_ATTRIBUTE_READONLY,
  353. /*hTemplateFile=*/nullptr);
  354. if (!handle.is_valid()) {
  355. return WindowsError(filename, ::GetLastError());
  356. }
  357. if (!mmap_limiter_.Acquire()) {
  358. *result = new WindowsRandomAccessFile(filename, std::move(handle));
  359. return Status::OK();
  360. }
  361. LARGE_INTEGER file_size;
  362. Status status;
  363. if (!::GetFileSizeEx(handle.get(), &file_size)) {
  364. mmap_limiter_.Release();
  365. return WindowsError(filename, ::GetLastError());
  366. }
  367. ScopedHandle mapping =
  368. ::CreateFileMappingA(handle.get(),
  369. /*security attributes=*/nullptr, PAGE_READONLY,
  370. /*dwMaximumSizeHigh=*/0,
  371. /*dwMaximumSizeLow=*/0,
  372. /*lpName=*/nullptr);
  373. if (mapping.is_valid()) {
  374. void* mmap_base = ::MapViewOfFile(mapping.get(), FILE_MAP_READ,
  375. /*dwFileOffsetHigh=*/0,
  376. /*dwFileOffsetLow=*/0,
  377. /*dwNumberOfBytesToMap=*/0);
  378. if (mmap_base) {
  379. *result = new WindowsMmapReadableFile(
  380. filename, reinterpret_cast<char*>(mmap_base),
  381. static_cast<size_t>(file_size.QuadPart), &mmap_limiter_);
  382. return Status::OK();
  383. }
  384. }
  385. mmap_limiter_.Release();
  386. return WindowsError(filename, ::GetLastError());
  387. }
  388. Status NewWritableFile(const std::string& filename,
  389. WritableFile** result) override {
  390. DWORD desired_access = GENERIC_WRITE;
  391. DWORD share_mode = 0; // Exclusive access.
  392. ScopedHandle handle = ::CreateFileA(
  393. filename.c_str(), desired_access, share_mode,
  394. /*lpSecurityAttributes=*/nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
  395. /*hTemplateFile=*/nullptr);
  396. if (!handle.is_valid()) {
  397. *result = nullptr;
  398. return WindowsError(filename, ::GetLastError());
  399. }
  400. *result = new WindowsWritableFile(filename, std::move(handle));
  401. return Status::OK();
  402. }
  403. Status NewAppendableFile(const std::string& filename,
  404. WritableFile** result) override {
  405. DWORD desired_access = FILE_APPEND_DATA;
  406. DWORD share_mode = 0; // Exclusive access.
  407. ScopedHandle handle = ::CreateFileA(
  408. filename.c_str(), desired_access, share_mode,
  409. /*lpSecurityAttributes=*/nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
  410. /*hTemplateFile=*/nullptr);
  411. if (!handle.is_valid()) {
  412. *result = nullptr;
  413. return WindowsError(filename, ::GetLastError());
  414. }
  415. *result = new WindowsWritableFile(filename, std::move(handle));
  416. return Status::OK();
  417. }
  418. bool FileExists(const std::string& filename) override {
  419. return GetFileAttributesA(filename.c_str()) != INVALID_FILE_ATTRIBUTES;
  420. }
  421. Status GetChildren(const std::string& directory_path,
  422. std::vector<std::string>* result) override {
  423. const std::string find_pattern = directory_path + "\\*";
  424. WIN32_FIND_DATAA find_data;
  425. HANDLE dir_handle = ::FindFirstFileA(find_pattern.c_str(), &find_data);
  426. if (dir_handle == INVALID_HANDLE_VALUE) {
  427. DWORD last_error = ::GetLastError();
  428. if (last_error == ERROR_FILE_NOT_FOUND) {
  429. return Status::OK();
  430. }
  431. return WindowsError(directory_path, last_error);
  432. }
  433. do {
  434. char base_name[_MAX_FNAME];
  435. char ext[_MAX_EXT];
  436. if (!_splitpath_s(find_data.cFileName, nullptr, 0, nullptr, 0, base_name,
  437. ARRAYSIZE(base_name), ext, ARRAYSIZE(ext))) {
  438. result->emplace_back(std::string(base_name) + ext);
  439. }
  440. } while (::FindNextFileA(dir_handle, &find_data));
  441. DWORD last_error = ::GetLastError();
  442. ::FindClose(dir_handle);
  443. if (last_error != ERROR_NO_MORE_FILES) {
  444. return WindowsError(directory_path, last_error);
  445. }
  446. return Status::OK();
  447. }
  448. Status RemoveFile(const std::string& filename) override {
  449. if (!::DeleteFileA(filename.c_str())) {
  450. return WindowsError(filename, ::GetLastError());
  451. }
  452. return Status::OK();
  453. }
  454. Status CreateDir(const std::string& dirname) override {
  455. if (!::CreateDirectoryA(dirname.c_str(), nullptr)) {
  456. return WindowsError(dirname, ::GetLastError());
  457. }
  458. return Status::OK();
  459. }
  460. Status RemoveDir(const std::string& dirname) override {
  461. if (!::RemoveDirectoryA(dirname.c_str())) {
  462. return WindowsError(dirname, ::GetLastError());
  463. }
  464. return Status::OK();
  465. }
  466. Status GetFileSize(const std::string& filename, uint64_t* size) override {
  467. WIN32_FILE_ATTRIBUTE_DATA file_attributes;
  468. if (!::GetFileAttributesExA(filename.c_str(), GetFileExInfoStandard,
  469. &file_attributes)) {
  470. return WindowsError(filename, ::GetLastError());
  471. }
  472. ULARGE_INTEGER file_size;
  473. file_size.HighPart = file_attributes.nFileSizeHigh;
  474. file_size.LowPart = file_attributes.nFileSizeLow;
  475. *size = file_size.QuadPart;
  476. return Status::OK();
  477. }
  478. Status RenameFile(const std::string& from, const std::string& to) override {
  479. // Try a simple move first. It will only succeed when |to| doesn't already
  480. // exist.
  481. if (::MoveFileA(from.c_str(), to.c_str())) {
  482. return Status::OK();
  483. }
  484. DWORD move_error = ::GetLastError();
  485. // Try the full-blown replace if the move fails, as ReplaceFile will only
  486. // succeed when |to| does exist. When writing to a network share, we may not
  487. // be able to change the ACLs. Ignore ACL errors then
  488. // (REPLACEFILE_IGNORE_MERGE_ERRORS).
  489. if (::ReplaceFileA(to.c_str(), from.c_str(), /*lpBackupFileName=*/nullptr,
  490. REPLACEFILE_IGNORE_MERGE_ERRORS,
  491. /*lpExclude=*/nullptr, /*lpReserved=*/nullptr)) {
  492. return Status::OK();
  493. }
  494. DWORD replace_error = ::GetLastError();
  495. // In the case of FILE_ERROR_NOT_FOUND from ReplaceFile, it is likely that
  496. // |to| does not exist. In this case, the more relevant error comes from the
  497. // call to MoveFile.
  498. if (replace_error == ERROR_FILE_NOT_FOUND ||
  499. replace_error == ERROR_PATH_NOT_FOUND) {
  500. return WindowsError(from, move_error);
  501. } else {
  502. return WindowsError(from, replace_error);
  503. }
  504. }
  505. Status LockFile(const std::string& filename, FileLock** lock) override {
  506. *lock = nullptr;
  507. Status result;
  508. ScopedHandle handle = ::CreateFileA(
  509. filename.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
  510. /*lpSecurityAttributes=*/nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
  511. nullptr);
  512. if (!handle.is_valid()) {
  513. result = WindowsError(filename, ::GetLastError());
  514. } else if (!LockOrUnlock(handle.get(), true)) {
  515. result = WindowsError("lock " + filename, ::GetLastError());
  516. } else {
  517. *lock = new WindowsFileLock(std::move(handle), filename);
  518. }
  519. return result;
  520. }
  521. Status UnlockFile(FileLock* lock) override {
  522. WindowsFileLock* windows_file_lock =
  523. reinterpret_cast<WindowsFileLock*>(lock);
  524. if (!LockOrUnlock(windows_file_lock->handle().get(), false)) {
  525. return WindowsError("unlock " + windows_file_lock->filename(),
  526. ::GetLastError());
  527. }
  528. delete windows_file_lock;
  529. return Status::OK();
  530. }
  531. void Schedule(void (*background_work_function)(void* background_work_arg),
  532. void* background_work_arg) override;
  533. void StartThread(void (*thread_main)(void* thread_main_arg),
  534. void* thread_main_arg) override {
  535. std::thread new_thread(thread_main, thread_main_arg);
  536. new_thread.detach();
  537. }
  538. Status GetTestDirectory(std::string* result) override {
  539. const char* env = getenv("TEST_TMPDIR");
  540. if (env && env[0] != '\0') {
  541. *result = env;
  542. return Status::OK();
  543. }
  544. char tmp_path[MAX_PATH];
  545. if (!GetTempPathA(ARRAYSIZE(tmp_path), tmp_path)) {
  546. return WindowsError("GetTempPath", ::GetLastError());
  547. }
  548. std::stringstream ss;
  549. ss << tmp_path << "leveldbtest-" << std::this_thread::get_id();
  550. *result = ss.str();
  551. // Directory may already exist
  552. CreateDir(*result);
  553. return Status::OK();
  554. }
  555. Status NewLogger(const std::string& filename, Logger** result) override {
  556. std::FILE* fp = std::fopen(filename.c_str(), "wN");
  557. if (fp == nullptr) {
  558. *result = nullptr;
  559. return WindowsError(filename, ::GetLastError());
  560. } else {
  561. *result = new WindowsLogger(fp);
  562. return Status::OK();
  563. }
  564. }
  565. uint64_t NowMicros() override {
  566. // GetSystemTimeAsFileTime typically has a resolution of 10-20 msec.
  567. // TODO(cmumford): Switch to GetSystemTimePreciseAsFileTime which is
  568. // available in Windows 8 and later.
  569. FILETIME ft;
  570. ::GetSystemTimeAsFileTime(&ft);
  571. // Each tick represents a 100-nanosecond intervals since January 1, 1601
  572. // (UTC).
  573. uint64_t num_ticks =
  574. (static_cast<uint64_t>(ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
  575. return num_ticks / 10;
  576. }
  577. void SleepForMicroseconds(int micros) override {
  578. std::this_thread::sleep_for(std::chrono::microseconds(micros));
  579. }
  580. private:
  581. void BackgroundThreadMain();
  582. static void BackgroundThreadEntryPoint(WindowsEnv* env) {
  583. env->BackgroundThreadMain();
  584. }
  585. // Stores the work item data in a Schedule() call.
  586. //
  587. // Instances are constructed on the thread calling Schedule() and used on the
  588. // background thread.
  589. //
  590. // This structure is thread-safe because it is immutable.
  591. struct BackgroundWorkItem {
  592. explicit BackgroundWorkItem(void (*function)(void* arg), void* arg)
  593. : function(function), arg(arg) {}
  594. void (*const function)(void*);
  595. void* const arg;
  596. };
  597. port::Mutex background_work_mutex_;
  598. port::CondVar background_work_cv_ GUARDED_BY(background_work_mutex_);
  599. bool started_background_thread_ GUARDED_BY(background_work_mutex_);
  600. std::queue<BackgroundWorkItem> background_work_queue_
  601. GUARDED_BY(background_work_mutex_);
  602. Limiter mmap_limiter_; // Thread-safe.
  603. };
  604. // Return the maximum number of concurrent mmaps.
  605. int MaxMmaps() { return g_mmap_limit; }
  606. WindowsEnv::WindowsEnv()
  607. : background_work_cv_(&background_work_mutex_),
  608. started_background_thread_(false),
  609. mmap_limiter_(MaxMmaps()) {}
  610. void WindowsEnv::Schedule(
  611. void (*background_work_function)(void* background_work_arg),
  612. void* background_work_arg) {
  613. background_work_mutex_.Lock();
  614. // Start the background thread, if we haven't done so already.
  615. if (!started_background_thread_) {
  616. started_background_thread_ = true;
  617. std::thread background_thread(WindowsEnv::BackgroundThreadEntryPoint, this);
  618. background_thread.detach();
  619. }
  620. // If the queue is empty, the background thread may be waiting for work.
  621. if (background_work_queue_.empty()) {
  622. background_work_cv_.Signal();
  623. }
  624. background_work_queue_.emplace(background_work_function, background_work_arg);
  625. background_work_mutex_.Unlock();
  626. }
  627. void WindowsEnv::BackgroundThreadMain() {
  628. while (true) {
  629. background_work_mutex_.Lock();
  630. // Wait until there is work to be done.
  631. while (background_work_queue_.empty()) {
  632. background_work_cv_.Wait();
  633. }
  634. assert(!background_work_queue_.empty());
  635. auto background_work_function = background_work_queue_.front().function;
  636. void* background_work_arg = background_work_queue_.front().arg;
  637. background_work_queue_.pop();
  638. background_work_mutex_.Unlock();
  639. background_work_function(background_work_arg);
  640. }
  641. }
  642. // Wraps an Env instance whose destructor is never created.
  643. //
  644. // Intended usage:
  645. // using PlatformSingletonEnv = SingletonEnv<PlatformEnv>;
  646. // void ConfigurePosixEnv(int param) {
  647. // PlatformSingletonEnv::AssertEnvNotInitialized();
  648. // // set global configuration flags.
  649. // }
  650. // Env* Env::Default() {
  651. // static PlatformSingletonEnv default_env;
  652. // return default_env.env();
  653. // }
  654. template <typename EnvType>
  655. class SingletonEnv {
  656. public:
  657. SingletonEnv() {
  658. #if !defined(NDEBUG)
  659. env_initialized_.store(true, std::memory_order_relaxed);
  660. #endif // !defined(NDEBUG)
  661. static_assert(sizeof(env_storage_) >= sizeof(EnvType),
  662. "env_storage_ will not fit the Env");
  663. static_assert(alignof(decltype(env_storage_)) >= alignof(EnvType),
  664. "env_storage_ does not meet the Env's alignment needs");
  665. new (&env_storage_) EnvType();
  666. }
  667. ~SingletonEnv() = default;
  668. SingletonEnv(const SingletonEnv&) = delete;
  669. SingletonEnv& operator=(const SingletonEnv&) = delete;
  670. Env* env() { return reinterpret_cast<Env*>(&env_storage_); }
  671. static void AssertEnvNotInitialized() {
  672. #if !defined(NDEBUG)
  673. assert(!env_initialized_.load(std::memory_order_relaxed));
  674. #endif // !defined(NDEBUG)
  675. }
  676. private:
  677. typename std::aligned_storage<sizeof(EnvType), alignof(EnvType)>::type
  678. env_storage_;
  679. #if !defined(NDEBUG)
  680. static std::atomic<bool> env_initialized_;
  681. #endif // !defined(NDEBUG)
  682. };
  683. #if !defined(NDEBUG)
  684. template <typename EnvType>
  685. std::atomic<bool> SingletonEnv<EnvType>::env_initialized_;
  686. #endif // !defined(NDEBUG)
  687. using WindowsDefaultEnv = SingletonEnv<WindowsEnv>;
  688. } // namespace
  689. void EnvWindowsTestHelper::SetReadOnlyMMapLimit(int limit) {
  690. WindowsDefaultEnv::AssertEnvNotInitialized();
  691. g_mmap_limit = limit;
  692. }
  693. Env* Env::Default() {
  694. static WindowsDefaultEnv env_container;
  695. return env_container.env();
  696. }
  697. } // namespace leveldb