1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
|
# DB_File.pm -- Perl 5 interface to Berkeley DB
#
# written by Paul Marquess (pmarquess@bfsec.bt.co.uk)
# last modified 14th November 1995
# version 1.01
package DB_File::HASHINFO ;
use Carp;
sub TIEHASH
{
bless {} ;
}
%elements = ( 'bsize' => 0,
'ffactor' => 0,
'nelem' => 0,
'cachesize' => 0,
'hash' => 0,
'lorder' => 0
) ;
sub FETCH
{
return $_[0]{$_[1]} if defined $elements{$_[1]} ;
croak "DB_File::HASHINFO::FETCH - Unknown element '$_[1]'" ;
}
sub STORE
{
if ( defined $elements{$_[1]} )
{
$_[0]{$_[1]} = $_[2] ;
return ;
}
croak "DB_File::HASHINFO::STORE - Unknown element '$_[1]'" ;
}
sub DELETE
{
if ( defined $elements{$_[1]} )
{
delete ${$_[0]}{$_[1]} ;
return ;
}
croak "DB_File::HASHINFO::DELETE - Unknown element '$_[1]'" ;
}
sub DESTROY {undef %{$_[0]} }
sub FIRSTKEY { croak "DB_File::HASHINFO::FIRSTKEY is not implemented" }
sub NEXTKEY { croak "DB_File::HASHINFO::NEXTKEY is not implemented" }
sub EXISTS { croak "DB_File::HASHINFO::EXISTS is not implemented" }
sub CLEAR { croak "DB_File::HASHINFO::CLEAR is not implemented" }
package DB_File::BTREEINFO ;
use Carp;
sub TIEHASH
{
bless {} ;
}
%elements = ( 'flags' => 0,
'cachesize' => 0,
'maxkeypage' => 0,
'minkeypage' => 0,
'psize' => 0,
'compare' => 0,
'prefix' => 0,
'lorder' => 0
) ;
sub FETCH
{
return $_[0]{$_[1]} if defined $elements{$_[1]} ;
croak "DB_File::BTREEINFO::FETCH - Unknown element '$_[1]'" ;
}
sub STORE
{
if ( defined $elements{$_[1]} )
{
$_[0]{$_[1]} = $_[2] ;
return ;
}
croak "DB_File::BTREEINFO::STORE - Unknown element '$_[1]'" ;
}
sub DELETE
{
if ( defined $elements{$_[1]} )
{
delete ${$_[0]}{$_[1]} ;
return ;
}
croak "DB_File::BTREEINFO::DELETE - Unknown element '$_[1]'" ;
}
sub DESTROY {undef %{$_[0]} }
sub FIRSTKEY { croak "DB_File::BTREEINFO::FIRSTKEY is not implemented" }
sub NEXTKEY { croak "DB_File::BTREEINFO::NEXTKEY is not implemented" }
sub EXISTS { croak "DB_File::BTREEINFO::EXISTS is not implemented" }
sub CLEAR { croak "DB_File::BTREEINFO::CLEAR is not implemented" }
package DB_File::RECNOINFO ;
use Carp;
sub TIEHASH
{
bless {} ;
}
%elements = ( 'bval' => 0,
'cachesize' => 0,
'psize' => 0,
'flags' => 0,
'lorder' => 0,
'reclen' => 0,
'bfname' => 0
) ;
sub FETCH
{
return $_[0]{$_[1]} if defined $elements{$_[1]} ;
croak "DB_File::RECNOINFO::FETCH - Unknown element '$_[1]'" ;
}
sub STORE
{
if ( defined $elements{$_[1]} )
{
$_[0]{$_[1]} = $_[2] ;
return ;
}
croak "DB_File::RECNOINFO::STORE - Unknown element '$_[1]'" ;
}
sub DELETE
{
if ( defined $elements{$_[1]} )
{
delete ${$_[0]}{$_[1]} ;
return ;
}
croak "DB_File::RECNOINFO::DELETE - Unknown element '$_[1]'" ;
}
sub DESTROY {undef %{$_[0]} }
sub FIRSTKEY { croak "DB_File::RECNOINFO::FIRSTKEY is not implemented" }
sub NEXTKEY { croak "DB_File::RECNOINFO::NEXTKEY is not implemented" }
sub EXISTS { croak "DB_File::BTREEINFO::EXISTS is not implemented" }
sub CLEAR { croak "DB_File::BTREEINFO::CLEAR is not implemented" }
package DB_File ;
use Carp;
$VERSION = $VERSION = 1.01 ;
#typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE;
$DB_BTREE = $DB_BTREE = TIEHASH DB_File::BTREEINFO ;
$DB_HASH = $DB_HASH = TIEHASH DB_File::HASHINFO ;
$DB_RECNO = $DB_RECNO = TIEHASH DB_File::RECNOINFO ;
require TieHash;
require Exporter;
use AutoLoader;
require DynaLoader;
@ISA = qw(TieHash Exporter DynaLoader);
@EXPORT = qw(
$DB_BTREE $DB_HASH $DB_RECNO
BTREEMAGIC
BTREEVERSION
DB_LOCK
DB_SHMEM
DB_TXN
HASHMAGIC
HASHVERSION
MAX_PAGE_NUMBER
MAX_PAGE_OFFSET
MAX_REC_NUMBER
RET_ERROR
RET_SPECIAL
RET_SUCCESS
R_CURSOR
R_DUP
R_FIRST
R_FIXEDLEN
R_IAFTER
R_IBEFORE
R_LAST
R_NEXT
R_NOKEY
R_NOOVERWRITE
R_PREV
R_RECNOSYNC
R_SETCURSOR
R_SNAPSHOT
__R_UNUSED
);
sub AUTOLOAD {
local($constname);
($constname = $AUTOLOAD) =~ s/.*:://;
$val = constant($constname, @_ ? $_[0] : 0);
if ($! != 0) {
if ($! =~ /Invalid/) {
$AutoLoader::AUTOLOAD = $AUTOLOAD;
goto &AutoLoader::AUTOLOAD;
}
else {
($pack,$file,$line) = caller;
croak "Your vendor has not defined DB macro $constname, used at $file line $line.
";
}
}
eval "sub $AUTOLOAD { $val }";
goto &$AUTOLOAD;
}
bootstrap DB_File ;
# Preloaded methods go here. Autoload methods go after __END__, and are
# processed by the autosplit program.
1;
__END__
=cut
=head1 NAME
DB_File - Perl5 access to Berkeley DB
=head1 SYNOPSIS
use DB_File ;
[$X =] tie %hash, DB_File, $filename [, $flags, $mode, $DB_HASH] ;
[$X =] tie %hash, DB_File, $filename, $flags, $mode, $DB_BTREE ;
[$X =] tie @array, DB_File, $filename, $flags, $mode, $DB_RECNO ;
$status = $X->del($key [, $flags]) ;
$status = $X->put($key, $value [, $flags]) ;
$status = $X->get($key, $value [, $flags]) ;
$status = $X->seq($key, $value [, $flags]) ;
$status = $X->sync([$flags]) ;
$status = $X->fd ;
untie %hash ;
untie @array ;
=head1 DESCRIPTION
B<DB_File> is a module which allows Perl programs to make use of the
facilities provided by Berkeley DB. If you intend to use this
module you should really have a copy of the Berkeley DB manualpage at
hand. The interface defined here mirrors the Berkeley DB interface
closely.
Berkeley DB is a C library which provides a consistent interface to a
number of database formats. B<DB_File> provides an interface to all
three of the database types currently supported by Berkeley DB.
The file types are:
=over 5
=item DB_HASH
This database type allows arbitrary key/data pairs to be stored in data
files. This is equivalent to the functionality provided by other
hashing packages like DBM, NDBM, ODBM, GDBM, and SDBM. Remember though,
the files created using DB_HASH are not compatible with any of the
other packages mentioned.
A default hashing algorithm, which will be adequate for most
applications, is built into Berkeley DB. If you do need to use your own
hashing algorithm it is possible to write your own in Perl and have
B<DB_File> use it instead.
=item DB_BTREE
The btree format allows arbitrary key/data pairs to be stored in a
sorted, balanced binary tree.
As with the DB_HASH format, it is possible to provide a user defined
Perl routine to perform the comparison of keys. By default, though, the
keys are stored in lexical order.
=item DB_RECNO
DB_RECNO allows both fixed-length and variable-length flat text files
to be manipulated using the same key/value pair interface as in DB_HASH
and DB_BTREE. In this case the key will consist of a record (line)
number.
=back
=head2 How does DB_File interface to Berkeley DB?
B<DB_File> allows access to Berkeley DB files using the tie() mechanism
in Perl 5 (for full details, see L<perlfunc/tie()>). This facility
allows B<DB_File> to access Berkeley DB files using either an
associative array (for DB_HASH & DB_BTREE file types) or an ordinary
array (for the DB_RECNO file type).
In addition to the tie() interface, it is also possible to use most of
the functions provided in the Berkeley DB API.
=head2 Differences with Berkeley DB
Berkeley DB uses the function dbopen() to open or create a database.
Below is the C prototype for dbopen().
DB*
dbopen (const char * file, int flags, int mode,
DBTYPE type, const void * openinfo)
The parameter C<type> is an enumeration which specifies which of the 3
interface methods (DB_HASH, DB_BTREE or DB_RECNO) is to be used.
Depending on which of these is actually chosen, the final parameter,
I<openinfo> points to a data structure which allows tailoring of the
specific interface method.
This interface is handled slightly differently in B<DB_File>. Here is
an equivalent call using B<DB_File>.
tie %array, DB_File, $filename, $flags, $mode, $DB_HASH ;
The C<filename>, C<flags> and C<mode> parameters are the direct
equivalent of their dbopen() counterparts. The final parameter $DB_HASH
performs the function of both the C<type> and C<openinfo> parameters in
dbopen().
In the example above $DB_HASH is actually a reference to a hash
object. B<DB_File> has three of these pre-defined references. Apart
from $DB_HASH, there is also $DB_BTREE and $DB_RECNO.
The keys allowed in each of these pre-defined references is limited to
the names used in the equivalent C structure. So, for example, the
$DB_HASH reference will only allow keys called C<bsize>, C<cachesize>,
C<ffactor>, C<hash>, C<lorder> and C<nelem>.
To change one of these elements, just assign to it like this
$DB_HASH{cachesize} = 10000 ;
=head2 RECNO
In order to make RECNO more compatible with Perl the array offset for all
RECNO arrays begins at 0 rather than 1 as in Berkeley DB.
=head2 In Memory Databases
Berkeley DB allows the creation of in-memory databases by using NULL
(that is, a C<(char *)0 in C) in place of the filename. B<DB_File>
uses C<undef> instead of NULL to provide this functionality.
=head2 Using the Berkeley DB Interface Directly
As well as accessing Berkeley DB using a tied hash or array, it is also
possible to make direct use of most of the functions defined in the
Berkeley DB documentation.
To do this you need to remember the return value from the tie.
$db = tie %hash, DB_File, "filename"
Once you have done that, you can access the Berkeley DB API functions
directly.
$db->put($key, $value, R_NOOVERWRITE) ;
All the functions defined in L<dbx(3X)> are available except for
close() and dbopen() itself. The B<DB_File> interface to these
functions have been implemented to mirror the the way Berkeley DB
works. In particular note that all the functions return only a status
value. Whenever a Berkeley DB function returns data via one of its
parameters, the B<DB_File> equivalent does exactly the same.
All the constants defined in L<dbopen> are also available.
Below is a list of the functions available.
=over 5
=item get
Same as in C<recno> except that the flags parameter is optional.
Remember the value associated with the key you request is returned in
the $value parameter.
=item put
As usual the flags parameter is optional.
If you use either the R_IAFTER or R_IBEFORE flags, the key parameter
will have the record number of the inserted key/value pair set.
=item del
The flags parameter is optional.
=item fd
As in I<recno>.
=item seq
The flags parameter is optional.
Both the key and value parameters will be set.
=item sync
The flags parameter is optional.
=back
=head1 EXAMPLES
It is always a lot easier to understand something when you see a real
example. So here are a few.
=head2 Using HASH
use DB_File ;
use Fcntl ;
tie %h, "DB_File", "hashed", O_RDWR|O_CREAT, 0640, $DB_HASH ;
# Add a key/value pair to the file
$h{"apple"} = "orange" ;
# Check for existence of a key
print "Exists\n" if $h{"banana"} ;
# Delete
delete $h{"apple"} ;
untie %h ;
=head2 Using BTREE
Here is sample of code which used BTREE. Just to make life more
interesting the default comparision function will not be used. Instead
a Perl sub, C<Compare()>, will be used to do a case insensitive
comparison.
use DB_File ;
use Fcntl ;
sub Compare
{
my ($key1, $key2) = @_ ;
"\L$key1" cmp "\L$key2" ;
}
$DB_BTREE->{compare} = 'Compare' ;
tie %h, 'DB_File', "tree", O_RDWR|O_CREAT, 0640, $DB_BTREE ;
# Add a key/value pair to the file
$h{'Wall'} = 'Larry' ;
$h{'Smith'} = 'John' ;
$h{'mouse'} = 'mickey' ;
$h{'duck'} = 'donald' ;
# Delete
delete $h{"duck"} ;
# Cycle through the keys printing them in order.
# Note it is not necessary to sort the keys as
# the btree will have kept them in order automatically.
foreach (keys %h)
{ print "$_\n" }
untie %h ;
Here is the output from the code above.
mouse
Smith
Wall
=head2 Using RECNO
use DB_File ;
use Fcntl ;
$DB_RECNO->{psize} = 3000 ;
tie @h, DB_File, "text", O_RDWR|O_CREAT, 0640, $DB_RECNO ;
# Add a key/value pair to the file
$h[0] = "orange" ;
# Check for existence of a key
print "Exists\n" if $h[1] ;
untie @h ;
=head2 Locking Databases
Concurrent access of a read-write database by several parties requires
them all to use some kind of locking. Here's an example of Tom's that
uses the I<fd> method to get the file descriptor, and then a careful
open() to give something Perl will flock() for you. Run this repeatedly
in the background to watch the locks granted in proper order.
use Fcntl;
use DB_File;
use strict;
sub LOCK_SH { 1 }
sub LOCK_EX { 2 }
sub LOCK_NB { 4 }
sub LOCK_UN { 8 }
my($oldval, $fd, $db, %db, $value, $key);
$key = shift || 'default';
$value = shift || 'magic';
$value .= " $$";
$db = tie(%db, 'DB_File', '/tmp/foo.db', O_CREAT|O_RDWR, 0644)
|| die "dbcreat /tmp/foo.db $!";
$fd = $db->fd;
print "$$: db fd is $fd\n";
open(DB_FH, "+<&=$fd") || die "dup $!";
unless (flock (DB_FH, LOCK_SH | LOCK_NB)) {
print "$$: CONTENTION; can't read during write update!
Waiting for read lock ($!) ....";
unless (flock (DB_FH, LOCK_SH)) { die "flock: $!" }
}
print "$$: Read lock granted\n";
$oldval = $db{$key};
print "$$: Old value was $oldval\n";
flock(DB_FH, LOCK_UN);
unless (flock (DB_FH, LOCK_EX | LOCK_NB)) {
print "$$: CONTENTION; must have exclusive lock!
Waiting for write lock ($!) ....";
unless (flock (DB_FH, LOCK_EX)) { die "flock: $!" }
}
print "$$: Write lock granted\n";
$db{$key} = $value;
sleep 10;
flock(DB_FH, LOCK_UN);
untie %db;
close(DB_FH);
print "$$: Updated db to $key=$value\n";
=head1 HISTORY
=over
=item 0.1
First Release.
=item 0.2
When B<DB_File> is opening a database file it no longer terminates the
process if I<dbopen> returned an error. This allows file protection
errors to be caught at run time. Thanks to Judith Grass
E<lt>grass@cybercash.comE<gt> for spotting the bug.
=item 0.3
Added prototype support for multiple btree compare callbacks.
=item 1.0
B<DB_File> has been in use for over a year. To reflect that, the
version number has been incremented to 1.0.
Added complete support for multiple concurrent callbacks.
Using the I<push> method on an empty list didn't work properly. This
has been fixed.
=item 1.01
Fixed a core dump problem with SunOS.
The return value from TIEHASH wasn't set to NULL when dbopen returned
an error.
=head1 WARNINGS
If you happen find any other functions defined in the source for this
module that have not been mentioned in this document -- beware. I may
drop them at a moments notice.
If you cannot find any, then either you didn't look very hard or the
moment has passed and I have dropped them.
=head1 BUGS
Some older versions of Berkeley DB had problems with fixed length
records using the RECNO file format. The newest version at the time of
writing was 1.85 - this seems to have fixed the problems with RECNO.
I am sure there are bugs in the code. If you do find any, or can
suggest any enhancements, I would welcome your comments.
=head1 AVAILABILITY
Berkeley DB is available at your nearest CPAN archive (see
L<perlmod/"CPAN"> for a list) in F<src/misc/db.1.85.tar.gz>, or via the
host F<ftp.cs.berkeley.edu> in F</ucb/4bsd/db.tar.gz>. It is I<not> under
the GPL.
=head1 SEE ALSO
L<perl(1)>, L<dbopen(3)>, L<hash(3)>, L<recno(3)>, L<btree(3)>
Berkeley DB is available from F<ftp.cs.berkeley.edu> in the directory
F</ucb/4bsd>.
=head1 AUTHOR
The DB_File interface was written by Paul Marquess
<pmarquess@bfsec.bt.co.uk>.
Questions about the DB system itself may be addressed to Keith Bostic
<bostic@cs.berkeley.edu>.
=cut
|