[FLINK-38023][formats] Fix GenericRecord Avro state migration#28161
[FLINK-38023][formats] Fix GenericRecord Avro state migration#28161avi-sanwal wants to merge 5 commits into
Conversation
Resolve GenericRecord values with an older record schema to the serializer runtime schema before writing them during state migration. Generated-by: OpenAI Codex GPT-5
Align GenericRecord restore behavior with SpecificRecord by constructing the restored reader with previous and current schemas instead of rewriting records at serialize time. Generated-by: OpenAI Codex GPT-5
Handle the nullable previous schema inside the GenericRecord factory helper instead of passing Optional as a parameter. Generated-by: OpenAI Codex GPT-5
Generated-by: OpenAI Codex (GPT-5)
| this.avroData = factory.getAvroData(); | ||
| } | ||
|
|
||
| private T resolveGenericRecord(T value) throws IOException { |
There was a problem hiding this comment.
It would be useful to include a comment as to the intent of this new method. I assume it is when the generic record does not match the type we think it is , due to schema migration.
There was a problem hiding this comment.
Thanks, addressed in 85bd596. I added a short method comment clarifying that this handles GenericRecord values restored during state migration that still carry the previous schema, before the writer indexes fields by position.
| final GenericRecord record = (GenericRecord) value; | ||
| final Schema recordSchema = record.getSchema(); | ||
| if (Objects.equals(recordSchema, runtimeSchema)) { | ||
| return value; |
There was a problem hiding this comment.
can we add a test to test this return?
There was a problem hiding this comment.
Thanks, addressed in 85bd596. I added coverage for the same-schema GenericRecord path, and also added a nullable-union GenericRecord roundtrip to exercise the null return branch through public serializer behavior.
Generated-by: OpenAI Codex (GPT-5)
What is the purpose of the change
This pull request fixes GenericRecord Avro state migration when compatible schema evolution changes the record shape, for example by adding a field with a default.
During migration, Flink can deserialize old state bytes with the restored previous serializer. For GenericRecord that value can still carry the old Avro schema, while the new serializer must write bytes using the new schema. Writing the old-shaped GenericRecord directly with the new GenericDatumWriter can fail or address fields by the wrong index.
Brief change log
Verifying this change
This change added tests and can be verified as follows:
AvroSerializerSnapshotTest#genericRecordWithSerializerSchemaShouldBeSerializedAsIs.AvroSerializerSnapshotTest#nullGenericRecordShouldBeSerializedWithNullableSchema.AvroSerializerSnapshotTest#migratedGenericRecordShouldBeSerializedWithNewSchema.AvroSerializerSnapshotTest#migratedGenericRecordShouldBeSerializedWithNewSchemaWhenFieldIsInsertedInMiddle../mvnw -pl flink-formats/flink-avro spotless:apply -Dspotless.check.skip=false../mvnw -pl flink-formats/flink-avro -am -Dtest=AvroSerializerSnapshotTest -DfailIfNoTests=false -Dsurefire.failIfNoSpecifiedTests=false -Dcheckstyle.skip -Drat.skip -Dspotless.check.skip test.Does this pull request potentially affect one of the following parts:
@Public(Evolving): noDocumentation
Was generative AI tooling used to co-author this PR?
Generated-by: OpenAI Codex GPT-5