use of org.apache.flink.runtime.persistence.PossibleInconsistentStateException in project flink by apache.
the class Fabric8FlinkKubeClientTest method testCheckAndUpdateConfigMapWhenGetConfigMapFailed.
@Test
public void testCheckAndUpdateConfigMapWhenGetConfigMapFailed() throws Exception {
final int configuredRetries = flinkConfig.getInteger(KubernetesConfigOptions.KUBERNETES_TRANSACTIONAL_OPERATION_MAX_RETRIES);
final KubernetesConfigMap configMap = buildTestingConfigMap();
this.flinkKubeClient.createConfigMap(configMap).get();
mockGetConfigMapFailed(configMap.getInternalResource());
final int initialRequestCount = server.getRequestCount();
try {
this.flinkKubeClient.checkAndUpdateConfigMap(TESTING_CONFIG_MAP_NAME, c -> {
throw new AssertionError("The replace operation should have never been triggered.");
}).get();
fail("checkAndUpdateConfigMap should fail without a PossibleInconsistentStateException being the cause when number of retries has been exhausted.");
} catch (Exception ex) {
assertThat(ex, FlinkMatchers.containsMessage("Could not complete the " + "operation. Number of retries has been exhausted."));
final int actualRetryCount = server.getRequestCount() - initialRequestCount;
assertThat(actualRetryCount, is(configuredRetries + 1));
assertThat("An error while retrieving the ConfigMap should not cause a PossibleInconsistentStateException.", ExceptionUtils.findThrowable(ex, PossibleInconsistentStateException.class).isPresent(), is(false));
}
}
use of org.apache.flink.runtime.persistence.PossibleInconsistentStateException in project flink by apache.
the class KubernetesStateHandleStoreTest method testReplaceFailedWithPossiblyInconsistentState.
@Test
public void testReplaceFailedWithPossiblyInconsistentState() throws Exception {
final PossibleInconsistentStateException updateException = new PossibleInconsistentStateException();
new Context() {
{
runTest(() -> {
leaderCallbackGrantLeadership();
final KubernetesStateHandleStore<TestingLongStateHandleHelper.LongStateHandle> store = new KubernetesStateHandleStore<>(flinkKubeClient, LEADER_CONFIGMAP_NAME, longStateStorage, filter, LOCK_IDENTITY);
store.addAndLock(key, state);
final FlinkKubeClient anotherFlinkKubeClient = createFlinkKubeClientBuilder().setCheckAndUpdateConfigMapFunction((configMapName, function) -> FutureUtils.completedExceptionally(updateException)).build();
final KubernetesStateHandleStore<TestingLongStateHandleHelper.LongStateHandle> anotherStore = new KubernetesStateHandleStore<>(anotherFlinkKubeClient, LEADER_CONFIGMAP_NAME, longStateStorage, filter, LOCK_IDENTITY);
final StringResourceVersion resourceVersion = anotherStore.exists(key);
assertThat(resourceVersion.isExisting(), is(true));
try {
anotherStore.replace(key, resourceVersion, new TestingLongStateHandleHelper.LongStateHandle(23456L));
fail("An exception having a PossibleInconsistentStateException as its cause should have been thrown.");
} catch (Exception ex) {
assertThat(ex, is(updateException));
}
assertThat(anotherStore.getAllAndLock().size(), is(1));
// The state does not change
assertThat(anotherStore.getAndLock(key).retrieveState(), is(state));
assertThat(TestingLongStateHandleHelper.getGlobalStorageSize(), is(2));
// no state was discarded
assertThat(TestingLongStateHandleHelper.getDiscardCallCountForStateHandleByIndex(0), is(0));
assertThat(TestingLongStateHandleHelper.getDiscardCallCountForStateHandleByIndex(1), is(0));
});
}
};
}
use of org.apache.flink.runtime.persistence.PossibleInconsistentStateException in project flink by apache.
the class ZooKeeperStateHandleStore method addAndLock.
/**
* Creates a state handle, stores it in ZooKeeper and locks it. A locked node cannot be removed
* by another {@link ZooKeeperStateHandleStore} instance as long as this instance remains
* connected to ZooKeeper.
*
* <p><strong>Important</strong>: This will <em>not</em> store the actual state in ZooKeeper,
* but create a state handle and store it in ZooKeeper. This level of indirection makes sure
* that data in ZooKeeper is small.
*
* <p>The operation will fail if there is already a node under the given path.
*
* @param pathInZooKeeper Destination path in ZooKeeper (expected to *not* exist yet)
* @param state State to be added
* @return The Created {@link RetrievableStateHandle}.
* @throws PossibleInconsistentStateException if the write-to-ZooKeeper operation failed. This
* indicates that it's not clear whether the new state was successfully written to ZooKeeper
* or not. Proper error handling has to be applied on the caller's side.
* @throws Exception If a ZooKeeper or state handle operation fails
*/
@Override
public RetrievableStateHandle<T> addAndLock(String pathInZooKeeper, T state) throws PossibleInconsistentStateException, Exception {
checkNotNull(pathInZooKeeper, "Path in ZooKeeper");
checkNotNull(state, "State");
final String path = normalizePath(pathInZooKeeper);
if (exists(path).isExisting()) {
throw new AlreadyExistException(String.format("ZooKeeper node %s already exists.", path));
}
final RetrievableStateHandle<T> storeHandle = storage.store(state);
final byte[] serializedStoreHandle = serializeOrDiscard(storeHandle);
try {
writeStoreHandleTransactionally(path, serializedStoreHandle);
return storeHandle;
} catch (KeeperException.NodeExistsException e) {
// we can assume that this is a result of the retry mechanism.
return storeHandle;
} catch (Exception e) {
if (indicatesPossiblyInconsistentState(e)) {
throw new PossibleInconsistentStateException(e);
}
// In case of any other failure, discard the state and rethrow the exception.
storeHandle.discardState();
throw e;
}
}
use of org.apache.flink.runtime.persistence.PossibleInconsistentStateException in project flink by apache.
the class ZooKeeperStateHandleStore method replace.
/**
* Replaces a state handle in ZooKeeper and discards the old state handle.
*
* @param pathInZooKeeper Destination path in ZooKeeper (expected to exist and start with a '/')
* @param expectedVersion Expected version of the node to replace
* @param state The new state to replace the old one
* @throws Exception If a ZooKeeper or state handle operation fails
*/
@Override
public void replace(String pathInZooKeeper, IntegerResourceVersion expectedVersion, T state) throws Exception {
checkNotNull(pathInZooKeeper, "Path in ZooKeeper");
checkNotNull(state, "State");
final String path = normalizePath(pathInZooKeeper);
RetrievableStateHandle<T> oldStateHandle = get(path, false);
RetrievableStateHandle<T> newStateHandle = storage.store(state);
final byte[] serializedStateHandle = serializeOrDiscard(newStateHandle);
// initialize flags to serve the failure case
boolean discardOldState = false;
boolean discardNewState = true;
try {
setStateHandle(path, serializedStateHandle, expectedVersion.getValue());
// swap subject for deletion in case of success
discardOldState = true;
discardNewState = false;
} catch (Exception e) {
if (indicatesPossiblyInconsistentState(e)) {
// it's unclear whether the state handle metadata was written to ZooKeeper -
// hence, we don't discard any data
discardNewState = false;
throw new PossibleInconsistentStateException(e);
}
// We wrap the exception here so that it could be caught in DefaultJobGraphStore
throw ExceptionUtils.findThrowable(e, KeeperException.NoNodeException.class).map(nnee -> new NotExistException("ZooKeeper node " + path + " does not exist.", nnee)).orElseThrow(() -> e);
} finally {
if (discardOldState) {
oldStateHandle.discardState();
}
if (discardNewState) {
newStateHandle.discardState();
}
}
}
use of org.apache.flink.runtime.persistence.PossibleInconsistentStateException in project flink by apache.
the class Fabric8FlinkKubeClientTest method testCheckAndUpdateConfigMapWhenReplaceConfigMapFailed.
@Test
public void testCheckAndUpdateConfigMapWhenReplaceConfigMapFailed() throws Exception {
final int configuredRetries = flinkConfig.getInteger(KubernetesConfigOptions.KUBERNETES_TRANSACTIONAL_OPERATION_MAX_RETRIES);
final KubernetesConfigMap configMap = buildTestingConfigMap();
this.flinkKubeClient.createConfigMap(configMap).get();
mockReplaceConfigMapFailed(configMap.getInternalResource());
final AtomicInteger retries = new AtomicInteger(0);
try {
this.flinkKubeClient.checkAndUpdateConfigMap(TESTING_CONFIG_MAP_NAME, c -> {
retries.incrementAndGet();
return Optional.of(configMap);
}).get();
fail("checkAndUpdateConfigMap should fail due to a PossibleInconsistentStateException when number of retries has been exhausted.");
} catch (Exception ex) {
assertThat(ex, FlinkMatchers.containsMessage("Could not complete the " + "operation. Number of retries has been exhausted."));
assertThat(retries.get(), is(configuredRetries + 1));
assertThat("An error while replacing the ConfigMap should cause an PossibleInconsistentStateException.", ExceptionUtils.findThrowable(ex, PossibleInconsistentStateException.class).isPresent(), is(true));
}
}
Aggregations