github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/closedts/minprop/doc_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 minprop 12 13 import ( 14 "context" 15 "fmt" 16 "sort" 17 "strings" 18 19 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/closedts/ctpb" 20 "github.com/cockroachdb/cockroach/pkg/roachpb" 21 "github.com/cockroachdb/cockroach/pkg/util/hlc" 22 ) 23 24 func Example() { 25 ctx := context.Background() 26 27 tracker := NewTracker() 28 const ep1 ctpb.Epoch = 1 29 fmt.Println("The newly initialized tracker has a zero closed timestamp:") 30 fmt.Println(tracker) 31 32 fmt.Println("A first command arrives on range 12 (though the range isn't known yet to the Tracker).") 33 ts, done1 := tracker.Track(ctx) 34 fmt.Println("All commands initially start out on the right. The command has its timestamp forwarded to", ts, ".") 35 fmt.Println(tracker) 36 37 fmt.Println("Two more commands arrive, on r1 and r12.") 38 _, done2 := tracker.Track(ctx) 39 _, done3 := tracker.Track(ctx) 40 fmt.Println(tracker) 41 42 fmt.Println("The command on r1 finishes evaluating at Lease Applied Index 10 and lets the Tracker know.") 43 done2(ctx, ep1, 1, 10) 44 fmt.Println(tracker) 45 46 fmt.Println("The command on r12 also finishes quickly, at LAI 77.") 47 done3(ctx, ep1, 12, 77) 48 fmt.Println(tracker) 49 50 fmt.Println("The system closes out a timestamp (registering 1000 as the next timestamp to close out).") 51 closed1, mlai1, _ := tracker.Close(hlc.Timestamp{WallTime: 1e9}, ep1) 52 fmt.Println("No problem: nothing is tracked on the left side; returns:", closed1, "and", mlaiString(mlai1)) 53 fmt.Println("Note how the items on the right have moved to the left, as they are relevant for the") 54 fmt.Println("next call to Close.") 55 fmt.Println(tracker) 56 57 fmt.Println("Nothing happens for a while until the system tries to close out the next timestamp.") 58 fmt.Println("However, the very first proposal is still tracked and blocks progress.") 59 closed2, mlai2, _ := tracker.Close(hlc.Timestamp{WallTime: 2e9}, ep1) 60 fmt.Println("The call returns a no-op in the form", closed2, mlaiString(mlai2), ".") 61 fmt.Println(tracker) 62 63 ts4, done4 := tracker.Track(ctx) 64 fmt.Println("A new command gets tracked on r12 (and is forwarded to", ts4, "(if necessary).") 65 fmt.Println("It terminates quickly, leaving an MLAI entry of 78 behind.") 66 done4(ctx, ep1, 12, 78) 67 fmt.Println(tracker) 68 69 fmt.Println("Finally! The slow evaluation finishes and the command gets proposed at index 79.") 70 fmt.Println("Note that the right now tracks a smaller value of 78. Consumers have to keep the") 71 fmt.Println("maximum they've seen.") 72 done1(ctx, ep1, 12, 79) 73 fmt.Println(tracker) 74 75 closed3, mlai3, _ := tracker.Close(hlc.Timestamp{WallTime: 3e9}, ep1) 76 fmt.Println("The next call to Close() is successful and returns:", closed3, "and", mlaiString(mlai3)) 77 fmt.Println(tracker) 78 79 // Output: 80 // The newly initialized tracker has a zero closed timestamp: 81 // 82 // closed=0,0 83 // | next=0,1 84 // | left | right 85 // | 0 # 0 86 // | 1 e 1 87 // v v 88 // ---------------------------------------------------------> time 89 // 90 // A first command arrives on range 12 (though the range isn't known yet to the Tracker). 91 // All commands initially start out on the right. The command has its timestamp forwarded to 0,2 . 92 // 93 // closed=0,0 94 // | next=0,1 95 // | left | right 96 // | 0 # 1 97 // | 1 e 1 98 // v v 99 // ---------------------------------------------------------> time 100 // 101 // Two more commands arrive, on r1 and r12. 102 // 103 // closed=0,0 104 // | next=0,1 105 // | left | right 106 // | 0 # 3 107 // | 1 e 1 108 // v v 109 // ---------------------------------------------------------> time 110 // 111 // The command on r1 finishes evaluating at Lease Applied Index 10 and lets the Tracker know. 112 // 113 // closed=0,0 114 // | next=0,1 115 // | left | right 116 // | 0 # 2 117 // | 1 e 1 118 // | @ 10 (r1) 119 // v v 120 // ---------------------------------------------------------> time 121 // 122 // The command on r12 also finishes quickly, at LAI 77. 123 // 124 // closed=0,0 125 // | next=0,1 126 // | left | right 127 // | 0 # 1 128 // | 1 e 1 129 // | @ 10 (r1) 130 // | @ 77 (r12) 131 // v v 132 // ---------------------------------------------------------> time 133 // 134 // The system closes out a timestamp (registering 1000 as the next timestamp to close out). 135 // No problem: nothing is tracked on the left side; returns: 0,1 and map[] 136 // Note how the items on the right have moved to the left, as they are relevant for the 137 // next call to Close. 138 // 139 // closed=0,1 140 // | next=1.000000000,0 141 // | left | right 142 // | 1 # 0 143 // | 1 e 1 144 // | 10 @ (r1) 145 // | 77 @ (r12) 146 // v v 147 // ---------------------------------------------------------> time 148 // 149 // Nothing happens for a while until the system tries to close out the next timestamp. 150 // However, the very first proposal is still tracked and blocks progress. 151 // The call returns a no-op in the form 0,1 map[] . 152 // 153 // closed=0,1 154 // | next=1.000000000,0 155 // | left | right 156 // | 1 # 0 157 // | 1 e 1 158 // | 10 @ (r1) 159 // | 77 @ (r12) 160 // v v 161 // ---------------------------------------------------------> time 162 // 163 // A new command gets tracked on r12 (and is forwarded to 1.000000000,1 (if necessary). 164 // It terminates quickly, leaving an MLAI entry of 78 behind. 165 // 166 // closed=0,1 167 // | next=1.000000000,0 168 // | left | right 169 // | 1 # 0 170 // | 1 e 1 171 // | 10 @ (r1) 172 // | 77 @ (r12) 173 // | @ 78 (r12) 174 // v v 175 // ---------------------------------------------------------> time 176 // 177 // Finally! The slow evaluation finishes and the command gets proposed at index 79. 178 // Note that the right now tracks a smaller value of 78. Consumers have to keep the 179 // maximum they've seen. 180 // 181 // closed=0,1 182 // | next=1.000000000,0 183 // | left | right 184 // | 0 # 0 185 // | 1 e 1 186 // | 10 @ (r1) 187 // | @ 78 (r12) 188 // | 79 @ (r12) 189 // v v 190 // ---------------------------------------------------------> time 191 // 192 // The next call to Close() is successful and returns: 1.000000000,0 and map[1:10 12:79] 193 // 194 // closed=1.000000000,0 195 // | next=3.000000000,0 196 // | left | right 197 // | 0 # 0 198 // | 1 e 1 199 // | 78 @ (r12) 200 // v v 201 // ---------------------------------------------------------> time 202 } 203 204 // mlaiString converts an mlai map into a string. Avoids randomized ordering of 205 // map elements in string output. 206 func mlaiString(mlai map[roachpb.RangeID]ctpb.LAI) string { 207 var rangeIDs []roachpb.RangeID 208 for rangeID := range mlai { 209 rangeIDs = append(rangeIDs, rangeID) 210 } 211 sort.Slice(rangeIDs, func(i, j int) bool { 212 return rangeIDs[i] < rangeIDs[j] 213 }) 214 215 var sb strings.Builder 216 sb.WriteString("map[") 217 for i, rangeID := range rangeIDs { 218 if i > 0 { 219 sb.WriteString(" ") 220 } 221 fmt.Fprintf(&sb, "%d:%d", rangeID, mlai[rangeID]) 222 } 223 sb.WriteString("]") 224 return sb.String() 225 }