|  | // Copyright 2017 The Bazel Authors. All rights reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  | package com.google.devtools.build.skyframe; | 
|  |  | 
|  | import com.google.common.collect.Interner; | 
|  | import com.google.devtools.build.lib.concurrent.BlazeInterners; | 
|  | import com.google.devtools.build.lib.util.Preconditions; | 
|  |  | 
|  | /** | 
|  | * Basic implementation of {@link SkyKey}. Potentially non-optimal from a memory perspective, since | 
|  | * it uses fields for hash code and {@link #functionName}. The latter should be implemented instead | 
|  | * using polymorphism. See {@code ArtifactSkyKey} for an example. | 
|  | */ | 
|  | public class LegacySkyKey implements SkyKey { | 
|  | private static final Interner<SkyKey> SKY_KEY_INTERNER = BlazeInterners.newWeakInterner(); | 
|  |  | 
|  | /** | 
|  | * Creates a {@link SkyKey}. Prefer instead creating custom SkyKeys that are their own arguments, | 
|  | * saving the object wrapper. See {@code ArtifactSkyKey} for an example. | 
|  | */ | 
|  | // TODO(janakr): migrate users of this to use custom SkyKey subclasses and delete this. | 
|  | @Deprecated | 
|  | public static SkyKey create(SkyFunctionName functionName, Object argument) { | 
|  | // Intern to save memory. | 
|  | return SKY_KEY_INTERNER.intern(new LegacySkyKey(functionName, argument)); | 
|  | } | 
|  |  | 
|  | private final SkyFunctionName functionName; | 
|  |  | 
|  | /** | 
|  | * The name of the value. | 
|  | * | 
|  | * <p>This is deliberately an untyped Object so that we can use arbitrary value types (e.g., | 
|  | * Labels, PathFragments, BuildConfigurations, etc.) as value names without incurring | 
|  | * serialization costs in the in-memory implementation of the graph. | 
|  | */ | 
|  | private final Object argument; | 
|  |  | 
|  | /** | 
|  | * Cache the hash code for this object. It might be expensive to compute. It is transient because | 
|  | * argument's hash code might not be stable across JVM instances. | 
|  | */ | 
|  | private transient int hashCode; | 
|  |  | 
|  | private LegacySkyKey(SkyFunctionName functionName, Object argument) { | 
|  | this.functionName = Preconditions.checkNotNull(functionName); | 
|  | this.argument = Preconditions.checkNotNull(argument); | 
|  | // 'hashCode' is non-volatile and non-final, so this write may in fact *not* be visible to other | 
|  | // threads. But this isn't a concern from a correctness perspective. See the comments in | 
|  | // #hashCode for more details. | 
|  | this.hashCode = computeHashCode(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public SkyFunctionName functionName() { | 
|  | return functionName; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public Object argument() { | 
|  | return argument; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String toString() { | 
|  | return functionName + ":" + argument; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int hashCode() { | 
|  | // We use the hash code caching strategy employed by java.lang.String. There are three subtle | 
|  | // things going on here: | 
|  | // | 
|  | // (1) We use a value of 0 to indicate that the hash code hasn't been computed and cached yet. | 
|  | // Yes, this means that if the hash code is really 0 then we will "recompute" it each time. But | 
|  | // this isn't a problem in practice since a hash code of 0 should be rare. | 
|  | // | 
|  | // (2) Since we have no synchronization, multiple threads can race here thinking there are the | 
|  | // first one to compute and cache the hash code. | 
|  | // | 
|  | // (3) Moreover, since 'hashCode' is non-volatile, the cached hash code value written from one | 
|  | // thread may not be visible by another. | 
|  | // | 
|  | // All three of these issues are benign from a correctness perspective; in the end we have no | 
|  | // overhead from synchronization, at the cost of potentially computing the hash code more than | 
|  | // once. | 
|  | int h = hashCode; | 
|  | if (h == 0) { | 
|  | h = computeHashCode(); | 
|  | hashCode = h; | 
|  | } | 
|  | return h; | 
|  | } | 
|  |  | 
|  | private int computeHashCode() { | 
|  | return 31 * functionName.hashCode() + argument.hashCode(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean equals(Object obj) { | 
|  | if (this == obj) { | 
|  | return true; | 
|  | } | 
|  | if (obj == null) { | 
|  | return false; | 
|  | } | 
|  | if (getClass() != obj.getClass()) { | 
|  | return false; | 
|  | } | 
|  | LegacySkyKey other = (LegacySkyKey) obj; | 
|  | if (hashCode() != other.hashCode()) { | 
|  | return false; | 
|  | } | 
|  | return functionName.equals(other.functionName) && argument.equals(other.argument); | 
|  | } | 
|  | } |