You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by jq...@apache.org on 2020/11/08 15:11:46 UTC

[flink] 05/07: [hotfix][connector/common] Add a new util class to help with serde in the Source.

This is an automated email from the ASF dual-hosted git repository.

jqin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git

commit 94b8f8f573c0ea42ae2de68e861904f5153a1924
Author: Jiangjie (Becket) Qin <ji...@alibaba-inc.com>
AuthorDate: Sat Oct 10 00:38:31 2020 +0800

    [hotfix][connector/common] Add a new util class to help with serde in the Source.
---
 .../connector/base/source/utils/SerdeUtils.java    | 131 +++++++++++++++++++++
 1 file changed, 131 insertions(+)

diff --git a/flink-connectors/flink-connector-base/src/main/java/org/apache/flink/connector/base/source/utils/SerdeUtils.java b/flink-connectors/flink-connector-base/src/main/java/org/apache/flink/connector/base/source/utils/SerdeUtils.java
new file mode 100644
index 0000000..cd43ccf
--- /dev/null
+++ b/flink-connectors/flink-connector-base/src/main/java/org/apache/flink/connector/base/source/utils/SerdeUtils.java
@@ -0,0 +1,131 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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.apache.flink.connector.base.source.utils;
+
+import org.apache.flink.api.connector.source.SourceSplit;
+import org.apache.flink.core.io.SimpleVersionedSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * A util class with some helper method for serde in the sources.
+ */
+public class SerdeUtils {
+
+	/** Private constructor for util class. */
+	private SerdeUtils() { }
+
+	/**
+	 * Serialize a mapping from subtask ids to lists of assigned splits.
+	 * The serialized format is following:
+	 * <pre>
+	 * 4 bytes - number of subtasks
+	 * 4 bytes - split serializer version
+	 * N bytes - [assignment_for_subtask]
+	 * 		4 bytes - subtask id
+	 * 		4 bytes - number of assigned splits
+	 * 		N bytes - [assigned_splits]
+	 * 			4 bytes - serialized split length
+	 * 			N bytes - serialized splits
+	 * </pre>
+	 *
+	 * @param splitAssignments a mapping from subtask ids to lists of assigned splits.
+	 * @param splitSerializer the serializer of the split.
+	 * @param <SplitT> the type of the splits.
+	 * @param <C> the type of the collection to hold the assigned splits for a subtask.
+	 * @return the serialized bytes of the given subtask to splits assignment mapping.
+	 * @throws IOException when serialization failed.
+	 */
+	public static <SplitT extends SourceSplit, C extends Collection<SplitT>> byte[] serializeSplitAssignments(
+			Map<Integer, C> splitAssignments,
+			SimpleVersionedSerializer<SplitT> splitSerializer) throws IOException {
+		try (
+				ByteArrayOutputStream baos = new ByteArrayOutputStream();
+				DataOutputStream out = new DataOutputStream(baos)) {
+
+			out.writeInt(splitAssignments.size());
+			// Split serializer version.
+			out.writeInt(splitSerializer.getVersion());
+			// Write assignments for subtasks.
+			for (Map.Entry<Integer, C> entry : splitAssignments.entrySet()) {
+				// Subtask ID
+				int subtaskId = entry.getKey();
+				Collection<SplitT> splitsForSubtask = entry.getValue();
+				// Number of the splits.
+				out.writeInt(subtaskId);
+				out.writeInt(splitsForSubtask.size());
+				for (SplitT split : splitsForSubtask) {
+					byte[] serializedSplit = splitSerializer.serialize(split);
+					out.writeInt(serializedSplit.length);
+					out.write(serializedSplit);
+				}
+			}
+			return baos.toByteArray();
+		}
+	}
+
+	/**
+	 * Deserialize the given bytes returned by {@link #serializeSplitAssignments(Map, SimpleVersionedSerializer)}.
+	 *
+	 * @param serialized the serialized bytes returned by
+	 * 					 {@link #serializeSplitAssignments(Map, SimpleVersionedSerializer)}.
+	 * @param splitSerializer the split serializer for the splits.
+	 * @param collectionSupplier the supplier for the {@link Collection} instance to hold the assigned splits for a
+	 *                           subtask.
+	 * @param <SplitT> the type of the splits.
+	 * @param <C> the type of the collection to hold the assigned splits for a subtask.
+	 * @return A mapping from subtask id to its assigned splits.
+	 * @throws IOException when deserialization failed.
+	 */
+	public static <SplitT extends SourceSplit, C extends Collection<SplitT>> Map<Integer, C> deserializeSplitAssignments(
+			byte[] serialized,
+			SimpleVersionedSerializer<SplitT> splitSerializer,
+			Function<Integer, C> collectionSupplier) throws IOException {
+		try (
+				ByteArrayInputStream bais = new ByteArrayInputStream(serialized);
+				DataInputStream in = new DataInputStream(bais)) {
+
+			int numSubtasks = in.readInt();
+			Map<Integer, C> splitsAssignments = new HashMap<>(numSubtasks);
+			int serializerVersion = in.readInt();
+			for (int i = 0; i < numSubtasks; i++) {
+				int subtaskId = in.readInt();
+				int numAssignedSplits = in.readInt();
+				C assignedSplits = collectionSupplier.apply(numAssignedSplits);
+				for (int j = 0; j < numAssignedSplits; j++) {
+					int serializedSplitSize = in.readInt();
+					byte[] serializedSplit = new byte[serializedSplitSize];
+					in.readFully(serializedSplit);
+					SplitT split = splitSerializer.deserialize(serializerVersion, serializedSplit);
+					assignedSplits.add(split);
+				}
+				splitsAssignments.put(subtaskId, assignedSplits);
+			}
+			return splitsAssignments;
+		}
+	}
+}