-
Notifications
You must be signed in to change notification settings - Fork 322
Add ByteBuffer input support again #377
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| // | ||
| // MessagePack for Java | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
| // | ||
| package org.msgpack.core.buffer; | ||
|
|
||
| import java.io.IOException; | ||
| import java.nio.ByteBuffer; | ||
|
|
||
| import static org.msgpack.core.Preconditions.checkNotNull; | ||
|
|
||
| /** | ||
| * {@link MessageBufferInput} adapter for {@link java.nio.ByteBuffer} | ||
| */ | ||
| public class ByteBufferInput | ||
| implements MessageBufferInput | ||
| { | ||
| private ByteBuffer input; | ||
| private boolean isRead = false; | ||
|
|
||
| public ByteBufferInput(ByteBuffer input) | ||
| { | ||
| this.input = checkNotNull(input, "input ByteBuffer is null"); | ||
| } | ||
|
|
||
| /** | ||
| * Reset buffer. This method doesn't close the old resource. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| * | ||
| * @param input new buffer | ||
| * @return the old resource | ||
| */ | ||
| public ByteBuffer reset(ByteBuffer input) | ||
| { | ||
| ByteBuffer old = this.input; | ||
| this.input = input; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same with above: |
||
| isRead = false; | ||
| return old; | ||
| } | ||
|
|
||
| @Override | ||
| public MessageBuffer next() | ||
| throws IOException | ||
| { | ||
| if (isRead) { | ||
| return null; | ||
| } | ||
|
|
||
| isRead = true; | ||
| return MessageBuffer.wrap(input); | ||
| } | ||
|
|
||
| @Override | ||
| public void close() | ||
| throws IOException | ||
| { | ||
| // Nothing to do | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,6 +43,7 @@ public class MessageBuffer | |
| * Reference to MessageBuffer Constructors | ||
| */ | ||
| private static final Constructor<?> mbArrConstructor; | ||
| private static final Constructor<?> mbBBConstructor; | ||
|
|
||
| /** | ||
| * The offset from the object memory header to its byte array data | ||
|
|
@@ -145,6 +146,11 @@ public class MessageBuffer | |
| Constructor<?> mbArrCstr = bufferCls.getDeclaredConstructor(byte[].class, int.class, int.class); | ||
| mbArrCstr.setAccessible(true); | ||
| mbArrConstructor = mbArrCstr; | ||
|
|
||
| // MessageBufferX(ByteBuffer) constructor | ||
| Constructor<?> mbBBCstr = bufferCls.getDeclaredConstructor(ByteBuffer.class); | ||
| mbBBCstr.setAccessible(true); | ||
| mbBBConstructor = mbBBCstr; | ||
| } | ||
| catch (Exception e) { | ||
| e.printStackTrace(System.err); | ||
|
|
@@ -170,6 +176,12 @@ public class MessageBuffer | |
| */ | ||
| protected final int size; | ||
|
|
||
| /** | ||
| * Reference is used to hold a reference to an object that holds the underlying memory so that it cannot be | ||
| * released by the garbage collector. | ||
| */ | ||
| protected final ByteBuffer reference; | ||
|
|
||
| public static MessageBuffer allocate(int length) | ||
| { | ||
| return wrap(new byte[length]); | ||
|
|
@@ -185,6 +197,11 @@ public static MessageBuffer wrap(byte[] array, int offset, int length) | |
| return newMessageBuffer(array, offset, length); | ||
| } | ||
|
|
||
| public static MessageBuffer wrap(ByteBuffer bb) | ||
| { | ||
| return newMessageBuffer(bb).slice(bb.position(), bb.remaining()); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a new MessageBuffer instance backed by a java heap array | ||
| * | ||
|
|
@@ -202,11 +219,32 @@ private static MessageBuffer newMessageBuffer(byte[] arr, int off, int len) | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Creates a new MessageBuffer instance backed by ByteBuffer | ||
| * | ||
| * @param bb | ||
| * @return | ||
| */ | ||
| private static MessageBuffer newMessageBuffer(ByteBuffer bb) | ||
| { | ||
| checkNotNull(bb); | ||
| try { | ||
| // We need to use reflection to create MessageBuffer instances in order to prevent TypeProfile generation for getInt method. TypeProfile will be | ||
| // generated to resolve one of the method references when two or more classes overrides the method. | ||
| return (MessageBuffer) mbBBConstructor.newInstance(bb); | ||
| } catch (Exception e) { | ||
| throw new RuntimeException(e); | ||
| } | ||
| } | ||
|
|
||
| public static void releaseBuffer(MessageBuffer buffer) | ||
| { | ||
| if (isUniversalBuffer || buffer.base instanceof byte[]) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @xerial I think that type of
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @frsyuki If we never use this class for reading
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see...but I think it's too early to think about it. Exception handling becomes more complicated with consideration of long[] there.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2GB is not so huge, so we should think about it if we are going to support huge message pack based DataFrame in memory. The index of getXXX(index) is using int, so we already have a technical limit of the accessible buffer range, but this should not limit the underlying buffer size; if we use |
||
| // We have nothing to do. Wait until the garbage-collector collects this array object | ||
| } | ||
| else if (DirectBufferAccess.isDirectByteBufferInstance(buffer.base)) { | ||
| DirectBufferAccess.clean(buffer.base); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @miniway shouldn't this be
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch! it should be the |
||
| } | ||
| else { | ||
| // Maybe cannot reach here | ||
| unsafe.freeMemory(buffer.address); | ||
|
|
@@ -225,13 +263,43 @@ public static void releaseBuffer(MessageBuffer buffer) | |
| this.base = arr; | ||
| this.address = ARRAY_BYTE_BASE_OFFSET + offset; | ||
| this.size = length; | ||
| this.reference = null; | ||
| } | ||
|
|
||
| /** | ||
| * Create a MessageBuffer instance from a given ByteBuffer instance | ||
| * | ||
| * @param bb | ||
| */ | ||
| MessageBuffer(ByteBuffer bb) | ||
| { | ||
| if (bb.isDirect()) { | ||
| if (isUniversalBuffer) { | ||
| throw new IllegalStateException("Cannot create MessageBuffer from DirectBuffer"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's include "on this platform" in the message so that people don't think it's not MessagePack's fault... |
||
| } | ||
| // Direct buffer or off-heap memory | ||
| this.base = null; | ||
| this.address = DirectBufferAccess.getAddress(bb); | ||
| this.size = bb.capacity(); | ||
| this.reference = bb; | ||
| } | ||
| else if (bb.hasArray()) { | ||
| this.base = bb.array(); | ||
| this.address = ARRAY_BYTE_BASE_OFFSET; | ||
| this.size = bb.array().length; | ||
| this.reference = null; | ||
| } | ||
| else { | ||
| throw new IllegalArgumentException("Only the array-backed ByteBuffer or DirectBuffer are supported"); | ||
| } | ||
| } | ||
|
|
||
| protected MessageBuffer(Object base, long address, int length) | ||
| { | ||
| this.base = base; | ||
| this.address = address; | ||
| this.size = length; | ||
| this.reference = null; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -393,6 +461,11 @@ else if (src.hasArray()) { | |
| } | ||
| } | ||
|
|
||
| public void putMessageBuffer(int index, MessageBuffer src, int srcOffset, int len) | ||
| { | ||
| unsafe.copyMemory(src.base, src.address + srcOffset, base, address + index, len); | ||
| } | ||
|
|
||
| /** | ||
| * Create a ByteBuffer view of the range [index, index+length) of this memory | ||
| * | ||
|
|
@@ -402,7 +475,13 @@ else if (src.hasArray()) { | |
| */ | ||
| public ByteBuffer sliceAsByteBuffer(int index, int length) | ||
| { | ||
| return ByteBuffer.wrap((byte[]) base, (int) ((address - ARRAY_BYTE_BASE_OFFSET) + index), length); | ||
| if (hasArray()) { | ||
| return ByteBuffer.wrap((byte[]) base, (int) ((address - ARRAY_BYTE_BASE_OFFSET) + index), length); | ||
| } | ||
| else { | ||
| assert (!isUniversalBuffer); | ||
| return DirectBufferAccess.newByteBuffer(address, index, length, reference); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -415,6 +494,11 @@ public ByteBuffer sliceAsByteBuffer() | |
| return sliceAsByteBuffer(0, size()); | ||
| } | ||
|
|
||
| public boolean hasArray() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
| { | ||
| return base instanceof byte[]; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how about using
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer |
||
| } | ||
|
|
||
| /** | ||
| * Get a copy of this buffer | ||
| * | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is better to call
slice()as following to avoid this unexpected scenario:ByteBufferInputwith the ByteBuffer