diff options
author | Martin Fick <mfick@nvidia.com> | 2024-11-27 10:15:30 -0800 |
---|---|---|
committer | Martin Fick <mfick@nvidia.com> | 2024-12-02 23:29:44 +0000 |
commit | 44d61a3d727eb68db9e57acec0704bfc6758f878 (patch) | |
tree | 27ffa6eecd5b0d8106f332dcb25ed09d9f0fbcd0 /org.eclipse.jgit/src | |
parent | 702db13af2b96c0f699fa6be0a63ba281535f337 (diff) | |
download | jgit-44d61a3d727eb68db9e57acec0704bfc6758f878.tar.gz jgit-44d61a3d727eb68db9e57acec0704bfc6758f878.zip |
WindowCache: add bulk purge(), call from bulk sites
Purging a Pack from the WindowCache requires a linear search over all
the entries in the cache, and thus is rather expensive. Since git gc
often deletes more than one packfile at a time, avoid multiplying this
expensive operation when possible by purging a Set of Packs when closing
deleted pack files during a directory scan. Purge the Set of Packs with
a single linear search of the cache. Closing the PackDirectory also
cccbngljkihltghcnbiftcubdvgugdcvujkejehbjr
Change-Id: Ic9b45cab57e1ef610c2e20ad392d8b45f8091f41
Signed-off-by: Martin Fick <mfick@nvidia.com>
Diffstat (limited to 'org.eclipse.jgit/src')
3 files changed, 37 insertions, 21 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java index 3518342f97..9073c1675a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java @@ -296,15 +296,28 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { } /** - * Close the resources utilized by this repository + * Close the resources utilized by these pack files + * + * @param packs + * packs to close + */ + public static void close(Set<Pack> packs) { + WindowCache.purge(packs); + packs.forEach(p -> p.closeIndices()); + } + + /** + * Close the resources utilized by this pack file */ public void close() { WindowCache.purge(this); - synchronized (this) { - loadedIdx.clear(); - reverseIdx.clear(); - bitmapIdx.clear(); - } + closeIndices(); + } + + private synchronized void closeIndices() { + loadedIdx.clear(); + reverseIdx.clear(); + bitmapIdx.clear(); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java index 51a8148838..e31126f027 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java @@ -24,6 +24,7 @@ import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -111,9 +112,7 @@ class PackDirectory { void close() { PackList packs = packList.get(); if (packs != NO_PACKS && packList.compareAndSet(packs, NO_PACKS)) { - for (Pack p : packs.packs) { - p.close(); - } + Pack.close(Set.of(packs.packs)); } } @@ -484,9 +483,7 @@ class PackDirectory { return old; } - for (Pack p : forReuse.values()) { - p.close(); - } + Pack.close(new HashSet<>(forReuse.values())); if (list.isEmpty()) { return new PackList(snapshot, NO_PACKS.packs); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java index 30f8240aa9..3ec7e6e666 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCache.java @@ -17,6 +17,7 @@ import java.lang.ref.SoftReference; import java.util.Collections; import java.util.Map; import java.util.Random; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; @@ -397,7 +398,11 @@ public class WindowCache { } static final void purge(Pack pack) { - cache.removeAll(pack); + purge(Collections.singleton(pack)); + } + + static final void purge(Set<Pack> packs) { + cache.removeAll(packs); } /** cleanup released and/or garbage collected windows. */ @@ -710,20 +715,21 @@ public class WindowCache { /** * Clear all entries related to a single file. * <p> - * Typically this method is invoked during {@link Pack#close()}, when we - * know the pack is never going to be useful to us again (for example, it no - * longer exists on disk). A concurrent reader loading an entry from this - * same pack may cause the pack to become stuck in the cache anyway. + * Typically this method is invoked during {@link Pack#close()}, or + * {@link Pack#close(Set)}, when we know the packs are never going to be + * useful to us again (for example, they no longer exist on disk after gc). + * A concurrent reader loading an entry from these same packs may cause a + * pack to become stuck in the cache anyway. * - * @param pack - * the file to purge all entries of. + * @param packs + * the files to purge all entries of. */ - private void removeAll(Pack pack) { + private void removeAll(Set<Pack> packs) { for (int s = 0; s < tableSize; s++) { final Entry e1 = table.get(s); boolean hasDead = false; for (Entry e = e1; e != null; e = e.next) { - if (e.ref.getPack() == pack) { + if (packs.contains(e.ref.getPack())) { e.kill(); hasDead = true; } else if (e.dead) |