rocksdb/port/win/env_win.h
zczhu 96206531bc Support reservation in thread pool (#10278)
Summary:
Add `ReserveThreads` and `ReleaseThreads` functions in thread pool to support reservation in for a specific thread pool.  With this feature, a thread will be blocked if the number of waiting threads (noted by `num_waiting_threads_`) equals the number of reserved threads (noted by `reserved_threads_`), normally `reserved_threads_` is upper bounded by `num_waiting_threads_`; in rare cases (e.g. `SetBackgroundThreadsInternal` is called when some threads are already reserved), `num_waiting_threads_` can be less than `reserved_threads`.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/10278

Test Plan: Add `ReserveThreads` unit test in `env_test`. Update the unit test `SimpleColumnFamilyInfoTest` in `thread_list_test` with adding `ReserveThreads` related assertions.

Reviewed By: hx235

Differential Revision: D37640946

Pulled By: littlepig2013

fbshipit-source-id: 4d691f6b9a433569f96ab52d52c3defe5b065367
2022-07-08 19:48:09 -07:00

305 lines
12 KiB
C++

// 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.
//
// An Env is an interface used by the rocksdb implementation to access
// operating system functionality like the filesystem etc. Callers
// may wish to provide a custom Env object when opening a database to
// get fine gain control; e.g., to rate limit file system operations.
//
// All Env implementations are safe for concurrent access from
// multiple threads without any external synchronization.
#pragma once
#include <stdint.h>
#include <windows.h>
#include <mutex>
#include <string>
#include <vector>
#include "env/composite_env_wrapper.h"
#include "port/port.h"
#include "rocksdb/env.h"
#include "rocksdb/file_system.h"
#include "rocksdb/system_clock.h"
#include "util/threadpool_imp.h"
#undef GetCurrentTime
#undef DeleteFile
#undef LoadLibrary
namespace ROCKSDB_NAMESPACE {
namespace port {
// Currently not designed for inheritance but rather a replacement
class WinEnvThreads {
public:
explicit WinEnvThreads(Env* hosted_env);
~WinEnvThreads();
WinEnvThreads(const WinEnvThreads&) = delete;
WinEnvThreads& operator=(const WinEnvThreads&) = delete;
void Schedule(void (*function)(void*), void* arg, Env::Priority pri,
void* tag, void (*unschedFunction)(void* arg));
int UnSchedule(void* arg, Env::Priority pri);
void StartThread(void (*function)(void* arg), void* arg);
void WaitForJoin();
unsigned int GetThreadPoolQueueLen(Env::Priority pri) const;
int ReserveThreads(int threads_to_be_reserved, Env::Priority pri);
int ReleaseThreads(int threads_to_be_released, Env::Priority pri);
static uint64_t gettid();
uint64_t GetThreadID() const;
// Allow increasing the number of worker threads.
void SetBackgroundThreads(int num, Env::Priority pri);
int GetBackgroundThreads(Env::Priority pri);
void IncBackgroundThreadsIfNeeded(int num, Env::Priority pri);
private:
Env* hosted_env_;
mutable std::mutex mu_;
std::vector<ThreadPoolImpl> thread_pools_;
std::vector<Thread> threads_to_join_;
};
class WinClock : public SystemClock {
public:
WinClock();
virtual ~WinClock() {}
static const char* kClassName() { return "WindowsClock"; }
const char* Name() const override { return kDefaultName(); }
const char* NickName() const override { return kClassName(); }
uint64_t NowMicros() override;
uint64_t NowNanos() override;
// 0 indicates not supported
uint64_t CPUMicros() override { return 0; }
void SleepForMicroseconds(int micros) override;
Status GetCurrentTime(int64_t* unix_time) override;
// Converts seconds-since-Jan-01-1970 to a printable string
virtual std::string TimeToString(uint64_t time);
uint64_t GetPerfCounterFrequency() const { return perf_counter_frequency_; }
private:
using FnGetSystemTimePreciseAsFileTime = VOID(WINAPI*)(LPFILETIME);
uint64_t perf_counter_frequency_;
uint64_t nano_seconds_per_period_;
FnGetSystemTimePreciseAsFileTime GetSystemTimePreciseAsFileTime_;
};
class WinFileSystem : public FileSystem {
public:
static const std::shared_ptr<WinFileSystem>& Default();
WinFileSystem(const std::shared_ptr<SystemClock>& clock);
~WinFileSystem() {}
static const char* kClassName() { return "WinFS"; }
const char* Name() const override { return kClassName(); }
const char* NickName() const { return kDefaultName(); }
static size_t GetSectorSize(const std::string& fname);
size_t GetPageSize() const { return page_size_; }
size_t GetAllocationGranularity() const { return allocation_granularity_; }
IOStatus DeleteFile(const std::string& fname, const IOOptions& options,
IODebugContext* dbg) override;
// Truncate the named file to the specified size.
IOStatus Truncate(const std::string& /*fname*/, size_t /*size*/,
const IOOptions& /*options*/,
IODebugContext* /*dbg*/) override;
IOStatus NewSequentialFile(const std::string& fname,
const FileOptions& file_opts,
std::unique_ptr<FSSequentialFile>* result,
IODebugContext* dbg) override;
IOStatus NewRandomAccessFile(const std::string& fname,
const FileOptions& options,
std::unique_ptr<FSRandomAccessFile>* result,
IODebugContext* /*dbg*/) override;
IOStatus NewWritableFile(const std::string& f, const FileOptions& file_opts,
std::unique_ptr<FSWritableFile>* r,
IODebugContext* dbg) override;
IOStatus ReopenWritableFile(const std::string& fname,
const FileOptions& options,
std::unique_ptr<FSWritableFile>* result,
IODebugContext* dbg) override;
IOStatus NewRandomRWFile(const std::string& fname,
const FileOptions& file_opts,
std::unique_ptr<FSRandomRWFile>* result,
IODebugContext* dbg) override;
IOStatus NewMemoryMappedFileBuffer(
const std::string& fname,
std::unique_ptr<MemoryMappedFileBuffer>* result) override;
IOStatus NewDirectory(const std::string& name, const IOOptions& io_opts,
std::unique_ptr<FSDirectory>* result,
IODebugContext* dbg) override;
IOStatus FileExists(const std::string& f, const IOOptions& io_opts,
IODebugContext* dbg) override;
IOStatus GetChildren(const std::string& dir, const IOOptions& io_opts,
std::vector<std::string>* r,
IODebugContext* dbg) override;
IOStatus CreateDir(const std::string& dirname, const IOOptions& options,
IODebugContext* dbg) override;
// Creates directory if missing. Return Ok if it exists, or successful in
// Creating.
IOStatus CreateDirIfMissing(const std::string& dirname,
const IOOptions& options,
IODebugContext* dbg) override;
// Delete the specified directory.
IOStatus DeleteDir(const std::string& dirname, const IOOptions& options,
IODebugContext* dbg) override;
// Store the size of fname in *file_size.
IOStatus GetFileSize(const std::string& fname, const IOOptions& options,
uint64_t* file_size, IODebugContext* dbg) override;
// Store the last modification time of fname in *file_mtime.
IOStatus GetFileModificationTime(const std::string& fname,
const IOOptions& options,
uint64_t* file_mtime,
IODebugContext* dbg) override;
// Rename file src to target.
IOStatus RenameFile(const std::string& src, const std::string& target,
const IOOptions& options, IODebugContext* dbg) override;
// Hard Link file src to target.
IOStatus LinkFile(const std::string& /*src*/, const std::string& /*target*/,
const IOOptions& /*options*/,
IODebugContext* /*dbg*/) override;
IOStatus NumFileLinks(const std::string& /*fname*/,
const IOOptions& /*options*/, uint64_t* /*count*/,
IODebugContext* /*dbg*/) override;
IOStatus AreFilesSame(const std::string& /*first*/,
const std::string& /*second*/,
const IOOptions& /*options*/, bool* /*res*/,
IODebugContext* /*dbg*/) override;
IOStatus LockFile(const std::string& fname, const IOOptions& options,
FileLock** lock, IODebugContext* dbg) override;
IOStatus UnlockFile(FileLock* lock, const IOOptions& options,
IODebugContext* dbg) override;
IOStatus GetTestDirectory(const IOOptions& options, std::string* path,
IODebugContext* dbg) override;
// Create and returns a default logger (an instance of EnvLogger) for storing
// informational messages. Derived classes can override to provide custom
// logger.
IOStatus NewLogger(const std::string& fname, const IOOptions& io_opts,
std::shared_ptr<Logger>* result,
IODebugContext* dbg) override;
// Get full directory name for this db.
IOStatus GetAbsolutePath(const std::string& db_path, const IOOptions& options,
std::string* output_path,
IODebugContext* dbg) override;
IOStatus IsDirectory(const std::string& /*path*/, const IOOptions& options,
bool* is_dir, IODebugContext* /*dgb*/) override;
// This seems to clash with a macro on Windows, so #undef it here
#undef GetFreeSpace
IOStatus GetFreeSpace(const std::string& /*path*/,
const IOOptions& /*options*/, uint64_t* /*diskfree*/,
IODebugContext* /*dbg*/) override;
FileOptions OptimizeForLogWrite(const FileOptions& file_options,
const DBOptions& db_options) const override;
FileOptions OptimizeForManifestRead(
const FileOptions& file_options) const override;
FileOptions OptimizeForManifestWrite(
const FileOptions& file_options) const override;
protected:
static uint64_t FileTimeToUnixTime(const FILETIME& ftTime);
// Returns true iff the named directory exists and is a directory.
virtual bool DirExists(const std::string& dname);
// Helper for NewWritable and ReopenWritableFile
virtual IOStatus OpenWritableFile(const std::string& fname,
const FileOptions& options,
std::unique_ptr<FSWritableFile>* result,
bool reopen);
private:
std::shared_ptr<SystemClock> clock_;
size_t page_size_;
size_t allocation_granularity_;
};
// Designed for inheritance so can be re-used
// but certain parts replaced
class WinEnvIO {
public:
explicit WinEnvIO(Env* hosted_env);
virtual ~WinEnvIO();
virtual Status GetHostName(char* name, uint64_t len);
private:
Env* hosted_env_;
};
class WinEnv : public CompositeEnv {
public:
WinEnv();
~WinEnv();
static const char* kClassName() { return "WinEnv"; }
const char* Name() const override { return kClassName(); }
const char* NickName() const override { return kDefaultName(); }
Status GetHostName(char* name, uint64_t len) override;
Status GetThreadList(std::vector<ThreadStatus>* thread_list) override;
void Schedule(void (*function)(void*), void* arg, Env::Priority pri,
void* tag, void (*unschedFunction)(void* arg)) override;
int UnSchedule(void* arg, Env::Priority pri) override;
void StartThread(void (*function)(void* arg), void* arg) override;
void WaitForJoin() override;
unsigned int GetThreadPoolQueueLen(Env::Priority pri) const override;
int ReserveThreads(int threads_to_be_reserved, Env::Priority pri) override;
int ReleaseThreads(int threads_to_be_released, Env::Priority pri) override;
uint64_t GetThreadID() const override;
// Allow increasing the number of worker threads.
void SetBackgroundThreads(int num, Env::Priority pri) override;
int GetBackgroundThreads(Env::Priority pri) override;
void IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) override;
private:
WinEnvIO winenv_io_;
WinEnvThreads winenv_threads_;
};
} // namespace port
} // namespace ROCKSDB_NAMESPACE