Search in sources :

Example 6 with LazyPath

use of com.facebook.buck.io.LazyPath in project buck by facebook.

the class ThriftArtifactCache method fetchImpl.

@Override
public CacheResult fetchImpl(RuleKey ruleKey, LazyPath output, HttpArtifactCacheEvent.Finished.Builder eventBuilder) throws IOException {
    BuckCacheFetchRequest fetchRequest = new BuckCacheFetchRequest();
    com.facebook.buck.artifact_cache.thrift.RuleKey thriftRuleKey = new com.facebook.buck.artifact_cache.thrift.RuleKey();
    thriftRuleKey.setHashString(ruleKey.getHashCode().toString());
    fetchRequest.setRuleKey(thriftRuleKey);
    fetchRequest.setRepository(repository);
    fetchRequest.setScheduleType(scheduleType);
    fetchRequest.setDistributedBuildModeEnabled(distributedBuildModeEnabled);
    BuckCacheRequest cacheRequest = new BuckCacheRequest();
    cacheRequest.setType(BuckCacheRequestType.FETCH);
    cacheRequest.setFetchRequest(fetchRequest);
    LOG.verbose("Will fetch key %s", thriftRuleKey);
    final ThriftArtifactCacheProtocol.Request request = ThriftArtifactCacheProtocol.createRequest(PROTOCOL, cacheRequest);
    Request.Builder builder = toOkHttpRequest(request);
    try (HttpResponse httpResponse = fetchClient.makeRequest(hybridThriftEndpoint, builder)) {
        if (httpResponse.statusCode() != 200) {
            String message = String.format("Failed to fetch cache artifact with HTTP status code [%d:%s] " + " to url [%s] for rule key [%s].", httpResponse.statusCode(), httpResponse.statusMessage(), httpResponse.requestUrl(), ruleKey.toString());
            LOG.error(message);
            return CacheResult.error(name, message);
        }
        try (ThriftArtifactCacheProtocol.Response response = ThriftArtifactCacheProtocol.parseResponse(PROTOCOL, httpResponse.getBody())) {
            eventBuilder.getFetchBuilder().setResponseSizeBytes(httpResponse.contentLength());
            BuckCacheResponse cacheResponse = response.getThriftData();
            if (!cacheResponse.isWasSuccessful()) {
                LOG.warn("Request was unsuccessful: %s", cacheResponse.getErrorMessage());
                return CacheResult.error(name, cacheResponse.getErrorMessage());
            }
            BuckCacheFetchResponse fetchResponse = cacheResponse.getFetchResponse();
            if (LOG.isDebugEnabled()) {
                LOG.debug("Debug info for cache fetch request: request=[%s] response=[%s]", ThriftUtil.thriftToDebugJson(cacheRequest), ThriftUtil.thriftToDebugJson(cacheResponse));
            }
            if (!fetchResponse.isArtifactExists()) {
                LOG.verbose("Artifact did not exist.");
                return CacheResult.miss();
            }
            LOG.verbose("Got artifact.  Attempting to read payload.");
            Path tmp = createTempFileForDownload();
            ThriftArtifactCacheProtocol.Response.ReadPayloadInfo readResult;
            try (OutputStream tmpFile = projectFilesystem.newFileOutputStream(tmp)) {
                readResult = response.readPayload(tmpFile);
                LOG.verbose("Successfully read payload: %d bytes.", readResult.getBytesRead());
            }
            ArtifactMetadata metadata = fetchResponse.getMetadata();
            if (LOG.isVerboseEnabled()) {
                LOG.verbose(String.format("Fetched artifact with rule key [%s] contains the following metadata: [%s]", ruleKey, ThriftUtil.thriftToDebugJson(metadata)));
            }
            eventBuilder.setTarget(Optional.ofNullable(metadata.getBuildTarget())).getFetchBuilder().setAssociatedRuleKeys(toImmutableSet(metadata.getRuleKeys())).setArtifactSizeBytes(readResult.getBytesRead());
            if (!metadata.isSetArtifactPayloadMd5()) {
                String msg = "Fetched artifact is missing the MD5 hash.";
                LOG.warn(msg);
            } else {
                eventBuilder.getFetchBuilder().setArtifactContentHash(metadata.getArtifactPayloadMd5());
                if (!readResult.getMd5Hash().equals(fetchResponse.getMetadata().getArtifactPayloadMd5())) {
                    String msg = String.format("The artifact fetched from cache is corrupted. ExpectedMD5=[%s] ActualMD5=[%s]", fetchResponse.getMetadata().getArtifactPayloadMd5(), readResult.getMd5Hash());
                    LOG.error(msg);
                    return CacheResult.error(name, msg);
                }
            }
            // This makes sure we don't have 'half downloaded files' in the dir cache.
            projectFilesystem.move(tmp, output.get(), StandardCopyOption.REPLACE_EXISTING);
            return CacheResult.hit(name, ImmutableMap.copyOf(fetchResponse.getMetadata().getMetadata()), readResult.getBytesRead());
        }
    }
}
Also used : Path(java.nio.file.Path) LazyPath(com.facebook.buck.io.LazyPath) BuckCacheFetchResponse(com.facebook.buck.artifact_cache.thrift.BuckCacheFetchResponse) RuleKey(com.facebook.buck.rules.RuleKey) OutputStream(java.io.OutputStream) BuckCacheStoreRequest(com.facebook.buck.artifact_cache.thrift.BuckCacheStoreRequest) Request(okhttp3.Request) BuckCacheRequest(com.facebook.buck.artifact_cache.thrift.BuckCacheRequest) BuckCacheFetchRequest(com.facebook.buck.artifact_cache.thrift.BuckCacheFetchRequest) HttpResponse(com.facebook.buck.slb.HttpResponse) BuckCacheRequest(com.facebook.buck.artifact_cache.thrift.BuckCacheRequest) BuckCacheFetchRequest(com.facebook.buck.artifact_cache.thrift.BuckCacheFetchRequest) BuckCacheResponse(com.facebook.buck.artifact_cache.thrift.BuckCacheResponse) HttpResponse(com.facebook.buck.slb.HttpResponse) BuckCacheFetchResponse(com.facebook.buck.artifact_cache.thrift.BuckCacheFetchResponse) BuckCacheResponse(com.facebook.buck.artifact_cache.thrift.BuckCacheResponse) ArtifactMetadata(com.facebook.buck.artifact_cache.thrift.ArtifactMetadata)

Example 7 with LazyPath

use of com.facebook.buck.io.LazyPath in project buck by facebook.

the class CachingBuildEngine method tryToFetchArtifactFromBuildCacheAndOverlayOnTopOfProjectFilesystem.

private CacheResult tryToFetchArtifactFromBuildCacheAndOverlayOnTopOfProjectFilesystem(final BuildRule rule, final RuleKey ruleKey, final ArtifactCache artifactCache, final ProjectFilesystem filesystem, final BuildEngineBuildContext buildContext) {
    if (!rule.isCacheable()) {
        return CacheResult.ignored();
    }
    // Create a temp file whose extension must be ".zip" for Filesystems.newFileSystem() to infer
    // that we are creating a zip-based FileSystem.
    final LazyPath lazyZipPath = new LazyPath() {

        @Override
        protected Path create() throws IOException {
            return Files.createTempFile("buck_artifact_" + MoreFiles.sanitize(rule.getBuildTarget().getShortName()), ".zip");
        }
    };
    // TODO(bolinfest): Change ArtifactCache.fetch() so that it returns a File instead of takes one.
    // Then we could download directly from the remote cache into the on-disk cache and unzip it
    // from there.
    CacheResult cacheResult = fetchArtifactForBuildable(ruleKey, lazyZipPath, artifactCache);
    return unzipArtifactFromCacheResult(rule, ruleKey, lazyZipPath, buildContext, filesystem, cacheResult);
}
Also used : CacheResult(com.facebook.buck.artifact_cache.CacheResult) LazyPath(com.facebook.buck.io.LazyPath)

Example 8 with LazyPath

use of com.facebook.buck.io.LazyPath in project buck by facebook.

the class CachingBuildEngine method unzipArtifactFromCacheResult.

private CacheResult unzipArtifactFromCacheResult(BuildRule rule, RuleKey ruleKey, LazyPath lazyZipPath, BuildEngineBuildContext buildContext, ProjectFilesystem filesystem, CacheResult cacheResult) {
    // We only unpack artifacts from hits.
    if (!cacheResult.getType().isSuccess()) {
        LOG.debug("Cache miss for '%s' with rulekey '%s'", rule, ruleKey);
        return cacheResult;
    }
    Preconditions.checkArgument(cacheResult.getType() == CacheResultType.HIT);
    LOG.debug("Fetched '%s' from cache with rulekey '%s'", rule, ruleKey);
    // It should be fine to get the path straight away, since cache already did it's job.
    Path zipPath = lazyZipPath.getUnchecked();
    // We unzip the file in the root of the project directory.
    // Ideally, the following would work:
    //
    // Path pathToZip = Paths.get(zipPath.getAbsolutePath());
    // FileSystem fs = FileSystems.newFileSystem(pathToZip, /* loader */ null);
    // Path root = Iterables.getOnlyElement(fs.getRootDirectories());
    // MoreFiles.copyRecursively(root, projectRoot);
    //
    // Unfortunately, this does not appear to work, in practice, because MoreFiles fails when trying
    // to resolve a Path for a zip entry against a file Path on disk.
    ArtifactCompressionEvent.Started started = ArtifactCompressionEvent.started(ArtifactCompressionEvent.Operation.DECOMPRESS, ImmutableSet.of(ruleKey));
    buildContext.getEventBus().post(started);
    try {
        // First, clear out the pre-existing metadata directory.  We have to do this *before*
        // unpacking the zipped artifact, as it includes files that will be stored in the metadata
        // directory.
        Path metadataDir = BuildInfo.getPathToMetadataDirectory(rule.getBuildTarget(), rule.getProjectFilesystem());
        rule.getProjectFilesystem().deleteRecursivelyIfExists(metadataDir);
        Unzip.extractZipFile(zipPath.toAbsolutePath(), filesystem, Unzip.ExistingFileMode.OVERWRITE_AND_CLEAN_DIRECTORIES);
        // We only delete the ZIP file when it has been unzipped successfully. Otherwise, we leave it
        // around for debugging purposes.
        Files.delete(zipPath);
        // Also write out the build metadata.
        for (Map.Entry<String, String> ent : cacheResult.getMetadata().entrySet()) {
            Path dest = metadataDir.resolve(ent.getKey());
            filesystem.createParentDirs(dest);
            filesystem.writeContentsToPath(ent.getValue(), dest);
        }
    } catch (IOException e) {
        // In the wild, we have seen some inexplicable failures during this step. For now, we try to
        // give the user as much information as we can to debug the issue, but return CacheResult.MISS
        // so that Buck will fall back on doing a local build.
        buildContext.getEventBus().post(ConsoleEvent.warning("Failed to unzip the artifact for %s at %s.\n" + "The rule will be built locally, " + "but here is the stacktrace of the failed unzip call:\n" + rule.getBuildTarget(), zipPath.toAbsolutePath(), Throwables.getStackTraceAsString(e)));
        return CacheResult.miss();
    } finally {
        buildContext.getEventBus().post(ArtifactCompressionEvent.finished(started));
    }
    return cacheResult;
}
Also used : Path(java.nio.file.Path) LazyPath(com.facebook.buck.io.LazyPath) BorrowablePath(com.facebook.buck.io.BorrowablePath) IOException(java.io.IOException) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) ConcurrentMap(java.util.concurrent.ConcurrentMap) ImmutableSortedMap(com.google.common.collect.ImmutableSortedMap) ArtifactCompressionEvent(com.facebook.buck.event.ArtifactCompressionEvent)

Example 9 with LazyPath

use of com.facebook.buck.io.LazyPath in project buck by facebook.

the class CachingBuildEngine method performManifestBasedCacheFetch.

// Fetch an artifact from the cache using manifest-based caching.
private Optional<BuildResult> performManifestBasedCacheFetch(final BuildRule rule, final BuildEngineBuildContext context, BuildInfoRecorder buildInfoRecorder, RuleKeyAndInputs manifestKey) throws IOException {
    Preconditions.checkArgument(useManifestCaching(rule));
    final LazyPath tempFile = new LazyPath() {

        @Override
        protected Path create() throws IOException {
            return Files.createTempFile("buck.", ".manifest");
        }
    };
    CacheResult manifestResult = fetchArtifactForBuildable(manifestKey.getRuleKey(), tempFile, context.getArtifactCache());
    if (!manifestResult.getType().isSuccess()) {
        return Optional.empty();
    }
    Path manifestPath = getManifestPath(rule);
    // Clear out any existing manifest.
    rule.getProjectFilesystem().deleteFileAtPathIfExists(manifestPath);
    // Now, fetch an existing manifest from the cache.
    rule.getProjectFilesystem().createParentDirs(manifestPath);
    try (OutputStream outputStream = rule.getProjectFilesystem().newFileOutputStream(manifestPath);
        InputStream inputStream = new GZIPInputStream(new BufferedInputStream(Files.newInputStream(tempFile.get())))) {
        ByteStreams.copy(inputStream, outputStream);
    }
    Files.delete(tempFile.get());
    // Deserialize the manifest.
    Manifest manifest;
    try (InputStream input = rule.getProjectFilesystem().newFileInputStream(manifestPath)) {
        manifest = new Manifest(input);
    }
    // Lookup the rule for the current state of our inputs.
    Optional<RuleKey> ruleKey = manifest.lookup(fileHashCache, pathResolver, manifestKey.getInputs());
    if (!ruleKey.isPresent()) {
        return Optional.empty();
    }
    CacheResult cacheResult = tryToFetchArtifactFromBuildCacheAndOverlayOnTopOfProjectFilesystem(rule, ruleKey.get(), context.getArtifactCache(), // TODO(shs96c): This should be shared between all tests, not one per cell
    rule.getProjectFilesystem(), context);
    if (cacheResult.getType().isSuccess()) {
        fillMissingBuildMetadataFromCache(cacheResult, buildInfoRecorder, BuildInfo.MetadataKey.DEP_FILE_RULE_KEY, BuildInfo.MetadataKey.DEP_FILE);
        return Optional.of(BuildResult.success(rule, BuildRuleSuccessType.FETCHED_FROM_CACHE_MANIFEST_BASED, cacheResult));
    }
    return Optional.empty();
}
Also used : Path(java.nio.file.Path) LazyPath(com.facebook.buck.io.LazyPath) BorrowablePath(com.facebook.buck.io.BorrowablePath) GZIPInputStream(java.util.zip.GZIPInputStream) BufferedInputStream(java.io.BufferedInputStream) SupportsInputBasedRuleKey(com.facebook.buck.rules.keys.SupportsInputBasedRuleKey) SupportsDependencyFileRuleKey(com.facebook.buck.rules.keys.SupportsDependencyFileRuleKey) GZIPInputStream(java.util.zip.GZIPInputStream) BufferedInputStream(java.io.BufferedInputStream) InputStream(java.io.InputStream) GZIPOutputStream(java.util.zip.GZIPOutputStream) BufferedOutputStream(java.io.BufferedOutputStream) OutputStream(java.io.OutputStream) CacheResult(com.facebook.buck.artifact_cache.CacheResult) LazyPath(com.facebook.buck.io.LazyPath)

Example 10 with LazyPath

use of com.facebook.buck.io.LazyPath in project buck by facebook.

the class MultiArtifactCacheTest method cacheFetchPushesMetadataToHigherCache.

@Test
public void cacheFetchPushesMetadataToHigherCache() throws Exception {
    InMemoryArtifactCache cache1 = new InMemoryArtifactCache();
    InMemoryArtifactCache cache2 = new InMemoryArtifactCache();
    MultiArtifactCache multiArtifactCache = new MultiArtifactCache(ImmutableList.of(cache1, cache2));
    LazyPath output = LazyPath.ofInstance(tmp.newFile());
    ImmutableMap<String, String> metadata = ImmutableMap.of("hello", "world");
    cache2.store(ArtifactInfo.builder().addRuleKeys(dummyRuleKey).setMetadata(metadata).build(), new byte[0]);
    multiArtifactCache.fetch(dummyRuleKey, output);
    CacheResult result = cache1.fetch(dummyRuleKey, output);
    assertThat(result.getType(), Matchers.equalTo(CacheResultType.HIT));
    assertThat(result.getMetadata(), Matchers.equalTo(metadata));
    multiArtifactCache.close();
}
Also used : LazyPath(com.facebook.buck.io.LazyPath) Test(org.junit.Test)

Aggregations

LazyPath (com.facebook.buck.io.LazyPath)19 Test (org.junit.Test)12 Path (java.nio.file.Path)10 BorrowablePath (com.facebook.buck.io.BorrowablePath)9 ArtifactCache (com.facebook.buck.artifact_cache.ArtifactCache)8 CacheResult (com.facebook.buck.artifact_cache.CacheResult)8 RuleKey (com.facebook.buck.rules.RuleKey)6 ProjectFilesystem (com.facebook.buck.io.ProjectFilesystem)5 OutputStream (java.io.OutputStream)3 HttpResponse (com.facebook.buck.slb.HttpResponse)2 IOException (java.io.IOException)2 InputStream (java.io.InputStream)2 Request (okhttp3.Request)2 ArtifactCacheBuckConfig (com.facebook.buck.artifact_cache.ArtifactCacheBuckConfig)1 ArtifactInfo (com.facebook.buck.artifact_cache.ArtifactInfo)1 ArtifactMetadata (com.facebook.buck.artifact_cache.thrift.ArtifactMetadata)1 BuckCacheFetchRequest (com.facebook.buck.artifact_cache.thrift.BuckCacheFetchRequest)1 BuckCacheFetchResponse (com.facebook.buck.artifact_cache.thrift.BuckCacheFetchResponse)1 BuckCacheRequest (com.facebook.buck.artifact_cache.thrift.BuckCacheRequest)1 BuckCacheResponse (com.facebook.buck.artifact_cache.thrift.BuckCacheResponse)1