env_win.cc 45.6 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.

A
Aaron Gao 已提交
10
#include "port/win/env_win.h"
D
Dmitri Smirnov 已提交
11
#include "port/win/win_thread.h"
D
Dmitri Smirnov 已提交
12 13
#include <algorithm>
#include <ctime>
A
Aaron Gao 已提交
14
#include <thread>
D
Dmitri Smirnov 已提交
15 16

#include <errno.h>
17 18 19
#include <process.h> // _getpid
#include <io.h> // _access
#include <direct.h> // _rmdir, _mkdir, _getcwd
D
Dmitri Smirnov 已提交
20 21 22 23 24 25 26
#include <sys/types.h>
#include <sys/stat.h>

#include "rocksdb/env.h"
#include "rocksdb/slice.h"

#include "port/port.h"
27
#include "port/port_dirent.h"
D
Dmitri Smirnov 已提交
28
#include "port/win/win_logger.h"
29
#include "port/win/io_win.h"
D
Dmitri Smirnov 已提交
30

31
#include "monitoring/iostats_context_imp.h"
D
Dmitri Smirnov 已提交
32

33 34
#include "monitoring/thread_status_updater.h"
#include "monitoring/thread_status_util.h"
D
Dmitri Smirnov 已提交
35

36 37
#include <rpc.h>  // for uuid generation
#include <windows.h>
D
Dmitri Smirnov 已提交
38 39 40 41
#include <shlwapi.h>
#include "strsafe.h"

#include <algorithm>
D
Dmitri Smirnov 已提交
42

43
namespace ROCKSDB_NAMESPACE {
D
Dmitri Smirnov 已提交
44 45 46 47 48

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

D
Dmitri Smirnov 已提交
49 50
namespace {

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

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

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

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

}

70
namespace port {
D
Dmitri Smirnov 已提交
71

72
WinEnvIO::WinEnvIO(Env* hosted_env)
73
    : hosted_env_(hosted_env),
D
Dmitri Smirnov 已提交
74
      page_size_(4 * 1024),
75 76
      allocation_granularity_(page_size_),
      perf_counter_frequency_(0),
B
Burton Li 已提交
77
      nano_seconds_per_period_(0),
78
      GetSystemTimePreciseAsFileTime_(NULL) {
D
Dmitri Smirnov 已提交
79

80 81
  SYSTEM_INFO sinfo;
  GetSystemInfo(&sinfo);
D
Dmitri Smirnov 已提交
82

83 84
  page_size_ = sinfo.dwPageSize;
  allocation_granularity_ = sinfo.dwAllocationGranularity;
D
Dmitri Smirnov 已提交
85

86 87
  {
    LARGE_INTEGER qpf;
T
Tamir Duberstein 已提交
88
    BOOL ret __attribute__((__unused__));
89
    ret = QueryPerformanceFrequency(&qpf);
90 91
    assert(ret == TRUE);
    perf_counter_frequency_ = qpf.QuadPart;
B
Burton Li 已提交
92 93 94 95

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

98 99
  HMODULE module = GetModuleHandle("kernel32.dll");
  if (module != NULL) {
100 101 102
    GetSystemTimePreciseAsFileTime_ =
      (FnGetSystemTimePreciseAsFileTime)GetProcAddress(
          module, "GetSystemTimePreciseAsFileTime");
D
Dmitri Smirnov 已提交
103 104 105
  }
}

106
WinEnvIO::~WinEnvIO() {
D
Dmitri Smirnov 已提交
107 108
}

109 110
Status WinEnvIO::DeleteFile(const std::string& fname) {
  Status result;
D
Dmitri Smirnov 已提交
111

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

D
Dmitri Smirnov 已提交
114 115 116
  if(!ret) {
    auto lastError = GetLastError();
    result = IOErrorFromWindowsError("Failed to delete: " + fname,
117
                                     lastError);
D
Dmitri Smirnov 已提交
118 119
  }

120
  return result;
D
Dmitri Smirnov 已提交
121 122
}

D
Dmitri Smirnov 已提交
123 124
Status WinEnvIO::Truncate(const std::string& fname, size_t size) {
  Status s;
125
  int result = ROCKSDB_NAMESPACE::port::Truncate(fname, size);
D
Dmitri Smirnov 已提交
126 127 128 129 130 131
  if (result != 0) {
    s = IOError("Failed to truncate: " + fname, errno);
  }
  return s;
}

132 133 134 135
Status WinEnvIO::GetCurrentTime(int64_t* unix_time) {
  time_t time = std::time(nullptr);
  if (time == (time_t)(-1)) {
    return Status::NotSupported("Failed to get time");
D
Dmitri Smirnov 已提交
136 137
  }

138 139
  *unix_time = time;
  return Status::OK();
D
Dmitri Smirnov 已提交
140 141
}

142
Status WinEnvIO::NewSequentialFile(const std::string& fname,
143 144
                                   std::unique_ptr<SequentialFile>* result,
                                   const EnvOptions& options) {
145
  Status s;
D
Dmitri Smirnov 已提交
146

147
  result->reset();
D
Dmitri Smirnov 已提交
148

149 150 151 152
  // 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 已提交
153 154 155 156 157 158 159

  DWORD fileFlags = FILE_ATTRIBUTE_READONLY;

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

160 161
  {
    IOSTATS_TIMER_GUARD(open_nanos);
162
    hFile = RX_CreateFile(
163 164 165 166
        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);
167
  }
D
Dmitri Smirnov 已提交
168

169 170 171
  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError("Failed to open NewSequentialFile" + fname,
172
                                lastError);
173 174
  } else {
    result->reset(new WinSequentialFile(fname, hFile, options));
D
Dmitri Smirnov 已提交
175
  }
176 177
  return s;
}
D
Dmitri Smirnov 已提交
178

179
Status WinEnvIO::NewRandomAccessFile(const std::string& fname,
180 181
                                     std::unique_ptr<RandomAccessFile>* result,
                                     const EnvOptions& options) {
182 183
  result->reset();
  Status s;
D
Dmitri Smirnov 已提交
184

185 186 187
  // 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 已提交
188

A
Aaron Gao 已提交
189
  if (options.use_direct_reads && !options.use_mmap_reads) {
190 191 192
    fileFlags |= FILE_FLAG_NO_BUFFERING;
  } else {
    fileFlags |= FILE_FLAG_RANDOM_ACCESS;
D
Dmitri Smirnov 已提交
193
  }
D
Dmitri Smirnov 已提交
194

195 196 197 198 199
  /// 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);
200 201 202 203
    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 已提交
204 205
  }

206 207 208
  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError(
209
        "NewRandomAccessFile failed to Create/Open: " + fname, lastError);
D
Dmitri Smirnov 已提交
210 211
  }

212
  UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);
D
Dmitri Smirnov 已提交
213

214 215 216 217
  // 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 已提交
218

219
    s = GetFileSize(fname, &fileSize);
220

221 222 223 224
    if (s.ok()) {
      // Will not map empty files
      if (fileSize == 0) {
        return IOError(
225
            "NewRandomAccessFile failed to map empty file: " + fname, EINVAL);
D
Dmitri Smirnov 已提交
226
      }
227

228
      HANDLE hMap = RX_CreateFileMapping(hFile, NULL, PAGE_READONLY,
229 230 231
                                         0,  // At its present length
                                         0,
                                         NULL);  // Mapping name
D
Dmitri Smirnov 已提交
232

233 234 235
      if (!hMap) {
        auto lastError = GetLastError();
        return IOErrorFromWindowsError(
236 237
            "Failed to create file mapping for NewRandomAccessFile: " + fname,
            lastError);
D
Dmitri Smirnov 已提交
238 239
      }

240
      UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc);
D
Dmitri Smirnov 已提交
241

242 243
      const void* mapped_region =
        MapViewOfFileEx(hMap, FILE_MAP_READ,
244 245 246 247
                        0,  // High DWORD of access start
                        0,  // Low DWORD
                        static_cast<SIZE_T>(fileSize),
                        NULL);  // Let the OS choose the mapping
D
Dmitri Smirnov 已提交
248

249 250
      if (!mapped_region) {
        auto lastError = GetLastError();
S
sdong 已提交
251
        return IOErrorFromWindowsError(
252 253
            "Failed to MapViewOfFile for NewRandomAccessFile: " + fname,
            lastError);
S
sdong 已提交
254
      }
255

256
      result->reset(new WinMmapReadableFile(fname, hFile, hMap, mapped_region,
257
                                            static_cast<size_t>(fileSize)));
258 259 260

      mapGuard.release();
      fileGuard.release();
D
Dmitri Smirnov 已提交
261
    }
262
  } else {
263 264 265 266
    result->reset(new WinRandomAccessFile(fname, hFile,
                                          std::max(GetSectorSize(fname),
                                                   page_size_),
                                          options));
267 268 269 270
    fileGuard.release();
  }
  return s;
}
D
Dmitri Smirnov 已提交
271

272
Status WinEnvIO::OpenWritableFile(const std::string& fname,
273 274 275
                                  std::unique_ptr<WritableFile>* result,
                                  const EnvOptions& options,
                                  bool reopen) {
276

277
  const size_t c_BufferCapacity = 64 * 1024;
D
Dmitri Smirnov 已提交
278

279
  EnvOptions local_options(options);
D
Dmitri Smirnov 已提交
280

281 282
  result->reset();
  Status s;
D
Dmitri Smirnov 已提交
283

284
  DWORD fileFlags = FILE_ATTRIBUTE_NORMAL;
D
Dmitri Smirnov 已提交
285

A
Aaron Gao 已提交
286
  if (local_options.use_direct_writes && !local_options.use_mmap_writes) {
287
    fileFlags = FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
D
Dmitri Smirnov 已提交
288 289
  }

290 291 292 293 294 295 296
  // 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 已提交
297

298 299
  if (local_options.use_mmap_writes) {
    desired_access |= GENERIC_READ;
D
Dmitri Smirnov 已提交
300
  } else {
301 302 303 304
    // Adding this solely for tests to pass (fault_injection_test,
    // wal_manager_test).
    shared_mode |= (FILE_SHARE_WRITE | FILE_SHARE_DELETE);
  }
D
Dmitri Smirnov 已提交
305

306 307 308 309 310 311
  // This will always truncate the file
  DWORD creation_disposition = CREATE_ALWAYS;
  if (reopen) {
    creation_disposition = OPEN_ALWAYS;
  }

312 313 314
  HANDLE hFile = 0;
  {
    IOSTATS_TIMER_GUARD(open_nanos);
315
    hFile = RX_CreateFile(
316 317 318 319 320 321 322 323
        RX_FN(fname).c_str(),
        desired_access,  // Access desired
        shared_mode,
        NULL,           // Security attributes
        // Posix env says (reopen) ? (O_CREATE | O_APPEND) : O_CREAT | O_TRUNC
        creation_disposition,
        fileFlags,      // Flags
        NULL);          // Template File
324 325 326 327 328
  }

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

332 333 334 335 336 337 338 339
  // 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(
340 341
          "Failed to create a ReopenWritableFile move to the end: " + fname,
          lastError);
342 343 344
    }
  }

345 346 347 348
  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_,
349
                                  allocation_granularity_, local_options));
350 351 352
  } else {
    // Here we want the buffer allocation to be aligned by the SSD page size
    // and to be a multiple of it
353 354 355 356
    result->reset(new WinWritableFile(fname, hFile,
                                      std::max(GetSectorSize(fname),
                                               GetPageSize()),
                                      c_BufferCapacity, local_options));
357
  }
358 359
  return s;
}
360

361
Status WinEnvIO::NewRandomRWFile(const std::string & fname,
362 363
                                 std::unique_ptr<RandomRWFile>* result,
                                 const EnvOptions & options) {
364 365 366 367 368 369 370

  Status s;

  // 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;
D
Dmitri Smirnov 已提交
371
  DWORD creation_disposition = OPEN_EXISTING; // Fail if file does not exist
372 373
  DWORD file_flags = FILE_FLAG_RANDOM_ACCESS;

A
Aaron Gao 已提交
374
  if (options.use_direct_reads && options.use_direct_writes) {
375 376 377 378 379 380 381 382 383
    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);
    hFile =
384
      RX_CreateFile(RX_FN(fname).c_str(),
385 386 387 388 389 390
                    desired_access,
                    shared_mode,
                    NULL, // Security attributes
                    creation_disposition,
                    file_flags,
                    NULL);
391 392 393 394 395 396 397 398 399
  }

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

  UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);
400 401 402 403
  result->reset(new WinRandomRWFile(fname, hFile,
                                    std::max(GetSectorSize(fname),
                                             GetPageSize()),
                                    options));
404 405 406 407 408
  fileGuard.release();

  return s;
}

409 410 411
Status WinEnvIO::NewMemoryMappedFileBuffer(
    const std::string & fname,
    std::unique_ptr<MemoryMappedFileBuffer>* result) {
D
Dmitri Smirnov 已提交
412 413 414 415 416 417 418 419
  Status s;
  result->reset();

  DWORD fileFlags = FILE_ATTRIBUTE_READONLY;

  HANDLE hFile = INVALID_HANDLE_VALUE;
  {
    IOSTATS_TIMER_GUARD(open_nanos);
420
    hFile = RX_CreateFile(
421 422 423 424 425 426
        RX_FN(fname).c_str(), GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        NULL,
        OPEN_EXISTING,  // Open only if it exists
        fileFlags,
        NULL);
D
Dmitri Smirnov 已提交
427 428 429 430
  }

  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
431 432
    s = IOErrorFromWindowsError(
        "Failed to open NewMemoryMappedFileBuffer: " + fname, lastError);
D
Dmitri Smirnov 已提交
433 434 435 436 437 438 439 440 441 442 443
    return s;
  }
  UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);

  uint64_t fileSize = 0;
  s = GetFileSize(fname, &fileSize);
  if (!s.ok()) {
    return s;
  }
  // Will not map empty files
  if (fileSize == 0) {
444 445
    return Status::NotSupported(
        "NewMemoryMappedFileBuffer can not map zero length files: " + fname);
D
Dmitri Smirnov 已提交
446 447 448 449 450
  }

  // size_t is 32-bit with 32-bit builds
  if (fileSize > std::numeric_limits<size_t>::max()) {
    return Status::NotSupported(
451 452
        "The specified file size does not fit into 32-bit memory addressing: "
         + fname);
D
Dmitri Smirnov 已提交
453 454
  }

455
  HANDLE hMap = RX_CreateFileMapping(hFile, NULL, PAGE_READWRITE,
456 457 458
                                     0,  // Whole file at its present length
                                     0,
                                     NULL);  // Mapping name
D
Dmitri Smirnov 已提交
459 460 461 462

  if (!hMap) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError(
463
        "Failed to create file mapping for: " + fname, lastError);
D
Dmitri Smirnov 已提交
464 465 466 467
  }
  UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc);

  void* base = MapViewOfFileEx(hMap, FILE_MAP_WRITE,
468 469 470 471
                               0,  // High DWORD of access start
                               0,  // Low DWORD
                               static_cast<SIZE_T>(fileSize),
                               NULL);  // Let the OS choose the mapping
D
Dmitri Smirnov 已提交
472 473 474 475

  if (!base) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError(
476 477
        "Failed to MapViewOfFile for NewMemoryMappedFileBuffer: " + fname,
        lastError);
D
Dmitri Smirnov 已提交
478 479
  }

480 481
  result->reset(new WinMemoryMappedBuffer(hFile, hMap, base,
                                          static_cast<size_t>(fileSize)));
D
Dmitri Smirnov 已提交
482 483 484 485 486 487 488

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

  return s;
}

489
Status WinEnvIO::NewDirectory(const std::string& name,
490
                              std::unique_ptr<Directory>* result) {
491 492 493
  Status s;
  // Must be nullptr on failure
  result->reset();
D
Dmitri Smirnov 已提交
494

495
  if (!DirExists(name)) {
D
Dmitri Smirnov 已提交
496
    s = IOErrorFromWindowsError(
497
        "open folder: " + name, ERROR_DIRECTORY);
D
Dmitri Smirnov 已提交
498 499 500 501 502 503
    return s;
  }

  HANDLE handle = INVALID_HANDLE_VALUE;
  // 0 - for access means read metadata
  {
504
    IOSTATS_TIMER_GUARD(open_nanos);
505 506 507 508 509 510 511
    handle = RX_CreateFile(
        RX_FN(name).c_str(), 0,
        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_BACKUP_SEMANTICS, // make opening folders possible
        NULL);
512
  }
D
Dmitri Smirnov 已提交
513 514 515

  if (INVALID_HANDLE_VALUE == handle) {
    auto lastError = GetLastError();
516
    s = IOErrorFromWindowsError("open folder: " + name, lastError);
D
Dmitri Smirnov 已提交
517 518 519 520 521
    return s;
  }

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

522 523
  return s;
}
D
Dmitri Smirnov 已提交
524

525
Status WinEnvIO::FileExists(const std::string& fname) {
D
Dmitri Smirnov 已提交
526 527 528 529 530
  Status s;
  // 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;
531 532
  if (FALSE == RX_GetFileAttributesEx(RX_FN(fname).c_str(),
                                      GetFileExInfoStandard, &attrs)) {
D
Dmitri Smirnov 已提交
533 534 535 536 537 538 539 540 541 542
    auto lastError = GetLastError();
    switch (lastError) {
    case ERROR_ACCESS_DENIED:
    case ERROR_NOT_FOUND:
    case ERROR_FILE_NOT_FOUND:
    case ERROR_PATH_NOT_FOUND:
      s = Status::NotFound();
      break;
    default:
      s = IOErrorFromWindowsError("Unexpected error for: " + fname,
543
                                  lastError);
D
Dmitri Smirnov 已提交
544 545 546 547
      break;
    }
  }
  return s;
548
}
D
Dmitri Smirnov 已提交
549

550
Status WinEnvIO::GetChildren(const std::string& dir,
551
                             std::vector<std::string>* result) {
D
Dmitri Smirnov 已提交
552

D
Dmitri Smirnov 已提交
553
  Status status;
D
Dmitri Smirnov 已提交
554
  result->clear();
555
  std::vector<std::string> output;
D
Dmitri Smirnov 已提交
556

557 558
  RX_WIN32_FIND_DATA data;
  memset(&data, 0, sizeof(data));
D
Dmitri Smirnov 已提交
559 560
  std::string pattern(dir);
  pattern.append("\\").append("*");
D
Dmitri Smirnov 已提交
561

562
  HANDLE handle = RX_FindFirstFileEx(RX_FN(pattern).c_str(),
563 564 565 566 567 568
                                     // Do not want alternative name
                                     FindExInfoBasic,
                                     &data,
                                     FindExSearchNameMatch,
                                     NULL,  // lpSearchFilter
                                     0);
D
Dmitri Smirnov 已提交
569

D
Dmitri Smirnov 已提交
570 571 572 573 574 575 576 577 578 579 580
  if (handle == INVALID_HANDLE_VALUE) {
    auto lastError = GetLastError();
    switch (lastError) {
    case ERROR_NOT_FOUND:
    case ERROR_ACCESS_DENIED:
    case ERROR_FILE_NOT_FOUND:
    case ERROR_PATH_NOT_FOUND:
      status = Status::NotFound();
      break;
    default:
      status = IOErrorFromWindowsError(
581
          "Failed to GetChhildren for: " + dir, lastError);
582
    }
D
Dmitri Smirnov 已提交
583
    return status;
584
  }
585

D
Dmitri Smirnov 已提交
586 587 588 589 590
  UniqueFindClosePtr fc(handle, FindCloseFunc);

  if (result->capacity() > 0) {
    output.reserve(result->capacity());
  }
D
Dmitri Smirnov 已提交
591

D
Dmitri Smirnov 已提交
592 593 594 595
  // For safety
  data.cFileName[MAX_PATH - 1] = 0;

  while (true) {
596 597 598
    auto x = RX_FILESTRING(data.cFileName, RX_FNLEN(data.cFileName));
    output.emplace_back(FN_TO_RX(x));
    BOOL ret =- RX_FindNextFile(handle, &data);
D
Dmitri Smirnov 已提交
599 600 601 602 603 604 605 606 607
    // 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;
  }
  output.swap(*result);
608 609
  return status;
}
D
Dmitri Smirnov 已提交
610

611 612
Status WinEnvIO::CreateDir(const std::string& name) {
  Status result;
613
  BOOL ret = RX_CreateDirectory(RX_FN(name).c_str(), NULL);
D
Dmitri Smirnov 已提交
614 615 616 617
  if (!ret) {
    auto lastError = GetLastError();
    result = IOErrorFromWindowsError(
        "Failed to create a directory: " + name, lastError);
D
Dmitri Smirnov 已提交
618 619
  }

620 621
  return result;
}
D
Dmitri Smirnov 已提交
622

623 624 625
Status  WinEnvIO::CreateDirIfMissing(const std::string& name) {
  Status result;

D
Dmitri Smirnov 已提交
626 627 628 629
  if (DirExists(name)) {
    return result;
  }

630
  BOOL ret = RX_CreateDirectory(RX_FN(name).c_str(), NULL);
D
Dmitri Smirnov 已提交
631 632 633 634
  if (!ret) {
    auto lastError = GetLastError();
    if (lastError != ERROR_ALREADY_EXISTS) {
      result = IOErrorFromWindowsError(
635
          "Failed to create a directory: " + name, lastError);
D
Dmitri Smirnov 已提交
636
    } else {
637
      result =
638
          Status::IOError(name + ": exists but is not a directory");
D
Dmitri Smirnov 已提交
639 640
    }
  }
641 642
  return result;
}
D
Dmitri Smirnov 已提交
643

644 645
Status WinEnvIO::DeleteDir(const std::string& name) {
  Status result;
646
  BOOL ret = RX_RemoveDirectory(RX_FN(name).c_str());
D
Dmitri Smirnov 已提交
647 648
  if (!ret) {
    auto lastError = GetLastError();
649 650
    result = IOErrorFromWindowsError("Failed to remove dir: " + name,
                                     lastError);
D
Dmitri Smirnov 已提交
651
  }
652 653
  return result;
}
D
Dmitri Smirnov 已提交
654

655 656 657
Status WinEnvIO::GetFileSize(const std::string& fname,
  uint64_t* size) {
  Status s;
658

659
  WIN32_FILE_ATTRIBUTE_DATA attrs;
660 661
  if (RX_GetFileAttributesEx(RX_FN(fname).c_str(), GetFileExInfoStandard,
                             &attrs)) {
662 663 664 665 666 667 668
    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 已提交
669
  }
670 671
  return s;
}
D
Dmitri Smirnov 已提交
672

673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
uint64_t WinEnvIO::FileTimeToUnixTime(const FILETIME& ftTime) {
  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 =
    (li.QuadPart / c_FileTimePerSecond) - c_SecondBeforeUnixEpoch;
  return result;
}

Status WinEnvIO::GetFileModificationTime(const std::string& fname,
  uint64_t* file_mtime) {
  Status s;

  WIN32_FILE_ATTRIBUTE_DATA attrs;
696 697
  if (RX_GetFileAttributesEx(RX_FN(fname).c_str(), GetFileExInfoStandard,
                            &attrs)) {
698 699 700 701 702 703
    *file_mtime = FileTimeToUnixTime(attrs.ftLastWriteTime);
  } else {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError(
      "Can not get file modification time for: " + fname, lastError);
    *file_mtime = 0;
D
Dmitri Smirnov 已提交
704 705
  }

706 707
  return s;
}
D
Dmitri Smirnov 已提交
708

709 710 711
Status WinEnvIO::RenameFile(const std::string& src,
  const std::string& target) {
  Status result;
712

713 714
  // rename() is not capable of replacing the existing file as on Linux
  // so use OS API directly
715 716
  if (!RX_MoveFileEx(RX_FN(src).c_str(), RX_FN(target).c_str(),
                     MOVEFILE_REPLACE_EXISTING)) {
717
    DWORD lastError = GetLastError();
D
Dmitri Smirnov 已提交
718

719 720
    std::string text("Failed to rename: ");
    text.append(src).append(" to: ").append(target);
D
Dmitri Smirnov 已提交
721

722
    result = IOErrorFromWindowsError(text, lastError);
D
Dmitri Smirnov 已提交
723 724
  }

725 726
  return result;
}
727

728 729 730
Status WinEnvIO::LinkFile(const std::string& src,
  const std::string& target) {
  Status result;
D
Dmitri Smirnov 已提交
731

732
  if (!RX_CreateHardLink(RX_FN(target).c_str(), RX_FN(src).c_str(),  NULL)) {
733
    DWORD lastError = GetLastError();
734 735 736
    if (lastError == ERROR_NOT_SAME_DEVICE) {
      return Status::NotSupported("No cross FS links allowed");
    }
737

738 739
    std::string text("Failed to link: ");
    text.append(src).append(" to: ").append(target);
740

741
    result = IOErrorFromWindowsError(text, lastError);
742 743
  }

744 745
  return result;
}
746

747
Status WinEnvIO::NumFileLinks(const std::string& fname, uint64_t* count) {
748
  Status s;
749 750 751
  HANDLE handle = RX_CreateFile(
      RX_FN(fname).c_str(), 0,
      FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
752
      NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
753 754 755

  if (INVALID_HANDLE_VALUE == handle) {
    auto lastError = GetLastError();
756
    s = IOErrorFromWindowsError("NumFileLinks: " + fname, lastError);
757 758 759 760
    return s;
  }
  UniqueCloseHandlePtr handle_guard(handle, CloseHandleFunc);
  FILE_STANDARD_INFO standard_info;
761 762 763
  if (0 != GetFileInformationByHandleEx(handle, FileStandardInfo,
                                        &standard_info,
                                        sizeof(standard_info))) {
764 765 766
    *count = standard_info.NumberOfLinks;
  } else {
    auto lastError = GetLastError();
767 768
    s = IOErrorFromWindowsError("GetFileInformationByHandleEx: " + fname,
                                lastError);
769 770 771 772
  }
  return s;
}

D
Dmitri Smirnov 已提交
773 774 775 776 777 778 779 780 781 782 783 784 785 786
Status WinEnvIO::AreFilesSame(const std::string& first,
  const std::string& second, bool* res) {
// For MinGW builds
#if (_WIN32_WINNT == _WIN32_WINNT_VISTA)
  Status s = Status::NotSupported();
#else
  assert(res != nullptr);
  Status s;
  if (res == nullptr) {
    s = Status::InvalidArgument("res");
    return s;
  }

  // 0 - for access means read metadata
787 788 789 790 791 792 793
  HANDLE file_1 = RX_CreateFile(
      RX_FN(first).c_str(), 0,
      FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      FILE_FLAG_BACKUP_SEMANTICS, // make opening folders possible
      NULL);
D
Dmitri Smirnov 已提交
794 795 796

  if (INVALID_HANDLE_VALUE == file_1) {
    auto lastError = GetLastError();
797
    s = IOErrorFromWindowsError("open file: " + first, lastError);
D
Dmitri Smirnov 已提交
798 799 800 801
    return s;
  }
  UniqueCloseHandlePtr g_1(file_1, CloseHandleFunc);

802 803 804 805 806 807
  HANDLE file_2 = RX_CreateFile(
      RX_FN(second).c_str(), 0,
      FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL, OPEN_EXISTING,
      FILE_FLAG_BACKUP_SEMANTICS, // make opening folders possible
      NULL);
D
Dmitri Smirnov 已提交
808 809 810

  if (INVALID_HANDLE_VALUE == file_2) {
    auto lastError = GetLastError();
811
    s = IOErrorFromWindowsError("open file: " + second, lastError);
D
Dmitri Smirnov 已提交
812 813 814 815 816 817
    return s;
  }
  UniqueCloseHandlePtr g_2(file_2, CloseHandleFunc);

  FILE_ID_INFO FileInfo_1;
  BOOL result = GetFileInformationByHandleEx(file_1, FileIdInfo, &FileInfo_1,
818
                                             sizeof(FileInfo_1));
D
Dmitri Smirnov 已提交
819 820 821

  if (!result) {
    auto lastError = GetLastError();
822
    s = IOErrorFromWindowsError("stat file: " + first, lastError);
D
Dmitri Smirnov 已提交
823 824 825 826 827
    return s;
  }

   FILE_ID_INFO FileInfo_2;
   result = GetFileInformationByHandleEx(file_2, FileIdInfo, &FileInfo_2,
828
                                         sizeof(FileInfo_2));
D
Dmitri Smirnov 已提交
829 830 831

  if (!result) {
    auto lastError = GetLastError();
832
    s = IOErrorFromWindowsError("stat file: " + second, lastError);
D
Dmitri Smirnov 已提交
833 834 835 836
    return s;
  }

  if (FileInfo_1.VolumeSerialNumber == FileInfo_2.VolumeSerialNumber) {
837 838 839
    *res = (0 == memcmp(FileInfo_1.FileId.Identifier,
                        FileInfo_2.FileId.Identifier,
                        sizeof(FileInfo_1.FileId.Identifier)));
D
Dmitri Smirnov 已提交
840 841 842 843 844 845 846
  } else {
    *res = false;
  }
#endif
  return s;
}

847
Status  WinEnvIO::LockFile(const std::string& lockFname,
848
                           FileLock** lock) {
849
  assert(lock != nullptr);
850

851 852
  *lock = NULL;
  Status result;
853

854 855
  // No-sharing, this is a LOCK file
  const DWORD ExclusiveAccessON = 0;
856

857 858 859 860 861 862
  // 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);
863 864 865 866
    hFile = RX_CreateFile(RX_FN(lockFname).c_str(),
                          (GENERIC_READ | GENERIC_WRITE),
                          ExclusiveAccessON, NULL, CREATE_ALWAYS,
                          FILE_ATTRIBUTE_NORMAL, NULL);
867 868
  }

869 870 871
  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
    result = IOErrorFromWindowsError(
872
        "Failed to create lock file: " + lockFname, lastError);
873 874
  } else {
    *lock = new WinFileLock(hFile);
D
Dmitri Smirnov 已提交
875
  }
S
sdong 已提交
876

877 878
  return result;
}
D
Dmitri Smirnov 已提交
879

880 881
Status WinEnvIO::UnlockFile(FileLock* lock) {
  Status result;
882

883
  assert(lock != nullptr);
884

885
  delete lock;
D
Dmitri Smirnov 已提交
886

887 888
  return result;
}
889

890
Status WinEnvIO::GetTestDirectory(std::string* result) {
D
Dmitri Smirnov 已提交
891

892
  std::string output;
D
Dmitri Smirnov 已提交
893

894 895 896 897 898
  const char* env = getenv("TEST_TMPDIR");
  if (env && env[0] != '\0') {
    output = env;
  } else {
    env = getenv("TMP");
D
Dmitri Smirnov 已提交
899

900 901 902 903
    if (env && env[0] != '\0') {
      output = env;
    } else {
      output = "c:\\tmp";
D
Dmitri Smirnov 已提交
904
    }
905
  }
D
Dmitri Smirnov 已提交
906
  CreateDir(output);
907

908 909
  output.append("\\testrocksdb-");
  output.append(std::to_string(_getpid()));
910

911
  CreateDir(output);
D
Dmitri Smirnov 已提交
912

913
  output.swap(*result);
D
Dmitri Smirnov 已提交
914

915 916
  return Status::OK();
}
D
Dmitri Smirnov 已提交
917

918
Status WinEnvIO::NewLogger(const std::string& fname,
919
                           std::shared_ptr<Logger>* result) {
920
  Status s;
D
Dmitri Smirnov 已提交
921

922
  result->reset();
D
Dmitri Smirnov 已提交
923

924 925 926
  HANDLE hFile = 0;
  {
    IOSTATS_TIMER_GUARD(open_nanos);
927
    hFile = RX_CreateFile(
928 929 930 931 932 933 934 935
        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);
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
  }

  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);
    }
    result->reset(new WinLogger(&WinEnvThreads::gettid, hosted_env_, hFile));
  }
  return s;
}
D
Dmitri Smirnov 已提交
957

958 959 960 961 962 963 964 965
Status WinEnvIO::IsDirectory(const std::string& path, bool* is_dir) {
  BOOL ret = RX_PathIsDirectory(RX_FN(path).c_str());
  if (is_dir) {
    *is_dir = ret ? true : false;
  }
  return Status::OK();
}

966
uint64_t WinEnvIO::NowMicros() {
D
Dmitri Smirnov 已提交
967

968 969 970
  if (GetSystemTimePreciseAsFileTime_ != NULL) {
    // all std::chrono clocks on windows proved to return
    // values that may repeat that is not good enough for some uses.
O
Orgad Shaneh 已提交
971
    const int64_t c_UnixEpochStartTicks = 116444736000000000LL;
972
    const int64_t c_FtToMicroSec = 10;
D
Dmitri Smirnov 已提交
973

974 975 976 977 978
    // 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);
D
Dmitri Smirnov 已提交
979

980 981 982 983 984 985 986 987
    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;
988
  }
989
  using namespace std::chrono;
990 991
  return duration_cast<microseconds>(system_clock::now().time_since_epoch())
      .count();
992
}
D
Dmitri Smirnov 已提交
993

994
uint64_t WinEnvIO::NowNanos() {
B
Burton Li 已提交
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
  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>(
1012
      high_resolution_clock::now().time_since_epoch()).count();
1013
}
D
Dmitri Smirnov 已提交
1014

1015 1016 1017 1018
Status WinEnvIO::GetHostName(char* name, uint64_t len) {
  Status s;
  DWORD nSize = static_cast<DWORD>(
    std::min<uint64_t>(len, std::numeric_limits<DWORD>::max()));
D
Dmitri Smirnov 已提交
1019

1020 1021 1022 1023 1024
  if (!::GetComputerNameA(name, &nSize)) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError("GetHostName", lastError);
  } else {
    name[nSize] = 0;
1025
  }
D
Dmitri Smirnov 已提交
1026

1027 1028 1029 1030
  return s;
}

Status WinEnvIO::GetAbsolutePath(const std::string& db_path,
1031
                                 std::string* output_path) {
1032
  // Check if we already have an absolute path
D
Dmitri Smirnov 已提交
1033 1034 1035
  // For test compatibility we will consider starting slash as an
  // absolute path
  if ((!db_path.empty() && (db_path[0] == '\\' || db_path[0] == '/')) ||
1036
    !RX_PathIsRelative(RX_FN(db_path).c_str())) {
1037 1038
    *output_path = db_path;
    return Status::OK();
D
Dmitri Smirnov 已提交
1039 1040
  }

1041
  RX_FILESTRING result;
D
Dmitri Smirnov 已提交
1042
  result.resize(MAX_PATH);
D
Dmitri Smirnov 已提交
1043

D
Dmitri Smirnov 已提交
1044 1045
  // Hopefully no changes the current directory while we do this
  // however _getcwd also suffers from the same limitation
1046
  DWORD len = RX_GetCurrentDirectory(MAX_PATH, &result[0]);
D
Dmitri Smirnov 已提交
1047 1048 1049
  if (len == 0) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError("Failed to get current working directory",
1050
                                   lastError);
1051
  }
D
Dmitri Smirnov 已提交
1052

D
Dmitri Smirnov 已提交
1053
  result.resize(len);
1054
  std::string res = FN_TO_RX(result);
1055

1056
  res.swap(*output_path);
1057 1058
  return Status::OK();
}
D
Dmitri Smirnov 已提交
1059

1060 1061
std::string WinEnvIO::TimeToString(uint64_t secondsSince1970) {
  std::string result;
D
Dmitri Smirnov 已提交
1062

1063 1064
  const time_t seconds = secondsSince1970;
  const int maxsize = 64;
D
Dmitri Smirnov 已提交
1065

1066 1067
  struct tm t;
  errno_t ret = localtime_s(&t, &seconds);
D
Dmitri Smirnov 已提交
1068

1069 1070 1071 1072 1073
  if (ret) {
    result = std::to_string(seconds);
  } else {
    result.resize(maxsize);
    char* p = &result[0];
D
Dmitri Smirnov 已提交
1074

1075
    int len = snprintf(p, maxsize, "%04d/%02d/%02d-%02d:%02d:%02d ",
1076 1077
                       t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
                       t.tm_min, t.tm_sec);
1078
    assert(len > 0);
D
Dmitri Smirnov 已提交
1079

1080
    result.resize(len);
D
Dmitri Smirnov 已提交
1081 1082
  }

1083 1084
  return result;
}
D
Dmitri Smirnov 已提交
1085

1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
Status WinEnvIO::GetFreeSpace(const std::string& path, uint64_t* diskfree) {
  assert(diskfree != nullptr);
  ULARGE_INTEGER freeBytes;
  BOOL f = RX_GetDiskFreeSpaceEx(RX_FN(path).c_str(), &freeBytes, NULL, NULL);
  if (f) {
    *diskfree = freeBytes.QuadPart;
    return Status::OK();
  } else {
    DWORD lastError = GetLastError();
    return IOErrorFromWindowsError("Failed to get free space: " + path,
                                   lastError);
  }
}

1100
EnvOptions WinEnvIO::OptimizeForLogWrite(const EnvOptions& env_options,
1101
                                         const DBOptions& db_options) const {
D
Dmitri Smirnov 已提交
1102 1103
  EnvOptions optimized(env_options);
  // These two the same as default optimizations
1104
  optimized.bytes_per_sync = db_options.wal_bytes_per_sync;
1105 1106
  optimized.writable_file_max_buffer_size =
      db_options.writable_file_max_buffer_size;
D
Dmitri Smirnov 已提交
1107 1108 1109 1110 1111 1112

  // 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;
1113 1114
  return optimized;
}
D
Dmitri Smirnov 已提交
1115

1116
EnvOptions WinEnvIO::OptimizeForManifestWrite(
1117
    const EnvOptions& env_options) const {
D
Dmitri Smirnov 已提交
1118
  EnvOptions optimized(env_options);
1119
  optimized.use_mmap_writes = false;
D
Dmitri Smirnov 已提交
1120 1121 1122 1123 1124
  optimized.use_direct_reads = false;
  return optimized;
}

EnvOptions WinEnvIO::OptimizeForManifestRead(
1125
    const EnvOptions& env_options) const {
D
Dmitri Smirnov 已提交
1126 1127 1128
  EnvOptions optimized(env_options);
  optimized.use_mmap_writes = false;
  optimized.use_direct_reads = false;
1129 1130 1131 1132 1133 1134
  return optimized;
}

// Returns true iff the named directory exists and is a directory.
bool WinEnvIO::DirExists(const std::string& dname) {
  WIN32_FILE_ATTRIBUTE_DATA attrs;
1135 1136
  if (RX_GetFileAttributesEx(RX_FN(dname).c_str(),
                             GetFileExInfoStandard, &attrs)) {
1137
    return 0 != (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
D
Dmitri Smirnov 已提交
1138
  }
1139 1140
  return false;
}
D
Dmitri Smirnov 已提交
1141

D
Dmitri Smirnov 已提交
1142 1143 1144
size_t WinEnvIO::GetSectorSize(const std::string& fname) {
  size_t sector_size = kSectorSize;

1145
  if (RX_PathIsRelative(RX_FN(fname).c_str())) {
D
Dmitri Smirnov 已提交
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
    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;
  }

1158 1159
  HANDLE hDevice = CreateFile(devicename, 0, 0, nullptr, OPEN_EXISTING,
                              FILE_ATTRIBUTE_NORMAL, nullptr);
D
Dmitri Smirnov 已提交
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172

  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;

  BOOL ret = DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
1173 1174 1175 1176
                             &spropertyquery, sizeof(spropertyquery),
                             output_buffer,
                             sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR),
                             &output_bytes, nullptr);
D
Dmitri Smirnov 已提交
1177 1178 1179 1180 1181 1182 1183 1184 1185

  if (ret) {
    sector_size = ((STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR *)output_buffer)->BytesPerLogicalSector;
  } else {
    // many devices do not support StorageProcessAlignmentProperty. Any failure here and we
    // fall back to logical alignment

    DISK_GEOMETRY_EX geometry = { 0 };
    ret = DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY,
1186
           nullptr, 0, &geometry, sizeof(geometry), &output_bytes, nullptr);
D
Dmitri Smirnov 已提交
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
    if (ret) {
      sector_size = geometry.Geometry.BytesPerSector;
    }
  }

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

  return sector_size;
}

1199 1200
////////////////////////////////////////////////////////////////////////
// WinEnvThreads
D
Dmitri Smirnov 已提交
1201

1202 1203
WinEnvThreads::WinEnvThreads(Env* hosted_env)
    : hosted_env_(hosted_env), thread_pools_(Env::Priority::TOTAL) {
D
Dmitri Smirnov 已提交
1204

1205 1206 1207 1208 1209
  for (int pool_id = 0; pool_id < Env::Priority::TOTAL; ++pool_id) {
    thread_pools_[pool_id].SetThreadPriority(
      static_cast<Env::Priority>(pool_id));
    // This allows later initializing the thread-local-env of each thread.
    thread_pools_[pool_id].SetHostEnv(hosted_env);
D
Dmitri Smirnov 已提交
1210
  }
1211
}
D
Dmitri Smirnov 已提交
1212

1213
WinEnvThreads::~WinEnvThreads() {
D
Dmitri Smirnov 已提交
1214

1215
  WaitForJoin();
D
Dmitri Smirnov 已提交
1216

1217 1218
  for (auto& thpool : thread_pools_) {
    thpool.JoinAllThreads();
D
Dmitri Smirnov 已提交
1219 1220 1221
  }
}

1222 1223 1224
void WinEnvThreads::Schedule(void(*function)(void*), void* arg,
                             Env::Priority pri, void* tag,
                             void(*unschedFunction)(void* arg)) {
A
Andrew Kryczka 已提交
1225
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1226 1227
  thread_pools_[pri].Schedule(function, arg, tag, unschedFunction);
}
D
Dmitri Smirnov 已提交
1228

1229 1230 1231
int WinEnvThreads::UnSchedule(void* arg, Env::Priority pri) {
  return thread_pools_[pri].UnSchedule(arg);
}
D
Dmitri Smirnov 已提交
1232

1233
namespace {
D
Dmitri Smirnov 已提交
1234

1235 1236 1237 1238
  struct StartThreadState {
    void(*user_function)(void*);
    void* arg;
  };
D
Dmitri Smirnov 已提交
1239

1240 1241 1242 1243 1244
  void* StartThreadWrapper(void* arg) {
    std::unique_ptr<StartThreadState> state(
      reinterpret_cast<StartThreadState*>(arg));
    state->user_function(state->arg);
    return nullptr;
D
Dmitri Smirnov 已提交
1245 1246
  }

1247
}
D
Dmitri Smirnov 已提交
1248

1249 1250 1251 1252 1253
void WinEnvThreads::StartThread(void(*function)(void* arg), void* arg) {
  std::unique_ptr<StartThreadState> state(new StartThreadState);
  state->user_function = function;
  state->arg = arg;
  try {
1254
    ROCKSDB_NAMESPACE::port::WindowsThread th(&StartThreadWrapper, state.get());
1255
    state.release();
D
Dmitri Smirnov 已提交
1256

1257 1258
    std::lock_guard<std::mutex> lg(mu_);
    threads_to_join_.push_back(std::move(th));
D
Dmitri Smirnov 已提交
1259

1260 1261
  } catch (const std::system_error& ex) {
    WinthreadCall("start thread", ex.code());
D
Dmitri Smirnov 已提交
1262
  }
1263
}
D
Dmitri Smirnov 已提交
1264

1265 1266 1267
void WinEnvThreads::WaitForJoin() {
  for (auto& th : threads_to_join_) {
    th.join();
D
Dmitri Smirnov 已提交
1268
  }
1269 1270
  threads_to_join_.clear();
}
D
Dmitri Smirnov 已提交
1271

1272
unsigned int WinEnvThreads::GetThreadPoolQueueLen(Env::Priority pri) const {
A
Andrew Kryczka 已提交
1273
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1274 1275
  return thread_pools_[pri].GetQueueLen();
}
D
Dmitri Smirnov 已提交
1276

1277 1278 1279 1280
uint64_t WinEnvThreads::gettid() {
  uint64_t thread_id = GetCurrentThreadId();
  return thread_id;
}
D
Dmitri Smirnov 已提交
1281

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

1284 1285 1286
void  WinEnvThreads::SleepForMicroseconds(int micros) {
  std::this_thread::sleep_for(std::chrono::microseconds(micros));
}
D
Dmitri Smirnov 已提交
1287

1288
void WinEnvThreads::SetBackgroundThreads(int num, Env::Priority pri) {
A
Andrew Kryczka 已提交
1289
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1290 1291
  thread_pools_[pri].SetBackgroundThreads(num);
}
D
Dmitri Smirnov 已提交
1292

1293
int WinEnvThreads::GetBackgroundThreads(Env::Priority pri) {
A
Andrew Kryczka 已提交
1294
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1295 1296 1297
  return thread_pools_[pri].GetBackgroundThreads();
}

1298
void WinEnvThreads::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) {
A
Andrew Kryczka 已提交
1299
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1300 1301
  thread_pools_[pri].IncBackgroundThreadsIfNeeded(num);
}
D
Dmitri Smirnov 已提交
1302

1303 1304
/////////////////////////////////////////////////////////////////////////
// WinEnv
D
Dmitri Smirnov 已提交
1305

1306 1307 1308 1309
WinEnv::WinEnv() : winenv_io_(this), winenv_threads_(this) {
  // Protected member of the base class
  thread_status_updater_ = CreateThreadStatusUpdater();
}
D
Dmitri Smirnov 已提交
1310 1311


1312 1313 1314 1315 1316
WinEnv::~WinEnv() {
  // All threads must be joined before the deletion of
  // thread_status_updater_.
  delete thread_status_updater_;
}
D
Dmitri Smirnov 已提交
1317

1318
Status WinEnv::GetThreadList(std::vector<ThreadStatus>* thread_list) {
1319 1320 1321
  assert(thread_status_updater_);
  return thread_status_updater_->GetThreadList(thread_list);
}
D
Dmitri Smirnov 已提交
1322

1323 1324 1325
Status WinEnv::DeleteFile(const std::string& fname) {
  return winenv_io_.DeleteFile(fname);
}
D
Dmitri Smirnov 已提交
1326

D
Dmitri Smirnov 已提交
1327 1328 1329 1330
Status WinEnv::Truncate(const std::string& fname, size_t size) {
  return winenv_io_.Truncate(fname, size);
}

1331 1332 1333
Status WinEnv::GetCurrentTime(int64_t* unix_time) {
  return winenv_io_.GetCurrentTime(unix_time);
}
D
Dmitri Smirnov 已提交
1334

1335
Status  WinEnv::NewSequentialFile(const std::string& fname,
1336 1337
                                  std::unique_ptr<SequentialFile>* result,
                                  const EnvOptions& options) {
1338 1339
  return winenv_io_.NewSequentialFile(fname, result, options);
}
D
Dmitri Smirnov 已提交
1340

1341
Status WinEnv::NewRandomAccessFile(const std::string& fname,
1342 1343
                                   std::unique_ptr<RandomAccessFile>* result,
                                   const EnvOptions& options) {
1344 1345
  return winenv_io_.NewRandomAccessFile(fname, result, options);
}
D
Dmitri Smirnov 已提交
1346

1347
Status WinEnv::NewWritableFile(const std::string& fname,
A
Aaron Gao 已提交
1348 1349
                               std::unique_ptr<WritableFile>* result,
                               const EnvOptions& options) {
1350 1351 1352 1353
  return winenv_io_.OpenWritableFile(fname, result, options, false);
}

Status WinEnv::ReopenWritableFile(const std::string& fname,
1354 1355
                                  std::unique_ptr<WritableFile>* result,
                                  const EnvOptions& options) {
1356
  return winenv_io_.OpenWritableFile(fname, result, options, true);
1357
}
D
Dmitri Smirnov 已提交
1358

1359
Status WinEnv::NewRandomRWFile(const std::string & fname,
1360 1361
                               std::unique_ptr<RandomRWFile>* result,
                               const EnvOptions & options) {
1362 1363 1364
  return winenv_io_.NewRandomRWFile(fname, result, options);
}

1365 1366 1367
Status WinEnv::NewMemoryMappedFileBuffer(
    const std::string& fname,
    std::unique_ptr<MemoryMappedFileBuffer>* result) {
D
Dmitri Smirnov 已提交
1368 1369 1370
  return winenv_io_.NewMemoryMappedFileBuffer(fname, result);
}

1371
Status WinEnv::NewDirectory(const std::string& name,
1372
                            std::unique_ptr<Directory>* result) {
1373 1374
  return winenv_io_.NewDirectory(name, result);
}
D
Dmitri Smirnov 已提交
1375

1376 1377 1378
Status WinEnv::FileExists(const std::string& fname) {
  return winenv_io_.FileExists(fname);
}
D
Dmitri Smirnov 已提交
1379

1380
Status WinEnv::GetChildren(const std::string& dir,
1381
                           std::vector<std::string>* result) {
1382 1383
  return winenv_io_.GetChildren(dir, result);
}
D
Dmitri Smirnov 已提交
1384

1385 1386 1387
Status WinEnv::CreateDir(const std::string& name) {
  return winenv_io_.CreateDir(name);
}
D
Dmitri Smirnov 已提交
1388

1389 1390 1391
Status WinEnv::CreateDirIfMissing(const std::string& name) {
  return winenv_io_.CreateDirIfMissing(name);
}
D
Dmitri Smirnov 已提交
1392

1393 1394 1395
Status WinEnv::DeleteDir(const std::string& name) {
  return winenv_io_.DeleteDir(name);
}
D
Dmitri Smirnov 已提交
1396

1397
Status WinEnv::GetFileSize(const std::string& fname,
1398
                           uint64_t* size) {
1399 1400
  return winenv_io_.GetFileSize(fname, size);
}
D
Dmitri Smirnov 已提交
1401

1402
Status  WinEnv::GetFileModificationTime(const std::string& fname,
1403
                                        uint64_t* file_mtime) {
1404 1405
  return winenv_io_.GetFileModificationTime(fname, file_mtime);
}
D
Dmitri Smirnov 已提交
1406

1407
Status WinEnv::RenameFile(const std::string& src,
1408
                          const std::string& target) {
1409 1410
  return winenv_io_.RenameFile(src, target);
}
D
Dmitri Smirnov 已提交
1411

1412
Status WinEnv::LinkFile(const std::string& src,
1413
                        const std::string& target) {
1414 1415
  return winenv_io_.LinkFile(src, target);
}
D
Dmitri Smirnov 已提交
1416

1417 1418 1419 1420
Status WinEnv::NumFileLinks(const std::string& fname, uint64_t* count) {
  return winenv_io_.NumFileLinks(fname, count);
}

D
Dmitri Smirnov 已提交
1421
Status WinEnv::AreFilesSame(const std::string& first,
1422
                            const std::string& second, bool* res) {
D
Dmitri Smirnov 已提交
1423 1424 1425
  return winenv_io_.AreFilesSame(first, second, res);
}

1426 1427 1428 1429
Status WinEnv::LockFile(const std::string& lockFname,
  FileLock** lock) {
  return winenv_io_.LockFile(lockFname, lock);
}
D
Dmitri Smirnov 已提交
1430

1431 1432 1433
Status WinEnv::UnlockFile(FileLock* lock) {
  return winenv_io_.UnlockFile(lock);
}
D
Dmitri Smirnov 已提交
1434

1435
Status WinEnv::GetTestDirectory(std::string* result) {
1436 1437
  return winenv_io_.GetTestDirectory(result);
}
D
Dmitri Smirnov 已提交
1438

1439
Status WinEnv::NewLogger(const std::string& fname,
1440
                         std::shared_ptr<Logger>* result) {
1441 1442
  return winenv_io_.NewLogger(fname, result);
}
1443

1444 1445 1446 1447
Status WinEnv::IsDirectory(const std::string& path, bool* is_dir) {
  return winenv_io_.IsDirectory(path, is_dir);
}

1448 1449 1450
uint64_t WinEnv::NowMicros() {
  return winenv_io_.NowMicros();
}
1451

1452 1453 1454
uint64_t  WinEnv::NowNanos() {
  return winenv_io_.NowNanos();
}
D
Dmitri Smirnov 已提交
1455

1456 1457 1458
Status WinEnv::GetHostName(char* name, uint64_t len) {
  return winenv_io_.GetHostName(name, len);
}
D
Dmitri Smirnov 已提交
1459

1460 1461 1462 1463
Status WinEnv::GetAbsolutePath(const std::string& db_path,
  std::string* output_path) {
  return winenv_io_.GetAbsolutePath(db_path, output_path);
}
D
Dmitri Smirnov 已提交
1464

1465 1466 1467
std::string WinEnv::TimeToString(uint64_t secondsSince1970) {
  return winenv_io_.TimeToString(secondsSince1970);
}
D
Dmitri Smirnov 已提交
1468

1469
void  WinEnv::Schedule(void(*function)(void*), void* arg, Env::Priority pri,
1470 1471
                       void* tag,
                       void(*unschedFunction)(void* arg)) {
1472
  return winenv_threads_.Schedule(function, arg, pri, tag, unschedFunction);
D
Dmitri Smirnov 已提交
1473 1474
}

1475 1476
int WinEnv::UnSchedule(void* arg, Env::Priority pri) {
  return winenv_threads_.UnSchedule(arg, pri);
D
Dmitri Smirnov 已提交
1477 1478
}

1479 1480
void WinEnv::StartThread(void(*function)(void* arg), void* arg) {
  return winenv_threads_.StartThread(function, arg);
D
Dmitri Smirnov 已提交
1481 1482
}

1483 1484
void WinEnv::WaitForJoin() {
  return winenv_threads_.WaitForJoin();
D
Dmitri Smirnov 已提交
1485 1486
}

1487 1488
unsigned int  WinEnv::GetThreadPoolQueueLen(Env::Priority pri) const {
  return winenv_threads_.GetThreadPoolQueueLen(pri);
D
Dmitri Smirnov 已提交
1489 1490
}

1491 1492
uint64_t WinEnv::GetThreadID() const {
  return winenv_threads_.GetThreadID();
D
Dmitri Smirnov 已提交
1493 1494
}

1495 1496 1497 1498
Status WinEnv::GetFreeSpace(const std::string& path, uint64_t* diskfree) {
  return winenv_io_.GetFreeSpace(path, diskfree);
}

1499 1500 1501
void WinEnv::SleepForMicroseconds(int micros) {
  return winenv_threads_.SleepForMicroseconds(micros);
}
D
Dmitri Smirnov 已提交
1502

1503 1504 1505 1506
// Allow increasing the number of worker threads.
void  WinEnv::SetBackgroundThreads(int num, Env::Priority pri) {
  return winenv_threads_.SetBackgroundThreads(num, pri);
}
D
Dmitri Smirnov 已提交
1507

1508 1509 1510 1511
int WinEnv::GetBackgroundThreads(Env::Priority pri) {
  return winenv_threads_.GetBackgroundThreads(pri);
}

1512 1513
void  WinEnv::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) {
  return winenv_threads_.IncBackgroundThreadsIfNeeded(num, pri);
D
Dmitri Smirnov 已提交
1514 1515
}

D
Dmitri Smirnov 已提交
1516
EnvOptions WinEnv::OptimizeForManifestRead(
1517
    const EnvOptions& env_options) const {
D
Dmitri Smirnov 已提交
1518 1519 1520
  return winenv_io_.OptimizeForManifestRead(env_options);
}

1521
EnvOptions WinEnv::OptimizeForLogWrite(const EnvOptions& env_options,
1522
                                       const DBOptions& db_options) const {
1523 1524
  return winenv_io_.OptimizeForLogWrite(env_options, db_options);
}
D
Dmitri Smirnov 已提交
1525

1526
EnvOptions WinEnv::OptimizeForManifestWrite(
1527
    const EnvOptions& env_options) const {
1528
  return winenv_io_.OptimizeForManifestWrite(env_options);
D
Dmitri Smirnov 已提交
1529 1530
}

1531
}  // namespace port
D
Dmitri Smirnov 已提交
1532 1533 1534 1535 1536 1537 1538 1539

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

  UUID uuid;
  UuidCreateSequential(&uuid);

  RPC_CSTR rpc_str;
O
Orgad Shaneh 已提交
1540 1541 1542
  auto status = UuidToStringA(&uuid, &rpc_str);
  (void)status;
  assert(status == RPC_S_OK);
D
Dmitri Smirnov 已提交
1543 1544 1545

  result = reinterpret_cast<char*>(rpc_str);

O
Orgad Shaneh 已提交
1546 1547
  status = RpcStringFreeA(&rpc_str);
  assert(status == RPC_S_OK);
D
Dmitri Smirnov 已提交
1548 1549 1550 1551

  return result;
}

1552
}  // namespace ROCKSDB_NAMESPACE