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 &regionTsManager{
    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  }