Skip to content

Commit dd849cf

Browse files
l46kokcopybara-github
authored andcommitted
Keep each lite message's descriptor instead of building its CelType on every hop
PiperOrigin-RevId: 999023029
1 parent 66bfaf9 commit dd849cf

4 files changed

Lines changed: 169 additions & 191 deletions

File tree

‎common/src/main/java/dev/cel/common/values/ProtoLiteCelValueConverter.java‎

Lines changed: 34 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -119,34 +119,39 @@ private Object readLengthDelimitedField(
119119
return CelByteString.of(inputStream.readByteArray());
120120
case MESSAGE:
121121
return mergeOrReadMessageField(
122-
inputStream.readBytes(), fieldDescriptor.getFieldProtoTypeName(), existingValue);
122+
inputStream.readBytes(),
123+
fieldDescriptor.getFieldProtoTypeName(),
124+
existingValue,
125+
/* isView= */ true);
123126
case STRING:
124127
return inputStream.readStringRequireUtf8();
125128
default:
126129
throw new IllegalStateException("Unexpected field type: " + fieldType);
127130
}
128131
}
129132

133+
// For bytes that don't alias another message's buffer (empty or freshly serialized).
130134
private Object readMessageField(ByteString bytes, String fieldProtoTypeName) {
131-
return mergeOrReadMessageField(bytes, fieldProtoTypeName, /* existingValue= */ null);
135+
return mergeOrReadMessageField(
136+
bytes, fieldProtoTypeName, /* existingValue= */ null, /* isView= */ false);
132137
}
133138

134139
private Object mergeOrReadMessageField(
135-
ByteString bytes, String fieldProtoTypeName, @Nullable Object existingValue) {
140+
ByteString bytes, String fieldProtoTypeName, @Nullable Object existingValue, boolean isView) {
136141
MessageLiteDescriptor descriptor =
137142
descriptorPool.findDescriptor(fieldProtoTypeName).orElse(null);
138143
if (descriptor == null) {
139144
if (existingValue instanceof RawProtoMessageLiteValue) {
140145
bytes = ((RawProtoMessageLiteValue) existingValue).toByteString().concat(bytes);
141146
}
142-
return RawProtoMessageLiteValue.create(bytes, fieldProtoTypeName, this, /* isView= */ true);
147+
return RawProtoMessageLiteValue.create(bytes, fieldProtoTypeName, this, isView);
143148
}
144149
WellKnownProto wellKnownProto = WellKnownProto.getByTypeName(fieldProtoTypeName).orElse(null);
145150
if (isStructLike(wellKnownProto)) {
146151
if (existingValue instanceof ProtoMessageLiteValue) {
147152
bytes = ((ProtoMessageLiteValue) existingValue).toByteString().concat(bytes);
148153
}
149-
return ProtoMessageLiteValue.create(bytes, fieldProtoTypeName, this);
154+
return ProtoMessageLiteValue.create(bytes, descriptor, this);
150155
}
151156
if (existingValue instanceof MessageLite) {
152157
return mergeMessageLite(((MessageLite) existingValue).toBuilder(), bytes, fieldProtoTypeName);
@@ -171,29 +176,7 @@ Object getDefaultCelValue(SelectField field, FieldLiteDescriptor fieldDescriptor
171176
: getDefaultCelValue(fieldDescriptor);
172177
}
173178

174-
@Nullable FieldLiteDescriptor findFieldDescriptor(String protoTypeName, int fieldNumber) {
175-
MessageLiteDescriptor descriptor = descriptorPool.findDescriptor(protoTypeName).orElse(null);
176-
return descriptor == null ? null : descriptor.findByFieldNumber(fieldNumber);
177-
}
178-
179-
@Nullable FieldLiteDescriptor findFieldDescriptor(String protoTypeName, String fieldName) {
180-
MessageLiteDescriptor descriptor = descriptorPool.findDescriptor(protoTypeName).orElse(null);
181-
return descriptor == null ? null : descriptor.findByFieldName(fieldName);
182-
}
183-
184-
@Nullable MessageLiteDescriptor findDescriptorWithGetters(String protoTypeName) {
185-
return descriptorPool
186-
.findDescriptor(protoTypeName)
187-
.filter(MessageLiteDescriptor::hasGetters)
188-
.orElse(null);
189-
}
190-
191-
MessageLite parseMessageLite(ByteString bytes, String protoTypeName) {
192-
MessageLiteDescriptor descriptor = descriptorPool.getDescriptorOrThrow(protoTypeName);
193-
return parseMessageLite(bytes, descriptor);
194-
}
195-
196-
private static MessageLite parseMessageLite(ByteString bytes, MessageLiteDescriptor descriptor) {
179+
static MessageLite parseMessageLite(ByteString bytes, MessageLiteDescriptor descriptor) {
197180
if (bytes.isEmpty()) {
198181
return descriptor.newMessageBuilder().getDefaultInstanceForType();
199182
}
@@ -229,7 +212,7 @@ private Object toRuntimeValue(MessageLite msg, MessageLiteDescriptor descriptor)
229212
WellKnownProto wellKnownProto =
230213
WellKnownProto.getByTypeName(descriptor.getProtoTypeName()).orElse(null);
231214
if (isStructLike(wellKnownProto)) {
232-
return ProtoMessageLiteValue.create(msg, descriptor.getProtoTypeName(), this);
215+
return ProtoMessageLiteValue.create(msg, descriptor, this);
233216
}
234217

235218
return fromWellKnownProto(msg, checkNotNull(wellKnownProto));
@@ -425,12 +408,17 @@ Optional<Object> findByFieldNumber(ByteString bytes, String protoTypeName, Selec
425408
return Optional.ofNullable(readField(bytes, protoTypeName, field));
426409
}
427410

428-
/** Returns whether {@code field} is present in {@code bytes}. */
411+
/** Returns whether {@code field}, unknown to its message's descriptor, is in {@code bytes}. */
429412
boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField field) {
430-
FieldLiteDescriptor fieldDescriptor = findFieldDescriptor(protoTypeName, field.fieldNumber());
431-
if (fieldDescriptor == null) {
432-
fieldDescriptor = newFieldDescriptor(field);
433-
}
413+
return hasFieldByNumber(bytes, protoTypeName, field, newFieldDescriptor(field));
414+
}
415+
416+
/** Like the overload above, for a field its message's descriptor has. */
417+
boolean hasFieldByNumber(
418+
ByteString bytes,
419+
String protoTypeName,
420+
SelectField field,
421+
FieldLiteDescriptor fieldDescriptor) {
434422
if (fieldDescriptor.getProtoFieldType().equals(FieldLiteDescriptor.Type.GROUP)) {
435423
throw new UnsupportedOperationException("Groups are not supported");
436424
}
@@ -469,8 +457,8 @@ boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField fie
469457
* wire bytes: its CEL value, or null if it's absent.
470458
*/
471459
@Nullable Object readFieldByGetter(
472-
MessageLite message, MessageLiteDescriptor descriptor, FieldLiteDescriptor fieldDescriptor) {
473-
Object value = readGetter(message, descriptor, fieldDescriptor.getFieldNumber());
460+
ProtoMessageLiteValue message, FieldLiteDescriptor fieldDescriptor) {
461+
Object value = readGetter(message, fieldDescriptor.getFieldNumber());
474462
if (value == null) {
475463
return null;
476464
}
@@ -519,14 +507,14 @@ boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField fie
519507
}
520508

521509
/** Like {@link #hasFieldByNumber}, through the field's generated getter. */
522-
boolean hasByGetter(MessageLite message, MessageLiteDescriptor descriptor, SelectField field) {
523-
return readGetter(message, descriptor, field.fieldNumber()) != null;
510+
boolean hasByGetter(ProtoMessageLiteValue message, SelectField field) {
511+
return readGetter(message, field.fieldNumber()) != null;
524512
}
525513

526514
// A field's value as its getter returns it, or null if it's unset or an empty repeated or map.
527-
private static @Nullable Object readGetter(
528-
MessageLite message, MessageLiteDescriptor descriptor, int fieldNumber) {
529-
Object value = descriptor.getFieldValue(message, fieldNumber);
515+
private static @Nullable Object readGetter(ProtoMessageLiteValue message, int fieldNumber) {
516+
Object value =
517+
message.descriptor().getFieldValue(checkNotNull(message.rawValue()), fieldNumber);
530518
boolean isEmpty =
531519
(value instanceof List && ((List<?>) value).isEmpty())
532520
|| (value instanceof Map && ((Map<?, ?>) value).isEmpty());
@@ -549,18 +537,11 @@ private Object fromGetterValue(Object value, FieldLiteDescriptor fieldDescriptor
549537
: (long) ((EnumLite) value).getNumber();
550538
case MESSAGE:
551539
MessageLite message = (MessageLite) value;
552-
String protoTypeName = fieldDescriptor.getFieldProtoTypeName();
553-
MessageLiteDescriptor descriptor =
554-
descriptorPool.findDescriptor(protoTypeName).orElse(null);
555-
if (descriptor == null) {
556-
// Without a descriptor, only this submessage is serialized, rather than its whole root.
557-
return RawProtoMessageLiteValue.create(message.toByteString(), protoTypeName, this);
558-
}
559-
if (descriptorPool.findDescriptor(message).orElse(null) != descriptor) {
560-
// The pool decodes this type into another class, such as an older version of it.
561-
return readMessageField(message.toByteString(), protoTypeName);
562-
}
563-
return toRuntimeValue(message, descriptor);
540+
MessageLiteDescriptor descriptor = descriptorPool.findDescriptor(message).orElse(null);
541+
// Not a class the pool knows (e.g. another version of its type): read its own bytes.
542+
return descriptor != null
543+
? toRuntimeValue(message, descriptor)
544+
: readMessageField(message.toByteString(), fieldDescriptor.getFieldProtoTypeName());
564545
default:
565546
return super.toRuntimeValue(value);
566547
}

‎common/src/main/java/dev/cel/common/values/ProtoMessageLiteValue.java‎

Lines changed: 44 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,24 @@ abstract class ProtoMessageLiteValue extends StructValue<String, MessageLite>
6868
// re-serializing intermediate hops; lazily parsed into a MessageLite only if value() is called.
6969
abstract @Nullable ByteString wireBytes();
7070

71-
@Override
72-
public abstract CelType celType();
71+
abstract MessageLiteDescriptor descriptor();
7372

7473
abstract ProtoLiteCelValueConverter protoLiteCelValueConverter();
7574

75+
@Override
76+
public CelType celType() {
77+
// Built on demand, since one of these values is created on every hop but rarely asked its type.
78+
return StructTypeReference.create(protoTypeName());
79+
}
80+
7681
@Memoized
7782
@Override
7883
public MessageLite value() {
7984
MessageLite msg = rawValue();
8085
if (msg != null) {
8186
return msg;
8287
}
83-
return protoLiteCelValueConverter()
84-
.parseMessageLite(checkNotNull(wireBytes()), celType().name());
88+
return ProtoLiteCelValueConverter.parseMessageLite(checkNotNull(wireBytes()), descriptor());
8589
}
8690

8791
@Memoized
@@ -112,20 +116,26 @@ public final boolean equals(Object other) {
112116
return false;
113117
}
114118
ProtoMessageLiteValue that = (ProtoMessageLiteValue) other;
115-
return this.celType().equals(that.celType()) && this.value().equals(that.value());
119+
return this.protoTypeName().equals(that.protoTypeName()) && this.value().equals(that.value());
116120
}
117121

118122
@Override
119123
public final int hashCode() {
120-
return Objects.hash(value(), celType());
124+
return Objects.hash(value(), protoTypeName());
125+
}
126+
127+
@Override
128+
public final String toString() {
129+
// AutoValue's would print the message's contents, which may be sensitive.
130+
return "ProtoMessageLiteValue{protoTypeName=" + protoTypeName() + "}";
121131
}
122132

123133
@Override
124134
public Object select(String field) {
125-
FieldLiteDescriptor fd = findFieldDescriptor(field);
135+
FieldLiteDescriptor fd = descriptor().findByFieldName(field);
126136
if (fd == null) {
127137
throw CelAttributeNotFoundException.of(
128-
String.format("field '%s' is not declared in message '%s'", field, celType().name()));
138+
String.format("field '%s' is not declared in message '%s'", field, protoTypeName()));
129139
}
130140
Object fieldValue = readField(fd);
131141
return fieldValue != null ? fieldValue : protoLiteCelValueConverter().getDefaultCelValue(fd);
@@ -134,88 +144,73 @@ public Object select(String field) {
134144
@Override
135145
public Optional<Object> find(String field) {
136146
// Per SelectableValue#find, a field that doesn't exist is reported as absent.
137-
return Optional.ofNullable(findFieldDescriptor(field)).map(this::readField);
147+
return Optional.ofNullable(descriptor().findByFieldName(field)).map(this::readField);
138148
}
139149

140150
@Override
141151
public Object selectByFieldNumber(SelectField field) {
142-
FieldLiteDescriptor fd = findFieldDescriptor(field.fieldNumber());
152+
FieldLiteDescriptor fd = descriptor().findByFieldNumber(field.fieldNumber());
143153
if (fd != null) {
144154
Object value = readField(fd);
145155
return value != null ? value : protoLiteCelValueConverter().getDefaultCelValue(field, fd);
146156
}
147-
return protoLiteCelValueConverter()
148-
.selectByFieldNumber(toByteString(), celType().name(), field);
157+
return protoLiteCelValueConverter().selectByFieldNumber(toByteString(), protoTypeName(), field);
149158
}
150159

151160
@Override
152161
public boolean hasFieldByNumber(SelectField field) {
153-
MessageLite message = rawValue();
154-
if (message != null && findFieldDescriptor(field.fieldNumber()) != null) {
155-
MessageLiteDescriptor descriptor = findDescriptorWithGetters();
156-
if (descriptor != null) {
157-
return protoLiteCelValueConverter().hasByGetter(message, descriptor, field);
158-
}
162+
FieldLiteDescriptor fd = descriptor().findByFieldNumber(field.fieldNumber());
163+
if (fd == null) {
164+
return protoLiteCelValueConverter().hasFieldByNumber(toByteString(), protoTypeName(), field);
159165
}
160-
return protoLiteCelValueConverter().hasFieldByNumber(toByteString(), celType().name(), field);
166+
return canReadByGetter()
167+
? protoLiteCelValueConverter().hasByGetter(this, field)
168+
: protoLiteCelValueConverter().hasFieldByNumber(toByteString(), protoTypeName(), field, fd);
161169
}
162170

163171
@Override
164172
public Optional<Object> findByFieldNumber(SelectField field) {
165-
FieldLiteDescriptor fd = findFieldDescriptor(field.fieldNumber());
173+
FieldLiteDescriptor fd = descriptor().findByFieldNumber(field.fieldNumber());
166174
if (fd != null) {
167175
return Optional.ofNullable(readField(fd));
168176
}
169-
return protoLiteCelValueConverter().findByFieldNumber(toByteString(), celType().name(), field);
177+
return protoLiteCelValueConverter().findByFieldNumber(toByteString(), protoTypeName(), field);
170178
}
171179

172180
private @Nullable Object readField(FieldLiteDescriptor fd) {
173-
MessageLite message = rawValue();
174-
if (message != null) {
175-
MessageLiteDescriptor descriptor = findDescriptorWithGetters();
176-
if (descriptor != null) {
177-
return protoLiteCelValueConverter().readFieldByGetter(message, descriptor, fd);
178-
}
179-
}
180-
return protoLiteCelValueConverter().readField(toByteString(), celType().name(), fd);
181+
return canReadByGetter()
182+
? protoLiteCelValueConverter().readFieldByGetter(this, fd)
183+
: protoLiteCelValueConverter().readField(toByteString(), protoTypeName(), fd);
181184
}
182185

183-
private @Nullable FieldLiteDescriptor findFieldDescriptor(String fieldName) {
184-
return protoLiteCelValueConverter().findFieldDescriptor(celType().name(), fieldName);
186+
private boolean canReadByGetter() {
187+
return rawValue() != null && descriptor().hasGetters();
185188
}
186189

187-
private @Nullable FieldLiteDescriptor findFieldDescriptor(int fieldNumber) {
188-
return protoLiteCelValueConverter().findFieldDescriptor(celType().name(), fieldNumber);
189-
}
190-
191-
private @Nullable MessageLiteDescriptor findDescriptorWithGetters() {
192-
return protoLiteCelValueConverter().findDescriptorWithGetters(celType().name());
190+
private String protoTypeName() {
191+
return descriptor().getProtoTypeName();
193192
}
194193

195194
static ProtoMessageLiteValue create(
196-
MessageLite value, String typeName, ProtoLiteCelValueConverter protoLiteCelValueConverter) {
195+
MessageLite value,
196+
MessageLiteDescriptor descriptor,
197+
ProtoLiteCelValueConverter protoLiteCelValueConverter) {
197198
checkNotNull(value);
198-
checkNotNull(typeName);
199+
checkNotNull(descriptor);
199200
checkNotNull(protoLiteCelValueConverter);
200201
return new AutoValue_ProtoMessageLiteValue(
201-
value,
202-
/* wireBytes= */ null,
203-
StructTypeReference.create(typeName),
204-
protoLiteCelValueConverter);
202+
value, /* wireBytes= */ null, descriptor, protoLiteCelValueConverter);
205203
}
206204

207205
static ProtoMessageLiteValue create(
208206
ByteString wireBytes,
209-
String typeName,
207+
MessageLiteDescriptor descriptor,
210208
ProtoLiteCelValueConverter protoLiteCelValueConverter) {
211209
checkNotNull(wireBytes);
212-
checkNotNull(typeName);
210+
checkNotNull(descriptor);
213211
checkNotNull(protoLiteCelValueConverter);
214212
return new AutoValue_ProtoMessageLiteValue(
215-
/* rawValue= */ null,
216-
wireBytes,
217-
StructTypeReference.create(typeName),
218-
protoLiteCelValueConverter);
213+
/* rawValue= */ null, wireBytes, descriptor, protoLiteCelValueConverter);
219214
}
220215

221216
ProtoMessageLiteValue() {}

0 commit comments

Comments
 (0)