From ef8c0ddf5cf35237a41baac8d8c8adc5cbbcc8b9 Mon Sep 17 00:00:00 2001 From: sebastien-doyon Date: Thu, 12 Oct 2023 17:50:12 +0200 Subject: [PATCH] [MNG-7899] Various memory usage improvements - Non-threadsafe FileSizeFormat instance can be make class instance since its formatProgress() method is only called in a synchronized block. - add a test in a multi-threaded context --- .../ConsoleMavenTransferListener.java | 3 +- .../ConsoleMavenTransferListenerTest.java | 102 ++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 maven-embedder/src/test/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListenerTest.java diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java index c7b132adc5b6..be13b815b7c0 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java @@ -36,6 +36,7 @@ public class ConsoleMavenTransferListener extends AbstractMavenTransferListener { private Map transfers = Collections.synchronizedMap(new LinkedHashMap<>()); + private FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH); // use in a synchronized fashion private boolean printResourceNames; private int lastLength; @@ -68,8 +69,6 @@ public synchronized void transferProgressed(TransferEvent event) throws Transfer buffer.append("Progress (").append(transfers.size()).append("): "); synchronized (transfers) { - FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH); - Iterator> entries = transfers.entrySet().iterator(); while (entries.hasNext()) { diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListenerTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListenerTest.java new file mode 100644 index 000000000000..b53737f32937 --- /dev/null +++ b/maven-embedder/src/test/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListenerTest.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.cli.transfer; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.eclipse.aether.transfer.TransferEvent; +import org.eclipse.aether.transfer.TransferResource; +import org.junit.jupiter.api.Test; + +class ConsoleMavenTransferListenerTest { + + private CountDownLatch latch; + + @Test + void testTransferProgressedWithPrintResourceNames() throws FileNotFoundException, InterruptedException { + int size = 1000; + ExecutorService service = Executors.newFixedThreadPool(1000); + latch = new CountDownLatch(size); + Map output = new ConcurrentHashMap(); + + ConsoleMavenTransferListener listener = new ConsoleMavenTransferListener( + new PrintStream(System.out) { + + @Override + public void print(Object o) { + String string = o.toString() + .substring(0, o.toString().length() - 1) + .trim(); + output.put(string, string); + System.out.print(o); + } + }, + true); + TransferResource resource = new TransferResource(null, null, "http://maven.org/test/test-resource", null, null); + resource.setContentLength(size - 1); + + DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(); + + // warm up + test(listener, session, resource, 0); + + for (int i = 1; i < size; i++) { + final int bytes = i; + + service.execute(() -> { + test(listener, session, resource, bytes); + }); + } + try { + latch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + boolean test = true; + for (int i = 0; i < 999; i++) { + boolean ok = output.containsKey("Progress (1): test-resource (" + i + "/999 B)"); + if (!ok) { + System.out.println("false : " + i); + } + test = test & ok; + } + assertTrue(test); + } + + private void test(ConsoleMavenTransferListener listener, DefaultRepositorySystemSession session, TransferResource resource, final int bytes) { + TransferEvent event = new TransferEvent.Builder(session, resource) + .setTransferredBytes(bytes).build(); + latch.countDown(); + try { + listener.transferProgressed(event); + } catch (TransferCancelledException e) { + } + } +}