github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/google.golang.org/appengine/blobstore/read.go (about) 1 // Copyright 2012 Google Inc. All rights reserved. 2 // Use of this source code is governed by the Apache 2.0 3 // license that can be found in the LICENSE file. 4 5 package blobstore 6 7 import ( 8 "errors" 9 "fmt" 10 "io" 11 "os" 12 "sync" 13 14 "github.com/golang/protobuf/proto" 15 "golang.org/x/net/context" 16 17 "google.golang.org/appengine" 18 "google.golang.org/appengine/internal" 19 20 blobpb "google.golang.org/appengine/internal/blobstore" 21 ) 22 23 // openBlob returns a reader for a blob. It always succeeds; if the blob does 24 // not exist then an error will be reported upon first read. 25 func openBlob(c context.Context, blobKey appengine.BlobKey) Reader { 26 return &reader{ 27 c: c, 28 blobKey: blobKey, 29 } 30 } 31 32 const readBufferSize = 256 * 1024 33 34 // reader is a blob reader. It implements the Reader interface. 35 type reader struct { 36 c context.Context 37 38 // Either blobKey or filename is set: 39 blobKey appengine.BlobKey 40 filename string 41 42 closeFunc func() // is nil if unavailable or already closed. 43 44 // buf is the read buffer. r is how much of buf has been read. 45 // off is the offset of buf[0] relative to the start of the blob. 46 // An invariant is 0 <= r && r <= len(buf). 47 // Reads that don't require an RPC call will increment r but not off. 48 // Seeks may modify r without discarding the buffer, but only if the 49 // invariant can be maintained. 50 mu sync.Mutex 51 buf []byte 52 r int 53 off int64 54 } 55 56 func (r *reader) Close() error { 57 if f := r.closeFunc; f != nil { 58 f() 59 } 60 r.closeFunc = nil 61 return nil 62 } 63 64 func (r *reader) Read(p []byte) (int, error) { 65 if len(p) == 0 { 66 return 0, nil 67 } 68 r.mu.Lock() 69 defer r.mu.Unlock() 70 if r.r == len(r.buf) { 71 if err := r.fetch(r.off + int64(r.r)); err != nil { 72 return 0, err 73 } 74 } 75 n := copy(p, r.buf[r.r:]) 76 r.r += n 77 return n, nil 78 } 79 80 func (r *reader) ReadAt(p []byte, off int64) (int, error) { 81 if len(p) == 0 { 82 return 0, nil 83 } 84 r.mu.Lock() 85 defer r.mu.Unlock() 86 // Convert relative offsets to absolute offsets. 87 ab0 := r.off + int64(r.r) 88 ab1 := r.off + int64(len(r.buf)) 89 ap0 := off 90 ap1 := off + int64(len(p)) 91 // Check if we can satisfy the read entirely out of the existing buffer. 92 if r.off <= ap0 && ap1 <= ab1 { 93 // Convert off from an absolute offset to a relative offset. 94 rp0 := int(ap0 - r.off) 95 return copy(p, r.buf[rp0:]), nil 96 } 97 // Restore the original Read/Seek offset after ReadAt completes. 98 defer r.seek(ab0) 99 // Repeatedly fetch and copy until we have filled p. 100 n := 0 101 for len(p) > 0 { 102 if err := r.fetch(off + int64(n)); err != nil { 103 return n, err 104 } 105 r.r = copy(p, r.buf) 106 n += r.r 107 p = p[r.r:] 108 } 109 return n, nil 110 } 111 112 func (r *reader) Seek(offset int64, whence int) (ret int64, err error) { 113 r.mu.Lock() 114 defer r.mu.Unlock() 115 switch whence { 116 case os.SEEK_SET: 117 ret = offset 118 case os.SEEK_CUR: 119 ret = r.off + int64(r.r) + offset 120 case os.SEEK_END: 121 return 0, errors.New("seeking relative to the end of a blob isn't supported") 122 default: 123 return 0, fmt.Errorf("invalid Seek whence value: %d", whence) 124 } 125 if ret < 0 { 126 return 0, errors.New("negative Seek offset") 127 } 128 return r.seek(ret) 129 } 130 131 // fetch fetches readBufferSize bytes starting at the given offset. On success, 132 // the data is saved as r.buf. 133 func (r *reader) fetch(off int64) error { 134 req := &blobpb.FetchDataRequest{ 135 BlobKey: proto.String(string(r.blobKey)), 136 StartIndex: proto.Int64(off), 137 EndIndex: proto.Int64(off + readBufferSize - 1), // EndIndex is inclusive. 138 } 139 res := &blobpb.FetchDataResponse{} 140 if err := internal.Call(r.c, "blobstore", "FetchData", req, res); err != nil { 141 return err 142 } 143 if len(res.Data) == 0 { 144 return io.EOF 145 } 146 r.buf, r.r, r.off = res.Data, 0, off 147 return nil 148 } 149 150 // seek seeks to the given offset with an effective whence equal to SEEK_SET. 151 // It discards the read buffer if the invariant cannot be maintained. 152 func (r *reader) seek(off int64) (int64, error) { 153 delta := off - r.off 154 if delta >= 0 && delta < int64(len(r.buf)) { 155 r.r = int(delta) 156 return off, nil 157 } 158 r.buf, r.r, r.off = nil, 0, off 159 return off, nil 160 }