Changeset 494
- Timestamp:
- 06/10/08 23:13:56 (5 months ago)
- Files:
-
- trunk/Changes (modified) (1 diff)
- trunk/lib/Data/ObjectDriver.pm (modified) (1 diff)
- trunk/lib/Data/ObjectDriver/BaseObject.pm (modified) (1 diff)
- trunk/lib/Data/ObjectDriver/Driver/BaseCache.pm (modified) (1 diff)
- trunk/lib/Data/ObjectDriver/Driver/DBI.pm (modified) (3 diffs)
- trunk/lib/Data/ObjectDriver/SQL.pm (modified) (1 diff)
- trunk/t/05-deflate.t (modified) (1 diff)
- trunk/t/12-windows.t (added)
- trunk/t/32-partitioned.t (modified) (2 diffs)
- trunk/t/34-both.t (modified) (1 diff)
- trunk/t/lib/both/Recipe.pm (modified) (1 diff)
- trunk/t/lib/cached/Ingredient.pm (modified) (2 diffs)
- trunk/t/lib/partitioned/Recipe.pm (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/Changes
r467 r494 13 13 - Added a "distinct" method to D::OD::SQL that forces the DISTINCT keyword 14 14 in the generated SQL statement. Thanks to John Berthels for the patch. 15 - Added a "window_size" argument for the search() method of the caching 16 layer to constrain the number of objects loaded from the database for 17 large or unbounded searches. 15 18 16 19 0.05 2008.02.24 trunk/lib/Data/ObjectDriver.pm
r482 r494 415 415 416 416 A sql comment to watermark the SQL query. 417 418 =item * window_size 419 420 Used when requesting an iterator for the search method and selecting 421 a large result set or a result set of unknown size. In such a case, 422 no LIMIT clause is assigned, which can load all available objects into 423 memory. Specifying C<window_size> will load objects in manageable chunks. 424 This will also cause any caching driver to be bypassed for issuing 425 the search itself. Objects are still placed into the cache upon load. 426 427 This attribute is ignored when the search method is invoked in an array 428 context, or if a C<limit> attribute is also specified that is smaller than 429 the C<window_size>. 417 430 418 431 =back trunk/lib/Data/ObjectDriver/BaseObject.pm
r493 r494 490 490 my($terms, $args) = @_; 491 491 my $driver = $class->driver; 492 my @objs = $driver->search($class, $terms, $args); 493 494 ## Don't attempt to cache objects where the caller specified fetchonly, 495 ## because they won't be complete. 496 ## Also skip this step if we don't get any objects back from the search 497 if (!$args->{fetchonly} || !@objs) { 498 for my $obj (@objs) { 499 $driver->cache_object($obj) if $obj; 492 if (wantarray) { 493 my @objs = $driver->search($class, $terms, $args); 494 495 ## Don't attempt to cache objects where the caller specified fetchonly, 496 ## because they won't be complete. 497 ## Also skip this step if we don't get any objects back from the search 498 if (!$args->{fetchonly} || !@objs) { 499 for my $obj (@objs) { 500 $driver->cache_object($obj) if $obj; 501 } 500 502 } 501 } 502 $driver->list_or_iterator(\@objs); 503 return @objs; 504 } else { 505 my $iter = $driver->search($class, $terms, $args); 506 return $iter if $args->{fetchonly}; 507 508 my $caching_iter = sub { 509 my $d = $driver; 510 511 my $o = $iter->(); 512 unless ($o) { 513 $iter->end; 514 return; 515 } 516 $driver->cache_object($o); 517 return $o; 518 }; 519 return Data::ObjectDriver::Iterator->new($caching_iter, sub { $iter->end }); 520 } 503 521 } 504 522 trunk/lib/Data/ObjectDriver/Driver/BaseCache.pm
r482 r494 187 187 ## Disable triggers for this load. We don't want the post_load trigger 188 188 ## being called twice. 189 $args->{no_triggers} = 1;189 local $args->{no_triggers} = 1; 190 190 my @objs = $driver->fallback->search($class, $terms, $args); 191 191 192 ## Load all of the objects using a lookup_multi, which is fast from 193 ## cache. 194 my $objs = $driver->lookup_multi($class, [ map { $_->primary_key } @objs ]); 195 196 $driver->list_or_iterator($objs); 192 my $windowed = (!wantarray) && $args->{window_size}; 193 194 if ( $windowed ) { 195 my @window; 196 my $window_size = $args->{window_size}; 197 my $iter = sub { 198 my $d = $driver; 199 while ( (!@window) && @objs ) { 200 my $objs = $driver->lookup_multi( 201 $class, 202 [ map { $_->primary_key } 203 splice( @objs, 0, $window_size ) ] 204 ); 205 # A small possibility exists that we may fetch 206 # some IDs here that no longer exist; grep these out 207 @window = grep { defined $_ } @$objs if $objs; 208 } 209 return @window ? shift @window : undef; 210 }; 211 return Data::ObjectDriver::Iterator->new($iter, sub { @objs = (); @window = () }); 212 } else { 213 ## Load all of the objects using a lookup_multi, which is fast from 214 ## cache. 215 my $objs = $driver->lookup_multi($class, [ map { $_->primary_key } @objs ]); 216 217 return $driver->list_or_iterator($objs); 218 } 197 219 } 198 220 trunk/lib/Data/ObjectDriver/Driver/DBI.pm
r493 r494 99 99 100 100 ## Use (shallow) duplicates so the pre_search trigger can modify them. 101 my $terms = defined $orig_terms ? ( ref $orig_terms eq 'ARRAY' ? [ @$orig_terms ] : { %$orig_terms } ) : undef;102 my $args = defined $orig_args ? { %$orig_args } : undef;101 my $terms = defined $orig_terms ? ( ref $orig_terms eq 'ARRAY' ? [ @$orig_terms ] : { %$orig_terms } ) : {}; 102 my $args = defined $orig_args ? { %$orig_args } : {}; 103 103 $class->call_trigger('pre_search', $terms, $args); 104 104 … … 188 188 my @got; 189 189 ## If it's a single-column PK, assume it's in one partition, and 190 ## use an OR search. 190 ## use an OR search. FIXME: can we instead check for partitioning? 191 191 unless (ref($ids->[0])) { 192 192 my $terms = $class->primary_key_to_terms([ $ids ]); … … 239 239 240 240 my $class = ref $obj; 241 $terms ||= {}; 241 242 $class->call_trigger('pre_search', $terms); 242 243 trunk/lib/Data/ObjectDriver/SQL.pm
r492 r494 471 471 are as described for the C<joins> attribute member above. 472 472 473 =head2 C<$sql-E<gt>add_index_hint($table, $index)> 474 475 Specifies a particular index to use for a particular table. 476 473 477 =head2 C<$sql-E<gt>add_where($column, $value)> 474 478 trunk/t/05-deflate.t
r232 r494 43 43 { 44 44 no warnings 'once'; 45 no warnings 'redefine'; 45 46 *Data::ObjectDriver::Driver::Cache::Cache::deflate = sub { 46 47 $_[1]->deflate; trunk/t/32-partitioned.t
r313 r494 49 49 is(ref $tmp, 'Recipe', 'Iterator gave us a recipe'); 50 50 is($tmp->title, 'My Banana Milkshake', 'Title is My Banana Milkshake'); 51 $iter->end(); 51 52 52 53 my $ingredient = Ingredient->new; … … 73 74 is(ref $tmp, 'Ingredient', 'Iterator gave us an ingredient'); 74 75 is($tmp->name, 'Vanilla Ice Cream', 'Name is Vanilla Ice Cream'); 76 $iter->end(); 75 77 76 78 my $ingredient2 = Ingredient->new; trunk/t/34-both.t
r480 r494 33 33 { 34 34 no warnings 'once'; 35 no warnings 'redefine'; 35 36 *Data::ObjectDriver::Driver::Cache::Cache::deflate = sub { 36 37 $_[1]->deflate; trunk/t/lib/both/Recipe.pm
r232 r494 21 21 }); 22 22 23 my %drivers; 23 24 __PACKAGE__->has_partitions( 24 25 number => 2, 25 26 get_driver => sub { 26 return Data::ObjectDriver::Driver::DBI->new( 27 dsn => 'dbi:SQLite:dbname=cluster' . shift() . '.db', 28 @_, 29 ), 27 my $cluster = shift; 28 my $driver = $drivers{$cluster} ||= 29 Data::ObjectDriver::Driver::DBI->new( 30 dsn => 'dbi:SQLite:dbname=cluster' . $cluster . '.db', 31 @_, 32 ); 33 return $driver; 30 34 }, 31 35 ); trunk/t/lib/cached/Ingredient.pm
r60 r494 7 7 use Carp (); 8 8 use Data::ObjectDriver::Driver::DBI; 9 use Data::ObjectDriver::Driver::Cache::Cache; 10 use Cache::Memory; 9 use Data::ObjectDriver::Driver::Cache::RAM; 11 10 12 11 our %IDs; … … 16 15 datasource => 'ingredients', 17 16 primary_key => [ 'recipe_id', 'id' ], 18 driver => Data::ObjectDriver::Driver::Cache::Cache->new( 19 cache => Cache::Memory->new, 17 driver => Data::ObjectDriver::Driver::Cache::RAM->new( 20 18 fallback => Data::ObjectDriver::Driver::DBI->new( 21 19 dsn => 'dbi:SQLite:dbname=global.db', trunk/t/lib/partitioned/Recipe.pm
r232 r494 16 16 }); 17 17 18 my %drivers; 18 19 __PACKAGE__->has_partitions( 19 20 number => 2, 20 21 get_driver => sub { 21 return Data::ObjectDriver::Driver::DBI->new( 22 dsn => 'dbi:SQLite:dbname=cluster' . shift() . '.db', 23 @_, 24 ), 22 my $cluster = shift; 23 my $driver = $drivers{$cluster} ||= 24 Data::ObjectDriver::Driver::DBI->new( 25 dsn => 'dbi:SQLite:dbname=cluster' . $cluster . '.db', 26 @_, 27 ); 28 return $driver; 25 29 }, 26 30 );
