NAME
ObjStore - Perl Extension For ObjectStore
OODBMS
SYNOPSIS
Enjoy perl? Sick of SQL? Ready to trying something new?
DESCRIPTION
ObjectStore
is the market leader in object-oriented databases http://www.odi.com (NASDAQ: ODIS). They use a unique Cache-Forward Architecture to make persistent data available in literally the most efficient manner possible.
Prior to this joining of forces
ObjectStore
was too radical a design decision for many applicationsPerl5 did not have a simple way of storing complex data persistently
Now there is an easy way to build database applications (especially if you are concerned about preserving your ideals of encapsulation).
PREREQUISITES
ObjectStore
OODBMS (see http://www.odi.com - evaluations are available!)Perl 5.005 (5.004_05 might be okay)
ExtUtils::ExCxx (only needed on Digital UNIX, HP (5.x), OS/2 (3.x), or MS Windows NT/95; send email)
WHAT IS THIS GREEN SLIME??
Maybe you're feeling like you're in unfamiliar territory? You see green slime oozing from the ceiling. Something doesn't smell right and the a shiver runs through hair on the back of your neck. I hope you're a quick learner! Many people haven't made it!
Learning something new is hard work. This may be true, but isn't it easier to get ahead than be left behind? It's a preditory world. Which is really easier?
Quick Start!
#!/usr/local/bin/perl -w
use ObjStore;
use ObjStore::Config ('$TMP_DBDIR');
my $db = ObjStore::open("$TMP_DBDIR/myjunk", 'update', 0666);
begin 'update', sub {
# $junk can be any arbitrary non-circular structure up to 2GB in size
my $junk = {
pork => [1,2,3],
chicken => [1,2,3],
wheat => [1,2,3],
trials => 0,
};
$db->root("junk", sub { $junk }); #store it, if it's not there already
my $pjunk = $db->root("junk"); #fetch it
$pjunk->{trials} ++; #update something
ObjStore::peek($db); #dump to stdout
};
Sample Inheritance Tree
ObjStore::UNIVERSAL
ObjStore::Container
ObjStore::AV
ObjStore::AV::QSet
ObjStore::AVHV
ObjStore::Path::Ref
ObjStore::REP::FatTree::Index::Conf
ObjStore::REP::ODI::HashIndex::Conf
ObjStore::REP::Splash::Heap::Conf
ObjStore::HV
ObjStore::AVHV::Fields
ObjStore::Serve
ObjStore::ServerDB::Top
ObjStore::Table3
ObjStore::Index
ObjStore::Cursor
ObjStore::Ref
Also see Devel::Symdump.
Tools
ospeek
Prints out databases in a style similar to Data::Dumper.
posh & qtposh
Like
sh
/csh
, except that you can change directory into your database and walk around from the inside. You can also invoke methods on your objects or write custom reports (in perl, of course :-). (Similar toisql
/wisql
.)osperlserver
Provides a server framework including remote method invokation, job scheduling, and server-object collaboration services. Completely generic.
WHAT IS PERSISTENT PERL?
It's just like normal perl, except that you can create data that doesn't go away when your program exits. This more permenant data lives in files or raw disk partitions that are divided into databases. And databases are comprised of...
Segments
Segments dynamically resize from very small to very big. You should split your data into lots segments when it makes sense. Segments improve locality and can be a unit of locking or caching.
When you create a database object you must specify the segment in which it is to be allocated. All objects use the form '$class-
new($near, ...)'>. You may pass any persistent object (or database or segment) in place of $near
and the new object will be created appropriately.
Hashes
The following code snippet creates a persistent hash reference with an expected cardinality of ten elements.
my $h7 = ObjStore::HV->new($store, 10);
A simple array representation is used for low cardinalities. Arrays do not scale well, but they do afford a pleasingly compact memory footprint. ObjectStore
's os_Dictionary
is transparently used for large cardinalities [MAYCHANGE].
Persistent data structures can be built with the normal perl construction:
$h7->{foo} = { 'fwaz'=> { 1=>'blort', 'snorf'=>3 }, b=>'ouph' };
Or the equally effective, but unbearibly tedious:
my $h1 = $dict->{foo} ||= ObjStore::HV->new($dict);
my $h2 = $h1->{fwaz} ||= ObjStore::HV->new($h1);
$h2->{1}='blort';
$h2->{snorf}=3;
$h1->{b}='ouph';
Perl saves us again!
Arrays
The following code snippet creates a persistent array reference with an expected cardinality of ten elements.
my $a7 = ObjStore::AV->new($store, 10);
Once you have a persistent array, everything else is mostly the same as any other type of array. All the usual array operations will just work.
However, complete array support requires at least perl 5.004_57. If you need to upgrade, consider doing so.
References
You can generate a reference to any persistent object with the method new_ref($segment, $type)
. Since reference do not affect reference counts, they are a safe way to refer across databases. They can also be allocated transiently. Transient references are useful because they remain valid across transaction boundries.
$r->open($how); # attempts to open the focus' database
$yes = $r->deleted; # is the focus deleted?
$f = $r->focus; # returns the focus of the ref
$str = $r->dump; # the ref as a string
Be aware that references can return garbage if they point to data in a database that is not open. You will need explicitly open
them if in doubt (see ObjStore::Ref::POSH_ENTER
). Currently, there are two types of references supported. They correspond to os_reference
and os_reference_protected
. The type passed to new_ref
should be either 'unsafe' or 'safe' respectively. For example,
$r = $o->new_ref('transient', 'unsafe');
$r = $o->new_ref(); # same as above
This creates an os_reference
. Care must to taken that these hard reference do not point to objects that have already been deleted. A SEGV
(if you're lucky) or garbled data can result.
Fortunately, it is always safe to use hard references in the case that they are used to merely to avoid circular references within a single database. For example:
my $o = ObjStore::HV->new($db);
$$o{SELF} = $o->new_ref($o,'hard');
The reference in hash slot 'SELF' can be used by any part of the downwardly nested data structure to point back to the top-level.
A database itself is somewhat similar in the sense that every object has a database_of
method. You might say that every member of a database has an implicit reference to the top-level of the database.
Indices
SQL has this fantastic facility called indices. ObjStore
does too!
my $nx = ObjStore::Index->new($near);
$nx->configure(unique => 1, path=>"name");
$nx->add({name=> 'Square'}, {name=> 'Round'}, {name=> 'Triangular'});
my $c = $nx->new_cursor;
$c->seek('T');
$c->step(1);
warn $c->at()->{name}; # Triangular
All the index representations supplied by default do not copy records' keys. The keys are used in-place and are (usually) marked read-only. Since the keys are not copied, the index is stored in less space and can be accessed faster. Or at least until it grows larger than the client-side cache. None of the indices support key copying at the present but the change is not difficult. If you send email to the list, I probably come up with a fix.
Indices should not be used unless other data structures prove inadequate. Some indices cannot be allocated transiently. Simple hashes and arrays are less trouble in most cases. Indices are best suited to large data-sets that must be indexed in more than a few ways. If you can always afford to iterate through every record then indices probably aren't worth the trouble.
Index Cursors
Index cursors are a lot more powerful than hash or array cursors. The methods available are:
$c->focus();
$c->moveto($record_no);
$c->step($delta);
$c->seek(@keys);
my $pos = $c->pos();
my @keys = $c->keys();
my $v = $c->at();
my $v = $c->each($delta);
Where the following invariants hold:
$c->moveto($c->pos() + $delta) is $c->step($delta)
$c->each($delta) is { $c->step($delta); $c->at(); }
Be aware that index cursors may only be used by one thread at a time. Thus, it is usually not worthwhile to store pre-created cursors persistently. Create transient ones as needed.
Index Representations
Certain representations for indices are very sensitive to the proper order of the records that they contain (trees in particular). To eliminate the possibility of indices diverging with indexed data, keys are marked read-only when records are added to the index. This insures that indices will not be disordered by ad-hoc updates to records' keys. (Just imagine if people were constantly changing the meanings of words as you read this sentance!)
For example:
my $category = { name => 'Bath Toy' };
my $row = { name => 'Rubber Ducky', category => $category };
$index->configure(path => 'category/name, name');
$index->add($row);
$row->{category}{name} = 'Beach Toy'; # READONLY
$row->{name} = "Rubber Doggie"; # READONLY
$row->{owner} = $bob; # ok
The first key is the category's name. The second key is the row's name.
Another scheme for keeping indices up-to-date is to use os_backptr
. This scheme is not supported because it has considerable memory overhead (12-bytes per record!) and provides little benefit beyond the read-only scheme.
The exact constraints of indexing are dependent on the index representation and the record representation. Different representations can allow a greater or lesser degree of flexibility. If you need something that is not supported by default, it is likely that the wanted behavior can be implemented with new representations. (Virtual sunglasses not included. :-)
And Access Paths (Oh My!)
If you cross your eyes, you may be able to visualize an array of references or cursors as an access path. Two simple implementations are included:
ObjStore::Path::Ref # access path composed of refs
ObjStore::Path::Cursor # EXPERIMENTAL
See the source code for details.
DATABASE DESIGN
The best design is to be flexible!
The best design is to be flexible!
The best design is to be flexible!
ospeek [-all] [-addr] [-refcnt] [-raw] <database>
While there does not exist a central formalized schema for a perl database the ospeek
utility outputs a sample of data content and structure. ospeek
never outputs more than a brief summary no matter how much stuff is in your database.
You can get the same output within a perl script using:
ObjStore::peek($whatever);
Wait! No Schema?! How Can This Scale? Wont I get lost in a morass of disorganization and change-control meetings?
How can a relational database scale?! When you write down a central schema you are violating the principle of encapsulation. This is dumb. While relational databases might have been a revelation when they were conceived, why is it still common practice to create artificial dependencies and breaches of abstraction in database design? It is entirely avoidable!
The Theory of Lazy Evolution
When you practice lazy evolution, you avoid changing data layouts in favor of making queries smarter.
This is the correct trade because data usually out-bulks code. Furthermore, since there isn't a artificial split between the implementation language and a goofy, unempowered database language schema evolution is reduced to the same problem as source code compatibility. (Database are just a rich API.)
Now, I'm not saying that data layouts never have to change. When thinking about data, the first thing to consider is how to organize your data to improve your ability to evolve.
First of all, it is entirely unnecessary to store all data in a single database. Multiple databases interoperate and can be used simultaniously. For example, you can have a separate database for each day or each month. By starting fresh with a new database it is easier to make structural changes while perserving backward compatibility. It reduces the scope of the problem in comparison to relational databases.
Within a database, the way you split up your database generally depends on three things:
LOCALITY OF REFERENCE
The less data you have, the faster you can access it. Aim for a perfect awareness of nothing.
REAL-TIME WRITERS
It is usually good design to create a separate database for each group of real-time writers. Readers of real-time data can open databases in
mvcc
mode and writers will never encounter lock contention (which can cause performance degradation).COUPLING TIGHTNESS
Loosely coupled data can easily be split into multiple databases. The most exciting data is tightly coupled; keep this data close together.
A few additional considerations can be found in the ObjectStore
documentation but that's about it. Don't over-complicate things. This isn't a relational database, remember? The power and simplicity is hard to describe because there's just not much to it. (Just the absolute minimum to get the job done. :-)
RDBMS Emulation
Un-structured perl databases are probably under-constrained for most applications. Fortunately, RDBMS style tables have been adapted, adopted, and included with this package. While they are a little different from traditional tables, with a few doses of Prozac relational developers should feel right at home. See ObjStore::Index
and ObjStore::Table3.
API REFERENCE
Fortunately, you will probably not need to use most of the API. It is exhibited here mainly to make it seem like this extension has a difficult and steep learning curve (it doesn't). In general, the API mostly mirrors the ObjectStore
C++
API. Refer to the ObjectStore
documentation for exact symantics.
The API for ::UNIVERSAL
is probably of most interest to ex-C++
developers. If you are just getting started, skip to the next section.
ObjStore
$db = ObjStore::open($pathname, $read_only, $mode);
Also see ObjStore::HV::Database.
$name = ObjStore::release_name()
$version = ObjStore::os_version()
$yes = ObjStore::network_servers_available();
$num = ObjStore::return_all_pages();
$size = ObjStore::get_page_size();
@Servers = ObjStore::get_all_servers();
$in_abort = ObjStore::abort_in_progress();
$num = ObjStore::get_n_databases();
::Server
$name = $s->get_host_name();
$is_broken = $s->connection_is_broken();
$s->disconnect();
$s->reconnect();
@Databases = $s->get_databases();
::Database
Also see ObjStore::HV::Database.
$open_mode = $db->is_open();
$s = $db->create_segment($comment);
$value = $db->root($root_name => sub{ $new_value });
This is the recommended API for roots. If the given root is not found, creates a new one. Returns the root's current value.
In general, you should try to avoid using roots. Roots have an unnatural API for perl: hashes can nest but roots cannot. Roots are similar to a necessary but annoying accounting detail. It is much better practice to use ObjStore::HV::Database or ObjStore::ServerDB.
$s = $db->get_segment($segment_number);
Be aware that this method (correctly) never returns an error. The only way to know which segments are actually created in a database is to iterate through
get_all_segments
.@Segments = $db->get_all_segments();
$db->close();
$db->destroy();
$db->get_default_segment_size();
$db->get_sector_size();
$db->size();
$db->size_in_sectors();
$ctime = $db->time_created();
$can_write = $db->is_writable();
$db->set_fetch_policy(policy[, blocksize]);
Policy can be one of
segment
,page
, orstream
.$db->set_lock_whole_segment(policy);
Policy can be one of
as_used
,read
, orwrite
.@Roots = $db->get_all_roots();
$root = $db->create_root($root_name);
$root = $db->find_root($root_name);
$db->destroy_root($root_name);
Destroys the root with the given name if it exists.
::Root
$root->get_name();
$root->get_value();
$root->set_value($new_value);
$root->destroy();
::Transaction
ObjectStore
transactions and exceptions are seemlessly integrated into perl. ObjectStore
exceptions cause a die
in perl just as perl exceptions can cause a transaction abort.
begin 'update', sub {
$top = $db->root('top');
$top->{abc} = 3;
die "Oops! abc should not change!"; # aborts the transaction
};
die if $@;
There are three types of transactions: read
, update
, and abort_only
. The default is read
. Read transaction are blindingly fast.
begin 'read', sub {
my $var = $db->root('top');
$var->{abc} = 7; # write to $var triggers exception
};
die if $@;
(In a read transaction, you are not allowed to modify persistent data.)
$T = ObjStore::Transaction::get_current();
$type = $T->get_type();
$pop = $T->get_parent();
$T->prepare_to_commit();
$yes = $T->is_prepare_to_commit_invoked();
$yes = $T->is_prepare_to_commit_completed();
$ObjStore::TRANSACTION_PRIORITY
ObjStore::set_max_retries($oops);
my $oops = ObjStore::get_max_retries();
my $yes = ObjStore::is_lock_contention();
my $type = ObjStore::get_lock_status($ref);
my $tm = ObjStore::lock_timeout($rw);
$rw
should be either 'read' or 'write'. Return value of 1 == 1 second. Undef indicates that there is no timeout.ObjStore::lock_timeout($rw, $tm);
Set lock timeouts.
Dynamic transactions are also available. See ObjStore::Serve.
::Segment
$s->set_comment($comment);
$s->destroy();
$size = $s->size();
$yes = $s->is_empty();
$yes = $s->is_deleted();
$num = $s->get_number();
$comment = $s->get_comment();
$s->lock_into_cache();
$s->unlock_from_cache();
$s->set_fetch_policy($policy[, $size]);
Policy can be one of
segment
,page
, orstream
.$s->set_lock_whole_segment($policy);
Policy can be one of
as_used
,read
, orwrite
.
::Notification
Easy event dispatching for network distributed objects. See ObjStore::notify.
ObjStore::subscribe(...);
ObjStore::unsubscribe(...);
set_queue_size($size);
($size, $pending, $overflow) = queue_status();
$fd = _get_fd();
$n = receive([$timeout]);
Receive();
$db = $n->get_database;
$p = $n->focus;
$why = $n->why;
::UNIVERSAL
All persistent objects inherit from ObjStore::UNIVERSAL
.
overload
Stringify, boolean & numeric coersion, equality tests.
os_class
Reports the natural persistent class of the object. All persistent objects must have this class in their
@ISA
tree.rep_class
Reports the representation's class.
bless
In addition to the usual meaning of bless, ObjStore
bless
stores the current@ISA
tree and theVERSION
of every member of the@ISA
tree.$o-
isa($baseclass)>Whether the $baseclass was part of the
@ISA
tree at the moment of blessing.$o-
versionof($baseclass)>Returns the version of the $baseclass (at the moment of blessing).
$o-
subscribe()> and$o-
unsubscribe()>These might not be available per-object. Only per-segment or per-database. XXX
$o-
notify($why, $when)>Sends a notification to subscribers. When can be either 'now' or 'commit'. The $when parameter might be required. [Also under consideration is a means to bunch notifications together for batch send. XXX]
Of
database_of
andsegment_of
are available as methods.posh
posh
behavior can be customized by adding special methods that are detected byposh
. See the posh section.
To make everything seem apparently consistent, ObjStore::Database
(while not really being a storable object) is lavishly special-cased to support most (maybe all!) of the above features.
THE ADVANCED CHAPTER
Performance Check List
The word tuning implies too high a brain-level requirement. Getting performance out of ObjectStore
is not rocket science. On the other hand, you shouldn't think that perl will ever go as fast as optimized C++
. That's what DLL
schemas are for. For an example, see ObjStore::REP::HashRecord.
DO AS MUCH AS POSSIBLE PER TRANSACTION
Transactions, especially update transactions, involve a good deal of setup and cleanup. The more you do per transaction the better.
AVOID THE NETWORK
Run your program on the same machine as the
ObjectStore
server.SEGMENTS
Is your data partitioned into a reasonable number of segments?
IS MUTABLE DATA MOSTLY SEPARATED FROM READ-ONLY DATA?
Update transaction commit time is proportional to the amount of data written AND to the number of pages with modifications. Examine your data-flow and data-dependencies.
COMPACTNESS
You get 90% of your performance because you can fit your whole working data set into RAM. If you are doing a good job, your un-indexed database should be more compact that it's un-compressed ASCII dump. (See the "Internal" in ObjStore section on data representation.)
DO STUFF IN PARALLEL
If you have an MP machine, you can do reads/updates in parallel (even without multi-threading).
WHERE IS THE REAL BOTTLENECK?
Use
Devel::*Prof
or a similar tools to analyze your program. Make your client-side cache bigger/smaller.SPEED UP PERL
Try using the perl compiler. See 'perlcc --help'.
LOCKING AND CACHING
Object Design claims that caching and locking parameters also impact performance. (See
os_segment::set_lock_whole_segment
andos_database::set_fetch_policy
.) You may also want to take advantage of their knowledgable consulting services arm.AVOID DATABASES
Plain cheap RAM is always faster than any database. If you don't need all the guarentees of data integrity then memory-mapped files or battery-backed RAM are as fast as it gets. There is no reason that an application cannot make use of every opportunity to optimize for speed.
Transactions Redux
EXCEPTIONS & EVAL
Transactions are always executed within an implicit
eval
. Therefore, after a transaction check$@
to see if anything went wrong:begin(sub { ... }); die if $@;
XXX explain how $@ is set up as a reference XXX
NESTING
Nested transactions are supported with all the same restrictions of the
C++
interface. You can nest reads within reads or updates within updates, but not reads within updates (nor updates within reads). If you need to do a read but you don't care if the parent transaction is an update or not, you can leave the mode unspecified.sub do_extra_push_ups_in_a_transaction { begin sub { ... # Unspecified mode assumes 'read' # or the same mode as the parent. ... }; }
DEADLOCK RETRIES
Built-in automatic deadlock retry is not supported. Support was withdrawn not because it doesn't work but because it doesn't make much sense in perl. Deadlock retry is so easy to implement yourself, you should (if you even need it).
Stargate Mechanics
Here is how to create hashes and arrays pre-sized to exactly the right number of slots:
ObjStore::HV->new($near, { key => 'value' }); # 1 slot
ObjStore::AV->new($near, [1..3]); # 3 slots
Or you can interface the stargate directly:
my $persistent_junk = ObjStore::translate($near, [1,2,3,{fat=>'dog'}]);
If you want to design your own stargate, you may inspect the default stargate in ObjStore.pm
for inspiration. (Not recommended. ;-)
How Can I Rescue Persistent Objects From Oblivion?
All data stored in ObjectStore
is reference counted. This is a fantastically efficient way to manage memory (for most applications). It has very good locality and low overhead. However, as soon as an object's refcnt reaches zero, it is permenantly deleted from the database. You only have one chance to save the object. The NOREFS
method is invoked just prior to deletion. You must hook it back into the database or kiss the object goodbye.
Be aware that the DESTROY
method is still invoked every time an object becomes unreachable from the current scope. However, contrary to transient objects this method does not preview persistent object destruction. (Hacking DESTROY
such that it is used instead of NOREFS
is desirable but would require changes to the perl code-base. This change is under consideration. Let me know if you care. XXX)
Also see ObjStore::Mortician!
posh
posh
is your command-line window into databases.
posh
obediently tries to treat your data in an application specific manner. Customize by providing your own implementation of these methods:
$o-
help();>$o->POSH_PEEK($peeker, $o_name);
$o->POSH_CD($path);
$o->POSH_ENTER();
There are lots of good examples throughout the standard ObjStore::
libraries. Also see ObjStore::Peeker.
Arrays-as-Hashes
use base 'ObjStore::AVHV';
use fields qw(f1 f2 f3);
Fantastically efficient records hash records. See ObjStore::AVHV and fields.
Autoloading
As you use a database, ObjStore
tries to require
each class that doesn't seem to be loaded. To disable class autoloading behavior, call this function before you open any databases:
ObjStore::disable_class_auto_loading();
This mechanism is orthogonal to perl's AUTOLOAD
mechanism for autoloading functions.
Where Is The Hard Part?
I don't know. I am humbly working hard trying to find it.
DIRECTION
PERFECT NATURAL CLARITY
The overwhelming top priority is to make this extension work seemlessly, obviously, and effortlessly. Really, the only difference between lisp and perl (if there is any difference) is ease of use. No detail will be overlooked, everything must conform to effortless styistic perfection.
MORE APIs
Support for any other interesting
ObjectStore
APIs.MORE BUILT-IN DATA TYPES
Support for bit vectors (Bit::Vector) and matrices (PDL)?
How Does CORBA Fit In?
CORBA
standardizes remote method invokation (RMI). ObjectStore
greatly reduces the need for remote method invokation and also provides a simple but effective RMI mechanism (see ObjStore::notify and ObjStore::ServerDB). The two technologies address different problems but here is a rough comparison:
GENERALLY CORBA ObjectStore
-------------------- ------------------------- -------------------------
flow you follow the data the data comes to you
network central assumption what network?
flexibility brittle up to you
object-oriented yes up to you
data copying 2-4 times 0-2 times
binary portability yes somewhat
reference counted no (does not store data) yes (at least for perl)
multi-vendor yes not yet
MESSAGING CORBA ObjectStore
--------------------- ------------------------- ------------------------
reliable yes? no
a/syncronous both? async only
Why Is Perl a Better Fit For Databases Than SQL
, C++
, or Java
?
struct CXX_or_Java_style {
char *name;
char *title;
double size;
};
When you write a structure declaration in C++
or Java
you are declaring field-names, field-types, and field-order. Programs almost always require a re-compile to change such rigid declarations. This is fine for small applications but becomes cumbersome quickly. It is too hard to change (brittle). An SQL
-style language is needed. When you create a table in SQL
you are declaring only field-names and field-types.
create table SQL_style
(name varchar(80),
title varchar(80),
size double)
This is more flexible, but SQL
gives you far less expressive power than C++
or Java
. Applications end up being written in C++
or Java
while their data is stored with SQL
. Managing the syncronization between the two languages creates enormous extra complexity. So much so that there are lots of software companies that exist solely to address this headache. (You'd think they'd try to cure the problem directly instead of addressing the symptom!) Perl is better because it transparently spans all the requirements in a single language.
my $h1 = { name => undef, title => undef, size => 'perl' };
Only the field-names are specified. It should be clear that this declaration is even more flexible than SQL
. The field-types are left dynamic. Actually, even the field-names are not fixed. The flexibility potential is very great. It might even be too flexible!
Fortunately, perl anticipated this. Perl is flexible about how flexible it is. Therefore, if you need rigidity and the speed that comes with it, you have recourse. Specific objects or subsystems can be implemented directly in C++. It's win-win (at least!).
Why Is Perl Easier Than All Other Programming Languages?
I have no idea!
Summary (LONG)
SQL
All perl databases use the same flexible schema that can be examined and updated with generic tools. This is the key advantage of
SQL
, now available in perl. In addition, Perl /ObjectStore
is blatantly faster thanSQL
/C++
. (Not to mention that perl is a fun programming language whileSQL
is at best a clunky query language andC++
is at best an engineering language.)C++
Perl has no friction with
C++
. Special purpose data types can be coded inC++
and dynamically linked into perl. SinceC++
will always beatJava
benchmarks (see below) this gives perl an edge in the long run. Perl is toC/C++
asC/C++
is to assembly language.JAVA
Java
has the buzz (had?), but:Just like
C++
, the lack of a universal generic schema limits use to single applications. Without some sort oftie
mechanism I can't imagine how this could be remedied. (Even withtie
it might already be too late. Java was not conceived to evolve quite as rapidly as is perl. One must embrace the paradox "design for change!")All
Java
databases must serialize data to store and retrieve it. UntilJava
supports memory-mapped persistent allocation, database operations will always be sluggish compared toC++
. Not even god-like compiler technology can completely cure poor language design.Perl integrates with
Java
and theSwingSet / AWT
API. (Of course, this is a moot point if you can useQt
orGtk
.)
Summary (SHORT)
Perl can store data
optimized for flexibility and/or for speed
in transient memory and persistent memory
without violating the encapsulation principle or obstructing general ease of use.
EXPORTS
bless
and begin
by default. Most other static methods can also be exported.
ENVIRONMENT VARIABLES
PERL5PREFIX
Where the distribution is installed.
OSPERL_SCHEMA_DBDIR
Where to find schema databases.
AUTHOR
Copyright © 1997-1998 Joshua Nathaniel Pritikin. All rights reserved.
This package is free software and is provided "as is" without express or implied warranty. It may be used, redistributed and/or modified under the terms of the Perl Artistic License (see http://www.perl.com/perl/misc/Artistic.html)
The Perl / ObjectStore
extension is available via any CPAN mirror site. See http://www.perl.com/CPAN/authors/id/JPRIT/
Portions of the collection code were derived from splash, Jim Morris's delightful C++
library ftp://ftp.wolfman.com/users/morris/public/splash
SEE ALSO
ObjStore::Table3
, examples in the t/ directory, ObjStore::Internals
, Event
, PerlQt
, and The SQL Reference Manual
(just kidding :-)
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 1127:
Non-ASCII character seen before =encoding in '©'. Assuming CP1252