Summary: Add a new class SstFileTracker that will be notified whenever a DB add/delete/move and sst file, it will also replace DeleteScheduler SstFileTracker can be used later to abort writes when we exceed a specific size Test Plan: unit tests Reviewers: rven, anthony, yhchiang, sdong Reviewed By: sdong Subscribers: igor, lovro, march, dhruba Differential Revision: https://reviews.facebook.net/D50469main
parent
45768ade4f
commit
d6c838f1e1
@ -1,67 +0,0 @@ |
|||||||
// Copyright (c) 2015, Facebook, Inc. All rights reserved.
|
|
||||||
// This source code is licensed under the BSD-style license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
// of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
|
|
||||||
#pragma once |
|
||||||
|
|
||||||
#include <map> |
|
||||||
#include <string> |
|
||||||
#include <memory> |
|
||||||
|
|
||||||
#include "rocksdb/status.h" |
|
||||||
|
|
||||||
namespace rocksdb { |
|
||||||
|
|
||||||
class Env; |
|
||||||
class Logger; |
|
||||||
|
|
||||||
// DeleteScheduler allow the DB to enforce a rate limit on file deletion,
|
|
||||||
// Instead of deleteing files immediately, files are moved to trash_dir
|
|
||||||
// and deleted in a background thread that apply sleep penlty between deletes
|
|
||||||
// if they are happening in a rate faster than rate_bytes_per_sec,
|
|
||||||
//
|
|
||||||
// Rate limiting can be turned off by setting rate_bytes_per_sec = 0, In this
|
|
||||||
// case DeleteScheduler will delete files immediately.
|
|
||||||
class DeleteScheduler { |
|
||||||
public: |
|
||||||
virtual ~DeleteScheduler() {} |
|
||||||
|
|
||||||
// Return delete rate limit in bytes per second
|
|
||||||
virtual int64_t GetRateBytesPerSecond() = 0; |
|
||||||
|
|
||||||
// Move file to trash directory and schedule it's deletion
|
|
||||||
virtual Status DeleteFile(const std::string& fname) = 0; |
|
||||||
|
|
||||||
// Return a map containing errors that happened in the background thread
|
|
||||||
// file_path => error status
|
|
||||||
virtual std::map<std::string, Status> GetBackgroundErrors() = 0; |
|
||||||
|
|
||||||
// Wait for all files being deleteing in the background to finish or for
|
|
||||||
// destructor to be called.
|
|
||||||
virtual void WaitForEmptyTrash() = 0; |
|
||||||
}; |
|
||||||
|
|
||||||
// Create a new DeleteScheduler that can be shared among multiple RocksDB
|
|
||||||
// instances to control the file deletion rate.
|
|
||||||
//
|
|
||||||
// @env: Pointer to Env object, please see "rocksdb/env.h".
|
|
||||||
// @trash_dir: Path to the directory where deleted files will be moved into
|
|
||||||
// to be deleted in a background thread while applying rate limiting. If this
|
|
||||||
// directory dont exist, it will be created. This directory should not be
|
|
||||||
// used by any other process or any other DeleteScheduler.
|
|
||||||
// @rate_bytes_per_sec: How many bytes should be deleted per second, If this
|
|
||||||
// value is set to 1024 (1 Kb / sec) and we deleted a file of size 4 Kb
|
|
||||||
// in 1 second, we will wait for another 3 seconds before we delete other
|
|
||||||
// files, Set to 0 to disable rate limiting.
|
|
||||||
// @info_log: If not nullptr, info_log will be used to log errors.
|
|
||||||
// @delete_exisitng_trash: If set to true, the newly created DeleteScheduler
|
|
||||||
// will delete files that already exist in trash_dir.
|
|
||||||
// @status: If not nullptr, status will contain any errors that happened during
|
|
||||||
// creating the missing trash_dir or deleting existing files in trash.
|
|
||||||
extern DeleteScheduler* NewDeleteScheduler( |
|
||||||
Env* env, const std::string& trash_dir, int64_t rate_bytes_per_sec, |
|
||||||
std::shared_ptr<Logger> info_log = nullptr, |
|
||||||
bool delete_exisitng_trash = true, Status* status = nullptr); |
|
||||||
|
|
||||||
} // namespace rocksdb
|
|
@ -0,0 +1,64 @@ |
|||||||
|
// Copyright (c) 2015, Facebook, Inc. All rights reserved.
|
||||||
|
// This source code is licensed under the BSD-style license found in the
|
||||||
|
// LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
#include <string> |
||||||
|
#include <unordered_map> |
||||||
|
|
||||||
|
#include "rocksdb/status.h" |
||||||
|
|
||||||
|
namespace rocksdb { |
||||||
|
|
||||||
|
class Env; |
||||||
|
class Logger; |
||||||
|
|
||||||
|
// SstFileManager is used to track SST files in the DB and control there
|
||||||
|
// deletion rate.
|
||||||
|
// All SstFileManager public functions are thread-safe.
|
||||||
|
class SstFileManager { |
||||||
|
public: |
||||||
|
virtual ~SstFileManager() {} |
||||||
|
|
||||||
|
// Return the total size of all tracked files.
|
||||||
|
// thread-safe
|
||||||
|
virtual uint64_t GetTotalSize() = 0; |
||||||
|
|
||||||
|
// Return a map containing all tracked files and there corresponding sizes.
|
||||||
|
// thread-safe
|
||||||
|
virtual std::unordered_map<std::string, uint64_t> GetTrackedFiles() = 0; |
||||||
|
|
||||||
|
// Return delete rate limit in bytes per second.
|
||||||
|
// thread-safe
|
||||||
|
virtual int64_t GetDeleteRateBytesPerSecond() = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
// Create a new SstFileManager that can be shared among multiple RocksDB
|
||||||
|
// instances to track SST file and control there deletion rate.
|
||||||
|
//
|
||||||
|
// @param env: Pointer to Env object, please see "rocksdb/env.h".
|
||||||
|
// @param info_log: If not nullptr, info_log will be used to log errors.
|
||||||
|
//
|
||||||
|
// == Deletion rate limiting specific arguments ==
|
||||||
|
// @param trash_dir: Path to the directory where deleted files will be moved
|
||||||
|
// to be deleted in a background thread while applying rate limiting. If this
|
||||||
|
// directory dont exist, it will be created. This directory should not be
|
||||||
|
// used by any other process or any other SstFileManager, Set to "" to
|
||||||
|
// disable deletion rate limiting.
|
||||||
|
// @param rate_bytes_per_sec: How many bytes should be deleted per second, If
|
||||||
|
// this value is set to 1024 (1 Kb / sec) and we deleted a file of size 4 Kb
|
||||||
|
// in 1 second, we will wait for another 3 seconds before we delete other
|
||||||
|
// files, Set to 0 to disable deletion rate limiting.
|
||||||
|
// @param delete_exisitng_trash: If set to true, the newly created
|
||||||
|
// SstFileManager will delete files that already exist in trash_dir.
|
||||||
|
// @param status: If not nullptr, status will contain any errors that happened
|
||||||
|
// during creating the missing trash_dir or deleting existing files in trash.
|
||||||
|
extern SstFileManager* NewSstFileManager( |
||||||
|
Env* env, std::shared_ptr<Logger> info_log = nullptr, |
||||||
|
std::string trash_dir = "", int64_t rate_bytes_per_sec = 0, |
||||||
|
bool delete_exisitng_trash = true, Status* status = nullptr); |
||||||
|
|
||||||
|
} // namespace rocksdb
|
@ -0,0 +1,143 @@ |
|||||||
|
// Copyright (c) 2015, Facebook, Inc. All rights reserved.
|
||||||
|
// This source code is licensed under the BSD-style license found in the
|
||||||
|
// LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
|
#include "util/sst_file_manager_impl.h" |
||||||
|
|
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include "port/port.h" |
||||||
|
#include "rocksdb/env.h" |
||||||
|
#include "util/mutexlock.h" |
||||||
|
#include "util/sync_point.h" |
||||||
|
|
||||||
|
namespace rocksdb { |
||||||
|
|
||||||
|
SstFileManagerImpl::SstFileManagerImpl(Env* env, std::shared_ptr<Logger> logger, |
||||||
|
const std::string& trash_dir, |
||||||
|
int64_t rate_bytes_per_sec) |
||||||
|
: env_(env), |
||||||
|
logger_(logger), |
||||||
|
total_files_size_(0), |
||||||
|
delete_scheduler_(env, trash_dir, rate_bytes_per_sec, logger.get(), |
||||||
|
this) {} |
||||||
|
|
||||||
|
SstFileManagerImpl::~SstFileManagerImpl() {} |
||||||
|
|
||||||
|
Status SstFileManagerImpl::OnAddFile(const std::string& file_path) { |
||||||
|
uint64_t file_size; |
||||||
|
Status s = env_->GetFileSize(file_path, &file_size); |
||||||
|
if (s.ok()) { |
||||||
|
MutexLock l(&mu_); |
||||||
|
OnAddFileImpl(file_path, file_size); |
||||||
|
} |
||||||
|
TEST_SYNC_POINT("SstFileManagerImpl::OnAddFile"); |
||||||
|
return s; |
||||||
|
} |
||||||
|
|
||||||
|
Status SstFileManagerImpl::OnDeleteFile(const std::string& file_path) { |
||||||
|
{ |
||||||
|
MutexLock l(&mu_); |
||||||
|
OnDeleteFileImpl(file_path); |
||||||
|
} |
||||||
|
TEST_SYNC_POINT("SstFileManagerImpl::OnDeleteFile"); |
||||||
|
return Status::OK(); |
||||||
|
} |
||||||
|
|
||||||
|
Status SstFileManagerImpl::OnMoveFile(const std::string& old_path, |
||||||
|
const std::string& new_path) { |
||||||
|
{ |
||||||
|
MutexLock l(&mu_); |
||||||
|
OnAddFileImpl(new_path, tracked_files_[old_path]); |
||||||
|
OnDeleteFileImpl(old_path); |
||||||
|
} |
||||||
|
TEST_SYNC_POINT("SstFileManagerImpl::OnMoveFile"); |
||||||
|
return Status::OK(); |
||||||
|
} |
||||||
|
|
||||||
|
uint64_t SstFileManagerImpl::GetTotalSize() { |
||||||
|
MutexLock l(&mu_); |
||||||
|
return total_files_size_; |
||||||
|
} |
||||||
|
|
||||||
|
std::unordered_map<std::string, uint64_t> |
||||||
|
SstFileManagerImpl::GetTrackedFiles() { |
||||||
|
MutexLock l(&mu_); |
||||||
|
return tracked_files_; |
||||||
|
} |
||||||
|
|
||||||
|
int64_t SstFileManagerImpl::GetDeleteRateBytesPerSecond() { |
||||||
|
return delete_scheduler_.GetRateBytesPerSecond(); |
||||||
|
} |
||||||
|
|
||||||
|
Status SstFileManagerImpl::ScheduleFileDeletion(const std::string& file_path) { |
||||||
|
return delete_scheduler_.DeleteFile(file_path); |
||||||
|
} |
||||||
|
|
||||||
|
void SstFileManagerImpl::WaitForEmptyTrash() { |
||||||
|
delete_scheduler_.WaitForEmptyTrash(); |
||||||
|
} |
||||||
|
|
||||||
|
void SstFileManagerImpl::OnAddFileImpl(const std::string& file_path, |
||||||
|
uint64_t file_size) { |
||||||
|
auto tracked_file = tracked_files_.find(file_path); |
||||||
|
if (tracked_file != tracked_files_.end()) { |
||||||
|
// File was added before, we will just update the size
|
||||||
|
total_files_size_ -= tracked_file->second; |
||||||
|
total_files_size_ += file_size; |
||||||
|
} else { |
||||||
|
total_files_size_ += file_size; |
||||||
|
} |
||||||
|
tracked_files_[file_path] = file_size; |
||||||
|
} |
||||||
|
|
||||||
|
void SstFileManagerImpl::OnDeleteFileImpl(const std::string& file_path) { |
||||||
|
auto tracked_file = tracked_files_.find(file_path); |
||||||
|
if (tracked_file == tracked_files_.end()) { |
||||||
|
// File is not tracked
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
total_files_size_ -= tracked_file->second; |
||||||
|
tracked_files_.erase(tracked_file); |
||||||
|
} |
||||||
|
|
||||||
|
SstFileManager* NewSstFileManager(Env* env, std::shared_ptr<Logger> info_log, |
||||||
|
std::string trash_dir, |
||||||
|
int64_t rate_bytes_per_sec, |
||||||
|
bool delete_exisitng_trash, Status* status) { |
||||||
|
SstFileManagerImpl* res = |
||||||
|
new SstFileManagerImpl(env, info_log, trash_dir, rate_bytes_per_sec); |
||||||
|
|
||||||
|
Status s; |
||||||
|
if (trash_dir != "" && rate_bytes_per_sec > 0) { |
||||||
|
s = env->CreateDirIfMissing(trash_dir); |
||||||
|
if (s.ok() && delete_exisitng_trash) { |
||||||
|
std::vector<std::string> files_in_trash; |
||||||
|
s = env->GetChildren(trash_dir, &files_in_trash); |
||||||
|
if (s.ok()) { |
||||||
|
for (const std::string& trash_file : files_in_trash) { |
||||||
|
if (trash_file == "." || trash_file == "..") { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
std::string path_in_trash = trash_dir + "/" + trash_file; |
||||||
|
res->OnAddFile(path_in_trash); |
||||||
|
Status file_delete = res->ScheduleFileDeletion(path_in_trash); |
||||||
|
if (s.ok() && !file_delete.ok()) { |
||||||
|
s = file_delete; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (status) { |
||||||
|
*status = s; |
||||||
|
} |
||||||
|
|
||||||
|
return res; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace rocksdb
|
@ -0,0 +1,77 @@ |
|||||||
|
// Copyright (c) 2015, Facebook, Inc. All rights reserved.
|
||||||
|
// This source code is licensed under the BSD-style license found in the
|
||||||
|
// LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "port/port.h" |
||||||
|
|
||||||
|
#include "rocksdb/sst_file_manager.h" |
||||||
|
#include "util/delete_scheduler.h" |
||||||
|
|
||||||
|
namespace rocksdb { |
||||||
|
|
||||||
|
class Env; |
||||||
|
class Logger; |
||||||
|
|
||||||
|
// SstFileManager is used to track SST files in the DB and control there
|
||||||
|
// deletion rate.
|
||||||
|
// All SstFileManager public functions are thread-safe.
|
||||||
|
class SstFileManagerImpl : public SstFileManager { |
||||||
|
public: |
||||||
|
explicit SstFileManagerImpl(Env* env, std::shared_ptr<Logger> logger, |
||||||
|
const std::string& trash_dir, |
||||||
|
int64_t rate_bytes_per_sec); |
||||||
|
|
||||||
|
~SstFileManagerImpl(); |
||||||
|
|
||||||
|
// DB will call OnAddFile whenever a new sst file is added.
|
||||||
|
Status OnAddFile(const std::string& file_path); |
||||||
|
|
||||||
|
// DB will call OnDeleteFile whenever an sst file is deleted.
|
||||||
|
Status OnDeleteFile(const std::string& file_path); |
||||||
|
|
||||||
|
// DB will call OnMoveFile whenever an sst file is move to a new path.
|
||||||
|
Status OnMoveFile(const std::string& old_path, const std::string& new_path); |
||||||
|
|
||||||
|
// Return the total size of all tracked files.
|
||||||
|
uint64_t GetTotalSize() override; |
||||||
|
|
||||||
|
// Return a map containing all tracked files and there corresponding sizes.
|
||||||
|
std::unordered_map<std::string, uint64_t> GetTrackedFiles() override; |
||||||
|
|
||||||
|
// Return delete rate limit in bytes per second.
|
||||||
|
virtual int64_t GetDeleteRateBytesPerSecond() override; |
||||||
|
|
||||||
|
// Move file to trash directory and schedule it's deletion.
|
||||||
|
virtual Status ScheduleFileDeletion(const std::string& file_path); |
||||||
|
|
||||||
|
// Wait for all files being deleteing in the background to finish or for
|
||||||
|
// destructor to be called.
|
||||||
|
virtual void WaitForEmptyTrash(); |
||||||
|
|
||||||
|
private: |
||||||
|
// REQUIRES: mutex locked
|
||||||
|
void OnAddFileImpl(const std::string& file_path, uint64_t file_size); |
||||||
|
// REQUIRES: mutex locked
|
||||||
|
void OnDeleteFileImpl(const std::string& file_path); |
||||||
|
|
||||||
|
Env* env_; |
||||||
|
std::shared_ptr<Logger> logger_; |
||||||
|
// Mutex to protect tracked_files_, total_files_size_
|
||||||
|
port::Mutex mu_; |
||||||
|
// The summation of the sizes of all files in tracked_files_ map
|
||||||
|
uint64_t total_files_size_; |
||||||
|
// A map containing all tracked files and there sizes
|
||||||
|
// file_path => file_size
|
||||||
|
std::unordered_map<std::string, uint64_t> tracked_files_; |
||||||
|
// DeleteScheduler used to throttle file deletition, if SstFileManagerImpl was
|
||||||
|
// created with rate_bytes_per_sec == 0 or trash_dir == "", delete_scheduler_
|
||||||
|
// rate limiting will be disabled and will simply delete the files.
|
||||||
|
DeleteScheduler delete_scheduler_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace rocksdb
|
Loading…
Reference in new issue