#!/usr/bin/env perl use strict; use warnings; use CGI; use Template; use Text::Xslate; use Cache::Memcached::Fast; use DBI; use Time::HiRes qw/tv_interval gettimeofday/; use List::MoreUtils qw/natatime/; use Test::More; use Test::Deep; use Test::Differences; my $pedantic = shift; $pedantic = 0 if !$pedantic; my $mem = new Cache::Memcached::Fast( { servers => [ '127.0.0.1:11211' ], namespace => 'ttc:', connect_timeout => 0.2, io_timeout => 0.5, close_on_error => 1, compress_threshold => 100_000, compress_ratio => 0.9, nowait => 1, } ); die "CANNOT CONNECT TO MEMCACHE" unless $mem; my $db = DBI->connect('DBI:mysql:database=MYDBNAME;host=127.0.0.1;port=3306','USERNAME','PASSWORD'); die "CANNOT CONNECT TO DB" unless $db; sub timeblock { my ($text,$coderef) = @_; my $t0 = [gettimeofday]; my $res = $coderef->(); warn "$text: " . tv_interval($t0,[gettimeofday]); return $res } timeblock( 'Deleting key "ENTITY"', sub { $mem->delete('entity') } ); my $entity_ids = timeblock( 'Get all entity id from db', sub { my $sth = $db->prepare('SELECT id FROM mydatabasename.entity'); $sth->execute; [ map { $_->[0] } @{ $sth->fetchall_arrayref() } ]; } ); timeblock( 'Set all entity ids to "entity"', sub { $mem->set( 'entity', $entity_ids, 90 ); } ); timeblock( 'Deleting keys "entity_ID"', sub { $mem->delete("entity_$_") for @$entity_ids } ); my $mentity_ids = timeblock( 'Get all entity ids from memcache', sub { $mem->get('entity') } ); my $entities = timeblock( 'getting all entity from db', sub { my $sth = $db->prepare('SELECT * FROM mydatabasename.entity'); $sth->execute(); $sth->fetchall_hashref('id'); } ); my $db_entities = {}; $db_entities->{"entity_$_"} = $entities->{$_} for keys %$entities; warn "There are " . scalar(keys(%$db_entities)) . " entities in the db/hash\n"; my $mentities; for ( 1..3 ) { next unless $pedantic; $mentities = timeblock("Getting all entities from cache/db ($_)", sub { my %status = (fetched=>0,cached=>0); my $_mentities = timeblock('get_multi on entities',sub{$mem->get_multi(map { "entity_$_" } @$entity_ids)}); my @notcached; timeblock('getting non-cached entities', sub { for my $entity_id ( @$entity_ids ) { if ( exists $_mentities->{"entity_$entity_id"} ) { $status{cached}++; next; } my $entity = do { my $sth = $db->prepare('SELECT * FROM mydatabasename.entity WHERE id = ? LIMIT 1'); $sth->execute($entity_id); $sth->fetchrow_hashref; }; push @notcached, "entity_$entity_id"; $_mentities->{"entity_$entity_id"} = { %$entity }; $status{fetched}++; } }); timeblock('setting cache for noncached', sub { if ( @notcached ) { my $it = natatime(20,@notcached); while ( my @keys = $it->() ) { $mem->set_multi( map { [$_,$_mentities->{$_}, 90] } @keys ); } } }); warn "$status{cached} cached, $status{fetched} fetched"; $_mentities; }); } sub do_template { my $name = shift; my $template_line = shift; if ( $pedantic ) { my $tt_html_1 = timeblock( "$name - TT - one template per entity", sub { my $template = "$template_line"; my $text = ''; my $tt = Template->new; for ( map { $mentities->{$_} } sort keys %$mentities ) { my $t = ''; $tt->process( \$template, { entity => $_ }, \$t ); $text .= $t; } $text; } ); } my $tt_html_a = timeblock( "$name - TT - one template for all", sub { my $template = "[% FOR entity IN entities %]${template_line}[% END %]"; my $text = ''; my $tt = Template->new; $tt->process( \$template, { entities => [ map { $db_entities->{$_} } sort keys %$db_entities ] }, \$text ); $text; } ); #eq_or_diff_text( $tt_html_1, $tt_html_a ); if ($pedantic) { my $tx_html_1 = timeblock( "$name - XSlate - one template per entity", sub { my $template = "$template_line"; my $text = ''; my $tx = Text::Xslate->new( syntax => 'TTerse' ); for ( map { $mentities->{$_} } sort keys %$mentities ) { $text .= $tx->render_string( $template, { entity => $_ } ); } $text; } ); } my $tx_html_a = timeblock( "$name - XSlate - one template for all", sub { my $template = "[% FOR entiey IN entities %]${template_line}[% END %]"; my $tx = Text::Xslate->new( syntax => 'TTerse' ); $tx->render_string( $template, { entities => [ map { $db_entities->{$_} } sort keys %$db_entities ] }); } ); #eq_or_diff_text( $tx_html_1, $tx_html_a ); #eq_or_diff_text($tt_html_a,$tx_html_a); } for ( 1..3 ) { do_template('template with 2 vars', "entity [% entity.id %] - [% entity.name %]\n"); do_template('template with 3 vars', "entity [% entity.id %] - [% entity.level %] - [% entity.name %]\n"); do_template('template with 4 vars', "entity [% entity.id %] - [% entity.level %] - [% entity.actiontype %] - [% entity.name %]\n"); do_template('template with 4x2 vars', "entity [% entity.id %] - [% entity.level %] - [% entity.actiontype %] - [% entity.name %]\n" . "entity [% entity.id %] - [% entity.level %] - [% entity.actiontype %] - [% entity.name %]\n" ); } done_testing(); __END__ $ perl compare-templates.pl Deleting key "entities": 0.000587 at compare-templates.pl line 38. Get all entity id from db: 0.068345 at compare-templates.pl line 38. Set all entity ids to "entities": 0.005586 at compare-templates.pl line 38. Deleting keys "entity_ID": 0.171479 at compare-templates.pl line 38. Get all entity ids from memcache: 0.043279 at compare-templates.pl line 38. getting all entities from db: 0.596708 at compare-templates.pl line 38. There are 7477 entities in the db/hash template with 2 vars - TT - one template for all: 0.633764 at compare-templates.pl line 38. template with 2 vars - XSlate - one template for all: 0.215143 at compare-templates.pl line 38. template with 3 vars - TT - one template for all: 0.656645 at compare-templates.pl line 38. template with 3 vars - XSlate - one template for all: 0.07301 at compare-templates.pl line 38. template with 4 vars - TT - one template for all: 0.850882 at compare-templates.pl line 38. template with 4 vars - XSlate - one template for all: 0.078638 at compare-templates.pl line 38. template with 4x2 vars - TT - one template for all: 1.511315 at compare-templates.pl line 38. template with 4x2 vars - XSlate - one template for all: 0.105154 at compare-templates.pl line 38. template with 2 vars - TT - one template for all: 0.525834 at compare-templates.pl line 38. template with 2 vars - XSlate - one template for all: 0.068484 at compare-templates.pl line 38. template with 3 vars - TT - one template for all: 0.683544 at compare-templates.pl line 38. template with 3 vars - XSlate - one template for all: 0.073587 at compare-templates.pl line 38. template with 4 vars - TT - one template for all: 0.851955 at compare-templates.pl line 38. template with 4 vars - XSlate - one template for all: 0.080936 at compare-templates.pl line 38. template with 4x2 vars - TT - one template for all: 1.477847 at compare-templates.pl line 38. template with 4x2 vars - XSlate - one template for all: 0.10789 at compare-templates.pl line 38. template with 2 vars - TT - one template for all: 0.560357 at compare-templates.pl line 38. template with 2 vars - XSlate - one template for all: 0.06881 at compare-templates.pl line 38. template with 3 vars - TT - one template for all: 0.681476 at compare-templates.pl line 38. template with 3 vars - XSlate - one template for all: 0.073922 at compare-templates.pl line 38. template with 4 vars - TT - one template for all: 0.852714 at compare-templates.pl line 38. template with 4 vars - XSlate - one template for all: 0.080748 at compare-templates.pl line 38. template with 4x2 vars - TT - one template for all: 1.505461 at compare-templates.pl line 38. template with 4x2 vars - XSlate - one template for all: 0.107543 at compare-templates.pl line 38.