В нашем приложении мы используем сервис fabri c индексированные словари для хранения данных. Мы также используем пакет Service Fabri c Queryable для добавления возможностей запросов в наши коллекции.
В нашем случае у нас есть транзакция, в которой мы делаем несколько обновлений и фиксируем все их сразу. Мы также создали индексы для некоторых свойств для более быстрого поиска данных. Благодаря этому индексированию запись создается внутри словарного индекса с индексированным свойством в качестве ключа и объектом в качестве значения. Это также операция AddOrUpdate, которая включена в ту же транзакцию. И транзакция, которая используется для выполнения этой операции обновления, получает эксклюзивную блокировку для всех вновь создаваемых записей.
Используя ту же транзакцию, когда мы пытаемся выполнить запрос к индексируемому индексируемому словарю, используя свойство, которое имеет после индексации мы получаем исключение тайм-аута.
Мы просмотрели исходный код в пакете расширений 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 Fabri c 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();
}
}
Есть ли какой-нибудь способ, которым мы можем запросить словарь с возможностью запроса без фиксации предыдущей транзакции?