You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by tr...@apache.org on 2017/12/14 16:42:18 UTC

[01/11] flink git commit: [hotfix] [tests] Speed up queryable state IT tests by removing sleep

Repository: flink
Updated Branches:
  refs/heads/master 331ce82c7 -> 917fbcbee


[hotfix] [tests] Speed up queryable state IT tests by removing sleep


Project: http://git-wip-us.apache.org/repos/asf/flink/repo
Commit: http://git-wip-us.apache.org/repos/asf/flink/commit/917fbcbe
Tree: http://git-wip-us.apache.org/repos/asf/flink/tree/917fbcbe
Diff: http://git-wip-us.apache.org/repos/asf/flink/diff/917fbcbe

Branch: refs/heads/master
Commit: 917fbcbee4599c1d198a4c63942fe1d2762aa64a
Parents: 0ef7fdd
Author: Till Rohrmann <tr...@apache.org>
Authored: Mon Nov 27 09:29:54 2017 +0100
Committer: Till Rohrmann <tr...@apache.org>
Committed: Thu Dec 14 15:26:39 2017 +0100

----------------------------------------------------------------------
 .../itcases/AbstractQueryableStateTestBase.java | 42 ++++++++++----------
 1 file changed, 22 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flink/blob/917fbcbe/flink-queryable-state/flink-queryable-state-runtime/src/test/java/org/apache/flink/queryablestate/itcases/AbstractQueryableStateTestBase.java
----------------------------------------------------------------------
diff --git a/flink-queryable-state/flink-queryable-state-runtime/src/test/java/org/apache/flink/queryablestate/itcases/AbstractQueryableStateTestBase.java b/flink-queryable-state/flink-queryable-state-runtime/src/test/java/org/apache/flink/queryablestate/itcases/AbstractQueryableStateTestBase.java
index 5a28367..73ad7fa 100644
--- a/flink-queryable-state/flink-queryable-state-runtime/src/test/java/org/apache/flink/queryablestate/itcases/AbstractQueryableStateTestBase.java
+++ b/flink-queryable-state/flink-queryable-state-runtime/src/test/java/org/apache/flink/queryablestate/itcases/AbstractQueryableStateTestBase.java
@@ -107,6 +107,7 @@ import static org.junit.Assert.fail;
 public abstract class AbstractQueryableStateTestBase extends TestLogger {
 
 	private static final FiniteDuration TEST_TIMEOUT = new FiniteDuration(10000L, TimeUnit.SECONDS);
+	public static final long RETRY_TIMEOUT = 50L;
 
 	private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(4);
 	private final ScheduledExecutor executor = new ScheduledExecutorServiceAdapter(executorService);
@@ -196,11 +197,12 @@ public abstract class AbstractQueryableStateTestBase extends TestLogger {
 
 			final AtomicLongArray counts = new AtomicLongArray(numKeys);
 
+			final List<CompletableFuture<ReducingState<Tuple2<Integer, Long>>>> futures = new ArrayList<>(numKeys);
+
 			boolean allNonZero = false;
 			while (!allNonZero && deadline.hasTimeLeft()) {
 				allNonZero = true;
-
-				final List<CompletableFuture<ReducingState<Tuple2<Integer, Long>>>> futures = new ArrayList<>(numKeys);
+				futures.clear();
 
 				for (int i = 0; i < numKeys; i++) {
 					final int key = i;
@@ -712,7 +714,7 @@ public abstract class AbstractQueryableStateTestBase extends TestLogger {
 						success = true;
 					} else {
 						// Retry
-						Thread.sleep(50L);
+						Thread.sleep(RETRY_TIMEOUT);
 					}
 				}
 
@@ -785,7 +787,7 @@ public abstract class AbstractQueryableStateTestBase extends TestLogger {
 						success = true;
 					} else {
 						// Retry
-						Thread.sleep(50L);
+						Thread.sleep(RETRY_TIMEOUT);
 					}
 				}
 
@@ -877,7 +879,7 @@ public abstract class AbstractQueryableStateTestBase extends TestLogger {
 						success = true;
 					} else {
 						// Retry
-						Thread.sleep(50L);
+						Thread.sleep(RETRY_TIMEOUT);
 					}
 				}
 
@@ -973,7 +975,7 @@ public abstract class AbstractQueryableStateTestBase extends TestLogger {
 						results.put(key, res);
 					} else {
 						// Retry
-						Thread.sleep(50L);
+						Thread.sleep(RETRY_TIMEOUT);
 					}
 				}
 
@@ -1050,7 +1052,7 @@ public abstract class AbstractQueryableStateTestBase extends TestLogger {
 						success = true;
 					} else {
 						// Retry
-						Thread.sleep(50L);
+						Thread.sleep(RETRY_TIMEOUT);
 					}
 				}
 
@@ -1129,6 +1131,7 @@ public abstract class AbstractQueryableStateTestBase extends TestLogger {
 		private final int numKeys;
 		private final ThreadLocalRandom random = ThreadLocalRandom.current();
 		private volatile boolean isRunning = true;
+		private int counter = 0;
 
 		TestKeyRangeSource(int numKeys) {
 			this.numKeys = numKeys;
@@ -1151,9 +1154,13 @@ public abstract class AbstractQueryableStateTestBase extends TestLogger {
 				synchronized (ctx.getCheckpointLock()) {
 					record.f0 = random.nextInt(numKeys);
 					ctx.collect(record);
+					counter++;
+				}
+
+				if (counter % 50 == 0) {
+					// mild slow down
+					Thread.sleep(1L);
 				}
-				// mild slow down
-				Thread.sleep(1L);
 			}
 		}
 
@@ -1327,7 +1334,7 @@ public abstract class AbstractQueryableStateTestBase extends TestLogger {
 			final TypeInformation<K> keyTypeInfo,
 			final StateDescriptor<S, V> stateDescriptor,
 			final boolean failForUnknownKeyOrNamespace,
-			final ScheduledExecutor executor) throws InterruptedException {
+			final ScheduledExecutor executor) {
 
 		final CompletableFuture<S> resultFuture = new CompletableFuture<>();
 		getKvStateIgnoringCertainExceptions(
@@ -1346,10 +1353,9 @@ public abstract class AbstractQueryableStateTestBase extends TestLogger {
 			final TypeInformation<K> keyTypeInfo,
 			final StateDescriptor<S, V> stateDescriptor,
 			final boolean failForUnknownKeyOrNamespace,
-			final ScheduledExecutor executor) throws InterruptedException {
+			final ScheduledExecutor executor) {
 
 		if (!resultFuture.isDone()) {
-			Thread.sleep(100L);
 			CompletableFuture<S> expected = client.getKvState(jobId, queryName, key, keyTypeInfo, stateDescriptor);
 			expected.whenCompleteAsync((result, throwable) -> {
 				if (throwable != null) {
@@ -1360,13 +1366,9 @@ public abstract class AbstractQueryableStateTestBase extends TestLogger {
 					) {
 						resultFuture.completeExceptionally(throwable.getCause());
 					} else if (deadline.hasTimeLeft()) {
-						try {
-							getKvStateIgnoringCertainExceptions(
-									deadline, resultFuture, client, jobId, queryName, key, keyTypeInfo,
-									stateDescriptor, failForUnknownKeyOrNamespace, executor);
-						} catch (InterruptedException e) {
-							e.printStackTrace();
-						}
+						getKvStateIgnoringCertainExceptions(
+								deadline, resultFuture, client, jobId, queryName, key, keyTypeInfo,
+								stateDescriptor, failForUnknownKeyOrNamespace, executor);
 					}
 				} else {
 					resultFuture.complete(result);
@@ -1410,7 +1412,7 @@ public abstract class AbstractQueryableStateTestBase extends TestLogger {
 					success = true;
 				} else {
 					// Retry
-					Thread.sleep(50L);
+					Thread.sleep(RETRY_TIMEOUT);
 				}
 			}
 


[06/11] flink git commit: [FLINK-7956] [flip6] Add support for queued scheduling with slot sharing to SlotPool

Posted by tr...@apache.org.
http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotPoolRpcTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotPoolRpcTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotPoolRpcTest.java
deleted file mode 100644
index 60e1d34..0000000
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotPoolRpcTest.java
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * 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.instance;
-
-import org.apache.flink.api.common.JobID;
-import org.apache.flink.api.common.time.Time;
-import org.apache.flink.configuration.Configuration;
-import org.apache.flink.runtime.akka.AkkaUtils;
-import org.apache.flink.runtime.clusterframework.types.AllocationID;
-import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
-import org.apache.flink.runtime.jobmanager.scheduler.NoResourceAvailableException;
-import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
-import org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestUtils;
-import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
-import org.apache.flink.runtime.jobmaster.JobMasterId;
-import org.apache.flink.runtime.messages.Acknowledge;
-import org.apache.flink.runtime.resourcemanager.ResourceManagerGateway;
-import org.apache.flink.runtime.resourcemanager.SlotRequest;
-import org.apache.flink.runtime.resourcemanager.utils.TestingResourceManagerGateway;
-import org.apache.flink.runtime.rpc.RpcService;
-import org.apache.flink.runtime.rpc.RpcUtils;
-import org.apache.flink.runtime.rpc.akka.AkkaRpcService;
-import org.apache.flink.runtime.taskexecutor.slot.SlotOffer;
-import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
-import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-import org.apache.flink.runtime.testingUtils.TestingUtils;
-import org.apache.flink.runtime.util.clock.Clock;
-import org.apache.flink.runtime.util.clock.SystemClock;
-import org.apache.flink.util.ExceptionUtils;
-import org.apache.flink.util.Preconditions;
-import org.apache.flink.util.TestLogger;
-
-import akka.actor.ActorSystem;
-import akka.pattern.AskTimeoutException;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.util.Collections;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.function.Consumer;
-
-import static org.apache.flink.runtime.instance.AvailableSlotsTest.DEFAULT_TESTING_PROFILE;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-/**
- * Tests for the SlotPool using a proper RPC setup.
- */
-public class SlotPoolRpcTest extends TestLogger {
-
-	private static RpcService rpcService;
-
-	private static final Time timeout = Time.seconds(10L);
-
-	// ------------------------------------------------------------------------
-	//  setup
-	// ------------------------------------------------------------------------
-
-	@BeforeClass
-	public static void setup() {
-		ActorSystem actorSystem = AkkaUtils.createLocalActorSystem(new Configuration());
-		rpcService = new AkkaRpcService(actorSystem, Time.seconds(10));
-	}
-
-	@AfterClass
-	public static  void shutdown() {
-		if (rpcService != null) {
-			rpcService.stopService();
-			rpcService = null;
-		}
-	}
-
-	// ------------------------------------------------------------------------
-	//  tests
-	// ------------------------------------------------------------------------
-
-	@Test
-	public void testSlotAllocationNoResourceManager() throws Exception {
-		final JobID jid = new JobID();
-		
-		final SlotPool pool = new SlotPool(
-			rpcService,
-			jid,
-			SystemClock.getInstance(),
-			TestingUtils.infiniteTime(),
-			TestingUtils.infiniteTime(),
-			Time.milliseconds(10L) // this is the timeout for the request tested here
-		);
-
-		try {
-			pool.start(JobMasterId.generate(), "foobar");
-
-			CompletableFuture<LogicalSlot> future = pool.allocateSlot(
-				new SlotRequestID(),
-				new ScheduledUnit(SchedulerTestUtils.getDummyTask()),
-				DEFAULT_TESTING_PROFILE,
-				Collections.emptyList(),
-				TestingUtils.infiniteTime());
-
-			try {
-				future.get();
-				fail("We expected an ExecutionException.");
-			} catch (ExecutionException e) {
-				assertTrue(ExceptionUtils.stripExecutionException(e) instanceof NoResourceAvailableException);
-			}
-		} finally {
-			RpcUtils.terminateRpcEndpoint(pool, timeout);
-		}
-	}
-
-	@Test
-	public void testCancelSlotAllocationWithoutResourceManager() throws Exception {
-		final JobID jid = new JobID();
-
-		final TestingSlotPool pool = new TestingSlotPool(
-			rpcService,
-			jid,
-			SystemClock.getInstance(),
-			TestingUtils.infiniteTime(),
-			TestingUtils.infiniteTime(),
-			TestingUtils.infiniteTime());
-
-		try {
-			pool.start(JobMasterId.generate(), "foobar");
-			SlotPoolGateway slotPoolGateway = pool.getSelfGateway(SlotPoolGateway.class);
-
-			SlotRequestID requestId = new SlotRequestID();
-			CompletableFuture<LogicalSlot> future = slotPoolGateway.allocateSlot(
-				requestId,
-				new ScheduledUnit(SchedulerTestUtils.getDummyTask()),
-				DEFAULT_TESTING_PROFILE,
-				Collections.emptyList(),
-				Time.milliseconds(10L));
-
-			try {
-				future.get();
-				fail("We expected a AskTimeoutException.");
-			} catch (ExecutionException e) {
-				assertTrue(ExceptionUtils.stripExecutionException(e) instanceof AskTimeoutException);
-			}
-
-			assertEquals(1L, (long) pool.getNumberOfWaitingForResourceRequests().get());
-
-			slotPoolGateway.cancelSlotRequest(requestId).get();
-
-			assertEquals(0L, (long) pool.getNumberOfWaitingForResourceRequests().get());
-		} finally {
-			RpcUtils.terminateRpcEndpoint(pool, timeout);
-		}
-	}
-
-	@Test
-	public void testCancelSlotAllocationWithResourceManager() throws Exception {
-		final JobID jid = new JobID();
-
-		final TestingSlotPool pool = new TestingSlotPool(
-			rpcService,
-			jid,
-			SystemClock.getInstance(),
-			TestingUtils.infiniteTime(),
-			TestingUtils.infiniteTime(),
-			TestingUtils.infiniteTime());
-
-		try {
-			pool.start(JobMasterId.generate(), "foobar");
-			SlotPoolGateway slotPoolGateway = pool.getSelfGateway(SlotPoolGateway.class);
-
-			ResourceManagerGateway resourceManagerGateway = new TestingResourceManagerGateway();
-			pool.connectToResourceManager(resourceManagerGateway);
-
-			SlotRequestID requestId = new SlotRequestID();
-			CompletableFuture<LogicalSlot> future = slotPoolGateway.allocateSlot(
-				requestId,
-				new ScheduledUnit(SchedulerTestUtils.getDummyTask()),
-				DEFAULT_TESTING_PROFILE,
-				Collections.emptyList(),
-				Time.milliseconds(10L));
-
-			try {
-				future.get();
-				fail("We expected a AskTimeoutException.");
-			} catch (ExecutionException e) {
-				assertTrue(ExceptionUtils.stripExecutionException(e) instanceof AskTimeoutException);
-			}
-
-			assertEquals(1L, (long) pool.getNumberOfPendingRequests().get());
-
-			slotPoolGateway.cancelSlotRequest(requestId).get();
-			assertEquals(0L, (long) pool.getNumberOfPendingRequests().get());
-		} finally {
-			RpcUtils.terminateRpcEndpoint(pool, timeout);
-		}
-	}
-
-	/**
-	 * Tests that allocated slots are not cancelled.
-	 */
-	@Test
-	public void testCancelSlotAllocationWhileSlotFulfilled() throws Exception {
-		final JobID jid = new JobID();
-
-		final TestingSlotPool pool = new TestingSlotPool(
-			rpcService,
-			jid,
-			SystemClock.getInstance(),
-			TestingUtils.infiniteTime(),
-			TestingUtils.infiniteTime(),
-			TestingUtils.infiniteTime());
-
-		try {
-			pool.start(JobMasterId.generate(), "foobar");
-			SlotPoolGateway slotPoolGateway = pool.getSelfGateway(SlotPoolGateway.class);
-
-			final CompletableFuture<AllocationID> allocationIdFuture = new CompletableFuture<>();
-
-			TestingResourceManagerGateway resourceManagerGateway = new TestingResourceManagerGateway();
-			resourceManagerGateway.setRequestSlotConsumer(
-				(SlotRequest slotRequest) -> allocationIdFuture.complete(slotRequest.getAllocationId()));
-
-			pool.connectToResourceManager(resourceManagerGateway);
-
-			SlotRequestID requestId = new SlotRequestID();
-			CompletableFuture<LogicalSlot> future = slotPoolGateway.allocateSlot(
-				requestId,
-				new ScheduledUnit(SchedulerTestUtils.getDummyTask()),
-				DEFAULT_TESTING_PROFILE,
-				Collections.emptyList(),
-				Time.milliseconds(10L));
-
-			try {
-				future.get();
-				fail("We expected a AskTimeoutException.");
-			} catch (ExecutionException e) {
-				assertTrue(ExceptionUtils.stripExecutionException(e) instanceof AskTimeoutException);
-			}
-
-			AllocationID allocationId = allocationIdFuture.get();
-			final SlotOffer slotOffer = new SlotOffer(
-				allocationId,
-				0,
-				DEFAULT_TESTING_PROFILE);
-			final TaskManagerLocation taskManagerLocation = new LocalTaskManagerLocation();
-			final TaskManagerGateway taskManagerGateway = new SimpleAckingTaskManagerGateway();
-
-			slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID()).get();
-
-			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
-
-			assertEquals(0L, (long) pool.getNumberOfPendingRequests().get());
-
-			assertTrue(pool.containsAllocatedSlot(allocationId).get());
-
-			pool.cancelSlotRequest(requestId).get();
-
-			assertFalse(pool.containsAllocatedSlot(allocationId).get());
-			assertTrue(pool.containsAvailableSlot(allocationId).get());
-		} finally {
-			RpcUtils.terminateRpcEndpoint(pool, timeout);
-		}
-	}
-
-	/**
-	 * This case make sure when allocateSlot in ProviderAndOwner timeout,
-	 * it will automatically call cancelSlotAllocation as will inject future.whenComplete in ProviderAndOwner.
-	 */
-	@Test
-	public void testProviderAndOwner() throws Exception {
-		final JobID jid = new JobID();
-
-		final TestingSlotPool pool = new TestingSlotPool(
-			rpcService,
-			jid,
-			SystemClock.getInstance(),
-			Time.milliseconds(10L),
-			TestingUtils.infiniteTime(),
-			TestingUtils.infiniteTime());
-
-		final CompletableFuture<SlotRequestID> cancelFuture = new CompletableFuture<>();
-
-		pool.setCancelSlotAllocationConsumer(
-			slotRequestID -> cancelFuture.complete(slotRequestID));
-
-		try {
-			pool.start(JobMasterId.generate(), "foobar");
-			ResourceManagerGateway resourceManagerGateway = new TestingResourceManagerGateway();
-			pool.connectToResourceManager(resourceManagerGateway);
-
-			ScheduledUnit mockScheduledUnit = new ScheduledUnit(SchedulerTestUtils.getDummyTask());
-
-			// test the pending request is clear when timed out
-			CompletableFuture<LogicalSlot> future = pool.getSlotProvider().allocateSlot(
-				mockScheduledUnit,
-				true,
-				Collections.emptyList());
-
-			try {
-				future.get();
-				fail("We expected a AskTimeoutException.");
-			} catch (ExecutionException e) {
-				assertTrue(ExceptionUtils.stripExecutionException(e) instanceof AskTimeoutException);
-			}
-
-			// wait for the cancel call on the SlotPool
-			cancelFuture.get();
-
-			assertEquals(0L, (long) pool.getNumberOfPendingRequests().get());
-		} finally {
-			RpcUtils.terminateRpcEndpoint(pool, timeout);
-		}
-	}
-
-	/**
-	 * Testing SlotPool which exposes internal state via some testing methods.
-	 */
-	private static final class TestingSlotPool extends SlotPool {
-
-		private volatile Consumer<SlotRequestID> cancelSlotAllocationConsumer;
-
-		public TestingSlotPool(
-				RpcService rpcService,
-				JobID jobId,
-				Clock clock,
-				Time slotRequestTimeout,
-				Time resourceManagerAllocationTimeout,
-				Time resourceManagerRequestTimeout) {
-			super(
-				rpcService,
-				jobId,
-				clock,
-				slotRequestTimeout,
-				resourceManagerAllocationTimeout,
-				resourceManagerRequestTimeout);
-
-			cancelSlotAllocationConsumer = null;
-		}
-
-		public void setCancelSlotAllocationConsumer(Consumer<SlotRequestID> cancelSlotAllocationConsumer) {
-			this.cancelSlotAllocationConsumer = Preconditions.checkNotNull(cancelSlotAllocationConsumer);
-		}
-
-		@Override
-		public CompletableFuture<Acknowledge> cancelSlotRequest(SlotRequestID slotRequestId) {
-			final Consumer<SlotRequestID> currentCancelSlotAllocationConsumer = cancelSlotAllocationConsumer;
-
-			if (currentCancelSlotAllocationConsumer != null) {
-				currentCancelSlotAllocationConsumer.accept(slotRequestId);
-			}
-
-			return super.cancelSlotRequest(slotRequestId);
-		}
-
-		CompletableFuture<Boolean> containsAllocatedSlot(AllocationID allocationId) {
-			return callAsync(
-				() -> getAllocatedSlots().contains(allocationId),
-				timeout);
-		}
-
-		CompletableFuture<Boolean> containsAvailableSlot(AllocationID allocationId) {
-			return callAsync(
-				() -> getAvailableSlots().contains(allocationId),
-				timeout);
-		}
-
-		CompletableFuture<Integer> getNumberOfPendingRequests() {
-			return callAsync(
-				() -> getPendingRequests().size(),
-				timeout);
-		}
-
-		CompletableFuture<Integer> getNumberOfWaitingForResourceRequests() {
-			return callAsync(
-				() -> getWaitingForResourceManager().size(),
-				timeout);
-		}
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotPoolTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotPoolTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotPoolTest.java
deleted file mode 100644
index 1af9cce..0000000
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotPoolTest.java
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- * 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.instance;
-
-import org.apache.flink.api.common.JobID;
-import org.apache.flink.api.common.time.Time;
-import org.apache.flink.runtime.clusterframework.types.AllocationID;
-import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
-import org.apache.flink.runtime.executiongraph.Execution;
-import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
-import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
-import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
-import org.apache.flink.runtime.jobmaster.JobMasterId;
-import org.apache.flink.runtime.messages.Acknowledge;
-import org.apache.flink.runtime.resourcemanager.ResourceManagerGateway;
-import org.apache.flink.runtime.resourcemanager.SlotRequest;
-import org.apache.flink.runtime.resourcemanager.utils.TestingResourceManagerGateway;
-import org.apache.flink.runtime.rpc.RpcService;
-import org.apache.flink.runtime.rpc.RpcUtils;
-import org.apache.flink.runtime.rpc.TestingRpcService;
-import org.apache.flink.runtime.taskexecutor.slot.SlotOffer;
-import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
-import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-import org.apache.flink.util.ExceptionUtils;
-import org.apache.flink.util.FlinkException;
-import org.apache.flink.util.TestLogger;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-
-import static org.apache.flink.runtime.instance.AvailableSlotsTest.DEFAULT_TESTING_PROFILE;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.RETURNS_MOCKS;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class SlotPoolTest extends TestLogger {
-
-	private static final Logger LOG = LoggerFactory.getLogger(SlotPoolTest.class);
-
-	private final Time timeout = Time.seconds(10L);
-
-	private RpcService rpcService;
-
-	private JobID jobId;
-
-	private TaskManagerLocation taskManagerLocation;
-
-	private TaskManagerGateway taskManagerGateway;
-
-	@Before
-	public void setUp() throws Exception {
-		this.rpcService = new TestingRpcService();
-		this.jobId = new JobID();
-
-		taskManagerLocation = new LocalTaskManagerLocation();
-		taskManagerGateway = new SimpleAckingTaskManagerGateway();
-	}
-
-	@After
-	public void tearDown() throws Exception {
-		rpcService.stopService();
-	}
-
-	@Test
-	public void testAllocateSimpleSlot() throws Exception {
-		ResourceManagerGateway resourceManagerGateway = createResourceManagerGatewayMock();
-		final SlotPool slotPool = new SlotPool(rpcService, jobId);
-
-		try {
-			SlotPoolGateway slotPoolGateway = setupSlotPool(slotPool, resourceManagerGateway);
-			slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID());
-
-			SlotRequestID requestId = new SlotRequestID();
-			CompletableFuture<LogicalSlot> future = slotPoolGateway.allocateSlot(requestId, mock(ScheduledUnit.class), DEFAULT_TESTING_PROFILE, null, timeout);
-			assertFalse(future.isDone());
-
-			ArgumentCaptor<SlotRequest> slotRequestArgumentCaptor = ArgumentCaptor.forClass(SlotRequest.class);
-			verify(resourceManagerGateway, Mockito.timeout(timeout.toMilliseconds())).requestSlot(any(JobMasterId.class), slotRequestArgumentCaptor.capture(), any(Time.class));
-
-			final SlotRequest slotRequest = slotRequestArgumentCaptor.getValue();
-
-			final SlotOffer slotOffer = new SlotOffer(
-				slotRequest.getAllocationId(),
-				0,
-				DEFAULT_TESTING_PROFILE);
-
-			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
-
-			LogicalSlot slot = future.get(1, TimeUnit.SECONDS);
-			assertTrue(future.isDone());
-			assertTrue(slot.isAlive());
-			assertEquals(taskManagerLocation, slot.getTaskManagerLocation());
-		} finally {
-			slotPool.shutDown();
-		}
-	}
-
-	@Test
-	public void testAllocationFulfilledByReturnedSlot() throws Exception {
-		ResourceManagerGateway resourceManagerGateway = createResourceManagerGatewayMock();
-		final SlotPool slotPool = new SlotPool(rpcService, jobId);
-
-		try {
-			SlotPoolGateway slotPoolGateway = setupSlotPool(slotPool, resourceManagerGateway);
-			slotPool.registerTaskManager(taskManagerLocation.getResourceID());
-
-			CompletableFuture<LogicalSlot> future1 = slotPoolGateway.allocateSlot(new SlotRequestID(), mock(ScheduledUnit.class), DEFAULT_TESTING_PROFILE, null, timeout);
-			CompletableFuture<LogicalSlot> future2 = slotPoolGateway.allocateSlot(new SlotRequestID(), mock(ScheduledUnit.class), DEFAULT_TESTING_PROFILE, null, timeout);
-
-			assertFalse(future1.isDone());
-			assertFalse(future2.isDone());
-
-			ArgumentCaptor<SlotRequest> slotRequestArgumentCaptor = ArgumentCaptor.forClass(SlotRequest.class);
-			verify(resourceManagerGateway, Mockito.timeout(timeout.toMilliseconds()).times(2))
-				.requestSlot(any(JobMasterId.class), slotRequestArgumentCaptor.capture(), any(Time.class));
-
-			final List<SlotRequest> slotRequests = slotRequestArgumentCaptor.getAllValues();
-
-			final SlotOffer slotOffer = new SlotOffer(
-				slotRequests.get(0).getAllocationId(),
-				0,
-				DEFAULT_TESTING_PROFILE);
-
-			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
-
-			LogicalSlot slot1 = future1.get(1, TimeUnit.SECONDS);
-			assertTrue(future1.isDone());
-			assertFalse(future2.isDone());
-
-			// return this slot to pool
-			slot1.releaseSlot();
-
-			// second allocation fulfilled by previous slot returning
-			LogicalSlot slot2 = future2.get(1, TimeUnit.SECONDS);
-			assertTrue(future2.isDone());
-
-			assertNotEquals(slot1, slot2);
-			assertFalse(slot1.isAlive());
-			assertTrue(slot2.isAlive());
-			assertEquals(slot1.getTaskManagerLocation(), slot2.getTaskManagerLocation());
-			assertEquals(slot1.getPhysicalSlotNumber(), slot2.getPhysicalSlotNumber());
-			assertEquals(slot1.getAllocationId(), slot2.getAllocationId());
-		} finally {
-			slotPool.shutDown();
-		}
-	}
-
-	@Test
-	public void testAllocateWithFreeSlot() throws Exception {
-		ResourceManagerGateway resourceManagerGateway = createResourceManagerGatewayMock();
-		final SlotPool slotPool = new SlotPool(rpcService, jobId);
-
-		try {
-			SlotPoolGateway slotPoolGateway = setupSlotPool(slotPool, resourceManagerGateway);
-			slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID());
-
-			CompletableFuture<LogicalSlot> future1 = slotPoolGateway.allocateSlot(new SlotRequestID(), mock(ScheduledUnit.class), DEFAULT_TESTING_PROFILE, null, timeout);
-			assertFalse(future1.isDone());
-
-			ArgumentCaptor<SlotRequest> slotRequestArgumentCaptor = ArgumentCaptor.forClass(SlotRequest.class);
-			verify(resourceManagerGateway, Mockito.timeout(timeout.toMilliseconds())).requestSlot(any(JobMasterId.class), slotRequestArgumentCaptor.capture(), any(Time.class));
-
-			final SlotRequest slotRequest = slotRequestArgumentCaptor.getValue();
-
-			final SlotOffer slotOffer = new SlotOffer(
-				slotRequest.getAllocationId(),
-				0,
-				DEFAULT_TESTING_PROFILE);
-
-			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
-
-			LogicalSlot slot1 = future1.get(1, TimeUnit.SECONDS);
-			assertTrue(future1.isDone());
-
-			// return this slot to pool
-			slot1.releaseSlot();
-
-			CompletableFuture<LogicalSlot> future2 = slotPoolGateway.allocateSlot(new SlotRequestID(), mock(ScheduledUnit.class), DEFAULT_TESTING_PROFILE, null, timeout);
-
-			// second allocation fulfilled by previous slot returning
-			LogicalSlot slot2 = future2.get(1, TimeUnit.SECONDS);
-			assertTrue(future2.isDone());
-
-			assertNotEquals(slot1, slot2);
-			assertFalse(slot1.isAlive());
-			assertTrue(slot2.isAlive());
-			assertEquals(slot1.getTaskManagerLocation(), slot2.getTaskManagerLocation());
-			assertEquals(slot1.getPhysicalSlotNumber(), slot2.getPhysicalSlotNumber());
-		} finally {
-			slotPool.shutDown();
-		}
-	}
-
-	@Test
-	public void testOfferSlot() throws Exception {
-		ResourceManagerGateway resourceManagerGateway = createResourceManagerGatewayMock();
-		final SlotPool slotPool = new SlotPool(rpcService, jobId);
-
-		try {
-			SlotPoolGateway slotPoolGateway = setupSlotPool(slotPool, resourceManagerGateway);
-			slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID());
-
-			CompletableFuture<LogicalSlot> future = slotPoolGateway.allocateSlot(new SlotRequestID(), mock(ScheduledUnit.class), DEFAULT_TESTING_PROFILE, null, timeout);
-			assertFalse(future.isDone());
-
-			ArgumentCaptor<SlotRequest> slotRequestArgumentCaptor = ArgumentCaptor.forClass(SlotRequest.class);
-			verify(resourceManagerGateway, Mockito.timeout(timeout.toMilliseconds())).requestSlot(any(JobMasterId.class), slotRequestArgumentCaptor.capture(), any(Time.class));
-
-			final SlotRequest slotRequest = slotRequestArgumentCaptor.getValue();
-
-			final SlotOffer slotOffer = new SlotOffer(
-				slotRequest.getAllocationId(),
-				0,
-				DEFAULT_TESTING_PROFILE);
-
-			final TaskManagerLocation invalidTaskManagerLocation = new LocalTaskManagerLocation();
-
-			// slot from unregistered resource
-			assertFalse(slotPoolGateway.offerSlot(invalidTaskManagerLocation, taskManagerGateway, slotOffer).get());
-
-			final SlotOffer nonRequestedSlotOffer = new SlotOffer(
-				new AllocationID(),
-				0,
-				DEFAULT_TESTING_PROFILE);
-
-			// we'll also accept non requested slots
-			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, nonRequestedSlotOffer).get());
-
-			// accepted slot
-			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
-			LogicalSlot slot = future.get(timeout.toMilliseconds(), TimeUnit.MILLISECONDS);
-			assertTrue(slot.isAlive());
-
-			// duplicated offer with using slot
-			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
-			assertTrue(slot.isAlive());
-
-			// duplicated offer with free slot
-			slot.releaseSlot();
-			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
-		} finally {
-			slotPool.shutDown();
-		}
-	}
-
-	@Test
-	public void testReleaseResource() throws Exception {
-		ResourceManagerGateway resourceManagerGateway = createResourceManagerGatewayMock();
-
-		final CompletableFuture<Boolean> slotReturnFuture = new CompletableFuture<>();
-
-		final SlotPool slotPool = new SlotPool(rpcService, jobId) {
-			@Override
-			public void returnAllocatedSlot(SlotRequestID slotRequestId) {
-				super.returnAllocatedSlot(slotRequestId);
-
-				slotReturnFuture.complete(true);
-			}
-		};
-
-		try {
-			SlotPoolGateway slotPoolGateway = setupSlotPool(slotPool, resourceManagerGateway);
-			slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID());
-
-			CompletableFuture<LogicalSlot> future1 = slotPoolGateway.allocateSlot(new SlotRequestID(), mock(ScheduledUnit.class), DEFAULT_TESTING_PROFILE, null, timeout);
-
-			ArgumentCaptor<SlotRequest> slotRequestArgumentCaptor = ArgumentCaptor.forClass(SlotRequest.class);
-			verify(resourceManagerGateway, Mockito.timeout(timeout.toMilliseconds())).requestSlot(any(JobMasterId.class), slotRequestArgumentCaptor.capture(), any(Time.class));
-
-			final SlotRequest slotRequest = slotRequestArgumentCaptor.getValue();
-
-			CompletableFuture<LogicalSlot> future2 = slotPoolGateway.allocateSlot(new SlotRequestID(), mock(ScheduledUnit.class), DEFAULT_TESTING_PROFILE, null, timeout);
-
-			final SlotOffer slotOffer = new SlotOffer(
-				slotRequest.getAllocationId(),
-				0,
-				DEFAULT_TESTING_PROFILE);
-
-			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
-
-			LogicalSlot slot1 = future1.get(1, TimeUnit.SECONDS);
-			assertTrue(future1.isDone());
-			assertFalse(future2.isDone());
-
-			slotPoolGateway.releaseTaskManager(taskManagerLocation.getResourceID());
-
-			// wait until the slot has been returned
-			slotReturnFuture.get();
-
-			assertFalse(slot1.isAlive());
-
-			// slot released and not usable, second allocation still not fulfilled
-			Thread.sleep(10);
-			assertFalse(future2.isDone());
-		} finally {
-			slotPool.shutDown();
-		}
-	}
-
-	/**
-	 * Tests that a slot request is cancelled if it failed with an exception (e.g. TimeoutException).
-	 *
-	 * <p>See FLINK-7870
-	 */
-	@Test
-	public void testSlotRequestCancellationUponFailingRequest() throws Exception {
-		final SlotPool slotPool = new SlotPool(rpcService, jobId);
-		final CompletableFuture<Acknowledge> requestSlotFuture = new CompletableFuture<>();
-		final CompletableFuture<AllocationID> cancelSlotFuture = new CompletableFuture<>();
-		final CompletableFuture<AllocationID> requestSlotFutureAllocationId = new CompletableFuture<>();
-
-		final TestingResourceManagerGateway resourceManagerGateway = new TestingResourceManagerGateway();
-		resourceManagerGateway.setRequestSlotFuture(requestSlotFuture);
-		resourceManagerGateway.setRequestSlotConsumer(slotRequest -> requestSlotFutureAllocationId.complete(slotRequest.getAllocationId()));
-		resourceManagerGateway.setCancelSlotConsumer(allocationID -> cancelSlotFuture.complete(allocationID));
-
-		final ScheduledUnit scheduledUnit = new ScheduledUnit(mock(Execution.class));
-
-		try {
-			slotPool.start(JobMasterId.generate(), "localhost");
-
-			final SlotPoolGateway slotPoolGateway = slotPool.getSelfGateway(SlotPoolGateway.class);
-
-			slotPoolGateway.connectToResourceManager(resourceManagerGateway);
-
-			CompletableFuture<LogicalSlot> slotFuture = slotPoolGateway.allocateSlot(
-				new SlotRequestID(),
-				scheduledUnit,
-				ResourceProfile.UNKNOWN,
-				Collections.emptyList(),
-				timeout);
-
-			requestSlotFuture.completeExceptionally(new FlinkException("Testing exception."));
-
-			try {
-				slotFuture.get();
-				fail("The slot future should not have been completed properly.");
-			} catch (Exception ignored) {
-				// expected
-			}
-
-			// check that a failure triggered the slot request cancellation
-			// with the correct allocation id
-			assertEquals(requestSlotFutureAllocationId.get(), cancelSlotFuture.get());
-		} finally {
-			try {
-				RpcUtils.terminateRpcEndpoint(slotPool, timeout);
-			} catch (Exception e) {
-				LOG.warn("Could not properly terminate the SlotPool.", e);
-			}
-		}
-	}
-
-	/**
-	 * Tests that unused offered slots are directly used to fulfill pending slot
-	 * requests.
-	 *
-	 * <p>See FLINK-8089
-	 */
-	@Test
-	public void testFulfillingSlotRequestsWithUnusedOfferedSlots() throws Exception {
-		final SlotPool slotPool = new SlotPool(rpcService, jobId);
-
-		final JobMasterId jobMasterId = JobMasterId.generate();
-		final String jobMasterAddress = "foobar";
-		final CompletableFuture<AllocationID> allocationIdFuture = new CompletableFuture<>();
-		final TestingResourceManagerGateway resourceManagerGateway = new TestingResourceManagerGateway();
-
-		resourceManagerGateway.setRequestSlotConsumer(
-			(SlotRequest slotRequest) -> allocationIdFuture.complete(slotRequest.getAllocationId()));
-
-		final SlotRequestID slotRequestId1 = new SlotRequestID();
-		final SlotRequestID slotRequestId2 = new SlotRequestID();
-
-		try {
-			slotPool.start(jobMasterId, jobMasterAddress);
-
-			final SlotPoolGateway slotPoolGateway = slotPool.getSelfGateway(SlotPoolGateway.class);
-
-			final ScheduledUnit scheduledUnit = new ScheduledUnit(mock(Execution.class));
-
-			slotPoolGateway.connectToResourceManager(resourceManagerGateway);
-
-			CompletableFuture<LogicalSlot> slotFuture1 = slotPoolGateway.allocateSlot(
-				slotRequestId1,
-				scheduledUnit,
-				ResourceProfile.UNKNOWN,
-				Collections.emptyList(),
-				timeout);
-
-			// wait for the first slot request
-			final AllocationID allocationId = allocationIdFuture.get();
-
-			CompletableFuture<LogicalSlot> slotFuture2 = slotPoolGateway.allocateSlot(
-				slotRequestId2,
-				scheduledUnit,
-				ResourceProfile.UNKNOWN,
-				Collections.emptyList(),
-				timeout);
-
-			slotPoolGateway.cancelSlotRequest(slotRequestId1);
-
-			try {
-				// this should fail with a CancellationException
-				slotFuture1.get();
-				fail("The first slot future should have failed because it was cancelled.");
-			} catch (ExecutionException ee) {
-				assertTrue(ExceptionUtils.stripExecutionException(ee) instanceof CancellationException);
-			}
-
-			final SlotOffer slotOffer = new SlotOffer(allocationId, 0, ResourceProfile.UNKNOWN);
-
-			slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID()).get();
-
-			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
-
-			// the slot offer should fulfill the second slot request
-			assertEquals(allocationId, slotFuture2.get().getAllocationId());
-		} finally {
-			RpcUtils.terminateRpcEndpoint(slotPool, timeout);
-		}
-	}
-
-	private static ResourceManagerGateway createResourceManagerGatewayMock() {
-		ResourceManagerGateway resourceManagerGateway = mock(ResourceManagerGateway.class);
-		when(resourceManagerGateway
-			.requestSlot(any(JobMasterId.class), any(SlotRequest.class), any(Time.class)))
-			.thenReturn(mock(CompletableFuture.class, RETURNS_MOCKS));
-
-		return resourceManagerGateway;
-	}
-
-	private static SlotPoolGateway setupSlotPool(
-			SlotPool slotPool,
-			ResourceManagerGateway resourceManagerGateway) throws Exception {
-		final String jobManagerAddress = "foobar";
-
-		slotPool.start(JobMasterId.generate(), jobManagerAddress);
-
-		slotPool.connectToResourceManager(resourceManagerGateway);
-
-		return slotPool.getSelfGateway(SlotPoolGateway.class);
-	}
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotSharingGroupAssignmentTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotSharingGroupAssignmentTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotSharingGroupAssignmentTest.java
index 28cab72..2407c1d 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotSharingGroupAssignmentTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SlotSharingGroupAssignmentTest.java
@@ -21,8 +21,8 @@ package org.apache.flink.runtime.instance;
 import org.apache.flink.runtime.clusterframework.types.ResourceID;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
 import org.apache.flink.runtime.jobmanager.scheduler.Locality;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
 import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+import org.apache.flink.runtime.jobmaster.SlotOwner;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 import org.apache.flink.util.TestLogger;
 

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/instance/TestingLogicalSlot.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/TestingLogicalSlot.java b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/TestingLogicalSlot.java
deleted file mode 100644
index 2066017..0000000
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/TestingLogicalSlot.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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.instance;
-
-import org.apache.flink.runtime.clusterframework.types.AllocationID;
-import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
-import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
-import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
-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.AtomicReference;
-
-/**
- * Simple testing logical slot for testing purposes.
- */
-public class TestingLogicalSlot implements LogicalSlot {
-
-	private final TaskManagerLocation taskManagerLocation;
-
-	private final TaskManagerGateway taskManagerGateway;
-
-	private final AtomicReference<Payload> payloadReference;
-
-	private final int slotNumber;
-
-	private final CompletableFuture<?> releaseFuture = new CompletableFuture<>();
-	
-	private final AllocationID allocationId;
-
-	private final SlotRequestID slotRequestId;
-
-	public TestingLogicalSlot() {
-		this(
-			new LocalTaskManagerLocation(),
-			new SimpleAckingTaskManagerGateway(),
-			0,
-			new AllocationID(),
-			new SlotRequestID());
-	}
-
-	public TestingLogicalSlot(
-			TaskManagerLocation taskManagerLocation,
-			TaskManagerGateway taskManagerGateway,
-			int slotNumber,
-			AllocationID allocationId,
-			SlotRequestID slotRequestId) {
-		this.taskManagerLocation = Preconditions.checkNotNull(taskManagerLocation);
-		this.taskManagerGateway = Preconditions.checkNotNull(taskManagerGateway);
-		this.payloadReference = new AtomicReference<>();
-		this.slotNumber = slotNumber;
-		this.allocationId = Preconditions.checkNotNull(allocationId);
-		this.slotRequestId = Preconditions.checkNotNull(slotRequestId);
-	}
-
-	@Override
-	public TaskManagerLocation getTaskManagerLocation() {
-		return taskManagerLocation;
-	}
-
-	@Override
-	public TaskManagerGateway getTaskManagerGateway() {
-		return taskManagerGateway;
-	}
-
-	@Override
-	public boolean isAlive() {
-		return !releaseFuture.isDone();
-	}
-
-	@Override
-	public boolean tryAssignPayload(Payload payload) {
-		return payloadReference.compareAndSet(null, payload);
-	}
-
-	@Nullable
-	@Override
-	public Payload getPayload() {
-		return payloadReference.get();
-	}
-
-	@Override
-	public CompletableFuture<?> releaseSlot() {
-		releaseFuture.complete(null);
-
-		return releaseFuture;
-	}
-
-	@Override
-	public int getPhysicalSlotNumber() {
-		return slotNumber;
-	}
-
-	@Override
-	public AllocationID getAllocationId() {
-		return allocationId;
-	}
-
-	@Override
-	public SlotRequestID getSlotRequestId() {
-		return slotRequestId;
-	}
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/instance/TestingPayload.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/TestingPayload.java b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/TestingPayload.java
deleted file mode 100644
index 3369882..0000000
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/TestingPayload.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.instance;
-
-import java.util.concurrent.CompletableFuture;
-
-/**
- * Simple payload implementation for testing purposes.
- */
-public class TestingPayload implements LogicalSlot.Payload {
-
-	private final CompletableFuture<?> terminationFuture;
-
-	public TestingPayload() {
-		this.terminationFuture = new CompletableFuture<>();
-	}
-
-
-	@Override
-	public void fail(Throwable cause) {
-		terminationFuture.complete(null);
-	}
-
-	@Override
-	public CompletableFuture<?> getTerminalStateFuture() {
-		return terminationFuture;
-	}
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/CoLocationConstraintTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/CoLocationConstraintTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/CoLocationConstraintTest.java
index d40ff61..77d162f 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/CoLocationConstraintTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/CoLocationConstraintTest.java
@@ -143,7 +143,7 @@ public class CoLocationConstraintTest {
 			assertEquals(instance2.getTaskManagerLocation(), constraint.getLocation());
 			
 			// release the slot
-			slot2_1.releaseInstanceSlot();
+			slot2_1.releaseSlot();
 
 			// we should still have a location
 			assertTrue(constraint.isAssigned());


[11/11] flink git commit: [FLINK-7956] [flip6] Add support for queued scheduling with slot sharing to SlotPool

Posted by tr...@apache.org.
[FLINK-7956] [flip6] Add support for queued scheduling with slot sharing to SlotPool

This commit adds support for queued scheduling with slot sharing to the
SlotPool. The idea of slot sharing is that multiple tasks can run in the
same slot. Moreover, queued scheduling means that a slot request must not
be completed right away but at a later point in time. This allows to
start new TaskExecutors in case that there are no more slots left.

The main component responsible for the management of shared slots is the
SlotSharingManager. The SlotSharingManager maintains internally a tree-like
structure which stores the SlotContext future of the underlying
AllocatedSlot. Whenever this future is completed potentially pending
LogicalSlot instantiations are executed and sent to the slot requester.

A shared slot is represented by a MultiTaskSlot which can harbour multiple
TaskSlots. A TaskSlot can either be a MultiTaskSlot or a SingleTaskSlot.

In order to represent co-location constraints, we first obtain a root
MultiTaskSlot and then allocate a nested MultiTaskSlot in which the
co-located tasks are allocated. The corresponding SlotRequestID is assigned
to the CoLocationConstraint in order to make the TaskSlot retrievable for
other tasks assigned to the same CoLocationConstraint.

Port SchedulerSlotSharingTest, SchedulerIsolatedTasksTest and
ScheduleWithCoLocationHintTest to run with SlotPool.

Restructure SlotPool components.

Add SlotSharingManagerTest, SlotPoolSlotSharingTest and
SlotPoolCoLocationTest.

This closes #5091.


Project: http://git-wip-us.apache.org/repos/asf/flink/repo
Commit: http://git-wip-us.apache.org/repos/asf/flink/commit/0ef7fdde
Tree: http://git-wip-us.apache.org/repos/asf/flink/tree/0ef7fdde
Diff: http://git-wip-us.apache.org/repos/asf/flink/diff/0ef7fdde

Branch: refs/heads/master
Commit: 0ef7fddeff8430fd40d2d7a1b8a6454fd9416ced
Parents: 331ce82
Author: Till Rohrmann <tr...@apache.org>
Authored: Thu Dec 14 15:24:35 2017 +0100
Committer: Till Rohrmann <tr...@apache.org>
Committed: Thu Dec 14 15:26:39 2017 +0100

----------------------------------------------------------------------
 .../InputChannelDeploymentDescriptor.java       |    2 +-
 .../flink/runtime/executiongraph/Execution.java |   31 +-
 .../runtime/executiongraph/ExecutionGraph.java  |    2 +-
 .../executiongraph/ExecutionGraphBuilder.java   |    2 +-
 .../executiongraph/ExecutionJobVertex.java      |    2 +-
 .../runtime/executiongraph/ExecutionVertex.java |    4 +-
 .../flink/runtime/instance/AllocatedSlot.java   |  287 ----
 .../flink/runtime/instance/DualKeyMap.java      |  162 --
 .../apache/flink/runtime/instance/Instance.java |   10 +-
 .../flink/runtime/instance/LogicalSlot.java     |  123 --
 .../flink/runtime/instance/SharedSlot.java      |   40 +-
 .../flink/runtime/instance/SimpleSlot.java      |   31 +-
 .../runtime/instance/SimpleSlotContext.java     |   70 +
 .../org/apache/flink/runtime/instance/Slot.java |   13 +-
 .../apache/flink/runtime/instance/SlotPool.java | 1219 --------------
 .../flink/runtime/instance/SlotPoolGateway.java |  110 --
 .../flink/runtime/instance/SlotProvider.java    |   52 -
 .../flink/runtime/instance/SlotRequestID.java   |   34 -
 .../instance/SlotSharingGroupAssignment.java    |   45 +-
 .../runtime/instance/SlotSharingGroupId.java    |   32 +
 .../scheduler/CoLocationConstraint.java         |   62 +-
 .../scheduler/NoResourceAvailableException.java |    4 +-
 .../jobmanager/scheduler/ScheduledUnit.java     |  106 +-
 .../runtime/jobmanager/scheduler/Scheduler.java |   38 +-
 .../jobmanager/scheduler/SlotSharingGroup.java  |   11 +-
 .../jobmanager/slots/SimpleSlotContext.java     |   78 -
 .../jobmanager/slots/SlotAndLocality.java       |    6 +-
 .../runtime/jobmanager/slots/SlotContext.java   |   70 -
 .../runtime/jobmanager/slots/SlotOwner.java     |   37 -
 .../flink/runtime/jobmaster/JobMaster.java      |    5 +-
 .../flink/runtime/jobmaster/LogicalSlot.java    |  165 ++
 .../flink/runtime/jobmaster/SlotContext.java    |   61 +
 .../flink/runtime/jobmaster/SlotOwner.java      |   35 +
 .../flink/runtime/jobmaster/SlotRequestId.java  |   37 +
 .../jobmaster/slotpool/AllocatedSlot.java       |  225 +++
 .../slotpool/AllocatedSlotActions.java          |   48 +
 .../runtime/jobmaster/slotpool/DualKeyMap.java  |  172 ++
 .../jobmaster/slotpool/SingleLogicalSlot.java   |  170 ++
 .../runtime/jobmaster/slotpool/SlotPool.java    | 1559 ++++++++++++++++++
 .../jobmaster/slotpool/SlotPoolGateway.java     |  159 ++
 .../jobmaster/slotpool/SlotProvider.java        |   53 +
 .../jobmaster/slotpool/SlotSharingManager.java  |  740 +++++++++
 .../CheckpointSettingsSerializableTest.java     |    2 +-
 .../InputChannelDeploymentDescriptorTest.java   |    2 +-
 .../ArchivedExecutionGraphTest.java             |    2 +-
 .../ExecutionGraphDeploymentTest.java           |    4 +-
 .../ExecutionGraphMetricsTest.java              |    4 +-
 .../ExecutionGraphRestartTest.java              |    2 +-
 .../ExecutionGraphSchedulingTest.java           |   10 +-
 .../ExecutionGraphSuspendTest.java              |    2 +-
 .../executiongraph/ExecutionGraphTestUtils.java |    8 +-
 .../runtime/executiongraph/ExecutionTest.java   |    4 +-
 .../ExecutionVertexDeploymentTest.java          |    4 +-
 .../ExecutionVertexLocalityTest.java            |   10 +-
 .../ExecutionVertexSchedulingTest.java          |    4 +-
 .../executiongraph/FailoverRegionTest.java      |    2 +-
 .../IndividualRestartsConcurrencyTest.java      |    2 +-
 .../executiongraph/LegacyJobVertexIdTest.java   |    2 +-
 .../PipelinedRegionFailoverConcurrencyTest.java |    2 +-
 .../executiongraph/ProgrammedSlotProvider.java  |    4 +-
 .../PipelinedFailoverRegionBuildingTest.java    |    2 +-
 .../utils/SimpleSlotProvider.java               |   12 +-
 .../runtime/instance/AllocatedSlotsTest.java    |  149 --
 .../runtime/instance/AvailableSlotsTest.java    |  122 --
 .../flink/runtime/instance/InstanceTest.java    |    8 +-
 .../flink/runtime/instance/SharedSlotsTest.java |   42 +-
 .../flink/runtime/instance/SimpleSlotTest.java  |    5 +-
 .../flink/runtime/instance/SlotPoolRpcTest.java |  397 -----
 .../flink/runtime/instance/SlotPoolTest.java    |  479 ------
 .../SlotSharingGroupAssignmentTest.java         |    2 +-
 .../runtime/instance/TestingLogicalSlot.java    |  122 --
 .../flink/runtime/instance/TestingPayload.java  |   44 -
 .../scheduler/CoLocationConstraintTest.java     |    2 +-
 .../ScheduleWithCoLocationHintTest.java         |  953 +++++------
 .../scheduler/SchedulerIsolatedTasksTest.java   |  519 +++---
 .../scheduler/SchedulerSlotSharingTest.java     |  683 ++++----
 .../jobmanager/scheduler/SchedulerTest.java     |   91 +
 .../jobmanager/scheduler/SchedulerTestBase.java |  416 +++++
 .../scheduler/SchedulerTestUtils.java           |   60 +-
 .../jobmanager/slots/DummySlotOwner.java        |    3 +-
 .../jobmanager/slots/TestingSlotOwner.java      |    3 +-
 .../runtime/jobmaster/TestingLogicalSlot.java   |  140 ++
 .../flink/runtime/jobmaster/TestingPayload.java |   44 +
 .../jobmaster/slotpool/AllocatedSlotsTest.java  |  148 ++
 .../jobmaster/slotpool/AvailableSlotsTest.java  |  120 ++
 .../slotpool/SlotPoolCoLocationTest.java        |  138 ++
 .../jobmaster/slotpool/SlotPoolRpcTest.java     |  409 +++++
 .../slotpool/SlotPoolSchedulingTestBase.java    |   95 ++
 .../slotpool/SlotPoolSlotSharingTest.java       |  304 ++++
 .../jobmaster/slotpool/SlotPoolTest.java        |  550 ++++++
 .../slotpool/SlotSharingManagerTest.java        |  519 ++++++
 .../slotpool/TestingAllocatedSlotActions.java   |   52 +
 .../flink/test/recovery/FastFailuresITCase.java |    2 +
 93 files changed, 7895 insertions(+), 4922 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/deployment/InputChannelDeploymentDescriptor.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/deployment/InputChannelDeploymentDescriptor.java b/flink-runtime/src/main/java/org/apache/flink/runtime/deployment/InputChannelDeploymentDescriptor.java
index 8d76207..7c2b30d 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/deployment/InputChannelDeploymentDescriptor.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/deployment/InputChannelDeploymentDescriptor.java
@@ -24,11 +24,11 @@ import org.apache.flink.runtime.executiongraph.Execution;
 import org.apache.flink.runtime.executiongraph.ExecutionEdge;
 import org.apache.flink.runtime.executiongraph.ExecutionGraphException;
 import org.apache.flink.runtime.executiongraph.IntermediateResultPartition;
-import org.apache.flink.runtime.instance.LogicalSlot;
 import org.apache.flink.runtime.io.network.ConnectionID;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionID;
 import org.apache.flink.runtime.io.network.partition.consumer.InputChannel;
 import org.apache.flink.runtime.io.network.partition.consumer.SingleInputGate;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 
 import java.io.Serializable;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/Execution.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/Execution.java b/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/Execution.java
index 12a6749..cc35060 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/Execution.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/Execution.java
@@ -33,8 +33,9 @@ import org.apache.flink.runtime.deployment.PartialInputChannelDeploymentDescript
 import org.apache.flink.runtime.deployment.ResultPartitionLocation;
 import org.apache.flink.runtime.deployment.TaskDeploymentDescriptor;
 import org.apache.flink.runtime.execution.ExecutionState;
-import org.apache.flink.runtime.instance.LogicalSlot;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.io.network.ConnectionID;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionID;
 import org.apache.flink.runtime.jobmanager.scheduler.CoLocationConstraint;
@@ -51,6 +52,8 @@ import org.apache.flink.util.FlinkRuntimeException;
 
 import org.slf4j.Logger;
 
+import javax.annotation.Nullable;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -441,9 +444,11 @@ public class Execution implements AccessExecution, Archiveable<ArchivedExecution
 		// this method only works if the execution is in the state 'CREATED'
 		if (transitionState(CREATED, SCHEDULED)) {
 
+			final SlotSharingGroupId slotSharingGroupId = sharingGroup != null ? sharingGroup.getSlotSharingGroupId() : null;
+
 			ScheduledUnit toSchedule = locationConstraint == null ?
-					new ScheduledUnit(this, sharingGroup) :
-					new ScheduledUnit(this, sharingGroup, locationConstraint);
+					new ScheduledUnit(this, slotSharingGroupId) :
+					new ScheduledUnit(this, slotSharingGroupId, locationConstraint);
 
 			// calculate the preferred locations
 			final CompletableFuture<Collection<TaskManagerLocation>> preferredLocationsFuture = calculatePreferredLocations(locationPreferenceConstraint);
@@ -461,7 +466,7 @@ public class Execution implements AccessExecution, Archiveable<ArchivedExecution
 							return this;
 						} else {
 							// release the slot
-							logicalSlot.releaseSlot();
+							logicalSlot.releaseSlot(new FlinkException("Could not assign logical slot to execution " + this + '.'));
 
 							throw new CompletionException(new FlinkException("Could not assign slot " + logicalSlot + " to execution " + this + " because it has already been assigned "));
 						}
@@ -513,7 +518,7 @@ public class Execution implements AccessExecution, Archiveable<ArchivedExecution
 
 			// race double check, did we fail/cancel and do we need to release the slot?
 			if (this.state != DEPLOYING) {
-				slot.releaseSlot();
+				slot.releaseSlot(new FlinkException("Actual state of execution " + this + " (" + state + ") does not match expected state DEPLOYING."));
 				return;
 			}
 
@@ -622,7 +627,7 @@ public class Execution implements AccessExecution, Archiveable<ArchivedExecution
 					try {
 						vertex.getExecutionGraph().deregisterExecution(this);
 
-						releaseAssignedResource();
+						releaseAssignedResource(new FlinkException("Execution " + this + " was cancelled."));
 					}
 					finally {
 						vertex.executionCanceled(this);
@@ -890,7 +895,7 @@ public class Execution implements AccessExecution, Archiveable<ArchivedExecution
 
 						updateAccumulatorsAndMetrics(userAccumulators, metrics);
 
-						releaseAssignedResource();
+						releaseAssignedResource(null);
 
 						vertex.getExecutionGraph().deregisterExecution(this);
 					}
@@ -943,7 +948,7 @@ public class Execution implements AccessExecution, Archiveable<ArchivedExecution
 
 				if (transitionState(current, CANCELED)) {
 					try {
-						releaseAssignedResource();
+						releaseAssignedResource(new FlinkException("Execution " + this + " was cancelled."));
 
 						vertex.getExecutionGraph().deregisterExecution(this);
 					}
@@ -1035,7 +1040,7 @@ public class Execution implements AccessExecution, Archiveable<ArchivedExecution
 				updateAccumulatorsAndMetrics(userAccumulators, metrics);
 
 				try {
-					releaseAssignedResource();
+					releaseAssignedResource(t);
 					vertex.getExecutionGraph().deregisterExecution(this);
 				}
 				finally {
@@ -1176,12 +1181,14 @@ public class Execution implements AccessExecution, Archiveable<ArchivedExecution
 	/**
 	 * Releases the assigned resource and completes the release future
 	 * once the assigned resource has been successfully released
+	 *
+	 * @param cause for the resource release, null if none 	 
 	 */
-	private void releaseAssignedResource() {
+	private void releaseAssignedResource(@Nullable Throwable cause) {
 		final LogicalSlot slot = assignedResource;
 
 		if (slot != null) {
-			slot.releaseSlot().whenComplete(
+			slot.releaseSlot(cause).whenComplete(
 				(Object ignored, Throwable throwable) -> {
 					if (throwable != null) {
 						releaseFuture.completeExceptionally(throwable);

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionGraph.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionGraph.java b/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionGraph.java
index c4ff6fb..a02a687 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionGraph.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionGraph.java
@@ -50,7 +50,7 @@ import org.apache.flink.runtime.executiongraph.failover.RestartAllStrategy;
 import org.apache.flink.runtime.executiongraph.restart.ExecutionGraphRestartCallback;
 import org.apache.flink.runtime.executiongraph.restart.RestartCallback;
 import org.apache.flink.runtime.executiongraph.restart.RestartStrategy;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionID;
 import org.apache.flink.runtime.jobgraph.IntermediateDataSetID;
 import org.apache.flink.runtime.jobgraph.JobStatus;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionGraphBuilder.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionGraphBuilder.java b/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionGraphBuilder.java
index 2a4315d..34ba3df 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionGraphBuilder.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionGraphBuilder.java
@@ -43,7 +43,7 @@ import org.apache.flink.runtime.executiongraph.metrics.NumberOfFullRestartsGauge
 import org.apache.flink.runtime.executiongraph.metrics.RestartTimeGauge;
 import org.apache.flink.runtime.executiongraph.metrics.UpTimeGauge;
 import org.apache.flink.runtime.executiongraph.restart.RestartStrategy;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.jobgraph.JobGraph;
 import org.apache.flink.runtime.jobgraph.JobVertex;
 import org.apache.flink.runtime.jobgraph.JobVertexID;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionJobVertex.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionJobVertex.java b/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionJobVertex.java
index fff7ce1..bb5ad28 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionJobVertex.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionJobVertex.java
@@ -35,7 +35,7 @@ import org.apache.flink.runtime.accumulators.StringifiedAccumulatorResult;
 import org.apache.flink.runtime.blob.BlobWriter;
 import org.apache.flink.runtime.blob.PermanentBlobKey;
 import org.apache.flink.runtime.execution.ExecutionState;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.jobgraph.IntermediateDataSet;
 import org.apache.flink.runtime.jobgraph.IntermediateDataSetID;
 import org.apache.flink.runtime.jobgraph.JobEdge;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionVertex.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionVertex.java b/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionVertex.java
index 27f2d5d..cb4f2c8 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionVertex.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/executiongraph/ExecutionVertex.java
@@ -32,9 +32,9 @@ import org.apache.flink.runtime.deployment.PartialInputChannelDeploymentDescript
 import org.apache.flink.runtime.deployment.ResultPartitionDeploymentDescriptor;
 import org.apache.flink.runtime.deployment.TaskDeploymentDescriptor;
 import org.apache.flink.runtime.execution.ExecutionState;
-import org.apache.flink.runtime.instance.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
 import org.apache.flink.runtime.instance.SimpleSlot;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionID;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionType;
 import org.apache.flink.runtime.jobgraph.DistributionPattern;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/AllocatedSlot.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/AllocatedSlot.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/AllocatedSlot.java
deleted file mode 100644
index 97be592..0000000
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/AllocatedSlot.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * 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.instance;
-
-import org.apache.flink.runtime.clusterframework.types.AllocationID;
-import org.apache.flink.runtime.clusterframework.types.ResourceID;
-import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
-import org.apache.flink.runtime.jobmanager.scheduler.Locality;
-import org.apache.flink.runtime.jobmanager.slots.SlotContext;
-import org.apache.flink.runtime.jobmanager.slots.SlotException;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
-import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
-import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-import org.apache.flink.util.Preconditions;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-import static org.apache.flink.util.Preconditions.checkNotNull;
-
-/**
- * The {@code AllocatedSlot} represents a slot that the JobManager allocated from a TaskManager.
- * It represents a slice of allocated resources from the TaskManager.
- * 
- * <p>To allocate an {@code AllocatedSlot}, the requests a slot from the ResourceManager. The
- * ResourceManager picks (or starts) a TaskManager that will then allocate the slot to the
- * JobManager and notify the JobManager.
- * 
- * <p>Note: Prior to the resource management changes introduced in (Flink Improvement Proposal 6),
- * an AllocatedSlot was allocated to the JobManager as soon as the TaskManager registered at the
- * JobManager. All slots had a default unknown resource profile. 
- */
-public class AllocatedSlot {
-
-	/** The ID under which the slot is allocated. Uniquely identifies the slot. */
-	private final AllocationID allocationId;
-
-	/** The location information of the TaskManager to which this slot belongs */
-	private final TaskManagerLocation taskManagerLocation;
-
-	/** The resource profile of the slot provides */
-	private final ResourceProfile resourceProfile;
-
-	/** RPC gateway to call the TaskManager that holds this slot */
-	private final TaskManagerGateway taskManagerGateway;
-
-	/** The number of the slot on the TaskManager to which slot belongs. Purely informational. */
-	private final int physicalSlotNumber;
-
-	private final SlotOwner slotOwner;
-
-	private final AtomicReference<LogicalSlot> logicalSlotReference;
-
-	// ------------------------------------------------------------------------
-
-	public AllocatedSlot(
-			AllocationID allocationId,
-			TaskManagerLocation location,
-			int physicalSlotNumber,
-			ResourceProfile resourceProfile,
-			TaskManagerGateway taskManagerGateway,
-			SlotOwner slotOwner) {
-		this.allocationId = checkNotNull(allocationId);
-		this.taskManagerLocation = checkNotNull(location);
-		this.physicalSlotNumber = physicalSlotNumber;
-		this.resourceProfile = checkNotNull(resourceProfile);
-		this.taskManagerGateway = checkNotNull(taskManagerGateway);
-		this.slotOwner = checkNotNull(slotOwner);
-
-		logicalSlotReference = new AtomicReference<>(null);
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Gets the ID under which the slot is allocated, which uniquely identifies the slot.
-	 * 
-	 * @return The ID under which the slot is allocated
-	 */
-	public AllocationID getAllocationId() {
-		return allocationId;
-	}
-
-	/**
-	 * Gets the ID of the TaskManager on which this slot was allocated.
-	 * 
-	 * <p>This is equivalent to {@link #getTaskManagerLocation()#getTaskManagerId()}.
-	 * 
-	 * @return This slot's TaskManager's ID.
-	 */
-	public ResourceID getTaskManagerId() {
-		return getTaskManagerLocation().getResourceID();
-	}
-
-	/**
-	 * Gets the resource profile of the slot.
-	 *
-	 * @return The resource profile of the slot.
-	 */
-	public ResourceProfile getResourceProfile() {
-		return resourceProfile;
-	}
-
-	/**
-	 * Gets the location info of the TaskManager that offers this slot.
-	 *
-	 * @return The location info of the TaskManager that offers this slot
-	 */
-	public TaskManagerLocation getTaskManagerLocation() {
-		return taskManagerLocation;
-	}
-
-	/**
-	 * Gets the actor gateway that can be used to send messages to the TaskManager.
-	 * <p>
-	 * This method should be removed once the new interface-based RPC abstraction is in place
-	 *
-	 * @return The actor gateway that can be used to send messages to the TaskManager.
-	 */
-	public TaskManagerGateway getTaskManagerGateway() {
-		return taskManagerGateway;
-	}
-
-	/**
-	 * Returns true if this slot is not being used (e.g. a logical slot is allocated from this slot).
-	 *
-	 * @return true if a logical slot is allocated from this slot, otherwise false
-	 */
-	public boolean isUsed() {
-		return logicalSlotReference.get() != null;
-	}
-
-	/**
-	 * Triggers the release of the logical slot.
-	 */
-	public void triggerLogicalSlotRelease() {
-		final LogicalSlot logicalSlot = logicalSlotReference.get();
-
-		if (logicalSlot != null) {
-			logicalSlot.releaseSlot();
-		}
-	}
-
-	/**
-	 * Releases the logical slot.
-	 *
-	 * @return true if the logical slot could be released, false otherwise.
-	 */
-	public boolean releaseLogicalSlot() {
-		final LogicalSlot logicalSlot = logicalSlotReference.get();
-
-		if (logicalSlot != null) {
-			if (logicalSlot instanceof Slot) {
-				final Slot slot = (Slot) logicalSlot;
-				if (slot.markReleased()) {
-					logicalSlotReference.set(null);
-					return true;
-				}
-			} else {
-				throw new RuntimeException("Unsupported logical slot type encountered " + logicalSlot.getClass());
-			}
-
-		}
-
-		return false;
-	}
-
-	/**
-	 * Allocates a logical {@link SimpleSlot}.
-	 *
-	 * @param slotRequestId identifying the corresponding slot request
-	 * @param locality specifying the locality of the allocated slot
-	 * @return an allocated logical simple slot
-	 * @throws SlotException if we could not allocate a simple slot
-	 */
-	public SimpleSlot allocateSimpleSlot(SlotRequestID slotRequestId, Locality locality) throws SlotException {
-		final AllocatedSlotContext allocatedSlotContext = new AllocatedSlotContext(
-			slotRequestId);
-
-		final SimpleSlot simpleSlot = new SimpleSlot(allocatedSlotContext, slotOwner, physicalSlotNumber);
-
-		if (logicalSlotReference.compareAndSet(null, simpleSlot)) {
-			simpleSlot.setLocality(locality);
-			return simpleSlot;
-		} else {
-			throw new SlotException("Could not allocate logical simple slot because the allocated slot is already used.");
-		}
-	}
-
-	/**
-	 * Allocates a logical {@link SharedSlot}.
-	 *
-	 * @param slotRequestId identifying the corresponding slot request
-	 * @param slotSharingGroupAssignment the slot sharing group to which the shared slot shall belong
-	 * @return an allocated logical shared slot
-	 * @throws SlotException if we could not allocate a shared slot
-	 */
-	public SharedSlot allocateSharedSlot(SlotRequestID slotRequestId, SlotSharingGroupAssignment slotSharingGroupAssignment) throws SlotException {
-
-		final AllocatedSlotContext allocatedSlotContext = new AllocatedSlotContext(
-			slotRequestId);
-		final SharedSlot sharedSlot = new SharedSlot(allocatedSlotContext, slotOwner, slotSharingGroupAssignment);
-
-		if (logicalSlotReference.compareAndSet(null, sharedSlot)) {
-
-
-			return sharedSlot;
-		} else {
-			throw new SlotException("Could not allocate logical shared slot because the allocated slot is already used.");
-		}
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * This always returns a reference hash code.
-	 */
-	@Override
-	public final int hashCode() {
-		return super.hashCode();
-	}
-
-	/**
-	 * This always checks based on reference equality.
-	 */
-	@Override
-	public final boolean equals(Object obj) {
-		return this == obj;
-	}
-
-	@Override
-	public String toString() {
-		return "AllocatedSlot " + allocationId + " @ " + taskManagerLocation + " - " + physicalSlotNumber;
-	}
-
-	/**
-	 * Slot context for {@link AllocatedSlot}.
-	 */
-	private final class AllocatedSlotContext implements SlotContext {
-
-		private final SlotRequestID slotRequestId;
-
-		private AllocatedSlotContext(SlotRequestID slotRequestId) {
-			this.slotRequestId = Preconditions.checkNotNull(slotRequestId);
-		}
-
-		@Override
-		public SlotRequestID getSlotRequestId() {
-			return slotRequestId;
-		}
-
-		@Override
-		public AllocationID getAllocationId() {
-			return allocationId;
-		}
-
-		@Override
-		public TaskManagerLocation getTaskManagerLocation() {
-			return taskManagerLocation;
-		}
-
-		@Override
-		public int getPhysicalSlotNumber() {
-			return physicalSlotNumber;
-		}
-
-		@Override
-		public TaskManagerGateway getTaskManagerGateway() {
-			return taskManagerGateway;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/DualKeyMap.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/DualKeyMap.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/DualKeyMap.java
deleted file mode 100644
index 741d137..0000000
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/DualKeyMap.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * 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.instance;
-
-import org.apache.flink.api.java.tuple.Tuple2;
-
-import java.util.AbstractCollection;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-
-/**
- * Map which stores values under two different indices.
- *
- * @param <A> Type of key A
- * @param <B> Type of key B
- * @param <V> Type of the value
- */
-public class DualKeyMap<A, B, V> {
-
-	private final HashMap<A, Tuple2<B, V>> aMap;
-
-	private final HashMap<B, A> bMap;
-
-	private transient Collection<V> values;
-
-	public DualKeyMap(int initialCapacity) {
-		this.aMap = new HashMap<>(initialCapacity);
-		this.bMap = new HashMap<>(initialCapacity);
-	}
-
-	public int size() {
-		return aMap.size();
-	}
-
-	public V getKeyA(A aKey) {
-		final Tuple2<B, V> value = aMap.get(aKey);
-
-		if (value != null) {
-			return value.f1;
-		} else {
-			return null;
-		}
-	}
-
-	public V getKeyB(B bKey) {
-		final A aKey = bMap.get(bKey);
-
-		if (aKey != null) {
-			return aMap.get(aKey).f1;
-		} else {
-			return null;
-		}
-	}
-
-	public V put(A aKey, B bKey, V value) {
-		Tuple2<B, V> aValue = aMap.put(aKey, Tuple2.of(bKey, value));
-		bMap.put(bKey, aKey);
-
-		if (aValue != null) {
-			return aValue.f1;
-		} else {
-			return null;
-		}
-	}
-
-	public boolean containsKeyA(A aKey) {
-		return aMap.containsKey(aKey);
-	}
-
-	public boolean containsKeyB(B bKey) {
-		return bMap.containsKey(bKey);
-	}
-
-	public V removeKeyA(A aKey) {
-		Tuple2<B, V> aValue = aMap.remove(aKey);
-
-		if (aValue != null) {
-			bMap.remove(aValue.f0);
-			return aValue.f1;
-		} else {
-			return null;
-		}
-	}
-
-	public V removeKeyB(B bKey) {
-		A aKey = bMap.remove(bKey);
-
-		if (aKey != null) {
-			Tuple2<B, V> aValue = aMap.remove(aKey);
-			if (aValue != null) {
-				return aValue.f1;
-			} else {
-				return null;
-			}
-		} else {
-			return null;
-		}
-	}
-
-	public Collection<V> values() {
-		Collection<V> vs = values;
-
-		if (vs == null) {
-			vs = new Values();
-			values = vs;
-		}
-
-		return vs;
-	}
-
-	public void clear() {
-		aMap.clear();
-		bMap.clear();
-	}
-
-	private final class Values extends AbstractCollection<V> {
-
-		@Override
-		public Iterator<V> iterator() {
-			return new ValueIterator();
-		}
-
-		@Override
-		public int size() {
-			return aMap.size();
-		}
-	}
-
-	private final class ValueIterator implements Iterator<V> {
-
-		private final Iterator<Tuple2<B, V>> iterator = aMap.values().iterator();
-
-		@Override
-		public boolean hasNext() {
-			return iterator.hasNext();
-		}
-
-		@Override
-		public V next() {
-			Tuple2<B, V> value = iterator.next();
-
-			return value.f1;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/Instance.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/Instance.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/Instance.java
index 44ee29d..0878f75 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/Instance.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/Instance.java
@@ -20,9 +20,11 @@ package org.apache.flink.runtime.instance;
 
 import org.apache.flink.runtime.clusterframework.types.ResourceID;
 import org.apache.flink.runtime.jobmanager.scheduler.SlotAvailabilityListener;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
 import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.SlotOwner;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+import org.apache.flink.util.FlinkException;
 import org.apache.flink.util.Preconditions;
 
 import org.slf4j.Logger;
@@ -163,8 +165,9 @@ public class Instance implements SlotOwner {
 		 * owning the assignment group lock wants to give itself back to the instance which requires
 		 * the instance lock
 		 */
+		final FlinkException cause = new FlinkException("Instance " + this + " has been marked as dead.");
 		for (Slot slot : slots) {
-			slot.releaseInstanceSlot();
+			slot.releaseSlot(cause);
 		}
 	}
 
@@ -321,8 +324,9 @@ public class Instance implements SlotOwner {
 			copy = new ArrayList<Slot>(this.allocatedSlots);
 		}
 
+		final FlinkException cause = new FlinkException("Cancel and release all slots of instance " + this + '.');
 		for (Slot slot : copy) {
-			slot.releaseInstanceSlot();
+			slot.releaseSlot(cause);
 		}
 	}
 

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/LogicalSlot.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/LogicalSlot.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/LogicalSlot.java
deleted file mode 100644
index b3104ac..0000000
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/LogicalSlot.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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.instance;
-
-import org.apache.flink.runtime.clusterframework.types.AllocationID;
-import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
-import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-
-import javax.annotation.Nullable;
-
-import java.util.concurrent.CompletableFuture;
-
-/**
- * A logical slot represents a resource on a TaskManager into
- * which a single task can be deployed.
- */
-public interface LogicalSlot {
-
-	/**
-	 * Return the TaskManager location of this slot
-	 *
-	 * @return TaskManager location of this slot
-	 */
-	TaskManagerLocation getTaskManagerLocation();
-
-	/**
-	 * Return the TaskManager gateway to talk to the TaskManager.
-	 *
-	 * @return TaskManager gateway to talk to the TaskManager
-	 */
-	TaskManagerGateway getTaskManagerGateway();
-
-	/**
-	 * True if the slot is still alive.
-	 *
-	 * @return True if the slot is still alive, otherwise false
-	 */
-	boolean isAlive();
-
-	/**
-	 * Tries to assign a payload to this slot. This can only happens
-	 * exactly once.
-	 *
-	 * @param payload to be assigned to this slot.
-	 * @return true if the payload could be set, otherwise false
-	 */
-	boolean tryAssignPayload(Payload payload);
-
-	/**
-	 * Returns the set payload or null if none.
-	 *
-	 * @return Payload of this slot of null if none
-	 */
-	@Nullable
-	Payload getPayload();
-
-	/**
-	 * Releases this slot.
-	 *
-	 * @return Future which is completed once the slot has been released,
-	 * 		in case of a failure it is completed exceptionally
-	 */
-	CompletableFuture<?> releaseSlot();
-
-	/**
-	 * Gets the slot number on the TaskManager.
-	 *
-	 * @return slot number
-	 */
-	int getPhysicalSlotNumber();
-
-	/**
-	 * Gets the allocation id of this slot.
-	 *
-	 * @return allocation id of this slot
-	 */
-	AllocationID getAllocationId();
-
-	/**
-	 * Gets the slot request id uniquely identifying the request with which this
-	 * slot has been allocated.
-	 *
-	 * @return Unique id identifying the slot request with which this slot was allocated
-	 */
-	SlotRequestID getSlotRequestId();
-
-	/**
-	 * Payload for a logical slot.
-	 */
-	interface Payload {
-
-		/**
-		 * Fail the payload with the given cause.
-		 *
-		 * @param cause of the failure
-		 */
-		void fail(Throwable cause);
-
-		/**
-		 * Gets the terminal state future which is completed once the payload
-		 * has reached a terminal state.
-		 *
-		 * @return Terminal state future
-		 */
-		CompletableFuture<?> getTerminalStateFuture();
-	}
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SharedSlot.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SharedSlot.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SharedSlot.java
index 8c9fe1a..d922d7c 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SharedSlot.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SharedSlot.java
@@ -19,12 +19,14 @@
 package org.apache.flink.runtime.instance;
 
 import org.apache.flink.runtime.clusterframework.types.AllocationID;
-import org.apache.flink.runtime.jobmanager.slots.SlotContext;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
+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.AbstractID;
-import org.apache.flink.util.FlinkException;
 
 import javax.annotation.Nullable;
 
@@ -55,8 +57,6 @@ public class SharedSlot extends Slot implements LogicalSlot {
 	/** The set os sub-slots allocated from this shared slot */
 	private final Set<Slot> subSlots;
 
-	private final CompletableFuture<?> cancellationFuture = new CompletableFuture<>();
-
 	// ------------------------------------------------------------------------
 	//  Old Constructors (prior FLIP-6)
 	// ------------------------------------------------------------------------
@@ -72,9 +72,9 @@ public class SharedSlot extends Slot implements LogicalSlot {
 	 * @param assignmentGroup The assignment group that this shared slot belongs to.
 	 */
 	public SharedSlot(
-			SlotOwner owner, TaskManagerLocation location, int slotNumber,
-			TaskManagerGateway taskManagerGateway,
-			SlotSharingGroupAssignment assignmentGroup) {
+		SlotOwner owner, TaskManagerLocation location, int slotNumber,
+		TaskManagerGateway taskManagerGateway,
+		SlotSharingGroupAssignment assignmentGroup) {
 
 		this(owner, location, slotNumber, taskManagerGateway, assignmentGroup, null, null);
 	}
@@ -175,6 +175,11 @@ public class SharedSlot extends Slot implements LogicalSlot {
 	}
 
 	@Override
+	public Locality getLocality() {
+		return Locality.UNKNOWN;
+	}
+
+	@Override
 	public boolean tryAssignPayload(Payload payload) {
 		throw new UnsupportedOperationException("Cannot assign an execution attempt id to a shared slot.");
 	}
@@ -186,9 +191,7 @@ public class SharedSlot extends Slot implements LogicalSlot {
 	}
 
 	@Override
-	public CompletableFuture<?> releaseSlot() {
-		cancellationFuture.completeExceptionally(new FlinkException("Shared slot " + this + " is being released."));
-
+	public CompletableFuture<?> releaseSlot(@Nullable Throwable cause) {
 		assignmentGroup.releaseSharedSlot(this);
 
 		if (!(isReleased() && subSlots.isEmpty())) {
@@ -199,11 +202,6 @@ public class SharedSlot extends Slot implements LogicalSlot {
 	}
 
 	@Override
-	public void releaseInstanceSlot() {
-		releaseSlot();
-	}
-
-	@Override
 	public int getPhysicalSlotNumber() {
 		return getRootSlotNumber();
 	}
@@ -214,8 +212,14 @@ public class SharedSlot extends Slot implements LogicalSlot {
 	}
 
 	@Override
-	public SlotRequestID getSlotRequestId() {
-		return getSlotContext().getSlotRequestId();
+	public SlotRequestId getSlotRequestId() {
+		return NO_SLOT_REQUEST_ID;
+	}
+
+	@Nullable
+	@Override
+	public SlotSharingGroupId getSlotSharingGroupId() {
+		return NO_SLOT_SHARING_GROUP_ID;
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SimpleSlot.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SimpleSlot.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SimpleSlot.java
index e98832f..e69247e 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SimpleSlot.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SimpleSlot.java
@@ -20,10 +20,11 @@ package org.apache.flink.runtime.instance;
 
 import org.apache.flink.runtime.clusterframework.types.AllocationID;
 import org.apache.flink.runtime.jobmanager.scheduler.Locality;
-import org.apache.flink.runtime.jobmanager.slots.SimpleSlotContext;
-import org.apache.flink.runtime.jobmanager.slots.SlotContext;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
 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.AbstractID;
 import org.apache.flink.util.FlinkException;
@@ -69,8 +70,8 @@ public class SimpleSlot extends Slot implements LogicalSlot {
 	 * @param taskManagerGateway The gateway to communicate with the TaskManager of this slot
 	 */
 	public SimpleSlot(
-			SlotOwner owner, TaskManagerLocation location, int slotNumber,
-			TaskManagerGateway taskManagerGateway) {
+		SlotOwner owner, TaskManagerLocation location, int slotNumber,
+		TaskManagerGateway taskManagerGateway) {
 		this(owner, location, slotNumber, taskManagerGateway, null, null);
 	}
 
@@ -97,7 +98,6 @@ public class SimpleSlot extends Slot implements LogicalSlot {
 			parent != null ?
 				parent.getSlotContext() :
 				new SimpleSlotContext(
-					NO_SLOT_REQUEST_ID,
 					NO_ALLOCATION_ID,
 					location,
 					slotNumber,
@@ -218,18 +218,13 @@ public class SimpleSlot extends Slot implements LogicalSlot {
 	// ------------------------------------------------------------------------
 
 	@Override
-	public void releaseInstanceSlot() {
-		releaseSlot();
-	}
-
-	@Override
-	public CompletableFuture<?> releaseSlot() {
+	public CompletableFuture<?> releaseSlot(@Nullable Throwable cause) {
 		if (!isCanceled()) {
 			final CompletableFuture<?> terminationFuture;
 
 			if (payload != null) {
 				// trigger the failure of the slot payload
-				payload.fail(new FlinkException("TaskManager was lost/killed: " + getTaskManagerLocation()));
+				payload.fail(cause != null ? cause : new FlinkException("TaskManager was lost/killed: " + getTaskManagerLocation()));
 
 				// wait for the termination of the payload before releasing the slot
 				terminationFuture = payload.getTerminalStateFuture();
@@ -276,8 +271,14 @@ public class SimpleSlot extends Slot implements LogicalSlot {
 	}
 
 	@Override
-	public SlotRequestID getSlotRequestId() {
-		return getSlotContext().getSlotRequestId();
+	public SlotRequestId getSlotRequestId() {
+		return NO_SLOT_REQUEST_ID;
+	}
+
+	@Nullable
+	@Override
+	public SlotSharingGroupId getSlotSharingGroupId() {
+		return NO_SLOT_SHARING_GROUP_ID;
 	}
 
 	// ------------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SimpleSlotContext.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SimpleSlotContext.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SimpleSlotContext.java
new file mode 100644
index 0000000..95dd1f6
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SimpleSlotContext.java
@@ -0,0 +1,70 @@
+/*
+ * 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.instance;
+
+import org.apache.flink.runtime.clusterframework.types.AllocationID;
+import org.apache.flink.runtime.jobmaster.SlotContext;
+import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+import org.apache.flink.util.Preconditions;
+
+/**
+ * Simple implementation of the {@link SlotContext} interface for the legacy code.
+ */
+public class SimpleSlotContext implements SlotContext {
+
+	private final AllocationID allocationId;
+
+	private final TaskManagerLocation taskManagerLocation;
+
+	private final int physicalSlotNumber;
+
+	private final TaskManagerGateway taskManagerGateway;
+
+	public SimpleSlotContext(
+			AllocationID allocationId,
+			TaskManagerLocation taskManagerLocation,
+			int physicalSlotNumber,
+			TaskManagerGateway taskManagerGateway) {
+		this.allocationId = Preconditions.checkNotNull(allocationId);
+		this.taskManagerLocation = Preconditions.checkNotNull(taskManagerLocation);
+		this.physicalSlotNumber = physicalSlotNumber;
+		this.taskManagerGateway = Preconditions.checkNotNull(taskManagerGateway);
+	}
+
+	@Override
+	public AllocationID getAllocationId() {
+		return allocationId;
+	}
+
+	@Override
+	public TaskManagerLocation getTaskManagerLocation() {
+		return taskManagerLocation;
+	}
+
+	@Override
+	public int getPhysicalSlotNumber() {
+		return physicalSlotNumber;
+	}
+
+	@Override
+	public TaskManagerGateway getTaskManagerGateway() {
+		return taskManagerGateway;
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/Slot.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/Slot.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/Slot.java
index e82f075..dbd6554 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/Slot.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/Slot.java
@@ -20,15 +20,16 @@ package org.apache.flink.runtime.instance;
 
 import org.apache.flink.runtime.clusterframework.types.AllocationID;
 import org.apache.flink.runtime.clusterframework.types.ResourceID;
-import org.apache.flink.runtime.jobmanager.slots.SimpleSlotContext;
-import org.apache.flink.runtime.jobmanager.slots.SlotContext;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
 import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+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.AbstractID;
 
 import javax.annotation.Nullable;
 
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
 
 import static org.apache.flink.util.Preconditions.checkArgument;
@@ -62,7 +63,8 @@ public abstract class Slot {
 
 	// temporary placeholder for Slots that are not constructed from an AllocatedSlot (prior to FLIP-6)
 	protected static final AllocationID NO_ALLOCATION_ID = new AllocationID(0L, 0L);
-	protected static final SlotRequestID NO_SLOT_REQUEST_ID = new SlotRequestID(0L, 0L);
+	protected static final SlotRequestId NO_SLOT_REQUEST_ID = new SlotRequestId(0L, 0L);
+	protected static final SlotSharingGroupId NO_SLOT_SHARING_GROUP_ID = new SlotSharingGroupId(0L, 0L);
 
 	// ------------------------------------------------------------------------
 
@@ -112,7 +114,6 @@ public abstract class Slot {
 
 		// create a simple slot context
 		this.slotContext = new SimpleSlotContext(
-			NO_SLOT_REQUEST_ID,
 			NO_ALLOCATION_ID,
 			location,
 			slotNumber,
@@ -333,7 +334,7 @@ public abstract class Slot {
 	 * If this slot is a simple slot, it will be returned to its instance. If it is a shared slot,
 	 * it will release all of its sub-slots and release itself.
 	 */
-	public abstract void releaseInstanceSlot();
+	public abstract CompletableFuture<?> releaseSlot(@Nullable Throwable cause);
 
 
 	// --------------------------------------------------------------------------------------------


[02/11] flink git commit: [FLINK-7956] [flip6] Add support for queued scheduling with slot sharing to SlotPool

Posted by tr...@apache.org.
http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolTest.java
new file mode 100644
index 0000000..707ea00
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolTest.java
@@ -0,0 +1,550 @@
+/*
+ * 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.api.common.JobID;
+import org.apache.flink.api.common.time.Time;
+import org.apache.flink.runtime.clusterframework.types.AllocationID;
+import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
+import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.jobgraph.JobVertexID;
+import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
+import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+import org.apache.flink.runtime.jobmaster.JobMasterId;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.SlotRequestId;
+import org.apache.flink.runtime.messages.Acknowledge;
+import org.apache.flink.runtime.resourcemanager.ResourceManagerGateway;
+import org.apache.flink.runtime.resourcemanager.SlotRequest;
+import org.apache.flink.runtime.resourcemanager.utils.TestingResourceManagerGateway;
+import org.apache.flink.runtime.rpc.RpcService;
+import org.apache.flink.runtime.rpc.RpcUtils;
+import org.apache.flink.runtime.rpc.TestingRpcService;
+import org.apache.flink.runtime.taskexecutor.slot.SlotOffer;
+import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+import org.apache.flink.util.ExceptionUtils;
+import org.apache.flink.util.FlinkException;
+import org.apache.flink.util.TestLogger;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.flink.runtime.jobmaster.slotpool.AvailableSlotsTest.DEFAULT_TESTING_PROFILE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.RETURNS_MOCKS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class SlotPoolTest extends TestLogger {
+
+	private static final Logger LOG = LoggerFactory.getLogger(SlotPoolTest.class);
+
+	private final Time timeout = Time.seconds(10L);
+
+	private RpcService rpcService;
+
+	private JobID jobId;
+
+	private TaskManagerLocation taskManagerLocation;
+
+	private TaskManagerGateway taskManagerGateway;
+
+	@Before
+	public void setUp() throws Exception {
+		this.rpcService = new TestingRpcService();
+		this.jobId = new JobID();
+
+		taskManagerLocation = new LocalTaskManagerLocation();
+		taskManagerGateway = new SimpleAckingTaskManagerGateway();
+	}
+
+	@After
+	public void tearDown() throws Exception {
+		rpcService.stopService();
+	}
+
+	@Test
+	public void testAllocateSimpleSlot() throws Exception {
+		ResourceManagerGateway resourceManagerGateway = createResourceManagerGatewayMock();
+		final SlotPool slotPool = new SlotPool(rpcService, jobId);
+
+		try {
+			SlotPoolGateway slotPoolGateway = setupSlotPool(slotPool, resourceManagerGateway);
+			slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID());
+
+			SlotRequestId requestId = new SlotRequestId();
+			CompletableFuture<LogicalSlot> future = slotPoolGateway.allocateSlot(
+				requestId,
+				mock(ScheduledUnit.class),
+				DEFAULT_TESTING_PROFILE,
+				Collections.emptyList(),
+				true,
+				timeout);
+			assertFalse(future.isDone());
+
+			ArgumentCaptor<SlotRequest> slotRequestArgumentCaptor = ArgumentCaptor.forClass(SlotRequest.class);
+			verify(resourceManagerGateway, Mockito.timeout(timeout.toMilliseconds())).requestSlot(any(JobMasterId.class), slotRequestArgumentCaptor.capture(), any(Time.class));
+
+			final SlotRequest slotRequest = slotRequestArgumentCaptor.getValue();
+
+			final SlotOffer slotOffer = new SlotOffer(
+				slotRequest.getAllocationId(),
+				0,
+				DEFAULT_TESTING_PROFILE);
+
+			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
+
+			LogicalSlot slot = future.get(1, TimeUnit.SECONDS);
+			assertTrue(future.isDone());
+			assertTrue(slot.isAlive());
+			assertEquals(taskManagerLocation, slot.getTaskManagerLocation());
+		} finally {
+			slotPool.shutDown();
+		}
+	}
+
+	@Test
+	public void testAllocationFulfilledByReturnedSlot() throws Exception {
+		ResourceManagerGateway resourceManagerGateway = createResourceManagerGatewayMock();
+		final SlotPool slotPool = new SlotPool(rpcService, jobId);
+
+		try {
+			SlotPoolGateway slotPoolGateway = setupSlotPool(slotPool, resourceManagerGateway);
+			slotPool.registerTaskManager(taskManagerLocation.getResourceID());
+
+			CompletableFuture<LogicalSlot> future1 = slotPoolGateway.allocateSlot(
+				new SlotRequestId(),
+				mock(ScheduledUnit.class),
+				DEFAULT_TESTING_PROFILE,
+				Collections.emptyList(),
+				true,
+				timeout);
+			CompletableFuture<LogicalSlot> future2 = slotPoolGateway.allocateSlot(
+				new SlotRequestId(),
+				mock(ScheduledUnit.class),
+				DEFAULT_TESTING_PROFILE,
+				Collections.emptyList(),
+				true,
+				timeout);
+
+			assertFalse(future1.isDone());
+			assertFalse(future2.isDone());
+
+			ArgumentCaptor<SlotRequest> slotRequestArgumentCaptor = ArgumentCaptor.forClass(SlotRequest.class);
+			verify(resourceManagerGateway, Mockito.timeout(timeout.toMilliseconds()).times(2))
+				.requestSlot(any(JobMasterId.class), slotRequestArgumentCaptor.capture(), any(Time.class));
+
+			final List<SlotRequest> slotRequests = slotRequestArgumentCaptor.getAllValues();
+
+			final SlotOffer slotOffer = new SlotOffer(
+				slotRequests.get(0).getAllocationId(),
+				0,
+				DEFAULT_TESTING_PROFILE);
+
+			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
+
+			LogicalSlot slot1 = future1.get(1, TimeUnit.SECONDS);
+			assertTrue(future1.isDone());
+			assertFalse(future2.isDone());
+
+			// return this slot to pool
+			slot1.releaseSlot();
+
+			// second allocation fulfilled by previous slot returning
+			LogicalSlot slot2 = future2.get(1, TimeUnit.SECONDS);
+			assertTrue(future2.isDone());
+
+			assertNotEquals(slot1, slot2);
+			assertFalse(slot1.isAlive());
+			assertTrue(slot2.isAlive());
+			assertEquals(slot1.getTaskManagerLocation(), slot2.getTaskManagerLocation());
+			assertEquals(slot1.getPhysicalSlotNumber(), slot2.getPhysicalSlotNumber());
+			assertEquals(slot1.getAllocationId(), slot2.getAllocationId());
+		} finally {
+			slotPool.shutDown();
+		}
+	}
+
+	@Test
+	public void testAllocateWithFreeSlot() throws Exception {
+		ResourceManagerGateway resourceManagerGateway = createResourceManagerGatewayMock();
+		final SlotPool slotPool = new SlotPool(rpcService, jobId);
+
+		try {
+			SlotPoolGateway slotPoolGateway = setupSlotPool(slotPool, resourceManagerGateway);
+			slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID());
+
+			CompletableFuture<LogicalSlot> future1 = slotPoolGateway.allocateSlot(
+				new SlotRequestId(),
+				mock(ScheduledUnit.class),
+				DEFAULT_TESTING_PROFILE,
+				Collections.emptyList(),
+				true,
+				timeout);
+			assertFalse(future1.isDone());
+
+			ArgumentCaptor<SlotRequest> slotRequestArgumentCaptor = ArgumentCaptor.forClass(SlotRequest.class);
+			verify(resourceManagerGateway, Mockito.timeout(timeout.toMilliseconds())).requestSlot(any(JobMasterId.class), slotRequestArgumentCaptor.capture(), any(Time.class));
+
+			final SlotRequest slotRequest = slotRequestArgumentCaptor.getValue();
+
+			final SlotOffer slotOffer = new SlotOffer(
+				slotRequest.getAllocationId(),
+				0,
+				DEFAULT_TESTING_PROFILE);
+
+			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
+
+			LogicalSlot slot1 = future1.get(1, TimeUnit.SECONDS);
+			assertTrue(future1.isDone());
+
+			// return this slot to pool
+			slot1.releaseSlot();
+
+			CompletableFuture<LogicalSlot> future2 = slotPoolGateway.allocateSlot(
+				new SlotRequestId(),
+				mock(ScheduledUnit.class),
+				DEFAULT_TESTING_PROFILE,
+				Collections.emptyList(),
+				true,
+				timeout);
+
+			// second allocation fulfilled by previous slot returning
+			LogicalSlot slot2 = future2.get(1, TimeUnit.SECONDS);
+			assertTrue(future2.isDone());
+
+			assertNotEquals(slot1, slot2);
+			assertFalse(slot1.isAlive());
+			assertTrue(slot2.isAlive());
+			assertEquals(slot1.getTaskManagerLocation(), slot2.getTaskManagerLocation());
+			assertEquals(slot1.getPhysicalSlotNumber(), slot2.getPhysicalSlotNumber());
+		} finally {
+			slotPool.shutDown();
+		}
+	}
+
+	@Test
+	public void testOfferSlot() throws Exception {
+		ResourceManagerGateway resourceManagerGateway = createResourceManagerGatewayMock();
+		final SlotPool slotPool = new SlotPool(rpcService, jobId);
+
+		try {
+			SlotPoolGateway slotPoolGateway = setupSlotPool(slotPool, resourceManagerGateway);
+			slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID());
+
+			CompletableFuture<LogicalSlot> future = slotPoolGateway.allocateSlot(
+				new SlotRequestId(),
+				mock(ScheduledUnit.class),
+				DEFAULT_TESTING_PROFILE,
+				Collections.emptyList(),
+				true,
+				timeout);
+			assertFalse(future.isDone());
+
+			ArgumentCaptor<SlotRequest> slotRequestArgumentCaptor = ArgumentCaptor.forClass(SlotRequest.class);
+			verify(resourceManagerGateway, Mockito.timeout(timeout.toMilliseconds())).requestSlot(any(JobMasterId.class), slotRequestArgumentCaptor.capture(), any(Time.class));
+
+			final SlotRequest slotRequest = slotRequestArgumentCaptor.getValue();
+
+			final SlotOffer slotOffer = new SlotOffer(
+				slotRequest.getAllocationId(),
+				0,
+				DEFAULT_TESTING_PROFILE);
+
+			final TaskManagerLocation invalidTaskManagerLocation = new LocalTaskManagerLocation();
+
+			// slot from unregistered resource
+			assertFalse(slotPoolGateway.offerSlot(invalidTaskManagerLocation, taskManagerGateway, slotOffer).get());
+
+			final SlotOffer nonRequestedSlotOffer = new SlotOffer(
+				new AllocationID(),
+				0,
+				DEFAULT_TESTING_PROFILE);
+
+			// we'll also accept non requested slots
+			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, nonRequestedSlotOffer).get());
+
+			// accepted slot
+			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
+			LogicalSlot slot = future.get(timeout.toMilliseconds(), TimeUnit.MILLISECONDS);
+			assertTrue(slot.isAlive());
+
+			// duplicated offer with using slot
+			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
+			assertTrue(slot.isAlive());
+
+			// duplicated offer with free slot
+			slot.releaseSlot();
+			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
+		} finally {
+			slotPool.shutDown();
+		}
+	}
+
+	@Test
+	public void testReleaseResource() throws Exception {
+		ResourceManagerGateway resourceManagerGateway = createResourceManagerGatewayMock();
+
+		final CompletableFuture<Boolean> slotReturnFuture = new CompletableFuture<>();
+
+		final SlotPool slotPool = new SlotPool(rpcService, jobId) {
+			@Override
+			public CompletableFuture<Acknowledge> releaseSlot(
+					SlotRequestId slotRequestId,
+					@Nullable SlotSharingGroupId slotSharingGroupId,
+					@Nullable Throwable cause) {
+				super.releaseSlot(
+					slotRequestId,
+					slotSharingGroupId,
+					cause);
+
+				slotReturnFuture.complete(true);
+
+				return CompletableFuture.completedFuture(Acknowledge.get());
+			}
+		};
+
+		try {
+			SlotPoolGateway slotPoolGateway = setupSlotPool(slotPool, resourceManagerGateway);
+			slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID());
+
+			CompletableFuture<LogicalSlot> future1 = slotPoolGateway.allocateSlot(
+				new SlotRequestId(),
+				mock(ScheduledUnit.class),
+				DEFAULT_TESTING_PROFILE,
+				Collections.emptyList(),
+				true,
+				timeout);
+
+			ArgumentCaptor<SlotRequest> slotRequestArgumentCaptor = ArgumentCaptor.forClass(SlotRequest.class);
+			verify(resourceManagerGateway, Mockito.timeout(timeout.toMilliseconds())).requestSlot(any(JobMasterId.class), slotRequestArgumentCaptor.capture(), any(Time.class));
+
+			final SlotRequest slotRequest = slotRequestArgumentCaptor.getValue();
+
+			CompletableFuture<LogicalSlot> future2 = slotPoolGateway.allocateSlot(
+				new SlotRequestId(),
+				mock(ScheduledUnit.class),
+				DEFAULT_TESTING_PROFILE,
+				Collections.emptyList(),
+				true,
+				timeout);
+
+			final SlotOffer slotOffer = new SlotOffer(
+				slotRequest.getAllocationId(),
+				0,
+				DEFAULT_TESTING_PROFILE);
+
+			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
+
+			LogicalSlot slot1 = future1.get(1, TimeUnit.SECONDS);
+			assertTrue(future1.isDone());
+			assertFalse(future2.isDone());
+
+			slotPoolGateway.releaseTaskManager(taskManagerLocation.getResourceID());
+
+			// wait until the slot has been returned
+			slotReturnFuture.get();
+
+			assertFalse(slot1.isAlive());
+
+			// slot released and not usable, second allocation still not fulfilled
+			Thread.sleep(10);
+			assertFalse(future2.isDone());
+		} finally {
+			slotPool.shutDown();
+		}
+	}
+
+	/**
+	 * Tests that a slot request is cancelled if it failed with an exception (e.g. TimeoutException).
+	 *
+	 * <p>See FLINK-7870
+	 */
+	@Test
+	public void testSlotRequestCancellationUponFailingRequest() throws Exception {
+		final SlotPool slotPool = new SlotPool(rpcService, jobId);
+		final CompletableFuture<Acknowledge> requestSlotFuture = new CompletableFuture<>();
+		final CompletableFuture<AllocationID> cancelSlotFuture = new CompletableFuture<>();
+		final CompletableFuture<AllocationID> requestSlotFutureAllocationId = new CompletableFuture<>();
+
+		final TestingResourceManagerGateway resourceManagerGateway = new TestingResourceManagerGateway();
+		resourceManagerGateway.setRequestSlotFuture(requestSlotFuture);
+		resourceManagerGateway.setRequestSlotConsumer(slotRequest -> requestSlotFutureAllocationId.complete(slotRequest.getAllocationId()));
+		resourceManagerGateway.setCancelSlotConsumer(allocationID -> cancelSlotFuture.complete(allocationID));
+
+		final ScheduledUnit scheduledUnit = new ScheduledUnit(
+			new JobVertexID(),
+			null,
+			null);
+
+		try {
+			slotPool.start(JobMasterId.generate(), "localhost");
+
+			final SlotPoolGateway slotPoolGateway = slotPool.getSelfGateway(SlotPoolGateway.class);
+
+			slotPoolGateway.connectToResourceManager(resourceManagerGateway);
+
+			CompletableFuture<LogicalSlot> slotFuture = slotPoolGateway.allocateSlot(
+				new SlotRequestId(),
+				scheduledUnit,
+				ResourceProfile.UNKNOWN,
+				Collections.emptyList(),
+				true,
+				timeout);
+
+			requestSlotFuture.completeExceptionally(new FlinkException("Testing exception."));
+
+			try {
+				slotFuture.get();
+				fail("The slot future should not have been completed properly.");
+			} catch (Exception ignored) {
+				// expected
+			}
+
+			// check that a failure triggered the slot request cancellation
+			// with the correct allocation id
+			assertEquals(requestSlotFutureAllocationId.get(), cancelSlotFuture.get());
+		} finally {
+			try {
+				RpcUtils.terminateRpcEndpoint(slotPool, timeout);
+			} catch (Exception e) {
+				LOG.warn("Could not properly terminate the SlotPool.", e);
+			}
+		}
+	}
+
+	/**
+	 * Tests that unused offered slots are directly used to fulfill pending slot
+	 * requests.
+	 *
+	 * <p>See FLINK-8089
+	 */
+	@Test
+	public void testFulfillingSlotRequestsWithUnusedOfferedSlots() throws Exception {
+		final SlotPool slotPool = new SlotPool(rpcService, jobId);
+
+		final JobMasterId jobMasterId = JobMasterId.generate();
+		final String jobMasterAddress = "foobar";
+		final CompletableFuture<AllocationID> allocationIdFuture = new CompletableFuture<>();
+		final TestingResourceManagerGateway resourceManagerGateway = new TestingResourceManagerGateway();
+
+		resourceManagerGateway.setRequestSlotConsumer(
+			(SlotRequest slotRequest) -> allocationIdFuture.complete(slotRequest.getAllocationId()));
+
+		final SlotRequestId slotRequestId1 = new SlotRequestId();
+		final SlotRequestId slotRequestId2 = new SlotRequestId();
+
+		try {
+			slotPool.start(jobMasterId, jobMasterAddress);
+
+			final SlotPoolGateway slotPoolGateway = slotPool.getSelfGateway(SlotPoolGateway.class);
+
+			final ScheduledUnit scheduledUnit = new ScheduledUnit(
+				new JobVertexID(),
+				null,
+				null);
+
+			slotPoolGateway.connectToResourceManager(resourceManagerGateway);
+
+			CompletableFuture<LogicalSlot> slotFuture1 = slotPoolGateway.allocateSlot(
+				slotRequestId1,
+				scheduledUnit,
+				ResourceProfile.UNKNOWN,
+				Collections.emptyList(),
+				true,
+				timeout);
+
+			// wait for the first slot request
+			final AllocationID allocationId = allocationIdFuture.get();
+
+			CompletableFuture<LogicalSlot> slotFuture2 = slotPoolGateway.allocateSlot(
+				slotRequestId2,
+				scheduledUnit,
+				ResourceProfile.UNKNOWN,
+				Collections.emptyList(),
+				true,
+				timeout);
+
+			slotPoolGateway.releaseSlot(slotRequestId1, null, null);
+
+			try {
+				// this should fail with a CancellationException
+				slotFuture1.get();
+				fail("The first slot future should have failed because it was cancelled.");
+			} catch (ExecutionException ee) {
+				// expected
+				assertTrue(ExceptionUtils.stripExecutionException(ee) instanceof FlinkException);
+
+			}
+
+			final SlotOffer slotOffer = new SlotOffer(allocationId, 0, ResourceProfile.UNKNOWN);
+
+			slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID()).get();
+
+			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
+
+			// the slot offer should fulfill the second slot request
+			assertEquals(allocationId, slotFuture2.get().getAllocationId());
+		} finally {
+			RpcUtils.terminateRpcEndpoint(slotPool, timeout);
+		}
+	}
+
+	private static ResourceManagerGateway createResourceManagerGatewayMock() {
+		ResourceManagerGateway resourceManagerGateway = mock(ResourceManagerGateway.class);
+		when(resourceManagerGateway
+			.requestSlot(any(JobMasterId.class), any(SlotRequest.class), any(Time.class)))
+			.thenReturn(mock(CompletableFuture.class, RETURNS_MOCKS));
+
+		return resourceManagerGateway;
+	}
+
+	private static SlotPoolGateway setupSlotPool(
+			SlotPool slotPool,
+			ResourceManagerGateway resourceManagerGateway) throws Exception {
+		final String jobManagerAddress = "foobar";
+
+		slotPool.start(JobMasterId.generate(), jobManagerAddress);
+
+		slotPool.connectToResourceManager(resourceManagerGateway);
+
+		return slotPool.getSelfGateway(SlotPoolGateway.class);
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotSharingManagerTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotSharingManagerTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotSharingManagerTest.java
new file mode 100644
index 0000000..c355f38
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotSharingManagerTest.java
@@ -0,0 +1,519 @@
+/*
+ * 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.executiongraph.utils.SimpleAckingTaskManagerGateway;
+import org.apache.flink.runtime.instance.SimpleSlotContext;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.jobmanager.scheduler.Locality;
+import org.apache.flink.runtime.jobmanager.slots.DummySlotOwner;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.SlotContext;
+import org.apache.flink.runtime.jobmaster.SlotRequestId;
+import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
+import org.apache.flink.util.AbstractID;
+import org.apache.flink.util.FlinkException;
+import org.apache.flink.util.TestLogger;
+
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test cases for the {@link SlotSharingManager}.
+ */
+public class SlotSharingManagerTest extends TestLogger {
+
+	private static final SlotSharingGroupId SLOT_SHARING_GROUP_ID = new SlotSharingGroupId();
+
+	private static final DummySlotOwner SLOT_OWNER = new DummySlotOwner();
+
+	@Test
+	public void testRootSlotCreation() {
+		final TestingAllocatedSlotActions allocatedSlotActions = new TestingAllocatedSlotActions();
+
+		final SlotSharingManager slotSharingManager = new SlotSharingManager(
+			SLOT_SHARING_GROUP_ID,
+			allocatedSlotActions,
+			SLOT_OWNER);
+
+		SlotRequestId slotRequestId = new SlotRequestId();
+		SlotRequestId allocatedSlotRequestId = new SlotRequestId();
+
+		final SlotSharingManager.MultiTaskSlot multiTaskSlot = slotSharingManager.createRootSlot(
+			slotRequestId,
+			new CompletableFuture<>(),
+			allocatedSlotRequestId);
+
+		assertEquals(slotRequestId, multiTaskSlot.getSlotRequestId());
+		assertNotNull(slotSharingManager.getTaskSlot(slotRequestId));
+	}
+
+	@Test
+	public void testRootSlotRelease() throws ExecutionException, InterruptedException {
+		final CompletableFuture<SlotRequestId> slotReleasedFuture = new CompletableFuture<>();
+		final TestingAllocatedSlotActions allocatedSlotActions = new TestingAllocatedSlotActions();
+
+		allocatedSlotActions.setReleaseSlotConsumer(
+			tuple3 -> slotReleasedFuture.complete(tuple3.f0));
+
+		final SlotSharingManager slotSharingManager = new SlotSharingManager(
+			SLOT_SHARING_GROUP_ID,
+			allocatedSlotActions,
+			SLOT_OWNER);
+
+		SlotRequestId slotRequestId = new SlotRequestId();
+		SlotRequestId allocatedSlotRequestId = new SlotRequestId();
+
+		CompletableFuture<SlotContext> slotContextFuture = new CompletableFuture<>();
+
+		SlotSharingManager.MultiTaskSlot rootSlot = slotSharingManager.createRootSlot(
+			slotRequestId,
+			slotContextFuture,
+			allocatedSlotRequestId);
+
+		assertTrue(slotSharingManager.contains(slotRequestId));
+
+		assertTrue(rootSlot.release(new FlinkException("Test exception")));
+
+		// check that we return the allocated slot
+		assertEquals(allocatedSlotRequestId, slotReleasedFuture.get());
+
+		assertFalse(slotSharingManager.contains(slotRequestId));
+	}
+
+	/**
+	 * Tests that we can create nested slots.
+	 */
+	@Test
+	public void testNestedSlotCreation() {
+		final TestingAllocatedSlotActions allocatedSlotActions = new TestingAllocatedSlotActions();
+
+		final SlotSharingManager slotSharingManager = new SlotSharingManager(
+			SLOT_SHARING_GROUP_ID,
+			allocatedSlotActions,
+			SLOT_OWNER);
+
+		SlotSharingManager.MultiTaskSlot rootSlot = slotSharingManager.createRootSlot(
+			new SlotRequestId(),
+			new CompletableFuture<>(),
+			new SlotRequestId());
+
+		AbstractID singleTaskSlotGroupId = new AbstractID();
+		SlotRequestId singleTaskSlotRequestId = new SlotRequestId();
+		SlotSharingManager.SingleTaskSlot singleTaskSlot = rootSlot.allocateSingleTaskSlot(
+			singleTaskSlotRequestId,
+			singleTaskSlotGroupId,
+			Locality.LOCAL);
+
+		AbstractID multiTaskSlotGroupId = new AbstractID();
+		SlotRequestId multiTaskSlotRequestId = new SlotRequestId();
+		SlotSharingManager.MultiTaskSlot multiTaskSlot = rootSlot.allocateMultiTaskSlot(
+			multiTaskSlotRequestId,
+			multiTaskSlotGroupId);
+
+		assertTrue(Objects.equals(singleTaskSlotRequestId, singleTaskSlot.getSlotRequestId()));
+		assertTrue(Objects.equals(multiTaskSlotRequestId, multiTaskSlot.getSlotRequestId()));
+
+		assertTrue(rootSlot.contains(singleTaskSlotGroupId));
+		assertTrue(rootSlot.contains(multiTaskSlotGroupId));
+
+		assertTrue(slotSharingManager.contains(singleTaskSlotRequestId));
+		assertTrue(slotSharingManager.contains(multiTaskSlotRequestId));
+	}
+
+	/**
+	 * Tests that we can release nested slots from the leaves onwards
+	 */
+	@Test
+	public void testNestedSlotRelease() throws Exception {
+		TestingAllocatedSlotActions testingAllocatedSlotActions = new TestingAllocatedSlotActions();
+
+		final CompletableFuture<SlotRequestId> releasedSlotFuture = new CompletableFuture<>();
+		testingAllocatedSlotActions.setReleaseSlotConsumer(
+			tuple3 -> releasedSlotFuture.complete(tuple3.f0));
+
+		final SlotSharingManager slotSharingManager = new SlotSharingManager(
+			SLOT_SHARING_GROUP_ID,
+			testingAllocatedSlotActions,
+			SLOT_OWNER);
+
+		SlotRequestId rootSlotRequestId = new SlotRequestId();
+		SlotRequestId allocatedSlotRequestId = new SlotRequestId();
+		SlotSharingManager.MultiTaskSlot rootSlot = slotSharingManager.createRootSlot(
+			rootSlotRequestId,
+			new CompletableFuture<>(),
+			allocatedSlotRequestId);
+
+		SlotRequestId singleTaskSlotRequestId = new SlotRequestId();
+		SlotSharingManager.SingleTaskSlot singleTaskSlot = rootSlot.allocateSingleTaskSlot(
+			singleTaskSlotRequestId,
+			new AbstractID(),
+			Locality.LOCAL);
+
+		SlotRequestId multiTaskSlotRequestId = new SlotRequestId();
+		SlotSharingManager.MultiTaskSlot multiTaskSlot = rootSlot.allocateMultiTaskSlot(
+			multiTaskSlotRequestId,
+			new AbstractID());
+
+		CompletableFuture<LogicalSlot> singleTaskSlotFuture = singleTaskSlot.getLogicalSlotFuture();
+
+		assertTrue(slotSharingManager.contains(rootSlotRequestId));
+		assertTrue(slotSharingManager.contains(singleTaskSlotRequestId));
+		assertFalse(singleTaskSlotFuture.isDone());
+
+		FlinkException testException = new FlinkException("Test exception");
+		assertTrue(singleTaskSlot.release(testException));
+
+		// check that we fail the single task slot future
+		assertTrue(singleTaskSlotFuture.isCompletedExceptionally());
+		assertFalse(slotSharingManager.contains(singleTaskSlotRequestId));
+
+		// the root slot has still one child
+		assertTrue(slotSharingManager.contains(rootSlotRequestId));
+
+		assertTrue(multiTaskSlot.release(testException));
+
+		assertEquals(allocatedSlotRequestId, releasedSlotFuture.get());
+		assertFalse(slotSharingManager.contains(rootSlotRequestId));
+		assertFalse(slotSharingManager.contains(multiTaskSlotRequestId));
+
+		assertTrue(slotSharingManager.isEmpty());
+	}
+
+	/**
+	 * Tests that we can release inner slots and that this triggers the slot release for all
+	 * its children.
+	 */
+	@Test
+	public void testInnerSlotRelease() {
+		final TestingAllocatedSlotActions allocatedSlotActions = new TestingAllocatedSlotActions();
+
+		final SlotSharingManager slotSharingManager = new SlotSharingManager(
+			SLOT_SHARING_GROUP_ID,
+			allocatedSlotActions,
+			SLOT_OWNER);
+
+		SlotSharingManager.MultiTaskSlot rootSlot = slotSharingManager.createRootSlot(
+			new SlotRequestId(),
+			new CompletableFuture<>(),
+			new SlotRequestId());
+
+		SlotSharingManager.MultiTaskSlot multiTaskSlot = rootSlot.allocateMultiTaskSlot(
+			new SlotRequestId(),
+			new AbstractID());
+
+		SlotSharingManager.SingleTaskSlot singleTaskSlot1 = multiTaskSlot.allocateSingleTaskSlot(
+			new SlotRequestId(),
+			new AbstractID(),
+			Locality.LOCAL);
+
+		SlotSharingManager.MultiTaskSlot multiTaskSlot1 = multiTaskSlot.allocateMultiTaskSlot(
+			new SlotRequestId(),
+			new AbstractID());
+
+		assertTrue(slotSharingManager.contains(multiTaskSlot1.getSlotRequestId()));
+		assertTrue(slotSharingManager.contains(singleTaskSlot1.getSlotRequestId()));
+		assertTrue(slotSharingManager.contains(multiTaskSlot.getSlotRequestId()));
+
+		multiTaskSlot.release(new FlinkException("Test exception"));
+
+		assertFalse(slotSharingManager.contains(multiTaskSlot1.getSlotRequestId()));
+		assertFalse(slotSharingManager.contains(singleTaskSlot1.getSlotRequestId()));
+		assertFalse(slotSharingManager.contains(multiTaskSlot.getSlotRequestId()));
+		assertTrue(singleTaskSlot1.getLogicalSlotFuture().isCompletedExceptionally());
+	}
+
+	/**
+	 * Tests that the logical task slot futures are completed once the slot context
+	 * future is completed.
+	 */
+	@Test
+	public void testSlotContextFutureCompletion() throws Exception {
+		final TestingAllocatedSlotActions allocatedSlotActions = new TestingAllocatedSlotActions();
+
+		final SlotSharingManager slotSharingManager = new SlotSharingManager(
+			SLOT_SHARING_GROUP_ID,
+			allocatedSlotActions,
+			SLOT_OWNER);
+
+		final SlotContext slotContext = new SimpleSlotContext(
+			new AllocationID(),
+			new LocalTaskManagerLocation(),
+			0,
+			new SimpleAckingTaskManagerGateway());
+
+		CompletableFuture<SlotContext> slotContextFuture = new CompletableFuture<>();
+		SlotSharingManager.MultiTaskSlot rootSlot = slotSharingManager.createRootSlot(
+			new SlotRequestId(),
+			slotContextFuture,
+			new SlotRequestId());
+
+		Locality locality1 = Locality.LOCAL;
+		SlotSharingManager.SingleTaskSlot singleTaskSlot1 = rootSlot.allocateSingleTaskSlot(
+			new SlotRequestId(),
+			new AbstractID(),
+			locality1);
+
+		Locality locality2 = Locality.HOST_LOCAL;
+		SlotSharingManager.SingleTaskSlot singleTaskSlot2 = rootSlot.allocateSingleTaskSlot(
+			new SlotRequestId(),
+			new AbstractID(),
+			locality2);
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture1 = singleTaskSlot1.getLogicalSlotFuture();
+		CompletableFuture<LogicalSlot> logicalSlotFuture2 = singleTaskSlot2.getLogicalSlotFuture();
+		assertFalse(logicalSlotFuture1.isDone());
+		assertFalse(logicalSlotFuture2.isDone());
+
+		slotContextFuture.complete(slotContext);
+
+		assertTrue(logicalSlotFuture1.isDone());
+		assertTrue(logicalSlotFuture2.isDone());
+
+		final LogicalSlot logicalSlot1 = logicalSlotFuture1.get();
+		final LogicalSlot logicalSlot2 = logicalSlotFuture2.get();
+
+		assertEquals(logicalSlot1.getAllocationId(), slotContext.getAllocationId());
+		assertEquals(logicalSlot2.getAllocationId(), slotContext.getAllocationId());
+		assertEquals(locality1, logicalSlot1.getLocality());
+		assertEquals(locality2, logicalSlot2.getLocality());
+
+		Locality locality3 = Locality.NON_LOCAL;
+		SlotSharingManager.SingleTaskSlot singleTaskSlot3 = rootSlot.allocateSingleTaskSlot(
+			new SlotRequestId(),
+			new AbstractID(),
+			locality3);
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture3 = singleTaskSlot3.getLogicalSlotFuture();
+
+		assertTrue(logicalSlotFuture3.isDone());
+		LogicalSlot logicalSlot3 = logicalSlotFuture3.get();
+
+		assertEquals(locality3, logicalSlot3.getLocality());
+		assertEquals(slotContext.getAllocationId(), logicalSlot3.getAllocationId());
+	}
+
+	/**
+	 * Tests that slot context future failures will release the root slot
+	 */
+	@Test
+	public void testSlotContextFutureFailure() {
+		final TestingAllocatedSlotActions allocatedSlotActions = new TestingAllocatedSlotActions();
+
+		SlotSharingManager slotSharingManager = new SlotSharingManager(
+			SLOT_SHARING_GROUP_ID,
+			allocatedSlotActions,
+			SLOT_OWNER);
+
+		CompletableFuture<SlotContext> slotContextFuture = new CompletableFuture<>();
+
+		assertTrue(slotSharingManager.isEmpty());
+
+		SlotSharingManager.MultiTaskSlot rootSlot = slotSharingManager.createRootSlot(
+			new SlotRequestId(),
+			slotContextFuture,
+			new SlotRequestId());
+
+		SlotSharingManager.SingleTaskSlot singleTaskSlot = rootSlot.allocateSingleTaskSlot(
+			new SlotRequestId(),
+			new AbstractID(),
+			Locality.LOCAL);
+
+		slotContextFuture.completeExceptionally(new FlinkException("Test exception"));
+
+		assertTrue(singleTaskSlot.getLogicalSlotFuture().isCompletedExceptionally());
+		assertTrue(slotSharingManager.isEmpty());
+		assertTrue(slotSharingManager.getResolvedRootSlots().isEmpty());
+		assertTrue(slotSharingManager.getUnresolvedRootSlots().isEmpty());
+	}
+
+	/**
+	 * Tests that the root slot are moved from unresolved to resolved once the
+	 * slot context future is successfully completed
+	 */
+	@Test
+	public void testRootSlotTransition() {
+		final TestingAllocatedSlotActions allocatedSlotActions = new TestingAllocatedSlotActions();
+
+		SlotSharingManager slotSharingManager = new SlotSharingManager(
+			SLOT_SHARING_GROUP_ID,
+			allocatedSlotActions,
+			SLOT_OWNER);
+
+		CompletableFuture<SlotContext> slotContextFuture = new CompletableFuture<>();
+		SlotSharingManager.MultiTaskSlot rootSlot = slotSharingManager.createRootSlot(
+			new SlotRequestId(),
+			slotContextFuture,
+			new SlotRequestId());
+
+		assertTrue(slotSharingManager.getUnresolvedRootSlots().contains(rootSlot));
+		assertFalse(slotSharingManager.getResolvedRootSlots().contains(rootSlot));
+
+		// now complete the slotContextFuture
+		slotContextFuture.complete(
+			new SimpleSlotContext(
+				new AllocationID(),
+				new LocalTaskManagerLocation(),
+				0,
+				new SimpleAckingTaskManagerGateway()));
+
+		assertFalse(slotSharingManager.getUnresolvedRootSlots().contains(rootSlot));
+		assertTrue(slotSharingManager.getResolvedRootSlots().contains(rootSlot));
+	}
+
+	/**
+	 * Tests that we can correctly retrieve resolved slots.
+	 */
+	@Test
+	public void testGetResolvedSlot() {
+		final TestingAllocatedSlotActions allocatedSlotActions = new TestingAllocatedSlotActions();
+
+		SlotSharingManager slotSharingManager = new SlotSharingManager(
+			SLOT_SHARING_GROUP_ID,
+			allocatedSlotActions,
+			SLOT_OWNER);
+
+		SlotSharingManager.MultiTaskSlot rootSlot = slotSharingManager.createRootSlot(
+			new SlotRequestId(),
+			CompletableFuture.completedFuture(
+				new SimpleSlotContext(
+					new AllocationID(),
+					new LocalTaskManagerLocation(),
+					0,
+					new SimpleAckingTaskManagerGateway())),
+			new SlotRequestId());
+
+		AbstractID groupId = new AbstractID();
+		SlotSharingManager.MultiTaskSlotLocality resolvedRootSlotLocality = slotSharingManager.getResolvedRootSlot(groupId, Collections.emptyList());
+
+		assertNotNull(resolvedRootSlotLocality);
+		assertEquals(Locality.UNCONSTRAINED, resolvedRootSlotLocality.getLocality());
+		assertEquals(rootSlot.getSlotRequestId(), resolvedRootSlotLocality.getMultiTaskSlot().getSlotRequestId());
+
+		SlotSharingManager.MultiTaskSlot resolvedRootSlot = resolvedRootSlotLocality.getMultiTaskSlot();
+
+		// occupy the resolved root slot
+		resolvedRootSlot.allocateSingleTaskSlot(
+			new SlotRequestId(),
+			groupId,
+			resolvedRootSlotLocality.getLocality());
+
+		SlotSharingManager.MultiTaskSlotLocality resolvedRootSlot1 = slotSharingManager.getResolvedRootSlot(
+			groupId,
+			Collections.emptyList());
+
+		assertNull(resolvedRootSlot1);
+	}
+
+	/**
+	 * Tests that the location preferences are honoured when looking for a resolved slot.
+	 */
+	@Test
+	public void testGetResolvedSlotWithLocationPreferences() {
+		final TestingAllocatedSlotActions allocatedSlotActions = new TestingAllocatedSlotActions();
+
+		SlotSharingManager slotSharingManager = new SlotSharingManager(
+			SLOT_SHARING_GROUP_ID,
+			allocatedSlotActions,
+			SLOT_OWNER);
+
+		SlotSharingManager.MultiTaskSlot rootSlot1 = slotSharingManager.createRootSlot(
+			new SlotRequestId(),
+			CompletableFuture.completedFuture(
+				new SimpleSlotContext(
+					new AllocationID(),
+					new LocalTaskManagerLocation(),
+					0,
+					new SimpleAckingTaskManagerGateway())),
+			new SlotRequestId());
+
+		LocalTaskManagerLocation taskManagerLocation = new LocalTaskManagerLocation();
+		SlotSharingManager.MultiTaskSlot rootSlot2 = slotSharingManager.createRootSlot(
+			new SlotRequestId(),
+			CompletableFuture.completedFuture(
+				new SimpleSlotContext(
+					new AllocationID(),
+					taskManagerLocation,
+					0,
+					new SimpleAckingTaskManagerGateway())),
+			new SlotRequestId());
+
+		AbstractID groupId = new AbstractID();
+		SlotSharingManager.MultiTaskSlotLocality resolvedRootSlot1 = slotSharingManager.getResolvedRootSlot(groupId, Collections.singleton(taskManagerLocation));
+		assertNotNull(resolvedRootSlot1);
+		assertEquals(Locality.LOCAL, resolvedRootSlot1.getLocality());
+		assertEquals(rootSlot2.getSlotRequestId(), resolvedRootSlot1.getMultiTaskSlot().getSlotRequestId());
+
+		// occupy the slot
+		resolvedRootSlot1.getMultiTaskSlot().allocateSingleTaskSlot(
+			new SlotRequestId(),
+			groupId,
+			resolvedRootSlot1.getLocality());
+
+		SlotSharingManager.MultiTaskSlotLocality resolvedRootSlot2 = slotSharingManager.getResolvedRootSlot(groupId, Collections.singleton(taskManagerLocation));
+
+		assertNotNull(resolvedRootSlot2);
+		assertNotSame(Locality.LOCAL, (resolvedRootSlot2.getLocality()));
+		assertEquals(rootSlot1.getSlotRequestId(), resolvedRootSlot2.getMultiTaskSlot().getSlotRequestId());
+	}
+
+	@Test
+	public void testGetUnresolvedSlot() {
+		final TestingAllocatedSlotActions allocatedSlotActions = new TestingAllocatedSlotActions();
+
+		SlotSharingManager slotSharingManager = new SlotSharingManager(
+			SLOT_SHARING_GROUP_ID,
+			allocatedSlotActions,
+			SLOT_OWNER);
+
+		SlotSharingManager.MultiTaskSlot rootSlot1 = slotSharingManager.createRootSlot(
+			new SlotRequestId(),
+			new CompletableFuture<>(),
+			new SlotRequestId());
+
+		final AbstractID groupId = new AbstractID();
+		SlotSharingManager.MultiTaskSlot unresolvedRootSlot = slotSharingManager.getUnresolvedRootSlot(groupId);
+
+		assertNotNull(unresolvedRootSlot);
+		assertEquals(rootSlot1.getSlotRequestId(), unresolvedRootSlot.getSlotRequestId());
+
+		// occupy the unresolved slot
+		unresolvedRootSlot.allocateSingleTaskSlot(
+			new SlotRequestId(),
+			groupId,
+			Locality.UNKNOWN);
+
+		SlotSharingManager.MultiTaskSlot unresolvedRootSlot1 = slotSharingManager.getUnresolvedRootSlot(groupId);
+
+		// we should no longer have a free unresolved root slot
+		assertNull(unresolvedRootSlot1);
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/TestingAllocatedSlotActions.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/TestingAllocatedSlotActions.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/TestingAllocatedSlotActions.java
new file mode 100644
index 0000000..159d076
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/TestingAllocatedSlotActions.java
@@ -0,0 +1,52 @@
+/*
+ * 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.api.java.tuple.Tuple3;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.jobmaster.SlotRequestId;
+import org.apache.flink.runtime.messages.Acknowledge;
+
+import javax.annotation.Nullable;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+/**
+ * Simple {@link AllocatedSlotActions} implementations for testing purposes.
+ */
+public class TestingAllocatedSlotActions implements AllocatedSlotActions {
+
+	private volatile Consumer<Tuple3<SlotRequestId, SlotSharingGroupId, Throwable>> releaseSlotConsumer;
+
+	public void setReleaseSlotConsumer(@Nullable Consumer<Tuple3<SlotRequestId, SlotSharingGroupId, Throwable>> releaseSlotConsumer) {
+		this.releaseSlotConsumer = releaseSlotConsumer;
+	}
+
+	@Override
+	public CompletableFuture<Acknowledge> releaseSlot(SlotRequestId slotRequestId, @Nullable SlotSharingGroupId slotSharingGroupId, @Nullable Throwable cause) {
+		Consumer<Tuple3<SlotRequestId, SlotSharingGroupId, Throwable>> currentReleaseSlotConsumer = this.releaseSlotConsumer;
+
+		if (currentReleaseSlotConsumer != null) {
+			currentReleaseSlotConsumer.accept(Tuple3.of(slotRequestId, slotSharingGroupId, cause));
+		}
+
+		return CompletableFuture.completedFuture(Acknowledge.get());
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-tests/src/test/java/org/apache/flink/test/recovery/FastFailuresITCase.java
----------------------------------------------------------------------
diff --git a/flink-tests/src/test/java/org/apache/flink/test/recovery/FastFailuresITCase.java b/flink-tests/src/test/java/org/apache/flink/test/recovery/FastFailuresITCase.java
index eb596d4..9a59e88 100644
--- a/flink-tests/src/test/java/org/apache/flink/test/recovery/FastFailuresITCase.java
+++ b/flink-tests/src/test/java/org/apache/flink/test/recovery/FastFailuresITCase.java
@@ -99,6 +99,8 @@ public class FastFailuresITCase extends TestLogger {
 		catch (Exception e) {
 			e.printStackTrace();
 			fail(e.getMessage());
+		} finally {
+			cluster.stop();
 		}
 	}
 }


[03/11] flink git commit: [FLINK-7956] [flip6] Add support for queued scheduling with slot sharing to SlotPool

Posted by tr...@apache.org.
http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTestBase.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTestBase.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTestBase.java
new file mode 100644
index 0000000..d5460eb
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTestBase.java
@@ -0,0 +1,416 @@
+/*
+ * 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.jobmanager.scheduler;
+
+import org.apache.flink.api.common.JobID;
+import org.apache.flink.runtime.clusterframework.types.AllocationID;
+import org.apache.flink.runtime.clusterframework.types.ResourceID;
+import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
+import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
+import org.apache.flink.runtime.instance.Instance;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotSharingManager;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotPool;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotPoolGateway;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.jobgraph.JobVertexID;
+import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+import org.apache.flink.runtime.jobmaster.JobMasterId;
+import org.apache.flink.runtime.rpc.RpcService;
+import org.apache.flink.runtime.rpc.RpcUtils;
+import org.apache.flink.runtime.rpc.TestingRpcService;
+import org.apache.flink.runtime.taskexecutor.slot.SlotOffer;
+import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+import org.apache.flink.runtime.testingUtils.TestingUtils;
+import org.apache.flink.util.FlinkException;
+import org.apache.flink.util.Preconditions;
+import org.apache.flink.util.TestLogger;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestBase.SchedulerType.SCHEDULER;
+import static org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestBase.SchedulerType.SLOT_POOL;
+import static org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestUtils.getRandomInstance;
+
+/**
+ * Test base for scheduler related test cases. The test are
+ * executed with the {@link Scheduler} and the {@link SlotPool}.
+ */
+public class SchedulerTestBase extends TestLogger {
+
+	protected TestingSlotProvider testingSlotProvider;
+
+	private SchedulerType schedulerType;
+
+	private RpcService rpcService;
+
+	enum SchedulerType {
+		SCHEDULER,
+		SLOT_POOL
+	}
+
+	@Parameterized.Parameters(name = "Scheduler type = {0}")
+	public static Collection<Object[]> schedulerTypes() {
+		return Arrays.asList(
+			new Object[]{SCHEDULER},
+			new Object[]{SLOT_POOL});
+	}
+
+	protected SchedulerTestBase(SchedulerType schedulerType) {
+		this.schedulerType = Preconditions.checkNotNull(schedulerType);
+		rpcService = null;
+	}
+
+	@Before
+	public void setup() throws Exception {
+		switch (schedulerType) {
+			case SCHEDULER:
+				testingSlotProvider = new TestingSchedulerSlotProvider(
+					new Scheduler(
+						TestingUtils.defaultExecutionContext()));
+				break;
+			case SLOT_POOL:
+				rpcService = new TestingRpcService();
+				final JobID jobId = new JobID();
+				final TestingSlotPool slotPool = new TestingSlotPool(rpcService, jobId);
+				testingSlotProvider = new TestingSlotPoolSlotProvider(slotPool);
+
+				final JobMasterId jobMasterId = JobMasterId.generate();
+				final String jobManagerAddress = "localhost";
+				slotPool.start(jobMasterId, jobManagerAddress);
+				break;
+		}
+	}
+
+	@After
+	public void teardown() throws Exception {
+		if (testingSlotProvider != null) {
+			testingSlotProvider.shutdown();
+			testingSlotProvider = null;
+		}
+
+		if (rpcService != null) {
+			rpcService.stopService();
+			rpcService = null;
+		}
+	}
+
+	protected interface TestingSlotProvider extends SlotProvider {
+		TaskManagerLocation addTaskManager(int numberSlots);
+
+		void releaseTaskManager(ResourceID resourceId);
+
+		int getNumberOfAvailableSlots();
+
+		int getNumberOfLocalizedAssignments();
+
+		int getNumberOfNonLocalizedAssignments();
+
+		int getNumberOfUnconstrainedAssignments();
+
+		int getNumberOfHostLocalizedAssignments();
+
+		int getNumberOfSlots(SlotSharingGroup slotSharingGroup);
+
+		int getNumberOfAvailableSlotsForGroup(SlotSharingGroup slotSharingGroup, JobVertexID jobVertexId);
+
+		void shutdown() throws Exception;
+	}
+
+	private static final class TestingSchedulerSlotProvider implements TestingSlotProvider {
+		private final Scheduler scheduler;
+
+		private TestingSchedulerSlotProvider(Scheduler scheduler) {
+			this.scheduler = Preconditions.checkNotNull(scheduler);
+		}
+
+		@Override
+		public CompletableFuture<LogicalSlot> allocateSlot(ScheduledUnit task, boolean allowQueued, Collection<TaskManagerLocation> preferredLocations) {
+			return scheduler.allocateSlot(task, allowQueued, preferredLocations);
+		}
+
+		@Override
+		public TaskManagerLocation addTaskManager(int numberSlots) {
+			final Instance instance = getRandomInstance(numberSlots);
+			scheduler.newInstanceAvailable(instance);
+
+			return instance.getTaskManagerLocation();
+		}
+
+		@Override
+		public void releaseTaskManager(ResourceID resourceId) {
+			final Instance instance = scheduler.getInstance(resourceId);
+
+			if (instance != null) {
+				scheduler.instanceDied(instance);
+			}
+		}
+
+		@Override
+		public int getNumberOfAvailableSlots() {
+			return scheduler.getNumberOfAvailableSlots();
+		}
+
+		@Override
+		public int getNumberOfLocalizedAssignments() {
+			return scheduler.getNumberOfLocalizedAssignments();
+		}
+
+		@Override
+		public int getNumberOfNonLocalizedAssignments() {
+			return scheduler.getNumberOfNonLocalizedAssignments();
+		}
+
+		@Override
+		public int getNumberOfUnconstrainedAssignments() {
+			return scheduler.getNumberOfUnconstrainedAssignments();
+		}
+
+		@Override
+		public int getNumberOfHostLocalizedAssignments() {
+			return 0;
+		}
+
+		@Override
+		public int getNumberOfSlots(SlotSharingGroup slotSharingGroup) {
+			return slotSharingGroup.getTaskAssignment().getNumberOfSlots();
+		}
+
+		@Override
+		public int getNumberOfAvailableSlotsForGroup(SlotSharingGroup slotSharingGroup, JobVertexID jobVertexId) {
+			return slotSharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jobVertexId);
+		}
+
+		@Override
+		public void shutdown() {
+			scheduler.shutdown();
+		}
+	}
+
+	private static final class TestingSlotPoolSlotProvider implements TestingSlotProvider {
+
+		private final TestingSlotPool slotPool;
+
+		private final SlotProvider slotProvider;
+
+		private final AtomicInteger numberOfLocalizedAssignments;
+
+		private final AtomicInteger numberOfNonLocalizedAssignments;
+
+		private final AtomicInteger numberOfUnconstrainedAssignments;
+
+		private final AtomicInteger numberOfHostLocalizedAssignments;
+
+		private TestingSlotPoolSlotProvider(TestingSlotPool slotPool) {
+			this.slotPool = Preconditions.checkNotNull(slotPool);
+			this.slotProvider = slotPool.getSlotProvider();
+
+			this.numberOfLocalizedAssignments = new AtomicInteger();
+			this.numberOfNonLocalizedAssignments = new AtomicInteger();
+			this.numberOfUnconstrainedAssignments = new AtomicInteger();
+			this.numberOfHostLocalizedAssignments = new AtomicInteger();
+		}
+
+		@Override
+		public TaskManagerLocation addTaskManager(int numberSlots) {
+			final TaskManagerLocation taskManagerLocation = new LocalTaskManagerLocation();
+			final ResourceID resourceId = taskManagerLocation.getResourceID();
+			final SlotPoolGateway slotPoolGateway = slotPool.getSelfGateway(SlotPoolGateway.class);
+
+			try {
+				slotPoolGateway.registerTaskManager(resourceId).get();
+			} catch (Exception e) {
+				throw new RuntimeException("Unexpected exception occurred. This indicates a programming bug.", e);
+			}
+
+			final TaskManagerGateway taskManagerGateway = new SimpleAckingTaskManagerGateway();
+			final Collection<SlotOffer> slotOffers = new ArrayList<>(numberSlots);
+
+			for (int i = 0; i < numberSlots; i++) {
+				final SlotOffer slotOffer = new SlotOffer(
+					new AllocationID(),
+					i,
+					ResourceProfile.UNKNOWN);
+
+				slotOffers.add(slotOffer);
+			}
+
+			final Collection<SlotOffer> acceptedSlotOffers;
+
+			try {
+				acceptedSlotOffers = slotPoolGateway.offerSlots(
+					taskManagerLocation,
+					taskManagerGateway,
+					slotOffers).get();
+			} catch (Exception e) {
+				throw new RuntimeException("Unexpected exception occurred. This indicates a programming bug.", e);
+			}
+
+			Preconditions.checkState(acceptedSlotOffers.size() == numberSlots);
+
+			return taskManagerLocation;
+		}
+
+		@Override
+		public void releaseTaskManager(ResourceID resourceId) {
+			try {
+				slotPool.releaseTaskManager(resourceId).get();
+			} catch (Exception e) {
+				throw new RuntimeException("Should not have happened.", e);
+			}
+		}
+
+		@Override
+		public int getNumberOfAvailableSlots() {
+			try {
+				return slotPool.getNumberOfAvailableSlots().get();
+			} catch (Exception e) {
+				throw new RuntimeException("Should not have happened.", e);
+			}
+		}
+
+		@Override
+		public int getNumberOfLocalizedAssignments() {
+			return numberOfLocalizedAssignments.get();
+		}
+
+		@Override
+		public int getNumberOfNonLocalizedAssignments() {
+			return numberOfNonLocalizedAssignments.get();
+		}
+
+		@Override
+		public int getNumberOfUnconstrainedAssignments() {
+			return numberOfUnconstrainedAssignments.get();
+		}
+
+		@Override
+		public int getNumberOfHostLocalizedAssignments() {
+			return numberOfHostLocalizedAssignments.get();
+		}
+
+		@Override
+		public int getNumberOfSlots(SlotSharingGroup slotSharingGroup) {
+			try {
+				return slotPool.getNumberOfSharedSlots(slotSharingGroup.getSlotSharingGroupId()).get();
+			} catch (Exception e) {
+				throw new RuntimeException("Should not have happened.", e);
+			}
+		}
+
+		@Override
+		public int getNumberOfAvailableSlotsForGroup(SlotSharingGroup slotSharingGroup, JobVertexID jobVertexId) {
+			try {
+				return slotPool.getNumberOfAvailableSlotsForGroup(slotSharingGroup.getSlotSharingGroupId(), jobVertexId).get();
+			} catch (Exception e) {
+				throw new RuntimeException("Should not have happened.", e);
+			}
+		}
+
+		@Override
+		public void shutdown() throws Exception {
+			RpcUtils.terminateRpcEndpoint(slotPool, TestingUtils.TIMEOUT());
+		}
+
+		@Override
+		public CompletableFuture<LogicalSlot> allocateSlot(ScheduledUnit task, boolean allowQueued, Collection<TaskManagerLocation> preferredLocations) {
+			return slotProvider.allocateSlot(task, allowQueued, preferredLocations).thenApply(
+				(LogicalSlot logicalSlot) -> {
+					switch (logicalSlot.getLocality()) {
+						case LOCAL:
+							numberOfLocalizedAssignments.incrementAndGet();
+							break;
+						case UNCONSTRAINED:
+							numberOfUnconstrainedAssignments.incrementAndGet();
+							break;
+						case NON_LOCAL:
+							numberOfNonLocalizedAssignments.incrementAndGet();
+							break;
+						case HOST_LOCAL:
+							numberOfHostLocalizedAssignments.incrementAndGet();
+							break;
+						default:
+							// ignore
+					}
+
+					return logicalSlot;
+				});
+		}
+	}
+
+	private static final class TestingSlotPool extends SlotPool {
+
+		public TestingSlotPool(RpcService rpcService, JobID jobId) {
+			super(rpcService, jobId);
+		}
+
+		CompletableFuture<Integer> getNumberOfAvailableSlots() {
+			return callAsync(
+				() -> getAvailableSlots().size(),
+				TestingUtils.infiniteTime());
+		}
+
+		CompletableFuture<Integer> getNumberOfSharedSlots(SlotSharingGroupId slotSharingGroupId) {
+			return callAsync(
+				() -> {
+					final SlotSharingManager multiTaskSlotManager = slotSharingManagers.get(slotSharingGroupId);
+
+					if (multiTaskSlotManager != null) {
+						return multiTaskSlotManager.getResolvedRootSlots().size();
+					} else {
+						throw new FlinkException("No MultiTaskSlotManager registered under " + slotSharingGroupId + '.');
+					}
+				},
+				TestingUtils.infiniteTime());
+		}
+
+		CompletableFuture<Integer> getNumberOfAvailableSlotsForGroup(SlotSharingGroupId slotSharingGroupId, JobVertexID jobVertexId) {
+			return callAsync(
+				() -> {
+					final SlotSharingManager multiTaskSlotManager = slotSharingManagers.get(slotSharingGroupId);
+
+					if (multiTaskSlotManager != null) {
+						int availableSlots = 0;
+
+						for (SlotSharingManager.MultiTaskSlot multiTaskSlot : multiTaskSlotManager.getResolvedRootSlots()) {
+							if (!multiTaskSlot.contains(jobVertexId)) {
+								availableSlots++;
+							}
+						}
+
+						return availableSlots;
+					} else {
+						throw new FlinkException("No MultiTaskSlotmanager registered under " + slotSharingGroupId + '.');
+					}
+				},
+				TestingUtils.infiniteTime());
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTestUtils.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTestUtils.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTestUtils.java
index 98dca03..4186255 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTestUtils.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTestUtils.java
@@ -18,9 +18,18 @@
 
 package org.apache.flink.runtime.jobmanager.scheduler;
 
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import org.apache.flink.api.common.JobID;
+import org.apache.flink.runtime.clusterframework.types.ResourceID;
+import org.apache.flink.runtime.executiongraph.Execution;
+import org.apache.flink.runtime.executiongraph.ExecutionJobVertex;
+import org.apache.flink.runtime.executiongraph.ExecutionVertex;
+import org.apache.flink.runtime.instance.DummyActorGateway;
+import org.apache.flink.runtime.instance.HardwareDescription;
+import org.apache.flink.runtime.instance.Instance;
+import org.apache.flink.runtime.instance.InstanceID;
+import org.apache.flink.runtime.jobgraph.JobVertexID;
+import org.apache.flink.runtime.jobmanager.slots.ActorTaskManagerGateway;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -33,17 +42,9 @@ import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.apache.flink.runtime.clusterframework.types.ResourceID;
-import org.apache.flink.runtime.executiongraph.Execution;
-import org.apache.flink.runtime.executiongraph.ExecutionVertex;
-import org.apache.flink.runtime.instance.DummyActorGateway;
-import org.apache.flink.runtime.instance.HardwareDescription;
-import org.apache.flink.runtime.instance.Instance;
-import org.apache.flink.runtime.jobmanager.slots.ActorTaskManagerGateway;
-import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-import org.apache.flink.runtime.instance.InstanceID;
-import org.apache.flink.api.common.JobID;
-import org.apache.flink.runtime.jobgraph.JobVertexID;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 
 public class SchedulerTestUtils {
@@ -83,9 +84,13 @@ public class SchedulerTestUtils {
 	
 	
 	public static Execution getDummyTask() {
+		ExecutionJobVertex executionJobVertex = mock(ExecutionJobVertex.class);
+
 		ExecutionVertex vertex = mock(ExecutionVertex.class);
 		when(vertex.getJobId()).thenReturn(new JobID());
 		when(vertex.toString()).thenReturn("TEST-VERTEX");
+		when(vertex.getJobVertex()).thenReturn(executionJobVertex);
+		when(vertex.getJobvertexId()).thenReturn(new JobVertexID());
 		
 		Execution execution = mock(Execution.class);
 		when(execution.getVertex()).thenReturn(vertex);
@@ -117,11 +122,14 @@ public class SchedulerTestUtils {
 	}
 
 	public static Execution getTestVertex(Collection<CompletableFuture<TaskManagerLocation>> preferredLocationFutures) {
+		ExecutionJobVertex executionJobVertex = mock(ExecutionJobVertex.class);
 		ExecutionVertex vertex = mock(ExecutionVertex.class);
 
 		when(vertex.getPreferredLocationsBasedOnInputs()).thenReturn(preferredLocationFutures);
 		when(vertex.getJobId()).thenReturn(new JobID());
 		when(vertex.toString()).thenReturn("TEST-VERTEX");
+		when(vertex.getJobVertex()).thenReturn(executionJobVertex);
+		when(vertex.getJobvertexId()).thenReturn(new JobVertexID());
 
 		Execution execution = mock(Execution.class);
 		when(execution.getVertex()).thenReturn(vertex);
@@ -130,9 +138,11 @@ public class SchedulerTestUtils {
 		return execution;
 	}
 	
-	public static Execution getTestVertex(JobVertexID jid, int taskIndex, int numTasks) {
+	public static Execution getTestVertex(JobVertexID jid, int taskIndex, int numTasks, SlotSharingGroup slotSharingGroup) {
+		ExecutionJobVertex executionJobVertex = mock(ExecutionJobVertex.class);
 		ExecutionVertex vertex = mock(ExecutionVertex.class);
-		
+
+		when(executionJobVertex.getSlotSharingGroup()).thenReturn(slotSharingGroup);
 		when(vertex.getPreferredLocationsBasedOnInputs()).thenReturn(Collections.emptyList());
 		when(vertex.getJobId()).thenReturn(new JobID());
 		when(vertex.getJobvertexId()).thenReturn(jid);
@@ -141,6 +151,7 @@ public class SchedulerTestUtils {
 		when(vertex.getMaxParallelism()).thenReturn(numTasks);
 		when(vertex.toString()).thenReturn("TEST-VERTEX");
 		when(vertex.getTaskNameWithSubtaskIndex()).thenReturn("TEST-VERTEX");
+		when(vertex.getJobVertex()).thenReturn(executionJobVertex);
 		
 		Execution execution = mock(Execution.class);
 		when(execution.getVertex()).thenReturn(vertex);
@@ -149,17 +160,26 @@ public class SchedulerTestUtils {
 	}
 
 	public static Execution getTestVertexWithLocation(
-			JobVertexID jid, int taskIndex, int numTasks, TaskManagerLocation... locations) {
+			JobVertexID jid,
+			int taskIndex,
+			int numTasks,
+			SlotSharingGroup slotSharingGroup,
+			TaskManagerLocation... locations) {
+
+		ExecutionJobVertex executionJobVertex = mock(ExecutionJobVertex.class);
+
+		when(executionJobVertex.getSlotSharingGroup()).thenReturn(slotSharingGroup);
 
 		ExecutionVertex vertex = mock(ExecutionVertex.class);
 
-		Collection<CompletableFuture<TaskManagerLocation>> preferrecLocationFutures = new ArrayList<>(locations.length);
+		Collection<CompletableFuture<TaskManagerLocation>> preferredLocationFutures = new ArrayList<>(locations.length);
 
 		for (TaskManagerLocation location : locations) {
-			preferrecLocationFutures.add(CompletableFuture.completedFuture(location));
+			preferredLocationFutures.add(CompletableFuture.completedFuture(location));
 		}
 
-		when(vertex.getPreferredLocationsBasedOnInputs()).thenReturn(preferrecLocationFutures);
+		when(vertex.getJobVertex()).thenReturn(executionJobVertex);
+		when(vertex.getPreferredLocationsBasedOnInputs()).thenReturn(preferredLocationFutures);
 		when(vertex.getJobId()).thenReturn(new JobID());
 		when(vertex.getJobvertexId()).thenReturn(jid);
 		when(vertex.getParallelSubtaskIndex()).thenReturn(taskIndex);

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/slots/DummySlotOwner.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/slots/DummySlotOwner.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/slots/DummySlotOwner.java
index 6d17ad0..add1ec2 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/slots/DummySlotOwner.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/slots/DummySlotOwner.java
@@ -18,7 +18,8 @@
 
 package org.apache.flink.runtime.jobmanager.slots;
 
-import org.apache.flink.runtime.instance.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.SlotOwner;
 
 import java.util.concurrent.CompletableFuture;
 

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/slots/TestingSlotOwner.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/slots/TestingSlotOwner.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/slots/TestingSlotOwner.java
index e7f9485..727c0b5 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/slots/TestingSlotOwner.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/slots/TestingSlotOwner.java
@@ -18,7 +18,8 @@
 
 package org.apache.flink.runtime.jobmanager.slots;
 
-import org.apache.flink.runtime.instance.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.SlotOwner;
 
 import java.util.concurrent.CompletableFuture;
 import java.util.function.Consumer;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/TestingLogicalSlot.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/TestingLogicalSlot.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/TestingLogicalSlot.java
new file mode 100644
index 0000000..e20700e
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/TestingLogicalSlot.java
@@ -0,0 +1,140 @@
+/*
+ * 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;
+
+import org.apache.flink.runtime.clusterframework.types.AllocationID;
+import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
+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.taskmanager.LocalTaskManagerLocation;
+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.AtomicReference;
+
+/**
+ * Simple logical slot for testing purposes.
+ */
+public class TestingLogicalSlot implements LogicalSlot {
+
+	private final TaskManagerLocation taskManagerLocation;
+
+	private final TaskManagerGateway taskManagerGateway;
+
+	private final AtomicReference<Payload> payloadReference;
+
+	private final int slotNumber;
+
+	private final CompletableFuture<?> releaseFuture = new CompletableFuture<>();
+	
+	private final AllocationID allocationId;
+
+	private final SlotRequestId slotRequestId;
+
+	private final SlotSharingGroupId slotSharingGroupId;
+
+	public TestingLogicalSlot() {
+		this(
+			new LocalTaskManagerLocation(),
+			new SimpleAckingTaskManagerGateway(),
+			0,
+			new AllocationID(),
+			new SlotRequestId(),
+			new SlotSharingGroupId());
+	}
+
+	public TestingLogicalSlot(
+			TaskManagerLocation taskManagerLocation,
+			TaskManagerGateway taskManagerGateway,
+			int slotNumber,
+			AllocationID allocationId,
+			SlotRequestId slotRequestId,
+			SlotSharingGroupId slotSharingGroupId) {
+		this.taskManagerLocation = Preconditions.checkNotNull(taskManagerLocation);
+		this.taskManagerGateway = Preconditions.checkNotNull(taskManagerGateway);
+		this.payloadReference = new AtomicReference<>();
+		this.slotNumber = slotNumber;
+		this.allocationId = Preconditions.checkNotNull(allocationId);
+		this.slotRequestId = Preconditions.checkNotNull(slotRequestId);
+		this.slotSharingGroupId = Preconditions.checkNotNull(slotSharingGroupId);
+	}
+
+	@Override
+	public TaskManagerLocation getTaskManagerLocation() {
+		return taskManagerLocation;
+	}
+
+	@Override
+	public TaskManagerGateway getTaskManagerGateway() {
+		return taskManagerGateway;
+	}
+
+	@Override
+	public Locality getLocality() {
+		return Locality.UNKNOWN;
+	}
+
+	@Override
+	public boolean isAlive() {
+		return !releaseFuture.isDone();
+	}
+
+	@Override
+	public boolean tryAssignPayload(Payload payload) {
+		return payloadReference.compareAndSet(null, payload);
+	}
+
+	@Nullable
+	@Override
+	public Payload getPayload() {
+		return payloadReference.get();
+	}
+
+	@Override
+	public CompletableFuture<?> releaseSlot(@Nullable Throwable cause) {
+		releaseFuture.complete(null);
+
+		return releaseFuture;
+	}
+
+	@Override
+	public int getPhysicalSlotNumber() {
+		return slotNumber;
+	}
+
+	@Override
+	public AllocationID getAllocationId() {
+		return allocationId;
+	}
+
+	@Override
+	public SlotRequestId getSlotRequestId() {
+		return slotRequestId;
+	}
+
+	@Nullable
+	@Override
+	public SlotSharingGroupId getSlotSharingGroupId() {
+		return slotSharingGroupId;
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/TestingPayload.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/TestingPayload.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/TestingPayload.java
new file mode 100644
index 0000000..a59f765
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/TestingPayload.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Simple payload implementation for testing purposes.
+ */
+public class TestingPayload implements LogicalSlot.Payload {
+
+	private final CompletableFuture<?> terminationFuture;
+
+	public TestingPayload() {
+		this.terminationFuture = new CompletableFuture<>();
+	}
+
+
+	@Override
+	public void fail(Throwable cause) {
+		terminationFuture.complete(null);
+	}
+
+	@Override
+	public CompletableFuture<?> getTerminalStateFuture() {
+		return terminationFuture;
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/AllocatedSlotsTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/AllocatedSlotsTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/AllocatedSlotsTest.java
new file mode 100644
index 0000000..4dee924
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/AllocatedSlotsTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.clusterframework.types.ResourceID;
+import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
+import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
+import org.apache.flink.runtime.jobmaster.SlotRequestId;
+import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+import org.apache.flink.util.TestLogger;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class AllocatedSlotsTest extends TestLogger {
+
+	@Test
+	public void testOperations() throws Exception {
+		SlotPool.AllocatedSlots allocatedSlots = new SlotPool.AllocatedSlots();
+
+		final AllocationID allocation1 = new AllocationID();
+		final SlotRequestId slotRequestID = new SlotRequestId();
+		final TaskManagerLocation taskManagerLocation = new LocalTaskManagerLocation();
+		final ResourceID resource1 = taskManagerLocation.getResourceID();
+		final AllocatedSlot slot1 = createSlot(allocation1, taskManagerLocation);
+
+		allocatedSlots.add(slotRequestID, slot1);
+
+		assertTrue(allocatedSlots.contains(slot1.getAllocationId()));
+		assertTrue(allocatedSlots.containResource(resource1));
+
+		assertEquals(slot1, allocatedSlots.get(allocation1));
+		assertEquals(1, allocatedSlots.getSlotsForTaskManager(resource1).size());
+		assertEquals(1, allocatedSlots.size());
+
+		final AllocationID allocation2 = new AllocationID();
+		final SlotRequestId slotRequestID2 = new SlotRequestId();
+		final AllocatedSlot slot2 = createSlot(allocation2, taskManagerLocation);
+
+		allocatedSlots.add(slotRequestID2, slot2);
+
+		assertTrue(allocatedSlots.contains(slot1.getAllocationId()));
+		assertTrue(allocatedSlots.contains(slot2.getAllocationId()));
+		assertTrue(allocatedSlots.containResource(resource1));
+
+		assertEquals(slot1, allocatedSlots.get(allocation1));
+		assertEquals(slot2, allocatedSlots.get(allocation2));
+		assertEquals(2, allocatedSlots.getSlotsForTaskManager(resource1).size());
+		assertEquals(2, allocatedSlots.size());
+
+		final AllocationID allocation3 = new AllocationID();
+		final SlotRequestId slotRequestID3 = new SlotRequestId();
+		final TaskManagerLocation taskManagerLocation2 = new LocalTaskManagerLocation();
+		final ResourceID resource2 = taskManagerLocation2.getResourceID();
+		final AllocatedSlot slot3 = createSlot(allocation3, taskManagerLocation2);
+
+		allocatedSlots.add(slotRequestID3, slot3);
+
+		assertTrue(allocatedSlots.contains(slot1.getAllocationId()));
+		assertTrue(allocatedSlots.contains(slot2.getAllocationId()));
+		assertTrue(allocatedSlots.contains(slot3.getAllocationId()));
+		assertTrue(allocatedSlots.containResource(resource1));
+		assertTrue(allocatedSlots.containResource(resource2));
+
+		assertEquals(slot1, allocatedSlots.get(allocation1));
+		assertEquals(slot2, allocatedSlots.get(allocation2));
+		assertEquals(slot3, allocatedSlots.get(allocation3));
+		assertEquals(2, allocatedSlots.getSlotsForTaskManager(resource1).size());
+		assertEquals(1, allocatedSlots.getSlotsForTaskManager(resource2).size());
+		assertEquals(3, allocatedSlots.size());
+
+		allocatedSlots.remove(slot2.getAllocationId());
+
+		assertTrue(allocatedSlots.contains(slot1.getAllocationId()));
+		assertFalse(allocatedSlots.contains(slot2.getAllocationId()));
+		assertTrue(allocatedSlots.contains(slot3.getAllocationId()));
+		assertTrue(allocatedSlots.containResource(resource1));
+		assertTrue(allocatedSlots.containResource(resource2));
+
+		assertEquals(slot1, allocatedSlots.get(allocation1));
+		assertNull(allocatedSlots.get(allocation2));
+		assertEquals(slot3, allocatedSlots.get(allocation3));
+		assertEquals(1, allocatedSlots.getSlotsForTaskManager(resource1).size());
+		assertEquals(1, allocatedSlots.getSlotsForTaskManager(resource2).size());
+		assertEquals(2, allocatedSlots.size());
+
+		allocatedSlots.remove(slot1.getAllocationId());
+
+		assertFalse(allocatedSlots.contains(slot1.getAllocationId()));
+		assertFalse(allocatedSlots.contains(slot2.getAllocationId()));
+		assertTrue(allocatedSlots.contains(slot3.getAllocationId()));
+		assertFalse(allocatedSlots.containResource(resource1));
+		assertTrue(allocatedSlots.containResource(resource2));
+
+		assertNull(allocatedSlots.get(allocation1));
+		assertNull(allocatedSlots.get(allocation2));
+		assertEquals(slot3, allocatedSlots.get(allocation3));
+		assertEquals(0, allocatedSlots.getSlotsForTaskManager(resource1).size());
+		assertEquals(1, allocatedSlots.getSlotsForTaskManager(resource2).size());
+		assertEquals(1, allocatedSlots.size());
+
+		allocatedSlots.remove(slot3.getAllocationId());
+
+		assertFalse(allocatedSlots.contains(slot1.getAllocationId()));
+		assertFalse(allocatedSlots.contains(slot2.getAllocationId()));
+		assertFalse(allocatedSlots.contains(slot3.getAllocationId()));
+		assertFalse(allocatedSlots.containResource(resource1));
+		assertFalse(allocatedSlots.containResource(resource2));
+
+		assertNull(allocatedSlots.get(allocation1));
+		assertNull(allocatedSlots.get(allocation2));
+		assertNull(allocatedSlots.get(allocation3));
+		assertEquals(0, allocatedSlots.getSlotsForTaskManager(resource1).size());
+		assertEquals(0, allocatedSlots.getSlotsForTaskManager(resource2).size());
+		assertEquals(0, allocatedSlots.size());
+	}
+
+	private AllocatedSlot createSlot(final AllocationID allocationId, final TaskManagerLocation taskManagerLocation) {
+		return new AllocatedSlot(
+			allocationId,
+			taskManagerLocation,
+			0,
+			ResourceProfile.UNKNOWN,
+			new SimpleAckingTaskManagerGateway());
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/AvailableSlotsTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/AvailableSlotsTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/AvailableSlotsTest.java
new file mode 100644
index 0000000..4835c57
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/AvailableSlotsTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.clusterframework.types.ResourceID;
+import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
+import org.apache.flink.runtime.jobmanager.slots.SlotAndLocality;
+import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+import org.apache.flink.util.TestLogger;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AvailableSlotsTest extends TestLogger {
+
+	static final ResourceProfile DEFAULT_TESTING_PROFILE = new ResourceProfile(1.0, 512);
+
+	static final ResourceProfile DEFAULT_TESTING_BIG_PROFILE = new ResourceProfile(2.0, 1024);
+
+	@Test
+	public void testAddAndRemove() throws Exception {
+		SlotPool.AvailableSlots availableSlots = new SlotPool.AvailableSlots();
+
+		final ResourceID resource1 = new ResourceID("resource1");
+		final ResourceID resource2 = new ResourceID("resource2");
+
+		final AllocatedSlot slot1 = createAllocatedSlot(resource1);
+		final AllocatedSlot slot2 = createAllocatedSlot(resource1);
+		final AllocatedSlot slot3 = createAllocatedSlot(resource2);
+
+		availableSlots.add(slot1, 1L);
+		availableSlots.add(slot2, 2L);
+		availableSlots.add(slot3, 3L);
+
+		assertEquals(3, availableSlots.size());
+		assertTrue(availableSlots.contains(slot1.getAllocationId()));
+		assertTrue(availableSlots.contains(slot2.getAllocationId()));
+		assertTrue(availableSlots.contains(slot3.getAllocationId()));
+		assertTrue(availableSlots.containsTaskManager(resource1));
+		assertTrue(availableSlots.containsTaskManager(resource2));
+
+		availableSlots.removeAllForTaskManager(resource1);
+
+		assertEquals(1, availableSlots.size());
+		assertFalse(availableSlots.contains(slot1.getAllocationId()));
+		assertFalse(availableSlots.contains(slot2.getAllocationId()));
+		assertTrue(availableSlots.contains(slot3.getAllocationId()));
+		assertFalse(availableSlots.containsTaskManager(resource1));
+		assertTrue(availableSlots.containsTaskManager(resource2));
+
+		availableSlots.removeAllForTaskManager(resource2);
+
+		assertEquals(0, availableSlots.size());
+		assertFalse(availableSlots.contains(slot1.getAllocationId()));
+		assertFalse(availableSlots.contains(slot2.getAllocationId()));
+		assertFalse(availableSlots.contains(slot3.getAllocationId()));
+		assertFalse(availableSlots.containsTaskManager(resource1));
+		assertFalse(availableSlots.containsTaskManager(resource2));
+	}
+
+	@Test
+	public void testPollFreeSlot() {
+		SlotPool.AvailableSlots availableSlots = new SlotPool.AvailableSlots();
+
+		final ResourceID resource1 = new ResourceID("resource1");
+		final AllocatedSlot slot1 = createAllocatedSlot(resource1);
+
+		availableSlots.add(slot1, 1L);
+
+		assertEquals(1, availableSlots.size());
+		assertTrue(availableSlots.contains(slot1.getAllocationId()));
+		assertTrue(availableSlots.containsTaskManager(resource1));
+
+		assertNull(availableSlots.poll(DEFAULT_TESTING_BIG_PROFILE, null));
+
+		SlotAndLocality slotAndLocality = availableSlots.poll(DEFAULT_TESTING_PROFILE, null);
+		assertEquals(slot1, slotAndLocality.getSlot());
+		assertEquals(0, availableSlots.size());
+		assertFalse(availableSlots.contains(slot1.getAllocationId()));
+		assertFalse(availableSlots.containsTaskManager(resource1));
+	}
+
+	static AllocatedSlot createAllocatedSlot(final ResourceID resourceId) {
+		TaskManagerLocation mockTaskManagerLocation = mock(TaskManagerLocation.class);
+		when(mockTaskManagerLocation.getResourceID()).thenReturn(resourceId);
+
+		TaskManagerGateway mockTaskManagerGateway = mock(TaskManagerGateway.class);
+
+		return new AllocatedSlot(
+			new AllocationID(),
+			mockTaskManagerLocation,
+			0,
+			DEFAULT_TESTING_PROFILE,
+			mockTaskManagerGateway);
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolCoLocationTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolCoLocationTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolCoLocationTest.java
new file mode 100644
index 0000000..7454e3e
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolCoLocationTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.clusterframework.types.ResourceProfile;
+import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.jobgraph.JobVertexID;
+import org.apache.flink.runtime.jobmanager.scheduler.CoLocationConstraint;
+import org.apache.flink.runtime.jobmanager.scheduler.CoLocationGroup;
+import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.resourcemanager.SlotRequest;
+import org.apache.flink.runtime.taskexecutor.slot.SlotOffer;
+import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test cases for {@link CoLocationConstraint} with the {@link SlotPool}.
+ */
+public class SlotPoolCoLocationTest extends SlotPoolSchedulingTestBase {
+
+	/**
+	 * Tests the scheduling of two tasks with a parallelism of 2 and a co-location constraint.
+	 */
+	@Test
+	public void testSimpleCoLocatedSlotScheduling() throws ExecutionException, InterruptedException {
+		final BlockingQueue<AllocationID> allocationIds = new ArrayBlockingQueue<>(2);
+
+		testingResourceManagerGateway.setRequestSlotConsumer(
+			(SlotRequest slotRequest) -> allocationIds.offer(slotRequest.getAllocationId()));
+
+		final TaskManagerLocation taskManagerLocation = new LocalTaskManagerLocation();
+
+		slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID()).get();
+
+		CoLocationGroup group = new CoLocationGroup();
+		CoLocationConstraint coLocationConstraint1 = group.getLocationConstraint(0);
+		CoLocationConstraint coLocationConstraint2 = group.getLocationConstraint(1);
+
+		final SlotSharingGroupId slotSharingGroupId = new SlotSharingGroupId();
+
+		JobVertexID jobVertexId1 = new JobVertexID();
+		JobVertexID jobVertexId2 = new JobVertexID();
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture11 = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				jobVertexId1,
+				slotSharingGroupId,
+				coLocationConstraint1),
+			true,
+			Collections.emptyList());
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture22 = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				jobVertexId2,
+				slotSharingGroupId,
+				coLocationConstraint2),
+			true,
+			Collections.emptyList());
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture12 = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				jobVertexId2,
+				slotSharingGroupId,
+				coLocationConstraint1),
+			true,
+			Collections.emptyList());
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture21 = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				jobVertexId1,
+				slotSharingGroupId,
+				coLocationConstraint2),
+			true,
+			Collections.emptyList());
+
+		final AllocationID allocationId1 = allocationIds.take();
+		final AllocationID allocationId2 = allocationIds.take();
+
+		CompletableFuture<Boolean> slotOfferFuture1 = slotPoolGateway.offerSlot(
+			taskManagerLocation,
+			new SimpleAckingTaskManagerGateway(),
+			new SlotOffer(
+				allocationId1,
+				0,
+				ResourceProfile.UNKNOWN));
+
+		CompletableFuture<Boolean> slotOfferFuture2 = slotPoolGateway.offerSlot(
+			taskManagerLocation,
+			new SimpleAckingTaskManagerGateway(),
+			new SlotOffer(
+				allocationId2,
+				0,
+				ResourceProfile.UNKNOWN));
+
+		assertTrue(slotOfferFuture1.get());
+		assertTrue(slotOfferFuture2.get());
+
+		LogicalSlot logicalSlot11 = logicalSlotFuture11.get();
+		LogicalSlot logicalSlot12 = logicalSlotFuture12.get();
+		LogicalSlot logicalSlot21 = logicalSlotFuture21.get();
+		LogicalSlot logicalSlot22 = logicalSlotFuture22.get();
+
+		assertEquals(logicalSlot11.getAllocationId(), logicalSlot12.getAllocationId());
+		assertEquals(logicalSlot21.getAllocationId(), logicalSlot22.getAllocationId());
+		assertNotEquals(logicalSlot11.getAllocationId(), logicalSlot21.getAllocationId());
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolRpcTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolRpcTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolRpcTest.java
new file mode 100644
index 0000000..2d862c5
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolRpcTest.java
@@ -0,0 +1,409 @@
+/*
+ * 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.api.common.JobID;
+import org.apache.flink.api.common.time.Time;
+import org.apache.flink.configuration.Configuration;
+import org.apache.flink.runtime.akka.AkkaUtils;
+import org.apache.flink.runtime.clusterframework.types.AllocationID;
+import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.jobmanager.scheduler.NoResourceAvailableException;
+import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
+import org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestUtils;
+import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+import org.apache.flink.runtime.jobmaster.JobMasterId;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.SlotRequestId;
+import org.apache.flink.runtime.messages.Acknowledge;
+import org.apache.flink.runtime.resourcemanager.ResourceManagerGateway;
+import org.apache.flink.runtime.resourcemanager.SlotRequest;
+import org.apache.flink.runtime.resourcemanager.utils.TestingResourceManagerGateway;
+import org.apache.flink.runtime.rpc.RpcService;
+import org.apache.flink.runtime.rpc.RpcUtils;
+import org.apache.flink.runtime.rpc.akka.AkkaRpcService;
+import org.apache.flink.runtime.taskexecutor.slot.SlotOffer;
+import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+import org.apache.flink.runtime.testingUtils.TestingUtils;
+import org.apache.flink.runtime.util.clock.Clock;
+import org.apache.flink.runtime.util.clock.SystemClock;
+import org.apache.flink.util.ExceptionUtils;
+import org.apache.flink.util.Preconditions;
+import org.apache.flink.util.TestLogger;
+
+import akka.actor.ActorSystem;
+import akka.pattern.AskTimeoutException;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
+
+import static org.apache.flink.runtime.jobmaster.slotpool.AvailableSlotsTest.DEFAULT_TESTING_PROFILE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests for the SlotPool using a proper RPC setup.
+ */
+public class SlotPoolRpcTest extends TestLogger {
+
+	private static RpcService rpcService;
+
+	private static final Time timeout = Time.seconds(10L);
+
+	// ------------------------------------------------------------------------
+	//  setup
+	// ------------------------------------------------------------------------
+
+	@BeforeClass
+	public static void setup() {
+		ActorSystem actorSystem = AkkaUtils.createLocalActorSystem(new Configuration());
+		rpcService = new AkkaRpcService(actorSystem, Time.seconds(10));
+	}
+
+	@AfterClass
+	public static  void shutdown() {
+		if (rpcService != null) {
+			rpcService.stopService();
+			rpcService = null;
+		}
+	}
+
+	// ------------------------------------------------------------------------
+	//  tests
+	// ------------------------------------------------------------------------
+
+	@Test
+	public void testSlotAllocationNoResourceManager() throws Exception {
+		final JobID jid = new JobID();
+		
+		final SlotPool pool = new SlotPool(
+			rpcService,
+			jid,
+			SystemClock.getInstance(),
+			TestingUtils.infiniteTime(),
+			TestingUtils.infiniteTime(),
+			Time.milliseconds(10L) // this is the timeout for the request tested here
+		);
+
+		try {
+			pool.start(JobMasterId.generate(), "foobar");
+
+			CompletableFuture<LogicalSlot> future = pool.allocateSlot(
+				new SlotRequestId(),
+				new ScheduledUnit(SchedulerTestUtils.getDummyTask()),
+				DEFAULT_TESTING_PROFILE,
+				Collections.emptyList(),
+				true,
+				TestingUtils.infiniteTime());
+
+			try {
+				future.get();
+				fail("We expected an ExecutionException.");
+			} catch (ExecutionException e) {
+				assertTrue(ExceptionUtils.stripExecutionException(e) instanceof NoResourceAvailableException);
+			}
+		} finally {
+			RpcUtils.terminateRpcEndpoint(pool, timeout);
+		}
+	}
+
+	@Test
+	public void testCancelSlotAllocationWithoutResourceManager() throws Exception {
+		final JobID jid = new JobID();
+
+		final TestingSlotPool pool = new TestingSlotPool(
+			rpcService,
+			jid,
+			SystemClock.getInstance(),
+			TestingUtils.infiniteTime(),
+			TestingUtils.infiniteTime(),
+			TestingUtils.infiniteTime());
+
+		try {
+			pool.start(JobMasterId.generate(), "foobar");
+			SlotPoolGateway slotPoolGateway = pool.getSelfGateway(SlotPoolGateway.class);
+
+			SlotRequestId requestId = new SlotRequestId();
+			CompletableFuture<LogicalSlot> future = slotPoolGateway.allocateSlot(
+				requestId,
+				new ScheduledUnit(SchedulerTestUtils.getDummyTask()),
+				DEFAULT_TESTING_PROFILE,
+				Collections.emptyList(),
+				true,
+				Time.milliseconds(10L));
+
+			try {
+				future.get();
+				fail("We expected a AskTimeoutException.");
+			} catch (ExecutionException e) {
+				assertTrue(ExceptionUtils.stripExecutionException(e) instanceof AskTimeoutException);
+			}
+
+			assertEquals(1L, (long) pool.getNumberOfWaitingForResourceRequests().get());
+
+			slotPoolGateway.releaseSlot(requestId, null, null).get();
+
+			assertEquals(0L, (long) pool.getNumberOfWaitingForResourceRequests().get());
+		} finally {
+			RpcUtils.terminateRpcEndpoint(pool, timeout);
+		}
+	}
+
+	@Test
+	public void testCancelSlotAllocationWithResourceManager() throws Exception {
+		final JobID jid = new JobID();
+
+		final TestingSlotPool pool = new TestingSlotPool(
+			rpcService,
+			jid,
+			SystemClock.getInstance(),
+			TestingUtils.infiniteTime(),
+			TestingUtils.infiniteTime(),
+			TestingUtils.infiniteTime());
+
+		try {
+			pool.start(JobMasterId.generate(), "foobar");
+			SlotPoolGateway slotPoolGateway = pool.getSelfGateway(SlotPoolGateway.class);
+
+			ResourceManagerGateway resourceManagerGateway = new TestingResourceManagerGateway();
+			pool.connectToResourceManager(resourceManagerGateway);
+
+			SlotRequestId requestId = new SlotRequestId();
+			CompletableFuture<LogicalSlot> future = slotPoolGateway.allocateSlot(
+				requestId,
+				new ScheduledUnit(SchedulerTestUtils.getDummyTask()),
+				DEFAULT_TESTING_PROFILE,
+				Collections.emptyList(),
+				true,
+				Time.milliseconds(10L));
+
+			try {
+				future.get();
+				fail("We expected a AskTimeoutException.");
+			} catch (ExecutionException e) {
+				assertTrue(ExceptionUtils.stripExecutionException(e) instanceof AskTimeoutException);
+			}
+
+			assertEquals(1L, (long) pool.getNumberOfPendingRequests().get());
+
+			slotPoolGateway.releaseSlot(requestId, null, null).get();
+			assertEquals(0L, (long) pool.getNumberOfPendingRequests().get());
+		} finally {
+			RpcUtils.terminateRpcEndpoint(pool, timeout);
+		}
+	}
+
+	/**
+	 * Tests that allocated slots are not cancelled.
+	 */
+	@Test
+	public void testCancelSlotAllocationWhileSlotFulfilled() throws Exception {
+		final JobID jid = new JobID();
+
+		final TestingSlotPool pool = new TestingSlotPool(
+			rpcService,
+			jid,
+			SystemClock.getInstance(),
+			TestingUtils.infiniteTime(),
+			TestingUtils.infiniteTime(),
+			TestingUtils.infiniteTime());
+
+		try {
+			pool.start(JobMasterId.generate(), "foobar");
+			SlotPoolGateway slotPoolGateway = pool.getSelfGateway(SlotPoolGateway.class);
+
+			final CompletableFuture<AllocationID> allocationIdFuture = new CompletableFuture<>();
+
+			TestingResourceManagerGateway resourceManagerGateway = new TestingResourceManagerGateway();
+			resourceManagerGateway.setRequestSlotConsumer(
+				(SlotRequest slotRequest) -> allocationIdFuture.complete(slotRequest.getAllocationId()));
+
+			pool.connectToResourceManager(resourceManagerGateway);
+
+			SlotRequestId requestId = new SlotRequestId();
+			CompletableFuture<LogicalSlot> future = slotPoolGateway.allocateSlot(
+				requestId,
+				new ScheduledUnit(SchedulerTestUtils.getDummyTask()),
+				DEFAULT_TESTING_PROFILE,
+				Collections.emptyList(),
+				true,
+				Time.milliseconds(10L));
+
+			try {
+				future.get();
+				fail("We expected a AskTimeoutException.");
+			} catch (ExecutionException e) {
+				assertTrue(ExceptionUtils.stripExecutionException(e) instanceof AskTimeoutException);
+			}
+
+			AllocationID allocationId = allocationIdFuture.get();
+			final SlotOffer slotOffer = new SlotOffer(
+				allocationId,
+				0,
+				DEFAULT_TESTING_PROFILE);
+			final TaskManagerLocation taskManagerLocation = new LocalTaskManagerLocation();
+			final TaskManagerGateway taskManagerGateway = new SimpleAckingTaskManagerGateway();
+
+			slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID()).get();
+
+			assertTrue(slotPoolGateway.offerSlot(taskManagerLocation, taskManagerGateway, slotOffer).get());
+
+			assertEquals(0L, (long) pool.getNumberOfPendingRequests().get());
+
+			assertTrue(pool.containsAllocatedSlot(allocationId).get());
+
+			pool.releaseSlot(requestId, null, null).get();
+
+			assertFalse(pool.containsAllocatedSlot(allocationId).get());
+			assertTrue(pool.containsAvailableSlot(allocationId).get());
+		} finally {
+			RpcUtils.terminateRpcEndpoint(pool, timeout);
+		}
+	}
+
+	/**
+	 * This case make sure when allocateSlot in ProviderAndOwner timeout,
+	 * it will automatically call cancelSlotAllocation as will inject future.whenComplete in ProviderAndOwner.
+	 */
+	@Test
+	public void testProviderAndOwner() throws Exception {
+		final JobID jid = new JobID();
+
+		final TestingSlotPool pool = new TestingSlotPool(
+			rpcService,
+			jid,
+			SystemClock.getInstance(),
+			Time.milliseconds(10L),
+			TestingUtils.infiniteTime(),
+			TestingUtils.infiniteTime());
+
+		final CompletableFuture<SlotRequestId> releaseSlotFuture = new CompletableFuture<>();
+
+		pool.setReleaseSlotConsumer(
+			slotRequestID -> releaseSlotFuture.complete(slotRequestID));
+
+		try {
+			pool.start(JobMasterId.generate(), "foobar");
+			ResourceManagerGateway resourceManagerGateway = new TestingResourceManagerGateway();
+			pool.connectToResourceManager(resourceManagerGateway);
+
+			ScheduledUnit mockScheduledUnit = new ScheduledUnit(SchedulerTestUtils.getDummyTask());
+
+			// test the pending request is clear when timed out
+			CompletableFuture<LogicalSlot> future = pool.getSlotProvider().allocateSlot(
+				mockScheduledUnit,
+				true,
+				Collections.emptyList());
+
+			try {
+				future.get();
+				fail("We expected a AskTimeoutException.");
+			} catch (ExecutionException e) {
+				assertTrue(ExceptionUtils.stripExecutionException(e) instanceof AskTimeoutException);
+			}
+
+			// wait for the cancel call on the SlotPool
+			releaseSlotFuture.get();
+
+			assertEquals(0L, (long) pool.getNumberOfPendingRequests().get());
+		} finally {
+			RpcUtils.terminateRpcEndpoint(pool, timeout);
+		}
+	}
+
+	/**
+	 * Testing SlotPool which exposes internal state via some testing methods.
+	 */
+	private static final class TestingSlotPool extends SlotPool {
+
+		private volatile Consumer<SlotRequestId> releaseSlotConsumer;
+
+		public TestingSlotPool(
+				RpcService rpcService,
+				JobID jobId,
+				Clock clock,
+				Time slotRequestTimeout,
+				Time resourceManagerAllocationTimeout,
+				Time resourceManagerRequestTimeout) {
+			super(
+				rpcService,
+				jobId,
+				clock,
+				slotRequestTimeout,
+				resourceManagerAllocationTimeout,
+				resourceManagerRequestTimeout);
+
+			releaseSlotConsumer = null;
+		}
+
+		public void setReleaseSlotConsumer(Consumer<SlotRequestId> releaseSlotConsumer) {
+			this.releaseSlotConsumer = Preconditions.checkNotNull(releaseSlotConsumer);
+		}
+
+		@Override
+		public CompletableFuture<Acknowledge> releaseSlot(
+			SlotRequestId slotRequestId,
+			@Nullable SlotSharingGroupId slotSharingGroupId,
+			@Nullable Throwable cause) {
+			final Consumer<SlotRequestId> currentReleaseSlotConsumer = releaseSlotConsumer;
+
+			if (currentReleaseSlotConsumer != null) {
+				currentReleaseSlotConsumer.accept(slotRequestId);
+			}
+
+			return super.releaseSlot(slotRequestId, slotSharingGroupId, cause);
+		}
+
+		CompletableFuture<Boolean> containsAllocatedSlot(AllocationID allocationId) {
+			return callAsync(
+				() -> getAllocatedSlots().contains(allocationId),
+				timeout);
+		}
+
+		CompletableFuture<Boolean> containsAvailableSlot(AllocationID allocationId) {
+			return callAsync(
+				() -> getAvailableSlots().contains(allocationId),
+				timeout);
+		}
+
+		CompletableFuture<Integer> getNumberOfPendingRequests() {
+			return callAsync(
+				() -> getPendingRequests().size(),
+				timeout);
+		}
+
+		CompletableFuture<Integer> getNumberOfWaitingForResourceRequests() {
+			return callAsync(
+				() -> getWaitingForResourceManager().size(),
+				timeout);
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolSchedulingTestBase.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolSchedulingTestBase.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolSchedulingTestBase.java
new file mode 100644
index 0000000..31be1ae
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolSchedulingTestBase.java
@@ -0,0 +1,95 @@
+/*
+ * 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.api.common.JobID;
+import org.apache.flink.runtime.jobmaster.JobMasterId;
+import org.apache.flink.runtime.resourcemanager.utils.TestingResourceManagerGateway;
+import org.apache.flink.runtime.rpc.RpcUtils;
+import org.apache.flink.runtime.rpc.TestingRpcService;
+import org.apache.flink.runtime.testingUtils.TestingUtils;
+import org.apache.flink.util.TestLogger;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Test base for {@link SlotPool} related scheduling test cases.
+ */
+public class SlotPoolSchedulingTestBase extends TestLogger {
+
+	private static final JobID jobId = new JobID();
+
+	private static final JobMasterId jobMasterId = new JobMasterId();
+
+	private static final String jobMasterAddress = "foobar";
+
+	private static TestingRpcService testingRpcService;
+
+	protected SlotPool slotPool;
+
+	protected SlotPoolGateway slotPoolGateway;
+
+	protected SlotProvider slotProvider;
+
+	protected TestingResourceManagerGateway testingResourceManagerGateway;
+
+	@BeforeClass
+	public static void setup() {
+		testingRpcService = new TestingRpcService();
+	}
+
+	@AfterClass
+	public static void teardown() {
+		if (testingRpcService != null) {
+			testingRpcService.stopService();
+			testingRpcService = null;
+		}
+	}
+
+	@Before
+	public void setupBefore() throws Exception {
+		testingResourceManagerGateway = new TestingResourceManagerGateway();
+
+		slotPool = new SlotPool(
+			testingRpcService,
+			jobId);
+
+		slotPool.start(jobMasterId, jobMasterAddress);
+
+		slotPoolGateway = slotPool.getSelfGateway(SlotPoolGateway.class);
+
+		slotProvider = slotPool.getSlotProvider();
+
+		slotPool.connectToResourceManager(testingResourceManagerGateway);
+	}
+
+	@After
+	public void teardownAfter() throws InterruptedException, ExecutionException, TimeoutException {
+		if (slotPool != null) {
+			RpcUtils.terminateRpcEndpoint(slotPool, TestingUtils.TIMEOUT());
+			slotPool = null;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolSlotSharingTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolSlotSharingTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolSlotSharingTest.java
new file mode 100644
index 0000000..bb6c2b7
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolSlotSharingTest.java
@@ -0,0 +1,304 @@
+/*
+ * 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.clusterframework.types.ResourceProfile;
+import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.jobgraph.JobVertexID;
+import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.resourcemanager.SlotRequest;
+import org.apache.flink.runtime.taskexecutor.slot.SlotOffer;
+import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+import org.apache.flink.util.ExceptionUtils;
+import org.apache.flink.util.FlinkException;
+
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Test cases for slot sharing with the {@link SlotPool}.
+ */
+public class SlotPoolSlotSharingTest extends SlotPoolSchedulingTestBase {
+
+	@Test
+	public void testSingleQueuedSharedSlotScheduling() throws Exception {
+		final CompletableFuture<AllocationID> allocationIdFuture = new CompletableFuture<>();
+		testingResourceManagerGateway.setRequestSlotConsumer(
+			(SlotRequest slotRequest) -> allocationIdFuture.complete(slotRequest.getAllocationId()));
+
+		LocalTaskManagerLocation taskManagerLocation = new LocalTaskManagerLocation();
+		slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID()).get();
+
+		SlotSharingGroupId slotSharingGroupId = new SlotSharingGroupId();
+		CompletableFuture<LogicalSlot> logicalSlotFuture = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				new JobVertexID(),
+				slotSharingGroupId,
+				null),
+			true,
+			Collections.emptyList());
+
+		assertFalse(logicalSlotFuture.isDone());
+
+		final AllocationID allocationId = allocationIdFuture.get();
+
+		CompletableFuture<Boolean> booleanCompletableFuture = slotPoolGateway.offerSlot(
+			taskManagerLocation,
+			new SimpleAckingTaskManagerGateway(),
+			new SlotOffer(
+				allocationId,
+				0,
+				ResourceProfile.UNKNOWN));
+
+		assertTrue(booleanCompletableFuture.get());
+
+		final LogicalSlot logicalSlot = logicalSlotFuture.get();
+
+		assertEquals(slotSharingGroupId, logicalSlot.getSlotSharingGroupId());
+	}
+
+	/**
+	 * Tests that returned slot futures are failed if the allocation request is failed.
+	 */
+	@Test
+	public void testFailingQueuedSharedSlotScheduling() throws ExecutionException, InterruptedException {
+		final CompletableFuture<AllocationID> allocationIdFuture = new CompletableFuture<>();
+		testingResourceManagerGateway.setRequestSlotConsumer(
+			(SlotRequest slotRequest) -> allocationIdFuture.complete(slotRequest.getAllocationId()));
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				new JobVertexID(),
+				new SlotSharingGroupId(),
+				null),
+			true,
+			Collections.emptyList());
+
+		final AllocationID allocationId = allocationIdFuture.get();
+
+		// this should fail the returned logical slot future
+		slotPoolGateway.failAllocation(allocationId, new FlinkException("Testing Exception"));
+
+		try {
+			logicalSlotFuture.get();
+			fail("The slot future should have failed.");
+		} catch (ExecutionException ee) {
+			assertTrue(ExceptionUtils.findThrowable(ee, FlinkException.class).isPresent());
+		}
+	}
+
+	/**
+	 * Tests queued slot scheduling with a single slot sharing group
+	 */
+	@Test
+	public void testQueuedSharedSlotScheduling() throws InterruptedException, ExecutionException {
+		final BlockingQueue<AllocationID> allocationIds = new ArrayBlockingQueue<>(2);
+		testingResourceManagerGateway.setRequestSlotConsumer(
+			(SlotRequest slotRequest) -> allocationIds.offer(slotRequest.getAllocationId()));
+
+		final TaskManagerLocation taskManagerLocation = new LocalTaskManagerLocation();
+
+		slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID()).get();
+
+		final SlotSharingGroupId slotSharingGroupId = new SlotSharingGroupId();
+		final JobVertexID jobVertexId1 = new JobVertexID();
+		final JobVertexID jobVertexId2 = new JobVertexID();
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture1 = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				jobVertexId1,
+				slotSharingGroupId,
+				null),
+			true,
+			Collections.emptyList());
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture2 = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				jobVertexId2,
+				slotSharingGroupId,
+				null),
+			true,
+			Collections.emptyList());
+
+		assertFalse(logicalSlotFuture1.isDone());
+		assertFalse(logicalSlotFuture2.isDone());
+
+		final AllocationID allocationId1 = allocationIds.take();
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture3 = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				jobVertexId1,
+				slotSharingGroupId,
+				null),
+			true,
+			Collections.emptyList());
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture4 = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				jobVertexId2,
+				slotSharingGroupId,
+				null),
+			true,
+			Collections.emptyList());
+
+		assertFalse(logicalSlotFuture3.isDone());
+		assertFalse(logicalSlotFuture4.isDone());
+
+		final AllocationID allocationId2 = allocationIds.take();
+
+		// this should fulfill the first two slot futures
+		CompletableFuture<Boolean> offerFuture = slotPoolGateway.offerSlot(
+			taskManagerLocation,
+			new SimpleAckingTaskManagerGateway(),
+			new SlotOffer(
+				allocationId1,
+				0,
+				ResourceProfile.UNKNOWN));
+
+		assertTrue(offerFuture.get());
+
+		LogicalSlot logicalSlot1 = logicalSlotFuture1.get();
+		LogicalSlot logicalSlot2 = logicalSlotFuture2.get();
+
+		assertEquals(logicalSlot1.getTaskManagerLocation(), logicalSlot2.getTaskManagerLocation());
+		assertEquals(allocationId1, logicalSlot1.getAllocationId());
+		assertEquals(allocationId1, logicalSlot2.getAllocationId());
+
+		assertFalse(logicalSlotFuture3.isDone());
+		assertFalse(logicalSlotFuture4.isDone());
+
+		// release the shared slot by releasing the individual tasks
+		logicalSlot1.releaseSlot(null);
+		logicalSlot2.releaseSlot(null);
+
+		LogicalSlot logicalSlot3 = logicalSlotFuture3.get();
+		LogicalSlot logicalSlot4 = logicalSlotFuture4.get();
+
+		assertEquals(logicalSlot3.getTaskManagerLocation(), logicalSlot4.getTaskManagerLocation());
+		assertEquals(allocationId1, logicalSlot3.getAllocationId());
+		assertEquals(allocationId1, logicalSlot4.getAllocationId());
+	}
+
+	/**
+	 * Tests queued slot scheduling with multiple slot sharing groups.
+	 */
+	@Test
+	public void testQueuedMultipleSlotSharingGroups() throws ExecutionException, InterruptedException {
+		final BlockingQueue<AllocationID> allocationIds = new ArrayBlockingQueue<>(4);
+
+		testingResourceManagerGateway.setRequestSlotConsumer(
+			(SlotRequest slotRequest) -> allocationIds.offer(slotRequest.getAllocationId()));
+
+		final TaskManagerLocation taskManagerLocation = new LocalTaskManagerLocation();
+		final SlotSharingGroupId slotSharingGroupId1 = new SlotSharingGroupId();
+		final SlotSharingGroupId slotSharingGroupId2 = new SlotSharingGroupId();
+		final JobVertexID jobVertexId1 = new JobVertexID();
+		final JobVertexID jobVertexId2 = new JobVertexID();
+		final JobVertexID jobVertexId3 = new JobVertexID();
+		final JobVertexID jobVertexId4 = new JobVertexID();
+
+		slotPoolGateway.registerTaskManager(taskManagerLocation.getResourceID()).get();
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture1 = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				jobVertexId1,
+				slotSharingGroupId1,
+				null),
+			true,
+			Collections.emptyList());
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture2 = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				jobVertexId2,
+				slotSharingGroupId1,
+				null),
+			true,
+			Collections.emptyList());
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture3 = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				jobVertexId3,
+				slotSharingGroupId2,
+				null),
+			true,
+			Collections.emptyList());
+
+		CompletableFuture<LogicalSlot> logicalSlotFuture4 = slotProvider.allocateSlot(
+			new ScheduledUnit(
+				jobVertexId4,
+				slotSharingGroupId2,
+				null),
+			true,
+			Collections.emptyList());
+
+		assertFalse(logicalSlotFuture1.isDone());
+		assertFalse(logicalSlotFuture2.isDone());
+		assertFalse(logicalSlotFuture3.isDone());
+		assertFalse(logicalSlotFuture4.isDone());
+
+		// we expect two slot requests
+		final AllocationID allocationId1 = allocationIds.take();
+		final AllocationID allocationId2 = allocationIds.take();
+
+		CompletableFuture<Boolean> offerFuture1 = slotPoolGateway.offerSlot(
+			taskManagerLocation,
+			new SimpleAckingTaskManagerGateway(),
+			new SlotOffer(
+				allocationId1,
+				0,
+				ResourceProfile.UNKNOWN));
+
+		CompletableFuture<Boolean> offerFuture2 = slotPoolGateway.offerSlot(
+			taskManagerLocation,
+			new SimpleAckingTaskManagerGateway(),
+			new SlotOffer(
+				allocationId2,
+				0,
+				ResourceProfile.UNKNOWN));
+
+		assertTrue(offerFuture1.get());
+		assertTrue(offerFuture2.get());
+
+		LogicalSlot logicalSlot1 = logicalSlotFuture1.get();
+		LogicalSlot logicalSlot2 = logicalSlotFuture2.get();
+		LogicalSlot logicalSlot3 = logicalSlotFuture3.get();
+		LogicalSlot logicalSlot4 = logicalSlotFuture4.get();
+
+		assertEquals(logicalSlot1.getTaskManagerLocation(), logicalSlot2.getTaskManagerLocation());
+		assertEquals(logicalSlot3.getTaskManagerLocation(), logicalSlot4.getTaskManagerLocation());
+
+		assertEquals(allocationId1, logicalSlot1.getAllocationId());
+		assertEquals(allocationId2, logicalSlot3.getAllocationId());
+	}
+
+}


[05/11] flink git commit: [FLINK-7956] [flip6] Add support for queued scheduling with slot sharing to SlotPool

Posted by tr...@apache.org.
http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/ScheduleWithCoLocationHintTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/ScheduleWithCoLocationHintTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/ScheduleWithCoLocationHintTest.java
index 08db591..19f4a2f 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/ScheduleWithCoLocationHintTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/ScheduleWithCoLocationHintTest.java
@@ -19,19 +19,17 @@
 package org.apache.flink.runtime.jobmanager.scheduler;
 
 import org.apache.flink.runtime.clusterframework.types.ResourceID;
-import org.apache.flink.runtime.instance.Instance;
-import org.apache.flink.runtime.instance.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-import org.apache.flink.runtime.testingUtils.TestingUtils;
-import org.apache.flink.util.TestLogger;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 import java.util.Collections;
 import java.util.concurrent.ExecutionException;
 
-import static org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestUtils.getRandomInstance;
 import static org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestUtils.getTestVertex;
 import static org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestUtils.getTestVertexWithLocation;
 import static org.junit.Assert.assertEquals;
@@ -39,606 +37,505 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-public class ScheduleWithCoLocationHintTest extends TestLogger {
+@RunWith(Parameterized.class)
+public class ScheduleWithCoLocationHintTest extends SchedulerTestBase {
 
-	@Test
-	public void scheduleAllSharedAndCoLocated() {
-		try {
-			JobVertexID jid1 = new JobVertexID();
-			JobVertexID jid2 = new JobVertexID();
-
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-
-			assertEquals(6, scheduler.getNumberOfAvailableSlots());
-
-			SlotSharingGroup sharingGroup = new SlotSharingGroup();
-
-			CoLocationGroup ccg = new CoLocationGroup();
-			CoLocationConstraint c1 = new CoLocationConstraint(ccg);
-			CoLocationConstraint c2 = new CoLocationConstraint(ccg);
-			CoLocationConstraint c3 = new CoLocationConstraint(ccg);
-			CoLocationConstraint c4 = new CoLocationConstraint(ccg);
-			CoLocationConstraint c5 = new CoLocationConstraint(ccg);
-			CoLocationConstraint c6 = new CoLocationConstraint(ccg);
-
-			// schedule 4 tasks from the first vertex group
-			LogicalSlot s1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 6), sharingGroup, c1), false, Collections.emptyList()).get();
-			LogicalSlot s2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 6), sharingGroup, c2), false, Collections.emptyList()).get();
-			LogicalSlot s3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 6), sharingGroup, c3), false, Collections.emptyList()).get();
-			LogicalSlot s4 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 6), sharingGroup, c4), false, Collections.emptyList()).get();
-			LogicalSlot s5 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 6), sharingGroup, c1), false, Collections.emptyList()).get();
-			LogicalSlot s6 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 6), sharingGroup, c2), false, Collections.emptyList()).get();
-			LogicalSlot s7 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 6), sharingGroup, c3), false, Collections.emptyList()).get();
-			LogicalSlot s8 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 4, 6), sharingGroup, c5), false, Collections.emptyList()).get();
-			LogicalSlot s9 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 5, 6), sharingGroup, c6), false, Collections.emptyList()).get();
-			LogicalSlot s10 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 3, 6), sharingGroup, c4), false, Collections.emptyList()).get();
-			LogicalSlot s11 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 4, 6), sharingGroup, c5), false, Collections.emptyList()).get();
-			LogicalSlot s12 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 5, 6), sharingGroup, c6), false, Collections.emptyList()).get();
-
-			assertNotNull(s1);
-			assertNotNull(s2);
-			assertNotNull(s3);
-			assertNotNull(s4);
-			assertNotNull(s5);
-			assertNotNull(s6);
-			assertNotNull(s7);
-			assertNotNull(s8);
-			assertNotNull(s9);
-			assertNotNull(s10);
-			assertNotNull(s11);
-			assertNotNull(s12);
-
-			// check that each slot got exactly two tasks
-			assertEquals(s1.getTaskManagerLocation(), s5.getTaskManagerLocation());
-			assertEquals(s2.getTaskManagerLocation(), s6.getTaskManagerLocation());
-			assertEquals(s3.getTaskManagerLocation(), s7.getTaskManagerLocation());
-			assertEquals(s4.getTaskManagerLocation(), s10.getTaskManagerLocation());
-			assertEquals(s8.getTaskManagerLocation(), s11.getTaskManagerLocation());
-			assertEquals(s9.getTaskManagerLocation(), s12.getTaskManagerLocation());
-
-			assertEquals(c1.getLocation(), s1.getTaskManagerLocation());
-			assertEquals(c2.getLocation(), s2.getTaskManagerLocation());
-			assertEquals(c3.getLocation(), s3.getTaskManagerLocation());
-			assertEquals(c4.getLocation(), s4.getTaskManagerLocation());
-			assertEquals(c5.getLocation(), s8.getTaskManagerLocation());
-			assertEquals(c6.getLocation(), s9.getTaskManagerLocation());
-
-			// check the scheduler's bookkeeping
-			assertEquals(0, scheduler.getNumberOfAvailableSlots());
-
-			// the first assignments are unconstrained, co.-scheduling is constrained
-			assertEquals(6, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(6, scheduler.getNumberOfUnconstrainedAssignments());
-
-			// release some slots, be sure that new available ones come up
-			s1.releaseSlot();
-			s2.releaseSlot();
-			s3.releaseSlot();
-			s4.releaseSlot();
-			s7.releaseSlot();
-			s10.releaseSlot();
-			s11.releaseSlot();
-			s12.releaseSlot();
-			assertTrue(scheduler.getNumberOfAvailableSlots() >= 1);
-
-			LogicalSlot single = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(new JobVertexID(), 0, 1)), false, Collections.emptyList()).get();
-			assertNotNull(single);
-
-			s1.releaseSlot();
-			s2.releaseSlot();
-			s3.releaseSlot();
-			s5.releaseSlot();
-			s6.releaseSlot();
-			s7.releaseSlot();
-			s8.releaseSlot();
-			s9.releaseSlot();
-			s11.releaseSlot();
-			s12.releaseSlot();
-
-			assertEquals(5, scheduler.getNumberOfAvailableSlots());
-
-			assertEquals(6, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(7, scheduler.getNumberOfUnconstrainedAssignments());
-		}
-		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
-		}
+	public ScheduleWithCoLocationHintTest(SchedulerType schedulerType) {
+		super(schedulerType);
 	}
 
 	@Test
-	public void scheduleWithIntermediateRelease() {
-		try {
-			JobVertexID jid1 = new JobVertexID();
-			JobVertexID jid2 = new JobVertexID();
-			JobVertexID jid3 = new JobVertexID();
-			JobVertexID jid4 = new JobVertexID();
-
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
+	public void scheduleAllSharedAndCoLocated() throws Exception {
+		JobVertexID jid1 = new JobVertexID();
+		JobVertexID jid2 = new JobVertexID();
+
+		testingSlotProvider.addTaskManager(2);
+		testingSlotProvider.addTaskManager(2);
+		testingSlotProvider.addTaskManager(2);
+
+		assertEquals(6, testingSlotProvider.getNumberOfAvailableSlots());
+
+		SlotSharingGroup sharingGroup = new SlotSharingGroup();
+
+		CoLocationGroup ccg = new CoLocationGroup();
+		CoLocationConstraint c1 = new CoLocationConstraint(ccg);
+		CoLocationConstraint c2 = new CoLocationConstraint(ccg);
+		CoLocationConstraint c3 = new CoLocationConstraint(ccg);
+		CoLocationConstraint c4 = new CoLocationConstraint(ccg);
+		CoLocationConstraint c5 = new CoLocationConstraint(ccg);
+		CoLocationConstraint c6 = new CoLocationConstraint(ccg);
+
+		// schedule 4 tasks from the first vertex group
+		LogicalSlot s1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 6, sharingGroup), sharingGroup.getSlotSharingGroupId(), c1), false, Collections.emptyList()).get();
+		LogicalSlot s2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 6, sharingGroup), sharingGroup.getSlotSharingGroupId(), c2), false, Collections.emptyList()).get();
+		LogicalSlot s3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 6, sharingGroup), sharingGroup.getSlotSharingGroupId(), c3), false, Collections.emptyList()).get();
+		LogicalSlot s4 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 6, sharingGroup), sharingGroup.getSlotSharingGroupId(), c4), false, Collections.emptyList()).get();
+		LogicalSlot s5 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 6, sharingGroup), sharingGroup.getSlotSharingGroupId(), c1), false, Collections.emptyList()).get();
+		LogicalSlot s6 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 6, sharingGroup), sharingGroup.getSlotSharingGroupId(), c2), false, Collections.emptyList()).get();
+		LogicalSlot s7 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 6, sharingGroup), sharingGroup.getSlotSharingGroupId(), c3), false, Collections.emptyList()).get();
+		LogicalSlot s8 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 4, 6, sharingGroup), sharingGroup.getSlotSharingGroupId(), c5), false, Collections.emptyList()).get();
+		LogicalSlot s9 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 5, 6, sharingGroup), sharingGroup.getSlotSharingGroupId(), c6), false, Collections.emptyList()).get();
+		LogicalSlot s10 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 3, 6, sharingGroup), sharingGroup.getSlotSharingGroupId(), c4), false, Collections.emptyList()).get();
+		LogicalSlot s11 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 4, 6, sharingGroup), sharingGroup.getSlotSharingGroupId(), c5), false, Collections.emptyList()).get();
+		LogicalSlot s12 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 5, 6, sharingGroup), sharingGroup.getSlotSharingGroupId(), c6), false, Collections.emptyList()).get();
+
+		assertNotNull(s1);
+		assertNotNull(s2);
+		assertNotNull(s3);
+		assertNotNull(s4);
+		assertNotNull(s5);
+		assertNotNull(s6);
+		assertNotNull(s7);
+		assertNotNull(s8);
+		assertNotNull(s9);
+		assertNotNull(s10);
+		assertNotNull(s11);
+		assertNotNull(s12);
+
+		// check that each slot got exactly two tasks
+		assertEquals(s1.getTaskManagerLocation(), s5.getTaskManagerLocation());
+		assertEquals(s2.getTaskManagerLocation(), s6.getTaskManagerLocation());
+		assertEquals(s3.getTaskManagerLocation(), s7.getTaskManagerLocation());
+		assertEquals(s4.getTaskManagerLocation(), s10.getTaskManagerLocation());
+		assertEquals(s8.getTaskManagerLocation(), s11.getTaskManagerLocation());
+		assertEquals(s9.getTaskManagerLocation(), s12.getTaskManagerLocation());
+
+		assertEquals(c1.getLocation(), s1.getTaskManagerLocation());
+		assertEquals(c2.getLocation(), s2.getTaskManagerLocation());
+		assertEquals(c3.getLocation(), s3.getTaskManagerLocation());
+		assertEquals(c4.getLocation(), s4.getTaskManagerLocation());
+		assertEquals(c5.getLocation(), s8.getTaskManagerLocation());
+		assertEquals(c6.getLocation(), s9.getTaskManagerLocation());
+
+		// check the scheduler's bookkeeping
+		assertEquals(0, testingSlotProvider.getNumberOfAvailableSlots());
+
+		// the first assignments are unconstrained, co.-scheduling is constrained
+		assertEquals(6, testingSlotProvider.getNumberOfLocalizedAssignments());
+		assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+		assertEquals(6, testingSlotProvider.getNumberOfUnconstrainedAssignments());
+
+		// release some slots, be sure that new available ones come up
+		s1.releaseSlot();
+		s2.releaseSlot();
+		s3.releaseSlot();
+		s4.releaseSlot();
+		s7.releaseSlot();
+		s10.releaseSlot();
+		s11.releaseSlot();
+		s12.releaseSlot();
+		assertTrue(testingSlotProvider.getNumberOfAvailableSlots() >= 1);
+
+		LogicalSlot single = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(new JobVertexID(), 0, 1, null)), false, Collections.emptyList()).get();
+		assertNotNull(single);
+
+		s1.releaseSlot();
+		s2.releaseSlot();
+		s3.releaseSlot();
+		s5.releaseSlot();
+		s6.releaseSlot();
+		s7.releaseSlot();
+		s8.releaseSlot();
+		s9.releaseSlot();
+		s11.releaseSlot();
+		s12.releaseSlot();
+
+		assertEquals(5, testingSlotProvider.getNumberOfAvailableSlots());
+
+		assertEquals(6, testingSlotProvider.getNumberOfLocalizedAssignments());
+		assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+		assertEquals(7, testingSlotProvider.getNumberOfUnconstrainedAssignments());
+	}
 
-			Instance i1 = getRandomInstance(1);
-			Instance i2 = getRandomInstance(1);
+	@Test
+	public void scheduleWithIntermediateRelease() throws Exception {
+		JobVertexID jid1 = new JobVertexID();
+		JobVertexID jid2 = new JobVertexID();
+		JobVertexID jid3 = new JobVertexID();
+		JobVertexID jid4 = new JobVertexID();
 
-			scheduler.newInstanceAvailable(i1);
-			scheduler.newInstanceAvailable(i2);
+		testingSlotProvider.addTaskManager(1);
+		testingSlotProvider.addTaskManager(1);
 
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
 
-			SlotSharingGroup sharingGroup = new SlotSharingGroup();
-			CoLocationConstraint c1 = new CoLocationConstraint(new CoLocationGroup());
+		SlotSharingGroup sharingGroup = new SlotSharingGroup();
+		CoLocationConstraint c1 = new CoLocationConstraint(new CoLocationGroup());
 
-			LogicalSlot s1 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(jid1, 0, 1), sharingGroup, c1), false, Collections.emptyList()).get();
-			LogicalSlot s2 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(jid2, 0, 1), sharingGroup, c1), false, Collections.emptyList()).get();
+		LogicalSlot s1 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(jid1, 0, 1, sharingGroup), sharingGroup.getSlotSharingGroupId(), c1), false, Collections.emptyList()).get();
+		LogicalSlot s2 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(jid2, 0, 1, sharingGroup), sharingGroup.getSlotSharingGroupId(), c1), false, Collections.emptyList()).get();
 
-			LogicalSlot sSolo = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 0, 1)), false, Collections.emptyList()).get();
+		LogicalSlot sSolo = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 0, 1, null)), false, Collections.emptyList()).get();
 
-			ResourceID taskManager = s1.getTaskManagerLocation().getResourceID();
+		ResourceID taskManager = s1.getTaskManagerLocation().getResourceID();
 
-			s1.releaseSlot();
-			s2.releaseSlot();
-			sSolo.releaseSlot();
+		s1.releaseSlot();
+		s2.releaseSlot();
+		sSolo.releaseSlot();
 
-			LogicalSlot sNew = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(jid3, 0, 1), sharingGroup, c1), false, Collections.emptyList()).get();
-			assertEquals(taskManager, sNew.getTaskManagerLocation().getResourceID());
+		LogicalSlot sNew = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(jid3, 0, 1, sharingGroup), sharingGroup.getSlotSharingGroupId(), c1), false, Collections.emptyList()).get();
+		assertEquals(taskManager, sNew.getTaskManagerLocation().getResourceID());
 
-			assertEquals(2, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(2, scheduler.getNumberOfUnconstrainedAssignments());
-		}
-		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
-		}
+		assertEquals(2, testingSlotProvider.getNumberOfLocalizedAssignments());
+		assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+		assertEquals(2, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 	}
 
 	@Test
-	public void scheduleWithReleaseNoResource() {
-		try {
-			JobVertexID jid1 = new JobVertexID();
-			JobVertexID jid2 = new JobVertexID();
-			JobVertexID jid3 = new JobVertexID();
-
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
+	public void scheduleWithReleaseNoResource() throws Exception {
+		JobVertexID jid1 = new JobVertexID();
+		JobVertexID jid2 = new JobVertexID();
+		JobVertexID jid3 = new JobVertexID();
 
-			Instance i1 = getRandomInstance(1);
-			Instance i2 = getRandomInstance(1);
+		testingSlotProvider.addTaskManager(1);
+		testingSlotProvider.addTaskManager(1);
 
-			scheduler.newInstanceAvailable(i1);
-			scheduler.newInstanceAvailable(i2);
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
 
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
+		SlotSharingGroup sharingGroup = new SlotSharingGroup();
+		CoLocationConstraint c1 = new CoLocationConstraint(new CoLocationGroup());
 
-			SlotSharingGroup sharingGroup = new SlotSharingGroup();
-			CoLocationConstraint c1 = new CoLocationConstraint(new CoLocationGroup());
+		LogicalSlot s1 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(jid1, 0, 1, sharingGroup), sharingGroup.getSlotSharingGroupId(), c1), false, Collections.emptyList()).get();
+		s1.releaseSlot();
 
-			LogicalSlot s1 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(jid1, 0, 1), sharingGroup, c1), false, Collections.emptyList()).get();
-			s1.releaseSlot();
+		testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 1, null)), false, Collections.emptyList()).get();
+		testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 2, null)), false, Collections.emptyList()).get();
 
-			scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 1)), false, Collections.emptyList()).get();
-			scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 2)), false, Collections.emptyList()).get();
-
-			try {
-				scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 0, 1), sharingGroup, c1), false, Collections.emptyList()).get();
-				fail("Scheduled even though no resource was available.");
-			} catch (ExecutionException e) {
-				assertTrue(e.getCause() instanceof NoResourceAvailableException);
-			}
-
-			assertEquals(0, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(3, scheduler.getNumberOfUnconstrainedAssignments());
-		}
-		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
+		try {
+			testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 0, 1, sharingGroup), sharingGroup.getSlotSharingGroupId(), c1), false, Collections.emptyList()).get();
+			fail("Scheduled even though no resource was available.");
+		} catch (ExecutionException e) {
+			assertTrue(e.getCause() instanceof NoResourceAvailableException);
 		}
+
+		assertEquals(0, testingSlotProvider.getNumberOfLocalizedAssignments());
+		assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+		assertEquals(3, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 	}
 
 	@Test
-	public void scheduleMixedCoLocationSlotSharing() {
-		try {
-			JobVertexID jid1 = new JobVertexID();
-			JobVertexID jid2 = new JobVertexID();
-			JobVertexID jid3 = new JobVertexID();
-			JobVertexID jid4 = new JobVertexID();
-			
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-			scheduler.newInstanceAvailable(getRandomInstance(1));
-			scheduler.newInstanceAvailable(getRandomInstance(1));
-			scheduler.newInstanceAvailable(getRandomInstance(1));
-			scheduler.newInstanceAvailable(getRandomInstance(1));
-			
-			assertEquals(4, scheduler.getNumberOfAvailableSlots());
-			
-			CoLocationGroup grp = new CoLocationGroup();
-			CoLocationConstraint clc1 = new CoLocationConstraint(grp);
-			CoLocationConstraint clc2 = new CoLocationConstraint(grp);
-			CoLocationConstraint clc3 = new CoLocationConstraint(grp);
-			CoLocationConstraint clc4 = new CoLocationConstraint(grp);
-			
-			SlotSharingGroup shareGroup = new SlotSharingGroup();
-
-			// first wave
-			scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 4), shareGroup), false, Collections.emptyList());
-			scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 4), shareGroup), false, Collections.emptyList());
-			scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 4), shareGroup), false, Collections.emptyList());
-			scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 4), shareGroup), false, Collections.emptyList());
-			
-			// second wave
-			LogicalSlot s21 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(jid2, 0, 4), shareGroup, clc1), false, Collections.emptyList()).get();
-			LogicalSlot s22 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(jid2, 2, 4), shareGroup, clc2), false, Collections.emptyList()).get();
-			LogicalSlot s23 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(jid2, 1, 4), shareGroup, clc3), false, Collections.emptyList()).get();
-			LogicalSlot s24 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(jid2, 3, 4), shareGroup, clc4), false, Collections.emptyList()).get();
-			
-			// third wave
-			LogicalSlot s31 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(jid3, 1, 4), shareGroup, clc2), false, Collections.emptyList()).get();
-			LogicalSlot s32 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(jid3, 2, 4), shareGroup, clc3), false, Collections.emptyList()).get();
-			LogicalSlot s33 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(jid3, 3, 4), shareGroup, clc4), false, Collections.emptyList()).get();
-			LogicalSlot s34 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertex(jid3, 0, 4), shareGroup, clc1), false, Collections.emptyList()).get();
-			
-			scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 0, 4), shareGroup), false, Collections.emptyList());
-			scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 1, 4), shareGroup), false, Collections.emptyList());
-			scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 2, 4), shareGroup), false, Collections.emptyList());
-			scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 3, 4), shareGroup), false, Collections.emptyList());
-			
-			assertEquals(s21.getTaskManagerLocation(), s34.getTaskManagerLocation());
-			assertEquals(s22.getTaskManagerLocation(), s31.getTaskManagerLocation());
-			assertEquals(s23.getTaskManagerLocation(), s32.getTaskManagerLocation());
-			assertEquals(s24.getTaskManagerLocation(), s33.getTaskManagerLocation());
-			
-			assertEquals(4, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(12, scheduler.getNumberOfUnconstrainedAssignments());
-		}
-		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
-		}
+	public void scheduleMixedCoLocationSlotSharing() throws Exception {
+		JobVertexID jid1 = new JobVertexID();
+		JobVertexID jid2 = new JobVertexID();
+		JobVertexID jid3 = new JobVertexID();
+		JobVertexID jid4 = new JobVertexID();
+
+		testingSlotProvider.addTaskManager(1);
+		testingSlotProvider.addTaskManager(1);
+		testingSlotProvider.addTaskManager(1);
+		testingSlotProvider.addTaskManager(1);
+
+		assertEquals(4, testingSlotProvider.getNumberOfAvailableSlots());
+
+		CoLocationGroup grp = new CoLocationGroup();
+		CoLocationConstraint clc1 = new CoLocationConstraint(grp);
+		CoLocationConstraint clc2 = new CoLocationConstraint(grp);
+		CoLocationConstraint clc3 = new CoLocationConstraint(grp);
+		CoLocationConstraint clc4 = new CoLocationConstraint(grp);
+
+		SlotSharingGroup shareGroup = new SlotSharingGroup();
+
+		// first wave
+		testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 4, shareGroup), shareGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 4, shareGroup), shareGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 4, shareGroup), shareGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 4, shareGroup), shareGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+
+		// second wave
+		LogicalSlot s21 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(jid2, 0, 4, shareGroup), shareGroup.getSlotSharingGroupId(), clc1), false, Collections.emptyList()).get();
+		LogicalSlot s22 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(jid2, 2, 4, shareGroup), shareGroup.getSlotSharingGroupId(), clc2), false, Collections.emptyList()).get();
+		LogicalSlot s23 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(jid2, 1, 4, shareGroup), shareGroup.getSlotSharingGroupId(), clc3), false, Collections.emptyList()).get();
+		LogicalSlot s24 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(jid2, 3, 4, shareGroup), shareGroup.getSlotSharingGroupId(), clc4), false, Collections.emptyList()).get();
+
+		// third wave
+		LogicalSlot s31 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(jid3, 1, 4, shareGroup), shareGroup.getSlotSharingGroupId(), clc2), false, Collections.emptyList()).get();
+		LogicalSlot s32 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(jid3, 2, 4, shareGroup), shareGroup.getSlotSharingGroupId(), clc3), false, Collections.emptyList()).get();
+		LogicalSlot s33 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(jid3, 3, 4, shareGroup), shareGroup.getSlotSharingGroupId(), clc4), false, Collections.emptyList()).get();
+		LogicalSlot s34 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertex(jid3, 0, 4, shareGroup), shareGroup.getSlotSharingGroupId(), clc1), false, Collections.emptyList()).get();
+
+		testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 0, 4, shareGroup), shareGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 1, 4, shareGroup), shareGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 2, 4, shareGroup), shareGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 3, 4, shareGroup), shareGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+
+		assertEquals(s21.getTaskManagerLocation(), s34.getTaskManagerLocation());
+		assertEquals(s22.getTaskManagerLocation(), s31.getTaskManagerLocation());
+		assertEquals(s23.getTaskManagerLocation(), s32.getTaskManagerLocation());
+		assertEquals(s24.getTaskManagerLocation(), s33.getTaskManagerLocation());
+
+		assertEquals(4, testingSlotProvider.getNumberOfLocalizedAssignments());
+		assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+		assertEquals(12, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 	}
 
 	
 	@Test
-	public void testGetsNonLocalFromSharingGroupFirst() {
-		try {
-			JobVertexID jid1 = new JobVertexID();
-			JobVertexID jid2 = new JobVertexID();
-			JobVertexID jid3 = new JobVertexID();
-			
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-
-			Instance i1 = getRandomInstance(1);
-			Instance i2 = getRandomInstance(1);
-
-			TaskManagerLocation loc1 = i1.getTaskManagerLocation();
-			TaskManagerLocation loc2 = i2.getTaskManagerLocation();
-
-			scheduler.newInstanceAvailable(i2);
-			scheduler.newInstanceAvailable(i1);
-			
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
-			
-			SlotSharingGroup sharingGroup = new SlotSharingGroup();
-			
-			CoLocationGroup ccg = new CoLocationGroup();
-			CoLocationConstraint cc1 = new CoLocationConstraint(ccg);
-			CoLocationConstraint cc2 = new CoLocationConstraint(ccg);
-
-			// schedule something into the shared group so that both instances are in the sharing group
-			LogicalSlot s1 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, loc1), sharingGroup), false, Collections.singleton(loc1)).get();
-			LogicalSlot s2 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, loc2), sharingGroup), false, Collections.singleton(loc2)).get();
-			
-			// schedule one locally to instance 1
-			LogicalSlot s3 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, loc1), sharingGroup, cc1), false, Collections.singleton(loc1)).get();
-
-			// schedule with co location constraint (yet unassigned) and a preference for
-			// instance 1, but it can only get instance 2
-			LogicalSlot s4 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 2, loc1), sharingGroup, cc2), false, Collections.singleton(loc1)).get();
-			
-			// schedule something into the assigned co-location constraints and check that they override the
-			// other preferences
-			LogicalSlot s5 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid3, 0, 2, loc2), sharingGroup, cc1), false, Collections.singleton(loc2)).get();
-			LogicalSlot s6 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid3, 1, 2, loc1), sharingGroup, cc2), false, Collections.singleton(loc1)).get();
-			
-			// check that each slot got three
-			assertEquals(s1.getTaskManagerLocation(), s3.getTaskManagerLocation());
-			assertEquals(s2.getTaskManagerLocation(), s4.getTaskManagerLocation());
-			assertEquals(s1.getTaskManagerLocation(), s5.getTaskManagerLocation());
-			assertEquals(s2.getTaskManagerLocation(), s6.getTaskManagerLocation());
-			
-			// check the scheduler's bookkeeping
-			assertEquals(0, scheduler.getNumberOfAvailableSlots());
-			
-			assertEquals(5, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(1, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfUnconstrainedAssignments());
-			
-			// release some slots, be sure that new available ones come up
-			s1.releaseSlot();
-			s2.releaseSlot();
-			s3.releaseSlot();
-			s4.releaseSlot();
-			s5.releaseSlot();
-			s6.releaseSlot();
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
-		}
-		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
-		}
+	public void testGetsNonLocalFromSharingGroupFirst() throws Exception {
+		JobVertexID jid1 = new JobVertexID();
+		JobVertexID jid2 = new JobVertexID();
+		JobVertexID jid3 = new JobVertexID();
+
+		TaskManagerLocation loc1 = testingSlotProvider.addTaskManager(1);
+		TaskManagerLocation loc2 = testingSlotProvider.addTaskManager(1);
+
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
+
+		SlotSharingGroup sharingGroup = new SlotSharingGroup();
+
+		CoLocationGroup ccg = new CoLocationGroup();
+		CoLocationConstraint cc1 = new CoLocationConstraint(ccg);
+		CoLocationConstraint cc2 = new CoLocationConstraint(ccg);
+
+		// schedule something into the shared group so that both instances are in the sharing group
+		LogicalSlot s1 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
+		LogicalSlot s2 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, sharingGroup, loc2), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc2)).get();
+
+		// schedule one locally to instance 1
+		LogicalSlot s3 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId(), cc1), false, Collections.singleton(loc1)).get();
+
+		// schedule with co location constraint (yet unassigned) and a preference for
+		// instance 1, but it can only get instance 2
+		LogicalSlot s4 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId(), cc2), false, Collections.singleton(loc1)).get();
+
+		// schedule something into the assigned co-location constraints and check that they override the
+		// other preferences
+		LogicalSlot s5 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid3, 0, 2, sharingGroup, loc2), sharingGroup.getSlotSharingGroupId(), cc1), false, Collections.singleton(loc2)).get();
+		LogicalSlot s6 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid3, 1, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId(), cc2), false, Collections.singleton(loc1)).get();
+
+		// check that each slot got three
+		assertEquals(s1.getTaskManagerLocation(), s3.getTaskManagerLocation());
+		assertEquals(s2.getTaskManagerLocation(), s4.getTaskManagerLocation());
+		assertEquals(s1.getTaskManagerLocation(), s5.getTaskManagerLocation());
+		assertEquals(s2.getTaskManagerLocation(), s6.getTaskManagerLocation());
+
+		// check the scheduler's bookkeeping
+		assertEquals(0, testingSlotProvider.getNumberOfAvailableSlots());
+
+		assertEquals(5, testingSlotProvider.getNumberOfLocalizedAssignments());
+		assertTrue(1 == testingSlotProvider.getNumberOfNonLocalizedAssignments() || 1 == testingSlotProvider.getNumberOfHostLocalizedAssignments());
+		assertEquals(0, testingSlotProvider.getNumberOfUnconstrainedAssignments());
+
+		// release some slots, be sure that new available ones come up
+		s1.releaseSlot();
+		s2.releaseSlot();
+		s3.releaseSlot();
+		s4.releaseSlot();
+		s5.releaseSlot();
+		s6.releaseSlot();
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
 	}
 
 	@Test
-	public void testSlotReleasedInBetween() {
-		try {
-			JobVertexID jid1 = new JobVertexID();
-			JobVertexID jid2 = new JobVertexID();
-
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-
-			Instance i1 = getRandomInstance(1);
-			Instance i2 = getRandomInstance(1);
+	public void testSlotReleasedInBetween() throws Exception {
+		JobVertexID jid1 = new JobVertexID();
+		JobVertexID jid2 = new JobVertexID();
 
-			TaskManagerLocation loc1 = i1.getTaskManagerLocation();
-			TaskManagerLocation loc2 = i2.getTaskManagerLocation();
+		TaskManagerLocation loc1 = testingSlotProvider.addTaskManager(1);
+		TaskManagerLocation loc2 = testingSlotProvider.addTaskManager(1);
 
-			scheduler.newInstanceAvailable(i2);
-			scheduler.newInstanceAvailable(i1);
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
 
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
+		SlotSharingGroup sharingGroup = new SlotSharingGroup();
 
-			SlotSharingGroup sharingGroup = new SlotSharingGroup();
+		CoLocationGroup ccg = new CoLocationGroup();
+		CoLocationConstraint cc1 = new CoLocationConstraint(ccg);
+		CoLocationConstraint cc2 = new CoLocationConstraint(ccg);
 
-			CoLocationGroup ccg = new CoLocationGroup();
-			CoLocationConstraint cc1 = new CoLocationConstraint(ccg);
-			CoLocationConstraint cc2 = new CoLocationConstraint(ccg);
+		LogicalSlot s1 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId(), cc1), false, Collections.singleton(loc1)).get();
+		LogicalSlot s2 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, sharingGroup, loc2), sharingGroup.getSlotSharingGroupId(), cc2), false, Collections.singleton(loc2)).get();
 
-			LogicalSlot s1 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, loc1), sharingGroup, cc1), false, Collections.singleton(loc1)).get();
-			LogicalSlot s2 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, loc2), sharingGroup, cc2), false, Collections.singleton(loc2)).get();
+		s1.releaseSlot();
+		s2.releaseSlot();
 
-			s1.releaseSlot();
-			s2.releaseSlot();
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
+		assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfSlots());
 
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfSlots());
+		LogicalSlot s3 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, sharingGroup, loc2), sharingGroup.getSlotSharingGroupId(), cc1), false, Collections.singleton(loc2)).get();
+		LogicalSlot s4 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId(), cc2), false, Collections.singleton(loc1)).get();
 
-			LogicalSlot s3 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, loc2), sharingGroup, cc1), false, Collections.singleton(loc2)).get();
-			LogicalSlot s4 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 2, loc1), sharingGroup, cc2), false, Collections.singleton(loc1)).get();
+		// still preserves the previous instance mapping)
+		assertEquals(loc1, s3.getTaskManagerLocation());
+		assertEquals(loc2, s4.getTaskManagerLocation());
 
-			// still preserves the previous instance mapping)
-			assertEquals(i1.getTaskManagerLocation(), s3.getTaskManagerLocation());
-			assertEquals(i2.getTaskManagerLocation(), s4.getTaskManagerLocation());
+		s3.releaseSlot();
+		s4.releaseSlot();
 
-			s3.releaseSlot();
-			s4.releaseSlot();
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
 
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
-
-			assertEquals(4, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfUnconstrainedAssignments());
-		}
-		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
-		}
+		assertEquals(4, testingSlotProvider.getNumberOfLocalizedAssignments());
+		assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+		assertEquals(0, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 	}
 
 	@Test
-	public void testSlotReleasedInBetweenAndNoNewLocal() {
-		try {
-			JobVertexID jid1 = new JobVertexID();
-			JobVertexID jid2 = new JobVertexID();
-			JobVertexID jidx = new JobVertexID();
-
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-
-			Instance i1 = getRandomInstance(1);
-			Instance i2 = getRandomInstance(1);
-
-			TaskManagerLocation loc1 = i1.getTaskManagerLocation();
-			TaskManagerLocation loc2 = i2.getTaskManagerLocation();
-
-			scheduler.newInstanceAvailable(i2);
-			scheduler.newInstanceAvailable(i1);
+	public void testSlotReleasedInBetweenAndNoNewLocal() throws Exception {
+		JobVertexID jid1 = new JobVertexID();
+		JobVertexID jid2 = new JobVertexID();
+		JobVertexID jidx = new JobVertexID();
 
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
+		TaskManagerLocation loc1 = testingSlotProvider.addTaskManager(1);
+		TaskManagerLocation loc2 = testingSlotProvider.addTaskManager(1);
 
-			SlotSharingGroup sharingGroup = new SlotSharingGroup();
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
 
-			CoLocationGroup ccg = new CoLocationGroup();
-			CoLocationConstraint cc1 = new CoLocationConstraint(ccg);
-			CoLocationConstraint cc2 = new CoLocationConstraint(ccg);
+		SlotSharingGroup sharingGroup = new SlotSharingGroup();
 
-			LogicalSlot s1 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, loc1), sharingGroup, cc1), false, Collections.singleton(loc1)).get();
-			LogicalSlot s2 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, loc2), sharingGroup, cc2), false, Collections.singleton(loc2)).get();
+		CoLocationGroup ccg = new CoLocationGroup();
+		CoLocationConstraint cc1 = new CoLocationConstraint(ccg);
+		CoLocationConstraint cc2 = new CoLocationConstraint(ccg);
 
-			s1.releaseSlot();
-			s2.releaseSlot();
+		LogicalSlot s1 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId(), cc1), false, Collections.singleton(loc1)).get();
+		LogicalSlot s2 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, sharingGroup, loc2), sharingGroup.getSlotSharingGroupId(), cc2), false, Collections.singleton(loc2)).get();
 
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfSlots());
+		s1.releaseSlot();
+		s2.releaseSlot();
 
-			LogicalSlot sa = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jidx, 0, 2)), false, Collections.emptyList()).get();
-			LogicalSlot sb = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jidx, 1, 2)), false, Collections.emptyList()).get();
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
+		assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfSlots());
 
-			try {
-				scheduler.allocateSlot(
-						new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, loc2), sharingGroup, cc1), false, Collections.singleton(loc2)).get();
-				fail("should not be able to find a resource");
-			}
-			catch (ExecutionException e) {
-				assertTrue(e.getCause() instanceof NoResourceAvailableException);
-			}
-			catch (Exception e) {
-				fail("wrong exception");
-			}
+		LogicalSlot sa = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jidx, 0, 2, null)), false, Collections.emptyList()).get();
+		LogicalSlot sb = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jidx, 1, 2, null)), false, Collections.emptyList()).get();
 
-			sa.releaseSlot();
-			sb.releaseSlot();
-
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
-
-			assertEquals(2, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(2, scheduler.getNumberOfUnconstrainedAssignments());
+		try {
+			testingSlotProvider.allocateSlot(
+					new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, sharingGroup, loc2), sharingGroup.getSlotSharingGroupId(), cc1), false, Collections.singleton(loc2)).get();
+			fail("should not be able to find a resource");
+		}
+		catch (ExecutionException e) {
+			assertTrue(e.getCause() instanceof NoResourceAvailableException);
 		}
 		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
+			fail("wrong exception");
 		}
-	}
-
-	@Test
-	public void testScheduleOutOfOrder() {
-		try {
-			JobVertexID jid1 = new JobVertexID();
-			JobVertexID jid2 = new JobVertexID();
-
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-
-			Instance i1 = getRandomInstance(1);
-			Instance i2 = getRandomInstance(1);
-
-			TaskManagerLocation loc1 = i1.getTaskManagerLocation();
-
-			scheduler.newInstanceAvailable(i2);
-			scheduler.newInstanceAvailable(i1);
 
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
+		sa.releaseSlot();
+		sb.releaseSlot();
 
-			SlotSharingGroup sharingGroup = new SlotSharingGroup();
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
 
-			CoLocationGroup ccg = new CoLocationGroup();
-			CoLocationConstraint cc1 = new CoLocationConstraint(ccg);
-			CoLocationConstraint cc2 = new CoLocationConstraint(ccg);
-
-			// schedule something from the second job vertex id before the first is filled,
-			// and give locality preferences that hint at using the same shared slot for both
-			// co location constraints (which we seek to prevent)
-			LogicalSlot s1 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, loc1), sharingGroup, cc1), false, Collections.singleton(loc1)).get();
-			LogicalSlot s2 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, loc1), sharingGroup, cc2), false, Collections.singleton(loc1)).get();
-
-			LogicalSlot s3 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 2, loc1), sharingGroup, cc1), false, Collections.singleton(loc1)).get();
-			LogicalSlot s4 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, loc1), sharingGroup, cc2), false, Collections.singleton(loc1)).get();
-
-			// check that each slot got three
-			assertEquals(s1.getTaskManagerLocation(), s3.getTaskManagerLocation());
-			assertEquals(s2.getTaskManagerLocation(), s4.getTaskManagerLocation());
-
-			// check the scheduler's bookkeeping
-			assertEquals(0, scheduler.getNumberOfAvailableSlots());
-
-			assertEquals(3, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(1, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfUnconstrainedAssignments());
-
-			// release some slots, be sure that new available ones come up
-			s1.releaseSlot();
-			s2.releaseSlot();
-			s3.releaseSlot();
-			s4.releaseSlot();
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
-
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid1));
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid2));
-		}
-		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
-		}
+		assertEquals(2, testingSlotProvider.getNumberOfLocalizedAssignments());
+		assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+		assertEquals(2, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 	}
 
 	@Test
-	public void nonColocationFollowsCoLocation() {
-		try {
-			JobVertexID jid1 = new JobVertexID();
-			JobVertexID jid2 = new JobVertexID();
-
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
+	public void testScheduleOutOfOrder() throws Exception {
+		JobVertexID jid1 = new JobVertexID();
+		JobVertexID jid2 = new JobVertexID();
+
+		TaskManagerLocation loc1 = testingSlotProvider.addTaskManager(1);
+		testingSlotProvider.addTaskManager(1);
+
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
+
+		SlotSharingGroup sharingGroup = new SlotSharingGroup();
+
+		CoLocationGroup ccg = new CoLocationGroup();
+		CoLocationConstraint cc1 = new CoLocationConstraint(ccg);
+		CoLocationConstraint cc2 = new CoLocationConstraint(ccg);
+
+		// schedule something from the second job vertex id before the first is filled,
+		// and give locality preferences that hint at using the same shared slot for both
+		// co location constraints (which we seek to prevent)
+		LogicalSlot s1 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId(), cc1), false, Collections.singleton(loc1)).get();
+		LogicalSlot s2 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId(), cc2), false, Collections.singleton(loc1)).get();
+
+		LogicalSlot s3 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId(), cc1), false, Collections.singleton(loc1)).get();
+		LogicalSlot s4 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId(), cc2), false, Collections.singleton(loc1)).get();
+
+		// check that each slot got three
+		assertEquals(s1.getTaskManagerLocation(), s3.getTaskManagerLocation());
+		assertEquals(s2.getTaskManagerLocation(), s4.getTaskManagerLocation());
+
+		// check the testingSlotProvider's bookkeeping
+		assertEquals(0, testingSlotProvider.getNumberOfAvailableSlots());
+
+		assertEquals(3, testingSlotProvider.getNumberOfLocalizedAssignments());
+		assertTrue(1 == testingSlotProvider.getNumberOfNonLocalizedAssignments() || 1 == testingSlotProvider.getNumberOfHostLocalizedAssignments());
+		assertEquals(0, testingSlotProvider.getNumberOfUnconstrainedAssignments());
+
+		// release some slots, be sure that new available ones come up
+		s1.releaseSlot();
+		s2.releaseSlot();
+		s3.releaseSlot();
+		s4.releaseSlot();
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
+
+		assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfSlots());
+		assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid1));
+		assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid2));
+	}
 
-			Instance i1 = getRandomInstance(1);
-			Instance i2 = getRandomInstance(1);
+	@Test
+	public void nonColocationFollowsCoLocation() throws Exception {
+		JobVertexID jid1 = new JobVertexID();
+		JobVertexID jid2 = new JobVertexID();
 
-			TaskManagerLocation loc1 = i1.getTaskManagerLocation();
-			TaskManagerLocation loc2 = i2.getTaskManagerLocation();
+		TaskManagerLocation loc1 = testingSlotProvider.addTaskManager(1);
+		TaskManagerLocation loc2 = testingSlotProvider.addTaskManager(1);
 
-			scheduler.newInstanceAvailable(i2);
-			scheduler.newInstanceAvailable(i1);
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
 
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
-			
-			SlotSharingGroup sharingGroup = new SlotSharingGroup();
+		SlotSharingGroup sharingGroup = new SlotSharingGroup();
 
-			CoLocationGroup ccg = new CoLocationGroup();
-			CoLocationConstraint cc1 = new CoLocationConstraint(ccg);
-			CoLocationConstraint cc2 = new CoLocationConstraint(ccg);
+		CoLocationGroup ccg = new CoLocationGroup();
+		CoLocationConstraint cc1 = new CoLocationConstraint(ccg);
+		CoLocationConstraint cc2 = new CoLocationConstraint(ccg);
 
-			LogicalSlot s1 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, loc1), sharingGroup, cc1), false, Collections.emptyList()).get();
-			LogicalSlot s2 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, loc2), sharingGroup, cc2), false, Collections.emptyList()).get();
+		LogicalSlot s1 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId(), cc1), false, Collections.singleton(loc1)).get();
+		LogicalSlot s2 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, sharingGroup, loc2), sharingGroup.getSlotSharingGroupId(), cc2), false, Collections.singleton(loc2)).get();
 
-			LogicalSlot s3 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, loc1), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4 = scheduler.allocateSlot(
-					new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 2, loc1), sharingGroup), false, Collections.emptyList()).get();
+		LogicalSlot s3 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
+		LogicalSlot s4 = testingSlotProvider.allocateSlot(
+				new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
 
-			// check that each slot got two
-			assertEquals(s1.getTaskManagerLocation(), s3.getTaskManagerLocation());
-			assertEquals(s2.getTaskManagerLocation(), s4.getTaskManagerLocation());
+		// check that each slot got two
+		assertEquals(s1.getTaskManagerLocation(), s3.getTaskManagerLocation());
+		assertEquals(s2.getTaskManagerLocation(), s4.getTaskManagerLocation());
 
-			s1.releaseSlot();
-			s2.releaseSlot();
-			s3.releaseSlot();
-			s4.releaseSlot();
+		s1.releaseSlot();
+		s2.releaseSlot();
+		s3.releaseSlot();
+		s4.releaseSlot();
 
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
 
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid1));
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid2));
-		}
-		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
-		}
+		assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfSlots());
+		assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid1));
+		assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid2));
 	}
 }

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerIsolatedTasksTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerIsolatedTasksTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerIsolatedTasksTest.java
index 2ece70f..ff166a8 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerIsolatedTasksTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerIsolatedTasksTest.java
@@ -20,11 +20,13 @@ package org.apache.flink.runtime.jobmanager.scheduler;
 
 import org.apache.flink.runtime.clusterframework.types.ResourceID;
 import org.apache.flink.runtime.instance.Instance;
-import org.apache.flink.runtime.instance.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 import org.apache.flink.runtime.testingUtils.TestingUtils;
-import org.apache.flink.util.TestLogger;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -40,7 +42,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import static org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestUtils.areAllDistinct;
 import static org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestUtils.getDummyTask;
-import static org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestUtils.getRandomInstance;
 import static org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestUtils.getTestVertex;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -50,355 +51,257 @@ import static org.junit.Assert.fail;
 /**
  * Tests for the {@link Scheduler} when scheduling individual tasks.
  */
-public class SchedulerIsolatedTasksTest extends TestLogger {
+@RunWith(Parameterized.class)
+public class SchedulerIsolatedTasksTest extends SchedulerTestBase {
 
-	@Test
-	public void testAddAndRemoveInstance() {
-		try {
-			Scheduler scheduler = new Scheduler(TestingUtils.defaultExecutionContext());
-			
-			Instance i1 = getRandomInstance(2);
-			Instance i2 = getRandomInstance(2);
-			Instance i3 = getRandomInstance(2);
-			
-			assertEquals(0, scheduler.getNumberOfAvailableInstances());
-			assertEquals(0, scheduler.getNumberOfAvailableSlots());
-			scheduler.newInstanceAvailable(i1);
-			assertEquals(1, scheduler.getNumberOfAvailableInstances());
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
-			scheduler.newInstanceAvailable(i2);
-			assertEquals(2, scheduler.getNumberOfAvailableInstances());
-			assertEquals(4, scheduler.getNumberOfAvailableSlots());
-			scheduler.newInstanceAvailable(i3);
-			assertEquals(3, scheduler.getNumberOfAvailableInstances());
-			assertEquals(6, scheduler.getNumberOfAvailableSlots());
-			
-			// cannot add available instance again
-			try {
-				scheduler.newInstanceAvailable(i2);
-				fail("Scheduler accepted instance twice");
-			}
-			catch (IllegalArgumentException e) {
-				// bueno!
-			}
-			
-			// some instances die
-			assertEquals(3, scheduler.getNumberOfAvailableInstances());
-			assertEquals(6, scheduler.getNumberOfAvailableSlots());
-			scheduler.instanceDied(i2);
-			assertEquals(2, scheduler.getNumberOfAvailableInstances());
-			assertEquals(4, scheduler.getNumberOfAvailableSlots());
-			
-			// try to add a dead instance
-			try {
-				scheduler.newInstanceAvailable(i2);
-				fail("Scheduler accepted dead instance");
-			}
-			catch (IllegalArgumentException e) {
-				// stimmt
-				
-			}
-						
-			scheduler.instanceDied(i1);
-			assertEquals(1, scheduler.getNumberOfAvailableInstances());
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
-			scheduler.instanceDied(i3);
-			assertEquals(0, scheduler.getNumberOfAvailableInstances());
-			assertEquals(0, scheduler.getNumberOfAvailableSlots());
-			
-			assertFalse(i1.isAlive());
-			assertFalse(i2.isAlive());
-			assertFalse(i3.isAlive());
-		}
-		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
-		}
+	public SchedulerIsolatedTasksTest(SchedulerType schedulerType) {
+		super(schedulerType);
 	}
 	
 	@Test
-	public void testScheduleImmediately() {
+	public void testScheduleImmediately() throws Exception {
+		assertEquals(0, testingSlotProvider.getNumberOfAvailableSlots());
+
+		testingSlotProvider.addTaskManager(2);
+		testingSlotProvider.addTaskManager(1);
+		testingSlotProvider.addTaskManager(2);
+		assertEquals(5, testingSlotProvider.getNumberOfAvailableSlots());
+
+		// schedule something into all slots
+		LogicalSlot s1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
+		LogicalSlot s2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
+		LogicalSlot s3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
+		LogicalSlot s4 = testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
+		LogicalSlot s5 = testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
+
+		// the slots should all be different
+		assertTrue(areAllDistinct(s1, s2, s3, s4, s5));
+
 		try {
-			Scheduler scheduler = new Scheduler(TestingUtils.defaultExecutionContext());
-			assertEquals(0, scheduler.getNumberOfAvailableSlots());
-			
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-			scheduler.newInstanceAvailable(getRandomInstance(1));
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-			assertEquals(5, scheduler.getNumberOfAvailableSlots());
-			
-			// schedule something into all slots
-			LogicalSlot s1 = scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
-			LogicalSlot s2 = scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
-			LogicalSlot s3 = scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
-			LogicalSlot s4 = scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
-			LogicalSlot s5 = scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
-			
-			// the slots should all be different
-			assertTrue(areAllDistinct(s1, s2, s3, s4, s5));
-			
-			try {
-				scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
-				fail("Scheduler accepted scheduling request without available resource.");
-			}
-			catch (ExecutionException e) {
-				assertTrue(e.getCause() instanceof NoResourceAvailableException);
-			}
-			
-			// release some slots again
-			s3.releaseSlot();
-			s4.releaseSlot();
-			assertEquals(2, scheduler.getNumberOfAvailableSlots());
-			
-			// now we can schedule some more slots
-			LogicalSlot s6 = scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
-			LogicalSlot s7 = scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
-			
-			assertTrue(areAllDistinct(s1, s2, s3, s4, s5, s6, s7));
-			
-			// release all
-			
-			s1.releaseSlot();
-			s2.releaseSlot();
-			s5.releaseSlot();
-			s6.releaseSlot();
-			s7.releaseSlot();
-			
-			assertEquals(5, scheduler.getNumberOfAvailableSlots());
-			
-			// check that slots that are released twice (accidentally) do not mess things up
-			
-			s1.releaseSlot();
-			s2.releaseSlot();
-			s5.releaseSlot();
-			s6.releaseSlot();
-			s7.releaseSlot();
-			
-			assertEquals(5, scheduler.getNumberOfAvailableSlots());
+			testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
+			fail("Scheduler accepted scheduling request without available resource.");
 		}
-		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
+		catch (ExecutionException e) {
+			assertTrue(e.getCause() instanceof NoResourceAvailableException);
 		}
+
+		// release some slots again
+		s3.releaseSlot();
+		s4.releaseSlot();
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
+
+		// now we can schedule some more slots
+		LogicalSlot s6 = testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
+		LogicalSlot s7 = testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
+
+		assertTrue(areAllDistinct(s1, s2, s3, s4, s5, s6, s7));
+
+		// release all
+
+		s1.releaseSlot();
+		s2.releaseSlot();
+		s5.releaseSlot();
+		s6.releaseSlot();
+		s7.releaseSlot();
+
+		assertEquals(5, testingSlotProvider.getNumberOfAvailableSlots());
+
+		// check that slots that are released twice (accidentally) do not mess things up
+
+		s1.releaseSlot();
+		s2.releaseSlot();
+		s5.releaseSlot();
+		s6.releaseSlot();
+		s7.releaseSlot();
+
+		assertEquals(5, testingSlotProvider.getNumberOfAvailableSlots());
 	}
 	
 	@Test
-	public void testScheduleQueueing() {
+	public void testScheduleQueueing() throws Exception {
 		final int NUM_INSTANCES = 50;
 		final int NUM_SLOTS_PER_INSTANCE = 3;
 		final int NUM_TASKS_TO_SCHEDULE = 2000;
 
-		try {
-			// note: since this test asynchronously releases slots, the executor needs release workers.
-			// doing the release call synchronous can lead to a deadlock
-			Scheduler scheduler = new Scheduler(TestingUtils.defaultExecutionContext());
+		// note: since this test asynchronously releases slots, the executor needs release workers.
+		// doing the release call synchronous can lead to a deadlock
 
-			for (int i = 0; i < NUM_INSTANCES; i++) {
-				scheduler.newInstanceAvailable(getRandomInstance((int) (Math.random() * NUM_SLOTS_PER_INSTANCE) + 1));
-			}
+		for (int i = 0; i < NUM_INSTANCES; i++) {
+			testingSlotProvider.addTaskManager((int) (Math.random() * NUM_SLOTS_PER_INSTANCE) + 1);
+		}
 
-			assertEquals(NUM_INSTANCES, scheduler.getNumberOfAvailableInstances());
-			final int totalSlots = scheduler.getNumberOfAvailableSlots();
+		final int totalSlots = testingSlotProvider.getNumberOfAvailableSlots();
 
-			// all slots we ever got.
-			List<CompletableFuture<LogicalSlot>> allAllocatedSlots = new ArrayList<>();
+		// all slots we ever got.
+		List<CompletableFuture<LogicalSlot>> allAllocatedSlots = new ArrayList<>();
 
-			// slots that need to be released
-			final Set<LogicalSlot> toRelease = new HashSet<>();
+		// slots that need to be released
+		final Set<LogicalSlot> toRelease = new HashSet<>();
 
-			// flag to track errors in the concurrent thread
-			final AtomicBoolean errored = new AtomicBoolean(false);
+		// flag to track errors in the concurrent thread
+		final AtomicBoolean errored = new AtomicBoolean(false);
 
-			// thread to asynchronously release slots
-			Runnable disposer = new Runnable() {
+		// thread to asynchronously release slots
+		Runnable disposer = new Runnable() {
 
-				@Override
-				public void run() {
-					try {
-						int recycled = 0;
-						while (recycled < NUM_TASKS_TO_SCHEDULE) {
-							synchronized (toRelease) {
-								while (toRelease.isEmpty()) {
-									toRelease.wait();
-								}
+			@Override
+			public void run() {
+				try {
+					int recycled = 0;
+					while (recycled < NUM_TASKS_TO_SCHEDULE) {
+						synchronized (toRelease) {
+							while (toRelease.isEmpty()) {
+								toRelease.wait();
+							}
 
-								Iterator<LogicalSlot> iter = toRelease.iterator();
-								LogicalSlot next = iter.next();
-								iter.remove();
+							Iterator<LogicalSlot> iter = toRelease.iterator();
+							LogicalSlot next = iter.next();
+							iter.remove();
 
-								next.releaseSlot();
-								recycled++;
-							}
+							next.releaseSlot();
+							recycled++;
 						}
-					} catch (Throwable t) {
-						errored.set(true);
 					}
+				} catch (Throwable t) {
+					errored.set(true);
 				}
-			};
-
-			Thread disposeThread = new Thread(disposer);
-			disposeThread.start();
-
-			for (int i = 0; i < NUM_TASKS_TO_SCHEDULE; i++) {
-				CompletableFuture<LogicalSlot> future = scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), true, Collections.emptyList());
-				future.thenAcceptAsync(
-					(LogicalSlot slot) -> {
-						synchronized (toRelease) {
-							toRelease.add(slot);
-							toRelease.notifyAll();
-						}
-					},
-					TestingUtils.defaultExecutionContext());
-				allAllocatedSlots.add(future);
 			}
+		};
 
-			disposeThread.join();
+		Thread disposeThread = new Thread(disposer);
+		disposeThread.start();
 
-			assertFalse("The slot releasing thread caused an error.", errored.get());
-
-			List<LogicalSlot> slotsAfter = new ArrayList<>();
-			for (CompletableFuture<LogicalSlot> future : allAllocatedSlots) {
-				slotsAfter.add(future.get());
-			}
+		for (int i = 0; i < NUM_TASKS_TO_SCHEDULE; i++) {
+			CompletableFuture<LogicalSlot> future = testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), true, Collections.emptyList());
+			future.thenAcceptAsync(
+				(LogicalSlot slot) -> {
+					synchronized (toRelease) {
+						toRelease.add(slot);
+						toRelease.notifyAll();
+					}
+				},
+				TestingUtils.defaultExecutionContext());
+			allAllocatedSlots.add(future);
+		}
 
-			assertEquals("All instances should have available slots.", NUM_INSTANCES,
-					scheduler.getNumberOfInstancesWithAvailableSlots());
+		disposeThread.join();
 
-			// the slots should all be different
-			assertTrue(areAllDistinct(slotsAfter.toArray()));
+		assertFalse("The slot releasing thread caused an error.", errored.get());
 
-			assertEquals("All slots should be available.", totalSlots,
-					scheduler.getNumberOfAvailableSlots());
-		} catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
+		List<LogicalSlot> slotsAfter = new ArrayList<>();
+		for (CompletableFuture<LogicalSlot> future : allAllocatedSlots) {
+			slotsAfter.add(future.get());
 		}
+
+		// the slots should all be different
+		assertTrue(areAllDistinct(slotsAfter.toArray()));
+
+		assertEquals("All slots should be available.", totalSlots,
+				testingSlotProvider.getNumberOfAvailableSlots());
 	}
 	
 	@Test
-	public void testScheduleWithDyingInstances() {
-		try {
-			Scheduler scheduler = new Scheduler(TestingUtils.defaultExecutionContext());
-			
-			Instance i1 = getRandomInstance(2);
-			Instance i2 = getRandomInstance(2);
-			Instance i3 = getRandomInstance(1);
-			
-			scheduler.newInstanceAvailable(i1);
-			scheduler.newInstanceAvailable(i2);
-			scheduler.newInstanceAvailable(i3);
-			
-			List<LogicalSlot> slots = new ArrayList<>();
-			slots.add(scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get());
-			slots.add(scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get());
-			slots.add(scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get());
-			slots.add(scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get());
-			slots.add(scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get());
-			
-			i2.markDead();
-			
-			for (LogicalSlot slot : slots) {
-				if (slot.getTaskManagerLocation().getResourceID().equals(i2.getTaskManagerID())) {
-					assertFalse(slot.isAlive());
-				} else {
-					assertTrue(slot.isAlive());
-				}
-				
-				slot.releaseSlot();
-			}
-			
-			assertEquals(3, scheduler.getNumberOfAvailableSlots());
-			
-			i1.markDead();
-			i3.markDead();
-			
-			// cannot get another slot, since all instances are dead
-			try {
-				scheduler.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
-				fail("Scheduler served a slot from a dead instance");
-			}
-			catch (ExecutionException e) {
-				assertTrue(e.getCause() instanceof NoResourceAvailableException);
-			}
-			catch (Exception e) {
-				fail("Wrong exception type.");
+	public void testScheduleWithDyingInstances() throws Exception {
+		final TaskManagerLocation taskManagerLocation1 = testingSlotProvider.addTaskManager(2);
+		final TaskManagerLocation taskManagerLocation2 = testingSlotProvider.addTaskManager(2);
+		final TaskManagerLocation taskManagerLocation3 = testingSlotProvider.addTaskManager(1);
+
+		List<LogicalSlot> slots = new ArrayList<>();
+		slots.add(testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get());
+		slots.add(testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get());
+		slots.add(testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get());
+		slots.add(testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get());
+		slots.add(testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get());
+
+		testingSlotProvider.releaseTaskManager(taskManagerLocation2.getResourceID());
+
+		for (LogicalSlot slot : slots) {
+			if (slot.getTaskManagerLocation().getResourceID().equals(taskManagerLocation2.getResourceID())) {
+				assertFalse(slot.isAlive());
+			} else {
+				assertTrue(slot.isAlive());
 			}
-			
-			// now the latest, the scheduler should have noticed (through the lazy mechanisms)
-			// that all instances have vanished
-			assertEquals(0, scheduler.getNumberOfInstancesWithAvailableSlots());
-			assertEquals(0, scheduler.getNumberOfAvailableSlots());
+
+			slot.releaseSlot();
+		}
+
+		assertEquals(3, testingSlotProvider.getNumberOfAvailableSlots());
+
+		testingSlotProvider.releaseTaskManager(taskManagerLocation1.getResourceID());
+		testingSlotProvider.releaseTaskManager(taskManagerLocation3.getResourceID());
+
+		// cannot get another slot, since all instances are dead
+		try {
+			testingSlotProvider.allocateSlot(new ScheduledUnit(getDummyTask()), false, Collections.emptyList()).get();
+			fail("Scheduler served a slot from a dead instance");
+		}
+		catch (ExecutionException e) {
+			assertTrue(e.getCause() instanceof NoResourceAvailableException);
 		}
 		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
+			fail("Wrong exception type.");
 		}
+
+		// now the latest, the scheduler should have noticed (through the lazy mechanisms)
+		// that all instances have vanished
+		assertEquals(0, testingSlotProvider.getNumberOfAvailableSlots());
 	}
 	
 	@Test
-	public void testSchedulingLocation() {
-		try {
-			Scheduler scheduler = new Scheduler(TestingUtils.defaultExecutionContext());
-			
-			Instance i1 = getRandomInstance(2);
-			Instance i2 = getRandomInstance(2);
-			Instance i3 = getRandomInstance(2);
-			
-			scheduler.newInstanceAvailable(i1);
-			scheduler.newInstanceAvailable(i2);
-			scheduler.newInstanceAvailable(i3);
-			
-			// schedule something on an arbitrary instance
-			LogicalSlot s1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(new Instance[0])), false, Collections.emptyList()).get();
-			
-			// figure out how we use the location hints
-			ResourceID firstResourceId = s1.getTaskManagerLocation().getResourceID();
-
-			List<Instance> instances = Arrays.asList(i1, i2, i3);
-
-			int index = 0;
-			for (; index < instances.size(); index++) {
-				if (Objects.equals(instances.get(index).getTaskManagerID(), firstResourceId)) {
-					break;
-				}
-			}
+	public void testSchedulingLocation() throws Exception {
+		final TaskManagerLocation taskManagerLocation1 = testingSlotProvider.addTaskManager(2);
+		final TaskManagerLocation taskManagerLocation2 = testingSlotProvider.addTaskManager(2);
+		final TaskManagerLocation taskManagerLocation3 = testingSlotProvider.addTaskManager(2);
 
-			Instance first = instances.get(index);
-			Instance second = instances.get((index + 1) % instances.size());
-			Instance third = instances.get((index + 2) % instances.size());
-
-			// something that needs to go to the first instance again
-			LogicalSlot s2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(s1.getTaskManagerLocation())), false, Collections.singleton(s1.getTaskManagerLocation())).get();
-			assertEquals(first.getTaskManagerID(), s2.getTaskManagerLocation().getResourceID());
-
-			// first or second --> second, because first is full
-			LogicalSlot s3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(first, second)), false, Arrays.asList(first.getTaskManagerLocation(), second.getTaskManagerLocation())).get();
-			assertEquals(second.getTaskManagerID(), s3.getTaskManagerLocation().getResourceID());
-			
-			// first or third --> third (because first is full)
-			LogicalSlot s4 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(first, third)), false, Arrays.asList(first.getTaskManagerLocation(), third.getTaskManagerLocation())).get();
-			LogicalSlot s5 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(first, third)), false, Arrays.asList(first.getTaskManagerLocation(), third.getTaskManagerLocation())).get();
-			assertEquals(third.getTaskManagerID(), s4.getTaskManagerLocation().getResourceID());
-			assertEquals(third.getTaskManagerID(), s5.getTaskManagerLocation().getResourceID());
-			
-			// first or third --> second, because all others are full
-			LogicalSlot s6 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(first, third)), false, Arrays.asList(first.getTaskManagerLocation(), third.getTaskManagerLocation())).get();
-			assertEquals(second.getTaskManagerID(), s6.getTaskManagerLocation().getResourceID());
-			
-			// release something on the first and second instance
-			s2.releaseSlot();
-			s6.releaseSlot();
-			
-			LogicalSlot s7 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(first, third)), false, Arrays.asList(first.getTaskManagerLocation(), third.getTaskManagerLocation())).get();
-			assertEquals(first.getTaskManagerID(), s7.getTaskManagerLocation().getResourceID());
-			
-			assertEquals(1, scheduler.getNumberOfUnconstrainedAssignments());
-			assertEquals(1, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(5, scheduler.getNumberOfLocalizedAssignments());
-		}
-		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
+		// schedule something on an arbitrary instance
+		LogicalSlot s1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(new Instance[0])), false, Collections.emptyList()).get();
+
+		// figure out how we use the location hints
+		ResourceID firstResourceId = s1.getTaskManagerLocation().getResourceID();
+
+		List<TaskManagerLocation> taskManagerLocations = Arrays.asList(
+			taskManagerLocation1,
+			taskManagerLocation2,
+			taskManagerLocation3);
+
+		int index = 0;
+		for (; index < taskManagerLocations.size(); index++) {
+			if (Objects.equals(taskManagerLocations.get(index).getResourceID(), firstResourceId)) {
+				break;
+			}
 		}
+
+		TaskManagerLocation first = taskManagerLocations.get(index);
+		TaskManagerLocation second = taskManagerLocations.get((index + 1) % taskManagerLocations.size());
+		TaskManagerLocation third = taskManagerLocations.get((index + 2) % taskManagerLocations.size());
+
+		// something that needs to go to the first instance again
+		LogicalSlot s2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(s1.getTaskManagerLocation())), false, Collections.singleton(s1.getTaskManagerLocation())).get();
+		assertEquals(first.getResourceID(), s2.getTaskManagerLocation().getResourceID());
+
+		// first or second --> second, because first is full
+		LogicalSlot s3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(first, second)), false, Arrays.asList(first, second)).get();
+		assertEquals(second.getResourceID(), s3.getTaskManagerLocation().getResourceID());
+
+		// first or third --> third (because first is full)
+		LogicalSlot s4 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(first, third)), false, Arrays.asList(first, third)).get();
+		LogicalSlot s5 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(first, third)), false, Arrays.asList(first, third)).get();
+		assertEquals(third.getResourceID(), s4.getTaskManagerLocation().getResourceID());
+		assertEquals(third.getResourceID(), s5.getTaskManagerLocation().getResourceID());
+
+		// first or third --> second, because all others are full
+		LogicalSlot s6 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(first, third)), false, Arrays.asList(first, third)).get();
+		assertEquals(second.getResourceID(), s6.getTaskManagerLocation().getResourceID());
+
+		// release something on the first and second instance
+		s2.releaseSlot();
+		s6.releaseSlot();
+
+		LogicalSlot s7 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(first, third)), false, Arrays.asList(first, third)).get();
+		assertEquals(first.getResourceID(), s7.getTaskManagerLocation().getResourceID());
+
+		assertEquals(1, testingSlotProvider.getNumberOfUnconstrainedAssignments());
+		assertTrue(1 == testingSlotProvider.getNumberOfNonLocalizedAssignments() || 1 == testingSlotProvider.getNumberOfHostLocalizedAssignments());
+		assertEquals(5, testingSlotProvider.getNumberOfLocalizedAssignments());
 	}
 }


[07/11] flink git commit: [FLINK-7956] [flip6] Add support for queued scheduling with slot sharing to SlotPool

Posted by tr...@apache.org.
http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotSharingManager.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotSharingManager.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotSharingManager.java
new file mode 100644
index 0000000..91ffa8d
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotSharingManager.java
@@ -0,0 +1,740 @@
+/*
+ * 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.annotation.VisibleForTesting;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.jobmanager.scheduler.Locality;
+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.AbstractID;
+import org.apache.flink.util.FlinkException;
+import org.apache.flink.util.Preconditions;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Manager which is responsible for slot sharing. Slot sharing allows to run different
+ * tasks in the same slot and to realize co-location constraints.
+ *
+ * <p>The SlotSharingManager allows to create a hierarchy of {@link TaskSlot} such that
+ * every {@link TaskSlot} is uniquely identified by a {@link SlotRequestId} identifying
+ * the request for the TaskSlot and a {@link AbstractID} identifying the task or the
+ * co-location constraint running in this slot.
+ *
+ * <p>The {@link TaskSlot} hierarchy is implemented by {@link MultiTaskSlot} and
+ * {@link SingleTaskSlot}. The former class represents inner nodes which can contain
+ * a number of other {@link TaskSlot} and the latter class represents the leaf nodes.
+ * The hierarchy starts with a root {@link MultiTaskSlot} which is a future
+ * {@link SlotContext} assigned. The {@link SlotContext} represents the allocated slot
+ * on the TaskExecutor in which all slots of this hierarchy run. A {@link MultiTaskSlot}
+ * can be assigned multiple {@link SingleTaskSlot} or {@link MultiTaskSlot} if and only if
+ * the task slot does not yet contain another child with the same {@link AbstractID} identifying
+ * the actual task or the co-location constraint.
+ *
+ * <p>Normal slot sharing is represented by a root {@link MultiTaskSlot} which contains a set
+ * of {@link SingleTaskSlot} on the second layer. Each {@link SingleTaskSlot} represents a different
+ * task.
+ *
+ * <p>Co-location constraints are modeled by adding a {@link MultiTaskSlot} to the root node. The co-location
+ * constraint is uniquely identified by a {@link AbstractID} such that we cannot add a second co-located
+ * {@link MultiTaskSlot} to the same root node. Now all co-located tasks will be added to co-located
+ * multi task slot.
+ */
+public class SlotSharingManager {
+
+	/** Lock for the internal data structures. */
+	private final Object lock = new Object();
+
+	private final SlotSharingGroupId slotSharingGroupId;
+
+	/** Actions to release allocated slots after a complete multi task slot hierarchy has been released. */
+	private final AllocatedSlotActions allocatedSlotActions;
+
+	/** Owner of the slots to which to return them when they are released from the outside. */
+	private final SlotOwner slotOwner;
+
+	private final Map<SlotRequestId, TaskSlot> allTaskSlots;
+
+	/** Root nodes which have not been completed because the allocated slot is still pending. */
+	@GuardedBy("lock")
+	private final Map<SlotRequestId, MultiTaskSlot> unresolvedRootSlots;
+
+	/** Root nodes which have been completed (the underlying allocated slot has been assigned). */
+	@GuardedBy("lock")
+	private final Map<TaskManagerLocation, Set<MultiTaskSlot>> resolvedRootSlots;
+
+	SlotSharingManager(
+			SlotSharingGroupId slotSharingGroupId,
+			AllocatedSlotActions allocatedSlotActions,
+			SlotOwner slotOwner) {
+		this.slotSharingGroupId = Preconditions.checkNotNull(slotSharingGroupId);
+		this.allocatedSlotActions = Preconditions.checkNotNull(allocatedSlotActions);
+		this.slotOwner = Preconditions.checkNotNull(slotOwner);
+
+		allTaskSlots = new HashMap<>(16);
+		unresolvedRootSlots = new HashMap<>(16);
+		resolvedRootSlots = new HashMap<>(16);
+	}
+
+	public boolean isEmpty() {
+		return allTaskSlots.isEmpty();
+	}
+
+	public boolean contains(SlotRequestId slotRequestId) {
+		return allTaskSlots.containsKey(slotRequestId);
+	}
+
+	@Nullable
+	TaskSlot getTaskSlot(SlotRequestId slotRequestId) {
+		return allTaskSlots.get(slotRequestId);
+	}
+
+	/**
+	 * Creates a new root slot with the given {@link SlotRequestId}, {@link SlotContext} future and
+	 * the {@link SlotRequestId} of the allocated slot.
+	 *
+	 * @param slotRequestId of the root slot
+	 * @param slotContextFuture with which we create the root slot
+	 * @param allocatedSlotRequestId slot request id of the underlying allocated slot which can be used
+	 *                               to cancel the pending slot request or release the allocated slot
+	 * @return New root slot
+	 */
+	MultiTaskSlot createRootSlot(
+			SlotRequestId slotRequestId,
+			CompletableFuture<? extends SlotContext> slotContextFuture,
+			SlotRequestId allocatedSlotRequestId) {
+		final MultiTaskSlot rootMultiTaskSlot = new MultiTaskSlot(
+			slotRequestId,
+			slotContextFuture,
+			allocatedSlotRequestId);
+
+		allTaskSlots.put(slotRequestId, rootMultiTaskSlot);
+
+		synchronized (lock) {
+			unresolvedRootSlots.put(slotRequestId, rootMultiTaskSlot);
+		}
+
+		// add the root node to the set of resolved root nodes once the SlotContext future has
+		// been completed and we know the slot's TaskManagerLocation
+		slotContextFuture.whenComplete(
+			(SlotContext slotContext, Throwable throwable) -> {
+				if (slotContext != null) {
+					synchronized (lock) {
+						final MultiTaskSlot resolvedRootNode = unresolvedRootSlots.remove(slotRequestId);
+
+						if (resolvedRootNode != null) {
+							final Set<MultiTaskSlot> innerCollection = resolvedRootSlots.computeIfAbsent(
+								slotContext.getTaskManagerLocation(),
+								taskManagerLocation -> new HashSet<>(4));
+
+							innerCollection.add(resolvedRootNode);
+						}
+					}
+				} else {
+					rootMultiTaskSlot.release(throwable);
+				}
+			});
+
+		return rootMultiTaskSlot;
+	}
+
+	/**
+	 * Gets a resolved root slot which does not yet contain the given groupId. First the given set of
+	 * preferred locations is checked.
+	 *
+	 * @param groupId which the returned slot must not contain
+	 * @param locationPreferences specifying which locations are preferred
+	 * @return the resolved root slot and its locality wrt to the specified location preferences
+	 * 		or null if there was no root slot which did not contain the given groupId
+	 */
+	@Nullable
+	MultiTaskSlotLocality getResolvedRootSlot(AbstractID groupId, Collection<TaskManagerLocation> locationPreferences) {
+		Preconditions.checkNotNull(locationPreferences);
+
+		final MultiTaskSlotLocality multiTaskSlotLocality;
+
+		if (locationPreferences.isEmpty()) {
+			multiTaskSlotLocality = getResolvedRootSlotWithoutLocationPreferences(groupId);
+		} else {
+			multiTaskSlotLocality = getResolvedRootSlotWithLocationPreferences(groupId, locationPreferences);
+		}
+
+		return multiTaskSlotLocality;
+	}
+
+	/**
+	 * Gets a resolved root slot which does not yet contain the given groupId. The method will try to
+	 * find a slot of a TaskManager contained in the collection of preferred locations. If there is no such slot
+	 * with free capacities available, then the method will look for slots of TaskManager which run on the same
+	 * machine as the TaskManager in the collection of preferred locations. If there is no such slot, then any slot
+	 * with free capacities is returned. If there is no such slot, then null is returned.
+	 *
+	 * @param groupId which the returned slot must not contain
+	 * @param locationPreferences specifying which locations are preferred
+	 * @return the resolved root slot and its locality wrt to the specified location preferences
+	 * 		or null if there was not root slot which did not contain the given groupId
+	 */
+	@Nullable
+	private MultiTaskSlotLocality getResolvedRootSlotWithLocationPreferences(AbstractID groupId, Collection<TaskManagerLocation> locationPreferences) {
+		Preconditions.checkNotNull(groupId);
+		Preconditions.checkNotNull(locationPreferences);
+		final Set<String> hostnameSet = new HashSet<>(16);
+		MultiTaskSlot nonLocalMultiTaskSlot = null;
+
+		synchronized (lock) {
+			for (TaskManagerLocation locationPreference : locationPreferences) {
+				final Set<MultiTaskSlot> multiTaskSlots = resolvedRootSlots.get(locationPreference);
+
+				if (multiTaskSlots != null) {
+					for (MultiTaskSlot multiTaskSlot : multiTaskSlots) {
+						if (!multiTaskSlot.contains(groupId)) {
+							return MultiTaskSlotLocality.of(multiTaskSlot, Locality.LOCAL);
+						}
+					}
+
+					hostnameSet.add(locationPreference.getHostname());
+				}
+			}
+
+			for (Map.Entry<TaskManagerLocation, Set<MultiTaskSlot>> taskManagerLocationSetEntry : resolvedRootSlots.entrySet()) {
+				if (hostnameSet.contains(taskManagerLocationSetEntry.getKey().getHostname())) {
+					for (MultiTaskSlot multiTaskSlot : taskManagerLocationSetEntry.getValue()) {
+						if (!multiTaskSlot.contains(groupId)) {
+							return MultiTaskSlotLocality.of(multiTaskSlot, Locality.HOST_LOCAL);
+						}
+					}
+				} else if (nonLocalMultiTaskSlot == null) {
+					for (MultiTaskSlot multiTaskSlot : taskManagerLocationSetEntry.getValue()) {
+						if (!multiTaskSlot.contains(groupId)) {
+							nonLocalMultiTaskSlot = multiTaskSlot;
+						}
+					}
+				}
+			}
+		}
+
+		if (nonLocalMultiTaskSlot != null) {
+			return MultiTaskSlotLocality.of(nonLocalMultiTaskSlot, Locality.NON_LOCAL);
+		} else {
+			return null;
+		}
+	}
+
+	/**
+	 * Gets a resolved slot which does not yet contain the given groupId without any location
+	 * preferences.
+	 *
+	 * @param groupId which the returned slot must not contain
+	 * @return the resolved slot or null if there was no root slot with free capacities
+	 */
+	@Nullable
+	private MultiTaskSlotLocality getResolvedRootSlotWithoutLocationPreferences(AbstractID groupId) {
+		Preconditions.checkNotNull(groupId);
+
+		synchronized (lock) {
+			for (Set<MultiTaskSlot> multiTaskSlots : resolvedRootSlots.values()) {
+				for (MultiTaskSlot multiTaskSlot : multiTaskSlots) {
+					if (!multiTaskSlot.contains(groupId)) {
+						return MultiTaskSlotLocality.of(multiTaskSlot, Locality.UNCONSTRAINED);
+					}
+				}
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Gets an unresolved slot which does not yet contain the given groupId. An unresolved
+	 * slot is a slot whose underlying allocated slot has not been allocated yet.
+	 *
+	 * @param groupId which the returned slot must not contain
+	 * @return the unresolved slot or null if there was no root slot with free capacities
+	 */
+	@Nullable
+	MultiTaskSlot getUnresolvedRootSlot(AbstractID groupId) {
+		synchronized (lock) {
+			for (MultiTaskSlot multiTaskSlot : unresolvedRootSlots.values()) {
+				if (!multiTaskSlot.contains(groupId)) {
+					return multiTaskSlot;
+				}
+			}
+		}
+
+		return null;
+	}
+
+	// ------------------------------------------------------------------------
+	// Inner classes: TaskSlot hierarchy and helper classes
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Helper class which contains a {@link MultiTaskSlot} and its {@link Locality}.
+	 */
+	static final class MultiTaskSlotLocality {
+		private final MultiTaskSlot multiTaskSlot;
+
+		private final Locality locality;
+
+		MultiTaskSlotLocality(MultiTaskSlot multiTaskSlot, Locality locality) {
+			this.multiTaskSlot = Preconditions.checkNotNull(multiTaskSlot);
+			this.locality = Preconditions.checkNotNull(locality);
+		}
+
+		MultiTaskSlot getMultiTaskSlot() {
+			return multiTaskSlot;
+		}
+
+		public Locality getLocality() {
+			return locality;
+		}
+
+		public static MultiTaskSlotLocality of(MultiTaskSlot multiTaskSlot, Locality locality) {
+			return new MultiTaskSlotLocality(multiTaskSlot, locality);
+		}
+	}
+
+	/**
+	 * Base class for all task slots.
+	 */
+	public abstract static class TaskSlot {
+		// every TaskSlot has an associated slot request id
+		private final SlotRequestId slotRequestId;
+
+		// all task slots except for the root slots have a group id assigned
+		@Nullable
+		private final AbstractID groupId;
+
+		TaskSlot(SlotRequestId slotRequestId, @Nullable AbstractID groupId) {
+			this.slotRequestId = Preconditions.checkNotNull(slotRequestId);
+			this.groupId = groupId;
+		}
+
+		public SlotRequestId getSlotRequestId() {
+			return slotRequestId;
+		}
+
+		@Nullable
+		public AbstractID getGroupId() {
+			return groupId;
+		}
+
+		/**
+		 * Check whether the task slot contains the given groupId.
+		 *
+		 * @param groupId which to check whether it is contained
+		 * @return true if the task slot contains the given groupId, otherwise false
+		 */
+		public boolean contains(AbstractID groupId) {
+			return Objects.equals(this.groupId, groupId);
+		}
+
+		/**
+		 * Release the task slot.
+		 *
+		 * @param cause for the release
+		 * @return true if the slot could be released, otherwise false
+		 */
+		public abstract boolean release(Throwable cause);
+	}
+
+	/**
+	 * {@link TaskSlot} implementation which can have multiple other task slots assigned as children.
+	 */
+	public final class MultiTaskSlot extends TaskSlot implements AllocatedSlot.Payload {
+
+		private final Map<AbstractID, TaskSlot> children;
+
+		// the root node has its parent set to null
+		@Nullable
+		private final MultiTaskSlot parent;
+
+		// underlying allocated slot
+		private final CompletableFuture<? extends SlotContext> slotContextFuture;
+
+		// slot request id of the allocated slot
+		@Nullable
+		private final SlotRequestId allocatedSlotRequestId;
+
+		// true if we are currently releasing our children
+		private boolean releasingChildren;
+
+		private MultiTaskSlot(
+				SlotRequestId slotRequestId,
+				AbstractID groupId,
+				MultiTaskSlot parent) {
+			this(
+				slotRequestId,
+				groupId,
+				Preconditions.checkNotNull(parent),
+				parent.getSlotContextFuture(),
+				null);
+		}
+
+		private MultiTaskSlot(
+				SlotRequestId slotRequestId,
+				CompletableFuture<? extends SlotContext> slotContextFuture,
+				SlotRequestId allocatedSlotRequestId) {
+			this(
+				slotRequestId,
+				null,
+				null,
+				slotContextFuture,
+				allocatedSlotRequestId);
+		}
+
+		private MultiTaskSlot(
+				SlotRequestId slotRequestId,
+				@Nullable AbstractID groupId,
+				MultiTaskSlot parent,
+				CompletableFuture<? extends SlotContext> slotContextFuture,
+				SlotRequestId allocatedSlotRequestId) {
+			super(slotRequestId, groupId);
+
+			this.parent = parent;
+			this.slotContextFuture = Preconditions.checkNotNull(slotContextFuture);
+			this.allocatedSlotRequestId = allocatedSlotRequestId;
+
+			this.children = new HashMap<>(16);
+			this.releasingChildren = false;
+
+			slotContextFuture.whenComplete(
+				(SlotContext ignored, Throwable throwable) -> {
+					if (throwable != null) {
+						release(throwable);
+					}
+				});
+		}
+
+		CompletableFuture<? extends SlotContext> getSlotContextFuture() {
+			return slotContextFuture;
+		}
+
+		/**
+		 * Allocates a MultiTaskSlot and registers it under the given groupId at
+		 * this MultiTaskSlot.
+		 *
+		 * @param slotRequestId of the new multi task slot
+		 * @param groupId under which the new multi task slot is registered
+		 * @return the newly allocated MultiTaskSlot
+		 */
+		MultiTaskSlot allocateMultiTaskSlot(SlotRequestId slotRequestId, AbstractID groupId) {
+			Preconditions.checkState(!super.contains(groupId));
+
+			final MultiTaskSlot inner = new MultiTaskSlot(
+				slotRequestId,
+				groupId,
+				this);
+
+			children.put(groupId, inner);
+
+			// register the newly allocated slot also at the SlotSharingManager
+			allTaskSlots.put(slotRequestId, inner);
+
+			return inner;
+		}
+
+		/**
+		 * Allocates a {@link SingleTaskSlot} and registers it under the given groupId at
+		 * this MultiTaskSlot.
+		 *
+		 * @param slotRequestId of the new single task slot
+		 * @param groupId under which the new single task slot is registered
+		 * @param locality of the allocation
+		 * @return the newly allocated {@link SingleTaskSlot}
+		 */
+		SingleTaskSlot allocateSingleTaskSlot(
+				SlotRequestId slotRequestId,
+				AbstractID groupId,
+				Locality locality) {
+			Preconditions.checkState(!super.contains(groupId));
+
+			final SingleTaskSlot leaf = new SingleTaskSlot(
+				slotRequestId,
+				groupId,
+				this,
+				locality);
+
+			children.put(groupId, leaf);
+
+			// register the newly allocated slot also at the SlotSharingManager
+			allTaskSlots.put(slotRequestId, leaf);
+
+			return leaf;
+		}
+
+		/**
+		 * Checks whether this slot or any of its children contains the given groupId.
+		 *
+		 * @param groupId which to check whether it is contained
+		 * @return true if this or any of its children contains the given groupId, otherwise false
+		 */
+		@Override
+		public boolean contains(AbstractID groupId) {
+			if (super.contains(groupId)) {
+				return true;
+			} else {
+				for (TaskSlot taskSlot : children.values()) {
+					if (taskSlot.contains(groupId)) {
+						return true;
+					}
+				}
+
+				return false;
+			}
+		}
+
+		@Override
+		public boolean release(Throwable cause) {
+			releasingChildren = true;
+
+			// first release all children and remove them if they could be released immediately
+			children.values().removeIf(node -> {
+				boolean release = node.release(cause);
+
+				if (release) {
+					allTaskSlots.remove(node.getSlotRequestId());
+				}
+
+				return release;
+			});
+
+			releasingChildren = false;
+
+			if (children.isEmpty()) {
+				if (parent != null) {
+					// we remove ourselves from our parent if we no longer have children
+					parent.releaseChild(getGroupId());
+				} else {
+					// we are the root node --> remove the root node from the list of task slots
+					allTaskSlots.remove(getSlotRequestId());
+
+					if (!slotContextFuture.isDone() || slotContextFuture.isCompletedExceptionally()) {
+						synchronized (lock) {
+							// the root node should still be unresolved
+							unresolvedRootSlots.remove(getSlotRequestId());
+						}
+					} else {
+						// the root node should be resolved --> we can access the slot context
+						final SlotContext slotContext = slotContextFuture.getNow(null);
+
+						if (slotContext != null) {
+							synchronized (lock) {
+								final Set<MultiTaskSlot> multiTaskSlots = resolvedRootSlots.get(slotContext.getTaskManagerLocation());
+
+								if (multiTaskSlots != null) {
+									multiTaskSlots.remove(this);
+
+									if (multiTaskSlots.isEmpty()) {
+										resolvedRootSlots.remove(slotContext.getTaskManagerLocation());
+									}
+								}
+							}
+						}
+					}
+
+					// release the underlying allocated slot
+					allocatedSlotActions.releaseSlot(allocatedSlotRequestId, null, cause);
+				}
+
+				return true;
+			} else {
+				return false;
+			}
+		}
+
+		/**
+		 * Releases the child with the given childGroupId.
+		 *
+		 * @param childGroupId identifying the child to release
+		 */
+		private void releaseChild(AbstractID childGroupId) {
+			if (!releasingChildren) {
+				TaskSlot child = children.remove(childGroupId);
+
+				if (child != null) {
+					allTaskSlots.remove(child.getSlotRequestId());
+				}
+
+				if (children.isEmpty()) {
+					release(new FlinkException("Release multi task slot because all children have been released."));
+				}
+			}
+		}
+	}
+
+	/**
+	 * {@link TaskSlot} implementation which harbours a {@link LogicalSlot}. The {@link SingleTaskSlot}
+	 * cannot have any children assigned.
+	 */
+	public final class SingleTaskSlot extends TaskSlot {
+		private final MultiTaskSlot parent;
+
+		// future containing a LogicalSlot which is completed once the underlying SlotContext future is completed
+		private final CompletableFuture<LogicalSlot> logicalSlotFuture;
+
+		private SingleTaskSlot(
+				SlotRequestId slotRequestId,
+				AbstractID groupId,
+				MultiTaskSlot parent,
+				Locality locality) {
+			super(slotRequestId, groupId);
+
+			this.parent = Preconditions.checkNotNull(parent);
+
+			Preconditions.checkNotNull(locality);
+			logicalSlotFuture = parent.getSlotContextFuture()
+				.thenApply(
+					(SlotContext slotContext) ->
+						new SingleLogicalSlot(
+							slotRequestId,
+							slotContext,
+							slotSharingGroupId,
+							locality,
+							slotOwner));
+		}
+
+		CompletableFuture<LogicalSlot> getLogicalSlotFuture() {
+			return logicalSlotFuture;
+		}
+
+		@Override
+		public boolean release(Throwable cause) {
+			logicalSlotFuture.completeExceptionally(cause);
+
+			boolean pendingLogicalSlotRelease = false;
+
+			if (logicalSlotFuture.isDone() && !logicalSlotFuture.isCompletedExceptionally()) {
+				// we have a single task slot which we first have to release
+				final LogicalSlot logicalSlot = logicalSlotFuture.getNow(null);
+
+				if ((logicalSlot != null) && (logicalSlot.isAlive())) {
+					pendingLogicalSlotRelease = logicalSlot.releaseSlot(cause).isDone();
+				}
+			}
+
+			if (!pendingLogicalSlotRelease) {
+				parent.releaseChild(getGroupId());
+			}
+
+			return !pendingLogicalSlotRelease;
+		}
+	}
+
+	// ------------------------------------------------------------------------
+	// Methods and classes for testing
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Returns a collection of all resolved root slots.
+	 *
+	 * @return Collection of all resolved root slots
+	 */
+	@VisibleForTesting
+	public Collection<MultiTaskSlot> getResolvedRootSlots() {
+		return new ResolvedRootSlotValues();
+	}
+
+	@VisibleForTesting
+	Collection<MultiTaskSlot> getUnresolvedRootSlots() {
+		synchronized (lock) {
+			return unresolvedRootSlots.values();
+		}
+	}
+
+	/**
+	 * Collection of all resolved {@link MultiTaskSlot} root slots.
+	 */
+	private final class ResolvedRootSlotValues extends AbstractCollection<MultiTaskSlot> {
+
+		@Override
+		public Iterator<MultiTaskSlot> iterator() {
+			synchronized (lock) {
+				return new ResolvedRootSlotIterator(resolvedRootSlots.values().iterator());
+			}
+		}
+
+		@Override
+		public int size() {
+			int numberResolvedMultiTaskSlots = 0;
+
+			synchronized (lock) {
+				for (Set<MultiTaskSlot> multiTaskSlots : resolvedRootSlots.values()) {
+					numberResolvedMultiTaskSlots += multiTaskSlots.size();
+				}
+			}
+
+			return numberResolvedMultiTaskSlots;
+		}
+	}
+
+	/**
+	 * Iterator over all resolved {@link MultiTaskSlot} root slots.
+	 */
+	private static final class ResolvedRootSlotIterator implements Iterator<MultiTaskSlot> {
+		private final Iterator<Set<MultiTaskSlot>> baseIterator;
+		private Iterator<MultiTaskSlot> currentIterator;
+
+		private ResolvedRootSlotIterator(Iterator<Set<MultiTaskSlot>> baseIterator) {
+			this.baseIterator = Preconditions.checkNotNull(baseIterator);
+
+			if (baseIterator.hasNext()) {
+				currentIterator = baseIterator.next().iterator();
+			} else {
+				currentIterator = Collections.emptyIterator();
+			}
+		}
+
+		@Override
+		public boolean hasNext() {
+			progressToNextElement();
+
+			return currentIterator.hasNext();
+		}
+
+		@Override
+		public MultiTaskSlot next() {
+			progressToNextElement();
+
+			return currentIterator.next();
+		}
+
+		private void progressToNextElement() {
+			while (baseIterator.hasNext() && !currentIterator.hasNext()) {
+				currentIterator = baseIterator.next().iterator();
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/checkpoint/CheckpointSettingsSerializableTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/checkpoint/CheckpointSettingsSerializableTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/checkpoint/CheckpointSettingsSerializableTest.java
index 7e85167..e98efc2 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/checkpoint/CheckpointSettingsSerializableTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/checkpoint/CheckpointSettingsSerializableTest.java
@@ -31,7 +31,7 @@ import org.apache.flink.runtime.execution.Environment;
 import org.apache.flink.runtime.executiongraph.ExecutionGraph;
 import org.apache.flink.runtime.executiongraph.ExecutionGraphBuilder;
 import org.apache.flink.runtime.executiongraph.restart.NoRestartStrategy;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.jobgraph.JobGraph;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
 import org.apache.flink.runtime.jobgraph.tasks.ExternalizedCheckpointSettings;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/deployment/InputChannelDeploymentDescriptorTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/deployment/InputChannelDeploymentDescriptorTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/deployment/InputChannelDeploymentDescriptorTest.java
index fc2c06f..6aa36b7 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/deployment/InputChannelDeploymentDescriptorTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/deployment/InputChannelDeploymentDescriptorTest.java
@@ -27,10 +27,10 @@ import org.apache.flink.runtime.executiongraph.ExecutionGraphException;
 import org.apache.flink.runtime.executiongraph.ExecutionVertex;
 import org.apache.flink.runtime.executiongraph.IntermediateResult;
 import org.apache.flink.runtime.executiongraph.IntermediateResultPartition;
-import org.apache.flink.runtime.instance.LogicalSlot;
 import org.apache.flink.runtime.io.network.ConnectionID;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionID;
 import org.apache.flink.runtime.jobgraph.IntermediateResultPartitionID;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ArchivedExecutionGraphTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ArchivedExecutionGraphTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ArchivedExecutionGraphTest.java
index 0d7c8e6..7b9d9aa 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ArchivedExecutionGraphTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ArchivedExecutionGraphTest.java
@@ -36,7 +36,7 @@ import org.apache.flink.runtime.checkpoint.StandaloneCheckpointIDCounter;
 import org.apache.flink.runtime.checkpoint.StandaloneCompletedCheckpointStore;
 import org.apache.flink.runtime.execution.ExecutionState;
 import org.apache.flink.runtime.executiongraph.restart.NoRestartStrategy;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.jobgraph.JobStatus;
 import org.apache.flink.runtime.jobgraph.JobVertex;
 import org.apache.flink.runtime.jobgraph.JobVertexID;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphDeploymentTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphDeploymentTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphDeploymentTest.java
index 16da8e6..e869625 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphDeploymentTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphDeploymentTest.java
@@ -40,7 +40,7 @@ import org.apache.flink.runtime.executiongraph.failover.RestartAllStrategy;
 import org.apache.flink.runtime.executiongraph.restart.NoRestartStrategy;
 import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
 import org.apache.flink.runtime.instance.Instance;
-import org.apache.flink.runtime.instance.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
 import org.apache.flink.runtime.instance.SimpleSlot;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionType;
 import org.apache.flink.runtime.jobgraph.DistributionPattern;
@@ -54,7 +54,7 @@ import org.apache.flink.runtime.jobgraph.tasks.ExternalizedCheckpointSettings;
 import org.apache.flink.runtime.jobgraph.tasks.JobCheckpointingSettings;
 import org.apache.flink.runtime.jobmanager.scheduler.Scheduler;
 import org.apache.flink.runtime.jobmanager.slots.ActorTaskManagerGateway;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
+import org.apache.flink.runtime.jobmaster.SlotOwner;
 import org.apache.flink.runtime.operators.BatchTask;
 import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
 import org.apache.flink.runtime.taskmanager.TaskExecutionState;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphMetricsTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphMetricsTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphMetricsTest.java
index 92c7c61..caf89e8 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphMetricsTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphMetricsTest.java
@@ -27,8 +27,8 @@ import org.apache.flink.runtime.execution.SuppressRestartsException;
 import org.apache.flink.runtime.executiongraph.metrics.RestartTimeGauge;
 import org.apache.flink.runtime.executiongraph.restart.RestartCallback;
 import org.apache.flink.runtime.executiongraph.restart.RestartStrategy;
-import org.apache.flink.runtime.instance.LogicalSlot;
-import org.apache.flink.runtime.instance.TestingLogicalSlot;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.TestingLogicalSlot;
 import org.apache.flink.runtime.jobgraph.JobGraph;
 import org.apache.flink.runtime.jobgraph.JobStatus;
 import org.apache.flink.runtime.jobgraph.JobVertex;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphRestartTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphRestartTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphRestartTest.java
index 80df852..2245a8c 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphRestartTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphRestartTest.java
@@ -41,7 +41,7 @@ import org.apache.flink.runtime.executiongraph.utils.SimpleSlotProvider;
 import org.apache.flink.runtime.instance.HardwareDescription;
 import org.apache.flink.runtime.instance.Instance;
 import org.apache.flink.runtime.instance.InstanceID;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionType;
 import org.apache.flink.runtime.jobgraph.DistributionPattern;
 import org.apache.flink.runtime.jobgraph.JobGraph;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphSchedulingTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphSchedulingTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphSchedulingTest.java
index 18e6cf1..f75cb4b 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphSchedulingTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphSchedulingTest.java
@@ -28,18 +28,17 @@ import org.apache.flink.runtime.clusterframework.types.AllocationID;
 import org.apache.flink.runtime.clusterframework.types.ResourceID;
 import org.apache.flink.runtime.deployment.TaskDeploymentDescriptor;
 import org.apache.flink.runtime.executiongraph.restart.NoRestartStrategy;
-import org.apache.flink.runtime.instance.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
 import org.apache.flink.runtime.instance.SimpleSlot;
-import org.apache.flink.runtime.instance.SlotProvider;
-import org.apache.flink.runtime.instance.SlotRequestID;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionType;
 import org.apache.flink.runtime.jobgraph.DistributionPattern;
 import org.apache.flink.runtime.jobgraph.JobGraph;
 import org.apache.flink.runtime.jobgraph.JobStatus;
 import org.apache.flink.runtime.jobgraph.JobVertex;
 import org.apache.flink.runtime.jobgraph.ScheduleMode;
-import org.apache.flink.runtime.jobmanager.slots.SimpleSlotContext;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
+import org.apache.flink.runtime.instance.SimpleSlotContext;
+import org.apache.flink.runtime.jobmaster.SlotOwner;
 import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
 import org.apache.flink.runtime.jobmanager.slots.TestingSlotOwner;
 import org.apache.flink.runtime.messages.Acknowledge;
@@ -448,7 +447,6 @@ public class ExecutionGraphSchedulingTest extends TestLogger {
 				ResourceID.generate(), InetAddress.getLoopbackAddress(), 12345);
 
 		SimpleSlotContext slot = new SimpleSlotContext(
-			new SlotRequestID(),
 			new AllocationID(),
 			location,
 			0,

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphSuspendTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphSuspendTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphSuspendTest.java
index 65a52bc..b5a29c3 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphSuspendTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphSuspendTest.java
@@ -25,7 +25,7 @@ import org.apache.flink.runtime.executiongraph.restart.FixedDelayRestartStrategy
 import org.apache.flink.runtime.executiongraph.restart.InfiniteDelayRestartStrategy;
 import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
 import org.apache.flink.runtime.executiongraph.utils.SimpleSlotProvider;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.jobgraph.JobStatus;
 import org.apache.flink.runtime.jobgraph.JobVertex;
 import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphTestUtils.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphTestUtils.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphTestUtils.java
index c97329f..b1ee3cc 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphTestUtils.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionGraphTestUtils.java
@@ -41,16 +41,15 @@ import org.apache.flink.runtime.instance.HardwareDescription;
 import org.apache.flink.runtime.instance.Instance;
 import org.apache.flink.runtime.instance.InstanceID;
 import org.apache.flink.runtime.instance.SimpleSlot;
-import org.apache.flink.runtime.instance.SlotProvider;
-import org.apache.flink.runtime.instance.SlotRequestID;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.jobgraph.JobGraph;
 import org.apache.flink.runtime.jobgraph.JobStatus;
 import org.apache.flink.runtime.jobgraph.JobVertex;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
 import org.apache.flink.runtime.jobgraph.tasks.AbstractInvokable;
 import org.apache.flink.runtime.jobmanager.scheduler.Scheduler;
-import org.apache.flink.runtime.jobmanager.slots.SimpleSlotContext;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
+import org.apache.flink.runtime.instance.SimpleSlotContext;
+import org.apache.flink.runtime.jobmaster.SlotOwner;
 import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
 import org.apache.flink.runtime.messages.Acknowledge;
 import org.apache.flink.runtime.messages.TaskMessages.CancelTask;
@@ -245,7 +244,6 @@ public class ExecutionGraphTestUtils {
 				ResourceID.generate(), InetAddress.getLoopbackAddress(), 6572);
 
 		final SimpleSlotContext allocatedSlot = new SimpleSlotContext(
-			new SlotRequestID(),
 			new AllocationID(),
 			location,
 			0,

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionTest.java
index e3fd0df..46dfd41 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionTest.java
@@ -22,13 +22,13 @@ import org.apache.flink.api.common.JobID;
 import org.apache.flink.runtime.execution.ExecutionState;
 import org.apache.flink.runtime.executiongraph.restart.NoRestartStrategy;
 import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
-import org.apache.flink.runtime.instance.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
 import org.apache.flink.runtime.instance.SimpleSlot;
 import org.apache.flink.runtime.jobgraph.JobVertex;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
 import org.apache.flink.runtime.jobmanager.scheduler.LocationPreferenceConstraint;
 import org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestUtils;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
+import org.apache.flink.runtime.jobmaster.SlotOwner;
 import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 import org.apache.flink.runtime.testingUtils.TestingUtils;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexDeploymentTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexDeploymentTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexDeploymentTest.java
index 63cebf3..d91380e 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexDeploymentTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexDeploymentTest.java
@@ -25,14 +25,14 @@ import org.apache.flink.runtime.deployment.ResultPartitionDeploymentDescriptor;
 import org.apache.flink.runtime.deployment.TaskDeploymentDescriptor;
 import org.apache.flink.runtime.execution.ExecutionState;
 import org.apache.flink.runtime.instance.Instance;
-import org.apache.flink.runtime.instance.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
 import org.apache.flink.runtime.instance.SimpleSlot;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionType;
 import org.apache.flink.runtime.jobgraph.IntermediateDataSetID;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
 import org.apache.flink.runtime.jobgraph.ScheduleMode;
 import org.apache.flink.runtime.jobmanager.slots.ActorTaskManagerGateway;
-import org.apache.flink.runtime.jobmanager.slots.SlotContext;
+import org.apache.flink.runtime.jobmaster.SlotContext;
 import org.apache.flink.runtime.testingUtils.TestingUtils;
 import org.apache.flink.runtime.testutils.DirectScheduledExecutorService;
 import org.apache.flink.util.TestLogger;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexLocalityTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexLocalityTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexLocalityTest.java
index bffbb6a..274df59 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexLocalityTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexLocalityTest.java
@@ -30,16 +30,15 @@ import org.apache.flink.runtime.clusterframework.types.ResourceID;
 import org.apache.flink.runtime.execution.ExecutionState;
 import org.apache.flink.runtime.executiongraph.restart.FixedDelayRestartStrategy;
 import org.apache.flink.runtime.instance.SimpleSlot;
-import org.apache.flink.runtime.instance.SlotProvider;
-import org.apache.flink.runtime.instance.SlotRequestID;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionType;
 import org.apache.flink.runtime.jobgraph.DistributionPattern;
 import org.apache.flink.runtime.jobgraph.JobGraph;
 import org.apache.flink.runtime.jobgraph.JobVertex;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
-import org.apache.flink.runtime.jobmanager.slots.SimpleSlotContext;
-import org.apache.flink.runtime.jobmanager.slots.SlotContext;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
+import org.apache.flink.runtime.instance.SimpleSlotContext;
+import org.apache.flink.runtime.jobmaster.SlotContext;
+import org.apache.flink.runtime.jobmaster.SlotOwner;
 import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 import org.apache.flink.runtime.testingUtils.TestingUtils;
@@ -235,7 +234,6 @@ public class ExecutionVertexLocalityTest extends TestLogger {
 		//  - exposing test methods in the ExecutionVertex leads to undesirable setters 
 
 		SlotContext slot = new SimpleSlotContext(
-			new SlotRequestID(),
 			new AllocationID(),
 			location,
 			0,

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexSchedulingTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexSchedulingTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexSchedulingTest.java
index 9310912..25e1207 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexSchedulingTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ExecutionVertexSchedulingTest.java
@@ -59,7 +59,7 @@ public class ExecutionVertexSchedulingTest {
 			final Instance instance = getInstance(new ActorTaskManagerGateway(DummyActorGateway.INSTANCE));
 			final SimpleSlot slot = instance.allocateSimpleSlot();
 			
-			slot.releaseInstanceSlot();
+			slot.releaseSlot();
 			assertTrue(slot.isReleased());
 
 			Scheduler scheduler = mock(Scheduler.class);
@@ -91,7 +91,7 @@ public class ExecutionVertexSchedulingTest {
 			final Instance instance = getInstance(new ActorTaskManagerGateway(DummyActorGateway.INSTANCE));
 			final SimpleSlot slot = instance.allocateSimpleSlot();
 
-			slot.releaseInstanceSlot();
+			slot.releaseSlot();
 			assertTrue(slot.isReleased());
 
 			final CompletableFuture<SimpleSlot> future = new CompletableFuture<>();

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/FailoverRegionTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/FailoverRegionTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/FailoverRegionTest.java
index 4d53e67..c411393 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/FailoverRegionTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/FailoverRegionTest.java
@@ -31,7 +31,7 @@ import org.apache.flink.runtime.executiongraph.restart.NoRestartStrategy;
 import org.apache.flink.runtime.executiongraph.restart.RestartStrategy;
 import org.apache.flink.runtime.executiongraph.utils.SimpleSlotProvider;
 import org.apache.flink.runtime.instance.Instance;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionType;
 import org.apache.flink.runtime.jobgraph.DistributionPattern;
 import org.apache.flink.runtime.jobgraph.JobStatus;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/IndividualRestartsConcurrencyTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/IndividualRestartsConcurrencyTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/IndividualRestartsConcurrencyTest.java
index 32ccad1..4725296 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/IndividualRestartsConcurrencyTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/IndividualRestartsConcurrencyTest.java
@@ -36,7 +36,7 @@ import org.apache.flink.runtime.executiongraph.restart.FixedDelayRestartStrategy
 import org.apache.flink.runtime.executiongraph.restart.NoRestartStrategy;
 import org.apache.flink.runtime.executiongraph.restart.RestartStrategy;
 import org.apache.flink.runtime.executiongraph.utils.SimpleSlotProvider;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.jobgraph.JobGraph;
 import org.apache.flink.runtime.jobgraph.JobStatus;
 import org.apache.flink.runtime.jobgraph.JobVertex;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/LegacyJobVertexIdTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/LegacyJobVertexIdTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/LegacyJobVertexIdTest.java
index b5a67fd..49a6dce 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/LegacyJobVertexIdTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/LegacyJobVertexIdTest.java
@@ -22,7 +22,7 @@ import org.apache.flink.api.common.JobID;
 import org.apache.flink.api.common.time.Time;
 import org.apache.flink.configuration.Configuration;
 import org.apache.flink.runtime.executiongraph.restart.RestartStrategy;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.jobgraph.JobVertex;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
 import org.apache.flink.runtime.jobgraph.OperatorID;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/PipelinedRegionFailoverConcurrencyTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/PipelinedRegionFailoverConcurrencyTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/PipelinedRegionFailoverConcurrencyTest.java
index 656c372..06647cc 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/PipelinedRegionFailoverConcurrencyTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/PipelinedRegionFailoverConcurrencyTest.java
@@ -30,7 +30,7 @@ import org.apache.flink.runtime.executiongraph.failover.RestartPipelinedRegionSt
 import org.apache.flink.runtime.executiongraph.restart.FixedDelayRestartStrategy;
 import org.apache.flink.runtime.executiongraph.restart.RestartStrategy;
 import org.apache.flink.runtime.executiongraph.utils.SimpleSlotProvider;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.jobgraph.JobGraph;
 import org.apache.flink.runtime.jobgraph.JobStatus;
 import org.apache.flink.runtime.jobgraph.JobVertex;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ProgrammedSlotProvider.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ProgrammedSlotProvider.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ProgrammedSlotProvider.java
index 24affad..f44626d 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ProgrammedSlotProvider.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/ProgrammedSlotProvider.java
@@ -18,8 +18,8 @@
 
 package org.apache.flink.runtime.executiongraph;
 
-import org.apache.flink.runtime.instance.LogicalSlot;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
 import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/failover/PipelinedFailoverRegionBuildingTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/failover/PipelinedFailoverRegionBuildingTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/failover/PipelinedFailoverRegionBuildingTest.java
index 4709bce..f94959d 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/failover/PipelinedFailoverRegionBuildingTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/failover/PipelinedFailoverRegionBuildingTest.java
@@ -30,7 +30,7 @@ import org.apache.flink.runtime.executiongraph.ExecutionGraph;
 import org.apache.flink.runtime.executiongraph.ExecutionGraphBuilder;
 import org.apache.flink.runtime.executiongraph.ExecutionVertex;
 import org.apache.flink.runtime.executiongraph.restart.NoRestartStrategy;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionType;
 import org.apache.flink.runtime.jobgraph.DistributionPattern;
 import org.apache.flink.runtime.jobgraph.JobGraph;

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/utils/SimpleSlotProvider.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/utils/SimpleSlotProvider.java b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/utils/SimpleSlotProvider.java
index 82953d6..bffdab6 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/utils/SimpleSlotProvider.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/executiongraph/utils/SimpleSlotProvider.java
@@ -22,16 +22,15 @@ import org.apache.flink.api.common.JobID;
 import org.apache.flink.runtime.clusterframework.types.AllocationID;
 import org.apache.flink.runtime.clusterframework.types.ResourceID;
 import org.apache.flink.runtime.concurrent.FutureUtils;
-import org.apache.flink.runtime.instance.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
 import org.apache.flink.runtime.instance.SimpleSlot;
 import org.apache.flink.runtime.instance.Slot;
-import org.apache.flink.runtime.instance.SlotProvider;
-import org.apache.flink.runtime.instance.SlotRequestID;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.jobmanager.scheduler.NoResourceAvailableException;
 import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
-import org.apache.flink.runtime.jobmanager.slots.SlotContext;
-import org.apache.flink.runtime.jobmanager.slots.SimpleSlotContext;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
+import org.apache.flink.runtime.instance.SimpleSlotContext;
+import org.apache.flink.runtime.jobmaster.SlotContext;
+import org.apache.flink.runtime.jobmaster.SlotOwner;
 import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 import org.apache.flink.util.Preconditions;
@@ -63,7 +62,6 @@ public class SimpleSlotProvider implements SlotProvider, SlotOwner {
 
 		for (int i = 0; i < numSlots; i++) {
 			SimpleSlotContext as = new SimpleSlotContext(
-				new SlotRequestID(),
 				new AllocationID(),
 				new TaskManagerLocation(ResourceID.generate(), InetAddress.getLoopbackAddress(), 10000 + i),
 				0,

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/instance/AllocatedSlotsTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/AllocatedSlotsTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/AllocatedSlotsTest.java
deleted file mode 100644
index 223d43c..0000000
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/AllocatedSlotsTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * 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.instance;
-
-import org.apache.flink.runtime.clusterframework.types.AllocationID;
-import org.apache.flink.runtime.clusterframework.types.ResourceID;
-import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
-import org.apache.flink.runtime.executiongraph.utils.SimpleAckingTaskManagerGateway;
-import org.apache.flink.runtime.jobmanager.slots.DummySlotOwner;
-import org.apache.flink.runtime.taskmanager.LocalTaskManagerLocation;
-import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-import org.apache.flink.util.TestLogger;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-public class AllocatedSlotsTest extends TestLogger {
-
-	@Test
-	public void testOperations() throws Exception {
-		SlotPool.AllocatedSlots allocatedSlots = new SlotPool.AllocatedSlots();
-
-		final AllocationID allocation1 = new AllocationID();
-		final SlotRequestID slotRequestID = new SlotRequestID();
-		final TaskManagerLocation taskManagerLocation = new LocalTaskManagerLocation();
-		final ResourceID resource1 = taskManagerLocation.getResourceID();
-		final AllocatedSlot slot1 = createSlot(allocation1, taskManagerLocation);
-
-		allocatedSlots.add(slotRequestID, slot1);
-
-		assertTrue(allocatedSlots.contains(slot1.getAllocationId()));
-		assertTrue(allocatedSlots.containResource(resource1));
-
-		assertEquals(slot1, allocatedSlots.get(allocation1));
-		assertEquals(1, allocatedSlots.getSlotsForTaskManager(resource1).size());
-		assertEquals(1, allocatedSlots.size());
-
-		final AllocationID allocation2 = new AllocationID();
-		final SlotRequestID slotRequestID2 = new SlotRequestID();
-		final AllocatedSlot slot2 = createSlot(allocation2, taskManagerLocation);
-
-		allocatedSlots.add(slotRequestID2, slot2);
-
-		assertTrue(allocatedSlots.contains(slot1.getAllocationId()));
-		assertTrue(allocatedSlots.contains(slot2.getAllocationId()));
-		assertTrue(allocatedSlots.containResource(resource1));
-
-		assertEquals(slot1, allocatedSlots.get(allocation1));
-		assertEquals(slot2, allocatedSlots.get(allocation2));
-		assertEquals(2, allocatedSlots.getSlotsForTaskManager(resource1).size());
-		assertEquals(2, allocatedSlots.size());
-
-		final AllocationID allocation3 = new AllocationID();
-		final SlotRequestID slotRequestID3 = new SlotRequestID();
-		final TaskManagerLocation taskManagerLocation2 = new LocalTaskManagerLocation();
-		final ResourceID resource2 = taskManagerLocation2.getResourceID();
-		final AllocatedSlot slot3 = createSlot(allocation3, taskManagerLocation2);
-
-		allocatedSlots.add(slotRequestID3, slot3);
-
-		assertTrue(allocatedSlots.contains(slot1.getAllocationId()));
-		assertTrue(allocatedSlots.contains(slot2.getAllocationId()));
-		assertTrue(allocatedSlots.contains(slot3.getAllocationId()));
-		assertTrue(allocatedSlots.containResource(resource1));
-		assertTrue(allocatedSlots.containResource(resource2));
-
-		assertEquals(slot1, allocatedSlots.get(allocation1));
-		assertEquals(slot2, allocatedSlots.get(allocation2));
-		assertEquals(slot3, allocatedSlots.get(allocation3));
-		assertEquals(2, allocatedSlots.getSlotsForTaskManager(resource1).size());
-		assertEquals(1, allocatedSlots.getSlotsForTaskManager(resource2).size());
-		assertEquals(3, allocatedSlots.size());
-
-		allocatedSlots.remove(slot2.getAllocationId());
-
-		assertTrue(allocatedSlots.contains(slot1.getAllocationId()));
-		assertFalse(allocatedSlots.contains(slot2.getAllocationId()));
-		assertTrue(allocatedSlots.contains(slot3.getAllocationId()));
-		assertTrue(allocatedSlots.containResource(resource1));
-		assertTrue(allocatedSlots.containResource(resource2));
-
-		assertEquals(slot1, allocatedSlots.get(allocation1));
-		assertNull(allocatedSlots.get(allocation2));
-		assertEquals(slot3, allocatedSlots.get(allocation3));
-		assertEquals(1, allocatedSlots.getSlotsForTaskManager(resource1).size());
-		assertEquals(1, allocatedSlots.getSlotsForTaskManager(resource2).size());
-		assertEquals(2, allocatedSlots.size());
-
-		allocatedSlots.remove(slot1.getAllocationId());
-
-		assertFalse(allocatedSlots.contains(slot1.getAllocationId()));
-		assertFalse(allocatedSlots.contains(slot2.getAllocationId()));
-		assertTrue(allocatedSlots.contains(slot3.getAllocationId()));
-		assertFalse(allocatedSlots.containResource(resource1));
-		assertTrue(allocatedSlots.containResource(resource2));
-
-		assertNull(allocatedSlots.get(allocation1));
-		assertNull(allocatedSlots.get(allocation2));
-		assertEquals(slot3, allocatedSlots.get(allocation3));
-		assertEquals(0, allocatedSlots.getSlotsForTaskManager(resource1).size());
-		assertEquals(1, allocatedSlots.getSlotsForTaskManager(resource2).size());
-		assertEquals(1, allocatedSlots.size());
-
-		allocatedSlots.remove(slot3.getAllocationId());
-
-		assertFalse(allocatedSlots.contains(slot1.getAllocationId()));
-		assertFalse(allocatedSlots.contains(slot2.getAllocationId()));
-		assertFalse(allocatedSlots.contains(slot3.getAllocationId()));
-		assertFalse(allocatedSlots.containResource(resource1));
-		assertFalse(allocatedSlots.containResource(resource2));
-
-		assertNull(allocatedSlots.get(allocation1));
-		assertNull(allocatedSlots.get(allocation2));
-		assertNull(allocatedSlots.get(allocation3));
-		assertEquals(0, allocatedSlots.getSlotsForTaskManager(resource1).size());
-		assertEquals(0, allocatedSlots.getSlotsForTaskManager(resource2).size());
-		assertEquals(0, allocatedSlots.size());
-	}
-
-	private AllocatedSlot createSlot(final AllocationID allocationId, final TaskManagerLocation taskManagerLocation) {
-		return new AllocatedSlot(
-			allocationId,
-			taskManagerLocation,
-			0,
-			ResourceProfile.UNKNOWN,
-			new SimpleAckingTaskManagerGateway(),
-			new DummySlotOwner());
-	}
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/instance/AvailableSlotsTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/AvailableSlotsTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/AvailableSlotsTest.java
deleted file mode 100644
index 9ede899..0000000
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/AvailableSlotsTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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.instance;
-
-import org.apache.flink.runtime.clusterframework.types.AllocationID;
-import org.apache.flink.runtime.clusterframework.types.ResourceID;
-import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
-import org.apache.flink.runtime.jobmanager.slots.DummySlotOwner;
-import org.apache.flink.runtime.jobmanager.slots.SlotAndLocality;
-import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
-import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-import org.apache.flink.util.TestLogger;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class AvailableSlotsTest extends TestLogger {
-
-	static final ResourceProfile DEFAULT_TESTING_PROFILE = new ResourceProfile(1.0, 512);
-
-	static final ResourceProfile DEFAULT_TESTING_BIG_PROFILE = new ResourceProfile(2.0, 1024);
-
-	@Test
-	public void testAddAndRemove() throws Exception {
-		SlotPool.AvailableSlots availableSlots = new SlotPool.AvailableSlots();
-
-		final ResourceID resource1 = new ResourceID("resource1");
-		final ResourceID resource2 = new ResourceID("resource2");
-
-		final AllocatedSlot slot1 = createAllocatedSlot(resource1);
-		final AllocatedSlot slot2 = createAllocatedSlot(resource1);
-		final AllocatedSlot slot3 = createAllocatedSlot(resource2);
-
-		availableSlots.add(slot1, 1L);
-		availableSlots.add(slot2, 2L);
-		availableSlots.add(slot3, 3L);
-
-		assertEquals(3, availableSlots.size());
-		assertTrue(availableSlots.contains(slot1.getAllocationId()));
-		assertTrue(availableSlots.contains(slot2.getAllocationId()));
-		assertTrue(availableSlots.contains(slot3.getAllocationId()));
-		assertTrue(availableSlots.containsTaskManager(resource1));
-		assertTrue(availableSlots.containsTaskManager(resource2));
-
-		availableSlots.removeAllForTaskManager(resource1);
-
-		assertEquals(1, availableSlots.size());
-		assertFalse(availableSlots.contains(slot1.getAllocationId()));
-		assertFalse(availableSlots.contains(slot2.getAllocationId()));
-		assertTrue(availableSlots.contains(slot3.getAllocationId()));
-		assertFalse(availableSlots.containsTaskManager(resource1));
-		assertTrue(availableSlots.containsTaskManager(resource2));
-
-		availableSlots.removeAllForTaskManager(resource2);
-
-		assertEquals(0, availableSlots.size());
-		assertFalse(availableSlots.contains(slot1.getAllocationId()));
-		assertFalse(availableSlots.contains(slot2.getAllocationId()));
-		assertFalse(availableSlots.contains(slot3.getAllocationId()));
-		assertFalse(availableSlots.containsTaskManager(resource1));
-		assertFalse(availableSlots.containsTaskManager(resource2));
-	}
-
-	@Test
-	public void testPollFreeSlot() {
-		SlotPool.AvailableSlots availableSlots = new SlotPool.AvailableSlots();
-
-		final ResourceID resource1 = new ResourceID("resource1");
-		final AllocatedSlot slot1 = createAllocatedSlot(resource1);
-
-		availableSlots.add(slot1, 1L);
-
-		assertEquals(1, availableSlots.size());
-		assertTrue(availableSlots.contains(slot1.getAllocationId()));
-		assertTrue(availableSlots.containsTaskManager(resource1));
-
-		assertNull(availableSlots.poll(DEFAULT_TESTING_BIG_PROFILE, null));
-
-		SlotAndLocality slotAndLocality = availableSlots.poll(DEFAULT_TESTING_PROFILE, null);
-		assertEquals(slot1, slotAndLocality.slot());
-		assertEquals(0, availableSlots.size());
-		assertFalse(availableSlots.contains(slot1.getAllocationId()));
-		assertFalse(availableSlots.containsTaskManager(resource1));
-	}
-
-	static AllocatedSlot createAllocatedSlot(final ResourceID resourceId) {
-		TaskManagerLocation mockTaskManagerLocation = mock(TaskManagerLocation.class);
-		when(mockTaskManagerLocation.getResourceID()).thenReturn(resourceId);
-
-		TaskManagerGateway mockTaskManagerGateway = mock(TaskManagerGateway.class);
-
-		return new AllocatedSlot(
-			new AllocationID(),
-			mockTaskManagerLocation,
-			0,
-			DEFAULT_TESTING_PROFILE,
-			mockTaskManagerGateway,
-			new DummySlotOwner());
-	}
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/instance/InstanceTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/InstanceTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/InstanceTest.java
index 229237d..6d7d1ae 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/InstanceTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/InstanceTest.java
@@ -84,10 +84,10 @@ public class InstanceTest {
 			}
 
 			// release the slots. this returns them to the instance
-			slot1.releaseInstanceSlot();
-			slot2.releaseInstanceSlot();
-			slot3.releaseInstanceSlot();
-			slot4.releaseInstanceSlot();
+			slot1.releaseSlot();
+			slot2.releaseSlot();
+			slot3.releaseSlot();
+			slot4.releaseSlot();
 
 			assertEquals(4, instance.getNumberOfAvailableSlots());
 			assertEquals(0, instance.getNumberOfAllocatedSlots());

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SharedSlotsTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SharedSlotsTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SharedSlotsTest.java
index 5104e48..860100a 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SharedSlotsTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SharedSlotsTest.java
@@ -83,7 +83,7 @@ public class SharedSlotsTest extends TestLogger {
 			assertEquals(0, slot.getRootSlotNumber());
 			
 			// release the slot immediately.
-			slot.releaseInstanceSlot();
+			slot.releaseSlot();
 
 			assertTrue(slot.isCanceled());
 			assertTrue(slot.isReleased());
@@ -202,7 +202,7 @@ public class SharedSlotsTest extends TestLogger {
 			assertEquals(0, assignment.getNumberOfAvailableSlotsForGroup(vid4));
 			
 			// release from the root.
-			sharedSlot.releaseInstanceSlot();
+			sharedSlot.releaseSlot();
 
 			assertTrue(sharedSlot.isReleased());
 			assertTrue(sub1.isReleased());
@@ -261,7 +261,7 @@ public class SharedSlotsTest extends TestLogger {
 			
 			// release from the leaves.
 			
-			sub2.releaseInstanceSlot();
+			sub2.releaseSlot();
 
 			assertTrue(sharedSlot.isAlive());
 			assertTrue(sub1.isAlive());
@@ -276,7 +276,7 @@ public class SharedSlotsTest extends TestLogger {
 			assertEquals(2, sharedSlot.getNumberLeaves());
 
 			
-			sub1.releaseInstanceSlot();
+			sub1.releaseSlot();
 
 			assertTrue(sharedSlot.isAlive());
 			assertTrue(sub1.isReleased());
@@ -290,7 +290,7 @@ public class SharedSlotsTest extends TestLogger {
 			
 			assertEquals(1, sharedSlot.getNumberLeaves());
 
-			sub3.releaseInstanceSlot();
+			sub3.releaseSlot();
 
 			assertTrue(sharedSlot.isReleased());
 			assertTrue(sub1.isReleased());
@@ -344,7 +344,7 @@ public class SharedSlotsTest extends TestLogger {
 			assertEquals(1, assignment.getNumberOfSlots());
 			
 			
-			sub2.releaseInstanceSlot();
+			sub2.releaseSlot();
 
 			assertEquals(1, sharedSlot.getNumberLeaves());
 			assertEquals(0, assignment.getNumberOfAvailableSlotsForGroup(vid1));
@@ -362,8 +362,8 @@ public class SharedSlotsTest extends TestLogger {
 			assertEquals(0, assignment.getNumberOfAvailableSlotsForGroup(vid3));
 			assertEquals(1, assignment.getNumberOfSlots());
 			
-			sub3.releaseInstanceSlot();
-			sub1.releaseInstanceSlot();
+			sub3.releaseSlot();
+			sub1.releaseSlot();
 
 			assertTrue(sharedSlot.isReleased());
 			assertEquals(0, sharedSlot.getNumberLeaves());
@@ -439,7 +439,7 @@ public class SharedSlotsTest extends TestLogger {
 			assertFalse(constraint.isAssigned());
 			
 			// we do not immediately lock the location
-			headSlot.releaseInstanceSlot();
+			headSlot.releaseSlot();
 			assertEquals(1, sharedSlot.getNumberLeaves());
 
 			assertNotNull(constraint.getSharedSlot());
@@ -464,8 +464,8 @@ public class SharedSlotsTest extends TestLogger {
 			assertEquals(4, sharedSlot.getNumberLeaves());
 			
 			// we release our co-location constraint tasks
-			headSlot.releaseInstanceSlot();
-			tailSlot.releaseInstanceSlot();
+			headSlot.releaseSlot();
+			tailSlot.releaseSlot();
 
 			assertEquals(2, sharedSlot.getNumberLeaves());
 			assertTrue(headSlot.isReleased());
@@ -497,10 +497,10 @@ public class SharedSlotsTest extends TestLogger {
 			assertEquals(constraint.getGroupId(), constraint.getSharedSlot().getGroupID());
 			
 			// release all
-			sourceSlot.releaseInstanceSlot();
-			headSlot.releaseInstanceSlot();
-			tailSlot.releaseInstanceSlot();
-			sinkSlot.releaseInstanceSlot();
+			sourceSlot.releaseSlot();
+			headSlot.releaseSlot();
+			tailSlot.releaseSlot();
+			sinkSlot.releaseSlot();
 			
 			assertTrue(sharedSlot.isReleased());
 			assertTrue(sourceSlot.isReleased());
@@ -573,10 +573,10 @@ public class SharedSlotsTest extends TestLogger {
 			assertEquals(4, sharedSlot.getNumberLeaves());
 
 			// release all
-			sourceSlot.releaseInstanceSlot();
-			headSlot.releaseInstanceSlot();
-			tailSlot.releaseInstanceSlot();
-			sinkSlot.releaseInstanceSlot();
+			sourceSlot.releaseSlot();
+			headSlot.releaseSlot();
+			tailSlot.releaseSlot();
+			sinkSlot.releaseSlot();
 
 			assertTrue(sharedSlot.isReleased());
 			assertTrue(sourceSlot.isReleased());
@@ -613,7 +613,7 @@ public class SharedSlotsTest extends TestLogger {
 			SharedSlot sharedSlot = instance.allocateSharedSlot(assignment);
 
 			SimpleSlot sub = assignment.addSharedSlotAndAllocateSubSlot(sharedSlot, Locality.UNCONSTRAINED, vid);
-			sub.releaseInstanceSlot();
+			sub.releaseSlot();
 			
 			assertTrue(sub.isReleased());
 			assertTrue(sharedSlot.isReleased());
@@ -648,7 +648,7 @@ public class SharedSlotsTest extends TestLogger {
 			assertNull(sub.getGroupID());
 			assertEquals(constraint.getSharedSlot(), sub.getParent());
 			
-			sub.releaseInstanceSlot();
+			sub.releaseSlot();
 
 			assertTrue(sub.isReleased());
 			assertTrue(sharedSlot.isReleased());

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SimpleSlotTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SimpleSlotTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SimpleSlotTest.java
index 6d572ad..de2ae41 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SimpleSlotTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/instance/SimpleSlotTest.java
@@ -20,6 +20,7 @@ package org.apache.flink.runtime.instance;
 
 import org.apache.flink.runtime.clusterframework.types.ResourceID;
 import org.apache.flink.runtime.jobmanager.slots.ActorTaskManagerGateway;
+import org.apache.flink.runtime.jobmaster.TestingPayload;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 import org.apache.flink.util.TestLogger;
 
@@ -43,7 +44,7 @@ public class SimpleSlotTest extends  TestLogger {
 				SimpleSlot slot = getSlot();
 				assertTrue(slot.isAlive());
 
-				slot.releaseInstanceSlot();
+				slot.releaseSlot();
 				assertFalse(slot.isAlive());
 				assertTrue(slot.isCanceled());
 				assertTrue(slot.isReleased());
@@ -111,7 +112,7 @@ public class SimpleSlotTest extends  TestLogger {
 			// assign to released
 			{
 				SimpleSlot slot = getSlot();
-				slot.releaseInstanceSlot();
+				slot.releaseSlot();
 
 				assertFalse(slot.tryAssignPayload(payload1));
 				assertNull(slot.getPayload());


[04/11] flink git commit: [FLINK-7956] [flip6] Add support for queued scheduling with slot sharing to SlotPool

Posted by tr...@apache.org.
http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerSlotSharingTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerSlotSharingTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerSlotSharingTest.java
index 41a7f02..025c795 100644
--- a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerSlotSharingTest.java
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerSlotSharingTest.java
@@ -18,14 +18,15 @@
 
 package org.apache.flink.runtime.jobmanager.scheduler;
 
-import org.apache.flink.runtime.instance.Instance;
-import org.apache.flink.runtime.instance.LogicalSlot;
+import org.apache.flink.runtime.clusterframework.types.ResourceID;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 import org.apache.flink.runtime.testingUtils.TestingUtils;
-import org.apache.flink.util.TestLogger;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 import java.util.Collections;
 import java.util.Random;
@@ -49,7 +50,12 @@ import static org.junit.Assert.fail;
 /**
  * Tests for the scheduler when scheduling tasks in slot sharing groups.
  */
-public class SchedulerSlotSharingTest extends TestLogger {
+@RunWith(Parameterized.class)
+public class SchedulerSlotSharingTest extends SchedulerTestBase {
+
+	public SchedulerSlotSharingTest(SchedulerType schedulerType) {
+		super(schedulerType);
+	}
 
 	@Test
 	public void scheduleSingleVertexType() {
@@ -57,18 +63,15 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			JobVertexID jid1 = new JobVertexID();
 			
 			SlotSharingGroup sharingGroup = new SlotSharingGroup(jid1);
-			
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-			Instance i1 = getRandomInstance(2);
-			Instance i2 = getRandomInstance(2);
-			scheduler.newInstanceAvailable(i1);
-			scheduler.newInstanceAvailable(i2);
+
+			final ResourceID tm1ResourceId = testingSlotProvider.addTaskManager(2).getResourceID();
+			testingSlotProvider.addTaskManager(2);
 			
 			// schedule 4 tasks from the first vertex group
-			LogicalSlot s1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 8), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 8), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 8), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 8), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 8, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 8, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 8, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s4 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 8, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
 			assertNotNull(s1);
 			assertNotNull(s2);
@@ -79,7 +82,7 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			
 			// we cannot schedule another task from the first vertex group
 			try {
-				scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 4, 8), sharingGroup), false, Collections.emptyList()).get();
+				testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 4, 8, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 				fail("Scheduler accepted too many tasks at the same time");
 			}
 			catch (ExecutionException e) {
@@ -93,7 +96,7 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			s3.releaseSlot();
 			
 			// allocate another slot from that group
-			LogicalSlot s5 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 4, 8), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s5 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 4, 8, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			assertNotNull(s5);
 			
 			// release all old slots
@@ -101,9 +104,9 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			s2.releaseSlot();
 			s4.releaseSlot();
 			
-			LogicalSlot s6 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 5, 8), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s7 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 6, 8), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s8 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 7, 8), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s6 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 5, 8, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s7 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 6, 8, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s8 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 7, 8, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
 			assertNotNull(s6);
 			assertNotNull(s7);
@@ -111,10 +114,10 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			
 			// make sure we have two slots on the first instance, and two on the second
 			int c = 0;
-			c += (s5.getTaskManagerLocation().equals(i1.getTaskManagerLocation())) ? 1 : -1;
-			c += (s6.getTaskManagerLocation().equals(i1.getTaskManagerLocation())) ? 1 : -1;
-			c += (s7.getTaskManagerLocation().equals(i1.getTaskManagerLocation())) ? 1 : -1;
-			c += (s8.getTaskManagerLocation().equals(i1.getTaskManagerLocation())) ? 1 : -1;
+			c += (s5.getTaskManagerLocation().getResourceID().equals(tm1ResourceId)) ? 1 : -1;
+			c += (s6.getTaskManagerLocation().getResourceID().equals(tm1ResourceId)) ? 1 : -1;
+			c += (s7.getTaskManagerLocation().getResourceID().equals(tm1ResourceId)) ? 1 : -1;
+			c += (s8.getTaskManagerLocation().getResourceID().equals(tm1ResourceId)) ? 1 : -1;
 			assertEquals(0, c);
 			
 			// release all
@@ -124,12 +127,12 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			s8.releaseSlot();
 			
 			// test that everything is released
-			assertEquals(4, scheduler.getNumberOfAvailableSlots());
+			assertEquals(4, testingSlotProvider.getNumberOfAvailableSlots());
 
 			// check the scheduler's bookkeeping
-			assertEquals(0, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(8, scheduler.getNumberOfUnconstrainedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfLocalizedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+			assertEquals(8, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 		}
 		catch (Exception e) {
 			e.printStackTrace();
@@ -138,123 +141,116 @@ public class SchedulerSlotSharingTest extends TestLogger {
 	}
 	
 	@Test
-	public void allocateSlotWithSharing() {
+	public void allocateSlotWithSharing() throws Exception {
+		JobVertexID jid1 = new JobVertexID();
+		JobVertexID jid2 = new JobVertexID();
+
+		SlotSharingGroup sharingGroup = new SlotSharingGroup(jid1, jid2);
+
+		testingSlotProvider.addTaskManager(2);
+		testingSlotProvider.addTaskManager(2);
+
+		// schedule 4 tasks from the first vertex group
+		LogicalSlot s1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		LogicalSlot s2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		LogicalSlot s3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		LogicalSlot s4 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+
+		assertNotNull(s1);
+		assertNotNull(s2);
+		assertNotNull(s3);
+		assertNotNull(s4);
+
+		assertTrue(areAllDistinct(s1, s2, s3, s4));
+
+		// we cannot schedule another task from the first vertex group
 		try {
-			JobVertexID jid1 = new JobVertexID();
-			JobVertexID jid2 = new JobVertexID();
-			
-			SlotSharingGroup sharingGroup = new SlotSharingGroup(jid1, jid2);
-			
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-			
-			// schedule 4 tasks from the first vertex group
-			LogicalSlot s1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 5), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 5), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 5), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 5), sharingGroup), false, Collections.emptyList()).get();
-			
-			assertNotNull(s1);
-			assertNotNull(s2);
-			assertNotNull(s3);
-			assertNotNull(s4);
-			
-			assertTrue(areAllDistinct(s1, s2, s3, s4));
-			
-			// we cannot schedule another task from the first vertex group
-			try {
-				scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 4, 5), sharingGroup), false, Collections.emptyList()).get();
-				fail("Scheduler accepted too many tasks at the same time");
-			}
-			catch (ExecutionException e) {
-				assertTrue(e.getCause() instanceof NoResourceAvailableException);
-			}
-			catch (Exception e) {
-				fail("Wrong exception.");
-			}
-			
-			// schedule some tasks from the second ID group
-			LogicalSlot s1_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 5), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 5), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s3_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 5), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 3, 5), sharingGroup), false, Collections.emptyList()).get();
-			
-			assertNotNull(s1_2);
-			assertNotNull(s2_2);
-			assertNotNull(s3_2);
-			assertNotNull(s4_2);
-			
-			// we cannot schedule another task from the second vertex group
-			try {
-				scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 4, 5), sharingGroup), false, Collections.emptyList()).get();
-				fail("Scheduler accepted too many tasks at the same time");
-			}
-			catch (ExecutionException e) {
-				assertTrue(e.getCause() instanceof NoResourceAvailableException);
-			}
-			catch (Exception e) {
-				fail("Wrong exception.");
-			}
-			
-			// now, we release some vertices (sub-slots) from the first group.
-			// that should allow us to schedule more vertices from the first group
-			s1.releaseSlot();
-			s4.releaseSlot();
-			
-			assertEquals(4, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(2, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid1));
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid2));
-			
-			// we can still not schedule anything from the second group of vertices
-			try {
-				scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 4, 5), sharingGroup), false, Collections.emptyList()).get();
-				fail("Scheduler accepted too many tasks at the same time");
-			}
-			catch (ExecutionException e) {
-				assertTrue(e.getCause() instanceof NoResourceAvailableException);
-			}
-			catch (Exception e) {
-				fail("Wrong exception.");
-			}
-			
-			// we can schedule something from the first vertex group
-			LogicalSlot s5 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 4, 5), sharingGroup), false, Collections.emptyList()).get();
-			assertNotNull(s5);
-			
-			assertEquals(4, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(1, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid1));
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid2));
-			
-			
-			// now we release a slot from the second vertex group and schedule another task from that group
-			s2_2.releaseSlot();
-			LogicalSlot s5_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 4, 5), sharingGroup), false, Collections.emptyList()).get();
-			assertNotNull(s5_2);
-			
-			// release all slots
-			s2.releaseSlot();
-			s3.releaseSlot();
-			s5.releaseSlot();
-			
-			s1_2.releaseSlot();
-			s3_2.releaseSlot();
-			s4_2.releaseSlot();
-			s5_2.releaseSlot();
-			
-			// test that everything is released
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(4, scheduler.getNumberOfAvailableSlots());
-			
-			// check the scheduler's bookkeeping
-			assertEquals(0, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(10, scheduler.getNumberOfUnconstrainedAssignments());
+			testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 4, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			fail("Scheduler accepted too many tasks at the same time");
+		}
+		catch (ExecutionException e) {
+			assertTrue(e.getCause() instanceof NoResourceAvailableException);
 		}
 		catch (Exception e) {
-			e.printStackTrace();
-			fail(e.getMessage());
+			fail("Wrong exception.");
+		}
+
+		// schedule some tasks from the second ID group
+		LogicalSlot s1_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		LogicalSlot s2_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		LogicalSlot s3_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		LogicalSlot s4_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 3, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+
+		assertNotNull(s1_2);
+		assertNotNull(s2_2);
+		assertNotNull(s3_2);
+		assertNotNull(s4_2);
+
+		// we cannot schedule another task from the second vertex group
+		try {
+			testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 4, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			fail("Scheduler accepted too many tasks at the same time");
+		}
+		catch (ExecutionException e) {
+			assertTrue(e.getCause() instanceof NoResourceAvailableException);
+		}
+		catch (Exception e) {
+			fail("Wrong exception.");
+		}
+
+		// now, we release some vertices (sub-slots) from the first group.
+		// that should allow us to schedule more vertices from the first group
+		s1.releaseSlot();
+		s4.releaseSlot();
+
+		assertEquals(4, testingSlotProvider.getNumberOfSlots(sharingGroup));
+		assertEquals(2, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid1));
+		assertEquals(0, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid2));
+
+		// we can still not schedule anything from the second group of vertices
+		try {
+			testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 4, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			fail("Scheduler accepted too many tasks at the same time");
 		}
+		catch (ExecutionException e) {
+			assertTrue(e.getCause() instanceof NoResourceAvailableException);
+		}
+		catch (Exception e) {
+			fail("Wrong exception.");
+		}
+
+		// we can schedule something from the first vertex group
+		LogicalSlot s5 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 4, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		assertNotNull(s5);
+
+		assertEquals(4, testingSlotProvider.getNumberOfSlots(sharingGroup));
+		assertEquals(1, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid1));
+		assertEquals(0, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid2));
+
+
+		// now we release a slot from the second vertex group and schedule another task from that group
+		s2_2.releaseSlot();
+		LogicalSlot s5_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 4, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+		assertNotNull(s5_2);
+
+		// release all slots
+		s2.releaseSlot();
+		s3.releaseSlot();
+		s5.releaseSlot();
+
+		s1_2.releaseSlot();
+		s3_2.releaseSlot();
+		s4_2.releaseSlot();
+		s5_2.releaseSlot();
+
+		// test that everything is released
+		assertEquals(0, testingSlotProvider.getNumberOfSlots(sharingGroup));
+		assertEquals(4, testingSlotProvider.getNumberOfAvailableSlots());
+
+		// check the scheduler's bookkeeping
+		assertEquals(0, testingSlotProvider.getNumberOfLocalizedAssignments());
+		assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+		assertEquals(10, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 	}
 	
 	@Test
@@ -264,56 +260,55 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			JobVertexID jid2 = new JobVertexID();
 			
 			SlotSharingGroup sharingGroup = new SlotSharingGroup(jid1, jid2);
-			
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-			
+
+			testingSlotProvider.addTaskManager(2);
+			testingSlotProvider.addTaskManager(2);
+
 			// schedule 4 tasks from the first vertex group
-			LogicalSlot s1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s4 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
-			assertEquals(4, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid1));
-			assertEquals(4, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid2));
+			assertEquals(4, testingSlotProvider.getNumberOfSlots(sharingGroup));
+			assertEquals(0, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid1));
+			assertEquals(4, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid2));
 			
 			s1.releaseSlot();
 			s2.releaseSlot();
 			s3.releaseSlot();
 			s4.releaseSlot();
 			
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid1));
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid2));
+			assertEquals(0, testingSlotProvider.getNumberOfSlots(sharingGroup));
+			assertEquals(0, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid1));
+			assertEquals(0, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid2));
 			
 			// schedule some tasks from the second ID group
-			LogicalSlot s1_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s3_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 3, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s1_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s3_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s4_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 3, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 
-			assertEquals(4, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(4, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid1));
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid2));
+			assertEquals(4, testingSlotProvider.getNumberOfSlots(sharingGroup));
+			assertEquals(4, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid1));
+			assertEquals(0, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid2));
 			
 			s1_2.releaseSlot();
 			s2_2.releaseSlot();
 			s3_2.releaseSlot();
 			s4_2.releaseSlot();
 			
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid1));
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid2));
+			assertEquals(0, testingSlotProvider.getNumberOfSlots(sharingGroup));
+			assertEquals(0, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid1));
+			assertEquals(0, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid2));
 
 			// test that everything is released
-			assertEquals(4, scheduler.getNumberOfAvailableSlots());
+			assertEquals(4, testingSlotProvider.getNumberOfAvailableSlots());
 			
 			// check the scheduler's bookkeeping
-			assertEquals(0, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(8, scheduler.getNumberOfUnconstrainedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfLocalizedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+			assertEquals(8, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 		}
 		catch (Exception e) {
 			e.printStackTrace();
@@ -329,16 +324,15 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			JobVertexID jid3 = new JobVertexID();
 			
 			SlotSharingGroup sharingGroup = new SlotSharingGroup(jid1, jid2, jid3);
-			
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-			
+
+			testingSlotProvider.addTaskManager(2);
+			testingSlotProvider.addTaskManager(2);
+
 			// schedule 4 tasks from the first vertex group
-			LogicalSlot s1_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s3_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s1_1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2_1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s3_1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s4_1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
 			assertNotNull(s1_1);
 			assertNotNull(s2_1);
@@ -348,10 +342,10 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			assertTrue(areAllDistinct(s1_1, s2_1, s3_1, s4_1));
 			
 			// schedule 4 tasks from the second vertex group
-			LogicalSlot s1_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 7), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 7), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s3_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 7), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 3, 7), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s1_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 7, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 7, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s3_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 7, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s4_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 3, 7, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
 			assertNotNull(s1_2);
 			assertNotNull(s2_2);
@@ -361,10 +355,10 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			assertTrue(areAllDistinct(s1_2, s2_2, s3_2, s4_2));
 			
 			// schedule 4 tasks from the third vertex group
-			LogicalSlot s1_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 0, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 1, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s3_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 2, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 3, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s1_3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 0, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2_3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 1, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s3_3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 2, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s4_3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 3, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
 			assertNotNull(s1_3);
 			assertNotNull(s2_3);
@@ -376,7 +370,7 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			
 			// we cannot schedule another task from the second vertex group
 			try {
-				scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 4, 5), sharingGroup), false, Collections.emptyList()).get();
+				testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 4, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 				fail("Scheduler accepted too many tasks at the same time");
 			}
 			catch (ExecutionException e) {
@@ -392,9 +386,9 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			s3_2.releaseSlot();
 			s4_2.releaseSlot();
 			
-			LogicalSlot s5_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 5, 7), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s6_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 6, 7), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s7_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 7, 7), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s5_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 5, 7, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s6_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 6, 7, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s7_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 7, 7, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
 			assertNotNull(s5_2);
 			assertNotNull(s6_2);
@@ -411,7 +405,7 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			s7_2.releaseSlot();
 			
 			// test that everything is released
-			assertEquals(0, scheduler.getNumberOfAvailableSlots());
+			assertEquals(0, testingSlotProvider.getNumberOfAvailableSlots());
 			
 			s1_3.releaseSlot();
 			s2_3.releaseSlot();
@@ -419,12 +413,12 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			s4_3.releaseSlot();
 			
 			// test that everything is released
-			assertEquals(4, scheduler.getNumberOfAvailableSlots());
+			assertEquals(4, testingSlotProvider.getNumberOfAvailableSlots());
 			
 			// check the scheduler's bookkeeping
-			assertEquals(0, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(15, scheduler.getNumberOfUnconstrainedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfLocalizedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+			assertEquals(15, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 		}
 		catch (Exception e) {
 			e.printStackTrace();
@@ -440,22 +434,21 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			JobVertexID jid3 = new JobVertexID();
 			
 			SlotSharingGroup sharingGroup = new SlotSharingGroup(jid1, jid2);
-			
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-			
+
+			testingSlotProvider.addTaskManager(2);
+
 			// schedule 1 tasks from the first vertex group and 2 from the second
-			LogicalSlot s1_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 2), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 2), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 2), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s1_1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 2, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2_1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 2, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 2, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
 			assertNotNull(s1_1);
 			assertNotNull(s2_1);
 			assertNotNull(s2_2);
 			
-			assertEquals(2, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(1, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid1));
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid2));
+			assertEquals(2, testingSlotProvider.getNumberOfSlots(sharingGroup));
+			assertEquals(1, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid1));
+			assertEquals(0, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid2));
 			
 			// release the two from the second
 			s2_1.releaseSlot();
@@ -463,17 +456,17 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			
 			
 			// this should free one slot so we can allocate one non-shared
-			LogicalSlot sx = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 0, 1)), false, Collections.emptyList()).get();
+			LogicalSlot sx = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 0, 1, null)), false, Collections.emptyList()).get();
 			assertNotNull(sx);
 			
-			assertEquals(1, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(0, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid1));
-			assertEquals(1, sharingGroup.getTaskAssignment().getNumberOfAvailableSlotsForGroup(jid2));
+			assertEquals(1, testingSlotProvider.getNumberOfSlots(sharingGroup));
+			assertEquals(0, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid1));
+			assertEquals(1, testingSlotProvider.getNumberOfAvailableSlotsForGroup(sharingGroup, jid2));
 			
 			// check the scheduler's bookkeeping
-			assertEquals(0, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(4, scheduler.getNumberOfUnconstrainedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfLocalizedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+			assertEquals(4, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 		}
 		catch (Exception e) {
 			e.printStackTrace();
@@ -492,34 +485,33 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			JobVertexID jidC = new JobVertexID();
 			
 			SlotSharingGroup sharingGroup = new SlotSharingGroup(jid1, jid2);
-			
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-			scheduler.newInstanceAvailable(getRandomInstance(3));
-			scheduler.newInstanceAvailable(getRandomInstance(2));
-			
+
+			testingSlotProvider.addTaskManager(3);
+			testingSlotProvider.addTaskManager(2);
+
 			// schedule some individual vertices
-			LogicalSlot sA1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jidA, 0, 2)), false, Collections.emptyList()).get();
-			LogicalSlot sA2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jidA, 1, 2)), false, Collections.emptyList()).get();
+			LogicalSlot sA2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jidA, 1, 2, null)), false, Collections.emptyList()).get();
+			LogicalSlot sA1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jidA, 0, 2, null)), false, Collections.emptyList()).get();
 			assertNotNull(sA1);
 			assertNotNull(sA2);
 			
 			// schedule some vertices in the sharing group
-			LogicalSlot s1_0 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s1_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2_0 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s1_0 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s1_1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2_0 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2_1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			assertNotNull(s1_0);
 			assertNotNull(s1_1);
 			assertNotNull(s2_0);
 			assertNotNull(s2_1);
 			
 			// schedule another isolated vertex
-			LogicalSlot sB1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jidB, 1, 3)), false, Collections.emptyList()).get();
+			LogicalSlot sB1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jidB, 1, 3, null)), false, Collections.emptyList()).get();
 			assertNotNull(sB1);
 			
 			// should not be able to schedule more vertices
 			try {
-				scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 4), sharingGroup), false, Collections.emptyList()).get();
+				testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 				fail("Scheduler accepted too many tasks at the same time");
 			}
 			catch (ExecutionException e) {
@@ -530,7 +522,7 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			}
 			
 			try {
-				scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 4), sharingGroup), false, Collections.emptyList()).get();
+				testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 				fail("Scheduler accepted too many tasks at the same time");
 			}
 			catch (ExecutionException e) {
@@ -541,7 +533,7 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			}
 			
 			try {
-				scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jidB, 0, 3)), false, Collections.emptyList()).get();
+				testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jidB, 0, 3, null)), false, Collections.emptyList()).get();
 				fail("Scheduler accepted too many tasks at the same time");
 			}
 			catch (ExecutionException e) {
@@ -552,7 +544,7 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			}
 			
 			try {
-				scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jidC, 0, 1)), false, Collections.emptyList()).get();
+				testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jidC, 0, 1, null)), false, Collections.emptyList()).get();
 				fail("Scheduler accepted too many tasks at the same time");
 			}
 			catch (ExecutionException e) {
@@ -565,8 +557,8 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			// release some isolated task and check that the sharing group may grow
 			sA1.releaseSlot();
 			
-			LogicalSlot s1_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 3, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s1_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 3, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			assertNotNull(s1_2);
 			assertNotNull(s2_2);
 			
@@ -575,22 +567,22 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			s1_1.releaseSlot();
 			s2_0.releaseSlot();
 			
-			assertEquals(1, scheduler.getNumberOfAvailableSlots());
+			assertEquals(1, testingSlotProvider.getNumberOfAvailableSlots());
 			
 			// schedule one more no-shared task
-			LogicalSlot sB0 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jidB, 0, 3)), false, Collections.emptyList()).get();
+			LogicalSlot sB0 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jidB, 0, 3, null)), false, Collections.emptyList()).get();
 			assertNotNull(sB0);
 			
 			// release the last of the original shared slots and allocate one more non-shared slot
 			s2_1.releaseSlot();
-			LogicalSlot sB2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jidB, 2, 3)), false, Collections.emptyList()).get();
+			LogicalSlot sB2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jidB, 2, 3, null)), false, Collections.emptyList()).get();
 			assertNotNull(sB2);
 			
 			
 			// release on non-shared and add some shared slots
 			sA2.releaseSlot();
-			LogicalSlot s1_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s1_3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2_3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			assertNotNull(s1_3);
 			assertNotNull(s2_3);
 			
@@ -600,8 +592,8 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			s1_3.releaseSlot();
 			s2_3.releaseSlot();
 			
-			LogicalSlot sC0 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jidC, 1, 2)), false, Collections.emptyList()).get();
-			LogicalSlot sC1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jidC, 0, 2)), false, Collections.emptyList()).get();
+			LogicalSlot sC0 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jidC, 1, 2, null)), false, Collections.emptyList()).get();
+			LogicalSlot sC1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jidC, 0, 2, null)), false, Collections.emptyList()).get();
 			assertNotNull(sC0);
 			assertNotNull(sC1);
 			
@@ -613,12 +605,12 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			sC1.releaseSlot();
 			
 			// test that everything is released
-			assertEquals(5, scheduler.getNumberOfAvailableSlots());
+			assertEquals(5, testingSlotProvider.getNumberOfAvailableSlots());
 			
 			// check the scheduler's bookkeeping
-			assertEquals(0, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(15, scheduler.getNumberOfUnconstrainedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfLocalizedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+			assertEquals(15, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 		}
 		catch (Exception e) {
 			e.printStackTrace();
@@ -637,41 +629,34 @@ public class SchedulerSlotSharingTest extends TestLogger {
 
 			SlotSharingGroup sharingGroup = new SlotSharingGroup(jid1, jid2);
 
-			Instance i1 = getRandomInstance(2);
-			Instance i2 = getRandomInstance(2);
-
-			TaskManagerLocation loc1 = i1.getTaskManagerLocation();
-			TaskManagerLocation loc2 = i2.getTaskManagerLocation();
-
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-			scheduler.newInstanceAvailable(i1);
-			scheduler.newInstanceAvailable(i2);
-			
+			TaskManagerLocation loc1 = testingSlotProvider.addTaskManager(2);
+			TaskManagerLocation loc2 = testingSlotProvider.addTaskManager(2);
 			
 			// schedule one to each instance
-			LogicalSlot s1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, loc1), sharingGroup), false, Collections.singleton(loc1)).get();
-			LogicalSlot s2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, loc2), sharingGroup), false, Collections.singleton(loc2)).get();
+			LogicalSlot s1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
+			LogicalSlot s2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, sharingGroup, loc2), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc2)).get();
 			assertNotNull(s1);
 			assertNotNull(s2);
 			
-			assertEquals(2, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(1, i1.getNumberOfAvailableSlots());
-			assertEquals(1, i2.getNumberOfAvailableSlots());
+			assertEquals(2, testingSlotProvider.getNumberOfSlots(sharingGroup));
+			assertEquals(loc1, s1.getTaskManagerLocation());
+			assertEquals(loc2, s2.getTaskManagerLocation());
 			
 			// schedule one from the other group to each instance
-			LogicalSlot s3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, loc1), sharingGroup), false, Collections.singleton(loc1)).get();
-			LogicalSlot s4 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 2, loc2), sharingGroup), false, Collections.singleton(loc2)).get();
+			LogicalSlot s3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
+			LogicalSlot s4 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 2, sharingGroup, loc2), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc2)).get();
 			assertNotNull(s3);
 			assertNotNull(s4);
 			
-			assertEquals(2, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(1, i1.getNumberOfAvailableSlots());
-			assertEquals(1, i2.getNumberOfAvailableSlots());
+			assertEquals(2, testingSlotProvider.getNumberOfSlots(sharingGroup));
+			assertEquals(loc1, s3.getTaskManagerLocation());
+			assertEquals(loc2, s4.getTaskManagerLocation());
+			assertEquals(2, testingSlotProvider.getNumberOfAvailableSlots());
 			
 			// check the scheduler's bookkeeping
-			assertEquals(4, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfUnconstrainedAssignments());
+			assertEquals(4, testingSlotProvider.getNumberOfLocalizedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 		}
 		catch (Exception e) {
 			e.printStackTrace();
@@ -690,41 +675,33 @@ public class SchedulerSlotSharingTest extends TestLogger {
 
 			SlotSharingGroup sharingGroup = new SlotSharingGroup(jid1, jid2);
 
-			Instance i1 = getRandomInstance(2);
-			Instance i2 = getRandomInstance(2);
-
-			TaskManagerLocation loc1 = i1.getTaskManagerLocation();
-			TaskManagerLocation loc2 = i2.getTaskManagerLocation();
+			TaskManagerLocation loc1 = testingSlotProvider.addTaskManager(2);
+			TaskManagerLocation loc2 = testingSlotProvider.addTaskManager(2);
 
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-			scheduler.newInstanceAvailable(i1);
-			scheduler.newInstanceAvailable(i2);
-			
-			
 			// schedule one to each instance
-			LogicalSlot s1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, loc1), sharingGroup), false, Collections.singleton(loc1)).get();
-			LogicalSlot s2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, loc1), sharingGroup), false, Collections.singleton(loc1)).get();
+			LogicalSlot s1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
+			LogicalSlot s2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
 			assertNotNull(s1);
 			assertNotNull(s2);
 			
-			assertEquals(2, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(0, i1.getNumberOfAvailableSlots());
-			assertEquals(2, i2.getNumberOfAvailableSlots());
+			assertEquals(2, testingSlotProvider.getNumberOfSlots(sharingGroup));
+			assertEquals(loc1, s1.getTaskManagerLocation());
+			assertEquals(loc1, s2.getTaskManagerLocation());
 			
 			// schedule one from the other group to each instance
-			LogicalSlot s3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, loc2), sharingGroup), false, Collections.singleton(loc2)).get();
-			LogicalSlot s4 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 2, loc2), sharingGroup), false, Collections.singleton(loc2)).get();
+			LogicalSlot s3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 2, sharingGroup, loc2), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc2)).get();
+			LogicalSlot s4 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 2, sharingGroup, loc2), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc2)).get();
 			assertNotNull(s3);
 			assertNotNull(s4);
 			
-			assertEquals(4, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			assertEquals(0, i1.getNumberOfAvailableSlots());
-			assertEquals(0, i2.getNumberOfAvailableSlots());
+			assertEquals(4, testingSlotProvider.getNumberOfSlots(sharingGroup));
+			assertEquals(loc2, s3.getTaskManagerLocation());
+			assertEquals(loc2, s4.getTaskManagerLocation());
 			
 			// check the scheduler's bookkeeping
-			assertEquals(4, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfUnconstrainedAssignments());
+			assertEquals(4, testingSlotProvider.getNumberOfLocalizedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfNonLocalizedAssignments());
+			assertEquals(0, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 		}
 		catch (Exception e) {
 			e.printStackTrace();
@@ -743,24 +720,18 @@ public class SchedulerSlotSharingTest extends TestLogger {
 
 			SlotSharingGroup sharingGroup = new SlotSharingGroup(jid1, jid2);
 
-			Instance i1 = getRandomInstance(2);
-			Instance i2 = getRandomInstance(2);
+			TaskManagerLocation loc1 = testingSlotProvider.addTaskManager(2);
+			TaskManagerLocation loc2 = testingSlotProvider.addTaskManager(2);
 
-			TaskManagerLocation loc1 = i1.getTaskManagerLocation();
-
-			Scheduler scheduler = new Scheduler(TestingUtils.directExecutionContext());
-			scheduler.newInstanceAvailable(i1);
-			scheduler.newInstanceAvailable(i2);
-			
 			// schedule until the one instance is full
-			LogicalSlot s1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, loc1), sharingGroup), false, Collections.singleton(loc1)).get();
-			LogicalSlot s2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, loc1), sharingGroup), false, Collections.singleton(loc1)).get();
-			LogicalSlot s3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 4, loc1), sharingGroup), false, Collections.singleton(loc1)).get();
-			LogicalSlot s4 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 4, loc1), sharingGroup), false, Collections.singleton(loc1)).get();
+			LogicalSlot s1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid1, 0, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
+			LogicalSlot s2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid1, 1, 2, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
+			LogicalSlot s3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 0, 4, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
+			LogicalSlot s4 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 1, 4, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
 
 			// schedule two more with preference of same instance --> need to go to other instance
-			LogicalSlot s5 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 3, 4, loc1), sharingGroup), false, Collections.singleton(loc1)).get();
-			LogicalSlot s6 = scheduler.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 4, 4, loc1), sharingGroup), false, Collections.singleton(loc1)).get();
+			LogicalSlot s5 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 3, 4, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
+			LogicalSlot s6 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertexWithLocation(jid2, 4, 4, sharingGroup, loc1), sharingGroup.getSlotSharingGroupId()), false, Collections.singleton(loc1)).get();
 			
 			assertNotNull(s1);
 			assertNotNull(s2);
@@ -769,22 +740,21 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			assertNotNull(s5);
 			assertNotNull(s6);
 			
-			assertEquals(4, sharingGroup.getTaskAssignment().getNumberOfSlots());
-			
-			assertEquals(0, i1.getNumberOfAvailableSlots());
-			assertEquals(0, i2.getNumberOfAvailableSlots());
-			
-			assertEquals(i1.getTaskManagerLocation(), s1.getTaskManagerLocation());
-			assertEquals(i1.getTaskManagerLocation(), s2.getTaskManagerLocation());
-			assertEquals(i1.getTaskManagerLocation(), s3.getTaskManagerLocation());
-			assertEquals(i1.getTaskManagerLocation(), s4.getTaskManagerLocation());
-			assertEquals(i2.getTaskManagerLocation(), s5.getTaskManagerLocation());
-			assertEquals(i2.getTaskManagerLocation(), s6.getTaskManagerLocation());
+			assertEquals(4, testingSlotProvider.getNumberOfSlots(sharingGroup));
+
+			assertEquals(loc1, s1.getTaskManagerLocation());
+			assertEquals(loc1, s2.getTaskManagerLocation());
+			assertEquals(loc1, s3.getTaskManagerLocation());
+			assertEquals(loc1, s4.getTaskManagerLocation());
+			assertEquals(loc2, s5.getTaskManagerLocation());
+			assertEquals(loc2, s6.getTaskManagerLocation());
 			
 			// check the scheduler's bookkeeping
-			assertEquals(4, scheduler.getNumberOfLocalizedAssignments());
-			assertEquals(2, scheduler.getNumberOfNonLocalizedAssignments());
-			assertEquals(0, scheduler.getNumberOfUnconstrainedAssignments());
+			assertEquals(4, testingSlotProvider.getNumberOfLocalizedAssignments());
+			// Flip-6 supports host localized assignments which happen in this case because all TaskManagerLocations point to the loopback address
+			assertTrue(2 == testingSlotProvider.getNumberOfNonLocalizedAssignments() || 2 == testingSlotProvider.getNumberOfHostLocalizedAssignments());
+
+			assertEquals(0, testingSlotProvider.getNumberOfUnconstrainedAssignments());
 		}
 		catch (Exception e) {
 			e.printStackTrace();
@@ -802,23 +772,22 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			
 			final SlotSharingGroup sharingGroup = new SlotSharingGroup(jid1, jid2, jid3, jid4);
 			
-			final Scheduler scheduler = new Scheduler(TestingUtils.defaultExecutionContext());
-			scheduler.newInstanceAvailable(getRandomInstance(4));
-			
+			testingSlotProvider.addTaskManager(4);
+
 			// allocate something from group 1 and 2 interleaved with schedule for group 3
-			LogicalSlot slot_1_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot slot_1_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot slot_1_1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot slot_1_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 1, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 
-			LogicalSlot slot_2_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot slot_2_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot slot_2_1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot slot_2_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 1, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
-			LogicalSlot slot_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 0, 1), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot slot_3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 0, 1, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
-			LogicalSlot slot_1_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot slot_1_4 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot slot_1_3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 2, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot slot_1_4 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 3, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
-			LogicalSlot slot_2_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot slot_2_4 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 3, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot slot_2_3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 2, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot slot_2_4 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 3, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
 			// release groups 1 and 2
 			
@@ -834,10 +803,10 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			
 			// allocate group 4
 			
-			LogicalSlot slot_4_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 0, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot slot_4_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 1, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot slot_4_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 2, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot slot_4_4 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 3, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot slot_4_1 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 0, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot slot_4_2 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 1, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot slot_4_3 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 2, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot slot_4_4 = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 3, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
 			// release groups 3 and 4
 			
@@ -859,6 +828,8 @@ public class SchedulerSlotSharingTest extends TestLogger {
 		final ExecutorService executor = Executors.newFixedThreadPool(20);
 
 		try {
+			testingSlotProvider.addTaskManager(4);
+
 			for (int run = 0; run < 50; run++) {
 				final JobVertexID jid1 = new JobVertexID();
 				final JobVertexID jid2 = new JobVertexID();
@@ -866,10 +837,7 @@ public class SchedulerSlotSharingTest extends TestLogger {
 				final JobVertexID jid4 = new JobVertexID();
 				
 				final SlotSharingGroup sharingGroup = new SlotSharingGroup(jid1, jid2, jid3, jid4);
-				
-				final Scheduler scheduler = new Scheduler(TestingUtils.defaultExecutionContext());
-				scheduler.newInstanceAvailable(getRandomInstance(4));
-				
+
 				final AtomicInteger enumerator1 = new AtomicInteger();
 				final AtomicInteger enumerator2 = new AtomicInteger();
 				final AtomicBoolean flag3 = new AtomicBoolean();
@@ -883,13 +851,11 @@ public class SchedulerSlotSharingTest extends TestLogger {
 				// use atomic integer as a mutable integer reference
 				final AtomicInteger completed = new AtomicInteger();
 				
-				
 				final Runnable deploy4 = new Runnable() {
 					@Override
 					public void run() {
 						try {
-							LogicalSlot slot = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, enumerator4.getAndIncrement(), 4), sharingGroup), false, Collections.emptyList()).get();
-
+							LogicalSlot slot = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid4, enumerator4.getAndIncrement(), 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 							sleepUninterruptibly(rnd.nextInt(5));
 							slot.releaseSlot();
 
@@ -911,8 +877,7 @@ public class SchedulerSlotSharingTest extends TestLogger {
 					public void run() {
 						try {
 							if (flag3.compareAndSet(false, true)) {
-								LogicalSlot slot = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 0, 1), sharingGroup), false, Collections.emptyList()).get();
-								
+								LogicalSlot slot = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 0, 1, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 								sleepUninterruptibly(5);
 								
 								executor.execute(deploy4);
@@ -940,8 +905,8 @@ public class SchedulerSlotSharingTest extends TestLogger {
 					@Override
 					public void run() {
 						try {
-							LogicalSlot slot = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, enumerator2.getAndIncrement(), 4), sharingGroup), false, Collections.emptyList()).get();
-							
+							LogicalSlot slot = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid2, enumerator2.getAndIncrement(), 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+
 							// wait a bit till scheduling the successor
 							sleepUninterruptibly(rnd.nextInt(5));
 							executor.execute(deploy3);
@@ -967,8 +932,8 @@ public class SchedulerSlotSharingTest extends TestLogger {
 					@Override
 					public void run() {
 						try {
-							LogicalSlot slot = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, enumerator1.getAndIncrement(), 4), sharingGroup), false, Collections.emptyList()).get();
-							
+							LogicalSlot slot = testingSlotProvider.allocateSlot(new ScheduledUnit(getTestVertex(jid1, enumerator1.getAndIncrement(), 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+
 							// wait a bit till scheduling the successor
 							sleepUninterruptibly(rnd.nextInt(5));
 							executor.execute(deploy2);
@@ -1012,14 +977,12 @@ public class SchedulerSlotSharingTest extends TestLogger {
 				
 				assertFalse("Thread failed", failed.get());
 				
-				while (scheduler.getNumberOfAvailableSlots() < 4) {
+				while (testingSlotProvider.getNumberOfAvailableSlots() < 4) {
 					sleepUninterruptibly(5);
 				}
 				
-				assertEquals(1, scheduler.getNumberOfAvailableInstances());
-				assertEquals(1, scheduler.getNumberOfInstancesWithAvailableSlots());
-				assertEquals(4, scheduler.getNumberOfAvailableSlots());
-				assertEquals(13, scheduler.getNumberOfUnconstrainedAssignments());
+				assertEquals(4, testingSlotProvider.getNumberOfAvailableSlots());
+				assertEquals(13 * (run + 1), testingSlotProvider.getNumberOfUnconstrainedAssignments());
 			}
 		}
 		catch (Exception e) {
@@ -1042,27 +1005,27 @@ public class SchedulerSlotSharingTest extends TestLogger {
 			scheduler.newInstanceAvailable(getRandomInstance(4));
 			
 			// schedule one task for the first and second vertex
-			LogicalSlot s1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 1), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 1), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid1, 0, 1, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid2, 0, 1, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
 			assertEquals( s1.getTaskManagerLocation(), s2.getTaskManagerLocation() );
 			assertEquals(3, scheduler.getNumberOfAvailableSlots());
 			
-			LogicalSlot s3_0 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 0, 5), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s3_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 1, 5), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4_0 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 0, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 1, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s3_0 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 0, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s3_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 1, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s4_0 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 0, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s4_1 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 1, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
 			s1.releaseSlot();
 			s2.releaseSlot();
 			
-			LogicalSlot s3_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 2, 5), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s3_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 3, 5), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 2, 4), sharingGroup), false, Collections.emptyList()).get();
-			LogicalSlot s4_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 3, 4), sharingGroup), false, Collections.emptyList()).get();
+			LogicalSlot s3_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 2, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s3_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 3, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s4_2 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 2, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
+			LogicalSlot s4_3 = scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid4, 3, 4, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 			
 			try {
-				scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 4, 5), sharingGroup), false, Collections.emptyList()).get();
+				scheduler.allocateSlot(new ScheduledUnit(getTestVertex(jid3, 4, 5, sharingGroup), sharingGroup.getSlotSharingGroupId()), false, Collections.emptyList()).get();
 				fail("should throw an exception");
 			}
 			catch (ExecutionException e) {

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTest.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTest.java b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTest.java
new file mode 100644
index 0000000..8fd5f9e
--- /dev/null
+++ b/flink-runtime/src/test/java/org/apache/flink/runtime/jobmanager/scheduler/SchedulerTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.jobmanager.scheduler;
+
+import org.apache.flink.runtime.instance.Instance;
+import org.apache.flink.runtime.testingUtils.TestingUtils;
+import org.apache.flink.util.TestLogger;
+
+import org.junit.Test;
+
+import static org.apache.flink.runtime.jobmanager.scheduler.SchedulerTestUtils.getRandomInstance;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+public class SchedulerTest extends TestLogger {
+
+	@Test
+	public void testAddAndRemoveInstance() {
+		Scheduler scheduler = new Scheduler(TestingUtils.defaultExecutionContext());
+
+		Instance i1 = getRandomInstance(2);
+		Instance i2 = getRandomInstance(2);
+		Instance i3 = getRandomInstance(2);
+
+		assertEquals(0, scheduler.getNumberOfAvailableInstances());
+		assertEquals(0, scheduler.getNumberOfAvailableSlots());
+		scheduler.newInstanceAvailable(i1);
+		assertEquals(1, scheduler.getNumberOfAvailableInstances());
+		assertEquals(2, scheduler.getNumberOfAvailableSlots());
+		scheduler.newInstanceAvailable(i2);
+		assertEquals(2, scheduler.getNumberOfAvailableInstances());
+		assertEquals(4, scheduler.getNumberOfAvailableSlots());
+		scheduler.newInstanceAvailable(i3);
+		assertEquals(3, scheduler.getNumberOfAvailableInstances());
+		assertEquals(6, scheduler.getNumberOfAvailableSlots());
+
+		// cannot add available instance again
+		try {
+			scheduler.newInstanceAvailable(i2);
+			fail("Scheduler accepted instance twice");
+		}
+		catch (IllegalArgumentException e) {
+			// bueno!
+		}
+
+		// some instances die
+		assertEquals(3, scheduler.getNumberOfAvailableInstances());
+		assertEquals(6, scheduler.getNumberOfAvailableSlots());
+		scheduler.instanceDied(i2);
+		assertEquals(2, scheduler.getNumberOfAvailableInstances());
+		assertEquals(4, scheduler.getNumberOfAvailableSlots());
+
+		// try to add a dead instance
+		try {
+			scheduler.newInstanceAvailable(i2);
+			fail("Scheduler accepted dead instance");
+		}
+		catch (IllegalArgumentException e) {
+			// stimmt
+
+		}
+
+		scheduler.instanceDied(i1);
+		assertEquals(1, scheduler.getNumberOfAvailableInstances());
+		assertEquals(2, scheduler.getNumberOfAvailableSlots());
+		scheduler.instanceDied(i3);
+		assertEquals(0, scheduler.getNumberOfAvailableInstances());
+		assertEquals(0, scheduler.getNumberOfAvailableSlots());
+
+		assertFalse(i1.isAlive());
+		assertFalse(i2.isAlive());
+		assertFalse(i3.isAlive());
+	}
+}


[10/11] flink git commit: [FLINK-7956] [flip6] Add support for queued scheduling with slot sharing to SlotPool

Posted by tr...@apache.org.
http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotPool.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotPool.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotPool.java
deleted file mode 100644
index 68f5be6..0000000
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotPool.java
+++ /dev/null
@@ -1,1219 +0,0 @@
-/*
- * 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.instance;
-
-import org.apache.flink.annotation.VisibleForTesting;
-import org.apache.flink.api.common.JobID;
-import org.apache.flink.api.common.time.Time;
-import org.apache.flink.runtime.clusterframework.types.AllocationID;
-import org.apache.flink.runtime.clusterframework.types.ResourceID;
-import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
-import org.apache.flink.runtime.concurrent.FutureUtils;
-import org.apache.flink.runtime.jobmanager.scheduler.Locality;
-import org.apache.flink.runtime.jobmanager.scheduler.NoResourceAvailableException;
-import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
-import org.apache.flink.runtime.jobmanager.slots.SlotAndLocality;
-import org.apache.flink.runtime.jobmanager.slots.SlotException;
-import org.apache.flink.runtime.jobmanager.slots.SlotOwner;
-import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
-import org.apache.flink.runtime.jobmaster.JobMasterId;
-import org.apache.flink.runtime.messages.Acknowledge;
-import org.apache.flink.runtime.resourcemanager.ResourceManagerGateway;
-import org.apache.flink.runtime.resourcemanager.SlotRequest;
-import org.apache.flink.runtime.rpc.RpcEndpoint;
-import org.apache.flink.runtime.rpc.RpcService;
-import org.apache.flink.runtime.taskexecutor.slot.SlotOffer;
-import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-import org.apache.flink.runtime.util.clock.Clock;
-import org.apache.flink.runtime.util.clock.SystemClock;
-import org.apache.flink.util.Preconditions;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.annotation.Nullable;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
-import java.util.concurrent.TimeoutException;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static org.apache.flink.util.Preconditions.checkNotNull;
-
-/**
- * The slot pool serves slot request issued by Scheduler or ExecutionGraph. It will will attempt to acquire new slots
- * from the ResourceManager when it cannot serve a slot request. If no ResourceManager is currently available,
- * or it gets a decline from the ResourceManager, or a request times out, it fails the slot request. The slot pool also
- * holds all the slots that were offered to it and accepted, and can thus provides registered free slots even if the
- * ResourceManager is down. The slots will only be released when they are useless, e.g. when the job is fully running
- * but we still have some free slots.
- * <p>
- * All the allocation or the slot offering will be identified by self generated AllocationID, we will use it to
- * eliminate ambiguities.
- * 
- * TODO : Make pending requests location preference aware
- * TODO : Make pass location preferences to ResourceManager when sending a slot request
- */
-public class SlotPool extends RpcEndpoint implements SlotPoolGateway {
-
-	/** The log for the pool - shared also with the internal classes */
-	static final Logger LOG = LoggerFactory.getLogger(SlotPool.class);
-
-	// ------------------------------------------------------------------------
-
-	private static final Time DEFAULT_SLOT_REQUEST_TIMEOUT = Time.minutes(5);
-
-	private static final Time DEFAULT_RM_ALLOCATION_TIMEOUT = Time.minutes(10);
-
-	private static final Time DEFAULT_RM_REQUEST_TIMEOUT = Time.seconds(10);
-
-	// ------------------------------------------------------------------------
-
-	private final JobID jobId;
-
-	private final ProviderAndOwner providerAndOwner;
-
-	/** All registered TaskManagers, slots will be accepted and used only if the resource is registered */
-	private final HashSet<ResourceID> registeredTaskManagers;
-
-	/** The book-keeping of all allocated slots */
-	private final AllocatedSlots allocatedSlots;
-
-	/** The book-keeping of all available slots */
-	private final AvailableSlots availableSlots;
-
-	/** All pending requests waiting for slots */
-	private final DualKeyMap<SlotRequestID, AllocationID, PendingRequest> pendingRequests;
-
-	/** The requests that are waiting for the resource manager to be connected */
-	private final HashMap<SlotRequestID, PendingRequest> waitingForResourceManager;
-
-	/** Timeout for request calls to the ResourceManager */
-	private final Time resourceManagerRequestsTimeout;
-
-	/** Timeout for allocation round trips (RM -> launch TM -> offer slot) */
-	private final Time resourceManagerAllocationTimeout;
-
-	private final Clock clock;
-
-	/** the fencing token of the job manager */
-	private JobMasterId jobMasterId;
-
-	/** The gateway to communicate with resource manager */
-	private ResourceManagerGateway resourceManagerGateway;
-
-	private String jobManagerAddress;
-
-	// ------------------------------------------------------------------------
-
-	public SlotPool(RpcService rpcService, JobID jobId) {
-		this(rpcService, jobId, SystemClock.getInstance(),
-				DEFAULT_SLOT_REQUEST_TIMEOUT, DEFAULT_RM_ALLOCATION_TIMEOUT, DEFAULT_RM_REQUEST_TIMEOUT);
-	}
-
-	public SlotPool(
-			RpcService rpcService,
-			JobID jobId,
-			Clock clock,
-			Time slotRequestTimeout,
-			Time resourceManagerAllocationTimeout,
-			Time resourceManagerRequestTimeout) {
-
-		super(rpcService);
-
-		this.jobId = checkNotNull(jobId);
-		this.clock = checkNotNull(clock);
-		this.resourceManagerRequestsTimeout = checkNotNull(resourceManagerRequestTimeout);
-		this.resourceManagerAllocationTimeout = checkNotNull(resourceManagerAllocationTimeout);
-
-		this.registeredTaskManagers = new HashSet<>();
-		this.allocatedSlots = new AllocatedSlots();
-		this.availableSlots = new AvailableSlots();
-		this.pendingRequests = new DualKeyMap<>(16);
-		this.waitingForResourceManager = new HashMap<>(16);
-
-		this.providerAndOwner = new ProviderAndOwner(getSelfGateway(SlotPoolGateway.class), slotRequestTimeout);
-
-		this.jobMasterId = null;
-		this.resourceManagerGateway = null;
-		this.jobManagerAddress = null;
-	}
-
-	// ------------------------------------------------------------------------
-	//  Starting and Stopping
-	// ------------------------------------------------------------------------
-
-	@Override
-	public void start() {
-		throw new UnsupportedOperationException("Should never call start() without leader ID");
-	}
-
-	/**
-	 * Start the slot pool to accept RPC calls.
-	 *
-	 * @param jobMasterId The necessary leader id for running the job.
-	 * @param newJobManagerAddress for the slot requests which are sent to the resource manager
-	 */
-	public void start(JobMasterId jobMasterId, String newJobManagerAddress) throws Exception {
-		this.jobMasterId = checkNotNull(jobMasterId);
-		this.jobManagerAddress = checkNotNull(newJobManagerAddress);
-
-		// TODO - start should not throw an exception
-		try {
-			super.start();
-		} catch (Exception e) {
-			throw new RuntimeException("This should never happen", e);
-		}
-	}
-
-	/**
-	 * Suspends this pool, meaning it has lost its authority to accept and distribute slots.
-	 */
-	@Override
-	public void suspend() {
-		validateRunsInMainThread();
-
-		// suspend this RPC endpoint
-		stop();
-
-		// do not accept any requests
-		jobMasterId = null;
-		resourceManagerGateway = null;
-
-		// Clear (but not release!) the available slots. The TaskManagers should re-register them
-		// at the new leader JobManager/SlotPool
-		availableSlots.clear();
-		allocatedSlots.clear();
-		pendingRequests.clear();
-	}
-
-	// ------------------------------------------------------------------------
-	//  Getting PoolOwner and PoolProvider
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Gets the slot owner implementation for this pool.
-	 * 
-	 * <p>This method does not mutate state and can be called directly (no RPC indirection)
-	 * 
-	 * @return The slot owner implementation for this pool.
-	 */
-	public SlotOwner getSlotOwner() {
-		return providerAndOwner;
-	}
-
-	/**
-	 * Gets the slot provider implementation for this pool.
-	 *
-	 * <p>This method does not mutate state and can be called directly (no RPC indirection)
-	 *
-	 * @return The slot provider implementation for this pool.
-	 */
-	public SlotProvider getSlotProvider() {
-		return providerAndOwner;
-	}
-
-	// ------------------------------------------------------------------------
-	//  Resource Manager Connection
-	// ------------------------------------------------------------------------
-
-	@Override
-	public void connectToResourceManager(ResourceManagerGateway resourceManagerGateway) {
-		this.resourceManagerGateway = checkNotNull(resourceManagerGateway);
-
-		// work on all slots waiting for this connection
-		for (PendingRequest pendingRequest : waitingForResourceManager.values()) {
-			requestSlotFromResourceManager(resourceManagerGateway, pendingRequest);
-		}
-
-		// all sent off
-		waitingForResourceManager.clear();
-	}
-
-	@Override
-	public void disconnectResourceManager() {
-		this.resourceManagerGateway = null;
-	}
-
-	// ------------------------------------------------------------------------
-	//  Slot Allocation
-	// ------------------------------------------------------------------------
-
-	@Override
-	public CompletableFuture<LogicalSlot> allocateSlot(
-			SlotRequestID requestId,
-			ScheduledUnit task,
-			ResourceProfile resources,
-			Iterable<TaskManagerLocation> locationPreferences,
-			Time timeout) {
-
-		return internalAllocateSlot(requestId, task, resources, locationPreferences);
-	}
-
-	@Override
-	public void returnAllocatedSlot(SlotRequestID slotRequestId) {
-		final AllocatedSlot allocatedSlot = allocatedSlots.remove(slotRequestId);
-
-		if (allocatedSlot != null) {
-			if (allocatedSlot.releaseLogicalSlot()) {
-				tryFulfillSlotRequestOrMakeAvailable(allocatedSlot);
-			} else {
-				throw new RuntimeException("Could not release allocated slot " + allocatedSlot + '.');
-			}
-		} else {
-			log.debug("There is no allocated slot with request id {}. Ignoring this request.", slotRequestId);
-		}
-	}
-
-	@Override
-	public CompletableFuture<Acknowledge> cancelSlotRequest(SlotRequestID slotRequestId) {
-		final PendingRequest pendingRequest = removePendingRequest(slotRequestId);
-
-		if (pendingRequest != null) {
-			failPendingRequest(pendingRequest, new CancellationException("Allocation with request id" + slotRequestId + " cancelled."));
-		} else {
-			final AllocatedSlot allocatedSlot = allocatedSlots.get(slotRequestId);
-
-			if (allocatedSlot != null) {
-				LOG.info("Returning allocated slot {} because the corresponding allocation request {} was cancelled.", allocatedSlot, slotRequestId);
-				// TODO: Avoid having to send another message to do the slot releasing (e.g. introduce Slot#cancelExecution) and directly return slot
-				allocatedSlot.triggerLogicalSlotRelease();
-			} else {
-				LOG.debug("There was no slot allocation with {} to be cancelled.", slotRequestId);
-			}
-		}
-
-		return CompletableFuture.completedFuture(Acknowledge.get());
-	}
-
-	CompletableFuture<LogicalSlot> internalAllocateSlot(
-			SlotRequestID requestId,
-			ScheduledUnit task,
-			ResourceProfile resources,
-			Iterable<TaskManagerLocation> locationPreferences) {
-
-		// (1) do we have a slot available already?
-		SlotAndLocality slotFromPool = availableSlots.poll(resources, locationPreferences);
-		if (slotFromPool != null) {
-			final AllocatedSlot allocatedSlot = slotFromPool.slot();
-
-			final SimpleSlot simpleSlot;
-			try {
-				simpleSlot = allocatedSlot.allocateSimpleSlot(requestId, slotFromPool.locality());
-			} catch (SlotException e) {
-				availableSlots.add(allocatedSlot, clock.relativeTimeMillis());
-
-				return FutureUtils.completedExceptionally(e);
-			}
-
-			allocatedSlots.add(requestId, allocatedSlot);
-			return CompletableFuture.completedFuture(simpleSlot);
-		}
-
-		// we have to request a new allocated slot
-		CompletableFuture<AllocatedSlot> allocatedSlotFuture = requestSlot(
-			requestId,
-			resources);
-
-		return allocatedSlotFuture.thenApply(
-			(AllocatedSlot allocatedSlot) -> {
-				try {
-					return allocatedSlot.allocateSimpleSlot(requestId, Locality.UNKNOWN);
-				} catch (SlotException e) {
-					throw new CompletionException("Could not allocate a logical simple slot from allocate slot " +
-						allocatedSlot + '.', e);
-				}
-			});
-	}
-
-	/**
-	 * Checks whether there exists a pending request with the given allocation id and removes it
-	 * from the internal data structures.
-	 *
-	 * @param requestId identifying the pending request
-	 * @return pending request if there is one, otherwise null
-	 */
-	@Nullable
-	private PendingRequest removePendingRequest(SlotRequestID requestId) {
-		PendingRequest result = waitingForResourceManager.remove(requestId);
-
-		if (result != null) {
-			// sanity check
-			assert !pendingRequests.containsKeyA(requestId) : "A pending requests should only be part of either " +
-				"the pendingRequests or waitingForResourceManager but not both.";
-
-			return result;
-		} else {
-			return pendingRequests.removeKeyA(requestId);
-		}
-	}
-
-	private CompletableFuture<AllocatedSlot> requestSlot(
-		SlotRequestID slotRequestId,
-		ResourceProfile resourceProfile) {
-
-		final PendingRequest pendingRequest = new PendingRequest(
-			slotRequestId,
-			resourceProfile);
-
-		if (resourceManagerGateway == null) {
-			stashRequestWaitingForResourceManager(pendingRequest);
-		} else {
-			requestSlotFromResourceManager(resourceManagerGateway, pendingRequest);
-		}
-
-		return pendingRequest.getAllocatedSlotFuture();
-	}
-
-	private void requestSlotFromResourceManager(
-			final ResourceManagerGateway resourceManagerGateway,
-			final PendingRequest pendingRequest) {
-
-		Preconditions.checkNotNull(resourceManagerGateway);
-		Preconditions.checkNotNull(pendingRequest);
-
-		LOG.info("Requesting slot with profile {} from resource manager (request = {}).", pendingRequest.getResourceProfile(), pendingRequest.getSlotRequestId());
-
-		final AllocationID allocationId = new AllocationID();
-
-		pendingRequests.put(pendingRequest.getSlotRequestId(), allocationId, pendingRequest);
-
-		pendingRequest.getAllocatedSlotFuture().whenComplete(
-			(value, throwable) -> {
-				if (throwable != null) {
-					resourceManagerGateway.cancelSlotRequest(allocationId);
-				}
-			});
-
-		CompletableFuture<Acknowledge> rmResponse = resourceManagerGateway.requestSlot(
-			jobMasterId,
-			new SlotRequest(jobId, allocationId, pendingRequest.getResourceProfile(), jobManagerAddress),
-			resourceManagerRequestsTimeout);
-
-		CompletableFuture<Void> slotRequestProcessingFuture = rmResponse.thenAcceptAsync(
-			(Acknowledge value) -> {
-				slotRequestToResourceManagerSuccess(pendingRequest.getSlotRequestId());
-			},
-			getMainThreadExecutor());
-
-		// on failure, fail the request future
-		slotRequestProcessingFuture.whenCompleteAsync(
-			(Void v, Throwable failure) -> {
-				if (failure != null) {
-					slotRequestToResourceManagerFailed(pendingRequest.getSlotRequestId(), failure);
-				}
-			},
-			getMainThreadExecutor());
-	}
-
-	private void slotRequestToResourceManagerSuccess(final SlotRequestID requestId) {
-		// a request is pending from the ResourceManager to a (future) TaskManager
-		// we only add the watcher here in case that request times out
-		scheduleRunAsync(new Runnable() {
-			@Override
-			public void run() {
-				checkTimeoutSlotAllocation(requestId);
-			}
-		}, resourceManagerAllocationTimeout);
-	}
-
-	private void slotRequestToResourceManagerFailed(SlotRequestID slotRequestID, Throwable failure) {
-		PendingRequest request = pendingRequests.removeKeyA(slotRequestID);
-		if (request != null) {
-			request.getAllocatedSlotFuture().completeExceptionally(new NoResourceAvailableException(
-					"No pooled slot available and request to ResourceManager for new slot failed", failure));
-		} else {
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("Unregistered slot request {} failed.", slotRequestID, failure);
-			}
-		}
-	}
-
-	private void checkTimeoutSlotAllocation(SlotRequestID slotRequestID) {
-		PendingRequest request = pendingRequests.removeKeyA(slotRequestID);
-		if (request != null) {
-			failPendingRequest(request, new TimeoutException("Slot allocation request " + slotRequestID + " timed out"));
-		}
-	}
-
-	private void failPendingRequest(PendingRequest pendingRequest, Exception e) {
-		Preconditions.checkNotNull(pendingRequest);
-		Preconditions.checkNotNull(e);
-
-		if (!pendingRequest.getAllocatedSlotFuture().isDone()) {
-			LOG.info("Failing pending request {}.", pendingRequest.getSlotRequestId());
-			pendingRequest.getAllocatedSlotFuture().completeExceptionally(e);
-		}
-	}
-
-	private void stashRequestWaitingForResourceManager(final PendingRequest pendingRequest) {
-
-		LOG.info("Cannot serve slot request, no ResourceManager connected. " +
-				"Adding as pending request {}",  pendingRequest.getSlotRequestId());
-
-		waitingForResourceManager.put(pendingRequest.getSlotRequestId(), pendingRequest);
-
-		scheduleRunAsync(new Runnable() {
-			@Override
-			public void run() {
-				checkTimeoutRequestWaitingForResourceManager(pendingRequest.getSlotRequestId());
-			}
-		}, resourceManagerRequestsTimeout);
-	}
-
-	private void checkTimeoutRequestWaitingForResourceManager(SlotRequestID slotRequestId) {
-		PendingRequest request = waitingForResourceManager.remove(slotRequestId);
-		if (request != null) {
-			failPendingRequest(
-				request,
-				new NoResourceAvailableException("No slot available and no connection to Resource Manager established."));
-		}
-	}
-
-	// ------------------------------------------------------------------------
-	//  Slot releasing & offering
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Tries to fulfill with the given allocated slot a pending slot request or add the
-	 * allocated slot to the set of available slots if no matching request is available.
-	 *
-	 * @param allocatedSlot which shall be returned
-	 */
-	private void tryFulfillSlotRequestOrMakeAvailable(AllocatedSlot allocatedSlot) {
-		Preconditions.checkState(!allocatedSlot.isUsed(), "Provided slot is still in use.");
-
-		final PendingRequest pendingRequest = pollMatchingPendingRequest(allocatedSlot);
-
-		if (pendingRequest != null) {
-			LOG.debug("Fulfilling pending request [{}] early with returned slot [{}]",
-				pendingRequest.getSlotRequestId(), allocatedSlot.getAllocationId());
-
-			allocatedSlots.add(pendingRequest.getSlotRequestId(), allocatedSlot);
-			pendingRequest.getAllocatedSlotFuture().complete(allocatedSlot);
-		} else {
-			LOG.debug("Adding returned slot [{}] to available slots", allocatedSlot.getAllocationId());
-			availableSlots.add(allocatedSlot, clock.relativeTimeMillis());
-		}
-	}
-
-	private PendingRequest pollMatchingPendingRequest(final AllocatedSlot slot) {
-		final ResourceProfile slotResources = slot.getResourceProfile();
-
-		// try the requests sent to the resource manager first
-		for (PendingRequest request : pendingRequests.values()) {
-			if (slotResources.isMatching(request.getResourceProfile())) {
-				pendingRequests.removeKeyA(request.getSlotRequestId());
-				return request;
-			}
-		}
-
-		// try the requests waiting for a resource manager connection next
-		for (PendingRequest request : waitingForResourceManager.values()) {
-			if (slotResources.isMatching(request.getResourceProfile())) {
-				waitingForResourceManager.remove(request.getSlotRequestId());
-				return request;
-			}
-		}
-
-		// no request pending, or no request matches
-		return null;
-	}
-
-	@Override
-	public CompletableFuture<Collection<SlotOffer>> offerSlots(
-			TaskManagerLocation taskManagerLocation,
-			TaskManagerGateway taskManagerGateway,
-			Collection<SlotOffer> offers) {
-		validateRunsInMainThread();
-
-		List<CompletableFuture<Optional<SlotOffer>>> acceptedSlotOffers = offers.stream().map(
-			offer -> {
-				CompletableFuture<Optional<SlotOffer>> acceptedSlotOffer = offerSlot(
-					taskManagerLocation,
-					taskManagerGateway,
-					offer)
-					.thenApply(
-						(acceptedSlot) -> {
-							if (acceptedSlot) {
-								return Optional.of(offer);
-							} else {
-								return Optional.empty();
-							}
-						});
-
-				return acceptedSlotOffer;
-			}
-		).collect(Collectors.toList());
-
-		CompletableFuture<Collection<Optional<SlotOffer>>> optionalSlotOffers = FutureUtils.combineAll(acceptedSlotOffers);
-
-		CompletableFuture<Collection<SlotOffer>> resultingSlotOffers = optionalSlotOffers.thenApply(
-			collection -> {
-				Collection<SlotOffer> slotOffers = collection
-					.stream()
-					.flatMap(
-						opt -> opt.map(Stream::of).orElseGet(Stream::empty))
-					.collect(Collectors.toList());
-
-				return slotOffers;
-			});
-
-		return resultingSlotOffers;
-	}
-	
-	/**
-	 * Slot offering by TaskManager with AllocationID. The AllocationID is originally generated by this pool and
-	 * transfer through the ResourceManager to TaskManager. We use it to distinguish the different allocation
-	 * we issued. Slot offering may be rejected if we find something mismatching or there is actually no pending
-	 * request waiting for this slot (maybe fulfilled by some other returned slot).
-	 *
-	 * @param taskManagerLocation location from where the offer comes from
-	 * @param taskManagerGateway TaskManager gateway
-	 * @param slotOffer the offered slot
-	 * @return True if we accept the offering
-	 */
-	@Override
-	public CompletableFuture<Boolean> offerSlot(
-			final TaskManagerLocation taskManagerLocation,
-			final TaskManagerGateway taskManagerGateway,
-			final SlotOffer slotOffer) {
-		validateRunsInMainThread();
-
-		// check if this TaskManager is valid
-		final ResourceID resourceID = taskManagerLocation.getResourceID();
-		final AllocationID allocationID = slotOffer.getAllocationId();
-
-		if (!registeredTaskManagers.contains(resourceID)) {
-			LOG.debug("Received outdated slot offering [{}] from unregistered TaskManager: {}",
-					slotOffer.getAllocationId(), taskManagerLocation);
-			return CompletableFuture.completedFuture(false);
-		}
-
-		// check whether we have already using this slot
-		if (allocatedSlots.contains(allocationID) || availableSlots.contains(allocationID)) {
-			LOG.debug("Received repeated offer for slot [{}]. Ignoring.", allocationID);
-
-			// return true here so that the sender will get a positive acknowledgement to the retry
-			// and mark the offering as a success
-			return CompletableFuture.completedFuture(true);
-		}
-
-		final AllocatedSlot allocatedSlot = new AllocatedSlot(
-			slotOffer.getAllocationId(),
-			taskManagerLocation,
-			slotOffer.getSlotIndex(),
-			slotOffer.getResourceProfile(),
-			taskManagerGateway,
-			providerAndOwner);
-
-		// check whether we have request waiting for this slot
-		PendingRequest pendingRequest = pendingRequests.removeKeyB(allocationID);
-		if (pendingRequest != null) {
-			// we were waiting for this!
-			allocatedSlots.add(pendingRequest.getSlotRequestId(), allocatedSlot);
-			pendingRequest.getAllocatedSlotFuture().complete(allocatedSlot);
-		}
-		else {
-			// we were actually not waiting for this:
-			//   - could be that this request had been fulfilled
-			//   - we are receiving the slots from TaskManagers after becoming leaders
-			tryFulfillSlotRequestOrMakeAvailable(allocatedSlot);
-		}
-
-		// we accepted the request in any case. slot will be released after it idled for
-		// too long and timed out
-		return CompletableFuture.completedFuture(true);
-	}
-
-	
-	// TODO - periodic (every minute or so) catch slots that were lost (check all slots, if they have any task active)
-
-	// TODO - release slots that were not used to the resource manager
-
-	// ------------------------------------------------------------------------
-	//  Error Handling
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Fail the specified allocation and release the corresponding slot if we have one.
-	 * This may triggered by JobManager when some slot allocation failed with timeout.
-	 * Or this could be triggered by TaskManager, when it finds out something went wrong with the slot,
-	 * and decided to take it back.
-	 *
-	 * @param allocationID Represents the allocation which should be failed
-	 * @param cause        The cause of the failure
-	 */
-	@Override
-	public void failAllocation(final AllocationID allocationID, final Exception cause) {
-		final PendingRequest pendingRequest = pendingRequests.removeKeyB(allocationID);
-		if (pendingRequest != null) {
-			// request was still pending
-			failPendingRequest(pendingRequest, cause);
-		}
-		else if (availableSlots.tryRemove(allocationID)) {
-			LOG.debug("Failed available slot [{}] with ", allocationID, cause);
-		}
-		else {
-			AllocatedSlot allocatedSlot = allocatedSlots.remove(allocationID);
-			if (allocatedSlot != null) {
-				// release the slot.
-				// since it is not in 'allocatedSlots' any more, it will be dropped o return'
-				allocatedSlot.triggerLogicalSlotRelease();
-			}
-			else {
-				LOG.debug("Outdated request to fail slot [{}] with ", allocationID, cause);
-			}
-		}
-		// TODO: add some unit tests when the previous two are ready, the allocation may failed at any phase
-	}
-
-	// ------------------------------------------------------------------------
-	//  Resource
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Register TaskManager to this pool, only those slots come from registered TaskManager will be considered valid.
-	 * Also it provides a way for us to keep "dead" or "abnormal" TaskManagers out of this pool.
-	 *
-	 * @param resourceID The id of the TaskManager
-	 * @return Future acknowledge if th operation was successful
-	 */
-	@Override
-	public CompletableFuture<Acknowledge> registerTaskManager(final ResourceID resourceID) {
-		registeredTaskManagers.add(resourceID);
-
-		return CompletableFuture.completedFuture(Acknowledge.get());
-	}
-
-	/**
-	 * Unregister TaskManager from this pool, all the related slots will be released and tasks be canceled. Called
-	 * when we find some TaskManager becomes "dead" or "abnormal", and we decide to not using slots from it anymore.
-	 *
-	 * @param resourceID The id of the TaskManager
-	 */
-	@Override
-	public CompletableFuture<Acknowledge> releaseTaskManager(final ResourceID resourceID) {
-		if (registeredTaskManagers.remove(resourceID)) {
-			availableSlots.removeAllForTaskManager(resourceID);
-
-			final Set<AllocatedSlot> allocatedSlotsForResource = allocatedSlots.removeSlotsForTaskManager(resourceID);
-			for (AllocatedSlot allocatedSlot : allocatedSlotsForResource) {
-				allocatedSlot.triggerLogicalSlotRelease();
-				// TODO: This is a work-around to mark the logical slot as released. We should split up the internalReturnSlot method to not poll pending requests
-				allocatedSlot.releaseLogicalSlot();
-			}
-		}
-
-		return CompletableFuture.completedFuture(Acknowledge.get());
-	}
-
-	// ------------------------------------------------------------------------
-	//  Methods for tests
-	// ------------------------------------------------------------------------
-
-	@VisibleForTesting
-	AllocatedSlots getAllocatedSlots() {
-		return allocatedSlots;
-	}
-
-	@VisibleForTesting
-	AvailableSlots getAvailableSlots() {
-		return availableSlots;
-	}
-
-	@VisibleForTesting
-	DualKeyMap<SlotRequestID, AllocationID, PendingRequest> getPendingRequests() {
-		return pendingRequests;
-	}
-
-	@VisibleForTesting
-	Map<SlotRequestID, PendingRequest> getWaitingForResourceManager() {
-		return waitingForResourceManager;
-	}
-
-	// ------------------------------------------------------------------------
-	//  Helper classes
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Organize allocated slots from different points of view.
-	 */
-	static class AllocatedSlots {
-
-		/** All allocated slots organized by TaskManager's id */
-		private final Map<ResourceID, Set<AllocatedSlot>> allocatedSlotsByTaskManager;
-
-		/** All allocated slots organized by AllocationID */
-		private final DualKeyMap<AllocationID, SlotRequestID, AllocatedSlot> allocatedSlotsById;
-
-		AllocatedSlots() {
-			this.allocatedSlotsByTaskManager = new HashMap<>(16);
-			this.allocatedSlotsById = new DualKeyMap<>(16);
-		}
-
-		/**
-		 * Adds a new slot to this collection.
-		 *
-		 * @param allocatedSlot The allocated slot
-		 */
-		void add(SlotRequestID slotRequestId, AllocatedSlot allocatedSlot) {
-			allocatedSlotsById.put(allocatedSlot.getAllocationId(), slotRequestId, allocatedSlot);
-
-			final ResourceID resourceID = allocatedSlot.getTaskManagerLocation().getResourceID();
-
-			Set<AllocatedSlot> slotsForTaskManager = allocatedSlotsByTaskManager.computeIfAbsent(
-				resourceID,
-				resourceId -> new HashSet<>(4));
-
-			slotsForTaskManager.add(allocatedSlot);
-		}
-
-		/**
-		 * Get allocated slot with allocation id
-		 *
-		 * @param allocationID The allocation id
-		 * @return The allocated slot, null if we can't find a match
-		 */
-		AllocatedSlot get(final AllocationID allocationID) {
-			return allocatedSlotsById.getKeyA(allocationID);
-		}
-
-		AllocatedSlot get(final SlotRequestID slotRequestId) {
-			return allocatedSlotsById.getKeyB(slotRequestId);
-		}
-
-		/**
-		 * Check whether we have allocated this slot
-		 *
-		 * @param slotAllocationId The allocation id of the slot to check
-		 * @return True if we contains this slot
-		 */
-		boolean contains(AllocationID slotAllocationId) {
-			return allocatedSlotsById.containsKeyA(slotAllocationId);
-		}
-
-		/**
-		 * Removes the allocated slot specified by the provided slot allocation id.
-		 *
-		 * @param allocationID identifying the allocated slot to remove
-		 * @return The removed allocated slot or null.
-		 */
-		@Nullable
-		AllocatedSlot remove(final AllocationID allocationID) {
-			AllocatedSlot allocatedSlot = allocatedSlotsById.removeKeyA(allocationID);
-
-			if (allocatedSlot != null) {
-				removeAllocatedSlot(allocatedSlot);
-			}
-
-			return allocatedSlot;
-		}
-
-		/**
-		 * Removes the allocated slot specified by the provided slot request id.
-		 *
-		 * @param slotRequestId identifying the allocated slot to remove
-		 * @return The removed allocated slot or null.
-		 */
-		@Nullable
-		AllocatedSlot remove(final SlotRequestID slotRequestId) {
-			final AllocatedSlot allocatedSlot = allocatedSlotsById.removeKeyB(slotRequestId);
-
-			if (allocatedSlot != null) {
-				removeAllocatedSlot(allocatedSlot);
-			}
-
-			return allocatedSlot;
-		}
-
-		private void removeAllocatedSlot(final AllocatedSlot allocatedSlot) {
-			Preconditions.checkNotNull(allocatedSlot);
-			final ResourceID taskManagerId = allocatedSlot.getTaskManagerLocation().getResourceID();
-			Set<AllocatedSlot> slotsForTM = allocatedSlotsByTaskManager.get(taskManagerId);
-
-			slotsForTM.remove(allocatedSlot);
-
-			if (slotsForTM.isEmpty()) {
-				allocatedSlotsByTaskManager.remove(taskManagerId);
-			}
-		}
-
-		/**
-		 * Get all allocated slot from same TaskManager.
-		 *
-		 * @param resourceID The id of the TaskManager
-		 * @return Set of slots which are allocated from the same TaskManager
-		 */
-		Set<AllocatedSlot> removeSlotsForTaskManager(final ResourceID resourceID) {
-			Set<AllocatedSlot> slotsForTaskManager = allocatedSlotsByTaskManager.remove(resourceID);
-			if (slotsForTaskManager != null) {
-				for (AllocatedSlot allocatedSlot : slotsForTaskManager) {
-					allocatedSlotsById.removeKeyA(allocatedSlot.getAllocationId());
-				}
-				return slotsForTaskManager;
-			}
-			else {
-				return Collections.emptySet();
-			}
-		}
-
-		void clear() {
-			allocatedSlotsById.clear();
-			allocatedSlotsByTaskManager.clear();
-		}
-
-		@VisibleForTesting
-		boolean containResource(final ResourceID resourceID) {
-			return allocatedSlotsByTaskManager.containsKey(resourceID);
-		}
-
-		@VisibleForTesting
-		int size() {
-			return allocatedSlotsById.size();
-		}
-
-		@VisibleForTesting
-		Set<AllocatedSlot> getSlotsForTaskManager(ResourceID resourceId) {
-			if (allocatedSlotsByTaskManager.containsKey(resourceId)) {
-				return allocatedSlotsByTaskManager.get(resourceId);
-			} else {
-				return Collections.emptySet();
-			}
-		}
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Organize all available slots from different points of view.
-	 */
-	static class AvailableSlots {
-
-		/** All available slots organized by TaskManager */
-		private final HashMap<ResourceID, Set<AllocatedSlot>> availableSlotsByTaskManager;
-
-		/** All available slots organized by host */
-		private final HashMap<String, Set<AllocatedSlot>> availableSlotsByHost;
-
-		/** The available slots, with the time when they were inserted */
-		private final HashMap<AllocationID, SlotAndTimestamp> availableSlots;
-
-		AvailableSlots() {
-			this.availableSlotsByTaskManager = new HashMap<>();
-			this.availableSlotsByHost = new HashMap<>();
-			this.availableSlots = new HashMap<>();
-		}
-
-		/**
-		 * Adds an available slot.
-		 *
-		 * @param slot The slot to add
-		 */
-		void add(final AllocatedSlot slot, final long timestamp) {
-			checkNotNull(slot);
-
-			SlotAndTimestamp previous = availableSlots.put(
-					slot.getAllocationId(), new SlotAndTimestamp(slot, timestamp));
-
-			if (previous == null) {
-				final ResourceID resourceID = slot.getTaskManagerLocation().getResourceID();
-				final String host = slot.getTaskManagerLocation().getFQDNHostname();
-
-				Set<AllocatedSlot> slotsForTaskManager = availableSlotsByTaskManager.get(resourceID);
-				if (slotsForTaskManager == null) {
-					slotsForTaskManager = new HashSet<>();
-					availableSlotsByTaskManager.put(resourceID, slotsForTaskManager);
-				}
-				slotsForTaskManager.add(slot);
-
-				Set<AllocatedSlot> slotsForHost = availableSlotsByHost.get(host);
-				if (slotsForHost == null) {
-					slotsForHost = new HashSet<>();
-					availableSlotsByHost.put(host, slotsForHost);
-				}
-				slotsForHost.add(slot);
-			}
-			else {
-				throw new IllegalStateException("slot already contained");
-			}
-		}
-
-		/**
-		 * Check whether we have this slot.
-		 */
-		boolean contains(AllocationID slotId) {
-			return availableSlots.containsKey(slotId);
-		}
-
-		/**
-		 * Poll a slot which matches the required resource profile. The polling tries to satisfy the
-		 * location preferences, by TaskManager and by host.
-		 *
-		 * @param resourceProfile      The required resource profile.
-		 * @param locationPreferences  The location preferences, in order to be checked.
-		 * 
-		 * @return Slot which matches the resource profile, null if we can't find a match
-		 */
-		SlotAndLocality poll(ResourceProfile resourceProfile, Iterable<TaskManagerLocation> locationPreferences) {
-			// fast path if no slots are available
-			if (availableSlots.isEmpty()) {
-				return null;
-			}
-
-			boolean hadLocationPreference = false;
-
-			if (locationPreferences != null) {
-
-				// first search by TaskManager
-				for (TaskManagerLocation location : locationPreferences) {
-					hadLocationPreference = true;
-
-					final Set<AllocatedSlot> onTaskManager = availableSlotsByTaskManager.get(location.getResourceID());
-					if (onTaskManager != null) {
-						for (AllocatedSlot candidate : onTaskManager) {
-							if (candidate.getResourceProfile().isMatching(resourceProfile)) {
-								remove(candidate.getAllocationId());
-								return new SlotAndLocality(candidate, Locality.LOCAL);
-							}
-						}
-					}
-				}
-
-				// now, search by host
-				for (TaskManagerLocation location : locationPreferences) {
-					final Set<AllocatedSlot> onHost = availableSlotsByHost.get(location.getFQDNHostname());
-					if (onHost != null) {
-						for (AllocatedSlot candidate : onHost) {
-							if (candidate.getResourceProfile().isMatching(resourceProfile)) {
-								remove(candidate.getAllocationId());
-								return new SlotAndLocality(candidate, Locality.HOST_LOCAL);
-							}
-						}
-					}
-				}
-			}
-
-			// take any slot
-			for (SlotAndTimestamp candidate : availableSlots.values()) {
-				final AllocatedSlot slot = candidate.slot();
-
-				if (slot.getResourceProfile().isMatching(resourceProfile)) {
-					remove(slot.getAllocationId());
-					return new SlotAndLocality(
-							slot, hadLocationPreference ? Locality.NON_LOCAL : Locality.UNCONSTRAINED);
-				}
-			}
-
-			// nothing available that matches
-			return null;
-		}
-
-		/**
-		 * Remove all available slots come from specified TaskManager.
-		 *
-		 * @param taskManager The id of the TaskManager
-		 */
-		void removeAllForTaskManager(final ResourceID taskManager) {
-			// remove from the by-TaskManager view
-			final Set<AllocatedSlot> slotsForTm = availableSlotsByTaskManager.remove(taskManager);
-
-			if (slotsForTm != null && slotsForTm.size() > 0) {
-				final String host = slotsForTm.iterator().next().getTaskManagerLocation().getFQDNHostname();
-				final Set<AllocatedSlot> slotsForHost = availableSlotsByHost.get(host);
-
-				// remove from the base set and the by-host view
-				for (AllocatedSlot slot : slotsForTm) {
-					availableSlots.remove(slot.getAllocationId());
-					slotsForHost.remove(slot);
-				}
-
-				if (slotsForHost.isEmpty()) {
-					availableSlotsByHost.remove(host);
-				}
-			}
-		}
-
-		boolean tryRemove(AllocationID slotId) {
-			final SlotAndTimestamp sat = availableSlots.remove(slotId);
-			if (sat != null) {
-				final AllocatedSlot slot = sat.slot();
-				final ResourceID resourceID = slot.getTaskManagerLocation().getResourceID();
-				final String host = slot.getTaskManagerLocation().getFQDNHostname();
-
-				final Set<AllocatedSlot> slotsForTm = availableSlotsByTaskManager.get(resourceID);
-				final Set<AllocatedSlot> slotsForHost = availableSlotsByHost.get(host);
-
-				slotsForTm.remove(slot);
-				slotsForHost.remove(slot);
-
-				if (slotsForTm.isEmpty()) {
-					availableSlotsByTaskManager.remove(resourceID);
-				}
-				if (slotsForHost.isEmpty()) {
-					availableSlotsByHost.remove(host);
-				}
-
-				return true;
-			}
-			else {
-				return false;
-			}
-		}
-
-		private void remove(AllocationID slotId) throws IllegalStateException {
-			if (!tryRemove(slotId)) {
-				throw new IllegalStateException("slot not contained");
-			}
-		}
-
-		@VisibleForTesting
-		boolean containsTaskManager(ResourceID resourceID) {
-			return availableSlotsByTaskManager.containsKey(resourceID);
-		}
-
-		@VisibleForTesting
-		int size() {
-			return availableSlots.size();
-		}
-
-		@VisibleForTesting
-		void clear() {
-			availableSlots.clear();
-			availableSlotsByTaskManager.clear();
-			availableSlotsByHost.clear();
-		}
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * An implementation of the {@link SlotOwner} and {@link SlotProvider} interfaces
-	 * that delegates methods as RPC calls to the SlotPool's RPC gateway.
-	 */
-	private static class ProviderAndOwner implements SlotOwner, SlotProvider {
-
-		private final SlotPoolGateway gateway;
-
-		private final Time timeout;
-
-		ProviderAndOwner(SlotPoolGateway gateway, Time timeout) {
-			this.gateway = gateway;
-			this.timeout = timeout;
-		}
-
-		@Override
-		public CompletableFuture<Boolean> returnAllocatedSlot(LogicalSlot slot) {
-			gateway.returnAllocatedSlot(slot.getSlotRequestId());
-			return CompletableFuture.completedFuture(true);
-		}
-
-		@Override
-		public CompletableFuture<LogicalSlot> allocateSlot(
-				ScheduledUnit task,
-				boolean allowQueued,
-				Collection<TaskManagerLocation> preferredLocations) {
-
-			final SlotRequestID requestId = new SlotRequestID();
-			CompletableFuture<LogicalSlot> slotFuture = gateway.allocateSlot(requestId, task, ResourceProfile.UNKNOWN, preferredLocations, timeout);
-			slotFuture.whenComplete(
-				(LogicalSlot slot, Throwable failure) -> {
-					if (failure != null) {
-						gateway.cancelSlotRequest(requestId);
-					}
-			});
-			return slotFuture;
-		}
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * A pending request for a slot
-	 */
-	private static class PendingRequest {
-
-		private final SlotRequestID slotRequestId;
-
-		private final ResourceProfile resourceProfile;
-
-		private final CompletableFuture<AllocatedSlot> allocatedSlotFuture;
-
-		PendingRequest(
-				SlotRequestID slotRequestId,
-				ResourceProfile resourceProfile) {
-			this.slotRequestId = Preconditions.checkNotNull(slotRequestId);
-			this.resourceProfile = Preconditions.checkNotNull(resourceProfile);
-
-			allocatedSlotFuture = new CompletableFuture<>();
-		}
-
-		public SlotRequestID getSlotRequestId() {
-			return slotRequestId;
-		}
-
-		public CompletableFuture<AllocatedSlot> getAllocatedSlotFuture() {
-			return allocatedSlotFuture;
-		}
-
-		public ResourceProfile getResourceProfile() {
-			return resourceProfile;
-		}
-	}
-
-	// ------------------------------------------------------------------------
-
-	/**
-	 * A slot, together with the timestamp when it was added
-	 */
-	private static class SlotAndTimestamp {
-
-		private final AllocatedSlot slot;
-
-		private final long timestamp;
-
-		SlotAndTimestamp(AllocatedSlot slot, long timestamp) {
-			this.slot = slot;
-			this.timestamp = timestamp;
-		}
-
-		public AllocatedSlot slot() {
-			return slot;
-		}
-
-		public long timestamp() {
-			return timestamp;
-		}
-
-		@Override
-		public String toString() {
-			return slot + " @ " + timestamp;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotPoolGateway.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotPoolGateway.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotPoolGateway.java
deleted file mode 100644
index 103bc61..0000000
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotPoolGateway.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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.instance;
-
-import org.apache.flink.api.common.time.Time;
-import org.apache.flink.runtime.clusterframework.types.AllocationID;
-import org.apache.flink.runtime.clusterframework.types.ResourceID;
-import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
-import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
-import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
-import org.apache.flink.runtime.messages.Acknowledge;
-import org.apache.flink.runtime.resourcemanager.ResourceManagerGateway;
-import org.apache.flink.runtime.rpc.RpcGateway;
-import org.apache.flink.runtime.rpc.RpcTimeout;
-import org.apache.flink.runtime.taskexecutor.slot.SlotOffer;
-import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-
-import java.util.Collection;
-import java.util.concurrent.CompletableFuture;
-
-/**
- * The gateway for calls on the {@link SlotPool}. 
- */
-public interface SlotPoolGateway extends RpcGateway {
-
-	// ------------------------------------------------------------------------
-	//  shutdown
-	// ------------------------------------------------------------------------
-
-	void suspend();
-
-	// ------------------------------------------------------------------------
-	//  resource manager connection
-	// ------------------------------------------------------------------------
-
-	/**
-	 * Connects the SlotPool to the given ResourceManager. After this method is called, the
-	 * SlotPool will be able to request resources from the given ResourceManager.
-	 * 
-	 * @param resourceManagerGateway  The RPC gateway for the resource manager.
-	 */
-	void connectToResourceManager(ResourceManagerGateway resourceManagerGateway);
-
-	/**
-	 * Disconnects the slot pool from its current Resource Manager. After this call, the pool will not
-	 * be able to request further slots from the Resource Manager, and all currently pending requests
-	 * to the resource manager will be canceled.
-	 * 
-	 * <p>The slot pool will still be able to serve slots from its internal pool.
-	 */
-	void disconnectResourceManager();
-
-	// ------------------------------------------------------------------------
-	//  registering / un-registering TaskManagers and slots
-	// ------------------------------------------------------------------------
-
-	CompletableFuture<Acknowledge> registerTaskManager(ResourceID resourceID);
-
-	CompletableFuture<Acknowledge> releaseTaskManager(ResourceID resourceID);
-
-	CompletableFuture<Boolean> offerSlot(
-		TaskManagerLocation taskManagerLocation,
-		TaskManagerGateway taskManagerGateway,
-		SlotOffer slotOffer);
-
-	CompletableFuture<Collection<SlotOffer>> offerSlots(
-		TaskManagerLocation taskManagerLocation,
-		TaskManagerGateway taskManagerGateway,
-		Collection<SlotOffer> offers);
-	
-	void failAllocation(AllocationID allocationID, Exception cause);
-
-	// ------------------------------------------------------------------------
-	//  allocating and disposing slots
-	// ------------------------------------------------------------------------
-
-	CompletableFuture<LogicalSlot> allocateSlot(
-			SlotRequestID requestId,
-			ScheduledUnit task,
-			ResourceProfile resources,
-			Iterable<TaskManagerLocation> locationPreferences,
-			@RpcTimeout Time timeout);
-
-	void returnAllocatedSlot(SlotRequestID slotRequestId);
-
-	/**
-	 * Cancel a slot allocation request.
-	 *
-	 * @param slotRequestId identifying the slot allocation request
-	 * @return Future acknowledge if the slot allocation has been cancelled
-	 */
-	CompletableFuture<Acknowledge> cancelSlotRequest(SlotRequestID slotRequestId);
-
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotProvider.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotProvider.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotProvider.java
deleted file mode 100644
index 98427c2..0000000
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotProvider.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.instance;
-
-import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
-import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-
-import java.util.Collection;
-import java.util.concurrent.CompletableFuture;
-
-/**
- * The slot provider is responsible for preparing slots for ready-to-run tasks.
- * 
- * <p>It supports two allocating modes:
- * <ul>
- *     <li>Immediate allocating: A request for a task slot immediately gets satisfied, we can call
- *         {@link CompletableFuture#getNow(Object)} to get the allocated slot.</li>
- *     <li>Queued allocating: A request for a task slot is queued and returns a future that will be
- *         fulfilled as soon as a slot becomes available.</li>
- * </ul>
- */
-public interface SlotProvider {
-
-	/**
-	 * Allocating slot with specific requirement.
-	 *
-	 * @param task         The task to allocate the slot for
-	 * @param allowQueued  Whether allow the task be queued if we do not have enough resource
-	 * @param preferredLocations preferred locations for the slot allocation
-	 * @return The future of the allocation
-	 */
-	CompletableFuture<LogicalSlot> allocateSlot(
-		ScheduledUnit task,
-		boolean allowQueued,
-		Collection<TaskManagerLocation> preferredLocations);
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotRequestID.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotRequestID.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotRequestID.java
deleted file mode 100644
index 8e19944..0000000
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotRequestID.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.instance;
-
-import org.apache.flink.util.AbstractID;
-
-/**
- * Request ID identifying different slot requests.
- */
-public final class SlotRequestID extends AbstractID {
-    private static final long serialVersionUID = -6072105912250154283L;
-
-    public SlotRequestID(long lowerPart, long upperPart) {
-        super(lowerPart, upperPart);
-    }
-
-    public SlotRequestID() {}
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotSharingGroupAssignment.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotSharingGroupAssignment.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotSharingGroupAssignment.java
index 45b4a96..289762c 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotSharingGroupAssignment.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotSharingGroupAssignment.java
@@ -18,28 +18,29 @@
 
 package org.apache.flink.runtime.instance;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 import org.apache.flink.api.java.tuple.Tuple2;
 import org.apache.flink.runtime.clusterframework.types.ResourceID;
+import org.apache.flink.runtime.executiongraph.ExecutionVertex;
+import org.apache.flink.runtime.jobgraph.JobVertexID;
 import org.apache.flink.runtime.jobmanager.scheduler.CoLocationConstraint;
 import org.apache.flink.runtime.jobmanager.scheduler.Locality;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 import org.apache.flink.util.AbstractID;
-import org.apache.flink.runtime.executiongraph.ExecutionVertex;
-import org.apache.flink.runtime.jobgraph.JobVertexID;
+import org.apache.flink.util.FlinkException;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 
 /**
  * The SlotSharingGroupAssignment manages a set of shared slots, which are shared between
@@ -215,7 +216,7 @@ public class SlotSharingGroupAssignment {
 						// note that this does implicitly release the slot we have just added
 						// as well, because we release its last child slot. That is expected
 						// and desired.
-						constraintGroupSlot.releaseInstanceSlot();
+						constraintGroupSlot.releaseSlot(new FlinkException("Could not create a sub slot in this shared slot."));
 					}
 				}
 				else {
@@ -273,7 +274,7 @@ public class SlotSharingGroupAssignment {
 	 */
 	public SimpleSlot getSlotForTask(JobVertexID vertexID, Iterable<TaskManagerLocation> locationPreferences) {
 		synchronized (lock) {
-			Tuple2<SharedSlot, Locality> p = getSlotForTaskInternal(vertexID, locationPreferences, false);
+			Tuple2<SharedSlot, Locality> p = getSharedSlotForTask(vertexID, locationPreferences, false);
 
 			if (p != null) {
 				SharedSlot ss = p.f0;
@@ -324,7 +325,7 @@ public class SlotSharingGroupAssignment {
 				}
 
 				TaskManagerLocation location = previous.getTaskManagerLocation();
-				Tuple2<SharedSlot, Locality> p = getSlotForTaskInternal(
+				Tuple2<SharedSlot, Locality> p = getSharedSlotForTask(
 						constraint.getGroupId(), Collections.singleton(location), true);
 
 				if (p == null) {
@@ -355,7 +356,7 @@ public class SlotSharingGroupAssignment {
 				// grab a new slot and initialize the constraint with that one.
 				// preferred locations are defined by the vertex
 				Tuple2<SharedSlot, Locality> p =
-						getSlotForTaskInternal(constraint.getGroupId(), locationPreferences, false);
+						getSharedSlotForTask(constraint.getGroupId(), locationPreferences, false);
 				if (p == null) {
 					// could not get a shared slot for this co-location-group
 					return null;
@@ -382,9 +383,10 @@ public class SlotSharingGroupAssignment {
 	}
 
 
-	private Tuple2<SharedSlot, Locality> getSlotForTaskInternal(
-			AbstractID groupId, Iterable<TaskManagerLocation> preferredLocations, boolean localOnly)
-	{
+	public Tuple2<SharedSlot, Locality> getSharedSlotForTask(
+			AbstractID groupId,
+			Iterable<TaskManagerLocation> preferredLocations,
+			boolean localOnly) {
 		// check if there is anything at all in this group assignment
 		if (allSlots.isEmpty()) {
 			return null;
@@ -507,7 +509,7 @@ public class SlotSharingGroupAssignment {
 	}
 
 	/**
-	 * Called from {@link org.apache.flink.runtime.instance.SharedSlot#releaseInstanceSlot()}.
+	 * Called from {@link org.apache.flink.runtime.instance.SharedSlot#releaseSlot(Throwable)}.
 	 * 
 	 * @param sharedSlot The slot to be released.
 	 */
@@ -517,10 +519,11 @@ public class SlotSharingGroupAssignment {
 				// we are releasing this slot
 				
 				if (sharedSlot.hasChildren()) {
+					final FlinkException cause = new FlinkException("Releasing shared slot parent.");
 					// by simply releasing all children, we should eventually release this slot.
 					Set<Slot> children = sharedSlot.getSubSlots();
 					while (children.size() > 0) {
-						children.iterator().next().releaseInstanceSlot();
+						children.iterator().next().releaseSlot(cause);
 					}
 				}
 				else {

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotSharingGroupId.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotSharingGroupId.java b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotSharingGroupId.java
new file mode 100644
index 0000000..e5d4467
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/instance/SlotSharingGroupId.java
@@ -0,0 +1,32 @@
+/*
+ * 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.instance;
+
+import org.apache.flink.util.AbstractID;
+
+public class SlotSharingGroupId extends AbstractID {
+	private static final long serialVersionUID = 8837647978345422042L;
+
+	public SlotSharingGroupId(long lowerPart, long upperPart) {
+		super(lowerPart, upperPart);
+	}
+
+	public SlotSharingGroupId() {
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/CoLocationConstraint.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/CoLocationConstraint.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/CoLocationConstraint.java
index ffc1a7c..baa452f 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/CoLocationConstraint.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/CoLocationConstraint.java
@@ -18,16 +18,20 @@
 
 package org.apache.flink.runtime.jobmanager.scheduler;
 
-import org.apache.flink.runtime.clusterframework.types.ResourceID;
+import org.apache.flink.runtime.instance.Instance;
+import org.apache.flink.runtime.instance.SharedSlot;
+import org.apache.flink.runtime.jobmaster.SlotRequestId;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 import org.apache.flink.util.AbstractID;
-import org.apache.flink.runtime.instance.Instance;
-
+import org.apache.flink.util.FlinkException;
 import org.apache.flink.util.Preconditions;
-import org.apache.flink.runtime.instance.SharedSlot;
 
-import static org.apache.flink.util.Preconditions.checkState;
+import javax.annotation.Nullable;
+
+import java.util.Objects;
+
 import static org.apache.flink.util.Preconditions.checkNotNull;
+import static org.apache.flink.util.Preconditions.checkState;
 
 /**
  * A CoLocationConstraint manages the location of a set of tasks
@@ -43,12 +47,14 @@ public class CoLocationConstraint {
 
 	private volatile SharedSlot sharedSlot;
 
-	private volatile ResourceID lockedLocation;
+	private volatile TaskManagerLocation lockedLocation;
 
+	private volatile SlotRequestId slotRequestId;
 
 	CoLocationConstraint(CoLocationGroup group) {
 		Preconditions.checkNotNull(group);
 		this.group = group;
+		this.slotRequestId = null;
 	}
 
 	// ------------------------------------------------------------------------
@@ -107,7 +113,7 @@ public class CoLocationConstraint {
 	 */
 	public TaskManagerLocation getLocation() {
 		if (lockedLocation != null) {
-			return sharedSlot.getTaskManagerLocation();
+			return lockedLocation;
 		} else {
 			throw new IllegalStateException("Location not yet locked");
 		}
@@ -136,12 +142,12 @@ public class CoLocationConstraint {
 			this.sharedSlot = newSlot;
 		}
 		else if (newSlot != this.sharedSlot){
-			if (lockedLocation != null && lockedLocation != newSlot.getTaskManagerID()) {
+			if (lockedLocation != null && !Objects.equals(lockedLocation, newSlot.getTaskManagerLocation())) {
 				throw new IllegalArgumentException(
 						"Cannot assign different location to a constraint whose location is locked.");
 			}
 			if (this.sharedSlot.isAlive()) {
-				this.sharedSlot.releaseInstanceSlot();
+				this.sharedSlot.releaseSlot(new FlinkException("Setting new shared slot for co-location constraint."));
 			}
 
 			this.sharedSlot = newSlot;
@@ -159,7 +165,43 @@ public class CoLocationConstraint {
 		checkState(lockedLocation == null, "Location is already locked");
 		checkState(sharedSlot != null, "Cannot lock location without a slot.");
 
-		lockedLocation = sharedSlot.getTaskManagerID();
+		lockedLocation = sharedSlot.getTaskManagerLocation();
+	}
+
+	/**
+	 * Locks the location of this slot. The location can be locked only once
+	 * and only after a shared slot has been assigned.
+	 *
+	 * <p>Note: This method exists for compatibility reasons with the Flip-6 SlotPool
+	 *
+	 * @param taskManagerLocation to lock this co-location constraint to
+	 */
+	public void lockLocation(TaskManagerLocation taskManagerLocation) {
+		checkNotNull(taskManagerLocation);
+		checkState(lockedLocation == null, "Location is already locked.");
+
+		lockedLocation = taskManagerLocation;
+	}
+
+	/**
+	 * Sets the slot request id of the currently assigned slot to the co-location constraint.
+	 * All other tasks belonging to this co-location constraint will be deployed to the same slot.
+	 *
+	 * @param slotRequestId identifying the assigned slot for this co-location constraint
+	 */
+	public void setSlotRequestId(@Nullable SlotRequestId slotRequestId) {
+		this.slotRequestId = slotRequestId;
+	}
+
+	/**
+	 * Returns the currently assigned slot request id identifying the slot to which tasks
+	 * belonging to this co-location constraint will be deployed to.
+	 *
+	 * @return Slot request id of the assigned slot or null if none
+	 */
+	@Nullable
+	public SlotRequestId getSlotRequestId() {
+		return slotRequestId;
 	}
 
 	// ------------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/NoResourceAvailableException.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/NoResourceAvailableException.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/NoResourceAvailableException.java
index 546f31f..e1c1657 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/NoResourceAvailableException.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/NoResourceAvailableException.java
@@ -44,8 +44,8 @@ public class NoResourceAvailableException extends JobException {
 	NoResourceAvailableException(ScheduledUnit task, int numInstances, int numSlotsTotal, int availableSlots) {
 		super(String.format("%s Task to schedule: < %s > with groupID < %s > in sharing group < %s >. Resources available to scheduler: Number of instances=%d, total number of slots=%d, available slots=%d",
 				BASE_MESSAGE, task.getTaskToExecute(),
-				task.getLocationConstraint() == null ? task.getTaskToExecute().getVertex().getJobvertexId() : task.getLocationConstraint().getGroupId(),
-				task.getSlotSharingGroup(),
+				task.getCoLocationConstraint() == null ? task.getTaskToExecute().getVertex().getJobvertexId() : task.getCoLocationConstraint().getGroupId(),
+				task.getSlotSharingGroupId(),
 				numInstances,
 				numSlotsTotal,
 				availableSlots));

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/ScheduledUnit.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/ScheduledUnit.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/ScheduledUnit.java
index 7348c9d..903872b 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/ScheduledUnit.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/ScheduledUnit.java
@@ -19,68 +19,108 @@
 package org.apache.flink.runtime.jobmanager.scheduler;
 
 import org.apache.flink.runtime.executiongraph.Execution;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
 import org.apache.flink.util.Preconditions;
 
+import javax.annotation.Nullable;
+
+/**
+ * ScheduledUnit contains the information necessary to allocate a slot for the given
+ * {@link JobVertexID}.
+ */
 public class ScheduledUnit {
-	
+
+	@Nullable
 	private final Execution vertexExecution;
-	
-	private final SlotSharingGroup sharingGroup;
-	
-	private final CoLocationConstraint locationConstraint;
+
+	private final JobVertexID jobVertexId;
+
+	@Nullable
+	private final SlotSharingGroupId slotSharingGroupId;
+
+	@Nullable
+	private final CoLocationConstraint coLocationConstraint;
 	
 	// --------------------------------------------------------------------------------------------
 	
 	public ScheduledUnit(Execution task) {
-		Preconditions.checkNotNull(task);
-		
-		this.vertexExecution = task;
-		this.sharingGroup = null;
-		this.locationConstraint = null;
+		this(
+			Preconditions.checkNotNull(task),
+			task.getVertex().getJobvertexId(),
+			null,
+			null);
 	}
 	
-	public ScheduledUnit(Execution task, SlotSharingGroup sharingUnit) {
-		Preconditions.checkNotNull(task);
-		
-		this.vertexExecution = task;
-		this.sharingGroup = sharingUnit;
-		this.locationConstraint = null;
+	public ScheduledUnit(Execution task, @Nullable SlotSharingGroupId slotSharingGroupId) {
+		this(
+			Preconditions.checkNotNull(task),
+			task.getVertex().getJobvertexId(),
+			slotSharingGroupId,
+			null);
 	}
 	
-	public ScheduledUnit(Execution task, SlotSharingGroup sharingUnit, CoLocationConstraint locationConstraint) {
-		Preconditions.checkNotNull(task);
-		Preconditions.checkNotNull(sharingUnit);
-		Preconditions.checkNotNull(locationConstraint);
-		
+	public ScheduledUnit(
+			Execution task,
+			@Nullable SlotSharingGroupId slotSharingGroupId,
+			@Nullable CoLocationConstraint coLocationConstraint) {
+		this(
+			Preconditions.checkNotNull(task),
+			task.getVertex().getJobvertexId(),
+			slotSharingGroupId,
+			coLocationConstraint);
+	}
+
+	public ScheduledUnit(
+			JobVertexID jobVertexId,
+			@Nullable SlotSharingGroupId slotSharingGroupId,
+			@Nullable CoLocationConstraint coLocationConstraint) {
+		this(
+			null,
+			jobVertexId,
+			slotSharingGroupId,
+			coLocationConstraint);
+	}
+
+	public ScheduledUnit(
+		@Nullable Execution task,
+		JobVertexID jobVertexId,
+		@Nullable SlotSharingGroupId slotSharingGroupId,
+		@Nullable CoLocationConstraint coLocationConstraint) {
+
 		this.vertexExecution = task;
-		this.sharingGroup = sharingUnit;
-		this.locationConstraint = locationConstraint;
+		this.jobVertexId = Preconditions.checkNotNull(jobVertexId);
+		this.slotSharingGroupId = slotSharingGroupId;
+		this.coLocationConstraint = coLocationConstraint;
+
 	}
 
 	// --------------------------------------------------------------------------------------------
 	
 	public JobVertexID getJobVertexId() {
-		return this.vertexExecution.getVertex().getJobvertexId();
+		return jobVertexId;
 	}
-	
+
+	@Nullable
 	public Execution getTaskToExecute() {
 		return vertexExecution;
 	}
-	
-	public SlotSharingGroup getSlotSharingGroup() {
-		return sharingGroup;
+
+	@Nullable
+	public SlotSharingGroupId getSlotSharingGroupId() {
+		return slotSharingGroupId;
 	}
-	
-	public CoLocationConstraint getLocationConstraint() {
-		return locationConstraint;
+
+	@Nullable
+	public CoLocationConstraint getCoLocationConstraint() {
+		return coLocationConstraint;
 	}
 
 	// --------------------------------------------------------------------------------------------
 	
 	@Override
 	public String toString() {
-		return "{task=" + vertexExecution.getVertexWithAttempt() + ", sharingUnit=" + sharingGroup + 
-				", locationConstraint=" + locationConstraint + '}';
+		return "{task=" + vertexExecution.getVertexWithAttempt() + ", sharingUnit=" + slotSharingGroupId +
+				", locationConstraint=" + coLocationConstraint + '}';
 	}
 }

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/Scheduler.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/Scheduler.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/Scheduler.java
index a3c38e0..40fb760 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/Scheduler.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/Scheduler.java
@@ -18,20 +18,22 @@
 
 package org.apache.flink.runtime.jobmanager.scheduler;
 
+import org.apache.flink.annotation.VisibleForTesting;
 import org.apache.flink.runtime.clusterframework.types.ResourceID;
 import org.apache.flink.runtime.concurrent.FutureUtils;
 import org.apache.flink.runtime.executiongraph.ExecutionVertex;
 import org.apache.flink.runtime.instance.Instance;
 import org.apache.flink.runtime.instance.InstanceDiedException;
 import org.apache.flink.runtime.instance.InstanceListener;
-import org.apache.flink.runtime.instance.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
 import org.apache.flink.runtime.instance.SharedSlot;
 import org.apache.flink.runtime.instance.SimpleSlot;
-import org.apache.flink.runtime.instance.SlotProvider;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
 import org.apache.flink.runtime.instance.SlotSharingGroupAssignment;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
 import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
 import org.apache.flink.util.ExceptionUtils;
+import org.apache.flink.util.FlinkException;
 import org.apache.flink.util.Preconditions;
 
 import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -39,6 +41,8 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.annotation.Nullable;
+
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -49,6 +53,7 @@ import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Queue;
 import java.util.Set;
 import java.util.concurrent.BlockingQueue;
@@ -177,7 +182,7 @@ public class Scheduler implements InstanceListener, SlotAvailabilityListener, Sl
 	
 		synchronized (globalLock) {
 			
-			SlotSharingGroup sharingUnit = task.getSlotSharingGroup();
+			SlotSharingGroup sharingUnit = vertex.getJobVertex().getSlotSharingGroup();
 			
 			if (sharingUnit != null) {
 
@@ -189,7 +194,7 @@ public class Scheduler implements InstanceListener, SlotAvailabilityListener, Sl
 				}
 				
 				final SlotSharingGroupAssignment assignment = sharingUnit.getTaskAssignment();
-				final CoLocationConstraint constraint = task.getLocationConstraint();
+				final CoLocationConstraint constraint = task.getCoLocationConstraint();
 				
 				// sanity check that we do not use an externally forced location and a co-location constraint together
 				if (constraint != null && forceExternalLocation) {
@@ -274,7 +279,7 @@ public class Scheduler implements InstanceListener, SlotAvailabilityListener, Sl
 						// if there is no slot from the group, or the new slot is local,
 						// then we use the new slot
 						if (slotFromGroup != null) {
-							slotFromGroup.releaseInstanceSlot();
+							slotFromGroup.releaseSlot(null);
 						}
 						toUse = newSlot;
 					}
@@ -282,7 +287,7 @@ public class Scheduler implements InstanceListener, SlotAvailabilityListener, Sl
 						// both are available and usable. neither is local. in that case, we may
 						// as well use the slot from the sharing group, to minimize the number of
 						// instances that the job occupies
-						newSlot.releaseInstanceSlot();
+						newSlot.releaseSlot(null);
 						toUse = slotFromGroup;
 					}
 
@@ -299,10 +304,10 @@ public class Scheduler implements InstanceListener, SlotAvailabilityListener, Sl
 				}
 				catch (Throwable t) {
 					if (slotFromGroup != null) {
-						slotFromGroup.releaseInstanceSlot();
+						slotFromGroup.releaseSlot(t);
 					}
 					if (newSlot != null) {
-						newSlot.releaseInstanceSlot();
+						newSlot.releaseSlot(t);
 					}
 
 					ExceptionUtils.rethrow(t, "An error occurred while allocating a slot in a sharing group");
@@ -444,7 +449,7 @@ public class Scheduler implements InstanceListener, SlotAvailabilityListener, Sl
 					}
 					else {
 						// could not add and allocate the sub-slot, so release shared slot
-						sharedSlot.releaseInstanceSlot();
+						sharedSlot.releaseSlot(new FlinkException("Could not allocate sub-slot."));
 					}
 				}
 			}
@@ -854,4 +859,19 @@ public class Scheduler implements InstanceListener, SlotAvailabilityListener, Sl
 			return future;
 		}
 	}
+
+	// ------------------------------------------------------------------------
+	//  Testing methods
+	// ------------------------------------------------------------------------
+
+	@VisibleForTesting
+	@Nullable
+	public Instance getInstance(ResourceID resourceId) {
+		for (Instance instance : allInstances) {
+			if (Objects.equals(resourceId, instance.getTaskManagerID())) {
+				return instance;
+			}
+		}
+		return null;
+	}
 }

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/SlotSharingGroup.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/SlotSharingGroup.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/SlotSharingGroup.java
index 0fa1362..86be9d4 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/SlotSharingGroup.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/scheduler/SlotSharingGroup.java
@@ -23,6 +23,7 @@ import java.util.Set;
 import java.util.TreeSet;
 
 import org.apache.flink.runtime.instance.SlotSharingGroupAssignment;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
 import org.apache.flink.runtime.jobgraph.JobVertexID;
 
 /**
@@ -39,7 +40,8 @@ public class SlotSharingGroup implements java.io.Serializable {
 	
 	/** Mapping of tasks to subslots. This field is only needed inside the JobManager, and is not RPCed. */
 	private transient SlotSharingGroupAssignment taskAssignment;
-	
+
+	private final SlotSharingGroupId slotSharingGroupId = new SlotSharingGroupId();
 	
 	public SlotSharingGroup() {}
 	
@@ -62,8 +64,11 @@ public class SlotSharingGroup implements java.io.Serializable {
 	public Set<JobVertexID> getJobVertexIds() {
 		return Collections.unmodifiableSet(ids);
 	}
-	
-	
+
+	public SlotSharingGroupId getSlotSharingGroupId() {
+		return slotSharingGroupId;
+	}
+
 	public SlotSharingGroupAssignment getTaskAssignment() {
 		if (this.taskAssignment == null) {
 			this.taskAssignment = new SlotSharingGroupAssignment();

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SimpleSlotContext.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SimpleSlotContext.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SimpleSlotContext.java
deleted file mode 100644
index a5b75d7..0000000
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SimpleSlotContext.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.jobmanager.slots;
-
-import org.apache.flink.runtime.clusterframework.types.AllocationID;
-import org.apache.flink.runtime.instance.SlotRequestID;
-import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-import org.apache.flink.util.Preconditions;
-
-/**
- * Simple implementation of the {@link SlotContext} interface for the legacy code.
- */
-public class SimpleSlotContext implements SlotContext {
-
-	private final SlotRequestID slotRequestId;
-
-	private final AllocationID allocationId;
-
-	private final TaskManagerLocation taskManagerLocation;
-
-	private final int physicalSlotNumber;
-
-	private final TaskManagerGateway taskManagerGateway;
-
-	public SimpleSlotContext(
-			SlotRequestID slotRequestId,
-			AllocationID allocationId,
-			TaskManagerLocation taskManagerLocation,
-			int physicalSlotNumber,
-			TaskManagerGateway taskManagerGateway) {
-		this.slotRequestId = Preconditions.checkNotNull(slotRequestId);
-		this.allocationId = Preconditions.checkNotNull(allocationId);
-		this.taskManagerLocation = Preconditions.checkNotNull(taskManagerLocation);
-		this.physicalSlotNumber = physicalSlotNumber;
-		this.taskManagerGateway = Preconditions.checkNotNull(taskManagerGateway);
-	}
-
-	@Override
-	public SlotRequestID getSlotRequestId() {
-		return slotRequestId;
-	}
-
-	@Override
-	public AllocationID getAllocationId() {
-		return allocationId;
-	}
-
-	@Override
-	public TaskManagerLocation getTaskManagerLocation() {
-		return taskManagerLocation;
-	}
-
-	@Override
-	public int getPhysicalSlotNumber() {
-		return physicalSlotNumber;
-	}
-
-	@Override
-	public TaskManagerGateway getTaskManagerGateway() {
-		return taskManagerGateway;
-	}
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotAndLocality.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotAndLocality.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotAndLocality.java
index 5ae057d..85871c8 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotAndLocality.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotAndLocality.java
@@ -18,7 +18,7 @@
 
 package org.apache.flink.runtime.jobmanager.slots;
 
-import org.apache.flink.runtime.instance.AllocatedSlot;
+import org.apache.flink.runtime.jobmaster.slotpool.AllocatedSlot;
 import org.apache.flink.runtime.jobmanager.scheduler.Locality;
 
 import static org.apache.flink.util.Preconditions.checkNotNull;
@@ -39,11 +39,11 @@ public class SlotAndLocality {
 
 	// ------------------------------------------------------------------------
 
-	public AllocatedSlot slot() {
+	public AllocatedSlot getSlot() {
 		return slot;
 	}
 
-	public Locality locality() {
+	public Locality getLocality() {
 		return locality;
 	}
 

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotContext.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotContext.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotContext.java
deleted file mode 100644
index 1e0317a..0000000
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotContext.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.jobmanager.slots;
-
-import org.apache.flink.runtime.clusterframework.types.AllocationID;
-import org.apache.flink.runtime.instance.Slot;
-import org.apache.flink.runtime.instance.SlotRequestID;
-import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
-
-/**
- * Interface for the context of a logical {@link Slot}. This context contains information
- * about the underlying allocated slot and how to communicate with the TaskManager on which
- * it was allocated.
- */
-public interface SlotContext {
-
-	/**
-	 * Gets the slot request id under which the slot has been requested. This id uniquely identifies the logical slot.
-	 *
-	 * @return The id under which the slot has been requested
-	 */
-	SlotRequestID getSlotRequestId();
-
-	/**
-	 * Gets the id under which the slot has been allocated on the TaskManager. This id uniquely identifies the
-	 * physical slot.
-	 *
-	 * @return The id under whic teh slot has been allocated on the TaskManager
-	 */
-	AllocationID getAllocationId();
-
-	/**
-	 * Gets the location info of the TaskManager that offers this slot.
-	 *
-	 * @return The location info of the TaskManager that offers this slot
-	 */
-	TaskManagerLocation getTaskManagerLocation();
-
-	/**
-	 * Gets the number of the slot.
-	 *
-	 * @return The number of the slot on the TaskManager.
-	 */
-	int getPhysicalSlotNumber();
-
-	/**
-	 * Gets the actor gateway that can be used to send messages to the TaskManager.
-	 * <p>
-	 * This method should be removed once the new interface-based RPC abstraction is in place
-	 *
-	 * @return The gateway that can be used to send messages to the TaskManager.
-	 */
-	TaskManagerGateway getTaskManagerGateway();
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotOwner.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotOwner.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotOwner.java
deleted file mode 100644
index bc1ced4..0000000
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmanager/slots/SlotOwner.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.jobmanager.slots;
-
-import org.apache.flink.runtime.instance.LogicalSlot;
-
-import java.util.concurrent.CompletableFuture;
-
-/**
- * Interface for components that hold slots and to which slots get released / recycled.
- */
-public interface SlotOwner {
-
-	/**
-	 * Return the given slot to the slot owner.
-	 *
-	 * @param logicalSlot to return
-	 * @return Future which is completed with true if the slot could be returned, otherwise with false
-	 */
-	CompletableFuture<Boolean> returnAllocatedSlot(LogicalSlot logicalSlot);
-}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/JobMaster.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/JobMaster.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/JobMaster.java
index 324557f..7a2844d 100644
--- a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/JobMaster.java
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/JobMaster.java
@@ -55,9 +55,8 @@ import org.apache.flink.runtime.heartbeat.HeartbeatManager;
 import org.apache.flink.runtime.heartbeat.HeartbeatServices;
 import org.apache.flink.runtime.heartbeat.HeartbeatTarget;
 import org.apache.flink.runtime.highavailability.HighAvailabilityServices;
-import org.apache.flink.runtime.instance.LogicalSlot;
-import org.apache.flink.runtime.instance.SlotPool;
-import org.apache.flink.runtime.instance.SlotPoolGateway;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotPool;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotPoolGateway;
 import org.apache.flink.runtime.io.network.partition.ResultPartitionID;
 import org.apache.flink.runtime.jobgraph.IntermediateDataSetID;
 import org.apache.flink.runtime.jobgraph.JobGraph;


[09/11] flink git commit: [FLINK-7956] [flip6] Add support for queued scheduling with slot sharing to SlotPool

Posted by tr...@apache.org.
http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/LogicalSlot.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/LogicalSlot.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/LogicalSlot.java
new file mode 100644
index 0000000..4511bf6
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/LogicalSlot.java
@@ -0,0 +1,165 @@
+/*
+ * 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;
+
+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.taskmanager.TaskManagerLocation;
+
+import javax.annotation.Nullable;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * A logical slot represents a resource on a TaskManager into
+ * which a single task can be deployed.
+ */
+public interface LogicalSlot {
+
+	Payload TERMINATED_PAYLOAD = new Payload() {
+
+		private final CompletableFuture<?> completedTerminationFuture = CompletableFuture.completedFuture(null);
+		@Override
+		public void fail(Throwable cause) {
+			// ignore
+		}
+
+		@Override
+		public CompletableFuture<?> getTerminalStateFuture() {
+			return completedTerminationFuture;
+		}
+	};
+
+	/**
+	 * Return the TaskManager location of this slot.
+	 *
+	 * @return TaskManager location of this slot
+	 */
+	TaskManagerLocation getTaskManagerLocation();
+
+	/**
+	 * Return the TaskManager gateway to talk to the TaskManager.
+	 *
+	 * @return TaskManager gateway to talk to the TaskManager
+	 */
+	TaskManagerGateway getTaskManagerGateway();
+
+	/**
+	 * Gets the locality of this slot.
+	 *
+	 * @return locality of this slot
+	 */
+	Locality getLocality();
+
+	/**
+	 * True if the slot is alive and has not been released.
+	 *
+	 * @return True if the slot is alive, otherwise false if the slot is released
+	 */
+	boolean isAlive();
+
+	/**
+	 * Tries to assign a payload to this slot. One can only assign a single
+	 * payload once.
+	 *
+	 * @param payload to be assigned to this slot.
+	 * @return true if the payload could be assigned, otherwise false
+	 */
+	boolean tryAssignPayload(Payload payload);
+
+	/**
+	 * Returns the set payload or null if none.
+	 *
+	 * @return Payload of this slot of null if none
+	 */
+	@Nullable
+	Payload getPayload();
+
+	/**
+	 * Releases this slot.
+	 *
+	 * @return Future which is completed once the slot has been released,
+	 * 		in case of a failure it is completed exceptionally
+	 * @deprecated Added because extended the actual releaseSlot method with cause parameter.
+	 */
+	default CompletableFuture<?> releaseSlot() {
+		return releaseSlot(null);
+	}
+
+	/**
+	 * Releases this slot.
+	 *
+	 * @param cause why the slot was released or null if none
+	 * @return future which is completed once the slot has been released
+	 */
+	CompletableFuture<?> releaseSlot(@Nullable Throwable cause);
+
+	/**
+	 * Gets the slot number on the TaskManager.
+	 *
+	 * @return slot number
+	 */
+	int getPhysicalSlotNumber();
+
+	/**
+	 * Gets the allocation id of this slot.
+	 *
+	 * @return allocation id of this slot
+	 */
+	AllocationID getAllocationId();
+
+	/**
+	 * Gets the slot request id uniquely identifying the request with which this
+	 * slot has been allocated.
+	 *
+	 * @return Unique id identifying the slot request with which this slot was allocated
+	 */
+	SlotRequestId getSlotRequestId();
+
+	/**
+	 * Gets the slot sharing group id to which this slot belongs.
+	 *
+	 * @return slot sharing group id of this slot or null, if none.
+	 */
+	@Nullable
+	SlotSharingGroupId getSlotSharingGroupId();
+
+	/**
+	 * Payload for a logical slot.
+	 */
+	interface Payload {
+
+		/**
+		 * Fail the payload with the given cause.
+		 *
+		 * @param cause of the failure
+		 */
+		void fail(Throwable cause);
+
+		/**
+		 * Gets the terminal state future which is completed once the payload
+		 * has reached a terminal state.
+		 *
+		 * @return Terminal state future
+		 */
+		CompletableFuture<?> getTerminalStateFuture();
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/SlotContext.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/SlotContext.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/SlotContext.java
new file mode 100644
index 0000000..65bf2a1
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/SlotContext.java
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+import org.apache.flink.runtime.clusterframework.types.AllocationID;
+import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+
+/**
+ * Interface for the context of a {@link LogicalSlot}. This context contains information
+ * about the underlying allocated slot and how to communicate with the TaskManager on which
+ * it was allocated.
+ */
+public interface SlotContext {
+	/**
+	 * Gets the id under which the slot has been allocated on the TaskManager. This id uniquely identifies the
+	 * physical slot.
+	 *
+	 * @return The id under whic teh slot has been allocated on the TaskManager
+	 */
+	AllocationID getAllocationId();
+
+	/**
+	 * Gets the location info of the TaskManager that offers this slot.
+	 *
+	 * @return The location info of the TaskManager that offers this slot
+	 */
+	TaskManagerLocation getTaskManagerLocation();
+
+	/**
+	 * Gets the number of the slot.
+	 *
+	 * @return The number of the slot on the TaskManager.
+	 */
+	int getPhysicalSlotNumber();
+
+	/**
+	 * Gets the actor gateway that can be used to send messages to the TaskManager.
+	 * <p>
+	 * This method should be removed once the new interface-based RPC abstraction is in place
+	 *
+	 * @return The gateway that can be used to send messages to the TaskManager.
+	 */
+	TaskManagerGateway getTaskManagerGateway();
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/SlotOwner.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/SlotOwner.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/SlotOwner.java
new file mode 100644
index 0000000..9cc6f81
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/SlotOwner.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Interface for components that hold slots and to which slots get released / recycled.
+ */
+public interface SlotOwner {
+
+	/**
+	 * Return the given slot to the slot owner.
+	 *
+	 * @param logicalSlot to return
+	 * @return Future which is completed with true if the slot could be returned, otherwise with false
+	 */
+	CompletableFuture<Boolean> returnAllocatedSlot(LogicalSlot logicalSlot);
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/SlotRequestId.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/SlotRequestId.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/SlotRequestId.java
new file mode 100644
index 0000000..d3fa775
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/SlotRequestId.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+import org.apache.flink.runtime.jobmaster.slotpool.SlotPool;
+import org.apache.flink.runtime.jobmaster.slotpool.SlotProvider;
+import org.apache.flink.util.AbstractID;
+
+/**
+ * Request id identifying slot requests made by the {@link SlotProvider} towards the
+ * {@link SlotPool}.
+ */
+public final class SlotRequestId extends AbstractID {
+    private static final long serialVersionUID = -6072105912250154283L;
+
+    public SlotRequestId(long lowerPart, long upperPart) {
+        super(lowerPart, upperPart);
+    }
+
+    public SlotRequestId() {}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/AllocatedSlot.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/AllocatedSlot.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/AllocatedSlot.java
new file mode 100644
index 0000000..a560ebc
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/AllocatedSlot.java
@@ -0,0 +1,225 @@
+/*
+ * 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.clusterframework.types.ResourceID;
+import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
+import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+import org.apache.flink.runtime.jobmaster.SlotContext;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.apache.flink.util.Preconditions.checkNotNull;
+
+/**
+ * The {@code AllocatedSlot} represents a slot that the JobMaster allocated from a TaskExecutor.
+ * It represents a slice of allocated resources from the TaskExecutor.
+ * 
+ * <p>To allocate an {@code AllocatedSlot}, the requests a slot from the ResourceManager. The
+ * ResourceManager picks (or starts) a TaskExecutor that will then allocate the slot to the
+ * JobMaster and notify the JobMaster.
+ * 
+ * <p>Note: Prior to the resource management changes introduced in (Flink Improvement Proposal 6),
+ * an AllocatedSlot was allocated to the JobManager as soon as the TaskManager registered at the
+ * JobManager. All slots had a default unknown resource profile. 
+ */
+public class AllocatedSlot implements SlotContext {
+
+	/** The ID under which the slot is allocated. Uniquely identifies the slot. */
+	private final AllocationID allocationId;
+
+	/** The location information of the TaskManager to which this slot belongs */
+	private final TaskManagerLocation taskManagerLocation;
+
+	/** The resource profile of the slot provides */
+	private final ResourceProfile resourceProfile;
+
+	/** RPC gateway to call the TaskManager that holds this slot */
+	private final TaskManagerGateway taskManagerGateway;
+
+	/** The number of the slot on the TaskManager to which slot belongs. Purely informational. */
+	private final int physicalSlotNumber;
+
+	private final AtomicReference<Payload> payloadReference;
+
+	// ------------------------------------------------------------------------
+
+	public AllocatedSlot(
+			AllocationID allocationId,
+			TaskManagerLocation location,
+			int physicalSlotNumber,
+			ResourceProfile resourceProfile,
+			TaskManagerGateway taskManagerGateway) {
+		this.allocationId = checkNotNull(allocationId);
+		this.taskManagerLocation = checkNotNull(location);
+		this.physicalSlotNumber = physicalSlotNumber;
+		this.resourceProfile = checkNotNull(resourceProfile);
+		this.taskManagerGateway = checkNotNull(taskManagerGateway);
+
+		payloadReference = new AtomicReference<>(null);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Gets the ID under which the slot is allocated, which uniquely identifies the slot.
+	 * 
+	 * @return The ID under which the slot is allocated
+	 */
+	public AllocationID getAllocationId() {
+		return allocationId;
+	}
+
+	/**
+	 * Gets the ID of the TaskManager on which this slot was allocated.
+	 * 
+	 * <p>This is equivalent to {@link #getTaskManagerLocation()#getTaskManagerId()}.
+	 * 
+	 * @return This slot's TaskManager's ID.
+	 */
+	public ResourceID getTaskManagerId() {
+		return getTaskManagerLocation().getResourceID();
+	}
+
+	/**
+	 * Gets the resource profile of the slot.
+	 *
+	 * @return The resource profile of the slot.
+	 */
+	public ResourceProfile getResourceProfile() {
+		return resourceProfile;
+	}
+
+	/**
+	 * Gets the location info of the TaskManager that offers this slot.
+	 *
+	 * @return The location info of the TaskManager that offers this slot
+	 */
+	public TaskManagerLocation getTaskManagerLocation() {
+		return taskManagerLocation;
+	}
+
+	/**
+	 * Gets the actor gateway that can be used to send messages to the TaskManager.
+	 * <p>
+	 * This method should be removed once the new interface-based RPC abstraction is in place
+	 *
+	 * @return The actor gateway that can be used to send messages to the TaskManager.
+	 */
+	public TaskManagerGateway getTaskManagerGateway() {
+		return taskManagerGateway;
+	}
+
+	/**
+	 * Returns the physical slot number of the allocated slot. The physical slot number corresponds
+	 * to the slot index on the TaskExecutor.
+	 *
+	 * @return Physical slot number of the allocated slot
+	 */
+	public int getPhysicalSlotNumber() {
+		return physicalSlotNumber;
+	}
+
+	/**
+	 * Returns true if this slot is not being used (e.g. a logical slot is allocated from this slot).
+	 *
+	 * @return true if a logical slot is allocated from this slot, otherwise false
+	 */
+	public boolean isUsed() {
+		return payloadReference.get() != null;
+	}
+
+	/**
+	 * Tries to assign the given payload to this allocated slot. This only works if there has not
+	 * been another payload assigned to this slot.
+	 *
+	 * @param payload to assign to this slot
+	 * @return true if the payload could be assigned, otherwise false
+	 */
+	public boolean tryAssignPayload(Payload payload) {
+		return payloadReference.compareAndSet(null, payload);
+	}
+
+	/**
+	 * Triggers the release of the assigned payload. If the payload could be released,
+	 * then it is removed from the slot.
+	 *
+	 * @param cause of the release operation
+	 * @return true if the payload could be released and was removed from the slot, otherwise false
+	 */
+	public boolean releasePayload(Throwable cause) {
+		final Payload payload = payloadReference.get();
+
+		if (payload != null) {
+			if (payload.release(cause)) {
+				payloadReference.set(null);
+
+				return true;
+			} else {
+				return false;
+			}
+		} else {
+			return true;
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * This always returns a reference hash code.
+	 */
+	@Override
+	public final int hashCode() {
+		return super.hashCode();
+	}
+
+	/**
+	 * This always checks based on reference equality.
+	 */
+	@Override
+	public final boolean equals(Object obj) {
+		return this == obj;
+	}
+
+	@Override
+	public String toString() {
+		return "AllocatedSlot " + allocationId + " @ " + taskManagerLocation + " - " + physicalSlotNumber;
+	}
+
+	// -----------------------------------------------------------------------
+	// Interfaces
+	// -----------------------------------------------------------------------
+
+	/**
+	 * Payload which can be assigned to an {@link AllocatedSlot}.
+	 */
+	interface Payload {
+
+		/**
+		 * Releases the payload. If the payload could be released, then it returns true,
+		 * otherwise false.
+		 *
+		 * @param cause of the payload release
+		 * @return true if the payload could be released, otherwise false
+		 */
+		boolean release(Throwable cause);
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/AllocatedSlotActions.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/AllocatedSlotActions.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/AllocatedSlotActions.java
new file mode 100644
index 0000000..045678e
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/AllocatedSlotActions.java
@@ -0,0 +1,48 @@
+/*
+ * 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.jobmaster.SlotRequestId;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.messages.Acknowledge;
+
+import javax.annotation.Nullable;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Interface for components which have to perform actions on allocated slots.
+ */
+public interface AllocatedSlotActions {
+
+	/**
+	 * Releases the slot with the given {@link SlotRequestId}. If the slot belonged to a
+	 * slot sharing group, then the corresponding {@link SlotSharingGroupId} has to be
+	 * provided. Additionally, one can provide a cause for the slot release.
+	 *
+	 * @param slotRequestId identifying the slot to release
+	 * @param slotSharingGroupId identifying the slot sharing group to which the slot belongs, null if none
+	 * @param cause of the slot release, null if none
+	 * @return Acknowledge (future) after the slot has been released
+	 */
+	CompletableFuture<Acknowledge> releaseSlot(
+		SlotRequestId slotRequestId,
+		@Nullable SlotSharingGroupId slotSharingGroupId,
+		@Nullable Throwable cause);
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/DualKeyMap.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/DualKeyMap.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/DualKeyMap.java
new file mode 100644
index 0000000..04b3ca6
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/DualKeyMap.java
@@ -0,0 +1,172 @@
+/*
+ * 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.api.java.tuple.Tuple2;
+
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * Map which stores values under two different indices.
+ *
+ * @param <A> Type of key A
+ * @param <B> Type of key B
+ * @param <V> Type of the value
+ */
+public class DualKeyMap<A, B, V> {
+
+	private final HashMap<A, Tuple2<B, V>> aMap;
+
+	private final HashMap<B, A> bMap;
+
+	private transient Collection<V> values;
+
+	public DualKeyMap(int initialCapacity) {
+		this.aMap = new HashMap<>(initialCapacity);
+		this.bMap = new HashMap<>(initialCapacity);
+	}
+
+	public int size() {
+		return aMap.size();
+	}
+
+	public V getKeyA(A aKey) {
+		final Tuple2<B, V> value = aMap.get(aKey);
+
+		if (value != null) {
+			return value.f1;
+		} else {
+			return null;
+		}
+	}
+
+	public V getKeyB(B bKey) {
+		final A aKey = bMap.get(bKey);
+
+		if (aKey != null) {
+			return aMap.get(aKey).f1;
+		} else {
+			return null;
+		}
+	}
+
+	public V put(A aKey, B bKey, V value) {
+		Tuple2<B, V> aValue = aMap.put(aKey, Tuple2.of(bKey, value));
+		bMap.put(bKey, aKey);
+
+		if (aValue != null) {
+			return aValue.f1;
+		} else {
+			return null;
+		}
+	}
+
+	public boolean containsKeyA(A aKey) {
+		return aMap.containsKey(aKey);
+	}
+
+	public boolean containsKeyB(B bKey) {
+		return bMap.containsKey(bKey);
+	}
+
+	public V removeKeyA(A aKey) {
+		Tuple2<B, V> aValue = aMap.remove(aKey);
+
+		if (aValue != null) {
+			bMap.remove(aValue.f0);
+			return aValue.f1;
+		} else {
+			return null;
+		}
+	}
+
+	public V removeKeyB(B bKey) {
+		A aKey = bMap.remove(bKey);
+
+		if (aKey != null) {
+			Tuple2<B, V> aValue = aMap.remove(aKey);
+			if (aValue != null) {
+				return aValue.f1;
+			} else {
+				return null;
+			}
+		} else {
+			return null;
+		}
+	}
+
+	public Collection<V> values() {
+		Collection<V> vs = values;
+
+		if (vs == null) {
+			vs = new Values();
+			values = vs;
+		}
+
+		return vs;
+	}
+
+	public void clear() {
+		aMap.clear();
+		bMap.clear();
+	}
+
+	// -----------------------------------------------------------------------
+	// Inner classes
+	// -----------------------------------------------------------------------
+
+	/**
+	 * Collection which contains the values of the dual key map.
+	 */
+	private final class Values extends AbstractCollection<V> {
+
+		@Override
+		public Iterator<V> iterator() {
+			return new ValueIterator();
+		}
+
+		@Override
+		public int size() {
+			return aMap.size();
+		}
+	}
+
+	/**
+	 * Iterator which iterates over the values of the dual key map.
+	 */
+	private final class ValueIterator implements Iterator<V> {
+
+		private final Iterator<Tuple2<B, V>> iterator = aMap.values().iterator();
+
+		@Override
+		public boolean hasNext() {
+			return iterator.hasNext();
+		}
+
+		@Override
+		public V next() {
+			Tuple2<B, V> value = iterator.next();
+
+			return value.f1;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SingleLogicalSlot.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SingleLogicalSlot.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SingleLogicalSlot.java
new file mode 100644
index 0000000..9bd559b
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SingleLogicalSlot.java
@@ -0,0 +1,170 @@
+/*
+ * 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.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.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.jobmanager.scheduler.Locality;
+import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+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<SingleLogicalSlot, Payload> PAYLOAD_UPDATER = AtomicReferenceFieldUpdater.newUpdater(
+		SingleLogicalSlot.class,
+		Payload.class,
+		"payload");
+
+	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;
+
+	// 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);
+
+		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() {
+		final Payload currentPayload = payload;
+
+		if (currentPayload != null) {
+			return !currentPayload.getTerminalStateFuture().isDone();
+		} else {
+			// We are always alive if there is no payload assigned yet.
+			// If this slot is released and no payload is assigned, then the TERMINATED_PAYLOAD is assigned
+			return true;
+		}
+	}
+
+	@Override
+	public boolean tryAssignPayload(Payload payload) {
+		Preconditions.checkNotNull(payload);
+		return PAYLOAD_UPDATER.compareAndSet(this, null, payload);
+	}
+
+	@Nullable
+	@Override
+	public Payload getPayload() {
+		return payload;
+	}
+
+	@Override
+	public CompletableFuture<?> releaseSlot(@Nullable Throwable cause) {
+		// set an already terminated payload if the payload of this slot is still empty
+		tryAssignPayload(TERMINATED_PAYLOAD);
+
+		// notify the payload that the slot will be released
+		payload.fail(cause);
+
+		// Wait until the payload has been terminated. Only then, we return the slot to its rightful owner
+		return payload.getTerminalStateFuture()
+			.handle((Object ignored, Throwable throwable) -> slotOwner.returnAllocatedSlot(this))
+			.thenApply(Function.identity());
+	}
+
+	@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
+	 * @return true if the logical slot's payload could be released, otherwise false
+	 */
+	@Override
+	public boolean release(Throwable cause) {
+		return releaseSlot(cause).isDone();
+	}
+}


[08/11] flink git commit: [FLINK-7956] [flip6] Add support for queued scheduling with slot sharing to SlotPool

Posted by tr...@apache.org.
http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPool.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPool.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPool.java
new file mode 100644
index 0000000..996e445
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPool.java
@@ -0,0 +1,1559 @@
+/*
+ * 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.annotation.VisibleForTesting;
+import org.apache.flink.api.common.JobID;
+import org.apache.flink.api.common.time.Time;
+import org.apache.flink.runtime.clusterframework.types.AllocationID;
+import org.apache.flink.runtime.clusterframework.types.ResourceID;
+import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
+import org.apache.flink.runtime.concurrent.FutureUtils;
+import org.apache.flink.runtime.executiongraph.ExecutionGraph;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.jobmanager.scheduler.CoLocationConstraint;
+import org.apache.flink.runtime.jobmanager.scheduler.Locality;
+import org.apache.flink.runtime.jobmanager.scheduler.NoResourceAvailableException;
+import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
+import org.apache.flink.runtime.jobmanager.slots.SlotAndLocality;
+import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+import org.apache.flink.runtime.jobmaster.JobMasterId;
+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.messages.Acknowledge;
+import org.apache.flink.runtime.resourcemanager.ResourceManagerGateway;
+import org.apache.flink.runtime.resourcemanager.SlotRequest;
+import org.apache.flink.runtime.rpc.RpcEndpoint;
+import org.apache.flink.runtime.rpc.RpcService;
+import org.apache.flink.runtime.taskexecutor.slot.SlotOffer;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+import org.apache.flink.runtime.util.clock.Clock;
+import org.apache.flink.runtime.util.clock.SystemClock;
+import org.apache.flink.util.AbstractID;
+import org.apache.flink.util.FlinkException;
+import org.apache.flink.util.Preconditions;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.apache.flink.util.Preconditions.checkNotNull;
+
+/**
+ * The slot pool serves slot request issued by {@link ExecutionGraph}. It will will attempt to acquire new slots
+ * from the ResourceManager when it cannot serve a slot request. If no ResourceManager is currently available,
+ * or it gets a decline from the ResourceManager, or a request times out, it fails the slot request. The slot pool also
+ * holds all the slots that were offered to it and accepted, and can thus provides registered free slots even if the
+ * ResourceManager is down. The slots will only be released when they are useless, e.g. when the job is fully running
+ * but we still have some free slots.
+ *
+ * <p>All the allocation or the slot offering will be identified by self generated AllocationID, we will use it to
+ * eliminate ambiguities.
+ *
+ * TODO : Make pending requests location preference aware
+ * TODO : Make pass location preferences to ResourceManager when sending a slot request
+ */
+public class SlotPool extends RpcEndpoint implements SlotPoolGateway, AllocatedSlotActions {
+
+	/** The log for the pool - shared also with the internal classes. */
+	static final Logger LOG = LoggerFactory.getLogger(SlotPool.class);
+
+	// ------------------------------------------------------------------------
+
+	private static final Time DEFAULT_SLOT_REQUEST_TIMEOUT = Time.minutes(5);
+
+	private static final Time DEFAULT_RM_ALLOCATION_TIMEOUT = Time.minutes(10);
+
+	private static final Time DEFAULT_RM_REQUEST_TIMEOUT = Time.seconds(10);
+
+	// ------------------------------------------------------------------------
+
+	private final JobID jobId;
+
+	private final ProviderAndOwner providerAndOwner;
+
+	/** All registered TaskManagers, slots will be accepted and used only if the resource is registered. */
+	private final HashSet<ResourceID> registeredTaskManagers;
+
+	/** The book-keeping of all allocated slots. */
+	private final AllocatedSlots allocatedSlots;
+
+	/** The book-keeping of all available slots. */
+	private final AvailableSlots availableSlots;
+
+	/** All pending requests waiting for slots. */
+	private final DualKeyMap<SlotRequestId, AllocationID, PendingRequest> pendingRequests;
+
+	/** The requests that are waiting for the resource manager to be connected. */
+	private final HashMap<SlotRequestId, PendingRequest> waitingForResourceManager;
+
+	/** Timeout for request calls to the ResourceManager. */
+	private final Time resourceManagerRequestsTimeout;
+
+	/** Timeout for allocation round trips (RM -> launch TM -> offer slot). */
+	private final Time resourceManagerAllocationTimeout;
+
+	private final Clock clock;
+
+	/** Managers for the different slot sharing groups. */
+	protected final Map<SlotSharingGroupId, SlotSharingManager> slotSharingManagers;
+
+	/** the fencing token of the job manager. */
+	private JobMasterId jobMasterId;
+
+	/** The gateway to communicate with resource manager. */
+	private ResourceManagerGateway resourceManagerGateway;
+
+	private String jobManagerAddress;
+
+	// ------------------------------------------------------------------------
+
+	public SlotPool(RpcService rpcService, JobID jobId) {
+		this(rpcService, jobId, SystemClock.getInstance(),
+				DEFAULT_SLOT_REQUEST_TIMEOUT, DEFAULT_RM_ALLOCATION_TIMEOUT, DEFAULT_RM_REQUEST_TIMEOUT);
+	}
+
+	public SlotPool(
+			RpcService rpcService,
+			JobID jobId,
+			Clock clock,
+			Time slotRequestTimeout,
+			Time resourceManagerAllocationTimeout,
+			Time resourceManagerRequestTimeout) {
+
+		super(rpcService);
+
+		this.jobId = checkNotNull(jobId);
+		this.clock = checkNotNull(clock);
+		this.resourceManagerRequestsTimeout = checkNotNull(resourceManagerRequestTimeout);
+		this.resourceManagerAllocationTimeout = checkNotNull(resourceManagerAllocationTimeout);
+
+		this.registeredTaskManagers = new HashSet<>();
+		this.allocatedSlots = new AllocatedSlots();
+		this.availableSlots = new AvailableSlots();
+		this.pendingRequests = new DualKeyMap<>(16);
+		this.waitingForResourceManager = new HashMap<>(16);
+
+		this.providerAndOwner = new ProviderAndOwner(getSelfGateway(SlotPoolGateway.class), slotRequestTimeout);
+
+		this.slotSharingManagers = new HashMap<>(4);
+
+		this.jobMasterId = null;
+		this.resourceManagerGateway = null;
+		this.jobManagerAddress = null;
+	}
+
+	// ------------------------------------------------------------------------
+	//  Starting and Stopping
+	// ------------------------------------------------------------------------
+
+	@Override
+	public void start() {
+		throw new UnsupportedOperationException("Should never call start() without leader ID");
+	}
+
+	/**
+	 * Start the slot pool to accept RPC calls.
+	 *
+	 * @param jobMasterId The necessary leader id for running the job.
+	 * @param newJobManagerAddress for the slot requests which are sent to the resource manager
+	 */
+	public void start(JobMasterId jobMasterId, String newJobManagerAddress) throws Exception {
+		this.jobMasterId = checkNotNull(jobMasterId);
+		this.jobManagerAddress = checkNotNull(newJobManagerAddress);
+
+		// TODO - start should not throw an exception
+		try {
+			super.start();
+		} catch (Exception e) {
+			throw new RuntimeException("This should never happen", e);
+		}
+	}
+
+	/**
+	 * Suspends this pool, meaning it has lost its authority to accept and distribute slots.
+	 */
+	@Override
+	public void suspend() {
+		validateRunsInMainThread();
+
+		// suspend this RPC endpoint
+		stop();
+
+		// do not accept any requests
+		jobMasterId = null;
+		resourceManagerGateway = null;
+
+		// Clear (but not release!) the available slots. The TaskManagers should re-register them
+		// at the new leader JobManager/SlotPool
+		availableSlots.clear();
+		allocatedSlots.clear();
+		pendingRequests.clear();
+	}
+
+	// ------------------------------------------------------------------------
+	//  Getting PoolOwner and PoolProvider
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Gets the slot owner implementation for this pool.
+	 *
+	 * <p>This method does not mutate state and can be called directly (no RPC indirection)
+	 *
+	 * @return The slot owner implementation for this pool.
+	 */
+	public SlotOwner getSlotOwner() {
+		return providerAndOwner;
+	}
+
+	/**
+	 * Gets the slot provider implementation for this pool.
+	 *
+	 * <p>This method does not mutate state and can be called directly (no RPC indirection)
+	 *
+	 * @return The slot provider implementation for this pool.
+	 */
+	public SlotProvider getSlotProvider() {
+		return providerAndOwner;
+	}
+
+	// ------------------------------------------------------------------------
+	//  Resource Manager Connection
+	// ------------------------------------------------------------------------
+
+	@Override
+	public void connectToResourceManager(ResourceManagerGateway resourceManagerGateway) {
+		this.resourceManagerGateway = checkNotNull(resourceManagerGateway);
+
+		// work on all slots waiting for this connection
+		for (PendingRequest pendingRequest : waitingForResourceManager.values()) {
+			requestSlotFromResourceManager(resourceManagerGateway, pendingRequest);
+		}
+
+		// all sent off
+		waitingForResourceManager.clear();
+	}
+
+	@Override
+	public void disconnectResourceManager() {
+		this.resourceManagerGateway = null;
+	}
+
+	// ------------------------------------------------------------------------
+	//  Slot Allocation
+	// ------------------------------------------------------------------------
+
+	@Override
+	public CompletableFuture<LogicalSlot> allocateSlot(
+			SlotRequestId slotRequestId,
+			ScheduledUnit scheduledUnit,
+			ResourceProfile resourceProfile,
+			Collection<TaskManagerLocation> locationPreferences,
+			boolean allowQueuedScheduling,
+			Time timeout) {
+
+		return internalAllocateSlot(
+			slotRequestId,
+			scheduledUnit,
+			resourceProfile,
+			locationPreferences,
+			allowQueuedScheduling);
+	}
+
+	private CompletableFuture<LogicalSlot> internalAllocateSlot(
+			SlotRequestId slotRequestId,
+			ScheduledUnit task,
+			ResourceProfile resourceProfile,
+			Collection<TaskManagerLocation> locationPreferences,
+			boolean allowQueuedScheduling) {
+
+		final SlotSharingGroupId slotSharingGroupId = task.getSlotSharingGroupId();
+
+		if (slotSharingGroupId != null) {
+			// allocate slot with slot sharing
+			final SlotSharingManager multiTaskSlotManager = slotSharingManagers.computeIfAbsent(
+				slotSharingGroupId,
+				id -> new SlotSharingManager(
+					id,
+					this,
+					providerAndOwner));
+
+			final SlotSharingManager.MultiTaskSlotLocality multiTaskSlotLocality;
+
+			try {
+				if (task.getCoLocationConstraint() != null) {
+					multiTaskSlotLocality = allocateCoLocatedMultiTaskSlot(
+						task.getCoLocationConstraint(),
+						multiTaskSlotManager,
+						resourceProfile,
+						locationPreferences,
+						allowQueuedScheduling);
+				} else {
+					multiTaskSlotLocality = allocateMultiTaskSlot(
+						task.getJobVertexId(), multiTaskSlotManager,
+						resourceProfile,
+						locationPreferences,
+						allowQueuedScheduling);
+				}
+			} catch (NoResourceAvailableException noResourceException) {
+				return FutureUtils.completedExceptionally(noResourceException);
+			}
+
+			// sanity check
+			Preconditions.checkState(!multiTaskSlotLocality.getMultiTaskSlot().contains(task.getJobVertexId()));
+
+			final SlotSharingManager.SingleTaskSlot leaf = multiTaskSlotLocality.getMultiTaskSlot().allocateSingleTaskSlot(
+				slotRequestId,
+				task.getJobVertexId(),
+				multiTaskSlotLocality.getLocality());
+
+			return leaf.getLogicalSlotFuture();
+		} else {
+			// request an allocated slot to assign a single logical slot to
+			CompletableFuture<SlotAndLocality> slotAndLocalityFuture = requestAllocatedSlot(
+				slotRequestId,
+				resourceProfile,
+				locationPreferences,
+				allowQueuedScheduling);
+
+			return slotAndLocalityFuture.thenApply(
+				(SlotAndLocality slotAndLocality) -> {
+					final AllocatedSlot allocatedSlot = slotAndLocality.getSlot();
+
+					final SingleLogicalSlot singleTaskSlot = new SingleLogicalSlot(
+						slotRequestId,
+						allocatedSlot,
+						null,
+						slotAndLocality.getLocality(),
+						providerAndOwner);
+
+					if (allocatedSlot.tryAssignPayload(singleTaskSlot)) {
+						return singleTaskSlot;
+					} else {
+						final FlinkException flinkException = new FlinkException("Could not assign payload to allocated slot " + allocatedSlot.getAllocationId() + '.');
+						releaseSlot(slotRequestId, null, flinkException);
+						throw new CompletionException(flinkException);
+					}
+				});
+		}
+	}
+
+	/**
+	 * Allocates a co-located {@link SlotSharingManager.MultiTaskSlot} for the given {@link CoLocationConstraint}.
+	 *
+	 * <p>If allowQueuedScheduling is true, then the returned {@link SlotSharingManager.MultiTaskSlot} can be
+	 * uncompleted.
+	 *
+	 * @param coLocationConstraint for which to allocate a {@link SlotSharingManager.MultiTaskSlot}
+	 * @param multiTaskSlotManager responsible for the slot sharing group for which to allocate the slot
+	 * @param resourceProfile specifying the requirements for the requested slot
+	 * @param locationPreferences containing preferred TaskExecutors on which to allocate the slot
+	 * @param allowQueuedScheduling true if queued scheduling (the returned task slot must not be completed yet) is allowed, otherwise false
+	 * @return A {@link SlotSharingManager.MultiTaskSlotLocality} which contains the allocated{@link SlotSharingManager.MultiTaskSlot}
+	 * 		and its locality wrt the given location preferences
+	 * @throws NoResourceAvailableException if no task slot could be allocated
+	 */
+	private SlotSharingManager.MultiTaskSlotLocality allocateCoLocatedMultiTaskSlot(
+			CoLocationConstraint coLocationConstraint,
+			SlotSharingManager multiTaskSlotManager,
+			ResourceProfile resourceProfile,
+			Collection<TaskManagerLocation> locationPreferences,
+			boolean allowQueuedScheduling) throws NoResourceAvailableException {
+		final SlotRequestId coLocationSlotRequestId = coLocationConstraint.getSlotRequestId();
+
+		if (coLocationSlotRequestId != null) {
+			// we have a slot assigned --> try to retrieve it
+			final SlotSharingManager.TaskSlot taskSlot = multiTaskSlotManager.getTaskSlot(coLocationSlotRequestId);
+
+			if (taskSlot != null) {
+				Preconditions.checkState(taskSlot instanceof SlotSharingManager.MultiTaskSlot);
+				return SlotSharingManager.MultiTaskSlotLocality.of(((SlotSharingManager.MultiTaskSlot) taskSlot), Locality.LOCAL);
+			} else {
+				// the slot may have been cancelled in the mean time
+				coLocationConstraint.setSlotRequestId(null);
+			}
+		}
+
+		final Collection<TaskManagerLocation> actualLocationPreferences;
+
+		if (coLocationConstraint.isAssigned()) {
+			actualLocationPreferences = Collections.singleton(coLocationConstraint.getLocation());
+		} else {
+			actualLocationPreferences = locationPreferences;
+		}
+
+		// get a new multi task slot
+		final SlotSharingManager.MultiTaskSlotLocality multiTaskSlotLocality = allocateMultiTaskSlot(
+			coLocationConstraint.getGroupId(), multiTaskSlotManager,
+			resourceProfile,
+			actualLocationPreferences,
+			allowQueuedScheduling);
+
+		// check whether we fulfill the co-location constraint
+		if (coLocationConstraint.isAssigned() && multiTaskSlotLocality.getLocality() != Locality.LOCAL) {
+			multiTaskSlotLocality.getMultiTaskSlot().release(
+				new FlinkException("Multi task slot is not local and, thus, does not fulfill the co-location constraint."));
+
+			throw new NoResourceAvailableException("Could not allocate a local multi task slot for the " +
+				"co location constraint " + coLocationConstraint + '.');
+		}
+
+		final SlotRequestId slotRequestId = new SlotRequestId();
+		final SlotSharingManager.MultiTaskSlot coLocationSlot = multiTaskSlotLocality.getMultiTaskSlot().allocateMultiTaskSlot(
+			slotRequestId,
+			coLocationConstraint.getGroupId());
+
+		// mark the requested slot as co-located slot for other co-located tasks
+		coLocationConstraint.setSlotRequestId(slotRequestId);
+
+		// lock the co-location constraint once we have obtained the allocated slot
+		coLocationSlot.getSlotContextFuture().whenComplete(
+			(SlotContext slotContext, Throwable throwable) -> {
+				if (throwable == null) {
+					// check whether we are still assigned to the co-location constraint
+					if (Objects.equals(coLocationConstraint.getSlotRequestId(), slotRequestId)) {
+						coLocationConstraint.lockLocation(slotContext.getTaskManagerLocation());
+					} else {
+						log.debug("Failed to lock colocation constraint {} because assigned slot " +
+							"request {} differs from fulfilled slot request {}.",
+							coLocationConstraint.getGroupId(),
+							coLocationConstraint.getSlotRequestId(),
+							slotRequestId);
+					}
+				} else {
+					log.debug("Failed to lock colocation constraint {} because the slot " +
+						"allocation for slot request {} failed.",
+						coLocationConstraint.getGroupId(),
+						coLocationConstraint.getSlotRequestId(),
+						throwable);
+				}
+			});
+
+		return SlotSharingManager.MultiTaskSlotLocality.of(coLocationSlot, multiTaskSlotLocality.getLocality());
+	}
+
+	/**
+	 * Allocates a {@link SlotSharingManager.MultiTaskSlot} for the given groupId which is in the
+	 * slot sharing group for which the given {@link SlotSharingManager} is responsible.
+	 *
+	 * <p>If allowQueuedScheduling is true, then the method can return an uncompleted {@link SlotSharingManager.MultiTaskSlot}.
+	 *
+	 * @param groupId for which to allocate a new {@link SlotSharingManager.MultiTaskSlot}
+	 * @param slotSharingManager responsible for the slot sharing group for which to allocate the slot
+	 * @param resourceProfile specifying the requirements for the requested slot
+	 * @param locationPreferences containing preferred TaskExecutors on which to allocate the slot
+	 * @param allowQueuedScheduling true if queued scheduling (the returned task slot must not be completed yet) is allowed, otherwise false
+	 * @return A {@link SlotSharingManager.MultiTaskSlotLocality} which contains the allocated {@link SlotSharingManager.MultiTaskSlot}
+	 * 		and its locality wrt the given location preferences
+	 * @throws NoResourceAvailableException if no task slot could be allocated
+	 */
+	private SlotSharingManager.MultiTaskSlotLocality allocateMultiTaskSlot(
+			AbstractID groupId,
+			SlotSharingManager slotSharingManager,
+			ResourceProfile resourceProfile,
+			Collection<TaskManagerLocation> locationPreferences,
+			boolean allowQueuedScheduling) throws NoResourceAvailableException {
+
+		// check first whether we have a resolved root slot which we can use
+		SlotSharingManager.MultiTaskSlotLocality multiTaskSlotLocality = slotSharingManager.getResolvedRootSlot(
+			groupId,
+			locationPreferences);
+
+		if (multiTaskSlotLocality != null && multiTaskSlotLocality.getLocality() == Locality.LOCAL) {
+			return multiTaskSlotLocality;
+		}
+
+		final SlotRequestId allocatedSlotRequestId = new SlotRequestId();
+		final SlotRequestId multiTaskSlotRequestId = new SlotRequestId();
+
+		// check whether we have an allocated slot available which we can use to create a new multi task slot in
+		final SlotAndLocality polledSlotAndLocality = pollAndAllocateSlot(allocatedSlotRequestId, resourceProfile, locationPreferences);
+
+		if (polledSlotAndLocality != null && (polledSlotAndLocality.getLocality() == Locality.LOCAL || multiTaskSlotLocality == null)) {
+
+			final AllocatedSlot allocatedSlot = polledSlotAndLocality.getSlot();
+			final SlotSharingManager.MultiTaskSlot multiTaskSlot = slotSharingManager.createRootSlot(
+				multiTaskSlotRequestId,
+				CompletableFuture.completedFuture(polledSlotAndLocality.getSlot()),
+				allocatedSlotRequestId);
+
+			if (allocatedSlot.tryAssignPayload(multiTaskSlot)) {
+				return SlotSharingManager.MultiTaskSlotLocality.of(multiTaskSlot, polledSlotAndLocality.getLocality());
+			} else {
+				multiTaskSlot.release(new FlinkException("Could not assign payload to allocated slot " +
+					allocatedSlot.getAllocationId() + '.'));
+			}
+		}
+
+		if (multiTaskSlotLocality != null) {
+			// prefer slot sharing group slots over unused slots
+			if (polledSlotAndLocality != null) {
+				releaseSlot(
+					allocatedSlotRequestId,
+					null,
+					new FlinkException("Locality constraint is not better fulfilled by allocated slot."));
+			}
+			return multiTaskSlotLocality;
+		}
+
+		if (allowQueuedScheduling) {
+			// there is no slot immediately available --> check first for uncompleted slots at the slot sharing group
+			SlotSharingManager.MultiTaskSlot multiTaskSlotFuture = slotSharingManager.getUnresolvedRootSlot(groupId);
+
+			if (multiTaskSlotFuture == null) {
+				// it seems as if we have to request a new slot from the resource manager, this is always the last resort!!!
+				final CompletableFuture<AllocatedSlot> futureSlot = requestNewAllocatedSlot(allocatedSlotRequestId, resourceProfile);
+
+				multiTaskSlotFuture = slotSharingManager.createRootSlot(
+					multiTaskSlotRequestId,
+					futureSlot,
+					allocatedSlotRequestId);
+
+				futureSlot.whenComplete(
+					(AllocatedSlot allocatedSlot, Throwable throwable) -> {
+						final SlotSharingManager.TaskSlot taskSlot = slotSharingManager.getTaskSlot(multiTaskSlotRequestId);
+
+						if (taskSlot != null) {
+							// still valid
+							if (!(taskSlot instanceof SlotSharingManager.MultiTaskSlot) || throwable != null) {
+								taskSlot.release(throwable);
+							} else {
+								if (!allocatedSlot.tryAssignPayload(((SlotSharingManager.MultiTaskSlot) taskSlot))) {
+									taskSlot.release(new FlinkException("Could not assign payload to allocated slot " +
+										allocatedSlot.getAllocationId() + '.'));
+								}
+							}
+						} else {
+							releaseSlot(
+								allocatedSlotRequestId,
+								null,
+								new FlinkException("Could not find task slot with " + multiTaskSlotRequestId + '.'));
+						}
+					});
+			}
+
+			return SlotSharingManager.MultiTaskSlotLocality.of(multiTaskSlotFuture, Locality.UNKNOWN);
+
+		} else {
+			throw new NoResourceAvailableException("Could not allocate a shared slot for " + groupId + '.');
+		}
+	}
+
+	/**
+	 * Allocates an allocated slot first by polling from the available slots and then requesting a new
+	 * slot from the ResourceManager if no fitting slot could be found.
+	 *
+	 * @param slotRequestId identifying the slot allocation request
+	 * @param resourceProfile which the allocated slot should fulfill
+	 * @param locationPreferences for the allocated slot
+	 * @param allowQueuedScheduling true if the slot allocation can be completed in the future
+	 * @return Future containing the allocated simple slot
+	 */
+	private CompletableFuture<SlotAndLocality> requestAllocatedSlot(
+			SlotRequestId slotRequestId,
+			ResourceProfile resourceProfile,
+			Collection<TaskManagerLocation> locationPreferences,
+			boolean allowQueuedScheduling) {
+
+		final CompletableFuture<SlotAndLocality> allocatedSlotLocalityFuture;
+
+		// (1) do we have a slot available already?
+		SlotAndLocality slotFromPool = pollAndAllocateSlot(slotRequestId, resourceProfile, locationPreferences);
+
+		if (slotFromPool != null) {
+			allocatedSlotLocalityFuture = CompletableFuture.completedFuture(slotFromPool);
+		} else if (allowQueuedScheduling) {
+			// we have to request a new allocated slot
+			CompletableFuture<AllocatedSlot> allocatedSlotFuture = requestNewAllocatedSlot(
+				slotRequestId,
+				resourceProfile);
+
+			allocatedSlotLocalityFuture = allocatedSlotFuture.thenApply((AllocatedSlot allocatedSlot) -> new SlotAndLocality(allocatedSlot, Locality.UNKNOWN));
+		} else {
+			allocatedSlotLocalityFuture = FutureUtils.completedExceptionally(new NoResourceAvailableException("Could not allocate a simple slot for " +
+				slotRequestId + '.'));
+		}
+
+		return allocatedSlotLocalityFuture;
+	}
+
+	/**
+	 * Requests a new slot with the given {@link ResourceProfile} from the ResourceManager. If there is
+	 * currently not ResourceManager connected, then the request is stashed and send once a new
+	 * ResourceManager is connected.
+	 *
+	 * @param slotRequestId identifying the requested slot
+	 * @param resourceProfile which the requested slot should fulfill
+	 * @return An {@link AllocatedSlot} future which is completed once the slot is offered to the {@link SlotPool}
+	 */
+	private CompletableFuture<AllocatedSlot> requestNewAllocatedSlot(
+		SlotRequestId slotRequestId,
+		ResourceProfile resourceProfile) {
+
+		final PendingRequest pendingRequest = new PendingRequest(
+			slotRequestId,
+			resourceProfile);
+
+		if (resourceManagerGateway == null) {
+			stashRequestWaitingForResourceManager(pendingRequest);
+		} else {
+			requestSlotFromResourceManager(resourceManagerGateway, pendingRequest);
+		}
+
+		return pendingRequest.getAllocatedSlotFuture();
+	}
+
+	private void requestSlotFromResourceManager(
+			final ResourceManagerGateway resourceManagerGateway,
+			final PendingRequest pendingRequest) {
+
+		Preconditions.checkNotNull(resourceManagerGateway);
+		Preconditions.checkNotNull(pendingRequest);
+
+		LOG.info("Requesting slot with profile {} from resource manager (request = {}).", pendingRequest.getResourceProfile(), pendingRequest.getSlotRequestId());
+
+		final AllocationID allocationId = new AllocationID();
+
+		pendingRequests.put(pendingRequest.getSlotRequestId(), allocationId, pendingRequest);
+
+		pendingRequest.getAllocatedSlotFuture().whenComplete(
+			(value, throwable) -> {
+				if (throwable != null) {
+					resourceManagerGateway.cancelSlotRequest(allocationId);
+				}
+			});
+
+		CompletableFuture<Acknowledge> rmResponse = resourceManagerGateway.requestSlot(
+			jobMasterId,
+			new SlotRequest(jobId, allocationId, pendingRequest.getResourceProfile(), jobManagerAddress),
+			resourceManagerRequestsTimeout);
+
+		CompletableFuture<Void> slotRequestProcessingFuture = rmResponse.thenAcceptAsync(
+			(Acknowledge value) -> {
+				slotRequestToResourceManagerSuccess(pendingRequest.getSlotRequestId());
+			},
+			getMainThreadExecutor());
+
+		// on failure, fail the request future
+		slotRequestProcessingFuture.whenCompleteAsync(
+			(Void v, Throwable failure) -> {
+				if (failure != null) {
+					slotRequestToResourceManagerFailed(pendingRequest.getSlotRequestId(), failure);
+				}
+			},
+			getMainThreadExecutor());
+	}
+
+	private void slotRequestToResourceManagerSuccess(final SlotRequestId requestId) {
+		// a request is pending from the ResourceManager to a (future) TaskManager
+		// we only add the watcher here in case that request times out
+		scheduleRunAsync(new Runnable() {
+			@Override
+			public void run() {
+				checkTimeoutSlotAllocation(requestId);
+			}
+		}, resourceManagerAllocationTimeout);
+	}
+
+	private void slotRequestToResourceManagerFailed(SlotRequestId slotRequestID, Throwable failure) {
+		PendingRequest request = pendingRequests.removeKeyA(slotRequestID);
+		if (request != null) {
+			request.getAllocatedSlotFuture().completeExceptionally(new NoResourceAvailableException(
+					"No pooled slot available and request to ResourceManager for new slot failed", failure));
+		} else {
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("Unregistered slot request {} failed.", slotRequestID, failure);
+			}
+		}
+	}
+
+	private void checkTimeoutSlotAllocation(SlotRequestId slotRequestID) {
+		PendingRequest request = pendingRequests.removeKeyA(slotRequestID);
+		if (request != null) {
+			failPendingRequest(request, new TimeoutException("Slot allocation request " + slotRequestID + " timed out"));
+		}
+	}
+
+	private void stashRequestWaitingForResourceManager(final PendingRequest pendingRequest) {
+
+		LOG.info("Cannot serve slot request, no ResourceManager connected. " +
+				"Adding as pending request {}",  pendingRequest.getSlotRequestId());
+
+		waitingForResourceManager.put(pendingRequest.getSlotRequestId(), pendingRequest);
+
+		scheduleRunAsync(new Runnable() {
+			@Override
+			public void run() {
+				checkTimeoutRequestWaitingForResourceManager(pendingRequest.getSlotRequestId());
+			}
+		}, resourceManagerRequestsTimeout);
+	}
+
+	private void checkTimeoutRequestWaitingForResourceManager(SlotRequestId slotRequestId) {
+		PendingRequest request = waitingForResourceManager.remove(slotRequestId);
+		if (request != null) {
+			failPendingRequest(
+				request,
+				new NoResourceAvailableException("No slot available and no connection to Resource Manager established."));
+		}
+	}
+
+	// ------------------------------------------------------------------------
+	//  Slot releasing & offering
+	// ------------------------------------------------------------------------
+
+	@Override
+	public CompletableFuture<Acknowledge> releaseSlot(SlotRequestId slotRequestId, @Nullable SlotSharingGroupId slotSharingGroupId, Throwable cause) {
+
+		if (slotSharingGroupId != null) {
+			final SlotSharingManager multiTaskSlotManager = slotSharingManagers.get(slotSharingGroupId);
+
+			if (multiTaskSlotManager != null) {
+				final SlotSharingManager.TaskSlot taskSlot = multiTaskSlotManager.getTaskSlot(slotRequestId);
+
+				if (taskSlot != null) {
+					taskSlot.release(cause);
+				} else {
+					log.debug("Could not find slot {} in slot sharing group {}. Ignoring release slot request.", slotRequestId, slotSharingGroupId, cause);
+				}
+			} else {
+				log.debug("Could not find slot sharing group {}. Ignoring release slot request.", slotSharingGroupId, cause);
+			}
+		} else {
+			final PendingRequest pendingRequest = removePendingRequest(slotRequestId);
+
+			if (pendingRequest != null) {
+				failPendingRequest(pendingRequest, new FlinkException("Pending slot request with " + slotRequestId + " has been released."));
+			} else {
+				final AllocatedSlot allocatedSlot = allocatedSlots.remove(slotRequestId);
+
+				if (allocatedSlot != null) {
+					// sanity check
+					if (allocatedSlot.releasePayload(cause)) {
+						tryFulfillSlotRequestOrMakeAvailable(allocatedSlot);
+					}
+				} else {
+					log.debug("There is no allocated slot with allocation id {}. Ignoring the release slot request.", slotRequestId, cause);
+				}
+			}
+		}
+
+		return CompletableFuture.completedFuture(Acknowledge.get());
+	}
+
+	/**
+	 * Checks whether there exists a pending request with the given allocation id and removes it
+	 * from the internal data structures.
+	 *
+	 * @param requestId identifying the pending request
+	 * @return pending request if there is one, otherwise null
+	 */
+	@Nullable
+	private PendingRequest removePendingRequest(SlotRequestId requestId) {
+		PendingRequest result = waitingForResourceManager.remove(requestId);
+
+		if (result != null) {
+			// sanity check
+			assert !pendingRequests.containsKeyA(requestId) : "A pending requests should only be part of either " +
+				"the pendingRequests or waitingForResourceManager but not both.";
+
+			return result;
+		} else {
+			return pendingRequests.removeKeyA(requestId);
+		}
+	}
+
+	private void failPendingRequest(PendingRequest pendingRequest, Exception e) {
+		Preconditions.checkNotNull(pendingRequest);
+		Preconditions.checkNotNull(e);
+
+		if (!pendingRequest.getAllocatedSlotFuture().isDone()) {
+			LOG.info("Failing pending request {}.", pendingRequest.getSlotRequestId());
+			pendingRequest.getAllocatedSlotFuture().completeExceptionally(e);
+		}
+	}
+
+	@Nullable
+	private SlotAndLocality pollAndAllocateSlot(
+		SlotRequestId slotRequestId,
+		ResourceProfile resourceProfile,
+		Collection<TaskManagerLocation> locationPreferences) {
+		SlotAndLocality slotFromPool = availableSlots.poll(resourceProfile, locationPreferences);
+
+		if (slotFromPool != null) {
+			allocatedSlots.add(slotRequestId, slotFromPool.getSlot());
+		}
+
+		return slotFromPool;
+	}
+
+	/**
+	 * Tries to fulfill with the given allocated slot a pending slot request or add the
+	 * allocated slot to the set of available slots if no matching request is available.
+	 *
+	 * @param allocatedSlot which shall be returned
+	 */
+	private void tryFulfillSlotRequestOrMakeAvailable(AllocatedSlot allocatedSlot) {
+		Preconditions.checkState(!allocatedSlot.isUsed(), "Provided slot is still in use.");
+
+		final PendingRequest pendingRequest = pollMatchingPendingRequest(allocatedSlot);
+
+		if (pendingRequest != null) {
+			LOG.debug("Fulfilling pending request [{}] early with returned slot [{}]",
+				pendingRequest.getSlotRequestId(), allocatedSlot.getAllocationId());
+
+			allocatedSlots.add(pendingRequest.getSlotRequestId(), allocatedSlot);
+			pendingRequest.getAllocatedSlotFuture().complete(allocatedSlot);
+		} else {
+			LOG.debug("Adding returned slot [{}] to available slots", allocatedSlot.getAllocationId());
+			availableSlots.add(allocatedSlot, clock.relativeTimeMillis());
+		}
+	}
+
+	private PendingRequest pollMatchingPendingRequest(final AllocatedSlot slot) {
+		final ResourceProfile slotResources = slot.getResourceProfile();
+
+		// try the requests sent to the resource manager first
+		for (PendingRequest request : pendingRequests.values()) {
+			if (slotResources.isMatching(request.getResourceProfile())) {
+				pendingRequests.removeKeyA(request.getSlotRequestId());
+				return request;
+			}
+		}
+
+		// try the requests waiting for a resource manager connection next
+		for (PendingRequest request : waitingForResourceManager.values()) {
+			if (slotResources.isMatching(request.getResourceProfile())) {
+				waitingForResourceManager.remove(request.getSlotRequestId());
+				return request;
+			}
+		}
+
+		// no request pending, or no request matches
+		return null;
+	}
+
+	@Override
+	public CompletableFuture<Collection<SlotOffer>> offerSlots(
+			TaskManagerLocation taskManagerLocation,
+			TaskManagerGateway taskManagerGateway,
+			Collection<SlotOffer> offers) {
+		validateRunsInMainThread();
+
+		List<CompletableFuture<Optional<SlotOffer>>> acceptedSlotOffers = offers.stream().map(
+			offer -> {
+				CompletableFuture<Optional<SlotOffer>> acceptedSlotOffer = offerSlot(
+					taskManagerLocation,
+					taskManagerGateway,
+					offer)
+					.thenApply(
+						(acceptedSlot) -> {
+							if (acceptedSlot) {
+								return Optional.of(offer);
+							} else {
+								return Optional.empty();
+							}
+						});
+
+				return acceptedSlotOffer;
+			}
+		).collect(Collectors.toList());
+
+		CompletableFuture<Collection<Optional<SlotOffer>>> optionalSlotOffers = FutureUtils.combineAll(acceptedSlotOffers);
+
+		CompletableFuture<Collection<SlotOffer>> resultingSlotOffers = optionalSlotOffers.thenApply(
+			collection -> {
+				Collection<SlotOffer> slotOffers = collection
+					.stream()
+					.flatMap(
+						opt -> opt.map(Stream::of).orElseGet(Stream::empty))
+					.collect(Collectors.toList());
+
+				return slotOffers;
+			});
+
+		return resultingSlotOffers;
+	}
+
+	/**
+	 * Slot offering by TaskExecutor with AllocationID. The AllocationID is originally generated by this pool and
+	 * transfer through the ResourceManager to TaskManager. We use it to distinguish the different allocation
+	 * we issued. Slot offering may be rejected if we find something mismatching or there is actually no pending
+	 * request waiting for this slot (maybe fulfilled by some other returned slot).
+	 *
+	 * @param taskManagerLocation location from where the offer comes from
+	 * @param taskManagerGateway TaskManager gateway
+	 * @param slotOffer the offered slot
+	 * @return True if we accept the offering
+	 */
+	@Override
+	public CompletableFuture<Boolean> offerSlot(
+			final TaskManagerLocation taskManagerLocation,
+			final TaskManagerGateway taskManagerGateway,
+			final SlotOffer slotOffer) {
+		validateRunsInMainThread();
+
+		// check if this TaskManager is valid
+		final ResourceID resourceID = taskManagerLocation.getResourceID();
+		final AllocationID allocationID = slotOffer.getAllocationId();
+
+		if (!registeredTaskManagers.contains(resourceID)) {
+			LOG.debug("Received outdated slot offering [{}] from unregistered TaskManager: {}",
+					slotOffer.getAllocationId(), taskManagerLocation);
+			return CompletableFuture.completedFuture(false);
+		}
+
+		// check whether we have already using this slot
+		if (allocatedSlots.contains(allocationID) || availableSlots.contains(allocationID)) {
+			LOG.debug("Received repeated offer for slot [{}]. Ignoring.", allocationID);
+
+			// return true here so that the sender will get a positive acknowledgement to the retry
+			// and mark the offering as a success
+			return CompletableFuture.completedFuture(true);
+		}
+
+		final AllocatedSlot allocatedSlot = new AllocatedSlot(
+			slotOffer.getAllocationId(),
+			taskManagerLocation,
+			slotOffer.getSlotIndex(),
+			slotOffer.getResourceProfile(),
+			taskManagerGateway);
+
+		// check whether we have request waiting for this slot
+		PendingRequest pendingRequest = pendingRequests.removeKeyB(allocationID);
+		if (pendingRequest != null) {
+			// we were waiting for this!
+			allocatedSlots.add(pendingRequest.getSlotRequestId(), allocatedSlot);
+
+			if (!pendingRequest.getAllocatedSlotFuture().complete(allocatedSlot)) {
+				// we could not complete the pending slot future --> try to fulfill another pending request
+				allocatedSlots.remove(pendingRequest.getSlotRequestId());
+				tryFulfillSlotRequestOrMakeAvailable(allocatedSlot);
+			}
+		}
+		else {
+			// we were actually not waiting for this:
+			//   - could be that this request had been fulfilled
+			//   - we are receiving the slots from TaskManagers after becoming leaders
+			tryFulfillSlotRequestOrMakeAvailable(allocatedSlot);
+		}
+
+		// we accepted the request in any case. slot will be released after it idled for
+		// too long and timed out
+		return CompletableFuture.completedFuture(true);
+	}
+
+
+	// TODO - periodic (every minute or so) catch slots that were lost (check all slots, if they have any task active)
+
+	// TODO - release slots that were not used to the resource manager
+
+	// ------------------------------------------------------------------------
+	//  Error Handling
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Fail the specified allocation and release the corresponding slot if we have one.
+	 * This may triggered by JobManager when some slot allocation failed with timeout.
+	 * Or this could be triggered by TaskManager, when it finds out something went wrong with the slot,
+	 * and decided to take it back.
+	 *
+	 * @param allocationID Represents the allocation which should be failed
+	 * @param cause        The cause of the failure
+	 */
+	@Override
+	public void failAllocation(final AllocationID allocationID, final Exception cause) {
+		final PendingRequest pendingRequest = pendingRequests.removeKeyB(allocationID);
+		if (pendingRequest != null) {
+			// request was still pending
+			failPendingRequest(pendingRequest, cause);
+		}
+		else if (availableSlots.tryRemove(allocationID)) {
+			LOG.debug("Failed available slot [{}] with ", allocationID, cause);
+		}
+		else {
+			AllocatedSlot allocatedSlot = allocatedSlots.remove(allocationID);
+			if (allocatedSlot != null) {
+				// release the slot.
+				// since it is not in 'allocatedSlots' any more, it will be dropped o return'
+				allocatedSlot.releasePayload(cause);
+			}
+			else {
+				LOG.debug("Outdated request to fail slot [{}] with ", allocationID, cause);
+			}
+		}
+		// TODO: add some unit tests when the previous two are ready, the allocation may failed at any phase
+	}
+
+	// ------------------------------------------------------------------------
+	//  Resource
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Register TaskManager to this pool, only those slots come from registered TaskManager will be considered valid.
+	 * Also it provides a way for us to keep "dead" or "abnormal" TaskManagers out of this pool.
+	 *
+	 * @param resourceID The id of the TaskManager
+	 * @return Future acknowledge if th operation was successful
+	 */
+	@Override
+	public CompletableFuture<Acknowledge> registerTaskManager(final ResourceID resourceID) {
+		registeredTaskManagers.add(resourceID);
+
+		return CompletableFuture.completedFuture(Acknowledge.get());
+	}
+
+	/**
+	 * Unregister TaskManager from this pool, all the related slots will be released and tasks be canceled. Called
+	 * when we find some TaskManager becomes "dead" or "abnormal", and we decide to not using slots from it anymore.
+	 *
+	 * @param resourceID The id of the TaskManager
+	 */
+	@Override
+	public CompletableFuture<Acknowledge> releaseTaskManager(final ResourceID resourceID) {
+		if (registeredTaskManagers.remove(resourceID)) {
+			availableSlots.removeAllForTaskManager(resourceID);
+
+			final Set<AllocatedSlot> allocatedSlotsForResource = allocatedSlots.removeSlotsForTaskManager(resourceID);
+
+			for (AllocatedSlot allocatedSlot : allocatedSlotsForResource) {
+				allocatedSlot.releasePayload(new FlinkException("TaskManager " + resourceID + " was released."));
+			}
+		}
+
+		return CompletableFuture.completedFuture(Acknowledge.get());
+	}
+
+	// ------------------------------------------------------------------------
+	//  Methods for tests
+	// ------------------------------------------------------------------------
+
+	@VisibleForTesting
+	protected AllocatedSlots getAllocatedSlots() {
+		return allocatedSlots;
+	}
+
+	@VisibleForTesting
+	protected AvailableSlots getAvailableSlots() {
+		return availableSlots;
+	}
+
+	@VisibleForTesting
+	DualKeyMap<SlotRequestId, AllocationID, PendingRequest> getPendingRequests() {
+		return pendingRequests;
+	}
+
+	@VisibleForTesting
+	Map<SlotRequestId, PendingRequest> getWaitingForResourceManager() {
+		return waitingForResourceManager;
+	}
+
+	// ------------------------------------------------------------------------
+	//  Helper classes
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Organize allocated slots from different points of view.
+	 */
+	static class AllocatedSlots {
+
+		/** All allocated slots organized by TaskManager's id. */
+		private final Map<ResourceID, Set<AllocatedSlot>> allocatedSlotsByTaskManager;
+
+		/** All allocated slots organized by AllocationID. */
+		private final DualKeyMap<AllocationID, SlotRequestId, AllocatedSlot> allocatedSlotsById;
+
+		AllocatedSlots() {
+			this.allocatedSlotsByTaskManager = new HashMap<>(16);
+			this.allocatedSlotsById = new DualKeyMap<>(16);
+		}
+
+		/**
+		 * Adds a new slot to this collection.
+		 *
+		 * @param allocatedSlot The allocated slot
+		 */
+		void add(SlotRequestId slotRequestId, AllocatedSlot allocatedSlot) {
+			allocatedSlotsById.put(allocatedSlot.getAllocationId(), slotRequestId, allocatedSlot);
+
+			final ResourceID resourceID = allocatedSlot.getTaskManagerLocation().getResourceID();
+
+			Set<AllocatedSlot> slotsForTaskManager = allocatedSlotsByTaskManager.computeIfAbsent(
+				resourceID,
+				resourceId -> new HashSet<>(4));
+
+			slotsForTaskManager.add(allocatedSlot);
+		}
+
+		/**
+		 * Get allocated slot with allocation id.
+		 *
+		 * @param allocationID The allocation id
+		 * @return The allocated slot, null if we can't find a match
+		 */
+		AllocatedSlot get(final AllocationID allocationID) {
+			return allocatedSlotsById.getKeyA(allocationID);
+		}
+
+		AllocatedSlot get(final SlotRequestId slotRequestId) {
+			return allocatedSlotsById.getKeyB(slotRequestId);
+		}
+
+		/**
+		 * Check whether we have allocated this slot.
+		 *
+		 * @param slotAllocationId The allocation id of the slot to check
+		 * @return True if we contains this slot
+		 */
+		boolean contains(AllocationID slotAllocationId) {
+			return allocatedSlotsById.containsKeyA(slotAllocationId);
+		}
+
+		/**
+		 * Removes the allocated slot specified by the provided slot allocation id.
+		 *
+		 * @param allocationID identifying the allocated slot to remove
+		 * @return The removed allocated slot or null.
+		 */
+		@Nullable
+		AllocatedSlot remove(final AllocationID allocationID) {
+			AllocatedSlot allocatedSlot = allocatedSlotsById.removeKeyA(allocationID);
+
+			if (allocatedSlot != null) {
+				removeAllocatedSlot(allocatedSlot);
+			}
+
+			return allocatedSlot;
+		}
+
+		/**
+		 * Removes the allocated slot specified by the provided slot request id.
+		 *
+		 * @param slotRequestId identifying the allocated slot to remove
+		 * @return The removed allocated slot or null.
+		 */
+		@Nullable
+		AllocatedSlot remove(final SlotRequestId slotRequestId) {
+			final AllocatedSlot allocatedSlot = allocatedSlotsById.removeKeyB(slotRequestId);
+
+			if (allocatedSlot != null) {
+				removeAllocatedSlot(allocatedSlot);
+			}
+
+			return allocatedSlot;
+		}
+
+		private void removeAllocatedSlot(final AllocatedSlot allocatedSlot) {
+			Preconditions.checkNotNull(allocatedSlot);
+			final ResourceID taskManagerId = allocatedSlot.getTaskManagerLocation().getResourceID();
+			Set<AllocatedSlot> slotsForTM = allocatedSlotsByTaskManager.get(taskManagerId);
+
+			slotsForTM.remove(allocatedSlot);
+
+			if (slotsForTM.isEmpty()) {
+				allocatedSlotsByTaskManager.remove(taskManagerId);
+			}
+		}
+
+		/**
+		 * Get all allocated slot from same TaskManager.
+		 *
+		 * @param resourceID The id of the TaskManager
+		 * @return Set of slots which are allocated from the same TaskManager
+		 */
+		Set<AllocatedSlot> removeSlotsForTaskManager(final ResourceID resourceID) {
+			Set<AllocatedSlot> slotsForTaskManager = allocatedSlotsByTaskManager.remove(resourceID);
+			if (slotsForTaskManager != null) {
+				for (AllocatedSlot allocatedSlot : slotsForTaskManager) {
+					allocatedSlotsById.removeKeyA(allocatedSlot.getAllocationId());
+				}
+				return slotsForTaskManager;
+			}
+			else {
+				return Collections.emptySet();
+			}
+		}
+
+		void clear() {
+			allocatedSlotsById.clear();
+			allocatedSlotsByTaskManager.clear();
+		}
+
+		@VisibleForTesting
+		boolean containResource(final ResourceID resourceID) {
+			return allocatedSlotsByTaskManager.containsKey(resourceID);
+		}
+
+		@VisibleForTesting
+		int size() {
+			return allocatedSlotsById.size();
+		}
+
+		@VisibleForTesting
+		Set<AllocatedSlot> getSlotsForTaskManager(ResourceID resourceId) {
+			if (allocatedSlotsByTaskManager.containsKey(resourceId)) {
+				return allocatedSlotsByTaskManager.get(resourceId);
+			} else {
+				return Collections.emptySet();
+			}
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Organize all available slots from different points of view.
+	 */
+	protected static class AvailableSlots {
+
+		/** All available slots organized by TaskManager. */
+		private final HashMap<ResourceID, Set<AllocatedSlot>> availableSlotsByTaskManager;
+
+		/** All available slots organized by host. */
+		private final HashMap<String, Set<AllocatedSlot>> availableSlotsByHost;
+
+		/** The available slots, with the time when they were inserted. */
+		private final HashMap<AllocationID, SlotAndTimestamp> availableSlots;
+
+		AvailableSlots() {
+			this.availableSlotsByTaskManager = new HashMap<>();
+			this.availableSlotsByHost = new HashMap<>();
+			this.availableSlots = new HashMap<>();
+		}
+
+		/**
+		 * Adds an available slot.
+		 *
+		 * @param slot The slot to add
+		 */
+		void add(final AllocatedSlot slot, final long timestamp) {
+			checkNotNull(slot);
+
+			SlotAndTimestamp previous = availableSlots.put(
+					slot.getAllocationId(), new SlotAndTimestamp(slot, timestamp));
+
+			if (previous == null) {
+				final ResourceID resourceID = slot.getTaskManagerLocation().getResourceID();
+				final String host = slot.getTaskManagerLocation().getFQDNHostname();
+
+				Set<AllocatedSlot> slotsForTaskManager = availableSlotsByTaskManager.get(resourceID);
+				if (slotsForTaskManager == null) {
+					slotsForTaskManager = new HashSet<>();
+					availableSlotsByTaskManager.put(resourceID, slotsForTaskManager);
+				}
+				slotsForTaskManager.add(slot);
+
+				Set<AllocatedSlot> slotsForHost = availableSlotsByHost.get(host);
+				if (slotsForHost == null) {
+					slotsForHost = new HashSet<>();
+					availableSlotsByHost.put(host, slotsForHost);
+				}
+				slotsForHost.add(slot);
+			}
+			else {
+				throw new IllegalStateException("slot already contained");
+			}
+		}
+
+		/**
+		 * Check whether we have this slot.
+		 */
+		boolean contains(AllocationID slotId) {
+			return availableSlots.containsKey(slotId);
+		}
+
+		/**
+		 * Poll a slot which matches the required resource profile. The polling tries to satisfy the
+		 * location preferences, by TaskManager and by host.
+		 *
+		 * @param resourceProfile      The required resource profile.
+		 * @param locationPreferences  The location preferences, in order to be checked.
+		 *
+		 * @return Slot which matches the resource profile, null if we can't find a match
+		 */
+		SlotAndLocality poll(ResourceProfile resourceProfile, Collection<TaskManagerLocation> locationPreferences) {
+			// fast path if no slots are available
+			if (availableSlots.isEmpty()) {
+				return null;
+			}
+
+			boolean hadLocationPreference = false;
+
+			if (locationPreferences != null && !locationPreferences.isEmpty()) {
+
+				// first search by TaskManager
+				for (TaskManagerLocation location : locationPreferences) {
+					hadLocationPreference = true;
+
+					final Set<AllocatedSlot> onTaskManager = availableSlotsByTaskManager.get(location.getResourceID());
+					if (onTaskManager != null) {
+						for (AllocatedSlot candidate : onTaskManager) {
+							if (candidate.getResourceProfile().isMatching(resourceProfile)) {
+								remove(candidate.getAllocationId());
+								return new SlotAndLocality(candidate, Locality.LOCAL);
+							}
+						}
+					}
+				}
+
+				// now, search by host
+				for (TaskManagerLocation location : locationPreferences) {
+					final Set<AllocatedSlot> onHost = availableSlotsByHost.get(location.getFQDNHostname());
+					if (onHost != null) {
+						for (AllocatedSlot candidate : onHost) {
+							if (candidate.getResourceProfile().isMatching(resourceProfile)) {
+								remove(candidate.getAllocationId());
+								return new SlotAndLocality(candidate, Locality.HOST_LOCAL);
+							}
+						}
+					}
+				}
+			}
+
+			// take any slot
+			for (SlotAndTimestamp candidate : availableSlots.values()) {
+				final AllocatedSlot slot = candidate.slot();
+
+				if (slot.getResourceProfile().isMatching(resourceProfile)) {
+					remove(slot.getAllocationId());
+					return new SlotAndLocality(
+							slot, hadLocationPreference ? Locality.NON_LOCAL : Locality.UNCONSTRAINED);
+				}
+			}
+
+			// nothing available that matches
+			return null;
+		}
+
+		/**
+		 * Remove all available slots come from specified TaskManager.
+		 *
+		 * @param taskManager The id of the TaskManager
+		 */
+		void removeAllForTaskManager(final ResourceID taskManager) {
+			// remove from the by-TaskManager view
+			final Set<AllocatedSlot> slotsForTm = availableSlotsByTaskManager.remove(taskManager);
+
+			if (slotsForTm != null && slotsForTm.size() > 0) {
+				final String host = slotsForTm.iterator().next().getTaskManagerLocation().getFQDNHostname();
+				final Set<AllocatedSlot> slotsForHost = availableSlotsByHost.get(host);
+
+				// remove from the base set and the by-host view
+				for (AllocatedSlot slot : slotsForTm) {
+					availableSlots.remove(slot.getAllocationId());
+					slotsForHost.remove(slot);
+				}
+
+				if (slotsForHost.isEmpty()) {
+					availableSlotsByHost.remove(host);
+				}
+			}
+		}
+
+		boolean tryRemove(AllocationID slotId) {
+			final SlotAndTimestamp sat = availableSlots.remove(slotId);
+			if (sat != null) {
+				final AllocatedSlot slot = sat.slot();
+				final ResourceID resourceID = slot.getTaskManagerLocation().getResourceID();
+				final String host = slot.getTaskManagerLocation().getFQDNHostname();
+
+				final Set<AllocatedSlot> slotsForTm = availableSlotsByTaskManager.get(resourceID);
+				final Set<AllocatedSlot> slotsForHost = availableSlotsByHost.get(host);
+
+				slotsForTm.remove(slot);
+				slotsForHost.remove(slot);
+
+				if (slotsForTm.isEmpty()) {
+					availableSlotsByTaskManager.remove(resourceID);
+				}
+				if (slotsForHost.isEmpty()) {
+					availableSlotsByHost.remove(host);
+				}
+
+				return true;
+			}
+			else {
+				return false;
+			}
+		}
+
+		private void remove(AllocationID slotId) throws IllegalStateException {
+			if (!tryRemove(slotId)) {
+				throw new IllegalStateException("slot not contained");
+			}
+		}
+
+		@VisibleForTesting
+		boolean containsTaskManager(ResourceID resourceID) {
+			return availableSlotsByTaskManager.containsKey(resourceID);
+		}
+
+		@VisibleForTesting
+		public int size() {
+			return availableSlots.size();
+		}
+
+		@VisibleForTesting
+		void clear() {
+			availableSlots.clear();
+			availableSlotsByTaskManager.clear();
+			availableSlotsByHost.clear();
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * An implementation of the {@link SlotOwner} and {@link SlotProvider} interfaces
+	 * that delegates methods as RPC calls to the SlotPool's RPC gateway.
+	 */
+	private static class ProviderAndOwner implements SlotOwner, SlotProvider {
+
+		private final SlotPoolGateway gateway;
+
+		private final Time timeout;
+
+		ProviderAndOwner(SlotPoolGateway gateway, Time timeout) {
+			this.gateway = gateway;
+			this.timeout = timeout;
+		}
+
+		@Override
+		public CompletableFuture<Boolean> returnAllocatedSlot(LogicalSlot slot) {
+			return gateway
+				.releaseSlot(
+					slot.getSlotRequestId(),
+					slot.getSlotSharingGroupId(),
+					new FlinkException("Slot is being returned to the SlotPool."))
+				.thenApply(
+					(Acknowledge acknowledge) -> true);
+		}
+
+		@Override
+		public CompletableFuture<LogicalSlot> allocateSlot(
+				ScheduledUnit task,
+				boolean allowQueued,
+				Collection<TaskManagerLocation> preferredLocations) {
+
+			final SlotRequestId requestId = new SlotRequestId();
+			CompletableFuture<LogicalSlot> slotFuture = gateway.allocateSlot(
+				requestId,
+				task,
+				ResourceProfile.UNKNOWN,
+				preferredLocations,
+				allowQueued,
+				timeout);
+
+			slotFuture.whenComplete(
+				(LogicalSlot slot, Throwable failure) -> {
+					if (failure != null) {
+						gateway.releaseSlot(
+							requestId,
+							task.getSlotSharingGroupId(),
+							failure);
+					}
+			});
+
+			return slotFuture;
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * A pending request for a slot.
+	 */
+	private static class PendingRequest {
+
+		private final SlotRequestId slotRequestId;
+
+		private final ResourceProfile resourceProfile;
+
+		private final CompletableFuture<AllocatedSlot> allocatedSlotFuture;
+
+		PendingRequest(
+				SlotRequestId slotRequestId,
+				ResourceProfile resourceProfile) {
+			this.slotRequestId = Preconditions.checkNotNull(slotRequestId);
+			this.resourceProfile = Preconditions.checkNotNull(resourceProfile);
+
+			allocatedSlotFuture = new CompletableFuture<>();
+		}
+
+		public SlotRequestId getSlotRequestId() {
+			return slotRequestId;
+		}
+
+		public CompletableFuture<AllocatedSlot> getAllocatedSlotFuture() {
+			return allocatedSlotFuture;
+		}
+
+		public ResourceProfile getResourceProfile() {
+			return resourceProfile;
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * A slot, together with the timestamp when it was added.
+	 */
+	private static class SlotAndTimestamp {
+
+		private final AllocatedSlot slot;
+
+		private final long timestamp;
+
+		SlotAndTimestamp(AllocatedSlot slot, long timestamp) {
+			this.slot = slot;
+			this.timestamp = timestamp;
+		}
+
+		public AllocatedSlot slot() {
+			return slot;
+		}
+
+		public long timestamp() {
+			return timestamp;
+		}
+
+		@Override
+		public String toString() {
+			return slot + " @ " + timestamp;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolGateway.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolGateway.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolGateway.java
new file mode 100644
index 0000000..d3b51f7
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotPoolGateway.java
@@ -0,0 +1,159 @@
+/*
+ * 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.api.common.time.Time;
+import org.apache.flink.runtime.clusterframework.types.AllocationID;
+import org.apache.flink.runtime.clusterframework.types.ResourceID;
+import org.apache.flink.runtime.clusterframework.types.ResourceProfile;
+import org.apache.flink.runtime.instance.SlotSharingGroupId;
+import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
+import org.apache.flink.runtime.jobmanager.slots.TaskManagerGateway;
+import org.apache.flink.runtime.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.jobmaster.SlotRequestId;
+import org.apache.flink.runtime.messages.Acknowledge;
+import org.apache.flink.runtime.resourcemanager.ResourceManagerGateway;
+import org.apache.flink.runtime.rpc.RpcGateway;
+import org.apache.flink.runtime.rpc.RpcTimeout;
+import org.apache.flink.runtime.taskexecutor.slot.SlotOffer;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * The gateway for calls on the {@link SlotPool}. 
+ */
+public interface SlotPoolGateway extends AllocatedSlotActions, RpcGateway {
+
+	// ------------------------------------------------------------------------
+	//  shutdown
+	// ------------------------------------------------------------------------
+
+	void suspend();
+
+	// ------------------------------------------------------------------------
+	//  resource manager connection
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Connects the SlotPool to the given ResourceManager. After this method is called, the
+	 * SlotPool will be able to request resources from the given ResourceManager.
+	 * 
+	 * @param resourceManagerGateway  The RPC gateway for the resource manager.
+	 */
+	void connectToResourceManager(ResourceManagerGateway resourceManagerGateway);
+
+	/**
+	 * Disconnects the slot pool from its current Resource Manager. After this call, the pool will not
+	 * be able to request further slots from the Resource Manager, and all currently pending requests
+	 * to the resource manager will be canceled.
+	 * 
+	 * <p>The slot pool will still be able to serve slots from its internal pool.
+	 */
+	void disconnectResourceManager();
+
+	// ------------------------------------------------------------------------
+	//  registering / un-registering TaskManagers and slots
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Registers a TaskExecutor with the given {@link ResourceID} at {@link SlotPool}.
+	 *
+	 * @param resourceID identifying the TaskExecutor to register
+	 * @return Future acknowledge which is completed after the TaskExecutor has been registered
+	 */
+	CompletableFuture<Acknowledge> registerTaskManager(ResourceID resourceID);
+
+	/**
+	 * Releases a TaskExecutor with the given {@link ResourceID} from the {@link SlotPool}.
+	 *
+	 * @param resourceID identifying the TaskExecutor which shall be released from the SlotPool
+	 * @return Future acknowledge which is completed after the TaskExecutor has been released
+	 */
+	CompletableFuture<Acknowledge> releaseTaskManager(ResourceID resourceID);
+
+	/**
+	 * Offers a slot to the {@link SlotPool}. The slot offer can be accepted or
+	 * rejected.
+	 *
+	 * @param taskManagerLocation from which the slot offer originates
+	 * @param taskManagerGateway to talk to the slot offerer
+	 * @param slotOffer slot which is offered to the {@link SlotPool}
+	 * @return True (future) if the slot has been accepted, otherwise false (future)
+	 */
+	CompletableFuture<Boolean> offerSlot(
+		TaskManagerLocation taskManagerLocation,
+		TaskManagerGateway taskManagerGateway,
+		SlotOffer slotOffer);
+
+	/**
+	 * Offers multiple slots to the {@link SlotPool}. The slot offerings can be
+	 * individually accepted or rejected by returning the collection of accepted
+	 * slot offers.
+	 *
+	 * @param taskManagerLocation from which the slot offeres originate
+	 * @param taskManagerGateway to talk to the slot offerer
+	 * @param offers slot offers which are offered to the {@link SlotPool}
+	 * @return A collection of accepted slot offers (future). The remaining slot offers are
+	 * 			implicitly rejected.
+	 */
+	CompletableFuture<Collection<SlotOffer>> offerSlots(
+		TaskManagerLocation taskManagerLocation,
+		TaskManagerGateway taskManagerGateway,
+		Collection<SlotOffer> offers);
+
+	/**
+	 * Fails the slot with the given allocation id.
+	 *
+	 * @param allocationID identifying the slot which is being failed
+	 * @param cause of the failure
+	 */
+	void failAllocation(AllocationID allocationID, Exception cause);
+
+	// ------------------------------------------------------------------------
+	//  allocating and disposing slots
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Requests to allocate a slot for the given {@link ScheduledUnit}. The request
+	 * is uniquely identified by the provided {@link SlotRequestId} which can also
+	 * be used to release the slot via {@link #releaseSlot(SlotRequestId, SlotSharingGroupId, Throwable)}.
+	 * The allocated slot will fulfill the requested {@link ResourceProfile} and it
+	 * is tried to place it on one of the location preferences.
+	 *
+	 * <p>If the returned future must not be completed right away (a.k.a. the slot request
+	 * can be queued), allowQueuedScheduling must be set to true.
+	 *
+	 * @param slotRequestId identifying the requested slot
+	 * @param scheduledUnit for which to allocate slot
+	 * @param resourceProfile which the allocated slot must fulfill
+	 * @param locationPreferences which define where the allocated slot should be placed, this can also be empty
+	 * @param allowQueuedScheduling true if the slot request can be queued (e.g. the returned future must not be completed)
+	 * @param timeout for the operation
+	 * @return
+	 */
+	CompletableFuture<LogicalSlot> allocateSlot(
+			SlotRequestId slotRequestId,
+			ScheduledUnit scheduledUnit,
+			ResourceProfile resourceProfile,
+			Collection<TaskManagerLocation> locationPreferences,
+			boolean allowQueuedScheduling,
+			@RpcTimeout Time timeout);
+}

http://git-wip-us.apache.org/repos/asf/flink/blob/0ef7fdde/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotProvider.java
----------------------------------------------------------------------
diff --git a/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotProvider.java b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotProvider.java
new file mode 100644
index 0000000..8e8d019
--- /dev/null
+++ b/flink-runtime/src/main/java/org/apache/flink/runtime/jobmaster/slotpool/SlotProvider.java
@@ -0,0 +1,53 @@
+/*
+ * 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.jobmaster.LogicalSlot;
+import org.apache.flink.runtime.jobmanager.scheduler.ScheduledUnit;
+import org.apache.flink.runtime.taskmanager.TaskManagerLocation;
+
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * The slot provider is responsible for preparing slots for ready-to-run tasks.
+ * 
+ * <p>It supports two allocating modes:
+ * <ul>
+ *     <li>Immediate allocating: A request for a task slot immediately gets satisfied, we can call
+ *         {@link CompletableFuture#getNow(Object)} to get the allocated slot.</li>
+ *     <li>Queued allocating: A request for a task slot is queued and returns a future that will be
+ *         fulfilled as soon as a slot becomes available.</li>
+ * </ul>
+ */
+public interface SlotProvider {
+
+	/**
+	 * Allocating slot with specific requirement.
+	 *
+	 * @param task         The task to allocate the slot for
+	 * @param allowQueued  Whether allow the task be queued if we do not have enough resource
+	 * @param preferredLocations preferred locations for the slot allocation
+	 * @return The future of the allocation
+	 */
+	CompletableFuture<LogicalSlot> allocateSlot(
+		ScheduledUnit task,
+		boolean allowQueued,
+		Collection<TaskManagerLocation> preferredLocations);
+}