Started refactoring of Iterator hierarchy
[dbsrgits/DBM-Deep.git] / lib / DBM / Deep / Iterator / File.pm
1 package DBM::Deep::Iterator::File;
2
3 use strict;
4 use warnings FATAL => 'all';
5
6 use base qw( DBM::Deep::Iterator );
7
8 use DBM::Deep::Iterator::File::BucketList ();
9 use DBM::Deep::Iterator::File::Index ();
10
11 sub get_sector_iterator {
12     my $self = shift;
13     my ($loc) = @_;
14
15     my $sector = $self->{engine}->load_sector( $loc )
16         or return;
17
18     if ( $sector->isa( 'DBM::Deep::Sector::File::Index' ) ) {
19         return DBM::Deep::Iterator::Index->new({
20             iterator => $self,
21             sector   => $sector,
22         });
23     }
24     elsif ( $sector->isa( 'DBM::Deep::Sector::File::BucketList' ) ) {
25         return DBM::Deep::Iterator::BucketList->new({
26             iterator => $self,
27             sector   => $sector,
28         });
29     }
30
31     DBM::Deep->_throw_error( "get_sector_iterator(): Why did $loc make a $sector?" );
32 }
33
34 sub get_next_key {
35     my $self = shift;
36     my ($obj) = @_;
37
38     my $crumbs = $self->{breadcrumbs};
39     my $e = $self->{engine};
40
41     unless ( @$crumbs ) {
42         # This will be a Reference sector
43         my $sector = $e->load_sector( $self->{base_offset} )
44             # If no sector is found, this must have been deleted from under us.
45             or return;
46
47         if ( $sector->staleness != $obj->_staleness ) {
48             return;
49         }
50
51         my $loc = $sector->get_blist_loc
52             or return;
53
54         push @$crumbs, $self->get_sector_iterator( $loc );
55     }
56
57     FIND_NEXT_KEY: {
58         # We're at the end.
59         unless ( @$crumbs ) {
60             $self->reset;
61             return;
62         }
63
64         my $iterator = $crumbs->[-1];
65
66         # This level is done.
67         if ( $iterator->at_end ) {
68             pop @$crumbs;
69             redo FIND_NEXT_KEY;
70         }
71
72         if ( $iterator->isa( 'DBM::Deep::Iterator::Index' ) ) {
73             # If we don't have any more, it will be caught at the
74             # prior check.
75             if ( my $next = $iterator->get_next_iterator ) {
76                 push @$crumbs, $next;
77             }
78             redo FIND_NEXT_KEY;
79         }
80
81         unless ( $iterator->isa( 'DBM::Deep::Iterator::BucketList' ) ) {
82             DBM::Deep->_throw_error(
83                 "Should have a bucketlist iterator here - instead have $iterator"
84             );
85         }
86
87         # At this point, we have a BucketList iterator
88         my $key = $iterator->get_next_key;
89         if ( defined $key ) {
90             return $key;
91         }
92         #XXX else { $iterator->set_to_end() } ?
93
94         # We hit the end of the bucketlist iterator, so redo
95         redo FIND_NEXT_KEY;
96     }
97
98     DBM::Deep->_throw_error( "get_next_key(): How did we get here?" );
99 }
100
101 1;
102 __END__