34
34
import org .apache .beam .sdk .annotations .Experimental ;
35
35
import org .apache .beam .sdk .annotations .Experimental .Kind ;
36
36
import org .apache .beam .sdk .coders .Coder ;
37
+ import org .apache .beam .sdk .coders .CoderException ;
37
38
import org .apache .beam .sdk .state .BagState ;
38
39
import org .apache .beam .sdk .state .CombiningState ;
39
40
import org .apache .beam .sdk .state .MapState ;
49
50
import org .apache .beam .sdk .transforms .CombineWithContext .CombineFnWithContext ;
50
51
import org .apache .beam .sdk .transforms .windowing .BoundedWindow ;
51
52
import org .apache .beam .sdk .transforms .windowing .TimestampCombiner ;
53
+ import org .apache .beam .sdk .util .CoderUtils ;
52
54
import org .apache .beam .sdk .util .CombineFnUtil ;
53
55
import org .joda .time .Instant ;
54
56
@@ -126,25 +128,25 @@ public InMemoryStateBinder(StateContext<?> c) {
126
128
@ Override
127
129
public <T > ValueState <T > bindValue (
128
130
StateTag <ValueState <T >> address , Coder <T > coder ) {
129
- return new InMemoryValue <>();
131
+ return new InMemoryValue <>(coder );
130
132
}
131
133
132
134
@ Override
133
135
public <T > BagState <T > bindBag (
134
136
final StateTag <BagState <T >> address , Coder <T > elemCoder ) {
135
- return new InMemoryBag <>();
137
+ return new InMemoryBag <>(elemCoder );
136
138
}
137
139
138
140
@ Override
139
141
public <T > SetState <T > bindSet (StateTag <SetState <T >> spec , Coder <T > elemCoder ) {
140
- return new InMemorySet <>();
142
+ return new InMemorySet <>(elemCoder );
141
143
}
142
144
143
145
@ Override
144
146
public <KeyT , ValueT > MapState <KeyT , ValueT > bindMap (
145
147
StateTag <MapState <KeyT , ValueT >> spec ,
146
148
Coder <KeyT > mapKeyCoder , Coder <ValueT > mapValueCoder ) {
147
- return new InMemoryMap <>();
149
+ return new InMemoryMap <>(mapKeyCoder , mapValueCoder );
148
150
}
149
151
150
152
@ Override
@@ -153,7 +155,7 @@ public <KeyT, ValueT> MapState<KeyT, ValueT> bindMap(
153
155
StateTag <CombiningState <InputT , AccumT , OutputT >> address ,
154
156
Coder <AccumT > accumCoder ,
155
157
final CombineFn <InputT , AccumT , OutputT > combineFn ) {
156
- return new InMemoryCombiningState <>(combineFn );
158
+ return new InMemoryCombiningState <>(combineFn , accumCoder );
157
159
}
158
160
159
161
@ Override
@@ -178,9 +180,15 @@ public WatermarkHoldState bindWatermark(
178
180
*/
179
181
public static final class InMemoryValue <T >
180
182
implements ValueState <T >, InMemoryState <InMemoryValue <T >> {
183
+ private final Coder <T > coder ;
184
+
181
185
private boolean isCleared = true ;
182
186
private @ Nullable T value = null ;
183
187
188
+ public InMemoryValue (Coder <T > coder ) {
189
+ this .coder = coder ;
190
+ }
191
+
184
192
@ Override
185
193
public void clear () {
186
194
// Even though we're clearing we can't remove this from the in-memory state map, since
@@ -207,10 +215,10 @@ public void write(T input) {
207
215
208
216
@ Override
209
217
public InMemoryValue <T > copy () {
210
- InMemoryValue <T > that = new InMemoryValue <>();
218
+ InMemoryValue <T > that = new InMemoryValue <>(coder );
211
219
if (!this .isCleared ) {
212
220
that .isCleared = this .isCleared ;
213
- that .value = this .value ;
221
+ that .value = unsafeClone ( coder , this .value ) ;
214
222
}
215
223
return that ;
216
224
}
@@ -305,14 +313,16 @@ public InMemoryWatermarkHold<W> copy() {
305
313
public static final class InMemoryCombiningState <InputT , AccumT , OutputT >
306
314
implements CombiningState <InputT , AccumT , OutputT >,
307
315
InMemoryState <InMemoryCombiningState <InputT , AccumT , OutputT >> {
308
- private boolean isCleared = true ;
309
316
private final CombineFn <InputT , AccumT , OutputT > combineFn ;
317
+ private final Coder <AccumT > accumCoder ;
318
+ private boolean isCleared = true ;
310
319
private AccumT accum ;
311
320
312
321
public InMemoryCombiningState (
313
- CombineFn <InputT , AccumT , OutputT > combineFn ) {
322
+ CombineFn <InputT , AccumT , OutputT > combineFn , Coder < AccumT > accumCoder ) {
314
323
this .combineFn = combineFn ;
315
324
accum = combineFn .createAccumulator ();
325
+ this .accumCoder = accumCoder ;
316
326
}
317
327
318
328
@ Override
@@ -378,7 +388,7 @@ public boolean isCleared() {
378
388
@ Override
379
389
public InMemoryCombiningState <InputT , AccumT , OutputT > copy () {
380
390
InMemoryCombiningState <InputT , AccumT , OutputT > that =
381
- new InMemoryCombiningState <>(combineFn );
391
+ new InMemoryCombiningState <>(combineFn , accumCoder );
382
392
if (!this .isCleared ) {
383
393
that .isCleared = this .isCleared ;
384
394
that .addAccum (accum );
@@ -391,8 +401,13 @@ public InMemoryCombiningState<InputT, AccumT, OutputT> copy() {
391
401
* An {@link InMemoryState} implementation of {@link BagState}.
392
402
*/
393
403
public static final class InMemoryBag <T > implements BagState <T >, InMemoryState <InMemoryBag <T >> {
404
+ private final Coder <T > elemCoder ;
394
405
private List <T > contents = new ArrayList <>();
395
406
407
+ public InMemoryBag (Coder <T > elemCoder ) {
408
+ this .elemCoder = elemCoder ;
409
+ }
410
+
396
411
@ Override
397
412
public void clear () {
398
413
// Even though we're clearing we can't remove this from the in-memory state map, since
@@ -442,8 +457,10 @@ public Boolean read() {
442
457
443
458
@ Override
444
459
public InMemoryBag <T > copy () {
445
- InMemoryBag <T > that = new InMemoryBag <>();
446
- that .contents .addAll (this .contents );
460
+ InMemoryBag <T > that = new InMemoryBag <>(elemCoder );
461
+ for (T elem : this .contents ) {
462
+ that .contents .add (unsafeClone (elemCoder , elem ));
463
+ }
447
464
return that ;
448
465
}
449
466
}
@@ -452,8 +469,13 @@ public InMemoryBag<T> copy() {
452
469
* An {@link InMemoryState} implementation of {@link SetState}.
453
470
*/
454
471
public static final class InMemorySet <T > implements SetState <T >, InMemoryState <InMemorySet <T >> {
472
+ private final Coder <T > elemCoder ;
455
473
private Set <T > contents = new HashSet <>();
456
474
475
+ public InMemorySet (Coder <T > elemCoder ) {
476
+ this .elemCoder = elemCoder ;
477
+ }
478
+
457
479
@ Override
458
480
public void clear () {
459
481
contents = new HashSet <>();
@@ -513,8 +535,10 @@ public Boolean read() {
513
535
514
536
@ Override
515
537
public InMemorySet <T > copy () {
516
- InMemorySet <T > that = new InMemorySet <>();
517
- that .contents .addAll (this .contents );
538
+ InMemorySet <T > that = new InMemorySet <>(elemCoder );
539
+ for (T elem : this .contents ) {
540
+ that .contents .add (unsafeClone (elemCoder , elem ));
541
+ }
518
542
return that ;
519
543
}
520
544
}
@@ -524,8 +548,16 @@ public InMemorySet<T> copy() {
524
548
*/
525
549
public static final class InMemoryMap <K , V > implements
526
550
MapState <K , V >, InMemoryState <InMemoryMap <K , V >> {
551
+ private final Coder <K > keyCoder ;
552
+ private final Coder <V > valueCoder ;
553
+
527
554
private Map <K , V > contents = new HashMap <>();
528
555
556
+ public InMemoryMap (Coder <K > keyCoder , Coder <V > valueCoder ) {
557
+ this .keyCoder = keyCoder ;
558
+ this .valueCoder = valueCoder ;
559
+ }
560
+
529
561
@ Override
530
562
public void clear () {
531
563
contents = new HashMap <>();
@@ -600,9 +632,21 @@ public boolean isCleared() {
600
632
601
633
@ Override
602
634
public InMemoryMap <K , V > copy () {
603
- InMemoryMap <K , V > that = new InMemoryMap <>();
635
+ InMemoryMap <K , V > that = new InMemoryMap <>(keyCoder , valueCoder );
636
+ for (Map .Entry <K , V > entry : this .contents .entrySet ()) {
637
+ that .contents .put (
638
+ unsafeClone (keyCoder , entry .getKey ()), unsafeClone (valueCoder , entry .getValue ()));
639
+ }
604
640
that .contents .putAll (this .contents );
605
641
return that ;
606
642
}
607
643
}
644
+
645
+ private static <T > T unsafeClone (Coder <T > coder , T value ) {
646
+ try {
647
+ return CoderUtils .clone (coder , value );
648
+ } catch (CoderException e ) {
649
+ throw new RuntimeException (e );
650
+ }
651
+ }
608
652
}
0 commit comments