| Filename | /usr/local/lib/perl/5.10.1/MongoDB/GridFS.pm |
| Statements | Executed 19 statements in 1.59ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 18.9ms | 156ms | MongoDB::GridFS::BEGIN@24 |
| 1 | 1 | 1 | 715µs | 1.56ms | MongoDB::GridFS::BEGIN@23 |
| 1 | 1 | 1 | 15µs | 416µs | MongoDB::GridFS::BEGIN@22 |
| 1 | 1 | 1 | 14µs | 43µs | MongoDB::GridFS::BEGIN@25 |
| 0 | 0 | 0 | 0s | 0s | MongoDB::GridFS::_build_chunks |
| 0 | 0 | 0 | 0s | 0s | MongoDB::GridFS::_build_files |
| 0 | 0 | 0 | 0s | 0s | MongoDB::GridFS::all |
| 0 | 0 | 0 | 0s | 0s | MongoDB::GridFS::delete |
| 0 | 0 | 0 | 0s | 0s | MongoDB::GridFS::drop |
| 0 | 0 | 0 | 0s | 0s | MongoDB::GridFS::find_one |
| 0 | 0 | 0 | 0s | 0s | MongoDB::GridFS::get |
| 0 | 0 | 0 | 0s | 0s | MongoDB::GridFS::insert |
| 0 | 0 | 0 | 0s | 0s | MongoDB::GridFS::put |
| 0 | 0 | 0 | 0s | 0s | MongoDB::GridFS::remove |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | # | ||||
| 2 | # Copyright 2009 10gen, Inc. | ||||
| 3 | # | ||||
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| 5 | # you may not use this file except in compliance with the License. | ||||
| 6 | # You may obtain a copy of the License at | ||||
| 7 | # | ||||
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 | ||||
| 9 | # | ||||
| 10 | # Unless required by applicable law or agreed to in writing, software | ||||
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| 13 | # See the License for the specific language governing permissions and | ||||
| 14 | # limitations under the License. | ||||
| 15 | # | ||||
| 16 | |||||
| 17 | package MongoDB::GridFS; | ||||
| 18 | 1 | 900ns | our $VERSION = '0.42'; | ||
| 19 | |||||
| 20 | # ABSTRACT: A file storage utility | ||||
| 21 | |||||
| 22 | 3 | 36µs | 2 | 817µs | # spent 416µs (15+401) within MongoDB::GridFS::BEGIN@22 which was called:
# once (15µs+401µs) by MongoDB::Database::BEGIN@23 at line 22 # spent 416µs making 1 call to MongoDB::GridFS::BEGIN@22
# spent 401µs making 1 call to Any::Moose::import |
| 23 | 3 | 159µs | 1 | 1.56ms | # spent 1.56ms (715µs+850µs) within MongoDB::GridFS::BEGIN@23 which was called:
# once (715µs+850µs) by MongoDB::Database::BEGIN@23 at line 23 # spent 1.56ms making 1 call to MongoDB::GridFS::BEGIN@23 |
| 24 | 3 | 128µs | 1 | 156ms | # spent 156ms (18.9+137) within MongoDB::GridFS::BEGIN@24 which was called:
# once (18.9ms+137ms) by MongoDB::Database::BEGIN@23 at line 24 # spent 156ms making 1 call to MongoDB::GridFS::BEGIN@24 |
| 25 | 3 | 1.24ms | 2 | 71µs | # spent 43µs (14+28) within MongoDB::GridFS::BEGIN@25 which was called:
# once (14µs+28µs) by MongoDB::Database::BEGIN@23 at line 25 # spent 43µs making 1 call to MongoDB::GridFS::BEGIN@25
# spent 28µs making 1 call to Exporter::import |
| 26 | |||||
| 27 | =head1 NAME | ||||
| 28 | |||||
| - - | |||||
| 57 | 1 | 300ns | $MongoDB::GridFS::chunk_size = 1048576; | ||
| 58 | |||||
| 59 | 1 | 4µs | 1 | 321µs | has _database => ( # spent 321µs making 1 call to Mouse::has |
| 60 | is => 'ro', | ||||
| 61 | isa => 'MongoDB::Database', | ||||
| 62 | required => 1, | ||||
| 63 | ); | ||||
| 64 | |||||
| 65 | =head2 prefix | ||||
| 66 | |||||
| - - | |||||
| 71 | 1 | 2µs | 1 | 201µs | has prefix => ( # spent 201µs making 1 call to Mouse::has |
| 72 | is => 'ro', | ||||
| 73 | isa => 'Str', | ||||
| 74 | default => 'fs' | ||||
| 75 | ); | ||||
| 76 | |||||
| 77 | =head2 files | ||||
| 78 | |||||
| - - | |||||
| 84 | 1 | 2µs | 1 | 497µs | has files => ( # spent 497µs making 1 call to Mouse::has |
| 85 | is => 'ro', | ||||
| 86 | isa => 'MongoDB::Collection', | ||||
| 87 | lazy_build => 1 | ||||
| 88 | ); | ||||
| 89 | sub _build_files { | ||||
| 90 | my $self = shift; | ||||
| 91 | my $coll = $self->_database->get_collection($self->prefix . '.files'); | ||||
| 92 | # ensure the necessary index is present (this may be first usage) | ||||
| 93 | $coll->ensure_index(Tie::IxHash->new(filename => 1), {"safe" => 1}); | ||||
| 94 | return $coll; | ||||
| 95 | } | ||||
| 96 | |||||
| 97 | =head2 chunks | ||||
| 98 | |||||
| - - | |||||
| 105 | 1 | 2µs | 1 | 270µs | has chunks => ( # spent 270µs making 1 call to Mouse::has |
| 106 | is => 'ro', | ||||
| 107 | isa => 'MongoDB::Collection', | ||||
| 108 | lazy_build => 1 | ||||
| 109 | ); | ||||
| 110 | sub _build_chunks { | ||||
| 111 | my $self = shift; | ||||
| 112 | my $coll = $self->_database->get_collection($self->prefix . '.chunks'); | ||||
| 113 | # ensure the necessary index is present (this may be first usage) | ||||
| 114 | $coll->ensure_index(Tie::IxHash->new(files_id => 1, n => 1), {"safe" => 1}); | ||||
| 115 | return $coll; | ||||
| 116 | } | ||||
| 117 | |||||
| 118 | =head1 METHODS | ||||
| 119 | |||||
| - - | |||||
| 128 | sub get { | ||||
| 129 | my ($self, $id) = @_; | ||||
| 130 | |||||
| 131 | return $self->find_one({_id => $id}); | ||||
| 132 | } | ||||
| 133 | |||||
| 134 | =head2 put($fh, $metadata) | ||||
| 135 | |||||
| - - | |||||
| 146 | sub put { | ||||
| 147 | my ($self, $fh, $metadata) = @_; | ||||
| 148 | |||||
| 149 | return $self->insert($fh, $metadata, {safe => 1}); | ||||
| 150 | } | ||||
| 151 | |||||
| 152 | =head2 delete($id) | ||||
| 153 | |||||
| - - | |||||
| 161 | sub delete { | ||||
| 162 | my ($self, $id) = @_; | ||||
| 163 | |||||
| 164 | $self->remove({_id => $id}, {safe => 1}); | ||||
| 165 | } | ||||
| 166 | |||||
| 167 | =head2 find_one ($criteria?, $fields?) | ||||
| 168 | |||||
| - - | |||||
| 175 | sub find_one { | ||||
| 176 | my ($self, $criteria, $fields) = @_; | ||||
| 177 | |||||
| 178 | my $file = $self->files->find_one($criteria, $fields); | ||||
| 179 | return undef unless $file; | ||||
| 180 | return MongoDB::GridFS::File->new({_grid => $self,info => $file}); | ||||
| 181 | } | ||||
| 182 | |||||
| 183 | =head2 remove ($criteria?, $options?) | ||||
| 184 | |||||
| - - | |||||
| 204 | sub remove { | ||||
| 205 | my ($self, $criteria, $options) = @_; | ||||
| 206 | |||||
| 207 | my $just_one = 0; | ||||
| 208 | my $safe = 0; | ||||
| 209 | |||||
| 210 | if (defined $options) { | ||||
| 211 | if (ref $options eq 'HASH') { | ||||
| 212 | $just_one = $options->{just_one} && 1; | ||||
| 213 | $safe = $options->{safe} && 1; | ||||
| 214 | } | ||||
| 215 | elsif ($options) { | ||||
| 216 | $just_one = $options && 1; | ||||
| 217 | } | ||||
| 218 | } | ||||
| 219 | |||||
| 220 | if ($just_one) { | ||||
| 221 | my $meta = $self->files->find_one($criteria); | ||||
| 222 | $self->chunks->remove({"files_id" => $meta->{'_id'}}, {safe => $safe}); | ||||
| 223 | $self->files->remove({"_id" => $meta->{'_id'}}, {safe => $safe}); | ||||
| 224 | } | ||||
| 225 | else { | ||||
| 226 | my $cursor = $self->files->query($criteria); | ||||
| 227 | while (my $meta = $cursor->next) { | ||||
| 228 | $self->chunks->remove({"files_id" => $meta->{'_id'}}, {safe => $safe}); | ||||
| 229 | } | ||||
| 230 | $self->files->remove($criteria, {safe => $safe}); | ||||
| 231 | } | ||||
| 232 | } | ||||
| 233 | |||||
| 234 | |||||
| 235 | =head2 insert ($fh, $metadata?, $options?) | ||||
| 236 | |||||
| - - | |||||
| 263 | sub insert { | ||||
| 264 | my ($self, $fh, $metadata, $options) = @_; | ||||
| 265 | $options ||= {}; | ||||
| 266 | |||||
| 267 | confess "not a file handle" unless $fh; | ||||
| 268 | $metadata = {} unless $metadata && ref $metadata eq 'HASH'; | ||||
| 269 | |||||
| 270 | $self->chunks->ensure_index(Tie::IxHash->new(files_id => 1, n => 1), | ||||
| 271 | {"safe" => 1}); | ||||
| 272 | |||||
| 273 | my $start_pos = $fh->getpos(); | ||||
| 274 | |||||
| 275 | my $id; | ||||
| 276 | if (exists $metadata->{"_id"}) { | ||||
| 277 | $id = $metadata->{"_id"}; | ||||
| 278 | } | ||||
| 279 | else { | ||||
| 280 | $id = MongoDB::OID->new; | ||||
| 281 | } | ||||
| 282 | |||||
| 283 | my $n = 0; | ||||
| 284 | my $length = 0; | ||||
| 285 | while ((my $len = $fh->read(my $data, $MongoDB::GridFS::chunk_size)) != 0) { | ||||
| 286 | $self->chunks->insert({"files_id" => $id, | ||||
| 287 | "n" => $n, | ||||
| 288 | "data" => bless(\$data)}, $options); | ||||
| 289 | $n++; | ||||
| 290 | $length += $len; | ||||
| 291 | } | ||||
| 292 | $fh->setpos($start_pos); | ||||
| 293 | |||||
| 294 | # get an md5 hash for the file | ||||
| 295 | my $result = $self->_database->run_command({"filemd5", $id, | ||||
| 296 | "root" => $self->prefix}); | ||||
| 297 | |||||
| 298 | # compare the md5 hashes | ||||
| 299 | if ($options->{safe}) { | ||||
| 300 | my $md5 = Digest::MD5->new; | ||||
| 301 | $md5->addfile($fh); | ||||
| 302 | my $digest = $md5->hexdigest; | ||||
| 303 | if ($digest ne $result->{md5}) { | ||||
| 304 | # cleanup and die | ||||
| 305 | $self->chunks->remove({files_id => $id}); | ||||
| 306 | die "md5 hashes don't match: database got $result->{md5}, fs got $digest"; | ||||
| 307 | } | ||||
| 308 | } | ||||
| 309 | |||||
| 310 | my %copy = %{$metadata}; | ||||
| 311 | $copy{"_id"} = $id; | ||||
| 312 | $copy{"md5"} = $result->{"md5"}; | ||||
| 313 | $copy{"chunkSize"} = $MongoDB::GridFS::chunk_size; | ||||
| 314 | $copy{"uploadDate"} = DateTime->now; | ||||
| 315 | $copy{"length"} = $length; | ||||
| 316 | return $self->files->insert(\%copy, $options); | ||||
| 317 | } | ||||
| 318 | |||||
| 319 | =head2 drop | ||||
| 320 | |||||
| - - | |||||
| 327 | sub drop { | ||||
| 328 | my ($self) = @_; | ||||
| 329 | |||||
| 330 | $self->files->drop; | ||||
| 331 | $self->chunks->drop; | ||||
| 332 | } | ||||
| 333 | |||||
| 334 | =head2 all | ||||
| 335 | |||||
| - - | |||||
| 342 | sub all { | ||||
| 343 | my ($self) = @_; | ||||
| 344 | my @ret; | ||||
| 345 | |||||
| 346 | my $cursor = $self->files->query; | ||||
| 347 | while (my $meta = $cursor->next) { | ||||
| 348 | push @ret, MongoDB::GridFS::File->new( | ||||
| 349 | _grid => $self, | ||||
| 350 | info => $meta); | ||||
| 351 | } | ||||
| 352 | return @ret; | ||||
| 353 | } | ||||
| 354 | |||||
| 355 | 1 | 17µs | 1; | ||
| 356 | |||||
| 357 | =head1 AUTHOR |