From 42bd00c4d6996795a31c0ea27a67b0ce5a2df49c Mon Sep 17 00:00:00 2001 From: Daniel Nichter Date: Wed, 16 Nov 2011 11:10:34 -0700 Subject: [PATCH] Handle resume in OobNibbleIterator. --- lib/NibbleIterator.pm | 60 ++++++++++++++++++++++++++++++---------- lib/OobNibbleIterator.pm | 18 ++++++++++-- 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/lib/NibbleIterator.pm b/lib/NibbleIterator.pm index b7dc48f9..8b600664 100644 --- a/lib/NibbleIterator.pm +++ b/lib/NibbleIterator.pm @@ -133,21 +133,37 @@ sub new { my $from = $q->quote(@{$tbl}{qw(db tbl)}) . " FORCE INDEX(`$index`)"; my $order_by = join(', ', map {$q->quote($_)} @{$index_cols}); - # These statements are only executed once, so they don't use sths. - my $first_lb_where = $where ? "($where)" : ''; - if ( $args{resume} ) { - $first_lb_where .= ($where ? " AND " : '') . $asc->{boundaries}->{'>'}; - } + # The real first row in the table. Usually we start nibbling from + # this row. Called once in _get_bounds(). my $first_lb_sql = "SELECT /*!40001 SQL_NO_CACHE */ " . join(', ', map { $q->quote($_) } @{$asc->{scols}}) . " FROM $from" - . ($first_lb_where ? " WHERE $first_lb_where" : '') + . ($where ? " WHERE $where" : '') . " ORDER BY $order_by" . " LIMIT 1" . " /*first lower boundary*/"; MKDEBUG && _d('First lower boundary statement:', $first_lb_sql); + # If we're resuming, this fetches the effective first row, which + # should differ from the real first row. Called once in _get_bounds(). + my $resume_lb_sql; + if ( $args{resume} ) { + $resume_lb_sql + = "SELECT /*!40001 SQL_NO_CACHE */ " + . join(', ', map { $q->quote($_) } @{$asc->{scols}}) + . " FROM $from" + . " WHERE " . $asc->{boundaries}->{'>'} + . ($where ? " AND ($where)" : '') + . " ORDER BY $order_by" + . " LIMIT 1" + . " /*resume lower boundary*/"; + MKDEBUG && _d('Resume lower boundary statement:', $resume_lb_sql); + } + + # The nibbles are inclusive, so we need to fetch the real last row + # in the table. Saved as boundary last_upper and used as boundary + # upper in some cases. Called once in _get_bounds(). my $last_ub_sql = "SELECT /*!40001 SQL_NO_CACHE */ " . join(', ', map { $q->quote($_) } @{$asc->{scols}}) @@ -218,6 +234,7 @@ sub new { explain_ub_sql => "EXPLAIN $ub_sql", explain_nibble_sql => $explain_nibble_sql, resume => $args{resume}, + resume_lb_sql => $resume_lb_sql, sql => { columns => $asc->{scols}, from => $from, @@ -534,20 +551,33 @@ sub _get_bounds { my $dbh = $self->{Cxn}->dbh(); + # Get the real first lower boundary. + $self->{first_lower} = $dbh->selectrow_arrayref($self->{first_lb_sql}); + MKDEBUG && _d('First lower boundary:', Dumper($self->{first_lower})); + + # The next boundary is the first lower boundary. If resuming, + # this should be something > the real first lower boundary. if ( my $nibble = $self->{resume} ) { - my $sth = $dbh->prepare($self->{first_lb_sql}); - my @ub = split ',', $nibble->{upper_boundary}; - MKDEBUG && _d($sth->{Statement}, 'params:', @ub); - $sth->execute(@ub); - $self->{first_lower} = $sth->fetchrow_arrayref(); - $sth->finish(); + if ( defined $nibble->{upper_boundary} ) { + my $sth = $dbh->prepare($self->{resume_lb_sql}); + my @ub = split ',', $nibble->{upper_boundary}; + MKDEBUG && _d($sth->{Statement}, 'params:', @ub); + $sth->execute(@ub); + $self->{next_lower} = $sth->fetchrow_arrayref(); + $sth->finish(); + } + else { + MKDEBUG && _d('No more boundaries to resume'); + $self->{no_more_boundaries} = 1; + } } else { - $self->{first_lower} = $dbh->selectrow_arrayref($self->{first_lb_sql}); + $self->{next_lower} = $self->{first_lower}; } - $self->{next_lower} = $self->{first_lower}; - MKDEBUG && _d('First lower boundary:', Dumper($self->{next_lower})); + MKDEBUG && _d('Next lower boundary:', Dumper($self->{next_lower})); + # Get the real last upper boundary, i.e. the last row of the table + # at this moment. If rows are inserted after, we won't see them. $self->{last_upper} = $dbh->selectrow_arrayref($self->{last_ub_sql}); MKDEBUG && _d('Last upper boundary:', Dumper($self->{last_upper})); diff --git a/lib/OobNibbleIterator.pm b/lib/OobNibbleIterator.pm index b41e4f85..fb1f2754 100644 --- a/lib/OobNibbleIterator.pm +++ b/lib/OobNibbleIterator.pm @@ -104,7 +104,21 @@ sub new { $self->{past_upper_sql} = $past_upper_sql; $self->{explain_past_lower_sql} = $explain_past_lower_sql; $self->{explain_past_upper_sql} = $explain_past_upper_sql; - $self->{past_nibbles} = [qw(lower upper)]; # what we nibble + + my @past_nibbles = qw(lower upper); + if ( my $nibble = $args{resume} ) { + if ( !defined $nibble->{lower_boundary} ) { + # Have past lower nibble, do only past upper nibble. + $self->{past_nibbles} = [qw(upper)]; + } + elsif ( !defined $nibble->{upper_boundary} ) { + # Have past upper nibble, so the past lower nibble + # should have alredy been done. Nothing for us to do. + $self->{past_nibbles} = []; + } + } + MKDEBUG && _d('Nibble past', @past_nibbles); + $self->{past_nibbles} = \@past_nibbles, } return bless $self, $class; @@ -131,7 +145,7 @@ sub statements { sub _prepare_sths { my ($self) = @_; - MKDEBUG && _d('Preparing boundless statement handles'); + MKDEBUG && _d('Preparing out-of-bound statement handles'); # Prepare our statements for nibbles past the lower and upper boundaries. if ( !$self->{one_nibble} ) {