|
20 | 20 | import static org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Preconditions.checkState; |
21 | 21 |
|
22 | 22 | import com.google.auto.value.AutoValue; |
| 23 | +import java.io.IOException; |
| 24 | +import java.io.InputStream; |
23 | 25 | import java.util.ArrayList; |
24 | 26 | import java.util.Collections; |
25 | 27 | import java.util.Iterator; |
|
46 | 48 | import org.apache.beam.vendor.grpc.v1p69p0.com.google.protobuf.ByteString; |
47 | 49 | import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.annotations.VisibleForTesting; |
48 | 50 | import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Throwables; |
| 51 | +import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.AbstractIterator; |
49 | 52 |
|
50 | 53 | /** |
51 | 54 | * Adapters which convert a logical series of chunks using continuation tokens over the Beam Fn |
@@ -91,6 +94,95 @@ public static <T> CachingStateIterable<T> readAllAndDecodeStartingFrom( |
91 | 94 | valueCoder); |
92 | 95 | } |
93 | 96 |
|
| 97 | + /** |
| 98 | + * This adapter handles using the continuation token to provide iteration over all the elements |
| 99 | + * returned by the Beam Fn State API using the supplied state client, state request for the first |
| 100 | + * chunk of the state stream, and a value decoder, without caching support. |
| 101 | + * |
| 102 | + * @param beamFnStateClient A client for handling state requests. |
| 103 | + * @param stateRequestForFirstChunk A fully populated state request for the first (and possibly |
| 104 | + * only) chunk of a state stream. This state request will be populated with a continuation |
| 105 | + * token to request further chunks of the stream if required. |
| 106 | + * @param valueCoder A coder for decoding the state stream. |
| 107 | + */ |
| 108 | + public static <T> UncachedStateIterable<T> readAllAndDecodeStartingFrom( |
| 109 | + BeamFnStateClient beamFnStateClient, |
| 110 | + StateRequest stateRequestForFirstChunk, |
| 111 | + Coder<T> valueCoder) { |
| 112 | + return new UncachedStateIterable<>(beamFnStateClient, stateRequestForFirstChunk, valueCoder); |
| 113 | + } |
| 114 | + |
| 115 | + private static class UncachedStateIterable<T> extends PrefetchableIterables.Default<T> { |
| 116 | + private final BeamFnStateClient beamFnStateClient; |
| 117 | + private final StateRequest stateRequestForFirstChunk; |
| 118 | + private final Coder<T> valueCoder; |
| 119 | + |
| 120 | + public UncachedStateIterable( |
| 121 | + BeamFnStateClient beamFnStateClient, |
| 122 | + StateRequest stateRequestForFirstChunk, |
| 123 | + Coder<T> valueCoder) { |
| 124 | + this.beamFnStateClient = beamFnStateClient; |
| 125 | + this.stateRequestForFirstChunk = stateRequestForFirstChunk; |
| 126 | + this.valueCoder = valueCoder; |
| 127 | + } |
| 128 | + |
| 129 | + @Override |
| 130 | + public PrefetchableIterator<T> createIterator() { |
| 131 | + return new DecodingIterator<T>( |
| 132 | + new LazyBlockingStateFetchingIterator(beamFnStateClient, stateRequestForFirstChunk), |
| 133 | + valueCoder); |
| 134 | + } |
| 135 | + |
| 136 | + private static class DecodingIterator<T> extends AbstractIterator<T> |
| 137 | + implements PrefetchableIterator<T> { |
| 138 | + private final PrefetchableIterator<ByteString> chunkIterator; |
| 139 | + private final Coder<T> valueCoder; |
| 140 | + private InputStream currentChunk; |
| 141 | + |
| 142 | + public DecodingIterator(PrefetchableIterator<ByteString> chunkIterator, Coder<T> valueCoder) { |
| 143 | + this.chunkIterator = chunkIterator; |
| 144 | + this.valueCoder = valueCoder; |
| 145 | + this.currentChunk = ByteString.EMPTY.newInput(); |
| 146 | + } |
| 147 | + |
| 148 | + @Override |
| 149 | + protected T computeNext() { |
| 150 | + try { |
| 151 | + while (currentChunk.available() == 0) { |
| 152 | + if (chunkIterator.hasNext()) { |
| 153 | + currentChunk = chunkIterator.next().newInput(); |
| 154 | + } else { |
| 155 | + return endOfData(); |
| 156 | + } |
| 157 | + } |
| 158 | + return valueCoder.decode(currentChunk); |
| 159 | + } catch (IOException exn) { |
| 160 | + // Should never get here as ByteString.newInput() returns InputStreams |
| 161 | + // that don't do actual IO operations. |
| 162 | + throw new IllegalStateException(exn); |
| 163 | + } |
| 164 | + } |
| 165 | + |
| 166 | + @Override |
| 167 | + public boolean isReady() { |
| 168 | + try { |
| 169 | + return currentChunk.available() > 0 || chunkIterator.isReady(); |
| 170 | + } catch (IOException exn) { |
| 171 | + // Should never get here as ByteString.newInput() returns InputStreams |
| 172 | + // that don't do actual IO operations. |
| 173 | + throw new IllegalStateException(exn); |
| 174 | + } |
| 175 | + } |
| 176 | + |
| 177 | + @Override |
| 178 | + public void prefetch() { |
| 179 | + if (!isReady()) { |
| 180 | + chunkIterator.prefetch(); |
| 181 | + } |
| 182 | + } |
| 183 | + } |
| 184 | + } |
| 185 | + |
94 | 186 | @VisibleForTesting |
95 | 187 | static class IterableCacheKey implements Weighted { |
96 | 188 |
|
|
0 commit comments