msgpack-value v07 API by xerial · Pull Request #109 · msgpack/msgpack-java

@xerial Thank you for the explication. Overall, I agree with you.
I think we need only one mutable Value implementation called ValueBuffer because:

  • A purpose to have mutable value is removing overhead to create a new Value instance when we unpack a value.
  • Value should be able to be any types (including array and map) because Unpacker can unpack any types.
  • Current holder/cursor implementations (FloatHolder, RawHolder, ArrayCursor, etc.) can't be different types. We need to create a new value if unpacked type different from an expected type.

My draft code implemented this idea: https://github.com/msgpack/msgpack-java/blob/v07-value-sf/msgpack-value/src/main/java/org/msgpack/value/ValueBuffer.java

A difficulty is reusing nested values to store nested elements of a array and map Value.
For example, in my draft code above, ValueBuffer needs only one ValueUnion when it stores an integer value. However, it needs multiple ValueUnion instances for each element when it stores an array value (because valueBuffer.asArrayValue().get(i) returns Value). This is an essential problem because the same problem anyways happens to deserialize nested values

A known solution is to use an object pool (ValueBufferPool). Another difficulty here is the timing to reuse nested elements. A solution is to add ValueBuffer.release(). These ideas need following complex interfaces:

  • interface ValueBufferAllocator
    • ValueBuffer allocate()
  • interface ValueBufferDeallocator
    • void deallocate(ValueBuffer unused)
  • class ValueBufferPool implements ValueBufferAllocator, ValueBufferDeallocator
  • ValueBuffer.(ValueBufferAllocator allocateFrom, ValueBufferDeallocator releaseTo)
    • ValueBuffer.() will creates a new ValueBufferPool
    • void release() { valueBufferDeallocator.deallocate(this); }
      • this could be reference-counted like Netty's ByteBuf. But could be non-reference-counted like Jetty's ByteBufferPool. I think reference-counting causes too much overhead when the value is a deeply nested map/array.

You may have another idea.