16
16
17
17
package com .google .cloud .storage ;
18
18
19
- import static com .google .common .base .Preconditions .checkArgument ;
20
-
21
19
import com .google .api .client .http .HttpStatusCodes ;
22
20
import com .google .api .core .ApiFuture ;
23
21
import com .google .api .core .SettableApiFuture ;
24
22
import com .google .api .gax .rpc .ServerStream ;
25
23
import com .google .api .gax .rpc .ServerStreamingCallable ;
26
24
import com .google .cloud .storage .Crc32cValue .Crc32cLengthKnown ;
27
25
import com .google .cloud .storage .UnbufferedReadableByteChannelSession .UnbufferedReadableByteChannel ;
26
+ import com .google .protobuf .ByteString ;
28
27
import com .google .storage .v2 .ChecksummedData ;
29
28
import com .google .storage .v2 .Object ;
30
29
import com .google .storage .v2 .ReadObjectRequest ;
@@ -46,25 +45,28 @@ final class GapicUnbufferedReadableByteChannel
46
45
private final ReadObjectRequest req ;
47
46
private final Hasher hasher ;
48
47
private final LazyServerStreamIterator iter ;
48
+ private final ResponseContentLifecycleManager rclm ;
49
49
50
50
private boolean open = true ;
51
51
private boolean complete = false ;
52
52
private long blobOffset ;
53
53
54
54
private Object metadata ;
55
55
56
- private ByteBuffer leftovers ;
56
+ private ResponseContentLifecycleHandle leftovers ;
57
57
58
58
GapicUnbufferedReadableByteChannel (
59
59
SettableApiFuture <Object > result ,
60
60
ServerStreamingCallable <ReadObjectRequest , ReadObjectResponse > read ,
61
61
ReadObjectRequest req ,
62
- Hasher hasher ) {
62
+ Hasher hasher ,
63
+ ResponseContentLifecycleManager rclm ) {
63
64
this .result = result ;
64
65
this .read = read ;
65
66
this .req = req ;
66
67
this .hasher = hasher ;
67
68
this .blobOffset = req .getReadOffset ();
69
+ this .rclm = rclm ;
68
70
this .iter = new LazyServerStreamIterator ();
69
71
}
70
72
@@ -82,15 +84,17 @@ public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
82
84
ReadCursor c = new ReadCursor (blobOffset , blobOffset + totalBufferCapacity );
83
85
while (c .hasRemaining ()) {
84
86
if (leftovers != null ) {
85
- copy (c , leftovers , dsts , offset , length );
87
+ leftovers . copy (c , dsts , offset , length );
86
88
if (!leftovers .hasRemaining ()) {
89
+ leftovers .close ();
87
90
leftovers = null ;
88
91
}
89
92
continue ;
90
93
}
91
94
92
95
if (iter .hasNext ()) {
93
96
ReadObjectResponse resp = iter .next ();
97
+ ResponseContentLifecycleHandle handle = rclm .get (resp );
94
98
if (resp .hasMetadata ()) {
95
99
Object respMetadata = resp .getMetadata ();
96
100
if (metadata == null ) {
@@ -107,22 +111,24 @@ public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
107
111
}
108
112
}
109
113
ChecksummedData checksummedData = resp .getChecksummedData ();
110
- ByteBuffer content = checksummedData .getContent ().asReadOnlyByteBuffer ();
111
- // very important to know whether a crc32c value is set. Without checking, protobuf will
114
+ ByteString content = checksummedData .getContent ();
115
+ int contentSize = content .size ();
116
+ // Very important to know whether a crc32c value is set. Without checking, protobuf will
112
117
// happily return 0, which is a valid crc32c value.
113
118
if (checksummedData .hasCrc32C ()) {
114
- Crc32cLengthKnown expected =
115
- Crc32cValue .of (checksummedData .getCrc32C (), checksummedData .getContent ().size ());
119
+ Crc32cLengthKnown expected = Crc32cValue .of (checksummedData .getCrc32C (), contentSize );
116
120
try {
117
- hasher .validate (expected , content :: duplicate );
121
+ hasher .validate (expected , content . asReadOnlyByteBufferList () );
118
122
} catch (IOException e ) {
119
123
close ();
120
124
throw e ;
121
125
}
122
126
}
123
- copy (c , content , dsts , offset , length );
124
- if (content .hasRemaining ()) {
125
- leftovers = content ;
127
+ handle .copy (c , dsts , offset , length );
128
+ if (handle .hasRemaining ()) {
129
+ leftovers = handle ;
130
+ } else {
131
+ handle .close ();
126
132
}
127
133
} else {
128
134
complete = true ;
@@ -144,59 +150,26 @@ public boolean isOpen() {
144
150
@ Override
145
151
public void close () throws IOException {
146
152
open = false ;
147
- iter .close ();
153
+ try {
154
+ if (leftovers != null ) {
155
+ leftovers .close ();
156
+ }
157
+ } finally {
158
+ iter .close ();
159
+ }
148
160
}
149
161
150
162
ApiFuture <Object > getResult () {
151
163
return result ;
152
164
}
153
165
154
- private void copy (ReadCursor c , ByteBuffer content , ByteBuffer [] dsts , int offset , int length ) {
155
- long copiedBytes = Buffers .copy (content , dsts , offset , length );
156
- c .advance (copiedBytes );
157
- }
158
-
159
166
private IOException closeWithError (String message ) throws IOException {
160
167
close ();
161
168
StorageException cause =
162
169
new StorageException (HttpStatusCodes .STATUS_CODE_PRECONDITION_FAILED , message );
163
170
throw new IOException (message , cause );
164
171
}
165
172
166
- /**
167
- * Shrink wraps a beginning, offset and limit for tracking state of an individual invocation of
168
- * {@link #read}
169
- */
170
- private static final class ReadCursor {
171
- private final long beginning ;
172
- private long offset ;
173
- private final long limit ;
174
-
175
- private ReadCursor (long beginning , long limit ) {
176
- this .limit = limit ;
177
- this .beginning = beginning ;
178
- this .offset = beginning ;
179
- }
180
-
181
- public boolean hasRemaining () {
182
- return limit - offset > 0 ;
183
- }
184
-
185
- public void advance (long incr ) {
186
- checkArgument (incr >= 0 );
187
- offset += incr ;
188
- }
189
-
190
- public long read () {
191
- return offset - beginning ;
192
- }
193
-
194
- @ Override
195
- public String toString () {
196
- return String .format ("ReadCursor{begin=%d, offset=%d, limit=%d}" , beginning , offset , limit );
197
- }
198
- }
199
-
200
173
private final class LazyServerStreamIterator implements Iterator <ReadObjectResponse >, Closeable {
201
174
private ServerStream <ReadObjectResponse > serverStream ;
202
175
private Iterator <ReadObjectResponse > responseIterator ;
0 commit comments