You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Zero/ZeroLevel/Services/Collections/KeyListValueTransactCollect...

220 lines
6.5 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace ZeroLevel.Services.Collections
{
/// <summary>
/// Класс обертывает коллекцию вида ключ-значение и позволяет проводить над ней транзакционные обновления
/// </summary>
/// <typeparam name="TKey">Тип ключа коллекции</typeparam>
/// <typeparam name="TValue">Тип значения коллекции</typeparam>
public class KeyListValueTransactCollection<TKey, TValue> :
ITransactable
{
/// <summary>
/// Коллекция
/// </summary>
readonly Dictionary<TKey, List<TValue>> _collection = new Dictionary<TKey, List<TValue>>();
private ReaderWriterLockSlim _rwLock =
new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
/// <summary>
/// Проверка наличия ключа
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool HasKey(TKey key)
{
try
{
_rwLock.EnterReadLock();
return _collection.ContainsKey(key);
}
finally
{
_rwLock.ExitReadLock();
}
}
/// <summary>
/// Получение значения коллекции по ключу
/// </summary>
/// <param name="key">Ключ</param>
/// <returns>Значение</returns>
public IEnumerable<TValue> this[TKey key]
{
get
{
try
{
_rwLock.EnterReadLock();
List<TValue> value;
if (_collection.TryGetValue(key, out value))
return value;
}
finally
{
_rwLock.ExitReadLock();
}
throw new KeyNotFoundException();
}
}
/// <summary>
/// Коллекция ключей
/// </summary>
public IEnumerable<TKey> Keys
{
get
{
try
{
_rwLock.EnterReadLock();
return _collection.Keys;
}
finally
{
_rwLock.ExitReadLock();
}
}
}
/// <summary>
/// Коллекция значений
/// </summary>
public IEnumerable<List<TValue>> Values
{
get
{
try
{
_rwLock.EnterReadLock();
return _collection.Values.ToArray();
}
finally
{
_rwLock.ExitReadLock();
}
}
}
#region Transaction update
/// <summary>
/// Список не обновленных данных (т.е. тех которые удалены в базе)
/// </summary>
readonly List<TKey> _removingDate = new List<TKey>();
/// <summary>
/// Обновленные данные
/// </summary>
readonly Dictionary<TKey, List<TValue>> _updatedRecords = new Dictionary<TKey, List<TValue>>();
/// <summary>
/// Новые данные
/// </summary>
readonly Dictionary<TKey, List<TValue>> _newRecords = new Dictionary<TKey, List<TValue>>();
void ClearTransactionDate()
{
_removingDate.Clear();
_updatedRecords.Clear();
_newRecords.Clear();
}
/// <summary>
/// Добавление или обновления записи
/// </summary>
/// <param name="id">Идентификатор записи</param>
/// <param name="value">Значение</param>
public void Post(TKey id, TValue value)
{
if (_isUpdating.State == false)
{
throw new Exception("Method Post allowed only in transaction");
}
if (!HasKey(id))
{
if (_newRecords.ContainsKey(id) == false)
{
_newRecords.Add(id, new List<TValue>());
}
_newRecords[id].Add(value);
}
else
{
if (!_updatedRecords.ContainsKey(id))
{
_updatedRecords.Add(id, new List<TValue>());
}
_updatedRecords[id].Add(value);
if (_removingDate.Contains(id))
_removingDate.Remove(id);
}
return;
}
readonly AtomicBoolean _isUpdating = new AtomicBoolean();
public bool Commit()
{
if (_isUpdating.State == false) return false;
try
{
_rwLock.EnterWriteLock();
foreach (TKey id in _removingDate)
{
_collection.Remove(id);
}
foreach (TKey key in _newRecords.Keys)
{
_collection.Add(key, _newRecords[key]);
}
foreach (TKey key in _updatedRecords.Keys)
{
_collection[key] = _updatedRecords[key];
}
}
finally
{
_rwLock.ExitWriteLock();
ClearTransactionDate();
_isUpdating.Reset();
}
return true;
}
public bool Rollback()
{
if (_isUpdating.State == false) return false;
ClearTransactionDate();
_isUpdating.Reset();
return true;
}
public bool StartTransction()
{
if (_isUpdating.Set())
{
_removingDate.AddRange(_collection.Keys.ToArray());
return true;
}
return false;
}
#endregion
#region IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
7 months ago
if (_collection != null!)
{
_collection.Clear();
}
}
}
#endregion
}
}

Powered by TurnKey Linux.