LRU semantic for workdir cache (#1735)

Introduces a maximum size for the simple workdir cache. On cache overflow workdirs are evicted using an LRU strategy.
Furthermore parallel requests for the same repository will now block until the workdir is released.
This commit is contained in:
René Pfeuffer
2021-07-28 07:54:37 +02:00
committed by GitHub
parent f2cc9f67ac
commit ad6000722d
17 changed files with 578 additions and 97 deletions

View File

@@ -46,10 +46,10 @@ public class GitRepositoryConfigStoreProvider {
}
public GitRepositoryConfig getGitRepositoryConfig(String repositoryId) {
return getFronStore(createStore(repositoryId));
return getFromStore(createStore(repositoryId));
}
private static GitRepositoryConfig getFronStore(ConfigurationStore<GitRepositoryConfig> store) {
private static GitRepositoryConfig getFromStore(ConfigurationStore<GitRepositoryConfig> store) {
return store.getOptional().orElse(new GitRepositoryConfig());
}
@@ -72,7 +72,7 @@ public class GitRepositoryConfigStoreProvider {
@Override
public GitRepositoryConfig get() {
return getFronStore(delegate);
return getFromStore(delegate);
}
@Override

View File

@@ -44,21 +44,22 @@ class GitWorkingCopyReclaimer {
private final GitContext context;
public GitWorkingCopyReclaimer(GitContext context) {
GitWorkingCopyReclaimer(GitContext context) {
this.context = context;
}
public ParentAndClone<Repository, Repository> reclaim(File target, String initialBranch) throws SimpleWorkingCopyFactory.ReclaimFailedException {
LOG.trace("reclaim repository {}", context.getRepository());
String branchToCheckout = determineBranch(initialBranch);
Stopwatch stopwatch = Stopwatch.createStarted();
Repository repo = openTarget(target);
try (Git git = Git.open(target)) {
git.reset().setMode(ResetCommand.ResetType.HARD).call();
git.clean().setForce(true).setCleanDirectories(true).call();
git.fetch().call();
git.checkout().setForced(true).setName("origin/" + initialBranch).call();
git.branchDelete().setBranchNames(initialBranch).setForce(true).call();
git.checkout().setName(initialBranch).setCreateBranch(true).call();
git.checkout().setForced(true).setName("origin/" + branchToCheckout).call();
git.branchDelete().setBranchNames(branchToCheckout).setForce(true).call();
git.checkout().setName(branchToCheckout).setCreateBranch(true).call();
return new ParentAndClone<>(null, repo, target);
} catch (GitAPIException | IOException e) {
throw new SimpleWorkingCopyFactory.ReclaimFailedException(e);
@@ -67,6 +68,16 @@ class GitWorkingCopyReclaimer {
}
}
private String determineBranch(String initialBranch) {
if (initialBranch != null) {
return initialBranch;
}
if (context.getConfig().getDefaultBranch() != null) {
return context.getConfig().getDefaultBranch();
}
return context.getGlobalConfig().getDefaultBranch();
}
private Repository openTarget(File target) throws SimpleWorkingCopyFactory.ReclaimFailedException {
try {
return GitUtil.open(target);

View File

@@ -70,7 +70,7 @@ public class SimpleGitWorkingCopyFactory extends SimpleWorkingCopyFactory<Reposi
}
@Override
protected void closeWorkingCopy(Repository workingCopy) throws Exception {
protected void closeWorkingCopy(Repository workingCopy) {
if (workingCopy != null) {
workingCopy.close();
}

View File

@@ -35,6 +35,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import sonia.scm.repository.GitRepositoryConfig;
import sonia.scm.repository.GitRepositoryHandler;
import sonia.scm.repository.GitTestHelper;
import sonia.scm.repository.PreProcessorUtil;
@@ -149,6 +150,32 @@ public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase
assertBranchCheckedOutAndClean(workdir, "master");
}
@Test
public void shouldReclaimCleanDirectoryConfiguredDefaultBranch() throws Exception {
SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider), new SimpleMeterRegistry());
File workdir = createExistingClone(factory);
GitContext context = createContext();
GitRepositoryConfig config = context.getConfig();
config.setDefaultBranch("master");
context.setConfig(config);
factory.reclaim(context, workdir, null);
assertBranchCheckedOutAndClean(workdir, "master");
}
@Test
public void shouldReclaimCleanDirectoryGloballyConfiguredDefaultBranch() throws Exception {
SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider), new SimpleMeterRegistry());
File workdir = createExistingClone(factory);
GitContext context = createContext();
context.getGlobalConfig().setDefaultBranch("master");
factory.reclaim(context, workdir, null);
assertBranchCheckedOutAndClean(workdir, "master");
}
@Test
public void shouldReclaimCleanDirectoryWithOtherBranch() throws Exception {
SimpleGitWorkingCopyFactory factory = new SimpleGitWorkingCopyFactory(new NoneCachingWorkingCopyPool(workdirProvider), new SimpleMeterRegistry());
@@ -192,6 +219,7 @@ public class SimpleGitWorkingCopyFactoryTest extends AbstractGitCommandTestBase
factory.reclaim(createContext(), workdir, "master");
assertBranchCheckedOutAndClean(workdir, "master");
assertThat(newDirectory).doesNotExist();
}
public File createExistingClone(SimpleGitWorkingCopyFactory factory) throws Exception {