Files
srdb/compaction_continuity_test.go
bourdon 4aade1cff1 前端:重构 Web UI 代码结构
- 添加 Import Map 支持 Lit 和本地模块的简洁导入
- 创建统一的 API 管理模块 (common/api.js)
- 重命名 styles/ 为 common/ 目录
- 修复分页时列选择被重置的问题
- 将 app.js 重命名为 main.js
- 所有导入路径使用 ~ 别名映射
2025-10-09 19:30:20 +08:00

277 lines
7.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package srdb
import (
"testing"
)
// TestPickL0MergeContinuity 测试 L0 合并任务的连续性
func TestPickL0MergeContinuity(t *testing.T) {
tmpDir := t.TempDir()
manifestDir := tmpDir
versionSet, err := NewVersionSet(manifestDir)
if err != nil {
t.Fatal(err)
}
defer versionSet.Close()
picker := NewPicker()
// 创建混合大小的文件:小-大-小-小
// 这是触发 bug 的场景
edit := NewVersionEdit()
// 文件1: 29MB (小文件)
edit.AddFile(&FileMetadata{
FileNumber: 1,
Level: 0,
FileSize: 29 * 1024 * 1024,
MinKey: 1,
MaxKey: 100,
RowCount: 100,
})
// 文件2: 36MB (大文件)
edit.AddFile(&FileMetadata{
FileNumber: 2,
Level: 0,
FileSize: 36 * 1024 * 1024,
MinKey: 101,
MaxKey: 200,
RowCount: 100,
})
// 文件3: 8MB (小文件)
edit.AddFile(&FileMetadata{
FileNumber: 3,
Level: 0,
FileSize: 8 * 1024 * 1024,
MinKey: 201,
MaxKey: 300,
RowCount: 100,
})
// 文件4: 15MB (小文件)
edit.AddFile(&FileMetadata{
FileNumber: 4,
Level: 0,
FileSize: 15 * 1024 * 1024,
MinKey: 301,
MaxKey: 400,
RowCount: 100,
})
edit.SetNextFileNumber(5)
err = versionSet.LogAndApply(edit)
if err != nil {
t.Fatal(err)
}
version := versionSet.GetCurrent()
// 测试 Stage 0: L0 合并任务
t.Log("=== 测试 Stage 0: L0 合并 ===")
tasks := picker.pickL0MergeTasks(version)
if len(tasks) == 0 {
t.Fatal("Expected L0 merge tasks")
}
t.Logf("找到 %d 个合并任务", len(tasks))
// 验证任务应该只有1个任务包含文件3和文件4
// 文件1是单个小文件不合并len > 1 才合并)
// 文件2是大文件跳过
// 文件3+文件4是连续的2个小文件应该合并
if len(tasks) != 1 {
t.Errorf("Expected 1 task, got %d", len(tasks))
for i, task := range tasks {
t.Logf("Task %d: %d files", i+1, len(task.InputFiles))
for _, f := range task.InputFiles {
t.Logf(" - File %d", f.FileNumber)
}
}
}
task1 := tasks[0]
if len(task1.InputFiles) != 2 {
t.Errorf("Task 1: expected 2 files, got %d", len(task1.InputFiles))
}
if task1.InputFiles[0].FileNumber != 3 || task1.InputFiles[1].FileNumber != 4 {
t.Errorf("Task 1: expected files 3,4, got %d,%d",
task1.InputFiles[0].FileNumber, task1.InputFiles[1].FileNumber)
}
t.Logf("✓ 合并任务: 文件3+文件4 (连续的2个小文件)")
t.Logf("✓ 文件1 (单个小文件) 不合并,留给升级阶段")
// 验证 seq 范围连续性
// 任务1: seq 201-400 (文件3+文件4)
// 文件1seq 1-100, 单个小文件)留给升级阶段
// 文件2seq 101-200, 大文件)留给 Stage 1
if task1.InputFiles[0].MinKey != 201 || task1.InputFiles[1].MaxKey != 400 {
t.Errorf("Task 1 seq range incorrect: [%d, %d]",
task1.InputFiles[0].MinKey, task1.InputFiles[1].MaxKey)
}
t.Logf("✓ Seq 范围正确任务1 [201-400]")
// 测试 Stage 1: L0 升级任务
t.Log("=== 测试 Stage 1: L0 升级 ===")
upgradeTasks := picker.pickL0UpgradeTasks(version)
if len(upgradeTasks) == 0 {
t.Fatal("Expected L0 upgrade tasks")
}
// 应该有1个任务以文件2大文件为中心搭配周围的小文件
// 文件2向左收集文件1向右收集文件3和文件4
// 总共文件1 (29MB) + 文件2 (36MB) + 文件3 (8MB) + 文件4 (15MB) = 88MB
if len(upgradeTasks) != 1 {
t.Errorf("Expected 1 upgrade task, got %d", len(upgradeTasks))
}
upgradeTask := upgradeTasks[0]
// 应该包含所有4个文件
if len(upgradeTask.InputFiles) != 4 {
t.Errorf("Upgrade task: expected 4 files, got %d", len(upgradeTask.InputFiles))
for i, f := range upgradeTask.InputFiles {
t.Logf(" File %d: %d", i+1, f.FileNumber)
}
}
// 验证文件顺序1, 2, 3, 4
expectedFiles := []int64{1, 2, 3, 4}
for i, expected := range expectedFiles {
if upgradeTask.InputFiles[i].FileNumber != expected {
t.Errorf("Upgrade task file %d: expected %d, got %d",
i, expected, upgradeTask.InputFiles[i].FileNumber)
}
}
if upgradeTask.OutputLevel != 1 {
t.Errorf("Upgrade task: expected OutputLevel 1, got %d", upgradeTask.OutputLevel)
}
t.Logf("✓ 升级任务: 文件1+文件2+文件3+文件4 (以大文件为中心,搭配周围小文件) → L1")
t.Log("=== 连续性测试通过 ===")
}
// TestPickL0UpgradeContinuity 测试 L0 升级任务的连续性
func TestPickL0UpgradeContinuity(t *testing.T) {
tmpDir := t.TempDir()
manifestDir := tmpDir
versionSet, err := NewVersionSet(manifestDir)
if err != nil {
t.Fatal(err)
}
defer versionSet.Close()
picker := NewPicker()
// 创建混合大小的文件:大-小-大-大
edit := NewVersionEdit()
// 文件1: 40MB (大文件)
edit.AddFile(&FileMetadata{
FileNumber: 1,
Level: 0,
FileSize: 40 * 1024 * 1024,
MinKey: 1,
MaxKey: 100,
RowCount: 100,
})
// 文件2: 20MB (小文件)
edit.AddFile(&FileMetadata{
FileNumber: 2,
Level: 0,
FileSize: 20 * 1024 * 1024,
MinKey: 101,
MaxKey: 200,
RowCount: 100,
})
// 文件3: 50MB (大文件)
edit.AddFile(&FileMetadata{
FileNumber: 3,
Level: 0,
FileSize: 50 * 1024 * 1024,
MinKey: 201,
MaxKey: 300,
RowCount: 100,
})
// 文件4: 45MB (大文件)
edit.AddFile(&FileMetadata{
FileNumber: 4,
Level: 0,
FileSize: 45 * 1024 * 1024,
MinKey: 301,
MaxKey: 400,
RowCount: 100,
})
edit.SetNextFileNumber(5)
err = versionSet.LogAndApply(edit)
if err != nil {
t.Fatal(err)
}
version := versionSet.GetCurrent()
// 测试 L0 升级任务
t.Log("=== 测试 L0 升级任务连续性 ===")
tasks := picker.pickL0UpgradeTasks(version)
if len(tasks) == 0 {
t.Fatal("Expected L0 upgrade tasks")
}
t.Logf("找到 %d 个升级任务", len(tasks))
// 验证任务1应该包含所有4个文件以大文件为锚点搭配周围文件
// 文件1大文件作为锚点 → 向左无文件 → 向右收集文件2+文件3+文件4
// 总大小40+20+50+45 = 155MB < 256MB符合 L1 限制
task1 := tasks[0]
expectedFileCount := 4
if len(task1.InputFiles) != expectedFileCount {
t.Errorf("Task 1: expected %d files, got %d", expectedFileCount, len(task1.InputFiles))
for i, f := range task1.InputFiles {
t.Logf(" File %d: %d", i+1, f.FileNumber)
}
}
// 验证文件顺序1, 2, 3, 4
expectedFiles := []int64{1, 2, 3, 4}
for i, expected := range expectedFiles {
if i >= len(task1.InputFiles) {
break
}
if task1.InputFiles[i].FileNumber != expected {
t.Errorf("Task 1 file %d: expected %d, got %d",
i, expected, task1.InputFiles[i].FileNumber)
}
}
t.Logf("✓ Task 1: 文件1+文件2+文件3+文件4 (以大文件为锚点搭配周围文件总155MB < 256MB)")
// 只应该有1个任务所有文件都被收集了
if len(tasks) != 1 {
t.Errorf("Expected 1 task (all files collected), got %d", len(tasks))
for i, task := range tasks {
t.Logf("Task %d: %d files", i+1, len(task.InputFiles))
for _, f := range task.InputFiles {
t.Logf(" - File %d", f.FileNumber)
}
}
}
// 验证所有任务的 OutputLevel 都是 1
for i, task := range tasks {
if task.OutputLevel != 1 {
t.Errorf("Task %d: expected OutputLevel 1, got %d", i+1, task.OutputLevel)
}
}
t.Logf("✓ 所有任务都升级到 L1")
t.Log("=== 升级任务连续性测试通过 ===")
}