CrackedRuby CrackedRuby

Disk Scheduling Algorithms

Overview

Disk scheduling algorithms determine the order in which disk I/O requests are processed by the operating system. When multiple processes request disk access simultaneously, the scheduler must decide which request to service first to optimize overall system performance. The primary goal is to minimize seek time—the time required for the disk arm to move to the correct track—while balancing fairness and preventing request starvation.

Traditional hard disk drives (HDDs) have mechanical components that move physically to access data. The disk arm moves across tracks, and each movement incurs a cost measured in milliseconds. Different scheduling algorithms make different trade-offs between minimizing total seek time, ensuring fair access, and preventing indefinite postponement of requests.

Disk Structure:
Track 0:  |------------|
Track 1:  |------------|
Track 2:  |------------|  <- Current head position
Track 3:  |------------|
Track 4:  |------------|

Request Queue: [98, 183, 37, 122, 14, 124, 65, 67]
Current Position: Track 53

The choice of disk scheduling algorithm affects system responsiveness, throughput, and fairness. Modern operating systems often implement hybrid approaches that adapt based on workload characteristics. While solid-state drives (SSDs) have different performance characteristics without mechanical seek time, understanding these algorithms remains relevant for systems using HDDs and for comprehending I/O scheduling principles.

Key Principles

Disk scheduling algorithms operate on several fundamental principles that govern how requests are ordered and serviced. The scheduler maintains a queue of pending I/O requests, each specifying a track number where data resides. The disk head position changes as requests are serviced, and the scheduler must determine the next request to process.

Seek Time represents the dominant cost in disk operations for HDDs. Seek time consists of the time to accelerate the disk arm, move it across tracks, and decelerate it at the destination. Minimizing total seek time across all requests improves overall throughput. The seek distance—the number of tracks between the current head position and the requested track—directly correlates with seek time.

Rotational Latency occurs after the head reaches the correct track. The disk must rotate until the desired sector passes under the head. Average rotational latency equals half the time for one complete rotation. Scheduling algorithms typically optimize seek time rather than rotational latency, though some advanced algorithms consider both factors.

Fairness ensures that all requests eventually receive service. Algorithms that aggressively optimize seek time may cause starvation, where requests far from the current head position wait indefinitely. Balancing efficiency with fairness prevents pathological cases where certain requests never complete.

Direction of Movement influences several algorithms. Once the disk head moves in a particular direction, continuing that direction for nearby requests often proves more efficient than reversing direction. This principle underlies the SCAN family of algorithms.

Request Patterns vary by workload. Sequential access patterns, where requests target consecutive tracks, differ from random access patterns. Database systems often generate localized request clusters, while multimedia applications produce sequential patterns. Effective scheduling algorithms adapt to these patterns.

The arrival order of requests affects some algorithms. First Come First Serve (FCFS) strictly follows arrival order, while other algorithms reorder requests based on optimization criteria. The scheduler must track both the original arrival sequence and the reordered service sequence.

Design Considerations

Selecting a disk scheduling algorithm requires analyzing workload characteristics, performance requirements, and fairness constraints. Different algorithms excel in different scenarios, and no single algorithm optimally handles all situations.

Throughput Optimization guides algorithm selection for high-volume systems. Algorithms like SSTF and SCAN minimize total seek time, maximizing the number of requests serviced per unit time. Systems processing large numbers of small I/O operations benefit from throughput-focused algorithms. However, extreme throughput optimization may compromise fairness, potentially causing starvation for requests to distant tracks.

Response Time Variation affects user experience in interactive systems. FCFS provides predictable response times since requests complete in arrival order, though overall response times may be longer. Algorithms that reorder requests introduce variance—some requests complete quickly while others wait longer. Applications requiring consistent latency prefer algorithms with bounded worst-case response times.

Workload Characteristics determine algorithm effectiveness. Sequential workloads, such as video streaming or database scans, naturally benefit from directional algorithms like SCAN. Random access workloads, typical of multi-user systems or virtual memory paging, may perform better with SSTF if the requests distribute evenly across the disk. Analyzing historical access patterns reveals whether requests cluster in specific disk regions or spread uniformly.

# Workload analysis determines algorithm selection
class WorkloadAnalyzer
  def initialize(requests)
    @requests = requests
  end
  
  def sequential_ratio
    sequential_count = 0
    @requests.each_cons(2) do |curr, nxt|
      sequential_count += 1 if (curr - nxt).abs <= 5
    end
    sequential_count.to_f / (@requests.size - 1)
  end
  
  def spread_metric
    @requests.max - @requests.min
  end
end

analyzer = WorkloadAnalyzer.new([50, 52, 100, 103, 105, 45])
analyzer.sequential_ratio  # => 0.6 (indicates sequential tendency)

Starvation Prevention requires careful consideration. SSTF and LOOK variants may indefinitely postpone requests to extreme track positions if requests continually arrive for middle tracks. Production systems must guarantee eventual service for all requests. Hybrid algorithms that periodically switch to FCFS mode or impose waiting time limits prevent starvation. Real-time systems may require strict deadlines, necessitating algorithms that guarantee maximum wait times.

Hardware Constraints influence algorithm implementation. Modern disk controllers cache requests and may reorder them internally, reducing the operating system scheduler's control. The disk's physical geometry—number of tracks, sectors per track, rotation speed—affects the relative cost of different operations. Some disks support Native Command Queuing (NCQ), allowing the drive firmware to optimize request ordering based on physical disk characteristics invisible to the OS.

System Load changes optimal algorithm selection. Under light load with few pending requests, algorithm choice matters less since reordering opportunities are limited. Heavy load with long request queues allows algorithms to make better optimization decisions. Adaptive scheduling systems switch algorithms based on current queue depth and system load.

Implementation Approaches

Disk scheduling algorithms differ in how they select the next request to service from the pending queue. Each approach maintains the request queue and current head position, but applies different selection logic.

First Come First Serve (FCFS) processes requests in strict arrival order. The implementation uses a simple FIFO queue. When a request completes, the scheduler removes the next request from the queue head. FCFS requires no complex data structures or sorting logic, making it the simplest algorithm to implement.

Request Queue: [98, 183, 37, 122, 14, 124, 65, 67]
Current Position: 53

Service Order: 98 -> 183 -> 37 -> 122 -> 14 -> 124 -> 65 -> 67
Total Seek Distance: 45 + 85 + 146 + 85 + 108 + 110 + 59 + 2 = 640 tracks

FCFS guarantees fairness and prevents starvation but provides poor performance when requests arrive in unfavorable orders. Wide disk arm movements waste seek time. FCFS works acceptably for systems with light I/O load or predictable sequential access patterns.

Shortest Seek Time First (SSTF) selects the request nearest to the current head position. The implementation maintains requests in a data structure supporting efficient nearest-neighbor queries. Each time a request completes, the scheduler scans pending requests to find the one requiring minimum seek distance.

Request Queue: [98, 183, 37, 122, 14, 124, 65, 67]
Current Position: 53

First selection: 65 (distance 12)
Next selection: 67 (distance 2)
Next selection: 37 (distance 30)
Continue selecting nearest...

Total Seek Distance significantly reduced compared to FCFS

SSTF minimizes average seek time and maximizes throughput. However, it suffers from starvation—requests to extreme tracks may wait indefinitely if requests continually arrive for middle tracks. SSTF also exhibits direction changes, potentially causing the disk arm to oscillate rather than sweep smoothly.

SCAN (Elevator Algorithm) moves the disk arm in one direction, servicing all requests in that direction until reaching the disk end, then reverses direction. The implementation maintains the current direction of movement and selects requests ahead of the current position in the movement direction.

Request Queue: [98, 183, 37, 122, 14, 124, 65, 67]
Current Position: 53, Direction: Increasing

Moving right: 65, 67, 98, 122, 124, 183, [reach end]
Reverse direction
Moving left: 37, 14

Total Seek Distance: Lower than FCFS, more fair than SSTF

SCAN provides better fairness than SSTF while maintaining good performance. Requests receive service in bounded time since the disk arm sweeps the entire disk periodically. The algorithm's name derives from its similarity to elevator scheduling in buildings.

Circular SCAN (C-SCAN) treats the disk as a circular structure. The arm moves in one direction, servicing requests, and upon reaching the end, returns to the beginning without servicing requests during the return sweep. C-SCAN provides more uniform wait times than SCAN since it eliminates the advantage given to middle tracks.

LOOK and C-LOOK optimize SCAN and C-SCAN by reversing direction at the last request in each direction rather than traveling to the disk end. This reduces unnecessary seeking to empty disk regions. LOOK serves requests in both directions while C-LOOK returns to the beginning after reaching the last request in one direction.

Ruby Implementation

Ruby implementations of disk scheduling algorithms demonstrate the core logic and data structure management. Production implementations typically reside in operating system kernels, but Ruby provides clear illustration of the algorithms.

class DiskScheduler
  attr_reader :requests, :head_position, :total_seek_distance
  
  def initialize(initial_head_position)
    @head_position = initial_head_position
    @requests = []
    @total_seek_distance = 0
    @service_order = []
  end
  
  def add_request(track)
    @requests << track
  end
  
  def service_order
    @service_order
  end
  
  protected
  
  def move_to(track)
    seek_distance = (track - @head_position).abs
    @total_seek_distance += seek_distance
    @head_position = track
    @service_order << track
    @requests.delete_at(@requests.index(track))
  end
end

The base class provides common functionality for tracking head position, calculating seek distance, and maintaining the service order. Specific algorithms inherit from this base and implement their scheduling logic.

class FCFSScheduler < DiskScheduler
  def schedule
    until @requests.empty?
      next_request = @requests.first
      move_to(next_request)
    end
  end
end

# Usage
scheduler = FCFSScheduler.new(53)
[98, 183, 37, 122, 14, 124, 65, 67].each { |r| scheduler.add_request(r) }
scheduler.schedule
scheduler.service_order  # => [98, 183, 37, 122, 14, 124, 65, 67]
scheduler.total_seek_distance  # => 640

FCFS implementation directly processes requests from the queue without reordering. The simplicity reflects the algorithm's straightforward nature.

class SSTFScheduler < DiskScheduler
  def schedule
    until @requests.empty?
      next_request = find_nearest_request
      move_to(next_request)
    end
  end
  
  private
  
  def find_nearest_request
    @requests.min_by { |track| (track - @head_position).abs }
  end
end

# Usage
scheduler = SSTFScheduler.new(53)
[98, 183, 37, 122, 14, 124, 65, 67].each { |r| scheduler.add_request(r) }
scheduler.schedule
scheduler.service_order  # => [65, 67, 37, 14, 98, 122, 124, 183]
scheduler.total_seek_distance  # => 236

SSTF finds the nearest request using Ruby's min_by method. Each iteration recalculates the nearest request based on the updated head position. The significant reduction in total seek distance compared to FCFS demonstrates SSTF's efficiency.

class SCANScheduler < DiskScheduler
  def initialize(initial_head_position, direction = :up)
    super(initial_head_position)
    @direction = direction
  end
  
  def schedule
    until @requests.empty?
      requests_in_direction = if @direction == :up
        @requests.select { |r| r >= @head_position }.sort
      else
        @requests.select { |r| r <= @head_position }.sort.reverse
      end
      
      if requests_in_direction.empty?
        @direction = (@direction == :up) ? :down : :up
        next
      end
      
      move_to(requests_in_direction.first)
    end
  end
end

# Usage
scheduler = SCANScheduler.new(53, :up)
[98, 183, 37, 122, 14, 124, 65, 67].each { |r| scheduler.add_request(r) }
scheduler.schedule
scheduler.service_order  # => [65, 67, 98, 122, 124, 183, 37, 14]
scheduler.total_seek_distance  # => 208

SCAN maintains direction state and selects requests ahead of the current position. When no requests remain in the current direction, the algorithm reverses. The implementation sorts requests in the current direction to process them in optimal order.

class LOOKScheduler < DiskScheduler
  def initialize(initial_head_position, direction = :up)
    super(initial_head_position)
    @direction = direction
  end
  
  def schedule
    until @requests.empty?
      requests_in_direction = if @direction == :up
        @requests.select { |r| r >= @head_position }.sort
      else
        @requests.select { |r| r <= @head_position }.sort.reverse
      end
      
      if requests_in_direction.empty?
        @direction = (@direction == :up) ? :down : :up
      else
        move_to(requests_in_direction.first)
      end
    end
  end
end

# LOOK avoids traveling to disk ends unnecessarily
scheduler = LOOKScheduler.new(53, :up)
[98, 183, 37, 122, 14, 124, 65, 67].each { |r| scheduler.add_request(r) }
scheduler.schedule
scheduler.total_seek_distance  # => 208 (same pattern as SCAN but potentially less if no requests at extremes)

LOOK improves upon SCAN by reversing at the last request rather than the disk boundary. The implementation logic closely resembles SCAN but provides better performance when requests don't span the entire disk.

class CSCANScheduler < DiskScheduler
  def initialize(initial_head_position, max_track = 199)
    super(initial_head_position)
    @max_track = max_track
  end
  
  def schedule
    until @requests.empty?
      requests_ahead = @requests.select { |r| r >= @head_position }.sort
      
      if requests_ahead.empty?
        # Jump back to beginning
        @head_position = 0
        next
      end
      
      move_to(requests_ahead.first)
    end
  end
end

# C-SCAN provides uniform wait time distribution
scheduler = CSCANScheduler.new(53, 199)
[98, 183, 37, 122, 14, 124, 65, 67].each { |r| scheduler.add_request(r) }
scheduler.schedule
scheduler.service_order  # => [65, 67, 98, 122, 124, 183, 14, 37]

C-SCAN unidirectionally services requests and returns to the disk start without servicing requests during the return. This approach provides more predictable wait times across all track positions.

Performance Considerations

Disk scheduling algorithm performance depends on multiple factors including request distribution, system load, and hardware characteristics. Different metrics reveal different aspects of algorithm effectiveness.

Average Seek Time measures the mean seek distance across all requests. SSTF typically achieves the lowest average seek time by consistently selecting nearby requests. SCAN and LOOK provide intermediate performance, while FCFS often exhibits the highest average seek time due to random movement patterns.

class PerformanceAnalyzer
  def initialize(scheduler_class, head_position, requests)
    @scheduler_class = scheduler_class
    @head_position = head_position
    @requests = requests
  end
  
  def analyze
    scheduler = @scheduler_class.new(@head_position)
    @requests.each { |r| scheduler.add_request(r) }
    scheduler.schedule
    
    {
      algorithm: @scheduler_class.name,
      total_seek: scheduler.total_seek_distance,
      average_seek: scheduler.total_seek_distance.to_f / @requests.size,
      service_order: scheduler.service_order,
      request_count: @requests.size
    }
  end
end

requests = [98, 183, 37, 122, 14, 124, 65, 67]

[FCFSScheduler, SSTFScheduler, SCANScheduler, LOOKScheduler].each do |algo|
  result = PerformanceAnalyzer.new(algo, 53, requests.dup).analyze
  puts "#{result[:algorithm]}: Average Seek = #{result[:average_seek].round(2)}"
end

# Output:
# FCFSScheduler: Average Seek = 80.00
# SSTFScheduler: Average Seek = 29.50
# SCANScheduler: Average Seek = 26.00
# LOOKScheduler: Average Seek = 26.00

Maximum Wait Time indicates fairness and starvation potential. FCFS provides bounded maximum wait time proportional to queue length. SSTF may cause unbounded wait times for distant requests under continuous arrival patterns. SCAN guarantees bounded wait time proportional to two full disk sweeps.

Variance in Wait Time affects perceived system responsiveness. FCFS exhibits high variance when requests arrive in random orders. SSTF shows extreme variance—nearby requests complete quickly while distant requests wait extensively. SCAN provides moderate variance with more uniform distribution than SSTF.

Throughput measures requests completed per time unit. SSTF typically achieves highest throughput by minimizing total seek time. However, under heavy load with continuous arrivals, SSTF may service the same disk region repeatedly while distant requests accumulate, eventually degrading throughput when the scheduler must address the backlog.

class ThroughputSimulator
  def initialize(scheduler_class, arrival_rate)
    @scheduler_class = scheduler_class
    @arrival_rate = arrival_rate
    @time = 0
    @completed = 0
  end
  
  def simulate(duration, disk_size = 200)
    scheduler = @scheduler_class.new(disk_size / 2)
    
    while @time < duration
      # Generate arrivals based on arrival rate
      arrivals = rand(0..@arrival_rate)
      arrivals.times { scheduler.add_request(rand(0...disk_size)) }
      
      # Service requests
      unless scheduler.requests.empty?
        scheduler.schedule
        @completed += scheduler.service_order.size
      end
      
      @time += 1
    end
    
    @completed.to_f / duration  # Throughput: requests per time unit
  end
end

Seek Pattern Locality impacts performance significantly. Sequential access patterns benefit all algorithms but especially SCAN-based approaches. Random access patterns expose algorithm differences more clearly. Database workloads often exhibit temporal locality—requests cluster in time—and spatial locality—requests cluster in disk regions. Algorithms that exploit locality outperform those treating requests independently.

Queue Length Effects change algorithm behavior. Short queues limit reordering opportunities, reducing differences between algorithms. Long queues allow aggressive optimization but increase average wait time for all algorithms. Very long queues may indicate system overload where no algorithm performs adequately.

Hardware Impact increasingly dominates algorithm performance. Modern disk drives with large caches, command queuing, and sophisticated firmware perform internal optimization that overrides OS-level scheduling decisions. The operating system submits multiple requests to the drive, which reorders them based on physical geometry knowledge unavailable to the OS. This reality reduces the performance gap between algorithms in production systems compared to theoretical analysis.

Practical Examples

Examining concrete scenarios demonstrates how different algorithms behave under various workload conditions and helps identify appropriate algorithm selection for specific use cases.

Database Transaction Processing generates random access patterns across the disk. Consider a database system processing multiple concurrent queries that access different table regions.

class DatabaseWorkloadSimulator
  def initialize(scheduler_class)
    @scheduler_class = scheduler_class
  end
  
  def simulate_transactions(num_transactions)
    # Database tables distributed across disk
    customer_table_tracks = (10..50)
    order_table_tracks = (100..150)
    product_table_tracks = (160..180)
    
    scheduler = @scheduler_class.new(75)  # Initial position
    
    num_transactions.times do
      # Each transaction accesses multiple tables
      scheduler.add_request(rand(customer_table_tracks))
      scheduler.add_request(rand(order_table_tracks))
      scheduler.add_request(rand(product_table_tracks))
    end
    
    scheduler.schedule
    
    {
      total_seek: scheduler.total_seek_distance,
      avg_seek: scheduler.total_seek_distance.to_f / (num_transactions * 3),
      service_order: scheduler.service_order
    }
  end
end

# Compare algorithms for database workload
fcfs_result = DatabaseWorkloadSimulator.new(FCFSScheduler).simulate_transactions(10)
sstf_result = DatabaseWorkloadSimulator.new(SSTFScheduler).simulate_transactions(10)
scan_result = DatabaseWorkloadSimulator.new(SCANScheduler).simulate_transactions(10)

puts "Database Workload Results:"
puts "FCFS: #{fcfs_result[:avg_seek].round(2)} tracks average"
puts "SSTF: #{sstf_result[:avg_seek].round(2)} tracks average"
puts "SCAN: #{scan_result[:avg_seek].round(2)} tracks average"

For database workloads with random access patterns, SSTF minimizes seek time but risks starving transactions requiring distant table access. SCAN provides better fairness, ensuring all transactions complete within bounded time. Production database systems often use SCAN variants or implement custom scheduling that considers transaction priorities.

Video Streaming Service produces sequential read patterns as the system reads video files stored contiguously on disk. Multiple concurrent streams create interleaved sequential access patterns.

class VideoStreamingSimulator
  def initialize(scheduler_class)
    @scheduler_class = scheduler_class
  end
  
  def simulate_streaming(num_streams, blocks_per_stream)
    scheduler = @scheduler_class.new(0)
    
    # Each stream starts at different disk location
    stream_positions = num_streams.times.map { |i| i * 40 }
    
    # Generate sequential reads for each stream
    num_streams.times do |stream_id|
      start_track = stream_positions[stream_id]
      blocks_per_stream.times do |block|
        scheduler.add_request(start_track + block)
      end
    end
    
    scheduler.schedule
    
    {
      total_seek: scheduler.total_seek_distance,
      service_order: scheduler.service_order
    }
  end
end

result = VideoStreamingSimulator.new(SCANScheduler).simulate_streaming(3, 10)

# SCAN efficiently handles sequential patterns
# Services requests in sweeping motion, naturally fitting sequential access

SCAN excels at video streaming workloads because its sweeping motion aligns with sequential access patterns. The algorithm services consecutive blocks for each stream during each sweep, providing smooth playback without excessive seeking. FCFS would thrash between streams, while SSTF might starve streams at disk extremes.

Virtual Memory Paging creates mixed access patterns. Page faults cause disk reads to swap pages into memory. The access pattern combines locality (programs often access nearby memory pages) with randomness (context switches between processes).

class PagingWorkloadSimulator
  def initialize(scheduler_class)
    @scheduler_class = scheduler_class
  end
  
  def simulate_paging(processes)
    scheduler = @scheduler_class.new(100)
    
    processes.each do |process|
      # Each process has working set (locality)
      base_page = process[:base_page]
      working_set_size = process[:working_set]
      
      # Generate page faults within working set
      process[:page_faults].times do
        # Most accesses near base (locality)
        if rand < 0.7
          page = base_page + rand(0...working_set_size)
        else
          # Occasional random access
          page = rand(0..199)
        end
        scheduler.add_request(page)
      end
    end
    
    scheduler.schedule
    
    {
      total_seek: scheduler.total_seek_distance,
      avg_seek: scheduler.total_seek_distance.to_f / 
                processes.sum { |p| p[:page_faults] }
    }
  end
end

processes = [
  { base_page: 20, working_set: 30, page_faults: 15 },
  { base_page: 100, working_set: 25, page_faults: 12 },
  { base_page: 170, working_set: 20, page_faults: 10 }
]

result = PagingWorkloadSimulator.new(LOOKScheduler).simulate_paging(processes)
puts "Paging workload average seek: #{result[:avg_seek].round(2)} tracks"

LOOK performs well for virtual memory paging because it exploits locality within each process's working set while avoiding starvation. When the scheduler sweeps through the disk, it services clustered page faults from each process efficiently. The algorithm adapts to the mixed random-sequential nature of paging workloads.

Real-Time System with Deadlines requires guaranteed completion times. Consider an industrial control system that must read sensor data from disk with strict deadlines.

class RealTimeScheduler < DiskScheduler
  def initialize(initial_head_position)
    super(initial_head_position)
    @deadlines = {}
  end
  
  def add_request_with_deadline(track, deadline)
    @requests << track
    @deadlines[track] = deadline
  end
  
  def schedule(current_time = 0)
    @time = current_time
    missed_deadlines = 0
    
    until @requests.empty?
      # Select request with earliest deadline
      next_request = @requests.min_by { |track| @deadlines[track] }
      
      seek_time = (next_request - @head_position).abs
      @time += seek_time
      
      if @time > @deadlines[next_request]
        missed_deadlines += 1
      end
      
      move_to(next_request)
    end
    
    missed_deadlines
  end
end

# Real-time system prioritizes deadlines over seek optimization
rt_scheduler = RealTimeScheduler.new(53)
rt_scheduler.add_request_with_deadline(98, 100)
rt_scheduler.add_request_with_deadline(14, 50)
rt_scheduler.add_request_with_deadline(183, 200)

missed = rt_scheduler.schedule(0)
puts "Missed deadlines: #{missed}"

Real-time systems require deadline-aware scheduling that may sacrifice seek time optimization to guarantee timing constraints. Earliest Deadline First (EDF) scheduling orders requests by deadline rather than track position. The system must ensure sufficient disk bandwidth to meet all deadlines under worst-case seek times.

Reference

Algorithm Comparison

Algorithm Average Seek Time Fairness Starvation Risk Complexity
FCFS High Excellent None O(1)
SSTF Low Poor High O(n) per selection
SCAN Medium Good None O(n log n) for sorting
C-SCAN Medium Excellent None O(n log n) for sorting
LOOK Medium Good None O(n log n) for sorting
C-LOOK Medium Excellent None O(n log n) for sorting

Algorithm Characteristics

Algorithm Direction Changes Services Both Directions Returns to Start
FCFS Frequent Yes N/A
SSTF Frequent Yes N/A
SCAN At endpoints Yes No
C-SCAN At endpoint No Yes
LOOK At last request Yes No
C-LOOK At last request No Yes

Performance Metrics

Metric FCFS SSTF SCAN C-SCAN LOOK C-LOOK
Best Case Seek Time High Lowest Medium Medium Medium Medium
Worst Case Seek Time Very High High Medium Medium Medium Medium
Wait Time Variance High Very High Medium Low Medium Low
Implementation Complexity Lowest Low Medium Medium Medium Medium

Use Case Recommendations

Workload Type Recommended Algorithm Reason
Sequential read SCAN or LOOK Aligns with directional movement
Random access SSTF or SCAN Balances performance and fairness
Real-time Custom deadline-aware Guarantees timing constraints
Mixed workload LOOK or C-LOOK Good balance of all factors
Fair share required C-SCAN or C-LOOK Uniform wait time distribution
Low system load FCFS acceptable Simple with adequate performance

Implementation Considerations

Consideration FCFS SSTF SCAN LOOK
Data Structure Queue Priority Queue or Array Sorted Arrays Sorted Arrays
Sorting Required No No Yes Yes
Direction Tracking No No Yes Yes
Request Insertion Complexity O(1) O(1) or O(log n) O(1) or O(log n) O(1) or O(log n)
Selection Complexity O(1) O(n) or O(log n) O(1) after sort O(1) after sort

Disk Hardware Parameters

Parameter Typical Value Impact on Scheduling
Track-to-track seek time 0.2-2 ms Minimum cost per seek
Average seek time 3-10 ms Cost of medium distance seeks
Full stroke seek time 10-20 ms Maximum seek cost
Rotational latency 2-8 ms Cannot be reduced by scheduling
Transfer rate 100-200 MB/s Affects request service time
Command queue depth 32-256 Limits reordering opportunities

Ruby Implementation Patterns

Pattern Code Example Purpose
Scheduler Base Class class DiskScheduler with common methods Shared functionality
Find Nearest requests.min_by distance calculation SSTF selection
Directional Filtering requests.select based on position and direction SCAN implementation
Direction Reversal Toggle direction state when no requests ahead SCAN direction change
Circular Return Jump to track 0 after reaching end C-SCAN implementation
Seek Distance Tracking Accumulate absolute position differences Performance measurement
Service Order Recording Array storing completed request sequence Result analysis