com.facebook.buck.artifact_cache.MultiArtifactCache.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.artifact_cache.MultiArtifactCache.java

Source

/*
 * Copyright 2012-present Facebook, Inc.
 *
 * 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.facebook.buck.artifact_cache;

import com.facebook.buck.io.BorrowablePath;
import com.facebook.buck.io.LazyPath;
import com.facebook.buck.rules.RuleKey;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

import java.util.List;
import java.util.Optional;

/**
 * MultiArtifactCache encapsulates a set of ArtifactCache instances such that fetch() succeeds if
 * any of the ArtifactCaches contain the desired artifact, and store() applies to all
 * ArtifactCaches.
 */
public class MultiArtifactCache implements ArtifactCache {

    private final ImmutableList<ArtifactCache> artifactCaches;
    private final ImmutableList<ArtifactCache> writableArtifactCaches;
    private final boolean isStoreSupported;

    public MultiArtifactCache(ImmutableList<ArtifactCache> artifactCaches) {
        this.artifactCaches = artifactCaches;
        this.writableArtifactCaches = ImmutableList
                .copyOf(Iterables.filter(artifactCaches, ArtifactCache::isStoreSupported));
        this.isStoreSupported = this.writableArtifactCaches.size() > 0;
    }

    /**
     * Fetch the artifact matching ruleKey and store it to output. If any of the encapsulated
     * ArtifactCaches contains the desired artifact, this method succeeds, and it may store the
     * artifact to one or more of the other encapsulated ArtifactCaches as a side effect.
     */
    @Override
    public CacheResult fetch(RuleKey ruleKey, LazyPath output) {
        CacheResult cacheResult = CacheResult.miss();
        ImmutableList.Builder<ArtifactCache> priorCaches = ImmutableList.builder();
        for (ArtifactCache artifactCache : artifactCaches) {
            cacheResult = artifactCache.fetch(ruleKey, output);
            if (cacheResult.getType().isSuccess()) {
                break;
            }
            if (artifactCache.isStoreSupported()) {
                priorCaches.add(artifactCache);
            }
        }
        if (cacheResult.getType().isSuccess()) {
            // Success; terminate search for a cached artifact, and propagate artifact to caches
            // earlier in the search order so that subsequent searches terminate earlier.
            storeToCaches(priorCaches.build(),
                    ArtifactInfo.builder().addRuleKeys(ruleKey).setMetadata(cacheResult.getMetadata()).build(),
                    BorrowablePath.notBorrowablePath(output.getUnchecked()));
        }
        return cacheResult;
    }

    private static ListenableFuture<Void> storeToCaches(ImmutableList<ArtifactCache> caches, ArtifactInfo info,
            BorrowablePath output) {
        // TODO(cjhopman): support BorrowablePath with multiple writable caches.
        if (caches.size() != 1) {
            output = BorrowablePath.notBorrowablePath(output.getPath());
        }
        List<ListenableFuture<Void>> storeFutures = Lists.newArrayListWithExpectedSize(caches.size());
        for (ArtifactCache artifactCache : caches) {
            storeFutures.add(artifactCache.store(info, output));
        }

        // Aggregate future to ensure all store operations have completed.
        return Futures.transform(Futures.allAsList(storeFutures), Functions.<Void>constant(null));
    }

    /**
     * Store the artifact to all encapsulated ArtifactCaches.
     */
    @Override
    public ListenableFuture<Void> store(ArtifactInfo info, BorrowablePath output) {
        return storeToCaches(writableArtifactCaches, info, output);
    }

    /** @return {@code true} if there is at least one ArtifactCache that supports storing. */
    @Override
    public boolean isStoreSupported() {
        return isStoreSupported;
    }

    @Override
    public void close() {
        Optional<RuntimeException> throwable = Optional.empty();
        for (ArtifactCache artifactCache : artifactCaches) {
            try {
                artifactCache.close();
            } catch (RuntimeException e) {
                throwable = Optional.of(e);
            }
        }
        if (throwable.isPresent()) {
            throw throwable.get();
        }
    }
}