Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MJARSIGNER-72] Parallel signing for increased speed #18

Merged
merged 1 commit into from
Dec 15, 2023

Conversation

schedin
Copy link
Contributor

@schedin schedin commented Dec 12, 2023

In this pull request I have implemented https://issues.apache.org/jira/projects/MJARSIGNER/issues/MJARSIGNER-72 so that signing of jar files can be done in parallel.

This ticket is the reason I added to many test cases in my previous work of implementing MJARSIGNER-41. In the scope of this ticket I have added new test cases to verify that the threading/parallelism works. I have also added some logging tests (to verify that the logging is correctly handled).

* @return a List of File objects
* @throws MojoExecutionException if it was not possible to build a list of jar files.
*/
private List<File> findJarfiles() throws MojoExecutionException {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once again the diff on GitHub displays like I have changed the entire function. View the diff from an IDE to easier see what rows I have only re-indented.

@schedin
Copy link
Contributor Author

schedin commented Dec 12, 2023

I tested this with a Maven project that signs 129 jar files using the DigiCert Keylocker PKCS 11 HSM software as a service and also using DigiCerts TSA server http://timestamp.digicert.com (that is: 2 network based requests per jar file).

  1. Single threaded: 473 seconds (7 minutes, 53 seconds)
  2. 8 threads: 71 seconds (1 minute, 11 seconds)
  3. 16 threads: 46 seconds

@@ -115,6 +122,17 @@ public class JarsignerSignMojo extends AbstractJarsignerMojo {
@Parameter(property = "jarsigner.maxRetryDelaySeconds", defaultValue = "0")
private int maxRetryDelaySeconds;

/**
* How many threads to use (in parallel) when signing jar files. Increases performance when signing multiple jar
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a plausible maximum here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about this a bit. In https://github.com/apache/maven-surefire it does not look like they have a limit (for both JUnit and TestNG). The https://github.com/apache/maven-compiler-plugin does not have a similar parameter. I tested to set threadCount to 10000 on my 129 jar-file-project. I only got 129 threads (because of the details in how ThreadPoolExecutor per default behaves).

Since I don't know what the future holds (how fast storage, CPU and how much network latency there may be) I suggest that I do not put a limit on this. In practice the threads are limited by the number of jar files anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case change "How many threads to use (in parallel)" --> "Maximum number of parallel threads to use"

*/
@Override
protected void processArchives(List<File> archives) throws MojoExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be the minimum of threadCount and the number of archives? No reason to spawn ten threads with only 5 files to sign

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice observation! I could, but I'm not sure I should, because it would make the code a bit harder to read. In the documentation for https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html there is this text:

When a new task is submitted in method execute(Runnable), and fewer than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle.

That is, for this specific case the number of threads will in practice be limited to the number of jobs I submit to the thread pool (number of jar files). Due to how Executors.newFixedThreadPool() work you might end up with a few more than needed, if the first jobs terminate very fast before the last has been submitted. But the number of threads will never be more than the amount of submitted jobs.

I have tested and verified that this behavior holds! Using threadCount=10000 and looking at the number of threads in my IDE.

* control the level of some logging events.
*/
@Test
public void testLoggingVerboseTrue() throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I prefer not to test logging since I don't consider it part of the contract of a method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could remove the logging tests? 🤷 The reason I added tests for so much was to be very sure that my refactor did not change anything unexpected.

@schedin schedin force-pushed the MJARSIGNER-72_threadCount branch 2 times, most recently from b25fb56 to 6f59f4b Compare December 13, 2023 11:58
@schedin
Copy link
Contributor Author

schedin commented Dec 15, 2023

I’m still waiting for feedback regarding if I should follow the https://www.oracle.com/technical-resources/articles/java/javadoc-tool.html example (under the @throws heading) and use upper case for the first letter. See also what I wrote in #18 (comment) and #18 (comment) with regards about that the text about capitalization exist for @param and @return, but does not exist for @throws.

@schedin schedin requested a review from elharo December 15, 2023 07:43
@schedin schedin force-pushed the MJARSIGNER-72_threadCount branch from 6f59f4b to 5710fb7 Compare December 15, 2023 14:40
@@ -115,6 +122,17 @@ public class JarsignerSignMojo extends AbstractJarsignerMojo {
@Parameter(property = "jarsigner.maxRetryDelaySeconds", defaultValue = "0")
private int maxRetryDelaySeconds;

/**
* How many threads to use (in parallel) when signing jar files. Increases performance when signing multiple jar
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case change "How many threads to use (in parallel)" --> "Maximum number of parallel threads to use"

Adding support for threadCount when signing jar files
@schedin schedin force-pushed the MJARSIGNER-72_threadCount branch from 5710fb7 to 7972fcd Compare December 15, 2023 17:00
@schedin
Copy link
Contributor Author

schedin commented Dec 15, 2023

I fixed the javadoc on threadCount according to the suggestion!

@elharo elharo merged commit 930b7e4 into apache:master Dec 15, 2023
10 checks passed
@andrew-tram
Copy link

Im not sure how this works, but will there eventually be a 3.1.0 (or whatever) Maven Jarsigner plugin that has this change or is it up to individuals to build it?

@slawekjaranowski
Copy link
Member

Im not sure how this works, but will there eventually be a 3.1.0 (or whatever) Maven Jarsigner plugin that has this change or is it up to individuals to build it?

I will release 3.1.0 in a few days

Always you can ask on Maven Developer List for release ... https://maven.apache.org/mailing-lists.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants