| // Copyright 2026 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.remote; |
| |
| import com.google.common.base.Preconditions; |
| import com.google.devtools.build.lib.actions.ActionInput; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.vfs.PathFragment; |
| import java.util.concurrent.ConcurrentSkipListSet; |
| |
| /** |
| * A specialized concurrent trie that stores paths of artifacts and allows checking whether a given |
| * path is contained in (in the case of a tree artifact) or exactly matches (in any other case) an |
| * artifact in the trie. |
| */ |
| final class ConcurrentArtifactPathTrie { |
| // Invariant: no path in this set is a prefix of another path. |
| private final ConcurrentSkipListSet<PathFragment> paths = |
| new ConcurrentSkipListSet<>(PathFragment.HIERARCHICAL_COMPARATOR); |
| |
| /** |
| * Adds the given {@link ActionInput} to the trie. |
| * |
| * <p>The caller must ensure that no object's path passed to this method is a prefix of any |
| * previously added object's path. Bazel enforces this for non-aggregate artifacts. Callers must |
| * not pass in {@link Artifact.TreeFileArtifact}s (which have exec paths that have their parent |
| * tree artifact's exec path as a prefix) or non-Artifact {@link ActionInput}s that violate this |
| * invariant. |
| */ |
| void add(ActionInput input) { |
| Preconditions.checkArgument( |
| !(input instanceof Artifact.TreeFileArtifact), |
| "TreeFileArtifacts should not be added to the trie: %s", |
| input); |
| paths.add(input.getExecPath()); |
| } |
| |
| /** Checks whether the given {@link PathFragment} is contained in an artifact in the trie. */ |
| boolean contains(PathFragment execPath) { |
| // By the invariant of this set, there is at most one prefix of execPath in the set. Since the |
| // comparator sorts all children of a path right after the path itself, if such a prefix |
| // exists, it must thus sort right before execPath (or be equal to it). |
| var floorPath = paths.floor(execPath); |
| return floorPath != null && execPath.startsWith(floorPath); |
| } |
| } |