///
/// Copyright © 2003-2008 JetBrains s.r.o.
/// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder).
///
using System;
using System.Collections.Generic;
using System.Threading;
using JetBrains.Omea.AsyncProcessing;
using JetBrains.Omea.Containers;
using JetBrains.Omea.FiltersManagement;
using JetBrains.Omea.OpenAPI;
namespace JetBrains.Omea.TextIndex
{
public class TextQueriesOptimizationManager
{
private readonly AsyncProcessor _textProcessor;
private readonly FullTextIndexer _textIndexer;
private readonly Dictionary _queryResults;
private readonly List _activeQueries;
private IResourceList _allTextConditions;
private int _dummyCounter;
#region Ctor and Intialization
public TextQueriesOptimizationManager( AsyncProcessor processor, FullTextIndexer indexer )
{
_textProcessor = processor;
_textIndexer = indexer;
_queryResults = new Dictionary();
_activeQueries = new List();
InitializeConditionsList();
InitializeListeners();
}
private void InitializeConditionsList()
{
_allTextConditions = CollectAllTextConditions();
ReloadQueryResults();
_allTextConditions.ResourceAdded += QuerySetChanged;
_allTextConditions.ResourceDeleting += QuerySetChanged;
_allTextConditions.ResourceChanged += QueryResourceChanged;
}
private void InitializeListeners()
{
_textIndexer.ResourceProcessed += CheckNewResourceOverQueries;
}
#endregion Ctor and Intialization
#region Querying and matching resources
internal delegate FullTextIndexer.QueryResult QueryRequest( string str, int dummy );
internal delegate bool MatchRequest( string str, int id, int dummy );
public FullTextIndexer.QueryResult QueryList( string query )
{
FullTextIndexer.QueryResult qr;
ThreadPriority priority = _textProcessor.ThreadPriority;
_textProcessor.ThreadPriority = ThreadPriority.Normal;
try
{
qr = (FullTextIndexer.QueryResult) _textProcessor.RunJob( "Searching for " + query,
new QueryRequest( _textIndexer.ProcessQuery ), query, Interlocked.Increment( ref _dummyCounter ) );
}
finally
{
_textProcessor.ThreadPriority = priority;
}
return qr;
}
public bool MatchResource( IResource res, string query )
{
#region Preconditions - Check that query has been processed earlier
if( !_activeQueries.Contains( query ) )
throw new ApplicationException( "TextQueriesOptimizationManager -- Outside query [" + query + "] does not have a counterpart internally");
#endregion Preconditions
IntArrayList list;
lock( _queryResults )
{
if( _queryResults.TryGetValue( query, out list ) )
{
return (list.IndexOf( res.Id ) != -1);
}
}
return false;
}
#endregion Querying and matching resources
#region Checking resource on readiness
private void CheckNewResourceOverQueries( object sender, EventArgs e )
{
#region Preconditions - Check that method is called in TextIndex thread
if( !_textProcessor.IsOwnerThread )
throw new ApplicationException( "TextQueryOptimizationManager -- [CheckNewResourceOverQueries] can be executed only in the TextIndex thread.");
#endregion Preconditions
int resId = (int)sender;
foreach( string query in _activeQueries )
{
bool matched = _textIndexer.MatchQuery( query, resId, Interlocked.Increment( ref _dummyCounter ) );
if( matched )
{
AddMatchedResourceToCache( resId, query );
}
}
}
private void AddMatchedResourceToCache( int Id, string query )
{
IntArrayList list;
if( !_queryResults.TryGetValue( query, out list ) )
{
list = new IntArrayList();
_queryResults.Add( query, list );
}
list.Add( Id );
}
#endregion Impl
#region Collecting and Monitoring Query Condition Resources
private static IResourceList CollectAllTextConditions()
{
// NOTE: Do not change to int value since FilterRegistry might not been initialized to that time.
string condProp = "ConditionOp" /*FilterRegistry.OpProp*/;
// Get ALL conditions with text queries and remove those which are
// "hanged" due to the bug of Search Views cleanup.
IResourceList allQuery = Core.ResourceStore.FindResourcesLive( FilterManagerProps.ConditionResName, condProp, (int)ConditionOp.QueryMatch );
IResourceList allActive = Core.ResourceStore.FindResourcesWithPropLive( FilterManagerProps.ConditionResName, "LinkedCondition" );
IResourceList result = allQuery.Intersect( allActive );
return result;
}
private void QueryResourceChanged(object sender, ResourcePropIndexEventArgs e)
{
ReloadQueryResults();
}
private void QuerySetChanged(object sender, ResourceIndexEventArgs e)
{
ReloadQueryResults();
}
///
/// Do not pay attention to the queries which could have been deleted - their
/// memory consumtion is too small to be accounted for.
///
private void ReloadQueryResults()
{
foreach( IResource res in _allTextConditions )
{
string query = FilterRegistry.ConstructQuery( res );
if( !_activeQueries.Contains( query ) )
{
_activeQueries.Add( query );
}
}
}
#endregion Collecting and Monitoring Query Condition Resources
}
}