← Index
NYTProf Performance Profile   « block view • line view • sub view »
For 05.Domain_and_Item.t
  Run on Tue May 4 17:21:41 2010
Reported on Tue May 4 17:22:58 2010

File /usr/local/lib/perl5/site_perl/5.10.1/SimpleDB/Client.pm
Statements Executed 1850
Statement Execution Time 9.04ms
Subroutines — ordered by exclusive time
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
41114.85ms33.1msSimpleDB::Client::::construct_requestSimpleDB::Client::construct_request
1114.08ms21.9msSimpleDB::Client::::BEGIN@54SimpleDB::Client::BEGIN@54
1113.91ms4.55msSimpleDB::Client::::BEGIN@53SimpleDB::Client::BEGIN@53
1111.81ms2.93msSimpleDB::Client::::BEGIN@52SimpleDB::Client::BEGIN@52
411241.61ms15.6sSimpleDB::Client::::send_requestSimpleDB::Client::send_request
4111828µs6.17msSimpleDB::Client::::handle_responseSimpleDB::Client::handle_response
111512µs1.25msSimpleDB::Client::::BEGIN@56SimpleDB::Client::BEGIN@56
4112204µs204µsSimpleDB::Client::::CORE:sortSimpleDB::Client::CORE:sort (opcode)
111189µs878µsSimpleDB::Client::::BEGIN@58SimpleDB::Client::BEGIN@58
4111178µs178µsSimpleDB::Client::::__ANON__[:165]SimpleDB::Client::__ANON__[:165]
11119µs2.83msSimpleDB::Client::::BEGIN@51SimpleDB::Client::BEGIN@51
11112µs58µsSimpleDB::Client::::BEGIN@57SimpleDB::Client::BEGIN@57
11111µs2.89msSimpleDB::Client::::__ANON__[:138]SimpleDB::Client::__ANON__[:138]
11111µs130µsSimpleDB::Client::::BEGIN@339SimpleDB::Client::BEGIN@339
1118µs8µsSimpleDB::Client::::BEGIN@55SimpleDB::Client::BEGIN@55
1117µs5.40msSimpleDB::Client::::__ANON__[:125]SimpleDB::Client::__ANON__[:125]
1117µs7µsSimpleDB::Client::::BEGIN@59SimpleDB::Client::BEGIN@59
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package SimpleDB::Client;
21900nsour $VERSION = '1.0401';
3
4=head1 NAME
5
6SimpleDB::Client - The network interface to the SimpleDB service.
7
8=head1 VERSION
9
10version 1.0401
11
12=head1 SYNOPSIS
13
14 use SimpleDB::Client;
15
16 my $sdb = SimpleDB::Client->new(secret_key=>'abc', access_key=>'123');
17
18 # create a domain
19 my $hashref = $sdb->send_request('CreateDomain', {DomainName => 'my_things'});
20
21 # insert attributes
22 my $hashref = $sdb->send_request('PutAttributes', {
23 DomainName => 'my_things',
24 ItemName => 'car',
25 'Attribute.1.Name' => 'color',
26 'Attribute.1.Value' => 'red',
27 'Attribute.1.Replace' => 'true',
28 });
29
30 # get attributes
31 my $hashref = $sdb->send_request('GetAttributes', {
32 DomainName => 'my_things',
33 ItemName => 'car',
34 });
35
36 # search attributes
37 my $hashref = $sdb->send_request('Select', {
38 SelectExpression => q{select * from my_things where color = 'red'},
39 });
40
41=head1 DESCRIPTION
42
43This class will let you quickly and easily inteface with AWS SimpleDB. It throws exceptions from L<SimpleDB::Client::Exception>. It's very light weight. Although we haven't run any benchmarks on the other modules, it should outperform any of the other Perl modules that exist today.
44
45=head1 METHODS
46
47The following methods are available from this class.
48
49=cut
50
51338µs25.64ms
# spent 2.83ms (19µs+2.81) within SimpleDB::Client::BEGIN@51 which was called # once (19µs+2.81ms) by SimpleDB::Class::BEGIN@140 at line 51
use Moose;
# spent 2.83ms making 1 call to SimpleDB::Client::BEGIN@51 # spent 2.81ms making 1 call to Moose::Exporter::__ANON__[Moose/Exporter.pm:389]
523131µs23.04ms
# spent 2.93ms (1.81+1.13) within SimpleDB::Client::BEGIN@52 which was called # once (1.81ms+1.13ms) by SimpleDB::Class::BEGIN@140 at line 52
use Digest::SHA qw(hmac_sha256_base64);
# spent 2.93ms making 1 call to SimpleDB::Client::BEGIN@52 # spent 104µs making 1 call to Exporter::import
533148µs24.58ms
# spent 4.55ms (3.91+647µs) within SimpleDB::Client::BEGIN@53 which was called # once (3.91ms+647µs) by SimpleDB::Class::BEGIN@140 at line 53
use XML::Bare;
# spent 4.55ms making 1 call to SimpleDB::Client::BEGIN@53 # spent 22µs making 1 call to Exporter::import
543119µs121.9ms
# spent 21.9ms (4.08+17.8) within SimpleDB::Client::BEGIN@54 which was called # once (4.08ms+17.8ms) by SimpleDB::Class::BEGIN@140 at line 54
use LWP::UserAgent;
# spent 21.9ms making 1 call to SimpleDB::Client::BEGIN@54
55324µs18µs
# spent 8µs within SimpleDB::Client::BEGIN@55 which was called # once (8µs+0s) by SimpleDB::Class::BEGIN@140 at line 55
use HTTP::Request;
# spent 8µs making 1 call to SimpleDB::Client::BEGIN@55
56399µs21.51ms
# spent 1.25ms (512µs+740µs) within SimpleDB::Client::BEGIN@56 which was called # once (512µs+740µs) by SimpleDB::Class::BEGIN@140 at line 56
use Time::HiRes qw(usleep);
# spent 1.25ms making 1 call to SimpleDB::Client::BEGIN@56 # spent 258µs making 1 call to Time::HiRes::import
57327µs2104µs
# spent 58µs (12+46) within SimpleDB::Client::BEGIN@57 which was called # once (12µs+46µs) by SimpleDB::Class::BEGIN@140 at line 57
use URI::Escape qw(uri_escape_utf8);
# spent 58µs making 1 call to SimpleDB::Client::BEGIN@57 # spent 46µs making 1 call to Exporter::import
583137µs1878µs
# spent 878µs (189+689) within SimpleDB::Client::BEGIN@58 which was called # once (189µs+689µs) by SimpleDB::Class::BEGIN@140 at line 58
use SimpleDB::Client::Exception;
# spent 878µs making 1 call to SimpleDB::Client::BEGIN@58
593535µs17µs
# spent 7µs within SimpleDB::Client::BEGIN@59 which was called # once (7µs+0s) by SimpleDB::Class::BEGIN@140 at line 59
use URI;
# spent 7µs making 1 call to SimpleDB::Client::BEGIN@59
60
61#--------------------------------------------------------
62
63=head2 new ( params )
64
65=head3 params
66
67A hash containing the parameters to pass in to this method.
68
69=head4 access_key
70
71The access key given to you from Amazon when you sign up for the SimpleDB service at this URL: L<http://aws.amazon.com/simpledb/>
72
73=head4 secret_key
74
75The secret access key given to you from Amazon.
76
77=head4 simpledb_uri
78
79The constructor that SimpleDB::Client will connect to. Defaults to:
80
81 URI->new('https://sdb.amazonaws.com/')
82
83=cut
84
85#--------------------------------------------------------
86
87=head2 access_key ( )
88
89Returns the access key passed to the constructor.
90
91=cut
92
9312µs11.64mshas 'access_key' => (
# spent 1.64ms making 1 call to Moose::has
94 is => 'ro',
95 required => 1,
96 documentation => 'The AWS SimpleDB access key id provided by Amazon.',
97);
98
99#--------------------------------------------------------
100
101=head2 secret_key ( )
102
103Returns the secret key passed to the constructor.
104
105=cut
106
10712µs1880µshas 'secret_key' => (
# spent 880µs making 1 call to Moose::has
108 is => 'ro',
109 required => 1,
110 documentation => 'The AWS SimpleDB secret access key id provided by Amazon.',
111);
112
113#--------------------------------------------------------
114
115=head2 simpledb_uri ( )
116
117Returns the L<URI> object passed into the constructor that SimpleDB::Client will connect to. Defaults to:
118
119 URI->new('https://sdb.amazonaws.com/')
120
121=cut
122
123has simpledb_uri => (
124 is => 'ro',
12517µs15.39ms
# spent 5.40ms (7µs+5.39) within SimpleDB::Client::__ANON__[/usr/local/lib/perl5/site_perl/5.10.1/SimpleDB/Client.pm:125] which was called # once (7µs+5.39ms) by Class::MOP::Mixin::AttributeCore::default at line 53 of Class/MOP/Mixin/AttributeCore.pm
default => sub { URI->new('http://sdb.amazonaws.com/') },
# spent 5.39ms making 1 call to URI::new
12613µs1876µs);
# spent 876µs making 1 call to Moose::has
127
128#--------------------------------------------------------
129
130=head2 user_agent ( )
131
132Returns the L<LWP::UserAgent> object that is used to connect to SimpleDB. It's cached here so it doesn't have to be created each time.
133
134=cut
135
136has user_agent => (
137 is => 'ro',
138112µs12.88ms
# spent 2.89ms (11µs+2.88) within SimpleDB::Client::__ANON__[/usr/local/lib/perl5/site_perl/5.10.1/SimpleDB/Client.pm:138] which was called # once (11µs+2.88ms) by Class::MOP::Mixin::AttributeCore::default at line 53 of Class/MOP/Mixin/AttributeCore.pm
default => sub { LWP::UserAgent->new(timeout=>30, keep_alive=>1); },
# spent 2.88ms making 1 call to LWP::UserAgent::new
13913µs1855µs);
# spent 855µs making 1 call to Moose::has
140
141#--------------------------------------------------------
142
143=head2 construct_request ( action, [ params ] )
144
145Returns a string that contains the HTTP post data ready to make a request to SimpleDB. Normally this is only called by send_request(), but if you want to debug a SimpleDB interaction, then having access to this method is critical.
146
147=head3 action
148
149The action to perform on SimpleDB. See the "Operations" section of the guide located at L<http://docs.amazonwebservices.com/AmazonSimpleDB/2009-04-15/DeveloperGuide/>.
150
151=head3 params
152
153Any extra prameters required by the operation. The normal parameters of Action, AWSAccessKeyId, Version, Timestamp, SignatureMethod, SignatureVersion, and Signature are all automatically provided by this method.
154
155=cut
156
157
# spent 33.1ms (4.85+28.3) within SimpleDB::Client::construct_request which was called 41 times, avg 808µs/call: # 41 times (4.85ms+28.3ms) by SimpleDB::Client::send_request at line 208, avg 808µs/call
sub construct_request {
1584153µs my ($self, $action, $params) = @_;
1594128µs my $encoding_pattern = "^A-Za-z0-9\-_.~";
160
161 # add required parameters
1624171µs $params->{'Action'} = $action;
16341193µs41180µs $params->{'AWSAccessKeyId'} = $self->access_key;
# spent 180µs making 41 calls to SimpleDB::Client::access_key, avg 4µs/call
1644155µs $params->{'Version'} = '2009-04-15';
16582851µs41178µs
# spent 178µs within SimpleDB::Client::__ANON__[/usr/local/lib/perl5/site_perl/5.10.1/SimpleDB/Client.pm:165] which was called 41 times, avg 4µs/call: # 41 times (178µs+0s) by SimpleDB::Client::construct_request at line 165, avg 4µs/call
$params->{'Timestamp'} = sprintf("%04d-%02d-%02dT%02d:%02d:%02d.000Z", sub { ($_[5]+1900, $_[4]+1, $_[3], $_[2], $_[1], $_[0]) }->(gmtime(time)));
# spent 178µs making 41 calls to SimpleDB::Client::__ANON__[SimpleDB/Client.pm:165], avg 4µs/call
1664146µs $params->{'SignatureMethod'} = 'HmacSHA256';
1674141µs $params->{'SignatureVersion'} = 2;
168
169 # construct post data
1704111µs my $post_data;
17141493µs41204µs foreach my $name (sort {$a cmp $b} keys %{$params}) {
# spent 204µs making 41 calls to SimpleDB::Client::CORE:sort, avg 5µs/call
1725411.12ms54112.8ms $post_data .= $name . '=' . uri_escape_utf8($params->{$name}, $encoding_pattern) . '&';
# spent 12.8ms making 541 calls to URI::Escape::uri_escape_utf8, avg 24µs/call
173 }
1744145µs chop $post_data;
175
176 # sign the post data
17741302µs821.48ms my $signature = "POST\n".$self->simpledb_uri->host."\n/\n". $post_data;
# spent 1.31ms making 41 calls to URI::_server::host, avg 32µs/call # spent 167µs making 41 calls to SimpleDB::Client::simpledb_uri, avg 4µs/call
178411.08ms82957µs $signature = hmac_sha256_base64($signature, $self->secret_key) . '=';
# spent 773µs making 41 calls to Digest::SHA::hmac_sha256_base64, avg 19µs/call # spent 184µs making 41 calls to SimpleDB::Client::secret_key, avg 4µs/call
1794185µs411.27ms $post_data .= '&Signature=' . uri_escape_utf8($signature, $encoding_pattern);
# spent 1.27ms making 41 calls to URI::Escape::uri_escape_utf8, avg 31µs/call
180
18141363µs1239.59ms my $request = HTTP::Request->new('POST', $self->simpledb_uri->as_string);
# spent 9.36ms making 41 calls to HTTP::Request::new, avg 228µs/call # spent 160µs making 41 calls to URI::as_string, avg 4µs/call # spent 71µs making 41 calls to SimpleDB::Client::simpledb_uri, avg 2µs/call
18241118µs41668µs $request->content_type("application/x-www-form-urlencoded; charset=utf-8");
# spent 654µs making 40 calls to HTTP::Message::__ANON__[HTTP/Message.pm:622], avg 16µs/call # spent 14µs making 1 call to HTTP::Message::AUTOLOAD
1834183µs41913µs $request->content($post_data);
# spent 913µs making 41 calls to HTTP::Message::content, avg 22µs/call
184
18541152µs return $request;
186}
187
188#--------------------------------------------------------
189
190=head2 send_request ( action, [ params ] )
191
192Creates a request, and then sends it to SimpleDB. The response is returned as a hash reference of the raw XML document returned by SimpleDB. Automatically attempts 5 cascading retries on connection failure.
193
194Throws SimpleDB::Client::Exception::Response and SimpleDB::Client::Exception::Connection.
195
196=head3 action
197
198See create_request() for details.
199
200=head3 params
201
202See create_request() for details.
203
204=cut
205
206
# spent 15.6s (1.61ms+15.6) within SimpleDB::Client::send_request which was called 41 times, avg 379ms/call: # 12 times (447µs+4.15s) by SimpleDB::Class::Item::put at line 498 of ../lib/SimpleDB/Class/Item.pm, avg 346ms/call # 10 times (352µs+843ms) by SimpleDB::Class::ResultSet::fetch_result at line 250 of ../lib/SimpleDB/Class/ResultSet.pm, avg 84.3ms/call # 3 times (119µs+5.58s) by SimpleDB::Class::Domain::delete at line 118 of ../lib/SimpleDB/Class/Domain.pm, avg 1.86s/call # 3 times (221µs+4.04s) by SimpleDB::Class::Domain::create at line 102 of ../lib/SimpleDB/Class/Domain.pm, avg 1.35s/call # 2 times (85µs+202ms) by SimpleDB::Class::Domain::find at line 166 of ../lib/SimpleDB/Class/Domain.pm, avg 101ms/call # 2 times (70µs+144ms) by SimpleDB::Class::list_domains at line 374 of ../lib/SimpleDB/Class.pm, avg 72.2ms/call # 2 times (69µs+144ms) by SimpleDB::Class::Domain::max at line 355 of ../lib/SimpleDB/Class/Domain.pm, avg 72.2ms/call # 2 times (71µs+140ms) by SimpleDB::Class::Domain::count at line 262 of ../lib/SimpleDB/Class/Domain.pm, avg 69.8ms/call # 2 times (68µs+127ms) by SimpleDB::Class::Domain::min at line 406 of ../lib/SimpleDB/Class/Domain.pm, avg 63.6ms/call # once (39µs+80.8ms) by SimpleDB::Class::ResultSet::paginate at line 409 of ../lib/SimpleDB/Class/ResultSet.pm # once (31µs+53.4ms) by SimpleDB::Class::ResultSet::count at line 292 of ../lib/SimpleDB/Class/ResultSet.pm # once (38µs+52.5ms) by SimpleDB::Class::Domain::fetch_ids at line 300 of ../lib/SimpleDB/Class/Domain.pm
sub send_request {
2074164µs my ($self, $action, $params) = @_;
20841121µs4133.1ms my $request = $self->construct_request($action, $params);
# spent 33.1ms making 41 calls to SimpleDB::Client::construct_request, avg 808µs/call
209 # loop til we get a response or throw an exception
2104151µs foreach my $retry (1..5) {
211
212 # make the request
21341137µs41167µs my $ua = $self->user_agent;
# spent 167µs making 41 calls to SimpleDB::Client::user_agent, avg 4µs/call
21441136µs4115.5s my $response = $ua->request($request);
# spent 15.5s making 41 calls to LWP::UserAgent::request, avg 378ms/call
215
216 # got a possibly recoverable error, let's retry
21741119µs41250µs if ($response->code >= 500 && $response->code < 600) {
# spent 250µs making 41 calls to HTTP::Response::code, avg 6µs/call
218 if ($retry < 5) {
219 usleep((4 ** $retry) * 100_000);
220 }
221 else {
222 warn $response->header('Reason');
223 SimpleDB::Client::Exception::Connection->throw(error=>'Exceeded maximum retries.', status_code=>$response->code);
224 }
225 }
226
227 # not a retry
228 else {
22941933µs416.17ms return $self->handle_response($response);
# spent 6.17ms making 41 calls to SimpleDB::Client::handle_response, avg 151µs/call
230 }
231 }
232}
233
234#--------------------------------------------------------
235
236=head2 handle_response ( response )
237
238Returns a hashref containing the response from SimpleDB.
239
240Throws SimpleDB::Client::Exception::Response.
241
242=head3 response
243
244The L<HTTP::Response> object created by the C<send_request> method.
245
246=cut
247
248
# spent 6.17ms (828µs+5.35) within SimpleDB::Client::handle_response which was called 41 times, avg 151µs/call: # 41 times (828µs+5.35ms) by SimpleDB::Client::send_request at line 229, avg 151µs/call
sub handle_response {
2494143µs my ($self, $response) = @_;
25082509µs1235.08ms my $content = eval {XML::Bare::xmlin($response->content)};
# spent 4.58ms making 41 calls to XML::Bare::xmlin, avg 112µs/call # spent 334µs making 41 calls to HTTP::Message::content, avg 8µs/call # spent 161µs making 41 calls to XML::Bare::DESTROY, avg 4µs/call
25141100µs if (exists $content->{SelectResult}{Item} && ref $content->{SelectResult}{Item} ne 'ARRAY') { # force an item list into an array
252 $content->{SelectResult}{Item} = [ $content->{SelectResult}{Item} ];
253 }
254
255 # choked reconstituing the XML, probably because it wasn't XML
25641274µs41431µs if ($@) {
# spent 431µs making 41 calls to HTTP::Response::is_success, avg 11µs/call
257 SimpleDB::Client::Exception::Response->throw(
258 error => 'Response was garbage. Confirm Net::SSLeay, XML::Parser, and XML::Simple installations.',
259 status_code => $response->code,
260 response => $response,
261 );
262 }
263
264 # got a valid response
265 elsif ($response->is_success) {
266 return $content;
267 }
268
269 # SimpleDB gave us an error message
270 else {
271 SimpleDB::Client::Exception::Response->throw(
272 error => $content->{Errors}{Error}{Message},
273 status_code => $response->code,
274 error_code => $content->{Errors}{Error}{Code},
275 box_usage => $content->{Errors}{Error}{BoxUsage},
276 request_id => $content->{RequestID},
277 response => $response,
278 );
279 }
280}
281
282=head1 PREREQS
283
284This package requires the following modules:
285
286L<XML::Simple>
287L<LWP>
288L<Time::HiRes>
289L<Crypt::SSLeay>
290L<Moose>
291L<Digest::SHA>
292L<URI>
293L<Exception::Class>
294
295=head1 SUPPORT
296
297=over
298
299=item Repository
300
301L<http://github.com/rizen/SimpleDB-Client>
302
303=item Bug Reports
304
305L<http://rt.cpan.org/Public/Dist/Display.html?Name=SimpleDB-Client>
306
307=back
308
309=head1 SEE ALSO
310
311There are other packages you can use to access SimpleDB. I chose not to use them because I wanted something a bit more lightweight that I could build L<SimpleDB::Class> on top of so I could easily map objects to SimpleDB Domain Items. If you're looking for a low level SimpleDB accessor and for some reason this module doesn't cut the mustard, then you should check out these:
312
313=over
314
315=item Amazon::SimpleDB (L<http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1136>)
316
317A complete and nicely functional low level library made by Amazon itself.
318
319=item L<Amazon::SimpleDB>
320
321A low level SimpleDB accessor that's in its infancy and may be abandoned, but appears to be pretty functional, and of the same scope as Amazon's own module.
322
323=back
324
325In addition to clients, there is at least one other API compatible server out there that basically lets you host your own SimpleDB if you don't want to put it in Amazon's cloud. It's called M/DB. You can read more about it here: L<http://gradvs1.mgateway.com/main/index.html?path=mdb>. Though I haven't tested it, since it's API compatible, you should be able to use it with both this module and L<SimpleDB::Class>.
326
327=head1 AUTHOR
328
329JT Smith <jt_at_plainblack_com>
330
331I have to give credit where credit is due: SimpleDB::Client is heavily inspired by the Amazon::SimpleDB class distributed by Amazon itself (not to be confused with L<Amazon::SimpleDB> written by Timothy Appnel).
332
333=head1 LEGAL
334
335SimpleDB::Client is Copyright 2009-2010 Plain Black Corporation (L<http://www.plainblack.com/>) and is licensed under the same terms as Perl itself.
336
337=cut
338
339346µs2249µs
# spent 130µs (11+119) within SimpleDB::Client::BEGIN@339 which was called # once (11µs+119µs) by SimpleDB::Class::BEGIN@140 at line 339
no Moose;
# spent 130µs making 1 call to SimpleDB::Client::BEGIN@339 # spent 119µs making 1 call to Moose::Exporter::__ANON__[Moose/Exporter.pm:478]
340128µs22.63ms__PACKAGE__->meta->make_immutable;
# spent 2.62ms making 1 call to Class::MOP::Class::make_immutable # spent 12µs making 1 call to SimpleDB::Client::meta
# spent 204µs within SimpleDB::Client::CORE:sort which was called 41 times, avg 5µs/call: # 41 times (204µs+0s) by SimpleDB::Client::construct_request at line 171 of SimpleDB/Client.pm, avg 5µs/call
sub SimpleDB::Client::CORE:sort; # xsub