-
Notifications
You must be signed in to change notification settings - Fork 17
SDSTOR-22799 feat: chunk ownership tracking, remove GC shard header/footer I/O, blob commit validation #446
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev/refactor_create_seal_shard
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,34 +44,10 @@ void HeapChunkSelector::add_chunk_internal(const chunk_num_t p_chunk_id, bool ad | |
| } | ||
| } | ||
|
|
||
| // select_chunk will only be called in homestore when creating a shard. | ||
| // select_chunk will never be called in homestore since create shard is log only. | ||
| csharedChunk HeapChunkSelector::select_chunk(homestore::blk_count_t count, const homestore::blk_alloc_hints& hint) { | ||
| auto& chunkIdHint = hint.chunk_id_hint; | ||
| if (chunkIdHint.has_value()) { | ||
| LOGWARNMOD(homeobject, "should not allocated a chunk with exiting chunkIdHint={} in hint!", | ||
| chunkIdHint.value()); | ||
| return nullptr; | ||
| } | ||
|
|
||
| if (!hint.application_hint.has_value()) { | ||
| LOGWARNMOD(homeobject, "should not allocated a chunk without exiting application_hint in hint!"); | ||
| return nullptr; | ||
| } else { | ||
| // Both chunk_num_t and pg_id_t are of type uint16_t. | ||
| static_assert(std::is_same< pg_id_t, uint16_t >::value, "pg_id_t is not uint16_t"); | ||
| static_assert(std::is_same< homestore::chunk_num_t, uint16_t >::value, "chunk_num_t is not uint16_t"); | ||
| auto application_hint = hint.application_hint.value(); | ||
| pg_id_t pg_id = (uint16_t)(application_hint >> 16 & 0xFFFF); | ||
| homestore::chunk_num_t v_chunk_id = (uint16_t)(application_hint & 0xFFFF); | ||
| auto exVChunk = select_specific_chunk(pg_id, v_chunk_id); | ||
| if (exVChunk == nullptr) { | ||
| LOGWARNMOD(homeobject, "failed to select chunk with pg_id={} and v_chunk_id={} from application_hint={}", | ||
| pg_id, v_chunk_id, application_hint); | ||
| return nullptr; | ||
| } else { | ||
| return exVChunk->get_internal_chunk(); | ||
| } | ||
| } | ||
| RELEASE_ASSERT(false, "create shard is log only, this function should never be called"); | ||
| return nullptr; | ||
| } | ||
|
|
||
| bool HeapChunkSelector::try_mark_chunk_to_gc_state(const chunk_num_t chunk_id, bool force) { | ||
|
|
@@ -114,9 +90,9 @@ void HeapChunkSelector::mark_chunk_out_of_gc_state(const chunk_num_t chunk_id, c | |
| } | ||
|
|
||
| homestore::cshared< HeapChunkSelector::ExtendedVChunk > | ||
| HeapChunkSelector::select_specific_chunk(const pg_id_t pg_id, const chunk_num_t v_chunk_id) { | ||
| HeapChunkSelector::select_specific_chunk(const pg_id_t pg_id, const chunk_num_t v_chunk_id, | ||
| const shard_id_t owner_shard_id) { | ||
| homestore::shared< ExtendedVChunk > chunk; | ||
|
|
||
| while (true) { | ||
| { | ||
| std::unique_lock lock_guard(m_chunk_selector_mtx); | ||
|
|
@@ -125,36 +101,34 @@ HeapChunkSelector::select_specific_chunk(const pg_id_t pg_id, const chunk_num_t | |
| LOGWARNMOD(homeobject, "No pg found for pg={}", pg_id); | ||
| return nullptr; | ||
| } | ||
|
|
||
| auto pg_chunk_collection = pg_it->second; | ||
| auto& pg_chunks = pg_chunk_collection->m_pg_chunks; | ||
| std::scoped_lock lock(pg_chunk_collection->mtx); | ||
| if (v_chunk_id >= pg_chunks.size()) { | ||
| LOGWARNMOD(homeobject, "No chunk found for v_chunk_id={}", v_chunk_id); | ||
| return nullptr; | ||
| } | ||
|
|
||
| chunk = pg_chunks[v_chunk_id]; | ||
|
|
||
| if (chunk->m_state == ChunkState::GC) { | ||
| LOGDEBUGMOD(homeobject, "v_chunk_id={} for pg={} is pchunk_id={}, in GC state, wait and retry!", | ||
| v_chunk_id, pg_id, chunk->get_chunk_id()); | ||
| } else { | ||
| if (chunk->m_state == ChunkState::AVAILABLE) { | ||
| chunk->m_state = ChunkState::INUSE; | ||
| --pg_chunk_collection->available_num_chunks; | ||
| pg_chunk_collection->available_blk_count -= chunk->available_blks(); | ||
| } | ||
| } else if (chunk->m_state == ChunkState::AVAILABLE) { | ||
| chunk->m_state = ChunkState::INUSE; | ||
| chunk->m_owner_shard_id = owner_shard_id; | ||
| --pg_chunk_collection->available_num_chunks; | ||
| pg_chunk_collection->available_blk_count -= chunk->available_blks(); | ||
| break; | ||
| } else { | ||
| // INUSE: same owner → idempotent; different owner → error. | ||
| if (chunk->m_owner_shard_id == owner_shard_id) { break; } | ||
| LOGWARNMOD(homeobject, | ||
| "v_chunk_id={} for pg={} is INUSE by shard=0x{:x}, cannot select for shard=0x{:x}", | ||
| v_chunk_id, pg_id, chunk->m_owner_shard_id.value_or(0), owner_shard_id); | ||
| return nullptr; | ||
| } | ||
| } | ||
|
|
||
| // if the chunk is not available, probably being gc. we wait for a while and retry | ||
| std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
| } | ||
|
|
||
| LOGDEBUGMOD(homeobject, "chunk={} is selected for v_chunk_id={}, pg={}", chunk->get_chunk_id(), v_chunk_id, pg_id); | ||
|
|
||
| return chunk; | ||
| } | ||
|
|
||
|
|
@@ -164,14 +138,14 @@ void HeapChunkSelector::foreach_chunks(std::function< void(csharedChunk&) >&& cb | |
| [cb = std::move(cb)](auto& p) { cb(p.second->get_internal_chunk()); }); | ||
| } | ||
|
|
||
| bool HeapChunkSelector::release_chunk(const pg_id_t pg_id, const chunk_num_t v_chunk_id) { | ||
| bool HeapChunkSelector::release_chunk(const pg_id_t pg_id, const chunk_num_t v_chunk_id, | ||
| const shard_id_t owner_shard_id) { | ||
| std::unique_lock lock_guard(m_chunk_selector_mtx); | ||
| auto pg_it = m_per_pg_chunks.find(pg_id); | ||
| if (pg_it == m_per_pg_chunks.end()) { | ||
| LOGWARNMOD(homeobject, "No pg found for pg={}", pg_id); | ||
| return false; | ||
| } | ||
|
|
||
| auto pg_chunk_collection = pg_it->second; | ||
| auto& pg_chunks = pg_chunk_collection->m_pg_chunks; | ||
| if (v_chunk_id >= pg_chunks.size()) { | ||
|
|
@@ -180,8 +154,17 @@ bool HeapChunkSelector::release_chunk(const pg_id_t pg_id, const chunk_num_t v_c | |
| } | ||
| std::scoped_lock lock(pg_chunk_collection->mtx); | ||
| auto chunk = pg_chunks[v_chunk_id]; | ||
| if (chunk->m_state == ChunkState::AVAILABLE) { | ||
| return true; // idempotent for replay | ||
| } | ||
| if (chunk->m_state == ChunkState::INUSE) { | ||
| if (chunk->m_owner_shard_id != owner_shard_id) { | ||
| LOGWARNMOD(homeobject, "v_chunk_id={} for pg={} is owned by shard=0x{:x}, release by shard=0x{:x} rejected", | ||
| v_chunk_id, pg_id, chunk->m_owner_shard_id.value_or(0), owner_shard_id); | ||
| return false; | ||
| } | ||
| chunk->m_state = ChunkState::AVAILABLE; | ||
| chunk->m_owner_shard_id.reset(); | ||
| ++pg_chunk_collection->available_num_chunks; | ||
| pg_chunk_collection->available_blk_count += chunk->available_blks(); | ||
| } | ||
|
|
@@ -228,6 +211,7 @@ bool HeapChunkSelector::return_pg_chunks_to_dev_heap(const pg_id_t pg_id) { | |
| } // with shard which should be first | ||
| chunk->m_pg_id = std::nullopt; | ||
| chunk->m_v_chunk_id = std::nullopt; | ||
| chunk->m_owner_shard_id = std::nullopt; | ||
|
|
||
| pdev_heap->m_heap.emplace(chunk); | ||
| pdev_heap->available_blk_count += chunk->available_blks(); | ||
|
|
@@ -347,10 +331,14 @@ void HeapChunkSelector::update_vchunk_info_after_gc(const chunk_num_t move_from_ | |
| // 1 change the pg_id and vchunk_id of the move_to_chunk according to metablk | ||
| move_to_vchunk->m_pg_id = pg_id; | ||
| move_to_vchunk->m_v_chunk_id = vchunk_id; | ||
| // GC transfers data but not ownership: move_to inherits move_from's owner_shard_id unchanged. | ||
| // (nullopt for normal GC since move_from was AVAILABLE; open shard id for EGC.) | ||
| move_to_vchunk->m_owner_shard_id = move_from_vchunk->m_owner_shard_id; | ||
|
|
||
| // 2 update the chunk state of move_from_chunk, now it is a reserved chunk | ||
| move_from_vchunk->m_pg_id = std::nullopt; | ||
| move_from_vchunk->m_v_chunk_id = std::nullopt; | ||
| move_from_vchunk->m_owner_shard_id = std::nullopt; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this line will revert the change in line 361
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this line(371) is to clear move_from_vchunk. |
||
|
|
||
| // 3 update the state of move_to_chunk, so that it can be used for creating shard or putting blob. we need to do | ||
| // this after reserved_chunk meta blk is updated, so that if crash happens, we recovery the move_to_chunk is the | ||
|
|
@@ -471,8 +459,7 @@ void HeapChunkSelector::build_pdev_available_chunk_heap() { | |
| } | ||
| } | ||
|
|
||
| bool HeapChunkSelector::recover_pg_chunks_states(pg_id_t pg_id, | ||
| const std::unordered_set< chunk_num_t >& excluding_v_chunk_ids) { | ||
| bool HeapChunkSelector::recover_pg_chunks_states(pg_id_t pg_id) { | ||
| std::unique_lock lock_guard(m_chunk_selector_mtx); | ||
| auto pg_it = m_per_pg_chunks.find(pg_id); | ||
| if (pg_it == m_per_pg_chunks.end()) { | ||
|
|
@@ -487,14 +474,8 @@ bool HeapChunkSelector::recover_pg_chunks_states(pg_id_t pg_id, | |
| for (size_t v_chunk_id = 0; v_chunk_id < pg_chunks.size(); ++v_chunk_id) { | ||
| auto chunk = pg_chunks[v_chunk_id]; | ||
| pg_chunk_collection->m_total_blks += chunk->get_total_blks(); | ||
| if (excluding_v_chunk_ids.find(v_chunk_id) == excluding_v_chunk_ids.end()) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if the "DISK_DOWN" state will be affected |
||
| chunk->m_state = ChunkState::AVAILABLE; | ||
| ++pg_chunk_collection->available_num_chunks; | ||
| pg_chunk_collection->available_blk_count += chunk->available_blks(); | ||
|
|
||
| } else { | ||
| chunk->m_state = ChunkState::INUSE; | ||
| } | ||
| ++pg_chunk_collection->available_num_chunks; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only increase when chunk available?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The implement is to let all chunks to be available (initialized state), and let log replay and on log replay done to recovery the final state. |
||
| pg_chunk_collection->available_blk_count += chunk->available_blks(); | ||
| } | ||
| return true; | ||
| } | ||
|
|
@@ -519,7 +500,7 @@ std::shared_ptr< const std::vector< homestore::chunk_num_t > > HeapChunkSelector | |
| } | ||
|
|
||
| homestore::cshared< HeapChunkSelector::ExtendedVChunk > | ||
| HeapChunkSelector::pick_most_available_blk_chunk(uint64_t ctx, pg_id_t pg_id) { | ||
| HeapChunkSelector::pick_most_available_blk_chunk(shard_id_t shard_id, pg_id_t pg_id) { | ||
| std::shared_lock lock_guard(m_chunk_selector_mtx); | ||
| auto pg_it = m_per_pg_chunks.find(pg_id); | ||
| if (pg_it == m_per_pg_chunks.end()) { | ||
|
|
@@ -535,16 +516,18 @@ HeapChunkSelector::pick_most_available_blk_chunk(uint64_t ctx, pg_id_t pg_id) { | |
| return !a->available() || (b->available() && a->available_blks() < b->available_blks()); | ||
| }); | ||
| if (!(*max_it)->available()) { | ||
| LOGWARNMOD(homeobject, "No available chunk for pg={}, ctx=0x{:x}", pg_id, ctx); | ||
| LOGWARNMOD(homeobject, "No available chunk for pg={}, shard_id=0x{:x}", pg_id, shard_id); | ||
| return nullptr; | ||
| } | ||
| auto v_chunk_id = std::distance(pg_chunks.begin(), max_it); | ||
| LOGDEBUGMOD(homeobject, "Picked v_chunk_id={} : [p_chunk_id={}, avail={}], ctx=0x{:x}", v_chunk_id, | ||
| pg_chunks[v_chunk_id]->get_chunk_id(), pg_chunks[v_chunk_id]->available_blks(), ctx); | ||
| pg_chunks[v_chunk_id]->m_state = ChunkState::INUSE; | ||
| auto& picked = pg_chunks[v_chunk_id]; | ||
| LOGDEBUGMOD(homeobject, "Picked v_chunk_id={} : [p_chunk_id={}, avail={}], shard_id=0x{:x}", v_chunk_id, | ||
| picked->get_chunk_id(), picked->available_blks(), shard_id); | ||
| picked->m_state = ChunkState::INUSE; | ||
| picked->m_owner_shard_id = shard_id; | ||
| --pg_chunk_collection->available_num_chunks; | ||
| pg_chunk_collection->available_blk_count -= pg_chunks[v_chunk_id]->available_blks(); | ||
| return pg_chunks[v_chunk_id]; | ||
| pg_chunk_collection->available_blk_count -= picked->available_blks(); | ||
| return picked; | ||
| } | ||
|
|
||
| // return the maximum number of chunks that can be allocated on pdev | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any issue without this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I met one time on my env, two case runs in parallel.