Skip to content

Refactor ByteArrayOutputStream into synchronized and non-synchronized versions#108

Merged
garydgregory merged 8 commits into
apache:masterfrom
adamretter:iostreams-sync
Apr 8, 2020
Merged

Refactor ByteArrayOutputStream into synchronized and non-synchronized versions#108
garydgregory merged 8 commits into
apache:masterfrom
adamretter:iostreams-sync

Conversation

@adamretter

@adamretter adamretter commented Apr 3, 2020

Copy link
Copy Markdown
Contributor

This abstracts the functionality of ByteArrayOutputStream into AbstractByteArrayOutputStream. Synchronized and non-synchronized (for performance) implementations are then provided in ByteArrayOutputStream and FastByteArrayOutputStream.

Tests are also provided.

p.s. I have just submitted by ICLA by email.

@coveralls

coveralls commented Apr 3, 2020

Copy link
Copy Markdown

Coverage Status

Coverage increased (+0.2%) to 89.588% when pulling 568e3e7 on adamretter:iostreams-sync into 335808a on apache:master.

@aherbert aherbert left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This looks like a nice conversion and maintains the previous support. I'd be wary of using a new dependency just to mark the code as Threadsafe with an annotation on an existing class. Bringing in an annotation framework is a different topic.

Using the name FastXXX is presumptuous but I cannot think of something better. NonSyncXXX is not as friendly. Others may have comments on this.

Comment thread pom.xml Outdated
<dependencies>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this just to bring in the @javax.annotation.concurrent.ThreadSafe annotation? I don't think this necessary since you already document the thread safety in the javadoc. Nothing else in the code base uses this non-standard annotation support.

@adamretter adamretter Apr 3, 2020

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Well yes it is to bring in the annotation... but these annotations can also be used by various tools like FindBugs and others to detect issues.

I think it adds value, and jsr305 is tiny (19KB). I can remove it if people prefer? It also adds useful annotations like @Nullable and @NotNull for similar purposes.

I can remove it though if that is preferred. Should I do that?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would remove it from this PR. Adding an annotation dependency should be in another PR that perhaps then makes more use of it than a single location. The Guava codebase uses these throughout and in that case they have value for a bug detection tool. I don't think a single annotation of @ThreadSafe is likely to detect many (any?) bugs given that synchronized code should be less of a problem than unsynchronized code. If you do have a bug detection tool that flags this class as a problem when used in a concurrent scenario a brief look at the javadoc (which notes this is safe for concurrent use) will allow you to mark the bug as false positive.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Okie dokie. Done.


private static Stream<Arguments> baosFactories() {
final BAOSFactory syncBaosFactory = size -> new ByteArrayOutputStream(size);
final BAOSFactory nonSyncBaos = size -> new FastByteArrayOutputStream(size);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

rename nonSyncBaosFactory

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

@garydgregory

Copy link
Copy Markdown
Member

This looks like a nice conversion and maintains the previous support. I'd be wary of using a new dependency just to mark the code as Threadsafe with an annotation on an existing class. Bringing in an annotation framework is a different topic.

Using the name FastXXX is presumptuous but I cannot think of something better. NonSyncXXX is not as friendly. Others may have comments on this.

I am a big -1 on calling a new class "Fast" since it is not fast, it just removes thread-safety. You can hope that it is "faster" than the standard class but that's it.

The JRE has been calling some thread-safe classes Concurrent like ConcurrentHashMap but other JRE thread-safe classes just have names that reflect behavior like CopyOnWriteArrayList, it therefore seem OK to me to call a classes that is not synchronized one of:

  • UnsynchronizedByteArrayOutputStream (to the point, precise)
  • SimpleByteArrayOutputStream (not great)
  • BasicByteArrayOutputStream (not great)
  • DefaultByteArrayOutputStream (not great)

My preference is UnsynchroniziedByteArrayOutputStream.

@adamretter

Copy link
Copy Markdown
Contributor Author

@garydgregory Okay I understand. Your preferred option is very long though. How do you feel about:

  1. UnsyncByteArrayOutputStream.
  2. UByteArrayOutputStream.
  3. USByteArrayOutputStream.
  4. UnsafeByteArrayOutputStream.

@garydgregory

garydgregory commented Apr 3, 2020

Copy link
Copy Markdown
Member

@garydgregory Okay I understand. Your preferred option is very long though. How do you feel about:

  1. UnsyncByteArrayOutputStream.

The least worst IMO.

  1. UByteArrayOutputStream.

Oh, the horror! ;-) There is no convention that equates "U" to "Unsynchronized", if anything "U" usually stands for "Unsigned".

  1. USByteArrayOutputStream.

Even worse IMO! Same comment as above except US usually means... United States?

  1. UnsafeByteArrayOutputStream.

Nope, same as for "Fast", unsafe compared in what area? Will this be a CVE?

I do not think there should be an issue spelling out Unsynchronized, if you look around, you'll see similar names spelled out:

  • javax.transaction.Synchronization
  • java.util.concurrent.locks.AbstractOwnableSynchronizer
  • java.util.concurrent.locks.AbstractQueuedLongSynchronizer
  • java.util.concurrent.locks.AbstractQueuedSynchronizer
  • java.util.Collections.SynchronizedCollection
  • java.util.Collections.SynchronizedList
  • java.util.Collections.SynchronizedMap
  • java.util.Collections.SynchronizedNavigableMap
  • java.util.Collections.SynchronizedNavigableSet
  • java.util.Collections.SynchronizedRandomAccessList
  • java.util.Collections.SynchronizedSet
  • java.util.Collections.SynchronizedSortedMap<
  • java.util.Collections.SynchronizedSortedSet
  • Too many to list in Google Guava.
  • Too many to list in our own Apache Commons Collections.

So, IMO, just say what it does.

@adamretter

Copy link
Copy Markdown
Contributor Author

@garydgregory Fair points. I have renamed it as you suggested.

* like the original. The only exception is the deprecated
* {@link java.io.ByteArrayOutputStream#toString(int)} method that has been
* ignored.
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please Add @since 2.7.

* <p>
* The data can be retrieved using <code>toByteArray()</code> and
* <code>toString()</code>.
* <p>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please close HTML tags.

}

/**
* Write the bytes to byte array.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

"Write" -> "Writes".

}

/**
* Return the current size of the byte array.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

"Return" -> "Returns".

* using the platform default charset.
* @return the contents of the byte array as a String
* @see java.io.ByteArrayOutputStream#toString()
* @deprecated 2.5 use {@link #toString(String)} instead

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I do not think it makes sense to deprecate toString() since it is such a basic JRE method that will never go away.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This was how it was previously in ByteArrayOutputStream. I just left it as I found it!

import java.io.OutputStream;

/**
* This class implements a version of {@link AbstractByteArrayOutputStream}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

"This class implements..." -> "Implements..."

@adamretter

Copy link
Copy Markdown
Contributor Author

@garydgregory I have incorporated your further feedback now.

@adamretter

Copy link
Copy Markdown
Contributor Author

@garydgregory Adding the closing <p> tags as you suggested breaks the javadoc build, so I will go ahead and remove them again:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  06:02 min
[INFO] Finished at: 2020-04-05T12:41:14Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:3.1.1:javadoc (default-cli) on project commons-io: An error has occurred in Javadoc report generation: 
[ERROR] Exit code: 1 - /home/travis/build/adamretter/commons-io/src/main/java/org/apache/commons/io/output/ByteArrayOutputStream.java:115: error: unexpected end tag: </p>
[ERROR]      * </p>
[ERROR]        ^
[ERROR] /home/travis/build/adamretter/commons-io/src/main/java/org/apache/commons/io/output/ByteArrayOutputStream.java:142: error: unexpected end tag: </p>
[ERROR]      * </p>
[ERROR]        ^
[ERROR] /home/travis/build/adamretter/commons-io/src/main/java/org/apache/commons/io/output/UnsynchronizedByteArrayOutputStream.java:112: error: unexpected end tag: </p>
[ERROR]      * </p>
[ERROR]        ^
[ERROR] /home/travis/build/adamretter/commons-io/src/main/java/org/apache/commons/io/output/UnsynchronizedByteArrayOutputStream.java:138: error: unexpected end tag: </p>
[ERROR]      * </p>
[ERROR]        ^
[ERROR] 
[ERROR] Command line was: /usr/local/lib/jvm/openjdk11/bin/javadoc @options @packages

@aherbert

aherbert commented Apr 5, 2020

Copy link
Copy Markdown
Contributor

Looking at the line errors for your </p> markers they are all at lines following a <ul> element that cannot be nested within a paragraph. Move the </p> to before the <ul>.

@adamretter

Copy link
Copy Markdown
Contributor Author

@aherbert Good point. I have incorporated the changes as you suggested.

@garydgregory

Copy link
Copy Markdown
Member

Hi @adamretter
Thank you for your updates.
JaCoCo reports that the code coverage for UnsynchronizedByteArrayOutputStream is less than it is for ByteArrayOutputStream.java. May you address this please?
Thank you!
You can run this: mvn -V clean install site -P jacoco -P japicmp

@adamretter

adamretter commented Apr 7, 2020

Copy link
Copy Markdown
Contributor Author

@garydgregory Hmm, from what I read in coveralls.io the code coverage after this PR is +0.07% so it is a net improvement, no?

@garydgregory

Copy link
Copy Markdown
Member

@garydgregory Hmm, from what I read in coveralls.io the code coverage after this PR is +0.07% so it is a net improvement, no?

Please run the command I provided and look at the JaCoCo report. You will see that the new class has less coverage than the current (refactored) one. We should strive to give the best possible code coverage for changes and new code.

@adamretter

Copy link
Copy Markdown
Contributor Author

@garydgregory Sure I see it now. I have just pushed a commit to further improve coverage.

@garydgregory garydgregory merged commit c2c2709 into apache:master Apr 8, 2020
asfgit pushed a commit that referenced this pull request Apr 8, 2020
@adamretter

Copy link
Copy Markdown
Contributor Author

@garydgregory @aherbert Yay! Thanks :-)

asfgit pushed a commit that referenced this pull request Apr 9, 2020
unsynchronized versions #108.

Simplify method name.
brettlounsbury pushed a commit to brettlounsbury/commons-io that referenced this pull request May 28, 2020
… versions (apache#108)

* Split ByteArrayOutputStream into synchronized and non-synchronized versions

* Improve the test coverage of AbstractByteArrayOutputStream and sub-classes

* Address review comments by @aherbert

* Address review comments by @garydgregory

* Address further review comments by @garydgregory

* Remove </p> tags, breaks the javadoc build

* Address review comments by @aherbert

* Improve coverage of tests
brettlounsbury pushed a commit to brettlounsbury/commons-io that referenced this pull request May 28, 2020
brettlounsbury pushed a commit to brettlounsbury/commons-io that referenced this pull request May 28, 2020
unsynchronized versions apache#108.

Simplify method name.
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