diff options
author | 2016-07-22 12:46:08 +0000 | |
---|---|---|
committer | 2016-07-22 13:44:50 +0000 | |
commit | 81c9dc946df2abcaa58823b7c78ef04f5cdc3add (patch) | |
tree | c26ee5a0d3d6230285ce316ae7435c8b61be6c8b /src/main/java/com/google | |
parent | a088d75da21294bc45ef7ef8d5de4327876db85c (diff) |
Simple REST URL cache
--
Change-Id: Ied34278c63c74aaf2db5ad90d5f076b3bddbe396
Reviewed-on: https://bazel-review.git.corp.google.com/#/c/4061/
MOS_MIGRATED_REVID=128165927
Diffstat (limited to 'src/main/java/com/google')
3 files changed, 204 insertions, 8 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java index 32e08615b9..c55a788720 100644 --- a/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java +++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java @@ -24,7 +24,6 @@ import com.google.devtools.build.lib.runtime.BlazeModule; import com.google.devtools.build.lib.runtime.Command; import com.google.devtools.build.lib.runtime.CommandEnvironment; import com.google.devtools.common.options.OptionsBase; - import java.net.URI; import java.net.URISyntaxException; @@ -62,15 +61,27 @@ public final class RemoteModule extends BlazeModule { buildRequest = event.getRequest(); RemoteOptions options = buildRequest.getOptions(RemoteOptions.class); + MemcacheActionCache cache = null; + // Don't provide the remote spawn unless at least action cache is initialized. - if (actionCache == null - && (options.hazelcastNode != null || options.hazelcastClientConfig != null)) { - MemcacheActionCache cache = - new MemcacheActionCache( - this.env.getDirectories().getExecRoot(), - options, - HazelcastCacheFactory.create(options)); + if (actionCache == null) { + if (options.hazelcastNode != null || options.hazelcastClientConfig != null) { + cache = + new MemcacheActionCache( + this.env.getDirectories().getExecRoot(), + options, + HazelcastCacheFactory.create(options)); + } else if (options.restCacheUrl != null) { + cache = + new MemcacheActionCache( + this.env.getDirectories().getExecRoot(), + options, + RestUrlCacheFactory.create(options)); + } actionCache = cache; + } + + if (cache != null) { if (workExecutor == null && options.remoteWorker != null) { try { URI uri = new URI("dummy://" + options.remoteWorker); diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteOptions.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteOptions.java index da8c3b935d..78747c8090 100644 --- a/src/main/java/com/google/devtools/build/lib/remote/RemoteOptions.java +++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteOptions.java @@ -22,6 +22,16 @@ import com.google.devtools.common.options.OptionsBase; */ public final class RemoteOptions extends OptionsBase { @Option( + name = "rest_cache_url", + defaultValue = "null", + category = "remote", + help = + "A base URL for a RESTful cache server for storing build artifacts." + + "It has to support PUT, GET, and HEAD requests." + ) + public String restCacheUrl; + + @Option( name = "hazelcast_node", defaultValue = "null", category = "remote", diff --git a/src/main/java/com/google/devtools/build/lib/remote/RestUrlCacheFactory.java b/src/main/java/com/google/devtools/build/lib/remote/RestUrlCacheFactory.java new file mode 100644 index 0000000000..aa98b253e7 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/remote/RestUrlCacheFactory.java @@ -0,0 +1,175 @@ +// Copyright 2016 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 java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpHead; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.util.EntityUtils; + +/** + * A factory class for providing a {@link ConcurrentMap} object implemented by a REST service. The + * URL has to support PUT, GET, and HEAD operations + */ +public final class RestUrlCacheFactory { + + public static ConcurrentMap<String, byte[]> create(RemoteOptions options) { + return new RestUrlCache(options.restCacheUrl); + } + + private static class RestUrlCache implements ConcurrentMap<String, byte[]> { + + final String baseUrl; + + RestUrlCache(String baseUrl) { + this.baseUrl = baseUrl; + } + + @Override + public boolean containsKey(Object key) { + try { + HttpClient client = new DefaultHttpClient(); + HttpHead head = new HttpHead(baseUrl + "/" + key); + HttpResponse response = client.execute(head); + int statusCode = response.getStatusLine().getStatusCode(); + return HttpStatus.SC_OK == statusCode; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public byte[] get(Object key) { + try { + HttpClient client = new DefaultHttpClient(); + HttpGet get = new HttpGet(baseUrl + "/" + key); + HttpResponse response = client.execute(get); + int statusCode = response.getStatusLine().getStatusCode(); + if (HttpStatus.SC_NOT_FOUND == statusCode) { + return null; + } + if (HttpStatus.SC_OK != statusCode) { + throw new RuntimeException("GET failed with status code " + statusCode); + } + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + HttpEntity entity = response.getEntity(); + entity.writeTo(buffer); + buffer.flush(); + EntityUtils.consume(entity); + + return buffer.toByteArray(); + + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public byte[] put(String key, byte[] value) { + try { + HttpClient client = new DefaultHttpClient(); + HttpPut put = new HttpPut(baseUrl + "/" + key); + put.setEntity(new ByteArrayEntity(value)); + HttpResponse response = client.execute(put); + int statusCode = response.getStatusLine().getStatusCode(); + + if (HttpStatus.SC_OK != statusCode) { + throw new RuntimeException("PUT failed with status code " + statusCode); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return null; + } + + //UnsupportedOperationExceptions from here down + @Override + public int size() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isEmpty() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsValue(Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public byte[] remove(Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(Map<? extends String, ? extends byte[]> m) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public Set<String> keySet() { + throw new UnsupportedOperationException(); + } + + @Override + public Collection<byte[]> values() { + throw new UnsupportedOperationException(); + } + + @Override + public Set<Entry<String, byte[]>> entrySet() { + throw new UnsupportedOperationException(); + } + + @Override + public byte[] putIfAbsent(String key, byte[] value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(String key, byte[] oldValue, byte[] newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public byte[] replace(String key, byte[] value) { + throw new UnsupportedOperationException(); + } + } +} |