mathi
mathi

Reputation: 1

How to safely swap in memory map while program is running?

I have a go service running that has a map in memory, say map1. The map data (keys and values) relies on a file stored in S3. A goroutine is running to monitor this file and if there are changes, downloads the file, parses it, and creates a new map, say map2. How can I swap the contents of map1 with map2 without causing other threads from reading inconsistent data?

Below I have the rough idea of how I was thinking of solving this problem. The output of the below program is a sequence of "map1-a", followed by sequence of "map2-a". The map was swapped. Is this the best way to do this?

package main

import (
    "fmt"
    "time"
)

func initializeAndMonitor() *map[string]string {
    map1 := make(map[string]string)
    map1["a"] = "map1-a"
    go func() {
        time.Sleep(5 * time.Second)
        map2 := make(map[string]string)
        map2["a"] = "map2-a"
        map1 = map2
    }()
    return &map1
}


func main() {
    map1 := initializeAndMonitor()
    for count := 0; count < 100; count = count + 1 {
        fmt.Println((*map1)["a"])
        time.Sleep(1 * time.Second)
    }
}

Upvotes: 0

Views: 115

Answers (1)

Adrian
Adrian

Reputation: 46472

This is the purpose of mutexes; wrap the reads and writes in a sync.RWMutex:

package main

import (
    "fmt"
    "time"
    "sync"
)

var mu = sync.RWMutex{}

func initializeAndMonitor() *map[string]string {
    map1 := make(map[string]string)
    map1["a"] = "map1-a"
    go func() {
        mu.Lock()
        defer mu.Unlock()
        time.Sleep(5 * time.Second)
        map2 := make(map[string]string)
        map2["a"] = "map2-a"
        map1 = map2
    }()
    return &map1
}


func main() {
    map1 := initializeAndMonitor()
    for count := 0; count < 100; count = count + 1 {
        mu.RLock()
        fmt.Println((*map1)["a"])
        mu.RUnlock()
        time.Sleep(1 * time.Second)
    }
}

Upvotes: 2

Related Questions