I’ve been trying to write a key value server that periodically pings a view service which maintains a primary and backup k/v server. I keep getting fatal error: concurrent map writes
and I believe it’s because of the way I’m using maps and mutexes:
func (pb *PBServer) Transfer(args *TransferArgs, reply *TransferReply) error {
pb.mu.Lock()
defer pb.mu.Unlock()
if pb.curview.Backup != pb.me {
reply.Err = ErrWrongServer
return nil
}
for k, v := range args.Database {
pb.data[k] = {v.name}
}
reply.Err = OK
return nil
}
// ping viewserver periodically.
func (pb *PBServer) tick() {
pb.mu.Lock()
defer pb.mu.Unlock()
for {
t, err := pb.vs.Ping(pb.curview.Viewnum)
if err != nil {
continue
}
pb.curview = t
if pb.me == pb.curview.Primary && pb.curview.Backup != "" {
args := &TransferArgs{pb.data}
var reply TransferReply
ok := call(pb.curview.Backup, "PBServer.Transfer", args, &reply)
if ok == false || reply.Err != OK {
continue
} else {
break
}
} else {
break
}
}
}
I use this call
function to perform my rpc call
func call(srv string, rpcname string,
args interface{}, reply interface{}) bool {
c, errx := rpc.Dial("unix", srv)
if errx != nil {
return false
}
defer c.Close()
err := c.Call(rpcname, args, reply)
if err == nil {
return true
}
fmt.Println(err)
return false
}
I’m suspecting that maybe the way in which I am trying to pass my pb.data
map to Transfer
is causing the concurrent map writes
but I’m not sure. Do I need to do a deep copy and pass the deep copy into args
like &TransferArgs{deepcopy}
? Should I be using pointers?