Commit | Line | Data |
065b45be |
1 | package DBM::Deep::Iterator; |
2 | |
9c7d9738 |
3 | use 5.006_000; |
065b45be |
4 | |
5 | use strict; |
6 | use warnings FATAL => 'all'; |
7 | |
8 | use Scalar::Util (); |
9 | |
10 | use DBM::Deep::Iterator::Index; |
11 | use DBM::Deep::Iterator::BucketList; |
12 | |
13 | sub new { |
14 | my $class = shift; |
15 | my ($args) = @_; |
16 | |
17 | my $self = bless { |
18 | breadcrumbs => [], |
19 | engine => $args->{engine}, |
20 | base_offset => $args->{base_offset}, |
21 | }, $class; |
22 | |
23 | Scalar::Util::weaken( $self->{engine} ); |
24 | |
25 | return $self; |
26 | } |
27 | |
28 | sub reset { $_[0]{breadcrumbs} = [] } |
29 | |
30 | sub get_sector_iterator { |
31 | my $self = shift; |
32 | my ($loc) = @_; |
33 | |
34 | my $sector = $self->{engine}->_load_sector( $loc ) |
35 | or return; |
36 | |
37 | if ( $sector->isa( 'DBM::Deep::Engine::Sector::Index' ) ) { |
38 | return DBM::Deep::Iterator::Index->new({ |
39 | iterator => $self, |
40 | sector => $sector, |
41 | }); |
42 | } |
43 | elsif ( $sector->isa( 'DBM::Deep::Engine::Sector::BucketList' ) ) { |
44 | return DBM::Deep::Iterator::BucketList->new({ |
45 | iterator => $self, |
46 | sector => $sector, |
47 | }); |
48 | } |
49 | |
50 | DBM::Deep->_throw_error( "get_sector_iterator(): Why did $loc make a $sector?" ); |
51 | } |
52 | |
53 | sub get_next_key { |
54 | my $self = shift; |
55 | my ($obj) = @_; |
56 | |
57 | my $crumbs = $self->{breadcrumbs}; |
58 | my $e = $self->{engine}; |
59 | |
9c87a079 |
60 | warn "1\n"; |
065b45be |
61 | unless ( @$crumbs ) { |
62 | # This will be a Reference sector |
63 | my $sector = $e->_load_sector( $self->{base_offset} ) |
64 | # If no sector is found, thist must have been deleted from under us. |
65 | or return; |
66 | |
67 | if ( $sector->staleness != $obj->_staleness ) { |
68 | return; |
69 | } |
70 | |
71 | my $loc = $sector->get_blist_loc |
72 | or return; |
73 | |
74 | push @$crumbs, $self->get_sector_iterator( $loc ); |
75 | } |
76 | |
9c87a079 |
77 | warn "2: " . $obj->_dump_file; |
065b45be |
78 | FIND_NEXT_KEY: { |
79 | # We're at the end. |
80 | unless ( @$crumbs ) { |
81 | $self->reset; |
82 | return; |
83 | } |
84 | |
85 | my $iterator = $crumbs->[-1]; |
86 | |
87 | # This level is done. |
88 | if ( $iterator->at_end ) { |
89 | pop @$crumbs; |
90 | redo FIND_NEXT_KEY; |
91 | } |
92 | |
93 | if ( $iterator->isa( 'DBM::Deep::Iterator::Index' ) ) { |
94 | # If we don't have any more, it will be caught at the |
95 | # prior check. |
96 | if ( my $next = $iterator->get_next_iterator ) { |
97 | push @$crumbs, $next; |
98 | } |
99 | redo FIND_NEXT_KEY; |
100 | } |
101 | |
102 | unless ( $iterator->isa( 'DBM::Deep::Iterator::BucketList' ) ) { |
103 | DBM::Deep->_throw_error( |
104 | "Should have a bucketlist iterator here - instead have $iterator" |
105 | ); |
106 | } |
107 | |
108 | # At this point, we have a BucketList iterator |
109 | my $key = $iterator->get_next_key; |
110 | if ( defined $key ) { |
111 | return $key; |
112 | } |
113 | #XXX else { $iterator->set_to_end() } ? |
114 | |
115 | # We hit the end of the bucketlist iterator, so redo |
116 | redo FIND_NEXT_KEY; |
117 | } |
118 | |
119 | DBM::Deep->_throw_error( "get_next_key(): How did we get here?" ); |
120 | } |
121 | |
122 | 1; |
123 | __END__ |