core: redo search cache from scratch. resolves #10382 (#10447)

In simple words, when you make a request in Jackett, the results are saved in memory (cache). The next request will return results form the cache improving response time and making fewer requests to the sites.
* We assume all indexers/sites are stateless, the same request return the same response. If you change the search term, categories or something in the query Jackett has to make a live request to the indexer.
* There are some situations when we don't want to use the cache:
** When we are testing the indexers => if query.IsTest results are not cached
** When the user updates the configuration of one indexer => We call CleanIndexerCache to remove cached results before testing the configuration
** When there is some error/exception in the indexer => The results are not cached so we can retry in the next request
* We want to limit the memory usage, so we try to remove elements from cache ASAP:
** Each indexer can have a maximum number of results in memory. If the limit is exceeded we remove old results
** Cached results expire after some time
* Users can configure the cache or even disable it
This commit is contained in:
Diego Heras
2020-12-11 23:14:21 +01:00
committed by GitHub
parent ec3787e803
commit 69125add3e
126 changed files with 744 additions and 364 deletions

View File

@@ -271,7 +271,6 @@ namespace Jackett.Server.Controllers
{
var searchResults = t.Result.Releases;
var indexer = t.Result.Indexer;
cacheService.CacheRssResults(indexer, searchResults);
return searchResults.Select(result =>
{
@@ -279,14 +278,20 @@ namespace Jackett.Server.Controllers
item.Tracker = indexer.DisplayName;
item.TrackerId = indexer.Id;
item.Peers = item.Peers - item.Seeders; // Use peers as leechers
return item;
});
}).OrderByDescending(d => d.PublishDate).ToList();
ConfigureCacheResults(manualResult.Results);
logger.Info(string.Format("Manual search for \"{0}\" on {1} with {2} results.", CurrentQuery.SanitizedSearchTerm, string.Join(", ", manualResult.Indexers.Select(i => i.ID)), manualResult.Results.Count()));
// Log info
var indexersName = string.Join(", ", manualResult.Indexers.Select(i => i.ID));
var cacheStr = tasks.Where(t => t.Status == TaskStatus.RanToCompletion).Any(t => t.Result.IsFromCache) ? " (from cache)" : "";
if (string.IsNullOrWhiteSpace(CurrentQuery.SanitizedSearchTerm))
logger.Info($"Manual search in {indexersName} => Found {manualResult.Results.Count()} releases{cacheStr}");
else
logger.Info($"Manual search in {indexersName} for {CurrentQuery.GetQueryString()} => Found {manualResult.Results.Count()} releases{cacheStr}");
return Json(manualResult);
}
@@ -386,33 +391,12 @@ namespace Jackett.Server.Controllers
{
var result = await CurrentIndexer.ResultsForQuery(CurrentQuery);
// Some trackers do not support multiple category filtering so filter the releases that match manually.
int? newItemCount = null;
// Cache non query results
if (string.IsNullOrEmpty(CurrentQuery.SanitizedSearchTerm))
{
newItemCount = cacheService.GetNewItemCount(CurrentIndexer, result.Releases);
cacheService.CacheRssResults(CurrentIndexer, result.Releases);
}
// Log info
var logBuilder = new StringBuilder();
if (newItemCount != null)
{
logBuilder.AppendFormat("Found {0} ({1} new) releases from {2}", result.Releases.Count(), newItemCount, CurrentIndexer.DisplayName);
}
var cacheStr = result.IsFromCache ? " (from cache)" : "";
if (string.IsNullOrWhiteSpace(CurrentQuery.SanitizedSearchTerm))
logger.Info($"Torznab search in {CurrentIndexer.DisplayName} => Found {result.Releases.Count()} releases{cacheStr}");
else
{
logBuilder.AppendFormat("Found {0} releases from {1}", result.Releases.Count(), CurrentIndexer.DisplayName);
}
if (!string.IsNullOrWhiteSpace(CurrentQuery.SanitizedSearchTerm))
{
logBuilder.AppendFormat(" for: {0}", CurrentQuery.GetQueryString());
}
logger.Info(logBuilder.ToString());
logger.Info($"Torznab search in {CurrentIndexer.DisplayName} for {CurrentQuery.GetQueryString()} => Found {result.Releases.Count()} releases{cacheStr}");
var serverUrl = serverService.GetServerUrl(Request);
var resultPage = new ResultPage(new ChannelInfo
@@ -501,15 +485,12 @@ namespace Jackett.Server.Controllers
{
var result = await CurrentIndexer.ResultsForQuery(CurrentQuery);
// Cache non query results
if (string.IsNullOrEmpty(CurrentQuery.SanitizedSearchTerm))
cacheService.CacheRssResults(CurrentIndexer, result.Releases);
// Log info
var cacheStr = result.IsFromCache ? " (from cache)" : "";
if (string.IsNullOrWhiteSpace(CurrentQuery.SanitizedSearchTerm))
logger.Info($"Found {result.Releases.Count()} torrentpotato releases from {CurrentIndexer.DisplayName}");
logger.Info($"Potato search in {CurrentIndexer.DisplayName} => Found {result.Releases.Count()} releases{cacheStr}");
else
logger.Info($"Found {result.Releases.Count()} torrentpotato releases from {CurrentIndexer.DisplayName} for: {CurrentQuery.GetQueryString()}");
logger.Info($"Potato search in {CurrentIndexer.DisplayName} for {CurrentQuery.GetQueryString()} => Found {result.Releases.Count()} releases{cacheStr}");
var serverUrl = serverService.GetServerUrl(Request);
var potatoReleases = result.Releases.Where(r => r.Link != null || r.MagnetUri != null).Select(r =>