Bind the project cache clock thread in its own object

This allows me to better control when this thread gets created in a
server. Right now its created 1:1 with the ProjectCacheImpl, which
works fine for servers that have only one site loaded in the JVM.
Longer term we should be supporting virtual hosting, where different
Gerrit Code Review sites are able to be managed from a single JVM,
and a single unified cache footprint (that still shards data uniquely
for each site).

Change-Id: I3e9b269aac7071a2f26a4289b4b524cb468592c7
This commit is contained in:
Shawn O. Pearce
2012-01-23 11:38:21 -08:00
parent 8dba895ad6
commit a595eacf30
2 changed files with 82 additions and 29 deletions

View File

@@ -19,8 +19,6 @@ import com.google.gerrit.server.cache.Cache;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.cache.EntryCreator;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.inject.Inject;
@@ -30,7 +28,6 @@ import com.google.inject.TypeLiteral;
import com.google.inject.name.Named;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Repository;
import java.util.Collections;
@@ -38,8 +35,6 @@ import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -71,39 +66,19 @@ public class ProjectCacheImpl implements ProjectCache {
private final Cache<Project.NameKey, ProjectState> byName;
private final Cache<ListKey,SortedSet<Project.NameKey>> list;
private final Lock listLock;
private volatile long generation;
private final ProjectCacheClock clock;
@Inject
ProjectCacheImpl(
final AllProjectsName allProjectsName,
@Named(CACHE_NAME) final Cache<Project.NameKey, ProjectState> byName,
@Named(CACHE_LIST) final Cache<ListKey, SortedSet<Project.NameKey>> list,
@GerritServerConfig final Config serverConfig) {
ProjectCacheClock clock) {
this.allProjectsName = allProjectsName;
this.byName = byName;
this.list = list;
this.listLock = new ReentrantLock(true /* fair */);
long checkFrequencyMillis = TimeUnit.MILLISECONDS.convert(
ConfigUtil.getTimeUnit(serverConfig,
"cache", "projects", "checkFrequency",
5, TimeUnit.MINUTES), TimeUnit.MINUTES);
if (10 < checkFrequencyMillis) {
// Start with generation 1 (to avoid magic 0 below).
generation = 1;
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// This is not exactly thread-safe, but is OK for our use.
// The only thread that writes the volatile is this task.
generation = generation + 1;
}
}, checkFrequencyMillis, checkFrequencyMillis, TimeUnit.MILLISECONDS);
} else {
// Magic generation 0 triggers ProjectState to always
// check on each needsRefresh() request we make to it.
generation = 0;
}
this.clock = clock;
}
@Override
@@ -125,7 +100,7 @@ public class ProjectCacheImpl implements ProjectCache {
*/
public ProjectState get(final Project.NameKey projectName) {
ProjectState state = byName.get(projectName);
if (state != null && state.needsRefresh(generation)) {
if (state != null && state.needsRefresh(clock.read())) {
byName.remove(projectName);
state = byName.get(projectName);
}