Skip to content
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

Closed
wants to merge 6 commits into from

Conversation

Yisaer
Copy link
Contributor

@Yisaer Yisaer commented Apr 21, 2022

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

  • Unit test

Release note

Please refer to Release Notes Language Style Guide to write a quality release note.

None

@ti-chi-bot
Copy link
Member

[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 /cc @reviewer in the comment.
After your PR has acquired the required number of LGTMs, you can assign this pull request to the committer in the list by filling /assign @committer in the comment to help you merge this pull request.

The full list of commands accepted by this bot can be found here.

Reviewer can indicate their review by submitting an approval review.
Reviewer can cancel approval by submitting a request changes review.

@ti-chi-bot ti-chi-bot added release-note-none Denotes a PR that doesn't merit a release note. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Apr 21, 2022
@sre-bot
Copy link
Contributor

sre-bot commented Apr 21, 2022

Signed-off-by: yisaer <[email protected]>

add lru statscache

Signed-off-by: yisaer <[email protected]>

add lru statscache

Signed-off-by: yisaer <[email protected]>
@Yisaer Yisaer force-pushed the introduce_lru_statscache branch from a4203d7 to 734dfbf Compare April 21, 2022 07:29
Yisaer added 2 commits April 21, 2022 16:15
Signed-off-by: yisaer <[email protected]>
Signed-off-by: yisaer <[email protected]>
metrics/stats.go Outdated Show resolved Hide resolved
metrics/stats.go Outdated Show resolved Hide resolved
if !exists {
return nil, false
}
l.cache.MoveToFront(element)
Copy link
Contributor

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?

Copy link
Contributor Author

@Yisaer Yisaer Apr 24, 2022

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
}

Copy link
Contributor

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.

Copy link
Contributor

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]>
statistics/handle/lru_cache.go Outdated Show resolved Hide resolved
statistics/handle/statscache.go Outdated Show resolved Hide resolved
statistics/handle/lru_cache.go Outdated Show resolved Hide resolved
statistics/handle/lru_cache.go Outdated Show resolved Hide resolved
statistics/handle/lru_cache.go Show resolved Hide resolved
statistics/handle/lru_cache.go Outdated Show resolved Hide resolved
Yisaer added 2 commits April 26, 2022 12:20
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]>
@Yisaer Yisaer force-pushed the introduce_lru_statscache branch from dbfac49 to 1341eb0 Compare April 26, 2022 06:36
@Yisaer
Copy link
Contributor Author

Yisaer commented Apr 26, 2022

/run-all-tests

@Yisaer Yisaer requested a review from xuyifangreeneyes April 26, 2022 10:24
// 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)
Copy link
Contributor

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?

Copy link
Contributor

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())
Copy link
Contributor

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})
Copy link
Contributor

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()
Copy link
Contributor

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)
Copy link
Contributor

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)
Copy link
Contributor

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() {
Copy link
Contributor

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)
Copy link
Contributor

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.

Copy link
Contributor

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
Copy link
Contributor

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)
Copy link
Contributor

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.

@Yisaer Yisaer closed this Apr 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release-note-none Denotes a PR that doesn't merit a release note. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants