github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/puller/frontier/list_test.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 frontier 15 16 import ( 17 "bytes" 18 "math/rand" 19 "testing" 20 21 "github.com/stretchr/testify/require" 22 ) 23 24 func insertIntoList(l *skipList, keys ...[]byte) { 25 for _, k := range keys { 26 l.Insert(k, nil) 27 } 28 } 29 30 func TestInsertAndRemove(t *testing.T) { 31 t.Parallel() 32 list := newSpanList() 33 var keys [][]byte 34 for i := 0; i < 100000; i++ { 35 key := make([]byte, rand.Intn(128)+1) 36 rand.Read(key) 37 keys = append(keys, key) 38 list.Insert(key, nil) 39 } 40 41 // check all the keys are exist in list 42 for _, k := range keys { 43 a := list.Seek(k, make(seekResult, maxHeight)).Node().Key() 44 cmp := bytes.Compare(a, k) 45 require.Equal(t, 0, cmp) 46 } 47 checkList(t, list) 48 49 for i := 0; i < 10000; i++ { 50 indexToRemove := rand.Intn(10000) 51 seekRes := list.Seek(keys[indexToRemove], make(seekResult, maxHeight)) 52 if seekRes.Node().Next() == nil { 53 break 54 } 55 removedKey := seekRes.Node().Next().Key() 56 list.Remove(seekRes, seekRes.Node().Next()) 57 58 // check the node is already removed 59 a := list.Seek(removedKey, make(seekResult, maxHeight)).Node().Key() 60 cmp := bytes.Compare(a, removedKey) 61 require.LessOrEqual(t, cmp, 0) 62 } 63 checkList(t, list) 64 } 65 66 func checkList(t *testing.T, list *skipList) { 67 // check the order of the keys in list 68 var lastKey []byte 69 var nodeNum int 70 for node := list.First(); node != nil; node = node.Next() { 71 if len(lastKey) != 0 { 72 cmp := bytes.Compare(lastKey, node.Key()) 73 require.LessOrEqual(t, cmp, 0) 74 } 75 lastKey = node.Key() 76 nodeNum++ 77 } 78 79 // check all the pointers are valid 80 prevs := make([]*skipListNode, list.height) 81 for i := range prevs { 82 prevs[i] = list.head.nexts[i] 83 } 84 85 for node := list.First(); node != nil; node = node.Next() { 86 for i := 0; i < len(node.nexts); i++ { 87 require.Equal(t, node, prevs[i]) 88 prevs[i] = node.nexts[i] 89 } 90 } 91 } 92 93 func TestSeek(t *testing.T) { 94 t.Parallel() 95 key1 := []byte("15") 96 keyA := []byte("a5") 97 keyB := []byte("b5") 98 keyC := []byte("c5") 99 keyD := []byte("d5") 100 keyE := []byte("e5") 101 keyF := []byte("f5") 102 keyG := []byte("g5") 103 keyH := []byte("h5") 104 keyZ := []byte("z5") 105 106 list := newSpanList() 107 108 require.Nil(t, list.Seek(keyA, make(seekResult, maxHeight)).Node()) 109 110 // insert keyA to keyH 111 insertIntoList(list, keyC, keyF, keyE, keyH, keyG, keyD, keyA, keyB) 112 113 // Point to the first node, if seek key is smaller than the first key in list. 114 require.Nil(t, list.Seek(key1, make(seekResult, maxHeight)).Node().Key()) 115 116 // Point to the last node with key smaller than seek key. 117 require.Equal(t, keyH, list.Seek(keyH, make(seekResult, maxHeight)).Node().key) 118 119 // Point to itself. 120 require.Equal(t, keyG, list.Seek(keyG, make(seekResult, maxHeight)).Node().key) 121 122 // Ensure there is no problem to seek a larger key. 123 require.Equal(t, keyH, list.Seek(keyZ, make(seekResult, maxHeight)).Node().key) 124 125 require.Equal(t, keyA, list.Seek([]byte("b0"), make(seekResult, maxHeight)).Node().key) 126 require.Equal(t, keyB, list.Seek([]byte("c0"), make(seekResult, maxHeight)).Node().key) 127 require.Equal(t, keyC, list.Seek([]byte("d0"), make(seekResult, maxHeight)).Node().key) 128 require.Equal(t, keyD, list.Seek([]byte("e0"), make(seekResult, maxHeight)).Node().key) 129 require.Equal(t, keyE, list.Seek([]byte("f0"), make(seekResult, maxHeight)).Node().key) 130 require.Equal(t, keyF, list.Seek([]byte("g0"), make(seekResult, maxHeight)).Node().key) 131 require.Equal(t, keyG, list.Seek([]byte("h0"), make(seekResult, maxHeight)).Node().key) 132 require.Equal(t, keyH, list.Seek([]byte("i0"), make(seekResult, maxHeight)).Node().key) 133 require.Equal(t, "[a5] [b5] [c5] [d5] [e5] [f5] [g5] [h5] ", list.String()) 134 checkList(t, list) 135 136 // remove c5 137 seekRes := list.Seek([]byte("c0"), make(seekResult, maxHeight)) 138 list.Remove(seekRes, seekRes.Node().Next()) 139 require.Equal(t, keyB, list.Seek([]byte("c0"), make(seekResult, maxHeight)).Node().key) 140 require.Equal(t, keyB, list.Seek([]byte("d0"), make(seekResult, maxHeight)).Node().key) 141 require.Equal(t, keyD, list.Seek([]byte("e0"), make(seekResult, maxHeight)).Node().key) 142 require.Equal(t, "[a5] [b5] [d5] [e5] [f5] [g5] [h5] ", list.String()) 143 checkList(t, list) 144 145 // remove d5 146 list.Remove(seekRes, seekRes.Node().Next()) 147 require.Equal(t, keyB, list.Seek([]byte("d0"), make(seekResult, maxHeight)).Node().key) 148 require.Equal(t, keyB, list.Seek([]byte("e0"), make(seekResult, maxHeight)).Node().key) 149 require.Equal(t, keyE, list.Seek([]byte("f0"), make(seekResult, maxHeight)).Node().key) 150 require.Equal(t, "[a5] [b5] [e5] [f5] [g5] [h5] ", list.String()) 151 checkList(t, list) 152 153 // remove the first node 154 seekRes = list.Seek([]byte("10"), make(seekResult, maxHeight)) 155 list.Remove(seekRes, seekRes.Node().Next()) 156 require.Equal(t, "[b5] [e5] [f5] [g5] [h5] ", list.String()) 157 checkList(t, list) 158 }