From 94749041b421f8e415174deb05e99563d65c25ee Mon Sep 17 00:00:00 2001 From: sebastien-doyon Date: Fri, 10 Nov 2023 00:47:54 +0100 Subject: [PATCH] [MNG-7899] Various memory usage improvements 4-1 (#1296) * [MNG-7899] Various memory usage improvements - BatchModeMavenTransferListener removed - FileSizeFormat moved to top level class - FileSizeFormat.formatProcess() refactored to accept an StringBuilder as argument - FileSizeFormat refactored format() methods - FileSizeFormat refactored, replace DecimalFormat with Math logic to reduce memory allocation --------- Co-authored-by: Guillaume Nodet --- .../AbstractMavenTransferListener.java | 156 +--------------- .../BatchModeMavenTransferListener.java | 30 --- .../ConsoleMavenTransferListener.java | 2 +- .../maven/cli/transfer/FileSizeFormat.java | 176 ++++++++++++++++++ .../transfer/Slf4jMavenTransferListener.java | 11 +- .../cli/transfer/FileSizeFormatTest.java | 3 +- 6 files changed, 190 insertions(+), 188 deletions(-) delete mode 100644 maven-embedder/src/main/java/org/apache/maven/cli/transfer/BatchModeMavenTransferListener.java create mode 100644 maven-embedder/src/main/java/org/apache/maven/cli/transfer/FileSizeFormat.java diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java index 803c9f9b60..bc6526806c 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java @@ -19,8 +19,6 @@ package org.apache.maven.cli.transfer; import java.io.PrintStream; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; import java.util.Locale; import org.apache.maven.cli.jansi.MessageUtils; @@ -38,153 +36,6 @@ public abstract class AbstractMavenTransferListener extends AbstractTransferList private static final String ANSI_DARK_SET = ESC + "[90m"; private static final String ANSI_DARK_RESET = ESC + "[0m"; - // CHECKSTYLE_OFF: LineLength - /** - * Formats file size with the associated SI prefix - * (GB, MB, kB) and using the patterns #0.0 for numbers between 1 and 10 - * and ###0 for numbers between 10 and 1000+ by default. - * - * @see https://en.wikipedia.org/wiki/Metric_prefix - * @see https://en.wikipedia.org/wiki/Binary_prefix - * @see https://en.wikipedia.org/wiki/Octet_(computing) - */ - // CHECKSTYLE_ON: LineLength - // TODO Move me to Maven Shared Utils - static class FileSizeFormat { - enum ScaleUnit { - BYTE { - @Override - public long bytes() { - return 1L; - } - - @Override - public String symbol() { - return "B"; - } - }, - KILOBYTE { - @Override - public long bytes() { - return 1000L; - } - - @Override - public String symbol() { - return "kB"; - } - }, - MEGABYTE { - @Override - public long bytes() { - return KILOBYTE.bytes() * KILOBYTE.bytes(); - } - - @Override - public String symbol() { - return "MB"; - } - }, - GIGABYTE { - @Override - public long bytes() { - return MEGABYTE.bytes() * KILOBYTE.bytes(); - } - ; - - @Override - public String symbol() { - return "GB"; - } - }; - - public abstract long bytes(); - - public abstract String symbol(); - - public static ScaleUnit getScaleUnit(long size) { - if (size < 0L) { - throw new IllegalArgumentException("file size cannot be negative: " + size); - } - - if (size >= GIGABYTE.bytes()) { - return GIGABYTE; - } else if (size >= MEGABYTE.bytes()) { - return MEGABYTE; - } else if (size >= KILOBYTE.bytes()) { - return KILOBYTE; - } else { - return BYTE; - } - } - } - - private DecimalFormat smallFormat; - private DecimalFormat largeFormat; - - FileSizeFormat(Locale locale) { - smallFormat = new DecimalFormat("#0.0", new DecimalFormatSymbols(locale)); - largeFormat = new DecimalFormat("###0", new DecimalFormatSymbols(locale)); - } - - public String format(long size) { - return format(size, null); - } - - public String format(long size, ScaleUnit unit) { - return format(size, unit, false); - } - - @SuppressWarnings("checkstyle:magicnumber") - public String format(long size, ScaleUnit unit, boolean omitSymbol) { - if (size < 0L) { - throw new IllegalArgumentException("file size cannot be negative: " + size); - } - - if (unit == null) { - unit = ScaleUnit.getScaleUnit(size); - } - - double scaledSize = (double) size / unit.bytes(); - String scaledSymbol = " " + unit.symbol(); - - if (omitSymbol) { - scaledSymbol = ""; - } - - if (unit == ScaleUnit.BYTE) { - return largeFormat.format(size) + scaledSymbol; - } - - if (scaledSize < 0.05 || scaledSize >= 10.0) { - return largeFormat.format(scaledSize) + scaledSymbol; - } else { - return smallFormat.format(scaledSize) + scaledSymbol; - } - } - - public String formatProgress(long progressedSize, long size) { - if (progressedSize < 0L) { - throw new IllegalArgumentException("progressed file size cannot be negative: " + size); - } - if (size >= 0 && progressedSize > size) { - throw new IllegalArgumentException( - "progressed file size cannot be greater than size: " + progressedSize + " > " + size); - } - - if (size >= 0L && progressedSize != size) { - ScaleUnit unit = ScaleUnit.getScaleUnit(size); - String formattedProgressedSize = format(progressedSize, unit, true); - String formattedSize = format(size, unit); - - return formattedProgressedSize + "/" + formattedSize; - } else { - return format(progressedSize); - } - } - } - protected PrintStream out; protected AbstractMavenTransferListener(PrintStream out) { @@ -234,12 +85,15 @@ public abstract class AbstractMavenTransferListener extends AbstractTransferList message.append(darkOff).append(resource.getRepositoryId()); message.append(darkOn).append(": ").append(resource.getRepositoryUrl()); message.append(darkOff).append(resource.getResourceName()); - message.append(darkOn).append(" (").append(format.format(contentLength)); + message.append(darkOn).append(" ("); + format.format(message, contentLength); long duration = System.currentTimeMillis() - resource.getTransferStartTime(); if (duration > 0L) { double bytesPerSecond = contentLength / (duration / 1000.0); - message.append(" at ").append(format.format((long) bytesPerSecond)).append("/s"); + message.append(" at "); + format.format(message, (long) bytesPerSecond); + message.append("/s"); } message.append(')').append(darkOff); diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/BatchModeMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/BatchModeMavenTransferListener.java deleted file mode 100644 index 667df5d958..0000000000 --- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/BatchModeMavenTransferListener.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 java.io.PrintStream; - -/** - * BatchModeMavenTransferListener - */ -public class BatchModeMavenTransferListener extends AbstractMavenTransferListener { - public BatchModeMavenTransferListener(PrintStream out) { - super(out); - } -} 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 04e8bed45f..78addd1349 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 @@ -87,7 +87,7 @@ public class ConsoleMavenTransferListener extends AbstractMavenTransferListener buffer.append(" ("); } - buffer.append(format.formatProgress(complete, total)); + format.formatProgress(buffer, complete, total); if (printResourceNames) { buffer.append(")"); diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/FileSizeFormat.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/FileSizeFormat.java new file mode 100644 index 0000000000..6ae2054e65 --- /dev/null +++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/FileSizeFormat.java @@ -0,0 +1,176 @@ +/* + * 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 java.util.Locale; + +/** + * Formats file size with the associated SI prefix + * (GB, MB, kB) and using the patterns #0.0 for numbers between 1 and 10 + * and ###0 for numbers between 10 and 1000+ by default. + * + * @see https://en.wikipedia.org/wiki/Metric_prefix + * @see https://en.wikipedia.org/wiki/Binary_prefix + * @see https://en.wikipedia.org/wiki/Octet_(computing) + */ +public class FileSizeFormat { + public enum ScaleUnit { + BYTE { + @Override + public long bytes() { + return 1L; + } + + @Override + public String symbol() { + return "B"; + } + }, + KILOBYTE { + @Override + public long bytes() { + return 1000L; + } + + @Override + public String symbol() { + return "kB"; + } + }, + MEGABYTE { + @Override + public long bytes() { + return KILOBYTE.bytes() * KILOBYTE.bytes(); + } + + @Override + public String symbol() { + return "MB"; + } + }, + GIGABYTE { + @Override + public long bytes() { + return MEGABYTE.bytes() * KILOBYTE.bytes(); + } + ; + + @Override + public String symbol() { + return "GB"; + } + }; + + public abstract long bytes(); + + public abstract String symbol(); + + public static ScaleUnit getScaleUnit(long size) { + if (size < 0L) { + throw new IllegalArgumentException("file size cannot be negative: " + size); + } + + if (size >= GIGABYTE.bytes()) { + return GIGABYTE; + } else if (size >= MEGABYTE.bytes()) { + return MEGABYTE; + } else if (size >= KILOBYTE.bytes()) { + return KILOBYTE; + } else { + return BYTE; + } + } + } + + public FileSizeFormat(Locale locale) {} + + public String format(long size) { + return format(size, null); + } + + public String format(long size, ScaleUnit unit) { + return format(size, unit, false); + } + + public String format(long size, ScaleUnit unit, boolean omitSymbol) { + StringBuilder sb = new StringBuilder(); + format(sb, size, unit, omitSymbol); + return sb.toString(); + } + + public void format(StringBuilder builder, long size) { + format(builder, size, null, false); + } + + public void format(StringBuilder builder, long size, ScaleUnit unit) { + format(builder, size, unit, false); + } + + @SuppressWarnings("checkstyle:magicnumber") + private void format(StringBuilder builder, long size, ScaleUnit unit, boolean omitSymbol) { + if (size < 0L) { + throw new IllegalArgumentException("file size cannot be negative: " + size); + } + if (unit == null) { + unit = ScaleUnit.getScaleUnit(size); + } + + double scaledSize = (double) size / unit.bytes(); + + if (unit == ScaleUnit.BYTE) { + builder.append(size); + } else if (scaledSize < 0.05d || scaledSize >= 10.0d) { + builder.append(Math.round(scaledSize)); + } else { + builder.append(Math.round(scaledSize * 10d) / 10d); + } + + if (!omitSymbol) { + builder.append(" ").append(unit.symbol()); + } + } + + public String formatProgress(long progressedSize, long size) { + StringBuilder sb = new StringBuilder(); + formatProgress(sb, progressedSize, size); + return sb.toString(); + } + + public void formatProgress(StringBuilder builder, long progressedSize, long size) { + if (progressedSize < 0L) { + throw new IllegalArgumentException("progressed file size cannot be negative: " + size); + } + if (size >= 0 && progressedSize > size) { + throw new IllegalArgumentException( + "progressed file size cannot be greater than size: " + progressedSize + " > " + size); + } + + if (size >= 0L && progressedSize != size) { + ScaleUnit unit = ScaleUnit.getScaleUnit(size); + format(builder, progressedSize, unit, true); + builder.append("/"); + format(builder, size, unit, false); + } else { + ScaleUnit unit = ScaleUnit.getScaleUnit(progressedSize); + + format(builder, progressedSize, unit, false); + } + } +} diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java index c5c8f09645..573b6ea7e3 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java @@ -20,7 +20,6 @@ package org.apache.maven.cli.transfer; import java.util.Locale; -import org.apache.maven.cli.transfer.AbstractMavenTransferListener.FileSizeFormat; import org.eclipse.aether.transfer.AbstractTransferListener; import org.eclipse.aether.transfer.TransferCancelledException; import org.eclipse.aether.transfer.TransferEvent; @@ -81,13 +80,17 @@ public class Slf4jMavenTransferListener extends AbstractTransferListener { StringBuilder message = new StringBuilder(); message.append(action).append(' ').append(direction).append(' ').append(resource.getRepositoryId()); message.append(": "); - message.append(resource.getRepositoryUrl()).append(resource.getResourceName()); - message.append(" (").append(format.format(contentLength)); + message.append(resource.getRepositoryUrl()) + .append(resource.getResourceName()) + .append(" ("); + format.format(message, contentLength); long duration = System.currentTimeMillis() - resource.getTransferStartTime(); if (duration > 0L) { double bytesPerSecond = contentLength / (duration / 1000.0); - message.append(" at ").append(format.format((long) bytesPerSecond)).append("/s"); + message.append(" at "); + format.format(message, (long) bytesPerSecond); + message.append("/s"); } message.append(')'); diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/transfer/FileSizeFormatTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/transfer/FileSizeFormatTest.java index 5587364035..6f96a59d90 100644 --- a/maven-embedder/src/test/java/org/apache/maven/cli/transfer/FileSizeFormatTest.java +++ b/maven-embedder/src/test/java/org/apache/maven/cli/transfer/FileSizeFormatTest.java @@ -20,8 +20,7 @@ package org.apache.maven.cli.transfer; import java.util.Locale; -import org.apache.maven.cli.transfer.AbstractMavenTransferListener.FileSizeFormat; -import org.apache.maven.cli.transfer.AbstractMavenTransferListener.FileSizeFormat.ScaleUnit; +import org.apache.maven.cli.transfer.FileSizeFormat.ScaleUnit; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals;