|
|
@@ -0,0 +1,61 @@
|
|
|
+package core
|
|
|
+
|
|
|
+import (
|
|
|
+ "bytes"
|
|
|
+ "strings"
|
|
|
+ "testing"
|
|
|
+
|
|
|
+ "git.ycl.pub/yl32940/TsDB2/DB/core/page"
|
|
|
+ "git.ycl.pub/yl32940/TsDB2/DB/core/types"
|
|
|
+)
|
|
|
+
|
|
|
+func TestVacuumBlobChain(t *testing.T) {
|
|
|
+ db := fixOpenDB(t)
|
|
|
+ tbl, err := db.CreateTable("docs", []types.FieldInfo{
|
|
|
+ {FieldType: types.FieldType_Uint64, FieldName: []byte("id")},
|
|
|
+ {FieldType: types.FieldType_Blob, FieldName: []byte("body")},
|
|
|
+ })
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ if _, err := tbl.CreateIndex("pk", page.IndexTypePrimary, []byte{0}); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ big := strings.Repeat("V", 60000)
|
|
|
+ if _, err := tbl.InsertRowWithID(1, []types.FieldValue{
|
|
|
+ {FieldName: []byte("id"), Value: uint64(1)},
|
|
|
+ {FieldName: []byte("body"), Value: []byte(big)},
|
|
|
+ }); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ db.Commit()
|
|
|
+ if _, err := db.VACUUM(); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ tbl2, ok := db.FindTable("docs")
|
|
|
+ if !ok {
|
|
|
+ t.Fatal("vacuum 后表丢失")
|
|
|
+ }
|
|
|
+ vals, err := tbl2.FindByPK(1)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("VACUUM 后读取: %v", err)
|
|
|
+ }
|
|
|
+ var ref types.BlobRef
|
|
|
+ found := false
|
|
|
+ for _, fv := range vals {
|
|
|
+ if string(fv.FieldName) == "body" {
|
|
|
+ ref, found = fv.Value.(types.BlobRef)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if !found || ref.Empty() {
|
|
|
+ t.Fatalf("body 列丢失或引用为空 (found=%v ref=%+v)", found, ref)
|
|
|
+ }
|
|
|
+ body, err := tbl2.BlobRead(ref, types.CompressNone)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("BlobRead (驱动物化同路径): %v", err)
|
|
|
+ }
|
|
|
+ if !bytes.Equal(body, []byte(big)) {
|
|
|
+ t.Fatalf("VACUUM 后 body 不一致: got %d B want %d B", len(body), len(big))
|
|
|
+ }
|
|
|
+ t.Logf("VACUUM 后 blob 链完整可读 (%d B)", len(body))
|
|
|
+}
|