@@ -35,6 +35,11 @@ import (
35
35
// leafCoders lists coder urns the runner knows how to manipulate.
36
36
// In particular, ones that won't be a problem to parse, in general
37
37
// because they have a known total size.
38
+ //
39
+ // Important: The 'leafCoders' and 'knownCompositeCoders' do not necessarily
40
+ // cover all possible standard coder types.
41
+ // For example, coderRow is neither a leaf coder nor a composite coder (so it
42
+ // will have to be LP'd).
38
43
var leafCoders = map [string ]struct {}{
39
44
urns .CoderBytes : {},
40
45
urns .CoderStringUTF8 : {},
@@ -51,6 +56,28 @@ func isLeafCoder(c *pipepb.Coder) bool {
51
56
return ok
52
57
}
53
58
59
+ // knownCompositeCoders lists coder urns that we expect to see components in
60
+ // their spec.
61
+ var knownCompositeCoders = map [string ]struct {}{
62
+ urns .CoderKV : {},
63
+ urns .CoderIterable : {},
64
+ urns .CoderTimer : {},
65
+ urns .CoderWindowedValue : {},
66
+ urns .CoderParamWindowedValue : {},
67
+ urns .CoderStateBackedIterable : {},
68
+ urns .CoderCustomWindow : {},
69
+ urns .CoderShardedKey : {},
70
+ urns .CoderNullable : {},
71
+ // Exclude CoderLengthPrefix from the list. Even though it is a composite coder,
72
+ // we never need to introspect its component.
73
+ // urns.CoderLengthPrefix: {},
74
+ }
75
+
76
+ func isKnownCompositeCoder (c * pipepb.Coder ) bool {
77
+ _ , ok := knownCompositeCoders [c .GetSpec ().GetUrn ()]
78
+ return ok
79
+ }
80
+
54
81
// makeWindowedValueCoder gets the coder for the PCollection, renders it safe, and adds it to the coders map.
55
82
//
56
83
// PCollection coders are not inherently WindowValueCoder wrapped, and they are added by the runner
@@ -123,10 +150,10 @@ func lpUnknownCoders(cID string, bundle, base map[string]*pipepb.Coder) (string,
123
150
}
124
151
// Add the original coder to the coders map.
125
152
bundle [cID ] = c
126
- // If we don't know this coder, and it has no sub components,
127
- // we must LP it, and we return the LP'd version.
153
+ // If we don't know this coder, we must LP it, and we return the LP'd version.
128
154
leaf := isLeafCoder (c )
129
- if len (c .GetComponentCoderIds ()) == 0 && ! leaf {
155
+ knownComposite := isKnownCompositeCoder (c )
156
+ if ! leaf && ! knownComposite {
130
157
lpc := & pipepb.Coder {
131
158
Spec : & pipepb.FunctionSpec {
132
159
Urn : urns .CoderLengthPrefix ,
@@ -136,15 +163,18 @@ func lpUnknownCoders(cID string, bundle, base map[string]*pipepb.Coder) (string,
136
163
bundle [lpcID ] = lpc
137
164
return lpcID , nil
138
165
}
139
- // We know we have a composite, so if we count this as a leaf, move everything to
140
- // the coders map.
166
+ // If it is a leaf, move its components (if any) to the coders map.
141
167
if leaf {
142
168
// Copy the components from the base.
143
169
for _ , cc := range c .GetComponentCoderIds () {
144
170
bundle [cc ] = base [cc ]
145
171
}
146
172
return cID , nil
147
173
}
174
+
175
+ // Now we have a known composite.
176
+ // We may need to LP its components. If so, we make a new composite with the
177
+ // LP'd components.
148
178
var needNewComposite bool
149
179
var comps []string
150
180
for i , cc := range c .GetComponentCoderIds () {
0 commit comments