2025-06-07 18:18:03 +08:00
|
|
|
package index
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestIndexStore(t *testing.T) {
|
|
|
|
// 测试目录
|
|
|
|
dir := "./testdb"
|
|
|
|
defer os.RemoveAll(dir)
|
|
|
|
|
|
|
|
// 初始化索引存储
|
|
|
|
is, err := NewIndexStore(dir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to create index store: %v", err)
|
|
|
|
}
|
|
|
|
defer is.storage.Close()
|
|
|
|
|
|
|
|
// 测试索引名称和字段
|
|
|
|
indexName := "test_index"
|
|
|
|
keyFields := []string{"name"}
|
|
|
|
|
2025-06-07 19:13:07 +08:00
|
|
|
// 测试创建索引(默认升序)
|
2025-06-07 22:28:29 +08:00
|
|
|
if err := is.CreateIndex(indexName, NonUnique, keyFields, []IndexSortOrder{Ascending}); err != nil {
|
2025-06-07 18:18:03 +08:00
|
|
|
t.Errorf("CreateIndex failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 验证元数据
|
|
|
|
metadata, err := is.GetIndexMetadata(indexName)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("GetIndexMetadata failed: %v", err)
|
|
|
|
}
|
|
|
|
|
2025-06-07 22:28:29 +08:00
|
|
|
if metadata.Name != indexName || metadata.Type != NonUnique {
|
2025-06-07 23:02:49 +08:00
|
|
|
t.Errorf("Metadata mismatch: got %+v want name=%s type=%d", metadata, indexName, NonUnique)
|
2025-06-07 18:18:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 测试删除索引
|
|
|
|
if err := is.DropIndex(indexName); err != nil {
|
|
|
|
t.Errorf("DropIndex failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 验证索引已被删除
|
|
|
|
_, err = is.GetIndexMetadata(indexName)
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("Expected error after DropIndex")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCompositeIndex(t *testing.T) {
|
|
|
|
// 测试目录
|
|
|
|
dir := "./testdb_composite"
|
|
|
|
defer os.RemoveAll(dir)
|
|
|
|
|
|
|
|
// 初始化索引存储
|
|
|
|
is, err := NewIndexStore(dir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to create index store: %v", err)
|
|
|
|
}
|
|
|
|
defer is.storage.Close()
|
|
|
|
|
|
|
|
// 测试复合索引
|
|
|
|
indexName := "composite_index"
|
|
|
|
keyFields := []string{"name", "age"}
|
|
|
|
|
2025-06-07 19:13:07 +08:00
|
|
|
// 创建复合索引(默认升序)
|
2025-06-07 22:28:29 +08:00
|
|
|
if err := is.CreateIndex(indexName, NonUnique, keyFields, []IndexSortOrder{Ascending, Ascending}); err != nil {
|
2025-06-07 19:13:07 +08:00
|
|
|
t.Errorf("CreateIndex failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 验证元数据
|
|
|
|
metadata, err := is.GetIndexMetadata(indexName)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("GetIndexMetadata failed: %v", err)
|
|
|
|
}
|
|
|
|
|
2025-06-07 22:28:29 +08:00
|
|
|
if metadata.Type != NonUnique || len(metadata.KeyFields) != 2 {
|
2025-06-07 23:02:49 +08:00
|
|
|
t.Errorf("Composite index metadata mismatch: got %+v want type=%d fieldsCount=2", metadata, NonUnique)
|
2025-06-07 19:13:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestIndexSortOrder(t *testing.T) {
|
|
|
|
// 测试目录
|
|
|
|
dir := "./testdb_sort"
|
|
|
|
defer os.RemoveAll(dir)
|
|
|
|
|
|
|
|
// 初始化索引存储
|
|
|
|
is, err := NewIndexStore(dir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to create index store: %v", err)
|
|
|
|
}
|
|
|
|
defer is.storage.Close()
|
|
|
|
|
|
|
|
// 测试单字段索引的排序
|
|
|
|
indexName := "sorted_index"
|
|
|
|
keyFields := []string{"timestamp"}
|
|
|
|
|
|
|
|
// 测试创建升序索引
|
2025-06-07 22:28:29 +08:00
|
|
|
if err := is.CreateIndex(indexName, NonUnique, keyFields, []IndexSortOrder{Ascending}); err != nil {
|
2025-06-07 19:13:07 +08:00
|
|
|
t.Errorf("CreateIndex failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 验证元数据
|
|
|
|
metadata, err := is.GetIndexMetadata(indexName)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("GetIndexMetadata failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(metadata.SortOrders) != 1 || metadata.SortOrders[0] != Ascending {
|
|
|
|
t.Errorf("Expected sort order to be ascending, got %v", metadata.SortOrders)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 测试创建降序索引
|
|
|
|
indexNameDesc := "sorted_index_desc"
|
2025-06-07 22:28:29 +08:00
|
|
|
if err := is.CreateIndex(indexNameDesc, NonUnique, keyFields, []IndexSortOrder{Descending}); err != nil {
|
2025-06-07 19:13:07 +08:00
|
|
|
t.Errorf("CreateIndex failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 验证降序元数据
|
|
|
|
metadataDesc, err := is.GetIndexMetadata(indexNameDesc)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("GetIndexMetadata failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(metadataDesc.SortOrders) != 1 || metadataDesc.SortOrders[0] != Descending {
|
|
|
|
t.Errorf("Expected sort order to be descending, got %v", metadataDesc.SortOrders)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCompositeIndexSortOrders(t *testing.T) {
|
|
|
|
// 测试复合索引的不同字段排序
|
|
|
|
dir := "./testdb_composite_sort"
|
|
|
|
defer os.RemoveAll(dir)
|
|
|
|
|
|
|
|
is, err := NewIndexStore(dir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Failed to create index store: %v", err)
|
|
|
|
}
|
|
|
|
defer is.storage.Close()
|
|
|
|
|
|
|
|
// 测试复合索引(不同字段不同排序)
|
|
|
|
indexName := "composite_index_mixed"
|
|
|
|
keyFields := []string{"name", "age"}
|
|
|
|
sortOrders := []IndexSortOrder{Descending, Ascending}
|
|
|
|
|
2025-06-07 18:18:03 +08:00
|
|
|
// 创建复合索引
|
2025-06-07 22:28:29 +08:00
|
|
|
if err := is.CreateIndex(indexName, NonUnique, keyFields, sortOrders); err != nil {
|
2025-06-07 18:18:03 +08:00
|
|
|
t.Errorf("CreateIndex failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 验证元数据
|
|
|
|
metadata, err := is.GetIndexMetadata(indexName)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("GetIndexMetadata failed: %v", err)
|
|
|
|
}
|
|
|
|
|
2025-06-07 22:28:29 +08:00
|
|
|
if metadata.Type != NonUnique || len(metadata.KeyFields) != 2 {
|
2025-06-07 23:02:49 +08:00
|
|
|
t.Errorf("Composite index metadata mismatch: got %+v want type=%d fieldsCount=2", metadata, NonUnique)
|
2025-06-07 18:18:03 +08:00
|
|
|
}
|
2025-06-07 19:13:07 +08:00
|
|
|
|
|
|
|
// 验证每个字段的排序方式
|
|
|
|
if metadata.SortOrders[0] != Descending || metadata.SortOrders[1] != Ascending {
|
|
|
|
t.Errorf("Expected sort orders [desc, asc], got [%v, %v]", metadata.SortOrders[0], metadata.SortOrders[1])
|
|
|
|
}
|
2025-06-07 18:18:03 +08:00
|
|
|
}
|
|
|
|
|
2025-06-07 22:28:29 +08:00
|
|
|
func BenchmarkNonUniqueQuery(b *testing.B) {
|
2025-06-07 18:18:03 +08:00
|
|
|
// 基准测试单字段查询性能
|
|
|
|
dir := "./testdb_bench"
|
|
|
|
defer os.RemoveAll(dir)
|
|
|
|
|
|
|
|
is, _ := NewIndexStore(dir)
|
|
|
|
|
|
|
|
// 创建测试数据
|
|
|
|
for i := 0; i < 1000; i++ {
|
2025-06-07 22:28:29 +08:00
|
|
|
is.CreateIndex(fmt.Sprintf("index_%d", i), NonUnique, []string{"name"}, []IndexSortOrder{Ascending})
|
2025-06-07 18:18:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
_, err := is.GetIndexMetadata(fmt.Sprintf("index_%d", i%1000))
|
|
|
|
if err != nil {
|
|
|
|
b.Error(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConcurrentIndexOperations(t *testing.T) {
|
|
|
|
// 测试并发索引操作
|
|
|
|
dir := "./testdb_concurrent"
|
|
|
|
defer os.RemoveAll(dir)
|
|
|
|
|
|
|
|
is, _ := NewIndexStore(dir)
|
|
|
|
|
|
|
|
numGoroutines := 10
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
|
|
for i := 0; i < numGoroutines; i++ {
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
|
|
go func(i int) {
|
|
|
|
defer wg.Done()
|
|
|
|
indexName := fmt.Sprintf("concurrent_index_%d", i)
|
|
|
|
|
2025-06-07 19:13:07 +08:00
|
|
|
// 创建索引(默认升序)
|
2025-06-07 22:28:29 +08:00
|
|
|
if err := is.CreateIndex(indexName, NonUnique, []string{"name"}, []IndexSortOrder{Ascending}); err != nil {
|
2025-06-07 18:18:03 +08:00
|
|
|
t.Errorf("CreateIndex failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 删除索引
|
|
|
|
if err := is.DropIndex(indexName); err != nil {
|
|
|
|
t.Errorf("DropIndex failed: %v", err)
|
|
|
|
}
|
|
|
|
}(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
wg.Wait()
|
2025-06-07 19:13:07 +08:00
|
|
|
}
|