github.com/matrixorigin/matrixone@v1.2.0/pkg/logservice/rsm_test.go (about)

     1  // Copyright 2021 - 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 logservice
    16  
    17  import (
    18  	"bytes"
    19  	"testing"
    20  
    21  	sm "github.com/lni/dragonboat/v4/statemachine"
    22  	"github.com/stretchr/testify/assert"
    23  
    24  	pb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
    25  )
    26  
    27  func TestGetLeaseHistory(t *testing.T) {
    28  	tsm := newStateMachine(1, 2).(*stateMachine)
    29  	tsm.state.LeaseHistory[100] = 1000
    30  	tsm.state.LeaseHistory[200] = 2000
    31  	tsm.state.LeaseHistory[300] = 3000
    32  	lease, index := tsm.getLeaseHistory(150)
    33  	assert.Equal(t, uint64(1000), lease)
    34  	assert.Equal(t, uint64(100), index)
    35  
    36  	lease, index = tsm.getLeaseHistory(200)
    37  	assert.Equal(t, uint64(1000), lease)
    38  	assert.Equal(t, uint64(100), index)
    39  
    40  	lease, index = tsm.getLeaseHistory(100)
    41  	assert.Equal(t, uint64(0), lease)
    42  	assert.Equal(t, uint64(0), index)
    43  
    44  	lease, index = tsm.getLeaseHistory(400)
    45  	assert.Equal(t, uint64(3000), lease)
    46  	assert.Equal(t, uint64(300), index)
    47  }
    48  
    49  func TestTruncateLeaseHistory(t *testing.T) {
    50  	getSM := func() *stateMachine {
    51  		tsm := newStateMachine(1, 2).(*stateMachine)
    52  		tsm.state.LeaseHistory[100] = 1000
    53  		tsm.state.LeaseHistory[200] = 2000
    54  		tsm.state.LeaseHistory[300] = 3000
    55  		return tsm
    56  	}
    57  
    58  	tsm := getSM()
    59  	tsm.truncateLeaseHistory(105)
    60  	assert.Equal(t, 3, len(tsm.state.LeaseHistory))
    61  	tsm.truncateLeaseHistory(200)
    62  	assert.Equal(t, 3, len(tsm.state.LeaseHistory))
    63  	tsm.truncateLeaseHistory(201)
    64  	assert.Equal(t, 2, len(tsm.state.LeaseHistory))
    65  	_, ok1 := tsm.state.LeaseHistory[200]
    66  	_, ok2 := tsm.state.LeaseHistory[300]
    67  	assert.True(t, ok1)
    68  	assert.True(t, ok2)
    69  
    70  	tsm = getSM()
    71  	tsm.truncateLeaseHistory(300)
    72  	assert.Equal(t, 2, len(tsm.state.LeaseHistory))
    73  	_, ok := tsm.state.LeaseHistory[100]
    74  	assert.False(t, ok)
    75  
    76  	tsm = getSM()
    77  	tsm.truncateLeaseHistory(301)
    78  	assert.Equal(t, 1, len(tsm.state.LeaseHistory))
    79  	_, ok = tsm.state.LeaseHistory[300]
    80  	assert.True(t, ok)
    81  }
    82  
    83  func TestGetSetLeaseHolderCmd(t *testing.T) {
    84  	cmd := getSetLeaseHolderCmd(100)
    85  	assert.True(t, isSetLeaseHolderUpdate(cmd))
    86  	cmd2 := getSetTruncatedLsnCmd(200)
    87  	assert.False(t, isSetLeaseHolderUpdate(cmd2))
    88  }
    89  
    90  func TestIsUserUpdate(t *testing.T) {
    91  	cmd := make([]byte, headerSize+8+1)
    92  	binaryEnc.PutUint32(cmd, uint32(pb.UserEntryUpdate))
    93  	assert.True(t, isUserUpdate(cmd))
    94  	cmd2 := getSetLeaseHolderCmd(1234)
    95  	cmd3 := getSetTruncatedLsnCmd(200)
    96  	assert.False(t, isUserUpdate(cmd2))
    97  	assert.False(t, isUserUpdate(cmd3))
    98  }
    99  
   100  func TestNewStateMachine(t *testing.T) {
   101  	tsm := newStateMachine(100, 200).(*stateMachine)
   102  	assert.Equal(t, uint64(100), tsm.shardID)
   103  	assert.Equal(t, uint64(200), tsm.replicaID)
   104  }
   105  
   106  func TestStateMachineCanBeClosed(t *testing.T) {
   107  	tsm := newStateMachine(100, 200)
   108  	assert.Nil(t, tsm.Close())
   109  }
   110  
   111  func TestTNLeaseHolderCanBeUpdated(t *testing.T) {
   112  	cmd := getSetLeaseHolderCmd(500)
   113  	tsm := newStateMachine(1, 2).(*stateMachine)
   114  	assert.Equal(t, uint64(0), tsm.state.LeaseHolderID)
   115  	e := sm.Entry{Cmd: cmd, Index: 100}
   116  	result, err := tsm.Update(e)
   117  	assert.Equal(t, sm.Result{}, result)
   118  	assert.Nil(t, err)
   119  	assert.Equal(t, uint64(500), tsm.state.LeaseHolderID)
   120  	assert.Equal(t, 1, len(tsm.state.LeaseHistory))
   121  	v, ok := tsm.state.LeaseHistory[100]
   122  	assert.True(t, ok)
   123  	assert.Equal(t, uint64(500), v)
   124  
   125  	cmd = getSetLeaseHolderCmd(1000)
   126  	e = sm.Entry{Cmd: cmd, Index: 200}
   127  	result, err = tsm.Update(e)
   128  	assert.Equal(t, sm.Result{}, result)
   129  	assert.Nil(t, err)
   130  	assert.Equal(t, uint64(1000), tsm.state.LeaseHolderID)
   131  	assert.Equal(t, 2, len(tsm.state.LeaseHistory))
   132  	v, ok = tsm.state.LeaseHistory[200]
   133  	assert.True(t, ok)
   134  	assert.Equal(t, uint64(1000), v)
   135  
   136  	cmd = getSetTruncatedLsnCmd(110)
   137  	e = sm.Entry{Cmd: cmd}
   138  	result, err = tsm.Update(e)
   139  	assert.Equal(t, sm.Result{}, result)
   140  	assert.Nil(t, err)
   141  	// first lease history record won't be truncated
   142  	assert.Equal(t, 2, len(tsm.state.LeaseHistory))
   143  }
   144  
   145  func TestTruncatedIndexCanBeUpdated(t *testing.T) {
   146  	cmd := getSetTruncatedLsnCmd(200)
   147  	tsm := newStateMachine(1, 2).(*stateMachine)
   148  	e := sm.Entry{Cmd: cmd}
   149  	result, err := tsm.Update(e)
   150  	assert.Equal(t, sm.Result{}, result)
   151  	assert.Nil(t, err)
   152  
   153  	cmd2 := getSetTruncatedLsnCmd(220)
   154  	e2 := sm.Entry{Cmd: cmd2}
   155  	result, err = tsm.Update(e2)
   156  	assert.Equal(t, sm.Result{}, result)
   157  	assert.Nil(t, err)
   158  
   159  	cmd3 := getSetTruncatedLsnCmd(100)
   160  	e3 := sm.Entry{Cmd: cmd3}
   161  	result, err = tsm.Update(e3)
   162  	assert.Equal(t, sm.Result{Value: 220}, result)
   163  	assert.Nil(t, err)
   164  }
   165  
   166  func TestStateMachineUserUpdate(t *testing.T) {
   167  	cmd := make([]byte, headerSize+8+1)
   168  	binaryEnc.PutUint32(cmd, uint32(pb.UserEntryUpdate))
   169  	binaryEnc.PutUint64(cmd[headerSize:], uint64(1234))
   170  
   171  	tsm := newStateMachine(1, 2).(*stateMachine)
   172  	tsm.state.LeaseHolderID = 1234
   173  	e := sm.Entry{Index: 100, Cmd: cmd}
   174  	result, err := tsm.Update(e)
   175  	assert.Nil(t, err)
   176  	assert.Equal(t, e.Index, result.Value)
   177  	assert.Nil(t, result.Data)
   178  
   179  	tsm.state.LeaseHolderID = 2345
   180  	e = sm.Entry{Cmd: cmd}
   181  	result, err = tsm.Update(e)
   182  	assert.Nil(t, err)
   183  	assert.Equal(t, uint64(0), result.Value)
   184  	assert.NotNil(t, result.Data)
   185  	assert.Equal(t, tsm.state.LeaseHolderID, binaryEnc.Uint64(result.Data))
   186  }
   187  
   188  func TestTsoUpdate(t *testing.T) {
   189  	tsm := newStateMachine(1, 2).(*stateMachine)
   190  	tsm.state.Tso = 200
   191  	cmd := getTsoUpdateCmd(100)
   192  	result, err := tsm.Update(sm.Entry{Cmd: cmd})
   193  	assert.NoError(t, err)
   194  	assert.Equal(t, uint64(200), result.Value)
   195  	assert.Equal(t, uint64(300), tsm.state.Tso)
   196  }
   197  
   198  func TestStateMachineSnapshot(t *testing.T) {
   199  	buf := bytes.NewBuffer(nil)
   200  	tsm := newStateMachine(1, 2).(*stateMachine)
   201  	tsm.state.LeaseHolderID = 123456
   202  	tsm.state.TruncatedLsn = 456789
   203  	assert.Nil(t, tsm.SaveSnapshot(buf, nil, nil))
   204  
   205  	tsm2 := newStateMachine(3, 4).(*stateMachine)
   206  	assert.Nil(t, tsm2.RecoverFromSnapshot(buf, nil, nil))
   207  	assert.Equal(t, tsm.state.LeaseHolderID, tsm2.state.LeaseHolderID)
   208  	assert.Equal(t, tsm.state.TruncatedLsn, tsm2.state.TruncatedLsn)
   209  	assert.Equal(t, uint64(3), tsm2.shardID)
   210  	assert.Equal(t, uint64(4), tsm2.replicaID)
   211  }
   212  
   213  func TestStateMachineLookup(t *testing.T) {
   214  	tsm := newStateMachine(1, 2).(*stateMachine)
   215  	tsm.state.Index = 1234
   216  	tsm.state.LeaseHolderID = 123456
   217  	tsm.state.TruncatedLsn = 456789
   218  	v, err := tsm.Lookup(leaseHolderIDQuery{})
   219  	assert.Nil(t, err)
   220  	assert.Equal(t, tsm.state.LeaseHolderID, v.(uint64))
   221  
   222  	v2, err := tsm.Lookup(truncatedLsnQuery{})
   223  	assert.Nil(t, err)
   224  	assert.Equal(t, tsm.state.TruncatedLsn, v2.(uint64))
   225  
   226  	v3, err := tsm.Lookup(indexQuery{})
   227  	assert.Nil(t, err)
   228  	assert.Equal(t, tsm.state.Index, v3.(uint64))
   229  }
   230  
   231  func TestStateMachineLookupPanicOnUnexpectedInputValue(t *testing.T) {
   232  	defer func() {
   233  		if r := recover(); r == nil {
   234  			t.Fatalf("failed to panic")
   235  		}
   236  	}()
   237  	tsm := newStateMachine(1, 2).(*stateMachine)
   238  	_, err := tsm.Lookup(uint16(1234))
   239  	assert.NoError(t, err)
   240  }
   241  
   242  func TestStateMachineLookupPanicOnUnexpectedInputType(t *testing.T) {
   243  	defer func() {
   244  		if r := recover(); r == nil {
   245  			t.Fatalf("failed to panic")
   246  		}
   247  	}()
   248  	tsm := newStateMachine(1, 2).(*stateMachine)
   249  	_, err := tsm.Lookup(uint64(1234))
   250  	assert.NoError(t, err)
   251  }