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

Input streams returned by DecompressingEntity.getContent() should support mark(int) and reset() #567

Conversation

garydgregory
Copy link
Member

@garydgregory garydgregory commented Aug 16, 2024

Input streams returned by DecompressingEntity.getContent() should support mark(int) and reset() if the underlying stream does

  • Pass calls to the underlying InputStream for mark(int)
  • Pass calls to the underlying InputStream for reset()
  • LazyDecompressingInputStream extends FilterInputStream
  • Reimplement internals fluently
  • Reuse Closer.close(Closeable)
  • Tested locally with git master 5.3-beta2-SNAPSHOT

}

@Override
public synchronized void mark(final int readlimit) {
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't we use ReentrantLock instead?

Copy link
Member

Choose a reason for hiding this comment

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

@garydgregory No more synchronized for us going forward. Thread synchronization must be implemented using locks in order to be compatible with Java 21 fibers

Copy link
Member Author

Choose a reason for hiding this comment

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

Hm, I guess the whole class isn't thread-safe to start with due to initWrapper(). I'll rework the PR.

These synchronized come from the Java 8, 11, and 17 contracts.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you both for the reviews.

The simplest change and implementation that keeps in line with what to have today is to remove the synchronized keyword and let the delegate's implementation do what it will. If we wanted mark/reset to be thread-safe, we could make the whole class thread-safe like this:

   private final ReentrantLock lock = new ReentrantLock();
   ...
    /**
     * Thread-safe initialization of the wrapped stream.
     *
     * @return the wrapper stream.
     * @throws IOException if an IO error occurs.
     */
    private InputStream initWrapper() throws IOException {
        if (wrapperStream == null) {
            lock.lock();
            try {
                wrapperStream = wrapperStream != null ? wrapperStream : inputStreamFactory.create(in);
            } finally {
                lock.unlock();
            }
        }
        return wrapperStream;
    }

but then each call to the stream would lock-unlock.

So, either:

  • Don't use synchronized and that's it.
  • Only have mark/reset use lock-unlock, or
  • Implement using the above thread-safe initWrapper()?

For now, the PR takes the simplest route.
WDYT?

Copy link
Member

Choose a reason for hiding this comment

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

  • Don't use synchronized and that's it.

I would go for this one.

}
}

@Override
public synchronized void reset() throws IOException {
Copy link
Member

Choose a reason for hiding this comment

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

same here

Copy link
Member Author

Choose a reason for hiding this comment

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

OK, I merged with this option.

Copy link
Member

@ok2c ok2c left a comment

Choose a reason for hiding this comment

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

@garydgregory I am not sure synchronization is even needed here. This class is not supposed to be used for concurrent access.

support mark(int) and reset() if the underlying stream does

- Pass calls to the underlying InputStream for mark(int)
- Pass calls to the underlying InputStream for reset()
- LazyDecompressingInputStream extends FilterInputStream
- Reimplement internals fluently
- Reuse Closer.close(Closeable)
- Tested locally with git master 5.3-beta2-SNAPSHOT
@garydgregory garydgregory force-pushed the 5.4.x_DecompressingEntity_getContent_mark_reset branch from 03ed192 to 780c2bd Compare August 17, 2024 12:28
@garydgregory garydgregory merged commit 2dafdca into apache:master Aug 17, 2024
10 checks passed
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.

3 participants