|  | // 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.lib.actions; | 
|  |  | 
|  | import com.google.common.collect.ImmutableList; | 
|  | import com.google.common.collect.Iterables; | 
|  | import com.google.common.collect.MapMaker; | 
|  |  | 
|  | import java.util.ArrayList; | 
|  | import java.util.List; | 
|  | import java.util.concurrent.ConcurrentMap; | 
|  | import java.util.concurrent.locks.ReadWriteLock; | 
|  | import java.util.concurrent.locks.ReentrantReadWriteLock; | 
|  |  | 
|  | /** | 
|  | * A registry that keeps a map of artifacts to unique integer ids. | 
|  | */ | 
|  | class ArtifactIdRegistry implements ArtifactSerializer, ArtifactDeserializer { | 
|  |  | 
|  | /** | 
|  | * A sequence of registered artifacts. The position in the list is the artifact's id. | 
|  | * | 
|  | * <p>Synchronized using {@link #artifactIdsLock}. | 
|  | */ | 
|  | private final List<Artifact> serializedArtifactList = new ArrayList<>(); | 
|  |  | 
|  | /** | 
|  | * A map of artifacts to unique integer ids. | 
|  | * | 
|  | * <p>Writes to this map must be synchronized using {@link #artifactIdsLock}, in order to | 
|  | * maintain consistency with {@link #serializedArtifactList}. | 
|  | */ | 
|  | private final ConcurrentMap<Artifact, Integer> serializedArtifactIds = | 
|  | new MapMaker().concurrencyLevel(1).makeMap(); | 
|  |  | 
|  | /** | 
|  | * A lock for keeping {@code serializedArtifactList} and {@code serializedArtifactIds} in sync. | 
|  | */ | 
|  | private ReadWriteLock artifactIdsLock = new ReentrantReadWriteLock(); | 
|  |  | 
|  | ArtifactIdRegistry() { | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int getArtifactId(Artifact artifact) { | 
|  | Integer artifactId = serializedArtifactIds.get(artifact); | 
|  | if (artifactId == null) { | 
|  | artifactId = assignArtifactId(artifact); | 
|  | } | 
|  | return artifactId; | 
|  | } | 
|  |  | 
|  | private Integer assignArtifactId(Artifact artifact) { | 
|  | artifactIdsLock.writeLock().lock(); | 
|  | try { | 
|  | Integer artifactId = serializedArtifactIds.get(artifact); | 
|  | if (artifactId == null) { | 
|  | artifactId = serializedArtifactList.size(); | 
|  | serializedArtifactList.add(artifact); | 
|  | serializedArtifactIds.put(artifact, artifactId); | 
|  | } | 
|  | return artifactId; | 
|  | } finally { | 
|  | artifactIdsLock.writeLock().unlock(); | 
|  | } | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public Artifact lookupArtifactById(int artifactId) { | 
|  | artifactIdsLock.readLock().lock(); | 
|  | try { | 
|  | return serializedArtifactList.get(artifactId); | 
|  | } finally { | 
|  | artifactIdsLock.readLock().unlock(); | 
|  | } | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public ImmutableList<Artifact> lookupArtifactsByIds(Iterable<Integer> artifactIds) { | 
|  | int size = Iterables.size(artifactIds); | 
|  | Artifact[] result = new Artifact[size]; | 
|  |  | 
|  | int i = 0; | 
|  |  | 
|  | artifactIdsLock.readLock().lock(); | 
|  | try { | 
|  | for (int artifactId : artifactIds) { | 
|  | result[i] = serializedArtifactList.get(artifactId); | 
|  | i++; | 
|  | } | 
|  | } finally { | 
|  | artifactIdsLock.readLock().unlock(); | 
|  | } | 
|  |  | 
|  | return ImmutableList.copyOf(result); | 
|  | } | 
|  | } |