File Coverage

blib/lib/DWH_File/Kernel.pm
Criterion Covered Total %
statement 131 138 94.9
branch 22 34 64.7
condition 10 26 38.4
subroutine 33 33 100.0
pod 0 23 0.0
total 196 254 77.1


line stmt bran cond sub pod time code
1             package DWH_File::Kernel;
2              
3 9     9   49 use warnings;
  9         18  
  9         295  
4 9     9   52 use strict;
  9         13  
  9         446  
5 9     9   871 use vars qw( @ISA $VERSION );
  9         235  
  9         1043  
6              
7 9     9   11918 use UNIVERSAL;
  9         395  
  9         53  
8              
9 9     9   9727 use DWH_File::ID_Mill;
  9         23  
  9         85  
10 9     9   5277 use DWH_File::Cache;
  9         25  
  9         102  
11 9     9   5958 use DWH_File::Registry::URI;
  9         153  
  9         91  
12 9     9   8514 use DWH_File::Registry::Class;
  9         23  
  9         89  
13 9     9   8160 use DWH_File::Value::Factory;
  9         30  
  9         84  
14              
15 9     9   8754 use URI::file;
  9         188241  
  9         147  
16              
17             @ISA = qw( );
18             $VERSION = 0.01;
19              
20             sub new {
21 13     13 0 37 my $this = shift;
22 13         156 my $file = $_[ 0 ];
23 13   33     133 my $class = ref $this || $this;
24 13         39 my %dummy = ();
25 13         65798 my $dbm = tie %dummy, $DWH_File::default_dbm, @_;
26 13 50       166 unless ( $dbm ) { die "Failed to create dbm file $file: $!" }
  0         0  
27 13         149 my $self = { dbm => $dbm,
28             file => $file,
29             cache => DWH_File::Cache->new,
30             garbage => {},
31             dummy => \%dummy,
32             alive => 1,
33             };
34 13         37 bless $self, $class;
35 13         106 $self->{ id_mill } = DWH_File::ID_Mill->new( $self, 'id_mill' );
36 13   100     109 $self->{ id_mill }{ current } ||= 0;
37 13         134 $self->{ uri_pool } = DWH_File::Registry::URI->new( $self, 'uri_pool' );
38 13         359 DWH_File::Registry::URI->register( $self );
39 13         144559 $self->{ class_pool } = DWH_File::Registry::Class->new( $self,
40             'class_pool' );
41 13         123 my $worker_id = $self->fetch_property( 'worker' );
42 13 100       141 if ( defined $worker_id ) {
43 9         123 $self->{ work } = $self->activate_by_id( $worker_id );
44             }
45             else {
46 4         150 $self->{ work } = DWH_File::Value::Factory->from_input( $self, {},
47             'DWH_File::Work' );
48 4         17 $self->store_property( 'worker', $self->{ work }{ id } );
49             }
50 13         183 return $self;
51             }
52              
53             sub uri {
54 47     47 0 356 return URI::file->new_abs( $_[ 0 ]->{ file } );
55             }
56              
57             sub store {
58 410     410 0 5740 $_[ 0 ]->{ dbm }->STORE( @_[ 1, 2 ] );
59             }
60              
61             sub store_property {
62 51     51 0 322 $_[ 0 ]->store( pack( 'La*', 0, $_[ 1 ] ), $_[ 2 ] );
63             }
64              
65             sub fetch {
66 1247     1247 0 9905 return $_[ 0 ]->{ dbm }->FETCH( $_[ 1 ] );
67             }
68              
69             sub fetch_property {
70 78     78 0 613 return $_[ 0 ]->fetch( pack 'La*', 0, $_[ 1 ] );
71             }
72              
73             sub delete {
74 60     60 0 334 $_[ 0 ]->{ dbm }->DELETE( $_[ 1 ] );
75             }
76              
77             sub next_id {
78 36     36 0 191 return $_[ 0 ]->{ id_mill }->next;
79             }
80              
81             sub save_state {
82 13     13 0 117 $_[ 0 ]->{ id_mill }->save;
83 13         233 $_[ 0 ]->{ class_pool }->save;
84 13         168 $_[ 0 ]->{ uri_pool }->save;
85             }
86              
87             sub class_id {
88 56     56 0 208 $_[ 0 ]->{ class_pool }->class_id( $_[ 1 ] );
89             }
90              
91             sub reference_string {
92 69     69 0 408 my $tag;
93 69 100       833 if ( $_[ 1 ]->{ kernel } == $_[ 0 ] ) { $tag = 0 }
  48         370  
94 21         129 else { $tag = $_[ 0 ]->{ uri_pool }->tag( $_[ 1 ]->{ kernel } ) }
95 69         2546 pack "aSL", '^', $tag, $_[ 1 ]->{ id };
96             }
97              
98             sub activate_reference {
99 1475     1475 0 2924 my ( $self, $stored ) = @_;
100 1475         3758 my ( $head, $tag, $id ) =
101             unpack "aSL", $stored;
102 1475 100       10714 $head eq '^' or return undef;
103 294 100       525 if ( $tag ) {
104             return DWH_File::Tie::Foreign->
105 19         166 new( $self, $self->{ uri_pool }->retrieve( $tag )->
106             activate_by_id( $id ) );
107             }
108 275         778 else { return $self->activate_by_id( $id ) }
109             }
110              
111             sub activate_by_id {
112 305     305 0 558 my ( $self, $id ) = @_;
113 305         351 my $val_obj;
114 305 100       1302 unless ( $val_obj = $self->{ cache }->retrieve( $id ) ) {
115 33         173 my $ground = $self->fetch( pack "L", $id );
116 33         205 my ( $tie_class_id, $blessing_id, $refcount, $tail )
117             = unpack "SSLa*", $ground;
118 33         72 my $ref;
119 33         260 my $tie_class = $self->{ class_pool }->fetch( $tie_class_id );
120 33         166 my $blessing = $self->{ class_pool }->fetch( $blessing_id );
121 33 50       112 $tie_class or die "Invalid class id: '$tie_class_id'";
122 33         402 $val_obj = $tie_class->tie_reference( $self, $ref, $blessing,
123             $id, $tail );
124 33 50       195 if ( UNIVERSAL::isa( $ref, 'DWH_File::Aware' ) ) {
125 0         0 $ref->dwh_activate( $val_obj );
126             }
127             }
128 305         1459 return $val_obj;
129             }
130              
131             sub ground_reference {
132 28     28 0 40 my ( $self, $value_obj ) = @_;
133 28 50 33     385 unless ( ref $value_obj and
      33        
134             $value_obj->isa( 'DWH_File::Value' ) and
135             $value_obj->isa( 'DWH_File::Reference' ) ) {
136 0         0 die "ground_reference() called for inapproproate object";
137             }
138 28         85 my $ground = pack "SSLa*", $self->class_id( $value_obj ),
139             $self->class_id( $value_obj->actual_value ),
140             0, # refcount
141             $value_obj->custom_grounding;
142 28         115 $self->store( pack( "L", $value_obj->{ id } ), $ground );
143             }
144              
145             sub save_custom_grounding {
146 134     134 0 179 my ( $self, $value_obj ) = @_;
147 134 50 33     1457 unless ( ref $value_obj and
      33        
148             $value_obj->isa( 'DWH_File::Value' ) and
149             $value_obj->isa( 'DWH_File::Reference' ) ) {
150 0         0 die "save_custom_grounding() called for inapproproate object";
151             }
152 134         217 my $id = $value_obj->{ id };
153 134 50       233 defined $id or return;
154 134         246 my $idstring = pack "L", $id;
155 134 100       379 my $ground = $self->fetch( $idstring ) or return;
156 37         106 my ( $pre ) = unpack "a8", $ground;
157 37 50       91 $pre or return;
158 37         145 $self->store( $idstring, pack "a8a*", $pre,
159             $value_obj->custom_grounding );
160             }
161              
162             sub unground {
163 2     2 0 4 my ( $self, $value_obj ) = @_;
164 2 50 33     69 unless ( ref $value_obj and
      33        
165             $value_obj->isa( 'DWH_File::Value' ) and
166             $value_obj->isa( 'DWH_File::Reference' ) ) {
167 0         0 die "unground() called for inapproproate object";
168             }
169 2         10 $self->delete( pack( "L", $value_obj->{ id } ) );
170             }
171              
172             sub bump_refcount {
173 27     27 0 48 my ( $self, $id ) = @_;
174 27         56 my $idstring = pack "L", $id;
175 27         74 my ( $pre, $refcount, $post ) = unpack "a4La*", $self->fetch( $idstring );
176 27         58 $refcount++;
177 27         106 $self->store( $idstring, pack( "a4La*", $pre, $refcount, $post ) );
178 27         146 delete $self->{ garbage }{ $id };
179             }
180              
181             sub cut_refcount {
182 2     2 0 5 my ( $self, $id ) = @_;
183 2         7 my $idstring = pack "L", $id;
184 2         6 my ( $pre, $refcount, $post ) = unpack "a4La*",
185             $self->fetch( $idstring );
186 2         5 $refcount--;
187 2         13 $self->store( $idstring, pack "a4La*", $pre, $refcount, $post );
188 2 50       9 if ( $refcount == 0 ) { $self->{ garbage }{ $id } = 1 }
  2 0       11  
189 0         0 elsif ( $refcount < 0 ) { die "Negative refcount exception! [$id]" }
190             }
191              
192             sub tieing {
193 61     61 0 1409 $_[ 0 ]->{ cache }->encache( $_[ 1 ] );
194             }
195              
196 61     61 0 130 sub did_tie {
197             }
198              
199             sub purge_garbage {
200 13     13 0 35 while ( my @goids = keys %{ $_[ 0 ]->{ garbage } } ) {
  15         105  
201 2         12 for my $goid ( @goids ) {
202 2         9 my $goner = $_[ 0 ]->activate_by_id( $goid );
203 2 50 33     17 if ( $goner and
204             UNIVERSAL::isa( $goner, 'DWH_File::Reference' ) ) {
205 2         22 $goner->vanish;
206 2         41 delete $_[ 0 ]->{ garbage }{ $goid };
207             }
208 0         0 else { warn "Garbage anomaly: $goid ~ $goner" }
209             }
210             }
211             }
212              
213             sub release {
214 13     13 0 35 my ( $self ) = @_;
215 13         81 $self->{ uri_pool }->release( $self );
216 13         63 delete $_[ 0 ]->{ dbm };
217 13         33 untie %{ $_[ 0 ]->{ dummy } };
  13         10677  
218 13         84 $self->{ alive } = 0;
219             }
220              
221             sub wipe {
222 13     13 0 43 my ( $self ) = @_;
223 13         83 $self->save_state;
224 13         74 $self->purge_garbage;
225 13         91 $self->release;
226             }
227              
228             1;
229              
230             __END__