Extract a local.
Make json keys more public-consumption friendly.
Pull scheduleComponent call out if branching.
Refactor TopologyScheduler, to ease scheduling whole topologies.
Only consider a component to be local if it specifies a table name.
Extract component scheduling logic within an inner class.
Hoist scheduleComponent parameters to constructor.
Component -> ComponentScheduler, scheduleComponent -> scheduleLocal.
ExecutorPreference::findAvailableSlot returns a success flag.
doco
Extract declareAssignmentsToCluster.
Swap names of available and various availableSlots locals.

Also other minor refactorings.
Introduce chosenSlots, which tracks which slots to use per host.

When a slot is chosen, we do not remove it from availableSlots: availableSlots reflects a snapshot of the available slots when scheduling started.
Invert a conditional to hoist numWorkers check above mutations.
Assigned maps slots to executor lists, not hosts to such lists.

The mapping of hosts to slots is supplied by chosenSlots.
doco
Introduce two soon-to-be-not-empty methods, document algorithms.
Here's (an untested) chooseRemainingRequestedSlots.

Its purpose is to consider the fixed set of already chosen hosts & inflate the selection of chosen work slots; this way we will respect numWorkers the same way the default scheduler does.

Notice we don't actually spread any executors out across these extra slots yet.
Tighten final check.
Here's a first stab at distributeTasksAmongSlots.