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