From a11bb03127b9ab193c956589381c496429f82d87 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Mon, 30 Jan 2017 00:52:33 +0100 Subject: [PATCH 1/2] GC.prune(Set): return early if objects directory is empty Change-Id: Id56b102604c4e0437230e3e7c59c0a3a1b676256 Signed-off-by: Matthias Sohn --- .../jgit/internal/storage/file/GC.java | 63 ++++++++++--------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java index e3e73e25f..d1cdbeb46 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java @@ -364,45 +364,48 @@ public class GC { Set indexObjects = null; File objects = repo.getObjectsDirectory(); String[] fanout = objects.list(); - if (fanout != null && fanout.length > 0) { - pm.beginTask(JGitText.get().pruneLooseUnreferencedObjects, - fanout.length); - try { - for (String d : fanout) { - pm.update(1); - if (d.length() != 2) + if (fanout == null || fanout.length == 0) { + return; + } + pm.beginTask(JGitText.get().pruneLooseUnreferencedObjects, + fanout.length); + try { + for (String d : fanout) { + pm.update(1); + if (d.length() != 2) + continue; + File[] entries = new File(objects, d).listFiles(); + if (entries == null) + continue; + for (File f : entries) { + String fName = f.getName(); + if (fName.length() != Constants.OBJECT_ID_STRING_LENGTH - 2) continue; - File[] entries = new File(objects, d).listFiles(); - if (entries == null) + if (repo.getFS().lastModified(f) >= expireDate) continue; - for (File f : entries) { - String fName = f.getName(); - if (fName.length() != Constants.OBJECT_ID_STRING_LENGTH - 2) - continue; - if (repo.getFS().lastModified(f) >= expireDate) + try { + ObjectId id = ObjectId.fromString(d + fName); + if (objectsToKeep.contains(id)) continue; - try { - ObjectId id = ObjectId.fromString(d + fName); - if (objectsToKeep.contains(id)) - continue; - if (indexObjects == null) - indexObjects = listNonHEADIndexObjects(); - if (indexObjects.contains(id)) - continue; - deletionCandidates.put(id, f); - } catch (IllegalArgumentException notAnObject) { - // ignoring the file that does not represent loose - // object + if (indexObjects == null) + indexObjects = listNonHEADIndexObjects(); + if (indexObjects.contains(id)) continue; - } + deletionCandidates.put(id, f); + } catch (IllegalArgumentException notAnObject) { + // ignoring the file that does not represent loose + // object + continue; } } - } finally { - pm.endTask(); } + } finally { + pm.endTask(); } - if (deletionCandidates.isEmpty()) + + if (deletionCandidates.isEmpty()) { return; + } // From the set of current refs remove all those which have been handled // during last repack(). Only those refs will survive which have been From 18cda3888c455e48de38088ee51803096a48ae28 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Mon, 30 Jan 2017 01:24:45 +0100 Subject: [PATCH 2/2] GC: delete empty directories after purging loose objects In order to limit the number of directories we check for emptiness only consider fanout directories which contained unreferenced loose objects we deleted in the same gc run. Change-Id: Idf8d512867ee1c8ed40bd55752122ce83a98ffa2 Signed-off-by: Matthias Sohn --- .../src/org/eclipse/jgit/internal/storage/file/GC.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java index d1cdbeb46..b60841686 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java @@ -475,12 +475,19 @@ public class GC { // loose objects. Make a last check, though, to avoid deleting objects // that could have been referenced while the candidates list was being // built (by an incoming push, for example). + Set touchedFanout = new HashSet<>(); for (File f : deletionCandidates.values()) { if (f.lastModified() < expireDate) { f.delete(); + touchedFanout.add(f.getParentFile()); } } + for (File f : touchedFanout) { + FileUtils.delete(f, + FileUtils.EMPTY_DIRECTORIES_ONLY | FileUtils.IGNORE_ERRORS); + } + repo.getObjectDatabase().close(); }