port_win.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #if !defined(OS_WIN) && !defined(WIN32) && !defined(_WIN32)
  10. #error Windows Specific Code
  11. #endif
  12. #include "port/win/port_win.h"
  13. #include <io.h>
  14. #include "port/port_dirent.h"
  15. #include "port/sys_time.h"
  16. #include <cstdlib>
  17. #include <stdio.h>
  18. #include <assert.h>
  19. #include <string.h>
  20. #include <memory>
  21. #include <exception>
  22. #include <chrono>
  23. #ifdef ROCKSDB_WINDOWS_UTF8_FILENAMES
  24. // utf8 <-> utf16
  25. #include <string>
  26. #include <locale>
  27. #include <codecvt>
  28. #endif
  29. #include "logging/logging.h"
  30. namespace ROCKSDB_NAMESPACE {
  31. extern const bool kDefaultToAdaptiveMutex = false;
  32. namespace port {
  33. #ifdef ROCKSDB_WINDOWS_UTF8_FILENAMES
  34. std::string utf16_to_utf8(const std::wstring& utf16) {
  35. std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> convert;
  36. return convert.to_bytes(utf16);
  37. }
  38. std::wstring utf8_to_utf16(const std::string& utf8) {
  39. std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
  40. return converter.from_bytes(utf8);
  41. }
  42. #endif
  43. void gettimeofday(struct timeval* tv, struct timezone* /* tz */) {
  44. using namespace std::chrono;
  45. microseconds usNow(
  46. duration_cast<microseconds>(system_clock::now().time_since_epoch()));
  47. seconds secNow(duration_cast<seconds>(usNow));
  48. tv->tv_sec = static_cast<long>(secNow.count());
  49. tv->tv_usec = static_cast<long>(usNow.count() -
  50. duration_cast<microseconds>(secNow).count());
  51. }
  52. Mutex::~Mutex() {}
  53. CondVar::~CondVar() {}
  54. void CondVar::Wait() {
  55. // Caller must ensure that mutex is held prior to calling this method
  56. std::unique_lock<std::mutex> lk(mu_->getLock(), std::adopt_lock);
  57. #ifndef NDEBUG
  58. mu_->locked_ = false;
  59. #endif
  60. cv_.wait(lk);
  61. #ifndef NDEBUG
  62. mu_->locked_ = true;
  63. #endif
  64. // Release ownership of the lock as we don't want it to be unlocked when
  65. // it goes out of scope (as we adopted the lock and didn't lock it ourselves)
  66. lk.release();
  67. }
  68. bool CondVar::TimedWait(uint64_t abs_time_us) {
  69. using namespace std::chrono;
  70. // MSVC++ library implements wait_until in terms of wait_for so
  71. // we need to convert absolute wait into relative wait.
  72. microseconds usAbsTime(abs_time_us);
  73. microseconds usNow(
  74. duration_cast<microseconds>(system_clock::now().time_since_epoch()));
  75. microseconds relTimeUs =
  76. (usAbsTime > usNow) ? (usAbsTime - usNow) : microseconds::zero();
  77. // Caller must ensure that mutex is held prior to calling this method
  78. std::unique_lock<std::mutex> lk(mu_->getLock(), std::adopt_lock);
  79. #ifndef NDEBUG
  80. mu_->locked_ = false;
  81. #endif
  82. std::cv_status cvStatus = cv_.wait_for(lk, relTimeUs);
  83. #ifndef NDEBUG
  84. mu_->locked_ = true;
  85. #endif
  86. // Release ownership of the lock as we don't want it to be unlocked when
  87. // it goes out of scope (as we adopted the lock and didn't lock it ourselves)
  88. lk.release();
  89. if (cvStatus == std::cv_status::timeout) {
  90. return true;
  91. }
  92. return false;
  93. }
  94. void CondVar::Signal() { cv_.notify_one(); }
  95. void CondVar::SignalAll() { cv_.notify_all(); }
  96. int PhysicalCoreID() { return GetCurrentProcessorNumber(); }
  97. void InitOnce(OnceType* once, void (*initializer)()) {
  98. std::call_once(once->flag_, initializer);
  99. }
  100. // Private structure, exposed only by pointer
  101. struct DIR {
  102. HANDLE handle_;
  103. bool firstread_;
  104. RX_WIN32_FIND_DATA data_;
  105. dirent entry_;
  106. DIR() : handle_(INVALID_HANDLE_VALUE),
  107. firstread_(true) {}
  108. DIR(const DIR&) = delete;
  109. DIR& operator=(const DIR&) = delete;
  110. ~DIR() {
  111. if (INVALID_HANDLE_VALUE != handle_) {
  112. ::FindClose(handle_);
  113. }
  114. }
  115. };
  116. DIR* opendir(const char* name) {
  117. if (!name || *name == 0) {
  118. errno = ENOENT;
  119. return nullptr;
  120. }
  121. std::string pattern(name);
  122. pattern.append("\\").append("*");
  123. std::unique_ptr<DIR> dir(new DIR);
  124. dir->handle_ = RX_FindFirstFileEx(RX_FN(pattern).c_str(),
  125. FindExInfoBasic, // Do not want alternative name
  126. &dir->data_,
  127. FindExSearchNameMatch,
  128. NULL, // lpSearchFilter
  129. 0);
  130. if (dir->handle_ == INVALID_HANDLE_VALUE) {
  131. return nullptr;
  132. }
  133. RX_FILESTRING x(dir->data_.cFileName, RX_FNLEN(dir->data_.cFileName));
  134. strcpy_s(dir->entry_.d_name, sizeof(dir->entry_.d_name),
  135. FN_TO_RX(x).c_str());
  136. return dir.release();
  137. }
  138. struct dirent* readdir(DIR* dirp) {
  139. if (!dirp || dirp->handle_ == INVALID_HANDLE_VALUE) {
  140. errno = EBADF;
  141. return nullptr;
  142. }
  143. if (dirp->firstread_) {
  144. dirp->firstread_ = false;
  145. return &dirp->entry_;
  146. }
  147. auto ret = RX_FindNextFile(dirp->handle_, &dirp->data_);
  148. if (ret == 0) {
  149. return nullptr;
  150. }
  151. RX_FILESTRING x(dirp->data_.cFileName, RX_FNLEN(dirp->data_.cFileName));
  152. strcpy_s(dirp->entry_.d_name, sizeof(dirp->entry_.d_name),
  153. FN_TO_RX(x).c_str());
  154. return &dirp->entry_;
  155. }
  156. int closedir(DIR* dirp) {
  157. delete dirp;
  158. return 0;
  159. }
  160. int truncate(const char* path, int64_t length) {
  161. if (path == nullptr) {
  162. errno = EFAULT;
  163. return -1;
  164. }
  165. return ROCKSDB_NAMESPACE::port::Truncate(path, length);
  166. }
  167. int Truncate(std::string path, int64_t len) {
  168. if (len < 0) {
  169. errno = EINVAL;
  170. return -1;
  171. }
  172. HANDLE hFile =
  173. RX_CreateFile(RX_FN(path).c_str(), GENERIC_READ | GENERIC_WRITE,
  174. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  175. NULL, // Security attrs
  176. OPEN_EXISTING, // Truncate existing file only
  177. FILE_ATTRIBUTE_NORMAL, NULL);
  178. if (INVALID_HANDLE_VALUE == hFile) {
  179. auto lastError = GetLastError();
  180. if (lastError == ERROR_FILE_NOT_FOUND) {
  181. errno = ENOENT;
  182. } else if (lastError == ERROR_ACCESS_DENIED) {
  183. errno = EACCES;
  184. } else {
  185. errno = EIO;
  186. }
  187. return -1;
  188. }
  189. int result = 0;
  190. FILE_END_OF_FILE_INFO end_of_file;
  191. end_of_file.EndOfFile.QuadPart = len;
  192. if (!SetFileInformationByHandle(hFile, FileEndOfFileInfo, &end_of_file,
  193. sizeof(FILE_END_OF_FILE_INFO))) {
  194. errno = EIO;
  195. result = -1;
  196. }
  197. CloseHandle(hFile);
  198. return result;
  199. }
  200. void Crash(const std::string& srcfile, int srcline) {
  201. fprintf(stdout, "Crashing at %s:%d\n", srcfile.c_str(), srcline);
  202. fflush(stdout);
  203. abort();
  204. }
  205. int GetMaxOpenFiles() { return -1; }
  206. // Assume 4KB page size
  207. const size_t kPageSize = 4U * 1024U;
  208. } // namespace port
  209. } // namespace ROCKSDB_NAMESPACE