@@ -7,14 +7,91 @@ namespace homeobject {
7
7
/* GCManager */
8
8
9
9
GCManager::GCManager (std::shared_ptr< HeapChunkSelector > chunk_selector, HSHomeObject* homeobject) :
10
- m_chunk_selector{chunk_selector}, m_hs_home_object{homeobject} {}
10
+ m_chunk_selector{chunk_selector}, m_hs_home_object{homeobject} {
11
+ homestore::HomeStore::instance ()->meta_service ().register_handler (
12
+ GCManager::_gc_actor_meta_name,
13
+ [this ](homestore::meta_blk* mblk, sisl::byte_view buf, size_t size) {
14
+ on_gc_actor_meta_blk_found (std::move (buf), voidptr_cast (mblk));
15
+ },
16
+ nullptr , true );
17
+
18
+ homestore::HomeStore::instance ()->meta_service ().register_handler (
19
+ GCManager::_gc_reserved_chunk_meta_name,
20
+ [this ](homestore::meta_blk* mblk, sisl::byte_view buf, size_t size) {
21
+ on_reserved_chunk_meta_blk_found (std::move (buf), voidptr_cast (mblk));
22
+ },
23
+ [this ](bool success) {
24
+ RELEASE_ASSERT (success, " Failed to recover all reserved chunk!!!" );
25
+ // we need to guarantee that pg meta blk is recovered before we start recover reserved chunk
26
+ m_chunk_selector->build_pdev_available_chunk_heap ();
27
+ },
28
+ true );
29
+
30
+ homestore::HomeStore::instance ()->meta_service ().register_handler (
31
+ GCManager::_gc_task_meta_name,
32
+ [this ](homestore::meta_blk* mblk, sisl::byte_view buf, size_t size) {
33
+ on_gc_task_meta_blk_found (std::move (buf), voidptr_cast (mblk));
34
+ },
35
+ nullptr , true );
36
+ }
37
+
38
+ void GCManager::on_gc_task_meta_blk_found (sisl::byte_view const & buf, void * meta_cookie) {
39
+ homestore::superblk< GCManager::gc_task_superblk > gc_task_sb (GCManager::_gc_task_meta_name);
40
+ const auto pending_gc_task = gc_task_sb.load (buf, meta_cookie);
41
+
42
+ // if a gc_task_super blk is found, we can make sure that all the valid data in move_from_chunk has been copied to
43
+ // move_to_chunk, and all the blob -> (new pba) have been written to the gc index table. Now, what we need to do is
44
+ // just updating blob indexes in pg index table according to the blob indexes in gc index table.
45
+
46
+ // pg_index_table: [pg_id, shard_id, blob_id] -> old pba
47
+ // gc_index_table: [move_to_chunk_id, pg_id, shard_id, blob_id] -> new pba
48
+
49
+ // we need to find all keys with the prefix of move_to_chunk_id in gc index table, and update the corrsponding
50
+ // keys(same pg_id + shard_id + blob_id) in pg index table with the new pba.
51
+ auto pdev_id = m_chunk_selector->get_extend_vchunk (pending_gc_task->move_from_chunk )->get_pdev_id ();
52
+ auto gc_actor = get_pdev_gc_actor (pdev_id);
53
+ RELEASE_ASSERT (gc_actor, " can not get gc actor for pdev {}!" , pdev_id);
54
+ gc_actor->handle_recovered_gc_task (pending_gc_task);
55
+
56
+ // delete gc task meta blk, so that it will not be recovered again if restart
57
+ gc_task_sb.destroy ();
58
+ }
59
+
60
+ void GCManager::on_gc_actor_meta_blk_found (sisl::byte_view const & buf, void * meta_cookie) {
61
+ homestore::superblk< GCManager::gc_actor_superblk > gc_actor_sb (GCManager::_gc_actor_meta_name);
62
+ gc_actor_sb.load (buf, meta_cookie);
63
+ auto pdev_id = gc_actor_sb->pdev_id ;
64
+ auto index_table_uuid = gc_actor_sb->index_table_uuid ;
65
+
66
+ auto gc_index_table = m_hs_home_object->get_gc_index_table (boost::uuids::to_string (index_table_uuid));
67
+
68
+ RELEASE_ASSERT (gc_index_table, " can not get gc index table for pdev {} with uuid {}!" , pdev_id,
69
+ boost::uuids::to_string (index_table_uuid));
70
+
71
+ // create a gc actor for this pdev if not exists
72
+ auto gc_actor = try_create_pdev_gc_actor (pdev_id, gc_index_table);
73
+ RELEASE_ASSERT (gc_actor, " can not get gc actor for pdev {}!" , pdev_id);
74
+ }
75
+
76
+ void GCManager::on_reserved_chunk_meta_blk_found (sisl::byte_view const & buf, void * meta_cookie) {
77
+ homestore::superblk< GCManager::gc_reserved_chunk_superblk > reserved_chunk_sb (
78
+ GCManager::_gc_reserved_chunk_meta_name);
79
+ reserved_chunk_sb.load (buf, meta_cookie);
80
+ auto chunk_id = reserved_chunk_sb->chunk_id ;
81
+ auto pdev_id = m_chunk_selector->get_extend_vchunk (chunk_id)->get_pdev_id ();
82
+ auto gc_actor = get_pdev_gc_actor (pdev_id);
83
+ RELEASE_ASSERT (gc_actor, " can not get gc actor for pdev {}!" , pdev_id);
84
+ gc_actor->add_reserved_chunk (chunk_id);
85
+ // mark a reserved chunk as gc state, so that it will not be selected as a gc candidate
86
+ m_chunk_selector->try_mark_chunk_to_gc_state (chunk_id, true /* force */ );
87
+ }
11
88
12
89
GCManager::~GCManager () { stop (); }
13
90
14
91
void GCManager::start () {
15
92
for (const auto & [pdev_id, gc_actor] : m_pdev_gc_actors) {
16
93
gc_actor->start ();
17
- LOGERROR (" start gc actor for pdev={}" , pdev_id);
94
+ LOGINFO (" start gc actor for pdev={}" , pdev_id);
18
95
}
19
96
20
97
m_gc_timer_hdl = iomanager.schedule_global_timer (
@@ -72,12 +149,22 @@ std::shared_ptr< GCManager::pdev_gc_actor > GCManager::get_pdev_gc_actor(uint32_
72
149
return it->second ;
73
150
}
74
151
75
- bool GCManager::is_eligible_for_gc (std::shared_ptr< HeapChunkSelector::ExtendedVChunk > chunk) {
152
+ bool GCManager::is_eligible_for_gc (chunk_id_t chunk_id) {
153
+ auto chunk = m_chunk_selector->get_extend_vchunk (chunk_id);
154
+
76
155
// 1 if the chunk state is inuse, it is occupied by a open shard, so it can not be selected and we don't need gc it.
77
156
// 2 if the chunk state is gc, it means this chunk is being gc, or this is a reserved chunk, so we don't need gc it.
78
- if (chunk->m_state != ChunkState::AVAILABLE) return false ;
157
+ if (chunk->m_state != ChunkState::AVAILABLE) {
158
+ LOGINFO (" chunk_id={} state is {}, not eligible for gc" , chunk_id, chunk->m_state )
159
+ return false ;
160
+ }
79
161
// it does not belong to any pg, so we don't need to gc it.
80
- if (!chunk->m_pg_id .has_value ()) return false ;
162
+ if (!chunk->m_pg_id .has_value ()) {
163
+ LOGINFO (" chunk_id={} belongs to no pg, not eligible for gc" , chunk_id)
164
+ return false ;
165
+ }
166
+
167
+ LOGINFO (" chunk_id={} is eligible for gc, belongs to pg {}" , chunk_id, chunk->m_pg_id .value ());
81
168
82
169
auto defrag_blk_num = chunk->get_defrag_nblks ();
83
170
auto total_blk_num = chunk->get_total_blks ();
@@ -88,21 +175,21 @@ bool GCManager::is_eligible_for_gc(std::shared_ptr< HeapChunkSelector::ExtendedV
88
175
}
89
176
90
177
void GCManager::scan_chunks_for_gc () {
91
- // in every iteration, we will select at most 2 * RESERVED_CHUNK_NUM_PER_PDEV gc tasks
92
- auto max_task_num = 2 * ( RESERVED_CHUNK_NUM_PER_PDEV - RESERVED_CHUNK_NUM_DEDICATED_FOR_EGC);
93
-
94
- for ( const auto & [_, chunk] : m_chunk_selector-> get_all_chunks ()) {
95
- if ( is_eligible_for_gc (chunk)) {
96
- auto pdev_id = chunk-> get_pdev_id ( );
97
- auto it = m_pdev_gc_actors. find (pdev_id) ;
98
- if (it != m_pdev_gc_actors. end ()) {
99
- auto & actor = it-> second ;
100
- auto chunk_id = chunk-> get_chunk_id ();
178
+ for ( const auto & [pdev_id, chunks] : m_chunk_selector-> get_pdev_chunks ()) {
179
+ // in every iteration, we will select at most 2 * RESERVED_CHUNK_NUM_PER_PDEV gc tasks
180
+ auto max_task_num = 2 * (RESERVED_CHUNK_NUM_PER_PDEV - RESERVED_CHUNK_NUM_DEDICATED_FOR_EGC);
181
+ auto it = m_pdev_gc_actors. find (pdev_id);
182
+ RELEASE_ASSERT (it != m_pdev_gc_actors. end (), " can not find gc actor for pdev_id {} when scanning chunks for gc " ,
183
+ pdev_id );
184
+ auto & actor = it-> second ;
185
+
186
+ for ( const auto & chunk_id : chunks) {
187
+ if ( is_eligible_for_gc (chunk_id)) {
101
188
auto future = actor->add_gc_task (static_cast < uint8_t >(task_priority::normal ), chunk_id);
102
189
if (future.isReady ()) {
103
190
// future is not expected to be ready immediately. if it is ready here, it probably means failing to
104
191
// add gc task. then we try to add one more.
105
- LOGWARN (" failed to add gc task for chunk_id={} on pdev_id={}, return value= {}" , chunk_id, pdev_id,
192
+ LOGWARN (" failed to add gc task for chunk_id={} on pdev_id={}, return value={}" , chunk_id, pdev_id,
106
193
future.value ());
107
194
} else if (0 == --max_task_num) {
108
195
LOGINFO (" reached max gc task limit for pdev_id={}, stopping further gc task submissions" , pdev_id);
@@ -146,7 +233,7 @@ void GCManager::pdev_gc_actor::start() {
146
233
void GCManager::pdev_gc_actor::stop () {
147
234
bool stopped = false ;
148
235
if (!m_is_stopped.compare_exchange_strong (stopped, true , std::memory_order_release, std::memory_order_relaxed)) {
149
- LOGERROR (" pdev gc actor for pdev_id={} is already stopped, no need to stop again!" , m_pdev_id);
236
+ LOGWARN (" pdev gc actor for pdev_id={} is already stopped, no need to stop again!" , m_pdev_id);
150
237
return ;
151
238
}
152
239
m_gc_executor->stop ();
@@ -168,12 +255,12 @@ folly::SemiFuture< bool > GCManager::pdev_gc_actor::add_gc_task(uint8_t priority
168
255
169
256
if (sisl_unlikely (priority == static_cast < uint8_t >(task_priority::emergent))) {
170
257
m_egc_executor->add ([this , priority, move_from_chunk, promise = std::move (promise)]() mutable {
171
- LOGERROR (" start gc task : move_from_chunk_id={}, priority={}" , move_from_chunk, priority);
258
+ LOGINFO (" start emergent gc task : move_from_chunk_id={}, priority={}" , move_from_chunk, priority);
172
259
process_gc_task (move_from_chunk, priority, std::move (promise));
173
260
});
174
261
} else {
175
262
m_gc_executor->add ([this , priority, move_from_chunk, promise = std::move (promise)]() mutable {
176
- LOGERROR (" start gc task : move_from_chunk_id={}, priority={}" , move_from_chunk, priority);
263
+ LOGINFO (" start gc task : move_from_chunk_id={}, priority={}" , move_from_chunk, priority);
177
264
process_gc_task (move_from_chunk, priority, std::move (promise));
178
265
});
179
266
}
@@ -256,8 +343,8 @@ bool GCManager::pdev_gc_actor::copy_valid_data(chunk_id_t move_from_chunk, chunk
256
343
257
344
void GCManager::pdev_gc_actor::purge_reserved_chunk (chunk_id_t chunk) {
258
345
auto vchunk = m_chunk_selector->get_extend_vchunk (chunk);
259
- RELEASE_ASSERT (!vchunk->m_pg_id .has_value (), " chunk_id={} is expected to a reserved chunk, and not belong to a pg " ,
260
- chunk);
346
+ RELEASE_ASSERT (!vchunk->m_pg_id .has_value (),
347
+ " chunk_id={} is expected to be a reserved chunk, and not belong to a pg " , chunk);
261
348
vchunk->reset (); // reset the chunk to make sure it is empty
262
349
263
350
// clear all the entries of this chunk in the gc index table
@@ -277,22 +364,8 @@ void GCManager::pdev_gc_actor::purge_reserved_chunk(chunk_id_t chunk) {
277
364
278
365
void GCManager::pdev_gc_actor::process_gc_task (chunk_id_t move_from_chunk, uint8_t priority,
279
366
folly::Promise< bool > task) {
280
- auto move_from_vchunk = m_chunk_selector->get_extend_vchunk (move_from_chunk);
281
-
282
367
LOGINFO (" start process gc task for move_from_chunk={} with priority={} " , move_from_chunk, priority);
283
368
284
- // we need to select the move_from_chunk out of the per pg chunk heap in chunk selector if it is a gc task with
285
- // normal priority. for the task with emergent priority, it is already selected since it is now used for an open
286
- // shard.
287
-
288
- if (!GCManager::is_eligible_for_gc (move_from_vchunk)) {
289
- LOGWARN (" move_from_chunk={} is not eligible for gc, so we can not process the gc task" , move_from_chunk);
290
- task.setValue (false );
291
- return ;
292
- }
293
-
294
- LOGINFO (" move_from_chunk={} belongs to pg {} " , move_from_chunk, move_from_vchunk->m_pg_id .value ());
295
-
296
369
// make chunk to gc state, so that it can be select for creating shard
297
370
auto succeed = m_chunk_selector->try_mark_chunk_to_gc_state (
298
371
move_from_chunk, priority == static_cast < uint8_t >(task_priority::emergent) /* force */ );
@@ -353,7 +426,7 @@ void GCManager::pdev_gc_actor::process_gc_task(chunk_id_t move_from_chunk, uint8
353
426
354
427
GCManager::pdev_gc_actor::~pdev_gc_actor () {
355
428
stop ();
356
- LOGINFO (" pdev gc actor for pdev_id={} is destroyed" , m_pdev_id);
429
+ LOGINFO (" gc actor for pdev_id={} is destroyed" , m_pdev_id);
357
430
}
358
431
359
432
/* RateLimiter */
0 commit comments