From 2a1ff2b30a931f13a3ff992e8fbc785d59809215 Mon Sep 17 00:00:00 2001 From: "(no author)" <(no author)@71dcc7fd-b1f2-4e5d-bb8e-274146e81173> Date: Fri, 20 Jun 2025 10:21:22 +0000 Subject: [PATCH] Introduce virtual threads and blocking queues for concurrent file comparison This commit introduces a significant refactoring of the `Task` class to improve performance and resource utilization when comparing files. Instead of reading directly within the main thread, it now leverages Java's virtual threads and blocking queues to handle file loading concurrently. Key changes: - **Virtual Threads:** Uses `ExecutorService` with `newVirtualThreadPerTaskExecutor()` to create lightweight virtual threads for reading from each file. This allows for highly concurrent I/O operations without excessive overhead. - **Blocking Queues:** Employs `LinkedBlockingQueue` to facilitate communication between the file loading threads and the comparison logic. Each queue holds buffers read from its corresponding file. - **Buffer Pool:** Continues utilizing the `BufferPool` for managing byte arrays to minimize memory allocation. - **Loader Method:** A new private method `loader` is introduced to encapsulate the file reading process within each virtual thread, placing read data into the respective queue. - **Error Handling:** Improved exception handling to properly cancel tasks and propagate exceptions. Interruptions are handled correctly. These changes should result in significantly improved throughput when comparing large files, especially on systems with multiple cores. git-svn-id: svn://home0/checkDataIntegrity@3744 71dcc7fd-b1f2-4e5d-bb8e-274146e81173 --- .../BufferPool$Buffer.class | Bin 0 -> 465 bytes bin/checkDataIntegrity/BufferPool.class | Bin 864 -> 1118 bytes bin/checkDataIntegrity/Main.class | Bin 3911 -> 3911 bytes bin/checkDataIntegrity/Task.class | Bin 4187 -> 6792 bytes checkDataIntegrity.jar | Bin 19385 -> 21037 bytes src/checkDataIntegrity/BufferPool.java | 18 +++- src/checkDataIntegrity/Main.java | 2 +- src/checkDataIntegrity/Task.java | 101 +++++++++++++----- 8 files changed, 89 insertions(+), 32 deletions(-) create mode 100644 bin/checkDataIntegrity/BufferPool$Buffer.class diff --git a/bin/checkDataIntegrity/BufferPool$Buffer.class b/bin/checkDataIntegrity/BufferPool$Buffer.class new file mode 100644 index 0000000000000000000000000000000000000000..8a3bfa3966645816376807ae504822d4764a3c6a GIT binary patch literal 465 zcma)2O-sW-5Pg%xrmg9x*7||qp%m@G{s2X4D`KHkLFvWQCT`o*xPfFN__I8SAmR`3 zM~RbE@FpH+-pt#XxBK?<>+J);DRyiagqAm#-u;=-VyLv7MZSLO_LJ#UMpt1Nw3ej} zi%?yNN6`(0nsqPTh4eJRbdxE;xb1TpNJXF_A$RO6U!O3we=s3fgYZrkVWQ-qfMNlJ zih~v87)QR6 z#*{m+a5}Xf-t#XgKl6!!D(7;h(tw2~N@$?QoU`0O9c$c~SkI;#*kDX`iD$R?uI-F( FegiIHV;TSe literal 0 HcmV?d00001 diff --git a/bin/checkDataIntegrity/BufferPool.class b/bin/checkDataIntegrity/BufferPool.class index 2b15b544bfdc0816519f0c8ef7cc9dd548be10c0..d3bb0e4ce9d4b4116e36c322efa3c3a3bce5cad1 100644 GIT binary patch delta 355 zcmaFBc8`PW)W2Q(7#J8F8T2P|)i4H4^wVUr@tG(f%c0^_nwFMYWIb{7Ar=h{O%$=o zRgAifDnM0YP*q$Eat!>849rQTX^aeNsA@MbN-%3`fW$;#W@?6UG4L>`^Dt;IXimPt zXs^b|z~h;hms;eUlUQ7wTFl762C?i+ZnqMEq zzzBp43}TxY1h+9r9bl02);i9>DJa0Ohr?TI15k#UK^RC1F|YthE+FJ)-~$>X0whI% zB0NCdAY&C6ucU*1*2QMSXWKP~?jI5hC@J?q00782O_5c6? delta 20 ccmX>ucU*1*2QMT0WKP~?jO?2?@J?q00782O_W%F@ diff --git a/bin/checkDataIntegrity/Task.class b/bin/checkDataIntegrity/Task.class index 931e1a4a87928c2ed7908d5baf3609fcffa55fce..a8cc54bd88017befbed7d8fee90e3a9be663eb24 100644 GIT binary patch literal 6792 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 literal 4187 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 delta 9847 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 Dfax&9 diff --git a/src/checkDataIntegrity/BufferPool.java b/src/checkDataIntegrity/BufferPool.java index 5b5a3ae..3372071 100644 --- a/src/checkDataIntegrity/BufferPool.java +++ b/src/checkDataIntegrity/BufferPool.java @@ -4,18 +4,26 @@ import java.util.concurrent.LinkedBlockingQueue; class BufferPool { - private static final LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); + private static final LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); - static byte[] get() { - byte[] buf = queue.poll(); + static Buffer get() { + Buffer buf = queue.poll(); if (buf == null) { - buf = new byte[4096]; + buf = new Buffer(); } return buf; } - static void put(final byte[] buf) { + static void put(final Buffer buf) { queue.offer(buf); } + static class Buffer { + + byte[] buf = new byte[16384]; + + volatile int len; + + } + } diff --git a/src/checkDataIntegrity/Main.java b/src/checkDataIntegrity/Main.java index f1e31c3..dc587bc 100644 --- a/src/checkDataIntegrity/Main.java +++ b/src/checkDataIntegrity/Main.java @@ -32,7 +32,7 @@ public class Main { } private static Args parseArgs(final String[] args) { - if (args.length < 4) { + if (args.length < 5) { System.err.println("Usage: checkDataIntegrity.java "); return null; } diff --git a/src/checkDataIntegrity/Task.java b/src/checkDataIntegrity/Task.java index fe929b3..1a0105e 100644 --- a/src/checkDataIntegrity/Task.java +++ b/src/checkDataIntegrity/Task.java @@ -1,19 +1,33 @@ package checkDataIntegrity; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.RandomAccessFile; import java.nio.file.InvalidPathException; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.Arrays; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; import java.util.function.Consumer; +import checkDataIntegrity.BufferPool.Buffer; + class Task implements Consumer { private final Args args; private final ProgramState state; + private final ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor(); + + private final BlockingQueue queue0 = new LinkedBlockingQueue<>(1); + + private final BlockingQueue queue1 = new LinkedBlockingQueue<>(1); + Task(final Args args, final ProgramState state) { this.args = args; this.state = state; @@ -30,42 +44,77 @@ class Task implements Consumer { final String rel = path.toString().substring(this.args.path0().length()); final Path p1 = Path.of(this.args.path1() + rel); - int len0, len1; - final byte[] buf0 = BufferPool.get(); - final byte[] buf1 = BufferPool.get(); - try ( - RandomAccessFile raf0 = new RandomAccessFile(path.toFile(), "r"); - RandomAccessFile raf1 = new RandomAccessFile(p1.toFile(), "r")) { - - do { - len0 = raf0.read(buf0); - len1 = raf1.read(buf1); - if (len0 != len1) { - System.out.println(rel + ": Length mismatch"); - this.state.countErr().incrementAndGet(); - break; - } - if (len0 > -1) { - this.state.bytes().addAndGet(len0); - if (!Arrays.equals(buf0, 0, len0, buf1, 0, len1)) { - System.out.println(rel + ": Data mismatch"); - this.state.countErr().incrementAndGet(); - break; + try (RandomAccessFile raf0 = new RandomAccessFile(path.toFile(), "r"); RandomAccessFile raf1 = new RandomAccessFile(p1.toFile(), "r")) { + final Future future0 = this.executorService.submit(() -> this.loader(raf0, this.queue0)); + final Future future1 = this.executorService.submit(() -> this.loader(raf1, this.queue1)); + try { + while (true) { + final Buffer buf0 = this.queue0.take(); + final Buffer buf1 = this.queue1.take(); + try { + if (buf0.len != buf1.len) { + System.out.println(rel + ": Length mismatch"); + this.state.countErr().incrementAndGet(); + break; + } + if (buf0.len == -1) { + break; + } + this.state.bytes().addAndGet(buf0.len); + if (!Arrays.equals(buf0.buf, 0, buf0.len, buf1.buf, 0, buf1.len)) { + System.out.println(rel + ": Data mismatch"); + this.state.countErr().incrementAndGet(); + break; + } + } + finally { + BufferPool.put(buf0); + BufferPool.put(buf1); } } - } while (len0 > -1); - } - finally { - BufferPool.put(buf0); - BufferPool.put(buf1); + } + catch (final Exception ex) { + future0.cancel(true); + future1.cancel(true); + throw ex; + } } } catch (NoSuchFileException | FileNotFoundException | InvalidPathException ex) { } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } catch (final Exception ex) { System.out.println(path + ": Exception: " + ex.getClass().getName() + " " + ex.getMessage()); this.state.countErr().incrementAndGet(); } } + private void loader(final RandomAccessFile raf, final BlockingQueue queue) { + try { + while (!Thread.currentThread().isInterrupted()) { + final Buffer buf = BufferPool.get(); + buf.len = raf.read(buf.buf); + if (buf.len == -1) { + queue.put(buf); + return; + } + queue.put(buf); + } + } + catch (final IOException e) { + e.printStackTrace(); + final Buffer buf = BufferPool.get(); + buf.len = -1; + try { + queue.put(buf); + } + catch (final InterruptedException e1) { + } + } + catch (final InterruptedException e) { + } + } + }