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

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

/*
 * 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.VisibleForTesting;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.util.Preconditions;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;

import java.util.Map;
import java.util.stream.Collectors;

/**
 * An implementation of {@link KeyedStateHandle} which will be used in incremental snapshot/restore.
 */
public class IncrementalKeyedStateSnapshot implements KeyedStateHandle, IncrementalStateHandle {

	private static final Logger LOG = LoggerFactory.getLogger(IncrementalKeyedStateHandle.class);

	private static final long serialVersionUID = 1L;

	/**
	 * The checkpoint Id.
	 */
	private final long checkpointId;

	/**
	 * Shared state in the incremental checkpoint.
	 */
	private final Map> sharedState;

	/**
	 * Private state in the incremental checkpoint.
	 */
	private final Map privateState;

	/**
	 * The key-group range covered by this state handle.
	 */
	private final KeyGroupRange keyGroupRange;

	/**
	 * Primary meta data state of the incremental checkpoint.
	 */
	@Nonnull
	private final StreamStateHandle metaStateHandle;

	/**
	 * Once the shared states are registered, it is the {@link SharedStateRegistry}'s
	 * responsibility to cleanup those shared states.
	 * But in the cases where the state handle is discarded before performing the registration,
	 * the handle should delete all the shared states created by it.
	 *
	 * 

his variable is not null iff the handles was registered. */ private transient SharedStateRegistry sharedStateRegistry; public IncrementalKeyedStateSnapshot( KeyGroupRange keyGroupRange, long checkpointId, Map> sharedState, Map privateState, StreamStateHandle metaStateHandle) { this.keyGroupRange = keyGroupRange; this.checkpointId = checkpointId; this.sharedState = sharedState; this.privateState = privateState; this.sharedStateRegistry = null; this.metaStateHandle = metaStateHandle; } public long getCheckpointId() { return checkpointId; } public Map> getSharedState() { return sharedState; } public Map getPrivateState() { return privateState; } @Override public KeyGroupRange getKeyGroupRange() { return keyGroupRange; } @Override public KeyedStateHandle getIntersection(KeyGroupRange otherKeyGroupRange) { return KeyGroupRange.EMPTY_KEY_GROUP_RANGE.equals(this.keyGroupRange.getIntersection(otherKeyGroupRange)) ? null : this; } @Override public void registerSharedStates(SharedStateRegistry stateRegistry) { // This is a quick check to avoid that we register twice with the same registry. However, the code allows to // register again with a different registry. The implication is that ownership is transferred to this new // registry. This should only happen in case of a restart, when the CheckpointCoordinator creates a new // SharedStateRegistry for the current attempt and the old registry becomes meaningless. We also assume that // an old registry object from a previous run is due to be GCed and will never be used for registration again. Preconditions.checkState( sharedStateRegistry != stateRegistry, "The state handle has already registered its shared states to the given registry."); sharedStateRegistry = Preconditions.checkNotNull(stateRegistry); LOG.trace("Registering IncrementalKeyedStateSnapshot for checkpoint {} from backend.", checkpointId); for (Map.Entry> sharedStateHandle : sharedState.entrySet()) { String uniqueId = sharedStateHandle.getValue().f0; SharedStateRegistryKey registryKey = createSharedStateRegistryKeyFromUniqueId(uniqueId, sharedStateHandle.getKey()); SharedStateRegistry.Result result = stateRegistry.registerReference(registryKey, sharedStateHandle.getValue().f1); // This step consolidates our shared handles with the registry, which does two things: // // 1) Replace placeholder state handle with already registered, actual state handles. // // 2) Deduplicate re-uploads of incremental state due to missing confirmations about // completed checkpoints. // // This prevents the following problem: // A previous checkpoint n has already registered the state. This can happen if a // following checkpoint (n + x) wants to reference the same state before the backend got // notified that checkpoint n completed. In this case, the shared registry did // deduplication and returns the previous reference. sharedStateHandle.setValue(Tuple2.of(uniqueId, result.getReference())); } } @Override public void discardState() throws Exception { SharedStateRegistry registry = this.sharedStateRegistry; final boolean isRegistered = (registry != null); LOG.trace("Discarding IncrementalKeyedStateSnapshot (registered = {}) for checkpoint {} from backend.", isRegistered, checkpointId); try { metaStateHandle.discardState(); } catch (Exception e) { LOG.warn("Could not properly discard meta data.", e); } try { StateUtil.bestEffortDiscardAllStateObjects(privateState.values()); } catch (Exception e) { LOG.warn("Could not properly discard misc file states.", e); } // If this was not registered, we can delete the shared state. We can simply apply this // to all handles, because all handles that have not been created for the first time for this // are only placeholders at this point (disposing them is a NOP). if (isRegistered) { // If this was registered, we only unregister all our referenced shared states // from the registry. for (Map.Entry> entry : sharedState.entrySet()) { registry.unregisterReference( createSharedStateRegistryKeyFromUniqueId(entry.getValue().f0, entry.getKey())); } } else { // Otherwise, we assume to own those handles and dispose them directly. try { StateUtil.bestEffortDiscardAllStateObjects(sharedState.values().stream().map(t -> t.f1).collect(Collectors.toSet())); } catch (Exception e) { LOG.warn("Could not properly discard new sst file states.", e); } } } @Override public long getStateSize() { long size = StateUtil.getStateSize(metaStateHandle); for (Tuple2 sharedStateHandle : sharedState.values()) { size += sharedStateHandle.f1.getStateSize(); } for (StreamStateHandle privateStateHandle : privateState.values()) { size += privateStateHandle.getStateSize(); } return size; } @Override public long getFullStateSize() { long fullSize = StateUtil.getStateSize(metaStateHandle); for (Tuple2 sharedStateHandle : sharedState.values()) { if (sharedStateHandle.f1 instanceof IncrementalStateHandle) { fullSize += ((IncrementalStateHandle) sharedStateHandle.f1).getFullStateSize(); } else { fullSize += sharedStateHandle.f1.getStateSize(); } } for (StreamStateHandle privateStateHandle : privateState.values()) { fullSize += privateStateHandle.getStateSize(); } return fullSize; } @Nonnull public StreamStateHandle getMetaStateHandle() { return metaStateHandle; } /** * Create a unique key to register one of our shared state handles. */ @VisibleForTesting public SharedStateRegistryKey createSharedStateRegistryKeyFromUniqueId(String uniqueId, StateHandleID shId) { return new SharedStateRegistryKey(uniqueId, shId); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } IncrementalKeyedStateSnapshot that = (IncrementalKeyedStateSnapshot) o; if (getCheckpointId() != that.getCheckpointId()) { return false; } if (!keyGroupRange.equals(that.getKeyGroupRange())) { return false; } if (!getSharedState().equals(that.getSharedState())) { return false; } if (!getPrivateState().equals(that.getPrivateState())) { return false; } return getMetaStateHandle().equals(that.getMetaStateHandle()); } @Override public int hashCode() { int result = getKeyGroupRange().hashCode(); result = 31 * result + (int) (getCheckpointId() ^ (getCheckpointId() >>> 32)); result = 31 * result + getSharedState().hashCode(); result = 31 * result + getPrivateState().hashCode(); result = 31 * result + getMetaStateHandle().hashCode(); return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy