Implement a snapshotting RefDirectory for use in request scope
Introduce a SnapshottingRefDirectory class which allows users to get a snapshot of the ref database and use it in a request scope (for example a Gerrit query) instead of having to re-read packed-refs several times in a request. This can potentially be further improved to avoid scanning/reading a loose ref several times in a request. This would especially help repeated lookups of a packed ref, where we check for the existence of a loose ref each time. Change-Id: I634b92877f819f8bf36a3b9586bbc1815108189a Signed-off-by: Kaushik Lingarkar <quic_kaushikl@quicinc.com>
This commit is contained in:
parent
d7400517bf
commit
33c00f3347
|
@ -58,13 +58,13 @@
|
||||||
public class RefDirectoryTest extends LocalDiskRepositoryTestCase {
|
public class RefDirectoryTest extends LocalDiskRepositoryTestCase {
|
||||||
private Repository diskRepo;
|
private Repository diskRepo;
|
||||||
|
|
||||||
private TestRepository<Repository> repo;
|
TestRepository<Repository> repo;
|
||||||
|
|
||||||
private RefDirectory refdir;
|
RefDirectory refdir;
|
||||||
|
|
||||||
private RevCommit A;
|
RevCommit A;
|
||||||
|
|
||||||
private RevCommit B;
|
RevCommit B;
|
||||||
|
|
||||||
private RevTag v1_0;
|
private RevTag v1_0;
|
||||||
|
|
||||||
|
@ -1349,6 +1349,17 @@ public void testPackedRefsLockFailure() throws Exception {
|
||||||
assertEquals(Storage.LOOSE, ref.getStorage());
|
assertEquals(Storage.LOOSE, ref.getStorage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void writePackedRef(String name, AnyObjectId id) throws IOException {
|
||||||
|
writePackedRefs(id.name() + " " + name + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void writePackedRefs(String content) throws IOException {
|
||||||
|
File pr = new File(diskRepo.getDirectory(), "packed-refs");
|
||||||
|
write(pr, content);
|
||||||
|
FS fs = diskRepo.getFS();
|
||||||
|
fs.setLastModified(pr.toPath(), Instant.now().minusSeconds(3600));
|
||||||
|
}
|
||||||
|
|
||||||
private void writeLooseRef(String name, AnyObjectId id) throws IOException {
|
private void writeLooseRef(String name, AnyObjectId id) throws IOException {
|
||||||
writeLooseRef(name, id.name() + "\n");
|
writeLooseRef(name, id.name() + "\n");
|
||||||
}
|
}
|
||||||
|
@ -1357,17 +1368,6 @@ private void writeLooseRef(String name, String content) throws IOException {
|
||||||
write(new File(diskRepo.getDirectory(), name), content);
|
write(new File(diskRepo.getDirectory(), name), content);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writePackedRef(String name, AnyObjectId id) throws IOException {
|
|
||||||
writePackedRefs(id.name() + " " + name + "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writePackedRefs(String content) throws IOException {
|
|
||||||
File pr = new File(diskRepo.getDirectory(), "packed-refs");
|
|
||||||
write(pr, content);
|
|
||||||
FS fs = diskRepo.getFS();
|
|
||||||
fs.setLastModified(pr.toPath(), Instant.now().minusSeconds(3600));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteLooseRef(String name) {
|
private void deleteLooseRef(String name) {
|
||||||
File path = new File(diskRepo.getDirectory(), name);
|
File path = new File(diskRepo.getDirectory(), name);
|
||||||
assertTrue("deleted " + name, path.delete());
|
assertTrue("deleted " + name, path.delete());
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Qualcomm Innovation Center, Inc.
|
||||||
|
* and other copyright owners as documented in the project's IP log.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||||
|
* https://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.eclipse.jgit.internal.storage.file;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.NullProgressMonitor;
|
||||||
|
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class SnapshottingRefDirectoryTest extends RefDirectoryTest {
|
||||||
|
private RefDirectory originalRefDirectory;
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Before
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
originalRefDirectory = refdir;
|
||||||
|
refdir = refdir.createSnapshottingRefDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSnapshot_CannotSeeExternalPackedRefsUpdates()
|
||||||
|
throws IOException {
|
||||||
|
String refName = "refs/heads/new";
|
||||||
|
|
||||||
|
writePackedRef(refName, A);
|
||||||
|
assertEquals(A, originalRefDirectory.exactRef(refName).getObjectId());
|
||||||
|
assertEquals(A, refdir.exactRef(refName).getObjectId());
|
||||||
|
|
||||||
|
writePackedRef(refName, B);
|
||||||
|
assertEquals(B, originalRefDirectory.exactRef(refName).getObjectId());
|
||||||
|
assertEquals(A, refdir.exactRef(refName).getObjectId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSnapshot_WriteThrough() throws IOException {
|
||||||
|
String refName = "refs/heads/new";
|
||||||
|
|
||||||
|
writePackedRef(refName, A);
|
||||||
|
assertEquals(A, originalRefDirectory.exactRef(refName).getObjectId());
|
||||||
|
assertEquals(A, refdir.exactRef(refName).getObjectId());
|
||||||
|
|
||||||
|
PackedBatchRefUpdate update = refdir.newBatchUpdate();
|
||||||
|
update.addCommand(new ReceiveCommand(A, B, refName));
|
||||||
|
update.execute(repo.getRevWalk(), NullProgressMonitor.INSTANCE);
|
||||||
|
|
||||||
|
assertEquals(B, originalRefDirectory.exactRef(refName).getObjectId());
|
||||||
|
assertEquals(B, refdir.exactRef(refName).getObjectId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSnapshot_IncludeExternalPackedRefsUpdatesWithWrites()
|
||||||
|
throws IOException {
|
||||||
|
String refA = "refs/heads/refA";
|
||||||
|
String refB = "refs/heads/refB";
|
||||||
|
writePackedRefs("" + //
|
||||||
|
A.name() + " " + refA + "\n" + //
|
||||||
|
A.name() + " " + refB + "\n");
|
||||||
|
assertEquals(A, refdir.exactRef(refA).getObjectId());
|
||||||
|
assertEquals(A, refdir.exactRef(refB).getObjectId());
|
||||||
|
|
||||||
|
writePackedRefs("" + //
|
||||||
|
B.name() + " " + refA + "\n" + //
|
||||||
|
A.name() + " " + refB + "\n");
|
||||||
|
PackedBatchRefUpdate update = refdir.newBatchUpdate();
|
||||||
|
update.addCommand(new ReceiveCommand(A, B, refB));
|
||||||
|
update.execute(repo.getRevWalk(), NullProgressMonitor.INSTANCE);
|
||||||
|
|
||||||
|
assertEquals(B, originalRefDirectory.exactRef(refA).getObjectId());
|
||||||
|
assertEquals(B, refdir.exactRef(refA).getObjectId());
|
||||||
|
assertEquals(B, originalRefDirectory.exactRef(refB).getObjectId());
|
||||||
|
assertEquals(B, refdir.exactRef(refB).getObjectId());
|
||||||
|
}
|
||||||
|
}
|
|
@ -179,6 +179,19 @@ public class RefDirectory extends RefDatabase {
|
||||||
|
|
||||||
private final TrustPackedRefsStat trustPackedRefsStat;
|
private final TrustPackedRefsStat trustPackedRefsStat;
|
||||||
|
|
||||||
|
RefDirectory(RefDirectory refDb) {
|
||||||
|
parent = refDb.parent;
|
||||||
|
gitDir = refDb.gitDir;
|
||||||
|
refsDir = refDb.refsDir;
|
||||||
|
logsDir = refDb.logsDir;
|
||||||
|
logsRefsDir = refDb.logsRefsDir;
|
||||||
|
packedRefsFile = refDb.packedRefsFile;
|
||||||
|
looseRefs.set(refDb.looseRefs.get());
|
||||||
|
packedRefs.set(refDb.packedRefs.get());
|
||||||
|
trustFolderStat = refDb.trustFolderStat;
|
||||||
|
trustPackedRefsStat = refDb.trustPackedRefsStat;
|
||||||
|
}
|
||||||
|
|
||||||
RefDirectory(FileRepository db) {
|
RefDirectory(FileRepository db) {
|
||||||
final FS fs = db.getFS();
|
final FS fs = db.getFS();
|
||||||
parent = db;
|
parent = db;
|
||||||
|
@ -223,6 +236,15 @@ public File logFor(String name) {
|
||||||
return new File(logsDir, name);
|
return new File(logsDir, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a cache of this {@link RefDirectory}.
|
||||||
|
*
|
||||||
|
* @return a cached RefDirectory.
|
||||||
|
*/
|
||||||
|
public SnapshottingRefDirectory createSnapshottingRefDirectory() {
|
||||||
|
return new SnapshottingRefDirectory(this);
|
||||||
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public void create() throws IOException {
|
public void create() throws IOException {
|
||||||
|
@ -575,18 +597,26 @@ public RefDirectoryUpdate newUpdate(String name, boolean detach)
|
||||||
else {
|
else {
|
||||||
detachingSymbolicRef = detach && ref.isSymbolic();
|
detachingSymbolicRef = detach && ref.isSymbolic();
|
||||||
}
|
}
|
||||||
RefDirectoryUpdate refDirUpdate = new RefDirectoryUpdate(this, ref);
|
RefDirectoryUpdate refDirUpdate = createRefDirectoryUpdate(ref);
|
||||||
if (detachingSymbolicRef)
|
if (detachingSymbolicRef)
|
||||||
refDirUpdate.setDetachingSymbolicRef();
|
refDirUpdate.setDetachingSymbolicRef();
|
||||||
return refDirUpdate;
|
return refDirUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefDirectoryUpdate createRefDirectoryUpdate(Ref ref) {
|
||||||
|
return new RefDirectoryUpdate(this, ref);
|
||||||
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public RefDirectoryRename newRename(String fromName, String toName)
|
public RefDirectoryRename newRename(String fromName, String toName)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
RefDirectoryUpdate from = newUpdate(fromName, false);
|
RefDirectoryUpdate from = newUpdate(fromName, false);
|
||||||
RefDirectoryUpdate to = newUpdate(toName, false);
|
RefDirectoryUpdate to = newUpdate(toName, false);
|
||||||
|
return createRefDirectoryRename(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
RefDirectoryRename createRefDirectoryRename(RefDirectoryUpdate from, RefDirectoryUpdate to) {
|
||||||
return new RefDirectoryRename(from, to);
|
return new RefDirectoryRename(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -966,6 +996,13 @@ private PackedRefList readPackedRefs() throws IOException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void compareAndSetPackedRefs(PackedRefList curList, PackedRefList newList) {
|
||||||
|
if (packedRefs.compareAndSet(curList, newList)
|
||||||
|
&& !curList.id.equals(newList.id)) {
|
||||||
|
modCnt.incrementAndGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private RefList<Ref> parsePackedRefs(BufferedReader br)
|
private RefList<Ref> parsePackedRefs(BufferedReader br)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
RefList.Builder<Ref> all = new RefList.Builder<>();
|
RefList.Builder<Ref> all = new RefList.Builder<>();
|
||||||
|
@ -1258,7 +1295,7 @@ RefDirectoryUpdate newTemporaryUpdate() throws IOException {
|
||||||
File tmp = File.createTempFile("renamed_", "_ref", refsDir); //$NON-NLS-1$ //$NON-NLS-2$
|
File tmp = File.createTempFile("renamed_", "_ref", refsDir); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
String name = Constants.R_REFS + tmp.getName();
|
String name = Constants.R_REFS + tmp.getName();
|
||||||
Ref ref = new ObjectIdRef.Unpeeled(NEW, name, null);
|
Ref ref = new ObjectIdRef.Unpeeled(NEW, name, null);
|
||||||
return new RefDirectoryUpdate(this, ref);
|
return createRefDirectoryUpdate(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -59,6 +59,15 @@ class RefDirectoryRename extends RefRename {
|
||||||
refdb = src.getRefDatabase();
|
refdb = src.getRefDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the ref directory associated with this rename.
|
||||||
|
*
|
||||||
|
* @return the ref directory.
|
||||||
|
*/
|
||||||
|
protected RefDirectory getRefDirectory() {
|
||||||
|
return refdb;
|
||||||
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
protected Result doRename() throws IOException {
|
protected Result doRename() throws IOException {
|
||||||
|
|
|
@ -0,0 +1,258 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Qualcomm Innovation Center, Inc.
|
||||||
|
* and other copyright owners as documented in the project's IP log.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||||
|
* https://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.eclipse.jgit.internal.storage.file;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.ProgressMonitor;
|
||||||
|
import org.eclipse.jgit.lib.Ref;
|
||||||
|
import org.eclipse.jgit.lib.RefDatabase;
|
||||||
|
import org.eclipse.jgit.lib.RefUpdate;
|
||||||
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snapshotting write-through cache of a {@link RefDirectory}.
|
||||||
|
* <p>
|
||||||
|
* This is intended to be short-term write-through snapshot based cache used in
|
||||||
|
* a request scope to avoid re-reading packed-refs on each read. A future
|
||||||
|
* improvement could also snapshot loose refs.
|
||||||
|
* <p>
|
||||||
|
* Only use this class when concurrent writes from other requests (not using the
|
||||||
|
* same instance of SnapshottingRefDirectory) generally need not be visible to
|
||||||
|
* the current request. The exception to this is when such writes would cause
|
||||||
|
* writes from this snapshot to fail due to their base ref value being
|
||||||
|
* outdated.
|
||||||
|
*/
|
||||||
|
class SnapshottingRefDirectory extends RefDirectory {
|
||||||
|
final RefDirectory refDb;
|
||||||
|
|
||||||
|
private volatile boolean isValid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a snapshotting write-through cache of a {@link RefDirectory}.
|
||||||
|
*
|
||||||
|
* @param refDb
|
||||||
|
* a reference to the ref database
|
||||||
|
*/
|
||||||
|
SnapshottingRefDirectory(RefDirectory refDb) {
|
||||||
|
super(refDb);
|
||||||
|
this.refDb = refDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lazily initializes and returns a PackedRefList snapshot.
|
||||||
|
* <p>
|
||||||
|
* A newer snapshot will be returned when a ref update is performed using
|
||||||
|
* this {@link SnapshottingRefDirectory}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
PackedRefList getPackedRefs() throws IOException {
|
||||||
|
if (!isValid) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (!isValid) {
|
||||||
|
refreshSnapshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return packedRefs.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
void delete(RefDirectoryUpdate update) throws IOException {
|
||||||
|
refreshSnapshot();
|
||||||
|
super.delete(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public RefDirectoryUpdate newUpdate(String name, boolean detach)
|
||||||
|
throws IOException {
|
||||||
|
refreshSnapshot();
|
||||||
|
return super.newUpdate(name, detach);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public PackedBatchRefUpdate newBatchUpdate() {
|
||||||
|
return new SnapshotPackedBatchRefUpdate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public PackedBatchRefUpdate newBatchUpdate(boolean shouldLockLooseRefs) {
|
||||||
|
return new SnapshotPackedBatchRefUpdate(this, shouldLockLooseRefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
RefDirectoryUpdate newTemporaryUpdate() throws IOException {
|
||||||
|
refreshSnapshot();
|
||||||
|
return super.newTemporaryUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
RefDirectoryUpdate createRefDirectoryUpdate(Ref ref) {
|
||||||
|
return new SnapshotRefDirectoryUpdate(this, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
RefDirectoryRename createRefDirectoryRename(RefDirectoryUpdate from,
|
||||||
|
RefDirectoryUpdate to) {
|
||||||
|
return new SnapshotRefDirectoryRename(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void invalidateSnapshot() {
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh our snapshot by calling the underlying RefDirectory's
|
||||||
|
* getPackedRefs().
|
||||||
|
* <p>
|
||||||
|
* Update the in-memory copy of the underlying RefDirectory's packed-refs to
|
||||||
|
* avoid the overhead of re-reading packed-refs on each new snapshot as the
|
||||||
|
* packed-refs of the underlying RefDirectory may not get updated if most
|
||||||
|
* threads use this snapshot.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private synchronized void refreshSnapshot() throws IOException {
|
||||||
|
compareAndSetPackedRefs(packedRefs.get(), refDb.getPackedRefs());
|
||||||
|
isValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
private interface SupplierThrowsException<R, E extends Exception> {
|
||||||
|
R call() throws E;
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
private interface FunctionThrowsException<A, R, E extends Exception> {
|
||||||
|
R apply(A a) throws E;
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
private interface TriConsumerThrowsException<A1, A2, A3, E extends Exception> {
|
||||||
|
void accept(A1 a1, A2 a2, A3 a3) throws E;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T invalidateSnapshotOnError(
|
||||||
|
SupplierThrowsException<T, IOException> f, RefDatabase refDb)
|
||||||
|
throws IOException {
|
||||||
|
return invalidateSnapshotOnError(a -> f.call(), null, refDb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <A, R> R invalidateSnapshotOnError(
|
||||||
|
FunctionThrowsException<A, R, IOException> f, A a,
|
||||||
|
RefDatabase refDb) throws IOException {
|
||||||
|
try {
|
||||||
|
return f.apply(a);
|
||||||
|
} catch (IOException e) {
|
||||||
|
((SnapshottingRefDirectory) refDb).invalidateSnapshot();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <A1, A2, A3> void invalidateSnapshotOnError(
|
||||||
|
TriConsumerThrowsException<A1, A2, A3, IOException> f, A1 a1, A2 a2,
|
||||||
|
A3 a3, RefDatabase refDb) throws IOException {
|
||||||
|
try {
|
||||||
|
f.accept(a1, a2, a3);
|
||||||
|
} catch (IOException e) {
|
||||||
|
((SnapshottingRefDirectory) refDb).invalidateSnapshot();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SnapshotRefDirectoryUpdate extends RefDirectoryUpdate {
|
||||||
|
SnapshotRefDirectoryUpdate(RefDirectory r, Ref ref) {
|
||||||
|
super(r, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result forceUpdate() throws IOException {
|
||||||
|
return invalidateSnapshotOnError(() -> super.forceUpdate(),
|
||||||
|
getRefDatabase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result update() throws IOException {
|
||||||
|
return invalidateSnapshotOnError(() -> super.update(),
|
||||||
|
getRefDatabase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result update(RevWalk walk) throws IOException {
|
||||||
|
return invalidateSnapshotOnError(rw -> super.update(rw), walk,
|
||||||
|
getRefDatabase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result delete() throws IOException {
|
||||||
|
return invalidateSnapshotOnError(() -> super.delete(),
|
||||||
|
getRefDatabase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result delete(RevWalk walk) throws IOException {
|
||||||
|
return invalidateSnapshotOnError(rw -> super.delete(rw), walk,
|
||||||
|
getRefDatabase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result link(String target) throws IOException {
|
||||||
|
return invalidateSnapshotOnError(t -> super.link(t), target,
|
||||||
|
getRefDatabase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SnapshotRefDirectoryRename extends RefDirectoryRename {
|
||||||
|
SnapshotRefDirectoryRename(RefDirectoryUpdate src,
|
||||||
|
RefDirectoryUpdate dst) {
|
||||||
|
super(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RefUpdate.Result rename() throws IOException {
|
||||||
|
return invalidateSnapshotOnError(() -> super.rename(),
|
||||||
|
getRefDirectory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SnapshotPackedBatchRefUpdate
|
||||||
|
extends PackedBatchRefUpdate {
|
||||||
|
SnapshotPackedBatchRefUpdate(RefDirectory refdb) {
|
||||||
|
super(refdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
SnapshotPackedBatchRefUpdate(RefDirectory refdb,
|
||||||
|
boolean shouldLockLooseRefs) {
|
||||||
|
super(refdb, shouldLockLooseRefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(RevWalk walk, ProgressMonitor monitor,
|
||||||
|
List<String> options) throws IOException {
|
||||||
|
invalidateSnapshotOnError((rw, m, o) -> super.execute(rw, m, o),
|
||||||
|
walk, monitor, options, getRefDatabase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(RevWalk walk, ProgressMonitor monitor)
|
||||||
|
throws IOException {
|
||||||
|
invalidateSnapshotOnError((rw, m, a3) -> super.execute(rw, m), walk,
|
||||||
|
monitor, null, getRefDatabase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -521,6 +521,15 @@ public void execute(RevWalk walk, ProgressMonitor monitor,
|
||||||
monitor.endTask();
|
monitor.endTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the ref database associated with this update.
|
||||||
|
*
|
||||||
|
* @return the ref database.
|
||||||
|
*/
|
||||||
|
protected RefDatabase getRefDatabase() {
|
||||||
|
return refdb;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isMissing(RevWalk walk, ObjectId id)
|
private static boolean isMissing(RevWalk walk, ObjectId id)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (id.equals(ObjectId.zeroId())) {
|
if (id.equals(ObjectId.zeroId())) {
|
||||||
|
|
Loading…
Reference in New Issue