Skip to content

Commit bcf971e

Browse files
committed
core, server/cluster: isolate preparing range size scans
Signed-off-by: lhy1024 <19542290+lhy1024@users.noreply.github.com>
1 parent ba23e72 commit bcf971e

5 files changed

Lines changed: 1281 additions & 10 deletions

File tree

pkg/core/region.go

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,10 @@ type RegionsInfo struct {
10591059
pendingPeers map[uint64]*regionTree // storeID -> sub regionTree
10601060
// This tree is used to check the overlaps among all the subtrees.
10611061
overlapTree *regionTree
1062+
// sizeTree is enabled only by the primary PD service. It never holds the
1063+
// root-tree or subtree lock while updating the size index.
1064+
sizeTreeMu syncutil.Mutex
1065+
sizeTree atomic.Pointer[regionSizeTree]
10621066
}
10631067

10641068
// NewRegionsInfo creates RegionsInfo with tree, regions, leaders and followers
@@ -1076,6 +1080,76 @@ func NewRegionsInfo() *RegionsInfo {
10761080
}
10771081
}
10781082

1083+
// StartRegionSizeTree starts the eventually consistent range-size index.
1084+
func (r *RegionsInfo) StartRegionSizeTree(ctx context.Context) {
1085+
if r.sizeTree.Load() != nil {
1086+
return
1087+
}
1088+
r.sizeTreeMu.Lock()
1089+
defer r.sizeTreeMu.Unlock()
1090+
if r.sizeTree.Load() != nil {
1091+
return
1092+
}
1093+
sizeTree := newRegionSizeTree(ctx, r)
1094+
r.sizeTree.Store(sizeTree)
1095+
sizeTree.requestRebuild()
1096+
sizeTree.start()
1097+
}
1098+
1099+
// StopRegionSizeTree stops the range-size index and waits for its worker.
1100+
func (r *RegionsInfo) StopRegionSizeTree() {
1101+
r.sizeTreeMu.Lock()
1102+
defer r.sizeTreeMu.Unlock()
1103+
if sizeTree := r.sizeTree.Swap(nil); sizeTree != nil {
1104+
sizeTree.stop()
1105+
}
1106+
}
1107+
1108+
func (r *RegionsInfo) notifyRegionSizeTree(regionIDs ...uint64) {
1109+
if sizeTree := r.sizeTree.Load(); sizeTree != nil {
1110+
sizeTree.notify(regionIDs...)
1111+
}
1112+
}
1113+
1114+
func (r *RegionsInfo) notifyRegionSizeTreeIfChanged(
1115+
origin, region *RegionInfo,
1116+
overlaps []*RegionInfo,
1117+
rangeChanged bool,
1118+
) {
1119+
sizeTree := r.sizeTree.Load()
1120+
if sizeTree == nil {
1121+
return
1122+
}
1123+
sizeChanged := origin == nil || rangeChanged ||
1124+
origin.GetApproximateSize() != region.GetApproximateSize()
1125+
if len(overlaps) == 0 {
1126+
if sizeChanged {
1127+
sizeTree.notify(region.GetID())
1128+
}
1129+
return
1130+
}
1131+
capacity := len(overlaps)
1132+
if sizeChanged {
1133+
capacity++
1134+
}
1135+
regionIDs := make([]uint64, 0, capacity)
1136+
if sizeChanged {
1137+
regionIDs = append(regionIDs, region.GetID())
1138+
}
1139+
for _, overlap := range overlaps {
1140+
if overlap.GetID() != region.GetID() {
1141+
regionIDs = append(regionIDs, overlap.GetID())
1142+
}
1143+
}
1144+
sizeTree.notify(regionIDs...)
1145+
}
1146+
1147+
func (r *RegionsInfo) resetRegionSizeTree() {
1148+
if sizeTree := r.sizeTree.Load(); sizeTree != nil {
1149+
sizeTree.requestReset()
1150+
}
1151+
}
1152+
10791153
// GetRegion returns the RegionInfo with regionID
10801154
func (r *RegionsInfo) GetRegion(regionID uint64) *RegionInfo {
10811155
r.t.RLock()
@@ -1108,6 +1182,7 @@ func (r *RegionsInfo) CheckAndPutRegion(region *RegionInfo) []*RegionInfo {
11081182
}
11091183
origin, overlaps, rangeChanged := r.setRegionLocked(region, true, ols...)
11101184
r.t.Unlock()
1185+
r.notifyRegionSizeTreeIfChanged(origin, region, overlaps, rangeChanged)
11111186
r.UpdateSubTree(region, origin, overlaps, rangeChanged)
11121187
return overlaps
11131188
}
@@ -1146,6 +1221,7 @@ func (r *RegionsInfo) AtomicCheckAndPutRegion(ctx *MetaProcessContext, region *R
11461221
origin, overlaps, rangeChanged := r.setRegionLocked(region, true, ols...)
11471222
r.t.Unlock()
11481223
tracer.OnSetRegionFinished()
1224+
r.notifyRegionSizeTreeIfChanged(origin, region, overlaps, rangeChanged)
11491225
r.UpdateSubTree(region, origin, overlaps, rangeChanged)
11501226
tracer.OnUpdateSubTreeFinished()
11511227
return overlaps, nil
@@ -1169,9 +1245,10 @@ func (r *RegionsInfo) CheckAndPutRootTree(ctx *MetaProcessContext, region *Regio
11691245
return nil, err
11701246
}
11711247
tracer.OnValidateRegionFinished()
1172-
_, overlaps, _ := r.setRegionLocked(region, true, ols...)
1248+
origin, overlaps, rangeChanged := r.setRegionLocked(region, true, ols...)
11731249
r.t.Unlock()
11741250
tracer.OnSetRegionFinished()
1251+
r.notifyRegionSizeTreeIfChanged(origin, region, overlaps, rangeChanged)
11751252
return overlaps, nil
11761253
}
11771254

@@ -1342,8 +1419,10 @@ func check(region, origin *RegionInfo, overlaps []*RegionInfo) error {
13421419
// SetRegion sets the RegionInfo to regionTree and regionMap and return the update info of subtree.
13431420
func (r *RegionsInfo) SetRegion(region *RegionInfo) (*RegionInfo, []*RegionInfo, bool) {
13441421
r.t.Lock()
1345-
defer r.t.Unlock()
1346-
return r.setRegionLocked(region, false)
1422+
origin, overlaps, rangeChanged := r.setRegionLocked(region, false)
1423+
r.t.Unlock()
1424+
r.notifyRegionSizeTreeIfChanged(origin, region, overlaps, rangeChanged)
1425+
return origin, overlaps, rangeChanged
13471426
}
13481427

13491428
func (r *RegionsInfo) setRegionLocked(region *RegionInfo, withOverlaps bool, ol ...*RegionInfo) (*RegionInfo, []*RegionInfo, bool) {
@@ -1455,17 +1534,19 @@ func (r *RegionsInfo) GetOverlaps(region *RegionInfo) []*RegionInfo {
14551534
// RemoveRegion removes RegionInfo from regionTree and regionMap
14561535
func (r *RegionsInfo) RemoveRegion(region *RegionInfo) {
14571536
r.t.Lock()
1458-
defer r.t.Unlock()
14591537
// Remove from tree and regions.
14601538
r.tree.remove(region)
14611539
delete(r.regions, region.GetID())
1540+
r.t.Unlock()
1541+
r.notifyRegionSizeTree(region.GetID())
14621542
}
14631543

14641544
// ResetRegionCache resets the regions info.
14651545
func (r *RegionsInfo) ResetRegionCache() {
14661546
r.t.Lock()
14671547
r.tree = newRegionTreeWithCountRef()
14681548
r.regions = make(map[uint64]*regionItem)
1549+
r.resetRegionSizeTree()
14691550
r.t.Unlock()
14701551
r.st.Lock()
14711552
defer r.st.Unlock()
@@ -2263,6 +2344,16 @@ func (r *RegionsInfo) GetRegionSizeByRange(startKey, endKey []byte) int64 {
22632344
return size
22642345
}
22652346

2347+
// GetRegionSizeByRangeFromSizeTree returns the approximate total size of
2348+
// Regions intersecting [startKey, endKey) and whether the eventually
2349+
// consistent index is ready.
2350+
func (r *RegionsInfo) GetRegionSizeByRangeFromSizeTree(startKey, endKey []byte) (int64, bool) {
2351+
if sizeTree := r.sizeTree.Load(); sizeTree != nil && sizeTree.isReady() {
2352+
return sizeTree.getRegionSizeByRange(startKey, endKey), true
2353+
}
2354+
return 0, false
2355+
}
2356+
22662357
// metrics default poll interval
22672358
const defaultPollInterval = 15 * time.Second
22682359

0 commit comments

Comments
 (0)