org.apache.flink.runtime.state.StateInitializationContextImpl 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.commons.io.IOUtils;
import org.apache.flink.api.common.state.KeyedStateStore;
import org.apache.flink.api.common.state.OperatorStateStore;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.core.fs.CloseableRegistry;
import org.apache.flink.core.fs.FSDataInputStream;
import org.apache.flink.util.Preconditions;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
/**
* Default implementation of {@link StateInitializationContext}.
*/
public class StateInitializationContextImpl implements StateInitializationContext {
/** Closable registry to participate in the operator's cancel/close methods */
private final CloseableRegistry closableRegistry;
/** Signal whether any state to restore was found */
private final boolean restored;
private final OperatorStateStore operatorStateStore;
private final Collection operatorStateHandles;
private final KeyedStateStore keyedStateStore;
private final Collection keyGroupsStateHandles;
private final Iterable keyedStateIterable;
public StateInitializationContextImpl(
boolean restored,
OperatorStateStore operatorStateStore,
KeyedStateStore keyedStateStore,
Collection keyedStateHandles,
Collection operatorStateHandles,
CloseableRegistry closableRegistry) {
this.restored = restored;
this.closableRegistry = Preconditions.checkNotNull(closableRegistry);
this.operatorStateStore = operatorStateStore;
this.keyedStateStore = keyedStateStore;
this.operatorStateHandles = operatorStateHandles;
this.keyGroupsStateHandles = transform(keyedStateHandles);
this.keyedStateIterable = keyGroupsStateHandles == null ?
null
: new Iterable() {
@Override
public Iterator iterator() {
return new KeyGroupStreamIterator(getKeyGroupsStateHandles().iterator(), getClosableRegistry());
}
};
}
@Override
public boolean isRestored() {
return restored;
}
public Collection getOperatorStateHandles() {
return operatorStateHandles;
}
public Collection getKeyGroupsStateHandles() {
return keyGroupsStateHandles;
}
public CloseableRegistry getClosableRegistry() {
return closableRegistry;
}
@Override
public Iterable getRawOperatorStateInputs() {
if (null != operatorStateHandles) {
return new Iterable() {
@Override
public Iterator iterator() {
return new OperatorStateStreamIterator(
DefaultOperatorStateBackend.DEFAULT_OPERATOR_STATE_NAME,
getOperatorStateHandles().iterator(), getClosableRegistry());
}
};
} else {
return Collections.emptyList();
}
}
@Override
public Iterable getRawKeyedStateInputs() {
if(null == keyedStateStore) {
throw new IllegalStateException("Attempt to access keyed state from non-keyed operator.");
}
if (null != keyGroupsStateHandles) {
return keyedStateIterable;
} else {
return Collections.emptyList();
}
}
@Override
public OperatorStateStore getOperatorStateStore() {
return operatorStateStore;
}
@Override
public KeyedStateStore getKeyedStateStore() {
return keyedStateStore;
}
public void close() {
IOUtils.closeQuietly(closableRegistry);
}
private static Collection transform(Collection keyedStateHandles) {
if (keyedStateHandles == null) {
return null;
}
List keyGroupsStateHandles = new ArrayList<>();
for (KeyedStateHandle keyedStateHandle : keyedStateHandles) {
if (! (keyedStateHandle instanceof KeyGroupsStateHandle)) {
throw new IllegalStateException("Unexpected state handle type, " +
"expected: " + KeyGroupsStateHandle.class +
", but found: " + keyedStateHandle.getClass() + ".");
}
keyGroupsStateHandles.add((KeyGroupsStateHandle) keyedStateHandle);
}
return keyGroupsStateHandles;
}
private static class KeyGroupStreamIterator
extends AbstractStateStreamIterator {
private Iterator> currentOffsetsIterator;
public KeyGroupStreamIterator(
Iterator stateHandleIterator, CloseableRegistry closableRegistry) {
super(stateHandleIterator, closableRegistry);
}
@Override
public boolean hasNext() {
if (null != currentStateHandle && currentOffsetsIterator.hasNext()) {
return true;
}
closeCurrentStream();
while (stateHandleIterator.hasNext()) {
currentStateHandle = stateHandleIterator.next();
if (currentStateHandle.getKeyGroupRange().getNumberOfKeyGroups() > 0) {
currentOffsetsIterator = currentStateHandle.getGroupRangeOffsets().iterator();
return true;
}
}
return false;
}
@Override
public KeyGroupStatePartitionStreamProvider next() {
if (!hasNext()) {
throw new NoSuchElementException("Iterator exhausted");
}
Tuple2 keyGroupOffset = currentOffsetsIterator.next();
try {
if (null == currentStream) {
openCurrentStream();
}
currentStream.seek(keyGroupOffset.f1);
return new KeyGroupStatePartitionStreamProvider(currentStream, keyGroupOffset.f0);
} catch (IOException ioex) {
return new KeyGroupStatePartitionStreamProvider(ioex, keyGroupOffset.f0);
}
}
}
private static class OperatorStateStreamIterator
extends AbstractStateStreamIterator {
private final String stateName; //TODO since we only support a single named state in raw, this could be dropped
private long[] offsets;
private int offPos;
public OperatorStateStreamIterator(
String stateName,
Iterator stateHandleIterator,
CloseableRegistry closableRegistry) {
super(stateHandleIterator, closableRegistry);
this.stateName = Preconditions.checkNotNull(stateName);
}
@Override
public boolean hasNext() {
if (null != offsets && offPos < offsets.length) {
return true;
}
closeCurrentStream();
while (stateHandleIterator.hasNext()) {
currentStateHandle = stateHandleIterator.next();
OperatorStateHandle.StateMetaInfo metaInfo =
currentStateHandle.getStateNameToPartitionOffsets().get(stateName);
if (null != metaInfo) {
long[] metaOffsets = metaInfo.getOffsets();
if (null != metaOffsets && metaOffsets.length > 0) {
this.offsets = metaOffsets;
this.offPos = 0;
closableRegistry.unregisterClosable(currentStream);
IOUtils.closeQuietly(currentStream);
currentStream = null;
return true;
}
}
}
return false;
}
@Override
public StatePartitionStreamProvider next() {
if (!hasNext()) {
throw new NoSuchElementException("Iterator exhausted");
}
long offset = offsets[offPos++];
try {
if (null == currentStream) {
openCurrentStream();
}
currentStream.seek(offset);
return new StatePartitionStreamProvider(currentStream);
} catch (IOException ioex) {
return new StatePartitionStreamProvider(ioex);
}
}
}
abstract static class AbstractStateStreamIterator
implements Iterator {
protected final Iterator stateHandleIterator;
protected final CloseableRegistry closableRegistry;
protected H currentStateHandle;
protected FSDataInputStream currentStream;
public AbstractStateStreamIterator(
Iterator stateHandleIterator,
CloseableRegistry closableRegistry) {
this.stateHandleIterator = Preconditions.checkNotNull(stateHandleIterator);
this.closableRegistry = Preconditions.checkNotNull(closableRegistry);
}
protected void openCurrentStream() throws IOException {
FSDataInputStream stream = currentStateHandle.openInputStream();
closableRegistry.registerClosable(stream);
currentStream = stream;
}
protected void closeCurrentStream() {
closableRegistry.unregisterClosable(currentStream);
IOUtils.closeQuietly(currentStream);
currentStream = null;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Read only Iterator");
}
}
}