From 4b65389d5e850dbae5fa729d18fe08b6367b2754 Mon Sep 17 00:00:00 2001 From: Jared Camins-Esakov Date: Thu, 1 Nov 2012 14:46:57 -0400 Subject: [PATCH] Bug 9005: Allow user to disable syspref cache Because C4::Context uses an in-memory hash for caching sysprefs, changing a syspref under a multi-threaded persistent environment requires a server restart. This patch makes it possible disable the syspref cache. To test: 1) If you are using a multi-threaded persistent server (Starman, etc.), change a syspref and note that the effects of the syspref change may or may not be visible on any given request before applying this patch. You will need to choose a syspref with obvious effects that can be seen by simply refreshing the page. I recommend enabling or disabling additional languages in the OPAC, since you can refresh the page a dozen times and reasonably expect to see the new behavior you set only 1/n of the time. 2) Apply patch. 3) Add "C4::Context->disable_syspref_cache();" to your koha.psgi file 4) Repeat step 1, noting that you never see the stale behavior. 5) Run test at t/db_dependent/Context.t. Signed-off-by: Kyle M Hall All tests passed. Signed-off-by: Paul Poulain Signed-off-by: Jared Camins-Esakov --- C4/Context.pm | 32 ++++++++++++++++++++- t/db_dependent/Context.t | 60 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/C4/Context.pm b/C4/Context.pm index e785002c4d..7de3f9479c 100644 --- a/C4/Context.pm +++ b/C4/Context.pm @@ -523,12 +523,13 @@ with this method. # flushing the caching mechanism. my %sysprefs; +my $use_syspref_cache = 1; sub preference { my $self = shift; my $var = lc(shift); # The system preference to return - if (exists $sysprefs{$var}) { + if ($use_syspref_cache && exists $sysprefs{$var}) { return $sysprefs{$var}; } @@ -552,6 +553,35 @@ sub boolean_preference { return defined($it)? C4::Boolean::true_p($it): undef; } +=head2 enable_syspref_cache + + C4::Context->enable_syspref_cache(); + +Enable the in-memory syspref cache used by C4::Context. This is the +default behavior. + +=cut + +sub enable_syspref_cache { + my ($self) = @_; + $use_syspref_cache = 1; +} + +=head2 disable_syspref_cache + + C4::Context->disable_syspref_cache(); + +Disable the in-memory syspref cache used by C4::Context. This should be +used with Plack and other persistent environments. + +=cut + +sub disable_syspref_cache { + my ($self) = @_; + $use_syspref_cache = 0; + $self->clear_syspref_cache(); +} + =head2 clear_syspref_cache C4::Context->clear_syspref_cache(); diff --git a/t/db_dependent/Context.t b/t/db_dependent/Context.t index eac32651c6..5105e848da 100755 --- a/t/db_dependent/Context.t +++ b/t/db_dependent/Context.t @@ -5,6 +5,7 @@ use strict; use warnings; use Test::More; +use Test::MockModule; use vars qw($debug $koha $dbh $config $ret); BEGIN { @@ -42,6 +43,65 @@ foreach (grep {defined $koha->{$_}} sort @keys) { } ok($config = $koha->{config}, 'Getting $koha->{config} '); +diag "Testing syspref caching."; + +my $dbh = C4::Context->dbh; +$dbh->disconnect; + +my $module = new Test::MockModule('C4::Context'); +$module->mock( + '_new_dbh', + sub { + my $dbh = DBI->connect( 'DBI:Mock:', '', '' ) + || die "Cannot create handle: $DBI::errstr\n"; + return $dbh; + } +); + +my $history; +$dbh = C4::Context->dbh; + +$dbh->{mock_add_resultset} = [ ['value'], ['thing1'] ]; +$dbh->{mock_add_resultset} = [ ['value'], ['thing2'] ]; +$dbh->{mock_add_resultset} = [ ['value'], ['thing3'] ]; +$dbh->{mock_add_resultset} = [ ['value'], ['thing4'] ]; + +is(C4::Context->preference("SillyPreference"), 'thing1', "Retrieved syspref (value='thing1') successfully with default behavior"); +$history = $dbh->{mock_all_history}; +is(scalar(@{$history}), 1, 'Retrieved syspref from database'); + +$dbh->{mock_clear_history} = 1; +is(C4::Context->preference("SillyPreference"), 'thing1', "Retrieved syspref (value='thing1') successfully with default behavior"); +$history = $dbh->{mock_all_history}; +is(scalar(@{$history}), 0, 'Did not retrieve syspref from database'); + +C4::Context->disable_syspref_cache(); +is(C4::Context->preference("SillyPreference"), 'thing2', "Retrieved syspref (value='thing2') successfully with disabled cache"); +$history = $dbh->{mock_all_history}; +is(scalar(@{$history}), 1, 'Retrieved syspref from database'); + +$dbh->{mock_clear_history} = 1; +is(C4::Context->preference("SillyPreference"), 'thing3', "Retrieved syspref (value='thing3') successfully with disabled cache"); +$history = $dbh->{mock_all_history}; +is(scalar(@{$history}), 1, 'Retrieved syspref from database'); + +C4::Context->enable_syspref_cache(); +$dbh->{mock_clear_history} = 1; +is(C4::Context->preference("SillyPreference"), 'thing3', "Retrieved syspref (value='thing3') successfully from cache"); +$history = $dbh->{mock_all_history}; +is(scalar(@{$history}), 0, 'Did not retrieve syspref from database'); + +C4::Context->clear_syspref_cache(); +$dbh->{mock_clear_history} = 1; +is(C4::Context->preference("SillyPreference"), 'thing4', "Retrieved syspref (value='thing4') successfully after clearing cache"); +$history = $dbh->{mock_all_history}; +is(scalar(@{$history}), 1, 'Retrieved syspref from database'); + +$dbh->{mock_clear_history} = 1; +is(C4::Context->preference("SillyPreference"), 'thing4', "Retrieved syspref (value='thing4') successfully from cache"); +$history = $dbh->{mock_all_history}; +is(scalar(@{$history}), 0, 'Did not retrieve syspref from database'); + done_testing(); 1; -- 2.39.5