github.com/ledgerwatch/erigon-lib@v1.0.0/recsplit/recsplit_test.go (about)

     1  /*
     2     Copyright 2021 Erigon contributors
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package recsplit
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"path/filepath"
    23  	"testing"
    24  
    25  	"github.com/ledgerwatch/log/v3"
    26  )
    27  
    28  func TestRecSplit2(t *testing.T) {
    29  	logger := log.New()
    30  	tmpDir := t.TempDir()
    31  	rs, err := NewRecSplit(RecSplitArgs{
    32  		KeyCount:   2,
    33  		BucketSize: 10,
    34  		Salt:       0,
    35  		TmpDir:     tmpDir,
    36  		IndexFile:  filepath.Join(tmpDir, "index"),
    37  		LeafSize:   8,
    38  	}, logger)
    39  	if err != nil {
    40  		t.Fatal(err)
    41  	}
    42  	if err = rs.AddKey([]byte("first_key"), 0); err != nil {
    43  		t.Error(err)
    44  	}
    45  	if err = rs.Build(context.Background()); err == nil {
    46  		t.Errorf("test is expected to fail, too few keys added")
    47  	}
    48  	if err = rs.AddKey([]byte("second_key"), 0); err != nil {
    49  		t.Error(err)
    50  	}
    51  	if err = rs.Build(context.Background()); err != nil {
    52  		t.Error(err)
    53  	}
    54  	if err = rs.Build(context.Background()); err == nil {
    55  		t.Errorf("test is expected to fail, hash gunction was built already")
    56  	}
    57  	if err = rs.AddKey([]byte("key_to_fail"), 0); err == nil {
    58  		t.Errorf("test is expected to fail, hash function was built")
    59  	}
    60  }
    61  
    62  func TestRecSplitDuplicate(t *testing.T) {
    63  	logger := log.New()
    64  	tmpDir := t.TempDir()
    65  	rs, err := NewRecSplit(RecSplitArgs{
    66  		KeyCount:   2,
    67  		BucketSize: 10,
    68  		Salt:       0,
    69  		TmpDir:     tmpDir,
    70  		IndexFile:  filepath.Join(tmpDir, "index"),
    71  		LeafSize:   8,
    72  	}, logger)
    73  	if err != nil {
    74  		t.Fatal(err)
    75  	}
    76  	if err := rs.AddKey([]byte("first_key"), 0); err != nil {
    77  		t.Error(err)
    78  	}
    79  	if err := rs.AddKey([]byte("first_key"), 0); err != nil {
    80  		t.Error(err)
    81  	}
    82  	if err := rs.Build(context.Background()); err == nil {
    83  		t.Errorf("test is expected to fail, duplicate key")
    84  	}
    85  }
    86  
    87  func TestRecSplitLeafSizeTooLarge(t *testing.T) {
    88  	logger := log.New()
    89  	tmpDir := t.TempDir()
    90  	_, err := NewRecSplit(RecSplitArgs{
    91  		KeyCount:   2,
    92  		BucketSize: 10,
    93  		Salt:       0,
    94  		TmpDir:     tmpDir,
    95  		IndexFile:  filepath.Join(tmpDir, "index"),
    96  		LeafSize:   64,
    97  	}, logger)
    98  	if err == nil {
    99  		t.Errorf("test is expected to fail, leaf size too large")
   100  	}
   101  }
   102  
   103  func TestIndexLookup(t *testing.T) {
   104  	logger := log.New()
   105  	tmpDir := t.TempDir()
   106  	indexFile := filepath.Join(tmpDir, "index")
   107  	rs, err := NewRecSplit(RecSplitArgs{
   108  		KeyCount:   100,
   109  		BucketSize: 10,
   110  		Salt:       0,
   111  		TmpDir:     tmpDir,
   112  		IndexFile:  indexFile,
   113  		LeafSize:   8,
   114  	}, logger)
   115  	if err != nil {
   116  		t.Fatal(err)
   117  	}
   118  	for i := 0; i < 100; i++ {
   119  		if err = rs.AddKey([]byte(fmt.Sprintf("key %d", i)), uint64(i*17)); err != nil {
   120  			t.Fatal(err)
   121  		}
   122  	}
   123  	if err := rs.Build(context.Background()); err != nil {
   124  		t.Fatal(err)
   125  	}
   126  	idx := MustOpen(indexFile)
   127  	defer idx.Close()
   128  	for i := 0; i < 100; i++ {
   129  		reader := NewIndexReader(idx)
   130  		offset := reader.Lookup([]byte(fmt.Sprintf("key %d", i)))
   131  		if offset != uint64(i*17) {
   132  			t.Errorf("expected offset: %d, looked up: %d", i*17, offset)
   133  		}
   134  	}
   135  }
   136  
   137  func TestTwoLayerIndex(t *testing.T) {
   138  	logger := log.New()
   139  	tmpDir := t.TempDir()
   140  	indexFile := filepath.Join(tmpDir, "index")
   141  	rs, err := NewRecSplit(RecSplitArgs{
   142  		KeyCount:   100,
   143  		BucketSize: 10,
   144  		Salt:       0,
   145  		TmpDir:     tmpDir,
   146  		IndexFile:  indexFile,
   147  		LeafSize:   8,
   148  		Enums:      true,
   149  	}, logger)
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  	for i := 0; i < 100; i++ {
   154  		if err = rs.AddKey([]byte(fmt.Sprintf("key %d", i)), uint64(i*17)); err != nil {
   155  			t.Fatal(err)
   156  		}
   157  	}
   158  	if err := rs.Build(context.Background()); err != nil {
   159  		t.Fatal(err)
   160  	}
   161  
   162  	idx := MustOpen(indexFile)
   163  	defer idx.Close()
   164  	for i := 0; i < 100; i++ {
   165  		reader := NewIndexReader(idx)
   166  		e := reader.Lookup([]byte(fmt.Sprintf("key %d", i)))
   167  		if e != uint64(i) {
   168  			t.Errorf("expected enumeration: %d, lookup up: %d", i, e)
   169  		}
   170  		offset := idx.OrdinalLookup(e)
   171  		if offset != uint64(i*17) {
   172  			t.Errorf("expected offset: %d, looked up: %d", i*17, offset)
   173  		}
   174  	}
   175  }