From 4f35681b636e5145ddd2e07cc0969cc27604341d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 22 Dec 2025 04:19:12 +0000 Subject: [PATCH] =?UTF-8?q?[LLM]=20=E2=9A=A1=20Bolt:=20Parallelize=20depen?= =?UTF-8?q?dency=20resolution=20and=20target=20generation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 💡 What: Parallelize the dependency resolution and target generation process in Merger.java. 🎯 Why: Downloading artifacts (for SHA calculation) and processing dependencies is I/O bound. Parallelization significantly speeds up the resolution phase. 📊 Impact: Expected ~2-4x speedup on multi-core machines for large dependency graphs. 🔬 Measurement: Verified with unit tests and local verification script. Commit made by Bolt (Jules). --- .jules/bolt.md | 1 + .../src/main/java/net/evendanan/bazel/mvn/Merger.java | 2 +- .../net/evendanan/bazel/mvn/impl/TargetsBuilders.java | 3 +-- .../main/java/net/evendanan/timing/ProgressTimer.java | 4 ++-- .../main/java/net/evendanan/timing/TaskTiming.java | 11 ++++++----- 5 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..e1fbf01 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1 @@ +# Bolt's Journal diff --git a/resolver/src/main/java/net/evendanan/bazel/mvn/Merger.java b/resolver/src/main/java/net/evendanan/bazel/mvn/Merger.java index b4c08e4..33ca5ae 100644 --- a/resolver/src/main/java/net/evendanan/bazel/mvn/Merger.java +++ b/resolver/src/main/java/net/evendanan/bazel/mvn/Merger.java @@ -340,7 +340,7 @@ private void writeResults( "Constructing Bazel targets", "%d out of %d (%.2f%%%s): %s..."); List targetsToWritePairs = - resolvedDependencies.stream() + resolvedDependencies.parallelStream() .peek(d -> timer.taskDone(dependencyTools.mavenCoordinates(d))) .map( dependency -> diff --git a/resolver/src/main/java/net/evendanan/bazel/mvn/impl/TargetsBuilders.java b/resolver/src/main/java/net/evendanan/bazel/mvn/impl/TargetsBuilders.java index a317e45..5a2cd56 100644 --- a/resolver/src/main/java/net/evendanan/bazel/mvn/impl/TargetsBuilders.java +++ b/resolver/src/main/java/net/evendanan/bazel/mvn/impl/TargetsBuilders.java @@ -180,12 +180,10 @@ private static Target addAlias( public static class HttpTargetsBuilder implements TargetsBuilder { private static final char[] hexArray = "0123456789abcdef".toCharArray(); private final boolean calculateSha; - private final byte[] readBuffer; private final Function downloader; public HttpTargetsBuilder(boolean calculateSha, Function downloader) { this.calculateSha = calculateSha; - this.readBuffer = calculateSha ? new byte[4096] : new byte[0]; this.downloader = downloader; } @@ -205,6 +203,7 @@ public List buildTargets(final Dependency dependency, DependencyTools de if (calculateSha && !dependency.mavenCoordinate().version().contains("SNAPSHOT")) { try (InputStream inputStream = downloader.apply(dependency).toURL().openStream()) { final MessageDigest digest = MessageDigest.getInstance("SHA-256"); + final byte[] readBuffer = new byte[16384]; int bytesCount; while ((bytesCount = inputStream.read(readBuffer)) != -1) { diff --git a/resolver/src/main/java/net/evendanan/timing/ProgressTimer.java b/resolver/src/main/java/net/evendanan/timing/ProgressTimer.java index b528274..59486e7 100644 --- a/resolver/src/main/java/net/evendanan/timing/ProgressTimer.java +++ b/resolver/src/main/java/net/evendanan/timing/ProgressTimer.java @@ -13,7 +13,7 @@ public ProgressTimer(int tasksCount, String title, String progressText) { this.timer.start(tasksCount); } - public void taskDone(String taskName) { + public synchronized void taskDone(String taskName) { final TimingData timingData = timer.taskDone(); final String estimatedTimeLeft; if (timingData.doneTasks >= 3) { @@ -32,7 +32,7 @@ public void taskDone(String taskName) { taskName); } - public void finish() { + public synchronized void finish() { TimingData finish = timer.finish(); report("Finished. %s", TaskTiming.humanReadableTime(finish.totalTime - finish.startTime)); } diff --git a/resolver/src/main/java/net/evendanan/timing/TaskTiming.java b/resolver/src/main/java/net/evendanan/timing/TaskTiming.java index 19b369c..6e5e997 100644 --- a/resolver/src/main/java/net/evendanan/timing/TaskTiming.java +++ b/resolver/src/main/java/net/evendanan/timing/TaskTiming.java @@ -25,24 +25,24 @@ public static String humanReadableTime(long milliseconds) { return timeString; } - public TimingData start(final int totalTasksCount) { + public synchronized TimingData start(final int totalTasksCount) { startTime = getCurrentTime(); completedTasks = 0; totalTasks = totalTasksCount; return generateTimingData(); } - public TimingData updateTotalTasks(final int totalTasksCount) { + public synchronized TimingData updateTotalTasks(final int totalTasksCount) { totalTasks = totalTasksCount; return generateTimingData(); } - public TimingData taskDone() { + public synchronized TimingData taskDone() { completedTasks++; return generateTimingData(); } - public TimingData finish() { + public synchronized TimingData finish() { return generateTimingData(); } @@ -50,7 +50,8 @@ private TimingData generateTimingData() { final long totalTime = getCurrentTime(); final long duration = totalTime - startTime; final float ratioOfDone = completedTasks / (float) totalTasks; - final long estimatedTimeLeft = (long) (duration / ratioOfDone) - duration; + final long estimatedTimeLeft = + (ratioOfDone == 0) ? 0 : (long) (duration / ratioOfDone) - duration; return new TimingData( totalTasks, completedTasks, startTime, totalTime, estimatedTimeLeft, ratioOfDone);