mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-11-01 08:00:05 +00:00
Use weak_ptr to hold product manager records
- When selecting a product that's expired, it successfully refreshes the data, but doesn't display unless selected again - When old data is downloaded, the refresh timer starts at 15 seconds, even if the newest data says the timer should be longer - Selecting a product should update the recent lists
This commit is contained in:
parent
871cae68dd
commit
5fbb748328
2 changed files with 124 additions and 33 deletions
|
|
@ -37,8 +37,10 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||||
typedef std::function<std::shared_ptr<wsr88d::NexradFile>()>
|
typedef std::function<std::shared_ptr<wsr88d::NexradFile>()>
|
||||||
CreateNexradFileFunction;
|
CreateNexradFileFunction;
|
||||||
typedef std::map<std::chrono::system_clock::time_point,
|
typedef std::map<std::chrono::system_clock::time_point,
|
||||||
std::shared_ptr<types::RadarProductRecord>>
|
std::weak_ptr<types::RadarProductRecord>>
|
||||||
RadarProductRecordMap;
|
RadarProductRecordMap;
|
||||||
|
typedef std::list<std::shared_ptr<types::RadarProductRecord>>
|
||||||
|
RadarProductRecordList;
|
||||||
|
|
||||||
static constexpr uint32_t NUM_RADIAL_GATES_0_5_DEGREE =
|
static constexpr uint32_t NUM_RADIAL_GATES_0_5_DEGREE =
|
||||||
common::MAX_0_5_DEGREE_RADIALS * common::MAX_DATA_MOMENT_GATES;
|
common::MAX_0_5_DEGREE_RADIALS * common::MAX_DATA_MOMENT_GATES;
|
||||||
|
|
@ -124,7 +126,9 @@ public:
|
||||||
coordinates0_5Degree_ {},
|
coordinates0_5Degree_ {},
|
||||||
coordinates1Degree_ {},
|
coordinates1Degree_ {},
|
||||||
level2ProductRecords_ {},
|
level2ProductRecords_ {},
|
||||||
|
level2ProductRecentRecords_ {},
|
||||||
level3ProductRecordsMap_ {},
|
level3ProductRecordsMap_ {},
|
||||||
|
level3ProductRecentRecordsMap_ {},
|
||||||
level2ProductRecordMutex_ {},
|
level2ProductRecordMutex_ {},
|
||||||
level3ProductRecordMutex_ {},
|
level3ProductRecordMutex_ {},
|
||||||
level2ProviderManager_ {std::make_shared<ProviderManager>(
|
level2ProviderManager_ {std::make_shared<ProviderManager>(
|
||||||
|
|
@ -179,6 +183,8 @@ public:
|
||||||
std::chrono::system_clock::time_point time);
|
std::chrono::system_clock::time_point time);
|
||||||
std::shared_ptr<types::RadarProductRecord>
|
std::shared_ptr<types::RadarProductRecord>
|
||||||
StoreRadarProductRecord(std::shared_ptr<types::RadarProductRecord> record);
|
StoreRadarProductRecord(std::shared_ptr<types::RadarProductRecord> record);
|
||||||
|
void UpdateRecentRecords(RadarProductRecordList& recentList,
|
||||||
|
std::shared_ptr<types::RadarProductRecord> record);
|
||||||
|
|
||||||
void LoadProviderData(std::chrono::system_clock::time_point time,
|
void LoadProviderData(std::chrono::system_clock::time_point time,
|
||||||
std::shared_ptr<ProviderManager> providerManager,
|
std::shared_ptr<ProviderManager> providerManager,
|
||||||
|
|
@ -202,9 +208,11 @@ public:
|
||||||
std::vector<float> coordinates1Degree_;
|
std::vector<float> coordinates1Degree_;
|
||||||
|
|
||||||
RadarProductRecordMap level2ProductRecords_;
|
RadarProductRecordMap level2ProductRecords_;
|
||||||
|
RadarProductRecordList level2ProductRecentRecords_;
|
||||||
std::unordered_map<std::string, RadarProductRecordMap>
|
std::unordered_map<std::string, RadarProductRecordMap>
|
||||||
level3ProductRecordsMap_;
|
level3ProductRecordsMap_;
|
||||||
|
std::unordered_map<std::string, RadarProductRecordList>
|
||||||
|
level3ProductRecentRecordsMap_;
|
||||||
std::shared_mutex level2ProductRecordMutex_;
|
std::shared_mutex level2ProductRecordMutex_;
|
||||||
std::shared_mutex level3ProductRecordMutex_;
|
std::shared_mutex level3ProductRecordMutex_;
|
||||||
|
|
||||||
|
|
@ -299,8 +307,9 @@ void RadarProductManager::DumpRecords()
|
||||||
for (auto& record :
|
for (auto& record :
|
||||||
radarProductManager->p->level2ProductRecords_)
|
radarProductManager->p->level2ProductRecords_)
|
||||||
{
|
{
|
||||||
logger_->info(" {}",
|
logger_->info(" {}{}",
|
||||||
scwx::util::TimeString(record.first));
|
scwx::util::TimeString(record.first),
|
||||||
|
record.second.expired() ? " (expired)" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -318,8 +327,10 @@ void RadarProductManager::DumpRecords()
|
||||||
|
|
||||||
for (auto& record : recordMap.second)
|
for (auto& record : recordMap.second)
|
||||||
{
|
{
|
||||||
logger_->info(" {}",
|
logger_->info(" {}{}",
|
||||||
scwx::util::TimeString(record.first));
|
scwx::util::TimeString(record.first),
|
||||||
|
record.second.expired() ? " (expired)" :
|
||||||
|
"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -673,11 +684,14 @@ void RadarProductManagerImpl::LoadProviderData(
|
||||||
|
|
||||||
auto it = recordMap.find(time);
|
auto it = recordMap.find(time);
|
||||||
if (it != recordMap.cend())
|
if (it != recordMap.cend())
|
||||||
|
{
|
||||||
|
existingRecord = it->second.lock();
|
||||||
|
|
||||||
|
if (existingRecord != nullptr)
|
||||||
{
|
{
|
||||||
logger_->debug(
|
logger_->debug(
|
||||||
"Data previously loaded, loading from data cache");
|
"Data previously loaded, loading from data cache");
|
||||||
|
}
|
||||||
existingRecord = it->second;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -844,22 +858,28 @@ RadarProductManagerImpl::GetLevel2ProductRecord(
|
||||||
std::chrono::system_clock::time_point time)
|
std::chrono::system_clock::time_point time)
|
||||||
{
|
{
|
||||||
std::shared_ptr<types::RadarProductRecord> record;
|
std::shared_ptr<types::RadarProductRecord> record;
|
||||||
|
RadarProductRecordMap::const_pointer recordPtr {nullptr};
|
||||||
|
|
||||||
if (!level2ProductRecords_.empty() &&
|
if (!level2ProductRecords_.empty() &&
|
||||||
time == std::chrono::system_clock::time_point {})
|
time == std::chrono::system_clock::time_point {})
|
||||||
{
|
{
|
||||||
// If a default-initialized time point is given, return the latest record
|
// If a default-initialized time point is given, return the latest record
|
||||||
record = level2ProductRecords_.rbegin()->second;
|
recordPtr = &(*level2ProductRecords_.rbegin());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: Round to minutes
|
// TODO: Round to minutes
|
||||||
record = scwx::util::GetBoundedElementValue(level2ProductRecords_, time);
|
recordPtr =
|
||||||
|
scwx::util::GetBoundedElementPointer(level2ProductRecords_, time);
|
||||||
|
}
|
||||||
|
|
||||||
// Does the record contain the time we are looking for?
|
if (recordPtr != nullptr)
|
||||||
if (record != nullptr && (time < record->level2_file()->start_time()))
|
|
||||||
{
|
{
|
||||||
record = nullptr;
|
record = recordPtr->second.lock();
|
||||||
|
if (record == nullptr)
|
||||||
|
{
|
||||||
|
// Product is expired, reload it
|
||||||
|
self_->LoadLevel2Data(recordPtr->first, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -871,6 +891,7 @@ RadarProductManagerImpl::GetLevel3ProductRecord(
|
||||||
const std::string& product, std::chrono::system_clock::time_point time)
|
const std::string& product, std::chrono::system_clock::time_point time)
|
||||||
{
|
{
|
||||||
std::shared_ptr<types::RadarProductRecord> record = nullptr;
|
std::shared_ptr<types::RadarProductRecord> record = nullptr;
|
||||||
|
RadarProductRecordMap::const_pointer recordPtr {nullptr};
|
||||||
|
|
||||||
std::unique_lock lock {level3ProductRecordMutex_};
|
std::unique_lock lock {level3ProductRecordMutex_};
|
||||||
|
|
||||||
|
|
@ -882,11 +903,24 @@ RadarProductManagerImpl::GetLevel3ProductRecord(
|
||||||
{
|
{
|
||||||
// If a default-initialized time point is given, return the latest
|
// If a default-initialized time point is given, return the latest
|
||||||
// record
|
// record
|
||||||
record = it->second.rbegin()->second;
|
recordPtr = &(*it->second.rbegin());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
record = scwx::util::GetBoundedElementValue(it->second, time);
|
recordPtr = scwx::util::GetBoundedElementPointer(it->second, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock is no longer needed
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
if (recordPtr != nullptr)
|
||||||
|
{
|
||||||
|
record = recordPtr->second.lock();
|
||||||
|
if (record == nullptr)
|
||||||
|
{
|
||||||
|
// Product is expired, reload it
|
||||||
|
self_->LoadLevel3Data(product, recordPtr->first, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -899,7 +933,7 @@ RadarProductManagerImpl::StoreRadarProductRecord(
|
||||||
{
|
{
|
||||||
logger_->debug("StoreRadarProductRecord()");
|
logger_->debug("StoreRadarProductRecord()");
|
||||||
|
|
||||||
std::shared_ptr<types::RadarProductRecord> storedRecord = record;
|
std::shared_ptr<types::RadarProductRecord> storedRecord = nullptr;
|
||||||
|
|
||||||
auto timeInSeconds =
|
auto timeInSeconds =
|
||||||
std::chrono::time_point_cast<std::chrono::seconds,
|
std::chrono::time_point_cast<std::chrono::seconds,
|
||||||
|
|
@ -911,16 +945,23 @@ RadarProductManagerImpl::StoreRadarProductRecord(
|
||||||
|
|
||||||
auto it = level2ProductRecords_.find(timeInSeconds);
|
auto it = level2ProductRecords_.find(timeInSeconds);
|
||||||
if (it != level2ProductRecords_.cend())
|
if (it != level2ProductRecords_.cend())
|
||||||
|
{
|
||||||
|
storedRecord = it->second.lock();
|
||||||
|
|
||||||
|
if (storedRecord != nullptr)
|
||||||
{
|
{
|
||||||
logger_->debug(
|
logger_->debug(
|
||||||
"Level 2 product previously loaded, loading from cache");
|
"Level 2 product previously loaded, loading from cache");
|
||||||
|
|
||||||
storedRecord = it->second;
|
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
if (storedRecord == nullptr)
|
||||||
{
|
{
|
||||||
|
storedRecord = record;
|
||||||
level2ProductRecords_[timeInSeconds] = record;
|
level2ProductRecords_[timeInSeconds] = record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateRecentRecords(level2ProductRecentRecords_, storedRecord);
|
||||||
}
|
}
|
||||||
else if (record->radar_product_group() == common::RadarProductGroup::Level3)
|
else if (record->radar_product_group() == common::RadarProductGroup::Level3)
|
||||||
{
|
{
|
||||||
|
|
@ -930,21 +971,55 @@ RadarProductManagerImpl::StoreRadarProductRecord(
|
||||||
|
|
||||||
auto it = productMap.find(timeInSeconds);
|
auto it = productMap.find(timeInSeconds);
|
||||||
if (it != productMap.cend())
|
if (it != productMap.cend())
|
||||||
|
{
|
||||||
|
storedRecord = it->second.lock();
|
||||||
|
|
||||||
|
if (storedRecord != nullptr)
|
||||||
{
|
{
|
||||||
logger_->debug(
|
logger_->debug(
|
||||||
"Level 3 product previously loaded, loading from cache");
|
"Level 3 product previously loaded, loading from cache");
|
||||||
|
|
||||||
storedRecord = it->second;
|
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
if (storedRecord == nullptr)
|
||||||
{
|
{
|
||||||
|
storedRecord = record;
|
||||||
productMap[timeInSeconds] = record;
|
productMap[timeInSeconds] = record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateRecentRecords(
|
||||||
|
level3ProductRecentRecordsMap_[record->radar_product()], storedRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
return storedRecord;
|
return storedRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RadarProductManagerImpl::UpdateRecentRecords(
|
||||||
|
RadarProductRecordList& recentList,
|
||||||
|
std::shared_ptr<types::RadarProductRecord> record)
|
||||||
|
{
|
||||||
|
static constexpr std::size_t kRecentListMaxSize_ {2u};
|
||||||
|
|
||||||
|
auto it = std::find(recentList.cbegin(), recentList.cend(), record);
|
||||||
|
if (it != recentList.cbegin() && it != recentList.cend())
|
||||||
|
{
|
||||||
|
// If the record exists beyond the front of the list, remove it
|
||||||
|
recentList.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recentList.size() == 0 || it != recentList.cbegin())
|
||||||
|
{
|
||||||
|
// Add the record to the front of the list, unless it's already there
|
||||||
|
recentList.push_front(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (recentList.size() > kRecentListMaxSize_)
|
||||||
|
{
|
||||||
|
// Remove from the end of the list while it's too big
|
||||||
|
recentList.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::tuple<std::shared_ptr<wsr88d::rda::ElevationScan>,
|
std::tuple<std::shared_ptr<wsr88d::rda::ElevationScan>,
|
||||||
float,
|
float,
|
||||||
std::vector<float>>
|
std::vector<float>>
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ namespace scwx
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
|
|
||||||
template<class Key, class T, class ReturnType = std::optional<T>>
|
template<class Key, class T, class ReturnType = std::map<Key, T>::const_pointer>
|
||||||
ReturnType GetBoundedElement(std::map<Key, T>& map, Key key)
|
ReturnType GetBoundedElementPointer(std::map<Key, T>& map, const Key& key)
|
||||||
{
|
{
|
||||||
ReturnType element;
|
ReturnType elementPtr {nullptr};
|
||||||
|
|
||||||
// Find the first element greater than the key requested
|
// Find the first element greater than the key requested
|
||||||
auto it = map.upper_bound(key);
|
auto it = map.upper_bound(key);
|
||||||
|
|
@ -24,26 +24,42 @@ ReturnType GetBoundedElement(std::map<Key, T>& map, Key key)
|
||||||
{
|
{
|
||||||
// Get the element immediately preceding, this the element we are
|
// Get the element immediately preceding, this the element we are
|
||||||
// looking for
|
// looking for
|
||||||
element = (--it)->second;
|
elementPtr = &(*(--it));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The current element is a good substitute
|
// The current element is a good substitute
|
||||||
element = it->second;
|
elementPtr = &(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (map.size() > 0)
|
else if (map.size() > 0)
|
||||||
{
|
{
|
||||||
// An element with a key greater was not found. If it exists, it must be
|
// An element with a key greater was not found. If it exists, it must be
|
||||||
// the last element.
|
// the last element.
|
||||||
element = map.rbegin()->second;
|
elementPtr = &(*map.rbegin());
|
||||||
|
}
|
||||||
|
|
||||||
|
return elementPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Key, class T, class ReturnType = std::optional<T>>
|
||||||
|
ReturnType GetBoundedElement(std::map<Key, T>& map, const Key& key)
|
||||||
|
{
|
||||||
|
ReturnType element;
|
||||||
|
|
||||||
|
typename std::map<Key, T>::pointer elementPtr =
|
||||||
|
GetBoundedElementPointer<Key, T, typename std::map<Key, T>::pointer>(map,
|
||||||
|
key);
|
||||||
|
if (elementPtr != nullptr)
|
||||||
|
{
|
||||||
|
element = elementPtr->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Key, class T>
|
template<class Key, class T>
|
||||||
inline T GetBoundedElementValue(std::map<Key, T>& map, Key key)
|
inline T GetBoundedElementValue(std::map<Key, T>& map, const Key& key)
|
||||||
{
|
{
|
||||||
return GetBoundedElement<Key, T, T>(map, key);
|
return GetBoundedElement<Key, T, T>(map, key);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue