From 63cc43a59cf31b1d2f48c9bbdd0d87afd7bccb4d Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Mon, 23 Nov 2015 14:12:04 -0800 Subject: [PATCH] Cache foreign key method lookup for better performance. Contributed by Jason Terry --- FS/FS/Record.pm | 62 ++++++++++++++++++++++++++++++++++++++++---------------- FS/FS/UID.pm | 15 +++++++++----- htetc/handler.pl | 6 ++++++ 3 files changed, 61 insertions(+), 22 deletions(-) diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index fafceacb5..827e4078f 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -3,7 +3,7 @@ use base qw( Exporter ); use strict; use vars qw( $AUTOLOAD - %virtual_fields_cache %fk_method_cache + %virtual_fields_cache %fk_method_cache $fk_table_cache $money_char $lat_lower $lon_upper ); use Carp qw(carp cluck croak confess); @@ -34,7 +34,7 @@ our @EXPORT_OK = qw( dbh fields hfields qsearch qsearchs dbdef jsearch str2time_sql str2time_sql_closing regexp_sql not_regexp_sql concat_sql group_concat_sql - midnight_sql + midnight_sql fk_methods_init ); our $DEBUG = 0; @@ -82,9 +82,7 @@ FS::UID->install_callback( sub { eval "sub PG_BYTEA { die 'guru meditation #9: calling PG_BYTEA when not running Pg?'; }"; } - foreach my $table ( dbdef->tables ) { - $fk_method_cache{$table} = fk_methods($table); - } + #fk_methods_init(); } ); @@ -988,7 +986,7 @@ sub exists { exists($self->{Hash}->{$field}); } -=item AUTLOADED METHODS +=item AUTOLOADED METHODS $record->column is a synonym for $record->get('column'); @@ -1010,10 +1008,8 @@ sub AUTOLOAD { confess "errant AUTOLOAD $field for $self (arg $value)" unless blessed($self) && $self->can('setfield'); - #$fk_method_cache{$self->table} ||= fk_methods($self->table); - if ( exists($fk_method_cache{$self->table}->{$field}) ) { + if ( my $fk_info = get_fk_method($self->table, $field) ) { - my $fk_info = $fk_method_cache{$self->table}->{$field}; my $method = $fk_info->{method} || 'qsearchs'; my $table = $fk_info->{table} || $field; my $column = $fk_info->{column}; @@ -1056,6 +1052,37 @@ sub AUTOLOAD { # } #} +# get_fk_method(TABLE, FIELD) +# Internal subroutine for fetching the foreign key descriptor for TABLE.FIELD +# if there is one. If not, returns undef. +# This will initialize fk_method_cache if it hasn't happened yet. It is the +# _only_ allowed way to access the contents of %fk_method_cache. + +# if we wanted to be even more efficient we'd create the fk methods in the +# symbol table instead of relying on AUTOLOAD every time + +sub get_fk_method { + my ($table, $field) = @_; + + # maybe should only load one table at a time? + fk_methods_init() unless exists($fk_method_cache{$table}); + + if ( exists($fk_method_cache{$table}) and + exists($fk_method_cache{$table}{$field}) ) { + return $fk_method_cache{$table}{$field}; + } else { + return undef; + } + +} + +sub fk_methods_init { + warn "[fk_methods_init]\n"; + foreach my $table ( dbdef->tables ) { + $fk_method_cache{$table} = fk_methods($table); + } +} + sub fk_methods { my $table = shift; @@ -1093,11 +1120,15 @@ sub fk_methods { # (alas. why we're cached. still, might this loop better be done once at # schema load time insetad of every time we AUTOLOAD a method on a new # class?) - foreach my $f_table ( dbdef->tables ) { - foreach my $fk (dbdef->table($f_table)->foreign_keys) { - - next unless $fk->table eq $table; - + if (! defined $fk_table_cache) { + foreach my $f_table ( dbdef->tables ) { + foreach my $fk (dbdef->table($f_table)->foreign_keys) { + push @{$fk_table_cache->{$fk->table}},[$f_table,$fk]; + } + } + } + foreach my $fks (@{$fk_table_cache->{$table}}) { + my ($f_table,$fk) = @$fks; my $method = ''; if ( scalar( @{$fk->columns} ) == 1 ) { if ( ! defined($fk->references) @@ -1120,9 +1151,6 @@ sub fk_methods { } } - - } - } \%hash; diff --git a/FS/FS/UID.pm b/FS/FS/UID.pm index c725f035a..50a917895 100644 --- a/FS/FS/UID.pm +++ b/FS/FS/UID.pm @@ -14,7 +14,7 @@ use IO::File; use FS::CurrentUser; @EXPORT_OK = qw( checkeuid checkruid cgi setcgi adminsuidsetup forksuidsetup - preuser_setup + preuser_setup load_schema getotaker dbh datasrc getsecrets driver_name myconnect ); @@ -113,6 +113,14 @@ sub env_setup { } +sub load_schema { + warn "$me loading schema\n" if $DEBUG; + getsecrets() unless $datasrc; + use FS::Schema qw(reload_dbdef dbdef); + reload_dbdef("$conf_dir/dbdef.$datasrc") + unless $FS::Schema::setup_hack; +} + sub db_setup { croak "Not running uid freeside (\$>=$>, \$<=$<)\n" unless checkeuid(); @@ -121,10 +129,7 @@ sub db_setup { warn "$me forksuidsetup connected to database with handle $dbh\n" if $DEBUG; - warn "$me forksuidsetup loading schema\n" if $DEBUG; - use FS::Schema qw(reload_dbdef dbdef); - reload_dbdef("$conf_dir/dbdef.$datasrc") - unless $FS::Schema::setup_hack; + load_schema(); warn "$me forksuidsetup deciding upon config system to use\n" if $DEBUG; diff --git a/htetc/handler.pl b/htetc/handler.pl index 416ea69c4..4bb214c98 100644 --- a/htetc/handler.pl +++ b/htetc/handler.pl @@ -10,6 +10,12 @@ use FS::Conf; $FS::Conf::conf_cache_enabled = 1; # enable FS::Conf caching for performance +# Preload to share in mod_perl parent for performance +use FS::UID qw(load_schema); +load_schema(); +use FS::Record qw(fk_methods_init); +fk_methods_init; + if ( %%%RT_ENABLED%%% ) { require RT; -- 2.11.0