github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/integration/commitlog_bootstrap_helpers.go (about)

     1  // +build integration
     2  
     3  // Copyright (c) 2017 Uber Technologies, Inc.
     4  //
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  //
    12  // The above copyright notice and this permission notice shall be included in
    13  // all copies or substantial portions of the Software.
    14  //
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    21  // THE SOFTWARE.
    22  
    23  package integration
    24  
    25  import (
    26  	"math/rand"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/m3db/m3/src/dbnode/integration/generate"
    31  	"github.com/m3db/m3/src/dbnode/namespace"
    32  	"github.com/m3db/m3/src/dbnode/persist/fs/commitlog"
    33  	"github.com/m3db/m3/src/dbnode/ts"
    34  	"github.com/m3db/m3/src/x/context"
    35  	"github.com/m3db/m3/src/x/ident"
    36  	xtime "github.com/m3db/m3/src/x/time"
    37  
    38  	"github.com/stretchr/testify/require"
    39  )
    40  
    41  var (
    42  	defaultIntegrationTestFlushInterval = 100 * time.Millisecond
    43  	defaultDerrangementPercent          = 0.20
    44  )
    45  
    46  type commitLogSeriesState struct {
    47  	uniqueIndex uint64
    48  	tags        ident.Tags
    49  }
    50  
    51  func newCommitLogSeriesStates(
    52  	timeBlocks generate.SeriesBlocksByStart,
    53  ) map[string]*commitLogSeriesState {
    54  	var idx uint64
    55  	lookup := make(map[string]*commitLogSeriesState)
    56  	for _, blks := range timeBlocks {
    57  		for _, blk := range blks {
    58  			id := blk.ID.String()
    59  			if _, ok := lookup[id]; !ok {
    60  				lookup[id] = &commitLogSeriesState{
    61  					uniqueIndex: idx,
    62  					tags:        blk.Tags,
    63  				}
    64  				idx++
    65  			}
    66  		}
    67  	}
    68  	return lookup
    69  }
    70  
    71  var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
    72  
    73  func randStringRunes(n int) string {
    74  	b := make([]rune, n)
    75  	for i := range b {
    76  		b[i] = letterRunes[rand.Intn(len(letterRunes))]
    77  	}
    78  	return string(b)
    79  }
    80  
    81  func generateSeriesMaps(
    82  	numBlocks int, updateConfig generate.UpdateBlockConfig, starts ...xtime.UnixNano,
    83  ) generate.SeriesBlocksByStart {
    84  	blockConfig := []generate.BlockConfig{}
    85  	for i := 0; i < numBlocks; i++ {
    86  		name := []string{}
    87  		for j := 0; j < rand.Intn(10)+1; j++ {
    88  			name = append(name, randStringRunes(100))
    89  		}
    90  
    91  		start := starts[rand.Intn(len(starts))]
    92  		blockConfig = append(blockConfig, generate.BlockConfig{
    93  			IDs:       name,
    94  			NumPoints: rand.Intn(100) + 1,
    95  			Start:     start,
    96  		})
    97  	}
    98  	if updateConfig != nil {
    99  		updateConfig(blockConfig)
   100  	}
   101  	return generate.BlocksByStart(blockConfig)
   102  }
   103  
   104  func writeCommitLogData(
   105  	t *testing.T,
   106  	s TestSetup,
   107  	opts commitlog.Options,
   108  	data generate.SeriesBlocksByStart,
   109  	namespace namespace.Metadata,
   110  	genSnapshots bool,
   111  ) int {
   112  	return writeCommitLogDataBase(t, s, opts, data, namespace, nil, nil)
   113  }
   114  
   115  func writeCommitLogDataSpecifiedTS(
   116  	t *testing.T,
   117  	s TestSetup,
   118  	opts commitlog.Options,
   119  	data generate.SeriesBlocksByStart,
   120  	namespace namespace.Metadata,
   121  	ts xtime.UnixNano,
   122  	genSnapshots bool,
   123  ) int {
   124  	return writeCommitLogDataBase(t, s, opts, data, namespace, &ts, nil)
   125  }
   126  
   127  func writeCommitLogDataWithPredicate(
   128  	t *testing.T,
   129  	s TestSetup,
   130  	opts commitlog.Options,
   131  	data generate.SeriesBlocksByStart,
   132  	namespace namespace.Metadata,
   133  	pred generate.WriteDatapointPredicate,
   134  ) int {
   135  	return writeCommitLogDataBase(t, s, opts, data, namespace, nil, pred)
   136  }
   137  
   138  // returns the number of data points written to the commit log
   139  func writeCommitLogDataBase(
   140  	t *testing.T,
   141  	s TestSetup,
   142  	opts commitlog.Options,
   143  	data generate.SeriesBlocksByStart,
   144  	namespace namespace.Metadata,
   145  	specifiedTS *xtime.UnixNano,
   146  	pred generate.WriteDatapointPredicate,
   147  ) int {
   148  	if pred == nil {
   149  		pred = generate.WriteAllPredicate
   150  	}
   151  
   152  	// ensure commit log is flushing frequently.
   153  	require.Equal(
   154  		t, defaultIntegrationTestFlushInterval, opts.FlushInterval())
   155  
   156  	var (
   157  		seriesLookup   = newCommitLogSeriesStates(data)
   158  		shardSet       = s.ShardSet()
   159  		tagEncoderPool = opts.FilesystemOptions().TagEncoderPool()
   160  		tagSliceIter   = ident.NewTagsIterator(ident.Tags{})
   161  		writes         int
   162  	)
   163  
   164  	// Write out commit log data.
   165  	for currTs, blk := range data {
   166  		if specifiedTS != nil {
   167  			s.SetNowFn(*specifiedTS)
   168  		} else {
   169  			s.SetNowFn(currTs)
   170  		}
   171  		ctx := context.NewBackground()
   172  		defer ctx.Close()
   173  
   174  		m := map[xtime.UnixNano]generate.SeriesBlock{
   175  			currTs: blk,
   176  		}
   177  
   178  		points := generate.
   179  			ToPointsByTime(m).
   180  			Dearrange(defaultDerrangementPercent)
   181  
   182  		// create new commit log.
   183  		commitLog, err := commitlog.NewCommitLog(opts)
   184  		require.NoError(t, err)
   185  		require.NoError(t, commitLog.Open())
   186  
   187  		// write points.
   188  		for _, point := range points {
   189  			series, ok := seriesLookup[point.ID.String()]
   190  			require.True(t, ok)
   191  
   192  			tagSliceIter.Reset(series.tags)
   193  
   194  			tagEncoder := tagEncoderPool.Get()
   195  			err := tagEncoder.Encode(tagSliceIter)
   196  			require.NoError(t, err)
   197  
   198  			encodedTagsChecked, ok := tagEncoder.Data()
   199  			require.True(t, ok)
   200  
   201  			cID := ts.Series{
   202  				Namespace:   namespace.ID(),
   203  				Shard:       shardSet.Lookup(point.ID),
   204  				ID:          point.ID,
   205  				EncodedTags: ts.EncodedTags(encodedTagsChecked.Bytes()),
   206  				UniqueIndex: series.uniqueIndex,
   207  			}
   208  			if pred(point.Value) {
   209  				require.NoError(t, commitLog.Write(ctx, cID, point.Value.Datapoint, xtime.Second, point.Value.Annotation))
   210  				writes++
   211  			}
   212  		}
   213  
   214  		// ensure writes finished.
   215  		require.NoError(t, commitLog.Close())
   216  	}
   217  	return writes
   218  }
   219  
   220  func writeSnapshotsWithPredicate(
   221  	t *testing.T,
   222  	s TestSetup,
   223  	opts commitlog.Options,
   224  	data generate.SeriesBlocksByStart,
   225  	volume int,
   226  	namespace namespace.Metadata,
   227  	specifiedTS *time.Time,
   228  	pred generate.WriteDatapointPredicate,
   229  	snapshotInterval time.Duration,
   230  ) {
   231  	// Write out snapshots
   232  	err := writeTestSnapshotsToDiskWithPredicate(
   233  		namespace, s, data, volume, pred, snapshotInterval)
   234  	require.NoError(t, err)
   235  }