Initial libraty creation The problem is with DynamicItem - it doesn't get updated with the Gerrit cache reference. It seems that it doesn't work across db and sys injector. Change-Id: I05cf4766e4b74b380c9fbf7c6e25553dfa76d5d3
diff --git a/BUILD b/BUILD new file mode 100644 index 0000000..f8f49ad --- /dev/null +++ b/BUILD
@@ -0,0 +1,44 @@ +load("//tools/bzl:junit.bzl", "junit_tests") +load("//javatests/com/google/gerrit/acceptance:tests.bzl", "acceptance_tests") +load( + "//tools/bzl:plugin.bzl", + "PLUGIN_DEPS", + "PLUGIN_DEPS_NEVERLINK", + "PLUGIN_TEST_DEPS", + "gerrit_plugin", +) + +gerrit_plugin( + name = "gerrit-cached-refdb", + srcs = glob(["src/main/java/**/*.java"]), + manifest_entries = [ + "Gerrit-PluginName: gerrit-cached-refdb", + "Implementation-Title: gerrit-cached-refdb plugin", + "Implementation-URL: TODO", + ], + resources = glob(["src/main/resources/**/*"]), + deps = [], +) + +junit_tests( + name = "gerrit-cached-refdb_tests", + srcs = glob(["src/test/java/**/*Test.java"]), + resources = glob(["src/test/resources/**/*"]), + tags = [ + "local", + "gerrit-cached-refdb", + ], + deps = PLUGIN_DEPS + PLUGIN_TEST_DEPS + [ + ":gerrit-cached-refdb__plugin", + ], +) + +acceptance_tests( + srcs = glob(["src/test/java/**/*IT.java"]), + group = "jgit_cache", + labels = ["server"], + vm_args = ["-Xmx2G"], + deps = [ + ":gerrit-cached-refdb__plugin", + ], +) \ No newline at end of file
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/BatchRefUpdateWithCacheUpdate.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/BatchRefUpdateWithCacheUpdate.java new file mode 100644 index 0000000..360dfa1 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/BatchRefUpdateWithCacheUpdate.java
@@ -0,0 +1,184 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import org.eclipse.jgit.lib.BatchRefUpdate; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.ProgressMonitor; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.PushCertificate; +import org.eclipse.jgit.transport.ReceiveCommand; +import org.eclipse.jgit.util.time.ProposedTimestamp; + +class BatchRefUpdateWithCacheUpdate extends BatchRefUpdate { + interface Factory { + BatchRefUpdateWithCacheUpdate create(Repository repo, BatchRefUpdate delegate); + } + + private final Repository repo; + private final RefByNameCacheWrapper refsCache; + private final BatchRefUpdate delegate; + + @Inject + BatchRefUpdateWithCacheUpdate( + RefByNameCacheWrapper refsCache, + @Assisted Repository repo, + @Assisted BatchRefUpdate delegate) { + super(repo.getRefDatabase()); + this.refsCache = refsCache; + this.repo = repo; + this.delegate = delegate; + } + + @Override + public boolean isAllowNonFastForwards() { + return delegate.isAllowNonFastForwards(); + } + + @Override + public BatchRefUpdate setAllowNonFastForwards(boolean allow) { + delegate.setAllowNonFastForwards(allow); + return this; + } + + @Override + public PersonIdent getRefLogIdent() { + return delegate.getRefLogIdent(); + } + + @Override + public BatchRefUpdate setRefLogIdent(PersonIdent pi) { + delegate.setRefLogIdent(pi); + return this; + } + + @Override + public String getRefLogMessage() { + return delegate.getRefLogMessage(); + } + + @Override + public boolean isRefLogIncludingResult() { + return delegate.isRefLogIncludingResult(); + } + + @Override + public BatchRefUpdate setRefLogMessage(String msg, boolean appendStatus) { + delegate.setRefLogMessage(msg, appendStatus); + return this; + } + + @Override + public BatchRefUpdate disableRefLog() { + delegate.disableRefLog(); + return this; + } + + @Override + public BatchRefUpdate setForceRefLog(boolean force) { + delegate.setForceRefLog(force); + return this; + } + + @Override + public boolean isRefLogDisabled() { + return delegate.isRefLogDisabled(); + } + + @Override + public BatchRefUpdate setAtomic(boolean atomic) { + delegate.setAtomic(atomic); + return this; + } + + @Override + public boolean isAtomic() { + return delegate.isAtomic(); + } + + @Override + public void setPushCertificate(PushCertificate cert) { + delegate.setPushCertificate(cert); + } + + @Override + public List<ReceiveCommand> getCommands() { + return delegate.getCommands(); + } + + @Override + public BatchRefUpdate addCommand(ReceiveCommand cmd) { + delegate.addCommand(cmd); + return this; + } + + @Override + public BatchRefUpdate addCommand(ReceiveCommand... cmd) { + delegate.addCommand(cmd); + return this; + } + + @Override + public BatchRefUpdate addCommand(Collection<ReceiveCommand> cmd) { + delegate.addCommand(cmd); + return this; + } + + @Override + public List<String> getPushOptions() { + return delegate.getPushOptions(); + } + + @Override + public List<ProposedTimestamp> getProposedTimestamps() { + return delegate.getProposedTimestamps(); + } + + @Override + public BatchRefUpdate addProposedTimestamp(ProposedTimestamp ts) { + delegate.addProposedTimestamp(ts); + return this; + } + + @Override + public void execute(RevWalk walk, ProgressMonitor monitor, List<String> options) + throws IOException { + delegate.execute(walk, monitor, options); + evictCache(); + } + + @Override + public void execute(RevWalk walk, ProgressMonitor monitor) throws IOException { + delegate.execute(walk, monitor); + evictCache(); + } + + private void evictCache() { + delegate + .getCommands() + .forEach( + cmd -> { + if (cmd.getResult() == ReceiveCommand.Result.OK) { + refsCache.evict(repo.getIdentifier(), cmd.getRefName()); + } + }); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/CachedRefDatabase.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/CachedRefDatabase.java new file mode 100644 index 0000000..79a619c --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/CachedRefDatabase.java
@@ -0,0 +1,174 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import org.eclipse.jgit.lib.BatchRefUpdate; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefDatabase; +import org.eclipse.jgit.lib.RefRename; +import org.eclipse.jgit.lib.RefUpdate; + +class CachedRefDatabase extends RefDatabase { + interface Factory { + CachedRefDatabase create(CachedRefRepository repo); + } + + private final RefByNameCacheWrapper refsCache; + private final BatchRefUpdateWithCacheUpdate.Factory batchUpdateFactory; + private final RefUpdateWithCacheUpdate.Factory updateFactory; + private final RefRenameWithCacheUpdate.Factory renameFactory; + private final RefDatabase delegate; + private final CachedRefRepository repo; + + @Inject + CachedRefDatabase( + RefByNameCacheWrapper refsCache, + BatchRefUpdateWithCacheUpdate.Factory batchUpdateFactory, + RefUpdateWithCacheUpdate.Factory updateFactory, + RefRenameWithCacheUpdate.Factory renameFactory, + @Assisted CachedRefRepository repo) { + this.refsCache = refsCache; + this.batchUpdateFactory = batchUpdateFactory; + this.updateFactory = updateFactory; + this.renameFactory = renameFactory; + this.delegate = repo.getDelegate().getRefDatabase(); + this.repo = repo; + } + + @Override + public void create() throws IOException { + delegate.create(); + } + + @Override + public void close() { + delegate.close(); + } + + @Override + public boolean isNameConflicting(String name) throws IOException { + return delegate.isNameConflicting(name); + } + + @Override + public RefUpdate newUpdate(String name, boolean detach) throws IOException { + return updateFactory.create(this, repo, delegate.newUpdate(name, detach)); + } + + @Override + public RefRename newRename(String fromName, String toName) throws IOException { + return renameFactory.create( + repo, + delegate.newRename(fromName, toName), + newUpdate(fromName, false), + newUpdate(toName, false)); + } + + @Override + public Ref exactRef(String name) throws IOException { + return refsCache.computeIfAbsent( + repo.getIdentifier(), name, () -> Optional.ofNullable(delegate.exactRef(name))); + } + + @Deprecated + @Override + public Map<String, Ref> getRefs(String prefix) throws IOException { + return delegate.getRefs(prefix); + } + + @Override + public List<Ref> getAdditionalRefs() throws IOException { + return delegate.getAdditionalRefs(); + } + + @Override + public Ref peel(Ref ref) throws IOException { + return delegate.peel(ref); + } + + @Override + public boolean hasVersioning() { + return delegate.hasVersioning(); + } + + @Override + public Collection<String> getConflictingNames(String name) throws IOException { + return delegate.getConflictingNames(name); + } + + @Override + public BatchRefUpdate newBatchUpdate() { + return batchUpdateFactory.create(repo, delegate.newBatchUpdate()); + } + + @Override + public boolean performsAtomicTransactions() { + return delegate.performsAtomicTransactions(); + } + + @Override + public Map<String, Ref> exactRef(String... refs) throws IOException { + return delegate.exactRef(refs); + } + + @Override + public Ref firstExactRef(String... refs) throws IOException { + return delegate.firstExactRef(refs); + } + + @Override + public List<Ref> getRefs() throws IOException { + return delegate.getRefs(); + } + + @Override + public List<Ref> getRefsByPrefix(String prefix) throws IOException { + return delegate.getRefsByPrefix(prefix); + } + + @Override + public List<Ref> getRefsByPrefix(String... prefixes) throws IOException { + return delegate.getRefsByPrefix(prefixes); + } + + @Override + public Set<Ref> getTipsWithSha1(ObjectId id) throws IOException { + return delegate.getTipsWithSha1(id); + } + + @Override + public boolean hasFastTipsWithSha1() throws IOException { + return delegate.hasFastTipsWithSha1(); + } + + @Override + public boolean hasRefs() throws IOException { + return delegate.hasRefs(); + } + + @Override + public void refresh() { + delegate.refresh(); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/CachedRefRepository.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/CachedRefRepository.java new file mode 100644 index 0000000..e7960e3 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/CachedRefRepository.java
@@ -0,0 +1,350 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.errors.AmbiguousObjectException; +import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.errors.NoWorkTreeException; +import org.eclipse.jgit.errors.RevisionSyntaxException; +import org.eclipse.jgit.events.ListenerList; +import org.eclipse.jgit.events.RepositoryEvent; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.ObjectLoader; +import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.lib.ProgressMonitor; +import org.eclipse.jgit.lib.RebaseTodoLine; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefDatabase; +import org.eclipse.jgit.lib.RefRename; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.RepositoryState; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.util.FS; + +class CachedRefRepository extends DelegateRepository { + interface Factory { + CachedRefRepository create(Repository repo); + } + + private final CachedRefDatabase refDb; + private final RefUpdateWithCacheUpdate.Factory updateFactory; + private final RefRenameWithCacheUpdate.Factory renameFactory; + + @Inject + CachedRefRepository( + CachedRefDatabase.Factory refDbFactory, + RefUpdateWithCacheUpdate.Factory updateFactory, + RefRenameWithCacheUpdate.Factory renameFactory, + @Assisted Repository repo) { + super(repo); + this.updateFactory = updateFactory; + this.renameFactory = renameFactory; + this.refDb = refDbFactory.create(this); + } + + @Override + public RefDatabase getRefDatabase() { + return refDb; + } + + @Override + public ListenerList getListenerList() { + return getDelegate().getListenerList(); + } + + @Override + public void fireEvent(RepositoryEvent<?> event) { + getDelegate().fireEvent(event); + } + + @Override + public File getDirectory() { + return getDelegate().getDirectory(); + } + + @Override + public ObjectInserter newObjectInserter() { + return getDelegate().newObjectInserter(); + } + + @Override + public ObjectReader newObjectReader() { + return getDelegate().newObjectReader(); + } + + @Override + public FS getFS() { + return getDelegate().getFS(); + } + + @Deprecated + @Override + public boolean hasObject(AnyObjectId objectId) { + return getDelegate().hasObject(objectId); + } + + @Override + public ObjectLoader open(AnyObjectId objectId) throws MissingObjectException, IOException { + return getDelegate().open(objectId); + } + + @Override + public ObjectLoader open(AnyObjectId objectId, int typeHint) + throws MissingObjectException, IncorrectObjectTypeException, IOException { + return getDelegate().open(objectId, typeHint); + } + + @Override + public RefUpdate updateRef(String ref) throws IOException { + return updateFactory.create(refDb, this, getDelegate().updateRef(ref)); + } + + @Override + public RefUpdate updateRef(String ref, boolean detach) throws IOException { + return updateFactory.create(refDb, this, getDelegate().updateRef(ref, detach)); + } + + @Override + public RefRename renameRef(String fromRef, String toRef) throws IOException { + return renameFactory.create( + this, getDelegate().renameRef(fromRef, toRef), updateRef(fromRef), updateRef(toRef)); + } + + @Override + public ObjectId resolve(String revstr) + throws AmbiguousObjectException, IncorrectObjectTypeException, RevisionSyntaxException, + IOException { + return getDelegate().resolve(revstr); + } + + @Override + public String simplify(String revstr) throws AmbiguousObjectException, IOException { + return getDelegate().simplify(revstr); + } + + @Override + public void incrementOpen() { + getDelegate().incrementOpen(); + } + + @Override + public void close() { + getDelegate().close(); + } + + @Override + public String getFullBranch() throws IOException { + return getDelegate().getFullBranch(); + } + + @Override + public String getBranch() throws IOException { + return getDelegate().getBranch(); + } + + @Override + public Set<ObjectId> getAdditionalHaves() { + return getDelegate().getAdditionalHaves(); + } + + @Deprecated + @Override + public Map<String, Ref> getAllRefs() { + return getDelegate().getAllRefs(); + } + + @Deprecated + @Override + public Map<String, Ref> getTags() { + return getDelegate().getTags(); + } + + @Deprecated + @Override + public Ref peel(Ref ref) { + return getDelegate().peel(ref); + } + + @Override + public Map<AnyObjectId, Set<Ref>> getAllRefsByPeeledObjectId() { + return getDelegate().getAllRefsByPeeledObjectId(); + } + + @Override + public File getIndexFile() throws NoWorkTreeException { + return getDelegate().getIndexFile(); + } + + @Override + public RevCommit parseCommit(AnyObjectId id) + throws IncorrectObjectTypeException, IOException, MissingObjectException { + return getDelegate().parseCommit(id); + } + + @Override + public DirCache readDirCache() throws NoWorkTreeException, CorruptObjectException, IOException { + return getDelegate().readDirCache(); + } + + @Override + public DirCache lockDirCache() throws NoWorkTreeException, CorruptObjectException, IOException { + return getDelegate().lockDirCache(); + } + + @Override + public RepositoryState getRepositoryState() { + return getDelegate().getRepositoryState(); + } + + @Override + public boolean isBare() { + return getDelegate().isBare(); + } + + @Override + public File getWorkTree() throws NoWorkTreeException { + return getDelegate().getWorkTree(); + } + + @Override + public String shortenRemoteBranchName(String refName) { + return getDelegate().shortenRemoteBranchName(refName); + } + + @Override + public String getRemoteName(String refName) { + return getDelegate().getRemoteName(refName); + } + + @Override + public String getGitwebDescription() throws IOException { + return getDelegate().getGitwebDescription(); + } + + @Override + public void setGitwebDescription(String description) throws IOException { + getDelegate().setGitwebDescription(description); + } + + @Override + public String readMergeCommitMsg() throws IOException, NoWorkTreeException { + return getDelegate().readMergeCommitMsg(); + } + + @Override + public void writeMergeCommitMsg(String msg) throws IOException { + getDelegate().writeMergeCommitMsg(msg); + } + + @Override + public String readCommitEditMsg() throws IOException, NoWorkTreeException { + return getDelegate().readCommitEditMsg(); + } + + @Override + public void writeCommitEditMsg(String msg) throws IOException { + getDelegate().writeCommitEditMsg(msg); + } + + @Override + public List<ObjectId> readMergeHeads() throws IOException, NoWorkTreeException { + return getDelegate().readMergeHeads(); + } + + @Override + public void writeMergeHeads(List<? extends ObjectId> heads) throws IOException { + getDelegate().writeMergeHeads(heads); + } + + @Override + public ObjectId readCherryPickHead() throws IOException, NoWorkTreeException { + return getDelegate().readCherryPickHead(); + } + + @Override + public ObjectId readRevertHead() throws IOException, NoWorkTreeException { + return getDelegate().readRevertHead(); + } + + @Override + public void writeCherryPickHead(ObjectId head) throws IOException { + getDelegate().writeCherryPickHead(head); + } + + @Override + public void writeRevertHead(ObjectId head) throws IOException { + getDelegate().writeRevertHead(head); + } + + @Override + public void writeOrigHead(ObjectId head) throws IOException { + getDelegate().writeOrigHead(head); + } + + @Override + public ObjectId readOrigHead() throws IOException, NoWorkTreeException { + return getDelegate().readOrigHead(); + } + + @Override + public String readSquashCommitMsg() throws IOException { + return getDelegate().readSquashCommitMsg(); + } + + @Override + public void writeSquashCommitMsg(String msg) throws IOException { + getDelegate().writeSquashCommitMsg(msg); + } + + @Override + public List<RebaseTodoLine> readRebaseTodo(String path, boolean includeComments) + throws IOException { + return getDelegate().readRebaseTodo(path, includeComments); + } + + @Override + public void writeRebaseTodoFile(String path, List<RebaseTodoLine> steps, boolean append) + throws IOException { + getDelegate().writeRebaseTodoFile(path, steps, append); + } + + @Override + public Set<String> getRemoteNames() { + return getDelegate().getRemoteNames(); + } + + @Override + public void autoGC(ProgressMonitor monitor) { + getDelegate().autoGC(monitor); + } + + @Override + public void create() throws IOException { + getDelegate().create(); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/CachedRefsModule.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/CachedRefsModule.java new file mode 100644 index 0000000..9d6eb2d --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/CachedRefsModule.java
@@ -0,0 +1,23 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import com.google.gerrit.extensions.config.FactoryModule; + +public class CachedRefsModule extends FactoryModule { + @Override + protected void configure() { + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/DelegateRepository.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/DelegateRepository.java new file mode 100644 index 0000000..1323398 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/DelegateRepository.java
@@ -0,0 +1,97 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import java.io.IOException; +import org.eclipse.jgit.attributes.AttributesNodeProvider; +import org.eclipse.jgit.lib.BaseRepositoryBuilder; +import org.eclipse.jgit.lib.ObjectDatabase; +import org.eclipse.jgit.lib.RefDatabase; +import org.eclipse.jgit.lib.ReflogReader; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; + +/** + * For the time being copied from com.google.gerrit.server.git.DelegateRepository as it is package + * protected in 'stable-3.2'. It can be dropped when change gets merged up to. + */ +class DelegateRepository extends Repository { + + private final Repository delegate; + + DelegateRepository(Repository delegate) { + super(toBuilder(delegate)); + this.delegate = delegate; + } + + @Override + public void create(boolean bare) throws IOException { + delegate.create(bare); + } + + @Override + public String getIdentifier() { + return delegate.getIdentifier(); + } + + @Override + public ObjectDatabase getObjectDatabase() { + return delegate.getObjectDatabase(); + } + + @Override + public RefDatabase getRefDatabase() { + return delegate.getRefDatabase(); + } + + @Override + public StoredConfig getConfig() { + return delegate.getConfig(); + } + + @Override + public AttributesNodeProvider createAttributesNodeProvider() { + return delegate.createAttributesNodeProvider(); + } + + @Override + public void scanForRepoChanges() throws IOException { + delegate.scanForRepoChanges(); + } + + @Override + public void notifyIndexChanged(boolean internal) { + delegate.notifyIndexChanged(internal); + } + + @Override + public ReflogReader getReflogReader(String refName) throws IOException { + return delegate.getReflogReader(refName); + } + + public Repository getDelegate() { + return delegate; + } + + @SuppressWarnings("rawtypes") + private static BaseRepositoryBuilder toBuilder(Repository repo) { + if (!repo.isBare()) { + throw new IllegalArgumentException( + "non-bare repository is not supported: " + repo.getIdentifier()); + } + + return new BaseRepositoryBuilder<>().setFS(repo.getFS()).setGitDir(repo.getDirectory()); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/GerritCachedGitRepositoryManager.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/GerritCachedGitRepositoryManager.java new file mode 100644 index 0000000..4eb0cf1 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/GerritCachedGitRepositoryManager.java
@@ -0,0 +1,52 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import com.google.gerrit.entities.Project; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.git.LocalDiskRepositoryManager; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import java.io.IOException; +import java.util.SortedSet; +import org.eclipse.jgit.lib.Repository; + +@Singleton +class GerritCachedGitRepositoryManager implements GitRepositoryManager { + private final LocalDiskRepositoryManager repoManager; + private final CachedRefRepository.Factory repoWrapperFactory; + + @Inject + GerritCachedGitRepositoryManager( + LocalDiskRepositoryManager repoManager, CachedRefRepository.Factory repoWrapperFactory) { + this.repoManager = repoManager; + this.repoWrapperFactory = repoWrapperFactory; + } + + @Override + public Repository openRepository(Project.NameKey name) throws IOException { + return repoWrapperFactory.create(repoManager.openRepository(name)); + } + + @Override + public Repository createRepository(Project.NameKey name) throws IOException { + return repoWrapperFactory.create(repoManager.createRepository(name)); + } + + @Override + public SortedSet<Project.NameKey> list() { + return repoManager.list(); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/LibDbModule.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/LibDbModule.java new file mode 100644 index 0000000..5787abe --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/LibDbModule.java
@@ -0,0 +1,38 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import com.google.common.flogger.FluentLogger; +import com.google.gerrit.extensions.config.FactoryModule; +import com.google.gerrit.extensions.registration.DynamicItem; +import com.google.gerrit.server.git.GitRepositoryManager; + +public class LibDbModule extends FactoryModule { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + + @Override + protected void configure() { + DynamicItem.itemOf(binder(), RefByNameCache.class); + + factory(RefUpdateWithCacheUpdate.Factory.class); + factory(RefRenameWithCacheUpdate.Factory.class); + factory(BatchRefUpdateWithCacheUpdate.Factory.class); + factory(CachedRefDatabase.Factory.class); + factory(CachedRefRepository.Factory.class); + + bind(GitRepositoryManager.class).to(GerritCachedGitRepositoryManager.class); + logger.atInfo().log("DB library loaded"); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/LibSysModule.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/LibSysModule.java new file mode 100644 index 0000000..e6dab8f --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/LibSysModule.java
@@ -0,0 +1,32 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import static com.google.inject.Scopes.SINGLETON; + +import com.google.common.flogger.FluentLogger; +import com.google.gerrit.extensions.registration.DynamicItem; +import com.google.inject.AbstractModule; + +public class LibSysModule extends AbstractModule { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + + @Override + protected void configure() { + install(RefByNameGerritCache.module()); + DynamicItem.bind(binder(), RefByNameCache.class).to(RefByNameGerritCache.class).in(SINGLETON); + logger.atInfo().log("Sys library loaded"); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/NoOpRefByNameCache.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/NoOpRefByNameCache.java new file mode 100644 index 0000000..44b6abb --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/NoOpRefByNameCache.java
@@ -0,0 +1,41 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import com.google.common.flogger.FluentLogger; +import java.util.Optional; +import java.util.concurrent.Callable; +import org.eclipse.jgit.lib.Ref; + +class NoOpRefByNameCache implements RefByNameCache { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + + @Override + public Ref computeIfAbsent( + String identifier, String ref, Callable<? extends Optional<Ref>> loader) { + try { + return loader.call().orElse(null); + } catch (Exception e) { + logger.atSevere().withCause(e).log( + "Repository '%s', getting ref '%s' failed", identifier, ref); + } + return null; + } + + @Override + public void evict(String identifier, String ref) { + // do nothing as there is no cache to be evicted + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefByNameCache.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefByNameCache.java new file mode 100644 index 0000000..69fabfc --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefByNameCache.java
@@ -0,0 +1,25 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import java.util.Optional; +import java.util.concurrent.Callable; +import org.eclipse.jgit.lib.Ref; + +interface RefByNameCache { + Ref computeIfAbsent(String identifier, String ref, Callable<? extends Optional<Ref>> loader); + + void evict(String identifier, String ref); +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefByNameCacheWrapper.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefByNameCacheWrapper.java new file mode 100644 index 0000000..c9744ad --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefByNameCacheWrapper.java
@@ -0,0 +1,45 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import com.google.common.annotations.VisibleForTesting; +import com.google.gerrit.extensions.registration.DynamicItem; +import com.google.inject.Inject; +import java.util.Optional; +import java.util.concurrent.Callable; +import org.eclipse.jgit.lib.Ref; + +class RefByNameCacheWrapper implements RefByNameCache { + private static final RefByNameCache NOOP_CACHE = new NoOpRefByNameCache(); + + @Inject(optional = true) + private DynamicItem<RefByNameCache> refByNameCache; + + @Override + public Ref computeIfAbsent( + String identifier, String ref, Callable<? extends Optional<Ref>> loader) { + return cache().computeIfAbsent(identifier, ref, loader); + } + + @Override + public void evict(String identifier, String ref) { + cache().evict(identifier, ref); + } + + @VisibleForTesting + RefByNameCache cache() { + return Optional.ofNullable(refByNameCache).map(DynamicItem::get).orElse(NOOP_CACHE); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefByNameGerritCache.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefByNameGerritCache.java new file mode 100644 index 0000000..e9fc2b7 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefByNameGerritCache.java
@@ -0,0 +1,70 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import com.google.common.cache.Cache; +import com.google.common.flogger.FluentLogger; +import com.google.gerrit.server.cache.CacheModule; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Named; +import java.util.Optional; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import org.eclipse.jgit.lib.Ref; + +@Singleton +class RefByNameGerritCache implements RefByNameCache { + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + private static final String REF_BY_NAME = "ref_by_name"; + + static com.google.inject.Module module() { + return new CacheModule() { + @Override + protected void configure() { + cache(REF_BY_NAME, String.class, new TypeLiteral<Optional<Ref>>() {}); + } + }; + } + + private final Cache<String, Optional<Ref>> refByName; + + @Inject + RefByNameGerritCache(@Named(REF_BY_NAME) Cache<String, Optional<Ref>> refByName) { + this.refByName = refByName; + } + + @Override + public Ref computeIfAbsent( + String identifier, String ref, Callable<? extends Optional<Ref>> loader) { + String uniqueRefName = getUniqueName(identifier, ref); + try { + return refByName.get(uniqueRefName, loader).orElse(null); + } catch (ExecutionException e) { + logger.atWarning().withCause(e).log("Getting ref for [%s] failed.", uniqueRefName); + return null; + } + } + + @Override + public void evict(String identifier, String ref) { + refByName.invalidate(getUniqueName(identifier, ref)); + } + + private static String getUniqueName(String identifier, String ref) { + return String.format("%s$%s", identifier, ref); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefRenameWithCacheUpdate.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefRenameWithCacheUpdate.java new file mode 100644 index 0000000..68de4ca --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefRenameWithCacheUpdate.java
@@ -0,0 +1,107 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import java.io.IOException; +import java.util.EnumSet; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.RefRename; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.RefUpdate.Result; +import org.eclipse.jgit.lib.Repository; + +class RefRenameWithCacheUpdate extends RefRename { + interface Factory { + RefRenameWithCacheUpdate create( + Repository repo, + RefRename delegate, + @Assisted("src") RefUpdate src, + @Assisted("dst") RefUpdate dst); + } + + private static final String NOT_SUPPORTED_MSG = "Should never be called"; + private static final EnumSet<Result> SUCCESSFUL_RENAMES = + EnumSet.of(Result.NEW, Result.FORCED, Result.FAST_FORWARD, Result.RENAMED); + + private final RefByNameCacheWrapper refsCache; + private final Repository repo; + private final RefRename delegate; + private final RefUpdate src; + + @Inject + RefRenameWithCacheUpdate( + RefByNameCacheWrapper refsCache, + @Assisted Repository repo, + @Assisted RefRename delegate, + @Assisted("src") RefUpdate src, + @Assisted("dst") RefUpdate dst) { + super(src, dst); + this.refsCache = refsCache; + this.repo = repo; + this.delegate = delegate; + this.src = src; + } + + @Override + public PersonIdent getRefLogIdent() { + return delegate.getRefLogIdent(); + } + + @Override + public void setRefLogIdent(PersonIdent pi) { + delegate.setRefLogIdent(pi); + } + + @Override + public String getRefLogMessage() { + return delegate.getRefLogMessage(); + } + + @Override + public void setRefLogMessage(String msg) { + // Method is called from the super constructor and delegate is not available yet therefore + // 'null' has to be checked. It doesn't matter as wrapped instance is properly constructed and + // its ref log message is used. + if (delegate != null) { + delegate.setRefLogMessage(msg); + } + } + + @Override + public void disableRefLog() { + delegate.disableRefLog(); + } + + @Override + public Result getResult() { + return delegate.getResult(); + } + + @Override + public Result rename() throws IOException { + Result r = delegate.rename(); + if (SUCCESSFUL_RENAMES.contains(r)) { + refsCache.evict(repo.getIdentifier(), src.getName()); + } + return r; + } + + @Override + protected Result doRename() throws IOException { + throw new UnsupportedOperationException(NOT_SUPPORTED_MSG); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefUpdateWithCacheUpdate.java b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefUpdateWithCacheUpdate.java new file mode 100644 index 0000000..a4bee39 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/RefUpdateWithCacheUpdate.java
@@ -0,0 +1,215 @@ +package com.googlesource.gerrit.plugins.gerritcachedrefdb; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import java.io.IOException; +import java.util.EnumSet; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefDatabase; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.PushCertificate; + +class RefUpdateWithCacheUpdate extends RefUpdate { + interface Factory { + RefUpdateWithCacheUpdate create(RefDatabase refDb, Repository repo, RefUpdate delegate); + } + + private static final String NOT_SUPPORTED_MSG = "Should never be called"; + private static final EnumSet<Result> SUCCESSFUL_UPDATES = + EnumSet.of(Result.NEW, Result.FORCED, Result.FAST_FORWARD, Result.RENAMED); + + private final RefByNameCacheWrapper refsCache; + private final RefDatabase refDb; + private final Repository repo; + private final RefUpdate delegate; + + @Inject + RefUpdateWithCacheUpdate( + RefByNameCacheWrapper refsCache, + @Assisted RefDatabase refDb, + @Assisted Repository repo, + @Assisted RefUpdate delegate) { + super(delegate.getRef()); + this.refsCache = refsCache; + this.refDb = refDb; + this.repo = repo; + this.delegate = delegate; + } + + @Override + public String getName() { + return delegate.getName(); + } + + @Override + public Ref getRef() { + return delegate.getRef(); + } + + @Override + public ObjectId getNewObjectId() { + return delegate.getNewObjectId(); + } + + @Override + public void setDetachingSymbolicRef() { + delegate.setDetachingSymbolicRef(); + } + + @Override + public boolean isDetachingSymbolicRef() { + return delegate.isDetachingSymbolicRef(); + } + + @Override + public void setNewObjectId(AnyObjectId id) { + delegate.setNewObjectId(id); + } + + @Override + public ObjectId getExpectedOldObjectId() { + return delegate.getExpectedOldObjectId(); + } + + @Override + public void setExpectedOldObjectId(AnyObjectId id) { + delegate.setExpectedOldObjectId(id); + } + + @Override + public boolean isForceUpdate() { + return delegate.isForceUpdate(); + } + + @Override + public void setForceUpdate(boolean b) { + delegate.setForceUpdate(b); + } + + @Override + public PersonIdent getRefLogIdent() { + return delegate.getRefLogIdent(); + } + + @Override + public void setRefLogIdent(PersonIdent pi) { + delegate.setRefLogIdent(pi); + } + + @Override + public String getRefLogMessage() { + return delegate.getRefLogMessage(); + } + + @Override + public void setRefLogMessage(String msg, boolean appendStatus) { + delegate.setRefLogMessage(msg, appendStatus); + } + + @Override + public void disableRefLog() { + delegate.disableRefLog(); + } + + @Override + public void setForceRefLog(boolean force) { + delegate.setForceRefLog(force); + } + + @Override + public ObjectId getOldObjectId() { + return delegate.getOldObjectId(); + } + + @Override + public void setPushCertificate(PushCertificate cert) { + delegate.setPushCertificate(cert); + } + + @Override + public Result getResult() { + return delegate.getResult(); + } + + @Override + public Result forceUpdate() throws IOException { + return evictCache(delegate.forceUpdate()); + } + + @Override + public Result update() throws IOException { + return evictCache(delegate.update()); + } + + @Override + public Result update(RevWalk walk) throws IOException { + return evictCache(delegate.update(walk)); + } + + @Override + public Result delete() throws IOException { + return evictCache(delegate.delete()); + } + + @Override + public Result delete(RevWalk walk) throws IOException { + return evictCache(delegate.delete(walk)); + } + + @Override + public Result link(String target) throws IOException { + return evictCache(delegate.link(target)); + } + + @Override + public void setCheckConflicting(boolean check) { + delegate.setCheckConflicting(check); + } + + @Override + protected RefDatabase getRefDatabase() { + return refDb; + } + + @Override + protected Repository getRepository() { + return repo; + } + + @Override + protected boolean tryLock(boolean deref) throws IOException { + throw new UnsupportedOperationException(NOT_SUPPORTED_MSG); + } + + @Override + protected void unlock() { + throw new UnsupportedOperationException(NOT_SUPPORTED_MSG); + } + + @Override + protected Result doUpdate(Result desiredResult) throws IOException { + throw new UnsupportedOperationException(NOT_SUPPORTED_MSG); + } + + @Override + protected Result doDelete(Result desiredResult) throws IOException { + throw new UnsupportedOperationException(NOT_SUPPORTED_MSG); + } + + @Override + protected Result doLink(String target) throws IOException { + throw new UnsupportedOperationException(NOT_SUPPORTED_MSG); + } + + private Result evictCache(Result r) { + if (SUCCESSFUL_UPDATES.contains(r)) { + refsCache.evict(repo.getIdentifier(), getName()); + } + return r; + } +}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/GerritCachedRefDbIT.java b/src/test/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/GerritCachedRefDbIT.java new file mode 100644 index 0000000..bf2ca31 --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/gerritcachedrefdb/GerritCachedRefDbIT.java
@@ -0,0 +1,45 @@ +// Copyright (C) 2021 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.googlesource.gerrit.plugins.gerritcachedrefdb; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.NoHttpd; +import com.google.gerrit.acceptance.UseLocalDisk; +import com.google.gerrit.acceptance.config.GerritConfig; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.inject.Inject; +import org.junit.Test; + +@UseLocalDisk +@NoHttpd +public class GerritCachedRefDbIT extends AbstractDaemonTest { + @Inject private GitRepositoryManager gitRepoManager; + + @Inject private RefByNameCacheWrapper refByNameCacheWrapper; + + @Test + @GerritConfig( + name = "gerrit.installDbModule", + value = "com.googlesource.gerrit.plugins.gerritcachedrefdb.LibDbModule") + @GerritConfig( + name = "gerrit.installModule", + value = "com.googlesource.gerrit.plugins.gerritcachedrefdb.LibSysModule") + public void shouldBeAbleToInstallGerritCachedGitRepoManager() { + assertThat(gitRepoManager).isInstanceOf(GerritCachedGitRepositoryManager.class); + assertThat(refByNameCacheWrapper.cache()).isInstanceOf(RefByNameGerritCache.class); + } +}