(search) Reduce the number of db queries a bit by caching data that doesn't change too often

This commit is contained in:
Viktor Lofgren 2025-01-10 13:46:19 +01:00
parent 6614d05bdf
commit b245cc9f38
2 changed files with 66 additions and 33 deletions

View File

@ -26,6 +26,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
@ -69,6 +71,8 @@ public class SearchSiteInfoService {
this.searchSiteSubscriptions = searchSiteSubscriptions;
}
private volatile SiteOverviewModel model = new SiteOverviewModel(List.of(), Instant.EPOCH);
@GET
@Path("/site")
public ModelAndView<?> handleOverview(@QueryParam String domain) {
@ -77,6 +81,27 @@ public class SearchSiteInfoService {
return new MapModelAndView("redirect.jte", Map.of("url", "/site/"+domain));
}
if (model.age().compareTo(Duration.ofMinutes(15)) > 0) {
updateModel();
}
return new MapModelAndView("siteinfo/start.jte",
Map.of("navbar", NavbarModel.SITEINFO,
"model", model));
}
/** Update the model if it is older than 15 minutes.
* This query is expensive and should not be run too often,
* and the data doesn't change that often either.
* <p></p>
* This method is synchronized to avoid multiple threads updating the model at the same time.
*/
private synchronized void updateModel() {
var currentModel = model;
if (currentModel.age().compareTo(Duration.ofMinutes(15)) < 0) {
return;
}
List<SiteOverviewModel.DiscoveredDomain> domains = new ArrayList<>();
try (var conn = dataSource.getConnection();
@ -91,13 +116,20 @@ public class SearchSiteInfoService {
throw new RuntimeException();
}
return new MapModelAndView("siteinfo/start.jte",
Map.of("navbar", NavbarModel.SITEINFO,
"model", new SiteOverviewModel(domains)));
model = new SiteOverviewModel(domains);
}
public record SiteOverviewModel(List<DiscoveredDomain> domains, Instant captureTime) {
public SiteOverviewModel(List<DiscoveredDomain> domains) {
this(domains, Instant.now());
}
public record SiteOverviewModel(List<DiscoveredDomain> domains) {
public record DiscoveredDomain(String name, String timestamp) {}
public Duration age() {
return Duration.between(captureTime, Instant.now());
}
}
@GET

View File

@ -81,35 +81,6 @@
@endif
@if (!siteInfo.siblingDomains().isEmpty())
<div class="mx-3 flex place-items-baseline space-x-2 p-2 bg-gray-100 dark:bg-gray-600 rounded">
<i class="fas fa-globe"></i>
<span>Related Subdomains</span>
</div>
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-600 mx-4">
<thead>
<tr class="bg-gray-50 dark:bg-gray-700">
<th scope="col" class="px-2 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-100 uppercase tracking-wider">Domain Name</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-600 text-xs">
@for (DbDomainQueries.DomainWithNode sibling : siteInfo.siblingDomains())
<tr>
<td class="px-3 py-6 md:py-3 whitespace-nowrap">
<a class="text-liteblue dark:text-blue-200" href="/site/${sibling.domain().toString()}">${sibling.domain().toString()}</a>
@if (!sibling.isIndexed())
<i class="ml-1 fa-regular fa-question-circle text-gray-400 dark:text-gray-600 text-xs" title="Not indexed"></i>
@endif
</td>
</tr>
@endfor
</tbody>
</table>
@endif
@if (siteInfo.domainInformation().isUnknownDomain())
<div class="mx-3 flex place-items-baseline space-x-2 p-2 bg-gray-100 dark:bg-gray-600 rounded">
<i class="fa-regular fa-circle-question"></i>
@ -178,6 +149,36 @@
</form>
@endif
@if (!siteInfo.siblingDomains().isEmpty())
<div class="mx-3 flex place-items-baseline space-x-2 p-2 bg-gray-100 dark:bg-gray-600 rounded">
<i class="fas fa-globe"></i>
<span>Related Subdomains</span>
</div>
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-600 mx-4">
<thead>
<tr class="bg-gray-50 dark:bg-gray-700">
<th scope="col" class="px-2 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-100 uppercase tracking-wider">Domain Name</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-600 text-xs">
@for (DbDomainQueries.DomainWithNode sibling : siteInfo.siblingDomains())
<tr>
<td class="px-3 py-6 md:py-3 whitespace-nowrap">
<a class="text-liteblue dark:text-blue-200" href="/site/${sibling.domain().toString()}">${sibling.domain().toString()}</a>
@if (!sibling.isIndexed())
<i class="ml-1 fa-regular fa-question-circle text-gray-400 dark:text-gray-600 text-xs" title="Not indexed"></i>
@endif
</td>
</tr>
@endfor
</tbody>
</table>
@endif
@if (siteInfo.isKnown())
<div class="mx-3 flex place-items-baseline space-x-2 p-2 bg-gray-100 dark:bg-gray-600 rounded">
<i class="fas fa-chart-simple"></i>