github.com/m3db/m3@v1.5.0/src/dbnode/persist/fs/index_write_test.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package fs
    22  
    23  import (
    24  	"fmt"
    25  	iofs "io/fs"
    26  	"io/ioutil"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/m3db/m3/src/dbnode/persist"
    31  	idxpersist "github.com/m3db/m3/src/m3ninx/persist"
    32  	xerrors "github.com/m3db/m3/src/x/errors"
    33  	xtime "github.com/m3db/m3/src/x/time"
    34  
    35  	"github.com/golang/mock/gomock"
    36  	"github.com/stretchr/testify/assert"
    37  	"github.com/stretchr/testify/require"
    38  )
    39  
    40  func TestSnapshotIndexWriter(t *testing.T) {
    41  	ctrl := gomock.NewController(t)
    42  	defer ctrl.Finish()
    43  
    44  	test := newIndexWriteTestSetup(t)
    45  	defer test.cleanup()
    46  
    47  	testSnapshotSegments := []struct {
    48  		snapshotIndex int
    49  		snapshotTime  xtime.UnixNano
    50  		shards        map[uint32]struct{}
    51  		segments      []testIndexSegment
    52  	}{
    53  		{
    54  			snapshotIndex: 0,
    55  			snapshotTime:  test.now.Add(-2 * time.Minute),
    56  			shards:        shardsSet(1, 2, 4),
    57  			segments: []testIndexSegment{
    58  				{
    59  					segmentType:  idxpersist.IndexSegmentType("fst"),
    60  					majorVersion: 1,
    61  					minorVersion: 2,
    62  					metadata:     []byte("some_metadata"),
    63  					files: []testIndexSegmentFile{
    64  						{idxpersist.IndexSegmentFileType("first"), randDataFactorOfBuffSize(t, 1.5)},
    65  						{idxpersist.IndexSegmentFileType("second"), randDataFactorOfBuffSize(t, 2.5)},
    66  					},
    67  				},
    68  			},
    69  		},
    70  		{
    71  			snapshotIndex: 1,
    72  			snapshotTime:  test.now.Add(-1 * time.Minute),
    73  			shards:        shardsSet(1, 3, 5),
    74  			segments: []testIndexSegment{
    75  				{
    76  					segmentType:  idxpersist.IndexSegmentType("fst"),
    77  					majorVersion: 3,
    78  					minorVersion: 4,
    79  					metadata:     []byte("some_other_metadata"),
    80  					files: []testIndexSegmentFile{
    81  						{idxpersist.IndexSegmentFileType("first"), randDataFactorOfBuffSize(t, 1.5)},
    82  						{idxpersist.IndexSegmentFileType("second"), randDataFactorOfBuffSize(t, 3.5)},
    83  					},
    84  				},
    85  			},
    86  		},
    87  	}
    88  
    89  	// Write the data out
    90  	writer := newTestIndexWriter(t, test.filePathPrefix)
    91  	for _, snapshot := range testSnapshotSegments {
    92  		// Add the snapshot index to the file set ID
    93  		fileSetID := test.fileSetID
    94  		fileSetID.VolumeIndex = snapshot.snapshotIndex
    95  
    96  		err := writer.Open(IndexWriterOpenOptions{
    97  			Identifier:  fileSetID,
    98  			BlockSize:   test.blockSize,
    99  			FileSetType: persist.FileSetSnapshotType,
   100  			Snapshot: IndexWriterSnapshotOptions{
   101  				SnapshotTime: snapshot.snapshotTime,
   102  			},
   103  			Shards: snapshot.shards,
   104  		})
   105  		require.NoError(t, err)
   106  
   107  		writeTestIndexSegments(t, ctrl, writer, snapshot.segments)
   108  
   109  		err = writer.Close()
   110  		require.NoError(t, err)
   111  	}
   112  
   113  	// Verify files look good
   114  	snapshotsDir := NamespaceIndexSnapshotDirPath(test.filePathPrefix,
   115  		test.fileSetID.Namespace)
   116  	files, err := ioutil.ReadDir(snapshotsDir)
   117  	require.NoError(t, err)
   118  
   119  	var actualFiles []string
   120  	for _, file := range files {
   121  		actualFiles = append(actualFiles, file.Name())
   122  	}
   123  	require.Equal(t, []string{
   124  		fmt.Sprintf("fileset-%d-0-checkpoint.db", test.blockStart),
   125  		fmt.Sprintf("fileset-%d-0-digest.db", test.blockStart),
   126  		fmt.Sprintf("fileset-%d-0-info.db", test.blockStart),
   127  		fmt.Sprintf("fileset-%d-0-segment-0-first.db", test.blockStart),
   128  		fmt.Sprintf("fileset-%d-0-segment-0-second.db", test.blockStart),
   129  		fmt.Sprintf("fileset-%d-1-checkpoint.db", test.blockStart),
   130  		fmt.Sprintf("fileset-%d-1-digest.db", test.blockStart),
   131  		fmt.Sprintf("fileset-%d-1-info.db", test.blockStart),
   132  		fmt.Sprintf("fileset-%d-1-segment-0-first.db", test.blockStart),
   133  		fmt.Sprintf("fileset-%d-1-segment-0-second.db", test.blockStart),
   134  	}, actualFiles)
   135  
   136  	// Verify can read them
   137  	reader := newTestIndexReader(t, test.filePathPrefix,
   138  		testIndexReaderOptions{})
   139  	for _, snapshot := range testSnapshotSegments {
   140  		// Add the snapshot index to the file set ID
   141  		fileSetID := test.fileSetID
   142  		fileSetID.VolumeIndex = snapshot.snapshotIndex
   143  
   144  		result, err := reader.Open(IndexReaderOpenOptions{
   145  			Identifier:  fileSetID,
   146  			FileSetType: persist.FileSetSnapshotType,
   147  		})
   148  		require.NoError(t, err)
   149  		require.Equal(t, snapshot.shards, result.Shards)
   150  
   151  		readTestIndexSegments(t, ctrl, reader, snapshot.segments)
   152  
   153  		err = reader.Validate()
   154  		require.NoError(t, err)
   155  
   156  		err = reader.Close()
   157  		require.NoError(t, err)
   158  	}
   159  }
   160  
   161  func TestIndexWriterFilesetErrExists(t *testing.T) {
   162  	test := newIndexWriteTestSetup(t)
   163  	defer test.cleanup()
   164  
   165  	writer := newTestIndexWriter(t, test.filePathPrefix)
   166  
   167  	indexWriterOpenOptions := IndexWriterOpenOptions{
   168  		Identifier:  test.fileSetID,
   169  		BlockSize:   test.blockSize,
   170  		FileSetType: persist.FileSetSnapshotType,
   171  		Shards:      map[uint32]struct{}{3: {}},
   172  	}
   173  
   174  	writeFn := func() error {
   175  		if err := writer.Open(indexWriterOpenOptions); err != nil {
   176  			return err
   177  		}
   178  		return writer.Close()
   179  	}
   180  
   181  	err := writeFn()
   182  	require.NoError(t, err)
   183  
   184  	err = writeFn()
   185  	require.Error(t, err)
   186  	assert.True(t, xerrors.Is(err, iofs.ErrExist))
   187  }