github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/log_test.go (about) 1 // Copyright 2016 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 kvserver_test 12 13 import ( 14 "context" 15 gosql "database/sql" 16 "encoding/json" 17 "net/url" 18 "testing" 19 20 "github.com/cockroachdb/cockroach/pkg/base" 21 "github.com/cockroachdb/cockroach/pkg/keys" 22 "github.com/cockroachdb/cockroach/pkg/kv" 23 "github.com/cockroachdb/cockroach/pkg/kv/kvserver" 24 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverpb" 25 "github.com/cockroachdb/cockroach/pkg/roachpb" 26 "github.com/cockroachdb/cockroach/pkg/security" 27 "github.com/cockroachdb/cockroach/pkg/server" 28 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 29 "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils" 30 "github.com/cockroachdb/cockroach/pkg/util/hlc" 31 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 32 _ "github.com/lib/pq" 33 ) 34 35 func TestLogSplits(t *testing.T) { 36 defer leaktest.AfterTest(t)() 37 s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) 38 ts := s.(*server.TestServer) 39 ctx := context.Background() 40 defer s.Stopper().Stop(ctx) 41 42 countSplits := func() int { 43 var count int 44 err := db.QueryRowContext(ctx, 45 `SELECT count(*) FROM system.rangelog WHERE "eventType" = $1`, 46 kvserverpb.RangeLogEventType_split.String()).Scan(&count) 47 if err != nil { 48 t.Fatal(err) 49 } 50 return count 51 } 52 53 // Count the number of split events. 54 initialSplits := countSplits() 55 56 // Generate an explicit split event. 57 if err := kvDB.AdminSplit(ctx, "splitkey", "splitkey", hlc.MaxTimestamp /* expirationTime */); err != nil { 58 t.Fatal(err) 59 } 60 61 // Verify that the count has increased by at least one. Realistically it's 62 // almost always by exactly one, but if there are any other splits they 63 // might race in after the previous call to countSplits(). 64 if now := countSplits(); now <= initialSplits { 65 t.Fatalf("expected >= %d splits, found %d", initialSplits, now) 66 } 67 68 // verify that RangeID always increases (a good way to see that the splits 69 // are logged correctly) 70 rows, err := db.QueryContext(ctx, 71 `SELECT "rangeID", "otherRangeID", info FROM system.rangelog WHERE "eventType" = $1`, 72 kvserverpb.RangeLogEventType_split.String(), 73 ) 74 if err != nil { 75 t.Fatal(err) 76 } 77 for rows.Next() { 78 var rangeID int64 79 var otherRangeID gosql.NullInt64 80 var infoStr gosql.NullString 81 if err := rows.Scan(&rangeID, &otherRangeID, &infoStr); err != nil { 82 t.Fatal(err) 83 } 84 85 if !otherRangeID.Valid { 86 t.Errorf("otherRangeID not recorded for split of range %d", rangeID) 87 } 88 if otherRangeID.Int64 <= rangeID { 89 t.Errorf("otherRangeID %d is not greater than rangeID %d", otherRangeID.Int64, rangeID) 90 } 91 // Verify that info returns a json struct. 92 if !infoStr.Valid { 93 t.Errorf("info not recorded for split of range %d", rangeID) 94 } 95 var info kvserverpb.RangeLogEvent_Info 96 if err := json.Unmarshal([]byte(infoStr.String), &info); err != nil { 97 t.Errorf("error unmarshalling info string for split of range %d: %+v", rangeID, err) 98 continue 99 } 100 if int64(info.UpdatedDesc.RangeID) != rangeID { 101 t.Errorf("recorded wrong updated descriptor %s for split of range %d", info.UpdatedDesc, rangeID) 102 } 103 if int64(info.NewDesc.RangeID) != otherRangeID.Int64 { 104 t.Errorf("recorded wrong new descriptor %s for split of range %d", info.NewDesc, rangeID) 105 } 106 } 107 if rows.Err() != nil { 108 t.Fatal(rows.Err()) 109 } 110 111 store, pErr := ts.Stores().GetStore(ts.GetFirstStoreID()) 112 if pErr != nil { 113 t.Fatal(pErr) 114 } 115 minSplits := int64(initialSplits + 1) 116 // Verify that the minimum number of splits has occurred. This is a min 117 // instead of an exact number, because the number of splits seems to vary 118 // between different runs of this test. 119 if a := store.Metrics().RangeSplits.Count(); a < minSplits { 120 t.Errorf("splits = %d < min %d", a, minSplits) 121 } 122 123 { 124 // Verify that the uniqueIDs have non-zero node IDs. The "& 0x7fff" is 125 // using internal knowledge of the structure of uniqueIDs that the node ID 126 // is embedded in the lower 15 bits. See #17560. 127 var count int 128 err := db.QueryRowContext(ctx, 129 `SELECT count(*) FROM system.rangelog WHERE ("uniqueID" & 0x7fff) = 0`).Scan(&count) 130 if err != nil { 131 t.Fatal(err) 132 } 133 if count != 0 { 134 t.Fatalf("found %d uniqueIDs with a zero node ID", count) 135 } 136 } 137 } 138 139 func TestLogMerges(t *testing.T) { 140 defer leaktest.AfterTest(t)() 141 142 ctx := context.Background() 143 s, db, kvDB := serverutils.StartServer(t, base.TestServerArgs{ 144 Knobs: base.TestingKnobs{ 145 Store: &kvserver.StoreTestingKnobs{ 146 DisableMergeQueue: true, 147 }, 148 }, 149 }) 150 defer s.Stopper().Stop(ctx) 151 152 ts := s.(*server.TestServer) 153 store, pErr := ts.Stores().GetStore(ts.GetFirstStoreID()) 154 if pErr != nil { 155 t.Fatal(pErr) 156 } 157 158 countRangeLogMerges := func() int { 159 var count int 160 err := db.QueryRowContext(ctx, 161 `SELECT count(*) FROM system.rangelog WHERE "eventType" = $1`, 162 kvserverpb.RangeLogEventType_merge.String()).Scan(&count) 163 if err != nil { 164 t.Fatal(err) 165 } 166 return count 167 } 168 169 // No ranges should have merged immediately after startup. 170 if n := countRangeLogMerges(); n != 0 { 171 t.Fatalf("expected 0 initial merges, but got %d", n) 172 } 173 if n := store.Metrics().RangeMerges.Count(); n != 0 { 174 t.Errorf("expected 0 initial merges, but got %d", n) 175 } 176 177 // Create two ranges, then merge them. 178 if err := kvDB.AdminSplit(ctx, "a", "a", hlc.MaxTimestamp /* expirationTime */); err != nil { 179 t.Fatal(err) 180 } 181 if err := kvDB.AdminSplit(ctx, "b", "b", hlc.MaxTimestamp /* expirationTime */); err != nil { 182 t.Fatal(err) 183 } 184 if err := kvDB.AdminMerge(ctx, "a"); err != nil { 185 t.Fatal(err) 186 } 187 188 if n := countRangeLogMerges(); n != 1 { 189 t.Fatalf("expected 1 merge, but got %d", n) 190 } 191 if n := store.Metrics().RangeMerges.Count(); n != 1 { 192 t.Errorf("expected 1 merge, but got %d", n) 193 } 194 195 rows, err := db.QueryContext(ctx, 196 `SELECT "rangeID", "otherRangeID", info FROM system.rangelog WHERE "eventType" = $1`, 197 kvserverpb.RangeLogEventType_merge.String(), 198 ) 199 if err != nil { 200 t.Fatal(err) 201 } 202 for rows.Next() { 203 var rangeID int64 204 var otherRangeID gosql.NullInt64 205 var infoStr gosql.NullString 206 if err := rows.Scan(&rangeID, &otherRangeID, &infoStr); err != nil { 207 t.Fatal(err) 208 } 209 210 if !otherRangeID.Valid { 211 t.Errorf("otherRangeID not recorded for merge of range %d", rangeID) 212 } 213 if otherRangeID.Int64 <= rangeID { 214 t.Errorf("otherRangeID %d is not greater than rangeID %d", otherRangeID.Int64, rangeID) 215 } 216 if !infoStr.Valid { 217 t.Errorf("info not recorded for merge of range %d", rangeID) 218 } 219 var info kvserverpb.RangeLogEvent_Info 220 if err := json.Unmarshal([]byte(infoStr.String), &info); err != nil { 221 t.Errorf("error unmarshalling info string for merge of range %d: %+v", rangeID, err) 222 continue 223 } 224 if int64(info.UpdatedDesc.RangeID) != rangeID { 225 t.Errorf("recorded wrong updated descriptor %s for merge of range %d", info.UpdatedDesc, rangeID) 226 } 227 if int64(info.RemovedDesc.RangeID) != otherRangeID.Int64 { 228 t.Errorf("recorded wrong new descriptor %s for merge of range %d", info.RemovedDesc, rangeID) 229 } 230 } 231 if rows.Err() != nil { 232 t.Fatal(rows.Err()) 233 } 234 } 235 236 func TestLogRebalances(t *testing.T) { 237 defer leaktest.AfterTest(t)() 238 s, _, db := serverutils.StartServer(t, base.TestServerArgs{}) 239 ctx := context.Background() 240 defer s.Stopper().Stop(ctx) 241 242 // Use a client to get the RangeDescriptor for the first range. We will use 243 // this range's information to log fake rebalance events. 244 desc := &roachpb.RangeDescriptor{} 245 if err := db.GetProto(ctx, keys.RangeDescriptorKey(roachpb.RKeyMin), desc); err != nil { 246 t.Fatal(err) 247 } 248 249 // This code assumes that there is only one TestServer, and thus that 250 // StoreID 1 is present on the testserver. If this assumption changes in the 251 // future, *any* store will work, but a new method will need to be added to 252 // Stores (or a creative usage of VisitStores could suffice). 253 store, err := s.(*server.TestServer).Stores().GetStore(roachpb.StoreID(1)) 254 if err != nil { 255 t.Fatal(err) 256 } 257 258 // Log several fake events using the store. 259 const details = "test" 260 logEvent := func(changeType roachpb.ReplicaChangeType, reason kvserverpb.RangeLogEventReason) { 261 if err := db.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { 262 return store.LogReplicaChangeTest(ctx, txn, changeType, desc.InternalReplicas[0], *desc, reason, details) 263 }); err != nil { 264 t.Fatal(err) 265 } 266 } 267 checkMetrics := func(expAdds, expRemoves int64) { 268 if a, e := store.Metrics().RangeAdds.Count(), expAdds; a != e { 269 t.Errorf("range adds %d != expected %d", a, e) 270 } 271 if a, e := store.Metrics().RangeRemoves.Count(), expRemoves; a != e { 272 t.Errorf("range removes %d != expected %d", a, e) 273 } 274 } 275 logEvent(roachpb.ADD_REPLICA, kvserverpb.ReasonRangeUnderReplicated) 276 checkMetrics(1 /*add*/, 0 /*remove*/) 277 logEvent(roachpb.ADD_REPLICA, kvserverpb.ReasonRangeUnderReplicated) 278 checkMetrics(2 /*adds*/, 0 /*remove*/) 279 logEvent(roachpb.REMOVE_REPLICA, kvserverpb.ReasonRangeOverReplicated) 280 checkMetrics(2 /*adds*/, 1 /*remove*/) 281 282 // Open a SQL connection to verify that the events have been logged. 283 pgURL, cleanupFn := sqlutils.PGUrl(t, s.ServingSQLAddr(), "TestLogRebalances", url.User(security.RootUser)) 284 defer cleanupFn() 285 286 sqlDB, err := gosql.Open("postgres", pgURL.String()) 287 if err != nil { 288 t.Fatal(err) 289 } 290 defer sqlDB.Close() 291 292 // verify that two add replica events have been logged. 293 rows, err := sqlDB.QueryContext(ctx, 294 `SELECT "rangeID", info FROM system.rangelog WHERE "eventType" = $1`, 295 kvserverpb.RangeLogEventType_add.String(), 296 ) 297 if err != nil { 298 t.Fatal(err) 299 } 300 var count int 301 for rows.Next() { 302 count++ 303 var rangeID int64 304 var infoStr gosql.NullString 305 if err := rows.Scan(&rangeID, &infoStr); err != nil { 306 t.Fatal(err) 307 } 308 309 if a, e := roachpb.RangeID(rangeID), desc.RangeID; a != e { 310 t.Errorf("wrong rangeID %d recorded for add event, expected %d", a, e) 311 } 312 // Verify that info returns a json struct. 313 if !infoStr.Valid { 314 t.Errorf("info not recorded for add replica of range %d", rangeID) 315 } 316 var info kvserverpb.RangeLogEvent_Info 317 if err := json.Unmarshal([]byte(infoStr.String), &info); err != nil { 318 t.Errorf("error unmarshalling info string for add replica %d: %+v", rangeID, err) 319 continue 320 } 321 if int64(info.UpdatedDesc.RangeID) != rangeID { 322 t.Errorf("recorded wrong updated descriptor %s for add replica of range %d", info.UpdatedDesc, rangeID) 323 } 324 if a, e := *info.AddedReplica, desc.InternalReplicas[0]; a != e { 325 t.Errorf("recorded wrong updated replica %s for add replica of range %d, expected %s", 326 a, rangeID, e) 327 } 328 if a, e := info.Reason, kvserverpb.ReasonRangeUnderReplicated; a != e { 329 t.Errorf("recorded wrong reason %s for add replica of range %d, expected %s", 330 a, rangeID, e) 331 } 332 if a, e := info.Details, details; a != e { 333 t.Errorf("recorded wrong details %s for add replica of range %d, expected %s", 334 a, rangeID, e) 335 } 336 } 337 if rows.Err() != nil { 338 t.Fatal(rows.Err()) 339 } 340 if a, e := count, 2; a != e { 341 t.Errorf("expected %d AddReplica events logged, found %d", e, a) 342 } 343 344 // verify that one remove replica event was logged. 345 rows, err = sqlDB.QueryContext(ctx, 346 `SELECT "rangeID", info FROM system.rangelog WHERE "eventType" = $1`, 347 kvserverpb.RangeLogEventType_remove.String(), 348 ) 349 if err != nil { 350 t.Fatal(err) 351 } 352 count = 0 353 for rows.Next() { 354 count++ 355 var rangeID int64 356 var infoStr gosql.NullString 357 if err := rows.Scan(&rangeID, &infoStr); err != nil { 358 t.Fatal(err) 359 } 360 361 if a, e := roachpb.RangeID(rangeID), desc.RangeID; a != e { 362 t.Errorf("wrong rangeID %d recorded for remove event, expected %d", a, e) 363 } 364 // Verify that info returns a json struct. 365 if !infoStr.Valid { 366 t.Errorf("info not recorded for remove replica of range %d", rangeID) 367 } 368 var info kvserverpb.RangeLogEvent_Info 369 if err := json.Unmarshal([]byte(infoStr.String), &info); err != nil { 370 t.Errorf("error unmarshalling info string for remove replica %d: %+v", rangeID, err) 371 continue 372 } 373 if int64(info.UpdatedDesc.RangeID) != rangeID { 374 t.Errorf("recorded wrong updated descriptor %s for remove replica of range %d", info.UpdatedDesc, rangeID) 375 } 376 if a, e := *info.RemovedReplica, desc.InternalReplicas[0]; a != e { 377 t.Errorf("recorded wrong updated replica %s for remove replica of range %d, expected %s", 378 a, rangeID, e) 379 } 380 if a, e := info.Reason, kvserverpb.ReasonRangeOverReplicated; a != e { 381 t.Errorf("recorded wrong reason %s for add replica of range %d, expected %s", 382 a, rangeID, e) 383 } 384 if a, e := info.Details, details; a != e { 385 t.Errorf("recorded wrong details %s for add replica of range %d, expected %s", 386 a, rangeID, e) 387 } 388 } 389 if rows.Err() != nil { 390 t.Fatal(rows.Err()) 391 } 392 if a, e := count, 1; a != e { 393 t.Errorf("expected %d RemoveReplica events logged, found %d", e, a) 394 } 395 }