【问题标题】:Modify the original object in Service Fabric Reliable Collections修改 Service Fabric 可靠集合中的原始对象
【发布时间】:2017-05-11 22:51:03
【问题描述】:

我阅读了 this 关于使用 Reliable Collections 的文章,其中提到 一旦将对象提供给可靠的集合,就不得修改它,以及更新中值的正确方法一个可靠的集合,就是获取一个值的副本(克隆),检查克隆的值,然后更新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(); 
   }
}

谢谢!

【问题讨论】:

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


    【解决方案1】:

    Reliable Dictionary 是一个复制的对象存储。如果您在不通过 Reliable Dictionary 的情况下更新 Reliable Dictionary 中的对象(例如 TryUpdateAsync),那么您可能会破坏状态。

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

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

    【讨论】:

      【解决方案2】:

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

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

      所以,正确的代码应该是

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

      【讨论】:

        猜你喜欢
        • 2017-12-08
        • 2017-12-01
        • 2017-12-07
        • 1970-01-01
        • 2016-08-09
        • 1970-01-01
        • 2016-03-14
        • 2022-06-18
        • 2017-01-28
        相关资源
        最近更新 更多