Cache improved

This commit is contained in:
Szymon Porwolik
2025-11-18 19:41:17 +01:00
parent 2d471d35de
commit 2d972c66ac
3 changed files with 87 additions and 87 deletions

View File

@@ -806,14 +806,19 @@ $config['max_login_attempts'] = 3;
| Controls file-based caching for DXCluster features. Two independent settings:
|
| 1. enable_dxcluster_file_cache_band
| - Caches spot lists (per band/mode/continent) from DXCache API
| - Caches processed spot lists (WITHOUT worked status) from DXCache API
| - Cache is INSTANCE-WIDE (shared by all users)
| - Cache duration: 59 seconds
| - Cache key includes: band, max age, continent, mode, user_id, logbook_id
| - Cache key format: dxcluster_raw_{maxage}_{continent}_{mode}_{band}
| - Example: dxcluster_raw_60_Any_All_20m
| - Contains: callsign, frequency, DXCC, mode, age, metadata
| - Does NOT contain: worked/confirmed status (always false in cache)
| - Set to TRUE to reduce API calls and speed up spot list loading
| - Set to FALSE to always fetch fresh data from API
|
| 2. enable_dxcluster_file_cache_worked
| - Caches worked/confirmed status lookups from database
| - Cache is USER-SPECIFIC (separate for each user/logbook)
| - Cache duration: 15 minutes (900 seconds)
| - Cache includes: All bands/modes combinations per callsign/DXCC/continent
| - Set to TRUE to significantly reduce database load
@@ -821,8 +826,10 @@ $config['max_login_attempts'] = 3;
|
| Default: false (both caching disabled)
|
| Recommendation: Enable both on high-traffic installations for best performance.
| Warning: May cause high disk usage on large multi-user installations.
| Recommendation:
| - Enable BAND cache on all installations to reduce API load (instance-wide)
| - Enable WORKED cache on high-traffic multi-user installations to reduce DB queries
| Warning: WORKED cache may cause high disk usage on large multi-user installations.
|--------------------------------------------------------------------------
*/

View File

@@ -48,23 +48,14 @@ class Dxcluster_model extends CI_Model {
$this->load->helper(array('psr4_autoloader'));
// Check if file caching is enabled in config
$cache_enabled = $this->config->item('enable_dxcluster_file_cache_band') === true;
$cache_band_enabled = $this->config->item('enable_dxcluster_file_cache_band') === true;
$cache_worked_enabled = $this->config->item('enable_dxcluster_file_cache_worked') === true;
// Only load cache driver if caching is enabled
if ($cache_enabled) {
if ($cache_band_enabled || $cache_worked_enabled) {
$this->load->driver('cache', array('adapter' => 'file', 'backup' => 'file'));
}
// Check cache first for processed spot list (only if caching is enabled)
$user_id = $this->session->userdata('user_id');
$logbook_id = $this->session->userdata('active_station_logbook');
$cache_key = "spotlist_{$band}_{$maxage}_{$de}_{$mode}_{$user_id}_{$logbook_id}";
// Try to get cached processed results (59 second cache) only if caching is enabled
if ($cache_enabled && ($cached_spots = $this->cache->get($cache_key))) {
return $cached_spots;
}
if($this->session->userdata('user_date_format')) {
$custom_date_format = $this->session->userdata('user_date_format');
} else {
@@ -82,14 +73,17 @@ class Dxcluster_model extends CI_Model {
$this->load->model('logbook_model');
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($this->session->userdata('active_station_logbook'));
// Check cache for raw DX cluster data (only if caching is enabled)
$jsonraw = null;
if ($cache_enabled) {
$jsonraw = $this->cache->get('dxcache'.$band);
// Cache key for RAW cluster response (instance-wide, no worked status)
$raw_cache_key = "dxcluster_raw_{$maxage}_{$de}_{$mode}_{$band}";
// Check cache for raw processed spots (without worked status)
$spotsout = null;
if ($cache_band_enabled) {
$spotsout = $this->cache->get($raw_cache_key);
}
if (!$jsonraw) {
// CURL Functions
if (!$spotsout) {
// Fetch raw DX cluster data from API
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $dxcache_url);
curl_setopt($ch, CURLOPT_USERAGENT, 'Wavelog '.$this->optionslib->get_option('version').' DXLookup');
@@ -106,50 +100,44 @@ class Dxcluster_model extends CI_Model {
return [];
}
// Save to cache only if caching is enabled
if ($cache_enabled) {
$this->cache->save('dxcache'.$band, $jsonraw, 59); // Cache DXClusterCache Instancewide for 59seconds
}
}
// Validate JSON before decoding
if (empty($jsonraw) || strlen($jsonraw) <= 20) {
return [];
}
$json = json_decode($jsonraw);
// Check for JSON decode errors
if (json_last_error() !== JSON_ERROR_NONE || !is_array($json)) {
log_message('error', 'DXCluster: Invalid JSON received: ' . json_last_error_msg());
return [];
}
$date = date('Ymd', time());
$dxccObj = new DXCC($date);
// DXCC lookup cache to avoid duplicate lookups
$dxcc_cache = [];
$spotsout=[];
// Cache current time outside loop (avoid creating DateTime on every iteration)
$currentTimestamp = time();
// Normalize continent filter once
$de_lower = strtolower($de);
$filter_continent = ($de != '' && $de != 'Any');
foreach($json as $singlespot){
// Early filtering - skip invalid spots immediately
if (!is_object($singlespot) || !isset($singlespot->frequency) || !is_numeric($singlespot->frequency)) {
continue;
// Validate JSON before decoding
if (empty($jsonraw) || strlen($jsonraw) <= 20) {
return [];
}
// Ensure frequency is always a number (not a string)
$singlespot->frequency = floatval($singlespot->frequency);
$json = json_decode($jsonraw);
$spotband = $this->frequency->GetBand($singlespot->frequency*1000); // Apply band filter early (before expensive operations)
// Check for JSON decode errors
if (json_last_error() !== JSON_ERROR_NONE || !is_array($json)) {
log_message('error', 'DXCluster: Invalid JSON received: ' . json_last_error_msg());
return [];
}
$date = date('Ymd', time());
$dxccObj = new DXCC($date);
// DXCC lookup cache to avoid duplicate lookups
$dxcc_cache = [];
$spotsout=[];
// Cache current time outside loop (avoid creating DateTime on every iteration)
$currentTimestamp = time();
// Normalize continent filter once
$de_lower = strtolower($de);
$filter_continent = ($de != '' && $de != 'Any');
foreach($json as $singlespot){
// Early filtering - skip invalid spots immediately
if (!is_object($singlespot) || !isset($singlespot->frequency) || !is_numeric($singlespot->frequency)) {
continue;
}
// Ensure frequency is always a number (not a string)
$singlespot->frequency = floatval($singlespot->frequency);
$spotband = $this->frequency->GetBand($singlespot->frequency*1000); // Apply band filter early (before expensive operations)
if (($band != 'All') && ($band != $spotband)) {
continue;
}
@@ -233,12 +221,17 @@ class Dxcluster_model extends CI_Model {
// Extract park references from message
$singlespot = $this->enrich_spot_metadata($singlespot);
// Collect spots for batch processing
$spotsout[] = $singlespot;
// Collect spots for batch processing
$spotsout[] = $singlespot;
}
// Cache the RAW processed spots (WITHOUT worked status) - instance-wide
if ($cache_band_enabled && !empty($spotsout)) {
$this->cache->save($raw_cache_key, $spotsout, 59);
}
}
// Batch process all spot statuses in a single optimized database query
// NOW add worked status if enabled (user-specific)
if (!empty($spotsout)) {
$batch_statuses = $this->logbook_model->get_batch_spot_statuses(
$spotsout,
@@ -308,17 +301,21 @@ class Dxcluster_model extends CI_Model {
$spotsout[$index] = $spot;
}
}
// Cache the processed results for 59 seconds (matches DXCache server TTL) only if caching is enabled
if ($cache_enabled && !empty($spotsout)) {
$this->cache->save($cache_key, $spotsout, 59);
} else {
// No worked status check - set all to false
foreach ($spotsout as $index => $spot) {
$spot->worked_dxcc = false;
$spot->worked_call = false;
$spot->cnfmd_dxcc = false;
$spot->cnfmd_call = false;
$spot->cnfmd_continent = false;
$spot->worked_continent = false;
$spotsout[$index] = $spot;
}
}
return $spotsout;
}
// Determine mode with priority: POTA/SOTA mode > message keywords > frequency-based
} // Determine mode with priority: POTA/SOTA mode > message keywords > frequency-based
function get_mode($spot) {
// Priority 0: If spot already has a valid mode from cluster, use it
if (isset($spot->mode) && !empty($spot->mode)) {

View File

@@ -2775,7 +2775,7 @@ class Logbook_model extends CI_Model {
if (!isset($this->spot_status_cache[$cache_key])) {
// Check file cache
if ($cache_enabled) {
$file_cache_key = "spot_status_call_{$logbook_ids_key}_{$callsign}";
$file_cache_key = "dxcluster_worked_call_{$logbook_ids_key}_{$callsign}";
$cached_data = $this->cache->get($file_cache_key);
if ($cached_data !== false) {
// Load from file cache into in-memory cache
@@ -2793,7 +2793,7 @@ class Logbook_model extends CI_Model {
if (!isset($this->spot_status_cache[$cache_key])) {
if ($cache_enabled) {
$file_cache_key = "spot_status_dxcc_{$logbook_ids_key}_{$dxcc}";
$file_cache_key = "dxcluster_worked_dxcc_{$logbook_ids_key}_{$dxcc}";
$cached_data = $this->cache->get($file_cache_key);
if ($cached_data !== false) {
$this->spot_status_cache[$cache_key] = $cached_data;
@@ -2809,7 +2809,7 @@ class Logbook_model extends CI_Model {
if (!isset($this->spot_status_cache[$cache_key])) {
if ($cache_enabled) {
$file_cache_key = "spot_status_cont_{$logbook_ids_key}_{$cont}";
$file_cache_key = "dxcluster_worked_cont_{$logbook_ids_key}_{$cont}";
$cached_data = $this->cache->get($file_cache_key);
if ($cached_data !== false) {
$this->spot_status_cache[$cache_key] = $cached_data;
@@ -3052,7 +3052,7 @@ class Logbook_model extends CI_Model {
// Save to file cache for 15 minutes
if ($cache_enabled) {
$file_cache_key = "spot_status_call_{$logbook_ids_key}_{$callsign}";
$file_cache_key = "dxcluster_worked_call_{$logbook_ids_key}_{$callsign}";
$this->cache->save($file_cache_key, $data, $cache_ttl);
}
}
@@ -3070,12 +3070,10 @@ class Logbook_model extends CI_Model {
$this->spot_status_cache[$cache_key] = $data;
if ($cache_enabled) {
$file_cache_key = "spot_status_cont_{$logbook_ids_key}_{$cont}";
$file_cache_key = "dxcluster_worked_cont_{$logbook_ids_key}_{$cont}";
$this->cache->save($file_cache_key, $data, $cache_ttl);
}
}
// Cache NOT WORKED items (negative results) - store empty arrays
} // Cache NOT WORKED items (negative results) - store empty arrays
// This prevents redundant database queries for callsigns/dxccs/continents not in logbook
foreach ($callsigns_array as $callsign) {
if (!isset($call_data[$callsign])) {
@@ -3105,13 +3103,11 @@ class Logbook_model extends CI_Model {
$this->spot_status_cache[$cache_key] = [];
if ($cache_enabled) {
$file_cache_key = "spot_status_cont_{$logbook_ids_key}_{$cont}";
$file_cache_key = "dxcluster_worked_cont_{$logbook_ids_key}_{$cont}";
$this->cache->save($file_cache_key, [], $cache_ttl);
}
}
}
// Now map all spots to their status using cached data (query results + previously cached)
} // Now map all spots to their status using cached data (query results + previously cached)
foreach ($spots_by_callsign as $callsign => $callsign_spots) {
foreach ($callsign_spots as $spot) {
$statuses[$callsign] = $this->map_spot_status_from_cache($spot, $logbook_ids_key);