Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FLINK-6178] [core] Allow serializer upgrades for managed state
This commit adds the functionality of allowing serializer upgrades for Flink's managed state. It consists of 2 major changes: 1) new user-facing API in `TypeSerializer`, and 2) activate serializer upgrades in state backends. For 1) new user-facing API for `TypeSerializer`, the following is added: - new class: TypeSerializerConfigSnapshot - new class: CompatibilityResult - new method: TypeSerializer#snapshotConfiguration() - new method: TypeSerializer#ensureCompatibility(TypeSerializerConfigSnapshot) Generally speaking, configuration snapshots contains a point-in-time view of a serializer's state / configuration, and is persisted along with checkpoints. On restore, the configuration is confronted with the new serializer of the state to check for compatibility, which may introduce reconfiguration of the new serializer to be compatible. This compatibility check is integrated in the state backends' restore flow in 2). Currently, if the check results in the need to perform state migration, the restore simply fails as the state migration feature isn't yet available.
- Loading branch information
Showing
120 changed files
with
6,429 additions
and
1,011 deletions.
There are no files selected for viewing
This file contains 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
203 changes: 129 additions & 74 deletions
203
...ksdb/src/main/java/org/apache/flink/contrib/streaming/state/RocksDBKeyedStateBackend.java
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains 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
80 changes: 80 additions & 0 deletions
80
flink-core/src/main/java/org/apache/flink/api/common/typeutils/CompatibilityResult.java
This file contains 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,80 @@ | ||
/* | ||
* 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.api.common.typeutils; | ||
|
||
import org.apache.flink.annotation.PublicEvolving; | ||
|
||
/** | ||
* A {@code CompatibilityResult} contains information about whether or not data migration | ||
* is required in order to continue using new serializers for previously serialized data. | ||
* | ||
* @param <T> the type of the data being migrated. | ||
*/ | ||
@PublicEvolving | ||
public final class CompatibilityResult<T> { | ||
|
||
/** Whether or not migration is required. */ | ||
private final boolean requiresMigration; | ||
|
||
/** | ||
* The convert deserializer to use for reading previous data during migration, | ||
* in the case that the preceding serializer cannot be found. | ||
* | ||
* <p>This is only relevant if migration is required. | ||
*/ | ||
private final TypeSerializer<T> convertDeserializer; | ||
|
||
/** | ||
* Returns a strategy that signals that the new serializer is compatible and no migration is required. | ||
* | ||
* @return a result that signals migration is not required for the new serializer | ||
*/ | ||
public static <T> CompatibilityResult<T> compatible() { | ||
return new CompatibilityResult<>(false, null); | ||
} | ||
|
||
/** | ||
* Returns a strategy that signals migration to be performed. | ||
* | ||
* <p>Furthermore, in the case that the preceding serializer cannot be found or restored to read the | ||
* previous data during migration, a provided convert deserializer can be used (may be {@code null} | ||
* if one cannot be provided). | ||
* | ||
* <p>In the case that the preceding serializer cannot be found and a convert deserializer is not | ||
* provided, the migration will fail due to the incapability of reading previous data. | ||
* | ||
* @return a result that signals migration is necessary, possibly providing a convert deserializer. | ||
*/ | ||
public static <T> CompatibilityResult<T> requiresMigration(TypeSerializer<T> convertDeserializer) { | ||
return new CompatibilityResult<>(true, convertDeserializer); | ||
} | ||
|
||
private CompatibilityResult(boolean requiresMigration, TypeSerializer<T> convertDeserializer) { | ||
this.requiresMigration = requiresMigration; | ||
this.convertDeserializer = convertDeserializer; | ||
} | ||
|
||
public TypeSerializer<T> getConvertDeserializer() { | ||
return convertDeserializer; | ||
} | ||
|
||
public boolean requiresMigration() { | ||
return requiresMigration; | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
...ain/java/org/apache/flink/api/common/typeutils/CompositeTypeSerializerConfigSnapshot.java
This file contains 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,85 @@ | ||
/* | ||
* 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.api.common.typeutils; | ||
|
||
import org.apache.flink.annotation.Internal; | ||
import org.apache.flink.core.memory.DataInputView; | ||
import org.apache.flink.core.memory.DataOutputView; | ||
import org.apache.flink.util.Preconditions; | ||
|
||
import java.io.IOException; | ||
import java.util.Arrays; | ||
|
||
/** | ||
* A {@link TypeSerializerConfigSnapshot} for serializers that has multiple nested serializers. | ||
* The configuration snapshot consists of the configuration snapshots of all nested serializers. | ||
*/ | ||
@Internal | ||
public abstract class CompositeTypeSerializerConfigSnapshot extends TypeSerializerConfigSnapshot { | ||
|
||
private TypeSerializerConfigSnapshot[] nestedSerializerConfigSnapshots; | ||
|
||
/** This empty nullary constructor is required for deserializing the configuration. */ | ||
public CompositeTypeSerializerConfigSnapshot() {} | ||
|
||
public CompositeTypeSerializerConfigSnapshot(TypeSerializerConfigSnapshot... nestedSerializerConfigSnapshots) { | ||
this.nestedSerializerConfigSnapshots = Preconditions.checkNotNull(nestedSerializerConfigSnapshots); | ||
} | ||
|
||
@Override | ||
public void write(DataOutputView out) throws IOException { | ||
super.write(out); | ||
TypeSerializerUtil.writeSerializerConfigSnapshots(out, nestedSerializerConfigSnapshots); | ||
} | ||
|
||
@Override | ||
public void read(DataInputView in) throws IOException { | ||
super.read(in); | ||
nestedSerializerConfigSnapshots = TypeSerializerUtil.readSerializerConfigSnapshots(in, getUserCodeClassLoader()); | ||
} | ||
|
||
public TypeSerializerConfigSnapshot[] getNestedSerializerConfigSnapshots() { | ||
return nestedSerializerConfigSnapshots; | ||
} | ||
|
||
public TypeSerializerConfigSnapshot getSingleNestedSerializerConfigSnapshot() { | ||
return nestedSerializerConfigSnapshots[0]; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (obj == this) { | ||
return true; | ||
} | ||
|
||
if (obj == null) { | ||
return false; | ||
} | ||
|
||
return (obj.getClass().equals(getClass())) | ||
&& Arrays.equals( | ||
nestedSerializerConfigSnapshots, | ||
((CompositeTypeSerializerConfigSnapshot) obj).getNestedSerializerConfigSnapshots()); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Arrays.hashCode(nestedSerializerConfigSnapshots); | ||
} | ||
} |
88 changes: 88 additions & 0 deletions
88
.../main/java/org/apache/flink/api/common/typeutils/GenericTypeSerializerConfigSnapshot.java
This file contains 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,88 @@ | ||
/* | ||
* 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.api.common.typeutils; | ||
|
||
import org.apache.flink.annotation.Internal; | ||
import org.apache.flink.core.memory.DataInputView; | ||
import org.apache.flink.core.memory.DataOutputView; | ||
import org.apache.flink.util.Preconditions; | ||
|
||
import java.io.IOException; | ||
|
||
/** | ||
* Configuration snapshot for serializers for generic types. | ||
* | ||
* @param <T> The type to be instantiated. | ||
*/ | ||
@Internal | ||
public abstract class GenericTypeSerializerConfigSnapshot<T> extends TypeSerializerConfigSnapshot { | ||
|
||
private Class<T> typeClass; | ||
|
||
/** This empty nullary constructor is required for deserializing the configuration. */ | ||
public GenericTypeSerializerConfigSnapshot() {} | ||
|
||
public GenericTypeSerializerConfigSnapshot(Class<T> typeClass) { | ||
this.typeClass = Preconditions.checkNotNull(typeClass); | ||
} | ||
|
||
@Override | ||
public void write(DataOutputView out) throws IOException { | ||
super.write(out); | ||
|
||
// write only the classname to avoid Java serialization | ||
out.writeUTF(typeClass.getName()); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
public void read(DataInputView in) throws IOException { | ||
super.read(in); | ||
|
||
String genericTypeClassname = in.readUTF(); | ||
try { | ||
typeClass = (Class<T>) Class.forName(genericTypeClassname, true, getUserCodeClassLoader()); | ||
} catch (ClassNotFoundException e) { | ||
throw new IOException("Could not find the requested class " + genericTypeClassname + " in classpath.", e); | ||
} | ||
} | ||
|
||
public Class<T> getTypeClass() { | ||
return typeClass; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (obj == this) { | ||
return true; | ||
} | ||
|
||
if (obj == null) { | ||
return false; | ||
} | ||
|
||
return (obj.getClass().equals(getClass())) | ||
&& typeClass.equals(((GenericTypeSerializerConfigSnapshot) obj).getTypeClass()); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return typeClass.hashCode(); | ||
} | ||
} |
Oops, something went wrong.