Add text event pruning

- Still need to prune AlertLayer
- Still need to test alerts reload after being pruned
This commit is contained in:
Dan Paulat 2025-05-03 23:20:26 -05:00
parent 4719badc54
commit f37a77a9f7
6 changed files with 158 additions and 8 deletions

View file

@ -116,13 +116,14 @@ public:
Impl(const Impl&&) = delete;
Impl& operator=(const Impl&&) = delete;
void
HandleMessage(const std::shared_ptr<awips::TextProductMessage>& message);
void HandleMessage(const std::shared_ptr<awips::TextProductMessage>& message,
bool archiveEvent = false);
template<ranges::forward_range DateRange>
requires std::same_as<ranges::range_value_t<DateRange>,
std::chrono::sys_days>
void ListArchives(DateRange dates);
void LoadArchives(std::chrono::system_clock::time_point dateTime);
void PruneArchives();
void RefreshAsync();
void Refresh();
template<ranges::forward_range DateRange>
@ -155,6 +156,15 @@ public:
std::mutex archiveMutex_ {};
std::list<std::chrono::sys_days> archiveDates_ {};
std::mutex archiveEventKeyMutex_ {};
std::map<std::chrono::sys_days,
std::unordered_set<types::TextEventKey,
types::TextEventHash<types::TextEventKey>>>
archiveEventKeys_ {};
std::unordered_set<types::TextEventKey,
types::TextEventHash<types::TextEventKey>>
liveEventKeys_ {};
std::mutex unloadedProductMapMutex_ {};
std::map<std::chrono::sys_days,
boost::container::stable_vector<scwx::types::iem::AfosEntry>>
@ -249,7 +259,7 @@ void TextEventManager::SelectTime(
const auto today = std::chrono::floor<std::chrono::days>(dateTime);
const auto yesterday = today - std::chrono::days {1};
const auto tomorrow = today + std::chrono::days {1};
const auto dateArray = std::array {today, yesterday, tomorrow};
const auto dateArray = std::array {yesterday, today, tomorrow};
const auto dates =
dateArray |
@ -265,6 +275,7 @@ void TextEventManager::SelectTime(
p->UpdateArchiveDates(dates);
p->ListArchives(dates);
p->LoadArchives(dateTime);
p->PruneArchives();
}
catch (const std::exception& ex)
{
@ -274,7 +285,7 @@ void TextEventManager::SelectTime(
}
void TextEventManager::Impl::HandleMessage(
const std::shared_ptr<awips::TextProductMessage>& message)
const std::shared_ptr<awips::TextProductMessage>& message, bool archiveEvent)
{
using namespace std::chrono_literals;
@ -335,6 +346,12 @@ void TextEventManager::Impl::HandleMessage(
textEventMap_.emplace(key, std::vector {message});
messageIndex = 0;
updated = true;
if (!archiveEvent)
{
// Add the Text Event Key to the list of live events to prevent pruning
liveEventKeys_.insert(key);
}
}
else if (std::find_if(it->second.cbegin(),
it->second.cend(),
@ -368,6 +385,17 @@ void TextEventManager::Impl::HandleMessage(
updated = true;
};
// If this is an archive event, and the key does not exist in the live events
// Assumption: A live event will always be loaded before a duplicate archive
// event
if (archiveEvent && !liveEventKeys_.contains(key))
{
// Add the Text Event Key to the current date's archive
const std::unique_lock archiveEventKeyLock {archiveEventKeyMutex_};
auto& archiveKeys = archiveEventKeys_[wmoDate];
archiveKeys.insert(key);
}
lock.unlock();
if (updated)
@ -518,11 +546,87 @@ void TextEventManager::Impl::LoadArchives(
for (auto& message : messages)
{
HandleMessage(message);
HandleMessage(message, true);
}
}
}
void TextEventManager::Impl::PruneArchives()
{
static constexpr std::size_t kMaxArchiveDates_ = 5;
std::unordered_set<types::TextEventKey,
types::TextEventHash<types::TextEventKey>>
eventKeysToKeep {};
std::unordered_set<types::TextEventKey,
types::TextEventHash<types::TextEventKey>>
eventKeysToPrune {};
// Remove oldest dates from the archive
while (archiveDates_.size() > kMaxArchiveDates_)
{
archiveDates_.pop_front();
}
const std::unique_lock archiveEventKeyLock {archiveEventKeyMutex_};
// If there are the same number of dates in both archiveEventKeys_ and
// archiveDates_, there is nothing to prune
if (archiveEventKeys_.size() == archiveDates_.size())
{
// Nothing to prune
return;
}
const std::unique_lock unloadedProductMapLock {unloadedProductMapMutex_};
for (auto it = archiveEventKeys_.begin(); it != archiveEventKeys_.end();)
{
const auto& date = it->first;
const auto& eventKeys = it->second;
// If date is not in recent days map
if (std::find(archiveDates_.cbegin(), archiveDates_.cend(), date) ==
archiveDates_.cend())
{
// Prune these keys (unless they are in the eventKeysToKeep set)
eventKeysToPrune.insert(eventKeys.begin(), eventKeys.end());
// The date is not in the list of recent dates, remove it
it = archiveEventKeys_.erase(it);
unloadedProductMap_.erase(date);
}
else
{
// Make sure these keys don't get pruned
eventKeysToKeep.insert(eventKeys.begin(), eventKeys.end());
// The date is recent, keep it
++it;
}
}
// Remove elements from eventKeysToPrune if they are in eventKeysToKeep
for (const auto& eventKey : eventKeysToKeep)
{
eventKeysToPrune.erase(eventKey);
}
// Remove eventKeysToPrune from textEventMap
for (const auto& eventKey : eventKeysToPrune)
{
textEventMap_.erase(eventKey);
}
// If event keys were pruned, emit a signal
if (!eventKeysToPrune.empty())
{
logger_->debug("Pruned {} archive events", eventKeysToPrune.size());
Q_EMIT self_->AlertsRemoved(eventKeysToPrune);
}
}
void TextEventManager::Impl::RefreshAsync()
{
boost::asio::post(threadPool_,