-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
statistics: add lru cache implement for statsCacheInner #34145
Conversation
[REVIEW NOTIFICATION] This pull request has not been approved. To complete the pull request process, please ask the reviewers in the list to review by filling The full list of commands accepted by this bot can be found here. Reviewer can indicate their review by submitting an approval review. |
Code Coverage Details: https://codecov.io/github/pingcap/tidb/commit/1341eb0303e21d8626e310790578d1cfe9b224ec |
Signed-off-by: yisaer <[email protected]> add lru statscache Signed-off-by: yisaer <[email protected]> add lru statscache Signed-off-by: yisaer <[email protected]>
a4203d7
to
734dfbf
Compare
Signed-off-by: yisaer <[email protected]>
Signed-off-by: yisaer <[email protected]>
if !exists { | ||
return nil, false | ||
} | ||
l.cache.MoveToFront(element) |
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.
Should we maintain the lru list for Column instead of Table?
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 think we can't, because the basic recent used element is table
for current code logic.
eg: For now we can only know the updated table id in following code, thus it's hard to maintain column in lru instead of table.
// update updates the statistics table cache using copy on write.
func (sc statsCache) update(tables []*statistics.Table, deletedIDs []int64, newVersion uint64) statsCache {
newCache := sc.copy()
if newVersion == newCache.version {
newCache.minorVersion += uint64(1)
} else {
newCache.version = newVersion
newCache.minorVersion = uint64(0)
}
for _, tbl := range tables {
id := tbl.PhysicalID
newCache.Put(id, tbl)
}
for _, id := range deletedIDs {
newCache.Del(id)
}
return newCache
}
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.
Agree, the information about which columns are used after getTableStats is everywhere. We can leverage CollectColumnStatsUsage later to maintain LRU of columns.
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.
And should only MoveToFront for GetByQuery.
Signed-off-by: yisaer <[email protected]>
Signed-off-by: yisaer <[email protected]>
Signed-off-by: yisaer <[email protected]> fix test Signed-off-by: yisaer <[email protected]> fix test Signed-off-by: yisaer <[email protected]>
dbfac49
to
1341eb0
Compare
/run-all-tests |
// We first push it into cache front here, if the element TotalColTrackingMemUsage is 0, it will be | ||
// removed form cache list in l.maintainList | ||
element = l.cache.PushFront(newCacheEntry) | ||
l.maintainList(element, newCacheEntry, tblMemUsage.TotalColTrackingMemUsage(), 1) |
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.
It seems that newCacheEntry
would not be used in maintainList
? Is it better to pass nil
in?
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.
Emmm, I' not sure about it.
element.Value.(*cacheItem).value = value | ||
element.Value.(*cacheItem).tblMemUsage = tblMemUsage | ||
l.calculateCost(tblMemUsage, oldMemUsage) | ||
l.maintainList(element, nil, tblMemUsage.TotalColTrackingMemUsage(), oldMemUsage.TotalColTrackingMemUsage()) |
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.
Is it possible that oldMemUsage.TotalColTrackingMemUsage() == 0
and newMemUsage.TotalColTrackingMemUsage() > 0
? If it is possible, we will add nil
into list.
Subsystem: "statistics", | ||
Name: "cache_mem_usage", | ||
Help: "The Gauge of stats cache mem usage", | ||
}, []string{LblType}) |
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.
Are you going to make changes to tidb.json in another PR?
l.evictIfNeeded() | ||
totalCost := l.totalCost | ||
trackingCost := l.trackingCost | ||
l.Unlock() |
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.
Better to start with defer unless your logic between Lock and Unlock is quite simple.
if !exists { | ||
return nil, false | ||
} | ||
l.cache.MoveToFront(element) |
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.
Agree, the information about which columns are used after getTableStats is everywhere. We can leverage CollectColumnStatsUsage later to maintain LRU of columns.
if !exists { | ||
return nil, false | ||
} | ||
l.cache.MoveToFront(element) |
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.
And should only MoveToFront for GetByQuery.
|
||
func (l *internalLRUCache) put(key int64, value *statistics.Table, tblMemUsage *statistics.TableMemoryUsage, tryEvict bool) { | ||
// If the item TotalColTrackingMemUsage is larger than capacity, we will drop some structures in order to put it in cache | ||
for l.capacity < tblMemUsage.TotalColTrackingMemUsage() { |
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.
Why do we need this forloop?
func (l *internalLRUCache) maintainList(element *list.Element, item *cacheItem, newTotalColTrackingMemUsage, oldTotalColTrackingMemUsage int64) *list.Element { | ||
if oldTotalColTrackingMemUsage > 0 { | ||
if newTotalColTrackingMemUsage > 0 { | ||
l.cache.MoveToFront(element) |
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 think we don't need to MoveToFront for update. It could be the table stats is updated by auto-analyze, it means nothing to LRU.
And I think oldTotalColTrackingMemUsage=0 doesn't mean the element does not exist, it could be the CMSketch of this table are all evicted.
I think we don't need to maintainList with memUsage, just do PushFront for new inserted table, do Remove for deleted table, and do MoveToFront for table GetByQuery.
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.
Just keep LRU list consistent with map, the only usage of LRU list is to provide the order for evict.
item.tblMemUsage = newMemUsage | ||
l.calculateCost(newMemUsage, oldMemUsage) | ||
if l.underCapacity() { | ||
break |
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.
Since we are maintaining LRU at Table level, why not evict CMSketch for all columns of this table directly to make it simple.
l.calculateCost(tblMemUsage, &statistics.TableMemoryUsage{}) | ||
// We first push it into cache front here, if the element TotalColTrackingMemUsage is 0, it will be | ||
// removed form cache list in l.maintainList | ||
element = l.cache.PushFront(newCacheEntry) |
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.
Put means nothing to "Last recently used", it could be updates when reading latest stats from kv.
What problem does this PR solve?
Issue Number: ref #34052
Problem Summary:
What is changed and how it works?
add lru cache implement for statsCacheInner.
The evict policy is desribed in this document
Check List
Tests
Release note
Please refer to Release Notes Language Style Guide to write a quality release note.