]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/port/win/port_win.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / port / win / port_win.cc
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
10 #if defined(OS_WIN)
11
12 #include "port/win/port_win.h"
13
14 #include <assert.h>
15 #include <io.h>
16 #include <rpc.h>
17 #include <stdio.h>
18 #include <string.h>
19
20 #include <chrono>
21 #include <cstdlib>
22 #include <exception>
23 #include <memory>
24
25 #include "port/port_dirent.h"
26 #include "port/sys_time.h"
27
28 #ifdef ROCKSDB_WINDOWS_UTF8_FILENAMES
29 // utf8 <-> utf16
30 #include <codecvt>
31 #include <locale>
32 #include <string>
33 #endif
34
35 #include "logging/logging.h"
36
37 namespace ROCKSDB_NAMESPACE {
38
39 extern const bool kDefaultToAdaptiveMutex = false;
40
41 namespace port {
42
43 #ifdef ROCKSDB_WINDOWS_UTF8_FILENAMES
44 std::string utf16_to_utf8(const std::wstring& utf16) {
45 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert;
46 return convert.to_bytes(utf16);
47 }
48
49 std::wstring utf8_to_utf16(const std::string& utf8) {
50 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
51 return converter.from_bytes(utf8);
52 }
53 #endif
54
55 void GetTimeOfDay(TimeVal* tv, struct timezone* /* tz */) {
56 std::chrono::microseconds usNow(
57 std::chrono::duration_cast<std::chrono::microseconds>(
58 std::chrono::system_clock::now().time_since_epoch()));
59
60 std::chrono::seconds secNow(
61 std::chrono::duration_cast<std::chrono::seconds>(usNow));
62
63 tv->tv_sec = static_cast<long>(secNow.count());
64 tv->tv_usec = static_cast<long>(
65 usNow.count() -
66 std::chrono::duration_cast<std::chrono::microseconds>(secNow).count());
67 }
68
69 Mutex::~Mutex() {}
70
71 CondVar::~CondVar() {}
72
73 void CondVar::Wait() {
74 // Caller must ensure that mutex is held prior to calling this method
75 std::unique_lock<std::mutex> lk(mu_->getLock(), std::adopt_lock);
76 #ifndef NDEBUG
77 mu_->locked_ = false;
78 #endif
79 cv_.wait(lk);
80 #ifndef NDEBUG
81 mu_->locked_ = true;
82 #endif
83 // Release ownership of the lock as we don't want it to be unlocked when
84 // it goes out of scope (as we adopted the lock and didn't lock it ourselves)
85 lk.release();
86 }
87
88 bool CondVar::TimedWait(uint64_t abs_time_us) {
89 // MSVC++ library implements wait_until in terms of wait_for so
90 // we need to convert absolute wait into relative wait.
91 std::chrono::microseconds usAbsTime(abs_time_us);
92
93 std::chrono::microseconds usNow(
94 std::chrono::duration_cast<std::chrono::microseconds>(
95 std::chrono::system_clock::now().time_since_epoch()));
96 std::chrono::microseconds relTimeUs = (usAbsTime > usNow)
97 ? (usAbsTime - usNow)
98 : std::chrono::microseconds::zero();
99
100 // Caller must ensure that mutex is held prior to calling this method
101 std::unique_lock<std::mutex> lk(mu_->getLock(), std::adopt_lock);
102
103 // Work around https://github.com/microsoft/STL/issues/369
104 #if defined(_MSC_VER) && \
105 (!defined(_MSVC_STL_UPDATE) || _MSVC_STL_UPDATE < 202008L)
106 if (relTimeUs == std::chrono::microseconds::zero()) {
107 lk.unlock();
108 lk.lock();
109 }
110 #endif
111 #ifndef NDEBUG
112 mu_->locked_ = false;
113 #endif
114 std::cv_status cvStatus = cv_.wait_for(lk, relTimeUs);
115 #ifndef NDEBUG
116 mu_->locked_ = true;
117 #endif
118 // Release ownership of the lock as we don't want it to be unlocked when
119 // it goes out of scope (as we adopted the lock and didn't lock it ourselves)
120 lk.release();
121
122 if (cvStatus == std::cv_status::timeout) {
123 return true;
124 }
125
126 return false;
127 }
128
129 void CondVar::Signal() { cv_.notify_one(); }
130
131 void CondVar::SignalAll() { cv_.notify_all(); }
132
133 int PhysicalCoreID() { return GetCurrentProcessorNumber(); }
134
135 void InitOnce(OnceType* once, void (*initializer)()) {
136 std::call_once(once->flag_, initializer);
137 }
138
139 // Private structure, exposed only by pointer
140 struct DIR {
141 HANDLE handle_;
142 bool firstread_;
143 RX_WIN32_FIND_DATA data_;
144 dirent entry_;
145
146 DIR() : handle_(INVALID_HANDLE_VALUE), firstread_(true) {}
147
148 DIR(const DIR&) = delete;
149 DIR& operator=(const DIR&) = delete;
150
151 ~DIR() {
152 if (INVALID_HANDLE_VALUE != handle_) {
153 ::FindClose(handle_);
154 }
155 }
156 };
157
158 DIR* opendir(const char* name) {
159 if (!name || *name == 0) {
160 errno = ENOENT;
161 return nullptr;
162 }
163
164 std::string pattern(name);
165 pattern.append("\\").append("*");
166
167 std::unique_ptr<DIR> dir(new DIR);
168
169 dir->handle_ =
170 RX_FindFirstFileEx(RX_FN(pattern).c_str(),
171 FindExInfoBasic, // Do not want alternative name
172 &dir->data_, FindExSearchNameMatch,
173 NULL, // lpSearchFilter
174 0);
175
176 if (dir->handle_ == INVALID_HANDLE_VALUE) {
177 return nullptr;
178 }
179
180 RX_FILESTRING x(dir->data_.cFileName, RX_FNLEN(dir->data_.cFileName));
181 strcpy_s(dir->entry_.d_name, sizeof(dir->entry_.d_name), FN_TO_RX(x).c_str());
182
183 return dir.release();
184 }
185
186 struct dirent* readdir(DIR* dirp) {
187 if (!dirp || dirp->handle_ == INVALID_HANDLE_VALUE) {
188 errno = EBADF;
189 return nullptr;
190 }
191
192 if (dirp->firstread_) {
193 dirp->firstread_ = false;
194 return &dirp->entry_;
195 }
196
197 auto ret = RX_FindNextFile(dirp->handle_, &dirp->data_);
198
199 if (ret == 0) {
200 return nullptr;
201 }
202
203 RX_FILESTRING x(dirp->data_.cFileName, RX_FNLEN(dirp->data_.cFileName));
204 strcpy_s(dirp->entry_.d_name, sizeof(dirp->entry_.d_name),
205 FN_TO_RX(x).c_str());
206
207 return &dirp->entry_;
208 }
209
210 int closedir(DIR* dirp) {
211 delete dirp;
212 return 0;
213 }
214
215 int truncate(const char* path, int64_t length) {
216 if (path == nullptr) {
217 errno = EFAULT;
218 return -1;
219 }
220 return ROCKSDB_NAMESPACE::port::Truncate(path, length);
221 }
222
223 int Truncate(std::string path, int64_t len) {
224 if (len < 0) {
225 errno = EINVAL;
226 return -1;
227 }
228
229 HANDLE hFile =
230 RX_CreateFile(RX_FN(path).c_str(), GENERIC_READ | GENERIC_WRITE,
231 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
232 NULL, // Security attrs
233 OPEN_EXISTING, // Truncate existing file only
234 FILE_ATTRIBUTE_NORMAL, NULL);
235
236 if (INVALID_HANDLE_VALUE == hFile) {
237 auto lastError = GetLastError();
238 if (lastError == ERROR_FILE_NOT_FOUND) {
239 errno = ENOENT;
240 } else if (lastError == ERROR_ACCESS_DENIED) {
241 errno = EACCES;
242 } else {
243 errno = EIO;
244 }
245 return -1;
246 }
247
248 int result = 0;
249 FILE_END_OF_FILE_INFO end_of_file;
250 end_of_file.EndOfFile.QuadPart = len;
251
252 if (!SetFileInformationByHandle(hFile, FileEndOfFileInfo, &end_of_file,
253 sizeof(FILE_END_OF_FILE_INFO))) {
254 errno = EIO;
255 result = -1;
256 }
257
258 CloseHandle(hFile);
259 return result;
260 }
261
262 void Crash(const std::string& srcfile, int srcline) {
263 fprintf(stdout, "Crashing at %s:%d\n", srcfile.c_str(), srcline);
264 fflush(stdout);
265 abort();
266 }
267
268 int GetMaxOpenFiles() { return -1; }
269
270 // Assume 4KB page size
271 const size_t kPageSize = 4U * 1024U;
272
273 void SetCpuPriority(ThreadId id, CpuPriority priority) {
274 // Not supported
275 (void)id;
276 (void)priority;
277 }
278
279 int64_t GetProcessID() { return GetCurrentProcessId(); }
280
281 bool GenerateRfcUuid(std::string* output) {
282 UUID uuid;
283 UuidCreateSequential(&uuid);
284
285 RPC_CSTR rpc_str;
286 auto status = UuidToStringA(&uuid, &rpc_str);
287 if (status != RPC_S_OK) {
288 return false;
289 }
290
291 // rpc_str is nul-terminated
292 *output = reinterpret_cast<char*>(rpc_str);
293
294 status = RpcStringFreeA(&rpc_str);
295 assert(status == RPC_S_OK);
296
297 return true;
298 }
299
300 } // namespace port
301 } // namespace ROCKSDB_NAMESPACE
302
303 #endif