Collaboration policy // Submit lab // Setup Go // Guidance // Piazza
In this lab you'll build a MapReduce system. You'll implement a worker process that calls application Map and Reduce functions and handles reading and writing files, and a coordinator process that hands out tasks to workers and copes with failed workers. You'll be building something similar to the MapReduce paper. (Note: this lab uses "coordinator" instead of the paper's "master".)
You need to setup Go to do the labs.
Fetch the initial lab software with git (a version control system). To learn more about git, look at the Pro Git book or the git user's manual.
$ git clone git://g.csail.mit.edu/6.5840-golabs-2026 6.5840 $ cd 6.5840 $ ls Makefile src $
We supply you with a simple sequential mapreduce implementation in src/main/mrsequential.go. It runs the maps and reduces one at a time, in a single process. We also provide you with a couple of MapReduce applications: word-count in mrapps/wc.go, and a text indexer in mrapps/indexer.go. You can run word count sequentially as follows:
$ cd ~/6.5840 $ cd src/main $ go build -buildmode=plugin ../mrapps/wc.go $ rm mr-out* $ go run mrsequential.go wc.so pg*.txt $ sort mr-out-0 A 509 ABOUT 2 ACT 8 ACTRESS 1 ...(You might need to set LC_COLLATE=C environment variable for sort to produce the above output: LC_COLLATE=C sort mr-out-0)
mrsequential.go leaves its output in the file mr-out-0. The input is from the text files named pg-xxx.txt.
Feel free to borrow code from mrsequential.go. You should also have a look at mrapps/wc.go to see what MapReduce application code looks like.
For this lab and all the others, we might issue updates to the code we provide you. To ensure that you can fetch those updates and easily merge them using git pull, it's best to leave the code we provide in the original files. You can add to the code we provide as directed in the lab write-ups; just don't move it. It's OK to put your own new functions in new files.
We have given you a little code to start you off. The "main" routines for the coordinator and worker are in main/mrcoordinator.go and main/mrworker.go; don't change these files. You should put your implementation in mr/coordinator.go, mr/worker.go, and mr/rpc.go.
Here's how to run your code on the word-count MapReduce application. First, build the word-count plugin:
$ cd main $ go build -buildmode=plugin ../mrapps/wc.goIn one window, run the coordinator:
$ rm mr-out* $ go run mrcoordinator.go sock123 pg-*.txtThe sock123 argument specifies a socket on which the coordinator receives RPCs from workers. The pg-*.txt arguments to mrcoordinator.go are the input files; each file corresponds to one "split", and is the input to one Map task.
In one or more other windows, run some workers:
$ go run mrworker.go wc.so sock123When the workers and coordinator have finished, look at the output in mr-out-*. When you've completed the lab, the sorted union of the output files should match the sequential output, like this:
$ cat mr-out-* | sort | more A 509 ABOUT 2 ACT 8 ACTRESS 1 ...
We supply you with all the tests that we'll use to grade your submitted lab. The source code for the tests are in mr/mr_test.go. You can run the tests in the src directory:
$ cd src $ make mr ...The tests check that the wc and indexer MapReduce applications produce the correct output when given the pg-xxx.txt files as input. The tests also check that your implementation runs the Map and Reduce tasks in parallel, and that your implementation recovers from workers that crash while running tasks.
If you run the tests now, they will hang in the first test:
$ cd ~/6.5840/src $ make mr ... cd mr; go test -v -race === RUN TestWc ...
You can change ret := false to true in the Done function in mr/coordinator.go so that the coordinator exits immediately. Then:
$ make mr ... === RUN TestWc 2026/01/22 14:56:24 reduce created no mr-out-X output files! exit status 1 FAIL 6.5840/mr 4.516s make: *** [Makefile:44: mr] Error 1 $
The tests expect to see output in files named mr-out-X, one for each reduce task. The empty implementations of mr/coordinator.go and mr/worker.go don't produce those files (or do much of anything else), so the test fails.
When you've finished, the test output should look like this:
$ make mr ... === RUN TestWc --- PASS: TestWc (8.64s) === RUN TestIndexer --- PASS: TestIndexer (5.90s) === RUN TestMapParallel --- PASS: TestMapParallel (7.05s) === RUN TestReduceParallel --- PASS: TestReduceParallel (8.05s) === RUN TestJobCount --- PASS: TestJobCount (10.04s) === RUN TestEarlyExit --- PASS: TestEarlyExit (6.05s) === RUN TestCrashWorker 2026/01/22 14:58:14 *re*-starting map ../../main/pg-tom_sawyer.txt 0 2026/01/22 14:58:14 *re*-starting map ../../main/pg-metamorphosis.txt 2 2026/01/22 14:58:39 *re*-starting map ../../main/pg-metamorphosis.txt 2 2026/01/22 14:58:40 map 2 already done 2026/01/22 14:58:45 *re*-starting reduce 0 --- PASS: TestCrashWorker (40.18s) PASS ok 6.5840/mr 86.932s $
Depending on your strategy for terminating worker processes, you may see errors like:
2026/02/11 16:21:32 dialing:dial unix /var/tmp/5840-mr-501: connect: connection refusedIt is fine to see a handful of these messages per test; they arise when the worker is unable to contact the coordinator RPC server after the coordinator has exited.
enc := json.NewEncoder(file)
for _, kv := ... {
err := enc.Encode(&kv)
and to read such a file back:
dec := json.NewDecoder(file)
for {
var kv KeyValue
if err := dec.Decode(&kv); err != nil {
break
}
kva = append(kva, kv)
}
reply := SomeType{}
call(..., &reply)
without setting any fields of reply before the call. If you
pass reply structures that have non-default fields, the RPC
system may silently return incorrect values.
Implement your own MapReduce application (see examples in mrapps/*), e.g., Distributed Grep (Section 2.3 of the MapReduce paper).
Get your MapReduce coordinator and workers to run on separate machines, as they would in practice. You will need to set up your RPCs to communicate over TCP/IP instead of Unix sockets (see the commented out line in Coordinator.server()), and read/write files using a shared file system. For example, you can ssh into multiple Athena cluster machines at MIT, which use AFS to share files; or you could rent a couple AWS instances and use S3 for storage.