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