Golang Fatal Error: Concurrent Map Read and Map Write

I'm writing minecraft server in Go, when server is being stressed by 2000+ connections I get this crash:

fatal error: concurrent map read and map write/root/work/src/ +0x351 created by main.main /root/work/src/ +0x368

My code:

package main

import (
    "log"
    "net"
    "bufio"
    "time"
    "math/rand"
    "fmt"
)

var (
    connCounter = 0
)

func main() {
    InitConfig()
    InitPackets()

    port := int(config["port"].(float64))
    ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
    if err != nil {
        log.Fatal(err)
    }
    log.Println("Server launched on port", port)
    go KeepAlive()
    for {
        conn, err := ln.Accept()
        if err != nil {
            log.Print(err)
        } else {
            connCounter+=1
            go HandleConnection(conn, connCounter)
        }
    }
}

func KeepAlive() {
    r := rand.New(rand.NewSource(15768735131534))
    keepalive := &PacketPlayKeepAlive{
        id: 0,
    }
    for {
        for _, player := range players {
            if player.state == PLAY {
                id := int(r.Uint32())
                keepalive.id = id
                player.keepalive = id
                player.WritePacket(keepalive)
            }
        }
        time.Sleep(20000000000)
    }
}

func HandleConnection(conn net.Conn, id int) {
    log.Printf("%s connected.", conn.RemoteAddr().String())

    player := &Player {
        id: id,
        conn: conn,
        state: HANDSHAKING,
        protocol: V1_10,
        io: &ConnReadWrite{
            rdr: bufio.NewReader(conn),
            wtr: bufio.NewWriter(conn),
        },
        inaddr: InAddr{
            "",
            0,
        },
        name: "",
        uuid: "d979912c-bb24-4f23-a6ac-c32985a1e5d3",
        keepalive: 0,
    }

    for {
        packet, err := player.ReadPacket()
        if err != nil {
            break
        }

        CallEvent("packetReceived", packet)
    }

    player.unregister()
    conn.Close()
    log.Printf("%s disconnected.", conn.RemoteAddr().String())
}

For now server is only "limbo".

1 Answer

Generally speaking (without having access to the code where the error occurs) you have a few options. Here are two of them:

sync.RWMutex

Control access to the map with sync.RWMutex{}. Use this option if you have single reads and writes, not loops over the map. See RWMutex

Here a sample with access control to someMap via someMapMutex:

var (
    someMap      = map[string]string{}
    someMapMutex = sync.RWMutex{}
)

go func() {
    someMapMutex.Lock()
    someMap["key"] = "value"
    someMapMutex.Unlock()
}()

someMapMutex.RLock()
v, ok := someMap["key"]
someMapMutex.RUnlock()
if !ok {
    fmt.Println("key missing")
    return
}
fmt.Println(v)

syncmap.Map

Use a syncmap.Map{} instead of a normal map. This map is already taking care of race issues but may be slower depending on your usage. syncmap.Map{}s main advantage lies with for loops. See syncmap

var (
    someMap = syncmap.Map{}
)

go func() {
    someMap.Store("key", "value")
}()

v, ok := someMap.Load("key")
if !ok {
    fmt.Println("key missing")
    return
}
fmt.Println(v)

// with syncmap, looping over all keys is simple without locking the whole map for the entire loop
someMap.Range(func(key, value interface{}) bool {
    // cast value to correct format
    val, ok := value.(string)
    if !ok {
        // this will break iteration
        return false
    }
    // do something with key/value
    fmt.Println(key, val)

    // this will continue iterating
    return true
})

General Advice

You should test your server with -race option and then eliminate all the race conditions it throws. That way you can easier eliminate such errors before they occur.

go run -race server.go

See golang race detector

20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

David Miller

David Miller

Executive Financial & Market Analyst

David Miller brings 15 years of experience in global economics, personal finance strategy, and market dynamics. He specializes in turning complex economic trends into actionable insights for everyday readers.

Share this article
Twitter Facebook Pinterest