github.com/bcskill/bcschain/v3@v3.4.9-beta2/ethdb/table_test.go (about) 1 package ethdb_test 2 3 import ( 4 "context" 5 "os" 6 "testing" 7 "time" 8 9 "github.com/bcskill/bcschain/v3/common" 10 "github.com/bcskill/bcschain/v3/ethdb" 11 ) 12 13 func TestTable_Put(t *testing.T) { 14 dir := MustTempDir() 15 tbl := ethdb.NewTable("test", dir, ðdb.StaticPartitioner{Name: "data"}) 16 defer os.RemoveAll(tbl.Path) 17 18 if err := tbl.Open(); err != nil { 19 t.Fatal(err) 20 } 21 defer tbl.Close() 22 23 if err := tbl.Put(numHashKey('b', 1000, common.Hash{}), []byte("BLOCKDATA")); err != nil { 24 t.Fatal(err) 25 } 26 27 if exists, err := tbl.Has(numHashKey('b', 1000, common.Hash{})); err != nil { 28 t.Fatal(err) 29 } else if !exists { 30 t.Fatal("expected value to exist") 31 } 32 33 if value, err := tbl.Get(numHashKey('b', 1000, common.Hash{})); err != nil { 34 t.Fatal(err) 35 } else if string(value) != "BLOCKDATA" { 36 t.Fatalf("unexpected value: %q", value) 37 } 38 39 // Close original database. 40 if err := tbl.Close(); err != nil { 41 t.Fatal(err) 42 } 43 } 44 45 func TestTable_Delete(t *testing.T) { 46 dir := MustTempDir() 47 tbl := ethdb.NewTable("test", dir, ðdb.StaticPartitioner{Name: "data"}) 48 defer os.RemoveAll(tbl.Path) 49 50 if err := tbl.Open(); err != nil { 51 t.Fatal(err) 52 } 53 defer tbl.Close() 54 55 if err := tbl.Put(numHashKey('b', 1000, common.Hash{}), []byte("BLOCKDATA")); err != nil { 56 t.Fatal(err) 57 } else if err := tbl.Delete(numHashKey('b', 1000, common.Hash{})); err != nil { 58 t.Fatal(err) 59 } 60 61 if exists, err := tbl.Has(numHashKey('b', 1000, common.Hash{})); err != nil { 62 t.Fatal(err) 63 } else if exists { 64 t.Fatal("expected value to not exist") 65 } 66 67 if _, err := tbl.Get(numHashKey('b', 1000, common.Hash{})); err != common.ErrNotFound { 68 t.Fatal(err) 69 } 70 } 71 72 func TestTable_Compact(t *testing.T) { 73 t.Run("OK", func(t *testing.T) { 74 dir := MustTempDir() 75 defer os.RemoveAll(dir) 76 77 tbl := ethdb.NewTable("test", dir, ethdb.NewBlockNumberPartitioner(1000)) 78 tbl.MinCompactionAge = 0 // compact immediately 79 tbl.MinMutableSegmentCount = 2 80 if err := tbl.Open(); err != nil { 81 t.Fatal(err) 82 } 83 defer tbl.Close() 84 85 if err := tbl.Put(numHashKey('b', 200, common.Hash{}), []byte("foo")); err != nil { 86 t.Fatal(err) 87 } else if err := tbl.Put(numHashKey('b', 700, common.Hash{}), []byte("bar")); err != nil { 88 t.Fatal(err) 89 } else if err := tbl.Put(numHashKey('b', 1500, common.Hash{}), []byte("baz")); err != nil { 90 t.Fatal(err) 91 } else if err := tbl.Put(numHashKey('b', 2100, common.Hash{}), []byte("bat")); err != nil { 92 t.Fatal(err) 93 } 94 95 // Force compaction. 96 if err := tbl.Compact(context.Background()); err != nil { 97 t.Fatal(err) 98 } 99 100 // Verify segment file names. 101 segments := tbl.SegmentSlice() 102 if len(segments) != 3 { 103 t.Fatalf("unexpected segment count: %d", len(segments)) 104 } else if _, ok := segments[0].(*ethdb.FileSegment); !ok { 105 t.Fatalf("expected file segment(0), got %T", segments[0]) 106 } else if _, ok := segments[1].(*ethdb.LDBSegment); !ok { 107 t.Fatalf("expected ldb segment(1), got %T", segments[1]) 108 } else if _, ok := segments[2].(*ethdb.LDBSegment); !ok { 109 t.Fatalf("expected ldb segment(1), got %T", segments[1]) 110 } 111 112 // Verify active segment. 113 if name := tbl.ActiveSegmentName(); name != `00000000000007d0` { 114 t.Fatalf("unexpected active segment name: %s", name) 115 } 116 117 // Verify data can be read from compacted segment. 118 if v, err := tbl.Get(numHashKey('b', 200, common.Hash{})); err != nil { 119 t.Fatal(err) 120 } else if string(v) != `foo` { 121 t.Fatalf("unexpected value: %q", v) 122 } 123 124 if v, err := tbl.Get(numHashKey('b', 700, common.Hash{})); err != nil { 125 t.Fatal(err) 126 } else if string(v) != `bar` { 127 t.Fatalf("unexpected value: %q", v) 128 } 129 }) 130 131 t.Run("MinCompactionAge", func(t *testing.T) { 132 dir := MustTempDir() 133 defer os.RemoveAll(dir) 134 135 tbl := ethdb.NewTable("test", dir, ethdb.NewBlockNumberPartitioner(1000)) 136 tbl.MinCompactionAge = 2 * time.Second 137 tbl.MinMutableSegmentCount = 2 138 if err := tbl.Open(); err != nil { 139 t.Fatal(err) 140 } 141 defer tbl.Close() 142 143 if err := tbl.Put(numHashKey('b', 200, common.Hash{}), []byte("foo")); err != nil { 144 t.Fatal(err) 145 } else if err := tbl.Put(numHashKey('b', 700, common.Hash{}), []byte("bar")); err != nil { 146 t.Fatal(err) 147 } else if err := tbl.Put(numHashKey('b', 1500, common.Hash{}), []byte("baz")); err != nil { 148 t.Fatal(err) 149 } else if err := tbl.Put(numHashKey('b', 2100, common.Hash{}), []byte("bat")); err != nil { 150 t.Fatal(err) 151 } 152 153 // Attempt compaction, too soon. Expect LDB segment still. 154 if err := tbl.Compact(context.Background()); err != nil { 155 t.Fatal(err) 156 } else if _, ok := tbl.SegmentSlice()[0].(*ethdb.LDBSegment); !ok { 157 t.Fatalf("expected ldb segment") 158 } 159 160 // Wait and retry. Expect compaction to file segment. 161 time.Sleep(tbl.MinCompactionAge) 162 if err := tbl.Compact(context.Background()); err != nil { 163 t.Fatal(err) 164 } else if _, ok := tbl.SegmentSlice()[0].(*ethdb.FileSegment); !ok { 165 t.Fatalf("expected file segment") 166 } 167 168 // Update first segment and expect uncompaction. 169 if err := tbl.Put(numHashKey('b', 300, common.Hash{}), []byte("XYZ")); err != nil { 170 t.Fatal(err) 171 } else if _, ok := tbl.SegmentSlice()[0].(*ethdb.LDBSegment); !ok { 172 t.Fatalf("expected ldb segment") 173 } 174 175 // Attempt compaction immediately. Too soon again. 176 if err := tbl.Compact(context.Background()); err != nil { 177 t.Fatal(err) 178 } else if _, ok := tbl.SegmentSlice()[0].(*ethdb.LDBSegment); !ok { 179 t.Fatalf("expected ldb segment") 180 } 181 182 // Wait and retry. Expect compaction to file segment. 183 time.Sleep(tbl.MinCompactionAge) 184 if err := tbl.Compact(context.Background()); err != nil { 185 t.Fatal(err) 186 } else if _, ok := tbl.SegmentSlice()[0].(*ethdb.FileSegment); !ok { 187 t.Fatalf("expected file segment") 188 } 189 190 // Verify data can be read from compacted segment. 191 if v, err := tbl.Get(numHashKey('b', 200, common.Hash{})); string(v) != `foo` || err != nil { 192 t.Fatalf("unexpected value: v=%q / err=%v", v, err) 193 } else if v, err := tbl.Get(numHashKey('b', 300, common.Hash{})); string(v) != `XYZ` || err != nil { 194 t.Fatalf("unexpected value: v=%q / err=%v", v, err) 195 } 196 }) 197 }