value for a key in a map is being changed automatically in golang

587 views Asked by At

So I have this var resolve of type map[string][]byte that is being initialised by calling a method. If I just iterate resolve the value is being printed correctly.

for k, v := range resolve {
        fmt.Printf("%s\t%s\n", k, v)
}

But in the very next line I am trying to iteration over the map to store the values in a db (bolt), in that value for a key (key1) in the map is being changed automatically and I am not able to figure out why. To further simplify that what I did is stored the value for that key in a new var

a:= resolve["key1"]

and then while storing the values in the db I checked if the key is key1 store a. In that case also the value of a is being changed which should not.

This gist has code we would be able to see that resolve that we have in line 30 has been change in line 34.

I have added the code in the go playground here is the link https://play.golang.org/p/2WacK-xxRp_m

2

There are 2 answers

6
Paul Hankin On BEST ANSWER

On your line in readAll:

lGraceP[string(k)] = v

you're storing the value for later use. The documentation specifies that the value v is not valid after the transaction ends.

From Cursor.First (and there's similar text in Cursor.Next) in the bolt library (see the highlighted text):

First moves the cursor to the first item in the bucket and returns its key and value. If the bucket is empty then a nil key and value are returned. The returned key and value are only valid for the life of the transaction.

The way that the key and value are only valid for the life of the transaction is that the array underlying their slices are re-used. That causes your values to mutate unexpectedly.

0
Sergio Tulentsev On

The problem must be somewhere in BoltDB and how it handles writing bigger values for the same key. If we don't increase the size

dbData["1"] = []byte("vivek-9"))

then it works (as in, the other values are not affected). Tried a quick glimpse into boltdb/bolt, but nothing jumps out so far.

If I were to guess, the byte slices you get from ReadAll are "windows" into the one big backing byte array. When you insert a bigger value, it causes subsequent bytes to shift. But the windows don't move and so they're now observing different data. Clone your values in ReadAll, this will help.