6.5840/src/mr/coordinator.go

158 lines
3.2 KiB
Go

package mr
import "log"
import "net"
import "os"
import "net/rpc"
import "net/http"
import "sync"
type status uint8
const (
idle status = iota
progress
completed
)
type Coordinator struct {
// Your definitions here.
mapJobStatus map[string]status
reduceJobStatus map[string]status
workerStatus map[int]status
intermediateFiles map[string][]string
nReduce int
workerCount int
m sync.Mutex
}
func (c *Coordinator) areMapJobsDone() bool {
done := true
for _, job := range c.mapJobStatus {
if job != completed {
done = false
}
}
return done
}
// Your code here -- RPC handlers for the worker to call.
//
// an example RPC handler.
//
// the RPC argument and reply types are defined in rpc.go.
//
func (c *Coordinator) Example(args *ExampleArgs, reply *ExampleReply) error {
reply.Y = args.X + 1
return nil
}
func (c *Coordinator) Register(args *RegisterArgs, reply *RegisterReply) error {
c.m.Lock()
defer c.m.Unlock()
reply.WorkerId = c.workerCount
c.workerCount += 1
c.workerStatus[reply.WorkerId] = idle
return nil
}
func (c *Coordinator) GetJob(args *GetJobArgs, reply *GetJobReply) error {
c.m.Lock()
c.m.Unlock()
if !c.areMapJobsDone() {
for filename, jobStatus := range c.mapJobStatus {
if jobStatus == idle {
var job MapJob
job.InputFile = filename
job.ReducerCount = c.nReduce
c.mapJobStatus[filename] = progress
reply.Finished = false
reply.JobType = Map
reply.MapJob = job
c.workerStatus[args.WorkerId] = progress
return nil
}
}
}
return nil
}
func (c *Coordinator) Finish(args *MapResult, reply *FinishReply) error {
c.m.Lock()
defer c.m.Unlock()
c.intermediateFiles[args.InputFile] = args.IntermediateFiles
c.mapJobStatus[args.InputFile] = completed
c.workerStatus[args.WorkerId] = idle
return nil
}
//
// start a thread that listens for RPCs from worker.go
//
func (c *Coordinator) server() {
rpc.Register(c)
rpc.HandleHTTP()
//l, e := net.Listen("tcp", ":1234")
sockname := coordinatorSock()
os.Remove(sockname)
l, e := net.Listen("unix", sockname)
if e != nil {
log.Fatal("listen error:", e)
}
go http.Serve(l, nil)
}
//
// main/mrcoordinator.go calls Done() periodically to find out
// if the entire job has finished.
//
func (c *Coordinator) Done() bool {
ret := false
// Your code here.
return ret
}
//
// create a Coordinator.
// main/mrcoordinator.go calls this function.
// nReduce is the number of reduce tasks to use.
//
func MakeCoordinator(files []string, nReduce int) *Coordinator {
c := Coordinator{}
// Your code here.
c.mapJobStatus = make(map[string]status)
c.intermediateFiles = make(map[string][]string)
c.workerStatus = make(map[int]status)
c.nReduce = nReduce
for _, v := range files {
c.mapJobStatus[v] = idle
c.intermediateFiles[v] = make([]string, nReduce)
}
c.server()
return &c
}