|
I'm working on a "set once" config module for mongodb, here's my go code:
package dao
|
|
import "github.com/globalsign/mgo/bson"
|
|
func InsertOnce(selector interface{}, update interface{}) (ret bson.M, err error) {
|
s, c := Mg("config")
|
defer s.Close()
|
|
_, err = c.Upsert(selector, &bson.M{
|
"$setOnInsert": update,
|
})
|
if err != nil {
|
return
|
}
|
ret = make(bson.M)
|
err = c.Find(selector).One(&ret)
|
return
|
}
|
When I test it:
package dao
|
|
import (
|
"sync"
|
"sync/atomic"
|
"testing"
|
|
"github.com/globalsign/mgo/bson"
|
)
|
|
func TestInsertOnce(t *testing.T) {
|
s, c := Mg("config")
|
defer s.Close()
|
defer c.DropCollection()
|
for n := 0; n < 10; n++ {
|
prev := int32(-1)
|
var changed int32
|
var wg sync.WaitGroup
|
for i := 0; i < 10; i++ {
|
wg.Add(1)
|
go func(i int) {
|
defer wg.Done()
|
result, err := InsertOnce(&bson.M{"entry": "secret"}, &bson.M{"value": i})
|
if err != nil {
|
t.Fatal("InsertOnce", err)
|
}
|
value := result["value"].(int)
|
t.Log(value, prev)
|
if atomic.SwapInt32(&prev, int32(value)) != int32(value) {
|
atomic.AddInt32(&changed, 1)
|
}
|
}(i)
|
}
|
wg.Wait()
|
if changed != 1 {
|
t.Fatal("value maybe changed by later func calls", changed)
|
}
|
c.DropCollection()
|
}
|
}
|
It sometime fails with more than once changed, is it related to my implementation or test code, or MongoDB will not guarantee the atomicity of $setOnInsert across single collection?
|