|
using System;
using System.Threading;
using System.Reflection;
using System.Collections.Generic;
using BrainTechLLC.ThreadSafeObjects;
namespace BrainTechLLC.DAL
{
public class DALWhereCache<T> : IWhereCache<T> where T : DBLayer<T>, IDBLayer<T>, new()
{
/// <summary>
/// If set to true, cached query results associated with specific WHERE logic will not be cached
/// </summary>
public bool _disableWhereCache;
internal Lockable _lock = new Lockable();
/// <summary>
/// Limits the number of entries in the in-memory WHERE logic statement result cache.
/// </summary>
public int _maxQueriesInWhereCache = 1000;
/// <summary>
/// Limits the number of rows/results contained in all of the in-memory WHERE logic statement result caches.
/// For classes that a large number of lengthy columns, this number should be set fairly low. For small/lean
/// tables or in situations where memory usage is less of a concern, this number can remain fairly large.
/// </summary>
public int _maxObjectsInWhereCache = 400000;
/// <summary>
/// Invalidates the WHERE cache, which stores results from frequently-used WHERE clauses
/// </summary>
public void MarkDirty()
{
_cachedQueriesDirty = true;
}
public bool CheckCacheDirty()
{
if (_cachedQueriesDirty)
{
_lock.AquireLock();
try
{
if (_cachedQueriesDirty)
{
_cachedQueries.Clear();
_cachedQueriesDirty = false;
return true;
}
}
finally
{
_lock.ReleaseLock();
}
}
return false;
}
/// <summary>
/// Support for quick "level one" cache. This cache is temporary (any update, insert, or delete
/// from a inheriting class invalidates the entire cache for that class), and only works with exact
/// matching WHERE statements (which occur frequently due to the use of the DBWhere class to
/// generate WHERE clauses). In addition, queries containing any parameters (@Param) will not
/// be cached at this level.
/// </summary>
internal ThreadSafeLookup<string, ResultSet<T>> _cachedQueries = new ThreadSafeLookup<string, ResultSet<T>>();
internal bool _cachedQueriesDirty;
/// <summary>
/// Stores the number of objects currently stored in all of the in-memory WHERE logic statement result caches.
/// </summary>
public int _currentObjectCountInWhereCache = 0;
public bool IsStatementInCache(string sqlStatement)
{
return _cachedQueries.ContainsKey(sqlStatement);
}
/// <summary>
/// Look in "level 1" cache for any results that match this SELECT query exactly
/// Will not work with parameters - parameterized queries should not call this method
/// </summary>
public ResultSet<T> FindInWhereCache(string sqlStatement)
{
if (_disableWhereCache) return null;
_lock.AquireLock();
try
{
if (_cachedQueries.Count > _maxQueriesInWhereCache) { ClearCachedQueries(); }
else
{
if (_cachedQueries.ContainsKey(sqlStatement))
{
ResultSet<T> results;
// check and handle any cache invalidation that has occured
if (_cachedQueriesDirty) { ClearCachedQueries(); }
else { if (_cachedQueries.TryGetValue(sqlStatement, out results)) { results._fromCache = true; return results; } }
}
}
}
finally
{
_lock.ReleaseLock();
}
return null;
}
internal void ClearCachedQueries()
{
//_findAllLookup.InvalidateCache();
//_findFirstLookup.InvalidateCache();
_cachedQueries.Clear();
DBLayer<T>._integerIndices.Clear();
DBLayer<T>._stringIndices.Clear();
_cachedQueriesDirty = false;
}
public void RecordInWhereCache(string sql, ResultSet<T> results)
{
RecordInWhereCache(sql, results, results.RowCount);
}
public void RecordInWhereCache(string sql, ResultSet<T> results, int nResultRows)
{
// Enforce the _maxObjectsInWhereCache cache limit
if (_currentObjectCountInWhereCache >= _maxObjectsInWhereCache)
{
MarkDirty();
}
_lock.AquireLock();
try
{
if (_cachedQueriesDirty) { ClearCachedQueries(); }
if (!_cachedQueries.ContainsKey(sql))
{
if (!_cachedQueries.Add(sql, results))
{
// consider making this non-thread safe to improve performance slightly? our exact count might be off, but we
// would not need to call Interlocked.Add... hmmm
Interlocked.Add(ref _currentObjectCountInWhereCache, nResultRows);
}
}
}
finally
{
_lock.ReleaseLock();
}
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Currently working as a Senior Silverlight Developer with Troppus Software in Superior, CO. I enjoy statistics, programming, new technology, playing the cello, and reading codeproject articles.