github.com/matrixorigin/matrixone@v1.2.0/pkg/incrservice/service_test.go (about) 1 // Copyright 2023 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 incrservice 16 17 import ( 18 "context" 19 "fmt" 20 "testing" 21 "time" 22 23 "github.com/lni/goutils/leaktest" 24 "github.com/matrixorigin/matrixone/pkg/catalog" 25 "github.com/matrixorigin/matrixone/pkg/defines" 26 "github.com/matrixorigin/matrixone/pkg/pb/timestamp" 27 "github.com/matrixorigin/matrixone/pkg/txn/client" 28 "github.com/matrixorigin/matrixone/pkg/txn/rpc" 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/require" 31 ) 32 33 func TestCreate(t *testing.T) { 34 runServiceTests( 35 t, 36 1, 37 func( 38 ctx context.Context, 39 ss []*service, 40 ops []client.TxnOperator) { 41 s := ss[0] 42 op := ops[0] 43 44 def := newTestTableDef(2) 45 require.NoError(t, s.Create(ctx, 0, def, op)) 46 47 s.mu.Lock() 48 assert.Equal(t, 1, len(s.mu.tables)) 49 assert.Equal(t, 1, len(s.mu.creates)) 50 assert.Equal(t, 0, len(s.mu.deletes)) 51 assert.Equal(t, 1, len(s.mu.creates[string(op.Txn().ID)])) 52 assert.Equal(t, 2, len(s.mu.tables[0].columns())) 53 s.mu.Unlock() 54 checkStoreCachesUncommitted(t, s.store.(*memStore), op, 2) 55 56 require.NoError(t, op.Commit(ctx)) 57 s.mu.Lock() 58 assert.Equal(t, 1, len(s.mu.tables)) 59 assert.Equal(t, 0, len(s.mu.creates)) 60 assert.Equal(t, 0, len(s.mu.deletes)) 61 s.mu.Unlock() 62 checkStoreCachesCommitted(t, s.store.(*memStore), 2) 63 }) 64 } 65 66 func TestCreateOnOtherService(t *testing.T) { 67 runServiceTests( 68 t, 69 2, 70 func( 71 ctx context.Context, 72 ss []*service, 73 ops []client.TxnOperator) { 74 s := ss[0] 75 op := ops[0] 76 def := newTestTableDef(2) 77 require.NoError(t, s.Create(ctx, 0, def, op)) 78 require.NoError(t, op.Commit(ctx)) 79 80 s2 := ss[0] 81 _, err := s2.getCommittedTableCache(ctx, 0) 82 require.NoError(t, err) 83 s2.mu.Lock() 84 assert.Equal(t, 1, len(s2.mu.tables)) 85 assert.Equal(t, 0, len(s2.mu.creates)) 86 assert.Equal(t, 0, len(s2.mu.deletes)) 87 s2.mu.Unlock() 88 }) 89 } 90 91 func TestCreateWithTxnAborted(t *testing.T) { 92 runServiceTests( 93 t, 94 1, 95 func( 96 ctx context.Context, 97 ss []*service, 98 ops []client.TxnOperator) { 99 s := ss[0] 100 op := ops[0] 101 def := newTestTableDef(2) 102 require.NoError(t, s.Create(ctx, 0, def, op)) 103 104 s.mu.Lock() 105 assert.Equal(t, 1, len(s.mu.tables)) 106 assert.Equal(t, 1, len(s.mu.creates)) 107 assert.Equal(t, 0, len(s.mu.deletes)) 108 assert.Equal(t, 1, len(s.mu.creates[string(op.Txn().ID)])) 109 assert.Equal(t, 2, len(s.mu.tables[0].columns())) 110 s.mu.Unlock() 111 checkStoreCachesUncommitted(t, s.store.(*memStore), op, 2) 112 113 require.NoError(t, op.Rollback(ctx)) 114 s.mu.Lock() 115 assert.Equal(t, 0, len(s.mu.creates)) 116 assert.Equal(t, 0, len(s.mu.deletes)) 117 s.mu.Unlock() 118 checkStoreCachesCommitted(t, s.store.(*memStore), 0) 119 assert.Equal(t, 0, len(s.mu.tables)) 120 }) 121 } 122 123 func TestDelete(t *testing.T) { 124 lazyDeleteInterval = time.Millisecond * 10 125 runServiceTests( 126 t, 127 2, 128 func( 129 ctx context.Context, 130 ss []*service, 131 ops []client.TxnOperator) { 132 s := ss[0] 133 op := ops[0] 134 135 def := newTestTableDef(2) 136 require.NoError(t, s.Create(ctx, 0, def, op)) 137 require.NoError(t, op.Commit(ctx)) 138 checkStoreCachesCommitted(t, s.store.(*memStore), 2) 139 140 s2 := ss[1] 141 op2 := ops[1] 142 require.NoError(t, s.Delete(ctx, 0, op2)) 143 require.NoError(t, op2.Commit(ctx)) 144 waitStoreCachesCommitted(t, s2.store.(*memStore), 0) 145 }) 146 } 147 148 func TestDeleteWithTxnAborted(t *testing.T) { 149 lazyDeleteInterval = time.Millisecond * 10 150 runServiceTests( 151 t, 152 2, 153 func( 154 ctx context.Context, 155 ss []*service, 156 ops []client.TxnOperator) { 157 s := ss[0] 158 op := ops[0] 159 160 def := newTestTableDef(2) 161 require.NoError(t, s.Create(ctx, 0, def, op)) 162 require.NoError(t, op.Commit(ctx)) 163 checkStoreCachesCommitted(t, s.store.(*memStore), 2) 164 165 op2 := ops[1] 166 require.NoError(t, s.Delete(ctx, 0, op2)) 167 require.NoError(t, op2.Rollback(ctx)) 168 checkStoreCachesCommitted(t, s.store.(*memStore), 2) 169 }) 170 } 171 172 func TestDeleteOnOtherService(t *testing.T) { 173 lazyDeleteInterval = time.Millisecond * 10 174 runServiceTests( 175 t, 176 2, 177 func( 178 ctx context.Context, 179 ss []*service, 180 ops []client.TxnOperator) { 181 s := ss[0] 182 op := ops[0] 183 184 def := newTestTableDef(2) 185 require.NoError(t, s.Create(ctx, 0, def, op)) 186 require.NoError(t, op.Commit(ctx)) 187 checkStoreCachesCommitted(t, s.store.(*memStore), 2) 188 189 s2 := ss[1] 190 op2 := ops[1] 191 require.NoError(t, s2.Delete(ctx, 0, op2)) 192 require.NoError(t, op2.Commit(ctx)) 193 waitStoreCachesCommitted(t, s2.store.(*memStore), 0) 194 }) 195 } 196 197 func runServiceTests( 198 t *testing.T, 199 n int, 200 fn func(ctx context.Context, ss []*service, ops []client.TxnOperator), 201 ) { 202 client.RunTxnTests(func( 203 tc client.TxnClient, 204 ts rpc.TxnSender) { 205 defer leaktest.AfterTest(t)() 206 ctx, cancel := context.WithTimeout(defines.AttachAccountId(context.Background(), catalog.System_Account), 10*time.Second) 207 defer cancel() 208 209 ss := make([]*service, 0, n) 210 ops := make([]client.TxnOperator, 0, n) 211 for i := 0; i < n; i++ { 212 store := NewMemStore() 213 ss = append(ss, NewIncrService("", store, Config{CountPerAllocate: 1}).(*service)) 214 215 op, err := tc.New(ctx, timestamp.Timestamp{}) 216 require.NoError(t, err) 217 ops = append(ops, op) 218 } 219 defer func() { 220 for _, s := range ss { 221 s.Close() 222 } 223 }() 224 225 fn(ctx, ss, ops) 226 }) 227 } 228 229 func newTestTableDef(autoCols int) []AutoColumn { 230 var cols []AutoColumn 231 for i := 0; i < autoCols; i++ { 232 cols = append(cols, AutoColumn{ 233 ColName: fmt.Sprintf("auto_%d", i), 234 Step: 1, 235 Offset: 0, 236 }) 237 } 238 return cols 239 } 240 241 func waitStoreCachesCommitted( 242 _ *testing.T, 243 store *memStore, 244 n int) { 245 for { 246 store.Lock() 247 if len(store.caches[0]) == n { 248 store.Unlock() 249 return 250 } 251 store.Unlock() 252 time.Sleep(time.Millisecond * 10) 253 } 254 } 255 256 func checkStoreCachesCommitted( 257 t *testing.T, 258 store *memStore, 259 n int) { 260 store.Lock() 261 defer store.Unlock() 262 require.Equal(t, n, len(store.caches[0])) 263 } 264 265 func checkStoreCachesUncommitted( 266 t *testing.T, 267 store *memStore, 268 txnOp client.TxnOperator, 269 n int) { 270 store.Lock() 271 defer store.Unlock() 272 require.Equal(t, n, len(store.uncommitted[string(txnOp.Txn().ID)][0])) 273 }