77
88using DistillNET . Extensions ;
99using Microsoft . Data . Sqlite ;
10+ using Microsoft . Extensions . Caching . Memory ;
11+ using Microsoft . Extensions . Options ;
1012using System ;
1113using System . Collections . Generic ;
1214using System . Data ;
1315using System . IO ;
1416using System . Linq ;
1517using System . Reflection ;
18+ using System . Threading ;
1619using System . Threading . Tasks ;
1720
1821namespace DistillNET
@@ -42,33 +45,23 @@ public class FilterDbCollection : IDisposable
4245 private readonly string m_globalKey ;
4346
4447 /// <summary>
45- /// Constructs a new FilterDbCollection using an in-memory database .
48+ /// Memory cache .
4649 /// </summary>
47- public FilterDbCollection ( )
48- {
49-
50- var version = typeof ( FilterDbCollection ) . Assembly . GetCustomAttribute < AssemblyFileVersionAttribute > ( ) . Version ;
51- var rnd = new Random ( ) ;
52- var rndNum = rnd . Next ( ) ;
53- var generatedDbName = string . Format ( "{0} {1} - {2}" , nameof ( FilterDbCollection ) , version , rndNum ) ;
54-
55- // "Data Source = :memory:; Cache = shared;"
56- var cb = new SqliteConnectionStringBuilder ( ) ;
57- cb . DataSource = generatedDbName ;
58- cb . Mode = SqliteOpenMode . Memory ;
59- cb . Cache = SqliteCacheMode . Shared ;
60- m_connection = new SqliteConnection ( cb . ToString ( ) ) ;
61-
62- //m_connection. = SQLiteConnectionFlags.UseConnectionPool | SQLiteConnectionFlags.NoConvertSettings | SQLiteConnectionFlags.NoVerifyTypeAffinity;
63- m_connection . Open ( ) ;
64-
65- ConfigureDatabase ( ) ;
66-
67- CreateTables ( ) ;
50+ private MemoryCache m_cache ;
6851
69- m_globalKey = "global" ;
52+ /// <summary>
53+ /// Mem cache options.
54+ /// </summary>
55+ private MemoryCacheOptions m_cacheOptions ;
7056
71- m_ruleParser = new AbpFormatRuleParser ( ) ;
57+ /// <summary>
58+ /// Constructs a new FilterDbCollection using an in-memory database.
59+ /// </summary>
60+ /// <param name="cacheOptions">
61+ /// User defined query caching options.
62+ /// </param>
63+ public FilterDbCollection ( MemoryCacheOptions cacheOptions = null ) : this ( null , true , true , cacheOptions )
64+ {
7265 }
7366
7467 /// <summary>
@@ -84,13 +77,24 @@ public FilterDbCollection()
8477 /// <param name="useMemory">
8578 /// If true, the database will be created as a purely in-memory database.
8679 /// </param>
87- public FilterDbCollection ( string dbAbsolutePath , bool overwrite = true , bool useMemory = false )
80+ /// <param name="cacheOptions">
81+ /// User defined query caching options.
82+ /// </param>
83+ public FilterDbCollection ( string dbAbsolutePath , bool overwrite = true , bool useMemory = false , MemoryCacheOptions cacheOptions = null )
8884 {
8985 if ( ! useMemory && overwrite && File . Exists ( dbAbsolutePath ) )
9086 {
9187 File . Delete ( dbAbsolutePath ) ;
9288 }
9389
90+ if ( cacheOptions == null )
91+ {
92+ cacheOptions = new MemoryCacheOptions ( ) ;
93+ cacheOptions . ExpirationScanFrequency = TimeSpan . FromMinutes ( 10 ) ;
94+ }
95+
96+ m_cacheOptions = cacheOptions ;
97+
9498 bool isNew = ! File . Exists ( dbAbsolutePath ) ;
9599
96100 m_ruleParser = new AbpFormatRuleParser ( ) ;
@@ -213,6 +217,16 @@ public void FinalizeForRead()
213217 CreatedIndexes ( ) ;
214218 }
215219
220+ private void RecreateCache ( )
221+ {
222+ if ( m_cache != null )
223+ {
224+ m_cache . Dispose ( ) ;
225+ }
226+
227+ m_cache = new MemoryCache ( m_cacheOptions ) ;
228+ }
229+
216230 /// <summary>
217231 /// Parses the supplied list of rules and stores them in the assigned database for retrieval,
218232 /// indexed by the rule's domain names.
@@ -230,6 +244,8 @@ public void FinalizeForRead()
230244 /// </returns>
231245 public async Task < Tuple < int , int > > ParseStoreRules ( string [ ] rawRuleStrings , short categoryId )
232246 {
247+ RecreateCache ( ) ;
248+
233249 int loaded = 0 , failed = 0 ;
234250
235251 using ( var transaction = m_connection . BeginTransaction ( ) )
@@ -305,6 +321,8 @@ public async Task<Tuple<int, int>> ParseStoreRules(string[] rawRuleStrings, shor
305321 /// </returns>
306322 public async Task < Tuple < int , int > > ParseStoreRulesFromStream ( Stream rawRulesStream , short categoryId )
307323 {
324+ RecreateCache ( ) ;
325+
308326 int loaded = 0 , failed = 0 ;
309327
310328 using ( var transaction = m_connection . BeginTransaction ( ) )
@@ -408,7 +426,16 @@ public async Task<List<UrlFilter>> GetWhitelistFiltersForDomain(string domain =
408426 /// </returns>
409427 private async Task < List < UrlFilter > > GetFiltersForDomain ( string domain , bool isWhitelist )
410428 {
411- var retVal = new List < UrlFilter > ( ) ;
429+ var cacheKey = new Tuple < string , bool > ( domain , isWhitelist ) ;
430+
431+ List < UrlFilter > retVal ;
432+
433+ if ( m_cache . TryGetValue ( cacheKey , out retVal ) )
434+ {
435+ return retVal ;
436+ }
437+
438+ retVal = new List < UrlFilter > ( ) ;
412439
413440 var allPossibleVariations = GetAllPossibleSubdomains ( domain ) ;
414441
@@ -454,6 +481,8 @@ private async Task<List<UrlFilter>> GetFiltersForDomain(string domain, bool isWh
454481 }
455482 }
456483
484+ m_cache . Set ( cacheKey , retVal ) ;
485+
457486 return retVal ;
458487 }
459488
0 commit comments