作者: 谢瑞阳 10225101483 徐翔宇 10225101535
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.

742 lines
22 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. #define NOMINMAX
  7. #include <windows.h>
  8. #include <algorithm>
  9. #include <chrono>
  10. #include <condition_variable>
  11. #include <deque>
  12. #include <memory>
  13. #include <mutex>
  14. #include <sstream>
  15. #include <string>
  16. #include <vector>
  17. #include "leveldb/env.h"
  18. #include "leveldb/slice.h"
  19. #include "port/port.h"
  20. #include "port/thread_annotations.h"
  21. #include "util/env_windows_test_helper.h"
  22. #include "util/logging.h"
  23. #include "util/mutexlock.h"
  24. #include "util/windows_logger.h"
  25. #if defined(DeleteFile)
  26. #undef DeleteFile
  27. #endif // defined(DeleteFile)
  28. namespace leveldb {
  29. namespace {
  30. constexpr const size_t kWritableFileBufferSize = 65536;
  31. // Up to 1000 mmaps for 64-bit binaries; none for 32-bit.
  32. constexpr int kDefaultMmapLimit = sizeof(void*) >= 8 ? 1000 : 0;
  33. // Modified by EnvWindowsTestHelper::SetReadOnlyMMapLimit().
  34. int g_mmap_limit = kDefaultMmapLimit;
  35. // Relax some file access permissions for testing.
  36. bool g_relax_permissions = false;
  37. std::string GetWindowsErrorMessage(DWORD error_code) {
  38. std::string message;
  39. char* error_text = nullptr;
  40. // Use MBCS version of FormatMessage to match return value.
  41. size_t error_text_size = ::FormatMessageA(
  42. FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
  43. FORMAT_MESSAGE_IGNORE_INSERTS,
  44. nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  45. reinterpret_cast<char*>(&error_text), 0, nullptr);
  46. if (!error_text) {
  47. return message;
  48. }
  49. message.assign(error_text, error_text_size);
  50. ::LocalFree(error_text);
  51. return message;
  52. }
  53. Status WindowsError(const std::string& context, DWORD error_code) {
  54. if (error_code == ERROR_FILE_NOT_FOUND || error_code == ERROR_PATH_NOT_FOUND)
  55. return Status::NotFound(context, GetWindowsErrorMessage(error_code));
  56. return Status::IOError(context, GetWindowsErrorMessage(error_code));
  57. }
  58. class ScopedHandle {
  59. public:
  60. ScopedHandle(HANDLE handle) : handle_(handle) {}
  61. ScopedHandle(ScopedHandle&& other) noexcept : handle_(other.Release()) {}
  62. ~ScopedHandle() { Close(); }
  63. ScopedHandle& operator=(ScopedHandle&& rhs) noexcept {
  64. if (this != &rhs) handle_ = rhs.Release();
  65. return *this;
  66. }
  67. bool Close() {
  68. if (!is_valid()) {
  69. return true;
  70. }
  71. HANDLE h = handle_;
  72. handle_ = INVALID_HANDLE_VALUE;
  73. return ::CloseHandle(h);
  74. }
  75. bool is_valid() const {
  76. return handle_ != INVALID_HANDLE_VALUE && handle_ != nullptr;
  77. }
  78. HANDLE get() const { return handle_; }
  79. HANDLE Release() {
  80. HANDLE h = handle_;
  81. handle_ = INVALID_HANDLE_VALUE;
  82. return h;
  83. }
  84. private:
  85. HANDLE handle_;
  86. };
  87. // Helper class to limit resource usage to avoid exhaustion.
  88. // Currently used to limit mmap file usage so that we do not end
  89. // up running out virtual memory, or running into kernel performance
  90. // problems for very large databases.
  91. class Limiter {
  92. public:
  93. // Limit maximum number of resources to |n|.
  94. Limiter(intptr_t n) { SetAllowed(n); }
  95. // If another resource is available, acquire it and return true.
  96. // Else return false.
  97. bool Acquire() LOCKS_EXCLUDED(mu_) {
  98. if (GetAllowed() <= 0) {
  99. return false;
  100. }
  101. MutexLock l(&mu_);
  102. intptr_t x = GetAllowed();
  103. if (x <= 0) {
  104. return false;
  105. } else {
  106. SetAllowed(x - 1);
  107. return true;
  108. }
  109. }
  110. // Release a resource acquired by a previous call to Acquire() that returned
  111. // true.
  112. void Release() LOCKS_EXCLUDED(mu_) {
  113. MutexLock l(&mu_);
  114. SetAllowed(GetAllowed() + 1);
  115. }
  116. private:
  117. port::Mutex mu_;
  118. port::AtomicPointer allowed_;
  119. intptr_t GetAllowed() const {
  120. return reinterpret_cast<intptr_t>(allowed_.Acquire_Load());
  121. }
  122. void SetAllowed(intptr_t v) EXCLUSIVE_LOCKS_REQUIRED(mu_) {
  123. allowed_.Release_Store(reinterpret_cast<void*>(v));
  124. }
  125. Limiter(const Limiter&);
  126. void operator=(const Limiter&);
  127. };
  128. class WindowsSequentialFile : public SequentialFile {
  129. public:
  130. WindowsSequentialFile(std::string fname, ScopedHandle file)
  131. : filename_(fname), file_(std::move(file)) {}
  132. ~WindowsSequentialFile() override {}
  133. Status Read(size_t n, Slice* result, char* scratch) override {
  134. Status s;
  135. DWORD bytes_read;
  136. // DWORD is 32-bit, but size_t could technically be larger. However leveldb
  137. // files are limited to leveldb::Options::max_file_size which is clamped to
  138. // 1<<30 or 1 GiB.
  139. assert(n <= std::numeric_limits<DWORD>::max());
  140. if (!::ReadFile(file_.get(), scratch, static_cast<DWORD>(n), &bytes_read,
  141. nullptr)) {
  142. s = WindowsError(filename_, ::GetLastError());
  143. } else {
  144. *result = Slice(scratch, bytes_read);
  145. }
  146. return s;
  147. }
  148. Status Skip(uint64_t n) override {
  149. LARGE_INTEGER distance;
  150. distance.QuadPart = n;
  151. if (!::SetFilePointerEx(file_.get(), distance, nullptr, FILE_CURRENT)) {
  152. return WindowsError(filename_, ::GetLastError());
  153. }
  154. return Status::OK();
  155. }
  156. private:
  157. std::string filename_;
  158. ScopedHandle file_;
  159. };
  160. class WindowsRandomAccessFile : public RandomAccessFile {
  161. public:
  162. WindowsRandomAccessFile(std::string fname, ScopedHandle handle)
  163. : filename_(fname), handle_(std::move(handle)) {}
  164. ~WindowsRandomAccessFile() override = default;
  165. Status Read(uint64_t offset, size_t n, Slice* result,
  166. char* scratch) const override {
  167. DWORD bytes_read = 0;
  168. OVERLAPPED overlapped = {0};
  169. overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
  170. overlapped.Offset = static_cast<DWORD>(offset);
  171. if (!::ReadFile(handle_.get(), scratch, static_cast<DWORD>(n), &bytes_read,
  172. &overlapped)) {
  173. DWORD error_code = ::GetLastError();
  174. if (error_code != ERROR_HANDLE_EOF) {
  175. *result = Slice(scratch, 0);
  176. return Status::IOError(filename_, GetWindowsErrorMessage(error_code));
  177. }
  178. }
  179. *result = Slice(scratch, bytes_read);
  180. return Status::OK();
  181. }
  182. private:
  183. std::string filename_;
  184. ScopedHandle handle_;
  185. };
  186. class WindowsMmapReadableFile : public RandomAccessFile {
  187. public:
  188. // base[0,length-1] contains the mmapped contents of the file.
  189. WindowsMmapReadableFile(std::string fname, void* base, size_t length,
  190. Limiter* limiter)
  191. : filename_(std::move(fname)),
  192. mmapped_region_(base),
  193. length_(length),
  194. limiter_(limiter) {}
  195. ~WindowsMmapReadableFile() override {
  196. ::UnmapViewOfFile(mmapped_region_);
  197. limiter_->Release();
  198. }
  199. Status Read(uint64_t offset, size_t n, Slice* result,
  200. char* scratch) const override {
  201. Status s;
  202. if (offset + n > length_) {
  203. *result = Slice();
  204. s = WindowsError(filename_, ERROR_INVALID_PARAMETER);
  205. } else {
  206. *result = Slice(reinterpret_cast<char*>(mmapped_region_) + offset, n);
  207. }
  208. return s;
  209. }
  210. private:
  211. std::string filename_;
  212. void* mmapped_region_;
  213. size_t length_;
  214. Limiter* limiter_;
  215. };
  216. class WindowsWritableFile : public WritableFile {
  217. public:
  218. WindowsWritableFile(std::string fname, ScopedHandle handle)
  219. : filename_(std::move(fname)), handle_(std::move(handle)), pos_(0) {}
  220. ~WindowsWritableFile() override = default;
  221. Status Append(const Slice& data) override {
  222. size_t n = data.size();
  223. const char* p = data.data();
  224. // Fit as much as possible into buffer.
  225. size_t copy = std::min(n, kWritableFileBufferSize - pos_);
  226. memcpy(buf_ + pos_, p, copy);
  227. p += copy;
  228. n -= copy;
  229. pos_ += copy;
  230. if (n == 0) {
  231. return Status::OK();
  232. }
  233. // Can't fit in buffer, so need to do at least one write.
  234. Status s = FlushBuffered();
  235. if (!s.ok()) {
  236. return s;
  237. }
  238. // Small writes go to buffer, large writes are written directly.
  239. if (n < kWritableFileBufferSize) {
  240. memcpy(buf_, p, n);
  241. pos_ = n;
  242. return Status::OK();
  243. }
  244. return WriteRaw(p, n);
  245. }
  246. Status Close() override {
  247. Status result = FlushBuffered();
  248. if (!handle_.Close() && result.ok()) {
  249. result = WindowsError(filename_, ::GetLastError());
  250. }
  251. return result;
  252. }
  253. Status Flush() override { return FlushBuffered(); }
  254. Status Sync() override {
  255. // On Windows no need to sync parent directory. It's metadata will be
  256. // updated via the creation of the new file, without an explicit sync.
  257. return FlushBuffered();
  258. }
  259. private:
  260. Status FlushBuffered() {
  261. Status s = WriteRaw(buf_, pos_);
  262. pos_ = 0;
  263. return s;
  264. }
  265. Status WriteRaw(const char* p, size_t n) {
  266. DWORD bytes_written;
  267. if (!::WriteFile(handle_.get(), p, static_cast<DWORD>(n), &bytes_written,
  268. nullptr)) {
  269. return Status::IOError(filename_,
  270. GetWindowsErrorMessage(::GetLastError()));
  271. }
  272. return Status::OK();
  273. }
  274. // buf_[0, pos_-1] contains data to be written to handle_.
  275. const std::string filename_;
  276. ScopedHandle handle_;
  277. char buf_[kWritableFileBufferSize];
  278. size_t pos_;
  279. };
  280. // Lock or unlock the entire file as specified by |lock|. Returns true
  281. // when successful, false upon failure. Caller should call ::GetLastError()
  282. // to determine cause of failure
  283. bool LockOrUnlock(HANDLE handle, bool lock) {
  284. if (lock) {
  285. return ::LockFile(handle,
  286. /*dwFileOffsetLow=*/0, /*dwFileOffsetHigh=*/0,
  287. /*nNumberOfBytesToLockLow=*/MAXDWORD,
  288. /*nNumberOfBytesToLockHigh=*/MAXDWORD);
  289. } else {
  290. return ::UnlockFile(handle,
  291. /*dwFileOffsetLow=*/0, /*dwFileOffsetHigh=*/0,
  292. /*nNumberOfBytesToLockLow=*/MAXDWORD,
  293. /*nNumberOfBytesToLockHigh=*/MAXDWORD);
  294. }
  295. }
  296. class WindowsFileLock : public FileLock {
  297. public:
  298. WindowsFileLock(ScopedHandle handle, std::string name)
  299. : handle_(std::move(handle)), name_(std::move(name)) {}
  300. ScopedHandle& handle() { return handle_; }
  301. const std::string& name() const { return name_; }
  302. private:
  303. ScopedHandle handle_;
  304. std::string name_;
  305. };
  306. class WindowsEnv : public Env {
  307. public:
  308. WindowsEnv();
  309. ~WindowsEnv() override {
  310. static char msg[] = "Destroying Env::Default()\n";
  311. fwrite(msg, 1, sizeof(msg), stderr);
  312. abort();
  313. }
  314. Status NewSequentialFile(const std::string& fname,
  315. SequentialFile** result) override {
  316. *result = nullptr;
  317. DWORD desired_access = GENERIC_READ;
  318. DWORD share_mode = FILE_SHARE_READ;
  319. if (g_relax_permissions) {
  320. desired_access |= GENERIC_WRITE;
  321. share_mode |= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  322. }
  323. ScopedHandle handle =
  324. ::CreateFileA(fname.c_str(), desired_access, share_mode, nullptr,
  325. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  326. if (!handle.is_valid()) {
  327. return WindowsError(fname, ::GetLastError());
  328. }
  329. *result = new WindowsSequentialFile(fname, std::move(handle));
  330. return Status::OK();
  331. }
  332. Status NewRandomAccessFile(const std::string& fname,
  333. RandomAccessFile** result) override {
  334. *result = nullptr;
  335. DWORD desired_access = GENERIC_READ;
  336. DWORD share_mode = FILE_SHARE_READ;
  337. if (g_relax_permissions) {
  338. // desired_access |= GENERIC_WRITE;
  339. share_mode |= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  340. }
  341. DWORD file_flags = FILE_ATTRIBUTE_READONLY;
  342. ScopedHandle handle =
  343. ::CreateFileA(fname.c_str(), desired_access, share_mode, nullptr,
  344. OPEN_EXISTING, file_flags, nullptr);
  345. if (!handle.is_valid()) {
  346. return WindowsError(fname, ::GetLastError());
  347. }
  348. if (!mmap_limiter_.Acquire()) {
  349. *result = new WindowsRandomAccessFile(fname, std::move(handle));
  350. return Status::OK();
  351. }
  352. LARGE_INTEGER file_size;
  353. if (!::GetFileSizeEx(handle.get(), &file_size)) {
  354. return WindowsError(fname, ::GetLastError());
  355. }
  356. ScopedHandle mapping =
  357. ::CreateFileMappingA(handle.get(),
  358. /*security attributes=*/nullptr, PAGE_READONLY,
  359. /*dwMaximumSizeHigh=*/0,
  360. /*dwMaximumSizeLow=*/0, nullptr);
  361. if (mapping.is_valid()) {
  362. void* base = MapViewOfFile(mapping.get(), FILE_MAP_READ, 0, 0, 0);
  363. if (base) {
  364. *result = new WindowsMmapReadableFile(
  365. fname, base, static_cast<size_t>(file_size.QuadPart),
  366. &mmap_limiter_);
  367. return Status::OK();
  368. }
  369. }
  370. Status s = WindowsError(fname, ::GetLastError());
  371. if (!s.ok()) {
  372. mmap_limiter_.Release();
  373. }
  374. return s;
  375. }
  376. Status NewWritableFile(const std::string& fname,
  377. WritableFile** result) override {
  378. DWORD desired_access = GENERIC_WRITE;
  379. DWORD share_mode = 0;
  380. if (g_relax_permissions) {
  381. desired_access |= GENERIC_READ;
  382. share_mode |= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  383. }
  384. ScopedHandle handle =
  385. ::CreateFileA(fname.c_str(), desired_access, share_mode, nullptr,
  386. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
  387. if (!handle.is_valid()) {
  388. *result = nullptr;
  389. return WindowsError(fname, ::GetLastError());
  390. }
  391. *result = new WindowsWritableFile(fname, std::move(handle));
  392. return Status::OK();
  393. }
  394. Status NewAppendableFile(const std::string& fname,
  395. WritableFile** result) override {
  396. ScopedHandle handle =
  397. ::CreateFileA(fname.c_str(), FILE_APPEND_DATA, 0, nullptr, OPEN_ALWAYS,
  398. FILE_ATTRIBUTE_NORMAL, nullptr);
  399. if (!handle.is_valid()) {
  400. *result = nullptr;
  401. return WindowsError(fname, ::GetLastError());
  402. }
  403. *result = new WindowsWritableFile(fname, std::move(handle));
  404. return Status::OK();
  405. }
  406. bool FileExists(const std::string& fname) override {
  407. return GetFileAttributesA(fname.c_str()) != INVALID_FILE_ATTRIBUTES;
  408. }
  409. Status GetChildren(const std::string& dir,
  410. std::vector<std::string>* result) override {
  411. const std::string find_pattern = dir + "\\*";
  412. WIN32_FIND_DATAA find_data;
  413. HANDLE dir_handle = ::FindFirstFileA(find_pattern.c_str(), &find_data);
  414. if (dir_handle == INVALID_HANDLE_VALUE) {
  415. DWORD last_error = ::GetLastError();
  416. if (last_error == ERROR_FILE_NOT_FOUND) {
  417. return Status::OK();
  418. }
  419. return WindowsError(dir, last_error);
  420. }
  421. do {
  422. char base_name[_MAX_FNAME];
  423. char ext[_MAX_EXT];
  424. if (!_splitpath_s(find_data.cFileName, nullptr, 0, nullptr, 0, base_name,
  425. ARRAYSIZE(base_name), ext, ARRAYSIZE(ext))) {
  426. result->emplace_back(std::string(base_name) + ext);
  427. }
  428. } while (::FindNextFileA(dir_handle, &find_data));
  429. DWORD last_error = ::GetLastError();
  430. ::FindClose(dir_handle);
  431. if (last_error != ERROR_NO_MORE_FILES) {
  432. return WindowsError(dir, last_error);
  433. }
  434. return Status::OK();
  435. }
  436. Status DeleteFile(const std::string& fname) override {
  437. if (!::DeleteFileA(fname.c_str())) {
  438. return WindowsError(fname, ::GetLastError());
  439. }
  440. return Status::OK();
  441. }
  442. Status CreateDir(const std::string& name) override {
  443. if (!::CreateDirectoryA(name.c_str(), nullptr)) {
  444. return WindowsError(name, ::GetLastError());
  445. }
  446. return Status::OK();
  447. }
  448. Status DeleteDir(const std::string& name) override {
  449. if (!::RemoveDirectoryA(name.c_str())) {
  450. return WindowsError(name, ::GetLastError());
  451. }
  452. return Status::OK();
  453. }
  454. Status GetFileSize(const std::string& fname, uint64_t* size) override {
  455. WIN32_FILE_ATTRIBUTE_DATA attrs;
  456. if (!::GetFileAttributesExA(fname.c_str(), GetFileExInfoStandard, &attrs)) {
  457. return WindowsError(fname, ::GetLastError());
  458. }
  459. ULARGE_INTEGER file_size;
  460. file_size.HighPart = attrs.nFileSizeHigh;
  461. file_size.LowPart = attrs.nFileSizeLow;
  462. *size = file_size.QuadPart;
  463. return Status::OK();
  464. }
  465. Status RenameFile(const std::string& src,
  466. const std::string& target) override {
  467. // Try a simple move first. It will only succeed when |to_path| doesn't
  468. // already exist.
  469. if (::MoveFileA(src.c_str(), target.c_str())) {
  470. return Status::OK();
  471. }
  472. DWORD move_error = ::GetLastError();
  473. // Try the full-blown replace if the move fails, as ReplaceFile will only
  474. // succeed when |to_path| does exist. When writing to a network share, we
  475. // may not be able to change the ACLs. Ignore ACL errors then
  476. // (REPLACEFILE_IGNORE_MERGE_ERRORS).
  477. if (::ReplaceFileA(target.c_str(), src.c_str(), nullptr,
  478. REPLACEFILE_IGNORE_MERGE_ERRORS, nullptr, nullptr)) {
  479. return Status::OK();
  480. }
  481. DWORD replace_error = ::GetLastError();
  482. // In the case of FILE_ERROR_NOT_FOUND from ReplaceFile, it is likely
  483. // that |to_path| does not exist. In this case, the more relevant error
  484. // comes from the call to MoveFile.
  485. if (replace_error == ERROR_FILE_NOT_FOUND ||
  486. replace_error == ERROR_PATH_NOT_FOUND) {
  487. return WindowsError(src, move_error);
  488. } else {
  489. return WindowsError(src, replace_error);
  490. }
  491. }
  492. Status LockFile(const std::string& fname, FileLock** lock) override {
  493. *lock = nullptr;
  494. Status result;
  495. ScopedHandle handle = ::CreateFileA(
  496. fname.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
  497. /*lpSecurityAttributes=*/nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
  498. nullptr);
  499. if (!handle.is_valid()) {
  500. result = WindowsError(fname, ::GetLastError());
  501. } else if (!LockOrUnlock(handle.get(), true)) {
  502. result = WindowsError("lock " + fname, ::GetLastError());
  503. } else {
  504. *lock = new WindowsFileLock(std::move(handle), std::move(fname));
  505. }
  506. return result;
  507. }
  508. Status UnlockFile(FileLock* lock) override {
  509. std::unique_ptr<WindowsFileLock> my_lock(
  510. reinterpret_cast<WindowsFileLock*>(lock));
  511. Status result;
  512. if (!LockOrUnlock(my_lock->handle().get(), false)) {
  513. result = WindowsError("unlock", ::GetLastError());
  514. }
  515. return result;
  516. }
  517. void Schedule(void (*function)(void*), void* arg) override;
  518. void StartThread(void (*function)(void* arg), void* arg) override {
  519. std::thread t(function, arg);
  520. t.detach();
  521. }
  522. Status GetTestDirectory(std::string* result) override {
  523. const char* env = getenv("TEST_TMPDIR");
  524. if (env && env[0] != '\0') {
  525. *result = env;
  526. return Status::OK();
  527. }
  528. char tmp_path[MAX_PATH];
  529. if (!GetTempPathA(ARRAYSIZE(tmp_path), tmp_path)) {
  530. return WindowsError("GetTempPath", ::GetLastError());
  531. }
  532. std::stringstream ss;
  533. ss << tmp_path << "leveldbtest-" << std::this_thread::get_id();
  534. *result = ss.str();
  535. // Directory may already exist
  536. CreateDir(*result);
  537. return Status::OK();
  538. }
  539. Status NewLogger(const std::string& filename, Logger** result) override {
  540. std::FILE* fp = std::fopen(filename.c_str(), "w");
  541. if (fp == nullptr) {
  542. *result = nullptr;
  543. return WindowsError("NewLogger", ::GetLastError());
  544. } else {
  545. *result = new WindowsLogger(fp);
  546. return Status::OK();
  547. }
  548. }
  549. uint64_t NowMicros() override {
  550. // GetSystemTimeAsFileTime typically has a resolution of 10-20 msec.
  551. // TODO(cmumford): Switch to GetSystemTimePreciseAsFileTime which is
  552. // available in Windows 8 and later.
  553. FILETIME ft;
  554. ::GetSystemTimeAsFileTime(&ft);
  555. // Each tick represents a 100-nanosecond intervals since January 1, 1601
  556. // (UTC).
  557. uint64_t num_ticks =
  558. (static_cast<uint64_t>(ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
  559. return num_ticks / 10;
  560. }
  561. void SleepForMicroseconds(int micros) override {
  562. std::this_thread::sleep_for(std::chrono::microseconds(micros));
  563. }
  564. private:
  565. // BGThread() is the body of the background thread
  566. void BGThread();
  567. std::mutex mu_;
  568. std::condition_variable bgsignal_;
  569. bool started_bgthread_;
  570. // Entry per Schedule() call
  571. struct BGItem {
  572. void* arg;
  573. void (*function)(void*);
  574. };
  575. typedef std::deque<BGItem> BGQueue;
  576. BGQueue queue_;
  577. Limiter mmap_limiter_;
  578. };
  579. // Return the maximum number of concurrent mmaps.
  580. int MaxMmaps() {
  581. if (g_mmap_limit >= 0) {
  582. return g_mmap_limit;
  583. }
  584. // Up to 1000 mmaps for 64-bit binaries; none for smaller pointer sizes.
  585. g_mmap_limit = sizeof(void*) >= 8 ? 1000 : 0;
  586. return g_mmap_limit;
  587. }
  588. WindowsEnv::WindowsEnv()
  589. : started_bgthread_(false), mmap_limiter_(MaxMmaps()) {}
  590. void WindowsEnv::Schedule(void (*function)(void*), void* arg) {
  591. std::lock_guard<std::mutex> guard(mu_);
  592. // Start background thread if necessary
  593. if (!started_bgthread_) {
  594. started_bgthread_ = true;
  595. std::thread t(&WindowsEnv::BGThread, this);
  596. t.detach();
  597. }
  598. // If the queue is currently empty, the background thread may currently be
  599. // waiting.
  600. if (queue_.empty()) {
  601. bgsignal_.notify_one();
  602. }
  603. // Add to priority queue
  604. queue_.push_back(BGItem());
  605. queue_.back().function = function;
  606. queue_.back().arg = arg;
  607. }
  608. void WindowsEnv::BGThread() {
  609. while (true) {
  610. // Wait until there is an item that is ready to run
  611. std::unique_lock<std::mutex> lk(mu_);
  612. bgsignal_.wait(lk, [this] { return !queue_.empty(); });
  613. void (*function)(void*) = queue_.front().function;
  614. void* arg = queue_.front().arg;
  615. queue_.pop_front();
  616. lk.unlock();
  617. (*function)(arg);
  618. }
  619. }
  620. } // namespace
  621. static std::once_flag once;
  622. static Env* default_env;
  623. static void InitDefaultEnv() { default_env = new WindowsEnv(); }
  624. void EnvWindowsTestHelper::SetReadOnlyMMapLimit(int limit) {
  625. assert(default_env == nullptr);
  626. g_mmap_limit = limit;
  627. }
  628. void EnvWindowsTestHelper::RelaxFilePermissions() {
  629. assert(default_env == nullptr);
  630. g_relax_permissions = true;
  631. }
  632. Env* Env::Default() {
  633. std::call_once(once, InitDefaultEnv);
  634. return default_env;
  635. }
  636. } // namespace leveldb