Skip to content

Commit 0590211

Browse files
committed
the chunk should be selected for open shard when recovery
1 parent 23f7f18 commit 0590211

9 files changed

Lines changed: 73 additions & 21 deletions

‎conanfile.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
class HomeObjectConan(ConanFile):
1212
name = "homeobject"
13-
version = "2.7.7"
13+
version = "2.7.8"
1414

1515
homepage = "https://github.com/eBay/HomeObject"
1616
description = "Blob Store built on HomeReplication"

‎src/lib/homestore_backend/gc_manager.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ namespace homeobject {
66

77
/* GCManager */
88

9-
GCManager::GCManager(std::shared_ptr< HeapChunkSelector > chunk_selector, HSHomeObject* homeobject) :
10-
m_chunk_selector{chunk_selector}, m_hs_home_object{homeobject} {
9+
GCManager::GCManager(HSHomeObject* homeobject) :
10+
m_chunk_selector{homeobject->chunk_selector()}, m_hs_home_object{homeobject} {
1111
homestore::HomeStore::instance()->meta_service().register_handler(
1212
GCManager::_gc_actor_meta_name,
1313
[this](homestore::meta_blk* mblk, sisl::byte_view buf, size_t size) {

‎src/lib/homestore_backend/gc_manager.hpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ using GCBlobIndexTable = homestore::IndexTable< BlobRouteByChunkKey, BlobRouteVa
2929

3030
class GCManager {
3131
public:
32-
GCManager(std::shared_ptr< HeapChunkSelector > chunk_selector, HSHomeObject* homeobject);
32+
GCManager(HSHomeObject* homeobject);
3333
~GCManager();
3434

3535
// Disallow copy and move

‎src/lib/homestore_backend/heap_chunk_selector.cpp‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,6 @@ void HeapChunkSelector::switch_chunks_for_pg(const pg_id_t pg_id, const chunk_nu
390390
"gc task_id={}, the pchunk_id for vchunk={} in chunkselector for pg_id={} is already {}, skip "
391391
"switching chunks!",
392392
task_id, v_chunk_id, pg_id, new_chunk_id);
393-
394393
return;
395394
} else {
396395
RELEASE_ASSERT(
@@ -405,9 +404,6 @@ void HeapChunkSelector::switch_chunks_for_pg(const pg_id_t pg_id, const chunk_nu
405404
"pchunk_id={}",
406405
task_id, v_chunk_id, pg_id, old_chunk_id, new_chunk_id);
407406
}
408-
409-
// LOGDEBUGMOD(homeobject, "gc: after switch chunks for pg_id={}, pg_chunks={}", pg_chunks);
410-
411407
pg_chunk_collection->available_blk_count += new_available_blks - old_available_blks;
412408
}
413409

‎src/lib/homestore_backend/hs_homeobject.cpp‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,6 @@ void HSHomeObject::init_homestore() {
221221

222222
// We dont have any repl dev now, explicitly call init_completed_cb() where we register PG/Shard meta types.
223223
repl_app->on_repl_devs_init_completed();
224-
225-
// we need to regitster the meta blk handlers after metaservice is ready.
226-
gc_mgr_ = std::make_shared< GCManager >(chunk_selector_, this);
227224
// if this is the first time we are starting, we need to create gc metablk for each pdev, which record the
228225
// reserved chunks and indextable.
229226
auto pdev_chunks = chunk_selector_->get_pdev_chunks();
@@ -321,6 +318,9 @@ void HSHomeObject::on_replica_restart() {
321318
},
322319
[this](bool success) { on_snp_rcvr_shard_list_meta_blk_recover_completed(success); }, true);
323320
HomeStore::instance()->meta_service().read_sub_sb(_snp_rcvr_shard_list_meta_name);
321+
322+
// gc_manager will be created only once here.
323+
gc_mgr_ = std::make_shared< GCManager >(this);
324324
});
325325
}
326326

@@ -352,7 +352,6 @@ void HSHomeObject::init_cp() {
352352

353353
void HSHomeObject::init_gc() {
354354
using namespace homestore;
355-
if (!gc_mgr_) gc_mgr_ = std::make_shared< GCManager >(chunk_selector_, this);
356355
// when initializing, there is not gc task. we need to recover reserved chunks here, so that the reserved chunks
357356
// will not be put into pdev heap when built
358357
HomeStore::instance()->meta_service().read_sub_sb(GCManager::_gc_actor_meta_name);

‎src/lib/homestore_backend/hs_homeobject.hpp‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,6 @@ class HSHomeObject : public HomeObjectImpl {
681681
static std::string serialize_pg_info(const PGInfo& info);
682682
static PGInfo deserialize_pg_info(const unsigned char* pg_info_str, size_t size);
683683
void add_pg_to_map(unique< HS_PG > hs_pg);
684-
const HS_PG* _get_hs_pg_unlocked(pg_id_t pg_id) const;
685684

686685
// create shard related
687686
shard_id_t generate_new_shard_id(pg_id_t pg);
@@ -923,7 +922,6 @@ class HSHomeObject : public HomeObjectImpl {
923922

924923
void update_pg_meta_after_gc(const pg_id_t pg_id, const homestore::chunk_num_t move_from_chunk,
925924
const homestore::chunk_num_t move_to_chunk, const uint64_t task_id);
926-
927925
uint32_t get_pg_tombstone_blob_count(pg_id_t pg_id) const;
928926

929927
// Snapshot persistence related
@@ -933,6 +931,7 @@ class HSHomeObject : public HomeObjectImpl {
933931
const Shard* _get_hs_shard(const shard_id_t shard_id) const;
934932
std::shared_ptr< GCBlobIndexTable > get_gc_index_table(std::string uuid) const;
935933
void trigger_immediate_gc();
934+
const HS_PG* _get_hs_pg_unlocked(pg_id_t pg_id) const;
936935

937936
private:
938937
std::shared_ptr< BlobIndexTable > create_pg_index_table();

‎src/lib/homestore_backend/hs_shard_manager.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,14 +489,14 @@ void HSHomeObject::on_shard_message_commit(int64_t lsn, sisl::blob const& h, hom
489489
std::error_code err = repl_dev->async_read(blkids, value_sgs, value_blob.size()).get();
490490
if (err) {
491491
LOGW("failed to read data from homestore blks, lsn={}", lsn);
492-
if (ctx) { ctx->promise_.setValue(folly::makeUnexpected(ShardError(ShardErrorCode::UNKNOWN)); }
492+
if (ctx) { ctx->promise_.setValue(folly::makeUnexpected(ShardError(ShardErrorCode::UNKNOWN))); }
493493
return;
494494
}
495495

496496
if (crc32_ieee(init_crc32, value.cbytes(), value.size()) != header->payload_crc) {
497497
// header & value is inconsistent;
498498
LOGW("replication message header is inconsistent with value, lsn={}", lsn);
499-
if (ctx) { ctx->promise_.setValue(folly::makeUnexpected(ShardError(ShardErrorCode::CRC_MISMATCH)); }
499+
if (ctx) { ctx->promise_.setValue(folly::makeUnexpected(ShardError(ShardErrorCode::CRC_MISMATCH))); }
500500
return;
501501
}
502502
#endif

‎src/lib/homestore_backend/replication_state_machine.cpp‎

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -607,11 +607,8 @@ folly::Future< std::error_code > ReplicationStateMachine::on_fetch_data(const in
607607
const homestore::MultiBlkId& local_blk_id,
608608
sisl::sg_list& sgs) {
609609
if (0 == header.size()) {
610-
LOGD("Header is empty, which means this req has been committed at leader, so ignore this request. req "
611-
"lsn={}",
612-
lsn);
613-
RELEASE_ASSERT(lsn != -1, "the lsn of a committed req should not be -1");
614-
return folly::makeFuture< std::error_code >(std::error_code{});
610+
LOGW("Header is empty in on_fetch_data for lsn {}", lsn);
611+
return folly::makeFuture< std::error_code >(std::make_error_code(std::errc::invalid_argument));
615612
}
616613

617614
// the lsn here will mostly be -1 ,since this lsn has not been appeneded and thus get no lsn
@@ -1006,4 +1003,60 @@ void ReplicationStateMachine::handle_no_space_left(homestore::repl_lsn_t lsn, ho
10061003
}
10071004
}
10081005

1006+
void ReplicationStateMachine::on_log_replay_done(const homestore::group_id_t& group_id) {
1007+
// when we reaching here, it means all the logs of this group has been replayed, but we don`t join the raft group
1008+
// ATM and thus no new request can be handled. Now, we can safely mark all the chunks with open shard in this group
1009+
// to inuse state, so that gc can not gc this chunk.
1010+
1011+
// we must do this job here, because:
1012+
1013+
// 1 we should change the chunk state after all the logs are replayed. since if we mark the chunk state to inuse
1014+
// before all the logs are replayed, there is a case that the chunk will be released by the last seal_shard, which
1015+
// is prior to the lastest open_shard of this chunk. for example: lsn 10 is create_shard_1 ,lsn 20 is seal_shard_1
1016+
// and lsn 30 is create_shard_2. shard1 and shard 2 are in the same chunk. now if we mark the chunk to inuse before
1017+
// replay lsn 20, then when replaying lsn 20, the chunk will be released by lsn 20(commit_seal_shard). and when we
1018+
// completed replay, the final state of this chunk is available. but what we want is inuse, since shard_2 is opened
1019+
// in lsn 30 and not sealed.
1020+
1021+
// 2 if we mark the chunk state to in use after the repl_dev join the raft group, then it can accept new request or
1022+
// can be gc before we mark it to inuse.
1023+
1024+
// so this is the only timepoint we should make all the chunks, which contains open shards, to inuse state.
1025+
1026+
auto pg_id_opt = home_object_->get_pg_id_with_group_id(group_id);
1027+
if (!pg_id_opt.has_value()) {
1028+
// there are two cases we might reach here.
1029+
1030+
// 1 when baseline resync, crash happens after pg is destroyed but before new pg is created in follower. when
1031+
// recovery, we will find we have a group , but the corresponding pg does not exist.
1032+
1033+
// 2 when replacememeber, we will destroy the repl_dev after destroying the pg. if crash happens after pg is
1034+
// destroyed but before the repl_dev superblk is destroyed, then when recovery, we will find we have a
1035+
// group(repl_dev), but have not corresponding pg.
1036+
1037+
// 3 when fail to create repl_dev, there might be some stale repl_dev left on a node. for example, success to
1038+
// add the first memeber but fail to add the second memeber, the there will be a stale repl_dev on leader and
1039+
// the first member. see https://github.com/eBay/HomeObject/pull/136#discussion_r1470504271
1040+
LOGW("can not find any pg for group={}!", group_id);
1041+
return;
1042+
}
1043+
1044+
const auto pg_id = pg_id_opt.value();
1045+
RELEASE_ASSERT(home_object_->pg_exists(pg_id), "pg={} should exist, but not! fatal error!", pg_id);
1046+
1047+
const auto& shards_in_pg = (const_cast< HSHomeObject::HS_PG* >(home_object_->_get_hs_pg_unlocked(pg_id)))->shards_;
1048+
auto chunk_selector = home_object_->chunk_selector();
1049+
1050+
for (const auto& shard_iter : shards_in_pg) {
1051+
const auto& shard_sb = ((d_cast< HSHomeObject::HS_Shard* >(shard_iter.get()))->sb_).get();
1052+
if (shard_sb->info.is_open()) {
1053+
const auto pg_id = shard_sb->info.placement_group;
1054+
const auto vchunk_id = shard_sb->v_chunk_id;
1055+
auto chunk = chunk_selector->select_specific_chunk(pg_id, vchunk_id);
1056+
RELEASE_ASSERT(chunk != nullptr, "chunk selection failed with v_chunk_id={} in pg={}", vchunk_id, pg_id);
1057+
LOGD("vchunk={} is selected for shard={} in pg={} when recovery", vchunk_id, shard_sb->info.id, pg_id);
1058+
}
1059+
}
1060+
}
1061+
10091062
} // namespace homeobject

‎src/lib/homestore_backend/replication_state_machine.hpp‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@ class ReplicationStateMachine : public homestore::ReplDevListener {
224224
///
225225
void notify_committed_lsn(int64_t lsn) override;
226226

227+
/// @brief this is called after all the logs are replayed but before joining raft group.
228+
/// @param group_id - the group , where all the logs are replayed but not join raft group
229+
///
230+
void on_log_replay_done(const homestore::group_id_t& group_id) override;
231+
227232
private:
228233
HSHomeObject* home_object_{nullptr};
229234

0 commit comments

Comments
 (0)