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).
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.
12 #include "port/win/port_win.h"
25 #include "port/port_dirent.h"
26 #include "port/sys_time.h"
28 #ifdef ROCKSDB_WINDOWS_UTF8_FILENAMES
35 #include "logging/logging.h"
37 namespace ROCKSDB_NAMESPACE
{
39 extern const bool kDefaultToAdaptiveMutex
= false;
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
);
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
);
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()));
60 std::chrono::seconds
secNow(
61 std::chrono::duration_cast
<std::chrono::seconds
>(usNow
));
63 tv
->tv_sec
= static_cast<long>(secNow
.count());
64 tv
->tv_usec
= static_cast<long>(
66 std::chrono::duration_cast
<std::chrono::microseconds
>(secNow
).count());
71 CondVar::~CondVar() {}
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
);
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)
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
);
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
)
98 : std::chrono::microseconds::zero();
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
);
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()) {
112 mu_
->locked_
= false;
114 std::cv_status cvStatus
= cv_
.wait_for(lk
, relTimeUs
);
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)
122 if (cvStatus
== std::cv_status::timeout
) {
129 void CondVar::Signal() { cv_
.notify_one(); }
131 void CondVar::SignalAll() { cv_
.notify_all(); }
133 int PhysicalCoreID() { return GetCurrentProcessorNumber(); }
135 void InitOnce(OnceType
* once
, void (*initializer
)()) {
136 std::call_once(once
->flag_
, initializer
);
139 // Private structure, exposed only by pointer
143 RX_WIN32_FIND_DATA data_
;
146 DIR() : handle_(INVALID_HANDLE_VALUE
), firstread_(true) {}
148 DIR(const DIR&) = delete;
149 DIR& operator=(const DIR&) = delete;
152 if (INVALID_HANDLE_VALUE
!= handle_
) {
153 ::FindClose(handle_
);
158 DIR* opendir(const char* name
) {
159 if (!name
|| *name
== 0) {
164 std::string
pattern(name
);
165 pattern
.append("\\").append("*");
167 std::unique_ptr
<DIR> dir(new DIR);
170 RX_FindFirstFileEx(RX_FN(pattern
).c_str(),
171 FindExInfoBasic
, // Do not want alternative name
172 &dir
->data_
, FindExSearchNameMatch
,
173 NULL
, // lpSearchFilter
176 if (dir
->handle_
== INVALID_HANDLE_VALUE
) {
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());
183 return dir
.release();
186 struct dirent
* readdir(DIR* dirp
) {
187 if (!dirp
|| dirp
->handle_
== INVALID_HANDLE_VALUE
) {
192 if (dirp
->firstread_
) {
193 dirp
->firstread_
= false;
194 return &dirp
->entry_
;
197 auto ret
= RX_FindNextFile(dirp
->handle_
, &dirp
->data_
);
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());
207 return &dirp
->entry_
;
210 int closedir(DIR* dirp
) {
215 int truncate(const char* path
, int64_t length
) {
216 if (path
== nullptr) {
220 return ROCKSDB_NAMESPACE::port::Truncate(path
, length
);
223 int Truncate(std::string path
, int64_t len
) {
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
);
236 if (INVALID_HANDLE_VALUE
== hFile
) {
237 auto lastError
= GetLastError();
238 if (lastError
== ERROR_FILE_NOT_FOUND
) {
240 } else if (lastError
== ERROR_ACCESS_DENIED
) {
249 FILE_END_OF_FILE_INFO end_of_file
;
250 end_of_file
.EndOfFile
.QuadPart
= len
;
252 if (!SetFileInformationByHandle(hFile
, FileEndOfFileInfo
, &end_of_file
,
253 sizeof(FILE_END_OF_FILE_INFO
))) {
262 void Crash(const std::string
& srcfile
, int srcline
) {
263 fprintf(stdout
, "Crashing at %s:%d\n", srcfile
.c_str(), srcline
);
268 int GetMaxOpenFiles() { return -1; }
270 // Assume 4KB page size
271 const size_t kPageSize
= 4U * 1024U;
273 void SetCpuPriority(ThreadId id
, CpuPriority priority
) {
279 int64_t GetProcessID() { return GetCurrentProcessId(); }
281 bool GenerateRfcUuid(std::string
* output
) {
283 UuidCreateSequential(&uuid
);
286 auto status
= UuidToStringA(&uuid
, &rpc_str
);
287 if (status
!= RPC_S_OK
) {
291 // rpc_str is nul-terminated
292 *output
= reinterpret_cast<char*>(rpc_str
);
294 status
= RpcStringFreeA(&rpc_str
);
295 assert(status
== RPC_S_OK
);
301 } // namespace ROCKSDB_NAMESPACE