修改Service Fabric Reliable Collections中的原始对象

时间:2016-12-27 16:32:04

标签: c# .net azure azure-service-fabric

我阅读了有关使用Reliable Collections的this文章,并且在那里提到一旦将对象提供给可靠的集合,就不能修改对象以及更新对象的正确方法可靠集合中的值是获取值的副本(克隆),检索克隆值,然后更新RC中的克隆值。

使用不当:

using (ITransaction tx = StateManager.CreateTransaction()) {
   // Use the user’s name to look up their data
   ConditionalValue<User> user = 
      await m_dic.TryGetValueAsync(tx, name);

   // The user exists in the dictionary, update one of their properties.
   if (user.HasValue) {
      // The line below updates the property’s value in memory only; the
      // new value is NOT serialized, logged, & sent to secondary replicas.
      user.Value.LastLogin = DateTime.UtcNow; // Corruption!
      await tx.CommitAsync(); 
   }
}

我的问题是:一旦我把它交给RC,为什么我不能修改它?为什么在更改内容之前我必须克隆该对象?为什么我不能做类似的事情(在同一个事务中更新对象):

using (ITransaction tx = StateManager.CreateTransaction()) {
   // Use the user’s name to look up their data
   ConditionalValue<User> user = 
      await m_dic.TryGetValueAsync(tx, name);

   // The user exists in the dictionary, update one of their properties.
   if (user.HasValue) {
      // The line below updates the property’s value in memory only; the
      // new value is NOT serialized, logged, & sent to secondary replicas.
      user.Value.LastLogin = DateTime.UtcNow;

      // Update
      await m_dic.SetValue(tx, name, user.Value);

      await tx.CommitAsync(); 
   }
}

谢谢!

2 个答案:

答案 0 :(得分:3)

Reliable Dictionary是一个复制的对象库。如果您更新Reliable Dictionary中的对象而不通过Reliable Dictionary(例如TryUpdateAsync),那么您可以破坏状态。

例如,如果使用引用更改Reliable Dictionary中的对象,则更改将不会复制到辅助副本。 这是因为Reliable Dictionary不知道你改变了其中一个TValues。因此,如果副本发生故障,则更改将丢失。

以上是最简单的例子。直接修改对象可能会导致其他严重问题,例如以多种方式破坏ACID。

答案 1 :(得分:2)

从技术上讲,你可以做你想做的事。但是不要忘记锁定模式和隔离级别 Here we can read:“默认情况下,任何可重复读取操作都需要共享锁。但是,对于任何支持可重复读取的读取操作,用户可以请求更新锁定而不是共享锁定。“

这意味着TryGetValueAsync只获得共享锁。并且稍后尝试更新此值可能会导致dedlock 下一个语句是:“更新锁定是一种非对称锁定,用于防止多个事务在以后锁定资源以进行潜在更新时发生的常见形式的死锁。”

所以,正确的代码是

await m_dic.TryGetValueAsync(tx, name, LockMode.Update)