org.apache.flink.runtime.jobmaster.slotpool.SingleLogicalSlot 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.jobmaster.slotpool;
import org.apache.flink.runtime.clusterframework.types.AllocationID;
import org.apache.flink.runtime.instance.SlotSharingGroupId;
import org.apache.flink.runtime.jobmanager.scheduler.Locality;
import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
import org.apache.flink.runtime.jobmaster.LogicalSlot;
import org.apache.flink.runtime.jobmaster.SlotContext;
import org.apache.flink.runtime.jobmaster.SlotOwner;
import org.apache.flink.runtime.jobmaster.SlotRequestId;
import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
import org.apache.flink.util.Preconditions;
import javax.annotation.Nullable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.function.Function;
/**
* Implementation of the {@link LogicalSlot} which is used by the {@link SlotPool}.
*/
public class SingleLogicalSlot implements LogicalSlot, AllocatedSlot.Payload {
private static final AtomicReferenceFieldUpdater PAYLOAD_UPDATER = AtomicReferenceFieldUpdater.newUpdater(
SingleLogicalSlot.class,
Payload.class,
"payload");
private static final AtomicReferenceFieldUpdater STATE_UPDATER = AtomicReferenceFieldUpdater.newUpdater(
SingleLogicalSlot.class,
State.class,
"state");
private final SlotRequestId slotRequestId;
private final SlotContext slotContext;
// null if the logical slot does not belong to a slot sharing group, otherwise non-null
@Nullable
private final SlotSharingGroupId slotSharingGroupId;
// locality of this slot wrt the requested preferred locations
private final Locality locality;
// owner of this slot to which it is returned upon release
private final SlotOwner slotOwner;
private final CompletableFuture releaseFuture;
private volatile State state;
// LogicalSlot.Payload of this slot
private volatile Payload payload;
public SingleLogicalSlot(
SlotRequestId slotRequestId,
SlotContext slotContext,
@Nullable SlotSharingGroupId slotSharingGroupId,
Locality locality,
SlotOwner slotOwner) {
this.slotRequestId = Preconditions.checkNotNull(slotRequestId);
this.slotContext = Preconditions.checkNotNull(slotContext);
this.slotSharingGroupId = slotSharingGroupId;
this.locality = Preconditions.checkNotNull(locality);
this.slotOwner = Preconditions.checkNotNull(slotOwner);
this.releaseFuture = new CompletableFuture<>();
this.state = State.ALIVE;
this.payload = null;
}
@Override
public TaskManagerLocation getTaskManagerLocation() {
return slotContext.getTaskManagerLocation();
}
@Override
public TaskManagerGateway getTaskManagerGateway() {
return slotContext.getTaskManagerGateway();
}
@Override
public Locality getLocality() {
return locality;
}
@Override
public boolean isAlive() {
return state == State.ALIVE;
}
@Override
public boolean tryAssignPayload(Payload payload) {
return PAYLOAD_UPDATER.compareAndSet(this, null, payload);
}
@Nullable
@Override
public Payload getPayload() {
return payload;
}
@Override
public CompletableFuture releaseSlot(@Nullable Throwable cause) {
if (STATE_UPDATER.compareAndSet(this, State.ALIVE, State.RELEASING)) {
final CompletableFuture payloadTerminalStateFuture = signalPayloadRelease(cause);
returnSlotToOwner(payloadTerminalStateFuture);
}
return releaseFuture;
}
@Override
public int getPhysicalSlotNumber() {
return slotContext.getPhysicalSlotNumber();
}
@Override
public AllocationID getAllocationId() {
return slotContext.getAllocationId();
}
@Override
public SlotRequestId getSlotRequestId() {
return slotRequestId;
}
@Nullable
@Override
public SlotSharingGroupId getSlotSharingGroupId() {
return slotSharingGroupId;
}
// -------------------------------------------------------------------------
// AllocatedSlot.Payload implementation
// -------------------------------------------------------------------------
/**
* A release of the payload by the {@link AllocatedSlot} triggers a release of the payload of
* the logical slot.
*
* @param cause of the payload release
*/
@Override
public void release(Throwable cause) {
if (STATE_UPDATER.compareAndSet(this, State.ALIVE, State.RELEASING)) {
signalPayloadRelease(cause);
}
markReleased();
releaseFuture.complete(null);
}
private CompletableFuture signalPayloadRelease(Throwable cause) {
tryAssignPayload(TERMINATED_PAYLOAD);
payload.fail(cause);
return payload.getTerminalStateFuture();
}
private void returnSlotToOwner(CompletableFuture terminalStateFuture) {
final CompletableFuture slotReturnFuture = terminalStateFuture.handle((Object ignored, Throwable throwable) -> {
if (state == State.RELEASING) {
return slotOwner.returnAllocatedSlot(this);
} else {
return CompletableFuture.completedFuture(true);
}
}).thenCompose(Function.identity());
slotReturnFuture.whenComplete(
(Object ignored, Throwable throwable) -> {
markReleased();
if (throwable != null) {
releaseFuture.completeExceptionally(throwable);
} else {
releaseFuture.complete(null);
}
});
}
private void markReleased() {
state = State.RELEASED;
}
// -------------------------------------------------------------------------
// Internal classes
// -------------------------------------------------------------------------
enum State {
ALIVE,
RELEASING,
RELEASED
}
}