github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/kv/resolvedts_heap.go (about) 1 // Copyright 2021 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package kv 15 16 import ( 17 "container/heap" 18 "time" 19 ) 20 21 type tsItem struct { 22 sortByEvTime bool 23 resolvedTs uint64 24 eventTime time.Time 25 penalty int 26 } 27 28 func newResolvedTsItem(ts uint64) tsItem { 29 return tsItem{resolvedTs: ts, eventTime: time.Now()} 30 } 31 32 func newEventTimeItem() tsItem { 33 return tsItem{sortByEvTime: true, eventTime: time.Now()} 34 } 35 36 // regionTsInfo contains region resolvedTs information 37 type regionTsInfo struct { 38 regionID uint64 39 index int 40 ts tsItem 41 } 42 43 type regionTsHeap []*regionTsInfo 44 45 func (rh regionTsHeap) Len() int { return len(rh) } 46 47 func (rh regionTsHeap) Less(i, j int) bool { 48 if rh[i].ts.sortByEvTime { 49 return rh[i].ts.eventTime.Before(rh[j].ts.eventTime) 50 } 51 return rh[i].ts.resolvedTs < rh[j].ts.resolvedTs 52 } 53 54 func (rh regionTsHeap) Swap(i, j int) { 55 rh[i], rh[j] = rh[j], rh[i] 56 rh[i].index = i 57 rh[j].index = j 58 } 59 60 func (rh *regionTsHeap) Push(x interface{}) { 61 n := len(*rh) 62 item := x.(*regionTsInfo) 63 item.index = n 64 *rh = append(*rh, item) 65 } 66 67 func (rh *regionTsHeap) Pop() interface{} { 68 old := *rh 69 n := len(old) 70 item := old[n-1] 71 item.index = -1 // for safety 72 *rh = old[0 : n-1] 73 return item 74 } 75 76 // regionTsManager is a used to maintain resolved ts information for N regions. 77 // This struct is not thread safe 78 type regionTsManager struct { 79 // mapping from regionID to regionTsInfo object 80 m map[uint64]*regionTsInfo 81 h regionTsHeap 82 } 83 84 func newRegionTsManager() *regionTsManager { 85 return ®ionTsManager{ 86 m: make(map[uint64]*regionTsInfo), 87 h: make(regionTsHeap, 0), 88 } 89 } 90 91 // Upsert implements insert and update on duplicated key 92 func (rm *regionTsManager) Upsert(item *regionTsInfo) { 93 if old, ok := rm.m[item.regionID]; ok { 94 // in a single resolved ts manager, the resolved ts of a region should not be fallen back 95 if !item.ts.sortByEvTime { 96 if item.ts.resolvedTs == old.ts.resolvedTs && item.ts.eventTime.After(old.ts.eventTime) { 97 old.ts.penalty++ 98 old.ts.eventTime = item.ts.eventTime 99 heap.Fix(&rm.h, old.index) 100 } else if item.ts.resolvedTs > old.ts.resolvedTs { 101 old.ts.resolvedTs = item.ts.resolvedTs 102 old.ts.eventTime = item.ts.eventTime 103 old.ts.penalty = 0 104 heap.Fix(&rm.h, old.index) 105 } 106 } else { 107 if item.ts.eventTime.After(old.ts.eventTime) { 108 old.ts.eventTime = item.ts.eventTime 109 heap.Fix(&rm.h, old.index) 110 } 111 } 112 } else { 113 heap.Push(&rm.h, item) 114 rm.m[item.regionID] = item 115 } 116 } 117 118 // Pop pops a regionTsInfo from rts heap, delete it from region rts map 119 func (rm *regionTsManager) Pop() *regionTsInfo { 120 if rm.Len() == 0 { 121 return nil 122 } 123 item := heap.Pop(&rm.h).(*regionTsInfo) 124 delete(rm.m, item.regionID) 125 return item 126 } 127 128 // Remove removes item from regionTsManager 129 func (rm *regionTsManager) Remove(regionID uint64) *regionTsInfo { 130 if item, ok := rm.m[regionID]; ok { 131 delete(rm.m, item.regionID) 132 return heap.Remove(&rm.h, item.index).(*regionTsInfo) 133 } 134 return nil 135 } 136 137 // Len returns the item count in regionTsManager 138 func (rm *regionTsManager) Len() int { 139 return len(rm.m) 140 }