github.com/m3db/m3@v1.5.0/src/m3em/os/fs/file_reader_iter.go (about)

     1  // Copyright (c) 2017 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  	"bufio"
    25  	"io"
    26  	"os"
    27  
    28  	"github.com/m3db/m3/src/m3em/checksum"
    29  )
    30  
    31  const (
    32  	defaultBufferSize = 1024
    33  )
    34  
    35  type bufferedFileReaderIter struct {
    36  	currentBytes   []byte
    37  	checksum       checksum.Accumulator
    38  	bufferedReader *bufio.Reader
    39  	fileHandle     *os.File
    40  	err            error
    41  	done           bool
    42  	init           bool
    43  }
    44  
    45  // NewFileReaderIter creates a new buffered FileReaderIter
    46  func NewFileReaderIter(
    47  	filepath string,
    48  ) (FileReaderIter, error) {
    49  	return NewSizedFileReaderIter(filepath, defaultBufferSize)
    50  }
    51  
    52  // NewSizedFileReaderIter creates a new buffered FileReaderIter
    53  func NewSizedFileReaderIter(
    54  	filepath string,
    55  	bufferSize int,
    56  ) (FileReaderIter, error) {
    57  	fhandle, err := os.Open(filepath)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	var (
    62  		bytes      = make([]byte, bufferSize)
    63  		buffReader = bufio.NewReaderSize(fhandle, bufferSize)
    64  		iter       = &bufferedFileReaderIter{
    65  			currentBytes:   bytes,
    66  			checksum:       checksum.NewAccumulator(),
    67  			bufferedReader: buffReader,
    68  			fileHandle:     fhandle,
    69  		}
    70  	)
    71  	return iter, nil
    72  }
    73  
    74  func (r *bufferedFileReaderIter) Current() []byte {
    75  	if r.Err() != nil {
    76  		return nil
    77  	}
    78  
    79  	return r.currentBytes
    80  }
    81  
    82  func (r *bufferedFileReaderIter) Next() bool {
    83  	if !r.init {
    84  		r.init = true
    85  	}
    86  
    87  	if r.done || r.err != nil {
    88  		return false
    89  	}
    90  
    91  	n, err := r.bufferedReader.Read(r.currentBytes)
    92  	if err != nil && err != io.EOF {
    93  		r.err = err
    94  		r.Close()
    95  		return false
    96  	}
    97  
    98  	bytes := r.currentBytes[:n]
    99  	r.checksum.Update(bytes)
   100  	r.currentBytes = bytes
   101  	if err == io.EOF {
   102  		r.done = true
   103  		r.Close()
   104  	}
   105  
   106  	return true
   107  }
   108  
   109  func (r *bufferedFileReaderIter) Close() error {
   110  	handle := r.fileHandle
   111  	r.fileHandle = nil
   112  	r.currentBytes = nil
   113  	r.bufferedReader = nil
   114  	if handle != nil {
   115  		return handle.Close()
   116  	}
   117  	return nil
   118  }
   119  
   120  func (r *bufferedFileReaderIter) Checksum() uint32 {
   121  	return r.checksum.Current()
   122  }
   123  
   124  func (r *bufferedFileReaderIter) Err() error {
   125  	return r.err
   126  }