github.com/m3db/m3@v1.5.0/src/dbnode/integration/disk_cleanup_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  	"errors"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/m3db/m3/src/dbnode/namespace"
    31  	"github.com/m3db/m3/src/dbnode/persist/fs"
    32  	"github.com/m3db/m3/src/dbnode/persist/fs/commitlog"
    33  	"github.com/m3db/m3/src/dbnode/sharding"
    34  	"github.com/m3db/m3/src/dbnode/storage"
    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 errDataCleanupTimedOut = errors.New("cleaning up data files took too long")
    42  
    43  func newDataFileSetWriter(storageOpts storage.Options) (fs.DataFileSetWriter, error) {
    44  	fsOpts := storageOpts.CommitLogOptions().FilesystemOptions()
    45  	return fs.NewWriter(fsOpts)
    46  }
    47  
    48  func writeDataFileSetFiles(
    49  	t *testing.T, storageOpts storage.Options, md namespace.Metadata,
    50  	shard uint32, fileTimes []xtime.UnixNano,
    51  ) {
    52  	rOpts := md.Options().RetentionOptions()
    53  	writer, err := newDataFileSetWriter(storageOpts)
    54  	require.NoError(t, err)
    55  	for _, start := range fileTimes {
    56  		writerOpts := fs.DataWriterOpenOptions{
    57  			Identifier: fs.FileSetFileIdentifier{
    58  				Namespace:  md.ID(),
    59  				Shard:      shard,
    60  				BlockStart: start,
    61  			},
    62  			BlockSize: rOpts.BlockSize(),
    63  		}
    64  		require.NoError(t, writer.Open(writerOpts))
    65  		require.NoError(t, writer.Close())
    66  	}
    67  }
    68  
    69  func writeIndexFileSetFiles(t *testing.T, storageOpts storage.Options, md namespace.Metadata,
    70  	filesets []fs.FileSetFileIdentifier) {
    71  	blockSize := md.Options().IndexOptions().BlockSize()
    72  	fsOpts := storageOpts.CommitLogOptions().FilesystemOptions()
    73  	writer, err := fs.NewIndexWriter(fsOpts)
    74  	require.NoError(t, err)
    75  	for _, fileset := range filesets {
    76  		writerOpts := fs.IndexWriterOpenOptions{
    77  			Identifier: fileset,
    78  			BlockSize:  blockSize,
    79  			Shards:     map[uint32]struct{}{0: {}},
    80  		}
    81  		require.NoError(t, writer.Open(writerOpts))
    82  		require.NoError(t, writer.Close())
    83  	}
    84  }
    85  
    86  type cleanupTimesCommitLog struct {
    87  	clOpts  commitlog.Options
    88  	indices []int64
    89  }
    90  
    91  func (c *cleanupTimesCommitLog) anyExist() bool {
    92  	commitlogs, _, err := commitlog.Files(c.clOpts)
    93  	if err != nil {
    94  		panic(err)
    95  	}
    96  
    97  	for _, cl := range commitlogs {
    98  		for _, index := range c.indices {
    99  			if cl.Index == index {
   100  				return true
   101  			}
   102  		}
   103  	}
   104  
   105  	return false
   106  }
   107  
   108  type cleanupTimesFileSet struct {
   109  	filePathPrefix string
   110  	namespace      ident.ID
   111  	shard          uint32
   112  	times          []xtime.UnixNano
   113  }
   114  
   115  func (fset *cleanupTimesFileSet) anyExist() bool {
   116  	for _, t := range fset.times {
   117  		exists, err := fs.DataFileSetExists(fset.filePathPrefix, fset.namespace, fset.shard, t, 0)
   118  		if err != nil {
   119  			panic(err)
   120  		}
   121  
   122  		if exists {
   123  			return true
   124  		}
   125  	}
   126  	return false
   127  }
   128  
   129  func waitUntilDataCleanedUpExtended(
   130  	filesetFiles []cleanupTimesFileSet,
   131  	commitlog cleanupTimesCommitLog,
   132  	timeout time.Duration,
   133  ) error {
   134  	dataCleanedUp := func() bool {
   135  		if commitlog.anyExist() {
   136  			return false
   137  		}
   138  
   139  		for _, fset := range filesetFiles {
   140  			if fset.anyExist() {
   141  				return false
   142  			}
   143  		}
   144  
   145  		return true
   146  	}
   147  
   148  	if waitUntil(dataCleanedUp, timeout) {
   149  		return nil
   150  	}
   151  	return errDataCleanupTimedOut
   152  }
   153  
   154  // nolint: unused
   155  func waitUntilNamespacesCleanedUp(filePathPrefix string, namespace ident.ID, waitTimeout time.Duration) error {
   156  	dataCleanedUp := func() bool {
   157  		namespaceDir := fs.NamespaceDataDirPath(filePathPrefix, namespace)
   158  		exists, err := fs.FileExists(namespaceDir)
   159  		if err != nil {
   160  			panic(err)
   161  		}
   162  		return !exists
   163  	}
   164  
   165  	if waitUntil(dataCleanedUp, waitTimeout) {
   166  		return nil
   167  	}
   168  	return errDataCleanupTimedOut
   169  }
   170  
   171  // nolint: unused
   172  func waitUntilNamespacesHaveReset(testSetup TestSetup, newNamespaces []namespace.Metadata, newShardSet sharding.ShardSet) (TestSetup, error) {
   173  	err := testSetup.StopServer()
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	// Reset to the desired shard set and namespaces
   178  	// Because restarting the server would bootstrap
   179  	// To old data we wanted to delete
   180  	testSetup.SetOpts(testSetup.Opts().SetNamespaces(newNamespaces))
   181  
   182  	resetSetup, err := NewTestSetup(nil, testSetup.Opts(), testSetup.FilesystemOpts())
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	resetSetup.SetShardSet(newShardSet)
   187  	err = resetSetup.StartServer()
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  
   192  	return resetSetup, nil
   193  }
   194  
   195  // nolint: unused
   196  func waitUntilDataFileSetsCleanedUp(clOpts commitlog.Options, namespaces []storage.Namespace, extraShard uint32, waitTimeout time.Duration) error {
   197  	filePathPrefix := clOpts.FilesystemOptions().FilePathPrefix()
   198  	dataCleanedUp := func() bool {
   199  		for _, n := range namespaces {
   200  			shardDir := fs.ShardDataDirPath(filePathPrefix, n.ID(), extraShard)
   201  			exists, err := fs.FileExists(shardDir)
   202  			if err != nil {
   203  				panic(err)
   204  			}
   205  			if exists {
   206  				return false
   207  			}
   208  		}
   209  		return true
   210  	}
   211  
   212  	if waitUntil(dataCleanedUp, waitTimeout) {
   213  		return nil
   214  	}
   215  	return errDataCleanupTimedOut
   216  }
   217  
   218  func waitUntilDataCleanedUp(
   219  	clOpts commitlog.Options,
   220  	namespace ident.ID,
   221  	shard uint32,
   222  	toDelete xtime.UnixNano,
   223  	timeout time.Duration,
   224  ) error {
   225  	filePathPrefix := clOpts.FilesystemOptions().FilePathPrefix()
   226  	return waitUntilDataCleanedUpExtended(
   227  		[]cleanupTimesFileSet{
   228  			{
   229  				filePathPrefix: filePathPrefix,
   230  				namespace:      namespace,
   231  				shard:          shard,
   232  				times:          []xtime.UnixNano{toDelete},
   233  			},
   234  		},
   235  		cleanupTimesCommitLog{
   236  			clOpts:  clOpts,
   237  			indices: []int64{},
   238  		},
   239  		timeout)
   240  }