| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #!/usr/bin/perl | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | package KiokuDB::LiveObjects; | 
| 4 | 22 |  |  | 22 |  | 31902 | use Moose; | 
|  | 22 |  |  |  |  | 393482 |  | 
|  | 22 |  |  |  |  | 152 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 22 |  |  | 22 |  | 80432 | use Scalar::Util qw(weaken refaddr); | 
|  | 22 |  |  |  |  | 46 |  | 
|  | 22 |  |  |  |  | 1374 |  | 
| 7 | 22 |  |  | 22 |  | 8154 | use KiokuDB::LiveObjects::Guard; | 
|  | 22 |  |  |  |  | 476 |  | 
|  | 22 |  |  |  |  | 964 |  | 
| 8 | 22 |  |  | 22 |  | 598 | use Hash::Util::FieldHash::Compat qw(fieldhash); | 
|  | 22 |  |  |  |  | 1829 |  | 
|  | 22 |  |  |  |  | 231 |  | 
| 9 | 22 |  |  | 22 |  | 1269 | use Carp qw(croak); | 
|  | 22 |  |  |  |  | 122 |  | 
|  | 22 |  |  |  |  | 1033 |  | 
| 10 | 22 |  |  | 22 |  | 48 | BEGIN { local $@; eval 'use Devel::PartialDump qw(croak)' }; | 
|  | 22 |  |  | 22 |  | 1225 |  | 
|  | 22 |  |  |  |  | 10630 |  | 
|  | 22 |  |  |  |  | 484586 |  | 
|  | 22 |  |  |  |  | 230 |  | 
| 11 | 22 |  |  | 22 |  | 8329 | use Set::Object; | 
|  | 22 |  |  |  |  | 15221 |  | 
|  | 22 |  |  |  |  | 1028 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 | 22 |  |  | 22 |  | 7370 | use KiokuDB::LiveObjects::Scope; | 
|  | 22 |  |  |  |  | 68 |  | 
|  | 22 |  |  |  |  | 888 |  | 
| 14 | 22 |  |  | 22 |  | 10574 | use KiokuDB::LiveObjects::TXNScope; | 
|  | 22 |  |  |  |  | 64 |  | 
|  | 22 |  |  |  |  | 876 |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 | 22 |  |  | 22 |  | 165 | use Moose::Util::TypeConstraints; | 
|  | 22 |  |  |  |  | 33 |  | 
|  | 22 |  |  |  |  | 196 |  | 
| 17 |  |  |  |  |  |  |  | 
| 18 | 22 |  |  | 22 |  | 38042 | use namespace::clean -except => 'meta'; | 
|  | 22 |  |  |  |  | 43 |  | 
|  | 22 |  |  |  |  | 159 |  | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | coerce __PACKAGE__, from "HashRef", via { __PACKAGE__->new($_) }; | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | has clear_leaks => ( | 
| 23 |  |  |  |  |  |  | isa => "Bool", | 
| 24 |  |  |  |  |  |  | is  => "rw", | 
| 25 |  |  |  |  |  |  | ); | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | has cache => ( | 
| 28 |  |  |  |  |  |  | isa => "Cache::Ref", | 
| 29 |  |  |  |  |  |  | is  => "ro", | 
| 30 |  |  |  |  |  |  | ); | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | has leak_tracker => ( | 
| 33 |  |  |  |  |  |  | isa => "CodeRef|Object", | 
| 34 |  |  |  |  |  |  | is  => "rw", | 
| 35 |  |  |  |  |  |  | clearer => "clear_leak_tracker", | 
| 36 |  |  |  |  |  |  | ); | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | has keep_entries => ( | 
| 39 |  |  |  |  |  |  | isa => "Bool", | 
| 40 |  |  |  |  |  |  | is  => "ro", | 
| 41 |  |  |  |  |  |  | default => 1, | 
| 42 |  |  |  |  |  |  | ); | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | has [qw(_objects _entries _object_entries)] => ( | 
| 45 |  |  |  |  |  |  | isa => "HashRef", | 
| 46 |  |  |  |  |  |  | is  => "ro", | 
| 47 |  |  |  |  |  |  | init_arg => undef, | 
| 48 |  |  |  |  |  |  | default => sub { fieldhash my %hash }, | 
| 49 |  |  |  |  |  |  | ); | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | has _ids => ( | 
| 52 |  |  |  |  |  |  | #metaclass => 'Collection::Hash', | 
| 53 |  |  |  |  |  |  | isa => "HashRef", | 
| 54 |  |  |  |  |  |  | is  => "ro", | 
| 55 |  |  |  |  |  |  | init_arg => undef, | 
| 56 |  |  |  |  |  |  | default => sub { return {} }, | 
| 57 |  |  |  |  |  |  | ); | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | sub _id_info { | 
| 60 | 30890 |  |  | 30890 |  | 45669 | my ( $self, @ids ) = @_; | 
| 61 |  |  |  |  |  |  |  | 
| 62 | 22 |  |  | 22 |  | 12224 | no warnings 'uninitialized'; # @ids can contain undefs | 
|  | 22 |  |  |  |  | 41 |  | 
|  | 22 |  |  |  |  | 50212 |  | 
| 63 |  |  |  |  |  |  |  | 
| 64 | 30890 | 100 |  |  |  | 55609 | if ( @ids == 1 ) { | 
| 65 | 29692 |  |  |  |  | 746412 | return $self->_ids->{$ids[0]}; | 
| 66 |  |  |  |  |  |  | } else { | 
| 67 | 1198 |  |  |  |  | 1387 | return @{ $self->_ids }{@ids}; | 
|  | 1198 |  |  |  |  | 30393 |  | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  | } | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | sub _vivify_id_info { | 
| 72 | 24222 |  |  | 24222 |  | 26440 | my ( $self, $id ) = @_; | 
| 73 |  |  |  |  |  |  |  | 
| 74 | 24222 |  |  |  |  | 21697 | my $info; | 
| 75 |  |  |  |  |  |  |  | 
| 76 | 24222 |  |  |  |  | 588474 | my $i = $self->_ids; | 
| 77 |  |  |  |  |  |  |  | 
| 78 | 24222 | 100 |  |  |  | 55286 | unless ( $info = $i->{$id} ) { | 
| 79 | 8143 |  |  |  |  | 31287 | $info = { guard => KiokuDB::LiveObjects::Guard->new( $i, $id ) }; | 
| 80 | 8143 |  |  |  |  | 23853 | weaken( $i->{$id} = $info ); | 
| 81 |  |  |  |  |  |  | } | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 24222 |  |  |  |  | 33086 | return $info; | 
| 84 |  |  |  |  |  |  | } | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | sub id_to_object { | 
| 87 | 9559 |  |  | 9559 | 1 | 13418 | my ( $self, $id ) = @_; | 
| 88 |  |  |  |  |  |  |  | 
| 89 | 9559 | 100 |  |  |  | 234402 | if ( my $c = $self->cache ) { | 
| 90 | 4304 |  |  |  |  | 14113 | $c->hit($id); | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  |  | 
| 93 | 9559 | 100 |  |  |  | 304514 | if ( my $data = $self->_id_info($id) ) { | 
| 94 | 4518 |  |  |  |  | 15434 | return $data->{object}; | 
| 95 |  |  |  |  |  |  | } | 
| 96 |  |  |  |  |  |  | } | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | sub ids_to_objects { | 
| 99 | 621 |  |  | 621 | 1 | 8256 | my ( $self, @ids ) = @_; | 
| 100 |  |  |  |  |  |  |  | 
| 101 | 621 | 100 |  |  |  | 15506 | if ( my $c = $self->cache ) { | 
| 102 | 240 |  |  |  |  | 959 | $c->hit(@ids); | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 621 | 100 |  |  |  | 19106 | map { $_ && $_->{object} } $self->_id_info(@ids); | 
|  | 3596 |  |  |  |  | 12337 |  | 
| 106 |  |  |  |  |  |  | } | 
| 107 |  |  |  |  |  |  |  | 
| 108 |  |  |  |  |  |  | sub known_ids { | 
| 109 | 19 |  |  | 19 | 0 | 1565 | keys %{ shift->_ids }; | 
|  | 19 |  |  |  |  | 989 |  | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | sub live_ids { | 
| 113 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 114 |  |  |  |  |  |  |  | 
| 115 | 0 |  |  |  |  | 0 | grep { ref $self->_id_info($_)->{object} } $self->known_ids; | 
|  | 0 |  |  |  |  | 0 |  | 
| 116 |  |  |  |  |  |  | } | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | sub live_objects { | 
| 119 | 5944 |  |  | 5944 | 1 | 13527 | grep { ref } map { $_->{object} } values %{ shift->_ids }; | 
|  | 8903 |  |  |  |  | 20286 |  | 
|  | 8903 |  |  |  |  | 14985 |  | 
|  | 5944 |  |  |  |  | 150108 |  | 
| 120 |  |  |  |  |  |  | } | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | sub id_to_entry { | 
| 123 | 4901 |  |  | 4901 | 0 | 42084 | my ( $self, $id ) = @_; | 
| 124 |  |  |  |  |  |  |  | 
| 125 | 4901 | 100 |  |  |  | 14957 | if ( my $data = $self->_id_info($id) ) { | 
| 126 | 1931 |  |  |  |  | 6602 | return $data->{entry}; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  |  | 
| 129 | 2970 |  |  |  |  | 15379 | return undef; | 
| 130 |  |  |  |  |  |  | } | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | sub ids_to_entries { | 
| 133 | 965 |  |  | 965 | 1 | 8542 | my ( $self, @ids ) = @_; | 
| 134 |  |  |  |  |  |  |  | 
| 135 | 965 | 100 |  |  |  | 3471 | return $self->id_to_entry($ids[0]) if @ids == 1; | 
| 136 |  |  |  |  |  |  |  | 
| 137 | 577 | 100 |  |  |  | 1338 | map { $_ && $_->{entry} } $self->_id_info(@ids); | 
|  | 1485 |  |  |  |  | 4198 |  | 
| 138 |  |  |  |  |  |  | } | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | sub loaded_ids { | 
| 141 | 10 |  |  | 10 | 0 | 33 | my $self = shift; | 
| 142 |  |  |  |  |  |  |  | 
| 143 | 10 |  |  |  |  | 35 | grep { $self->_id_info($_)->{entry} } $self->known_ids; | 
|  | 6 |  |  |  |  | 28 |  | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | sub live_entries { | 
| 147 | 2632 |  |  | 2632 | 1 | 5128 | grep { ref } map { $_->{entry} } values %{ shift->_ids }; | 
|  | 674 |  |  |  |  | 1724 |  | 
|  | 674 |  |  |  |  | 1383 |  | 
|  | 2632 |  |  |  |  | 68209 |  | 
| 148 |  |  |  |  |  |  | } | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | has current_scope => ( | 
| 151 |  |  |  |  |  |  | isa => "KiokuDB::LiveObjects::Scope", | 
| 152 |  |  |  |  |  |  | is  => "ro", | 
| 153 |  |  |  |  |  |  | writer   => "_set_current_scope", | 
| 154 |  |  |  |  |  |  | clearer  => "_clear_current_scope", | 
| 155 |  |  |  |  |  |  | weak_ref => 1, | 
| 156 |  |  |  |  |  |  | ); | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | has _known_scopes => ( | 
| 159 |  |  |  |  |  |  | isa => "Set::Object", | 
| 160 |  |  |  |  |  |  | is  => "ro", | 
| 161 |  |  |  |  |  |  | default => sub { Set::Object::Weak->new }, | 
| 162 |  |  |  |  |  |  | ); | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | sub detach_scope { | 
| 165 | 3483 |  |  | 3483 | 1 | 4613 | my ( $self, $scope ) = @_; | 
| 166 |  |  |  |  |  |  |  | 
| 167 | 3483 |  |  |  |  | 93048 | my $current_scope = $self->current_scope; | 
| 168 | 3483 | 100 | 66 |  |  | 28241 | if ( defined($current_scope) and refaddr($current_scope) == refaddr($scope) ) { | 
| 169 | 3482 | 100 |  |  |  | 96940 | if ( my $parent = $scope->parent ) { | 
| 170 | 695 |  |  |  |  | 22698 | $self->_set_current_scope($parent); | 
| 171 |  |  |  |  |  |  | } else { | 
| 172 | 2787 |  |  |  |  | 91417 | $self->_clear_current_scope; | 
| 173 |  |  |  |  |  |  | } | 
| 174 |  |  |  |  |  |  | } | 
| 175 |  |  |  |  |  |  | } | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | sub remove_scope { | 
| 178 | 3482 |  |  | 3482 | 1 | 4662 | my ( $self, $scope ) = @_; | 
| 179 |  |  |  |  |  |  |  | 
| 180 | 3482 |  |  |  |  | 10869 | $self->detach_scope($scope); | 
| 181 |  |  |  |  |  |  |  | 
| 182 | 3482 |  |  |  |  | 122426 | $scope->clear; | 
| 183 |  |  |  |  |  |  |  | 
| 184 | 3482 |  |  |  |  | 99905 | my $known = $self->_known_scopes; | 
| 185 |  |  |  |  |  |  |  | 
| 186 | 3482 |  |  |  |  | 29638 | $known->remove($scope); | 
| 187 |  |  |  |  |  |  |  | 
| 188 | 3482 | 100 |  |  |  | 17489 | if ( $known->size == 0 ) { | 
| 189 | 2786 |  |  |  |  | 9253 | $self->check_leaks; | 
| 190 |  |  |  |  |  |  | } | 
| 191 |  |  |  |  |  |  | } | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | sub check_leaks { | 
| 194 | 2786 |  |  | 2786 | 0 | 4056 | my $self = shift; | 
| 195 |  |  |  |  |  |  |  | 
| 196 | 2786 | 50 |  |  |  | 74283 | return if $self->_known_scopes->size; | 
| 197 |  |  |  |  |  |  |  | 
| 198 | 2786 | 100 |  |  |  | 9531 | if ( my @still_live = grep { defined } $self->live_objects ) { | 
|  | 781 |  |  |  |  | 2619 |  | 
| 199 |  |  |  |  |  |  | # immortal objects are still live but not considered leaks | 
| 200 | 483 |  |  |  |  | 12664 | my $o = $self->_objects; | 
| 201 | 781 |  |  |  |  | 1736 | my @leaked = grep { | 
| 202 | 483 |  |  |  |  | 1359 | my $i = $o->{$_}; | 
| 203 | 781 |  | 100 |  |  | 4445 | not($i->{immortal} or $i->{cache}) | 
| 204 |  |  |  |  |  |  | } @still_live; | 
| 205 |  |  |  |  |  |  |  | 
| 206 | 483 | 100 |  |  |  | 13720 | if ( $self->clear_leaks ) { | 
| 207 | 2 |  |  |  |  | 11 | $self->clear; | 
| 208 |  |  |  |  |  |  | } | 
| 209 |  |  |  |  |  |  |  | 
| 210 | 483 | 100 | 100 |  |  | 13254 | if ( my $tracker = $self->leak_tracker and @leaked ) { | 
| 211 | 1 | 50 |  |  |  | 6 | if ( ref($tracker) eq 'CODE' ) { | 
| 212 | 1 |  |  |  |  | 6 | $tracker->(@leaked); | 
| 213 |  |  |  |  |  |  | } else { | 
| 214 | 0 |  |  |  |  | 0 | $tracker->leaked_objects(@leaked); | 
| 215 |  |  |  |  |  |  | } | 
| 216 |  |  |  |  |  |  | } | 
| 217 |  |  |  |  |  |  | } | 
| 218 |  |  |  |  |  |  | } | 
| 219 |  |  |  |  |  |  |  | 
| 220 |  |  |  |  |  |  | has txn_scope => ( | 
| 221 |  |  |  |  |  |  | isa => "KiokuDB::LiveObjects::TXNScope", | 
| 222 |  |  |  |  |  |  | is  => "ro", | 
| 223 |  |  |  |  |  |  | writer   => "_set_txn_scope", | 
| 224 |  |  |  |  |  |  | clearer  => "_clear_txn_scope", | 
| 225 |  |  |  |  |  |  | weak_ref => 1, | 
| 226 |  |  |  |  |  |  | ); | 
| 227 |  |  |  |  |  |  |  | 
| 228 |  |  |  |  |  |  | sub new_scope { | 
| 229 | 3482 |  |  | 3482 | 1 | 43319 | my $self = shift; | 
| 230 |  |  |  |  |  |  |  | 
| 231 | 3482 |  |  |  |  | 97411 | my $parent = $self->current_scope; | 
| 232 |  |  |  |  |  |  |  | 
| 233 | 3482 | 100 |  |  |  | 107870 | my $child = KiokuDB::LiveObjects::Scope->new( | 
| 234 |  |  |  |  |  |  | ( $parent ? ( parent => $parent ) : () ), | 
| 235 |  |  |  |  |  |  | live_objects => $self, | 
| 236 |  |  |  |  |  |  | ); | 
| 237 |  |  |  |  |  |  |  | 
| 238 | 3482 |  |  |  |  | 123973 | $self->_set_current_scope($child); | 
| 239 |  |  |  |  |  |  |  | 
| 240 | 3482 |  |  |  |  | 96809 | $self->_known_scopes->insert($child); | 
| 241 |  |  |  |  |  |  |  | 
| 242 | 3482 |  |  |  |  | 13324 | return $child; | 
| 243 |  |  |  |  |  |  | } | 
| 244 |  |  |  |  |  |  |  | 
| 245 |  |  |  |  |  |  | sub new_txn { | 
| 246 | 2183 |  |  | 2183 | 1 | 3471 | my $self = shift; | 
| 247 |  |  |  |  |  |  |  | 
| 248 | 2183 | 100 |  |  |  | 64716 | return unless $self->keep_entries; | 
| 249 |  |  |  |  |  |  |  | 
| 250 | 1143 |  |  |  |  | 29619 | my $parent = $self->txn_scope; | 
| 251 |  |  |  |  |  |  |  | 
| 252 | 1143 | 100 |  |  |  | 37213 | my $child = KiokuDB::LiveObjects::TXNScope->new( | 
| 253 |  |  |  |  |  |  | ( $parent ? ( parent => $parent ) : () ), | 
| 254 |  |  |  |  |  |  | live_objects => $self, | 
| 255 |  |  |  |  |  |  | ); | 
| 256 |  |  |  |  |  |  |  | 
| 257 | 1143 |  |  |  |  | 38985 | $self->_set_txn_scope($child); | 
| 258 |  |  |  |  |  |  |  | 
| 259 | 1143 |  |  |  |  | 2678 | return $child; | 
| 260 |  |  |  |  |  |  | } | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | sub objects_to_ids { | 
| 263 | 2185 |  |  | 2185 | 1 | 13308 | my ( $self, @objects ) = @_; | 
| 264 |  |  |  |  |  |  |  | 
| 265 | 2185 | 100 |  |  |  | 7065 | return $self->object_to_id($objects[0]) | 
| 266 |  |  |  |  |  |  | if @objects == 1; | 
| 267 |  |  |  |  |  |  |  | 
| 268 | 648 | 100 |  |  |  | 1337 | map { $_ && $_->{guard}->key } @{ $self->_objects }{@objects}; | 
|  | 1633 |  |  |  |  | 6555 |  | 
|  | 648 |  |  |  |  | 17370 |  | 
| 269 |  |  |  |  |  |  | } | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | sub object_to_id { | 
| 272 | 38142 |  |  | 38142 | 1 | 50788 | my ( $self, $obj ) = @_; | 
| 273 |  |  |  |  |  |  |  | 
| 274 | 38142 | 100 |  |  |  | 953820 | if ( my $info = $self->_objects->{$obj} ){ | 
| 275 | 8234 |  |  |  |  | 27204 | return $info->{guard}->key; | 
| 276 |  |  |  |  |  |  | } | 
| 277 |  |  |  |  |  |  |  | 
| 278 | 29908 |  |  |  |  | 84925 | return undef; | 
| 279 |  |  |  |  |  |  | } | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | sub objects_to_entries { | 
| 282 | 340 |  |  | 340 | 1 | 866 | my ( $self, @objects ) = @_; | 
| 283 |  |  |  |  |  |  |  | 
| 284 | 340 |  |  |  |  | 1009 | return $self->ids_to_entries( $self->objects_to_ids(@objects) ); | 
| 285 |  |  |  |  |  |  | } | 
| 286 |  |  |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | sub object_to_entry { | 
| 288 | 10218 |  |  | 10218 | 1 | 13918 | my ( $self, $obj ) = @_; | 
| 289 |  |  |  |  |  |  |  | 
| 290 | 10218 |  | 100 |  |  | 17925 | return $self->id_to_entry( $self->object_to_id($obj) || return ); | 
| 291 |  |  |  |  |  |  | } | 
| 292 |  |  |  |  |  |  |  | 
| 293 |  |  |  |  |  |  | sub id_in_root_set { | 
| 294 | 867 |  |  | 867 | 0 | 1286 | my ( $self, $id ) = @_; | 
| 295 |  |  |  |  |  |  |  | 
| 296 | 867 | 50 |  |  |  | 1847 | if ( my $data = $self->_id_info($id) ) { | 
| 297 | 867 |  |  |  |  | 6440 | return $data->{root}; | 
| 298 |  |  |  |  |  |  | } | 
| 299 |  |  |  |  |  |  |  | 
| 300 | 0 |  |  |  |  | 0 | return undef; | 
| 301 |  |  |  |  |  |  | } | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  | sub id_in_storage { | 
| 304 | 13883 |  |  | 13883 | 0 | 19537 | my ( $self, $id ) = @_; | 
| 305 |  |  |  |  |  |  |  | 
| 306 | 13883 | 100 |  |  |  | 27716 | if ( my $data = $self->_id_info($id) ) { | 
| 307 | 3549 |  |  |  |  | 11650 | return $data->{in_storage}; | 
| 308 |  |  |  |  |  |  | } | 
| 309 |  |  |  |  |  |  |  | 
| 310 | 10334 |  |  |  |  | 32033 | return undef; | 
| 311 |  |  |  |  |  |  | } | 
| 312 |  |  |  |  |  |  |  | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | sub object_in_storage { | 
| 315 | 1316 |  |  | 1316 | 0 | 2040 | my ( $self, $object ) = @_; | 
| 316 |  |  |  |  |  |  |  | 
| 317 | 1316 |  | 100 |  |  | 3081 | $self->id_in_storage( $self->object_to_id($object) || return ); | 
| 318 |  |  |  |  |  |  | } | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | sub update_object_entry { | 
| 321 | 1436 |  |  | 1436 | 0 | 3447 | my ( $self, $object, $entry, %args ) = @_; | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  |  | 
| 324 | 1436 | 50 |  |  |  | 38561 | my $s = $self->current_scope or croak "no open live object scope"; | 
| 325 |  |  |  |  |  |  |  | 
| 326 | 1436 | 50 |  |  |  | 34139 | my $info = $self->_objects->{$object} or croak "Object not yet registered"; | 
| 327 | 1436 |  |  |  |  | 34382 | $self->_entries->{$entry} = $info; | 
| 328 |  |  |  |  |  |  |  | 
| 329 | 1436 |  |  |  |  | 2627 | @{$info}{keys %args} = values %args; | 
|  | 1436 |  |  |  |  | 2298 |  | 
| 330 | 1436 |  |  |  |  | 3944 | weaken($info->{entry} = $entry); | 
| 331 |  |  |  |  |  |  |  | 
| 332 | 1436 | 100 |  |  |  | 36431 | if ( $self->keep_entries ) { | 
| 333 | 785 |  |  |  |  | 20489 | $self->_object_entries->{$object} = $entry; | 
| 334 |  |  |  |  |  |  |  | 
| 335 | 785 | 50 | 33 |  |  | 2572 | if ( $args{in_storage} and my $txs = $self->txn_scope ) { | 
| 336 | 0 |  |  |  |  | 0 | $txs->push($entry); | 
| 337 |  |  |  |  |  |  | } | 
| 338 |  |  |  |  |  |  | } | 
| 339 |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  | # break cycle for passthrough objects | 
| 341 | 1436 | 50 | 66 |  |  | 33185 | if ( ref($entry->data) and refaddr($object) == refaddr($entry->data) ) { | 
| 342 | 0 |  |  |  |  | 0 | weaken($entry->{data}); # FIXME there should be a MOP way to do this | 
| 343 |  |  |  |  |  |  | } | 
| 344 |  |  |  |  |  |  | } | 
| 345 |  |  |  |  |  |  |  | 
| 346 |  |  |  |  |  |  | sub register_object { | 
| 347 | 8091 |  |  | 8091 | 0 | 16440 | my ( $self, $id, $object, %args ) = @_; | 
| 348 |  |  |  |  |  |  |  | 
| 349 | 8091 | 50 |  |  |  | 216326 | my $s = $self->current_scope or croak "no open live object scope"; | 
| 350 |  |  |  |  |  |  |  | 
| 351 | 8091 | 50 |  |  |  | 18869 | croak($object, " is not a reference") unless ref($object); | 
| 352 | 8091 | 50 | 66 |  |  | 79767 | croak($object, " is an entry") if blessed($object) && $object->isa("KiokuDB::Entry"); | 
| 353 |  |  |  |  |  |  |  | 
| 354 | 8091 | 100 |  |  |  | 19055 | if ( my $id = $self->object_to_id($object) ) { | 
| 355 | 1 |  |  |  |  | 30 | croak($object, " is already registered as $id") | 
| 356 |  |  |  |  |  |  | } | 
| 357 |  |  |  |  |  |  |  | 
| 358 | 8090 |  |  |  |  | 15555 | my $info = $self->_vivify_id_info($id); | 
| 359 |  |  |  |  |  |  |  | 
| 360 | 8090 | 50 |  |  |  | 18947 | if ( ref $info->{object} ) { | 
| 361 | 0 |  |  |  |  | 0 | croak "An object with the id '$id' is already registered ($info->{object} != $object)" | 
| 362 |  |  |  |  |  |  | } | 
| 363 |  |  |  |  |  |  |  | 
| 364 | 8090 |  |  |  |  | 194751 | $self->_objects->{$object} = $info; | 
| 365 |  |  |  |  |  |  |  | 
| 366 | 8090 |  |  |  |  | 27603 | weaken($info->{object} = $object); | 
| 367 |  |  |  |  |  |  |  | 
| 368 | 8090 | 100 | 100 |  |  | 213397 | if ( $self->keep_entries and my $entry = $info->{entry} ) { | 
| 369 | 4165 |  |  |  |  | 108068 | $self->_object_entries->{$object} = $entry; | 
| 370 |  |  |  |  |  |  | } | 
| 371 |  |  |  |  |  |  |  | 
| 372 | 8090 |  |  |  |  | 15172 | @{$info}{keys %args} = values %args; | 
|  | 8090 |  |  |  |  | 11898 |  | 
| 373 |  |  |  |  |  |  |  | 
| 374 | 8090 | 100 | 100 |  |  | 24064 | if ( $args{cache} and my $c = $self->cache ) { | 
| 375 | 48 |  |  |  |  | 192 | $c->set( $id => $object ); | 
| 376 |  |  |  |  |  |  | } | 
| 377 |  |  |  |  |  |  |  | 
| 378 | 8090 |  |  |  |  | 286502 | $s->push($object); | 
| 379 |  |  |  |  |  |  | } | 
| 380 |  |  |  |  |  |  |  | 
| 381 |  |  |  |  |  |  | sub register_entry { | 
| 382 | 16132 |  |  | 16132 | 0 | 33590 | my ( $self, $id, $entry, %args ) = @_; | 
| 383 |  |  |  |  |  |  |  | 
| 384 | 16132 |  |  |  |  | 30696 | my $info = $self->_vivify_id_info($id); | 
| 385 |  |  |  |  |  |  |  | 
| 386 | 16132 |  |  |  |  | 405398 | $self->_entries->{$entry} = $info; | 
| 387 |  |  |  |  |  |  |  | 
| 388 | 16132 | 50 |  |  |  | 72784 | confess "$entry" unless $entry->isa("KiokuDB::Entry"); | 
| 389 | 16132 |  |  |  |  | 387738 | @{$info}{keys %args, 'root'} = ( values %args, $entry->root ); | 
|  | 16132 |  |  |  |  | 36872 |  | 
| 390 |  |  |  |  |  |  |  | 
| 391 | 16132 |  |  |  |  | 48430 | weaken($info->{entry} = $entry); | 
| 392 |  |  |  |  |  |  |  | 
| 393 | 16132 | 100 | 100 |  |  | 309559 | if ( $args{in_storage} and $self->keep_entries and my $txs = $self->txn_scope ) { | 
|  |  |  | 100 |  |  |  |  | 
| 394 | 4313 |  |  |  |  | 12969 | $txs->push($entry); | 
| 395 |  |  |  |  |  |  | } | 
| 396 |  |  |  |  |  |  | } | 
| 397 |  |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | sub insert { | 
| 399 | 254 |  |  | 254 | 1 | 16406 | my ( $self, @pairs ) = @_; | 
| 400 |  |  |  |  |  |  |  | 
| 401 | 254 | 50 |  |  |  | 996 | croak "The arguments must be an list of pairs of IDs/Entries to objects" | 
| 402 |  |  |  |  |  |  | unless @pairs % 2 == 0; | 
| 403 |  |  |  |  |  |  |  | 
| 404 | 254 | 50 |  |  |  | 7258 | croak "no open live object scope" unless $self->current_scope; | 
| 405 |  |  |  |  |  |  |  | 
| 406 | 254 |  |  |  |  | 420 | my @register; | 
| 407 | 254 |  |  |  |  | 648 | while ( @pairs ) { | 
| 408 | 479 |  |  |  |  | 1201 | my ( $id, $object ) = splice @pairs, 0, 2; | 
| 409 | 479 |  |  |  |  | 551 | my $entry; | 
| 410 |  |  |  |  |  |  |  | 
| 411 | 479 | 100 |  |  |  | 946 | if ( ref $id ) { | 
| 412 | 2 |  |  |  |  | 7 | $entry = $id; | 
| 413 | 2 |  |  |  |  | 84 | $id = $entry->id; | 
| 414 |  |  |  |  |  |  | } | 
| 415 |  |  |  |  |  |  |  | 
| 416 | 479 | 50 |  |  |  | 827 | confess("blah") unless $id; | 
| 417 |  |  |  |  |  |  |  | 
| 418 | 479 | 100 |  |  |  | 1264 | croak($object, " is not a reference") unless ref($object); | 
| 419 | 478 | 50 | 66 |  |  | 4594 | croak($object, " is an entry") if blessed($object) && $object->isa("KiokuDB::Entry"); | 
| 420 |  |  |  |  |  |  |  | 
| 421 | 478 | 100 |  |  |  | 1006 | if ( $entry ) { | 
| 422 | 2 |  |  |  |  | 11 | $self->register_entry( $id => $entry, in_storage => 1 ); | 
| 423 | 2 |  |  |  |  | 11 | $self->register_object( $id => $object ); | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | # break cycle for passthrough objects | 
| 426 | 2 | 50 | 33 |  |  | 47 | if ( ref($entry->data) and refaddr($object) == refaddr($entry->data) ) { | 
| 427 | 0 |  |  |  |  | 0 | weaken($entry->{data}); # FIXME there should be a MOP way to do this | 
| 428 |  |  |  |  |  |  | } | 
| 429 |  |  |  |  |  |  | } else { | 
| 430 | 476 |  |  |  |  | 1280 | $self->register_object( $id => $object ); | 
| 431 |  |  |  |  |  |  | } | 
| 432 |  |  |  |  |  |  | } | 
| 433 |  |  |  |  |  |  | } | 
| 434 |  |  |  |  |  |  |  | 
| 435 |  |  |  |  |  |  | sub update_entries { | 
| 436 | 101 |  |  | 101 | 1 | 289405 | my ( $self, @pairs ) = @_; | 
| 437 | 101 |  |  |  |  | 180 | my @entries; | 
| 438 |  |  |  |  |  |  |  | 
| 439 | 101 |  |  |  |  | 307 | while ( @pairs ) { | 
| 440 | 101 |  |  |  |  | 369 | my ( $object, $entry ) = splice @pairs, 0, 2; | 
| 441 |  |  |  |  |  |  |  | 
| 442 | 101 |  |  |  |  | 2572 | $self->register_entry( $entry->id => $entry, in_storage => 1 ); | 
| 443 |  |  |  |  |  |  |  | 
| 444 | 101 | 100 |  |  |  | 305 | unless ( $self->object_to_id($object) ) { | 
| 445 | 2 |  |  |  |  | 38 | $self->register_object( $entry->id => $object ); | 
| 446 |  |  |  |  |  |  | } else { | 
| 447 | 99 |  |  |  |  | 360 | $self->update_object_entry( $object, $entry ); | 
| 448 |  |  |  |  |  |  | } | 
| 449 |  |  |  |  |  |  | } | 
| 450 |  |  |  |  |  |  |  | 
| 451 | 101 |  |  |  |  | 627 | return; | 
| 452 |  |  |  |  |  |  | } | 
| 453 |  |  |  |  |  |  |  | 
| 454 |  |  |  |  |  |  | sub rollback_entries { | 
| 455 | 140 |  |  | 140 | 1 | 359 | my ( $self, @entries ) = @_; | 
| 456 |  |  |  |  |  |  |  | 
| 457 | 140 |  |  |  |  | 405 | foreach my $entry ( reverse @entries ) { | 
| 458 | 476 |  |  |  |  | 10383 | my $info = $self->_id_info($entry->id); | 
| 459 |  |  |  |  |  |  |  | 
| 460 | 476 | 100 |  |  |  | 10547 | if ( my $prev = $entry->prev ) { | 
| 461 | 51 |  |  |  |  | 336 | weaken($info->{entry} = $prev); | 
| 462 |  |  |  |  |  |  | } else { | 
| 463 | 425 |  |  |  |  | 972 | delete $info->{entry}; | 
| 464 |  |  |  |  |  |  | } | 
| 465 |  |  |  |  |  |  | } | 
| 466 |  |  |  |  |  |  | } | 
| 467 |  |  |  |  |  |  |  | 
| 468 |  |  |  |  |  |  | sub remove { | 
| 469 | 171 |  |  | 171 | 1 | 506 | my ( $self, @stuff ) = @_; | 
| 470 |  |  |  |  |  |  |  | 
| 471 | 171 |  |  |  |  | 4911 | my ( $i, $o, $e, $oe ) = ( $self->_ids, $self->_objects, $self->_entries, $self->_object_entries ); | 
| 472 |  |  |  |  |  |  |  | 
| 473 | 171 |  |  |  |  | 716 | while ( @stuff ) { | 
| 474 | 228 |  |  |  |  | 450 | my $thing = shift @stuff; | 
| 475 |  |  |  |  |  |  |  | 
| 476 | 228 | 100 |  |  |  | 646 | if ( ref $thing ) { | 
| 477 |  |  |  |  |  |  | # FIXME make this a bit less zealous? | 
| 478 | 126 |  |  |  |  | 145 | my $info; | 
| 479 | 126 | 100 |  |  |  | 560 | if ( $info = delete $o->{$thing} ) { | 
|  |  | 50 |  |  |  |  |  | 
| 480 | 72 |  |  |  |  | 247 | delete $info->{object}; | 
| 481 | 72 |  |  |  |  | 295 | delete $oe->{$thing}; | 
| 482 | 72 | 100 |  |  |  | 484 | push @stuff, $info->{entry} if $info->{entry}; | 
| 483 |  |  |  |  |  |  | } elsif ( $info = delete $e->{$thing} ) { | 
| 484 | 54 |  |  |  |  | 138 | delete $info->{entry}; | 
| 485 | 54 | 50 |  |  |  | 490 | push @stuff, $info->{object} if ref $info->{object}; | 
| 486 |  |  |  |  |  |  | } | 
| 487 |  |  |  |  |  |  | } else { | 
| 488 | 102 |  |  |  |  | 275 | my $info = delete $i->{$thing}; | 
| 489 | 102 |  |  |  |  | 283 | push @stuff, grep { ref } delete @{$info}{qw(entry object)}; | 
|  | 204 |  |  |  |  | 1213 |  | 
|  | 102 |  |  |  |  | 297 |  | 
| 490 |  |  |  |  |  |  | } | 
| 491 |  |  |  |  |  |  | } | 
| 492 |  |  |  |  |  |  | } | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | sub clear { | 
| 495 | 966 |  |  | 966 | 1 | 11369 | my $self = shift; | 
| 496 |  |  |  |  |  |  |  | 
| 497 |  |  |  |  |  |  | # don't waste too much time in DESTROY | 
| 498 | 966 |  |  |  |  | 1255 | $_->{guard}->dismiss for values %{ $self->_ids }; | 
|  | 966 |  |  |  |  | 26339 |  | 
| 499 |  |  |  |  |  |  |  | 
| 500 | 966 |  |  |  |  | 1419 | %{ $self->_ids } = (); | 
|  | 966 |  |  |  |  | 23195 |  | 
| 501 | 966 |  |  |  |  | 1340 | %{ $self->_objects } = (); | 
|  | 966 |  |  |  |  | 24409 |  | 
| 502 | 966 |  |  |  |  | 1513 | %{ $self->_object_entries } = (); | 
|  | 966 |  |  |  |  | 25465 |  | 
| 503 | 966 |  |  |  |  | 1651 | %{ $self->_entries } = (); | 
|  | 966 |  |  |  |  | 23993 |  | 
| 504 |  |  |  |  |  |  |  | 
| 505 | 966 |  |  |  |  | 29965 | $self->_clear_current_scope; | 
| 506 | 966 |  |  |  |  | 23929 | $self->_known_scopes->clear; | 
| 507 |  |  |  |  |  |  | } | 
| 508 |  |  |  |  |  |  |  | 
| 509 |  |  |  |  |  |  | __PACKAGE__->meta->make_immutable; | 
| 510 |  |  |  |  |  |  |  | 
| 511 |  |  |  |  |  |  | __PACKAGE__ | 
| 512 |  |  |  |  |  |  |  | 
| 513 |  |  |  |  |  |  | __END__ | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | =pod | 
| 516 |  |  |  |  |  |  |  | 
| 517 |  |  |  |  |  |  | =head1 NAME | 
| 518 |  |  |  |  |  |  |  | 
| 519 |  |  |  |  |  |  | KiokuDB::LiveObjects - Live object set tracking | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 522 |  |  |  |  |  |  |  | 
| 523 |  |  |  |  |  |  | $live_objects->insert( $entry => $object ); | 
| 524 |  |  |  |  |  |  |  | 
| 525 |  |  |  |  |  |  | $live_objects->insert( $id => $object ); | 
| 526 |  |  |  |  |  |  |  | 
| 527 |  |  |  |  |  |  | my $id = $live_objects->object_to_id( $object ); | 
| 528 |  |  |  |  |  |  |  | 
| 529 |  |  |  |  |  |  | my $obj = $live_objects->id_to_object( $id ); | 
| 530 |  |  |  |  |  |  |  | 
| 531 |  |  |  |  |  |  | my $scope = $live_objects->new_scope; | 
| 532 |  |  |  |  |  |  |  | 
| 533 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 534 |  |  |  |  |  |  |  | 
| 535 |  |  |  |  |  |  | This object keeps track of the set of live objects, their associated IDs, and | 
| 536 |  |  |  |  |  |  | the storage entries. | 
| 537 |  |  |  |  |  |  |  | 
| 538 |  |  |  |  |  |  | =head1 ATTRIBUTES | 
| 539 |  |  |  |  |  |  |  | 
| 540 |  |  |  |  |  |  | =over 4 | 
| 541 |  |  |  |  |  |  |  | 
| 542 |  |  |  |  |  |  | =item clear_leaks | 
| 543 |  |  |  |  |  |  |  | 
| 544 |  |  |  |  |  |  | Boolean. Defaults to false. | 
| 545 |  |  |  |  |  |  |  | 
| 546 |  |  |  |  |  |  | If true, when the last known scope is removed but some objects are still live | 
| 547 |  |  |  |  |  |  | they will be removed from the live object set. | 
| 548 |  |  |  |  |  |  |  | 
| 549 |  |  |  |  |  |  | Note that this does B<NOT> prevent leaks (memory cannot be reclaimed), it | 
| 550 |  |  |  |  |  |  | merely prevents stale objects from staying loaded. | 
| 551 |  |  |  |  |  |  |  | 
| 552 |  |  |  |  |  |  | =item leak_tracker | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | This is a coderef or object. | 
| 555 |  |  |  |  |  |  |  | 
| 556 |  |  |  |  |  |  | If any objects ar eleaked (see C<clear_leaks>) then the this can be used to | 
| 557 |  |  |  |  |  |  | report them, or to break the circular structure. | 
| 558 |  |  |  |  |  |  |  | 
| 559 |  |  |  |  |  |  | When an object is provided the C<leaked_objects> method is called. The coderef | 
| 560 |  |  |  |  |  |  | is simply invoked with the objects as arguments. | 
| 561 |  |  |  |  |  |  |  | 
| 562 |  |  |  |  |  |  | Triggered after C<clear_leaks> causes C<clear> to be called. | 
| 563 |  |  |  |  |  |  |  | 
| 564 |  |  |  |  |  |  | For example, to break cycles you can use L<Data::Structure::Util>'s | 
| 565 |  |  |  |  |  |  | C<circular_off> function: | 
| 566 |  |  |  |  |  |  |  | 
| 567 |  |  |  |  |  |  | use Data::Structure::Util qw(circular_off); | 
| 568 |  |  |  |  |  |  |  | 
| 569 |  |  |  |  |  |  | $dir->live_objects->leak_tracker(sub { | 
| 570 |  |  |  |  |  |  | my @leaked_objects = @_; | 
| 571 |  |  |  |  |  |  | circular_off($_) for @leaked_objects; | 
| 572 |  |  |  |  |  |  | }); | 
| 573 |  |  |  |  |  |  |  | 
| 574 |  |  |  |  |  |  | =item keep_entries | 
| 575 |  |  |  |  |  |  |  | 
| 576 |  |  |  |  |  |  | B<EXPERIMENTAL> | 
| 577 |  |  |  |  |  |  |  | 
| 578 |  |  |  |  |  |  | When true (the default), L<KiokuDB::Entries> loaded from the backend or created | 
| 579 |  |  |  |  |  |  | by the collapser are kept around. | 
| 580 |  |  |  |  |  |  |  | 
| 581 |  |  |  |  |  |  | This results in a considerable memory overhead, so it's no longer required. | 
| 582 |  |  |  |  |  |  |  | 
| 583 |  |  |  |  |  |  | =back | 
| 584 |  |  |  |  |  |  |  | 
| 585 |  |  |  |  |  |  | =head1 METHODS | 
| 586 |  |  |  |  |  |  |  | 
| 587 |  |  |  |  |  |  | =over 4 | 
| 588 |  |  |  |  |  |  |  | 
| 589 |  |  |  |  |  |  | =item insert | 
| 590 |  |  |  |  |  |  |  | 
| 591 |  |  |  |  |  |  | Takes pairs, id or entry as the key, and object as the value, registering the | 
| 592 |  |  |  |  |  |  | objects. | 
| 593 |  |  |  |  |  |  |  | 
| 594 |  |  |  |  |  |  | =item objects_to_ids | 
| 595 |  |  |  |  |  |  |  | 
| 596 |  |  |  |  |  |  | =item object_to_id | 
| 597 |  |  |  |  |  |  |  | 
| 598 |  |  |  |  |  |  | Given objects, returns their IDs, or undef for objects which not registered. | 
| 599 |  |  |  |  |  |  |  | 
| 600 |  |  |  |  |  |  | =item objects_to_entries | 
| 601 |  |  |  |  |  |  |  | 
| 602 |  |  |  |  |  |  | =item object_to_entry | 
| 603 |  |  |  |  |  |  |  | 
| 604 |  |  |  |  |  |  | Given objects, find the corresponding entries. | 
| 605 |  |  |  |  |  |  |  | 
| 606 |  |  |  |  |  |  | =item ids_to_objects | 
| 607 |  |  |  |  |  |  |  | 
| 608 |  |  |  |  |  |  | =item id_to_object | 
| 609 |  |  |  |  |  |  |  | 
| 610 |  |  |  |  |  |  | Given IDs, find the corresponding objects. | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  | =item ids_to_entries | 
| 613 |  |  |  |  |  |  |  | 
| 614 |  |  |  |  |  |  | Given IDs, find the corresponding entries. | 
| 615 |  |  |  |  |  |  |  | 
| 616 |  |  |  |  |  |  | =item update_entries | 
| 617 |  |  |  |  |  |  |  | 
| 618 |  |  |  |  |  |  | Given entries, replaces the live entries of the corresponding objects with the | 
| 619 |  |  |  |  |  |  | newly updated ones. | 
| 620 |  |  |  |  |  |  |  | 
| 621 |  |  |  |  |  |  | The objects must already be in the live object set. | 
| 622 |  |  |  |  |  |  |  | 
| 623 |  |  |  |  |  |  | This method is called on a successful transaction commit. | 
| 624 |  |  |  |  |  |  |  | 
| 625 |  |  |  |  |  |  | =item new_scope | 
| 626 |  |  |  |  |  |  |  | 
| 627 |  |  |  |  |  |  | Creates a new L<KiokuDB::LiveObjects::Scope>, with the current scope as its | 
| 628 |  |  |  |  |  |  | parent. | 
| 629 |  |  |  |  |  |  |  | 
| 630 |  |  |  |  |  |  | =item current_scope | 
| 631 |  |  |  |  |  |  |  | 
| 632 |  |  |  |  |  |  | The current L<KiokuDB::LiveObjects::Scope> instance. | 
| 633 |  |  |  |  |  |  |  | 
| 634 |  |  |  |  |  |  | This is the scope into which newly registered objects are pushed. | 
| 635 |  |  |  |  |  |  |  | 
| 636 |  |  |  |  |  |  | =item new_txn | 
| 637 |  |  |  |  |  |  |  | 
| 638 |  |  |  |  |  |  | Creates a new L<KiokuDB::LiveObjects::TXNScope>, with the current txn scope as | 
| 639 |  |  |  |  |  |  | its parent. | 
| 640 |  |  |  |  |  |  |  | 
| 641 |  |  |  |  |  |  | =item txn_scope | 
| 642 |  |  |  |  |  |  |  | 
| 643 |  |  |  |  |  |  | The current L<KiokuDB::LiveObjects::TXNScope>. | 
| 644 |  |  |  |  |  |  |  | 
| 645 |  |  |  |  |  |  | =item clear | 
| 646 |  |  |  |  |  |  |  | 
| 647 |  |  |  |  |  |  | Forces a clear of the live object set. | 
| 648 |  |  |  |  |  |  |  | 
| 649 |  |  |  |  |  |  | This removes all objects and entries, and can be useful in the case of leaks | 
| 650 |  |  |  |  |  |  | (to prevent false positives on lookups). | 
| 651 |  |  |  |  |  |  |  | 
| 652 |  |  |  |  |  |  | Note that this does not actually break the circular structures, so the leak is | 
| 653 |  |  |  |  |  |  | unresolved, but the objects are no longer considered live by the L<KiokuDB> instance. | 
| 654 |  |  |  |  |  |  |  | 
| 655 |  |  |  |  |  |  | =item live_entries | 
| 656 |  |  |  |  |  |  |  | 
| 657 |  |  |  |  |  |  | =item live_objects | 
| 658 |  |  |  |  |  |  |  | 
| 659 |  |  |  |  |  |  | =item live_ids | 
| 660 |  |  |  |  |  |  |  | 
| 661 |  |  |  |  |  |  | Enumerates the live entries, objects or ids. | 
| 662 |  |  |  |  |  |  |  | 
| 663 |  |  |  |  |  |  | =item rollback_entries | 
| 664 |  |  |  |  |  |  |  | 
| 665 |  |  |  |  |  |  | Called by L<KiokuDB::LiveObjects::TXNScope/rollback>. | 
| 666 |  |  |  |  |  |  |  | 
| 667 |  |  |  |  |  |  | =item remove | 
| 668 |  |  |  |  |  |  |  | 
| 669 |  |  |  |  |  |  | Removes entries from the live object set. | 
| 670 |  |  |  |  |  |  |  | 
| 671 |  |  |  |  |  |  | =item remove_scope $scope | 
| 672 |  |  |  |  |  |  |  | 
| 673 |  |  |  |  |  |  | Removes a scope from the set of known scopes. | 
| 674 |  |  |  |  |  |  |  | 
| 675 |  |  |  |  |  |  | Also calls C<detach_scope>, and calls C<KiokuDB::LiveObjects::Scope/clear> on | 
| 676 |  |  |  |  |  |  | the scope itself. | 
| 677 |  |  |  |  |  |  |  | 
| 678 |  |  |  |  |  |  | =item detach_scope $scope | 
| 679 |  |  |  |  |  |  |  | 
| 680 |  |  |  |  |  |  | Detaches C<$scope> if it's the current scope. | 
| 681 |  |  |  |  |  |  |  | 
| 682 |  |  |  |  |  |  | This prevents C<push> from being called on this scope object implicitly | 
| 683 |  |  |  |  |  |  | anymore. | 
| 684 |  |  |  |  |  |  |  | 
| 685 |  |  |  |  |  |  | =back | 
| 686 |  |  |  |  |  |  |  | 
| 687 |  |  |  |  |  |  | =cut |