github.com/vescale/zgraph@v0.0.0-20230410094002-959c02d50f95/storage/transaction_test.go (about)

     1  // Copyright 2022 zGraph Authors. All rights reserved.
     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 storage
    16  
    17  import (
    18  	"context"
    19  	"encoding/binary"
    20  	"io"
    21  	"log"
    22  	"math/rand"
    23  	"testing"
    24  
    25  	"github.com/stretchr/testify/assert"
    26  	"github.com/vescale/zgraph/storage/kv"
    27  	"go.uber.org/atomic"
    28  )
    29  
    30  func TestTxn_Commit(t *testing.T) {
    31  	assert := assert.New(t)
    32  
    33  	storage, err := Open(t.TempDir())
    34  	assert.Nil(err)
    35  	assert.NotNil(storage)
    36  	defer storage.Close()
    37  
    38  	cases := []struct {
    39  		keys []string
    40  		vals []string
    41  	}{
    42  		{
    43  			keys: []string{"a"},
    44  			vals: []string{"b"},
    45  		},
    46  		// Overwrite same key.
    47  		{
    48  			keys: []string{"a"},
    49  			vals: []string{"c"},
    50  		},
    51  		// Multiple key transaction
    52  		{
    53  			keys: []string{"c", "d", "e"},
    54  			vals: []string{"x", "y", "z"},
    55  		},
    56  	}
    57  	for _, c := range cases {
    58  		txn, err := storage.Begin()
    59  		assert.Nil(err)
    60  		assert.NotNil(txn)
    61  		for i, k := range c.keys {
    62  			err := txn.Set(kv.Key(k), []byte(c.vals[i]))
    63  			assert.Nil(err)
    64  		}
    65  		err = txn.Commit(context.Background())
    66  		assert.Nil(err)
    67  
    68  		// Validate the data
    69  		snapshot, err := storage.Snapshot(storage.CurrentVersion())
    70  		assert.Nil(err)
    71  		for i, k := range c.keys {
    72  			val, err := snapshot.Get(context.Background(), kv.Key(k))
    73  			assert.Nil(err)
    74  			assert.Equal(c.vals[i], string(val))
    75  		}
    76  
    77  		// Batch get interface.
    78  		var keys []kv.Key
    79  		var vals = map[string][]byte{}
    80  		for i, k := range c.keys {
    81  			keys = append(keys, kv.Key(k))
    82  			vals[k] = []byte(c.vals[i])
    83  		}
    84  		res, err := snapshot.BatchGet(context.Background(), keys)
    85  		assert.Nil(err)
    86  		assert.Equal(vals, res)
    87  	}
    88  }
    89  
    90  func TestTxn_Iter(t *testing.T) {
    91  	assert := assert.New(t)
    92  
    93  	storage, err := Open(t.TempDir())
    94  	assert.Nil(err)
    95  	assert.NotNil(storage)
    96  	defer storage.Close()
    97  
    98  	cases := []struct {
    99  		keys   []string
   100  		vals   []string
   101  		order  []string
   102  		result map[string]string
   103  	}{
   104  		{
   105  			keys:  []string{"a"},
   106  			vals:  []string{"b"},
   107  			order: []string{"a"},
   108  			result: map[string]string{
   109  				"a": "b",
   110  			},
   111  		},
   112  		// Overwrite same key.
   113  		{
   114  			keys:  []string{"a"},
   115  			vals:  []string{"c"},
   116  			order: []string{"a"},
   117  			result: map[string]string{
   118  				"a": "c",
   119  			},
   120  		},
   121  		// Multiple key transaction
   122  		{
   123  			keys:  []string{"c", "d", "e"},
   124  			vals:  []string{"x", "y", "z"},
   125  			order: []string{"a", "c", "d", "e"},
   126  			result: map[string]string{
   127  				"a": "c",
   128  				"c": "x",
   129  				"d": "y",
   130  				"e": "z",
   131  			},
   132  		},
   133  	}
   134  	for _, c := range cases {
   135  		txn, err := storage.Begin()
   136  		assert.Nil(err)
   137  		assert.NotNil(txn)
   138  		for i, k := range c.keys {
   139  			err := txn.Set(kv.Key(k), []byte(c.vals[i]))
   140  			assert.Nil(err)
   141  		}
   142  		err = txn.Commit(context.Background())
   143  		assert.Nil(err)
   144  
   145  		// Validate the data
   146  		snapshot, err := storage.Snapshot(storage.CurrentVersion())
   147  		assert.Nil(err)
   148  		iter, err := snapshot.Iter(nil, nil)
   149  		assert.Nil(err)
   150  
   151  		var order []string
   152  		var result = map[string]string{}
   153  		for iter.Valid() {
   154  			key := iter.Key()
   155  			val := iter.Value()
   156  			order = append(order, string(key))
   157  			result[string(key)] = string(val)
   158  			err = iter.Next()
   159  			assert.Nil(err)
   160  		}
   161  		assert.Equal(c.order, order)
   162  		assert.Equal(c.result, result)
   163  	}
   164  }
   165  
   166  func benchmarkTxnCommit(b *testing.B, parallelism int) {
   167  	assert := assert.New(b)
   168  
   169  	const kvCount = 10
   170  
   171  	storage, err := Open(b.TempDir())
   172  	assert.Nil(err)
   173  	assert.NotNil(storage)
   174  
   175  	log.SetOutput(io.Discard)
   176  	b.SetParallelism(parallelism)
   177  
   178  	counter := atomic.Uint64{}
   179  
   180  	b.RunParallel(func(pb *testing.PB) {
   181  		for pb.Next() {
   182  			txn, err := storage.Begin()
   183  			assert.Nil(err)
   184  			for n := 0; n < kvCount; n++ {
   185  				key := make([]byte, 8)
   186  				val := make([]byte, 8)
   187  				binary.BigEndian.AppendUint64(key, counter.Inc())
   188  				binary.BigEndian.AppendUint64(val, rand.Uint64())
   189  				err := txn.Set(key, val)
   190  				assert.Nil(err)
   191  			}
   192  			err = txn.Commit(context.Background())
   193  			if err != nil {
   194  				// Only txn conflict allow
   195  				_, ok := err.(*kv.ErrConflict)
   196  				assert.True(ok)
   197  			}
   198  		}
   199  	})
   200  
   201  }
   202  
   203  func BenchmarkTxn_Commit_P32(b *testing.B) {
   204  	benchmarkTxnCommit(b, 32)
   205  }
   206  
   207  func BenchmarkTxn_Commit_P128(b *testing.B) {
   208  	benchmarkTxnCommit(b, 128)
   209  }
   210  
   211  func BenchmarkTxn_Commit_P256(b *testing.B) {
   212  	benchmarkTxnCommit(b, 256)
   213  }
   214  
   215  func BenchmarkTxn_Commit_P512(b *testing.B) {
   216  	benchmarkTxnCommit(b, 512)
   217  }
   218  
   219  func BenchmarkTxn_Commit_P1024(b *testing.B) {
   220  	benchmarkTxnCommit(b, 1024)
   221  }