Skip to content
Merged
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.idea/**
.cache
.clangd
.claude/*

build
test_package/build
Expand Down
2 changes: 1 addition & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

class HomeObjectConan(ConanFile):
name = "homeobject"
version = "3.0.20"
version = "4.1.0"

homepage = "https://github.com/eBay/HomeObject"
description = "Blob Store built on HomeStore"
Expand Down
2 changes: 1 addition & 1 deletion src/include/homeobject/blob_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class BlobManager : public Manager< BlobError > {
public:
virtual AsyncResult< blob_id_t > put(shard_id_t shard, Blob&&, trace_id_t tid = 0) = 0;
virtual AsyncResult< Blob > get(shard_id_t shard, blob_id_t const& blob, uint64_t off = 0, uint64_t len = 0,
trace_id_t tid = 0) const = 0;
bool allow_skip_verify = false, trace_id_t tid = 0) const = 0;
virtual NullAsyncResult del(shard_id_t shard, blob_id_t const& blob, trace_id_t tid = 0) = 0;
};

Expand Down
4 changes: 3 additions & 1 deletion src/include/homeobject/shard_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct ShardError {
};

struct ShardInfo {
static constexpr uint64_t meta_length = 1024 + 1;
enum class State : uint8_t {
OPEN = 0,
SEALED = 1,
Expand All @@ -40,6 +41,7 @@ struct ShardInfo {
uint64_t available_capacity_bytes;
uint64_t total_capacity_bytes;
std::optional< peer_id_t > current_leader{std::nullopt};
uint8_t meta[meta_length]{};

auto operator<=>(ShardInfo const& rhs) const { return id <=> rhs.id; }
auto operator==(ShardInfo const& rhs) const { return id == rhs.id; }
Expand All @@ -55,7 +57,7 @@ class ShardManager : public Manager< ShardError > {

virtual AsyncResult< ShardInfo > get_shard(shard_id_t id, trace_id_t tid = 0) const = 0;
virtual AsyncResult< InfoList > list_shards(pg_id_t id, trace_id_t tid = 0) const = 0;
virtual AsyncResult< ShardInfo > create_shard(pg_id_t pg_owner, uint64_t size_bytes, trace_id_t tid = 0) = 0;
virtual AsyncResult< ShardInfo > create_shard(pg_id_t pg_owner, uint64_t size_bytes, std::string meta, trace_id_t tid = 0) = 0;
virtual AsyncResult< ShardInfo > seal_shard(shard_id_t id, trace_id_t tid = 0) = 0;
};

Expand Down
6 changes: 3 additions & 3 deletions src/lib/blob_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ namespace homeobject {
std::shared_ptr< BlobManager > HomeObjectImpl::blob_manager() { return shared_from_this(); }

BlobManager::AsyncResult< Blob > HomeObjectImpl::get(shard_id_t shard, blob_id_t const& blob_id, uint64_t off,
uint64_t len, trace_id_t tid) const {
uint64_t len, bool allow_skip_verify, trace_id_t tid) const {
return _get_shard(shard, tid)
.thenValue([this, blob_id, off, len, tid](auto const e) -> BlobManager::AsyncResult< Blob > {
.thenValue([this, blob_id, off, len, allow_skip_verify, tid](auto const e) -> BlobManager::AsyncResult< Blob > {
if (!e) return folly::makeUnexpected(BlobError(BlobErrorCode::UNKNOWN_SHARD));
return _get_blob(e.value(), blob_id, off, len, tid);
return _get_blob(e.value(), blob_id, off, len, allow_skip_verify, tid);
});
}

Expand Down
8 changes: 4 additions & 4 deletions src/lib/homeobject_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ class HomeObjectImpl : public HomeObject,
public std::enable_shared_from_this< HomeObjectImpl > {

/// Implementation defines these
virtual ShardManager::AsyncResult< ShardInfo > _create_shard(pg_id_t, uint64_t size_bytes, trace_id_t tid) = 0;
virtual ShardManager::AsyncResult< ShardInfo > _create_shard(pg_id_t, uint64_t size_bytes, std::string meta, trace_id_t tid) = 0;
virtual ShardManager::AsyncResult< ShardInfo > _seal_shard(ShardInfo const&, trace_id_t tid) = 0;

virtual BlobManager::AsyncResult< blob_id_t > _put_blob(ShardInfo const&, Blob&&, trace_id_t tid) = 0;
virtual BlobManager::AsyncResult< Blob > _get_blob(ShardInfo const&, blob_id_t, uint64_t off, uint64_t len,
trace_id_t tid) const = 0;
bool allow_skip_verify, trace_id_t tid) const = 0;
virtual BlobManager::NullAsyncResult _del_blob(ShardInfo const&, blob_id_t, trace_id_t tid) = 0;
///

Expand Down Expand Up @@ -189,15 +189,15 @@ class HomeObjectImpl : public HomeObject,

/// ShardManager
ShardManager::AsyncResult< ShardInfo > get_shard(shard_id_t id, trace_id_t tid) const final;
ShardManager::AsyncResult< ShardInfo > create_shard(pg_id_t pg_owner, uint64_t size_bytes, trace_id_t tid) final;
ShardManager::AsyncResult< ShardInfo > create_shard(pg_id_t pg_owner, uint64_t size_bytes, std::string meta, trace_id_t tid) final;
ShardManager::AsyncResult< InfoList > list_shards(pg_id_t pg, trace_id_t tid) const final;
ShardManager::AsyncResult< ShardInfo > seal_shard(shard_id_t id, trace_id_t tid) final;
uint64_t get_current_timestamp();

/// BlobManager
BlobManager::AsyncResult< blob_id_t > put(shard_id_t shard, Blob&&, trace_id_t tid) final;
BlobManager::AsyncResult< Blob > get(shard_id_t shard, blob_id_t const& blob, uint64_t off, uint64_t len,
trace_id_t tid) const final;
bool allow_skip_verify, trace_id_t tid) const final;
BlobManager::NullAsyncResult del(shard_id_t shard, blob_id_t const& blob, trace_id_t tid) final;
};

Expand Down
33 changes: 27 additions & 6 deletions src/lib/homestore_backend/gc_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,10 @@ void GCManager::start() {
gc_actor->start();
LOGINFOMOD(gcmgr, "start gc actor for pdev={}", pdev_id);
}
start_gc_scan_timer();
}

void GCManager::start_gc_scan_timer() {
const auto gc_scan_interval_sec = HS_BACKEND_DYNAMIC_CONFIG(gc_scan_interval_sec);

// the initial idea here is that we want gc timer to run in a reactor that not shared with other fibers that
Expand All @@ -146,9 +149,7 @@ void GCManager::start() {
LOGINFOMOD(gcmgr, "gc scheduler timer has started, interval is set to {} seconds", gc_scan_interval_sec);
}

bool GCManager::is_started() { return m_gc_timer_hdl != iomgr::null_timer_handle; }

void GCManager::stop() {
void GCManager::stop_gc_scan_timer() {
if (m_gc_timer_hdl == iomgr::null_timer_handle) {
LOGWARNMOD(gcmgr, "gc scheduler timer is not running, no need to stop it");
return;
Expand All @@ -162,6 +163,10 @@ void GCManager::stop() {
m_gc_timer_hdl = iomgr::null_timer_handle;
});
m_gc_timer_fiber = nullptr;
}

void GCManager::stop() {
stop_gc_scan_timer();

for (const auto& [pdev_id, gc_actor] : m_pdev_gc_actors) {
gc_actor->stop();
Expand All @@ -170,9 +175,20 @@ void GCManager::stop() {
}

folly::SemiFuture< bool > GCManager::submit_gc_task(task_priority priority, chunk_id_t chunk_id) {
if (!is_started()) return folly::makeFuture< bool >(false);
auto ex_vchunk = m_chunk_selector->get_extend_vchunk(chunk_id);
if (ex_vchunk == nullptr) {
LOGERRORMOD(gcmgr, "chunk {} not found when submit gc task!", chunk_id);
return folly::makeFuture< bool >(false);
}

// if the chunk has no garbage to be reclaimed, we don`t need to gc it , return true directly
const auto defrag_blk_num = ex_vchunk->get_defrag_nblks();
if (!defrag_blk_num && task_priority::normal == priority) {
LOGERRORMOD(gcmgr, "chunk {} has no garbage to be reclaimed, skip gc for this chunk!", chunk_id);
return folly::makeFuture< bool >(true);
}

auto pdev_id = m_chunk_selector->get_extend_vchunk(chunk_id)->get_pdev_id();
auto pdev_id = ex_vchunk->get_pdev_id();
auto it = m_pdev_gc_actors.find(pdev_id);
if (it == m_pdev_gc_actors.end()) {
LOGINFOMOD(gcmgr, "pdev gc actor not found for pdev_id={}, chunk={}", pdev_id, chunk_id);
Expand Down Expand Up @@ -218,7 +234,7 @@ bool GCManager::is_eligible_for_gc(chunk_id_t chunk_id) {

const auto total_blk_num = chunk->get_total_blks();
const auto gc_garbage_rate_threshold = HS_BACKEND_DYNAMIC_CONFIG(gc_garbage_rate_threshold);
bool should_gc = 100 * defrag_blk_num >= total_blk_num * gc_garbage_rate_threshold;
bool should_gc = 100 * defrag_blk_num > total_blk_num * gc_garbage_rate_threshold;

LOGDEBUGMOD(gcmgr,
"gc scan chunk_id={}, use_blks={}, available_blks={}, total_blks={}, defrag_blks={}, should_gc={}",
Expand Down Expand Up @@ -334,6 +350,11 @@ void GCManager::pdev_gc_actor::add_reserved_chunk(
}

folly::SemiFuture< bool > GCManager::pdev_gc_actor::add_gc_task(uint8_t priority, chunk_id_t move_from_chunk) {
if (m_is_stopped.load()) {
LOGWARNMOD(gcmgr, "pdev gc actor for pdev_id={} is not started yet or already stopped, cannot add gc task!",
m_pdev_id);
return folly::makeSemiFuture< bool >(false);
}
auto EXvchunk = m_chunk_selector->get_extend_vchunk(move_from_chunk);
// it does not belong to any pg, so we don't need to gc it.
if (!EXvchunk->m_pg_id.has_value()) {
Expand Down
6 changes: 5 additions & 1 deletion src/lib/homestore_backend/gc_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,11 @@ class GCManager {

void start();
void stop();
bool is_started();

// the following two functions should not be called concurrently. if we need to call them concurrently, we need to
// add lock to protect
void start_gc_scan_timer();
void stop_gc_scan_timer();

void scan_chunks_for_gc();
void drain_pg_pending_gc_task(const pg_id_t pg_id);
Expand Down
Loading