github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/span/frontier_test.go (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package span
    12  
    13  import (
    14  	"container/heap"
    15  	"fmt"
    16  	"strings"
    17  	"testing"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    20  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    21  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  func (f *Frontier) entriesStr() string {
    26  	var buf strings.Builder
    27  	f.Entries(func(sp roachpb.Span, ts hlc.Timestamp) {
    28  		if buf.Len() != 0 {
    29  			buf.WriteString(` `)
    30  		}
    31  		fmt.Fprintf(&buf, `%s@%d`, sp, ts.WallTime)
    32  	})
    33  	return buf.String()
    34  }
    35  
    36  func TestSpanFrontier(t *testing.T) {
    37  	defer leaktest.AfterTest(t)()
    38  
    39  	keyA, keyB := roachpb.Key("a"), roachpb.Key("b")
    40  	keyC, keyD := roachpb.Key("c"), roachpb.Key("d")
    41  
    42  	spAB := roachpb.Span{Key: keyA, EndKey: keyB}
    43  	spAC := roachpb.Span{Key: keyA, EndKey: keyC}
    44  	spAD := roachpb.Span{Key: keyA, EndKey: keyD}
    45  	spBC := roachpb.Span{Key: keyB, EndKey: keyC}
    46  	spBD := roachpb.Span{Key: keyB, EndKey: keyD}
    47  	spCD := roachpb.Span{Key: keyC, EndKey: keyD}
    48  
    49  	f := MakeFrontier(spAD)
    50  	require.Equal(t, hlc.Timestamp{}, f.Frontier())
    51  	require.Equal(t, `{a-d}@0`, f.entriesStr())
    52  
    53  	// Untracked spans are ignored
    54  	adv := f.Forward(
    55  		roachpb.Span{Key: []byte("d"), EndKey: []byte("e")},
    56  		hlc.Timestamp{WallTime: 1},
    57  	)
    58  	require.Equal(t, false, adv)
    59  	require.Equal(t, hlc.Timestamp{}, f.Frontier())
    60  	require.Equal(t, `{a-d}@0`, f.entriesStr())
    61  
    62  	// Forward the entire tracked spanspace.
    63  	adv = f.Forward(spAD, hlc.Timestamp{WallTime: 1})
    64  	require.Equal(t, true, adv)
    65  	require.Equal(t, hlc.Timestamp{WallTime: 1}, f.Frontier())
    66  	require.Equal(t, `{a-d}@1`, f.entriesStr())
    67  
    68  	// Forward it again.
    69  	adv = f.Forward(spAD, hlc.Timestamp{WallTime: 2})
    70  	require.Equal(t, true, adv)
    71  	require.Equal(t, hlc.Timestamp{WallTime: 2}, f.Frontier())
    72  	require.Equal(t, `{a-d}@2`, f.entriesStr())
    73  
    74  	// Forward to the previous frontier.
    75  	adv = f.Forward(spAD, hlc.Timestamp{WallTime: 2})
    76  	require.Equal(t, false, adv)
    77  	require.Equal(t, hlc.Timestamp{WallTime: 2}, f.Frontier())
    78  	require.Equal(t, `{a-d}@2`, f.entriesStr())
    79  
    80  	// Forward into the past is ignored.
    81  	adv = f.Forward(spAD, hlc.Timestamp{WallTime: 1})
    82  	require.Equal(t, false, adv)
    83  	require.Equal(t, hlc.Timestamp{WallTime: 2}, f.Frontier())
    84  	require.Equal(t, `{a-d}@2`, f.entriesStr())
    85  
    86  	// Forward a subset.
    87  	adv = f.Forward(spBC, hlc.Timestamp{WallTime: 3})
    88  	require.Equal(t, false, adv)
    89  	require.Equal(t, hlc.Timestamp{WallTime: 2}, f.Frontier())
    90  	require.Equal(t, `{a-b}@2 {b-c}@3 {c-d}@2`, f.entriesStr())
    91  
    92  	// Forward it more.
    93  	adv = f.Forward(spBC, hlc.Timestamp{WallTime: 4})
    94  	require.Equal(t, false, adv)
    95  	require.Equal(t, hlc.Timestamp{WallTime: 2}, f.Frontier())
    96  	require.Equal(t, `{a-b}@2 {b-c}@4 {c-d}@2`, f.entriesStr())
    97  
    98  	// Forward all tracked spans to timestamp before BC (currently at 4).
    99  	// Advances to the min of tracked spans. Note that this requires the
   100  	// forwarded span to be split into two spans, one on each side of BC.
   101  	adv = f.Forward(spAD, hlc.Timestamp{WallTime: 3})
   102  	require.Equal(t, true, adv)
   103  	require.Equal(t, hlc.Timestamp{WallTime: 3}, f.Frontier())
   104  	require.Equal(t, `{a-b}@3 {b-c}@4 {c-d}@3`, f.entriesStr())
   105  
   106  	// Forward everything but BC, advances to the min of tracked spans.
   107  	adv = f.Forward(spAB, hlc.Timestamp{WallTime: 5})
   108  	require.Equal(t, false, adv)
   109  	require.Equal(t, hlc.Timestamp{WallTime: 3}, f.Frontier())
   110  	adv = f.Forward(spCD, hlc.Timestamp{WallTime: 5})
   111  	require.Equal(t, true, adv)
   112  	require.Equal(t, hlc.Timestamp{WallTime: 4}, f.Frontier())
   113  	require.Equal(t, `{a-b}@5 {b-c}@4 {c-d}@5`, f.entriesStr())
   114  
   115  	// Catch BC up.
   116  	adv = f.Forward(spBC, hlc.Timestamp{WallTime: 5})
   117  	require.Equal(t, true, adv)
   118  	require.Equal(t, hlc.Timestamp{WallTime: 5}, f.Frontier())
   119  	require.Equal(t, `{a-b}@5 {b-c}@5 {c-d}@5`, f.entriesStr())
   120  
   121  	// Forward them all at once (spans don't collapse for now, this is a TODO).
   122  	adv = f.Forward(spAD, hlc.Timestamp{WallTime: 6})
   123  	require.Equal(t, true, adv)
   124  	require.Equal(t, hlc.Timestamp{WallTime: 6}, f.Frontier())
   125  	require.Equal(t, `{a-b}@6 {b-c}@6 {c-d}@6`, f.entriesStr())
   126  
   127  	// Split AC with BD.
   128  	adv = f.Forward(spCD, hlc.Timestamp{WallTime: 7})
   129  	require.Equal(t, false, adv)
   130  	require.Equal(t, hlc.Timestamp{WallTime: 6}, f.Frontier())
   131  	require.Equal(t, `{a-b}@6 {b-c}@6 {c-d}@7`, f.entriesStr())
   132  	adv = f.Forward(spBD, hlc.Timestamp{WallTime: 8})
   133  	require.Equal(t, false, adv)
   134  	require.Equal(t, hlc.Timestamp{WallTime: 6}, f.Frontier())
   135  	require.Equal(t, `{a-b}@6 {b-c}@8 {c-d}@8`, f.entriesStr())
   136  	adv = f.Forward(spAB, hlc.Timestamp{WallTime: 8})
   137  	require.Equal(t, true, adv)
   138  	require.Equal(t, hlc.Timestamp{WallTime: 8}, f.Frontier())
   139  	require.Equal(t, `{a-b}@8 {b-c}@8 {c-d}@8`, f.entriesStr())
   140  
   141  	// Split BD with AC.
   142  	adv = f.Forward(spAC, hlc.Timestamp{WallTime: 9})
   143  	require.Equal(t, false, adv)
   144  	require.Equal(t, hlc.Timestamp{WallTime: 8}, f.Frontier())
   145  	require.Equal(t, `{a-b}@9 {b-c}@9 {c-d}@8`, f.entriesStr())
   146  	adv = f.Forward(spCD, hlc.Timestamp{WallTime: 9})
   147  	require.Equal(t, true, adv)
   148  	require.Equal(t, hlc.Timestamp{WallTime: 9}, f.Frontier())
   149  	require.Equal(t, `{a-b}@9 {b-c}@9 {c-d}@9`, f.entriesStr())
   150  }
   151  
   152  func TestSpanFrontierDisjointSpans(t *testing.T) {
   153  	defer leaktest.AfterTest(t)()
   154  	keyA, keyB, keyC := roachpb.Key("a"), roachpb.Key("b"), roachpb.Key("c")
   155  	keyD, keyE, keyF := roachpb.Key("d"), roachpb.Key("e"), roachpb.Key("f")
   156  	spAB := roachpb.Span{Key: keyA, EndKey: keyB}
   157  	spAD := roachpb.Span{Key: keyA, EndKey: keyD}
   158  	spCE := roachpb.Span{Key: keyC, EndKey: keyE}
   159  	spDF := roachpb.Span{Key: keyD, EndKey: keyF}
   160  
   161  	f := MakeFrontier(spAB, spCE)
   162  	require.Equal(t, hlc.Timestamp{}, f.Frontier())
   163  	require.Equal(t, `{a-b}@0 {c-e}@0`, f.entriesStr())
   164  
   165  	// Advance just the tracked spans
   166  	adv := f.Forward(spCE, hlc.Timestamp{WallTime: 1})
   167  	require.Equal(t, false, adv)
   168  	require.Equal(t, hlc.Timestamp{}, f.Frontier())
   169  	require.Equal(t, `{a-b}@0 {c-e}@1`, f.entriesStr())
   170  	adv = f.Forward(spAB, hlc.Timestamp{WallTime: 1})
   171  	require.Equal(t, true, adv)
   172  	require.Equal(t, hlc.Timestamp{WallTime: 1}, f.Frontier())
   173  	require.Equal(t, `{a-b}@1 {c-e}@1`, f.entriesStr())
   174  
   175  	// Advance a span that partially overlaps the tracked spans
   176  	adv = f.Forward(spDF, hlc.Timestamp{WallTime: 2})
   177  	require.Equal(t, false, adv)
   178  	require.Equal(t, hlc.Timestamp{WallTime: 1}, f.Frontier())
   179  	require.Equal(t, `{a-b}@1 {c-d}@1 {d-e}@2`, f.entriesStr())
   180  
   181  	// Advance one span that covers two tracked spans and so needs two entries.
   182  	adv = f.Forward(spAD, hlc.Timestamp{WallTime: 3})
   183  	require.Equal(t, true, adv)
   184  	require.Equal(t, hlc.Timestamp{WallTime: 2}, f.Frontier())
   185  	require.Equal(t, `{a-b}@3 {c-d}@3 {d-e}@2`, f.entriesStr())
   186  }
   187  
   188  func TestSpanFrontierHeap(t *testing.T) {
   189  	defer leaktest.AfterTest(t)()
   190  
   191  	keyA, keyB, keyC := roachpb.Key("a"), roachpb.Key("b"), roachpb.Key("c")
   192  	spAB := roachpb.Span{Key: keyA, EndKey: keyB}
   193  	spBC := roachpb.Span{Key: keyB, EndKey: keyC}
   194  
   195  	var fh frontierHeap
   196  
   197  	eAB1 := &frontierEntry{span: spAB, ts: hlc.Timestamp{WallTime: 1}}
   198  	eBC1 := &frontierEntry{span: spBC, ts: hlc.Timestamp{WallTime: 1}}
   199  	eAB2 := &frontierEntry{span: spAB, ts: hlc.Timestamp{WallTime: 2}}
   200  
   201  	// Push one
   202  	heap.Push(&fh, eAB1)
   203  	require.Equal(t, eAB1, heap.Pop(&fh))
   204  
   205  	// Push different spans and times
   206  	heap.Push(&fh, eAB1)
   207  	heap.Push(&fh, eBC1)
   208  	heap.Push(&fh, eAB2)
   209  	require.Equal(t, eAB1, heap.Pop(&fh))
   210  	require.Equal(t, eBC1, heap.Pop(&fh))
   211  	require.Equal(t, eAB2, heap.Pop(&fh))
   212  
   213  	// Push in a different span order
   214  	heap.Push(&fh, eBC1)
   215  	heap.Push(&fh, eAB1)
   216  	heap.Push(&fh, eAB2)
   217  	require.Equal(t, eAB1, heap.Pop(&fh))
   218  	require.Equal(t, eBC1, heap.Pop(&fh))
   219  	require.Equal(t, eAB2, heap.Pop(&fh))
   220  
   221  	// Push in a different time order
   222  	heap.Push(&fh, eAB2)
   223  	heap.Push(&fh, eAB1)
   224  	heap.Push(&fh, eBC1)
   225  	require.Equal(t, eAB1, heap.Pop(&fh))
   226  	require.Equal(t, eBC1, heap.Pop(&fh))
   227  	require.Equal(t, eAB2, heap.Pop(&fh))
   228  }