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 }