summaryrefslogtreecommitdiffstats
path: root/java/com/google/gerrit/server/rules/PrologEnvironment.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/google/gerrit/server/rules/PrologEnvironment.java')
-rw-r--r--java/com/google/gerrit/server/rules/PrologEnvironment.java263
1 files changed, 263 insertions, 0 deletions
diff --git a/java/com/google/gerrit/server/rules/PrologEnvironment.java b/java/com/google/gerrit/server/rules/PrologEnvironment.java
new file mode 100644
index 0000000000..568fa4eefc
--- /dev/null
+++ b/java/com/google/gerrit/server/rules/PrologEnvironment.java
@@ -0,0 +1,263 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// 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.gerrit.server.rules;
+
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.server.AnonymousUser;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.PatchSetUtil;
+import com.google.gerrit.server.account.Emails;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.patch.PatchSetInfoFactory;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.assistedinject.Assisted;
+import com.googlecode.prolog_cafe.lang.BufferingPrologControl;
+import com.googlecode.prolog_cafe.lang.Predicate;
+import com.googlecode.prolog_cafe.lang.PredicateEncoder;
+import com.googlecode.prolog_cafe.lang.Prolog;
+import com.googlecode.prolog_cafe.lang.PrologMachineCopy;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jgit.lib.Config;
+
+/**
+ * Per-thread Prolog interpreter.
+ *
+ * <p>This class is not thread safe.
+ *
+ * <p>A single copy of the Prolog interpreter, for the current thread.
+ */
+public class PrologEnvironment extends BufferingPrologControl {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ public interface Factory {
+ /**
+ * Construct a new Prolog interpreter.
+ *
+ * @param src the machine to template the new environment from.
+ * @return the new interpreter.
+ */
+ PrologEnvironment create(PrologMachineCopy src);
+ }
+
+ private final Args args;
+ private final Map<StoredValue<Object>, Object> storedValues;
+ private List<Runnable> cleanup;
+
+ @Inject
+ PrologEnvironment(Args a, @Assisted PrologMachineCopy src) {
+ super(src);
+ setEnabled(EnumSet.allOf(Prolog.Feature.class), false);
+ args = a;
+ storedValues = new HashMap<>();
+ cleanup = new LinkedList<>();
+ }
+
+ public Args getArgs() {
+ return args;
+ }
+
+ @Override
+ public void setPredicate(Predicate goal) {
+ super.setPredicate(goal);
+ int reductionLimit = args.reductionLimit(goal);
+ logger.atFine().log("setting reductionLimit %d", reductionLimit);
+ setReductionLimit(reductionLimit);
+ }
+
+ /**
+ * Lookup a stored value in the interpreter's hash manager.
+ *
+ * @param <T> type of stored Java object.
+ * @param sv unique key.
+ * @return the value; null if not stored.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T get(StoredValue<T> sv) {
+ return (T) storedValues.get(sv);
+ }
+
+ /**
+ * Set a stored value on the interpreter's hash manager.
+ *
+ * @param <T> type of stored Java object.
+ * @param sv unique key.
+ * @param obj the value to store under {@code sv}.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> void set(StoredValue<T> sv, T obj) {
+ storedValues.put((StoredValue<Object>) sv, obj);
+ }
+
+ /**
+ * Copy the stored values from another interpreter to this one. Also gets the cleanup from the
+ * child interpreter
+ */
+ public void copyStoredValues(PrologEnvironment child) {
+ storedValues.putAll(child.storedValues);
+ setCleanup(child.cleanup);
+ }
+
+ /**
+ * Assign the environment a cleanup list (in order to use a centralized list) If this
+ * enivronment's list is non-empty, append its cleanup tasks to the assigning list.
+ */
+ public void setCleanup(List<Runnable> newCleanupList) {
+ newCleanupList.addAll(cleanup);
+ cleanup = newCleanupList;
+ }
+
+ /**
+ * Adds cleanup task to run when close() is called
+ *
+ * @param task is run when close() is called
+ */
+ public void addToCleanup(Runnable task) {
+ cleanup.add(task);
+ }
+
+ /** Release resources stored in interpreter's hash manager. */
+ public void close() {
+ for (Iterator<Runnable> i = cleanup.iterator(); i.hasNext(); ) {
+ try {
+ i.next().run();
+ } catch (Throwable err) {
+ logger.atSevere().withCause(err).log("Failed to execute cleanup for PrologEnvironment");
+ }
+ i.remove();
+ }
+ }
+
+ @Singleton
+ public static class Args {
+ private static final Class<Predicate> CONSULT_STREAM_2;
+
+ static {
+ try {
+ @SuppressWarnings("unchecked")
+ Class<Predicate> c =
+ (Class<Predicate>)
+ Class.forName(
+ PredicateEncoder.encode(Prolog.BUILTIN, "consult_stream", 2),
+ false,
+ RulesCache.class.getClassLoader());
+ CONSULT_STREAM_2 = c;
+ } catch (ClassNotFoundException e) {
+ throw new LinkageError("cannot find predicate consult_stream", e);
+ }
+ }
+
+ private final ProjectCache projectCache;
+ private final PermissionBackend permissionBackend;
+ private final GitRepositoryManager repositoryManager;
+ private final PatchListCache patchListCache;
+ private final PatchSetInfoFactory patchSetInfoFactory;
+ private final IdentifiedUser.GenericFactory userFactory;
+ private final Provider<AnonymousUser> anonymousUser;
+ private final int reductionLimit;
+ private final int compileLimit;
+ private final PatchSetUtil patchsetUtil;
+ private Emails emails;
+
+ @Inject
+ Args(
+ ProjectCache projectCache,
+ PermissionBackend permissionBackend,
+ GitRepositoryManager repositoryManager,
+ PatchListCache patchListCache,
+ PatchSetInfoFactory patchSetInfoFactory,
+ IdentifiedUser.GenericFactory userFactory,
+ Provider<AnonymousUser> anonymousUser,
+ @GerritServerConfig Config config,
+ PatchSetUtil patchsetUtil,
+ Emails emails) {
+ this.projectCache = projectCache;
+ this.permissionBackend = permissionBackend;
+ this.repositoryManager = repositoryManager;
+ this.patchListCache = patchListCache;
+ this.patchSetInfoFactory = patchSetInfoFactory;
+ this.userFactory = userFactory;
+ this.anonymousUser = anonymousUser;
+ this.patchsetUtil = patchsetUtil;
+ this.emails = emails;
+
+ int limit = config.getInt("rules", null, "reductionLimit", 100000);
+ reductionLimit = limit <= 0 ? Integer.MAX_VALUE : limit;
+
+ limit =
+ config.getInt(
+ "rules",
+ null,
+ "compileReductionLimit",
+ (int) Math.min(10L * limit, Integer.MAX_VALUE));
+ compileLimit = limit <= 0 ? Integer.MAX_VALUE : limit;
+
+ logger.atInfo().log("reductionLimit: %d, compileLimit: %d", reductionLimit, compileLimit);
+ }
+
+ private int reductionLimit(Predicate goal) {
+ if (goal.getClass() == CONSULT_STREAM_2) {
+ return compileLimit;
+ }
+ return reductionLimit;
+ }
+
+ public ProjectCache getProjectCache() {
+ return projectCache;
+ }
+
+ public PermissionBackend getPermissionBackend() {
+ return permissionBackend;
+ }
+
+ public GitRepositoryManager getGitRepositoryManager() {
+ return repositoryManager;
+ }
+
+ public PatchListCache getPatchListCache() {
+ return patchListCache;
+ }
+
+ public PatchSetInfoFactory getPatchSetInfoFactory() {
+ return patchSetInfoFactory;
+ }
+
+ public IdentifiedUser.GenericFactory getUserFactory() {
+ return userFactory;
+ }
+
+ public AnonymousUser getAnonymousUser() {
+ return anonymousUser.get();
+ }
+
+ public PatchSetUtil getPatchsetUtil() {
+ return patchsetUtil;
+ }
+
+ public Emails getEmails() {
+ return emails;
+ }
+ }
+}