-
-
Notifications
You must be signed in to change notification settings - Fork 202
BE: Serde: Impl MM2 serdes #1381
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
Merged
Merged
Changes from 3 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
844e34e
Impl HeartbeatSerde
Haarolean 496aa43
Impl OffsetSyncSerde
Haarolean 13c951f
Impl CheckpointSerde
Haarolean c25604b
lint
Haarolean de52924
Change result type from string to json in appropriate cases
Haarolean 6146073
Impl tests
Haarolean fc59e6b
Logs
Haarolean 267d52d
Split k/v methods
Haarolean 89ca82c
Upd fields visibility
Haarolean 1ea2aa6
Auto register serdes for well known topic patterns
Haarolean 9c987ef
Simplify serialization
Haarolean 7e25c7c
Reduced duplicate code
germanosin c5cb67d
Reduced duplicate code
germanosin 40760ca
Reduced duplicate code
germanosin 68a8a26
Reduced duplicate code
germanosin dfa9cbb
Reduced duplicate code
germanosin 6b2431c
Reduced duplicate code
germanosin 35f6c08
Reduced duplicate code
germanosin 3ed9d82
Merge branch 'main' into issues/444-mm2-serdes
germanosin 435c4fd
Fix typos
Haarolean f510fbd
Add prefix to serde names
Haarolean File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
api/src/main/java/io/kafbat/ui/serdes/builtin/mm2/CheckpointSerde.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| package io.kafbat.ui.serdes.builtin.mm2; | ||
|
|
||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import io.kafbat.ui.serde.api.DeserializeResult; | ||
| import io.kafbat.ui.serde.api.SchemaDescription; | ||
| import io.kafbat.ui.serdes.BuiltInSerde; | ||
| import java.nio.ByteBuffer; | ||
| import java.util.Map; | ||
| import java.util.Optional; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.apache.kafka.common.protocol.types.Field; | ||
| import org.apache.kafka.common.protocol.types.Schema; | ||
| import org.apache.kafka.common.protocol.types.Struct; | ||
| import org.apache.kafka.common.protocol.types.Type; | ||
|
|
||
| @Slf4j | ||
| public class CheckpointSerde implements BuiltInSerde { | ||
|
|
||
| private final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); | ||
|
|
||
| public static final String TOPIC_KEY = "topic"; | ||
| public static final String PARTITION_KEY = "partition"; | ||
| public static final String CONSUMER_GROUP_ID_KEY = "group"; | ||
| public static final String UPSTREAM_OFFSET_KEY = "upstreamOffset"; | ||
| public static final String DOWNSTREAM_OFFSET_KEY = "offset"; | ||
| public static final String METADATA_KEY = "metadata"; | ||
| public static final String VERSION_KEY = "version"; | ||
| public static final short VERSION = 0; | ||
|
|
||
| public static final Schema VALUE_SCHEMA_V0 = new Schema( | ||
| new Field(UPSTREAM_OFFSET_KEY, Type.INT64), | ||
| new Field(DOWNSTREAM_OFFSET_KEY, Type.INT64), | ||
| new Field(METADATA_KEY, Type.STRING)); | ||
|
|
||
| public static final Schema KEY_SCHEMA = new Schema( | ||
| new Field(CONSUMER_GROUP_ID_KEY, Type.STRING), | ||
| new Field(TOPIC_KEY, Type.STRING), | ||
| new Field(PARTITION_KEY, Type.INT32)); | ||
|
|
||
| public static final Schema HEADER_SCHEMA = new Schema( | ||
| new Field(VERSION_KEY, Type.INT16)); | ||
|
|
||
| public static String name() { | ||
| return "Checkpoint"; | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<String> getDescription() { | ||
| return Optional.empty(); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<SchemaDescription> getSchema(String topic, Target type) { | ||
| return Optional.empty(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean canDeserialize(String topic, Target type) { | ||
| return true; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean canSerialize(String topic, Target type) { | ||
| return false; | ||
| } | ||
|
|
||
| @Override | ||
| public Serializer serializer(String topic, Target type) { | ||
| throw new UnsupportedOperationException(); | ||
| } | ||
|
|
||
| @Override | ||
| public Deserializer deserializer(String topic, Target target) { | ||
| return (recordHeaders, bytes) -> switch (target) { | ||
|
|
||
| case KEY: { | ||
| Struct keyStruct = KEY_SCHEMA.read(ByteBuffer.wrap(bytes)); | ||
|
|
||
| String group = keyStruct.getString(CONSUMER_GROUP_ID_KEY); | ||
| String t = keyStruct.getString(TOPIC_KEY); | ||
| int partition = keyStruct.getInt(PARTITION_KEY); | ||
|
|
||
| var map = Map.of( | ||
Haarolean marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| CONSUMER_GROUP_ID_KEY, group, | ||
| TOPIC_KEY, t, | ||
| PARTITION_KEY, partition | ||
| ); | ||
|
|
||
| try { | ||
| var result = OBJECT_MAPPER.writeValueAsString(map); | ||
| yield new DeserializeResult(result, DeserializeResult.Type.STRING, Map.of()); | ||
Haarolean marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } catch (JsonProcessingException e) { | ||
| log.error("Error serializing record", e); | ||
| throw new RuntimeException(e); | ||
Haarolean marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
|
|
||
| case VALUE: { | ||
| ByteBuffer value = ByteBuffer.wrap(bytes); | ||
| Struct header = HEADER_SCHEMA.read(value); | ||
| short version = header.getShort(VERSION_KEY); | ||
| Schema valueSchema = valueSchema(version); | ||
| Struct valueStruct = valueSchema.read(value); | ||
|
|
||
| long upstreamOffset = valueStruct.getLong(UPSTREAM_OFFSET_KEY); | ||
| long downstreamOffset = valueStruct.getLong(DOWNSTREAM_OFFSET_KEY); | ||
| String metadata = valueStruct.getString(METADATA_KEY); | ||
|
|
||
| var map = Map.of( | ||
| UPSTREAM_OFFSET_KEY, upstreamOffset, | ||
| DOWNSTREAM_OFFSET_KEY, downstreamOffset, | ||
| METADATA_KEY, metadata | ||
| ); | ||
|
|
||
| try { | ||
| var result = OBJECT_MAPPER.writeValueAsString(map); | ||
| yield new DeserializeResult(result, DeserializeResult.Type.STRING, Map.of()); | ||
| } catch (JsonProcessingException e) { | ||
| log.error("Error serializing record", e); | ||
| throw new RuntimeException(e); | ||
| } | ||
| } | ||
|
|
||
| }; | ||
| } | ||
|
|
||
| private static Schema valueSchema(short version) { | ||
| assert version == 0; | ||
| return VALUE_SCHEMA_V0; | ||
| } | ||
|
|
||
| } | ||
106 changes: 106 additions & 0 deletions
106
api/src/main/java/io/kafbat/ui/serdes/builtin/mm2/HeartbeatSerde.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| package io.kafbat.ui.serdes.builtin.mm2; | ||
|
|
||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import io.kafbat.ui.serde.api.DeserializeResult; | ||
| import io.kafbat.ui.serde.api.SchemaDescription; | ||
| import io.kafbat.ui.serdes.BuiltInSerde; | ||
| import java.nio.ByteBuffer; | ||
| import java.util.Map; | ||
| import java.util.Optional; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.apache.kafka.common.protocol.types.Field; | ||
| import org.apache.kafka.common.protocol.types.Schema; | ||
| import org.apache.kafka.common.protocol.types.Struct; | ||
| import org.apache.kafka.common.protocol.types.Type; | ||
|
|
||
| @Slf4j | ||
| public class HeartbeatSerde implements BuiltInSerde { | ||
|
|
||
| private final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); | ||
|
|
||
| public static final String SOURCE_CLUSTER_ALIAS_KEY = "sourceClusterAlias"; | ||
| public static final String TARGET_CLUSTER_ALIAS_KEY = "targetClusterAlias"; | ||
| public static final String TIMESTAMP_KEY = "timestamp"; | ||
| public static final String VERSION_KEY = "version"; | ||
| public static final short VERSION = 0; | ||
|
|
||
| public static final Schema VALUE_SCHEMA_V0 = new Schema( | ||
| new Field(TIMESTAMP_KEY, Type.INT64)); | ||
|
|
||
| public static final Schema KEY_SCHEMA = new Schema( | ||
| new Field(SOURCE_CLUSTER_ALIAS_KEY, Type.STRING), | ||
| new Field(TARGET_CLUSTER_ALIAS_KEY, Type.STRING)); | ||
|
|
||
| public static final Schema HEADER_SCHEMA = new Schema( | ||
| new Field(VERSION_KEY, Type.INT16)); | ||
|
|
||
| public static String name() { | ||
| return "Heartbeat"; | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<String> getDescription() { | ||
| return Optional.empty(); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<SchemaDescription> getSchema(String topic, Target type) { | ||
| return Optional.empty(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean canDeserialize(String topic, Target type) { | ||
| return true; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean canSerialize(String topic, Target type) { | ||
| return false; | ||
| } | ||
|
|
||
| @Override | ||
| public Serializer serializer(String topic, Target type) { | ||
| throw new UnsupportedOperationException(); | ||
| } | ||
|
|
||
| @Override | ||
| public Deserializer deserializer(String topic, Target target) { | ||
| return (recordHeaders, bytes) -> switch (target) { | ||
|
|
||
| case KEY: { | ||
| Struct keyStruct = KEY_SCHEMA.read(ByteBuffer.wrap(bytes)); | ||
| String sourceClusterAlias = keyStruct.getString(SOURCE_CLUSTER_ALIAS_KEY); | ||
| String targetClusterAlias = keyStruct.getString(TARGET_CLUSTER_ALIAS_KEY); | ||
|
|
||
| var map = Map.of( | ||
| "sourceClusterAlias", sourceClusterAlias, | ||
| "targetClusterAlias", targetClusterAlias | ||
| ); | ||
|
|
||
| try { | ||
| var result = OBJECT_MAPPER.writeValueAsString(map); | ||
| yield new DeserializeResult(result, DeserializeResult.Type.STRING, Map.of()); | ||
| } catch (JsonProcessingException e) { | ||
| log.error("Error serializing record", e); | ||
| throw new RuntimeException(e); | ||
| } | ||
| } | ||
|
|
||
| case VALUE: { | ||
| ByteBuffer value = ByteBuffer.wrap(bytes); | ||
| Struct headerStruct = HEADER_SCHEMA.read(value); | ||
| short version = headerStruct.getShort(VERSION_KEY); | ||
| Struct valueStruct = valueSchema(version).read(value); | ||
| long timestamp = valueStruct.getLong(TIMESTAMP_KEY); | ||
| yield new DeserializeResult(String.valueOf(timestamp), DeserializeResult.Type.STRING, Map.of()); | ||
| } | ||
|
|
||
| }; | ||
| } | ||
|
|
||
| private static Schema valueSchema(short version) { | ||
| assert version == 0; | ||
| return VALUE_SCHEMA_V0; | ||
| } | ||
| } |
104 changes: 104 additions & 0 deletions
104
api/src/main/java/io/kafbat/ui/serdes/builtin/mm2/OffsetSyncSerde.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| package io.kafbat.ui.serdes.builtin.mm2; | ||
|
|
||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import io.kafbat.ui.serde.api.DeserializeResult; | ||
| import io.kafbat.ui.serde.api.SchemaDescription; | ||
| import io.kafbat.ui.serdes.BuiltInSerde; | ||
| import java.nio.ByteBuffer; | ||
| import java.util.Map; | ||
| import java.util.Optional; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.apache.kafka.common.protocol.types.Field; | ||
| import org.apache.kafka.common.protocol.types.Schema; | ||
| import org.apache.kafka.common.protocol.types.Struct; | ||
| import org.apache.kafka.common.protocol.types.Type; | ||
|
|
||
| @Slf4j | ||
| public class OffsetSyncSerde implements BuiltInSerde { | ||
|
|
||
| private final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); | ||
|
|
||
| public static final String TOPIC_KEY = "topic"; | ||
| public static final String PARTITION_KEY = "partition"; | ||
| public static final String UPSTREAM_OFFSET_KEY = "upstreamOffset"; | ||
| public static final String DOWNSTREAM_OFFSET_KEY = "offset"; | ||
| public static final Schema VALUE_SCHEMA; | ||
| public static final Schema KEY_SCHEMA; | ||
|
|
||
| static { | ||
| VALUE_SCHEMA = new Schema(new Field("upstreamOffset", Type.INT64), new Field("offset", Type.INT64)); | ||
| KEY_SCHEMA = new Schema(new Field("topic", Type.STRING), new Field("partition", Type.INT32)); | ||
| } | ||
|
|
||
| public static String name() { | ||
| return "OffsetSync"; | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<String> getDescription() { | ||
| return Optional.empty(); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<SchemaDescription> getSchema(String topic, Target type) { | ||
| return Optional.empty(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean canDeserialize(String topic, Target type) { | ||
| return true; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean canSerialize(String topic, Target type) { | ||
| return false; | ||
| } | ||
|
|
||
| @Override | ||
| public Serializer serializer(String topic, Target type) { | ||
| throw new UnsupportedOperationException(); | ||
| } | ||
|
|
||
| @Override | ||
| public Deserializer deserializer(String topic, Target target) { | ||
| return (recordHeaders, bytes) -> switch (target) { | ||
|
|
||
| case KEY: { | ||
| Struct keyStruct = KEY_SCHEMA.read(ByteBuffer.wrap(bytes)); | ||
| String t = keyStruct.getString(TOPIC_KEY); | ||
| int partition = keyStruct.getInt(PARTITION_KEY); | ||
|
|
||
| var map = Map.of( | ||
| TOPIC_KEY, t, | ||
| PARTITION_KEY, partition | ||
| ); | ||
|
|
||
| try { | ||
| var result = OBJECT_MAPPER.writeValueAsString(map); | ||
| yield new DeserializeResult(result, DeserializeResult.Type.STRING, Map.of()); | ||
| } catch (JsonProcessingException e) { | ||
| log.error("Error serializing record", e); | ||
| throw new RuntimeException(e); | ||
| } | ||
| } | ||
|
|
||
| case VALUE: { | ||
| Struct valueStruct = VALUE_SCHEMA.read(ByteBuffer.wrap(bytes)); | ||
| var map = Map.of( | ||
| UPSTREAM_OFFSET_KEY, valueStruct.getLong(UPSTREAM_OFFSET_KEY), | ||
| DOWNSTREAM_OFFSET_KEY, valueStruct.getLong(DOWNSTREAM_OFFSET_KEY) | ||
| ); | ||
|
|
||
| try { | ||
| var result = OBJECT_MAPPER.writeValueAsString(map); | ||
| yield new DeserializeResult(result, DeserializeResult.Type.STRING, Map.of()); | ||
| } catch (JsonProcessingException e) { | ||
| log.error("Error serializing record", e); | ||
| throw new RuntimeException(e); | ||
| } | ||
| } | ||
|
|
||
| }; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.