github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/storage/stores/series/index/table_manager_test.go (about) 1 package index 2 3 import ( 4 "context" 5 "sync" 6 "testing" 7 "time" 8 9 "github.com/prometheus/common/model" 10 "github.com/stretchr/testify/require" 11 "github.com/weaveworks/common/mtime" 12 13 "github.com/grafana/loki/pkg/storage/config" 14 ) 15 16 const ( 17 baseTableName = "cortex_base" 18 tablePrefix = "cortex_" 19 table2Prefix = "cortex2_" 20 chunkTablePrefix = "chunks_" 21 chunkTable2Prefix = "chunks2_" 22 tableRetention = 2 * 7 * 24 * time.Hour 23 tablePeriod = 7 * 24 * time.Hour 24 gracePeriod = 15 * time.Minute 25 maxChunkAge = 12 * time.Hour 26 inactiveWrite = 1 27 inactiveRead = 2 28 write = 200 29 read = 100 30 autoScaleLastN = 2 31 autoScaleMin = 50 32 autoScaleMax = 500 33 autoScaleTarget = 80 34 ) 35 36 var ( 37 baseTableStart = time.Unix(0, 0) 38 weeklyTableStart = baseTableStart.Add(tablePeriod * 3) 39 weeklyTable2Start = baseTableStart.Add(tablePeriod * 5) 40 week1Suffix = "3" 41 week2Suffix = "4" 42 ) 43 44 type mockTableClient struct { 45 sync.Mutex 46 tables map[string]config.TableDesc 47 } 48 49 func newMockTableClient() *mockTableClient { 50 return &mockTableClient{ 51 tables: map[string]config.TableDesc{}, 52 } 53 } 54 55 func (m *mockTableClient) ListTables(_ context.Context) ([]string, error) { 56 m.Lock() 57 defer m.Unlock() 58 59 result := []string{} 60 for name := range m.tables { 61 result = append(result, name) 62 } 63 return result, nil 64 } 65 66 func (m *mockTableClient) CreateTable(_ context.Context, desc config.TableDesc) error { 67 m.Lock() 68 defer m.Unlock() 69 70 m.tables[desc.Name] = desc 71 return nil 72 } 73 74 func (m *mockTableClient) DeleteTable(_ context.Context, name string) error { 75 m.Lock() 76 defer m.Unlock() 77 78 delete(m.tables, name) 79 return nil 80 } 81 82 func (m *mockTableClient) DescribeTable(_ context.Context, name string) (desc config.TableDesc, isActive bool, err error) { 83 m.Lock() 84 defer m.Unlock() 85 86 return m.tables[name], true, nil 87 } 88 89 func (m *mockTableClient) UpdateTable(_ context.Context, current, expected config.TableDesc) error { 90 m.Lock() 91 defer m.Unlock() 92 93 m.tables[current.Name] = expected 94 return nil 95 } 96 97 func (*mockTableClient) Stop() {} 98 99 // nolint 100 func tmTest(t *testing.T, client *mockTableClient, tableManager *TableManager, name string, tm time.Time, expected []config.TableDesc) { 101 t.Run(name, func(t *testing.T) { 102 ctx := context.Background() 103 mtime.NowForce(tm) 104 defer mtime.NowReset() 105 if err := tableManager.SyncTables(ctx); err != nil { 106 t.Fatal(err) 107 } 108 err := ExpectTables(ctx, client, expected) 109 require.NoError(t, err) 110 }) 111 } 112 113 var activeScalingConfig = config.AutoScalingConfig{ 114 Enabled: true, 115 MinCapacity: autoScaleMin * 2, 116 MaxCapacity: autoScaleMax * 2, 117 TargetValue: autoScaleTarget, 118 } 119 120 var inactiveScalingConfig = config.AutoScalingConfig{ 121 Enabled: true, 122 MinCapacity: autoScaleMin, 123 MaxCapacity: autoScaleMax, 124 TargetValue: autoScaleTarget, 125 } 126 127 func TestTableManager(t *testing.T) { 128 client := newMockTableClient() 129 130 cfg := config.SchemaConfig{ 131 Configs: []config.PeriodConfig{ 132 { 133 From: config.DayTime{Time: model.TimeFromUnix(baseTableStart.Unix())}, 134 IndexTables: config.PeriodicTableConfig{ 135 Prefix: baseTableName, 136 }, 137 }, 138 { 139 From: config.DayTime{Time: model.TimeFromUnix(weeklyTableStart.Unix())}, 140 IndexTables: config.PeriodicTableConfig{ 141 Prefix: tablePrefix, 142 Period: tablePeriod, 143 }, 144 145 ChunkTables: config.PeriodicTableConfig{ 146 Prefix: chunkTablePrefix, 147 Period: tablePeriod, 148 }, 149 }, 150 { 151 From: config.DayTime{Time: model.TimeFromUnix(weeklyTable2Start.Unix())}, 152 IndexTables: config.PeriodicTableConfig{ 153 Prefix: table2Prefix, 154 Period: tablePeriod, 155 }, 156 157 ChunkTables: config.PeriodicTableConfig{ 158 Prefix: chunkTable2Prefix, 159 Period: tablePeriod, 160 }, 161 }, 162 }, 163 } 164 tbmConfig := TableManagerConfig{ 165 CreationGracePeriod: gracePeriod, 166 IndexTables: config.ProvisionConfig{ 167 ActiveTableProvisionConfig: config.ActiveTableProvisionConfig{ 168 ProvisionedWriteThroughput: write, 169 ProvisionedReadThroughput: read, 170 WriteScale: activeScalingConfig, 171 }, 172 InactiveTableProvisionConfig: config.InactiveTableProvisionConfig{ 173 InactiveWriteThroughput: inactiveWrite, 174 InactiveReadThroughput: inactiveRead, 175 InactiveWriteScale: inactiveScalingConfig, 176 InactiveWriteScaleLastN: autoScaleLastN, 177 }, 178 }, 179 ChunkTables: config.ProvisionConfig{ 180 ActiveTableProvisionConfig: config.ActiveTableProvisionConfig{ 181 ProvisionedWriteThroughput: write, 182 ProvisionedReadThroughput: read, 183 }, 184 InactiveTableProvisionConfig: config.InactiveTableProvisionConfig{ 185 InactiveWriteThroughput: inactiveWrite, 186 InactiveReadThroughput: inactiveRead, 187 }, 188 }, 189 } 190 tableManager, err := NewTableManager(tbmConfig, cfg, maxChunkAge, client, nil, nil, nil) 191 if err != nil { 192 t.Fatal(err) 193 } 194 195 // Check at time zero, we have the base table only 196 tmTest(t, client, tableManager, 197 "Initial test", 198 baseTableStart, 199 []config.TableDesc{ 200 {Name: baseTableName, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 201 }, 202 ) 203 204 // Check at start of weekly tables, we have the base table and one weekly table 205 tmTest(t, client, tableManager, 206 "Initial test weekly", 207 weeklyTableStart, 208 []config.TableDesc{ 209 {Name: baseTableName, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 210 {Name: tablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 211 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 212 }, 213 ) 214 215 // Check running twice doesn't change anything 216 tmTest(t, client, tableManager, 217 "Nothing changed", 218 weeklyTableStart, 219 []config.TableDesc{ 220 {Name: baseTableName, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 221 {Name: tablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 222 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 223 }, 224 ) 225 226 // Fast forward grace period, check we still have write throughput on base table 227 tmTest(t, client, tableManager, 228 "Move forward by grace period", 229 weeklyTableStart.Add(gracePeriod), 230 []config.TableDesc{ 231 {Name: baseTableName, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 232 {Name: tablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 233 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 234 }, 235 ) 236 237 // Fast forward max chunk age + grace period, check write throughput on base table has gone 238 // (and we don't put inactive auto-scaling on base table) 239 tmTest(t, client, tableManager, 240 "Move forward by max chunk age + grace period", 241 weeklyTableStart.Add(maxChunkAge).Add(gracePeriod), 242 []config.TableDesc{ 243 {Name: baseTableName, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 244 {Name: tablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 245 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 246 }, 247 ) 248 249 // Fast forward table period - grace period, check we add another weekly table 250 tmTest(t, client, tableManager, 251 "Move forward by table period - grace period", 252 weeklyTableStart.Add(tablePeriod).Add(-gracePeriod+time.Second), 253 []config.TableDesc{ 254 {Name: baseTableName, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 255 {Name: tablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 256 {Name: tablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 257 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 258 {Name: chunkTablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 259 }, 260 ) 261 262 // Fast forward table period + grace period, check we still have provisioned throughput 263 tmTest(t, client, tableManager, 264 "Move forward by table period + grace period", 265 weeklyTableStart.Add(tablePeriod).Add(gracePeriod), 266 []config.TableDesc{ 267 {Name: baseTableName, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 268 {Name: tablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 269 {Name: tablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 270 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 271 {Name: chunkTablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 272 }, 273 ) 274 275 // Fast forward table period + max chunk age + grace period, check we remove provisioned throughput 276 tmTest(t, client, tableManager, 277 "Move forward by table period + max chunk age + grace period", 278 weeklyTableStart.Add(tablePeriod).Add(maxChunkAge).Add(gracePeriod), 279 []config.TableDesc{ 280 {Name: baseTableName, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 281 {Name: tablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 282 {Name: tablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 283 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 284 {Name: chunkTablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 285 }, 286 ) 287 288 // Check running twice doesn't change anything 289 tmTest(t, client, tableManager, 290 "Nothing changed", 291 weeklyTableStart.Add(tablePeriod).Add(maxChunkAge).Add(gracePeriod), 292 []config.TableDesc{ 293 {Name: baseTableName, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 294 {Name: tablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 295 {Name: tablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 296 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 297 {Name: chunkTablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 298 }, 299 ) 300 301 // Move ahead where we are short by just grace period before hitting next section 302 tmTest(t, client, tableManager, 303 "Move ahead where we are short by just grace period before hitting next section", 304 weeklyTable2Start.Add(-gracePeriod+time.Second), 305 []config.TableDesc{ 306 {Name: baseTableName, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 307 {Name: tablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 308 {Name: tablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 309 {Name: table2Prefix + "5", ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 310 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 311 {Name: chunkTablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 312 {Name: chunkTable2Prefix + "5", ProvisionedRead: read, ProvisionedWrite: write}, 313 }, 314 ) 315 316 // Move to the next section of the config 317 tmTest(t, client, tableManager, 318 "Move forward to next section of schema config", 319 weeklyTable2Start, 320 []config.TableDesc{ 321 {Name: baseTableName, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 322 {Name: tablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 323 {Name: tablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 324 {Name: table2Prefix + "5", ProvisionedRead: read, ProvisionedWrite: write, WriteScale: activeScalingConfig}, 325 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 326 {Name: chunkTablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 327 {Name: chunkTable2Prefix + "5", ProvisionedRead: read, ProvisionedWrite: write}, 328 }, 329 ) 330 } 331 332 func TestTableManagerAutoscaleInactiveOnly(t *testing.T) { 333 client := newMockTableClient() 334 335 cfg := config.SchemaConfig{ 336 Configs: []config.PeriodConfig{ 337 { 338 From: config.DayTime{Time: model.TimeFromUnix(baseTableStart.Unix())}, 339 IndexTables: config.PeriodicTableConfig{ 340 Prefix: baseTableName, 341 }, 342 }, 343 { 344 From: config.DayTime{Time: model.TimeFromUnix(weeklyTableStart.Unix())}, 345 IndexTables: config.PeriodicTableConfig{ 346 Prefix: tablePrefix, 347 Period: tablePeriod, 348 }, 349 350 ChunkTables: config.PeriodicTableConfig{ 351 Prefix: chunkTablePrefix, 352 Period: tablePeriod, 353 }, 354 }, 355 }, 356 } 357 tbmConfig := TableManagerConfig{ 358 CreationGracePeriod: gracePeriod, 359 IndexTables: config.ProvisionConfig{ 360 ActiveTableProvisionConfig: config.ActiveTableProvisionConfig{ 361 ProvisionedWriteThroughput: write, 362 ProvisionedReadThroughput: read, 363 }, 364 InactiveTableProvisionConfig: config.InactiveTableProvisionConfig{ 365 InactiveWriteThroughput: inactiveWrite, 366 InactiveReadThroughput: inactiveRead, 367 InactiveWriteScale: inactiveScalingConfig, 368 InactiveWriteScaleLastN: autoScaleLastN, 369 }, 370 }, 371 ChunkTables: config.ProvisionConfig{ 372 ActiveTableProvisionConfig: config.ActiveTableProvisionConfig{ 373 ProvisionedWriteThroughput: write, 374 ProvisionedReadThroughput: read, 375 }, 376 InactiveTableProvisionConfig: config.InactiveTableProvisionConfig{ 377 InactiveWriteThroughput: inactiveWrite, 378 InactiveReadThroughput: inactiveRead, 379 }, 380 }, 381 } 382 tableManager, err := NewTableManager(tbmConfig, cfg, maxChunkAge, client, nil, nil, nil) 383 if err != nil { 384 t.Fatal(err) 385 } 386 387 // Check at time zero, we have the base table and one weekly table 388 tmTest(t, client, tableManager, 389 "Initial test", 390 weeklyTableStart, 391 []config.TableDesc{ 392 {Name: baseTableName, ProvisionedRead: read, ProvisionedWrite: write}, 393 {Name: tablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 394 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 395 }, 396 ) 397 398 // Fast forward table period + grace period, check we still have provisioned throughput 399 tmTest(t, client, tableManager, 400 "Move forward by table period + grace period", 401 weeklyTableStart.Add(tablePeriod).Add(gracePeriod), 402 []config.TableDesc{ 403 {Name: baseTableName, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 404 {Name: tablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 405 {Name: tablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 406 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 407 {Name: chunkTablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 408 }, 409 ) 410 411 // Fast forward table period + max chunk age + grace period, check we remove provisioned throughput 412 413 tmTest(t, client, tableManager, 414 "Move forward by table period + max chunk age + grace period", 415 weeklyTableStart.Add(tablePeriod).Add(maxChunkAge).Add(gracePeriod), 416 []config.TableDesc{ 417 {Name: baseTableName, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 418 {Name: tablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 419 {Name: tablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 420 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 421 {Name: chunkTablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 422 }, 423 ) 424 } 425 426 func TestTableManagerDynamicIOModeInactiveOnly(t *testing.T) { 427 client := newMockTableClient() 428 429 cfg := config.SchemaConfig{ 430 Configs: []config.PeriodConfig{ 431 { 432 From: config.DayTime{Time: model.TimeFromUnix(baseTableStart.Unix())}, 433 IndexTables: config.PeriodicTableConfig{ 434 Prefix: baseTableName, 435 }, 436 }, 437 { 438 From: config.DayTime{Time: model.TimeFromUnix(weeklyTableStart.Unix())}, 439 IndexTables: config.PeriodicTableConfig{ 440 Prefix: tablePrefix, 441 Period: tablePeriod, 442 }, 443 444 ChunkTables: config.PeriodicTableConfig{ 445 Prefix: chunkTablePrefix, 446 Period: tablePeriod, 447 }, 448 }, 449 }, 450 } 451 tbmConfig := TableManagerConfig{ 452 CreationGracePeriod: gracePeriod, 453 IndexTables: config.ProvisionConfig{ 454 ActiveTableProvisionConfig: config.ActiveTableProvisionConfig{ 455 ProvisionedWriteThroughput: write, 456 ProvisionedReadThroughput: read, 457 }, 458 InactiveTableProvisionConfig: config.InactiveTableProvisionConfig{ 459 InactiveWriteThroughput: inactiveWrite, 460 InactiveReadThroughput: inactiveRead, 461 InactiveWriteScale: inactiveScalingConfig, 462 InactiveThroughputOnDemandMode: true, 463 InactiveWriteScaleLastN: 1, 464 }, 465 }, 466 ChunkTables: config.ProvisionConfig{ 467 ActiveTableProvisionConfig: config.ActiveTableProvisionConfig{ 468 ProvisionedWriteThroughput: write, 469 ProvisionedReadThroughput: read, 470 }, 471 InactiveTableProvisionConfig: config.InactiveTableProvisionConfig{ 472 InactiveWriteThroughput: inactiveWrite, 473 InactiveReadThroughput: inactiveRead, 474 InactiveThroughputOnDemandMode: true, 475 }, 476 }, 477 } 478 tableManager, err := NewTableManager(tbmConfig, cfg, maxChunkAge, client, nil, nil, nil) 479 if err != nil { 480 t.Fatal(err) 481 } 482 483 // Check at time zero, we have the base table and one weekly table 484 tmTest(t, client, tableManager, 485 "Initial test", 486 weeklyTableStart, 487 []config.TableDesc{ 488 {Name: baseTableName, ProvisionedRead: read, ProvisionedWrite: write}, 489 {Name: tablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 490 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 491 }, 492 ) 493 494 // Fast forward table period + grace period, check we still have provisioned throughput 495 tmTest(t, client, tableManager, 496 "Move forward by table period + grace period", 497 weeklyTableStart.Add(tablePeriod).Add(gracePeriod), 498 []config.TableDesc{ 499 {Name: baseTableName, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, UseOnDemandIOMode: true}, 500 {Name: tablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 501 {Name: tablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 502 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 503 {Name: chunkTablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 504 }, 505 ) 506 507 // Fast forward table period + max chunk age + grace period, check we remove provisioned throughput 508 // Week 1 index table will not have dynamic mode enabled, since it has an active autoscale config for 509 // a managed provisioning mode. However the week 1 chunk table will flip to the DynamicIO mode. 510 tmTest(t, client, tableManager, 511 "Move forward by table period + max chunk age + grace period", 512 weeklyTableStart.Add(tablePeriod).Add(maxChunkAge).Add(gracePeriod), 513 []config.TableDesc{ 514 {Name: baseTableName, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, UseOnDemandIOMode: true}, 515 {Name: tablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig, UseOnDemandIOMode: false}, 516 {Name: tablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 517 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, UseOnDemandIOMode: true}, 518 {Name: chunkTablePrefix + week2Suffix, ProvisionedRead: read, ProvisionedWrite: write}, 519 }, 520 ) 521 522 // fast forward to another table period. Now week 1's dynamic mode will flip to true, as the managed autoscaling config is no longer active 523 tmTest(t, client, tableManager, 524 "Move forward by table period + max chunk age + grace period", 525 weeklyTableStart.Add(tablePeriod*2).Add(maxChunkAge).Add(gracePeriod), 526 []config.TableDesc{ 527 {Name: baseTableName, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, UseOnDemandIOMode: true}, 528 {Name: tablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, UseOnDemandIOMode: true}, 529 {Name: tablePrefix + week2Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig, UseOnDemandIOMode: false}, 530 {Name: tablePrefix + "5", ProvisionedRead: read, ProvisionedWrite: write}, 531 {Name: chunkTablePrefix + week1Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, UseOnDemandIOMode: true}, 532 {Name: chunkTablePrefix + week2Suffix, ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, UseOnDemandIOMode: true}, 533 {Name: chunkTablePrefix + "5", ProvisionedRead: read, ProvisionedWrite: write}, 534 }, 535 ) 536 } 537 538 func TestTableManagerTags(t *testing.T) { 539 client := newMockTableClient() 540 541 test := func(tableManager *TableManager, name string, tm time.Time, expected []config.TableDesc) { 542 t.Run(name, func(t *testing.T) { 543 ctx := context.Background() 544 mtime.NowForce(tm) 545 defer mtime.NowReset() 546 if err := tableManager.SyncTables(ctx); err != nil { 547 t.Fatal(err) 548 } 549 err := ExpectTables(ctx, client, expected) 550 require.NoError(t, err) 551 }) 552 } 553 554 // Check at time zero, we have the base table with no tags. 555 { 556 cfg := config.SchemaConfig{ 557 Configs: []config.PeriodConfig{{ 558 IndexTables: config.PeriodicTableConfig{}, 559 }}, 560 } 561 tableManager, err := NewTableManager(TableManagerConfig{}, cfg, maxChunkAge, client, nil, nil, nil) 562 if err != nil { 563 t.Fatal(err) 564 } 565 566 test( 567 tableManager, 568 "Initial test", 569 baseTableStart, 570 []config.TableDesc{ 571 {Name: ""}, 572 }, 573 ) 574 } 575 576 // Check after restarting table manager we get some tags. 577 { 578 cfg := config.SchemaConfig{ 579 Configs: []config.PeriodConfig{{ 580 IndexTables: config.PeriodicTableConfig{ 581 Tags: config.Tags{"foo": "bar"}, 582 }, 583 }}, 584 } 585 tableManager, err := NewTableManager(TableManagerConfig{}, cfg, maxChunkAge, client, nil, nil, nil) 586 if err != nil { 587 t.Fatal(err) 588 } 589 590 test( 591 tableManager, 592 "Tagged test", 593 baseTableStart, 594 []config.TableDesc{ 595 {Name: "", Tags: config.Tags{"foo": "bar"}}, 596 }, 597 ) 598 } 599 } 600 601 func TestTableManagerRetentionOnly(t *testing.T) { 602 client := newMockTableClient() 603 604 cfg := config.SchemaConfig{ 605 Configs: []config.PeriodConfig{ 606 { 607 From: config.DayTime{Time: model.TimeFromUnix(baseTableStart.Unix())}, 608 IndexTables: config.PeriodicTableConfig{ 609 Prefix: tablePrefix, 610 Period: tablePeriod, 611 }, 612 613 ChunkTables: config.PeriodicTableConfig{ 614 Prefix: chunkTablePrefix, 615 Period: tablePeriod, 616 }, 617 }, 618 }, 619 } 620 tbmConfig := TableManagerConfig{ 621 RetentionPeriod: tableRetention, 622 RetentionDeletesEnabled: true, 623 CreationGracePeriod: gracePeriod, 624 IndexTables: config.ProvisionConfig{ 625 ActiveTableProvisionConfig: config.ActiveTableProvisionConfig{ 626 ProvisionedWriteThroughput: write, 627 ProvisionedReadThroughput: read, 628 }, 629 InactiveTableProvisionConfig: config.InactiveTableProvisionConfig{ 630 InactiveWriteThroughput: inactiveWrite, 631 InactiveReadThroughput: inactiveRead, 632 InactiveWriteScale: inactiveScalingConfig, 633 InactiveWriteScaleLastN: autoScaleLastN, 634 }, 635 }, 636 ChunkTables: config.ProvisionConfig{ 637 ActiveTableProvisionConfig: config.ActiveTableProvisionConfig{ 638 ProvisionedWriteThroughput: write, 639 ProvisionedReadThroughput: read, 640 }, 641 InactiveTableProvisionConfig: config.InactiveTableProvisionConfig{ 642 InactiveWriteThroughput: inactiveWrite, 643 InactiveReadThroughput: inactiveRead, 644 }, 645 }, 646 } 647 tableManager, err := NewTableManager(tbmConfig, cfg, maxChunkAge, client, nil, nil, nil) 648 if err != nil { 649 t.Fatal(err) 650 } 651 652 // Check at time zero, we have one weekly table 653 tmTest(t, client, tableManager, 654 "Initial test", 655 baseTableStart, 656 []config.TableDesc{ 657 {Name: tablePrefix + "0", ProvisionedRead: read, ProvisionedWrite: write}, 658 {Name: chunkTablePrefix + "0", ProvisionedRead: read, ProvisionedWrite: write}, 659 }, 660 ) 661 662 // Check after one week, we have two weekly tables 663 tmTest(t, client, tableManager, 664 "Move forward by one table period", 665 baseTableStart.Add(tablePeriod), 666 []config.TableDesc{ 667 {Name: tablePrefix + "0", ProvisionedRead: read, ProvisionedWrite: write}, 668 {Name: tablePrefix + "1", ProvisionedRead: read, ProvisionedWrite: write}, 669 {Name: chunkTablePrefix + "0", ProvisionedRead: read, ProvisionedWrite: write}, 670 {Name: chunkTablePrefix + "1", ProvisionedRead: read, ProvisionedWrite: write}, 671 }, 672 ) 673 674 // Check after two weeks, we have three tables (two previous periods and the new one) 675 tmTest(t, client, tableManager, 676 "Move forward by two table periods", 677 baseTableStart.Add(tablePeriod*2), 678 []config.TableDesc{ 679 {Name: tablePrefix + "0", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 680 {Name: tablePrefix + "1", ProvisionedRead: read, ProvisionedWrite: write}, 681 {Name: tablePrefix + "2", ProvisionedRead: read, ProvisionedWrite: write}, 682 {Name: chunkTablePrefix + "0", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 683 {Name: chunkTablePrefix + "1", ProvisionedRead: read, ProvisionedWrite: write}, 684 {Name: chunkTablePrefix + "2", ProvisionedRead: read, ProvisionedWrite: write}, 685 }, 686 ) 687 688 // Check after three weeks, we have three tables (two previous periods and the new one), table 0 was deleted 689 tmTest(t, client, tableManager, 690 "Move forward by three table periods", 691 baseTableStart.Add(tablePeriod*3), 692 []config.TableDesc{ 693 {Name: tablePrefix + "1", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 694 {Name: tablePrefix + "2", ProvisionedRead: read, ProvisionedWrite: write}, 695 {Name: tablePrefix + "3", ProvisionedRead: read, ProvisionedWrite: write}, 696 {Name: chunkTablePrefix + "1", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 697 {Name: chunkTablePrefix + "2", ProvisionedRead: read, ProvisionedWrite: write}, 698 {Name: chunkTablePrefix + "3", ProvisionedRead: read, ProvisionedWrite: write}, 699 }, 700 ) 701 702 // Check after three weeks and a day short by grace period, we have three tables (two previous periods and the new one), table 0 was deleted 703 tmTest(t, client, tableManager, 704 "Move forward by three table periods and a day short by grace period", 705 baseTableStart.Add(tablePeriod*3+24*time.Hour-gracePeriod), 706 []config.TableDesc{ 707 {Name: tablePrefix + "1", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 708 {Name: tablePrefix + "2", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 709 {Name: tablePrefix + "3", ProvisionedRead: read, ProvisionedWrite: write}, 710 {Name: chunkTablePrefix + "1", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 711 {Name: chunkTablePrefix + "2", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 712 {Name: chunkTablePrefix + "3", ProvisionedRead: read, ProvisionedWrite: write}, 713 }, 714 ) 715 716 // Verify that without RetentionDeletesEnabled no tables are removed 717 tableManager.cfg.RetentionDeletesEnabled = false 718 // Retention > 0 will prevent older tables from being created so we need to create the old tables manually for the test 719 err = client.CreateTable(context.Background(), config.TableDesc{Name: tablePrefix + "0", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}) 720 require.NoError(t, err) 721 722 err = client.CreateTable(context.Background(), config.TableDesc{Name: chunkTablePrefix + "0", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}) 723 require.NoError(t, err) 724 725 tmTest(t, client, tableManager, 726 "Move forward by three table periods (no deletes)", 727 baseTableStart.Add(tablePeriod*3), 728 []config.TableDesc{ 729 {Name: tablePrefix + "0", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 730 {Name: tablePrefix + "1", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 731 {Name: tablePrefix + "2", ProvisionedRead: read, ProvisionedWrite: write}, 732 {Name: tablePrefix + "3", ProvisionedRead: read, ProvisionedWrite: write}, 733 {Name: chunkTablePrefix + "0", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 734 {Name: chunkTablePrefix + "1", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 735 {Name: chunkTablePrefix + "2", ProvisionedRead: read, ProvisionedWrite: write}, 736 {Name: chunkTablePrefix + "3", ProvisionedRead: read, ProvisionedWrite: write}, 737 }, 738 ) 739 740 // Re-enable table deletions 741 tableManager.cfg.RetentionDeletesEnabled = true 742 743 // Verify that with a retention period of zero no tables outside the configs 'From' range are removed 744 tableManager.cfg.RetentionPeriod = 0 745 tableManager.schemaCfg.Configs[0].From = config.DayTime{Time: model.TimeFromUnix(baseTableStart.Add(tablePeriod).Unix())} 746 // Retention > 0 will prevent older tables from being created so we need to create the old tables manually for the test 747 err = client.CreateTable(context.Background(), config.TableDesc{Name: tablePrefix + "0", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}) 748 require.NoError(t, err) 749 750 err = client.CreateTable(context.Background(), config.TableDesc{Name: chunkTablePrefix + "0", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}) 751 require.NoError(t, err) 752 753 tmTest(t, client, tableManager, 754 "Move forward by three table periods (no deletes) and move From one table forward", 755 baseTableStart.Add(tablePeriod*3), 756 []config.TableDesc{ 757 {Name: tablePrefix + "0", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 758 {Name: tablePrefix + "1", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite, WriteScale: inactiveScalingConfig}, 759 {Name: tablePrefix + "2", ProvisionedRead: read, ProvisionedWrite: write}, 760 {Name: tablePrefix + "3", ProvisionedRead: read, ProvisionedWrite: write}, 761 {Name: chunkTablePrefix + "0", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 762 {Name: chunkTablePrefix + "1", ProvisionedRead: inactiveRead, ProvisionedWrite: inactiveWrite}, 763 {Name: chunkTablePrefix + "2", ProvisionedRead: read, ProvisionedWrite: write}, 764 {Name: chunkTablePrefix + "3", ProvisionedRead: read, ProvisionedWrite: write}, 765 }, 766 ) 767 768 // Test table manager retention not multiple of periodic config 769 tbmConfig.RetentionPeriod++ 770 _, err = NewTableManager(tbmConfig, cfg, maxChunkAge, client, nil, nil, nil) 771 require.Error(t, err) 772 }