user3388293
user3388293

Reputation: 25

Increment field value in different records avoiding race condition in Golang

My Golang code gets different records from the database using goroutines, and increments the value in a determinated field in the record.

I can avoid the race condition If I use Mutex or Channels, but I have a bottleneck because every access to the database waits until the previous access is done.

I think I should do something like one Mutex for every different record, instead one only Mutex for all.

How could I do it?

Thanks for any reply.

Upvotes: 0

Views: 833

Answers (2)

James Henstridge
James Henstridge

Reputation: 43909

In the comments you said you are using Couchbase. If the record you wish to update consists of only an integer, you can use the built in atomic increment functionality with Bucket.Incr.

If the value is part of a larger document, you can use the database's "Check and Set" functionality. In essence, you want to create a loop that does the following:

  1. Retrieve the record to be updated along with its CAS value using Bucket.Gets
  2. Modify the document returned by (1) as needed.
  3. Store the modified document using Bucket.Cas, passing the CAS value retrieved in (1).
  4. If (4) succeeds, break out of the loop. Otherwise, start again at (1).

Note that it is important to retrieve the document fresh each time in the loop. If the update fails due to an incorrect CAS value, it means the document was updated between the read and the write.

Upvotes: 1

Dean Elbaz
Dean Elbaz

Reputation: 2450

If the database has a way of handling that (i.e. an atomic counter built in) you should use that. If not, or if you want to do this in go, you can use buffered channels. Inserting to a buffered channel is not blocking unless the buffer is full.

then, to handle the increments one at a time, in a goroutine you could have something like

for{
    select{
        value, _ := <-CounterChan
        incrementCounterBy(value)
    }
}

Upvotes: 0

Related Questions