// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // 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). // // 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. #include "port/win/env_win.h" #include "port/win/win_thread.h" #include #include #include #include #include // _getpid #include // _access #include // _rmdir, _mkdir, _getcwd #include #include #include "rocksdb/env.h" #include "rocksdb/slice.h" #include "port/port.h" #include "port/dirent.h" #include "port/win/win_logger.h" #include "port/win/io_win.h" #include "monitoring/iostats_context_imp.h" #include "monitoring/thread_status_updater.h" #include "monitoring/thread_status_util.h" #include // for uuid generation #include namespace rocksdb { ThreadStatusUpdater* CreateThreadStatusUpdater() { return new ThreadStatusUpdater(); } namespace { // RAII helpers for HANDLEs const auto CloseHandleFunc = [](HANDLE h) { ::CloseHandle(h); }; typedef std::unique_ptr UniqueCloseHandlePtr; void WinthreadCall(const char* label, std::error_code result) { if (0 != result.value()) { fprintf(stderr, "pthread %s: %s\n", label, strerror(result.value())); abort(); } } } namespace port { WinEnvIO::WinEnvIO(Env* hosted_env) : hosted_env_(hosted_env), page_size_(4 * 1012), allocation_granularity_(page_size_), perf_counter_frequency_(0), GetSystemTimePreciseAsFileTime_(NULL) { SYSTEM_INFO sinfo; GetSystemInfo(&sinfo); page_size_ = sinfo.dwPageSize; allocation_granularity_ = sinfo.dwAllocationGranularity; { LARGE_INTEGER qpf; // No init as the compiler complains about unused var BOOL ret; ret = QueryPerformanceFrequency(&qpf); assert(ret == TRUE); perf_counter_frequency_ = qpf.QuadPart; } HMODULE module = GetModuleHandle("kernel32.dll"); if (module != NULL) { GetSystemTimePreciseAsFileTime_ = (FnGetSystemTimePreciseAsFileTime)GetProcAddress( module, "GetSystemTimePreciseAsFileTime"); } } WinEnvIO::~WinEnvIO() { } Status WinEnvIO::DeleteFile(const std::string& fname) { Status result; if (_unlink(fname.c_str())) { result = IOError("Failed to delete: " + fname, errno); } return result; } 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"); } *unix_time = time; return Status::OK(); } Status WinEnvIO::NewSequentialFile(const std::string& fname, std::unique_ptr* result, const EnvOptions& options) { Status s; result->reset(); // 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; DWORD fileFlags = FILE_ATTRIBUTE_READONLY; if (options.use_direct_reads && !options.use_mmap_reads) { fileFlags |= FILE_FLAG_NO_BUFFERING; } { 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" fileFlags, NULL); } if (INVALID_HANDLE_VALUE == hFile) { auto lastError = GetLastError(); s = IOErrorFromWindowsError("Failed to open NewSequentialFile" + fname, lastError); } else { result->reset(new WinSequentialFile(fname, hFile, options)); } return s; } Status WinEnvIO::NewRandomAccessFile(const std::string& fname, std::unique_ptr* result, const EnvOptions& options) { result->reset(); 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 fileFlags = FILE_ATTRIBUTE_READONLY; if (options.use_direct_reads && !options.use_mmap_reads) { fileFlags |= FILE_FLAG_NO_BUFFERING; } else { fileFlags |= FILE_FLAG_RANDOM_ACCESS; } /// 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); } if (INVALID_HANDLE_VALUE == hFile) { auto lastError = GetLastError(); return IOErrorFromWindowsError( "NewRandomAccessFile failed to Create/Open: " + fname, lastError); } UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc); // 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; s = GetFileSize(fname, &fileSize); if (s.ok()) { // Will not map empty files if (fileSize == 0) { return IOError( "NewRandomAccessFile failed to map empty file: " + fname, EINVAL); } HANDLE hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, // Whole file at its present length 0, NULL); // Mapping name if (!hMap) { auto lastError = GetLastError(); return IOErrorFromWindowsError( "Failed to create file mapping for NewRandomAccessFile: " + fname, lastError); } UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc); 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 if (!mapped_region) { auto lastError = GetLastError(); return IOErrorFromWindowsError( "Failed to MapViewOfFile for NewRandomAccessFile: " + fname, lastError); } result->reset(new WinMmapReadableFile(fname, hFile, hMap, mapped_region, fileSize)); mapGuard.release(); fileGuard.release(); } } else { result->reset(new WinRandomAccessFile(fname, hFile, page_size_, options)); fileGuard.release(); } return s; } Status WinEnvIO::OpenWritableFile(const std::string& fname, std::unique_ptr* result, const EnvOptions& options, bool reopen) { const size_t c_BufferCapacity = 64 * 1024; EnvOptions local_options(options); result->reset(); Status s; DWORD fileFlags = FILE_ATTRIBUTE_NORMAL; if (local_options.use_direct_writes && !local_options.use_mmap_writes) { fileFlags = FILE_FLAG_NO_BUFFERING; } // 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; if (local_options.use_mmap_writes) { desired_access |= GENERIC_READ; } else { // Adding this solely for tests to pass (fault_injection_test, // wal_manager_test). shared_mode |= (FILE_SHARE_WRITE | FILE_SHARE_DELETE); } // This will always truncate the file DWORD creation_disposition = CREATE_ALWAYS; if (reopen) { creation_disposition = OPEN_ALWAYS; } HANDLE hFile = 0; { IOSTATS_TIMER_GUARD(open_nanos); hFile = CreateFileA( fname.c_str(), desired_access, // Access desired shared_mode, NULL, // Security attributes creation_disposition, // Posix env says (reopen) ? (O_CREATE | O_APPEND) : O_CREAT | O_TRUNC fileFlags, // Flags NULL); // Template File } if (INVALID_HANDLE_VALUE == hFile) { auto lastError = GetLastError(); return IOErrorFromWindowsError( "Failed to create a NewWriteableFile: " + fname, lastError); } // 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); } } 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 result->reset(new WinWritableFile(fname, hFile, page_size_, c_BufferCapacity, local_options)); } return s; } Status WinEnvIO::NewRandomRWFile(const std::string & fname, std::unique_ptr* result, const EnvOptions & options) { 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; DWORD creation_disposition = OPEN_ALWAYS; // Create if necessary or open existing DWORD file_flags = FILE_FLAG_RANDOM_ACCESS; if (options.use_direct_reads && options.use_direct_writes) { 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); result->reset(new WinRandomRWFile(fname, hFile, page_size_, options)); fileGuard.release(); return s; } Status WinEnvIO::NewDirectory(const std::string& name, std::unique_ptr* result) { Status s; // Must be nullptr on failure result->reset(); // Must fail if directory does not exist if (!DirExists(name)) { s = IOError("Directory does not exist: " + name, EEXIST); } else { IOSTATS_TIMER_GUARD(open_nanos); result->reset(new WinDirectory); } return s; } Status WinEnvIO::FileExists(const std::string& fname) { // F_OK == 0 const int F_OK_ = 0; return _access(fname.c_str(), F_OK_) == 0 ? Status::OK() : Status::NotFound(); } Status WinEnvIO::GetChildren(const std::string& dir, std::vector* result) { result->clear(); std::vector output; Status status; auto CloseDir = [](DIR* p) { closedir(p); }; std::unique_ptr dirp(opendir(dir.c_str()), CloseDir); if (!dirp) { switch (errno) { case EACCES: case ENOENT: case ENOTDIR: return Status::NotFound(); default: return IOError(dir, errno); } } else { if (result->capacity() > 0) { output.reserve(result->capacity()); } struct dirent* ent = readdir(dirp.get()); while (ent) { output.push_back(ent->d_name); ent = readdir(dirp.get()); } } output.swap(*result); return status; } Status WinEnvIO::CreateDir(const std::string& name) { Status result; if (_mkdir(name.c_str()) != 0) { auto code = errno; result = IOError("Failed to create dir: " + name, code); } return result; } Status WinEnvIO::CreateDirIfMissing(const std::string& name) { Status result; if (DirExists(name)) { return result; } if (_mkdir(name.c_str()) != 0) { if (errno == EEXIST) { result = Status::IOError("`" + name + "' exists but is not a directory"); } else { auto code = errno; result = IOError("Failed to create dir: " + name, code); } } return result; } Status WinEnvIO::DeleteDir(const std::string& name) { Status result; if (_rmdir(name.c_str()) != 0) { auto code = errno; result = IOError("Failed to remove dir: " + name, code); } return result; } Status WinEnvIO::GetFileSize(const std::string& fname, uint64_t* size) { Status s; 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); } return s; } 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; } return s; } Status WinEnvIO::RenameFile(const std::string& src, const std::string& target) { Status result; // 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(); std::string text("Failed to rename: "); text.append(src).append(" to: ").append(target); result = IOErrorFromWindowsError(text, lastError); } return result; } Status WinEnvIO::LinkFile(const std::string& src, const std::string& target) { Status result; if (!CreateHardLinkA(target.c_str(), src.c_str(), NULL)) { DWORD lastError = GetLastError(); std::string text("Failed to link: "); text.append(src).append(" to: ").append(target); result = IOErrorFromWindowsError(text, lastError); } return result; } Status WinEnvIO::LockFile(const std::string& lockFname, FileLock** lock) { assert(lock != nullptr); *lock = NULL; Status result; // No-sharing, this is a LOCK file const DWORD ExclusiveAccessON = 0; // 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); } if (INVALID_HANDLE_VALUE == hFile) { auto lastError = GetLastError(); result = IOErrorFromWindowsError( "Failed to create lock file: " + lockFname, lastError); } else { *lock = new WinFileLock(hFile); } return result; } Status WinEnvIO::UnlockFile(FileLock* lock) { Status result; assert(lock != nullptr); delete lock; return result; } Status WinEnvIO::GetTestDirectory(std::string* result) { std::string output; const char* env = getenv("TEST_TMPDIR"); if (env && env[0] != '\0') { output = env; CreateDir(output); } else { env = getenv("TMP"); if (env && env[0] != '\0') { output = env; } else { output = "c:\\tmp"; } CreateDir(output); } output.append("\\testrocksdb-"); output.append(std::to_string(_getpid())); CreateDir(output); output.swap(*result); return Status::OK(); } Status WinEnvIO::NewLogger(const std::string& fname, std::shared_ptr* result) { Status s; result->reset(); 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; } uint64_t WinEnvIO::NowMicros() { if (GetSystemTimePreciseAsFileTime_ != NULL) { // all std::chrono clocks on windows proved to return // values that may repeat that is not good enough for some uses. const int64_t c_UnixEpochStartTicks = 116444736000000000LL; const int64_t c_FtToMicroSec = 10; // This interface needs to return system time and not // just any microseconds because it is often used as an argument // to TimedWait() on condition variable FILETIME ftSystemTime; GetSystemTimePreciseAsFileTime_(&ftSystemTime); LARGE_INTEGER li; li.LowPart = ftSystemTime.dwLowDateTime; li.HighPart = ftSystemTime.dwHighDateTime; // Subtract unix epoch start li.QuadPart -= c_UnixEpochStartTicks; // Convert to microsecs li.QuadPart /= c_FtToMicroSec; return li.QuadPart; } using namespace std::chrono; return duration_cast(system_clock::now().time_since_epoch()).count(); } 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(¤t_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; } Status WinEnvIO::GetHostName(char* name, uint64_t len) { Status s; DWORD nSize = static_cast( std::min(len, std::numeric_limits::max())); if (!::GetComputerNameA(name, &nSize)) { auto lastError = GetLastError(); s = IOErrorFromWindowsError("GetHostName", lastError); } else { name[nSize] = 0; } return s; } Status WinEnvIO::GetAbsolutePath(const std::string& db_path, std::string* output_path) { // Check if we already have an absolute path // that starts with non dot and has a semicolon in it if ((!db_path.empty() && (db_path[0] == '/' || db_path[0] == '\\')) || (db_path.size() > 2 && db_path[0] != '.' && ((db_path[1] == ':' && db_path[2] == '\\') || (db_path[1] == ':' && db_path[2] == '/')))) { *output_path = db_path; return Status::OK(); } std::string result; result.resize(_MAX_PATH); char* ret = _getcwd(&result[0], _MAX_PATH); if (ret == nullptr) { return Status::IOError("Failed to get current working directory", strerror(errno)); } result.resize(strlen(result.data())); result.swap(*output_path); return Status::OK(); } std::string WinEnvIO::TimeToString(uint64_t secondsSince1970) { std::string result; const time_t seconds = secondsSince1970; const int maxsize = 64; struct tm t; errno_t ret = localtime_s(&t, &seconds); if (ret) { result = std::to_string(seconds); } else { result.resize(maxsize); char* p = &result[0]; int len = snprintf(p, maxsize, "%04d/%02d/%02d-%02d:%02d:%02d ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); assert(len > 0); result.resize(len); } return result; } EnvOptions WinEnvIO::OptimizeForLogWrite(const EnvOptions& env_options, const DBOptions& db_options) const { EnvOptions optimized = env_options; optimized.bytes_per_sync = db_options.wal_bytes_per_sync; optimized.use_mmap_writes = false; // This is because we flush only whole pages on unbuffered io and // the last records are not guaranteed to be flushed. optimized.use_direct_writes = false; // TODO(icanadi) it's faster if fallocate_with_keep_size is false, but it // breaks TransactionLogIteratorStallAtLastRecord unit test. Fix the unit // test and make this false optimized.fallocate_with_keep_size = true; return optimized; } EnvOptions WinEnvIO::OptimizeForManifestWrite( const EnvOptions& env_options) const { EnvOptions optimized = env_options; optimized.use_mmap_writes = false; optimized.use_direct_writes = false; optimized.fallocate_with_keep_size = true; 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); } return false; } //////////////////////////////////////////////////////////////////////// // WinEnvThreads WinEnvThreads::WinEnvThreads(Env* hosted_env) : hosted_env_(hosted_env), thread_pools_(Env::Priority::TOTAL) { for (int pool_id = 0; pool_id < Env::Priority::TOTAL; ++pool_id) { thread_pools_[pool_id].SetThreadPriority( static_cast(pool_id)); // This allows later initializing the thread-local-env of each thread. thread_pools_[pool_id].SetHostEnv(hosted_env); } } WinEnvThreads::~WinEnvThreads() { WaitForJoin(); for (auto& thpool : thread_pools_) { thpool.JoinAllThreads(); } } void WinEnvThreads::Schedule(void(*function)(void*), void* arg, Env::Priority pri, void* tag, void(*unschedFunction)(void* arg)) { assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH); thread_pools_[pri].Schedule(function, arg, tag, unschedFunction); } int WinEnvThreads::UnSchedule(void* arg, Env::Priority pri) { return thread_pools_[pri].UnSchedule(arg); } namespace { struct StartThreadState { void(*user_function)(void*); void* arg; }; void* StartThreadWrapper(void* arg) { std::unique_ptr state( reinterpret_cast(arg)); state->user_function(state->arg); return nullptr; } } void WinEnvThreads::StartThread(void(*function)(void* arg), void* arg) { std::unique_ptr state(new StartThreadState); state->user_function = function; state->arg = arg; try { rocksdb::port::WindowsThread th(&StartThreadWrapper, state.get()); state.release(); std::lock_guard lg(mu_); threads_to_join_.push_back(std::move(th)); } catch (const std::system_error& ex) { WinthreadCall("start thread", ex.code()); } } void WinEnvThreads::WaitForJoin() { for (auto& th : threads_to_join_) { th.join(); } threads_to_join_.clear(); } unsigned int WinEnvThreads::GetThreadPoolQueueLen(Env::Priority pri) const { assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH); return thread_pools_[pri].GetQueueLen(); } uint64_t WinEnvThreads::gettid() { uint64_t thread_id = GetCurrentThreadId(); return thread_id; } uint64_t WinEnvThreads::GetThreadID() const { return gettid(); } void WinEnvThreads::SleepForMicroseconds(int micros) { std::this_thread::sleep_for(std::chrono::microseconds(micros)); } void WinEnvThreads::SetBackgroundThreads(int num, Env::Priority pri) { assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH); thread_pools_[pri].SetBackgroundThreads(num); } int WinEnvThreads::GetBackgroundThreads(Env::Priority pri) { assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH); return thread_pools_[pri].GetBackgroundThreads(); } void WinEnvThreads::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) { assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH); thread_pools_[pri].IncBackgroundThreadsIfNeeded(num); } ///////////////////////////////////////////////////////////////////////// // WinEnv WinEnv::WinEnv() : winenv_io_(this), winenv_threads_(this) { // Protected member of the base class thread_status_updater_ = CreateThreadStatusUpdater(); } WinEnv::~WinEnv() { // All threads must be joined before the deletion of // thread_status_updater_. delete thread_status_updater_; } Status WinEnv::GetThreadList( std::vector* thread_list) { assert(thread_status_updater_); return thread_status_updater_->GetThreadList(thread_list); } Status WinEnv::DeleteFile(const std::string& fname) { return winenv_io_.DeleteFile(fname); } Status WinEnv::GetCurrentTime(int64_t* unix_time) { return winenv_io_.GetCurrentTime(unix_time); } Status WinEnv::NewSequentialFile(const std::string& fname, std::unique_ptr* result, const EnvOptions& options) { return winenv_io_.NewSequentialFile(fname, result, options); } Status WinEnv::NewRandomAccessFile(const std::string& fname, std::unique_ptr* result, const EnvOptions& options) { return winenv_io_.NewRandomAccessFile(fname, result, options); } Status WinEnv::NewWritableFile(const std::string& fname, std::unique_ptr* result, const EnvOptions& options) { return winenv_io_.OpenWritableFile(fname, result, options, false); } Status WinEnv::ReopenWritableFile(const std::string& fname, std::unique_ptr* result, const EnvOptions& options) { return winenv_io_.OpenWritableFile(fname, result, options, true); } Status WinEnv::NewRandomRWFile(const std::string & fname, unique_ptr* result, const EnvOptions & options) { return winenv_io_.NewRandomRWFile(fname, result, options); } Status WinEnv::NewDirectory(const std::string& name, std::unique_ptr* result) { return winenv_io_.NewDirectory(name, result); } Status WinEnv::FileExists(const std::string& fname) { return winenv_io_.FileExists(fname); } Status WinEnv::GetChildren(const std::string& dir, std::vector* result) { return winenv_io_.GetChildren(dir, result); } Status WinEnv::CreateDir(const std::string& name) { return winenv_io_.CreateDir(name); } Status WinEnv::CreateDirIfMissing(const std::string& name) { return winenv_io_.CreateDirIfMissing(name); } Status WinEnv::DeleteDir(const std::string& name) { return winenv_io_.DeleteDir(name); } Status WinEnv::GetFileSize(const std::string& fname, uint64_t* size) { return winenv_io_.GetFileSize(fname, size); } Status WinEnv::GetFileModificationTime(const std::string& fname, uint64_t* file_mtime) { return winenv_io_.GetFileModificationTime(fname, file_mtime); } Status WinEnv::RenameFile(const std::string& src, const std::string& target) { return winenv_io_.RenameFile(src, target); } Status WinEnv::LinkFile(const std::string& src, const std::string& target) { return winenv_io_.LinkFile(src, target); } Status WinEnv::LockFile(const std::string& lockFname, FileLock** lock) { return winenv_io_.LockFile(lockFname, lock); } Status WinEnv::UnlockFile(FileLock* lock) { return winenv_io_.UnlockFile(lock); } Status WinEnv::GetTestDirectory(std::string* result) { return winenv_io_.GetTestDirectory(result); } Status WinEnv::NewLogger(const std::string& fname, std::shared_ptr* result) { return winenv_io_.NewLogger(fname, result); } uint64_t WinEnv::NowMicros() { return winenv_io_.NowMicros(); } uint64_t WinEnv::NowNanos() { return winenv_io_.NowNanos(); } Status WinEnv::GetHostName(char* name, uint64_t len) { return winenv_io_.GetHostName(name, len); } Status WinEnv::GetAbsolutePath(const std::string& db_path, std::string* output_path) { return winenv_io_.GetAbsolutePath(db_path, output_path); } std::string WinEnv::TimeToString(uint64_t secondsSince1970) { return winenv_io_.TimeToString(secondsSince1970); } 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); } int WinEnv::UnSchedule(void* arg, Env::Priority pri) { return winenv_threads_.UnSchedule(arg, pri); } void WinEnv::StartThread(void(*function)(void* arg), void* arg) { return winenv_threads_.StartThread(function, arg); } void WinEnv::WaitForJoin() { return winenv_threads_.WaitForJoin(); } unsigned int WinEnv::GetThreadPoolQueueLen(Env::Priority pri) const { return winenv_threads_.GetThreadPoolQueueLen(pri); } uint64_t WinEnv::GetThreadID() const { return winenv_threads_.GetThreadID(); } void WinEnv::SleepForMicroseconds(int micros) { return winenv_threads_.SleepForMicroseconds(micros); } // Allow increasing the number of worker threads. void WinEnv::SetBackgroundThreads(int num, Env::Priority pri) { return winenv_threads_.SetBackgroundThreads(num, pri); } int WinEnv::GetBackgroundThreads(Env::Priority pri) { return winenv_threads_.GetBackgroundThreads(pri); } void WinEnv::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) { return winenv_threads_.IncBackgroundThreadsIfNeeded(num, pri); } EnvOptions WinEnv::OptimizeForLogWrite(const EnvOptions& env_options, const DBOptions& db_options) const { return winenv_io_.OptimizeForLogWrite(env_options, db_options); } EnvOptions WinEnv::OptimizeForManifestWrite( const EnvOptions& env_options) const { return winenv_io_.OptimizeForManifestWrite(env_options); } } // namespace port std::string Env::GenerateUniqueId() { std::string result; UUID uuid; UuidCreateSequential(&uuid); RPC_CSTR rpc_str; auto status = UuidToStringA(&uuid, &rpc_str); (void)status; assert(status == RPC_S_OK); result = reinterpret_cast(rpc_str); status = RpcStringFreeA(&rpc_str); assert(status == RPC_S_OK); return result; } } // namespace rocksdb