| // Copyright 2015 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 static com.google.common.truth.Truth.assertThat; |
| |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.ImmutableList; |
| import com.google.devtools.build.lib.cmdline.PackageIdentifier; |
| import com.google.devtools.build.skyframe.InMemoryGraphImpl.EdgelessInMemoryGraphImpl; |
| import com.google.devtools.build.skyframe.QueryableGraph.Reason; |
| import org.junit.Test; |
| |
| /** Tests for {@link InMemoryGraphImpl}. */ |
| public class InMemoryGraphTest extends GraphTest { |
| |
| @Override |
| protected Version getStartingVersion() { |
| return IntVersion.of(0); |
| } |
| |
| @Override |
| protected Version getNextVersion(Version v) { |
| Preconditions.checkState(v instanceof IntVersion); |
| return ((IntVersion) v).next(); |
| } |
| |
| @Override |
| protected void makeGraph() { |
| graph = new InMemoryGraphImpl(); |
| } |
| |
| @Override |
| protected ProcessableGraph getGraph(Version version) { |
| return graph; |
| } |
| |
| /** Tests for {@link EdgelessInMemoryGraphImpl}. */ |
| public static final class EdgelessInMemoryGraphTest extends InMemoryGraphTest { |
| |
| @Override |
| protected void makeGraph() {} |
| |
| @Override |
| protected ProcessableGraph getGraph(Version version) { |
| return new EdgelessInMemoryGraphImpl(/* usePooledInterning= */ true); |
| } |
| |
| @Override |
| protected Version getStartingVersion() { |
| return Version.constant(); |
| } |
| |
| @Override |
| protected Version getNextVersion(Version version) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| protected boolean shouldTestIncrementality() { |
| return false; |
| } |
| } |
| |
| public static final class SkyKeyWithSkyKeyInterner extends AbstractSkyKey<String> { |
| private static final SkyKeyInterner<SkyKeyWithSkyKeyInterner> interner = SkyKey.newInterner(); |
| |
| static SkyKeyWithSkyKeyInterner create(String arg) { |
| return interner.intern(new SkyKeyWithSkyKeyInterner(arg)); |
| } |
| |
| private SkyKeyWithSkyKeyInterner(String arg) { |
| super(arg); |
| } |
| |
| @Override |
| public SkyFunctionName functionName() { |
| return SkyFunctionName.FOR_TESTING; |
| } |
| |
| @Override |
| public SkyKeyInterner<SkyKeyWithSkyKeyInterner> getSkyKeyInterner() { |
| return interner; |
| } |
| } |
| |
| @Test |
| public void createIfAbsentBatch_skyKeyWithSkyKeyInterner() throws InterruptedException { |
| SkyKey cat = SkyKeyWithSkyKeyInterner.create("cat"); |
| |
| // Insert cat SkyKey into graph. |
| // (1) result of getting cat node from graph should not be null; |
| // (2) when re-creating cat SkyKeyWithSkyKeyInterner object, it should retrieve the instance |
| // from global pool (graph), which is also the same instance as the original one. |
| graph.createIfAbsentBatch(null, Reason.OTHER, ImmutableList.of(cat)); |
| assertThat(graph.get(null, Reason.OTHER, cat)).isNotNull(); |
| assertThat(SkyKeyWithSkyKeyInterner.create("cat")).isSameInstanceAs(cat); |
| |
| // Remove cat SkyKey from graph. |
| // (1) result of getting cat node from graph should be null, indicating the cat key has been |
| // removed from the global pool (graph); |
| // (2) since when removing key from global pool (graph), the removed key will be re-interned |
| // back to weak interner. So re-creating an equal "cat" object from SkyKeyWithSkyKeyInterner |
| // will result in the same instance to be returned (no new instance will be created). |
| graph.remove(cat); |
| assertThat(graph.get(null, Reason.OTHER, cat)).isNull(); |
| assertThat(SkyKeyWithSkyKeyInterner.create("cat")).isSameInstanceAs(cat); |
| } |
| |
| @Test |
| public void cleanupPool_weakInternerReintern() throws InterruptedException { |
| SkyKey cat = SkyKeyWithSkyKeyInterner.create("cat"); |
| |
| graph.createIfAbsentBatch(null, Reason.OTHER, ImmutableList.of(cat)); |
| assertThat(graph.get(null, Reason.OTHER, cat)).isNotNull(); |
| |
| assertThat(graph).isInstanceOf(InMemoryGraphImpl.class); |
| ((InMemoryGraphImpl) graph).cleanupInterningPools(); |
| |
| // When re-creating a cat SkyKeyWithSkyKeyInterner, we expect to get the original instance. Pool |
| // cleaning up re-interns the cat instance back to the weak interner, and thus, no new instance |
| // is created. |
| assertThat(SkyKeyWithSkyKeyInterner.create("cat")).isSameInstanceAs(cat); |
| } |
| |
| @Test |
| public void removePackageNode_notPresentInGraph() throws Exception { |
| PackageIdentifier packageIdentifier = PackageIdentifier.createUnchecked("repo", "hello"); |
| |
| graph.remove(packageIdentifier); |
| assertThat(graph.get(null, Reason.OTHER, packageIdentifier)).isNull(); |
| } |
| |
| @Test |
| public void removePackageNode_noValueWeakInternLabelsNoCrash() throws Exception { |
| PackageIdentifier packageIdentifier = PackageIdentifier.createUnchecked("repo", "hello"); |
| |
| graph.createIfAbsentBatch(null, Reason.OTHER, ImmutableList.of(packageIdentifier)); |
| NodeEntry entry = graph.get(null, Reason.OTHER, packageIdentifier); |
| assertThat(entry.toValue()).isNull(); |
| |
| graph.remove(packageIdentifier); |
| assertThat(graph.get(null, Reason.OTHER, packageIdentifier)).isNull(); |
| } |
| } |