I am pretty new in Golang and encountered the following problem.
// XXX a bit inefficient. could open r files and run over list once
for r := 0; r < nreduce; r++ {
file, err = os.Create(ReduceName(fileName, JobNumber, r))
if err != nil {
log.Fatal("DoMap: create ", err)
}
enc := json.NewEncoder(file)
for e := res.Front(); e != nil; e = e.Next() {
kv := e.Value.(KeyValue)
if ihash(kv.Key)%uint32(nreduce) == uint32(r) {
err := enc.Encode(&kv)
if err != nil {
log.Fatal("DoMap: marshall ", err)
}
}
}
file.Close()
}
Basically this code snippet creates a file in each for-loop iteration and then open a file to encode the stuff which belongs to this file, according to a (key, value) pair. However, this code is inefficient since it scan this file for too many times. The more efficient way to do so is to open r files and run over this list file once. So I would like to write like this (but I don't know how to do so):
enc_map := make(map[int]*Encode)
for r := 0; r < nreduce; r++ {
file. err = os.Create(ReduceName(fileName, JobNumber, r))
if err != nil {
log.Fatal("DoMap: create ", err)
}
enc := json.NewEncoder(file)
enc_map[r] = enc
for e := res.Front(); e != nil; e = e.Next() {
kv := e.Value.(KeyValue)
r := ihash(kv.Key)&uint32(nreduce)
err := enc_map[r].Encode(&kv)
if err != nil {
log.Fatal("DoMap: marshall ", err)
}
}
This code snippets first creates a map that saves the json.Encoder objects and then iterate over this file once. I looked up the go documentation and it says the type name of json.Encoder is *Encode. But the line
enc_map := make(map[int]*Encode)
is wrong and the compiler gives me the following error:
../mapreduce/mapreduce.go:228: undefined: Encode
../mapreduce/mapreduce.go:230: file.err undefined (type *os.File has no field or method err)
../mapreduce/mapreduce.go:230: multiple-value os.Create() in single-value context
So what's the right way to do things?