github.com/m3db/m3@v1.5.0/src/dbnode/persist/fs/read_decode_stream.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  	"bytes"
    25  	"fmt"
    26  	"io"
    27  
    28  	"github.com/m3db/m3/src/dbnode/digest"
    29  	"github.com/m3db/m3/src/dbnode/persist/fs/msgpack"
    30  )
    31  
    32  type dataFileSetReaderDecoderStream interface {
    33  	msgpack.ByteDecoderStream
    34  
    35  	// reader returns the underlying reader with access to the
    36  	// incremental computed digest
    37  	reader() digest.ReaderWithDigest
    38  }
    39  
    40  type readerDecoderStream struct {
    41  	bytesReader      *bytes.Reader
    42  	readerWithDigest digest.ReaderWithDigest
    43  	backingBytes     []byte
    44  	buf              [64]byte
    45  	lastReadByte     int
    46  	unreadByte       int
    47  }
    48  
    49  func newReaderDecoderStream() dataFileSetReaderDecoderStream {
    50  	return &readerDecoderStream{
    51  		readerWithDigest: digest.NewReaderWithDigest(nil),
    52  		bytesReader:      bytes.NewReader(nil),
    53  	}
    54  }
    55  
    56  func (s *readerDecoderStream) reader() digest.ReaderWithDigest {
    57  	return s.readerWithDigest
    58  }
    59  
    60  func (s *readerDecoderStream) Reset(d []byte) {
    61  	s.bytesReader.Reset(d)
    62  	s.readerWithDigest.Reset(s.bytesReader)
    63  	s.backingBytes = d
    64  	s.lastReadByte = -1
    65  	s.unreadByte = -1
    66  }
    67  
    68  func (s *readerDecoderStream) Read(p []byte) (int, error) {
    69  	if len(p) == 0 {
    70  		return 0, nil
    71  	}
    72  
    73  	ref := p
    74  
    75  	var numUnreadByte int
    76  	if s.unreadByte >= 0 {
    77  		p[0] = byte(s.unreadByte)
    78  		p = p[1:]
    79  		s.unreadByte = -1
    80  		numUnreadByte = 1
    81  	}
    82  	n, err := s.readerWithDigest.Read(p)
    83  	n += numUnreadByte
    84  	if n > 0 {
    85  		s.lastReadByte = int(ref[n-1])
    86  	}
    87  	if err == io.EOF && n > 0 {
    88  		return n, nil // return EOF next time, might be returning last byte still
    89  	}
    90  	return n, err
    91  }
    92  
    93  func (s *readerDecoderStream) ReadByte() (byte, error) {
    94  	if s.unreadByte >= 0 {
    95  		r := byte(s.unreadByte)
    96  		s.unreadByte = -1
    97  		return r, nil
    98  	}
    99  	n, err := s.readerWithDigest.Read(s.buf[:1])
   100  	if n > 0 {
   101  		s.lastReadByte = int(s.buf[0])
   102  	}
   103  	return s.buf[0], err
   104  }
   105  
   106  func (s *readerDecoderStream) UnreadByte() error {
   107  	if s.lastReadByte < 0 {
   108  		return fmt.Errorf("no previous read byte or already unread byte")
   109  	}
   110  	s.unreadByte = s.lastReadByte
   111  	s.lastReadByte = -1
   112  	return nil
   113  }
   114  
   115  func (s *readerDecoderStream) Bytes() []byte {
   116  	return s.backingBytes
   117  }
   118  
   119  func (s *readerDecoderStream) Skip(length int64) error {
   120  	// NB(r): This ensures the reader with digest is always read
   121  	// from start to end, i.e. to calculate digest properly.
   122  	remaining := length
   123  	for {
   124  		readEnd := int64(len(s.buf))
   125  		if remaining < readEnd {
   126  			readEnd = remaining
   127  		}
   128  		n, err := s.Read(s.buf[:readEnd])
   129  		if err != nil {
   130  			return err
   131  		}
   132  		remaining -= int64(n)
   133  		if remaining < 0 {
   134  			return fmt.Errorf("skipped too far, remaining is: %d", remaining)
   135  		}
   136  		if remaining == 0 {
   137  			return nil
   138  		}
   139  	}
   140  }
   141  
   142  func (s *readerDecoderStream) Remaining() int64 {
   143  	var unreadBytes int64
   144  	if s.unreadByte != -1 {
   145  		unreadBytes = 1
   146  	}
   147  	return int64(s.bytesReader.Len()) + unreadBytes
   148  }
   149  
   150  func (s *readerDecoderStream) Offset() int {
   151  	return len(s.backingBytes) - int(s.Remaining())
   152  }