env_win.cc 40.8 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 27 28
#include <sys/types.h>
#include <sys/stat.h>

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

#include "port/port.h"
#include "port/dirent.h"
#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

S
sdong 已提交
43
namespace rocksdb {
D
Dmitri Smirnov 已提交
44 45 46 47 48

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

D
Dmitri Smirnov 已提交
49 50
namespace {

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

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

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

60 61 62 63
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 已提交
64
  }
65
}
D
Dmitri Smirnov 已提交
66 67 68

}

69
namespace port {
D
Dmitri Smirnov 已提交
70

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

78 79
  SYSTEM_INFO sinfo;
  GetSystemInfo(&sinfo);
D
Dmitri Smirnov 已提交
80

81 82
  page_size_ = sinfo.dwPageSize;
  allocation_granularity_ = sinfo.dwAllocationGranularity;
D
Dmitri Smirnov 已提交
83

84 85
  {
    LARGE_INTEGER qpf;
T
Tamir Duberstein 已提交
86
    BOOL ret __attribute__((__unused__));
87
    ret = QueryPerformanceFrequency(&qpf);
88 89
    assert(ret == TRUE);
    perf_counter_frequency_ = qpf.QuadPart;
D
Dmitri Smirnov 已提交
90 91
  }

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

99
WinEnvIO::~WinEnvIO() {
D
Dmitri Smirnov 已提交
100 101
}

102 103
Status WinEnvIO::DeleteFile(const std::string& fname) {
  Status result;
D
Dmitri Smirnov 已提交
104

D
Dmitri Smirnov 已提交
105 106 107 108 109
  BOOL ret = DeleteFileA(fname.c_str());
  if(!ret) {
    auto lastError = GetLastError();
    result = IOErrorFromWindowsError("Failed to delete: " + fname,
      lastError);
D
Dmitri Smirnov 已提交
110 111
  }

112
  return result;
D
Dmitri Smirnov 已提交
113 114
}

D
Dmitri Smirnov 已提交
115 116 117 118 119 120 121 122 123
Status WinEnvIO::Truncate(const std::string& fname, size_t size) {
  Status s;
  int result = truncate(fname.c_str(), size);
  if (result != 0) {
    s = IOError("Failed to truncate: " + fname, errno);
  }
  return s;
}

124 125 126 127
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 已提交
128 129
  }

130 131
  *unix_time = time;
  return Status::OK();
D
Dmitri Smirnov 已提交
132 133
}

134 135 136 137
Status WinEnvIO::NewSequentialFile(const std::string& fname,
  std::unique_ptr<SequentialFile>* result,
  const EnvOptions& options) {
  Status s;
D
Dmitri Smirnov 已提交
138

139
  result->reset();
D
Dmitri Smirnov 已提交
140

141 142 143 144
  // 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 已提交
145 146 147 148 149 150 151

  DWORD fileFlags = FILE_ATTRIBUTE_READONLY;

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

152 153 154 155 156 157
  {
    IOSTATS_TIMER_GUARD(open_nanos);
    hFile = CreateFileA(
      fname.c_str(), GENERIC_READ,
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
      OPEN_EXISTING,  // Original fopen mode is "rb"
D
Dmitri Smirnov 已提交
158
      fileFlags, NULL);
159
  }
D
Dmitri Smirnov 已提交
160

161 162 163 164 165 166
  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError("Failed to open NewSequentialFile" + fname,
      lastError);
  } else {
    result->reset(new WinSequentialFile(fname, hFile, options));
D
Dmitri Smirnov 已提交
167
  }
168 169
  return s;
}
D
Dmitri Smirnov 已提交
170

171 172 173 174 175
Status WinEnvIO::NewRandomAccessFile(const std::string& fname,
  std::unique_ptr<RandomAccessFile>* result,
  const EnvOptions& options) {
  result->reset();
  Status s;
D
Dmitri Smirnov 已提交
176

177 178 179
  // 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 已提交
180

A
Aaron Gao 已提交
181
  if (options.use_direct_reads && !options.use_mmap_reads) {
182 183 184
    fileFlags |= FILE_FLAG_NO_BUFFERING;
  } else {
    fileFlags |= FILE_FLAG_RANDOM_ACCESS;
D
Dmitri Smirnov 已提交
185
  }
D
Dmitri Smirnov 已提交
186

187 188 189 190 191 192 193 194 195
  /// 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 =
      CreateFileA(fname.c_str(), GENERIC_READ,
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
      NULL, OPEN_EXISTING, fileFlags, NULL);
D
Dmitri Smirnov 已提交
196 197
  }

198 199 200 201
  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError(
      "NewRandomAccessFile failed to Create/Open: " + fname, lastError);
D
Dmitri Smirnov 已提交
202 203
  }

204
  UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);
D
Dmitri Smirnov 已提交
205

206 207 208 209
  // 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 已提交
210

211
    s = GetFileSize(fname, &fileSize);
212

213 214 215 216 217
    if (s.ok()) {
      // Will not map empty files
      if (fileSize == 0) {
        return IOError(
          "NewRandomAccessFile failed to map empty file: " + fname, EINVAL);
D
Dmitri Smirnov 已提交
218
      }
219

220 221 222 223
      HANDLE hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY,
        0,  // Whole file at its present length
        0,
        NULL);  // Mapping name
D
Dmitri Smirnov 已提交
224

225 226 227 228 229
      if (!hMap) {
        auto lastError = GetLastError();
        return IOErrorFromWindowsError(
          "Failed to create file mapping for NewRandomAccessFile: " + fname,
          lastError);
D
Dmitri Smirnov 已提交
230 231
      }

232
      UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc);
D
Dmitri Smirnov 已提交
233

234 235 236 237 238 239
      const void* mapped_region =
        MapViewOfFileEx(hMap, FILE_MAP_READ,
        0,  // High DWORD of access start
        0,  // Low DWORD
        fileSize,
        NULL);  // Let the OS choose the mapping
D
Dmitri Smirnov 已提交
240

241 242
      if (!mapped_region) {
        auto lastError = GetLastError();
S
sdong 已提交
243
        return IOErrorFromWindowsError(
244 245
          "Failed to MapViewOfFile for NewRandomAccessFile: " + fname,
          lastError);
S
sdong 已提交
246
      }
247

248 249 250 251 252
      result->reset(new WinMmapReadableFile(fname, hFile, hMap, mapped_region,
        fileSize));

      mapGuard.release();
      fileGuard.release();
D
Dmitri Smirnov 已提交
253
    }
254
  } else {
D
Dmitri Smirnov 已提交
255 256
    result->reset(new WinRandomAccessFile(fname, hFile, 
      std::max(GetSectorSize(fname), page_size_), options));
257 258 259 260
    fileGuard.release();
  }
  return s;
}
D
Dmitri Smirnov 已提交
261

262 263 264 265 266
Status WinEnvIO::OpenWritableFile(const std::string& fname,
  std::unique_ptr<WritableFile>* result,
  const EnvOptions& options,
  bool reopen) {

267
  const size_t c_BufferCapacity = 64 * 1024;
D
Dmitri Smirnov 已提交
268

269
  EnvOptions local_options(options);
D
Dmitri Smirnov 已提交
270

271 272
  result->reset();
  Status s;
D
Dmitri Smirnov 已提交
273

274
  DWORD fileFlags = FILE_ATTRIBUTE_NORMAL;
D
Dmitri Smirnov 已提交
275

A
Aaron Gao 已提交
276
  if (local_options.use_direct_writes && !local_options.use_mmap_writes) {
277
    fileFlags = FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
D
Dmitri Smirnov 已提交
278 279
  }

280 281 282 283 284 285 286
  // 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 已提交
287

288 289
  if (local_options.use_mmap_writes) {
    desired_access |= GENERIC_READ;
D
Dmitri Smirnov 已提交
290
  } else {
291 292 293 294
    // Adding this solely for tests to pass (fault_injection_test,
    // wal_manager_test).
    shared_mode |= (FILE_SHARE_WRITE | FILE_SHARE_DELETE);
  }
D
Dmitri Smirnov 已提交
295

296 297 298 299 300 301
  // This will always truncate the file
  DWORD creation_disposition = CREATE_ALWAYS;
  if (reopen) {
    creation_disposition = OPEN_ALWAYS;
  }

302 303 304 305 306 307 308 309
  HANDLE hFile = 0;
  {
    IOSTATS_TIMER_GUARD(open_nanos);
    hFile = CreateFileA(
      fname.c_str(),
      desired_access,  // Access desired
      shared_mode,
      NULL,           // Security attributes
310
      creation_disposition,  // Posix env says (reopen) ? (O_CREATE | O_APPEND) : O_CREAT | O_TRUNC
311 312 313 314 315 316 317 318
      fileFlags,      // Flags
      NULL);          // Template File
  }

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

321 322 323 324 325 326 327 328 329 330 331 332
  // 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(
        "Failed to create a ReopenWritableFile move to the end: " + fname, lastError);
    }
  }

333 334 335 336 337 338 339 340
  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_,
      allocation_granularity_, local_options));
  } else {
    // Here we want the buffer allocation to be aligned by the SSD page size
    // and to be a multiple of it
D
Dmitri Smirnov 已提交
341
    result->reset(new WinWritableFile(fname, hFile, std::max(GetSectorSize(fname), GetPageSize()),
342
      c_BufferCapacity, local_options));
343
  }
344 345
  return s;
}
346

347
Status WinEnvIO::NewRandomRWFile(const std::string & fname,
348
  std::unique_ptr<RandomRWFile>* result, const EnvOptions & options) {
349 350 351 352 353 354 355

  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 已提交
356
  DWORD creation_disposition = OPEN_EXISTING; // Fail if file does not exist
357 358
  DWORD file_flags = FILE_FLAG_RANDOM_ACCESS;

A
Aaron Gao 已提交
359
  if (options.use_direct_reads && options.use_direct_writes) {
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
    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 =
      CreateFileA(fname.c_str(),
        desired_access,
        shared_mode,
        NULL, // Security attributes
        creation_disposition,
        file_flags,
        NULL);
  }

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

  UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);
D
Dmitri Smirnov 已提交
385 386
  result->reset(new WinRandomRWFile(fname, hFile, std::max(GetSectorSize(fname), GetPageSize()),
   options));
387 388 389 390 391
  fileGuard.release();

  return s;
}

D
Dmitri Smirnov 已提交
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
Status WinEnvIO::NewMemoryMappedFileBuffer(const std::string & fname,
  std::unique_ptr<MemoryMappedFileBuffer>* result) {
  Status s;
  result->reset();

  DWORD fileFlags = FILE_ATTRIBUTE_READONLY;

  HANDLE hFile = INVALID_HANDLE_VALUE;
  {
    IOSTATS_TIMER_GUARD(open_nanos);
    hFile = CreateFileA(
      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);
  }

  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError("Failed to open NewMemoryMappedFileBuffer: " + fname,
      lastError);
    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) {
    return Status::NotSupported("NewMemoryMappedFileBuffer can not map zero length files: " + fname);
  }

  // size_t is 32-bit with 32-bit builds
  if (fileSize > std::numeric_limits<size_t>::max()) {
    return Status::NotSupported(
      "The specified file size does not fit into 32-bit memory addressing: " + fname);
  }

  HANDLE hMap = CreateFileMappingA(hFile, NULL, PAGE_READWRITE,
      0,  // Whole file at its present length
      0,
      NULL);  // Mapping name

  if (!hMap) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError(
      "Failed to create file mapping for NewMemoryMappedFileBuffer: " + fname,
      lastError);
  }
  UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc);

  void* base = MapViewOfFileEx(hMap, FILE_MAP_WRITE,
    0,  // High DWORD of access start
    0,  // Low DWORD
    fileSize,
    NULL);  // Let the OS choose the mapping

  if (!base) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError(
      "Failed to MapViewOfFile for NewMemoryMappedFileBuffer: " + fname,
      lastError);
  }

  result->reset(new WinMemoryMappedBuffer(hFile, hMap, 
    base, static_cast<size_t>(fileSize)));

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

  return s;
}

470 471 472 473 474
Status WinEnvIO::NewDirectory(const std::string& name,
  std::unique_ptr<Directory>* result) {
  Status s;
  // Must be nullptr on failure
  result->reset();
D
Dmitri Smirnov 已提交
475

476
  if (!DirExists(name)) {
D
Dmitri Smirnov 已提交
477 478 479 480 481 482 483 484
    s = IOErrorFromWindowsError(
      "open folder: " + name, ERROR_DIRECTORY);
    return s;
  }

  HANDLE handle = INVALID_HANDLE_VALUE;
  // 0 - for access means read metadata
  {
485
    IOSTATS_TIMER_GUARD(open_nanos);
D
Dmitri Smirnov 已提交
486 487 488 489 490 491
    handle = ::CreateFileA(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);
492
  }
D
Dmitri Smirnov 已提交
493 494 495 496 497 498 499 500 501 502

  if (INVALID_HANDLE_VALUE == handle) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError(
      "open folder: " + name, lastError);
    return s;
  }

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

503 504
  return s;
}
D
Dmitri Smirnov 已提交
505

506
Status WinEnvIO::FileExists(const std::string& fname) {
D
Dmitri Smirnov 已提交
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
  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;
  if (FALSE == GetFileAttributesExA(fname.c_str(), GetFileExInfoStandard,
    &attrs)) {
    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,
        lastError);
      break;
    }
  }
  return s;
529
}
D
Dmitri Smirnov 已提交
530

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

D
Dmitri Smirnov 已提交
534
  Status status;
D
Dmitri Smirnov 已提交
535
  result->clear();
536
  std::vector<std::string> output;
D
Dmitri Smirnov 已提交
537

D
Dmitri Smirnov 已提交
538 539 540
  WIN32_FIND_DATA data;
  std::string pattern(dir);
  pattern.append("\\").append("*");
D
Dmitri Smirnov 已提交
541

D
Dmitri Smirnov 已提交
542 543 544 545 546 547
  HANDLE handle = ::FindFirstFileExA(pattern.c_str(),
    FindExInfoBasic, // Do not want alternative name
    &data,
    FindExSearchNameMatch,
    NULL, // lpSearchFilter
    0);
D
Dmitri Smirnov 已提交
548

D
Dmitri Smirnov 已提交
549 550 551 552 553 554 555 556 557 558 559 560
  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(
        "Failed to GetChhildren for: " + dir, lastError);
561
    }
D
Dmitri Smirnov 已提交
562
    return status;
563
  }
564

D
Dmitri Smirnov 已提交
565 566 567 568 569
  UniqueFindClosePtr fc(handle, FindCloseFunc);

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

D
Dmitri Smirnov 已提交
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
  // For safety
  data.cFileName[MAX_PATH - 1] = 0;

  while (true) {
    output.emplace_back(data.cFileName);
    BOOL ret =- ::FindNextFileA(handle, &data);
    // 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);
586 587
  return status;
}
D
Dmitri Smirnov 已提交
588

589 590
Status WinEnvIO::CreateDir(const std::string& name) {
  Status result;
D
Dmitri Smirnov 已提交
591

D
Dmitri Smirnov 已提交
592 593 594 595 596
  BOOL ret = CreateDirectoryA(name.c_str(), NULL);
  if (!ret) {
    auto lastError = GetLastError();
    result = IOErrorFromWindowsError(
        "Failed to create a directory: " + name, lastError);
D
Dmitri Smirnov 已提交
597 598
  }

599 600
  return result;
}
D
Dmitri Smirnov 已提交
601

602 603 604
Status  WinEnvIO::CreateDirIfMissing(const std::string& name) {
  Status result;

D
Dmitri Smirnov 已提交
605 606 607 608
  if (DirExists(name)) {
    return result;
  }

D
Dmitri Smirnov 已提交
609 610 611 612 613 614
  BOOL ret = CreateDirectoryA(name.c_str(), NULL);
  if (!ret) {
    auto lastError = GetLastError();
    if (lastError != ERROR_ALREADY_EXISTS) {
      result = IOErrorFromWindowsError(
        "Failed to create a directory: " + name, lastError);
D
Dmitri Smirnov 已提交
615
    } else {
616
      result =
D
Dmitri Smirnov 已提交
617
        Status::IOError(name + ": exists but is not a directory");
D
Dmitri Smirnov 已提交
618 619
    }
  }
620 621
  return result;
}
D
Dmitri Smirnov 已提交
622

623 624
Status WinEnvIO::DeleteDir(const std::string& name) {
  Status result;
D
Dmitri Smirnov 已提交
625 626 627 628
  BOOL ret = RemoveDirectoryA(name.c_str());
  if (!ret) {
    auto lastError = GetLastError();
    result = IOErrorFromWindowsError("Failed to remove dir: " + name, lastError);
D
Dmitri Smirnov 已提交
629
  }
630 631
  return result;
}
D
Dmitri Smirnov 已提交
632

633 634 635
Status WinEnvIO::GetFileSize(const std::string& fname,
  uint64_t* size) {
  Status s;
636

637 638 639 640 641 642 643 644 645
  WIN32_FILE_ATTRIBUTE_DATA attrs;
  if (GetFileAttributesExA(fname.c_str(), GetFileExInfoStandard, &attrs)) {
    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 已提交
646
  }
647 648
  return s;
}
D
Dmitri Smirnov 已提交
649

650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
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;
  if (GetFileAttributesExA(fname.c_str(), GetFileExInfoStandard, &attrs)) {
    *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 已提交
680 681
  }

682 683
  return s;
}
D
Dmitri Smirnov 已提交
684

685 686 687
Status WinEnvIO::RenameFile(const std::string& src,
  const std::string& target) {
  Status result;
688

689 690 691 692
  // rename() is not capable of replacing the existing file as on Linux
  // so use OS API directly
  if (!MoveFileExA(src.c_str(), target.c_str(), MOVEFILE_REPLACE_EXISTING)) {
    DWORD lastError = GetLastError();
D
Dmitri Smirnov 已提交
693

694 695
    std::string text("Failed to rename: ");
    text.append(src).append(" to: ").append(target);
D
Dmitri Smirnov 已提交
696

697
    result = IOErrorFromWindowsError(text, lastError);
D
Dmitri Smirnov 已提交
698 699
  }

700 701
  return result;
}
702

703 704 705
Status WinEnvIO::LinkFile(const std::string& src,
  const std::string& target) {
  Status result;
D
Dmitri Smirnov 已提交
706

707 708
  if (!CreateHardLinkA(target.c_str(), src.c_str(), NULL)) {
    DWORD lastError = GetLastError();
709

710 711
    std::string text("Failed to link: ");
    text.append(src).append(" to: ").append(target);
712

713
    result = IOErrorFromWindowsError(text, lastError);
714 715
  }

716 717
  return result;
}
718

719
Status WinEnvIO::NumFileLinks(const std::string& fname, uint64_t* count) {
720
  Status s;
721 722 723
  HANDLE handle = ::CreateFileA(
      fname.c_str(), 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
724 725 726

  if (INVALID_HANDLE_VALUE == handle) {
    auto lastError = GetLastError();
727
    s = IOErrorFromWindowsError("NumFileLinks: " + fname, lastError);
728 729 730 731
    return s;
  }
  UniqueCloseHandlePtr handle_guard(handle, CloseHandleFunc);
  FILE_STANDARD_INFO standard_info;
732 733 734
  if (0 != GetFileInformationByHandleEx(handle, FileStandardInfo,
                                        &standard_info,
                                        sizeof(standard_info))) {
735 736 737
    *count = standard_info.NumberOfLinks;
  } else {
    auto lastError = GetLastError();
738 739
    s = IOErrorFromWindowsError("GetFileInformationByHandleEx: " + fname,
                                lastError);
740 741 742 743
  }
  return s;
}

D
Dmitri Smirnov 已提交
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
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
  HANDLE file_1 = ::CreateFileA(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);

  if (INVALID_HANDLE_VALUE == file_1) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError(
      "open file: " + first, lastError);
    return s;
  }
  UniqueCloseHandlePtr g_1(file_1, CloseHandleFunc);

  HANDLE file_2 = ::CreateFileA(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);

  if (INVALID_HANDLE_VALUE == file_2) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError(
      "open file: " + second, lastError);
    return s;
  }
  UniqueCloseHandlePtr g_2(file_2, CloseHandleFunc);

  FILE_ID_INFO FileInfo_1;
  BOOL result = GetFileInformationByHandleEx(file_1, FileIdInfo, &FileInfo_1,
    sizeof(FileInfo_1));

  if (!result) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError(
      "stat file: " + first, lastError);
    return s;
  }

   FILE_ID_INFO FileInfo_2;
   result = GetFileInformationByHandleEx(file_2, FileIdInfo, &FileInfo_2,
    sizeof(FileInfo_2));

  if (!result) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError(
      "stat file: " + second, lastError);
    return s;
  }

  if (FileInfo_1.VolumeSerialNumber == FileInfo_2.VolumeSerialNumber) {
    *res = (0 == memcmp(FileInfo_1.FileId.Identifier, FileInfo_2.FileId.Identifier, 
      sizeof(FileInfo_1.FileId.Identifier)));
  } else {
    *res = false;
  }
#endif
  return s;
}

819 820 821
Status  WinEnvIO::LockFile(const std::string& lockFname,
  FileLock** lock) {
  assert(lock != nullptr);
822

823 824
  *lock = NULL;
  Status result;
825

826 827
  // No-sharing, this is a LOCK file
  const DWORD ExclusiveAccessON = 0;
828

829 830 831 832 833 834 835 836 837
  // 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);
    hFile = CreateFileA(lockFname.c_str(), (GENERIC_READ | GENERIC_WRITE),
      ExclusiveAccessON, NULL, CREATE_ALWAYS,
      FILE_ATTRIBUTE_NORMAL, NULL);
838 839
  }

840 841 842 843 844 845
  if (INVALID_HANDLE_VALUE == hFile) {
    auto lastError = GetLastError();
    result = IOErrorFromWindowsError(
      "Failed to create lock file: " + lockFname, lastError);
  } else {
    *lock = new WinFileLock(hFile);
D
Dmitri Smirnov 已提交
846
  }
S
sdong 已提交
847

848 849
  return result;
}
D
Dmitri Smirnov 已提交
850

851 852
Status WinEnvIO::UnlockFile(FileLock* lock) {
  Status result;
853

854
  assert(lock != nullptr);
855

856
  delete lock;
D
Dmitri Smirnov 已提交
857

858 859
  return result;
}
860

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

863
  std::string output;
D
Dmitri Smirnov 已提交
864

865 866 867 868 869
  const char* env = getenv("TEST_TMPDIR");
  if (env && env[0] != '\0') {
    output = env;
  } else {
    env = getenv("TMP");
D
Dmitri Smirnov 已提交
870

871 872 873 874
    if (env && env[0] != '\0') {
      output = env;
    } else {
      output = "c:\\tmp";
D
Dmitri Smirnov 已提交
875
    }
876
  }
D
Dmitri Smirnov 已提交
877
  CreateDir(output);
878

879 880
  output.append("\\testrocksdb-");
  output.append(std::to_string(_getpid()));
881

882
  CreateDir(output);
D
Dmitri Smirnov 已提交
883

884
  output.swap(*result);
D
Dmitri Smirnov 已提交
885

886 887
  return Status::OK();
}
D
Dmitri Smirnov 已提交
888

889 890 891
Status WinEnvIO::NewLogger(const std::string& fname,
  std::shared_ptr<Logger>* result) {
  Status s;
D
Dmitri Smirnov 已提交
892

893
  result->reset();
D
Dmitri Smirnov 已提交
894

895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
  HANDLE hFile = 0;
  {
    IOSTATS_TIMER_GUARD(open_nanos);
    hFile = CreateFileA(
      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);
  }

  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 已提交
928

929
uint64_t WinEnvIO::NowMicros() {
D
Dmitri Smirnov 已提交
930

931 932 933
  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 已提交
934
    const int64_t c_UnixEpochStartTicks = 116444736000000000LL;
935
    const int64_t c_FtToMicroSec = 10;
D
Dmitri Smirnov 已提交
936

937 938 939 940 941
    // 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 已提交
942

943 944 945 946 947 948 949 950
    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;
951
  }
952 953 954
  using namespace std::chrono;
  return duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
}
D
Dmitri Smirnov 已提交
955

956 957 958 959 960 961 962 963 964 965 966 967 968
uint64_t WinEnvIO::NowNanos() {
  // 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 to nanoseconds first to avoid loss of precision
  // and divide by frequency
  li.QuadPart *= std::nano::den;
  li.QuadPart /= perf_counter_frequency_;
  return li.QuadPart;
}
D
Dmitri Smirnov 已提交
969

970 971 972 973
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 已提交
974

975 976 977 978 979
  if (!::GetComputerNameA(name, &nSize)) {
    auto lastError = GetLastError();
    s = IOErrorFromWindowsError("GetHostName", lastError);
  } else {
    name[nSize] = 0;
980
  }
D
Dmitri Smirnov 已提交
981

982 983 984 985 986
  return s;
}

Status WinEnvIO::GetAbsolutePath(const std::string& db_path,
  std::string* output_path) {
D
Dmitri Smirnov 已提交
987

988
  // Check if we already have an absolute path
D
Dmitri Smirnov 已提交
989 990 991 992
  // For test compatibility we will consider starting slash as an
  // absolute path
  if ((!db_path.empty() && (db_path[0] == '\\' || db_path[0] == '/')) ||
    !PathIsRelativeA(db_path.c_str())) {
993 994
    *output_path = db_path;
    return Status::OK();
D
Dmitri Smirnov 已提交
995 996
  }

997
  std::string result;
D
Dmitri Smirnov 已提交
998
  result.resize(MAX_PATH);
D
Dmitri Smirnov 已提交
999

D
Dmitri Smirnov 已提交
1000 1001 1002 1003 1004 1005 1006
  // Hopefully no changes the current directory while we do this
  // however _getcwd also suffers from the same limitation
  DWORD len = GetCurrentDirectoryA(MAX_PATH, &result[0]);
  if (len == 0) {
    auto lastError = GetLastError();
    return IOErrorFromWindowsError("Failed to get current working directory",
      lastError);
1007
  }
D
Dmitri Smirnov 已提交
1008

D
Dmitri Smirnov 已提交
1009
  result.resize(len);
D
Dmitri Smirnov 已提交
1010

1011 1012 1013
  result.swap(*output_path);
  return Status::OK();
}
D
Dmitri Smirnov 已提交
1014

1015 1016
std::string WinEnvIO::TimeToString(uint64_t secondsSince1970) {
  std::string result;
D
Dmitri Smirnov 已提交
1017

1018 1019
  const time_t seconds = secondsSince1970;
  const int maxsize = 64;
D
Dmitri Smirnov 已提交
1020

1021 1022
  struct tm t;
  errno_t ret = localtime_s(&t, &seconds);
D
Dmitri Smirnov 已提交
1023

1024 1025 1026 1027 1028
  if (ret) {
    result = std::to_string(seconds);
  } else {
    result.resize(maxsize);
    char* p = &result[0];
D
Dmitri Smirnov 已提交
1029

1030 1031 1032 1033
    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);
D
Dmitri Smirnov 已提交
1034

1035
    result.resize(len);
D
Dmitri Smirnov 已提交
1036 1037
  }

1038 1039
  return result;
}
D
Dmitri Smirnov 已提交
1040

1041 1042
EnvOptions WinEnvIO::OptimizeForLogWrite(const EnvOptions& env_options,
  const DBOptions& db_options) const {
D
Dmitri Smirnov 已提交
1043 1044
  EnvOptions optimized(env_options);
  // These two the same as default optimizations
1045
  optimized.bytes_per_sync = db_options.wal_bytes_per_sync;
1046 1047
  optimized.writable_file_max_buffer_size =
      db_options.writable_file_max_buffer_size;
D
Dmitri Smirnov 已提交
1048 1049 1050 1051 1052 1053

  // 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;
1054 1055
  return optimized;
}
D
Dmitri Smirnov 已提交
1056

1057 1058
EnvOptions WinEnvIO::OptimizeForManifestWrite(
  const EnvOptions& env_options) const {
D
Dmitri Smirnov 已提交
1059
  EnvOptions optimized(env_options);
1060
  optimized.use_mmap_writes = false;
D
Dmitri Smirnov 已提交
1061 1062 1063 1064 1065 1066 1067 1068 1069
  optimized.use_direct_reads = false;
  return optimized;
}

EnvOptions WinEnvIO::OptimizeForManifestRead(
  const EnvOptions& env_options) const {
  EnvOptions optimized(env_options);
  optimized.use_mmap_writes = false;
  optimized.use_direct_reads = false;
1070 1071 1072 1073 1074 1075 1076 1077
  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;
  if (GetFileAttributesExA(dname.c_str(), GetFileExInfoStandard, &attrs)) {
    return 0 != (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
D
Dmitri Smirnov 已提交
1078
  }
1079 1080
  return false;
}
D
Dmitri Smirnov 已提交
1081

D
Dmitri Smirnov 已提交
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
size_t WinEnvIO::GetSectorSize(const std::string& fname) {
  size_t sector_size = kSectorSize;

  if (PathIsRelativeA(fname.c_str())) {
    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;
  }

  HANDLE hDevice = CreateFile(devicename, 0, 0,
                    nullptr, OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL, nullptr);

  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,
              &spropertyquery, sizeof(spropertyquery), output_buffer,
              sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), &output_bytes, nullptr);

  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,
1125
           nullptr, 0, &geometry, sizeof(geometry), &output_bytes, nullptr);
D
Dmitri Smirnov 已提交
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
    if (ret) {
      sector_size = geometry.Geometry.BytesPerSector;
    }
  }

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

  return sector_size;
}

1138 1139
////////////////////////////////////////////////////////////////////////
// WinEnvThreads
D
Dmitri Smirnov 已提交
1140

1141
WinEnvThreads::WinEnvThreads(Env* hosted_env) : hosted_env_(hosted_env), thread_pools_(Env::Priority::TOTAL) {
D
Dmitri Smirnov 已提交
1142

1143 1144 1145 1146 1147
  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 已提交
1148
  }
1149
}
D
Dmitri Smirnov 已提交
1150

1151
WinEnvThreads::~WinEnvThreads() {
D
Dmitri Smirnov 已提交
1152

1153
  WaitForJoin();
D
Dmitri Smirnov 已提交
1154

1155 1156
  for (auto& thpool : thread_pools_) {
    thpool.JoinAllThreads();
D
Dmitri Smirnov 已提交
1157 1158 1159
  }
}

1160 1161
void WinEnvThreads::Schedule(void(*function)(void*), void* arg, Env::Priority pri,
  void* tag, void(*unschedFunction)(void* arg)) {
A
Andrew Kryczka 已提交
1162
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1163 1164
  thread_pools_[pri].Schedule(function, arg, tag, unschedFunction);
}
D
Dmitri Smirnov 已提交
1165

1166 1167 1168
int WinEnvThreads::UnSchedule(void* arg, Env::Priority pri) {
  return thread_pools_[pri].UnSchedule(arg);
}
D
Dmitri Smirnov 已提交
1169

1170
namespace {
D
Dmitri Smirnov 已提交
1171

1172 1173 1174 1175
  struct StartThreadState {
    void(*user_function)(void*);
    void* arg;
  };
D
Dmitri Smirnov 已提交
1176

1177 1178 1179 1180 1181
  void* StartThreadWrapper(void* arg) {
    std::unique_ptr<StartThreadState> state(
      reinterpret_cast<StartThreadState*>(arg));
    state->user_function(state->arg);
    return nullptr;
D
Dmitri Smirnov 已提交
1182 1183
  }

1184
}
D
Dmitri Smirnov 已提交
1185

1186 1187 1188 1189 1190
void WinEnvThreads::StartThread(void(*function)(void* arg), void* arg) {
  std::unique_ptr<StartThreadState> state(new StartThreadState);
  state->user_function = function;
  state->arg = arg;
  try {
D
Dmitri Smirnov 已提交
1191

D
Dmitri Smirnov 已提交
1192
    rocksdb::port::WindowsThread th(&StartThreadWrapper, state.get());
1193
    state.release();
D
Dmitri Smirnov 已提交
1194

1195 1196
    std::lock_guard<std::mutex> lg(mu_);
    threads_to_join_.push_back(std::move(th));
D
Dmitri Smirnov 已提交
1197

1198 1199
  } catch (const std::system_error& ex) {
    WinthreadCall("start thread", ex.code());
D
Dmitri Smirnov 已提交
1200
  }
1201
}
D
Dmitri Smirnov 已提交
1202

1203 1204 1205
void WinEnvThreads::WaitForJoin() {
  for (auto& th : threads_to_join_) {
    th.join();
D
Dmitri Smirnov 已提交
1206
  }
1207 1208
  threads_to_join_.clear();
}
D
Dmitri Smirnov 已提交
1209

1210
unsigned int WinEnvThreads::GetThreadPoolQueueLen(Env::Priority pri) const {
A
Andrew Kryczka 已提交
1211
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1212 1213
  return thread_pools_[pri].GetQueueLen();
}
D
Dmitri Smirnov 已提交
1214

1215 1216 1217 1218
uint64_t WinEnvThreads::gettid() {
  uint64_t thread_id = GetCurrentThreadId();
  return thread_id;
}
D
Dmitri Smirnov 已提交
1219

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

1222 1223 1224
void  WinEnvThreads::SleepForMicroseconds(int micros) {
  std::this_thread::sleep_for(std::chrono::microseconds(micros));
}
D
Dmitri Smirnov 已提交
1225

1226
void WinEnvThreads::SetBackgroundThreads(int num, Env::Priority pri) {
A
Andrew Kryczka 已提交
1227
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1228 1229
  thread_pools_[pri].SetBackgroundThreads(num);
}
D
Dmitri Smirnov 已提交
1230

1231
int WinEnvThreads::GetBackgroundThreads(Env::Priority pri) {
A
Andrew Kryczka 已提交
1232
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1233 1234 1235
  return thread_pools_[pri].GetBackgroundThreads();
}

1236
void WinEnvThreads::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) {
A
Andrew Kryczka 已提交
1237
  assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH);
1238 1239
  thread_pools_[pri].IncBackgroundThreadsIfNeeded(num);
}
D
Dmitri Smirnov 已提交
1240

1241 1242
/////////////////////////////////////////////////////////////////////////
// WinEnv
D
Dmitri Smirnov 已提交
1243

1244 1245 1246 1247
WinEnv::WinEnv() : winenv_io_(this), winenv_threads_(this) {
  // Protected member of the base class
  thread_status_updater_ = CreateThreadStatusUpdater();
}
D
Dmitri Smirnov 已提交
1248 1249


1250 1251 1252 1253 1254
WinEnv::~WinEnv() {
  // All threads must be joined before the deletion of
  // thread_status_updater_.
  delete thread_status_updater_;
}
D
Dmitri Smirnov 已提交
1255

1256 1257 1258 1259 1260
Status WinEnv::GetThreadList(
  std::vector<ThreadStatus>* thread_list) {
  assert(thread_status_updater_);
  return thread_status_updater_->GetThreadList(thread_list);
}
D
Dmitri Smirnov 已提交
1261

1262 1263 1264
Status WinEnv::DeleteFile(const std::string& fname) {
  return winenv_io_.DeleteFile(fname);
}
D
Dmitri Smirnov 已提交
1265

D
Dmitri Smirnov 已提交
1266 1267 1268 1269
Status WinEnv::Truncate(const std::string& fname, size_t size) {
  return winenv_io_.Truncate(fname, size);
}

1270 1271 1272
Status WinEnv::GetCurrentTime(int64_t* unix_time) {
  return winenv_io_.GetCurrentTime(unix_time);
}
D
Dmitri Smirnov 已提交
1273

1274 1275 1276 1277 1278
Status  WinEnv::NewSequentialFile(const std::string& fname,
  std::unique_ptr<SequentialFile>* result,
  const EnvOptions& options) {
  return winenv_io_.NewSequentialFile(fname, result, options);
}
D
Dmitri Smirnov 已提交
1279

1280 1281 1282 1283 1284
Status WinEnv::NewRandomAccessFile(const std::string& fname,
  std::unique_ptr<RandomAccessFile>* result,
  const EnvOptions& options) {
  return winenv_io_.NewRandomAccessFile(fname, result, options);
}
D
Dmitri Smirnov 已提交
1285

1286
Status WinEnv::NewWritableFile(const std::string& fname,
A
Aaron Gao 已提交
1287 1288
                               std::unique_ptr<WritableFile>* result,
                               const EnvOptions& options) {
1289 1290 1291 1292 1293 1294
  return winenv_io_.OpenWritableFile(fname, result, options, false);
}

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

1297
Status WinEnv::NewRandomRWFile(const std::string & fname,
D
Dmitri Smirnov 已提交
1298
  std::unique_ptr<RandomRWFile>* result, const EnvOptions & options) {
1299 1300 1301
  return winenv_io_.NewRandomRWFile(fname, result, options);
}

D
Dmitri Smirnov 已提交
1302 1303 1304 1305 1306
Status WinEnv::NewMemoryMappedFileBuffer(const std::string& fname,
  std::unique_ptr<MemoryMappedFileBuffer>* result) {
  return winenv_io_.NewMemoryMappedFileBuffer(fname, result);
}

1307 1308 1309 1310
Status WinEnv::NewDirectory(const std::string& name,
  std::unique_ptr<Directory>* result) {
  return winenv_io_.NewDirectory(name, result);
}
D
Dmitri Smirnov 已提交
1311

1312 1313 1314
Status WinEnv::FileExists(const std::string& fname) {
  return winenv_io_.FileExists(fname);
}
D
Dmitri Smirnov 已提交
1315

1316 1317 1318 1319
Status WinEnv::GetChildren(const std::string& dir,
  std::vector<std::string>* result) {
  return winenv_io_.GetChildren(dir, result);
}
D
Dmitri Smirnov 已提交
1320

1321 1322 1323
Status WinEnv::CreateDir(const std::string& name) {
  return winenv_io_.CreateDir(name);
}
D
Dmitri Smirnov 已提交
1324

1325 1326 1327
Status WinEnv::CreateDirIfMissing(const std::string& name) {
  return winenv_io_.CreateDirIfMissing(name);
}
D
Dmitri Smirnov 已提交
1328

1329 1330 1331
Status WinEnv::DeleteDir(const std::string& name) {
  return winenv_io_.DeleteDir(name);
}
D
Dmitri Smirnov 已提交
1332

1333 1334 1335 1336
Status WinEnv::GetFileSize(const std::string& fname,
  uint64_t* size) {
  return winenv_io_.GetFileSize(fname, size);
}
D
Dmitri Smirnov 已提交
1337

1338 1339 1340 1341
Status  WinEnv::GetFileModificationTime(const std::string& fname,
  uint64_t* file_mtime) {
  return winenv_io_.GetFileModificationTime(fname, file_mtime);
}
D
Dmitri Smirnov 已提交
1342

1343 1344 1345 1346
Status WinEnv::RenameFile(const std::string& src,
  const std::string& target) {
  return winenv_io_.RenameFile(src, target);
}
D
Dmitri Smirnov 已提交
1347

1348 1349 1350 1351
Status WinEnv::LinkFile(const std::string& src,
  const std::string& target) {
  return winenv_io_.LinkFile(src, target);
}
D
Dmitri Smirnov 已提交
1352

1353 1354 1355 1356
Status WinEnv::NumFileLinks(const std::string& fname, uint64_t* count) {
  return winenv_io_.NumFileLinks(fname, count);
}

D
Dmitri Smirnov 已提交
1357 1358 1359 1360 1361
Status WinEnv::AreFilesSame(const std::string& first,
  const std::string& second, bool* res) {
  return winenv_io_.AreFilesSame(first, second, res);
}

1362 1363 1364 1365
Status WinEnv::LockFile(const std::string& lockFname,
  FileLock** lock) {
  return winenv_io_.LockFile(lockFname, lock);
}
D
Dmitri Smirnov 已提交
1366

1367 1368 1369
Status WinEnv::UnlockFile(FileLock* lock) {
  return winenv_io_.UnlockFile(lock);
}
D
Dmitri Smirnov 已提交
1370

1371 1372 1373
Status  WinEnv::GetTestDirectory(std::string* result) {
  return winenv_io_.GetTestDirectory(result);
}
D
Dmitri Smirnov 已提交
1374

1375 1376 1377 1378
Status WinEnv::NewLogger(const std::string& fname,
  std::shared_ptr<Logger>* result) {
  return winenv_io_.NewLogger(fname, result);
}
1379

1380 1381 1382
uint64_t WinEnv::NowMicros() {
  return winenv_io_.NowMicros();
}
1383

1384 1385 1386
uint64_t  WinEnv::NowNanos() {
  return winenv_io_.NowNanos();
}
D
Dmitri Smirnov 已提交
1387

1388 1389 1390
Status WinEnv::GetHostName(char* name, uint64_t len) {
  return winenv_io_.GetHostName(name, len);
}
D
Dmitri Smirnov 已提交
1391

1392 1393 1394 1395
Status WinEnv::GetAbsolutePath(const std::string& db_path,
  std::string* output_path) {
  return winenv_io_.GetAbsolutePath(db_path, output_path);
}
D
Dmitri Smirnov 已提交
1396

1397 1398 1399
std::string WinEnv::TimeToString(uint64_t secondsSince1970) {
  return winenv_io_.TimeToString(secondsSince1970);
}
D
Dmitri Smirnov 已提交
1400

1401 1402 1403 1404
void  WinEnv::Schedule(void(*function)(void*), void* arg, Env::Priority pri,
  void* tag,
  void(*unschedFunction)(void* arg)) {
  return winenv_threads_.Schedule(function, arg, pri, tag, unschedFunction);
D
Dmitri Smirnov 已提交
1405 1406
}

1407 1408
int WinEnv::UnSchedule(void* arg, Env::Priority pri) {
  return winenv_threads_.UnSchedule(arg, pri);
D
Dmitri Smirnov 已提交
1409 1410
}

1411 1412
void WinEnv::StartThread(void(*function)(void* arg), void* arg) {
  return winenv_threads_.StartThread(function, arg);
D
Dmitri Smirnov 已提交
1413 1414
}

1415 1416
void WinEnv::WaitForJoin() {
  return winenv_threads_.WaitForJoin();
D
Dmitri Smirnov 已提交
1417 1418
}

1419 1420
unsigned int  WinEnv::GetThreadPoolQueueLen(Env::Priority pri) const {
  return winenv_threads_.GetThreadPoolQueueLen(pri);
D
Dmitri Smirnov 已提交
1421 1422
}

1423 1424
uint64_t WinEnv::GetThreadID() const {
  return winenv_threads_.GetThreadID();
D
Dmitri Smirnov 已提交
1425 1426
}

1427 1428 1429
void WinEnv::SleepForMicroseconds(int micros) {
  return winenv_threads_.SleepForMicroseconds(micros);
}
D
Dmitri Smirnov 已提交
1430

1431 1432 1433 1434
// Allow increasing the number of worker threads.
void  WinEnv::SetBackgroundThreads(int num, Env::Priority pri) {
  return winenv_threads_.SetBackgroundThreads(num, pri);
}
D
Dmitri Smirnov 已提交
1435

1436 1437 1438 1439
int WinEnv::GetBackgroundThreads(Env::Priority pri) {
  return winenv_threads_.GetBackgroundThreads(pri);
}

1440 1441
void  WinEnv::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) {
  return winenv_threads_.IncBackgroundThreadsIfNeeded(num, pri);
D
Dmitri Smirnov 已提交
1442 1443
}

D
Dmitri Smirnov 已提交
1444 1445 1446 1447 1448
EnvOptions WinEnv::OptimizeForManifestRead(
  const EnvOptions& env_options) const {
  return winenv_io_.OptimizeForManifestRead(env_options);
}

1449 1450 1451 1452
EnvOptions WinEnv::OptimizeForLogWrite(const EnvOptions& env_options,
  const DBOptions& db_options) const {
  return winenv_io_.OptimizeForLogWrite(env_options, db_options);
}
D
Dmitri Smirnov 已提交
1453

1454 1455 1456
EnvOptions WinEnv::OptimizeForManifestWrite(
  const EnvOptions& env_options) const {
  return winenv_io_.OptimizeForManifestWrite(env_options);
D
Dmitri Smirnov 已提交
1457 1458
}

1459
}  // namespace port
D
Dmitri Smirnov 已提交
1460 1461 1462 1463 1464 1465 1466 1467

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

  UUID uuid;
  UuidCreateSequential(&uuid);

  RPC_CSTR rpc_str;
O
Orgad Shaneh 已提交
1468 1469 1470
  auto status = UuidToStringA(&uuid, &rpc_str);
  (void)status;
  assert(status == RPC_S_OK);
D
Dmitri Smirnov 已提交
1471 1472 1473

  result = reinterpret_cast<char*>(rpc_str);

O
Orgad Shaneh 已提交
1474 1475
  status = RpcStringFreeA(&rpc_str);
  assert(status == RPC_S_OK);
D
Dmitri Smirnov 已提交
1476 1477 1478 1479 1480

  return result;
}

}  // namespace rocksdb