github.com/m3db/m3@v1.5.0/src/m3ninx/persist/writer.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 persist
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  
    28  	"github.com/m3db/m3/src/m3ninx/index/segment"
    29  	"github.com/m3db/m3/src/m3ninx/index/segment/fst"
    30  	"github.com/m3db/m3/src/m3ninx/x"
    31  )
    32  
    33  var (
    34  	errDocsDataFileNotWritten = errors.New("docs data file must be written before index data")
    35  )
    36  
    37  // NewMutableSegmentFileSetWriter returns a new IndexSegmentFileSetWriter for writing
    38  // out the provided Mutable Segment.
    39  func NewMutableSegmentFileSetWriter(
    40  	fstOpts fst.WriterOptions,
    41  ) (MutableSegmentFileSetWriter, error) {
    42  	w, err := fst.NewWriter(fstOpts)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	return newMutableSegmentFileSetWriter(w)
    47  }
    48  
    49  func newMutableSegmentFileSetWriter(
    50  	fsWriter fst.Writer,
    51  ) (MutableSegmentFileSetWriter, error) {
    52  	return &writer{
    53  		fsWriter: fsWriter,
    54  	}, nil
    55  }
    56  
    57  type writer struct {
    58  	fsWriter fst.Writer
    59  }
    60  
    61  func (w *writer) Reset(builder segment.Builder) error {
    62  	return w.fsWriter.Reset(builder)
    63  }
    64  
    65  func (w *writer) SegmentType() IndexSegmentType {
    66  	return FSTIndexSegmentType
    67  }
    68  
    69  func (w *writer) MajorVersion() int {
    70  	return w.fsWriter.MajorVersion()
    71  }
    72  
    73  func (w *writer) MinorVersion() int {
    74  	return w.fsWriter.MinorVersion()
    75  }
    76  
    77  func (w *writer) SegmentMetadata() []byte {
    78  	return w.fsWriter.Metadata()
    79  }
    80  
    81  func (w *writer) Files() []IndexSegmentFileType {
    82  	// NB(prateek): order is important here. It is the order of files written out,
    83  	// and needs to be maintained as it is below.
    84  	return []IndexSegmentFileType{
    85  		DocumentDataIndexSegmentFileType,
    86  		DocumentIndexIndexSegmentFileType,
    87  		PostingsIndexSegmentFileType,
    88  		FSTTermsIndexSegmentFileType,
    89  		FSTFieldsIndexSegmentFileType,
    90  	}
    91  }
    92  
    93  func (w *writer) WriteFile(fileType IndexSegmentFileType, iow io.Writer) error {
    94  	switch fileType {
    95  	case DocumentDataIndexSegmentFileType:
    96  		return w.fsWriter.WriteDocumentsData(iow)
    97  	case DocumentIndexIndexSegmentFileType:
    98  		return w.fsWriter.WriteDocumentsIndex(iow)
    99  	case PostingsIndexSegmentFileType:
   100  		return w.fsWriter.WritePostingsOffsets(iow)
   101  	case FSTFieldsIndexSegmentFileType:
   102  		return w.fsWriter.WriteFSTFields(iow)
   103  	case FSTTermsIndexSegmentFileType:
   104  		return w.fsWriter.WriteFSTTerms(iow)
   105  	}
   106  	return fmt.Errorf("unknown fileType: %s provided", fileType)
   107  }
   108  
   109  // NewFSTSegmentDataFileSetWriter creates a new file set writer for
   110  // fst segment data.
   111  func NewFSTSegmentDataFileSetWriter(
   112  	data fst.SegmentData,
   113  ) (IndexSegmentFileSetWriter, error) {
   114  	if err := data.Validate(); err != nil {
   115  		return nil, err
   116  	}
   117  
   118  	docsWriter, err := fst.NewDocumentsWriter()
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  
   123  	return &fstSegmentDataWriter{
   124  		data:       data,
   125  		docsWriter: docsWriter,
   126  	}, nil
   127  }
   128  
   129  type fstSegmentDataWriter struct {
   130  	data                fst.SegmentData
   131  	docsWriter          *fst.DocumentsWriter
   132  	docsDataFileWritten bool
   133  }
   134  
   135  func (w *fstSegmentDataWriter) SegmentType() IndexSegmentType {
   136  	return FSTIndexSegmentType
   137  }
   138  
   139  func (w *fstSegmentDataWriter) MajorVersion() int {
   140  	return w.data.Version.Major
   141  }
   142  
   143  func (w *fstSegmentDataWriter) MinorVersion() int {
   144  	return w.data.Version.Minor
   145  }
   146  
   147  func (w *fstSegmentDataWriter) SegmentMetadata() []byte {
   148  	return w.data.Metadata
   149  }
   150  
   151  func (w *fstSegmentDataWriter) Files() []IndexSegmentFileType {
   152  	return []IndexSegmentFileType{
   153  		DocumentDataIndexSegmentFileType,
   154  		DocumentIndexIndexSegmentFileType,
   155  		PostingsIndexSegmentFileType,
   156  		FSTTermsIndexSegmentFileType,
   157  		FSTFieldsIndexSegmentFileType,
   158  	}
   159  }
   160  
   161  func (w *fstSegmentDataWriter) WriteFile(fileType IndexSegmentFileType, iow io.Writer) error {
   162  	switch fileType {
   163  	case DocumentDataIndexSegmentFileType:
   164  		if err := w.writeDocsData(iow); err != nil {
   165  			return err
   166  		}
   167  		w.docsDataFileWritten = true
   168  		return nil
   169  	case DocumentIndexIndexSegmentFileType:
   170  		if !w.docsDataFileWritten {
   171  			return errDocsDataFileNotWritten
   172  		}
   173  		return w.writeDocsIndex(iow)
   174  	case PostingsIndexSegmentFileType:
   175  		_, err := iow.Write(w.data.PostingsData.Bytes)
   176  		return err
   177  	case FSTFieldsIndexSegmentFileType:
   178  		_, err := iow.Write(w.data.FSTFieldsData.Bytes)
   179  		return err
   180  	case FSTTermsIndexSegmentFileType:
   181  		_, err := iow.Write(w.data.FSTTermsData.Bytes)
   182  		return err
   183  	}
   184  	return fmt.Errorf("unknown fileType: %s provided", fileType)
   185  }
   186  
   187  func (w *fstSegmentDataWriter) writeDocsData(iow io.Writer) error {
   188  	if r := w.data.DocsReader; r != nil {
   189  		iter := r.Iter()
   190  		closer := x.NewSafeCloser(iter)
   191  		defer closer.Close()
   192  		w.docsWriter.Reset(fst.DocumentsWriterOptions{
   193  			Iter:     iter,
   194  			SizeHint: r.Len(),
   195  		})
   196  		return w.docsWriter.WriteDocumentsData(iow)
   197  	}
   198  
   199  	_, err := iow.Write(w.data.DocsData.Bytes)
   200  	return err
   201  }
   202  
   203  func (w *fstSegmentDataWriter) writeDocsIndex(iow io.Writer) error {
   204  	if r := w.data.DocsReader; r != nil {
   205  		return w.docsWriter.WriteDocumentsIndex(iow)
   206  	}
   207  
   208  	_, err := iow.Write(w.data.DocsData.Bytes)
   209  	return err
   210  }