From 2d972c66ac3649f7cc12e5300837c726ce9d18b4 Mon Sep 17 00:00:00 2001 From: Szymon Porwolik Date: Tue, 18 Nov 2025 19:41:17 +0100 Subject: [PATCH] Cache improved --- application/config/config.sample.php | 15 ++- application/models/Dxcluster_model.php | 139 ++++++++++++------------- application/models/Logbook_model.php | 20 ++-- 3 files changed, 87 insertions(+), 87 deletions(-) diff --git a/application/config/config.sample.php b/application/config/config.sample.php index 1a6b1a318..20d657395 100644 --- a/application/config/config.sample.php +++ b/application/config/config.sample.php @@ -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. |-------------------------------------------------------------------------- */ diff --git a/application/models/Dxcluster_model.php b/application/models/Dxcluster_model.php index 90b8d9720..40c3a3ce3 100644 --- a/application/models/Dxcluster_model.php +++ b/application/models/Dxcluster_model.php @@ -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)) { diff --git a/application/models/Logbook_model.php b/application/models/Logbook_model.php index bd84f79dd..101971af9 100644 --- a/application/models/Logbook_model.php +++ b/application/models/Logbook_model.php @@ -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);