aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google
diff options
context:
space:
mode:
authorGravatar Dan Fabulich <DanFabulich@gmail.com>2016-07-22 12:46:08 +0000
committerGravatar Philipp Wollermann <philwo@google.com>2016-07-22 13:44:50 +0000
commit81c9dc946df2abcaa58823b7c78ef04f5cdc3add (patch)
treec26ee5a0d3d6230285ce316ae7435c8b61be6c8b /src/main/java/com/google
parenta088d75da21294bc45ef7ef8d5de4327876db85c (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')
-rw-r--r--src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java27
-rw-r--r--src/main/java/com/google/devtools/build/lib/remote/RemoteOptions.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/remote/RestUrlCacheFactory.java175
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();
+ }
+ }
+}