1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 //
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
9 
10 #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/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 
36 #include <rpc.h>  // for uuid generation
37 #include <windows.h>
38 #include <shlwapi.h>
39 #include "strsafe.h"
40 
41 #include <algorithm>
42 
43 namespace ROCKSDB_NAMESPACE {
44 
CreateThreadStatusUpdater()45 ThreadStatusUpdater* CreateThreadStatusUpdater() {
46   return new ThreadStatusUpdater();
47 }
48 
49 namespace {
50 
51 // Sector size used when physical sector size cannot be obtained from device.
52 static const size_t kSectorSize = 512;
53 
54 // RAII helpers for HANDLEs
__anonce8e45300202(HANDLE h) 55 const auto CloseHandleFunc = [](HANDLE h) { ::CloseHandle(h); };
56 typedef std::unique_ptr<void, decltype(CloseHandleFunc)> UniqueCloseHandlePtr;
57 
__anonce8e45300302(HANDLE h) 58 const auto FindCloseFunc = [](HANDLE h) { ::FindClose(h); };
59 typedef std::unique_ptr<void, decltype(FindCloseFunc)> UniqueFindClosePtr;
60 
WinthreadCall(const char * label,std::error_code result)61 void 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 
70 namespace port {
71 
WinEnvIO(Env * hosted_env)72 WinEnvIO::WinEnvIO(Env* hosted_env)
73     : hosted_env_(hosted_env),
74       page_size_(4 * 1024),
75       allocation_granularity_(page_size_),
76       perf_counter_frequency_(0),
77       nano_seconds_per_period_(0),
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;
88     BOOL ret __attribute__((__unused__));
89     ret = QueryPerformanceFrequency(&qpf);
90     assert(ret == TRUE);
91     perf_counter_frequency_ = qpf.QuadPart;
92 
93     if (std::nano::den % perf_counter_frequency_ == 0) {
94       nano_seconds_per_period_ = std::nano::den / perf_counter_frequency_;
95     }
96   }
97 
98   HMODULE module = GetModuleHandle("kernel32.dll");
99   if (module != NULL) {
100     GetSystemTimePreciseAsFileTime_ =
101       (FnGetSystemTimePreciseAsFileTime)GetProcAddress(
102           module, "GetSystemTimePreciseAsFileTime");
103   }
104 }
105 
~WinEnvIO()106 WinEnvIO::~WinEnvIO() {
107 }
108 
DeleteFile(const std::string & fname)109 Status WinEnvIO::DeleteFile(const std::string& fname) {
110   Status result;
111 
112   BOOL ret = RX_DeleteFile(RX_FN(fname).c_str());
113 
114   if(!ret) {
115     auto lastError = GetLastError();
116     result = IOErrorFromWindowsError("Failed to delete: " + fname,
117                                      lastError);
118   }
119 
120   return result;
121 }
122 
Truncate(const std::string & fname,size_t size)123 Status WinEnvIO::Truncate(const std::string& fname, size_t size) {
124   Status s;
125   int result = ROCKSDB_NAMESPACE::port::Truncate(fname, size);
126   if (result != 0) {
127     s = IOError("Failed to truncate: " + fname, errno);
128   }
129   return s;
130 }
131 
GetCurrentTime(int64_t * unix_time)132 Status 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 
NewSequentialFile(const std::string & fname,std::unique_ptr<SequentialFile> * result,const EnvOptions & options)142 Status WinEnvIO::NewSequentialFile(const std::string& fname,
143                                    std::unique_ptr<SequentialFile>* result,
144                                    const EnvOptions& options) {
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);
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);
167   }
168 
169   if (INVALID_HANDLE_VALUE == hFile) {
170     auto lastError = GetLastError();
171     s = IOErrorFromWindowsError("Failed to open NewSequentialFile" + fname,
172                                 lastError);
173   } else {
174     result->reset(new WinSequentialFile(fname, hFile, options));
175   }
176   return s;
177 }
178 
NewRandomAccessFile(const std::string & fname,std::unique_ptr<RandomAccessFile> * result,const EnvOptions & options)179 Status WinEnvIO::NewRandomAccessFile(const std::string& fname,
180                                      std::unique_ptr<RandomAccessFile>* result,
181                                      const EnvOptions& options) {
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);
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);
204   }
205 
206   if (INVALID_HANDLE_VALUE == hFile) {
207     auto lastError = GetLastError();
208     return IOErrorFromWindowsError(
209         "NewRandomAccessFile failed to Create/Open: " + fname, lastError);
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(
225             "NewRandomAccessFile failed to map empty file: " + fname, EINVAL);
226       }
227 
228       HANDLE hMap = RX_CreateFileMapping(hFile, NULL, PAGE_READONLY,
229                                          0,  // At its present length
230                                          0,
231                                          NULL);  // Mapping name
232 
233       if (!hMap) {
234         auto lastError = GetLastError();
235         return IOErrorFromWindowsError(
236             "Failed to create file mapping for NewRandomAccessFile: " + fname,
237             lastError);
238       }
239 
240       UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc);
241 
242       const void* mapped_region =
243         MapViewOfFileEx(hMap, FILE_MAP_READ,
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
248 
249       if (!mapped_region) {
250         auto lastError = GetLastError();
251         return IOErrorFromWindowsError(
252             "Failed to MapViewOfFile for NewRandomAccessFile: " + fname,
253             lastError);
254       }
255 
256       result->reset(new WinMmapReadableFile(fname, hFile, hMap, mapped_region,
257                                             static_cast<size_t>(fileSize)));
258 
259       mapGuard.release();
260       fileGuard.release();
261     }
262   } else {
263     result->reset(new WinRandomAccessFile(fname, hFile,
264                                           std::max(GetSectorSize(fname),
265                                                    page_size_),
266                                           options));
267     fileGuard.release();
268   }
269   return s;
270 }
271 
OpenWritableFile(const std::string & fname,std::unique_ptr<WritableFile> * result,const EnvOptions & options,bool reopen)272 Status WinEnvIO::OpenWritableFile(const std::string& fname,
273                                   std::unique_ptr<WritableFile>* result,
274                                   const EnvOptions& options,
275                                   bool reopen) {
276 
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) {
287     fileFlags = FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
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 
306   // This will always truncate the file
307   DWORD creation_disposition = CREATE_ALWAYS;
308   if (reopen) {
309     creation_disposition = OPEN_ALWAYS;
310   }
311 
312   HANDLE hFile = 0;
313   {
314     IOSTATS_TIMER_GUARD(open_nanos);
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
324   }
325 
326   if (INVALID_HANDLE_VALUE == hFile) {
327     auto lastError = GetLastError();
328     return IOErrorFromWindowsError(
329         "Failed to create a NewWriteableFile: " + fname, lastError);
330   }
331 
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(
340           "Failed to create a ReopenWritableFile move to the end: " + fname,
341           lastError);
342     }
343   }
344 
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_,
349                                   allocation_granularity_, local_options));
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
353     result->reset(new WinWritableFile(fname, hFile,
354                                       std::max(GetSectorSize(fname),
355                                                GetPageSize()),
356                                       c_BufferCapacity, local_options));
357   }
358   return s;
359 }
360 
NewRandomRWFile(const std::string & fname,std::unique_ptr<RandomRWFile> * result,const EnvOptions & options)361 Status WinEnvIO::NewRandomRWFile(const std::string & fname,
362                                  std::unique_ptr<RandomRWFile>* result,
363                                  const EnvOptions & options) {
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;
371   DWORD creation_disposition = OPEN_EXISTING; // Fail if file does not exist
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 =
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);
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);
400   result->reset(new WinRandomRWFile(fname, hFile,
401                                     std::max(GetSectorSize(fname),
402                                              GetPageSize()),
403                                     options));
404   fileGuard.release();
405 
406   return s;
407 }
408 
NewMemoryMappedFileBuffer(const std::string & fname,std::unique_ptr<MemoryMappedFileBuffer> * result)409 Status WinEnvIO::NewMemoryMappedFileBuffer(
410     const std::string & fname,
411     std::unique_ptr<MemoryMappedFileBuffer>* result) {
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);
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);
427   }
428 
429   if (INVALID_HANDLE_VALUE == hFile) {
430     auto lastError = GetLastError();
431     s = IOErrorFromWindowsError(
432         "Failed to open NewMemoryMappedFileBuffer: " + fname, lastError);
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) {
444     return Status::NotSupported(
445         "NewMemoryMappedFileBuffer can not map zero length files: " + fname);
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(
451         "The specified file size does not fit into 32-bit memory addressing: "
452          + fname);
453   }
454 
455   HANDLE hMap = RX_CreateFileMapping(hFile, NULL, PAGE_READWRITE,
456                                      0,  // Whole file at its present length
457                                      0,
458                                      NULL);  // Mapping name
459 
460   if (!hMap) {
461     auto lastError = GetLastError();
462     return IOErrorFromWindowsError(
463         "Failed to create file mapping for: " + fname, lastError);
464   }
465   UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc);
466 
467   void* base = MapViewOfFileEx(hMap, FILE_MAP_WRITE,
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
472 
473   if (!base) {
474     auto lastError = GetLastError();
475     return IOErrorFromWindowsError(
476         "Failed to MapViewOfFile for NewMemoryMappedFileBuffer: " + fname,
477         lastError);
478   }
479 
480   result->reset(new WinMemoryMappedBuffer(hFile, hMap, base,
481                                           static_cast<size_t>(fileSize)));
482 
483   mapGuard.release();
484   fileGuard.release();
485 
486   return s;
487 }
488 
NewDirectory(const std::string & name,std::unique_ptr<Directory> * result)489 Status WinEnvIO::NewDirectory(const std::string& name,
490                               std::unique_ptr<Directory>* result) {
491   Status s;
492   // Must be nullptr on failure
493   result->reset();
494 
495   if (!DirExists(name)) {
496     s = IOErrorFromWindowsError(
497         "open folder: " + name, ERROR_DIRECTORY);
498     return s;
499   }
500 
501   HANDLE handle = INVALID_HANDLE_VALUE;
502   // 0 - for access means read metadata
503   {
504     IOSTATS_TIMER_GUARD(open_nanos);
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);
512   }
513 
514   if (INVALID_HANDLE_VALUE == handle) {
515     auto lastError = GetLastError();
516     s = IOErrorFromWindowsError("open folder: " + name, lastError);
517     return s;
518   }
519 
520   result->reset(new WinDirectory(handle));
521 
522   return s;
523 }
524 
FileExists(const std::string & fname)525 Status WinEnvIO::FileExists(const std::string& fname) {
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;
531   if (FALSE == RX_GetFileAttributesEx(RX_FN(fname).c_str(),
532                                       GetFileExInfoStandard, &attrs)) {
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,
543                                   lastError);
544       break;
545     }
546   }
547   return s;
548 }
549 
GetChildren(const std::string & dir,std::vector<std::string> * result)550 Status WinEnvIO::GetChildren(const std::string& dir,
551                              std::vector<std::string>* result) {
552 
553   Status status;
554   result->clear();
555   std::vector<std::string> output;
556 
557   RX_WIN32_FIND_DATA data;
558   memset(&data, 0, sizeof(data));
559   std::string pattern(dir);
560   pattern.append("\\").append("*");
561 
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);
569 
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(
581           "Failed to GetChhildren for: " + dir, lastError);
582     }
583     return status;
584   }
585 
586   UniqueFindClosePtr fc(handle, FindCloseFunc);
587 
588   if (result->capacity() > 0) {
589     output.reserve(result->capacity());
590   }
591 
592   // For safety
593   data.cFileName[MAX_PATH - 1] = 0;
594 
595   while (true) {
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);
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);
608   return status;
609 }
610 
CreateDir(const std::string & name)611 Status WinEnvIO::CreateDir(const std::string& name) {
612   Status result;
613   BOOL ret = RX_CreateDirectory(RX_FN(name).c_str(), NULL);
614   if (!ret) {
615     auto lastError = GetLastError();
616     result = IOErrorFromWindowsError(
617         "Failed to create a directory: " + name, lastError);
618   }
619 
620   return result;
621 }
622 
CreateDirIfMissing(const std::string & name)623 Status  WinEnvIO::CreateDirIfMissing(const std::string& name) {
624   Status result;
625 
626   if (DirExists(name)) {
627     return result;
628   }
629 
630   BOOL ret = RX_CreateDirectory(RX_FN(name).c_str(), NULL);
631   if (!ret) {
632     auto lastError = GetLastError();
633     if (lastError != ERROR_ALREADY_EXISTS) {
634       result = IOErrorFromWindowsError(
635           "Failed to create a directory: " + name, lastError);
636     } else {
637       result =
638           Status::IOError(name + ": exists but is not a directory");
639     }
640   }
641   return result;
642 }
643 
DeleteDir(const std::string & name)644 Status WinEnvIO::DeleteDir(const std::string& name) {
645   Status result;
646   BOOL ret = RX_RemoveDirectory(RX_FN(name).c_str());
647   if (!ret) {
648     auto lastError = GetLastError();
649     result = IOErrorFromWindowsError("Failed to remove dir: " + name,
650                                      lastError);
651   }
652   return result;
653 }
654 
GetFileSize(const std::string & fname,uint64_t * size)655 Status WinEnvIO::GetFileSize(const std::string& fname,
656   uint64_t* size) {
657   Status s;
658 
659   WIN32_FILE_ATTRIBUTE_DATA attrs;
660   if (RX_GetFileAttributesEx(RX_FN(fname).c_str(), GetFileExInfoStandard,
661                              &attrs)) {
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 
FileTimeToUnixTime(const FILETIME & ftTime)673 uint64_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 
GetFileModificationTime(const std::string & fname,uint64_t * file_mtime)691 Status WinEnvIO::GetFileModificationTime(const std::string& fname,
692   uint64_t* file_mtime) {
693   Status s;
694 
695   WIN32_FILE_ATTRIBUTE_DATA attrs;
696   if (RX_GetFileAttributesEx(RX_FN(fname).c_str(), GetFileExInfoStandard,
697                             &attrs)) {
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 
RenameFile(const std::string & src,const std::string & target)709 Status 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
715   if (!RX_MoveFileEx(RX_FN(src).c_str(), RX_FN(target).c_str(),
716                      MOVEFILE_REPLACE_EXISTING)) {
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 
LinkFile(const std::string & src,const std::string & target)728 Status WinEnvIO::LinkFile(const std::string& src,
729   const std::string& target) {
730   Status result;
731 
732   if (!RX_CreateHardLink(RX_FN(target).c_str(), RX_FN(src).c_str(),  NULL)) {
733     DWORD lastError = GetLastError();
734     if (lastError == ERROR_NOT_SAME_DEVICE) {
735       return Status::NotSupported("No cross FS links allowed");
736     }
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 
NumFileLinks(const std::string & fname,uint64_t * count)747 Status WinEnvIO::NumFileLinks(const std::string& fname, uint64_t* count) {
748   Status s;
749   HANDLE handle = RX_CreateFile(
750       RX_FN(fname).c_str(), 0,
751       FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
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 
AreFilesSame(const std::string & first,const std::string & second,bool * res)773 Status 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
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);
794 
795   if (INVALID_HANDLE_VALUE == file_1) {
796     auto lastError = GetLastError();
797     s = IOErrorFromWindowsError("open file: " + first, lastError);
798     return s;
799   }
800   UniqueCloseHandlePtr g_1(file_1, CloseHandleFunc);
801 
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);
808 
809   if (INVALID_HANDLE_VALUE == file_2) {
810     auto lastError = GetLastError();
811     s = IOErrorFromWindowsError("open file: " + second, lastError);
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,
818                                              sizeof(FileInfo_1));
819 
820   if (!result) {
821     auto lastError = GetLastError();
822     s = IOErrorFromWindowsError("stat file: " + first, lastError);
823     return s;
824   }
825 
826    FILE_ID_INFO FileInfo_2;
827    result = GetFileInformationByHandleEx(file_2, FileIdInfo, &FileInfo_2,
828                                          sizeof(FileInfo_2));
829 
830   if (!result) {
831     auto lastError = GetLastError();
832     s = IOErrorFromWindowsError("stat file: " + second, lastError);
833     return s;
834   }
835 
836   if (FileInfo_1.VolumeSerialNumber == FileInfo_2.VolumeSerialNumber) {
837     *res = (0 == memcmp(FileInfo_1.FileId.Identifier,
838                         FileInfo_2.FileId.Identifier,
839                         sizeof(FileInfo_1.FileId.Identifier)));
840   } else {
841     *res = false;
842   }
843 #endif
844   return s;
845 }
846 
LockFile(const std::string & lockFname,FileLock ** lock)847 Status  WinEnvIO::LockFile(const std::string& lockFname,
848                            FileLock** lock) {
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);
863     hFile = RX_CreateFile(RX_FN(lockFname).c_str(),
864                           (GENERIC_READ | GENERIC_WRITE),
865                           ExclusiveAccessON, NULL, CREATE_ALWAYS,
866                           FILE_ATTRIBUTE_NORMAL, NULL);
867   }
868 
869   if (INVALID_HANDLE_VALUE == hFile) {
870     auto lastError = GetLastError();
871     result = IOErrorFromWindowsError(
872         "Failed to create lock file: " + lockFname, lastError);
873   } else {
874     *lock = new WinFileLock(hFile);
875   }
876 
877   return result;
878 }
879 
UnlockFile(FileLock * lock)880 Status WinEnvIO::UnlockFile(FileLock* lock) {
881   Status result;
882 
883   assert(lock != nullptr);
884 
885   delete lock;
886 
887   return result;
888 }
889 
GetTestDirectory(std::string * result)890 Status WinEnvIO::GetTestDirectory(std::string* result) {
891 
892   std::string output;
893 
894   const char* env = getenv("TEST_TMPDIR");
895   if (env && env[0] != '\0') {
896     output = env;
897   } else {
898     env = getenv("TMP");
899 
900     if (env && env[0] != '\0') {
901       output = env;
902     } else {
903       output = "c:\\tmp";
904     }
905   }
906   CreateDir(output);
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 
NewLogger(const std::string & fname,std::shared_ptr<Logger> * result)918 Status WinEnvIO::NewLogger(const std::string& fname,
919                            std::shared_ptr<Logger>* result) {
920   Status s;
921 
922   result->reset();
923 
924   HANDLE hFile = 0;
925   {
926     IOSTATS_TIMER_GUARD(open_nanos);
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);
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 
NowMicros()958 uint64_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;
982   return duration_cast<microseconds>(system_clock::now().time_since_epoch())
983       .count();
984 }
985 
NowNanos()986 uint64_t WinEnvIO::NowNanos() {
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();
1005 }
1006 
GetHostName(char * name,uint64_t len)1007 Status 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 
GetAbsolutePath(const std::string & db_path,std::string * output_path)1022 Status WinEnvIO::GetAbsolutePath(const std::string& db_path,
1023                                  std::string* output_path) {
1024   // Check if we already have an absolute path
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] == '/')) ||
1028     !RX_PathIsRelative(RX_FN(db_path).c_str())) {
1029     *output_path = db_path;
1030     return Status::OK();
1031   }
1032 
1033   RX_FILESTRING result;
1034   result.resize(MAX_PATH);
1035 
1036   // Hopefully no changes the current directory while we do this
1037   // however _getcwd also suffers from the same limitation
1038   DWORD len = RX_GetCurrentDirectory(MAX_PATH, &result[0]);
1039   if (len == 0) {
1040     auto lastError = GetLastError();
1041     return IOErrorFromWindowsError("Failed to get current working directory",
1042                                    lastError);
1043   }
1044 
1045   result.resize(len);
1046   std::string res = FN_TO_RX(result);
1047 
1048   res.swap(*output_path);
1049   return Status::OK();
1050 }
1051 
TimeToString(uint64_t secondsSince1970)1052 std::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 ",
1068                        t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
1069                        t.tm_min, t.tm_sec);
1070     assert(len > 0);
1071 
1072     result.resize(len);
1073   }
1074 
1075   return result;
1076 }
1077 
GetFreeSpace(const std::string & path,uint64_t * diskfree)1078 Status 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 
OptimizeForLogWrite(const EnvOptions & env_options,const DBOptions & db_options) const1092 EnvOptions WinEnvIO::OptimizeForLogWrite(const EnvOptions& env_options,
1093                                          const DBOptions& db_options) const {
1094   EnvOptions optimized(env_options);
1095   // These two the same as default optimizations
1096   optimized.bytes_per_sync = db_options.wal_bytes_per_sync;
1097   optimized.writable_file_max_buffer_size =
1098       db_options.writable_file_max_buffer_size;
1099 
1100   // This adversely affects %999 on windows
1101   optimized.use_mmap_writes = false;
1102   // Direct writes will produce a huge perf impact on
1103   // Windows. Pre-allocate space for WAL.
1104   optimized.use_direct_writes = false;
1105   return optimized;
1106 }
1107 
OptimizeForManifestWrite(const EnvOptions & env_options) const1108 EnvOptions WinEnvIO::OptimizeForManifestWrite(
1109     const EnvOptions& env_options) const {
1110   EnvOptions optimized(env_options);
1111   optimized.use_mmap_writes = false;
1112   optimized.use_direct_reads = false;
1113   return optimized;
1114 }
1115 
OptimizeForManifestRead(const EnvOptions & env_options) const1116 EnvOptions WinEnvIO::OptimizeForManifestRead(
1117     const EnvOptions& env_options) const {
1118   EnvOptions optimized(env_options);
1119   optimized.use_mmap_writes = false;
1120   optimized.use_direct_reads = false;
1121   return optimized;
1122 }
1123 
1124 // Returns true iff the named directory exists and is a directory.
DirExists(const std::string & dname)1125 bool WinEnvIO::DirExists(const std::string& dname) {
1126   WIN32_FILE_ATTRIBUTE_DATA attrs;
1127   if (RX_GetFileAttributesEx(RX_FN(dname).c_str(),
1128                              GetFileExInfoStandard, &attrs)) {
1129     return 0 != (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
1130   }
1131   return false;
1132 }
1133 
GetSectorSize(const std::string & fname)1134 size_t WinEnvIO::GetSectorSize(const std::string& fname) {
1135   size_t sector_size = kSectorSize;
1136 
1137   if (RX_PathIsRelative(RX_FN(fname).c_str())) {
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 
1150   HANDLE hDevice = CreateFile(devicename, 0, 0, nullptr, OPEN_EXISTING,
1151                               FILE_ATTRIBUTE_NORMAL, nullptr);
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,
1165                              &spropertyquery, sizeof(spropertyquery),
1166                              output_buffer,
1167                              sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR),
1168                              &output_bytes, nullptr);
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 
1191 ////////////////////////////////////////////////////////////////////////
1192 // WinEnvThreads
1193 
WinEnvThreads(Env * hosted_env)1194 WinEnvThreads::WinEnvThreads(Env* hosted_env)
1195     : hosted_env_(hosted_env), thread_pools_(Env::Priority::TOTAL) {
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 
~WinEnvThreads()1205 WinEnvThreads::~WinEnvThreads() {
1206 
1207   WaitForJoin();
1208 
1209   for (auto& thpool : thread_pools_) {
1210     thpool.JoinAllThreads();
1211   }
1212 }
1213 
Schedule(void (* function)(void *),void * arg,Env::Priority pri,void * tag,void (* unschedFunction)(void * arg))1214 void WinEnvThreads::Schedule(void(*function)(void*), void* arg,
1215                              Env::Priority pri, void* tag,
1216                              void(*unschedFunction)(void* arg)) {
1217   assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1218   thread_pools_[pri].Schedule(function, arg, tag, unschedFunction);
1219 }
1220 
UnSchedule(void * arg,Env::Priority pri)1221 int WinEnvThreads::UnSchedule(void* arg, Env::Priority pri) {
1222   return thread_pools_[pri].UnSchedule(arg);
1223 }
1224 
1225 namespace {
1226 
1227   struct StartThreadState {
1228     void(*user_function)(void*);
1229     void* arg;
1230   };
1231 
StartThreadWrapper(void * arg)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 
StartThread(void (* function)(void * arg),void * arg)1241 void 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 {
1246     ROCKSDB_NAMESPACE::port::WindowsThread th(&StartThreadWrapper, state.get());
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 
WaitForJoin()1257 void WinEnvThreads::WaitForJoin() {
1258   for (auto& th : threads_to_join_) {
1259     th.join();
1260   }
1261   threads_to_join_.clear();
1262 }
1263 
GetThreadPoolQueueLen(Env::Priority pri) const1264 unsigned int WinEnvThreads::GetThreadPoolQueueLen(Env::Priority pri) const {
1265   assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1266   return thread_pools_[pri].GetQueueLen();
1267 }
1268 
gettid()1269 uint64_t WinEnvThreads::gettid() {
1270   uint64_t thread_id = GetCurrentThreadId();
1271   return thread_id;
1272 }
1273 
GetThreadID() const1274 uint64_t WinEnvThreads::GetThreadID() const { return gettid(); }
1275 
SleepForMicroseconds(int micros)1276 void  WinEnvThreads::SleepForMicroseconds(int micros) {
1277   std::this_thread::sleep_for(std::chrono::microseconds(micros));
1278 }
1279 
SetBackgroundThreads(int num,Env::Priority pri)1280 void WinEnvThreads::SetBackgroundThreads(int num, Env::Priority pri) {
1281   assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1282   thread_pools_[pri].SetBackgroundThreads(num);
1283 }
1284 
GetBackgroundThreads(Env::Priority pri)1285 int WinEnvThreads::GetBackgroundThreads(Env::Priority pri) {
1286   assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1287   return thread_pools_[pri].GetBackgroundThreads();
1288 }
1289 
IncBackgroundThreadsIfNeeded(int num,Env::Priority pri)1290 void WinEnvThreads::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) {
1291   assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1292   thread_pools_[pri].IncBackgroundThreadsIfNeeded(num);
1293 }
1294 
1295 /////////////////////////////////////////////////////////////////////////
1296 // WinEnv
1297 
WinEnv()1298 WinEnv::WinEnv() : winenv_io_(this), winenv_threads_(this) {
1299   // Protected member of the base class
1300   thread_status_updater_ = CreateThreadStatusUpdater();
1301 }
1302 
1303 
~WinEnv()1304 WinEnv::~WinEnv() {
1305   // All threads must be joined before the deletion of
1306   // thread_status_updater_.
1307   delete thread_status_updater_;
1308 }
1309 
GetThreadList(std::vector<ThreadStatus> * thread_list)1310 Status WinEnv::GetThreadList(std::vector<ThreadStatus>* thread_list) {
1311   assert(thread_status_updater_);
1312   return thread_status_updater_->GetThreadList(thread_list);
1313 }
1314 
DeleteFile(const std::string & fname)1315 Status WinEnv::DeleteFile(const std::string& fname) {
1316   return winenv_io_.DeleteFile(fname);
1317 }
1318 
Truncate(const std::string & fname,size_t size)1319 Status WinEnv::Truncate(const std::string& fname, size_t size) {
1320   return winenv_io_.Truncate(fname, size);
1321 }
1322 
GetCurrentTime(int64_t * unix_time)1323 Status WinEnv::GetCurrentTime(int64_t* unix_time) {
1324   return winenv_io_.GetCurrentTime(unix_time);
1325 }
1326 
NewSequentialFile(const std::string & fname,std::unique_ptr<SequentialFile> * result,const EnvOptions & options)1327 Status  WinEnv::NewSequentialFile(const std::string& fname,
1328                                   std::unique_ptr<SequentialFile>* result,
1329                                   const EnvOptions& options) {
1330   return winenv_io_.NewSequentialFile(fname, result, options);
1331 }
1332 
NewRandomAccessFile(const std::string & fname,std::unique_ptr<RandomAccessFile> * result,const EnvOptions & options)1333 Status WinEnv::NewRandomAccessFile(const std::string& fname,
1334                                    std::unique_ptr<RandomAccessFile>* result,
1335                                    const EnvOptions& options) {
1336   return winenv_io_.NewRandomAccessFile(fname, result, options);
1337 }
1338 
NewWritableFile(const std::string & fname,std::unique_ptr<WritableFile> * result,const EnvOptions & options)1339 Status WinEnv::NewWritableFile(const std::string& fname,
1340                                std::unique_ptr<WritableFile>* result,
1341                                const EnvOptions& options) {
1342   return winenv_io_.OpenWritableFile(fname, result, options, false);
1343 }
1344 
ReopenWritableFile(const std::string & fname,std::unique_ptr<WritableFile> * result,const EnvOptions & options)1345 Status WinEnv::ReopenWritableFile(const std::string& fname,
1346                                   std::unique_ptr<WritableFile>* result,
1347                                   const EnvOptions& options) {
1348   return winenv_io_.OpenWritableFile(fname, result, options, true);
1349 }
1350 
NewRandomRWFile(const std::string & fname,std::unique_ptr<RandomRWFile> * result,const EnvOptions & options)1351 Status WinEnv::NewRandomRWFile(const std::string & fname,
1352                                std::unique_ptr<RandomRWFile>* result,
1353                                const EnvOptions & options) {
1354   return winenv_io_.NewRandomRWFile(fname, result, options);
1355 }
1356 
NewMemoryMappedFileBuffer(const std::string & fname,std::unique_ptr<MemoryMappedFileBuffer> * result)1357 Status WinEnv::NewMemoryMappedFileBuffer(
1358     const std::string& fname,
1359     std::unique_ptr<MemoryMappedFileBuffer>* result) {
1360   return winenv_io_.NewMemoryMappedFileBuffer(fname, result);
1361 }
1362 
NewDirectory(const std::string & name,std::unique_ptr<Directory> * result)1363 Status WinEnv::NewDirectory(const std::string& name,
1364                             std::unique_ptr<Directory>* result) {
1365   return winenv_io_.NewDirectory(name, result);
1366 }
1367 
FileExists(const std::string & fname)1368 Status WinEnv::FileExists(const std::string& fname) {
1369   return winenv_io_.FileExists(fname);
1370 }
1371 
GetChildren(const std::string & dir,std::vector<std::string> * result)1372 Status WinEnv::GetChildren(const std::string& dir,
1373                            std::vector<std::string>* result) {
1374   return winenv_io_.GetChildren(dir, result);
1375 }
1376 
CreateDir(const std::string & name)1377 Status WinEnv::CreateDir(const std::string& name) {
1378   return winenv_io_.CreateDir(name);
1379 }
1380 
CreateDirIfMissing(const std::string & name)1381 Status WinEnv::CreateDirIfMissing(const std::string& name) {
1382   return winenv_io_.CreateDirIfMissing(name);
1383 }
1384 
DeleteDir(const std::string & name)1385 Status WinEnv::DeleteDir(const std::string& name) {
1386   return winenv_io_.DeleteDir(name);
1387 }
1388 
GetFileSize(const std::string & fname,uint64_t * size)1389 Status WinEnv::GetFileSize(const std::string& fname,
1390                            uint64_t* size) {
1391   return winenv_io_.GetFileSize(fname, size);
1392 }
1393 
GetFileModificationTime(const std::string & fname,uint64_t * file_mtime)1394 Status  WinEnv::GetFileModificationTime(const std::string& fname,
1395                                         uint64_t* file_mtime) {
1396   return winenv_io_.GetFileModificationTime(fname, file_mtime);
1397 }
1398 
RenameFile(const std::string & src,const std::string & target)1399 Status WinEnv::RenameFile(const std::string& src,
1400                           const std::string& target) {
1401   return winenv_io_.RenameFile(src, target);
1402 }
1403 
LinkFile(const std::string & src,const std::string & target)1404 Status WinEnv::LinkFile(const std::string& src,
1405                         const std::string& target) {
1406   return winenv_io_.LinkFile(src, target);
1407 }
1408 
NumFileLinks(const std::string & fname,uint64_t * count)1409 Status WinEnv::NumFileLinks(const std::string& fname, uint64_t* count) {
1410   return winenv_io_.NumFileLinks(fname, count);
1411 }
1412 
AreFilesSame(const std::string & first,const std::string & second,bool * res)1413 Status WinEnv::AreFilesSame(const std::string& first,
1414                             const std::string& second, bool* res) {
1415   return winenv_io_.AreFilesSame(first, second, res);
1416 }
1417 
LockFile(const std::string & lockFname,FileLock ** lock)1418 Status WinEnv::LockFile(const std::string& lockFname,
1419   FileLock** lock) {
1420   return winenv_io_.LockFile(lockFname, lock);
1421 }
1422 
UnlockFile(FileLock * lock)1423 Status WinEnv::UnlockFile(FileLock* lock) {
1424   return winenv_io_.UnlockFile(lock);
1425 }
1426 
GetTestDirectory(std::string * result)1427 Status  WinEnv::GetTestDirectory(std::string* result) {
1428   return winenv_io_.GetTestDirectory(result);
1429 }
1430 
NewLogger(const std::string & fname,std::shared_ptr<Logger> * result)1431 Status WinEnv::NewLogger(const std::string& fname,
1432                          std::shared_ptr<Logger>* result) {
1433   return winenv_io_.NewLogger(fname, result);
1434 }
1435 
NowMicros()1436 uint64_t WinEnv::NowMicros() {
1437   return winenv_io_.NowMicros();
1438 }
1439 
NowNanos()1440 uint64_t  WinEnv::NowNanos() {
1441   return winenv_io_.NowNanos();
1442 }
1443 
GetHostName(char * name,uint64_t len)1444 Status WinEnv::GetHostName(char* name, uint64_t len) {
1445   return winenv_io_.GetHostName(name, len);
1446 }
1447 
GetAbsolutePath(const std::string & db_path,std::string * output_path)1448 Status WinEnv::GetAbsolutePath(const std::string& db_path,
1449   std::string* output_path) {
1450   return winenv_io_.GetAbsolutePath(db_path, output_path);
1451 }
1452 
TimeToString(uint64_t secondsSince1970)1453 std::string WinEnv::TimeToString(uint64_t secondsSince1970) {
1454   return winenv_io_.TimeToString(secondsSince1970);
1455 }
1456 
Schedule(void (* function)(void *),void * arg,Env::Priority pri,void * tag,void (* unschedFunction)(void * arg))1457 void  WinEnv::Schedule(void(*function)(void*), void* arg, Env::Priority pri,
1458                        void* tag,
1459                        void(*unschedFunction)(void* arg)) {
1460   return winenv_threads_.Schedule(function, arg, pri, tag, unschedFunction);
1461 }
1462 
UnSchedule(void * arg,Env::Priority pri)1463 int WinEnv::UnSchedule(void* arg, Env::Priority pri) {
1464   return winenv_threads_.UnSchedule(arg, pri);
1465 }
1466 
StartThread(void (* function)(void * arg),void * arg)1467 void WinEnv::StartThread(void(*function)(void* arg), void* arg) {
1468   return winenv_threads_.StartThread(function, arg);
1469 }
1470 
WaitForJoin()1471 void WinEnv::WaitForJoin() {
1472   return winenv_threads_.WaitForJoin();
1473 }
1474 
GetThreadPoolQueueLen(Env::Priority pri) const1475 unsigned int  WinEnv::GetThreadPoolQueueLen(Env::Priority pri) const {
1476   return winenv_threads_.GetThreadPoolQueueLen(pri);
1477 }
1478 
GetThreadID() const1479 uint64_t WinEnv::GetThreadID() const {
1480   return winenv_threads_.GetThreadID();
1481 }
1482 
GetFreeSpace(const std::string & path,uint64_t * diskfree)1483 Status WinEnv::GetFreeSpace(const std::string& path, uint64_t* diskfree) {
1484   return winenv_io_.GetFreeSpace(path, diskfree);
1485 }
1486 
SleepForMicroseconds(int micros)1487 void WinEnv::SleepForMicroseconds(int micros) {
1488   return winenv_threads_.SleepForMicroseconds(micros);
1489 }
1490 
1491 // Allow increasing the number of worker threads.
SetBackgroundThreads(int num,Env::Priority pri)1492 void  WinEnv::SetBackgroundThreads(int num, Env::Priority pri) {
1493   return winenv_threads_.SetBackgroundThreads(num, pri);
1494 }
1495 
GetBackgroundThreads(Env::Priority pri)1496 int WinEnv::GetBackgroundThreads(Env::Priority pri) {
1497   return winenv_threads_.GetBackgroundThreads(pri);
1498 }
1499 
IncBackgroundThreadsIfNeeded(int num,Env::Priority pri)1500 void  WinEnv::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) {
1501   return winenv_threads_.IncBackgroundThreadsIfNeeded(num, pri);
1502 }
1503 
OptimizeForManifestRead(const EnvOptions & env_options) const1504 EnvOptions WinEnv::OptimizeForManifestRead(
1505     const EnvOptions& env_options) const {
1506   return winenv_io_.OptimizeForManifestRead(env_options);
1507 }
1508 
OptimizeForLogWrite(const EnvOptions & env_options,const DBOptions & db_options) const1509 EnvOptions WinEnv::OptimizeForLogWrite(const EnvOptions& env_options,
1510                                        const DBOptions& db_options) const {
1511   return winenv_io_.OptimizeForLogWrite(env_options, db_options);
1512 }
1513 
OptimizeForManifestWrite(const EnvOptions & env_options) const1514 EnvOptions WinEnv::OptimizeForManifestWrite(
1515     const EnvOptions& env_options) const {
1516   return winenv_io_.OptimizeForManifestWrite(env_options);
1517 }
1518 
1519 }  // namespace port
1520 
GenerateUniqueId()1521 std::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);
1529   (void)status;
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 
1540 }  // namespace ROCKSDB_NAMESPACE
1541