Transactions 访问由服务结构可靠索引字典中的另一事务锁定的记录

Transactions 访问由服务结构可靠索引字典中的另一事务锁定的记录,transactions,azure-service-fabric,iqueryable,indexed,reliable-dictionary,Transactions,Azure Service Fabric,Iqueryable,Indexed,Reliable Dictionary,在我们的应用程序中,我们使用服务结构索引字典来存储数据。我们还使用包在集合上添加查询功能 在我们的例子中,我们有一个事务,在该事务中,我们执行多个更新并同时提交所有更新。 我们还为一些属性创建了索引,以便更快地检索数据。由于这种索引,记录是在索引字典中内部创建的,索引属性是键,对象是值。这也是一个AddOrUpdate操作,包含在同一事务中。用于执行这些更新操作的事务将获得对所有新创建记录的独占锁 使用相同的事务,当我们尝试使用已被索引的属性对可查询索引字典执行查询时,我们得到一个超时异常 我们

在我们的应用程序中,我们使用服务结构索引字典来存储数据。我们还使用包在集合上添加查询功能

在我们的例子中,我们有一个事务,在该事务中,我们执行多个更新并同时提交所有更新。 我们还为一些属性创建了索引,以便更快地检索数据。由于这种索引,记录是在索引字典中内部创建的,索引属性是键,对象是值。这也是一个AddOrUpdate操作,包含在同一事务中。用于执行这些更新操作的事务将获得对所有新创建记录的独占锁

使用相同的事务,当我们尝试使用已被索引的属性对可查询索引字典执行查询时,我们得到一个超时异常

我们查看了Queryable extensions包中的源代码,发现在Queryable字典上运行的查询创建了一个新事务来获取过滤后的记录。但此事务无法访问记录,因为我们代码中的上一个事务已获得记录的独占锁

下面是一些描述我们的场景的示例代码

public async Task MyMethod() 
{
    using (var tx = this.StateManager.CreateTransaction())
    {
         foreach(var record in records)
         {
              // Here we perform an update operation 
              // The transaction takes an exclusive lock on the created record to perform this operation and releases only after it is committed
              var result = await indexedDictionary.AddOrUpdateAsync(tx, myKey, myValue, (key, value) => myValue);

              // Creating a Queryable dictionary
              var queryableDictionary = new QueryableReliableIndexedDictionary(indexedDictionary, this.StateManager);

              // Running a query on the queryableDictionary 
              var filteredRecords = queryableDictionary.Where(x => x.indexedProperty== propertyValue).ToList();

              // The code to filter the data exists in the Service Fabric Queryable package where a new transaction is being created.
              // Once we query with where condition on the queryable dictionary, the Execute method gets called in the package where the actual filtering takes place.
              // That code looks similar to the code snippet given below.
         }

         await tx.CommitAsync();

    }        
}
下面是Service Fabric Queryable包中的代码片段

internal static async Task<object> Execute<TKey, TValue>(Expression expression)
{


    // This transaction is being created which tries to access the records actual dictionary
    using (var tx = stateManager.CreateTransaction())
    {
         // This statement tries to access the dictionary.. but it can't as the previous transaction has acquired an exclusive lock on the record it is trying to access
         // It waits for 4 seconds and throws a Timeout Exception
         IEnumerable<KeyValuePair<TKey, TValue>> pairs = await indexedDictionary.GetAllAsync(tx, keys, TimeSpan.FromSeconds(4), new CancellationToken()).AsEnumerable();
         values = new KeyValueToValueEnumerable<TKey, TValue>(pairs);
         await tx.CommitAsync();
    }
}
内部静态异步任务执行(表达式)
{
//正在创建此事务,它试图访问实际字典中的记录
使用(var tx=stateManager.CreateTransaction())
{
//此语句尝试访问字典..但无法访问,因为上一个事务已在其尝试访问的记录上获得独占锁
//它等待4秒并抛出超时异常
IEnumerable pairs=await indexedDictionary.GetAllAsync(tx,keys,TimeSpan.FromSeconds(4),new CancellationToken()).AsEnumerable();
values=新的KeyValueToValueEnumerable(成对);
wait tx.CommitAsync();
}
}

我们是否有办法查询可查询字典,而不必提交上一个事务?

您可以创建一个方法,在其中添加一个重载,将当前事务作为参数,并使用它而不是在方法中创建一个。

谢谢您的建议。。但是包的所有者并不推荐这种方法,因为底层方法是LINQ实现,将事务传递给这些方法可能很棘手。