- All Implemented Interfaces:
Closeable, Flushable, AutoCloseable
MessageOutputStream.DataReceiver in chunks upon buffer full or flush. Provides throttling and blocking behavior according to the data receiver's needs.This class maintains an internal buffer with configurable size limits, supports resizing the buffer size during operation (only effective when buffer is empty), and allows passive flushes after inactivity delays to avoid excessive buffering.
MessageOutputStream -> ConnectionDataReceiver -> Connection -> PacketQueue -> I2PSession
Thread safety: - Write operations synchronize on an internal data lock when manipulating the buffer. - Waiting for buffer acceptance and completion is done outside synchronization to avoid blocking other threads.
Performance: - Uses a shared ByteCache for buffer byte arrays to reduce allocations. - Supports a passive flush mechanism to flush buffered data after inactivity. - Minimizes locking time by doing blocking waits outside of synchronized blocks.
Note: - Buffer resizing only affects the max size used to determine flush boundaries, buffer reallocation does not occur dynamically. - Stream errors are captured and thrown upon subsequent I/O calls. - Interruptions during wait throw InterruptedIOException accordingly. - Close() flushes any remaining data and releases internal buffers.
Nested Class Summary
Modifier and TypeClassDescriptionstatic interfaceInterface for receiving data flushed from this stream.private classPassive flush timer to flush buffered data after inactivity delay.static interfaceInterface to detect status of an asynchronous write operation.Field Summary
FieldsModifier and TypeFieldDescriptionprivate byte[]The buffer accumulating the written data.private final AtomicBooleanTrue once the stream is closed.private final I2PAppContextThe app context.private intBuffer size in use now.private final ByteCacheCache supplying the write buffer.private final ObjectLock for the write buffer.private final MessageOutputStream.DataReceiverThe connection receiving the data.private final MessageOutputStream.FlusherFlusher that sends buffered data after a period of inactivity.private longTimestamp of the most recently buffered data, in context clock ms.private final LogLogger for the output stream.private intBuffer size requested by the next flush, updated when buffer drains.private final byte[]Reusable buffer for single byte writes, guarded by _oneByteLock, not _dataLock.private final ObjectLock for the single byte writes.private final intBuffer size requested at construction, the two sizes control when the buffer is flushed.private intDelay in milliseconds before a passive flush is triggered.private final AtomicReference<IOException> The stream error, kept to rethrow on the next call.private intValid bytes held in the buffer.private intBlocking write timeout, in ms, -1 for no timeout.private longTotal bytes written to the connection since creation.private static intDefault passive flush delay optimized for lower latency while maintaining stability: 200 ms on a slow system, 100 ms otherwise.Constructor Summary
ConstructorsConstructorDescriptionMessageOutputStream(I2PAppContext ctx, SimpleTimer2 timer, MessageOutputStream.DataReceiver receiver, int bufSize, int initBufSize) Stream with default passive flush delay.MessageOutputStream(I2PAppContext ctx, SimpleTimer2 timer, MessageOutputStream.DataReceiver receiver, int bufSize, int initBufSize, int passiveFlushDelay) Stream with specified passive flush delay.Method Summary
Modifier and TypeMethodDescriptionprivate voidclearData(boolean shouldFlush) Clears any buffered data, optionally flushing it out first.voidclose()Closes the stream, flushing all buffered data and waiting for any CLOSE packet acknowledgments.(package private) voidNon-blocking internal close used within the package.(package private) voiddestroy()Releases resources without flushing.voidflush()Flushes buffered data, blocking until accepted into the send queue.private voidflush(boolean waitForAcceptOnly) Flush implementation allowing control over wait behavior.(package private) voidConvenience overload variant with blocking flush.(package private) voidflushAvailable(MessageOutputStream.DataReceiver target, boolean blocking) Attempts to flush buffered data to the target DataReceiver, optionally blocking until accepted.booleanReturns true if the stream is closed.static intRead the passive flush delay applied when a caller does not name one.intCurrent passive flush delay.intCurrent write timeout.private final intUpdates the current buffer size if a new size has been requested.voidsetBufferSize(int size) Requests resizing the buffer to the specified size.static voidsetDefaultPassiveFlushDelay(int val) Set the passive flush delay used when a caller does not name one.voidsetPassiveFlushDelay(int delayMs) Dynamically adjust the passive flush delay.voidsetWriteTimeout(int ms) Write timeout in milliseconds for blocking write operations.(package private) voidRecords a stream error and clears buffered data.private voidThrows any stored stream error and clears the error.voidwrite(byte[] b) Writes the specified byte array to the stream, may block waiting for acceptance.voidwrite(byte[] b, int off, int len) Writes len bytes from the specified byte array starting at offset off.voidwrite(int b) Writes a single byte to the stream.Methods inherited from class OutputStream
nullOutputStream
Field Details
_context
The app context._log
Logger for the output stream._buf
private byte[] _bufThe buffer accumulating the written data._valid
private int _validValid bytes held in the buffer._dataLock
Lock for the write buffer._oneByte
private final byte[] _oneByteReusable buffer for single byte writes, guarded by _oneByteLock, not _dataLock._oneByteLock
Lock for the single byte writes._dataReceiver
The connection receiving the data._streamError
The stream error, kept to rethrow on the next call._closed
True once the stream is closed._written
private long _writtenTotal bytes written to the connection since creation._writeTimeout
private volatile int _writeTimeoutBlocking write timeout, in ms, -1 for no timeout._dataCache
Cache supplying the write buffer._originalBufferSize
private final int _originalBufferSizeBuffer size requested at construction, the two sizes control when the buffer is flushed._currentBufferSize
private int _currentBufferSizeBuffer size in use now._nextBufferSize
private volatile int _nextBufferSizeBuffer size requested by the next flush, updated when buffer drains._flusher
Flusher that sends buffered data after a period of inactivity._lastBuffered
private volatile long _lastBufferedTimestamp of the most recently buffered data, in context clock ms._passiveFlushDelay
private volatile int _passiveFlushDelayDelay in milliseconds before a passive flush is triggered.defaultPassiveFlushDelay
private static volatile int defaultPassiveFlushDelayDefault passive flush delay optimized for lower latency while maintaining stability: 200 ms on a slow system, 100 ms otherwise.
Constructor Details
MessageOutputStream
public MessageOutputStream(I2PAppContext ctx, SimpleTimer2 timer, MessageOutputStream.DataReceiver receiver, int bufSize, int initBufSize) Stream with default passive flush delay.- Parameters:
ctx- Application context for logging and utilitiestimer- Timer used for scheduling passive flush eventsreceiver- DataReceiver that handles actual data dispatchbufSize- Maximum buffer size allowed (will be clamped to preset max values)initBufSize- Initial buffer size to use for buffering (<= bufSize)
MessageOutputStream
public MessageOutputStream(I2PAppContext ctx, SimpleTimer2 timer, MessageOutputStream.DataReceiver receiver, int bufSize, int initBufSize, int passiveFlushDelay) Stream with specified passive flush delay.- Parameters:
ctx- Application context for logging and utilitiestimer- Timer used for scheduling passive flush eventsreceiver- DataReceiver that handles actual data dispatchbufSize- Maximum buffer size allowed (will be clamped for safety)initBufSize- Initial buffer size to use for buffering (<= bufSize)passiveFlushDelay- Delay in ms before passive flush if data is buffered but not flushed
Method Details
getDefaultPassiveFlushDelay
public static int getDefaultPassiveFlushDelay()Read the passive flush delay applied when a caller does not name one.- Returns:
- the flush delay in milliseconds used when none is specified
setDefaultPassiveFlushDelay
public static void setDefaultPassiveFlushDelay(int val) Set the passive flush delay used when a caller does not name one.- Parameters:
val- requested flush delay in milliseconds, clamped to the range 10 - 500
setWriteTimeout
public void setWriteTimeout(int ms) Write timeout in milliseconds for blocking write operations.- Parameters:
ms- Timeout in milliseconds, -1 for infinite wait.
getWriteTimeout
public int getWriteTimeout()Current write timeout.- Returns:
- write timeout in milliseconds
getPassiveFlushDelay
public int getPassiveFlushDelay()Current passive flush delay.- Returns:
- current passive flush delay in ms
setPassiveFlushDelay
public void setPassiveFlushDelay(int delayMs) Dynamically adjust the passive flush delay. Clamped to [10, 500]. Used by the interactive profile to reduce flush latency mid-connection.- Parameters:
delayMs- new delay, will be clamped to valid range
setBufferSize
public void setBufferSize(int size) Requests resizing the buffer to the specified size. Effective only when the internal buffer is empty, and must be > 0 and <= the original max buffer size. Does not immediately resize the underlying byte array.- Parameters:
size- New desired buffer size, must be positive and no greater than original buffer size.
write
Writes the specified byte array to the stream, may block waiting for acceptance.- Overrides:
writein classOutputStream- Parameters:
b- byte array to write- Throws:
IOException- if the stream is closed or write fails
write
Writes len bytes from the specified byte array starting at offset off. Blocks if buffer becomes full waiting for acceptance.- Overrides:
writein classOutputStream- Parameters:
b- byte array sourceoff- start offset in arraylen- number of bytes to write- Throws:
IOException- if the stream is closed or write fails
write
Writes a single byte to the stream.- Specified by:
writein classOutputStream- Parameters:
b- byte to write (only least significant 8 bits used)- Throws:
IOException- if the stream is closed or write fails
locked_updateBufferSize
private final int locked_updateBufferSize()Updates the current buffer size if a new size has been requested. This occurs only when the buffer is empty to avoid data loss.- Returns:
- the effective current buffer size
flush
Flushes buffered data, blocking until accepted into the send queue. Does not wait for ACK from far end, to avoid performance bottlenecks.- Specified by:
flushin interfaceFlushable- Overrides:
flushin classOutputStream- Throws:
IOException- if flushing encounters an error
flush
Flush implementation allowing control over wait behavior.- Parameters:
waitForAcceptOnly- true to wait only for buffer acceptance, false to wait for full completion (ACK)- Throws:
IOException- if flushing fails or is interrupted
close
Closes the stream, flushing all buffered data and waiting for any CLOSE packet acknowledgments.- Specified by:
closein interfaceAutoCloseable- Specified by:
closein interfaceCloseable- Overrides:
closein classOutputStream- Throws:
IOException- if closing encounters an error
closeInternal
void closeInternal()Non-blocking internal close used within the package. Does not wait for flush or acknowledgment. Marks the stream as closed and pushes any buffered data out fire-and-forget, so a connection closed right after a write does not lose the application's last bytes.clearData
private void clearData(boolean shouldFlush) Clears any buffered data, optionally flushing it out first.- Parameters:
shouldFlush- if true, send the buffered data (but do not wait for acknowledgment); if false, discard it. The error path discards, the close path flushes.
getClosed
public boolean getClosed()Returns true if the stream is closed.- Returns:
- true if closed
throwAnyError
Throws any stored stream error and clears the error.- Throws:
IOException- if a stream error has occurred
streamErrorOccurred
Records a stream error and clears buffered data.- Parameters:
ioe- The IOException to record
flushAvailable
Attempts to flush buffered data to the target DataReceiver, optionally blocking until accepted.- Parameters:
target- the destination DataReceiverblocking- whether the flush should block until accepted- Throws:
IOException- if the flush fails or is interrupted
flushAvailable
Convenience overload variant with blocking flush.- Parameters:
target- DataReceiver to flush to- Throws:
IOException- if flush fails or interrupted
destroy
void destroy()Releases resources without flushing.