小组成员:姚凯文(kevinyao0901),姜嘉琪
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

800 lines
25 KiB

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