小组成员:谢瑞阳、徐翔宇
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.

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