in org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java [1125:1269]
private Pack writePack(@NonNull Set<? extends ObjectId> want,
@NonNull Set<? extends ObjectId> have, @NonNull Set<ObjectId> tags,
Set<ObjectId> tagTargets, List<ObjectIdSet> excludeObjects)
throws IOException {
checkCancelled();
File tmpPack = null;
Map<PackExt, File> tmpExts = new TreeMap<>((o1, o2) -> {
// INDEX entries must be returned last, so the pack
// scanner does pick up the new pack until all the
// PackExt entries have been written.
if (o1 == o2) {
return 0;
}
if (o1 == PackExt.INDEX) {
return 1;
}
if (o2 == PackExt.INDEX) {
return -1;
}
return Integer.signum(o1.hashCode() - o2.hashCode());
});
try (PackWriter pw = new PackWriter(
pconfig,
repo.newObjectReader())) {
// prepare the PackWriter
pw.setDeltaBaseAsOffset(true);
pw.setReuseDeltaCommits(false);
if (tagTargets != null) {
pw.setTagTargets(tagTargets);
}
if (excludeObjects != null)
for (ObjectIdSet idx : excludeObjects)
pw.excludeObjects(idx);
pw.preparePack(pm, want, have, PackWriter.NONE, tags);
if (pw.getObjectCount() == 0)
return null;
checkCancelled();
// create temporary files
ObjectId id = pw.computeName();
File packdir = repo.getObjectDatabase().getPackDirectory();
packdir.mkdirs();
tmpPack = File.createTempFile("gc_", ".pack_tmp", packdir); //$NON-NLS-1$ //$NON-NLS-2$
final String tmpBase = tmpPack.getName()
.substring(0, tmpPack.getName().lastIndexOf('.'));
File tmpIdx = new File(packdir, tmpBase + ".idx_tmp"); //$NON-NLS-1$
tmpExts.put(INDEX, tmpIdx);
if (!tmpIdx.createNewFile())
throw new IOException(MessageFormat.format(
JGitText.get().cannotCreateIndexfile, tmpIdx.getPath()));
// write the packfile
try (FileOutputStream fos = new FileOutputStream(tmpPack);
FileChannel channel = fos.getChannel();
OutputStream channelStream = Channels
.newOutputStream(channel)) {
pw.writePack(pm, pm, channelStream);
channel.force(true);
}
// write the packindex
try (FileOutputStream fos = new FileOutputStream(tmpIdx);
FileChannel idxChannel = fos.getChannel();
OutputStream idxStream = Channels
.newOutputStream(idxChannel)) {
pw.writeIndex(idxStream);
idxChannel.force(true);
}
if (pw.prepareBitmapIndex(pm)) {
File tmpBitmapIdx = new File(packdir, tmpBase + ".bitmap_tmp"); //$NON-NLS-1$
tmpExts.put(BITMAP_INDEX, tmpBitmapIdx);
if (!tmpBitmapIdx.createNewFile())
throw new IOException(MessageFormat.format(
JGitText.get().cannotCreateIndexfile,
tmpBitmapIdx.getPath()));
try (FileOutputStream fos = new FileOutputStream(tmpBitmapIdx);
FileChannel idxChannel = fos.getChannel();
OutputStream idxStream = Channels
.newOutputStream(idxChannel)) {
pw.writeBitmapIndex(idxStream);
idxChannel.force(true);
}
}
// rename the temporary files to real files
File packDir = repo.getObjectDatabase().getPackDirectory();
PackFile realPack = new PackFile(packDir, id, PackExt.PACK);
repo.getObjectDatabase().closeAllPackHandles(realPack);
tmpPack.setReadOnly();
FileUtils.rename(tmpPack, realPack, StandardCopyOption.ATOMIC_MOVE);
for (Map.Entry<PackExt, File> tmpEntry : tmpExts.entrySet()) {
File tmpExt = tmpEntry.getValue();
tmpExt.setReadOnly();
PackFile realExt = new PackFile(packDir, id, tmpEntry.getKey());
try {
FileUtils.rename(tmpExt, realExt,
StandardCopyOption.ATOMIC_MOVE);
} catch (IOException e) {
File newExt = new File(realExt.getParentFile(),
realExt.getName() + ".new"); //$NON-NLS-1$
try {
FileUtils.rename(tmpExt, newExt,
StandardCopyOption.ATOMIC_MOVE);
} catch (IOException e2) {
newExt = tmpExt;
e = e2;
}
throw new IOException(MessageFormat.format(
JGitText.get().panicCantRenameIndexFile, newExt,
realExt), e);
}
}
boolean interrupted = false;
try {
FileSnapshot snapshot = FileSnapshot.save(realPack);
if (pconfig.doWaitPreventRacyPack(snapshot.size())) {
snapshot.waitUntilNotRacy();
}
} catch (InterruptedException e) {
interrupted = true;
}
try {
return repo.getObjectDatabase().openPack(realPack);
} finally {
if (interrupted) {
// Re-set interrupted flag
Thread.currentThread().interrupt();
}
}
} finally {
if (tmpPack != null && tmpPack.exists())
tmpPack.delete();
for (File tmpExt : tmpExts.values()) {
if (tmpExt.exists())
tmpExt.delete();
}
}
}