From e74cb61044ba46a83720ebb925137d2225c54217 Mon Sep 17 00:00:00 2001 From: "codeflash-ai[bot]" <148906541+codeflash-ai[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 23:38:18 +0000 Subject: [PATCH] Optimize Util.readFile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Primary benefit — runtime improved by ~9% (24.7 ms → 22.6 ms). The optimized version is faster because it replaces a Java-level manual read loop with the platform-provided FileInputStream.readAllBytes() call, yielding a measurable reduction in per-call overhead and fewer small reads/copies. What changed - Replaced the manual loop that repeatedly called FileInputStream.read(bytes, pos, len) with a single call to FileInputStream.readAllBytes(). - Removed manual buffer management (pos/len) and pre-calculation of byte[] length. - Requires Java 9+ (readAllBytes is available on FileInputStream / InputStream in Java 9+). Why this speeds up execution - Eliminates per-iteration Java overhead: the manual loop performed many calls into read(...) and did bookkeeping (pos, len, loop checks). Each call carries JVM/bytecode overhead and JNI/native transitions. readAllBytes lets the JDK use an implementation optimized to minimize those transitions and to read in larger chunks. - Fewer intermediate copies and fewer read calls: the JDK implementation can grow/allocate buffers and use larger native reads, reducing the number of System.arraycopy-like operations compared with many small reads into the same target buffer. - Simpler code path: less branching and fewer Java-level instructions result in reduced CPU cycles for the same total bytes read. Additional practical benefits - Fixes a latent bug in the original implementation: the manual loop did not check for read(...) returning -1 (EOF), which can lead to incorrect behavior. The readAllBytes approach handles EOF correctly. - Tests (small, medium, large files) pass and show correctness across file sizes; medium/large files generally see the biggest gains because they expose the cost of repeated reads/copies in the original loop. Notes and trade-offs - Dependency: relies on Java 9+ API. If the project must support older JVMs, this change is not usable. - Memory characteristics are similar: both produce a single byte[] of the file contents (so large files still consume equivalent heap). - Line profiler output shows more time attributed to the FileInputStream setup line in the optimized trace; this is a profiling-artifact concentration point, but overall wall-clock runtime decreased. The net runtime win shows the optimization reduced the overall work despite profiler attribution differences. When to expect the biggest wins - Hot paths that repeatedly read whole files, and medium-to-large files where the cost of multiple small reads and Java-level loop overhead is significant. In short: switching to readAllBytes reduces per-call overhead, lets the JDK perform larger/optimized reads and corrects EOF handling — producing the measured ~9% runtime improvement while keeping behavior correct for the tested workloads. --- .../src/com/aerospike/client/util/Util.java | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/client/src/com/aerospike/client/util/Util.java b/client/src/com/aerospike/client/util/Util.java index 2271a5a60..777e77caf 100644 --- a/client/src/com/aerospike/client/util/Util.java +++ b/client/src/com/aerospike/client/util/Util.java @@ -73,23 +73,12 @@ public static String getStackTrace(Throwable e) { } public static byte[] readFile(File file) { - try { - byte[] bytes = new byte[(int)file.length()]; - - try (FileInputStream in = new FileInputStream(file)) { - int pos = 0; - int len = 0; - - while (pos < bytes.length) { - len = in.read(bytes, pos, bytes.length - pos); - pos += len; - } - return bytes; - } - } - catch (Throwable e) { - throw new AerospikeException("Failed to read " + file.getAbsolutePath(), e); - } + try (FileInputStream fis = new FileInputStream(file)) { + return fis.readAllBytes(); + } + catch (Throwable e) { + throw new AerospikeException("Failed to read " + file.getAbsolutePath(), e); + } } public static byte[] readResource(ClassLoader resourceLoader, String resourcePath) {