HDDS-14561. SCMRatisRequest/ResponseProto should use the shaded protobuf from Ratis#9733
HDDS-14561. SCMRatisRequest/ResponseProto should use the shaded protobuf from Ratis#9733Russole wants to merge 9 commits intoapache:masterfrom
Conversation
|
Thanks @szetszwo! The current change compiles and all CI checks pass: Agreed that SCMRatisRequestProto and SCMRatisResponseProto still extend Let me know if you think it makes sense to open a follow-up JIRA for generating |
| UnsafeByteOperations.unsafeWrap( | ||
| requestProto.toByteString().asReadOnlyByteBuffer())); |
There was a problem hiding this comment.
@Russole , I see how this change works now -- it does prevent copying to an array but still needs type conversion from com.google.protobuf.ByteString to org.apache.ratis.thirdparty.com.google.protobuf.ByteString.
Let's fix also the conversion in this JIRA; see ContainerCommandRequestProto as an example for how to do it.
There was a problem hiding this comment.
unsafeWrap is not needed anymore.
return Message.valueOf(requestProto.toByteString());|
Thanks for the clarification! I’m working on this now. I see the issue with the remaining type conversion between I’ll update the PR once this is addressed. |
szetszwo
left a comment
There was a problem hiding this comment.
@Russole , thanks for the great work! I believe that you have spent a lot time on this.
Please see the comments inlined and also https://issues.apache.org/jira/secure/attachment/13080780/9733_review.patch
| if (object instanceof ByteString) { | ||
| return (ByteString) object; | ||
| } | ||
| if (object instanceof com.google.protobuf.ByteString) { |
There was a problem hiding this comment.
Do we still need to keep supporting com.google.protobuf.ByteString? Should everything used in SCM Codec have changed to org.apache.ratis.thirdparty.com.google.protobuf.ByteString after this PR?
| codecs.put(com.google.protobuf.ByteString.class, new ByteStringCodec()); | ||
| codecs.put(org.apache.ratis.thirdparty.com.google.protobuf.ByteString.class, |
There was a problem hiding this comment.
If com.google.protobuf.ByteString is still needed,
- Add a new class, say ScmByteStringCodec, for org.apache.ratis.thirdparty.com.google.protobuf.ByteString.
- import org.apache.ratis.thirdparty.com.google.protobuf.ByteString.
codecs.put(com.google.protobuf.ByteString.class, new ByteStringCodec());
codecs.put(ByteString.class, new ScmByteStringCodec());If com.google.protobuf.ByteString is not needed, just remove it.
| // toByteArray returns a new array | ||
| return ProtoUtils.unsafeByteString(Ints.toByteArray( | ||
| ((ProtocolMessageEnum) object).getNumber())); | ||
| return UnsafeByteOperations.unsafeWrap(Ints.toByteArray(((ProtocolMessageEnum) object).getNumber())); |
|
|
||
| @Override | ||
| public ByteString serialize(Object object) { | ||
| return ((Message)object).toByteString(); |
There was a problem hiding this comment.
Do we need to support both com.google.protobuf.Message and org.apache.ratis.thirdparty.com.google.protobuf.Message?
If yes, use two GeneratedMessageCodec classes instead of using one class. Also, we need to put them to CodecFactory.
//CodecFactory
codecs.put(com.google.protobuf.Message.class, new GeneratedMessageCodec());
codecs.put(Message.class, new ScmGeneratedMessageCodec());| throw new org.apache.ratis.thirdparty.com.google.protobuf.InvalidProtocolBufferException( | ||
| e.getMessage()); |
There was a problem hiding this comment.
Let's include the type in the message and use e as the cause (it will keep e's stack trace.)
throw new InvalidProtocolBufferException("Failed to deserialize value for " + type, e);| UnsafeByteOperations.unsafeWrap( | ||
| requestProto.toByteString().asReadOnlyByteBuffer())); |
There was a problem hiding this comment.
unsafeWrap is not needed anymore.
return Message.valueOf(requestProto.toByteString());| private static byte[] bytesOf(com.google.protobuf.ByteString b) { | ||
| return b.toByteArray(); | ||
| } | ||
|
|
||
| private static byte[] bytesOf(org.apache.ratis.thirdparty.com.google.protobuf.ByteString b) { | ||
| return b.toByteArray(); | ||
| } |
There was a problem hiding this comment.
Use the following assertByteStringEquals and remove the bytesOf methods.
private static void assertByteStringEquals(com.google.protobuf.ByteString proto2, ByteString proto3) {
assertEquals(UnsafeByteOperations.unsafeWrap(proto2.asReadOnlyByteBuffer()), proto3);
}| private static String shortDebugStringProto2( | ||
| com.google.protobuf.MessageOrBuilder msg) { | ||
| return com.google.protobuf.TextFormat.shortDebugString(msg); | ||
| } | ||
|
|
||
| private static String shortDebugStringProto3( | ||
| org.apache.ratis.thirdparty.com.google.protobuf.MessageOrBuilder msg) { | ||
| return org.apache.ratis.thirdparty.com.google.protobuf.TextFormat.shortDebugString(msg); | ||
| } |
There was a problem hiding this comment.
Use assertShortDebugString below:
private static void assertShortDebugString(com.google.protobuf.MessageOrBuilder proto2,
org.apache.ratis.thirdparty.com.google.protobuf.MessageOrBuilder proto3) {
assertEquals(com.google.protobuf.TextFormat.shortDebugString(proto2),
org.apache.ratis.thirdparty.com.google.protobuf.TextFormat.shortDebugString(proto3));
}| when(reply.getMessage()).thenReturn(Message.valueOf( | ||
| org.apache.ratis.thirdparty.com.google.protobuf.ByteString.copyFrom( | ||
| proto.toByteArray()))); | ||
| org.apache.ratis.thirdparty.com.google.protobuf.UnsafeByteOperations |
There was a problem hiding this comment.
import UnsafeByteOperations.
| Message msg = Message.valueOf( | ||
| org.apache.ratis.thirdparty.com.google.protobuf.ByteString.copyFrom( | ||
| proto.toByteArray())); | ||
| org.apache.ratis.thirdparty.com.google.protobuf.UnsafeByteOperations |
There was a problem hiding this comment.
import UnsafeByteOperations.
|
Thanks @szetszwo for the detailed review and the patch. I really appreciate your time and guidance. |
| final byte[] bytes = ((Message) object).toByteString().toByteArray(); | ||
| return ByteString.copyFrom(bytes); |
There was a problem hiding this comment.
Use unsafeWarp as below?
UnsafeByteOperations.unsafeWrap(((Message) object).toByteString().asReadOnlyByteBuffer());| public Message deserialize(Class<?> type, ByteString value) | ||
| throws InvalidProtocolBufferException { | ||
| public Object deserialize(Class<?> type, ByteString value) | ||
| throws org.apache.ratis.thirdparty.com.google.protobuf.InvalidProtocolBufferException { |
There was a problem hiding this comment.
Keep throws InvalidProtocolBufferException since the import is changed.
| static final Class<?>[] TYPES = {String.class, Integer.class, byte[].class}; | ||
|
|
||
| static <T> ByteString randomValue(Class<T> clazz) { | ||
| static <T> org.apache.ratis.thirdparty.com.google.protobuf.ByteString randomValueProto3(Class<T> clazz) { |
There was a problem hiding this comment.
ByteString is already imported.
| return org.apache.ratis.thirdparty.com.google.protobuf.ByteString.copyFromUtf8(string); | ||
| } else if (clazz == Integer.class) { | ||
| final ByteBuffer buffer = ByteBuffer.allocate(4); | ||
| buffer.putInt(RANDOM.nextInt()); | ||
| return ByteString.copyFrom(buffer.array()); | ||
| return org.apache.ratis.thirdparty.com.google.protobuf.ByteString.copyFrom(buffer.array()); | ||
| } else if (clazz == byte[].class) { | ||
| final byte[] bytes = new byte[RANDOM.nextInt(3)]; | ||
| RANDOM.nextBytes(bytes); | ||
| return ByteString.copyFrom(bytes); | ||
| return org.apache.ratis.thirdparty.com.google.protobuf.ByteString.copyFrom(bytes); |
There was a problem hiding this comment.
ByteString is already imported.
| @@ -145,8 +145,8 @@ public void testDecodeMissingMethodNameShouldFail() throws Exception { | |||
| .build(); | |||
|
|
|||
| Message msg = Message.valueOf( | |||
| org.apache.ratis.thirdparty.com.google.protobuf.ByteString.copyFrom( | |||
| proto.toByteArray())); | |||
| org.apache.ratis.thirdparty.com.google.protobuf.UnsafeByteOperations | |||
| .unsafeWrap(proto.toByteString().asReadOnlyByteBuffer())); | |||
|
|
|||
| InvalidProtocolBufferException ex = assertThrows( | |||
| InvalidProtocolBufferException.class, | |||
| @@ -173,8 +173,8 @@ public void testDecodeMissingArgumentTypeShouldFail() throws Exception { | |||
| .build(); | |||
|
|
|||
| Message msg = Message.valueOf( | |||
| org.apache.ratis.thirdparty.com.google.protobuf.ByteString.copyFrom( | |||
| proto.toByteArray())); | |||
| org.apache.ratis.thirdparty.com.google.protobuf.UnsafeByteOperations | |||
There was a problem hiding this comment.
import UnsafeByteOperations.
| public Object deserialize(Class<?> type, ByteString value) | ||
| throws InvalidProtocolBufferException { | ||
| return value; | ||
| return com.google.protobuf.ByteString.copyFrom(value.toByteArray()); |
There was a problem hiding this comment.
Use com.google.protobuf.UnsafeByteOperations.
What changes were proposed in this pull request?
to use Ratis shaded protobuf (
ByteString/ByteBuffer) at the transport boundary.byte[]conversions in the SCM Ratis message path.implementation.
What is the link to the Apache JIRA
https://issues.apache.org/jira/browse/HDDS-14561
How was this patch tested?