Line data Source code
1 : // Copyright (C) 2011 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.rules; 16 : 17 : import com.google.common.flogger.FluentLogger; 18 : import com.google.gerrit.server.AnonymousUser; 19 : import com.google.gerrit.server.IdentifiedUser; 20 : import com.google.gerrit.server.PatchSetUtil; 21 : import com.google.gerrit.server.account.Emails; 22 : import com.google.gerrit.server.config.GerritServerConfig; 23 : import com.google.gerrit.server.config.PluginConfigFactory; 24 : import com.google.gerrit.server.git.GitRepositoryManager; 25 : import com.google.gerrit.server.patch.DiffOperations; 26 : import com.google.gerrit.server.patch.PatchSetInfoFactory; 27 : import com.google.gerrit.server.permissions.PermissionBackend; 28 : import com.google.gerrit.server.project.ProjectCache; 29 : import com.google.inject.Inject; 30 : import com.google.inject.Provider; 31 : import com.google.inject.Singleton; 32 : import com.google.inject.assistedinject.Assisted; 33 : import com.googlecode.prolog_cafe.lang.BufferingPrologControl; 34 : import com.googlecode.prolog_cafe.lang.Predicate; 35 : import com.googlecode.prolog_cafe.lang.PredicateEncoder; 36 : import com.googlecode.prolog_cafe.lang.Prolog; 37 : import com.googlecode.prolog_cafe.lang.PrologMachineCopy; 38 : import java.util.ArrayList; 39 : import java.util.EnumSet; 40 : import java.util.HashMap; 41 : import java.util.Iterator; 42 : import java.util.List; 43 : import java.util.Map; 44 : import org.eclipse.jgit.lib.Config; 45 : 46 : /** 47 : * Per-thread Prolog interpreter. 48 : * 49 : * <p>This class is not thread safe. 50 : * 51 : * <p>A single copy of the Prolog interpreter, for the current thread. 52 : */ 53 : public class PrologEnvironment extends BufferingPrologControl { 54 147 : private static final FluentLogger logger = FluentLogger.forEnclosingClass(); 55 : 56 : public interface Factory { 57 : /** 58 : * Construct a new Prolog interpreter. 59 : * 60 : * @param src the machine to template the new environment from. 61 : * @return the new interpreter. 62 : */ 63 : PrologEnvironment create(PrologMachineCopy src); 64 : } 65 : 66 : private final Args args; 67 : private final Map<StoredValue<Object>, Object> storedValues; 68 : private List<Runnable> cleanup; 69 : 70 : @Inject 71 : PrologEnvironment(Args a, @Assisted PrologMachineCopy src) { 72 104 : super(src); 73 104 : setEnabled(EnumSet.allOf(Prolog.Feature.class), false); 74 104 : args = a; 75 104 : storedValues = new HashMap<>(); 76 104 : cleanup = new ArrayList<>(); 77 104 : } 78 : 79 : public Args getArgs() { 80 4 : return args; 81 : } 82 : 83 : @Override 84 : public void setPredicate(Predicate goal) { 85 104 : super.setPredicate(goal); 86 104 : int reductionLimit = args.reductionLimit(goal); 87 104 : setReductionLimit(reductionLimit); 88 104 : } 89 : 90 : /** 91 : * Lookup a stored value in the interpreter's hash manager. 92 : * 93 : * @param <T> type of stored Java object. 94 : * @param sv unique key. 95 : * @return the value; null if not stored. 96 : */ 97 : @SuppressWarnings("unchecked") 98 : public <T> T get(StoredValue<T> sv) { 99 104 : return (T) storedValues.get(sv); 100 : } 101 : 102 : /** 103 : * Set a stored value on the interpreter's hash manager. 104 : * 105 : * @param <T> type of stored Java object. 106 : * @param sv unique key. 107 : * @param obj the value to store under {@code sv}. 108 : */ 109 : @SuppressWarnings("unchecked") 110 : public <T> void set(StoredValue<T> sv, T obj) { 111 104 : storedValues.put((StoredValue<Object>) sv, obj); 112 104 : } 113 : 114 : /** 115 : * Copy the stored values from another interpreter to this one. Also gets the cleanup from the 116 : * child interpreter 117 : */ 118 : public void copyStoredValues(PrologEnvironment child) { 119 102 : storedValues.putAll(child.storedValues); 120 102 : setCleanup(child.cleanup); 121 102 : } 122 : 123 : /** 124 : * Assign the environment a cleanup list (in order to use a centralized list) If this 125 : * enivronment's list is non-empty, append its cleanup tasks to the assigning list. 126 : */ 127 : public void setCleanup(List<Runnable> newCleanupList) { 128 102 : newCleanupList.addAll(cleanup); 129 102 : cleanup = newCleanupList; 130 102 : } 131 : 132 : /** 133 : * Adds cleanup task to run when close() is called 134 : * 135 : * @param task is run when close() is called 136 : */ 137 : public void addToCleanup(Runnable task) { 138 2 : cleanup.add(task); 139 2 : } 140 : 141 : /** Release resources stored in interpreter's hash manager. */ 142 : public void close() { 143 103 : for (Iterator<Runnable> i = cleanup.iterator(); i.hasNext(); ) { 144 : try { 145 2 : i.next().run(); 146 0 : } catch (Exception err) { 147 0 : logger.atSevere().withCause(err).log("Failed to execute cleanup for PrologEnvironment"); 148 2 : } 149 2 : i.remove(); 150 : } 151 103 : } 152 : 153 : @Singleton 154 : public static class Args { 155 : private static final Class<Predicate> CONSULT_STREAM_2; 156 : 157 : static { 158 : try { 159 : @SuppressWarnings("unchecked") 160 147 : Class<Predicate> c = 161 : (Class<Predicate>) 162 147 : Class.forName( 163 147 : PredicateEncoder.encode(Prolog.BUILTIN, "consult_stream", 2), 164 : false, 165 147 : RulesCache.class.getClassLoader()); 166 147 : CONSULT_STREAM_2 = c; 167 0 : } catch (ClassNotFoundException e) { 168 0 : throw new LinkageError("cannot find predicate consult_stream", e); 169 147 : } 170 147 : } 171 : 172 : private final ProjectCache projectCache; 173 : private final PermissionBackend permissionBackend; 174 : private final GitRepositoryManager repositoryManager; 175 : private final PluginConfigFactory pluginConfigFactory; 176 : private final DiffOperations diffOperations; 177 : private final PatchSetInfoFactory patchSetInfoFactory; 178 : private final IdentifiedUser.GenericFactory userFactory; 179 : private final Provider<AnonymousUser> anonymousUser; 180 : private final int reductionLimit; 181 : private final int compileLimit; 182 : private final PatchSetUtil patchsetUtil; 183 : private Emails emails; 184 : 185 : @Inject 186 : Args( 187 : ProjectCache projectCache, 188 : PermissionBackend permissionBackend, 189 : GitRepositoryManager repositoryManager, 190 : PluginConfigFactory pluginConfigFactory, 191 : DiffOperations diffOperations, 192 : PatchSetInfoFactory patchSetInfoFactory, 193 : IdentifiedUser.GenericFactory userFactory, 194 : Provider<AnonymousUser> anonymousUser, 195 : @GerritServerConfig Config config, 196 : PatchSetUtil patchsetUtil, 197 147 : Emails emails) { 198 147 : this.projectCache = projectCache; 199 147 : this.permissionBackend = permissionBackend; 200 147 : this.repositoryManager = repositoryManager; 201 147 : this.pluginConfigFactory = pluginConfigFactory; 202 147 : this.diffOperations = diffOperations; 203 147 : this.patchSetInfoFactory = patchSetInfoFactory; 204 147 : this.userFactory = userFactory; 205 147 : this.anonymousUser = anonymousUser; 206 147 : this.patchsetUtil = patchsetUtil; 207 147 : this.emails = emails; 208 147 : this.reductionLimit = RuleUtil.reductionLimit(config); 209 147 : this.compileLimit = RuleUtil.compileReductionLimit(config); 210 : 211 147 : logger.atInfo().log("reductionLimit: %d, compileLimit: %d", reductionLimit, compileLimit); 212 147 : } 213 : 214 : private int reductionLimit(Predicate goal) { 215 104 : if (goal.getClass() == CONSULT_STREAM_2) { 216 1 : logger.atFine().log( 217 : "predicate class is CONSULT_STREAM_2: override reductionLimit with compileLimit (%d)", 218 : compileLimit); 219 1 : return compileLimit; 220 : } 221 104 : return reductionLimit; 222 : } 223 : 224 : public ProjectCache getProjectCache() { 225 0 : return projectCache; 226 : } 227 : 228 : public PermissionBackend getPermissionBackend() { 229 0 : return permissionBackend; 230 : } 231 : 232 : public GitRepositoryManager getGitRepositoryManager() { 233 2 : return repositoryManager; 234 : } 235 : 236 : public PluginConfigFactory getPluginConfigFactory() { 237 0 : return pluginConfigFactory; 238 : } 239 : 240 : public DiffOperations getDiffOperations() { 241 2 : return diffOperations; 242 : } 243 : 244 : public PatchSetInfoFactory getPatchSetInfoFactory() { 245 0 : return patchSetInfoFactory; 246 : } 247 : 248 : public IdentifiedUser.GenericFactory getUserFactory() { 249 0 : return userFactory; 250 : } 251 : 252 : public AnonymousUser getAnonymousUser() { 253 0 : return anonymousUser.get(); 254 : } 255 : 256 : public PatchSetUtil getPatchsetUtil() { 257 4 : return patchsetUtil; 258 : } 259 : 260 : public Emails getEmails() { 261 3 : return emails; 262 : } 263 : } 264 : }