@@ -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
0 commit comments