github.com/matrixorigin/matrixone@v0.7.0/pkg/dnservice/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 dnservice 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 testDNStoreAddr = "unix:///tmp/test-dnstore.sock" 41 testDNLogtailAddress = "127.0.0.1:22001" 42 ) 43 44 func TestNewAndStartAndCloseService(t *testing.T) { 45 runDNStoreTest(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 runDNStoreTest(t, func(s *store) { 57 addTestReplica(t, s, 1, 2, 3) 58 }) 59 } 60 61 func TestStartWithReplicas(t *testing.T) { 62 localFS, err := fileservice.NewMemoryFS(defines.LocalFileServiceName) 63 assert.NoError(t, err) 64 65 factory := func(name string) (*fileservice.FileServices, error) { 66 s3fs, err := fileservice.NewMemoryFS(defines.SharedFileServiceName) 67 if err != nil { 68 return nil, err 69 } 70 return fileservice.NewFileServices( 71 defines.LocalFileServiceName, 72 s3fs, 73 localFS, 74 ) 75 } 76 77 runDNStoreTestWithFileServiceFactory(t, func(s *store) { 78 addTestReplica(t, s, 1, 2, 3) 79 }, factory) 80 81 runDNStoreTestWithFileServiceFactory(t, func(s *store) { 82 83 }, factory) 84 } 85 86 func TestStartReplica(t *testing.T) { 87 runDNStoreTest(t, func(s *store) { 88 assert.NoError(t, s.StartDNReplica(newTestDNShard(1, 2, 3))) 89 r := s.getReplica(1) 90 r.waitStarted() 91 assert.Equal(t, newTestDNShard(1, 2, 3), r.shard) 92 }) 93 } 94 95 func TestRemoveReplica(t *testing.T) { 96 runDNStoreTest(t, func(s *store) { 97 assert.NoError(t, s.StartDNReplica(newTestDNShard(1, 2, 3))) 98 r := s.getReplica(1) 99 r.waitStarted() 100 101 thc := s.hakeeperClient.(*testHAKeeperClient) 102 thc.setCommandBatch(logservicepb.CommandBatch{ 103 Commands: []logservicepb.ScheduleCommand{ 104 { 105 ServiceType: logservicepb.DNService, 106 ConfigChange: &logservicepb.ConfigChange{ 107 ChangeType: logservicepb.RemoveReplica, 108 Replica: logservicepb.Replica{ 109 LogShardID: 3, 110 ReplicaID: 2, 111 ShardID: 1, 112 }, 113 }, 114 }, 115 }, 116 }) 117 118 for { 119 r := s.getReplica(1) 120 if r == nil { 121 return 122 } 123 time.Sleep(time.Millisecond * 10) 124 } 125 }) 126 } 127 128 func TestCloseReplica(t *testing.T) { 129 runDNStoreTest(t, func(s *store) { 130 shard := newTestDNShard(1, 2, 3) 131 assert.NoError(t, s.StartDNReplica(shard)) 132 r := s.getReplica(1) 133 r.waitStarted() 134 assert.Equal(t, shard, r.shard) 135 136 assert.NoError(t, s.CloseDNReplica(shard)) 137 assert.Nil(t, s.getReplica(1)) 138 }) 139 } 140 141 func runDNStoreTest( 142 t *testing.T, 143 testFn func(*store), 144 opts ...Option) { 145 runDNStoreTestWithFileServiceFactory(t, testFn, func(name string) (*fileservice.FileServices, error) { 146 local, err := fileservice.NewMemoryFS( 147 defines.LocalFileServiceName, 148 ) 149 if err != nil { 150 return nil, err 151 } 152 s3, err := fileservice.NewMemoryFS( 153 defines.SharedFileServiceName, 154 ) 155 if err != nil { 156 return nil, err 157 } 158 etl, err := fileservice.NewMemoryFS( 159 defines.ETLFileServiceName, 160 ) 161 if err != nil { 162 return nil, err 163 } 164 return fileservice.NewFileServices(name, local, s3, etl) 165 }, opts...) 166 } 167 168 func runDNStoreTestWithFileServiceFactory( 169 t *testing.T, 170 testFn func(*store), 171 fsFactory fileservice.NewFileServicesFunc, 172 opts ...Option) { 173 thc := newTestHAKeeperClient() 174 opts = append(opts, 175 WithHAKeeperClientFactory(func() (logservice.DNHAKeeperClient, error) { 176 return thc, nil 177 }), 178 WithLogServiceClientFactory(func(d metadata.DNShard) (logservice.Client, error) { 179 return mem.NewMemLog(), nil 180 }), 181 WithConfigAdjust(func(c *Config) { 182 c.HAKeeper.HeatbeatInterval.Duration = time.Millisecond * 10 183 c.Txn.Storage.Backend = StorageMEMKV 184 })) 185 186 if fsFactory == nil { 187 fsFactory = func(name string) (*fileservice.FileServices, error) { 188 fs, err := fileservice.NewMemoryFS(name) 189 if err != nil { 190 return nil, err 191 } 192 return fileservice.NewFileServices(name, fs) 193 } 194 } 195 s := newTestStore(t, "u1", fsFactory, opts...) 196 defer func() { 197 assert.NoError(t, s.Close()) 198 }() 199 assert.NoError(t, s.Start()) 200 testFn(s) 201 } 202 203 func addTestReplica(t *testing.T, s *store, shardID, replicaID, logShardID uint64) { 204 thc := s.hakeeperClient.(*testHAKeeperClient) 205 thc.setCommandBatch(logservicepb.CommandBatch{ 206 Commands: []logservicepb.ScheduleCommand{ 207 { 208 ServiceType: logservicepb.DNService, 209 ConfigChange: &logservicepb.ConfigChange{ 210 ChangeType: logservicepb.AddReplica, 211 Replica: logservicepb.Replica{ 212 LogShardID: logShardID, 213 ReplicaID: replicaID, 214 ShardID: shardID, 215 }, 216 }, 217 }, 218 }, 219 }) 220 221 for { 222 r := s.getReplica(1) 223 if r != nil { 224 r.waitStarted() 225 assert.Equal(t, newTestDNShard(shardID, replicaID, logShardID), r.shard) 226 return 227 } 228 time.Sleep(time.Millisecond * 10) 229 } 230 } 231 232 func newTestStore( 233 t *testing.T, 234 uuid string, 235 fsFactory fileservice.NewFileServicesFunc, 236 options ...Option) *store { 237 assert.NoError(t, os.RemoveAll(testDNStoreAddr[7:])) 238 c := &Config{ 239 UUID: uuid, 240 ListenAddress: testDNStoreAddr, 241 } 242 c.LogtailServer.ListenAddress = testDNLogtailAddress 243 fs, err := fsFactory(defines.LocalFileServiceName) 244 assert.Nil(t, err) 245 246 rt := runtime.NewRuntime( 247 metadata.ServiceType_DN, 248 "", 249 logutil.Adjust(nil), 250 runtime.WithClock( 251 clock.NewHLCClock( 252 func() int64 { return time.Now().UTC().UnixNano() }, 253 time.Duration(math.MaxInt64)))) 254 s, err := NewService( 255 c, 256 rt, 257 fs, options...) 258 assert.NoError(t, err) 259 return s.(*store) 260 } 261 262 func newTestDNShard(shardID, replicaID, logShardID uint64) metadata.DNShard { 263 dnShard := service.NewTestDNShard(shardID) 264 dnShard.ReplicaID = replicaID 265 dnShard.LogShardID = logShardID 266 dnShard.Address = testDNStoreAddr 267 return dnShard 268 } 269 270 type testHAKeeperClient struct { 271 mu struct { 272 sync.RWMutex 273 commandBatch logservicepb.CommandBatch 274 } 275 276 atomic struct { 277 count uint64 278 } 279 } 280 281 func newTestHAKeeperClient() *testHAKeeperClient { 282 return &testHAKeeperClient{} 283 } 284 285 func (thc *testHAKeeperClient) setCommandBatch(commandBatch logservicepb.CommandBatch) { 286 thc.mu.Lock() 287 defer thc.mu.Unlock() 288 thc.mu.commandBatch = commandBatch 289 } 290 291 func (thc *testHAKeeperClient) getCount() uint64 { 292 return atomic.LoadUint64(&thc.atomic.count) 293 } 294 295 func (thc *testHAKeeperClient) Close() error { 296 return nil 297 } 298 299 func (thc *testHAKeeperClient) SendDNHeartbeat(ctx context.Context, hb logservicepb.DNStoreHeartbeat) (logservicepb.CommandBatch, error) { 300 atomic.AddUint64(&thc.atomic.count, 1) 301 thc.mu.RLock() 302 defer thc.mu.RUnlock() 303 return thc.mu.commandBatch, nil 304 } 305 306 var nextID uint64 307 308 func (thc *testHAKeeperClient) AllocateID(ctx context.Context) (uint64, error) { 309 return atomic.AddUint64(&nextID, 1), nil 310 } 311 312 func (thc *testHAKeeperClient) GetClusterDetails(ctx context.Context) (logservicepb.ClusterDetails, error) { 313 return logservicepb.ClusterDetails{}, nil 314 } 315 func (thc *testHAKeeperClient) GetClusterState(ctx context.Context) (logservicepb.CheckerState, error) { 316 return logservicepb.CheckerState{}, nil 317 }