env_win.cc 44.5 KB
Newer Older
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
S
Siying Dong 已提交
2 3 4
//  This source code is licensed under both the GPLv2 (found in the
//  COPYING file in the root directory) and Apache 2.0 License
//  (found in the LICENSE.Apache file in the root directory).
D
Dmitri Smirnov 已提交
5 6 7 8 9
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

10 11
#if defined(OS_WIN)

A
Aaron Gao 已提交
12
#include "port/win/env_win.h"
D
Dmitri Smirnov 已提交
13

14
#include <direct.h>  // _rmdir, _mkdir, _getcwd
D
Dmitri Smirnov 已提交
15
#include <errno.h>
16 17 18
#include <io.h>   // _access
#include <rpc.h>  // for uuid generation
#include <shlwapi.h>
D
Dmitri Smirnov 已提交
19
#include <sys/stat.h>
20 21
#include <sys/types.h>
#include <windows.h>
D
Dmitri Smirnov 已提交
22

23 24 25
#include <algorithm>
#include <ctime>
#include <thread>
D
Dmitri Smirnov 已提交
26

27 28 29
#include "monitoring/iostats_context_imp.h"
#include "monitoring/thread_status_updater.h"
#include "monitoring/thread_status_util.h"
30 31 32 33 34 35 36
#include "port/port.h"
#include "port/port_dirent.h"
#include "port/win/io_win.h"
#include "port/win/win_logger.h"
#include "port/win/win_thread.h"
#include "rocksdb/env.h"
#include "rocksdb/slice.h"
D
Dmitri Smirnov 已提交
37
#include "strsafe.h"
38
#include "util/string_util.h"
D
Dmitri Smirnov 已提交
39

40 41 42 43
// Undefine the functions  windows might use (again)...
#undef GetCurrentTime
#undef DeleteFile
#undef LoadLibrary
D
Dmitri Smirnov 已提交
44

45
namespace ROCKSDB_NAMESPACE {
D
Dmitri Smirnov 已提交
46 47 48 49 50

ThreadStatusUpdater* CreateThreadStatusUpdater() {
  return new ThreadStatusUpdater();
}

D
Dmitri Smirnov 已提交
51 52
namespace {

53 54
// Sector size used when physical sector size cannot be obtained from device.
static const size_t kSectorSize = 512;
D
Dmitri Smirnov 已提交
55

D
Dmitri Smirnov 已提交
56 57 58 59
// RAII helpers for HANDLEs
const auto CloseHandleFunc = [](HANDLE h) { ::CloseHandle(h); };
typedef std::unique_ptr<void, decltype(CloseHandleFunc)> UniqueCloseHandlePtr;

D
Dmitri Smirnov 已提交
60 61 62
const auto FindCloseFunc = [](HANDLE h) { ::FindClose(h); };
typedef std::unique_ptr<void, decltype(FindCloseFunc)> UniqueFindClosePtr;

63 64
void WinthreadCall(const char* label, std::error_code result) {
  if (0 != result.value()) {
65 66
    fprintf(stderr, "Winthread %s: %s\n", label,
            errnoStr(result.value()).c_str());
67
    abort();
D
Dmitri Smirnov 已提交
68
  }
69
}
D
Dmitri Smirnov 已提交
70

71
}  // namespace
D
Dmitri Smirnov 已提交
72

73
namespace port {
74 75
WinClock::WinClock()
    : perf_counter_frequency_(0),
B
Burton Li 已提交
76
      nano_seconds_per_period_(0),
77 78 79
      GetSystemTimePreciseAsFileTime_(NULL) {
  {
    LARGE_INTEGER qpf;
T
Tamir Duberstein 已提交
80
    BOOL ret __attribute__((__unused__));
81
    ret = QueryPerformanceFrequency(&qpf);
82 83
    assert(ret == TRUE);
    perf_counter_frequency_ = qpf.QuadPart;
B
Burton Li 已提交
84 85 86 87

    if (std::nano::den % perf_counter_frequency_ == 0) {
      nano_seconds_per_period_ = std::nano::den / perf_counter_frequency_;
    }
D
Dmitri Smirnov 已提交
88 89
  }

90 91
  HMODULE module = GetModuleHandle("kernel32.dll");
  if (module != NULL) {
92
    GetSystemTimePreciseAsFileTime_ =
93 94
        (FnGetSystemTimePreciseAsFileTime)GetProcAddress(
            module, "GetSystemTimePreciseAsFileTime");
D
Dmitri Smirnov 已提交
95 96 97
  }
}

98 99
void WinClock::SleepForMicroseconds(int micros) {
  std::this_thread::sleep_for(std::chrono::microseconds(micros));
D
Dmitri Smirnov 已提交
100 101
}

102 103
std::string WinClock::TimeToString(uint64_t secondsSince1970) {
  std::string result;
D
Dmitri Smirnov 已提交
104

105 106
  const time_t seconds = secondsSince1970;
  const int maxsize = 64;
107

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
  struct tm t;
  errno_t ret = localtime_s(&t, &seconds);

  if (ret) {
    result = std::to_string(seconds);
  } else {
    result.resize(maxsize);
    char* p = &result[0];

    int len =
        snprintf(p, maxsize, "%04d/%02d/%02d-%02d:%02d:%02d ", t.tm_year + 1900,
                 t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
    assert(len > 0);

    result.resize(len);
D
Dmitri Smirnov 已提交
123 124
  }

125
  return result;
D
Dmitri Smirnov 已提交
126 127
}

128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
uint64_t WinClock::NowMicros() {
  if (GetSystemTimePreciseAsFileTime_ != NULL) {
    // all std::chrono clocks on windows proved to return
    // values that may repeat that is not good enough for some uses.
    const int64_t c_UnixEpochStartTicks = 116444736000000000LL;
    const int64_t c_FtToMicroSec = 10;

    // This interface needs to return system time and not
    // just any microseconds because it is often used as an argument
    // to TimedWait() on condition variable
    FILETIME ftSystemTime;
    GetSystemTimePreciseAsFileTime_(&ftSystemTime);

    LARGE_INTEGER li;
    li.LowPart = ftSystemTime.dwLowDateTime;
    li.HighPart = ftSystemTime.dwHighDateTime;
    // Subtract unix epoch start
    li.QuadPart -= c_UnixEpochStartTicks;
    // Convert to microsecs
    li.QuadPart /= c_FtToMicroSec;
    return li.QuadPart;
D
Dmitri Smirnov 已提交
149
  }
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
  using namespace std::chrono;
  return duration_cast<microseconds>(system_clock::now().time_since_epoch())
      .count();
}

uint64_t WinClock::NowNanos() {
  if (nano_seconds_per_period_ != 0) {
    // all std::chrono clocks on windows have the same resolution that is only
    // good enough for microseconds but not nanoseconds
    // On Windows 8 and Windows 2012 Server
    // GetSystemTimePreciseAsFileTime(&current_time) can be used
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    // Convert performance counter to nanoseconds by precomputed ratio.
    // Directly multiply nano::den with li.QuadPart causes overflow.
    // Only do this when nano::den is divisible by perf_counter_frequency_,
    // which most likely is the case in reality. If it's not, fall back to
    // high_resolution_clock, which may be less precise under old compilers.
    li.QuadPart *= nano_seconds_per_period_;
    return li.QuadPart;
  }
  using namespace std::chrono;
  return duration_cast<nanoseconds>(
             high_resolution_clock::now().time_since_epoch())
      .count();
D
Dmitri Smirnov 已提交
175 176
}

177
Status WinClock::GetCurrentTime(int64_t* unix_time) {
178 179 180
  time_t time = std::time(nullptr);
  if (time == (time_t)(-1)) {
    return Status::NotSupported("Failed to get time");
D
Dmitri Smirnov 已提交
181 182
  }

183 184
  *unix_time = time;
  return Status::OK();
D
Dmitri Smirnov 已提交
185 186
}

187
WinFileSystem::WinFileSystem(const std::shared_ptr<SystemClock>& clock)
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
    : clock_(clock), page_size_(4 * 1024), allocation_granularity_(page_size_) {
  SYSTEM_INFO sinfo;
  GetSystemInfo(&sinfo);

  page_size_ = sinfo.dwPageSize;
  allocation_granularity_ = sinfo.dwAllocationGranularity;
}

const std::shared_ptr<WinFileSystem>& WinFileSystem::Default() {
  static std::shared_ptr<WinFileSystem> fs =
      std::make_shared<WinFileSystem>(WinClock::Default());
  return fs;
}

WinEnvIO::WinEnvIO(Env* hosted_env) : hosted_env_(hosted_env) {}

WinEnvIO::~WinEnvIO() {}

IOStatus WinFileSystem::DeleteFile(const std::string& fname,
                                   const IOOptions& /*options*/,
                                   IODebugContext* /*dbg*/) {
  IOStatus result;

  BOOL ret = RX_DeleteFile(RX_FN(fname).c_str());

  if (!ret) {
    auto lastError = GetLastError();
    result = IOErrorFromWindowsError("Failed to delete: " + fname, lastError);
  }

  return result;
}

IOStatus WinFileSystem::Truncate(const std::string& fname, size_t size,
                                 const IOOptions& /*options*/,
                                 IODebugContext* /*dbg*/) {
  IOStatus s;
  int result = ROCKSDB_NAMESPACE::port::Truncate(fname, size);
  if (result != 0) {
    s = IOError("Failed to truncate: " + fname, errno);
  }
  return s;
}

IOStatus WinFileSystem::NewSequentialFile(
    const std::string& fname, const FileOptions& options,
    std::unique_ptr<FSSequentialFile>* result, IODebugContext* /*dbg*/) {
  IOStatus s;
D
Dmitri Smirnov 已提交
236

237
  result->reset();
D
Dmitri Smirnov 已提交
238

239 240 241 242
  // Corruption test needs to rename and delete files of these kind
  // while they are still open with another handle. For that reason we
  // allow share_write and delete(allows rename).
  HANDLE hFile = INVALID_HANDLE_VALUE;
D
Dmitri Smirnov 已提交
243 244 245 246 247 248 249

  DWORD fileFlags = FILE_ATTRIBUTE_READONLY;

  if (options.use_direct_reads && !options.use_mmap_reads) {
    fileFlags |= FILE_FLAG_NO_BUFFERING;
  }

250 251
  {
    IOSTATS_TIMER_GUARD(open_nanos);
252
    hFile = RX_CreateFile(
253 254 255 256
        RX_FN(fname).c_str(), GENERIC_READ,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
        OPEN_EXISTING,  // Original fopen mode is "rb"
        fileFlags, NULL);
257
  }
D
Dmitri Smirnov 已提交
258

259 260 261
  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError("Failed to open NewSequentialFile" + fname,
262
                                lastError);
263 264
  } else {
    result->reset(new WinSequentialFile(fname, hFile, options));
D
Dmitri Smirnov 已提交
265
  }
266 267
  return s;
}
D
Dmitri Smirnov 已提交
268

269 270 271
IOStatus WinFileSystem::NewRandomAccessFile(
    const std::string& fname, const FileOptions& options,
    std::unique_ptr<FSRandomAccessFile>* result, IODebugContext* dbg) {
272
  result->reset();
273
  IOStatus s;
D
Dmitri Smirnov 已提交
274

275 276 277
  // Open the file for read-only random access
  // Random access is to disable read-ahead as the system reads too much data
  DWORD fileFlags = FILE_ATTRIBUTE_READONLY;
D
Dmitri Smirnov 已提交
278

A
Aaron Gao 已提交
279
  if (options.use_direct_reads && !options.use_mmap_reads) {
280 281 282
    fileFlags |= FILE_FLAG_NO_BUFFERING;
  } else {
    fileFlags |= FILE_FLAG_RANDOM_ACCESS;
D
Dmitri Smirnov 已提交
283
  }
D
Dmitri Smirnov 已提交
284

285 286 287 288 289
  /// Shared access is necessary for corruption test to pass
  // almost all tests would work with a possible exception of fault_injection
  HANDLE hFile = 0;
  {
    IOSTATS_TIMER_GUARD(open_nanos);
290 291 292 293
    hFile =
        RX_CreateFile(RX_FN(fname).c_str(), GENERIC_READ,
                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                      NULL, OPEN_EXISTING, fileFlags, NULL);
D
Dmitri Smirnov 已提交
294 295
  }

296 297 298
  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError(
299
        "NewRandomAccessFile failed to Create/Open: " + fname, lastError);
D
Dmitri Smirnov 已提交
300 301
  }

302
  UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);
D
Dmitri Smirnov 已提交
303

304 305 306 307
  // CAUTION! This will map the entire file into the process address space
  if (options.use_mmap_reads && sizeof(void*) >= 8) {
    // Use mmap when virtual address-space is plentiful.
    uint64_t fileSize;
D
Dmitri Smirnov 已提交
308

309
    s = GetFileSize(fname, IOOptions(), &fileSize, dbg);
310

311 312 313
    if (s.ok()) {
      // Will not map empty files
      if (fileSize == 0) {
314 315
        return IOError("NewRandomAccessFile failed to map empty file: " + fname,
                       EINVAL);
D
Dmitri Smirnov 已提交
316
      }
317

318
      HANDLE hMap = RX_CreateFileMapping(hFile, NULL, PAGE_READONLY,
319 320 321
                                         0,  // At its present length
                                         0,
                                         NULL);  // Mapping name
D
Dmitri Smirnov 已提交
322

323 324 325
      if (!hMap) {
        auto lastError = GetLastError();
        return IOErrorFromWindowsError(
326 327
            "Failed to create file mapping for NewRandomAccessFile: " + fname,
            lastError);
D
Dmitri Smirnov 已提交
328 329
      }

330
      UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc);
D
Dmitri Smirnov 已提交
331

332
      const void* mapped_region =
333 334 335 336 337
          MapViewOfFileEx(hMap, FILE_MAP_READ,
                          0,  // High DWORD of access start
                          0,  // Low DWORD
                          static_cast<SIZE_T>(fileSize),
                          NULL);  // Let the OS choose the mapping
D
Dmitri Smirnov 已提交
338

339 340
      if (!mapped_region) {
        auto lastError = GetLastError();
S
sdong 已提交
341
        return IOErrorFromWindowsError(
342 343
            "Failed to MapViewOfFile for NewRandomAccessFile: " + fname,
            lastError);
S
sdong 已提交
344
      }
345

346
      result->reset(new WinMmapReadableFile(fname, hFile, hMap, mapped_region,
347
                                            static_cast<size_t>(fileSize)));
348 349 350

      mapGuard.release();
      fileGuard.release();
D
Dmitri Smirnov 已提交
351
    }
352
  } else {
353 354
    result->reset(new WinRandomAccessFile(
        fname, hFile, std::max(GetSectorSize(fname), page_size_), options));
355 356 357 358
    fileGuard.release();
  }
  return s;
}
D
Dmitri Smirnov 已提交
359

360 361 362
IOStatus WinFileSystem::OpenWritableFile(
    const std::string& fname, const FileOptions& options,
    std::unique_ptr<FSWritableFile>* result, bool reopen) {
363
  const size_t c_BufferCapacity = 64 * 1024;
D
Dmitri Smirnov 已提交
364

365
  EnvOptions local_options(options);
D
Dmitri Smirnov 已提交
366

367
  result->reset();
368
  IOStatus s;
D
Dmitri Smirnov 已提交
369

370
  DWORD fileFlags = FILE_ATTRIBUTE_NORMAL;
D
Dmitri Smirnov 已提交
371

A
Aaron Gao 已提交
372
  if (local_options.use_direct_writes && !local_options.use_mmap_writes) {
373
    fileFlags = FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
D
Dmitri Smirnov 已提交
374 375
  }

376 377 378 379 380 381 382
  // Desired access. We are want to write only here but if we want to memory
  // map
  // the file then there is no write only mode so we have to create it
  // Read/Write
  // However, MapViewOfFile specifies only Write only
  DWORD desired_access = GENERIC_WRITE;
  DWORD shared_mode = FILE_SHARE_READ;
D
Dmitri Smirnov 已提交
383

384 385
  if (local_options.use_mmap_writes) {
    desired_access |= GENERIC_READ;
D
Dmitri Smirnov 已提交
386
  } else {
387 388 389 390
    // Adding this solely for tests to pass (fault_injection_test,
    // wal_manager_test).
    shared_mode |= (FILE_SHARE_WRITE | FILE_SHARE_DELETE);
  }
D
Dmitri Smirnov 已提交
391

392 393 394 395 396 397
  // This will always truncate the file
  DWORD creation_disposition = CREATE_ALWAYS;
  if (reopen) {
    creation_disposition = OPEN_ALWAYS;
  }

398 399 400
  HANDLE hFile = 0;
  {
    IOSTATS_TIMER_GUARD(open_nanos);
401
    hFile = RX_CreateFile(
402 403 404
        RX_FN(fname).c_str(),
        desired_access,  // Access desired
        shared_mode,
405
        NULL,  // Security attributes
406 407
        // Posix env says (reopen) ? (O_CREATE | O_APPEND) : O_CREAT | O_TRUNC
        creation_disposition,
408 409
        fileFlags,  // Flags
        NULL);      // Template File
410 411 412 413 414
  }

  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError(
415
        "Failed to create a NewWriteableFile: " + fname, lastError);
D
Dmitri Smirnov 已提交
416 417
  }

418 419 420 421 422 423 424 425
  // We will start writing at the end, appending
  if (reopen) {
    LARGE_INTEGER zero_move;
    zero_move.QuadPart = 0;
    BOOL ret = SetFilePointerEx(hFile, zero_move, NULL, FILE_END);
    if (!ret) {
      auto lastError = GetLastError();
      return IOErrorFromWindowsError(
426 427
          "Failed to create a ReopenWritableFile move to the end: " + fname,
          lastError);
428 429 430
    }
  }

431 432 433 434
  if (options.use_mmap_writes) {
    // We usually do not use mmmapping on SSD and thus we pass memory
    // page_size
    result->reset(new WinMmapFile(fname, hFile, page_size_,
435
                                  allocation_granularity_, local_options));
436 437 438
  } else {
    // Here we want the buffer allocation to be aligned by the SSD page size
    // and to be a multiple of it
439 440 441
    result->reset(new WinWritableFile(
        fname, hFile, std::max(GetSectorSize(fname), GetPageSize()),
        c_BufferCapacity, local_options));
442
  }
443 444
  return s;
}
445

446 447 448 449 450 451
IOStatus WinFileSystem::NewWritableFile(const std::string& fname,
                                        const FileOptions& options,
                                        std::unique_ptr<FSWritableFile>* result,
                                        IODebugContext* /*dbg*/) {
  return OpenWritableFile(fname, options, result, false);
}
452

453 454 455 456 457 458 459 460 461 462 463
IOStatus WinFileSystem::ReopenWritableFile(
    const std::string& fname, const FileOptions& options,
    std::unique_ptr<FSWritableFile>* result, IODebugContext* /*dbg*/) {
  return OpenWritableFile(fname, options, result, true);
}

IOStatus WinFileSystem::NewRandomRWFile(const std::string& fname,
                                        const FileOptions& options,
                                        std::unique_ptr<FSRandomRWFile>* result,
                                        IODebugContext* /*dbg*/) {
  IOStatus s;
464 465 466 467 468

  // Open the file for read-only random access
  // Random access is to disable read-ahead as the system reads too much data
  DWORD desired_access = GENERIC_READ | GENERIC_WRITE;
  DWORD shared_mode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
469
  DWORD creation_disposition = OPEN_EXISTING;  // Fail if file does not exist
470 471
  DWORD file_flags = FILE_FLAG_RANDOM_ACCESS;

A
Aaron Gao 已提交
472
  if (options.use_direct_reads && options.use_direct_writes) {
473 474 475 476 477 478 479 480
    file_flags |= FILE_FLAG_NO_BUFFERING;
  }

  /// Shared access is necessary for corruption test to pass
  // almost all tests would work with a possible exception of fault_injection
  HANDLE hFile = 0;
  {
    IOSTATS_TIMER_GUARD(open_nanos);
481 482 483
    hFile = RX_CreateFile(RX_FN(fname).c_str(), desired_access, shared_mode,
                          NULL,  // Security attributes
                          creation_disposition, file_flags, NULL);
484 485 486 487 488
  }

  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError(
489
        "NewRandomRWFile failed to Create/Open: " + fname, lastError);
490 491 492
  }

  UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);
493 494
  result->reset(new WinRandomRWFile(
      fname, hFile, std::max(GetSectorSize(fname), GetPageSize()), options));
495 496 497 498 499
  fileGuard.release();

  return s;
}

500 501 502
IOStatus WinFileSystem::NewMemoryMappedFileBuffer(
    const std::string& fname, std::unique_ptr<MemoryMappedFileBuffer>* result) {
  IOStatus s;
D
Dmitri Smirnov 已提交
503 504 505 506 507 508 509
  result->reset();

  DWORD fileFlags = FILE_ATTRIBUTE_READONLY;

  HANDLE hFile = INVALID_HANDLE_VALUE;
  {
    IOSTATS_TIMER_GUARD(open_nanos);
510
    hFile = RX_CreateFile(
511
        RX_FN(fname).c_str(), GENERIC_READ | GENERIC_WRITE,
512
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
513
        OPEN_EXISTING,  // Open only if it exists
514
        fileFlags, NULL);
D
Dmitri Smirnov 已提交
515 516 517 518
  }

  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
519 520
    s = IOErrorFromWindowsError(
        "Failed to open NewMemoryMappedFileBuffer: " + fname, lastError);
D
Dmitri Smirnov 已提交
521 522 523 524 525
    return s;
  }
  UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);

  uint64_t fileSize = 0;
526
  s = GetFileSize(fname, IOOptions(), &fileSize, nullptr);
D
Dmitri Smirnov 已提交
527 528 529 530 531
  if (!s.ok()) {
    return s;
  }
  // Will not map empty files
  if (fileSize == 0) {
532
    return IOStatus::NotSupported(
533
        "NewMemoryMappedFileBuffer can not map zero length files: " + fname);
D
Dmitri Smirnov 已提交
534 535 536 537
  }

  // size_t is 32-bit with 32-bit builds
  if (fileSize > std::numeric_limits<size_t>::max()) {
538 539 540
    return IOStatus::NotSupported(
        "The specified file size does not fit into 32-bit memory addressing: " +
        fname);
D
Dmitri Smirnov 已提交
541 542
  }

543
  HANDLE hMap = RX_CreateFileMapping(hFile, NULL, PAGE_READWRITE,
544 545 546
                                     0,  // Whole file at its present length
                                     0,
                                     NULL);  // Mapping name
D
Dmitri Smirnov 已提交
547 548 549 550

  if (!hMap) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError(
551
        "Failed to create file mapping for: " + fname, lastError);
D
Dmitri Smirnov 已提交
552 553 554 555
  }
  UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc);

  void* base = MapViewOfFileEx(hMap, FILE_MAP_WRITE,
556 557 558 559
                               0,  // High DWORD of access start
                               0,  // Low DWORD
                               static_cast<SIZE_T>(fileSize),
                               NULL);  // Let the OS choose the mapping
D
Dmitri Smirnov 已提交
560 561 562 563

  if (!base) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError(
564 565
        "Failed to MapViewOfFile for NewMemoryMappedFileBuffer: " + fname,
        lastError);
D
Dmitri Smirnov 已提交
566 567
  }

568 569
  result->reset(new WinMemoryMappedBuffer(hFile, hMap, base,
                                          static_cast<size_t>(fileSize)));
D
Dmitri Smirnov 已提交
570 571 572 573 574 575 576

  mapGuard.release();
  fileGuard.release();

  return s;
}

577 578 579 580 581
IOStatus WinFileSystem::NewDirectory(const std::string& name,
                                     const IOOptions& /*options*/,
                                     std::unique_ptr<FSDirectory>* result,
                                     IODebugContext* /*dbg*/) {
  IOStatus s;
582 583
  // Must be nullptr on failure
  result->reset();
D
Dmitri Smirnov 已提交
584

585
  if (!DirExists(name)) {
586
    s = IOErrorFromWindowsError("open folder: " + name, ERROR_DIRECTORY);
D
Dmitri Smirnov 已提交
587 588 589 590 591 592
    return s;
  }

  HANDLE handle = INVALID_HANDLE_VALUE;
  // 0 - for access means read metadata
  {
593
    IOSTATS_TIMER_GUARD(open_nanos);
594 595
    handle = RX_CreateFile(
        RX_FN(name).c_str(), 0,
596
        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
597
        OPEN_EXISTING,
598
        FILE_FLAG_BACKUP_SEMANTICS,  // make opening folders possible
599
        NULL);
600
  }
D
Dmitri Smirnov 已提交
601 602 603

  if (INVALID_HANDLE_VALUE == handle) {
    auto lastError = GetLastError();
604
    s = IOErrorFromWindowsError("open folder: " + name, lastError);
D
Dmitri Smirnov 已提交
605 606 607 608 609
    return s;
  }

  result->reset(new WinDirectory(handle));

610 611
  return s;
}
D
Dmitri Smirnov 已提交
612

613 614 615 616
IOStatus WinFileSystem::FileExists(const std::string& fname,
                                   const IOOptions& /*opts*/,
                                   IODebugContext* /*dbg*/) {
  IOStatus s;
D
Dmitri Smirnov 已提交
617 618 619 620
  // TODO: This does not follow symbolic links at this point
  // which is consistent with _access() impl on windows
  // but can be added
  WIN32_FILE_ATTRIBUTE_DATA attrs;
621 622
  if (FALSE == RX_GetFileAttributesEx(RX_FN(fname).c_str(),
                                      GetFileExInfoStandard, &attrs)) {
D
Dmitri Smirnov 已提交
623 624
    auto lastError = GetLastError();
    switch (lastError) {
625 626 627 628 629 630 631 632 633 634
      case ERROR_ACCESS_DENIED:
      case ERROR_NOT_FOUND:
      case ERROR_FILE_NOT_FOUND:
      case ERROR_PATH_NOT_FOUND:
        s = IOStatus::NotFound();
        break;
      default:
        s = IOErrorFromWindowsError("Unexpected error for: " + fname,
                                    lastError);
        break;
D
Dmitri Smirnov 已提交
635 636 637
    }
  }
  return s;
638
}
D
Dmitri Smirnov 已提交
639

640 641 642 643 644
IOStatus WinFileSystem::GetChildren(const std::string& dir,
                                    const IOOptions& /*opts*/,
                                    std::vector<std::string>* result,
                                    IODebugContext* /*dbg*/) {
  IOStatus status;
D
Dmitri Smirnov 已提交
645
  result->clear();
D
Dmitri Smirnov 已提交
646

647 648
  RX_WIN32_FIND_DATA data;
  memset(&data, 0, sizeof(data));
D
Dmitri Smirnov 已提交
649 650
  std::string pattern(dir);
  pattern.append("\\").append("*");
D
Dmitri Smirnov 已提交
651

652 653 654 655 656 657
  HANDLE handle =
      RX_FindFirstFileEx(RX_FN(pattern).c_str(),
                         // Do not want alternative name
                         FindExInfoBasic, &data, FindExSearchNameMatch,
                         NULL,  // lpSearchFilter
                         0);
D
Dmitri Smirnov 已提交
658

D
Dmitri Smirnov 已提交
659 660 661
  if (handle == INVALID_HANDLE_VALUE) {
    auto lastError = GetLastError();
    switch (lastError) {
662 663 664 665 666 667 668 669 670
      case ERROR_NOT_FOUND:
      case ERROR_ACCESS_DENIED:
      case ERROR_FILE_NOT_FOUND:
      case ERROR_PATH_NOT_FOUND:
        status = IOStatus::NotFound();
        break;
      default:
        status = IOErrorFromWindowsError("Failed to GetChhildren for: " + dir,
                                         lastError);
671
    }
D
Dmitri Smirnov 已提交
672
    return status;
673
  }
674

D
Dmitri Smirnov 已提交
675 676 677 678 679 680
  UniqueFindClosePtr fc(handle, FindCloseFunc);

  // For safety
  data.cFileName[MAX_PATH - 1] = 0;

  while (true) {
681 682 683 684 685 686 687 688 689 690
    // filter out '.' and '..' directory entries
    // which appear only on some platforms
    const bool ignore =
        ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) &&
        (strcmp(data.cFileName, ".") == 0 || strcmp(data.cFileName, "..") == 0);
    if (!ignore) {
      auto x = RX_FILESTRING(data.cFileName, RX_FNLEN(data.cFileName));
      result->push_back(FN_TO_RX(x));
    }

691
    BOOL ret = -RX_FindNextFile(handle, &data);
D
Dmitri Smirnov 已提交
692 693 694 695 696 697 698 699
    // If the function fails the return value is zero
    // and non-zero otherwise. Not TRUE or FALSE.
    if (ret == FALSE) {
      // Posix does not care why we stopped
      break;
    }
    data.cFileName[MAX_PATH - 1] = 0;
  }
700 701
  return status;
}
D
Dmitri Smirnov 已提交
702

703 704 705 706
IOStatus WinFileSystem::CreateDir(const std::string& name,
                                  const IOOptions& /*opts*/,
                                  IODebugContext* /*dbg*/) {
  IOStatus result;
707
  BOOL ret = RX_CreateDirectory(RX_FN(name).c_str(), NULL);
D
Dmitri Smirnov 已提交
708 709
  if (!ret) {
    auto lastError = GetLastError();
710 711
    result = IOErrorFromWindowsError("Failed to create a directory: " + name,
                                     lastError);
D
Dmitri Smirnov 已提交
712 713
  }

714 715
  return result;
}
D
Dmitri Smirnov 已提交
716

717 718 719 720
IOStatus WinFileSystem::CreateDirIfMissing(const std::string& name,
                                           const IOOptions& /*opts*/,
                                           IODebugContext* /*dbg*/) {
  IOStatus result;
721

D
Dmitri Smirnov 已提交
722 723 724 725
  if (DirExists(name)) {
    return result;
  }

726
  BOOL ret = RX_CreateDirectory(RX_FN(name).c_str(), NULL);
D
Dmitri Smirnov 已提交
727 728 729
  if (!ret) {
    auto lastError = GetLastError();
    if (lastError != ERROR_ALREADY_EXISTS) {
730 731
      result = IOErrorFromWindowsError("Failed to create a directory: " + name,
                                       lastError);
D
Dmitri Smirnov 已提交
732
    } else {
733
      result = IOStatus::IOError(name + ": exists but is not a directory");
D
Dmitri Smirnov 已提交
734 735
    }
  }
736 737
  return result;
}
D
Dmitri Smirnov 已提交
738

739 740 741 742
IOStatus WinFileSystem::DeleteDir(const std::string& name,
                                  const IOOptions& /*options*/,
                                  IODebugContext* /*dbg*/) {
  IOStatus result;
743
  BOOL ret = RX_RemoveDirectory(RX_FN(name).c_str());
D
Dmitri Smirnov 已提交
744 745
  if (!ret) {
    auto lastError = GetLastError();
746 747
    result =
        IOErrorFromWindowsError("Failed to remove dir: " + name, lastError);
D
Dmitri Smirnov 已提交
748
  }
749 750
  return result;
}
D
Dmitri Smirnov 已提交
751

752 753 754 755
IOStatus WinFileSystem::GetFileSize(const std::string& fname,
                                    const IOOptions& /*opts*/, uint64_t* size,
                                    IODebugContext* /*dbg*/) {
  IOStatus s;
756

757
  WIN32_FILE_ATTRIBUTE_DATA attrs;
758 759
  if (RX_GetFileAttributesEx(RX_FN(fname).c_str(), GetFileExInfoStandard,
                             &attrs)) {
760 761 762 763 764 765 766
    ULARGE_INTEGER file_size;
    file_size.HighPart = attrs.nFileSizeHigh;
    file_size.LowPart = attrs.nFileSizeLow;
    *size = file_size.QuadPart;
  } else {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError("Can not get size for: " + fname, lastError);
D
Dmitri Smirnov 已提交
767
  }
768 769
  return s;
}
D
Dmitri Smirnov 已提交
770

771
uint64_t WinFileSystem::FileTimeToUnixTime(const FILETIME& ftTime) {
772 773 774 775 776 777 778 779 780 781 782 783 784
  const uint64_t c_FileTimePerSecond = 10000000U;
  // UNIX epoch starts on 1970-01-01T00:00:00Z
  // Windows FILETIME starts on 1601-01-01T00:00:00Z
  // Therefore, we need to subtract the below number of seconds from
  // the seconds that we obtain from FILETIME with an obvious loss of
  // precision
  const uint64_t c_SecondBeforeUnixEpoch = 11644473600U;

  ULARGE_INTEGER li;
  li.HighPart = ftTime.dwHighDateTime;
  li.LowPart = ftTime.dwLowDateTime;

  uint64_t result =
785
      (li.QuadPart / c_FileTimePerSecond) - c_SecondBeforeUnixEpoch;
786 787 788
  return result;
}

789 790 791 792 793
IOStatus WinFileSystem::GetFileModificationTime(const std::string& fname,
                                                const IOOptions& /*opts*/,
                                                uint64_t* file_mtime,
                                                IODebugContext* /*dbg*/) {
  IOStatus s;
794 795

  WIN32_FILE_ATTRIBUTE_DATA attrs;
796
  if (RX_GetFileAttributesEx(RX_FN(fname).c_str(), GetFileExInfoStandard,
797
                             &attrs)) {
798 799 800 801
    *file_mtime = FileTimeToUnixTime(attrs.ftLastWriteTime);
  } else {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError(
802
        "Can not get file modification time for: " + fname, lastError);
803
    *file_mtime = 0;
D
Dmitri Smirnov 已提交
804 805
  }

806 807
  return s;
}
D
Dmitri Smirnov 已提交
808

809 810 811 812 813
IOStatus WinFileSystem::RenameFile(const std::string& src,
                                   const std::string& target,
                                   const IOOptions& /*opts*/,
                                   IODebugContext* /*dbg*/) {
  IOStatus result;
814

815 816
  // rename() is not capable of replacing the existing file as on Linux
  // so use OS API directly
817 818
  if (!RX_MoveFileEx(RX_FN(src).c_str(), RX_FN(target).c_str(),
                     MOVEFILE_REPLACE_EXISTING)) {
819
    DWORD lastError = GetLastError();
D
Dmitri Smirnov 已提交
820

821 822
    std::string text("Failed to rename: ");
    text.append(src).append(" to: ").append(target);
D
Dmitri Smirnov 已提交
823

824
    result = IOErrorFromWindowsError(text, lastError);
D
Dmitri Smirnov 已提交
825 826
  }

827 828
  return result;
}
829

830 831 832 833 834
IOStatus WinFileSystem::LinkFile(const std::string& src,
                                 const std::string& target,
                                 const IOOptions& /*opts*/,
                                 IODebugContext* /*dbg*/) {
  IOStatus result;
D
Dmitri Smirnov 已提交
835

836
  if (!RX_CreateHardLink(RX_FN(target).c_str(), RX_FN(src).c_str(), NULL)) {
837
    DWORD lastError = GetLastError();
838
    if (lastError == ERROR_NOT_SAME_DEVICE) {
839
      return IOStatus::NotSupported("No cross FS links allowed");
840
    }
841

842 843
    std::string text("Failed to link: ");
    text.append(src).append(" to: ").append(target);
844

845
    result = IOErrorFromWindowsError(text, lastError);
846 847
  }

848 849
  return result;
}
850

851 852 853 854 855 856 857 858
IOStatus WinFileSystem::NumFileLinks(const std::string& fname,
                                     const IOOptions& /*opts*/, uint64_t* count,
                                     IODebugContext* /*dbg*/) {
  IOStatus s;
  HANDLE handle =
      RX_CreateFile(RX_FN(fname).c_str(), 0,
                    FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
                    NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
859 860 861

  if (INVALID_HANDLE_VALUE == handle) {
    auto lastError = GetLastError();
862
    s = IOErrorFromWindowsError("NumFileLinks: " + fname, lastError);
863 864 865 866
    return s;
  }
  UniqueCloseHandlePtr handle_guard(handle, CloseHandleFunc);
  FILE_STANDARD_INFO standard_info;
867 868 869
  if (0 != GetFileInformationByHandleEx(handle, FileStandardInfo,
                                        &standard_info,
                                        sizeof(standard_info))) {
870 871 872
    *count = standard_info.NumberOfLinks;
  } else {
    auto lastError = GetLastError();
873 874
    s = IOErrorFromWindowsError("GetFileInformationByHandleEx: " + fname,
                                lastError);
875 876 877 878
  }
  return s;
}

879 880 881 882
IOStatus WinFileSystem::AreFilesSame(const std::string& first,
                                     const std::string& second,
                                     const IOOptions& /*opts*/, bool* res,
                                     IODebugContext* /*dbg*/) {
D
Dmitri Smirnov 已提交
883 884
// For MinGW builds
#if (_WIN32_WINNT == _WIN32_WINNT_VISTA)
885
  IOStatus s = IOStatus::NotSupported();
D
Dmitri Smirnov 已提交
886 887
#else
  assert(res != nullptr);
888
  IOStatus s;
D
Dmitri Smirnov 已提交
889
  if (res == nullptr) {
890
    s = IOStatus::InvalidArgument("res");
D
Dmitri Smirnov 已提交
891 892 893 894
    return s;
  }

  // 0 - for access means read metadata
895 896
  HANDLE file_1 = RX_CreateFile(
      RX_FN(first).c_str(), 0,
897
      FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
898
      OPEN_EXISTING,
899
      FILE_FLAG_BACKUP_SEMANTICS,  // make opening folders possible
900
      NULL);
D
Dmitri Smirnov 已提交
901 902 903

  if (INVALID_HANDLE_VALUE == file_1) {
    auto lastError = GetLastError();
904
    s = IOErrorFromWindowsError("open file: " + first, lastError);
D
Dmitri Smirnov 已提交
905 906 907 908
    return s;
  }
  UniqueCloseHandlePtr g_1(file_1, CloseHandleFunc);

909 910
  HANDLE file_2 = RX_CreateFile(
      RX_FN(second).c_str(), 0,
911 912 913
      FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
      OPEN_EXISTING,
      FILE_FLAG_BACKUP_SEMANTICS,  // make opening folders possible
914
      NULL);
D
Dmitri Smirnov 已提交
915 916 917

  if (INVALID_HANDLE_VALUE == file_2) {
    auto lastError = GetLastError();
918
    s = IOErrorFromWindowsError("open file: " + second, lastError);
D
Dmitri Smirnov 已提交
919 920 921 922 923 924
    return s;
  }
  UniqueCloseHandlePtr g_2(file_2, CloseHandleFunc);

  FILE_ID_INFO FileInfo_1;
  BOOL result = GetFileInformationByHandleEx(file_1, FileIdInfo, &FileInfo_1,
925
                                             sizeof(FileInfo_1));
D
Dmitri Smirnov 已提交
926 927 928

  if (!result) {
    auto lastError = GetLastError();
929
    s = IOErrorFromWindowsError("stat file: " + first, lastError);
D
Dmitri Smirnov 已提交
930 931 932
    return s;
  }

933 934 935
  FILE_ID_INFO FileInfo_2;
  result = GetFileInformationByHandleEx(file_2, FileIdInfo, &FileInfo_2,
                                        sizeof(FileInfo_2));
D
Dmitri Smirnov 已提交
936 937 938

  if (!result) {
    auto lastError = GetLastError();
939
    s = IOErrorFromWindowsError("stat file: " + second, lastError);
D
Dmitri Smirnov 已提交
940 941 942 943
    return s;
  }

  if (FileInfo_1.VolumeSerialNumber == FileInfo_2.VolumeSerialNumber) {
944 945 946
    *res =
        (0 == memcmp(FileInfo_1.FileId.Identifier, FileInfo_2.FileId.Identifier,
                     sizeof(FileInfo_1.FileId.Identifier)));
D
Dmitri Smirnov 已提交
947 948 949 950 951 952 953
  } else {
    *res = false;
  }
#endif
  return s;
}

954 955 956
IOStatus WinFileSystem::LockFile(const std::string& lockFname,
                                 const IOOptions& /*opts*/, FileLock** lock,
                                 IODebugContext* /*dbg*/) {
957
  assert(lock != nullptr);
958

959
  *lock = NULL;
960
  IOStatus result;
961

962 963
  // No-sharing, this is a LOCK file
  const DWORD ExclusiveAccessON = 0;
964

965 966 967 968 969 970
  // Obtain exclusive access to the LOCK file
  // Previously, instead of NORMAL attr we set DELETE on close and that worked
  // well except with fault_injection test that insists on deleting it.
  HANDLE hFile = 0;
  {
    IOSTATS_TIMER_GUARD(open_nanos);
971
    hFile = RX_CreateFile(RX_FN(lockFname).c_str(),
972 973
                          (GENERIC_READ | GENERIC_WRITE), ExclusiveAccessON,
                          NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
974 975
  }

976 977
  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
978 979
    result = IOErrorFromWindowsError("Failed to create lock file: " + lockFname,
                                     lastError);
980 981
  } else {
    *lock = new WinFileLock(hFile);
D
Dmitri Smirnov 已提交
982
  }
S
sdong 已提交
983

984 985
  return result;
}
D
Dmitri Smirnov 已提交
986

987 988 989
IOStatus WinFileSystem::UnlockFile(FileLock* lock, const IOOptions& /*opts*/,
                                   IODebugContext* /*dbg*/) {
  IOStatus result;
990

991
  assert(lock != nullptr);
992

993
  delete lock;
D
Dmitri Smirnov 已提交
994

995 996
  return result;
}
997

998 999 1000
IOStatus WinFileSystem::GetTestDirectory(const IOOptions& opts,
                                         std::string* result,
                                         IODebugContext* dbg) {
1001
  std::string output;
D
Dmitri Smirnov 已提交
1002

1003 1004 1005 1006 1007
  const char* env = getenv("TEST_TMPDIR");
  if (env && env[0] != '\0') {
    output = env;
  } else {
    env = getenv("TMP");
D
Dmitri Smirnov 已提交
1008

1009 1010 1011 1012
    if (env && env[0] != '\0') {
      output = env;
    } else {
      output = "c:\\tmp";
D
Dmitri Smirnov 已提交
1013
    }
1014
  }
1015
  CreateDir(output, opts, dbg);
1016

1017
  output.append("\\testrocksdb-");
L
Lucian Petrut 已提交
1018
  output.append(std::to_string(GetCurrentProcessId()));
1019

1020
  CreateDir(output, opts, dbg);
D
Dmitri Smirnov 已提交
1021

1022
  output.swap(*result);
D
Dmitri Smirnov 已提交
1023

1024
  return IOStatus::OK();
1025
}
D
Dmitri Smirnov 已提交
1026

1027 1028 1029 1030 1031
IOStatus WinFileSystem::NewLogger(const std::string& fname,
                                  const IOOptions& /*opts*/,
                                  std::shared_ptr<Logger>* result,
                                  IODebugContext* /*dbg*/) {
  IOStatus s;
D
Dmitri Smirnov 已提交
1032

1033
  result->reset();
D
Dmitri Smirnov 已提交
1034

1035 1036 1037
  HANDLE hFile = 0;
  {
    IOSTATS_TIMER_GUARD(open_nanos);
1038
    hFile = RX_CreateFile(
1039 1040 1041 1042 1043 1044 1045 1046
        RX_FN(fname).c_str(), GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_DELETE,  // In RocksDb log files are
        // renamed and deleted before
        // they are closed. This enables
        // doing so.
        NULL,
        CREATE_ALWAYS,  // Original fopen mode is "w"
        FILE_ATTRIBUTE_NORMAL, NULL);
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
  }

  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError("Failed to open LogFile" + fname, lastError);
  } else {
    {
      // With log files we want to set the true creation time as of now
      // because the system
      // for some reason caches the attributes of the previous file that just
      // been renamed from
      // this name so auto_roll_logger_test fails
      FILETIME ft;
      GetSystemTimeAsFileTime(&ft);
      // Set creation, last access and last write time to the same value
      SetFileTime(hFile, &ft, &ft, &ft);
    }
1064
    result->reset(new WinLogger(&WinEnvThreads::gettid, clock_.get(), hFile));
1065 1066 1067
  }
  return s;
}
D
Dmitri Smirnov 已提交
1068

1069 1070 1071
IOStatus WinFileSystem::IsDirectory(const std::string& path,
                                    const IOOptions& /*opts*/, bool* is_dir,
                                    IODebugContext* /*dbg*/) {
1072 1073 1074 1075
  BOOL ret = RX_PathIsDirectory(RX_FN(path).c_str());
  if (is_dir) {
    *is_dir = ret ? true : false;
  }
1076
  return IOStatus::OK();
1077
}
D
Dmitri Smirnov 已提交
1078

1079 1080 1081
Status WinEnvIO::GetHostName(char* name, uint64_t len) {
  Status s;
  DWORD nSize = static_cast<DWORD>(
1082
      std::min<uint64_t>(len, std::numeric_limits<DWORD>::max()));
D
Dmitri Smirnov 已提交
1083

1084 1085 1086 1087 1088
  if (!::GetComputerNameA(name, &nSize)) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError("GetHostName", lastError);
  } else {
    name[nSize] = 0;
1089
  }
D
Dmitri Smirnov 已提交
1090

1091 1092 1093
  return s;
}

1094 1095 1096 1097
IOStatus WinFileSystem::GetAbsolutePath(const std::string& db_path,
                                        const IOOptions& /*options*/,
                                        std::string* output_path,
                                        IODebugContext* dbg) {
1098
  // Check if we already have an absolute path
D
Dmitri Smirnov 已提交
1099 1100 1101
  // For test compatibility we will consider starting slash as an
  // absolute path
  if ((!db_path.empty() && (db_path[0] == '\\' || db_path[0] == '/')) ||
1102
      !RX_PathIsRelative(RX_FN(db_path).c_str())) {
1103
    *output_path = db_path;
1104
    return IOStatus::OK();
D
Dmitri Smirnov 已提交
1105 1106
  }

1107
  RX_FILESTRING result;
D
Dmitri Smirnov 已提交
1108
  result.resize(MAX_PATH);
D
Dmitri Smirnov 已提交
1109

D
Dmitri Smirnov 已提交
1110 1111
  // Hopefully no changes the current directory while we do this
  // however _getcwd also suffers from the same limitation
1112
  DWORD len = RX_GetCurrentDirectory(MAX_PATH, &result[0]);
D
Dmitri Smirnov 已提交
1113 1114 1115
  if (len == 0) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError("Failed to get current working directory",
1116
                                   lastError);
1117
  }
D
Dmitri Smirnov 已提交
1118

D
Dmitri Smirnov 已提交
1119
  result.resize(len);
1120
  std::string res = FN_TO_RX(result);
1121

1122
  res.swap(*output_path);
1123
  return IOStatus::OK();
1124
}
D
Dmitri Smirnov 已提交
1125

1126 1127 1128 1129
IOStatus WinFileSystem::GetFreeSpace(const std::string& path,
                                     const IOOptions& /*options*/,
                                     uint64_t* diskfree,
                                     IODebugContext* /*dbg*/) {
1130 1131 1132 1133 1134
  assert(diskfree != nullptr);
  ULARGE_INTEGER freeBytes;
  BOOL f = RX_GetDiskFreeSpaceEx(RX_FN(path).c_str(), &freeBytes, NULL, NULL);
  if (f) {
    *diskfree = freeBytes.QuadPart;
1135
    return IOStatus::OK();
1136 1137 1138 1139 1140 1141 1142
  } else {
    DWORD lastError = GetLastError();
    return IOErrorFromWindowsError("Failed to get free space: " + path,
                                   lastError);
  }
}

1143 1144 1145
FileOptions WinFileSystem::OptimizeForLogWrite(
    const FileOptions& file_options, const DBOptions& db_options) const {
  FileOptions optimized(file_options);
D
Dmitri Smirnov 已提交
1146
  // These two the same as default optimizations
1147
  optimized.bytes_per_sync = db_options.wal_bytes_per_sync;
1148 1149
  optimized.writable_file_max_buffer_size =
      db_options.writable_file_max_buffer_size;
D
Dmitri Smirnov 已提交
1150 1151 1152 1153 1154 1155

  // This adversely affects %999 on windows
  optimized.use_mmap_writes = false;
  // Direct writes will produce a huge perf impact on
  // Windows. Pre-allocate space for WAL.
  optimized.use_direct_writes = false;
1156 1157
  return optimized;
}
D
Dmitri Smirnov 已提交
1158

1159 1160 1161
FileOptions WinFileSystem::OptimizeForManifestWrite(
    const FileOptions& options) const {
  FileOptions optimized(options);
1162
  optimized.use_mmap_writes = false;
D
Dmitri Smirnov 已提交
1163 1164 1165 1166
  optimized.use_direct_reads = false;
  return optimized;
}

1167 1168 1169
FileOptions WinFileSystem::OptimizeForManifestRead(
    const FileOptions& file_options) const {
  FileOptions optimized(file_options);
D
Dmitri Smirnov 已提交
1170 1171
  optimized.use_mmap_writes = false;
  optimized.use_direct_reads = false;
1172 1173 1174 1175
  return optimized;
}

// Returns true iff the named directory exists and is a directory.
1176
bool WinFileSystem::DirExists(const std::string& dname) {
1177
  WIN32_FILE_ATTRIBUTE_DATA attrs;
1178 1179
  if (RX_GetFileAttributesEx(RX_FN(dname).c_str(), GetFileExInfoStandard,
                             &attrs)) {
1180
    return 0 != (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
D
Dmitri Smirnov 已提交
1181
  }
1182 1183
  return false;
}
D
Dmitri Smirnov 已提交
1184

1185
size_t WinFileSystem::GetSectorSize(const std::string& fname) {
D
Dmitri Smirnov 已提交
1186 1187
  size_t sector_size = kSectorSize;

1188
  if (RX_PathIsRelative(RX_FN(fname).c_str())) {
D
Dmitri Smirnov 已提交
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
    return sector_size;
  }

  // obtain device handle
  char devicename[7] = "\\\\.\\";
  int erresult = strncat_s(devicename, sizeof(devicename), fname.c_str(), 2);

  if (erresult) {
    assert(false);
    return sector_size;
  }

1201 1202
  HANDLE hDevice = CreateFile(devicename, 0, 0, nullptr, OPEN_EXISTING,
                              FILE_ATTRIBUTE_NORMAL, nullptr);
D
Dmitri Smirnov 已提交
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214

  if (hDevice == INVALID_HANDLE_VALUE) {
    return sector_size;
  }

  STORAGE_PROPERTY_QUERY spropertyquery;
  spropertyquery.PropertyId = StorageAccessAlignmentProperty;
  spropertyquery.QueryType = PropertyStandardQuery;

  BYTE output_buffer[sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR)];
  DWORD output_bytes = 0;

1215 1216 1217 1218
  BOOL ret = DeviceIoControl(
      hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &spropertyquery,
      sizeof(spropertyquery), output_buffer,
      sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), &output_bytes, nullptr);
D
Dmitri Smirnov 已提交
1219 1220

  if (ret) {
1221 1222
    sector_size = ((STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR*)output_buffer)
                      ->BytesPerLogicalSector;
D
Dmitri Smirnov 已提交
1223
  } else {
1224 1225
    // many devices do not support StorageProcessAlignmentProperty. Any failure
    // here and we fall back to logical alignment
D
Dmitri Smirnov 已提交
1226

1227 1228 1229
    DISK_GEOMETRY_EX geometry = {0};
    ret = DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr, 0,
                          &geometry, sizeof(geometry), &output_bytes, nullptr);
D
Dmitri Smirnov 已提交
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241
    if (ret) {
      sector_size = geometry.Geometry.BytesPerSector;
    }
  }

  if (hDevice != INVALID_HANDLE_VALUE) {
    CloseHandle(hDevice);
  }

  return sector_size;
}

1242 1243
////////////////////////////////////////////////////////////////////////
// WinEnvThreads
D
Dmitri Smirnov 已提交
1244

1245 1246
WinEnvThreads::WinEnvThreads(Env* hosted_env)
    : hosted_env_(hosted_env), thread_pools_(Env::Priority::TOTAL) {
1247 1248
  for (int pool_id = 0; pool_id < Env::Priority::TOTAL; ++pool_id) {
    thread_pools_[pool_id].SetThreadPriority(
1249
        static_cast<Env::Priority>(pool_id));
1250 1251
    // This allows later initializing the thread-local-env of each thread.
    thread_pools_[pool_id].SetHostEnv(hosted_env);
D
Dmitri Smirnov 已提交
1252
  }
1253
}
D
Dmitri Smirnov 已提交
1254

1255 1256
WinEnvThreads::~WinEnvThreads() {
  WaitForJoin();
D
Dmitri Smirnov 已提交
1257

1258 1259
  for (auto& thpool : thread_pools_) {
    thpool.JoinAllThreads();
D
Dmitri Smirnov 已提交
1260 1261 1262
  }
}

1263
void WinEnvThreads::Schedule(void (*function)(void*), void* arg,
1264
                             Env::Priority pri, void* tag,
1265
                             void (*unschedFunction)(void* arg)) {
A
Andrew Kryczka 已提交
1266
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1267 1268
  thread_pools_[pri].Schedule(function, arg, tag, unschedFunction);
}
D
Dmitri Smirnov 已提交
1269

1270 1271 1272
int WinEnvThreads::UnSchedule(void* arg, Env::Priority pri) {
  return thread_pools_[pri].UnSchedule(arg);
}
D
Dmitri Smirnov 已提交
1273

1274
namespace {
D
Dmitri Smirnov 已提交
1275

1276 1277 1278 1279
struct StartThreadState {
  void (*user_function)(void*);
  void* arg;
};
D
Dmitri Smirnov 已提交
1280

1281 1282
void* StartThreadWrapper(void* arg) {
  std::unique_ptr<StartThreadState> state(
1283
      reinterpret_cast<StartThreadState*>(arg));
1284 1285
  state->user_function(state->arg);
  return nullptr;
1286
}
D
Dmitri Smirnov 已提交
1287

1288 1289 1290
}  // namespace

void WinEnvThreads::StartThread(void (*function)(void* arg), void* arg) {
1291 1292 1293 1294
  std::unique_ptr<StartThreadState> state(new StartThreadState);
  state->user_function = function;
  state->arg = arg;
  try {
1295
    ROCKSDB_NAMESPACE::port::WindowsThread th(&StartThreadWrapper, state.get());
1296
    state.release();
D
Dmitri Smirnov 已提交
1297

1298 1299
    std::lock_guard<std::mutex> lg(mu_);
    threads_to_join_.push_back(std::move(th));
D
Dmitri Smirnov 已提交
1300

1301 1302
  } catch (const std::system_error& ex) {
    WinthreadCall("start thread", ex.code());
D
Dmitri Smirnov 已提交
1303
  }
1304
}
D
Dmitri Smirnov 已提交
1305

1306 1307 1308
void WinEnvThreads::WaitForJoin() {
  for (auto& th : threads_to_join_) {
    th.join();
D
Dmitri Smirnov 已提交
1309
  }
1310 1311
  threads_to_join_.clear();
}
D
Dmitri Smirnov 已提交
1312

1313
unsigned int WinEnvThreads::GetThreadPoolQueueLen(Env::Priority pri) const {
A
Andrew Kryczka 已提交
1314
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1315 1316
  return thread_pools_[pri].GetQueueLen();
}
D
Dmitri Smirnov 已提交
1317

1318 1319 1320 1321
uint64_t WinEnvThreads::gettid() {
  uint64_t thread_id = GetCurrentThreadId();
  return thread_id;
}
D
Dmitri Smirnov 已提交
1322

1323
uint64_t WinEnvThreads::GetThreadID() const { return gettid(); }
D
Dmitri Smirnov 已提交
1324

1325
void WinEnvThreads::SetBackgroundThreads(int num, Env::Priority pri) {
A
Andrew Kryczka 已提交
1326
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1327 1328
  thread_pools_[pri].SetBackgroundThreads(num);
}
D
Dmitri Smirnov 已提交
1329

1330
int WinEnvThreads::GetBackgroundThreads(Env::Priority pri) {
A
Andrew Kryczka 已提交
1331
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1332 1333 1334
  return thread_pools_[pri].GetBackgroundThreads();
}

1335
void WinEnvThreads::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) {
A
Andrew Kryczka 已提交
1336
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1337 1338
  thread_pools_[pri].IncBackgroundThreadsIfNeeded(num);
}
D
Dmitri Smirnov 已提交
1339

1340 1341
/////////////////////////////////////////////////////////////////////////
// WinEnv
D
Dmitri Smirnov 已提交
1342

1343
WinEnv::WinEnv()
1344
    : CompositeEnv(WinFileSystem::Default(), WinClock::Default()),
1345 1346
      winenv_io_(this),
      winenv_threads_(this) {
1347 1348 1349
  // Protected member of the base class
  thread_status_updater_ = CreateThreadStatusUpdater();
}
D
Dmitri Smirnov 已提交
1350

1351 1352 1353 1354 1355
WinEnv::~WinEnv() {
  // All threads must be joined before the deletion of
  // thread_status_updater_.
  delete thread_status_updater_;
}
D
Dmitri Smirnov 已提交
1356

1357
Status WinEnv::GetThreadList(std::vector<ThreadStatus>* thread_list) {
1358 1359 1360
  assert(thread_status_updater_);
  return thread_status_updater_->GetThreadList(thread_list);
}
D
Dmitri Smirnov 已提交
1361

1362 1363 1364
Status WinEnv::GetHostName(char* name, uint64_t len) {
  return winenv_io_.GetHostName(name, len);
}
1365

1366 1367
void WinEnv::Schedule(void (*function)(void*), void* arg, Env::Priority pri,
                      void* tag, void (*unschedFunction)(void* arg)) {
1368
  return winenv_threads_.Schedule(function, arg, pri, tag, unschedFunction);
D
Dmitri Smirnov 已提交
1369 1370
}

1371 1372
int WinEnv::UnSchedule(void* arg, Env::Priority pri) {
  return winenv_threads_.UnSchedule(arg, pri);
D
Dmitri Smirnov 已提交
1373 1374
}

1375
void WinEnv::StartThread(void (*function)(void* arg), void* arg) {
1376
  return winenv_threads_.StartThread(function, arg);
D
Dmitri Smirnov 已提交
1377 1378
}

1379
void WinEnv::WaitForJoin() { return winenv_threads_.WaitForJoin(); }
D
Dmitri Smirnov 已提交
1380

1381
unsigned int WinEnv::GetThreadPoolQueueLen(Env::Priority pri) const {
1382
  return winenv_threads_.GetThreadPoolQueueLen(pri);
D
Dmitri Smirnov 已提交
1383 1384
}

1385
uint64_t WinEnv::GetThreadID() const { return winenv_threads_.GetThreadID(); }
1386

1387
// Allow increasing the number of worker threads.
1388
void WinEnv::SetBackgroundThreads(int num, Env::Priority pri) {
1389 1390
  return winenv_threads_.SetBackgroundThreads(num, pri);
}
D
Dmitri Smirnov 已提交
1391

1392 1393 1394 1395
int WinEnv::GetBackgroundThreads(Env::Priority pri) {
  return winenv_threads_.GetBackgroundThreads(pri);
}

1396
void WinEnv::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) {
1397
  return winenv_threads_.IncBackgroundThreadsIfNeeded(num, pri);
D
Dmitri Smirnov 已提交
1398 1399
}

1400
}  // namespace port
D
Dmitri Smirnov 已提交
1401 1402 1403 1404 1405 1406 1407 1408

std::string Env::GenerateUniqueId() {
  std::string result;

  UUID uuid;
  UuidCreateSequential(&uuid);

  RPC_CSTR rpc_str;
O
Orgad Shaneh 已提交
1409 1410 1411
  auto status = UuidToStringA(&uuid, &rpc_str);
  (void)status;
  assert(status == RPC_S_OK);
D
Dmitri Smirnov 已提交
1412 1413 1414

  result = reinterpret_cast<char*>(rpc_str);

O
Orgad Shaneh 已提交
1415 1416
  status = RpcStringFreeA(&rpc_str);
  assert(status == RPC_S_OK);
D
Dmitri Smirnov 已提交
1417 1418 1419 1420

  return result;
}

1421 1422 1423 1424
std::shared_ptr<FileSystem> FileSystem::Default() {
  return port::WinFileSystem::Default();
}

1425 1426 1427 1428 1429 1430
const std::shared_ptr<SystemClock>& SystemClock::Default() {
  static std::shared_ptr<SystemClock> clock =
      std::make_shared<port::WinClock>();
  return clock;
}

1431 1432 1433
std::unique_ptr<Env> NewCompositeEnv(const std::shared_ptr<FileSystem>& fs) {
  return std::unique_ptr<Env>(new CompositeEnvWrapper(Env::Default(), fs));
}
1434
}  // namespace ROCKSDB_NAMESPACE
1435 1436

#endif