Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Caching the local timezone #19

Open
wants to merge 2 commits into from

1 participant

@Gimpson

I was profiling our application that's using DynamoDB, and the creation of the DateTime::TimeZone objects in _init_security_token turns out to be very expensive. This change would potentially cause problems on systems where the local timezone changes, so definitely let me know if you have any concerns.

This is a pretty major performance improvement in my application, so if you're hesitant to potentially break people on systems with changing local timezones, maybe I could make this a configuration option instead of caching by default?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 28, 2013
  1. @Gimpson
  2. @Gimpson

    Cache the local timezone.

    Gimpson authored
This page is out of date. Refresh to see the latest.
Showing with 134 additions and 2 deletions.
  1. +8 −2 lib/Net/Amazon/DynamoDB.pm
  2. +126 −0 t/02-security-token.t
View
10 lib/Net/Amazon/DynamoDB.pm
@@ -346,6 +346,12 @@ has _credentials => ( isa => 'HashRef[Str]', is => 'rw', predicate => '_has_cred
has _credentials_expire => ( isa => 'DateTime', is => 'rw' );
+has _local_timezone => (
+ is => 'ro',
+ isa => 'DateTime::TimeZone',
+ default => sub { DateTime::TimeZone->new(name => 'local') },
+);
+
#
# _error
# Contains credentials received by GetSession
@@ -2193,7 +2199,7 @@ sub _init_security_token {
# wheter has valid credentials
if ( $self->_has_credentials() ) {
- my $dt = DateTime->now( time_zone => 'local' )->add( seconds => 5 );
+ my $dt = DateTime->now( time_zone => $self->_local_timezone )->add( seconds => 5 );
return 1 if $dt < $self->_credentials_expire;
}
@@ -2230,7 +2236,7 @@ sub _init_security_token {
time_zone => 'UTC'
);
my $expire = $pattern->parse_datetime( $cred_ref->{ Expiration } );
- $expire->set_time_zone( 'local' );
+ $expire->set_time_zone( $self->_local_timezone );
$self->_credentials_expire( $expire );
# set credentials
View
126 t/02-security-token.t
@@ -0,0 +1,126 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Test::More tests => 9;
+
+use Net::Amazon::DynamoDB;
+
+use Test::MockObject;
+use Test::LWP::UserAgent;
+use HTTP::Response;
+
+my $signer = Test::MockObject->new();
+$signer->set_isa('Net::Amazon::AWSSign');
+$signer->mock('addRESTSecret',sub{
+ return 'http://example.com';
+});
+
+# A DDB that doesn't yet have a security token.
+{
+ my $ua = get_mock_ua();
+
+ my $ddb = Net::Amazon::DynamoDB->new(
+ access_key => 'abcdefghijklmnopqrstuvwxyz',
+ secret_key => 'zyxwvutsrqponmlkjihgfedcba',
+ tables => {},
+ _aws_signer => $signer,
+ lwp => $ua,
+ );
+
+ $ddb->_init_security_token;
+ my $expiration = $ddb->_credentials_expire;
+
+ isa_ok($expiration,'DateTime');
+ cmp_ok($expiration,'>',DateTime->now,'Token is not expired yet');
+
+ my $last_request = $ua->last_http_request_sent;
+
+ ok($last_request,'A token request was made');
+}
+
+# Now do a test with expired credentials.
+{
+ my $ua = get_mock_ua();
+
+ my $ddb = Net::Amazon::DynamoDB->new(
+ access_key => 'abcdefghijklmnopqrstuvwxyz',
+ secret_key => 'zyxwvutsrqponmlkjihgfedcba',
+ tables => {},
+ _aws_signer => $signer,
+ lwp => $ua,
+ );
+
+ my $one_minute_ago = DateTime->now->subtract( minutes => 1 );
+ $ddb->_credentials_expire( $one_minute_ago );
+
+ $ddb->_init_security_token;
+
+ my $expiration = $ddb->_credentials_expire;
+
+ isa_ok($expiration,'DateTime');
+ cmp_ok($expiration,'>',DateTime->now,'Token is not expired yet');
+
+ my $last_request = $ua->last_http_request_sent;
+
+ ok($last_request,'A token request was made');
+}
+
+# Now do a test with still valid credentials.
+{
+ my $ua = get_mock_ua();
+
+ my $ddb = Net::Amazon::DynamoDB->new(
+ access_key => 'abcdefghijklmnopqrstuvwxyz',
+ secret_key => 'zyxwvutsrqponmlkjihgfedcba',
+ tables => {},
+ _aws_signer => $signer,
+ lwp => $ua,
+ );
+
+ my $plus_one_hour = DateTime->now->add( hours => 1 );
+ $ddb->_credentials_expire( $plus_one_hour );
+ $ddb->_credentials({ these => "aren't", real => "credentials" });
+
+ $ddb->_init_security_token;
+
+ my $expiration = $ddb->_credentials_expire;
+
+ isa_ok($expiration,'DateTime');
+ cmp_ok($expiration,'>',DateTime->now,'Token is not expired yet');
+
+ my $last_request = $ua->last_http_request_sent;
+
+ ok(! defined($last_request),'A token request was NOT made');
+}
+
+sub get_mock_ua {
+ my $token_expiration = shift || DateTime->now->add( hours => 1 );
+ my $ua = Test::LWP::UserAgent->new;
+
+ my $exp_iso8601 = $token_expiration->iso8601;
+ my $token_response = <<EOF;
+ <GetSessionTokenResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
+ <GetSessionTokenResult>
+ <Credentials>
+ <SessionToken>AQoDY8d5ECYa0AH820eMIj5H8bfCf5zRG4VF4heIxuHeuzBWcHftN9Cqf+6tcAK8vGLB76ja0Wq9iM9GIKE7Y9f8anynRG4KlsjpOzbL5UNIj6fgHsdbJFBmyu9eby4lSTLWOstgcTQZt3gwYa7nI7lU7JyoQx+3J7rlQJKyZMs7zSQ4vxe7eXYJO7tC2WbY70guBzTU57pzNP2T7QpZ9S3h75rGzW6E7rJxeIaIuAu7hTfWoyTlyA2pkD007dAHN2ntDjU7HQNudzTUZCotRsh45vcqf0E+JOahIKrf8osF</SessionToken>
+ <SecretAccessKey>b7yo7Mv7WIVJ7l1ftp7NLH7F0ga7GHmnKeaL30WZ</SecretAccessKey>
+ <Expiration>$exp_iso8601</Expiration>
+ <AccessKeyId>XXXXXXXXXXXXXXXXXXXX</AccessKeyId>
+ </Credentials>
+ </GetSessionTokenResult>
+ <ResponseMetadata>
+ <RequestId>2e08a198-afc2-dead-beef-978228beea7d</RequestId>
+ </ResponseMetadata>
+ </GetSessionTokenResponse>
+EOF
+
+ $ua->map_response(
+ qr{example.com},
+ HTTP::Response->new(
+ 200, 'OK', [ 'Content-Type' => 'application/xml' ],
+ $token_response
+ ));
+
+ return $ua;
+}
Something went wrong with that request. Please try again.