]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/port/win/env_win.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / rocksdb / port / win / env_win.cc
CommitLineData
7c673cae 1// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
11fdf7f2
TL
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).
7c673cae
FG
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#include "port/win/env_win.h"
11#include "port/win/win_thread.h"
12#include <algorithm>
13#include <ctime>
14#include <thread>
15
16#include <errno.h>
17#include <process.h> // _getpid
18#include <io.h> // _access
19#include <direct.h> // _rmdir, _mkdir, _getcwd
20#include <sys/types.h>
21#include <sys/stat.h>
22
23#include "rocksdb/env.h"
24#include "rocksdb/slice.h"
25
26#include "port/port.h"
494da23a 27#include "port/port_dirent.h"
7c673cae
FG
28#include "port/win/win_logger.h"
29#include "port/win/io_win.h"
30
31#include "monitoring/iostats_context_imp.h"
32
33#include "monitoring/thread_status_updater.h"
34#include "monitoring/thread_status_util.h"
35
11fdf7f2
TL
36#include <rpc.h> // for uuid generation
37#include <windows.h>
38#include <shlwapi.h>
39#include "strsafe.h"
40
41#include <algorithm>
7c673cae 42
f67539c2 43namespace ROCKSDB_NAMESPACE {
7c673cae
FG
44
45ThreadStatusUpdater* CreateThreadStatusUpdater() {
46 return new ThreadStatusUpdater();
47}
48
49namespace {
50
494da23a
TL
51// Sector size used when physical sector size cannot be obtained from device.
52static const size_t kSectorSize = 512;
11fdf7f2 53
7c673cae
FG
54// RAII helpers for HANDLEs
55const auto CloseHandleFunc = [](HANDLE h) { ::CloseHandle(h); };
56typedef std::unique_ptr<void, decltype(CloseHandleFunc)> UniqueCloseHandlePtr;
57
11fdf7f2
TL
58const auto FindCloseFunc = [](HANDLE h) { ::FindClose(h); };
59typedef std::unique_ptr<void, decltype(FindCloseFunc)> UniqueFindClosePtr;
60
7c673cae
FG
61void WinthreadCall(const char* label, std::error_code result) {
62 if (0 != result.value()) {
63 fprintf(stderr, "pthread %s: %s\n", label, strerror(result.value()));
64 abort();
65 }
66}
67
68}
69
70namespace port {
71
72WinEnvIO::WinEnvIO(Env* hosted_env)
494da23a 73 : hosted_env_(hosted_env),
11fdf7f2 74 page_size_(4 * 1024),
7c673cae
FG
75 allocation_granularity_(page_size_),
76 perf_counter_frequency_(0),
494da23a 77 nano_seconds_per_period_(0),
7c673cae
FG
78 GetSystemTimePreciseAsFileTime_(NULL) {
79
80 SYSTEM_INFO sinfo;
81 GetSystemInfo(&sinfo);
82
83 page_size_ = sinfo.dwPageSize;
84 allocation_granularity_ = sinfo.dwAllocationGranularity;
85
86 {
87 LARGE_INTEGER qpf;
11fdf7f2
TL
88 BOOL ret __attribute__((__unused__));
89 ret = QueryPerformanceFrequency(&qpf);
7c673cae
FG
90 assert(ret == TRUE);
91 perf_counter_frequency_ = qpf.QuadPart;
494da23a
TL
92
93 if (std::nano::den % perf_counter_frequency_ == 0) {
94 nano_seconds_per_period_ = std::nano::den / perf_counter_frequency_;
95 }
7c673cae
FG
96 }
97
98 HMODULE module = GetModuleHandle("kernel32.dll");
99 if (module != NULL) {
494da23a
TL
100 GetSystemTimePreciseAsFileTime_ =
101 (FnGetSystemTimePreciseAsFileTime)GetProcAddress(
102 module, "GetSystemTimePreciseAsFileTime");
7c673cae
FG
103 }
104}
105
106WinEnvIO::~WinEnvIO() {
107}
108
109Status WinEnvIO::DeleteFile(const std::string& fname) {
110 Status result;
111
494da23a
TL
112 BOOL ret = RX_DeleteFile(RX_FN(fname).c_str());
113
11fdf7f2
TL
114 if(!ret) {
115 auto lastError = GetLastError();
116 result = IOErrorFromWindowsError("Failed to delete: " + fname,
494da23a 117 lastError);
7c673cae
FG
118 }
119
120 return result;
121}
122
11fdf7f2
TL
123Status WinEnvIO::Truncate(const std::string& fname, size_t size) {
124 Status s;
f67539c2 125 int result = ROCKSDB_NAMESPACE::port::Truncate(fname, size);
11fdf7f2
TL
126 if (result != 0) {
127 s = IOError("Failed to truncate: " + fname, errno);
128 }
129 return s;
130}
131
7c673cae
FG
132Status WinEnvIO::GetCurrentTime(int64_t* unix_time) {
133 time_t time = std::time(nullptr);
134 if (time == (time_t)(-1)) {
135 return Status::NotSupported("Failed to get time");
136 }
137
138 *unix_time = time;
139 return Status::OK();
140}
141
142Status WinEnvIO::NewSequentialFile(const std::string& fname,
494da23a
TL
143 std::unique_ptr<SequentialFile>* result,
144 const EnvOptions& options) {
7c673cae
FG
145 Status s;
146
147 result->reset();
148
149 // Corruption test needs to rename and delete files of these kind
150 // while they are still open with another handle. For that reason we
151 // allow share_write and delete(allows rename).
152 HANDLE hFile = INVALID_HANDLE_VALUE;
153
154 DWORD fileFlags = FILE_ATTRIBUTE_READONLY;
155
156 if (options.use_direct_reads && !options.use_mmap_reads) {
157 fileFlags |= FILE_FLAG_NO_BUFFERING;
158 }
159
160 {
161 IOSTATS_TIMER_GUARD(open_nanos);
494da23a
TL
162 hFile = RX_CreateFile(
163 RX_FN(fname).c_str(), GENERIC_READ,
164 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
165 OPEN_EXISTING, // Original fopen mode is "rb"
166 fileFlags, NULL);
7c673cae
FG
167 }
168
169 if (INVALID_HANDLE_VALUE == hFile) {
170 auto lastError = GetLastError();
171 s = IOErrorFromWindowsError("Failed to open NewSequentialFile" + fname,
494da23a 172 lastError);
7c673cae
FG
173 } else {
174 result->reset(new WinSequentialFile(fname, hFile, options));
175 }
176 return s;
177}
178
179Status WinEnvIO::NewRandomAccessFile(const std::string& fname,
494da23a
TL
180 std::unique_ptr<RandomAccessFile>* result,
181 const EnvOptions& options) {
7c673cae
FG
182 result->reset();
183 Status s;
184
185 // Open the file for read-only random access
186 // Random access is to disable read-ahead as the system reads too much data
187 DWORD fileFlags = FILE_ATTRIBUTE_READONLY;
188
189 if (options.use_direct_reads && !options.use_mmap_reads) {
190 fileFlags |= FILE_FLAG_NO_BUFFERING;
191 } else {
192 fileFlags |= FILE_FLAG_RANDOM_ACCESS;
193 }
194
195 /// Shared access is necessary for corruption test to pass
196 // almost all tests would work with a possible exception of fault_injection
197 HANDLE hFile = 0;
198 {
199 IOSTATS_TIMER_GUARD(open_nanos);
494da23a
TL
200 hFile = RX_CreateFile(
201 RX_FN(fname).c_str(), GENERIC_READ,
202 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
203 NULL, OPEN_EXISTING, fileFlags, NULL);
7c673cae
FG
204 }
205
206 if (INVALID_HANDLE_VALUE == hFile) {
207 auto lastError = GetLastError();
208 return IOErrorFromWindowsError(
494da23a 209 "NewRandomAccessFile failed to Create/Open: " + fname, lastError);
7c673cae
FG
210 }
211
212 UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);
213
214 // CAUTION! This will map the entire file into the process address space
215 if (options.use_mmap_reads && sizeof(void*) >= 8) {
216 // Use mmap when virtual address-space is plentiful.
217 uint64_t fileSize;
218
219 s = GetFileSize(fname, &fileSize);
220
221 if (s.ok()) {
222 // Will not map empty files
223 if (fileSize == 0) {
224 return IOError(
494da23a 225 "NewRandomAccessFile failed to map empty file: " + fname, EINVAL);
7c673cae
FG
226 }
227
494da23a
TL
228 HANDLE hMap = RX_CreateFileMapping(hFile, NULL, PAGE_READONLY,
229 0, // At its present length
230 0,
231 NULL); // Mapping name
7c673cae
FG
232
233 if (!hMap) {
234 auto lastError = GetLastError();
235 return IOErrorFromWindowsError(
494da23a
TL
236 "Failed to create file mapping for NewRandomAccessFile: " + fname,
237 lastError);
7c673cae
FG
238 }
239
240 UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc);
241
242 const void* mapped_region =
243 MapViewOfFileEx(hMap, FILE_MAP_READ,
494da23a
TL
244 0, // High DWORD of access start
245 0, // Low DWORD
246 static_cast<SIZE_T>(fileSize),
247 NULL); // Let the OS choose the mapping
7c673cae
FG
248
249 if (!mapped_region) {
250 auto lastError = GetLastError();
251 return IOErrorFromWindowsError(
494da23a
TL
252 "Failed to MapViewOfFile for NewRandomAccessFile: " + fname,
253 lastError);
7c673cae
FG
254 }
255
256 result->reset(new WinMmapReadableFile(fname, hFile, hMap, mapped_region,
494da23a 257 static_cast<size_t>(fileSize)));
7c673cae
FG
258
259 mapGuard.release();
260 fileGuard.release();
261 }
262 } else {
494da23a
TL
263 result->reset(new WinRandomAccessFile(fname, hFile,
264 std::max(GetSectorSize(fname),
265 page_size_),
266 options));
7c673cae
FG
267 fileGuard.release();
268 }
269 return s;
270}
271
11fdf7f2 272Status WinEnvIO::OpenWritableFile(const std::string& fname,
494da23a
TL
273 std::unique_ptr<WritableFile>* result,
274 const EnvOptions& options,
275 bool reopen) {
11fdf7f2 276
7c673cae
FG
277 const size_t c_BufferCapacity = 64 * 1024;
278
279 EnvOptions local_options(options);
280
281 result->reset();
282 Status s;
283
284 DWORD fileFlags = FILE_ATTRIBUTE_NORMAL;
285
286 if (local_options.use_direct_writes && !local_options.use_mmap_writes) {
11fdf7f2 287 fileFlags = FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
7c673cae
FG
288 }
289
290 // Desired access. We are want to write only here but if we want to memory
291 // map
292 // the file then there is no write only mode so we have to create it
293 // Read/Write
294 // However, MapViewOfFile specifies only Write only
295 DWORD desired_access = GENERIC_WRITE;
296 DWORD shared_mode = FILE_SHARE_READ;
297
298 if (local_options.use_mmap_writes) {
299 desired_access |= GENERIC_READ;
300 } else {
301 // Adding this solely for tests to pass (fault_injection_test,
302 // wal_manager_test).
303 shared_mode |= (FILE_SHARE_WRITE | FILE_SHARE_DELETE);
304 }
305
11fdf7f2
TL
306 // This will always truncate the file
307 DWORD creation_disposition = CREATE_ALWAYS;
308 if (reopen) {
309 creation_disposition = OPEN_ALWAYS;
310 }
311
7c673cae
FG
312 HANDLE hFile = 0;
313 {
314 IOSTATS_TIMER_GUARD(open_nanos);
494da23a
TL
315 hFile = RX_CreateFile(
316 RX_FN(fname).c_str(),
317 desired_access, // Access desired
318 shared_mode,
319 NULL, // Security attributes
320 // Posix env says (reopen) ? (O_CREATE | O_APPEND) : O_CREAT | O_TRUNC
321 creation_disposition,
322 fileFlags, // Flags
323 NULL); // Template File
7c673cae
FG
324 }
325
326 if (INVALID_HANDLE_VALUE == hFile) {
327 auto lastError = GetLastError();
328 return IOErrorFromWindowsError(
494da23a 329 "Failed to create a NewWriteableFile: " + fname, lastError);
7c673cae
FG
330 }
331
11fdf7f2
TL
332 // We will start writing at the end, appending
333 if (reopen) {
334 LARGE_INTEGER zero_move;
335 zero_move.QuadPart = 0;
336 BOOL ret = SetFilePointerEx(hFile, zero_move, NULL, FILE_END);
337 if (!ret) {
338 auto lastError = GetLastError();
339 return IOErrorFromWindowsError(
494da23a
TL
340 "Failed to create a ReopenWritableFile move to the end: " + fname,
341 lastError);
11fdf7f2
TL
342 }
343 }
344
7c673cae
FG
345 if (options.use_mmap_writes) {
346 // We usually do not use mmmapping on SSD and thus we pass memory
347 // page_size
348 result->reset(new WinMmapFile(fname, hFile, page_size_,
494da23a 349 allocation_granularity_, local_options));
7c673cae
FG
350 } else {
351 // Here we want the buffer allocation to be aligned by the SSD page size
352 // and to be a multiple of it
494da23a
TL
353 result->reset(new WinWritableFile(fname, hFile,
354 std::max(GetSectorSize(fname),
355 GetPageSize()),
356 c_BufferCapacity, local_options));
7c673cae
FG
357 }
358 return s;
359}
360
361Status WinEnvIO::NewRandomRWFile(const std::string & fname,
494da23a
TL
362 std::unique_ptr<RandomRWFile>* result,
363 const EnvOptions & options) {
7c673cae
FG
364
365 Status s;
366
367 // Open the file for read-only random access
368 // Random access is to disable read-ahead as the system reads too much data
369 DWORD desired_access = GENERIC_READ | GENERIC_WRITE;
370 DWORD shared_mode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
11fdf7f2 371 DWORD creation_disposition = OPEN_EXISTING; // Fail if file does not exist
7c673cae
FG
372 DWORD file_flags = FILE_FLAG_RANDOM_ACCESS;
373
374 if (options.use_direct_reads && options.use_direct_writes) {
375 file_flags |= FILE_FLAG_NO_BUFFERING;
376 }
377
378 /// Shared access is necessary for corruption test to pass
379 // almost all tests would work with a possible exception of fault_injection
380 HANDLE hFile = 0;
381 {
382 IOSTATS_TIMER_GUARD(open_nanos);
383 hFile =
494da23a
TL
384 RX_CreateFile(RX_FN(fname).c_str(),
385 desired_access,
386 shared_mode,
387 NULL, // Security attributes
388 creation_disposition,
389 file_flags,
390 NULL);
7c673cae
FG
391 }
392
393 if (INVALID_HANDLE_VALUE == hFile) {
394 auto lastError = GetLastError();
395 return IOErrorFromWindowsError(
396 "NewRandomRWFile failed to Create/Open: " + fname, lastError);
397 }
398
399 UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);
494da23a
TL
400 result->reset(new WinRandomRWFile(fname, hFile,
401 std::max(GetSectorSize(fname),
402 GetPageSize()),
403 options));
11fdf7f2
TL
404 fileGuard.release();
405
406 return s;
407}
408
494da23a
TL
409Status WinEnvIO::NewMemoryMappedFileBuffer(
410 const std::string & fname,
411 std::unique_ptr<MemoryMappedFileBuffer>* result) {
11fdf7f2
TL
412 Status s;
413 result->reset();
414
415 DWORD fileFlags = FILE_ATTRIBUTE_READONLY;
416
417 HANDLE hFile = INVALID_HANDLE_VALUE;
418 {
419 IOSTATS_TIMER_GUARD(open_nanos);
494da23a
TL
420 hFile = RX_CreateFile(
421 RX_FN(fname).c_str(), GENERIC_READ | GENERIC_WRITE,
422 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
423 NULL,
424 OPEN_EXISTING, // Open only if it exists
425 fileFlags,
426 NULL);
11fdf7f2
TL
427 }
428
429 if (INVALID_HANDLE_VALUE == hFile) {
430 auto lastError = GetLastError();
494da23a
TL
431 s = IOErrorFromWindowsError(
432 "Failed to open NewMemoryMappedFileBuffer: " + fname, lastError);
11fdf7f2
TL
433 return s;
434 }
435 UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);
436
437 uint64_t fileSize = 0;
438 s = GetFileSize(fname, &fileSize);
439 if (!s.ok()) {
440 return s;
441 }
442 // Will not map empty files
443 if (fileSize == 0) {
494da23a
TL
444 return Status::NotSupported(
445 "NewMemoryMappedFileBuffer can not map zero length files: " + fname);
11fdf7f2
TL
446 }
447
448 // size_t is 32-bit with 32-bit builds
449 if (fileSize > std::numeric_limits<size_t>::max()) {
450 return Status::NotSupported(
494da23a
TL
451 "The specified file size does not fit into 32-bit memory addressing: "
452 + fname);
11fdf7f2
TL
453 }
454
494da23a
TL
455 HANDLE hMap = RX_CreateFileMapping(hFile, NULL, PAGE_READWRITE,
456 0, // Whole file at its present length
457 0,
458 NULL); // Mapping name
11fdf7f2
TL
459
460 if (!hMap) {
461 auto lastError = GetLastError();
462 return IOErrorFromWindowsError(
494da23a 463 "Failed to create file mapping for: " + fname, lastError);
11fdf7f2
TL
464 }
465 UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc);
466
467 void* base = MapViewOfFileEx(hMap, FILE_MAP_WRITE,
494da23a
TL
468 0, // High DWORD of access start
469 0, // Low DWORD
470 static_cast<SIZE_T>(fileSize),
471 NULL); // Let the OS choose the mapping
11fdf7f2
TL
472
473 if (!base) {
474 auto lastError = GetLastError();
475 return IOErrorFromWindowsError(
494da23a
TL
476 "Failed to MapViewOfFile for NewMemoryMappedFileBuffer: " + fname,
477 lastError);
11fdf7f2
TL
478 }
479
494da23a
TL
480 result->reset(new WinMemoryMappedBuffer(hFile, hMap, base,
481 static_cast<size_t>(fileSize)));
11fdf7f2
TL
482
483 mapGuard.release();
7c673cae
FG
484 fileGuard.release();
485
486 return s;
487}
488
489Status WinEnvIO::NewDirectory(const std::string& name,
494da23a 490 std::unique_ptr<Directory>* result) {
7c673cae
FG
491 Status s;
492 // Must be nullptr on failure
493 result->reset();
11fdf7f2 494
7c673cae 495 if (!DirExists(name)) {
11fdf7f2 496 s = IOErrorFromWindowsError(
494da23a 497 "open folder: " + name, ERROR_DIRECTORY);
11fdf7f2
TL
498 return s;
499 }
500
501 HANDLE handle = INVALID_HANDLE_VALUE;
502 // 0 - for access means read metadata
503 {
7c673cae 504 IOSTATS_TIMER_GUARD(open_nanos);
494da23a
TL
505 handle = RX_CreateFile(
506 RX_FN(name).c_str(), 0,
507 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
508 NULL,
509 OPEN_EXISTING,
510 FILE_FLAG_BACKUP_SEMANTICS, // make opening folders possible
511 NULL);
11fdf7f2
TL
512 }
513
514 if (INVALID_HANDLE_VALUE == handle) {
515 auto lastError = GetLastError();
494da23a 516 s = IOErrorFromWindowsError("open folder: " + name, lastError);
11fdf7f2 517 return s;
7c673cae 518 }
11fdf7f2
TL
519
520 result->reset(new WinDirectory(handle));
521
7c673cae
FG
522 return s;
523}
524
525Status WinEnvIO::FileExists(const std::string& fname) {
11fdf7f2
TL
526 Status s;
527 // TODO: This does not follow symbolic links at this point
528 // which is consistent with _access() impl on windows
529 // but can be added
530 WIN32_FILE_ATTRIBUTE_DATA attrs;
494da23a
TL
531 if (FALSE == RX_GetFileAttributesEx(RX_FN(fname).c_str(),
532 GetFileExInfoStandard, &attrs)) {
11fdf7f2
TL
533 auto lastError = GetLastError();
534 switch (lastError) {
535 case ERROR_ACCESS_DENIED:
536 case ERROR_NOT_FOUND:
537 case ERROR_FILE_NOT_FOUND:
538 case ERROR_PATH_NOT_FOUND:
539 s = Status::NotFound();
540 break;
541 default:
542 s = IOErrorFromWindowsError("Unexpected error for: " + fname,
494da23a 543 lastError);
11fdf7f2
TL
544 break;
545 }
546 }
547 return s;
7c673cae
FG
548}
549
550Status WinEnvIO::GetChildren(const std::string& dir,
494da23a 551 std::vector<std::string>* result) {
7c673cae 552
11fdf7f2 553 Status status;
7c673cae
FG
554 result->clear();
555 std::vector<std::string> output;
556
494da23a
TL
557 RX_WIN32_FIND_DATA data;
558 memset(&data, 0, sizeof(data));
11fdf7f2
TL
559 std::string pattern(dir);
560 pattern.append("\\").append("*");
7c673cae 561
494da23a
TL
562 HANDLE handle = RX_FindFirstFileEx(RX_FN(pattern).c_str(),
563 // Do not want alternative name
564 FindExInfoBasic,
565 &data,
566 FindExSearchNameMatch,
567 NULL, // lpSearchFilter
568 0);
7c673cae 569
11fdf7f2
TL
570 if (handle == INVALID_HANDLE_VALUE) {
571 auto lastError = GetLastError();
572 switch (lastError) {
573 case ERROR_NOT_FOUND:
574 case ERROR_ACCESS_DENIED:
575 case ERROR_FILE_NOT_FOUND:
576 case ERROR_PATH_NOT_FOUND:
577 status = Status::NotFound();
578 break;
579 default:
580 status = IOErrorFromWindowsError(
494da23a 581 "Failed to GetChhildren for: " + dir, lastError);
7c673cae 582 }
11fdf7f2 583 return status;
7c673cae
FG
584 }
585
11fdf7f2
TL
586 UniqueFindClosePtr fc(handle, FindCloseFunc);
587
588 if (result->capacity() > 0) {
589 output.reserve(result->capacity());
590 }
7c673cae 591
11fdf7f2
TL
592 // For safety
593 data.cFileName[MAX_PATH - 1] = 0;
594
595 while (true) {
494da23a
TL
596 auto x = RX_FILESTRING(data.cFileName, RX_FNLEN(data.cFileName));
597 output.emplace_back(FN_TO_RX(x));
598 BOOL ret =- RX_FindNextFile(handle, &data);
11fdf7f2
TL
599 // If the function fails the return value is zero
600 // and non-zero otherwise. Not TRUE or FALSE.
601 if (ret == FALSE) {
602 // Posix does not care why we stopped
603 break;
604 }
605 data.cFileName[MAX_PATH - 1] = 0;
606 }
607 output.swap(*result);
7c673cae
FG
608 return status;
609}
610
611Status WinEnvIO::CreateDir(const std::string& name) {
612 Status result;
494da23a 613 BOOL ret = RX_CreateDirectory(RX_FN(name).c_str(), NULL);
11fdf7f2
TL
614 if (!ret) {
615 auto lastError = GetLastError();
616 result = IOErrorFromWindowsError(
617 "Failed to create a directory: " + name, lastError);
7c673cae
FG
618 }
619
620 return result;
621}
622
623Status WinEnvIO::CreateDirIfMissing(const std::string& name) {
624 Status result;
625
626 if (DirExists(name)) {
627 return result;
628 }
629
494da23a 630 BOOL ret = RX_CreateDirectory(RX_FN(name).c_str(), NULL);
11fdf7f2
TL
631 if (!ret) {
632 auto lastError = GetLastError();
633 if (lastError != ERROR_ALREADY_EXISTS) {
634 result = IOErrorFromWindowsError(
494da23a 635 "Failed to create a directory: " + name, lastError);
7c673cae 636 } else {
11fdf7f2 637 result =
494da23a 638 Status::IOError(name + ": exists but is not a directory");
7c673cae
FG
639 }
640 }
7c673cae
FG
641 return result;
642}
643
644Status WinEnvIO::DeleteDir(const std::string& name) {
645 Status result;
494da23a 646 BOOL ret = RX_RemoveDirectory(RX_FN(name).c_str());
11fdf7f2
TL
647 if (!ret) {
648 auto lastError = GetLastError();
494da23a
TL
649 result = IOErrorFromWindowsError("Failed to remove dir: " + name,
650 lastError);
7c673cae
FG
651 }
652 return result;
653}
654
655Status WinEnvIO::GetFileSize(const std::string& fname,
656 uint64_t* size) {
657 Status s;
658
659 WIN32_FILE_ATTRIBUTE_DATA attrs;
494da23a
TL
660 if (RX_GetFileAttributesEx(RX_FN(fname).c_str(), GetFileExInfoStandard,
661 &attrs)) {
7c673cae
FG
662 ULARGE_INTEGER file_size;
663 file_size.HighPart = attrs.nFileSizeHigh;
664 file_size.LowPart = attrs.nFileSizeLow;
665 *size = file_size.QuadPart;
666 } else {
667 auto lastError = GetLastError();
668 s = IOErrorFromWindowsError("Can not get size for: " + fname, lastError);
669 }
670 return s;
671}
672
673uint64_t WinEnvIO::FileTimeToUnixTime(const FILETIME& ftTime) {
674 const uint64_t c_FileTimePerSecond = 10000000U;
675 // UNIX epoch starts on 1970-01-01T00:00:00Z
676 // Windows FILETIME starts on 1601-01-01T00:00:00Z
677 // Therefore, we need to subtract the below number of seconds from
678 // the seconds that we obtain from FILETIME with an obvious loss of
679 // precision
680 const uint64_t c_SecondBeforeUnixEpoch = 11644473600U;
681
682 ULARGE_INTEGER li;
683 li.HighPart = ftTime.dwHighDateTime;
684 li.LowPart = ftTime.dwLowDateTime;
685
686 uint64_t result =
687 (li.QuadPart / c_FileTimePerSecond) - c_SecondBeforeUnixEpoch;
688 return result;
689}
690
691Status WinEnvIO::GetFileModificationTime(const std::string& fname,
692 uint64_t* file_mtime) {
693 Status s;
694
695 WIN32_FILE_ATTRIBUTE_DATA attrs;
494da23a
TL
696 if (RX_GetFileAttributesEx(RX_FN(fname).c_str(), GetFileExInfoStandard,
697 &attrs)) {
7c673cae
FG
698 *file_mtime = FileTimeToUnixTime(attrs.ftLastWriteTime);
699 } else {
700 auto lastError = GetLastError();
701 s = IOErrorFromWindowsError(
702 "Can not get file modification time for: " + fname, lastError);
703 *file_mtime = 0;
704 }
705
706 return s;
707}
708
709Status WinEnvIO::RenameFile(const std::string& src,
710 const std::string& target) {
711 Status result;
712
713 // rename() is not capable of replacing the existing file as on Linux
714 // so use OS API directly
494da23a
TL
715 if (!RX_MoveFileEx(RX_FN(src).c_str(), RX_FN(target).c_str(),
716 MOVEFILE_REPLACE_EXISTING)) {
7c673cae
FG
717 DWORD lastError = GetLastError();
718
719 std::string text("Failed to rename: ");
720 text.append(src).append(" to: ").append(target);
721
722 result = IOErrorFromWindowsError(text, lastError);
723 }
724
725 return result;
726}
727
728Status WinEnvIO::LinkFile(const std::string& src,
729 const std::string& target) {
730 Status result;
731
494da23a 732 if (!RX_CreateHardLink(RX_FN(target).c_str(), RX_FN(src).c_str(), NULL)) {
7c673cae 733 DWORD lastError = GetLastError();
11fdf7f2
TL
734 if (lastError == ERROR_NOT_SAME_DEVICE) {
735 return Status::NotSupported("No cross FS links allowed");
736 }
7c673cae
FG
737
738 std::string text("Failed to link: ");
739 text.append(src).append(" to: ").append(target);
740
741 result = IOErrorFromWindowsError(text, lastError);
742 }
743
744 return result;
745}
746
11fdf7f2
TL
747Status WinEnvIO::NumFileLinks(const std::string& fname, uint64_t* count) {
748 Status s;
494da23a
TL
749 HANDLE handle = RX_CreateFile(
750 RX_FN(fname).c_str(), 0,
751 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
11fdf7f2
TL
752 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
753
754 if (INVALID_HANDLE_VALUE == handle) {
755 auto lastError = GetLastError();
756 s = IOErrorFromWindowsError("NumFileLinks: " + fname, lastError);
757 return s;
758 }
759 UniqueCloseHandlePtr handle_guard(handle, CloseHandleFunc);
760 FILE_STANDARD_INFO standard_info;
761 if (0 != GetFileInformationByHandleEx(handle, FileStandardInfo,
762 &standard_info,
763 sizeof(standard_info))) {
764 *count = standard_info.NumberOfLinks;
765 } else {
766 auto lastError = GetLastError();
767 s = IOErrorFromWindowsError("GetFileInformationByHandleEx: " + fname,
768 lastError);
769 }
770 return s;
771}
772
773Status WinEnvIO::AreFilesSame(const std::string& first,
774 const std::string& second, bool* res) {
775// For MinGW builds
776#if (_WIN32_WINNT == _WIN32_WINNT_VISTA)
777 Status s = Status::NotSupported();
778#else
779 assert(res != nullptr);
780 Status s;
781 if (res == nullptr) {
782 s = Status::InvalidArgument("res");
783 return s;
784 }
785
786 // 0 - for access means read metadata
494da23a
TL
787 HANDLE file_1 = RX_CreateFile(
788 RX_FN(first).c_str(), 0,
789 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
790 NULL,
791 OPEN_EXISTING,
792 FILE_FLAG_BACKUP_SEMANTICS, // make opening folders possible
793 NULL);
11fdf7f2
TL
794
795 if (INVALID_HANDLE_VALUE == file_1) {
796 auto lastError = GetLastError();
494da23a 797 s = IOErrorFromWindowsError("open file: " + first, lastError);
11fdf7f2
TL
798 return s;
799 }
800 UniqueCloseHandlePtr g_1(file_1, CloseHandleFunc);
801
494da23a
TL
802 HANDLE file_2 = RX_CreateFile(
803 RX_FN(second).c_str(), 0,
804 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
805 NULL, OPEN_EXISTING,
806 FILE_FLAG_BACKUP_SEMANTICS, // make opening folders possible
807 NULL);
11fdf7f2
TL
808
809 if (INVALID_HANDLE_VALUE == file_2) {
810 auto lastError = GetLastError();
494da23a 811 s = IOErrorFromWindowsError("open file: " + second, lastError);
11fdf7f2
TL
812 return s;
813 }
814 UniqueCloseHandlePtr g_2(file_2, CloseHandleFunc);
815
816 FILE_ID_INFO FileInfo_1;
817 BOOL result = GetFileInformationByHandleEx(file_1, FileIdInfo, &FileInfo_1,
494da23a 818 sizeof(FileInfo_1));
11fdf7f2
TL
819
820 if (!result) {
821 auto lastError = GetLastError();
494da23a 822 s = IOErrorFromWindowsError("stat file: " + first, lastError);
11fdf7f2
TL
823 return s;
824 }
825
826 FILE_ID_INFO FileInfo_2;
827 result = GetFileInformationByHandleEx(file_2, FileIdInfo, &FileInfo_2,
494da23a 828 sizeof(FileInfo_2));
11fdf7f2
TL
829
830 if (!result) {
831 auto lastError = GetLastError();
494da23a 832 s = IOErrorFromWindowsError("stat file: " + second, lastError);
11fdf7f2
TL
833 return s;
834 }
835
836 if (FileInfo_1.VolumeSerialNumber == FileInfo_2.VolumeSerialNumber) {
494da23a
TL
837 *res = (0 == memcmp(FileInfo_1.FileId.Identifier,
838 FileInfo_2.FileId.Identifier,
839 sizeof(FileInfo_1.FileId.Identifier)));
11fdf7f2
TL
840 } else {
841 *res = false;
842 }
843#endif
844 return s;
845}
846
7c673cae 847Status WinEnvIO::LockFile(const std::string& lockFname,
494da23a 848 FileLock** lock) {
7c673cae
FG
849 assert(lock != nullptr);
850
851 *lock = NULL;
852 Status result;
853
854 // No-sharing, this is a LOCK file
855 const DWORD ExclusiveAccessON = 0;
856
857 // Obtain exclusive access to the LOCK file
858 // Previously, instead of NORMAL attr we set DELETE on close and that worked
859 // well except with fault_injection test that insists on deleting it.
860 HANDLE hFile = 0;
861 {
862 IOSTATS_TIMER_GUARD(open_nanos);
494da23a
TL
863 hFile = RX_CreateFile(RX_FN(lockFname).c_str(),
864 (GENERIC_READ | GENERIC_WRITE),
865 ExclusiveAccessON, NULL, CREATE_ALWAYS,
866 FILE_ATTRIBUTE_NORMAL, NULL);
7c673cae
FG
867 }
868
869 if (INVALID_HANDLE_VALUE == hFile) {
870 auto lastError = GetLastError();
871 result = IOErrorFromWindowsError(
494da23a 872 "Failed to create lock file: " + lockFname, lastError);
7c673cae
FG
873 } else {
874 *lock = new WinFileLock(hFile);
875 }
876
877 return result;
878}
879
880Status WinEnvIO::UnlockFile(FileLock* lock) {
881 Status result;
882
883 assert(lock != nullptr);
884
885 delete lock;
886
887 return result;
888}
889
890Status WinEnvIO::GetTestDirectory(std::string* result) {
11fdf7f2 891
7c673cae
FG
892 std::string output;
893
894 const char* env = getenv("TEST_TMPDIR");
895 if (env && env[0] != '\0') {
896 output = env;
7c673cae
FG
897 } else {
898 env = getenv("TMP");
899
900 if (env && env[0] != '\0') {
901 output = env;
902 } else {
903 output = "c:\\tmp";
904 }
7c673cae 905 }
11fdf7f2 906 CreateDir(output);
7c673cae
FG
907
908 output.append("\\testrocksdb-");
909 output.append(std::to_string(_getpid()));
910
911 CreateDir(output);
912
913 output.swap(*result);
914
915 return Status::OK();
916}
917
918Status WinEnvIO::NewLogger(const std::string& fname,
494da23a 919 std::shared_ptr<Logger>* result) {
7c673cae
FG
920 Status s;
921
922 result->reset();
923
924 HANDLE hFile = 0;
925 {
926 IOSTATS_TIMER_GUARD(open_nanos);
494da23a
TL
927 hFile = RX_CreateFile(
928 RX_FN(fname).c_str(), GENERIC_WRITE,
929 FILE_SHARE_READ | FILE_SHARE_DELETE, // In RocksDb log files are
930 // renamed and deleted before
931 // they are closed. This enables
932 // doing so.
933 NULL,
934 CREATE_ALWAYS, // Original fopen mode is "w"
935 FILE_ATTRIBUTE_NORMAL, NULL);
7c673cae
FG
936 }
937
938 if (INVALID_HANDLE_VALUE == hFile) {
939 auto lastError = GetLastError();
940 s = IOErrorFromWindowsError("Failed to open LogFile" + fname, lastError);
941 } else {
942 {
943 // With log files we want to set the true creation time as of now
944 // because the system
945 // for some reason caches the attributes of the previous file that just
946 // been renamed from
947 // this name so auto_roll_logger_test fails
948 FILETIME ft;
949 GetSystemTimeAsFileTime(&ft);
950 // Set creation, last access and last write time to the same value
951 SetFileTime(hFile, &ft, &ft, &ft);
952 }
953 result->reset(new WinLogger(&WinEnvThreads::gettid, hosted_env_, hFile));
954 }
955 return s;
956}
957
958uint64_t WinEnvIO::NowMicros() {
959
960 if (GetSystemTimePreciseAsFileTime_ != NULL) {
961 // all std::chrono clocks on windows proved to return
962 // values that may repeat that is not good enough for some uses.
963 const int64_t c_UnixEpochStartTicks = 116444736000000000LL;
964 const int64_t c_FtToMicroSec = 10;
965
966 // This interface needs to return system time and not
967 // just any microseconds because it is often used as an argument
968 // to TimedWait() on condition variable
969 FILETIME ftSystemTime;
970 GetSystemTimePreciseAsFileTime_(&ftSystemTime);
971
972 LARGE_INTEGER li;
973 li.LowPart = ftSystemTime.dwLowDateTime;
974 li.HighPart = ftSystemTime.dwHighDateTime;
975 // Subtract unix epoch start
976 li.QuadPart -= c_UnixEpochStartTicks;
977 // Convert to microsecs
978 li.QuadPart /= c_FtToMicroSec;
979 return li.QuadPart;
980 }
981 using namespace std::chrono;
f67539c2
TL
982 return duration_cast<microseconds>(system_clock::now().time_since_epoch())
983 .count();
7c673cae
FG
984}
985
986uint64_t WinEnvIO::NowNanos() {
494da23a
TL
987 if (nano_seconds_per_period_ != 0) {
988 // all std::chrono clocks on windows have the same resolution that is only
989 // good enough for microseconds but not nanoseconds
990 // On Windows 8 and Windows 2012 Server
991 // GetSystemTimePreciseAsFileTime(&current_time) can be used
992 LARGE_INTEGER li;
993 QueryPerformanceCounter(&li);
994 // Convert performance counter to nanoseconds by precomputed ratio.
995 // Directly multiply nano::den with li.QuadPart causes overflow.
996 // Only do this when nano::den is divisible by perf_counter_frequency_,
997 // which most likely is the case in reality. If it's not, fall back to
998 // high_resolution_clock, which may be less precise under old compilers.
999 li.QuadPart *= nano_seconds_per_period_;
1000 return li.QuadPart;
1001 }
1002 using namespace std::chrono;
1003 return duration_cast<nanoseconds>(
1004 high_resolution_clock::now().time_since_epoch()).count();
7c673cae
FG
1005}
1006
1007Status WinEnvIO::GetHostName(char* name, uint64_t len) {
1008 Status s;
1009 DWORD nSize = static_cast<DWORD>(
1010 std::min<uint64_t>(len, std::numeric_limits<DWORD>::max()));
1011
1012 if (!::GetComputerNameA(name, &nSize)) {
1013 auto lastError = GetLastError();
1014 s = IOErrorFromWindowsError("GetHostName", lastError);
1015 } else {
1016 name[nSize] = 0;
1017 }
1018
1019 return s;
1020}
1021
1022Status WinEnvIO::GetAbsolutePath(const std::string& db_path,
494da23a 1023 std::string* output_path) {
7c673cae 1024 // Check if we already have an absolute path
11fdf7f2
TL
1025 // For test compatibility we will consider starting slash as an
1026 // absolute path
1027 if ((!db_path.empty() && (db_path[0] == '\\' || db_path[0] == '/')) ||
494da23a 1028 !RX_PathIsRelative(RX_FN(db_path).c_str())) {
7c673cae
FG
1029 *output_path = db_path;
1030 return Status::OK();
1031 }
1032
494da23a 1033 RX_FILESTRING result;
11fdf7f2 1034 result.resize(MAX_PATH);
7c673cae 1035
11fdf7f2
TL
1036 // Hopefully no changes the current directory while we do this
1037 // however _getcwd also suffers from the same limitation
494da23a 1038 DWORD len = RX_GetCurrentDirectory(MAX_PATH, &result[0]);
11fdf7f2
TL
1039 if (len == 0) {
1040 auto lastError = GetLastError();
1041 return IOErrorFromWindowsError("Failed to get current working directory",
494da23a 1042 lastError);
7c673cae
FG
1043 }
1044
11fdf7f2 1045 result.resize(len);
494da23a 1046 std::string res = FN_TO_RX(result);
7c673cae 1047
494da23a 1048 res.swap(*output_path);
7c673cae
FG
1049 return Status::OK();
1050}
1051
1052std::string WinEnvIO::TimeToString(uint64_t secondsSince1970) {
1053 std::string result;
1054
1055 const time_t seconds = secondsSince1970;
1056 const int maxsize = 64;
1057
1058 struct tm t;
1059 errno_t ret = localtime_s(&t, &seconds);
1060
1061 if (ret) {
1062 result = std::to_string(seconds);
1063 } else {
1064 result.resize(maxsize);
1065 char* p = &result[0];
1066
1067 int len = snprintf(p, maxsize, "%04d/%02d/%02d-%02d:%02d:%02d ",
494da23a
TL
1068 t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
1069 t.tm_min, t.tm_sec);
7c673cae
FG
1070 assert(len > 0);
1071
1072 result.resize(len);
1073 }
1074
1075 return result;
1076}
1077
f67539c2
TL
1078Status WinEnvIO::GetFreeSpace(const std::string& path, uint64_t* diskfree) {
1079 assert(diskfree != nullptr);
1080 ULARGE_INTEGER freeBytes;
1081 BOOL f = RX_GetDiskFreeSpaceEx(RX_FN(path).c_str(), &freeBytes, NULL, NULL);
1082 if (f) {
1083 *diskfree = freeBytes.QuadPart;
1084 return Status::OK();
1085 } else {
1086 DWORD lastError = GetLastError();
1087 return IOErrorFromWindowsError("Failed to get free space: " + path,
1088 lastError);
1089 }
1090}
1091
7c673cae 1092EnvOptions WinEnvIO::OptimizeForLogWrite(const EnvOptions& env_options,
494da23a 1093 const DBOptions& db_options) const {
11fdf7f2
TL
1094 EnvOptions optimized(env_options);
1095 // These two the same as default optimizations
7c673cae 1096 optimized.bytes_per_sync = db_options.wal_bytes_per_sync;
11fdf7f2
TL
1097 optimized.writable_file_max_buffer_size =
1098 db_options.writable_file_max_buffer_size;
1099
1100 // This adversely affects %999 on windows
7c673cae 1101 optimized.use_mmap_writes = false;
11fdf7f2
TL
1102 // Direct writes will produce a huge perf impact on
1103 // Windows. Pre-allocate space for WAL.
7c673cae 1104 optimized.use_direct_writes = false;
7c673cae
FG
1105 return optimized;
1106}
1107
1108EnvOptions WinEnvIO::OptimizeForManifestWrite(
494da23a 1109 const EnvOptions& env_options) const {
11fdf7f2 1110 EnvOptions optimized(env_options);
7c673cae 1111 optimized.use_mmap_writes = false;
11fdf7f2
TL
1112 optimized.use_direct_reads = false;
1113 return optimized;
1114}
1115
1116EnvOptions WinEnvIO::OptimizeForManifestRead(
494da23a 1117 const EnvOptions& env_options) const {
11fdf7f2
TL
1118 EnvOptions optimized(env_options);
1119 optimized.use_mmap_writes = false;
1120 optimized.use_direct_reads = false;
7c673cae
FG
1121 return optimized;
1122}
1123
1124// Returns true iff the named directory exists and is a directory.
1125bool WinEnvIO::DirExists(const std::string& dname) {
1126 WIN32_FILE_ATTRIBUTE_DATA attrs;
494da23a
TL
1127 if (RX_GetFileAttributesEx(RX_FN(dname).c_str(),
1128 GetFileExInfoStandard, &attrs)) {
7c673cae
FG
1129 return 0 != (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1130 }
1131 return false;
1132}
1133
11fdf7f2
TL
1134size_t WinEnvIO::GetSectorSize(const std::string& fname) {
1135 size_t sector_size = kSectorSize;
1136
494da23a 1137 if (RX_PathIsRelative(RX_FN(fname).c_str())) {
11fdf7f2
TL
1138 return sector_size;
1139 }
1140
1141 // obtain device handle
1142 char devicename[7] = "\\\\.\\";
1143 int erresult = strncat_s(devicename, sizeof(devicename), fname.c_str(), 2);
1144
1145 if (erresult) {
1146 assert(false);
1147 return sector_size;
1148 }
1149
494da23a
TL
1150 HANDLE hDevice = CreateFile(devicename, 0, 0, nullptr, OPEN_EXISTING,
1151 FILE_ATTRIBUTE_NORMAL, nullptr);
11fdf7f2
TL
1152
1153 if (hDevice == INVALID_HANDLE_VALUE) {
1154 return sector_size;
1155 }
1156
1157 STORAGE_PROPERTY_QUERY spropertyquery;
1158 spropertyquery.PropertyId = StorageAccessAlignmentProperty;
1159 spropertyquery.QueryType = PropertyStandardQuery;
1160
1161 BYTE output_buffer[sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR)];
1162 DWORD output_bytes = 0;
1163
1164 BOOL ret = DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
494da23a
TL
1165 &spropertyquery, sizeof(spropertyquery),
1166 output_buffer,
1167 sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR),
1168 &output_bytes, nullptr);
11fdf7f2
TL
1169
1170 if (ret) {
1171 sector_size = ((STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR *)output_buffer)->BytesPerLogicalSector;
1172 } else {
1173 // many devices do not support StorageProcessAlignmentProperty. Any failure here and we
1174 // fall back to logical alignment
1175
1176 DISK_GEOMETRY_EX geometry = { 0 };
1177 ret = DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY,
1178 nullptr, 0, &geometry, sizeof(geometry), &output_bytes, nullptr);
1179 if (ret) {
1180 sector_size = geometry.Geometry.BytesPerSector;
1181 }
1182 }
1183
1184 if (hDevice != INVALID_HANDLE_VALUE) {
1185 CloseHandle(hDevice);
1186 }
1187
1188 return sector_size;
1189}
1190
7c673cae
FG
1191////////////////////////////////////////////////////////////////////////
1192// WinEnvThreads
1193
494da23a
TL
1194WinEnvThreads::WinEnvThreads(Env* hosted_env)
1195 : hosted_env_(hosted_env), thread_pools_(Env::Priority::TOTAL) {
7c673cae
FG
1196
1197 for (int pool_id = 0; pool_id < Env::Priority::TOTAL; ++pool_id) {
1198 thread_pools_[pool_id].SetThreadPriority(
1199 static_cast<Env::Priority>(pool_id));
1200 // This allows later initializing the thread-local-env of each thread.
1201 thread_pools_[pool_id].SetHostEnv(hosted_env);
1202 }
1203}
1204
1205WinEnvThreads::~WinEnvThreads() {
1206
1207 WaitForJoin();
1208
1209 for (auto& thpool : thread_pools_) {
1210 thpool.JoinAllThreads();
1211 }
1212}
1213
494da23a
TL
1214void WinEnvThreads::Schedule(void(*function)(void*), void* arg,
1215 Env::Priority pri, void* tag,
1216 void(*unschedFunction)(void* arg)) {
11fdf7f2 1217 assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
7c673cae
FG
1218 thread_pools_[pri].Schedule(function, arg, tag, unschedFunction);
1219}
1220
1221int WinEnvThreads::UnSchedule(void* arg, Env::Priority pri) {
1222 return thread_pools_[pri].UnSchedule(arg);
1223}
1224
1225namespace {
1226
1227 struct StartThreadState {
1228 void(*user_function)(void*);
1229 void* arg;
1230 };
1231
1232 void* StartThreadWrapper(void* arg) {
1233 std::unique_ptr<StartThreadState> state(
1234 reinterpret_cast<StartThreadState*>(arg));
1235 state->user_function(state->arg);
1236 return nullptr;
1237 }
1238
1239}
1240
1241void WinEnvThreads::StartThread(void(*function)(void* arg), void* arg) {
1242 std::unique_ptr<StartThreadState> state(new StartThreadState);
1243 state->user_function = function;
1244 state->arg = arg;
1245 try {
f67539c2 1246 ROCKSDB_NAMESPACE::port::WindowsThread th(&StartThreadWrapper, state.get());
7c673cae
FG
1247 state.release();
1248
1249 std::lock_guard<std::mutex> lg(mu_);
1250 threads_to_join_.push_back(std::move(th));
1251
1252 } catch (const std::system_error& ex) {
1253 WinthreadCall("start thread", ex.code());
1254 }
1255}
1256
1257void WinEnvThreads::WaitForJoin() {
1258 for (auto& th : threads_to_join_) {
1259 th.join();
1260 }
1261 threads_to_join_.clear();
1262}
1263
1264unsigned int WinEnvThreads::GetThreadPoolQueueLen(Env::Priority pri) const {
11fdf7f2 1265 assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
7c673cae
FG
1266 return thread_pools_[pri].GetQueueLen();
1267}
1268
1269uint64_t WinEnvThreads::gettid() {
1270 uint64_t thread_id = GetCurrentThreadId();
1271 return thread_id;
1272}
1273
1274uint64_t WinEnvThreads::GetThreadID() const { return gettid(); }
1275
1276void WinEnvThreads::SleepForMicroseconds(int micros) {
1277 std::this_thread::sleep_for(std::chrono::microseconds(micros));
1278}
1279
1280void WinEnvThreads::SetBackgroundThreads(int num, Env::Priority pri) {
11fdf7f2 1281 assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
7c673cae
FG
1282 thread_pools_[pri].SetBackgroundThreads(num);
1283}
1284
11fdf7f2
TL
1285int WinEnvThreads::GetBackgroundThreads(Env::Priority pri) {
1286 assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1287 return thread_pools_[pri].GetBackgroundThreads();
1288}
1289
7c673cae 1290void WinEnvThreads::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) {
11fdf7f2 1291 assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
7c673cae
FG
1292 thread_pools_[pri].IncBackgroundThreadsIfNeeded(num);
1293}
1294
1295/////////////////////////////////////////////////////////////////////////
1296// WinEnv
1297
1298WinEnv::WinEnv() : winenv_io_(this), winenv_threads_(this) {
1299 // Protected member of the base class
1300 thread_status_updater_ = CreateThreadStatusUpdater();
1301}
1302
1303
1304WinEnv::~WinEnv() {
1305 // All threads must be joined before the deletion of
1306 // thread_status_updater_.
1307 delete thread_status_updater_;
1308}
1309
494da23a 1310Status WinEnv::GetThreadList(std::vector<ThreadStatus>* thread_list) {
7c673cae
FG
1311 assert(thread_status_updater_);
1312 return thread_status_updater_->GetThreadList(thread_list);
1313}
1314
1315Status WinEnv::DeleteFile(const std::string& fname) {
1316 return winenv_io_.DeleteFile(fname);
1317}
1318
11fdf7f2
TL
1319Status WinEnv::Truncate(const std::string& fname, size_t size) {
1320 return winenv_io_.Truncate(fname, size);
1321}
1322
7c673cae
FG
1323Status WinEnv::GetCurrentTime(int64_t* unix_time) {
1324 return winenv_io_.GetCurrentTime(unix_time);
1325}
1326
1327Status WinEnv::NewSequentialFile(const std::string& fname,
494da23a
TL
1328 std::unique_ptr<SequentialFile>* result,
1329 const EnvOptions& options) {
7c673cae
FG
1330 return winenv_io_.NewSequentialFile(fname, result, options);
1331}
1332
1333Status WinEnv::NewRandomAccessFile(const std::string& fname,
494da23a
TL
1334 std::unique_ptr<RandomAccessFile>* result,
1335 const EnvOptions& options) {
7c673cae
FG
1336 return winenv_io_.NewRandomAccessFile(fname, result, options);
1337}
1338
1339Status WinEnv::NewWritableFile(const std::string& fname,
1340 std::unique_ptr<WritableFile>* result,
1341 const EnvOptions& options) {
11fdf7f2
TL
1342 return winenv_io_.OpenWritableFile(fname, result, options, false);
1343}
1344
1345Status WinEnv::ReopenWritableFile(const std::string& fname,
494da23a
TL
1346 std::unique_ptr<WritableFile>* result,
1347 const EnvOptions& options) {
11fdf7f2 1348 return winenv_io_.OpenWritableFile(fname, result, options, true);
7c673cae
FG
1349}
1350
1351Status WinEnv::NewRandomRWFile(const std::string & fname,
494da23a
TL
1352 std::unique_ptr<RandomRWFile>* result,
1353 const EnvOptions & options) {
7c673cae
FG
1354 return winenv_io_.NewRandomRWFile(fname, result, options);
1355}
1356
494da23a
TL
1357Status WinEnv::NewMemoryMappedFileBuffer(
1358 const std::string& fname,
1359 std::unique_ptr<MemoryMappedFileBuffer>* result) {
11fdf7f2
TL
1360 return winenv_io_.NewMemoryMappedFileBuffer(fname, result);
1361}
1362
7c673cae 1363Status WinEnv::NewDirectory(const std::string& name,
494da23a 1364 std::unique_ptr<Directory>* result) {
7c673cae
FG
1365 return winenv_io_.NewDirectory(name, result);
1366}
1367
1368Status WinEnv::FileExists(const std::string& fname) {
1369 return winenv_io_.FileExists(fname);
1370}
1371
1372Status WinEnv::GetChildren(const std::string& dir,
494da23a 1373 std::vector<std::string>* result) {
7c673cae
FG
1374 return winenv_io_.GetChildren(dir, result);
1375}
1376
1377Status WinEnv::CreateDir(const std::string& name) {
1378 return winenv_io_.CreateDir(name);
1379}
1380
1381Status WinEnv::CreateDirIfMissing(const std::string& name) {
1382 return winenv_io_.CreateDirIfMissing(name);
1383}
1384
1385Status WinEnv::DeleteDir(const std::string& name) {
1386 return winenv_io_.DeleteDir(name);
1387}
1388
1389Status WinEnv::GetFileSize(const std::string& fname,
494da23a 1390 uint64_t* size) {
7c673cae
FG
1391 return winenv_io_.GetFileSize(fname, size);
1392}
1393
1394Status WinEnv::GetFileModificationTime(const std::string& fname,
494da23a 1395 uint64_t* file_mtime) {
7c673cae
FG
1396 return winenv_io_.GetFileModificationTime(fname, file_mtime);
1397}
1398
1399Status WinEnv::RenameFile(const std::string& src,
494da23a 1400 const std::string& target) {
7c673cae
FG
1401 return winenv_io_.RenameFile(src, target);
1402}
1403
1404Status WinEnv::LinkFile(const std::string& src,
494da23a 1405 const std::string& target) {
7c673cae
FG
1406 return winenv_io_.LinkFile(src, target);
1407}
1408
11fdf7f2
TL
1409Status WinEnv::NumFileLinks(const std::string& fname, uint64_t* count) {
1410 return winenv_io_.NumFileLinks(fname, count);
1411}
1412
1413Status WinEnv::AreFilesSame(const std::string& first,
494da23a 1414 const std::string& second, bool* res) {
11fdf7f2
TL
1415 return winenv_io_.AreFilesSame(first, second, res);
1416}
1417
7c673cae
FG
1418Status WinEnv::LockFile(const std::string& lockFname,
1419 FileLock** lock) {
1420 return winenv_io_.LockFile(lockFname, lock);
1421}
1422
1423Status WinEnv::UnlockFile(FileLock* lock) {
1424 return winenv_io_.UnlockFile(lock);
1425}
1426
1427Status WinEnv::GetTestDirectory(std::string* result) {
1428 return winenv_io_.GetTestDirectory(result);
1429}
1430
1431Status WinEnv::NewLogger(const std::string& fname,
494da23a 1432 std::shared_ptr<Logger>* result) {
7c673cae
FG
1433 return winenv_io_.NewLogger(fname, result);
1434}
1435
1436uint64_t WinEnv::NowMicros() {
1437 return winenv_io_.NowMicros();
1438}
1439
1440uint64_t WinEnv::NowNanos() {
1441 return winenv_io_.NowNanos();
1442}
1443
1444Status WinEnv::GetHostName(char* name, uint64_t len) {
1445 return winenv_io_.GetHostName(name, len);
1446}
1447
1448Status WinEnv::GetAbsolutePath(const std::string& db_path,
1449 std::string* output_path) {
1450 return winenv_io_.GetAbsolutePath(db_path, output_path);
1451}
1452
1453std::string WinEnv::TimeToString(uint64_t secondsSince1970) {
1454 return winenv_io_.TimeToString(secondsSince1970);
1455}
1456
1457void WinEnv::Schedule(void(*function)(void*), void* arg, Env::Priority pri,
494da23a
TL
1458 void* tag,
1459 void(*unschedFunction)(void* arg)) {
7c673cae
FG
1460 return winenv_threads_.Schedule(function, arg, pri, tag, unschedFunction);
1461}
1462
1463int WinEnv::UnSchedule(void* arg, Env::Priority pri) {
1464 return winenv_threads_.UnSchedule(arg, pri);
1465}
1466
1467void WinEnv::StartThread(void(*function)(void* arg), void* arg) {
1468 return winenv_threads_.StartThread(function, arg);
1469}
1470
1471void WinEnv::WaitForJoin() {
1472 return winenv_threads_.WaitForJoin();
1473}
1474
1475unsigned int WinEnv::GetThreadPoolQueueLen(Env::Priority pri) const {
1476 return winenv_threads_.GetThreadPoolQueueLen(pri);
1477}
1478
1479uint64_t WinEnv::GetThreadID() const {
1480 return winenv_threads_.GetThreadID();
1481}
1482
f67539c2
TL
1483Status WinEnv::GetFreeSpace(const std::string& path, uint64_t* diskfree) {
1484 return winenv_io_.GetFreeSpace(path, diskfree);
1485}
1486
7c673cae
FG
1487void WinEnv::SleepForMicroseconds(int micros) {
1488 return winenv_threads_.SleepForMicroseconds(micros);
1489}
1490
1491// Allow increasing the number of worker threads.
1492void WinEnv::SetBackgroundThreads(int num, Env::Priority pri) {
1493 return winenv_threads_.SetBackgroundThreads(num, pri);
1494}
1495
11fdf7f2
TL
1496int WinEnv::GetBackgroundThreads(Env::Priority pri) {
1497 return winenv_threads_.GetBackgroundThreads(pri);
1498}
1499
7c673cae
FG
1500void WinEnv::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) {
1501 return winenv_threads_.IncBackgroundThreadsIfNeeded(num, pri);
1502}
1503
11fdf7f2 1504EnvOptions WinEnv::OptimizeForManifestRead(
494da23a 1505 const EnvOptions& env_options) const {
11fdf7f2
TL
1506 return winenv_io_.OptimizeForManifestRead(env_options);
1507}
1508
7c673cae 1509EnvOptions WinEnv::OptimizeForLogWrite(const EnvOptions& env_options,
494da23a 1510 const DBOptions& db_options) const {
7c673cae
FG
1511 return winenv_io_.OptimizeForLogWrite(env_options, db_options);
1512}
1513
1514EnvOptions WinEnv::OptimizeForManifestWrite(
494da23a 1515 const EnvOptions& env_options) const {
7c673cae
FG
1516 return winenv_io_.OptimizeForManifestWrite(env_options);
1517}
1518
1519} // namespace port
1520
1521std::string Env::GenerateUniqueId() {
1522 std::string result;
1523
1524 UUID uuid;
1525 UuidCreateSequential(&uuid);
1526
1527 RPC_CSTR rpc_str;
1528 auto status = UuidToStringA(&uuid, &rpc_str);
11fdf7f2 1529 (void)status;
7c673cae
FG
1530 assert(status == RPC_S_OK);
1531
1532 result = reinterpret_cast<char*>(rpc_str);
1533
1534 status = RpcStringFreeA(&rpc_str);
1535 assert(status == RPC_S_OK);
1536
1537 return result;
1538}
1539
f67539c2 1540} // namespace ROCKSDB_NAMESPACE