github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/sink/txns_heap.go (about)

     1  // Copyright 2020 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 sink
    15  
    16  import (
    17  	"container/heap"
    18  
    19  	"github.com/pingcap/ticdc/cdc/model"
    20  )
    21  
    22  type innerTxnsHeap []innerHeapEntry
    23  
    24  type innerHeapEntry struct {
    25  	ts     uint64
    26  	bucket int
    27  }
    28  
    29  func (h innerTxnsHeap) Len() int           { return len(h) }
    30  func (h innerTxnsHeap) Less(i, j int) bool { return h[i].ts < h[j].ts }
    31  func (h innerTxnsHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
    32  
    33  func (h *innerTxnsHeap) Push(x interface{}) {
    34  	// Push and Pop use pointer receivers because they modify the slice's length,
    35  	// not just its contents.
    36  	*h = append(*h, x.(innerHeapEntry))
    37  }
    38  
    39  func (h *innerTxnsHeap) Pop() interface{} {
    40  	old := *h
    41  	n := len(old)
    42  	x := old[n-1]
    43  	*h = old[0 : n-1]
    44  	return x
    45  }
    46  
    47  type txnsHeap struct {
    48  	inner     *innerTxnsHeap
    49  	txnsGroup [][]*model.SingleTableTxn
    50  }
    51  
    52  func newTxnsHeap(txnsMap map[model.TableID][]*model.SingleTableTxn) *txnsHeap {
    53  	txnsGroup := make([][]*model.SingleTableTxn, 0, len(txnsMap))
    54  	for _, txns := range txnsMap {
    55  		txnsGroup = append(txnsGroup, txns)
    56  	}
    57  	inner := make(innerTxnsHeap, 0, len(txnsGroup))
    58  	heap.Init(&inner)
    59  	for bucket, txns := range txnsGroup {
    60  		if len(txns) == 0 {
    61  			continue
    62  		}
    63  		entry := innerHeapEntry{ts: txns[0].CommitTs, bucket: bucket}
    64  		heap.Push(&inner, entry)
    65  	}
    66  	return &txnsHeap{inner: &inner, txnsGroup: txnsGroup}
    67  }
    68  
    69  func (h *txnsHeap) iter(fn func(txn *model.SingleTableTxn)) {
    70  	for {
    71  		if h.inner.Len() == 0 {
    72  			break
    73  		}
    74  		minEntry := heap.Pop(h.inner).(innerHeapEntry)
    75  		bucket := minEntry.bucket
    76  		fn(h.txnsGroup[bucket][0])
    77  		h.txnsGroup[bucket] = h.txnsGroup[bucket][1:]
    78  		if len(h.txnsGroup[bucket]) > 0 {
    79  			heap.Push(h.inner, innerHeapEntry{
    80  				ts:     h.txnsGroup[bucket][0].CommitTs,
    81  				bucket: bucket,
    82  			})
    83  		}
    84  	}
    85  }