// Copyright 2014 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.annotations.VisibleForTesting; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.annotation.Nullable; /** * An in-memory graph implementation. All operations are thread-safe with ConcurrentMap semantics. * Also see {@link NodeEntry}. * *

This class is public only for use in alternative graph implementations. */ public class InMemoryGraphImpl implements InMemoryGraph { protected final ConcurrentMap nodeMap = new ConcurrentHashMap<>(1024); private final boolean keepEdges; InMemoryGraphImpl() { this(/*keepEdges=*/ true); } public InMemoryGraphImpl(boolean keepEdges) { this.keepEdges = keepEdges; } @Override public void remove(SkyKey skyKey) { nodeMap.remove(skyKey); } @Override public NodeEntry get(@Nullable SkyKey requestor, Reason reason, SkyKey skyKey) { return nodeMap.get(skyKey); } @Override public Map getBatch( SkyKey requestor, Reason reason, Iterable keys) { // Use a HashMap, not an ImmutableMap.Builder, because we have not yet deduplicated these keys // and ImmutableMap.Builder does not tolerate duplicates. The map will be thrown away shortly. HashMap result = new HashMap<>(); for (SkyKey key : keys) { NodeEntry entry = get(null, Reason.OTHER, key); if (entry != null) { result.put(key, entry); } } return result; } protected NodeEntry newNodeEntry(SkyKey key) { return keepEdges ? new InMemoryNodeEntry() : new EdgelessInMemoryNodeEntry(); } protected NodeEntry createIfAbsent(SkyKey key) { NodeEntry newval = newNodeEntry(key); NodeEntry oldval = nodeMap.putIfAbsent(key, newval); return oldval == null ? newval : oldval; } @Override public Map createIfAbsentBatch( @Nullable SkyKey requestor, Reason reason, Iterable keys) { ImmutableMap.Builder builder = ImmutableMap.builder(); for (SkyKey key : keys) { builder.put(key, createIfAbsent(key)); } return builder.build(); } @Override public DepsReport analyzeDepsDoneness(SkyKey parent, Collection deps) { return DepsReport.NO_INFORMATION; } @Override public Map getValues() { return Collections.unmodifiableMap( Maps.transformValues( nodeMap, entry -> { try { return entry.toValue(); } catch (InterruptedException e) { throw new IllegalStateException(e); } })); } @Override public Map getDoneValues() { return Collections.unmodifiableMap( Maps.filterValues( Maps.transformValues( nodeMap, entry -> { if (!entry.isDone()) { return null; } try { return entry.getValue(); } catch (InterruptedException e) { throw new IllegalStateException(e); } }), Predicates.notNull())); } @Override public Map getAllValues() { return Collections.unmodifiableMap(nodeMap); } @Override public Map getAllValuesMutable() { return nodeMap; } @VisibleForTesting protected ConcurrentMap getNodeMap() { return nodeMap; } boolean keepsEdges() { return keepEdges; } @Override public Iterable getCurrentlyAvailableNodes(Iterable keys, Reason reason) { ImmutableSet.Builder builder = ImmutableSet.builder(); for (SkyKey key : keys) { if (get(null, reason, key) != null) { builder.add(key); } } return builder.build(); } }