github.com/LazyboyChen7/engine@v17.12.1-ce-rc2+incompatible/daemon/logger/loggerutils/multireader/multireader.go (about)

     1  package multireader
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  )
     9  
    10  type pos struct {
    11  	idx    int
    12  	offset int64
    13  }
    14  
    15  type multiReadSeeker struct {
    16  	readers []io.ReadSeeker
    17  	pos     *pos
    18  	posIdx  map[io.ReadSeeker]int
    19  }
    20  
    21  func (r *multiReadSeeker) Seek(offset int64, whence int) (int64, error) {
    22  	var tmpOffset int64
    23  	switch whence {
    24  	case os.SEEK_SET:
    25  		for i, rdr := range r.readers {
    26  			// get size of the current reader
    27  			s, err := rdr.Seek(0, os.SEEK_END)
    28  			if err != nil {
    29  				return -1, err
    30  			}
    31  
    32  			if offset > tmpOffset+s {
    33  				if i == len(r.readers)-1 {
    34  					rdrOffset := s + (offset - tmpOffset)
    35  					if _, err := rdr.Seek(rdrOffset, os.SEEK_SET); err != nil {
    36  						return -1, err
    37  					}
    38  					r.pos = &pos{i, rdrOffset}
    39  					return offset, nil
    40  				}
    41  
    42  				tmpOffset += s
    43  				continue
    44  			}
    45  
    46  			rdrOffset := offset - tmpOffset
    47  			idx := i
    48  
    49  			if _, err := rdr.Seek(rdrOffset, os.SEEK_SET); err != nil {
    50  				return -1, err
    51  			}
    52  			// make sure all following readers are at 0
    53  			for _, rdr := range r.readers[i+1:] {
    54  				rdr.Seek(0, os.SEEK_SET)
    55  			}
    56  
    57  			if rdrOffset == s && i != len(r.readers)-1 {
    58  				idx++
    59  				rdrOffset = 0
    60  			}
    61  			r.pos = &pos{idx, rdrOffset}
    62  			return offset, nil
    63  		}
    64  	case os.SEEK_END:
    65  		for _, rdr := range r.readers {
    66  			s, err := rdr.Seek(0, os.SEEK_END)
    67  			if err != nil {
    68  				return -1, err
    69  			}
    70  			tmpOffset += s
    71  		}
    72  		if _, err := r.Seek(tmpOffset+offset, os.SEEK_SET); err != nil {
    73  			return -1, err
    74  		}
    75  		return tmpOffset + offset, nil
    76  	case os.SEEK_CUR:
    77  		if r.pos == nil {
    78  			return r.Seek(offset, os.SEEK_SET)
    79  		}
    80  		// Just return the current offset
    81  		if offset == 0 {
    82  			return r.getCurOffset()
    83  		}
    84  
    85  		curOffset, err := r.getCurOffset()
    86  		if err != nil {
    87  			return -1, err
    88  		}
    89  		rdr, rdrOffset, err := r.getReaderForOffset(curOffset + offset)
    90  		if err != nil {
    91  			return -1, err
    92  		}
    93  
    94  		r.pos = &pos{r.posIdx[rdr], rdrOffset}
    95  		return curOffset + offset, nil
    96  	default:
    97  		return -1, fmt.Errorf("Invalid whence: %d", whence)
    98  	}
    99  
   100  	return -1, fmt.Errorf("Error seeking for whence: %d, offset: %d", whence, offset)
   101  }
   102  
   103  func (r *multiReadSeeker) getReaderForOffset(offset int64) (io.ReadSeeker, int64, error) {
   104  
   105  	var offsetTo int64
   106  
   107  	for _, rdr := range r.readers {
   108  		size, err := getReadSeekerSize(rdr)
   109  		if err != nil {
   110  			return nil, -1, err
   111  		}
   112  		if offsetTo+size > offset {
   113  			return rdr, offset - offsetTo, nil
   114  		}
   115  		if rdr == r.readers[len(r.readers)-1] {
   116  			return rdr, offsetTo + offset, nil
   117  		}
   118  		offsetTo += size
   119  	}
   120  
   121  	return nil, 0, nil
   122  }
   123  
   124  func (r *multiReadSeeker) getCurOffset() (int64, error) {
   125  	var totalSize int64
   126  	for _, rdr := range r.readers[:r.pos.idx+1] {
   127  		if r.posIdx[rdr] == r.pos.idx {
   128  			totalSize += r.pos.offset
   129  			break
   130  		}
   131  
   132  		size, err := getReadSeekerSize(rdr)
   133  		if err != nil {
   134  			return -1, fmt.Errorf("error getting seeker size: %v", err)
   135  		}
   136  		totalSize += size
   137  	}
   138  	return totalSize, nil
   139  }
   140  
   141  func (r *multiReadSeeker) getOffsetToReader(rdr io.ReadSeeker) (int64, error) {
   142  	var offset int64
   143  	for _, r := range r.readers {
   144  		if r == rdr {
   145  			break
   146  		}
   147  
   148  		size, err := getReadSeekerSize(rdr)
   149  		if err != nil {
   150  			return -1, err
   151  		}
   152  		offset += size
   153  	}
   154  	return offset, nil
   155  }
   156  
   157  func (r *multiReadSeeker) Read(b []byte) (int, error) {
   158  	if r.pos == nil {
   159  		// make sure all readers are at 0
   160  		r.Seek(0, os.SEEK_SET)
   161  	}
   162  
   163  	bLen := int64(len(b))
   164  	buf := bytes.NewBuffer(nil)
   165  	var rdr io.ReadSeeker
   166  
   167  	for _, rdr = range r.readers[r.pos.idx:] {
   168  		readBytes, err := io.CopyN(buf, rdr, bLen)
   169  		if err != nil && err != io.EOF {
   170  			return -1, err
   171  		}
   172  		bLen -= readBytes
   173  
   174  		if bLen == 0 {
   175  			break
   176  		}
   177  	}
   178  
   179  	rdrPos, err := rdr.Seek(0, os.SEEK_CUR)
   180  	if err != nil {
   181  		return -1, err
   182  	}
   183  	r.pos = &pos{r.posIdx[rdr], rdrPos}
   184  	return buf.Read(b)
   185  }
   186  
   187  func getReadSeekerSize(rdr io.ReadSeeker) (int64, error) {
   188  	// save the current position
   189  	pos, err := rdr.Seek(0, os.SEEK_CUR)
   190  	if err != nil {
   191  		return -1, err
   192  	}
   193  
   194  	// get the size
   195  	size, err := rdr.Seek(0, os.SEEK_END)
   196  	if err != nil {
   197  		return -1, err
   198  	}
   199  
   200  	// reset the position
   201  	if _, err := rdr.Seek(pos, os.SEEK_SET); err != nil {
   202  		return -1, err
   203  	}
   204  	return size, nil
   205  }
   206  
   207  // MultiReadSeeker returns a ReadSeeker that's the logical concatenation of the provided
   208  // input readseekers. After calling this method the initial position is set to the
   209  // beginning of the first ReadSeeker. At the end of a ReadSeeker, Read always advances
   210  // to the beginning of the next ReadSeeker and returns EOF at the end of the last ReadSeeker.
   211  // Seek can be used over the sum of lengths of all readseekers.
   212  //
   213  // When a MultiReadSeeker is used, no Read and Seek operations should be made on
   214  // its ReadSeeker components. Also, users should make no assumption on the state
   215  // of individual readseekers while the MultiReadSeeker is used.
   216  func MultiReadSeeker(readers ...io.ReadSeeker) io.ReadSeeker {
   217  	if len(readers) == 1 {
   218  		return readers[0]
   219  	}
   220  	idx := make(map[io.ReadSeeker]int)
   221  	for i, rdr := range readers {
   222  		idx[rdr] = i
   223  	}
   224  	return &multiReadSeeker{
   225  		readers: readers,
   226  		posIdx:  idx,
   227  	}
   228  }