我正在尝试使用数据存储作为分布式锁。根据 docs,我预计以下内容会因
datastore: concurrent transaction
失败,但它只会失败 <5% of the time. The database used is in Optimistic concurrency mode.
如何让它锁定该实体并使任何并发读/写操作失败?
此代码取自官方文档,在事务读写之间添加了
Put
。
ctx := context.Background()
client, err := datastore.NewClientWithDatabase(ctx, "project-id", "database-id")
if err != nil {
panic(err)
}
type Counter struct {
Count int
}
var count int
key := datastore.NameKey("Counter", "singleton", nil)
if _, err = client.RunInTransaction(ctx, func(tx *datastore.Transaction) error {
var x Counter
if err := tx.Get(key, &x); err != nil && err != datastore.ErrNoSuchEntity {
return err
}
y := x
y.Count = 10
if _, err = client.Put(ctx, key, &y); err != nil {
return err
}
x.Count++
if _, err = tx.Put(key, &x); err != nil {
return err
}
count = x.Count
return nil
}); err != nil {
panic(err)
}
if err = client.Delete(ctx, key); err != nil {
panic(err)
}
fmt.Println("COUNT:", count)
为了确保我们在同一页面上,您的数据库是处于
OPTIMISTIC
模式还是 OPTIMISTIC_WITH_ENTITY_GROUPS
?
https://cloud.google.com/datastore/docs/concepts/transactions#view_concurrency_mode
假设它使用
OPTIMISTIC
并发性,启动事务并通过 tx.Get(key, &x)
执行读取不会阻止另一个写入者修改同一文档。然而,假设 client.Put(ctx, key, &y)
是一个在 RunInTransaction 主体完成执行之前完成的阻塞操作,则整个 RunInTransaction 操作应该始终失败。
在
PESSIMISTIC
模式下,is 可以使用在一个事务中获得的写锁来延迟其他事务写入者完成,直到锁被释放:https://cloud.google.com/datastore/docs/concepts/交易#concurrency_modes