github.com/m3db/m3@v1.5.0/src/dbnode/persist/fs/index_read_segments.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  	"errors"
    25  	"fmt"
    26  	"io"
    27  
    28  	"github.com/m3db/m3/src/m3ninx/index/segment"
    29  	m3ninxpersist "github.com/m3db/m3/src/m3ninx/persist"
    30  )
    31  
    32  var (
    33  	errFilesystemOptionsNotSpecified = errors.New("filesystem options not specified")
    34  )
    35  
    36  // ReadIndexSegmentsOptions is a set of options used when reading
    37  // index segments.
    38  type ReadIndexSegmentsOptions struct {
    39  	// ReaderOptions is the index file set reader options.
    40  	ReaderOptions IndexReaderOpenOptions
    41  
    42  	// FilesystemOptions is the filesystem options which is
    43  	// required for reading index segments.
    44  	FilesystemOptions Options
    45  
    46  	// Unexported fields that are hooks used for testing.
    47  	newReaderFn            newIndexReaderFn
    48  	newPersistentSegmentFn newPersistentSegmentFn
    49  }
    50  
    51  // ReadIndexSegmentsResult is the result of a call to ReadIndexSegments.
    52  type ReadIndexSegmentsResult struct {
    53  	Segments  []segment.Segment
    54  	Validated bool
    55  }
    56  
    57  // ReadIndexSegments will read a set of segments.
    58  func ReadIndexSegments(
    59  	opts ReadIndexSegmentsOptions,
    60  ) (ReadIndexSegmentsResult, error) {
    61  	readerOpts := opts.ReaderOptions
    62  	fsOpts := opts.FilesystemOptions
    63  	if fsOpts == nil {
    64  		return ReadIndexSegmentsResult{}, errFilesystemOptionsNotSpecified
    65  	}
    66  
    67  	newReader := opts.newReaderFn
    68  	if newReader == nil {
    69  		newReader = NewIndexReader
    70  	}
    71  
    72  	newPersistentSegment := opts.newPersistentSegmentFn
    73  	if newPersistentSegment == nil {
    74  		newPersistentSegment = m3ninxpersist.NewSegment
    75  	}
    76  
    77  	reader, err := newReader(fsOpts)
    78  	if err != nil {
    79  		return ReadIndexSegmentsResult{}, err
    80  	}
    81  
    82  	var (
    83  		segments []segment.Segment
    84  		validate = opts.FilesystemOptions.IndexReaderAutovalidateIndexSegments()
    85  		success  = false
    86  	)
    87  
    88  	// Need to do this to guarantee we release all resources in case of failure.
    89  	defer func() {
    90  		if !success {
    91  			for _, seg := range segments {
    92  				seg.Close()
    93  			}
    94  			reader.Close()
    95  		}
    96  	}()
    97  
    98  	if _, err := reader.Open(readerOpts); err != nil {
    99  		return ReadIndexSegmentsResult{}, err
   100  	}
   101  	segments = make([]segment.Segment, 0, reader.SegmentFileSets())
   102  
   103  	for {
   104  		fileset, err := reader.ReadSegmentFileSet()
   105  		if err == io.EOF {
   106  			break
   107  		}
   108  		if err != nil {
   109  			return ReadIndexSegmentsResult{}, err
   110  		}
   111  
   112  		fstOpts := fsOpts.FSTOptions()
   113  		seg, err := newPersistentSegment(fileset, fstOpts)
   114  		if err != nil {
   115  			return ReadIndexSegmentsResult{}, err
   116  		}
   117  
   118  		segments = append(segments, seg)
   119  	}
   120  
   121  	// Note: need to validate after all segment file sets read.
   122  	if validate {
   123  		if err = reader.Validate(); err != nil {
   124  			return ReadIndexSegmentsResult{}, fmt.Errorf("failed to validate index segments: %w", err)
   125  		}
   126  	}
   127  
   128  	// Indicate we don't need the defer() above to release any resources, as we are
   129  	// transferring ownership to the caller.
   130  	success = true
   131  	return ReadIndexSegmentsResult{
   132  		Segments:  segments,
   133  		Validated: validate,
   134  	}, nil
   135  }