-
Notifications
You must be signed in to change notification settings - Fork 409
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
[WIP] Delta flush background #7088
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,8 @@ | |
#include <Storages/Transaction/TMTContext.h> | ||
#include <common/likely.h> | ||
|
||
#include <tuple> | ||
|
||
namespace DB | ||
{ | ||
namespace ErrorCodes | ||
|
@@ -98,6 +100,7 @@ RegionPtr KVStore::getRegion(RegionID region_id) const | |
return it->second; | ||
return nullptr; | ||
} | ||
// TODO: may get regions not in segment? | ||
RegionMap KVStore::getRegionsByRangeOverlap(const RegionRange & range) const | ||
{ | ||
auto manage_lock = genRegionReadLock(); | ||
|
@@ -365,11 +368,11 @@ bool KVStore::tryFlushRegionData(UInt64 region_id, bool force_persist, bool try_ | |
} | ||
else | ||
{ | ||
return canFlushRegionDataImpl(curr_region_ptr, true, try_until_succeed, tmt, region_task_lock, index, term); | ||
return canFlushRegionDataImpl(curr_region_ptr, false, try_until_succeed, tmt, region_task_lock, index, term); | ||
} | ||
} | ||
|
||
bool KVStore::canFlushRegionDataImpl(const RegionPtr & curr_region_ptr, UInt8 flush_if_possible, bool try_until_succeed, TMTContext & tmt, const RegionTaskLock & region_task_lock, UInt64 index, UInt64 term) | ||
bool KVStore::canFlushRegionDataImpl(const RegionPtr & curr_region_ptr, UInt8, bool, TMTContext &, const RegionTaskLock &, UInt64, UInt64) | ||
{ | ||
if (curr_region_ptr == nullptr) | ||
{ | ||
|
@@ -381,26 +384,7 @@ bool KVStore::canFlushRegionDataImpl(const RegionPtr & curr_region_ptr, UInt8 fl | |
|
||
LOG_DEBUG(log, "{} approx mem cache info: rows {}, bytes {}", curr_region.toString(false), rows, size_bytes); | ||
|
||
bool can_flush = false; | ||
if (rows >= region_compact_log_min_rows.load(std::memory_order_relaxed) | ||
|| size_bytes >= region_compact_log_min_bytes.load(std::memory_order_relaxed)) | ||
{ | ||
// if rows or bytes more than threshold, flush cache and persist mem data. | ||
can_flush = true; | ||
} | ||
else | ||
{ | ||
// if there is little data in mem, wait until time interval reached threshold. | ||
// use random period so that lots of regions will not be persisted at same time. | ||
auto compact_log_period = std::rand() % region_compact_log_period.load(std::memory_order_relaxed); // NOLINT | ||
can_flush = !(curr_region.lastCompactLogTime() + Seconds{compact_log_period} > Clock::now()); | ||
} | ||
if (can_flush && flush_if_possible) | ||
{ | ||
LOG_DEBUG(log, "{} flush region due to tryFlushRegionData, index {} term {}", curr_region.toString(false), index, term); | ||
return forceFlushRegionDataImpl(curr_region, try_until_succeed, tmt, region_task_lock, index, term); | ||
} | ||
return can_flush; | ||
return false; | ||
} | ||
|
||
bool KVStore::forceFlushRegionDataImpl(Region & curr_region, bool try_until_succeed, TMTContext & tmt, const RegionTaskLock & region_task_lock, UInt64 index, UInt64 term) | ||
|
@@ -859,4 +843,92 @@ FileUsageStatistics KVStore::getFileUsageStatistics() const | |
return region_persister->getFileUsageStatistics(); | ||
} | ||
|
||
// We need to get applied index before flushing cache, and can't hold region task lock when flush cache to avoid hang write cmd apply. | ||
// 1. store applied index and applied term, | ||
// 2. flush cache, | ||
// 3. notify regions to compact log and store fushed state with applied index/term before flushing cache. | ||
void KVStore::copmactLogByRowKeyRange(TMTContext & tmt, const DM::RowKeyRange & rowkey_range, TableID table_id, bool is_background) | ||
{ | ||
auto storage = tmt.getStorages().get(table_id); | ||
if (unlikely(storage == nullptr)) | ||
{ | ||
LOG_WARNING(log, | ||
"tryFlushRegionCacheInStorage can not get table for table id {}, ignored", | ||
table_id); | ||
return; | ||
} | ||
auto range = std::make_pair(TiKVRangeKey::makeTiKVRangeKey<true>(RecordKVFormat::encodeAsTiKVKey(*rowkey_range.start.toRegionKey(table_id))), | ||
TiKVRangeKey::makeTiKVRangeKey<false>(RecordKVFormat::encodeAsTiKVKey(*rowkey_range.end.toRegionKey(table_id)))); | ||
std::unordered_map<UInt64, std::tuple<UInt64, UInt64, DM::RowKeyRange>> region_copmact_indexes; | ||
{ | ||
auto task_lock = genTaskLock(); | ||
auto region_map = getRegionsByRangeOverlap(range); | ||
for (const auto & overlapped_region : region_map) | ||
{ | ||
auto region_rowkey_range = DM::RowKeyRange::fromRegionRange( | ||
overlapped_region.second->getRange(), | ||
table_id, | ||
storage->isCommonHandle(), | ||
storage->getRowKeyColumnSize()); | ||
auto region_task_lock = region_manager.genRegionTaskLock(overlapped_region.first); | ||
region_copmact_indexes[overlapped_region.first] = {overlapped_region.second->appliedIndex(), overlapped_region.second->appliedIndexTerm(), region_rowkey_range}; | ||
persistRegion(*overlapped_region.second, region_task_lock, "triggerCompactLog"); | ||
} | ||
} | ||
storage->flushCache(tmt.getContext(), rowkey_range); | ||
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. Why |
||
// flush all segments in the range of regions. | ||
// TODO: combine continues range to do one flush. | ||
for (const auto & region : region_copmact_indexes) | ||
{ | ||
auto region_rowkey_range = std::get<2>(region.second); | ||
if (rowkey_range.getStart() <= region_rowkey_range.getStart() && region_rowkey_range.getEnd() < rowkey_range.getEnd()) | ||
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. Why |
||
{ | ||
// This segment has flushed, skip it. | ||
LOG_DEBUG(log, "flushed segment of region {}", region.first); | ||
continue; | ||
} | ||
LOG_DEBUG(log, "flush extra segment of region {}, region range:[{},{}], flushed segment range:[{},{}]", region.first, region_rowkey_range.getStart().toDebugString(), region_rowkey_range.getEnd().toDebugString(), rowkey_range.getStart().toDebugString(), rowkey_range.getEnd().toDebugString()); | ||
storage->flushCache(tmt.getContext(), std::get<2>(region.second)); | ||
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 flushCache is not protected by region task lock. |
||
} | ||
// forbid regions being removed. | ||
auto task_lock = genTaskLock(); | ||
for (const auto & region : region_copmact_indexes) | ||
{ | ||
auto reion_ptr = getRegion(region.first); | ||
if (!reion_ptr) | ||
{ | ||
LOG_INFO(log, "region {} has been removed, ignore", region.first); | ||
continue; | ||
} | ||
notifyCompactLog(region.first, std::get<0>(region.second), std::get<1>(region.second), is_background); | ||
} | ||
} | ||
|
||
// the caller guarantee that delta cache has been flushed. This function need to persiste region cache before trigger proxy to compact log. | ||
void KVStore::notifyCompactLog(RegionID region_id, UInt64 compact_index, UInt64 compact_term, bool is_background) | ||
{ | ||
auto region = getRegion(region_id); | ||
if (!region) | ||
{ | ||
LOG_INFO(log, "region {} has been removed, ignore", region_id); | ||
return; | ||
} | ||
if (region->lastCompactLogTime() + Seconds{region_compact_log_period.load(std::memory_order_relaxed)} > Clock::now()) | ||
{ | ||
return; | ||
} | ||
if (is_background) | ||
{ | ||
GET_METRIC(tiflash_storage_subtask_count, type_compact_log_region_bg).Increment(); | ||
} | ||
else | ||
{ | ||
GET_METRIC(tiflash_storage_subtask_count, type_compact_log_region_fg).Increment(); | ||
} | ||
auto region_task_lock = region_manager.genRegionTaskLock(region_id); | ||
region->setFlushedState(compact_index, compact_term); | ||
region->markCompactLog(); | ||
region->cleanApproxMemCacheInfo(); | ||
getProxyHelper()->notifyCompactLog(region_id, compact_index, compact_term); | ||
} | ||
} // namespace DB |
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.
What will happen if we also flush data from those obsolete regions?