Skip to main content

SwapFullWithEmpty

Move Type: Swap Complexity: O(empty_containers) with full container move

Move ALL objects from hot container to an empty container. Ideal for consolidation, decommissioning, and bin-packing scenarios.

Overview

SwapFullWithEmpty evaluates moving all objects from the hot container to every empty container in the system. This is a specialized move type for consolidation - reducing the number of active containers by emptying overloaded or problematic containers.

Use when:

  • Consolidating workload (reducing active containers)
  • Decommissioning servers/containers
  • Bin-packing optimization
  • Have spare capacity in empty containers
  • Want to empty specific containers

Avoid when:

  • No empty containers available
  • Objects can't all fit in one container
  • Need fine-grained object placement
  • Container capacities would be violated

Quick Example

# Move all objects from hot container to empty containers
solver.addSolver(
SolverSpecs(
localSearchSolverSpec=LocalSearchSolverSpec(
moveTypeList=[
SwapFullWithEmptyContainersMoveTypeSpec(), # Consolidate to empties
]
)
)
)

Parameters

ParameterTypeRequiredDefaultDescription
(none)---SwapFullWithEmpty has no configuration parameters

How It Works

Given a hot container (the container contributing most to the objective):

  1. Find empty containers: Identify all containers with zero objects
  2. Try each empty: For each empty container:
    • Move ALL objects from hot container to empty container
    • Evaluate resulting objective
  3. Parallel evaluation: All empty containers evaluated in parallel
  4. Apply best: Apply the move to empty container that improves objective most

Visual Example

Before move:                      After full move to empty:
┌─────────────────┐ ┌─────────────────┐
│ Hot Container │ │ Hot Container │
│ • obj1 ───────┼──┐ │ (empty) │
│ • obj2 │ │ │ │
│ • obj3 │ │ │ │
└─────────────────┘ │ └─────────────────┘

│ ┌─────────────────┐
┌─────────────────┐ │ │ Empty Container │
│ Empty Container │ │ │ • obj1 ←───────┼─┘
│ (empty) │ │ │ • obj2 │
│ │ │ │ • obj3 │
└─────────────────┘ │ └─────────────────┘
All objects moved in ONE move

Comparison with Alternatives

Move TypeSourceDestinationUse Case
SingleAny objectAny containerGeneral placement
SwapObject pairsOccupied containersCapacity-constrained
SwapFullContainersAll objectsAny container (swap)Container migration
SwapFullWithEmptyAll objectsEmpty containers onlyConsolidation

Complexity

Moves evaluated per iteration: O(E)

Where:

  • E = number of empty containers

Example:

  • System: 1,000 containers total
  • Empty containers: 100
  • Hot container: 1,000 objects
  • Moves evaluated: 100 (one per empty container)

Note: Much faster than regular moves since only empty containers are considered.

Usage Patterns

Container Consolidation

Reduce number of active containers:

# Consolidate workload to reduce active servers
solver.addGoal(
GoalSpecs(
minimizeContainersSpec=MinimizeContainersSpec(
name="minimize-servers",
scope="server",
),
),
weight=1.0,
)

solver.addSolver(
SolverSpecs(
localSearchSolverSpec=LocalSearchSolverSpec(
moveTypeList=[
SwapFullWithEmptyContainersMoveTypeSpec(), # Empty servers
SingleMoveTypeSpec(), # Pack remaining efficiently
]
)
)
)

Server Decommissioning

Empty servers for maintenance:

# Decommission specific servers by moving all shards to empties
# Use nonAccepting or toFree constraints to mark servers for decommission
solver.addSolver(
SolverSpecs(
localSearchSolverSpec=LocalSearchSolverSpec(
moveTypeList=[
SwapFullWithEmptyContainersMoveTypeSpec(), # Move to empty servers
]
)
)
)

Bin-Packing Optimization

Minimize number of active bins:

# Bin-packing: minimize active containers
solver.addGoal(
GoalSpecs(
minimizeContainersSpec=MinimizeContainersSpec(
name="minimize-bins",
scope="container",
),
),
weight=10.0, # High weight for consolidation
)

solver.addSolver(
SolverSpecs(
localSearchSolverSpec=LocalSearchSolverSpec(
moveTypeList=[
SwapFullWithEmptyContainersMoveTypeSpec(), # Empty containers
SingleMoveTypeSpec(), # Pack efficiently
]
)
)
)

Combined Strategy

Use with other moves for complete consolidation:

# Multi-stage consolidation strategy
solver.addGoal(
GoalSpecs(
minimizeContainersSpec=MinimizeContainersSpec(
name="minimize-containers",
scope="container",
),
),
weight=5.0,
)

solver.addSolver(
SolverSpecs(
localSearchSolverSpec=LocalSearchSolverSpec(
moveTypeList=[
SwapFullWithEmptyContainersMoveTypeSpec(), # Empty containers quickly
SingleMoveTypeSpec(), # Efficient packing
]
)
)
)

Performance Characteristics

Scalability

Empty ContainersObjects to MoveEvaluation TimePractical?
101K<1s✓ Yes
10010K1-5s✓ Yes
100010K10-60s✓ Yes
10K100K2-10 min△ Depends on objective

Note: Complexity is O(empty_containers), independent of total containers.

When Does It Help?

SwapFullWithEmpty helps when:

  • Consolidation goal: Want to reduce active containers
  • Spare capacity: Have empty containers available
  • Decommissioning: Need to empty specific containers
  • Bin-packing: Minimize container usage
  • Hot container is problematic: Want it completely empty

SwapFullWithEmpty does NOT help when:

  • No empty containers: Can't move anywhere
  • Capacity issues: Objects won't fit in one container
  • Need fine-grained placement: Full move too coarse
  • Hot container should stay active: Just needs rebalancing

Comparison with Variants

Move TypeDestination TypeGranularityPrimary Use Case
SingleAny containerIndividual objectsGeneral optimization
SwapOccupied containersObject pairsCapacity-constrained
SwapFullContainersAny containerFull swapContainer migration
SwapFullWithEmptyEmpty onlyAll objectsConsolidation

Consolidation strategy order:

  1. SwapFullWithEmpty - Empty problematic containers
  2. Single - Pack remaining objects efficiently
  3. MinimizeContainers goal - Drive toward fewer containers

Troubleshooting

Problem: No improving moves found

Diagnosis: No empty containers OR moving to empty doesn't improve objective

Solutions:

  • Check if empty containers exist (containers - used_containers)
  • Verify objective function rewards consolidation
  • May need MinimizeContainers goal
  • Use Single to create empty containers first

Problem: Capacity violations when moving to empty

Diagnosis: All objects don't fit in empty container

Solutions:

  • Check container capacity constraints
  • Objects may exceed single container capacity
  • Use Single to move objects individually
  • Split hot container load across multiple destinations

Problem: Empties wrong containers

Diagnosis: Hot container selection not aligned with decommissioning goals

Solutions:

  • Use avoidMoving to protect containers that should stay active
  • Use nonAccepting to mark containers for decommissioning
  • Set toFree constraints on containers to empty
  • Adjust objective to penalize specific containers

Problem: Too slow despite few empty containers

Diagnosis: Objective evaluation is expensive for full container moves

Solutions:

  • Profile objective function evaluation
  • Each move evaluates all objects moving together
  • Consider if full move is necessary
  • May be inherently expensive for this problem

When to Use SwapFullWithEmpty

DO use when:

  • Consolidating workload to reduce container count
  • Decommissioning servers or containers
  • Bin-packing optimization
  • Have empty containers available
  • Want to completely empty specific containers

DO NOT use when:

  • No empty containers in system
  • Need fine-grained object placement
  • Objects won't fit in single container
  • Hot container should remain active

Consolidation moves:

  • SwapFullWithEmpty - Move all to empty (this)
  • MinimizeContainers - Goal to reduce containers
  • Single - Move individual objects

Full container moves:

  • SwapFullContainers - Swap entire containers
  • SwapFullWithEmpty - Move to empty only (this)

Use together:

  1. SwapFullWithEmpty to empty problematic containers
  2. Single to pack efficiently
  3. MinimizeContainers goal to drive consolidation

Source Code

Next Steps