How to pass map via rpc call while using mutexes?

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?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.