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, &ethdb.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, &ethdb.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  }