aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/skyframe/serialization/DeserializationContext.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/serialization/DeserializationContext.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/serialization/DeserializationContext.java143
1 files changed, 74 insertions, 69 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/DeserializationContext.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/DeserializationContext.java
index 3948b64118..54b5820d31 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/DeserializationContext.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/DeserializationContext.java
@@ -14,35 +14,92 @@
package com.google.devtools.build.lib.skyframe.serialization;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.skyframe.serialization.Memoizer.Deserializer;
-import com.google.devtools.build.lib.skyframe.serialization.Memoizer.MemoizingAfterObjectCodecAdapter;
-import com.google.devtools.build.lib.skyframe.serialization.Memoizer.MemoizingCodec;
-import com.google.devtools.build.lib.skyframe.serialization.Memoizer.Serializer;
-import com.google.devtools.build.lib.skyframe.serialization.Memoizer.Strategy;
+import com.google.devtools.build.lib.skyframe.serialization.ObjectCodecRegistry.CodecDescriptor;
+import com.google.devtools.build.lib.skyframe.serialization.ObjectCodecs.MemoizationPermission;
import com.google.protobuf.CodedInputStream;
-import com.google.protobuf.CodedOutputStream;
import java.io.IOException;
-import javax.annotation.Nullable;
+import java.util.function.Function;
+import javax.annotation.CheckReturnValue;
-/** Stateful class for providing additional context to a single deserialization "session". */
-// TODO(bazel-team): This class is just a shell, fill in.
+/**
+ * Stateful class for providing additional context to a single deserialization "session". This class
+ * is thread-safe so long as {@link #deserializer} is null. If it is not null, this class is not
+ * thread-safe and should only be accessed on a single thread for deserializing one serialized
+ * object (that may contain other serialized objects inside it).
+ */
public class DeserializationContext {
-
private final ObjectCodecRegistry registry;
private final ImmutableMap<Class<?>, Object> dependencies;
+ private final MemoizationPermission memoizationPermission;
+ private final Memoizer.Deserializer deserializer;
- public DeserializationContext(
- ObjectCodecRegistry registry, ImmutableMap<Class<?>, Object> dependencies) {
+ private DeserializationContext(
+ ObjectCodecRegistry registry,
+ ImmutableMap<Class<?>, Object> dependencies,
+ MemoizationPermission memoizationPermission,
+ Deserializer deserializer) {
this.registry = registry;
this.dependencies = dependencies;
+ this.memoizationPermission = memoizationPermission;
+ this.deserializer = deserializer;
}
+ @VisibleForTesting
+ public DeserializationContext(
+ ObjectCodecRegistry registry, ImmutableMap<Class<?>, Object> dependencies) {
+ this(registry, dependencies, MemoizationPermission.ALLOWED, /*deserializer=*/ null);
+ }
+
+ @VisibleForTesting
public DeserializationContext(ImmutableMap<Class<?>, Object> dependencies) {
this(AutoRegistry.get(), dependencies);
}
+ DeserializationContext disableMemoization() {
+ Preconditions.checkState(
+ memoizationPermission == MemoizationPermission.ALLOWED, "memoization already disabled");
+ Preconditions.checkState(deserializer == null, "deserializer already present");
+ return new DeserializationContext(
+ registry, dependencies, MemoizationPermission.DISABLED, deserializer);
+ }
+
+ /**
+ * Returns a {@link DeserializationContext} that will memoize values it encounters (using
+ * reference equality), the inverse of the memoization performed by a {@link SerializationContext}
+ * returned by {@link SerializationContext#newMemoizingContext}. The context returned here should
+ * be used instead of the original: memoization may only occur when using the returned context.
+ *
+ * <p>A new {@link DeserializationContext} will be created for each call of this method, since it
+ * is assumed that each codec that calls this method has data that it needs to inject into its
+ * children that should mask its parents' injected data. Thus, over-eagerly calling this method
+ * will reduce the effectiveness of memoization.
+ */
+ @CheckReturnValue
+ public DeserializationContext newMemoizingContext(Object additionalData) {
+ Preconditions.checkNotNull(additionalData);
+ Preconditions.checkState(
+ memoizationPermission == MemoizationPermission.ALLOWED, "memoization disabled");
+ // TODO(janakr,brandjon): De we want to support a single context with data that gets pushed and
+ // popped.
+ return new DeserializationContext(
+ this.registry, this.dependencies, memoizationPermission, new Deserializer(additionalData));
+ }
+
+ /**
+ * Construct an initial value for the currently deserializing value from the additional data
+ * stored in a memoizing deserializer. The additional data must have type {@code klass}. The given
+ * {@code initialValueFunction} should be a hermetic function that does not interact with this
+ * context or {@code codedIn in any way}: it should be a pure function of an element of type
+ * {@link A}.
+ */
+ public <A, T> T makeInitialValue(Function<A, T> initialValueFunction, Class<A> klass) {
+ return deserializer.makeInitialValue(initialValueFunction, klass);
+ }
+
// TODO(shahan): consider making codedIn a member of this class.
@SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"})
public <T> T deserialize(CodedInputStream codedIn) throws IOException, SerializationException {
@@ -51,69 +108,17 @@ public class DeserializationContext {
return null;
}
T constant = (T) registry.maybeGetConstantByTag(tag);
- return constant == null
- ? (T) registry.getCodecDescriptorByTag(tag).deserialize(this, codedIn)
- : constant;
- }
-
- /**
- * Returns a {@link MemoizingCodec} appropriate for deserializing the next object on the wire.
- * Only for use by {@link Memoizer.Deserializer}.
- */
- @SuppressWarnings("unchecked")
- public MemoizingCodec<?> getMemoizingCodecRecordedInInput(CodedInputStream codedIn)
- throws IOException, SerializationException {
- int tag = codedIn.readSInt32();
- if (tag == 0) {
- return new InitializedMemoizingCodec<>(null);
- }
- Object constant = registry.maybeGetConstantByTag(tag);
if (constant != null) {
- return new InitializedMemoizingCodec<>(constant);
+ return constant;
}
- MemoizingCodec<?> codec = registry.maybeGetMemoizingCodecByTag(tag);
- if (codec != null) {
- return codec;
+ CodecDescriptor codecDescriptor = registry.getCodecDescriptorByTag(tag);
+ if (deserializer == null) {
+ return (T) codecDescriptor.deserialize(this, codedIn);
+ } else {
+ return deserializer.deserialize(this, (ObjectCodec<T>) codecDescriptor.getCodec(), codedIn);
}
- return new MemoizingAfterObjectCodecAdapter<>(registry.getCodecDescriptorByTag(tag).getCodec());
}
- private static class InitializedMemoizingCodec<T> implements MemoizingCodec<T> {
- private final T obj;
- private boolean deserialized = false;
-
- private InitializedMemoizingCodec(T obj) {
- this.obj = obj;
- }
-
- @Override
- public Strategy getStrategy() {
- return Strategy.DO_NOT_MEMOIZE;
- }
-
- @Override
- public void serializePayload(
- SerializationContext context, T obj, CodedOutputStream codedOut, Serializer serializer) {
- throw new UnsupportedOperationException("Unexpected serialize: " + obj);
- }
-
- @Override
- public T deserializePayload(
- DeserializationContext context,
- @Nullable T initial,
- CodedInputStream codedIn,
- Deserializer deserializer) {
- Preconditions.checkState(!deserialized, "Already deserialized: %s", obj);
- deserialized = true;
- return obj;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Class<T> getEncodedClass() {
- return (Class<T>) obj.getClass();
- }
- }
@SuppressWarnings("unchecked")
public <T> T getDependency(Class<T> type) {
Preconditions.checkNotNull(type);