Skip to content

Commit e05db5c

Browse files
Optimize redaction state calculation
Memoizes the state, shifts to using a single `volatile` field, and updates `TextFormat` to look at the state directly. PiperOrigin-RevId: 803053745
1 parent c47f34c commit e05db5c

File tree

2 files changed

+56
-38
lines changed

2 files changed

+56
-38
lines changed

‎java/core/src/main/java/com/google/protobuf/Descriptors.java‎

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,15 +1753,37 @@ public String toString() {
17531753
private final Descriptor extensionScope;
17541754
private final boolean isProto3Optional;
17551755

1756-
private enum Sensitivity {
1757-
UNKNOWN,
1758-
SENSITIVE,
1759-
NOT_SENSITIVE
1756+
static final class RedactionState {
1757+
private static final RedactionState FALSE_FALSE = new RedactionState(false, false);
1758+
private static final RedactionState FALSE_TRUE = new RedactionState(false, true);
1759+
private static final RedactionState TRUE_FALSE = new RedactionState(true, false);
1760+
private static final RedactionState TRUE_TRUE = new RedactionState(true, true);
1761+
1762+
final boolean redact;
1763+
final boolean report;
1764+
1765+
private RedactionState(boolean redact, boolean report) {
1766+
this.redact = redact;
1767+
this.report = report;
1768+
}
1769+
1770+
private static RedactionState of(boolean redact) {
1771+
return of(redact, false);
1772+
}
1773+
1774+
private static RedactionState of(boolean redact, boolean report) {
1775+
if (redact) {
1776+
return report ? TRUE_TRUE : TRUE_FALSE;
1777+
}
1778+
return report ? FALSE_TRUE : FALSE_FALSE;
1779+
}
1780+
1781+
private static RedactionState combine(RedactionState lhs, RedactionState rhs) {
1782+
return of(lhs.redact || rhs.redact, rhs.report);
1783+
}
17601784
}
17611785

1762-
// Caches the result of isSensitive() for performance reasons.
1763-
private volatile Sensitivity sensitivity = Sensitivity.UNKNOWN;
1764-
private volatile boolean isReportable = false;
1786+
private volatile RedactionState redactionState;
17651787

17661788
// Possibly initialized during cross-linking.
17671789
private Type type;
@@ -1937,73 +1959,68 @@ private FieldDescriptor(
19371959
}
19381960

19391961
@SuppressWarnings("unchecked") // List<EnumValueDescriptor> guaranteed by protobuf runtime.
1940-
private List<Boolean> isOptionSensitive(FieldDescriptor field, Object value) {
1962+
private static RedactionState isOptionSensitive(FieldDescriptor field, Object value) {
19411963
if (field.getType() == Descriptors.FieldDescriptor.Type.ENUM) {
19421964
if (field.isRepeated()) {
19431965
for (EnumValueDescriptor v : (List<EnumValueDescriptor>) value) {
19441966
if (v.getOptions().getDebugRedact()) {
1945-
return Arrays.asList(true, false);
1967+
return RedactionState.of(true, false);
19461968
}
19471969
}
19481970
} else {
19491971
if (((EnumValueDescriptor) value).getOptions().getDebugRedact()) {
1950-
return Arrays.asList(true, false);
1972+
return RedactionState.of(true, false);
19511973
}
19521974
}
19531975
} else if (field.getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
19541976
if (field.isRepeated()) {
19551977
for (Message m : (List<Message>) value) {
19561978
for (Map.Entry<FieldDescriptor, Object> entry : m.getAllFields().entrySet()) {
1957-
List<Boolean> result = isOptionSensitive(entry.getKey(), entry.getValue());
1958-
if (result.get(0)) {
1959-
return result;
1979+
RedactionState state = isOptionSensitive(entry.getKey(), entry.getValue());
1980+
if (state.redact) {
1981+
return state;
19601982
}
19611983
}
19621984
}
19631985
} else {
19641986
for (Map.Entry<FieldDescriptor, Object> entry :
19651987
((Message) value).getAllFields().entrySet()) {
1966-
List<Boolean> result = isOptionSensitive(entry.getKey(), entry.getValue());
1967-
if (result.get(0)) {
1968-
return result;
1988+
RedactionState state = isOptionSensitive(entry.getKey(), entry.getValue());
1989+
if (state.redact) {
1990+
return state;
19691991
}
19701992
}
19711993
}
19721994
}
1973-
return Arrays.asList(false, false);
1995+
return RedactionState.of(false);
19741996
}
19751997

1976-
// Lazily calculates if the field is marked as sensitive, and caches results.
1977-
private List<Boolean> calculateSensitivityData() {
1978-
if (sensitivity == Sensitivity.UNKNOWN) {
1998+
// Lazily calculates the redact state of the field, caching the result.
1999+
RedactionState getRedactionState() {
2000+
RedactionState state = redactionState;
2001+
if (state == null) {
19792002
// If the field is directly marked with debug_redact=true, then it is sensitive.
19802003
synchronized (this) {
1981-
if (sensitivity == Sensitivity.UNKNOWN) {
1982-
boolean isSensitive = proto.getOptions().getDebugRedact();
2004+
state = redactionState;
2005+
if (state == null) {
2006+
FieldOptions options = getOptions();
2007+
state = RedactionState.of(options.getDebugRedact());
19832008
// Check if the FieldOptions contain any enums that are marked as debug_redact=true,
19842009
// either directly or indirectly via a message option.
19852010
for (Map.Entry<Descriptors.FieldDescriptor, Object> entry :
1986-
proto.getOptions().getAllFields().entrySet()) {
1987-
List<Boolean> result = isOptionSensitive(entry.getKey(), entry.getValue());
1988-
isSensitive = isSensitive || result.get(0);
1989-
isReportable = result.get(1);
1990-
if (isSensitive) {
2011+
options.getAllFields().entrySet()) {
2012+
state =
2013+
RedactionState.combine(
2014+
state, isOptionSensitive(entry.getKey(), entry.getValue()));
2015+
if (state.redact) {
19912016
break;
19922017
}
19932018
}
1994-
sensitivity = isSensitive ? Sensitivity.SENSITIVE : Sensitivity.NOT_SENSITIVE;
2019+
redactionState = state;
19952020
}
19962021
}
19972022
}
1998-
return Arrays.asList(sensitivity == Sensitivity.SENSITIVE, isReportable);
1999-
}
2000-
2001-
boolean isSensitive() {
2002-
return calculateSensitivityData().get(0);
2003-
}
2004-
2005-
boolean isReportable() {
2006-
return calculateSensitivityData().get(1);
2023+
return state;
20072024
}
20082025

20092026
/** See {@link FileDescriptor#resolveAllFeatures}. */

‎java/core/src/main/java/com/google/protobuf/TextFormat.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,8 @@ private void printFieldValue(
665665
// field, b) via an enum field marked with debug_redact=true that is within the proto's
666666
// FieldOptions, either directly or indirectly via a message option.
667667
private boolean shouldRedact(final FieldDescriptor field, TextGenerator generator) {
668-
return enablingSafeDebugFormat && field.isSensitive();
668+
FieldDescriptor.RedactionState state = field.getRedactionState();
669+
return enablingSafeDebugFormat && state.redact;
669670
}
670671

671672
/** Like {@code print()}, but writes directly to a {@code String} and returns it. */

0 commit comments

Comments
 (0)