C-LOOK Disk Scheduling: Jump to the Lowest
Sweep one way serving requests, then jump straight to the lowest pending request and sweep the same way again.
How C-LOOK Disk Scheduling Works
C-LOOK (Circular LOOK) is C-SCAN with both wasted trips removed. It serves in one direction only, but stops at the last pending request rather than the disk edge, and jumps back to the lowest pending request rather than to cylinder 0.
- Choose one service direction and keep it for every sweep, as C-SCAN does.
- Serve every pending request in that direction in cylinder order as the head passes.
- Stop at the last request in that direction rather than continuing to the disk edge.
- Jump directly to the lowest pending request, serving nothing on the way the jump spans the queue, not the disk.
- Resume serving in the same direction from there, so every cylinder is still approached from the same side.
- One-directional service, like C-SCAN
- Turns at the last request, like LOOK
- The return jump spans the queue, not the whole disk
- Combines both savings into one algorithm
Where the 60 Cylinders Go
C-SCAN needs 382 cylinders on the standard queue; C-LOOK needs 322. The 60-cylinder difference is entirely accounted for by the two edges C-LOOK never visits.
Going up, C-SCAN continues from 183 to 199 and back — but C-LOOK simply stops at 183, saving the 16-cylinder overshoot. Coming back, C-SCAN returns all the way to cylinder 0 and then climbs to 14, while C-LOOK jumps straight to 14, saving another 44 cylinders of travel below the lowest request.
The saving depends entirely on how far the outermost requests sit from the disk edges. On a queue that happens to include cylinder 0 and cylinder 199, C-LOOK and C-SCAN behave identically — a useful check that the two algorithms are the same idea with different stopping rules.
- 382 for C-SCAN against 322 for C-LOOK here
- 16 saved at the top by stopping at 183, not 199
- 44 saved at the bottom by jumping to 14, not 0
- The two coincide when the queue reaches both edges
C-LOOK on the standard request queue
def c_look(requests, head):
"""Sweep up, jump to the lowest request, sweep up again."""
above = sorted(c for c in requests if c >= head)
below = sorted(c for c in requests if c < head)
# The jump spans the queue, not the disk: from the highest request
# straight to the lowest one.
order = above + below
total, position = 0, head
for cylinder in order:
total += abs(cylinder - position)
position = cylinder
return order, total
order, total = c_look([98, 183, 37, 122, 14, 140, 65], 53)
print(order, total)#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
using namespace std;
// Returns total head movement in cylinders; `order` receives the service order.
int cLook(const vector<int>& requests, int head, vector<int>& order) {
int total = 0, position = head;
// The jump spans the queue: highest request straight to lowest.
vector<int> above, below;
for (int c : requests) (c >= head ? above : below).push_back(c);
sort(above.begin(), above.end());
sort(below.begin(), below.end());
for (int c : above) order.push_back(c);
for (int c : below) order.push_back(c);
total = 0;
position = head;
for (int cylinder : order) {
total += abs(cylinder - position);
position = cylinder;
}
return total;
}
int main() {
vector<int> requests = {98, 183, 37, 122, 14, 140, 65}, order;
int total = cLook(requests, 53, order);
for (int c : order) cout << c << " ";
cout << "| " << total << " cylinders" << endl;
return 0;
}import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CLookDiskScheduling {
// Returns total head movement in cylinders; `order` receives the service order.
static int cLook(int[] requests, int head, List<Integer> order) {
int total = 0, position = head;
// The jump spans the queue: highest request straight to lowest.
List<Integer> above = new ArrayList<>(), below = new ArrayList<>();
for (int c : requests) (c >= head ? above : below).add(c);
Collections.sort(above);
Collections.sort(below);
order.addAll(above);
order.addAll(below);
total = 0;
position = head;
for (int cylinder : order) {
total += Math.abs(cylinder - position);
position = cylinder;
}
return total;
}
public static void main(String[] args) {
int[] requests = {98, 183, 37, 122, 14, 140, 65};
List<Integer> order = new ArrayList<>();
int total = cLook(requests, 53, order);
System.out.println(order + " | " + total + " cylinders");
}
}Step through it
Running on requests [98, 183, 37, 122, 14, 140, 65], head at 53
Choosing Between the Four Sweeps
With four sweeping variants the choice comes down to two independent questions, and being able to state them is usually what an exam is testing. First: should the head serve in both directions, or only one? Both directions is SCAN and LOOK, and it is cheaper. One direction is C-SCAN and C-LOOK, and it makes waiting time uniform across the disk.
Second: should the head travel to the disk edge, or stop at the last request? Stopping is always cheaper and costs nothing, which is why LOOK and C-LOOK are the forms that actually ship.
On this queue the ranking is LOOK 299 < C-LOOK 322 < SCAN 331 < C-SCAN 382. LOOK wins on raw movement; C-LOOK is the one to choose when a request at the edge of the disk must not wait systematically longer than one in the middle.
- Both directions is cheaper; one direction is fairer across cylinders
- Stopping at the last request is always cheaper than reaching the edge
- LOOK 299 < C-LOOK 322 < SCAN 331 < C-SCAN 382
- C-LOOK is the choice when edge cylinders must not wait longer
Where C-LOOK Still Runs Today
C-LOOK is the most refined of the four sweeps — it wastes no travel at either end and still distributes waiting evenly — which makes it the default elevator in most operating-systems courses and in several real drivers.
Its relevance is now bounded by the hardware. On a hard disk the reasoning holds exactly: the arm is real, the jump back is one long seek instead of many short ones, and no cylinder is favoured. On an SSD or NVMe drive none of it applies. The flash translation layer decides physical placement, access cost is uniform, and Linux defaults such devices to the none scheduler so the controller can parallelise across channels itself.
For rotational media Linux ships bfq, which keeps elevator-style merging under a fair-share layer, and mq-deadline, which sorts by block but lets expiry timers override the order. Both inherit C-LOOK's two commitments — serve requests in positional order, and never let one wait forever — while enforcing the second with clocks rather than geometry.
- On rotational disks C-LOOK's reasoning holds exactly as taught
- On flash, the FTL controls placement and access cost is uniform
bfqkeeps elevator merging;mq-deadlinesorts with expiry overrides- Both enforce fairness with timers rather than sweep geometry