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  }