github.com/m3db/m3@v1.5.0/src/dbnode/persist/fs/clone/cloner.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 clone
    22  
    23  import (
    24  	"fmt"
    25  	"io"
    26  	"time"
    27  
    28  	"github.com/m3db/m3/src/dbnode/persist"
    29  	"github.com/m3db/m3/src/dbnode/persist/fs"
    30  	"github.com/m3db/m3/src/x/ident"
    31  	"github.com/m3db/m3/src/x/ident/testutil"
    32  )
    33  
    34  type cloner struct {
    35  	opts Options
    36  }
    37  
    38  // New creates a new fileset cloner
    39  func New(opts Options) FileSetCloner {
    40  	return &cloner{
    41  		opts: opts,
    42  	}
    43  }
    44  
    45  func (c *cloner) Clone(src FileSetID, dest FileSetID, destBlocksize time.Duration) error {
    46  	fsopts := fs.NewOptions().
    47  		SetDataReaderBufferSize(c.opts.BufferSize()).
    48  		SetInfoReaderBufferSize(c.opts.BufferSize()).
    49  		SetWriterBufferSize(c.opts.BufferSize()).
    50  		SetNewFileMode(c.opts.FileMode()).
    51  		SetNewDirectoryMode(c.opts.DirMode())
    52  	reader, err := fs.NewReader(nil, fsopts.SetFilePathPrefix(src.PathPrefix))
    53  	if err != nil {
    54  		return fmt.Errorf("unable to create fileset reader: %v", err)
    55  	}
    56  	openOpts := fs.DataReaderOpenOptions{
    57  		Identifier: fs.FileSetFileIdentifier{
    58  			Namespace:  ident.StringID(src.Namespace),
    59  			Shard:      src.Shard,
    60  			BlockStart: src.Blockstart,
    61  		},
    62  		FileSetType: persist.FileSetFlushType,
    63  	}
    64  
    65  	if err := reader.Open(openOpts); err != nil {
    66  		return fmt.Errorf("unable to read source fileset: %v", err)
    67  	}
    68  
    69  	writer, err := fs.NewWriter(fsopts.SetFilePathPrefix(dest.PathPrefix))
    70  	if err != nil {
    71  		return fmt.Errorf("unable to create fileset writer: %v", err)
    72  	}
    73  	writerOpts := fs.DataWriterOpenOptions{
    74  		BlockSize: destBlocksize,
    75  		Identifier: fs.FileSetFileIdentifier{
    76  			Namespace:  ident.StringID(dest.Namespace),
    77  			Shard:      dest.Shard,
    78  			BlockStart: dest.Blockstart,
    79  		},
    80  	}
    81  	if err := writer.Open(writerOpts); err != nil {
    82  		return fmt.Errorf("unable to open fileset writer: %v", err)
    83  	}
    84  
    85  	for {
    86  		id, tagsIter, data, checksum, err := reader.Read()
    87  		if err != nil {
    88  			if err == io.EOF {
    89  				break
    90  			}
    91  			return fmt.Errorf("unexpected error while reading data: %v", err)
    92  		}
    93  
    94  		tags, err := testutil.NewTagsFromTagIterator(tagsIter)
    95  		if err != nil {
    96  			return err
    97  		}
    98  
    99  		data.IncRef()
   100  		metadata := persist.NewMetadataFromIDAndTags(id, tags,
   101  			persist.MetadataOptions{})
   102  		if err := writer.Write(metadata, data, checksum); err != nil {
   103  			return fmt.Errorf("unexpected error while writing data: %v", err)
   104  		}
   105  		data.DecRef()
   106  		data.Finalize()
   107  	}
   108  
   109  	if err := writer.Close(); err != nil {
   110  		return fmt.Errorf("unable to finalize writer: %v", err)
   111  	}
   112  
   113  	if err := reader.Close(); err != nil {
   114  		return fmt.Errorf("unable to finalize reader: %v", err)
   115  	}
   116  
   117  	return nil
   118  }