Load precompiled prolog rules from jar file
Looks in (site)/cache/rules for a jar file called: rules-(sha1 of rules.pl).jar Loads the precompiled prolog rules and uses them instead of consulting rules.pl. If the jar does not exist, consults rules.pl. If rules.pl does not exist, uses the default submit rules. Change-Id: Iae415de08dbe249eff26b753d258fd7f79a8771f
This commit is contained in:
committed by
Shawn O. Pearce
parent
76409cf7fa
commit
4efeb4fc64
@@ -76,6 +76,7 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
private Map<String, AccessSection> accessSections;
|
||||
private List<ValidationError> validationErrors;
|
||||
private String prologRules;
|
||||
private ObjectId rulesId;
|
||||
|
||||
public static ProjectConfig read(MetaDataUpdate update) throws IOException,
|
||||
ConfigInvalidException {
|
||||
@@ -163,6 +164,14 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
return prologRules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the project's rules.pl ObjectId, if present in the branch.
|
||||
* Null if it doesn't exist.
|
||||
*/
|
||||
public ObjectId getRulesId() {
|
||||
return rulesId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all GroupReferences use current group name, repairing stale ones.
|
||||
*
|
||||
@@ -204,6 +213,7 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
Map<String, GroupReference> groupsByName = readGroupList();
|
||||
|
||||
prologRules = readUTF8("rules.pl");
|
||||
rulesId = getObjectId("rules.pl");
|
||||
Config rc = readConfig(PROJECT_CONFIG);
|
||||
project = new Project(projectName);
|
||||
|
||||
|
||||
@@ -264,6 +264,19 @@ public abstract class VersionedMetaData {
|
||||
}
|
||||
}
|
||||
|
||||
protected ObjectId getObjectId(String fileName) throws IOException {
|
||||
if (revision == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TreeWalk tw = TreeWalk.forPath(reader, fileName, revision.getTree());
|
||||
if (tw != null) {
|
||||
return tw.getObjectId(0);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static void set(Config rc, String section, String subsection,
|
||||
String name, String value) {
|
||||
if (value != null) {
|
||||
|
||||
@@ -60,6 +60,7 @@ public class ProjectState {
|
||||
|
||||
private final ProjectConfig config;
|
||||
private final Set<AccountGroup.UUID> localOwners;
|
||||
private final ClassLoader ruleLoader;
|
||||
|
||||
/** Last system time the configuration's revision was examined. */
|
||||
private transient long lastCheckTime;
|
||||
@@ -71,6 +72,7 @@ public class ProjectState {
|
||||
final ProjectControl.AssistedFactory projectControlFactory,
|
||||
final PrologEnvironment.Factory envFactory,
|
||||
final GitRepositoryManager gitMgr,
|
||||
final RulesCache rulesCache,
|
||||
@Assisted final ProjectConfig config) {
|
||||
this.projectCache = projectCache;
|
||||
this.isAllProjects = config.getProject().getNameKey().equals(allProjectsName);
|
||||
@@ -79,6 +81,11 @@ public class ProjectState {
|
||||
this.gitMgr = gitMgr;
|
||||
this.config = config;
|
||||
this.lastCheckTime = System.currentTimeMillis();
|
||||
if (rulesCache != null) {
|
||||
ruleLoader = rulesCache.getClassLoader(config.getRulesId());
|
||||
} else {
|
||||
ruleLoader = null;
|
||||
}
|
||||
|
||||
HashSet<AccountGroup.UUID> groups = new HashSet<AccountGroup.UUID>();
|
||||
AccessSection all = config.getAccessSection(AccessSection.ALL);
|
||||
@@ -126,7 +133,10 @@ public class ProjectState {
|
||||
|
||||
/** @return Construct a new PrologEnvironment for the calling thread. */
|
||||
public PrologEnvironment newPrologEnvironment() throws CompileException {
|
||||
// TODO Replace this with a per-project ClassLoader to isolate rules.
|
||||
if (ruleLoader != null) {
|
||||
return envFactory.create(ruleLoader);
|
||||
}
|
||||
|
||||
PrologEnvironment env = envFactory.create(getClass().getClassLoader());
|
||||
|
||||
//consult rules.pl at refs/meta/config branch for custom submit rules
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
// 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.project;
|
||||
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Singleton
|
||||
public class RulesCache {
|
||||
private static final Logger log = LoggerFactory.getLogger(RulesCache.class);
|
||||
|
||||
private final Map<ObjectId, LoaderRef> classLoaderCache =
|
||||
new HashMap<ObjectId, LoaderRef>();
|
||||
|
||||
private final ReferenceQueue<ClassLoader> DEAD = new ReferenceQueue<ClassLoader>();
|
||||
|
||||
private final File cacheDir;
|
||||
private final File rulesDir;
|
||||
|
||||
private final class LoaderRef extends WeakReference<ClassLoader> {
|
||||
final ObjectId key;
|
||||
|
||||
LoaderRef(ObjectId key, ClassLoader loader) {
|
||||
super(loader, DEAD);
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected RulesCache (@GerritServerConfig Config config, SitePaths site) {
|
||||
cacheDir = site.resolve(config.getString("cache", null, "directory"));
|
||||
if (cacheDir != null) {
|
||||
rulesDir = new File(cacheDir, "rules");
|
||||
} else {
|
||||
rulesDir = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return URLClassLoader with precompiled rules jar from rules.pl if it exists,
|
||||
* null otherwise
|
||||
*/
|
||||
public synchronized ClassLoader getClassLoader(ObjectId rulesId) {
|
||||
if (rulesId == null || rulesDir == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference<? extends ClassLoader> ref = classLoaderCache.get(rulesId);
|
||||
if (ref != null) {
|
||||
ClassLoader cl = ref.get();
|
||||
if (cl != null) {
|
||||
return cl;
|
||||
}
|
||||
classLoaderCache.remove(rulesId);
|
||||
ref.enqueue();
|
||||
}
|
||||
|
||||
cleanCache();
|
||||
|
||||
//read jar from (site)/cache/rules
|
||||
//the included jar file should be in format:
|
||||
//rules-(rules.pl's sha1).jar
|
||||
File jarFile = new File(rulesDir, "rules-" + rulesId.getName() + ".jar");
|
||||
if (!jarFile.isFile()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClassLoader defaultLoader = getClass().getClassLoader();
|
||||
URL url;
|
||||
try {
|
||||
url = jarFile.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
log.error("Path to rules jar is broken", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
ClassLoader urlLoader = new URLClassLoader(new URL[]{url}, defaultLoader);
|
||||
|
||||
LoaderRef lRef = new LoaderRef(rulesId, urlLoader);
|
||||
classLoaderCache.put(rulesId, lRef);
|
||||
return urlLoader;
|
||||
}
|
||||
|
||||
private void cleanCache() {
|
||||
Reference<? extends ClassLoader> ref;
|
||||
while ((ref = DEAD.poll()) != null) {
|
||||
ObjectId key = ((LoaderRef) ref).key;
|
||||
if (classLoaderCache.get(key) == ref) {
|
||||
classLoaderCache.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,12 +170,12 @@ is_all_ok(_) :- fail.
|
||||
%%
|
||||
|
||||
locate_submit_rule(RuleName) :-
|
||||
clause(user:submit_rule(_), _),
|
||||
'$compiled_predicate'(user, submit_rule, 1),
|
||||
!,
|
||||
RuleName = user:submit_rule
|
||||
.
|
||||
locate_submit_rule(RuleName) :-
|
||||
'$compiled_predicate'(user, submit_rule, 1),
|
||||
clause(user:submit_rule(_), _),
|
||||
!,
|
||||
RuleName = user:submit_rule
|
||||
.
|
||||
|
||||
@@ -317,12 +317,13 @@ public class RefControlTest extends TestCase {
|
||||
PrologEnvironment.Factory envFactory = null;
|
||||
GitRepositoryManager mgr = null;
|
||||
ProjectControl.AssistedFactory projectControlFactory = null;
|
||||
RulesCache rulesCache = null;
|
||||
all.put(local.getProject().getNameKey(), new ProjectState(
|
||||
projectCache, allProjectsName, projectControlFactory,
|
||||
envFactory, mgr, local));
|
||||
envFactory, mgr, rulesCache, local));
|
||||
all.put(parent.getProject().getNameKey(), new ProjectState(
|
||||
projectCache, allProjectsName, projectControlFactory,
|
||||
envFactory, mgr, parent));
|
||||
envFactory, mgr, rulesCache, parent));
|
||||
return all.get(local.getProject().getNameKey());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user