github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/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 }