3 # Check ->defer and ->flush methods
8 $: = Tie::File::_default_recsep();
9 my $data = "rec0$:rec1$:rec2$:";
16 print "ok $N\n"; $N++;
18 open F, "> $file" or die $!;
22 $o = tie @a, 'Tie::File', $file;
23 print $o ? "ok $N\n" : "not ok $N\n";
26 # (3-6) Deferred storage
29 check_contents($data); # nothing written yet
31 check_contents($data); # nothing written yet
35 check_contents($data . "rec3$:rec4$:"); # now it's written
37 # (9-12) Deferred writing disabled?
39 check_contents("${data}rec9$:rec4$:");
41 check_contents("${data}rec9$:rec8$:");
43 # (13-18) Now let's try two batches of records
47 check_contents($data); # nothing written yet
49 check_contents($data); # nothing written yet
51 check_contents("record0$:rec1$:record2$:");
53 # (19-22) Deferred writing past the end of the file
56 check_contents("record0$:rec1$:record2$:");
58 check_contents("record0$:rec1$:record2$:$:record4$:");
61 # (23-26) Now two long batches
66 check_contents("record0$:rec1$:record2$:$:record4$:");
68 check_contents(join $:, "r0".."r2", "", "r4".."r6", "");
70 # (27-30) Now let's make sure that discarded writes are really discarded
71 # We have a 2Mib buffer here, so we can be sure that we aren't accidentally
75 $a[$_] = "discarded$_";
77 check_contents(join $:, "r0".."r2", "", "r4".."r6", "");
79 check_contents(join $:, "r0".."r2", "", "r4".."r6", "");
81 ################################################################
83 # Now we're going to test the results of a small memory limit
87 $data = join "$:", map("record$_", 0..7), ""; # records are 8 or 9 bytes long
88 open F, "> $file" or die $!;
93 # Limit cache+buffer size to 47 bytes
95 # -- that's enough space for 5 records, but not 6, on both \n and \r\n systems
97 # -- that's enough space for 2 records, but not 3, on both \n and \r\n systems
98 $o = tie @a, 'Tie::File', $file, memory => $MAX, dw_size => $BUF;
99 print $o ? "ok $N\n" : "not ok $N\n";
102 # (31-32) Fill up the read cache
105 # the cache now contains records 3,4,5,6,7.
106 check_caches({map(($_ => "record$_$:"), 3..7)},
109 # (33-44) See if overloading the defer starts by flushing the read cache
110 # and then flushes out the defer
112 $a[0] = "recordA"; # That should flush record 3 from the cache
113 check_caches({map(($_ => "record$_$:"), 4..7)},
115 check_contents($data);
117 $a[1] = "recordB"; # That should flush record 4 from the cache
118 check_caches({map(($_ => "record$_$:"), 5..7)},
121 check_contents($data);
123 $a[2] = "recordC"; # That should flush the whole darn defer
124 # Flushing the defer requires looking up the true lengths of records
125 # 0..2, which flushes out the read cache, leaving only 1..2 there.
126 # Then the splicer updates the cached versions of 1..2 to contain the
128 check_caches({1 => "recordB$:", 2 => "recordC$:"},
130 check_contents(join("$:", qw(recordA recordB recordC
131 record3 record4 record5 record6 record7)) . "$:");
133 $a[3] = "recordD"; # even though we flushed, deferring is STILL ENABLED
134 check_caches({1 => "recordB$:", 2 => "recordC$:"},
136 check_contents(join("$:", qw(recordA recordB recordC
137 record3 record4 record5 record6 record7)) . "$:");
139 # Check readcache-deferbuffer interactions
141 # (45-47) This should remove outdated data from the read cache
143 check_caches({1 => "recordB$:", },
144 {3 => "recordD$:", 2 => "recordE$:"});
145 check_contents(join("$:", qw(recordA recordB recordC
146 record3 record4 record5 record6 record7)) . "$:");
148 # (48-51) This should read back out of the defer buffer
149 # without adding anything to the read cache
152 print $z eq "recordE" ? "ok $N\n" : "not ok $N\n"; $N++;
153 check_caches({1 => "recordB$:", },
154 {3 => "recordD$:", 2 => "recordE$:"});
155 check_contents(join("$:", qw(recordA recordB recordC
156 record3 record4 record5 record6 record7)) . "$:");
158 # (52-55) This should repopulate the read cache with a new record
160 print $z eq "recordA" ? "ok $N\n" : "not ok $N\n"; $N++;
161 check_caches({1 => "recordB$:", 0 => "recordA$:"},
162 {3 => "recordD$:", 2 => "recordE$:"});
163 check_contents(join("$:", qw(recordA recordB recordC
164 record3 record4 record5 record6 record7)) . "$:");
166 # (56-59) This should flush the LRU record from the read cache
167 $z = $a[4]; $z = $a[5];
168 print $z eq "record5" ? "ok $N\n" : "not ok $N\n"; $N++;
169 check_caches({5 => "record5$:", 0 => "recordA$:", 4 => "record4$:"},
170 {3 => "recordD$:", 2 => "recordE$:"});
171 check_contents(join("$:", qw(recordA recordB recordC
172 record3 record4 record5 record6 record7)) . "$:");
174 # (60-63) This should FLUSH the deferred buffer
175 # In doing so, it will read in records 2 and 3, flushing 0 and 4
176 # from the read cache, leaving 2, 3, and 5.
177 $z = splice @a, 3, 1, "recordZ";
178 print $z eq "recordD" ? "ok $N\n" : "not ok $N\n"; $N++;
179 check_caches({5 => "record5$:", 3 => "recordZ$:", 2 => "recordE$:"},
181 check_contents(join("$:", qw(recordA recordB recordE
182 recordZ record4 record5 record6 record7)) . "$:");
184 # (64-66) We should STILL be in deferred writing mode
186 check_caches({3 => "recordZ$:", 2 => "recordE$:"},
188 check_contents(join("$:", qw(recordA recordB recordE
189 recordZ record4 record5 record6 record7)) . "$:");
191 # Fill up the defer buffer again
193 # (67-69) This should OVERWRITE the existing deferred record
194 # and NOT flush the buffer
196 check_caches({3 => "recordZ$:", 2 => "recordE$:"},
197 {5 => "recordQ$:", 4 => "recordP$:"});
198 check_contents(join("$:", qw(recordA recordB recordE
199 recordZ record4 record5 record6 record7)) . "$:");
202 # (70-72) Discard should just dump the whole deferbuffer
204 check_caches({3 => "recordZ$:", 2 => "recordE$:"},
206 check_contents(join("$:", qw(recordA recordB recordE
207 recordZ record4 record5 record6 record7)) . "$:");
208 # (73-75) NOW we are out of deferred writing mode
210 check_caches({3 => "recordZ$:", 2 => "recordE$:", 0 => "recordF$:"},
212 check_contents(join("$:", qw(recordF recordB recordE
213 recordZ record4 record5 record6 record7)) . "$:");
215 # (76-79) Last call--untying the array should flush the deferbuffer
218 check_caches({3 => "recordZ$:", 2 => "recordE$:"},
219 {0 => "flushed$:" });
220 check_contents(join("$:", qw(recordF recordB recordE
221 recordZ record4 record5 record6 record7)) . "$:");
224 # (79) We can't use check_contents any more, because the object is dead
225 open F, "< $file" or die;
227 { local $/ ; $z = <F> }
229 my $x = join("$:", qw(flushed recordB recordE
230 recordZ record4 record5 record6 record7)) . "$:";
234 my $msg = ctrlfix("expected <$x>, got <$z>");
235 print "not ok $N \# $msg\n";
239 ################################################################
243 my ($xcache, $xdefer) = @_;
245 # my $integrity = $o->_check_integrity($file, $ENV{INTEGRITY});
246 # print $integrity ? "ok $N\n" : "not ok $N\n";
250 $good &&= hash_equal($o->{cache}, $xcache, "true cache", "expected cache");
251 $good &&= hash_equal($o->{deferred}, $xdefer, "true defer", "expected defer");
252 print $good ? "ok $N\n" : "not ok $N\n";
257 my ($a, $b, $ha, $hb) = @_;
258 $ha = 'first hash' unless defined $ha;
259 $hb = 'second hash' unless defined $hb;
264 for my $k (keys %$a) {
265 if (! exists $b->{$k}) {
266 print ctrlfix("# Key $k is in $ha but not $hb"), "\n";
268 } elsif ($b->{$k} ne $a->{$k}) {
269 print ctrlfix("# Key $k is <$a->{$k}> in $ha but <$b->{$k}> in $hb"), "\n";
277 for my $k (keys %$b) {
278 unless ($b_seen{$k}) {
279 print ctrlfix("# Key $k is in $hb but not $ha"), "\n";
291 my $integrity = $o->_check_integrity($file, $ENV{INTEGRITY});
292 print $integrity ? "ok $N\n" : "not ok $N\n";
295 local *FH = $o->{fh};
296 seek FH, 0, SEEK_SET;
299 { local $/; $a = <FH> }
300 $a = "" unless defined $a;
304 my $msg = ctrlfix("# expected <$x>, got <$a>");
305 print "not ok $N\n$msg\n";
318 1 while unlink $file;