github.com/matrixorigin/matrixone@v1.2.0/pkg/tnservice/store_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 tnservice 16 17 import ( 18 "context" 19 "math" 20 "os" 21 "sync" 22 "sync/atomic" 23 "testing" 24 "time" 25 26 "github.com/matrixorigin/matrixone/pkg/common/runtime" 27 "github.com/matrixorigin/matrixone/pkg/defines" 28 "github.com/matrixorigin/matrixone/pkg/fileservice" 29 "github.com/matrixorigin/matrixone/pkg/logservice" 30 "github.com/matrixorigin/matrixone/pkg/logutil" 31 logservicepb "github.com/matrixorigin/matrixone/pkg/pb/logservice" 32 "github.com/matrixorigin/matrixone/pkg/pb/metadata" 33 "github.com/matrixorigin/matrixone/pkg/txn/clock" 34 "github.com/matrixorigin/matrixone/pkg/txn/service" 35 "github.com/matrixorigin/matrixone/pkg/txn/storage/mem" 36 "github.com/stretchr/testify/assert" 37 ) 38 39 var ( 40 testTNStoreAddr = "unix:///tmp/test-dnstore.sock" 41 testTNLogtailAddress = "127.0.0.1:22001" 42 ) 43 44 func TestNewAndStartAndCloseService(t *testing.T) { 45 runTNStoreTest(t, func(s *store) { 46 thc := s.hakeeperClient.(*testHAKeeperClient) 47 for { 48 if v := thc.getCount(); v > 0 { 49 return 50 } 51 } 52 }) 53 } 54 55 func TestAddReplica(t *testing.T) { 56 runTNStoreTest(t, func(s *store) { 57 addTestReplica(t, s, 1, 2, 3) 58 }) 59 } 60 61 func TestHandleShutdown(t *testing.T) { 62 fn := func(s *store) { 63 cmd := logservicepb.ScheduleCommand{ 64 UUID: s.cfg.UUID, 65 ShutdownStore: &logservicepb.ShutdownStore{ 66 StoreID: s.cfg.UUID, 67 }, 68 ServiceType: logservicepb.TNService, 69 } 70 71 shutdownC := make(chan struct{}) 72 exit := atomic.Bool{} 73 go func() { 74 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 75 defer func() { 76 cancel() 77 exit.Store(true) 78 }() 79 80 select { 81 case <-ctx.Done(): 82 panic("deadline reached") 83 case <-shutdownC: 84 runtime.DefaultRuntime().Logger().Info("received shutdown command") 85 } 86 }() 87 88 s.shutdownC = shutdownC 89 90 for !exit.Load() { 91 s.handleCommands([]logservicepb.ScheduleCommand{cmd}) 92 time.Sleep(time.Millisecond) 93 } 94 95 } 96 runTNStoreTest(t, fn) 97 } 98 99 func TestStartWithReplicas(t *testing.T) { 100 localFS, err := fileservice.NewMemoryFS(defines.LocalFileServiceName, fileservice.DisabledCacheConfig, nil) 101 assert.NoError(t, err) 102 103 factory := func(name string) (*fileservice.FileServices, error) { 104 s3fs, err := fileservice.NewMemoryFS(defines.SharedFileServiceName, fileservice.DisabledCacheConfig, nil) 105 if err != nil { 106 return nil, err 107 } 108 return fileservice.NewFileServices( 109 "", 110 s3fs, 111 localFS, 112 ) 113 } 114 115 runTNStoreTestWithFileServiceFactory(t, func(s *store) { 116 addTestReplica(t, s, 1, 2, 3) 117 }, factory) 118 119 runTNStoreTestWithFileServiceFactory(t, func(s *store) { 120 121 }, factory) 122 } 123 124 func TestStartReplica(t *testing.T) { 125 runTNStoreTest(t, func(s *store) { 126 assert.NoError(t, s.StartTNReplica(newTestTNShard(1, 2, 3))) 127 r := s.getReplica(1) 128 r.waitStarted() 129 assert.Equal(t, newTestTNShard(1, 2, 3), r.shard) 130 }) 131 } 132 133 func TestRemoveReplica(t *testing.T) { 134 runTNStoreTest(t, func(s *store) { 135 assert.NoError(t, s.StartTNReplica(newTestTNShard(1, 2, 3))) 136 r := s.getReplica(1) 137 r.waitStarted() 138 139 thc := s.hakeeperClient.(*testHAKeeperClient) 140 thc.setCommandBatch(logservicepb.CommandBatch{ 141 Commands: []logservicepb.ScheduleCommand{ 142 { 143 ServiceType: logservicepb.TNService, 144 ConfigChange: &logservicepb.ConfigChange{ 145 ChangeType: logservicepb.RemoveReplica, 146 Replica: logservicepb.Replica{ 147 LogShardID: 3, 148 ReplicaID: 2, 149 ShardID: 1, 150 }, 151 }, 152 }, 153 }, 154 }) 155 156 for { 157 r := s.getReplica(1) 158 if r == nil { 159 return 160 } 161 time.Sleep(time.Millisecond * 10) 162 } 163 }) 164 } 165 166 func TestCloseReplica(t *testing.T) { 167 runTNStoreTest(t, func(s *store) { 168 shard := newTestTNShard(1, 2, 3) 169 assert.NoError(t, s.StartTNReplica(shard)) 170 r := s.getReplica(1) 171 r.waitStarted() 172 assert.Equal(t, shard, r.shard) 173 174 assert.NoError(t, s.CloseTNReplica(shard)) 175 assert.Nil(t, s.getReplica(1)) 176 }) 177 } 178 179 func runTNStoreTest( 180 t *testing.T, 181 testFn func(*store), 182 opts ...Option) { 183 runTNStoreTestWithFileServiceFactory(t, testFn, func(name string) (*fileservice.FileServices, error) { 184 local, err := fileservice.NewMemoryFS( 185 defines.LocalFileServiceName, 186 fileservice.DisabledCacheConfig, nil, 187 ) 188 if err != nil { 189 return nil, err 190 } 191 s3, err := fileservice.NewMemoryFS( 192 defines.SharedFileServiceName, 193 fileservice.DisabledCacheConfig, nil, 194 ) 195 if err != nil { 196 return nil, err 197 } 198 etl, err := fileservice.NewMemoryFS( 199 defines.ETLFileServiceName, 200 fileservice.DisabledCacheConfig, nil, 201 ) 202 if err != nil { 203 return nil, err 204 } 205 return fileservice.NewFileServices(name, local, s3, etl) 206 }, opts...) 207 } 208 209 func runTNStoreTestWithFileServiceFactory( 210 t *testing.T, 211 testFn func(*store), 212 fsFactory fileservice.NewFileServicesFunc, 213 opts ...Option) { 214 runtime.SetupProcessLevelRuntime(runtime.DefaultRuntime()) 215 thc := newTestHAKeeperClient() 216 opts = append(opts, 217 WithHAKeeperClientFactory(func() (logservice.TNHAKeeperClient, error) { 218 return thc, nil 219 }), 220 WithLogServiceClientFactory(func(d metadata.TNShard) (logservice.Client, error) { 221 return mem.NewMemLog(), nil 222 }), 223 WithConfigAdjust(func(c *Config) { 224 c.HAKeeper.HeatbeatInterval.Duration = time.Millisecond * 10 225 c.Txn.Storage.Backend = StorageMEMKV 226 })) 227 228 if fsFactory == nil { 229 fsFactory = func(name string) (*fileservice.FileServices, error) { 230 fs, err := fileservice.NewMemoryFS(name, fileservice.DisabledCacheConfig, nil) 231 if err != nil { 232 return nil, err 233 } 234 return fileservice.NewFileServices(name, fs) 235 } 236 } 237 s := newTestStore(t, "u1", fsFactory, opts...) 238 defer func() { 239 assert.NoError(t, s.Close()) 240 }() 241 assert.NoError(t, s.Start()) 242 testFn(s) 243 } 244 245 func addTestReplica(t *testing.T, s *store, shardID, replicaID, logShardID uint64) { 246 thc := s.hakeeperClient.(*testHAKeeperClient) 247 thc.setCommandBatch(logservicepb.CommandBatch{ 248 Commands: []logservicepb.ScheduleCommand{ 249 { 250 ServiceType: logservicepb.TNService, 251 ConfigChange: &logservicepb.ConfigChange{ 252 ChangeType: logservicepb.AddReplica, 253 Replica: logservicepb.Replica{ 254 LogShardID: logShardID, 255 ReplicaID: replicaID, 256 ShardID: shardID, 257 }, 258 }, 259 }, 260 }, 261 }) 262 263 for { 264 r := s.getReplica(1) 265 if r != nil { 266 r.waitStarted() 267 assert.Equal(t, newTestTNShard(shardID, replicaID, logShardID), r.shard) 268 return 269 } 270 time.Sleep(time.Millisecond * 10) 271 } 272 } 273 274 func newTestStore( 275 t *testing.T, 276 uuid string, 277 fsFactory fileservice.NewFileServicesFunc, 278 options ...Option) *store { 279 assert.NoError(t, os.RemoveAll(testTNStoreAddr[7:])) 280 c := &Config{ 281 UUID: uuid, 282 ListenAddress: testTNStoreAddr, 283 ServiceAddress: testTNStoreAddr, 284 } 285 c.LogtailServer.ListenAddress = testTNLogtailAddress 286 fs, err := fsFactory(defines.LocalFileServiceName) 287 assert.Nil(t, err) 288 289 rt := runtime.NewRuntime( 290 metadata.ServiceType_TN, 291 "", 292 logutil.Adjust(nil), 293 runtime.WithClock( 294 clock.NewHLCClock( 295 func() int64 { return time.Now().UTC().UnixNano() }, 296 time.Duration(math.MaxInt64)))) 297 s, err := NewService( 298 c, 299 rt, 300 fs, 301 nil, 302 options...) 303 assert.NoError(t, err) 304 return s.(*store) 305 } 306 307 func newTestTNShard(shardID, replicaID, logShardID uint64) metadata.TNShard { 308 tnShard := service.NewTestTNShard(shardID) 309 tnShard.ReplicaID = replicaID 310 tnShard.LogShardID = logShardID 311 tnShard.Address = testTNStoreAddr 312 return tnShard 313 } 314 315 type testHAKeeperClient struct { 316 mu struct { 317 sync.RWMutex 318 commandBatch logservicepb.CommandBatch 319 } 320 321 atomic struct { 322 count uint64 323 } 324 } 325 326 func newTestHAKeeperClient() *testHAKeeperClient { 327 return &testHAKeeperClient{} 328 } 329 330 func (thc *testHAKeeperClient) setCommandBatch(commandBatch logservicepb.CommandBatch) { 331 thc.mu.Lock() 332 defer thc.mu.Unlock() 333 thc.mu.commandBatch = commandBatch 334 } 335 336 func (thc *testHAKeeperClient) getCount() uint64 { 337 return atomic.LoadUint64(&thc.atomic.count) 338 } 339 340 func (thc *testHAKeeperClient) Close() error { 341 return nil 342 } 343 344 func (thc *testHAKeeperClient) SendTNHeartbeat(ctx context.Context, hb logservicepb.TNStoreHeartbeat) (logservicepb.CommandBatch, error) { 345 atomic.AddUint64(&thc.atomic.count, 1) 346 thc.mu.RLock() 347 defer thc.mu.RUnlock() 348 return thc.mu.commandBatch, nil 349 } 350 351 var nextID uint64 352 353 func (thc *testHAKeeperClient) AllocateID(ctx context.Context) (uint64, error) { 354 return atomic.AddUint64(&nextID, 1), nil 355 } 356 357 func (thc *testHAKeeperClient) AllocateIDByKey(ctx context.Context, key string) (uint64, error) { 358 return atomic.AddUint64(&nextID, 1), nil 359 } 360 361 func (thc *testHAKeeperClient) AllocateIDByKeyWithBatch(ctx context.Context, key string, batch uint64) (uint64, error) { 362 return atomic.AddUint64(&nextID, 1), nil 363 } 364 365 func (thc *testHAKeeperClient) GetClusterDetails(ctx context.Context) (logservicepb.ClusterDetails, error) { 366 return logservicepb.ClusterDetails{}, nil 367 } 368 func (thc *testHAKeeperClient) GetClusterState(ctx context.Context) (logservicepb.CheckerState, error) { 369 return logservicepb.CheckerState{}, nil 370 }