All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.flink.runtime.state.SerializedCompositeKeyBuilder Maven / Gradle / Ivy

There is a newer version: 1.13.6
Show newest version
/*
 * 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.runtime.state;

import org.apache.flink.annotation.Internal;
import org.apache.flink.annotation.VisibleForTesting;
import org.apache.flink.api.common.typeutils.TypeSerializer;
import org.apache.flink.core.memory.DataOutputSerializer;
import org.apache.flink.util.FlinkRuntimeException;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.NotThreadSafe;

import java.io.IOException;

/**
 * Responsible for serialization of currentKey, currentGroup and namespace. Will reuse the previous
 * serialized currentKeyed if possible.
 *
 * @param  type of the key.
 */
@NotThreadSafe
@Internal
public final class SerializedCompositeKeyBuilder {

    /** The serializer for the key. */
    @Nonnull private final TypeSerializer keySerializer;

    /** The output to write the key into. */
    @Nonnull private final DataOutputSerializer keyOutView;

    /** The number of Key-group-prefix bytes for the key. */
    @Nonnegative private final int keyGroupPrefixBytes;

    /** This flag indicates whether the key type has a variable byte size in serialization. */
    private final boolean keySerializerTypeVariableSized;

    /** Mark for the position after the serialized key. */
    @Nonnegative private int afterKeyMark;

    @Nonnegative private int afterNamespaceMark;

    public SerializedCompositeKeyBuilder(
            @Nonnull TypeSerializer keySerializer,
            @Nonnegative int keyGroupPrefixBytes,
            @Nonnegative int initialSize) {
        this(
                keySerializer,
                new DataOutputSerializer(initialSize),
                keyGroupPrefixBytes,
                CompositeKeySerializationUtils.isSerializerTypeVariableSized(keySerializer),
                0);
    }

    @VisibleForTesting
    SerializedCompositeKeyBuilder(
            @Nonnull TypeSerializer keySerializer,
            @Nonnull DataOutputSerializer keyOutView,
            @Nonnegative int keyGroupPrefixBytes,
            boolean keySerializerTypeVariableSized,
            @Nonnegative int afterKeyMark) {
        this.keySerializer = keySerializer;
        this.keyOutView = keyOutView;
        this.keyGroupPrefixBytes = keyGroupPrefixBytes;
        this.keySerializerTypeVariableSized = keySerializerTypeVariableSized;
        this.afterKeyMark = afterKeyMark;
    }

    /**
     * Sets the key and key-group as prefix. This will serialize them into the buffer and the will
     * be used to create composite keys with provided namespaces.
     *
     * @param key the key.
     * @param keyGroupId the key-group id for the key.
     */
    public void setKeyAndKeyGroup(@Nonnull K key, @Nonnegative int keyGroupId) {
        try {
            serializeKeyGroupAndKey(key, keyGroupId);
        } catch (IOException shouldNeverHappen) {
            throw new FlinkRuntimeException(shouldNeverHappen);
        }
    }

    public  void setNamespace(
            @Nonnull N namespace, @Nonnull TypeSerializer namespaceSerializer) {
        try {
            serializeNamespace(namespace, namespaceSerializer);
        } catch (IOException shouldNeverHappen) {
            throw new FlinkRuntimeException(shouldNeverHappen);
        }
    }

    /**
     * Returns a serialized composite key, from the key and key-group provided in a previous call to
     * {@link #setKeyAndKeyGroup(Object, int)} and the given namespace.
     *
     * @param namespace the namespace to concatenate for the serialized composite key bytes.
     * @param namespaceSerializer the serializer to obtain the serialized form of the namespace.
     * @param  the type of the namespace.
     * @return the bytes for the serialized composite key of key-group, key, namespace.
     */
    @Nonnull
    public  byte[] buildCompositeKeyNamespace(
            @Nonnull N namespace, @Nonnull TypeSerializer namespaceSerializer) {
        try {
            serializeNamespace(namespace, namespaceSerializer);
            return keyOutView.getCopyOfBuffer();
        } catch (IOException shouldNeverHappen) {
            throw new FlinkRuntimeException(shouldNeverHappen);
        }
    }

    /**
     * Returns a serialized composite key, from the key and key-group provided in a previous call to
     * {@link #setKeyAndKeyGroup(Object, int)} and the given namespace, followed by the given
     * user-key.
     *
     * @param namespace the namespace to concatenate for the serialized composite key bytes.
     * @param namespaceSerializer the serializer to obtain the serialized form of the namespace.
     * @param userKey the user-key to concatenate for the serialized composite key, after the
     *     namespace.
     * @param userKeySerializer the serializer to obtain the serialized form of the user-key.
     * @param  the type of the namespace.
     * @param  the type of the user-key.
     * @return the bytes for the serialized composite key of key-group, key, namespace.
     */
    @Nonnull
    public  byte[] buildCompositeKeyNamesSpaceUserKey(
            @Nonnull N namespace,
            @Nonnull TypeSerializer namespaceSerializer,
            @Nonnull UK userKey,
            @Nonnull TypeSerializer userKeySerializer)
            throws IOException {
        serializeNamespace(namespace, namespaceSerializer);
        userKeySerializer.serialize(userKey, keyOutView);
        return keyOutView.getCopyOfBuffer();
    }

    /**
     * Returns a serialized composite key, from the key and key-group provided in a previous call to
     * {@link #setKeyAndKeyGroup(Object, int)} and the namespace provided in {@link
     * #setNamespace(Object, TypeSerializer)}, followed by the given user-key.
     *
     * @param userKey the user-key to concatenate for the serialized composite key, after the
     *     namespace.
     * @param userKeySerializer the serializer to obtain the serialized form of the user-key.
     * @param  the type of the user-key.
     * @return the bytes for the serialized composite key of key-group, key, namespace.
     */
    @Nonnull
    public  byte[] buildCompositeKeyUserKey(
            @Nonnull UK userKey, @Nonnull TypeSerializer userKeySerializer) throws IOException {
        // this should only be called when there is already a namespace written.
        assert isNamespaceWritten();
        resetToNamespace();

        userKeySerializer.serialize(userKey, keyOutView);
        return keyOutView.getCopyOfBuffer();
    }

    /** Returns a serialized composite key, from whatever was set so far. */
    @Nonnull
    public byte[] build() throws IOException {
        return keyOutView.getCopyOfBuffer();
    }

    private void serializeKeyGroupAndKey(K key, int keyGroupId) throws IOException {

        // clear buffer and mark
        resetFully();

        // write key-group
        CompositeKeySerializationUtils.writeKeyGroup(keyGroupId, keyGroupPrefixBytes, keyOutView);
        // write key
        keySerializer.serialize(key, keyOutView);
        afterKeyMark = keyOutView.length();
    }

    private  void serializeNamespace(
            @Nonnull N namespace, @Nonnull TypeSerializer namespaceSerializer)
            throws IOException {

        // this should only be called when there is already a key written so that we build the
        // composite.
        assert isKeyWritten();
        resetToKey();

        final boolean ambiguousCompositeKeyPossible =
                isAmbiguousCompositeKeyPossible(namespaceSerializer);
        if (ambiguousCompositeKeyPossible) {
            CompositeKeySerializationUtils.writeVariableIntBytes(
                    afterKeyMark - keyGroupPrefixBytes, keyOutView);
        }
        CompositeKeySerializationUtils.writeNameSpace(
                namespace, namespaceSerializer, keyOutView, ambiguousCompositeKeyPossible);
        afterNamespaceMark = keyOutView.length();
    }

    private void resetFully() {
        afterKeyMark = 0;
        afterNamespaceMark = 0;
        keyOutView.clear();
    }

    private void resetToKey() {
        afterNamespaceMark = 0;
        keyOutView.setPosition(afterKeyMark);
    }

    private void resetToNamespace() {
        keyOutView.setPosition(afterNamespaceMark);
    }

    private boolean isKeyWritten() {
        return afterKeyMark > 0;
    }

    private boolean isNamespaceWritten() {
        return afterNamespaceMark > 0;
    }

    @VisibleForTesting
    boolean isAmbiguousCompositeKeyPossible(TypeSerializer namespaceSerializer) {
        return keySerializerTypeVariableSized
                & CompositeKeySerializationUtils.isSerializerTypeVariableSized(namespaceSerializer);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy