github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/rtree/rtree.go (about)

     1  // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0.
     2  
     3  package rtree
     4  
     5  import (
     6  	"bytes"
     7  
     8  	"github.com/google/btree"
     9  	backuppb "github.com/pingcap/kvproto/pkg/backup"
    10  	"github.com/pingcap/log"
    11  
    12  	"github.com/pingcap/br/pkg/logutil"
    13  )
    14  
    15  // Range represents a backup response.
    16  type Range struct {
    17  	StartKey []byte
    18  	EndKey   []byte
    19  	Files    []*backuppb.File
    20  }
    21  
    22  // BytesAndKeys returns total bytes and keys in a range.
    23  func (rg *Range) BytesAndKeys() (bytes, keys uint64) {
    24  	for _, f := range rg.Files {
    25  		bytes += f.TotalBytes
    26  		keys += f.TotalKvs
    27  	}
    28  	return
    29  }
    30  
    31  // Intersect returns intersect range in the tree.
    32  func (rg *Range) Intersect(
    33  	start, end []byte,
    34  ) (subStart, subEnd []byte, isIntersect bool) {
    35  	// empty mean the max end key
    36  	if len(rg.EndKey) != 0 && bytes.Compare(start, rg.EndKey) >= 0 {
    37  		isIntersect = false
    38  		return
    39  	}
    40  	if len(end) != 0 && bytes.Compare(end, rg.StartKey) <= 0 {
    41  		isIntersect = false
    42  		return
    43  	}
    44  	isIntersect = true
    45  	if bytes.Compare(start, rg.StartKey) >= 0 {
    46  		subStart = start
    47  	} else {
    48  		subStart = rg.StartKey
    49  	}
    50  	switch {
    51  	case len(end) == 0:
    52  		subEnd = rg.EndKey
    53  	case len(rg.EndKey) == 0:
    54  		subEnd = end
    55  	case bytes.Compare(end, rg.EndKey) < 0:
    56  		subEnd = end
    57  	default:
    58  		subEnd = rg.EndKey
    59  	}
    60  	return
    61  }
    62  
    63  // Contains check if the range contains the given key, [start, end).
    64  func (rg *Range) Contains(key []byte) bool {
    65  	start, end := rg.StartKey, rg.EndKey
    66  	return bytes.Compare(key, start) >= 0 &&
    67  		(len(end) == 0 || bytes.Compare(key, end) < 0)
    68  }
    69  
    70  // Less impls btree.Item.
    71  func (rg *Range) Less(than btree.Item) bool {
    72  	// rg.StartKey < than.StartKey
    73  	ta := than.(*Range)
    74  	return bytes.Compare(rg.StartKey, ta.StartKey) < 0
    75  }
    76  
    77  var _ btree.Item = &Range{}
    78  
    79  // RangeTree is sorted tree for Ranges.
    80  // All the ranges it stored do not overlap.
    81  type RangeTree struct {
    82  	*btree.BTree
    83  }
    84  
    85  // NewRangeTree returns an empty range tree.
    86  func NewRangeTree() RangeTree {
    87  	return RangeTree{
    88  		BTree: btree.New(32),
    89  	}
    90  }
    91  
    92  // Find is a helper function to find an item that contains the range start
    93  // key.
    94  func (rangeTree *RangeTree) Find(rg *Range) *Range {
    95  	var ret *Range
    96  	rangeTree.DescendLessOrEqual(rg, func(i btree.Item) bool {
    97  		ret = i.(*Range)
    98  		return false
    99  	})
   100  
   101  	if ret == nil || !ret.Contains(rg.StartKey) {
   102  		return nil
   103  	}
   104  
   105  	return ret
   106  }
   107  
   108  // getOverlaps gets the ranges which are overlapped with the specified range range.
   109  func (rangeTree *RangeTree) getOverlaps(rg *Range) []*Range {
   110  	// note that find() gets the last item that is less or equal than the range.
   111  	// in the case: |_______a_______|_____b_____|___c___|
   112  	// new range is     |______d______|
   113  	// find() will return Range of range_a
   114  	// and both startKey of range_a and range_b are less than endKey of range_d,
   115  	// thus they are regarded as overlapped ranges.
   116  	found := rangeTree.Find(rg)
   117  	if found == nil {
   118  		found = rg
   119  	}
   120  
   121  	var overlaps []*Range
   122  	rangeTree.AscendGreaterOrEqual(found, func(i btree.Item) bool {
   123  		over := i.(*Range)
   124  		if len(rg.EndKey) > 0 && bytes.Compare(rg.EndKey, over.StartKey) <= 0 {
   125  			return false
   126  		}
   127  		overlaps = append(overlaps, over)
   128  		return true
   129  	})
   130  	return overlaps
   131  }
   132  
   133  // Update inserts range into tree and delete overlapping ranges.
   134  func (rangeTree *RangeTree) Update(rg Range) {
   135  	overlaps := rangeTree.getOverlaps(&rg)
   136  	// Range has backuped, overwrite overlapping range.
   137  	for _, item := range overlaps {
   138  		log.Info("delete overlapping range",
   139  			logutil.Key("startKey", item.StartKey),
   140  			logutil.Key("endKey", item.EndKey))
   141  		rangeTree.Delete(item)
   142  	}
   143  	rangeTree.ReplaceOrInsert(&rg)
   144  }
   145  
   146  // Put forms a range and inserts it into tree.
   147  func (rangeTree *RangeTree) Put(
   148  	startKey, endKey []byte, files []*backuppb.File,
   149  ) {
   150  	rg := Range{
   151  		StartKey: startKey,
   152  		EndKey:   endKey,
   153  		Files:    files,
   154  	}
   155  	rangeTree.Update(rg)
   156  }
   157  
   158  // InsertRange inserts ranges into the range tree.
   159  // It returns a non-nil range if there are soe overlapped ranges.
   160  func (rangeTree *RangeTree) InsertRange(rg Range) *Range {
   161  	out := rangeTree.ReplaceOrInsert(&rg)
   162  	if out == nil {
   163  		return nil
   164  	}
   165  	return out.(*Range)
   166  }
   167  
   168  // GetSortedRanges collects and returns sorted ranges.
   169  func (rangeTree *RangeTree) GetSortedRanges() []Range {
   170  	sortedRanges := make([]Range, 0, rangeTree.Len())
   171  	rangeTree.Ascend(func(rg btree.Item) bool {
   172  		if rg == nil {
   173  			return false
   174  		}
   175  		sortedRanges = append(sortedRanges, *rg.(*Range))
   176  		return true
   177  	})
   178  	return sortedRanges
   179  }
   180  
   181  // GetIncompleteRange returns missing range covered by startKey and endKey.
   182  func (rangeTree *RangeTree) GetIncompleteRange(
   183  	startKey, endKey []byte,
   184  ) []Range {
   185  	if len(startKey) != 0 && bytes.Equal(startKey, endKey) {
   186  		return []Range{}
   187  	}
   188  	incomplete := make([]Range, 0, 64)
   189  	requsetRange := Range{StartKey: startKey, EndKey: endKey}
   190  	lastEndKey := startKey
   191  	pviot := &Range{StartKey: startKey}
   192  	if first := rangeTree.Find(pviot); first != nil {
   193  		pviot.StartKey = first.StartKey
   194  	}
   195  	rangeTree.AscendGreaterOrEqual(pviot, func(i btree.Item) bool {
   196  		rg := i.(*Range)
   197  		if bytes.Compare(lastEndKey, rg.StartKey) < 0 {
   198  			start, end, isIntersect :=
   199  				requsetRange.Intersect(lastEndKey, rg.StartKey)
   200  			if isIntersect {
   201  				// There is a gap between the last item and the current item.
   202  				incomplete =
   203  					append(incomplete, Range{StartKey: start, EndKey: end})
   204  			}
   205  		}
   206  		lastEndKey = rg.EndKey
   207  		return len(endKey) == 0 || bytes.Compare(rg.EndKey, endKey) < 0
   208  	})
   209  
   210  	// Check whether we need append the last range
   211  	if !bytes.Equal(lastEndKey, endKey) && len(lastEndKey) != 0 &&
   212  		(len(endKey) == 0 || bytes.Compare(lastEndKey, endKey) < 0) {
   213  		start, end, isIntersect := requsetRange.Intersect(lastEndKey, endKey)
   214  		if isIntersect {
   215  			incomplete =
   216  				append(incomplete, Range{StartKey: start, EndKey: end})
   217  		}
   218  	}
   219  	return incomplete
   220  }