erigon-pulse/kv/mdbx/kv_mdbx_test.go
TKartist 8b2c02d1fb
Test for kv_mdbx optimized (#528)
* tests for GetOne and Put added

* test configured

* multiple tests added

* conflict resolve

* optimized and tests updated

* conflict fix
2022-07-18 21:36:58 +02:00

386 lines
9.9 KiB
Go

/*
Copyright 2022 Erigon contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mdbx
import (
"context"
"testing"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/log/v3"
"github.com/stretchr/testify/require"
)
func BaseCase(t *testing.T) (kv.RwDB, kv.RwTx, kv.RwCursorDupSort) {
path := t.TempDir()
logger := log.New()
table := "Table"
db := NewMDBX(logger).Path(path).WithTablessCfg(func(defaultBuckets kv.TableCfg) kv.TableCfg {
return kv.TableCfg{
table: kv.TableCfgItem{Flags: kv.DupSort},
kv.Sequence: kv.TableCfgItem{},
}
}).MustOpen()
tx, err := db.BeginRw(context.Background())
require.NoError(t, err)
c, err := tx.RwCursorDupSort(table)
require.NoError(t, err)
// Insert some dupsorted records
require.NoError(t, c.Put([]byte("key1"), []byte("value1.1")))
require.NoError(t, c.Put([]byte("key3"), []byte("value3.1")))
require.NoError(t, c.Put([]byte("key1"), []byte("value1.3")))
require.NoError(t, c.Put([]byte("key3"), []byte("value3.3")))
return db, tx, c
}
func TestSeekBothRange(t *testing.T) {
db, tx, c := BaseCase(t)
defer db.Close()
defer tx.Rollback()
defer c.Close()
v, err := c.SeekBothRange([]byte("key2"), []byte("value1.2"))
require.NoError(t, err)
// SeekBothRange does extact match of the key, but range match of the value, so we get nil here
require.Nil(t, v)
v, err = c.SeekBothRange([]byte("key3"), []byte("value3.2"))
require.NoError(t, err)
require.Equal(t, "value3.3", string(v))
}
func TestLastDup(t *testing.T) {
db, tx, c := BaseCase(t)
defer db.Close()
defer tx.Rollback()
defer c.Close()
err := tx.Commit()
require.NoError(t, err)
roTx, err := db.BeginRo(context.Background())
require.NoError(t, err)
defer roTx.Rollback()
roC, err := roTx.CursorDupSort("Table")
require.NoError(t, err)
defer roC.Close()
var keys, vals []string
var k, v []byte
for k, _, err = roC.First(); err == nil && k != nil; k, _, err = roC.NextNoDup() {
v, err = roC.LastDup()
require.NoError(t, err)
keys = append(keys, string(k))
vals = append(vals, string(v))
}
require.NoError(t, err)
require.Equal(t, []string{"key1", "key3"}, keys)
require.Equal(t, []string{"value1.3", "value3.3"}, vals)
}
func TestPutGet(t *testing.T) {
db, tx, c := BaseCase(t)
defer db.Close()
defer tx.Rollback()
defer c.Close()
require.Error(t, c.Put([]byte(""), []byte("value1.1")))
var v []byte
v, err := tx.GetOne("Table", []byte("key1"))
require.Nil(t, err)
require.Equal(t, v, []byte("value1.1"))
v, err = tx.GetOne("RANDOM", []byte("key1"))
require.Error(t, err) // Error from non-existent bucket returns error
require.Nil(t, v)
}
func TestIncrementRead(t *testing.T) {
db, tx, c := BaseCase(t)
defer db.Close()
defer tx.Rollback()
defer c.Close()
table := "Table"
_, err := tx.IncrementSequence(table, uint64(12))
require.Nil(t, err)
chaV, err := tx.ReadSequence(table)
require.Nil(t, err)
require.Equal(t, chaV, uint64(12))
_, err = tx.IncrementSequence(table, uint64(240))
require.Nil(t, err)
chaV, err = tx.ReadSequence(table)
require.Nil(t, err)
require.Equal(t, chaV, uint64(252))
}
func TestHasDelete(t *testing.T) {
db, tx, c := BaseCase(t)
defer db.Close()
defer tx.Rollback()
defer c.Close()
table := "Table"
require.NoError(t, tx.Put(table, []byte("key2"), []byte("value2.1")))
require.NoError(t, tx.Put(table, []byte("key4"), []byte("value4.1")))
require.NoError(t, tx.Put(table, []byte("key5"), []byte("value5.1")))
require.NoError(t, tx.Delete(table, []byte("key1"), []byte("value1.1")))
require.NoError(t, tx.Delete(table, []byte("key1"), []byte("value1.3")))
require.NoError(t, tx.Delete(table, []byte("key1"), []byte("value1.1"))) //valid but already deleted
require.NoError(t, tx.Delete(table, []byte("key2"), []byte("value1.1"))) //valid key but wrong value
res, err := tx.Has(table, []byte("key1"))
require.Nil(t, err)
require.False(t, res)
res, err = tx.Has(table, []byte("key2"))
require.Nil(t, err)
require.True(t, res)
res, err = tx.Has(table, []byte("key3"))
require.Nil(t, err)
require.True(t, res) //There is another key3 left
res, err = tx.Has(table, []byte("k"))
require.Nil(t, err)
require.False(t, res)
}
func TestForAmount(t *testing.T) {
db, tx, c := BaseCase(t)
defer db.Close()
defer tx.Rollback()
defer c.Close()
table := "Table"
require.NoError(t, tx.Put(table, []byte("key2"), []byte("value2.1")))
require.NoError(t, tx.Put(table, []byte("key4"), []byte("value4.1")))
require.NoError(t, tx.Put(table, []byte("key5"), []byte("value5.1")))
var keys []string
err := tx.ForAmount(table, []byte("key3"), uint32(2), func(k, v []byte) error {
keys = append(keys, string(k))
return nil
})
require.Nil(t, err)
require.Equal(t, []string{"key3", "key3"}, keys)
var keys1 []string
err1 := tx.ForAmount(table, []byte("key1"), 100, func(k, v []byte) error {
keys1 = append(keys1, string(k))
return nil
})
require.Nil(t, err1)
require.Equal(t, []string{"key1", "key1", "key2", "key3", "key3", "key4", "key5"}, keys1)
var keys2 []string
err2 := tx.ForAmount(table, []byte("value"), 100, func(k, v []byte) error {
keys2 = append(keys2, string(k))
return nil
})
require.Nil(t, err2)
require.Nil(t, keys2)
var keys3 []string
err3 := tx.ForAmount(table, []byte("key1"), 0, func(k, v []byte) error {
keys3 = append(keys3, string(k))
return nil
})
require.Nil(t, err3)
require.Nil(t, keys3)
}
func TestForPrefix(t *testing.T) {
db, tx, c := BaseCase(t)
defer db.Close()
defer tx.Rollback()
defer c.Close()
table := "Table"
var keys []string
err := tx.ForPrefix(table, []byte("key"), func(k, v []byte) error {
keys = append(keys, string(k))
return nil
})
require.Nil(t, err)
require.Equal(t, []string{"key1", "key1", "key3", "key3"}, keys)
var keys1 []string
err = tx.ForPrefix(table, []byte("key1"), func(k, v []byte) error {
keys1 = append(keys1, string(k))
return nil
})
require.Nil(t, err)
require.Equal(t, []string{"key1", "key1"}, keys1)
var keys2 []string
err = tx.ForPrefix(table, []byte("e"), func(k, v []byte) error {
keys2 = append(keys2, string(k))
return nil
})
require.Nil(t, err)
require.Nil(t, keys2)
}
func TestAppendFirstLast(t *testing.T) {
db, tx, c := BaseCase(t)
defer db.Close()
defer tx.Rollback()
defer c.Close()
table := "Table"
require.Error(t, tx.Append(table, []byte("key2"), []byte("value2.1")))
require.NoError(t, tx.Append(table, []byte("key6"), []byte("value6.1")))
require.Error(t, tx.Append(table, []byte("key4"), []byte("value4.1")))
require.NoError(t, tx.Put(table, []byte("key2"), []byte("value1.11")))
k, v, err := c.First()
require.Nil(t, err)
require.Equal(t, k, []byte("key1"))
require.Equal(t, v, []byte("value1.1"))
k, v, err = c.Last()
require.Nil(t, err)
require.Equal(t, k, []byte("key6"))
require.Equal(t, v, []byte("value6.1"))
}
func TestNextPrevCurrent(t *testing.T) {
db, tx, c := BaseCase(t)
defer db.Close()
defer tx.Rollback()
defer c.Close()
k, v, err := c.First()
require.Nil(t, err)
require.Equal(t, k, []byte("key1"))
require.Equal(t, v, []byte("value1.1"))
k, v, err = c.Next()
require.Nil(t, err)
require.Equal(t, k, []byte("key1"))
require.Equal(t, v, []byte("value1.3"))
k, v, err = c.Current()
require.Nil(t, err)
require.Equal(t, k, []byte("key1"))
require.Equal(t, v, []byte("value1.3"))
k, v, err = c.Next()
require.Nil(t, err)
require.Equal(t, k, []byte("key3"))
require.Equal(t, v, []byte("value3.1"))
k, v, err = c.Prev()
require.Nil(t, err)
require.Equal(t, k, []byte("key1"))
require.Equal(t, v, []byte("value1.3"))
k, v, err = c.Current()
require.Nil(t, err)
require.Equal(t, k, []byte("key1"))
require.Equal(t, v, []byte("value1.3"))
k, v, err = c.Prev()
require.Nil(t, err)
require.Equal(t, k, []byte("key1"))
require.Equal(t, v, []byte("value1.1"))
}
func TestSeek(t *testing.T) {
db, tx, c := BaseCase(t)
defer db.Close()
defer tx.Rollback()
defer c.Close()
var keys []string
var values []string
for k, v, err := c.Seek([]byte("k")); k != nil; k, v, err = c.Next() {
require.Nil(t, err)
keys = append(keys, string(k))
values = append(values, string(v))
}
require.Equal(t, []string{"key1", "key1", "key3", "key3"}, keys)
require.Equal(t, []string{"value1.1", "value1.3", "value3.1", "value3.3"}, values)
var keys1 []string
var values1 []string
for k, v, err := c.Seek([]byte("key3")); k != nil; k, v, err = c.Next() {
require.Nil(t, err)
keys1 = append(keys1, string(k))
values1 = append(values1, string(v))
}
require.Equal(t, []string{"key3", "key3"}, keys1)
require.Equal(t, []string{"value3.1", "value3.3"}, values1)
var keys2 []string
var values2 []string
for k, v, err := c.Seek([]byte("xy")); k != nil; k, v, err = c.Next() {
require.Nil(t, err)
keys2 = append(keys2, string(k))
values2 = append(values2, string(v))
}
require.Nil(t, keys2)
require.Nil(t, values2)
}
func TestSeekExact(t *testing.T) {
db, tx, c := BaseCase(t)
defer db.Close()
defer tx.Rollback()
defer c.Close()
var keys []string
var values []string
for k, v, err := c.SeekExact([]byte("key3")); k != nil; k, v, err = c.Next() {
require.Nil(t, err)
keys = append(keys, string(k))
values = append(values, string(v))
}
require.Equal(t, []string{"key3", "key3"}, keys)
require.Equal(t, []string{"value3.1", "value3.3"}, values)
var keys1 []string
var values1 []string
for k, v, err := c.SeekExact([]byte("key")); k != nil; k, v, err = c.Next() {
require.Nil(t, err)
keys1 = append(keys, string(k))
values1 = append(values, string(v))
}
require.Nil(t, keys1)
require.Nil(t, values1)
}