[
https://issues.jboss.org/browse/JGRP-2218?page=com.atlassian.jira.plugin....
]
Bela Ban updated JGRP-2218:
---------------------------
Description:
h3. Goal
Change payload in {{Message}} from byte[] arrays to a {{Buffer}} interface which can have
multiple implementations.
h3. Motivation
Currently, having to pass a byte[] array to a message leads to unnecessary copying:
* When an application has a ref to an NIO (direct) {{ByteBuffer}}, the bytes in the byte
buffer have to be copied into a byte[] array and then set in the message
* When the application sends around byte[] arrays, but also wants to add some additional
metadata, e.g. type (1000-byte requests/responses), it needs to create a new byte[] array
of (say) 1001 bytes and copy the data (1000 bytes) plus the request type (1 byte) into the
new copy. Example: {{MPerf}} and {{UPerf}}
h3. Design
Instead of copying, the application creates an instance of {{Buffer}} and sets the buffer
in {{Message}}. The {{Buffer}} is then passed all the way down into the transport where it
is marshalled and sent. There can be a number of buffer implementations, e.g.
* {{ArrayBuffer}}: wraps a byte[] array with an offset and length
* {{NioDirectBuffer}}: wraps an NIO direct {{ByteBuffer}}
* {{NioHeapBuffer}}: wraps an NIO heap-based {{ByteBuffer}}
* {{CompositeBuffer}}: wraps multiple Buffers. E.g. type (1 byte) and data (1000 bytes) as
described above
* {{IntBuffer}}: a single integer
* {{ObjectBuffer}}: has an Object and a ClassLoader (for reading), plus a Marshaller which
know how to marshal the object, this allows for objects to be passed in buffers and
they're only marshalled at the end (transport).
* {{PartialBuffer}}: a ref to a {{Buffer}}, with an offset and length
The {{Buffer}} interface has methods:
* {{size()}}
* {{writeTo(DataOutput)}}
* {{readFrom(DataInput)}}
* {{getInput()}}: this provides a {{DataInput}} stream for reading from the underlying
buffer
and possibly also
* {{acquire()}} and
* {{release()}} (for ref-counting).
Each buffer impl has an ID and it should be possible to register new impls. A
{{BufferFactory}} maintains a mapping between IDs and impl classes.
When marshalling a {{Buffer}}, the ID is written first, followed by the buffer's
{{writeTo()}} method. When reading buffers, the {{BufferFactory}} is used to create
instances from IDs.
h4. Fragmentation
When fragmenting a buffer, the fragments are instances of {{PartialBuffer}} which
maintains an offset and length over an underlying buffer. When marshalling a
{{PartialBuffer}}, only the part between offset and offset+length is written to the output
stream.
h4. Reference counting
If we implement ref-counting, then buffers can be reused as soon as the ref-count is 0.
For example, when sending a message, the buffer's ref-count could be incremented by
the app calling {{acquire()}}. (Assuming the message is a unicast message), {{UNICAST3}}
would increment the count to 2. This is needed because {{UNICAST3}} might have to
retransmit the message if it was lost on the network, and meanwhile the buffer cannot be
reused (changed). The app calls {{release()}} when the {{JChannel.send()}} call returns,
but the buffer cannot be reused until {{UNICAST3}} calls {{release()}} as well. This will
happen when an {{ACK}} for the given message has been received.
was:
h3. Goal
Change payload in {{Message}} from byte[] arrays to a {{Buffer}} interface which can have
multiple implementations.
h3. Motivation
Currently, having to pass a byte[] array to a message leads to unnecessary copying:
* When an application has a ref to an NIO (direct) {{ByteBuffer}}, the bytes in the byte
buffer have to be copied into a byte[] array and then set in the message
* When the application sends around byte[] arrays, but also wants to add some additional
metadata, e.g. type (1000-byte requests/responses), it needs to create a new byte[] array
of (say) 1001 bytes and copy the data (1000 bytes) plus the request type (1 byte) into the
new copy. Example: {{MPerf}} and {{UPerf}}
h3. Design
Instead of copying, the application creates an instance of {{Buffer}} and sets the buffer
in {{Message}}. The {{Buffer}} is then passed all the way down into the transport where it
is marshalled and sent. There can be a number of buffer implementations, e.g.
* {{ArrayBuffer}}: wraps a byte[] array with an offset and length
* {{NioDirectBuffer}}: wraps an NIO direct {{ByteBuffer}}
* {{NioHeapBuffer}}: wraps an NIO heap-based {{ByteBuffer}}
* {{CompositeBuffer}}: wraps multiple Buffers. E.g. type (1 byte) and data (1000 bytes) as
described above
* {{IntBuffer}}: a single integer
* {{ObjectBuffer}}: has an Object and a ClassLoader (for reading), plus a Marshaller which
know how to marshal the object, this allows for objects to be passed in buffers and
they're only marshalled at the end (transport).
* {{PartialBuffer}}: a ref to a {{Buffer}}, with an offset and length
The {{Buffer}} interface has methods {{size()}}, {{writeTo(DataOutput)}},
{{readFrom(DataInput)}}, possibly also {{acquire()}} and {{release()}} (for
ref-counting).
Each buffer impl has an ID and it should be possible to register new impls. A
{{BufferFactory}} maintains a mapping between IDs and impl classes.
When marshalling a {{Buffer}}, the ID is written first, followed by the buffer's
{{writeTo()}} method. When reading buffers, the {{BufferFactory}} is used to create
instances from IDs.
h4. Fragmentation
When fragmenting a buffer, the fragments are instances of {{PartialBuffer}} which
maintains an offset and length over an underlying buffer. When marshalling a
{{PartialBuffer}}, only the part between offset and offset+length is written to the output
stream.
h4. Reference counting
If we implement ref-counting, then buffers can be reused as soon as the ref-count is 0.
For example, when sending a message, the buffer's ref-count could be incremented by
the app calling {{acquire()}}. (Assuming the message is a unicast message), {{UNICAST3}}
would increment the count to 2. This is needed because {{UNICAST3}} might have to
retransmit the message if it was lost on the network, and meanwhile the buffer cannot be
reused (changed). The app calls {{release()}} when the {{JChannel.send()}} call returns,
but the buffer cannot be reused until {{UNICAST3}} calls {{release()}} as well. This will
happen when an {{ACK}} for the given message has been received.
New buffers
-----------
Key: JGRP-2218
URL:
https://issues.jboss.org/browse/JGRP-2218
Project: JGroups
Issue Type: Feature Request
Reporter: Bela Ban
Assignee: Bela Ban
Fix For: 5.0
h3. Goal
Change payload in {{Message}} from byte[] arrays to a {{Buffer}} interface which can have
multiple implementations.
h3. Motivation
Currently, having to pass a byte[] array to a message leads to unnecessary copying:
* When an application has a ref to an NIO (direct) {{ByteBuffer}}, the bytes in the byte
buffer have to be copied into a byte[] array and then set in the message
* When the application sends around byte[] arrays, but also wants to add some additional
metadata, e.g. type (1000-byte requests/responses), it needs to create a new byte[] array
of (say) 1001 bytes and copy the data (1000 bytes) plus the request type (1 byte) into the
new copy. Example: {{MPerf}} and {{UPerf}}
h3. Design
Instead of copying, the application creates an instance of {{Buffer}} and sets the buffer
in {{Message}}. The {{Buffer}} is then passed all the way down into the transport where it
is marshalled and sent. There can be a number of buffer implementations, e.g.
* {{ArrayBuffer}}: wraps a byte[] array with an offset and length
* {{NioDirectBuffer}}: wraps an NIO direct {{ByteBuffer}}
* {{NioHeapBuffer}}: wraps an NIO heap-based {{ByteBuffer}}
* {{CompositeBuffer}}: wraps multiple Buffers. E.g. type (1 byte) and data (1000 bytes)
as described above
* {{IntBuffer}}: a single integer
* {{ObjectBuffer}}: has an Object and a ClassLoader (for reading), plus a Marshaller
which know how to marshal the object, this allows for objects to be passed in buffers and
they're only marshalled at the end (transport).
* {{PartialBuffer}}: a ref to a {{Buffer}}, with an offset and length
The {{Buffer}} interface has methods:
* {{size()}}
* {{writeTo(DataOutput)}}
* {{readFrom(DataInput)}}
* {{getInput()}}: this provides a {{DataInput}} stream for reading from the underlying
buffer
and possibly also
* {{acquire()}} and
* {{release()}} (for ref-counting).
Each buffer impl has an ID and it should be possible to register new impls. A
{{BufferFactory}} maintains a mapping between IDs and impl classes.
When marshalling a {{Buffer}}, the ID is written first, followed by the buffer's
{{writeTo()}} method. When reading buffers, the {{BufferFactory}} is used to create
instances from IDs.
h4. Fragmentation
When fragmenting a buffer, the fragments are instances of {{PartialBuffer}} which
maintains an offset and length over an underlying buffer. When marshalling a
{{PartialBuffer}}, only the part between offset and offset+length is written to the output
stream.
h4. Reference counting
If we implement ref-counting, then buffers can be reused as soon as the ref-count is 0.
For example, when sending a message, the buffer's ref-count could be incremented by
the app calling {{acquire()}}. (Assuming the message is a unicast message), {{UNICAST3}}
would increment the count to 2. This is needed because {{UNICAST3}} might have to
retransmit the message if it was lost on the network, and meanwhile the buffer cannot be
reused (changed). The app calls {{release()}} when the {{JChannel.send()}} call returns,
but the buffer cannot be reused until {{UNICAST3}} calls {{release()}} as well. This will
happen when an {{ACK}} for the given message has been received.
--
This message was sent by Atlassian JIRA
(v7.2.3#72005)