From 89173442f3333a287fce3515451848b29c98efee Mon Sep 17 00:00:00 2001 From: Kirill Solomko Date: Fri, 5 May 2023 13:42:21 +0200 Subject: [PATCH] MT#57223 improve sems audio cache invalidation * clear_audio_cache is now invoked also from: - when a sound file is added (to reflect use_parent/potential child sets) - when a parent is changed for a sound set (to reflect current and potential child sets) - when a sound set is removed (to reflect potential child sets) * clear_audio_cache() is reworked - clear_audio_cache() now calls virtual_child_sound_sets to fetch all potentially affected child sound sets and also clears audio cache for them. if the amount of fetched sound_sets is greater than 10000 then the the whole audio cache is invalidated * _clear_audio_cache_service() is reworked - supports/expects a list of sound sets and sends them as a string with ':' separator - if both sound handle and sound sets are provided it calls clearFiles (so that only the specific sound handle is cleared) - if only sound sets are provided it calls clearSets (so that all of the cached files beloning to the sets are removed) - if none of the above are provided it calls clearAll to invalidate the whole cache Change-Id: Ie85f208e27183e88665803b93bb16d7de8e3d7ac --- .../Panel/Controller/API/SoundSetsItem.pm | 5 + lib/NGCP/Panel/Controller/Sound.pm | 41 +++++--- lib/NGCP/Panel/Role/API/SoundSets.pm | 10 ++ lib/NGCP/Panel/Utils/Sems.pm | 97 ++++++++++++++----- 4 files changed, 117 insertions(+), 36 deletions(-) diff --git a/lib/NGCP/Panel/Controller/API/SoundSetsItem.pm b/lib/NGCP/Panel/Controller/API/SoundSetsItem.pm index 575e11a943..61293e6ad4 100644 --- a/lib/NGCP/Panel/Controller/API/SoundSetsItem.pm +++ b/lib/NGCP/Panel/Controller/API/SoundSetsItem.pm @@ -3,6 +3,7 @@ use NGCP::Panel::Utils::Generic qw(:all); use Sipwise::Base; use HTTP::Status qw(:constants); +use NGCP::Panel::Utils::Sems; use parent qw/NGCP::Panel::Role::EntitiesItem NGCP::Panel::Role::API::SoundSets/; @@ -85,6 +86,10 @@ sub delete_item { })->delete_all; # explicit delete_all, otherwise query fails } + # clear audio cache of the current sound set and + # and all potentially affected children sets + NGCP::Panel::Utils::Sems::clear_audio_cache($c, $item->id); + $item->delete; return 1; diff --git a/lib/NGCP/Panel/Controller/Sound.pm b/lib/NGCP/Panel/Controller/Sound.pm index 5273263229..c5fcd877a9 100644 --- a/lib/NGCP/Panel/Controller/Sound.pm +++ b/lib/NGCP/Panel/Controller/Sound.pm @@ -235,6 +235,7 @@ sub edit :Chained('base') :PathPart('edit') { my $parent_loop_err; try { my $own_id = $c->stash->{set_result}->id; + my $old_parent_id = $c->stash->{set_result}->parent_id; my $parent_id = $form->values->{parent_id} = $form->values->{parent}{id} // undef; if ($c->user->roles eq "admin") { $form->values->{reseller_id} = $form->values->{reseller}{id}; @@ -293,6 +294,14 @@ sub edit :Chained('base') :PathPart('edit') { NGCP::Panel::Utils::Sounds::contract_sound_set_propagate( $c, $c->stash->{set_result}->contract, $c->stash->{set_result}->id); } + + # invalidate cache of this sound set if parent is changed + if ((!$old_parent_id && $parent_id) || + ($old_parent_id && !$parent_id) || + $old_parent_id != $parent_id) { + NGCP::Panel::Utils::Sems::clear_audio_cache($c, $own_id); + } + }); delete $c->session->{created_objects}->{reseller}; delete $c->session->{created_objects}->{contract}; @@ -329,6 +338,7 @@ sub delete_sound :Chained('base') :PathPart('delete') { my $schema = $c->model('DB'); $schema->txn_do(sub { + my $own_id = $c->stash->{set_result}->id; # remove all usr_preferenes where this set is assigned if($c->stash->{set_result}->contract_id) { my $pref_rs = NGCP::Panel::Utils::Preferences::get_usr_preference_rs( @@ -345,6 +355,10 @@ sub delete_sound :Chained('base') :PathPart('delete') { })->delete_all; # explicit delete_all, otherwise query fails } + # clear audio cache of the current sound set and + # all potentially affected children sets + NGCP::Panel::Utils::Sems::clear_audio_cache($c, $own_id); + $c->stash->{set_result}->delete; }); NGCP::Panel::Utils::Message::info( @@ -592,19 +606,6 @@ sub handles_edit :Chained('handles_base') :PathPart('edit') { my $target_codec = 'WAV'; - # clear audio caches - my $group_name = $file_result->handle->group->name; - try { - NGCP::Panel::Utils::Sems::clear_audio_cache($c, $file_result->set_id, $file_result->handle->name, $group_name); - } catch ($e) { - NGCP::Panel::Utils::Message::error( - c => $c, - error => "Failed to clear audio cache for " . $group_name . " at appserver", - desc => $c->loc('Failed to clear audio cache.'), - ); - NGCP::Panel::Utils::Navigation::back_or($c, $c->stash->{handles_base_uri}); - } - try { $soundfile = NGCP::Panel::Utils::Sounds::transcode_file( $upload->tempname, 'WAV', $target_codec); @@ -654,6 +655,20 @@ sub handles_edit :Chained('handles_base') :PathPart('edit') { ); } } + + # clear audio caches + my $group_name = $file_result->handle->group->name; + try { + NGCP::Panel::Utils::Sems::clear_audio_cache($c, $file_result->set_id, $file_result->handle->name, $group_name); + } catch ($e) { + NGCP::Panel::Utils::Message::error( + c => $c, + error => "Failed to clear audio cache for " . $group_name . " at appserver", + desc => $c->loc('Failed to clear audio cache.'), + ); + NGCP::Panel::Utils::Navigation::back_or($c, $c->stash->{handles_base_uri}); + } + NGCP::Panel::Utils::Navigation::back_or($c, $c->stash->{handles_base_uri}); } diff --git a/lib/NGCP/Panel/Role/API/SoundSets.pm b/lib/NGCP/Panel/Role/API/SoundSets.pm index 371ccda27b..b4c4a658b8 100644 --- a/lib/NGCP/Panel/Role/API/SoundSets.pm +++ b/lib/NGCP/Panel/Role/API/SoundSets.pm @@ -10,6 +10,7 @@ use Data::HAL qw(); use Data::HAL::Link qw(); use HTTP::Status qw(:constants); use NGCP::Panel::Utils::Sounds; +use NGCP::Panel::Utils::Sems; sub resource_name{ return 'soundsets'; @@ -182,6 +183,15 @@ sub update_item_model { NGCP::Panel::Utils::Sounds::revoke_exposed_sound_set($c, $item->id); } + # invalidate cache of this sound set if parent is changed + my $old_parent_id = $old_resource->{parent_id}; + my $parent_id = $resource->{parent_id}; + if ((!$old_parent_id && $parent_id) || + ($old_parent_id && !$parent_id) || + $old_parent_id != $parent_id) { + NGCP::Panel::Utils::Sems::clear_audio_cache($c, $item->id); + } + return $item; } diff --git a/lib/NGCP/Panel/Utils/Sems.pm b/lib/NGCP/Panel/Utils/Sems.pm index 22f0b530d4..ed76fda0b9 100644 --- a/lib/NGCP/Panel/Utils/Sems.pm +++ b/lib/NGCP/Panel/Utils/Sems.pm @@ -359,26 +359,31 @@ EOF sub clear_audio_cache { my ($c, $sound_set_id, $handle_name, $group_name) = @_; - my @pbx = $c->config->{features}->{cloudpbx} ? ('pbx') : (); - my @services; - if ($group_name eq "pbx" ) { - @services = (@pbx); - } elsif ($group_name =~ /^(music_on_hold|digits|custom_announcements)$/) { - @services = (@pbx, "appserver"); - } elsif ($group_name =~ /^(malicious_call_identification|voucher_recharge|play_balance|conference|calling_card)$/) { - @services = ("appserver"); - } + my $rs = $c->model('DB')->resultset('virtual_child_sound_sets')->search({ + },{ + bind => [$sound_set_id], + }); + + my $count = $rs->count; - for my $service (@services) { - _clear_audio_cache_service($c, $service, $sound_set_id, $handle_name); + if ($count > 10000) { # invalidate the whole sems audio cache if the amount of child sound sets is too big + _clear_audio_cache_service($c, "appserver", undef, undef); + } else { + my @sound_sets = map { $_->id } $rs->all; + _clear_audio_cache_service($c, "appserver", \@sound_sets, $handle_name) } + return; } sub _clear_audio_cache_service { - my ($c, $service, $sound_set_id, $handle_name) = @_; + my ($c, $service, $sound_sets, $handle_name) = @_; - my @ret = NGCP::Panel::Utils::XMLDispatcher::dispatch($c, $service, 1, 1, < postDSMEvent @@ -390,22 +395,68 @@ sub _clear_audio_cache_service { cmd - clearFile + clearFiles - audio_id + handle_name $handle_name - - - sound_set_id - $sound_set_id - - - - + + + sound_sets + $sound_sets_str + + + + + +EOF + } elsif ($sound_sets_str) { + $msg = < + + postDSMEvent + + + sw_audio + + + + + cmd + clearSets + + + sound_sets + $sound_sets_str + + + + + +EOF + } else { + $msg = < + + postDSMEvent + + + sw_audio + + + + + cmd + clearAll + + + + EOF + } + my @ret = NGCP::Panel::Utils::XMLDispatcher::dispatch($c, $service, 1, 1, $msg); if (grep { $$_[1] == 0 || ($$_[1] != -1 && $$_[2] !~ m#OK#) } @ret) { # error die "failed to clear SEMS audio cache"; }