github.com/matrixorigin/matrixone@v0.7.0/pkg/txn/storage/memorystorage/memtable/table_test.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package memtable
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    22  	"github.com/matrixorigin/matrixone/pkg/pb/timestamp"
    23  	"github.com/matrixorigin/matrixone/pkg/vm/engine/memoryengine"
    24  	"github.com/stretchr/testify/assert"
    25  )
    26  
    27  type TestRow struct {
    28  	key   Int
    29  	value int
    30  }
    31  
    32  func (t TestRow) Key() Int {
    33  	return t.key
    34  }
    35  
    36  func (t TestRow) Value() int {
    37  	return t.value
    38  }
    39  
    40  func (t TestRow) Indexes() []Tuple {
    41  	return []Tuple{
    42  		{Text("foo"), Int(t.value)},
    43  	}
    44  }
    45  
    46  func (t TestRow) UniqueIndexes() []Tuple {
    47  	return []Tuple{
    48  		{Int(t.value)},
    49  	}
    50  }
    51  
    52  func TestTable(t *testing.T) {
    53  
    54  	table := NewTable[Int, int, TestRow]()
    55  	tx := NewTransaction("1", Time{}, Serializable)
    56  	row := TestRow{key: 42, value: 1}
    57  
    58  	// insert
    59  	err := table.Insert(tx, row)
    60  	assert.Nil(t, err)
    61  
    62  	// get
    63  	r, err := table.Get(tx, Int(42))
    64  	assert.Nil(t, err)
    65  	assert.Equal(t, 1, r)
    66  
    67  	// update
    68  	row.value = 2
    69  	err = table.Update(tx, row)
    70  	assert.Nil(t, err)
    71  
    72  	r, err = table.Get(tx, Int(42))
    73  	assert.Nil(t, err)
    74  	assert.Equal(t, 2, r)
    75  
    76  	// index
    77  	entries, err := table.Index(tx, Tuple{
    78  		Text("foo"), Int(1),
    79  	})
    80  	assert.Nil(t, err)
    81  	assert.Equal(t, 0, len(entries))
    82  	entries, err = table.Index(tx, Tuple{
    83  		Text("foo"), Int(2),
    84  	})
    85  	assert.Nil(t, err)
    86  	assert.Equal(t, 1, len(entries))
    87  	assert.Equal(t, Int(42), entries[0].Key)
    88  
    89  	// delete
    90  	err = table.Delete(tx, Int(42))
    91  	assert.Nil(t, err)
    92  
    93  }
    94  
    95  // time util
    96  func ts(i int64) Time {
    97  	return Time{
    98  		Timestamp: timestamp.Timestamp{
    99  			PhysicalTime: i,
   100  		},
   101  	}
   102  }
   103  
   104  func TestTableIsolation(t *testing.T) {
   105  
   106  	// table
   107  	table := NewTable[Int, int, TestRow]()
   108  
   109  	// tx 1
   110  	tx1 := NewTransaction("1", ts(1), SnapshotIsolation)
   111  
   112  	// tx 2
   113  	tx2 := NewTransaction("2", ts(2), SnapshotIsolation)
   114  	err := table.Insert(tx2, TestRow{
   115  		key:   1,
   116  		value: 2,
   117  	})
   118  	assert.Nil(t, err)
   119  	v, err := table.Get(tx2, 1)
   120  	assert.Nil(t, err)
   121  	assert.Equal(t, 2, v)
   122  	err = tx2.Commit(ts(3))
   123  	assert.Nil(t, err)
   124  
   125  	// duplicated key
   126  	err = table.Insert(tx1, TestRow{
   127  		key:   1,
   128  		value: 3,
   129  	})
   130  	assert.NotNil(t, err)
   131  	assert.True(t, moerr.IsMoErrCode(err, moerr.ErrDuplicate))
   132  
   133  	// read committed
   134  	iter := table.NewIter(tx1)
   135  	n := 0
   136  	for ok := iter.First(); ok; ok = iter.Next() {
   137  		n++
   138  	}
   139  	assert.Equal(t, 0, n)
   140  
   141  	tx3 := NewTransaction("3", Time{
   142  		Timestamp: timestamp.Timestamp{
   143  			PhysicalTime: 3,
   144  		},
   145  	}, SnapshotIsolation)
   146  	iter = table.NewIter(tx3)
   147  	n = 0
   148  	for ok := iter.First(); ok; ok = iter.Next() {
   149  		n++
   150  	}
   151  	assert.Equal(t, 1, n)
   152  
   153  }
   154  
   155  type Issue5388Row struct {
   156  	RowID memoryengine.ID
   157  	A     int
   158  	B     int
   159  }
   160  
   161  func (i Issue5388Row) Key() memoryengine.ID {
   162  	return i.RowID
   163  }
   164  
   165  func (i Issue5388Row) Value() Issue5388Row {
   166  	return i
   167  }
   168  
   169  func (i Issue5388Row) Indexes() []Tuple {
   170  	return nil
   171  }
   172  
   173  func (i Issue5388Row) UniqueIndexes() []Tuple {
   174  	return nil
   175  }
   176  
   177  func TestIssue5388(t *testing.T) {
   178  	table := NewTable[memoryengine.ID, Issue5388Row, Issue5388Row]()
   179  
   180  	newID := func() ID {
   181  		id, err := memoryengine.RandomIDGenerator.NewID(context.Background())
   182  		assert.Nil(t, err)
   183  		return id
   184  	}
   185  
   186  	// insert 10, 10
   187  	tx1 := NewTransaction("1", ts(1), SnapshotIsolation)
   188  	id1 := newID()
   189  	assert.Nil(t, table.Insert(tx1, Issue5388Row{
   190  		RowID: id1,
   191  		A:     10,
   192  		B:     10,
   193  	}))
   194  	assert.Nil(t, tx1.Commit(ts(1)))
   195  
   196  	tx2 := NewTransaction("2", ts(2), SnapshotIsolation)
   197  	// set a = a - 1
   198  	assert.Nil(t, table.Delete(tx2, id1))
   199  	id2 := newID()
   200  	assert.Nil(t, table.Insert(tx2, Issue5388Row{
   201  		RowID: id2,
   202  		A:     9,
   203  		B:     10,
   204  	}))
   205  	// set b = b + 1
   206  	assert.Nil(t, table.Delete(tx2, id2))
   207  	id3 := newID()
   208  	assert.Nil(t, table.Insert(tx2, Issue5388Row{
   209  		RowID: id3,
   210  		A:     9,
   211  		B:     11,
   212  	}))
   213  
   214  	// concurrent tx
   215  	tx3 := NewTransaction("3", ts(3), SnapshotIsolation)
   216  
   217  	// read before tx2 commit
   218  	iter := table.NewIter(tx3)
   219  	n := 0
   220  	for ok := iter.First(); ok; ok = iter.Next() {
   221  		n++
   222  		_, value, err := iter.Read()
   223  		assert.Nil(t, err)
   224  		assert.Equal(t, 10, value.A)
   225  		assert.Equal(t, 10, value.B)
   226  	}
   227  	assert.Equal(t, 1, n)
   228  
   229  	// tx2 commit
   230  	assert.Nil(t, tx2.Commit(ts(4)))
   231  
   232  	// read after tx2 commit
   233  	iter = table.NewIter(tx3)
   234  	n = 0
   235  	for ok := iter.First(); ok; ok = iter.Next() {
   236  		n++
   237  		_, value, err := iter.Read()
   238  		assert.Nil(t, err)
   239  		assert.Equal(t, 10, value.A)
   240  		assert.Equal(t, 10, value.B)
   241  	}
   242  	assert.Equal(t, 1, n)
   243  
   244  }
   245  
   246  func TestUniqueIndex(t *testing.T) {
   247  	table := NewTable[Int, int, TestRow]()
   248  	tx1 := NewTransaction("1", ts(1), Serializable)
   249  	tx2 := NewTransaction("2", ts(1), Serializable)
   250  
   251  	row := TestRow{key: 42, value: 1}
   252  
   253  	err := table.Insert(tx1, row)
   254  	assert.Nil(t, err)
   255  
   256  	err = table.Insert(tx2, row)
   257  	assert.Nil(t, err)
   258  
   259  	err = tx1.Commit(ts(2))
   260  	assert.Nil(t, err)
   261  
   262  	err = tx2.Commit(ts(2))
   263  	assert.True(t, moerr.IsMoErrCode(err, moerr.ErrDuplicate))
   264  }
   265  
   266  func TestFilterVersions(t *testing.T) {
   267  	table := NewTable[Int, int, TestRow]()
   268  
   269  	for i := 0; i < 10; i++ {
   270  		row := TestRow{key: 42, value: i}
   271  		tx1 := NewTransaction("foo", ts(int64(i)), SnapshotIsolation)
   272  		err := table.Upsert(tx1, row)
   273  		assert.Nil(t, err)
   274  		err = tx1.Commit(ts(int64(i)))
   275  		assert.Nil(t, err)
   276  	}
   277  
   278  	err := table.FilterVersions(func(key Int, versions []Version[int]) (filtered []Version[int], err error) {
   279  		return nil, nil
   280  	})
   281  	assert.Nil(t, err)
   282  
   283  }