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