=head1 NAME

ObjStore - Perl Extension For C<ObjectStore> OODBMS

=head1 SYNOPSIS

The new C<SQL> and the sunset of relational databases.

=head1 DESCRIPTION

C<ObjectStore> is the market leader in object-oriented databases
http://www.odi.com (NASDAQ: ODIS).  They use a unique I<Cache-Forward
Architecture> to make persistent data available in literally the most
efficient manner possible.

Prior to this joining of forces,

=over 4

=item *

C<ObjectStore> was too radical a design decision for many applications.

=item *

Perl5 did not have a simple way of storing complex data persistently.

=back

I<Now there is an easy way to build database applications, especially
if you are concerned about preserving your ideals of encapsulation.
(See below!)>

=head1 PREREQUISITES

=over 4

=item *

C<ObjectStore> OODBMS (see http://www.odi.com; evaluations are available!)

=item *

Perl 5.004_04 (or perl 5.005, once released)

=item *

L<Tree::Fat> & L<Test> perl extensions

=item *

L<ExtUtils::ExCxx> (only needed on Digital UNIX, HP (5.x), OS/2 (3.x),
or MS Windows NT/95; send email)

=back

=head1 TUTORIAL

One way to get started is to win the tutorial.  See
C<ObjStore::Tutorial> or, if you just can't wait, run the following
code and start molding it right now:

=head2 Quick Start!

  #!/usr/local/bin/perl -w
 
  use ObjStore;
  use ObjStore::Config;   #for 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
  };

=head2 TOOLS

=over 4

=item * ospeek

Prints out databases in a style similar to Data::Dumper.

=item * posh

Like C<sh>/C<csh>, except that you can I<change directory> B<into>
your database and walk around the data from the inside.  You can also
invoke methods on your objects or write custom reports (in perl, of
course :-).

=item * osperlserver

Run it against any database that inherits C<ObjStore::ServerDB> and it
will provide a remote method invokation service.

=back

=head1 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...

=head2 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 C<'new
$class($near, ...)'>.  You may pass any persistent object
(or database, or segment) in place of $near and the new object will
be created appropriately!

=head2 Hashes

The following code snippet creates a persistent hash reference with an
expected cardinality of ten elements.

    my $h7 = ObjStore::HV->new($store, 10);

An array representation is used for low cardinalities.  Arrays do not
scale well, but they do afford a pleasingly compact representation.
C<ObjectStore>'s C<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!  (Relief.)

=head2 Arrays

The following code snippet creates a persistent array reference with
an expected cardinality of ten elements.

    my $a7 = ObjStore::AV->new($store, 10);

Complete array support is available now, but you must must have at
least perl 5.004_57.  If you don't, none of the usually array
operations are supported except fetch and store.  (Actually push, pop,
shift and unshift might be available but are undocumented.)  At least
the following works:

    $a7->[1] = [1,2,3,[4,5],6];

=head2 References

You can generate a reference to any persistent object with the method
C<new_ref($segment)>.  Since refcnts are not updated remotely, refs
are the safest way to refer across databases.  They are also designed
to be allocated transiently.

  $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 are not open.  You
will need to C<open> them explicitly (see C<ObjStore::Ref::POSH_ENTER>).
Also note that references use significantly more memory than pointers.
(Look up C<os_reference_protected> in the ODI FAQ.)

Unsafe, unprotected references are also available:

  $r = $o->new_ref('transient', 'unsafe');

Care must to taken that these hard reference do not point to objects
that have already been deleted.  C<SEGV> or garbled data can result.
It is always safe to use hard references given they are used to merely
to avoid circular references within a single database.

=head2 Cursors

All containers have a method, C<new_cursor($near)>, that creates a
persistent cursor for the given container.  The following methods are
available.

  $cs->focus();                 # returns the cursor's collection
  $cs->moveto($pos);            # seek to the nth element
  ($k,$v) = $cs->at;            # returns the current element
  ($k,$v) = $cs->each(1);       # returns the next element

=over 4

=item *

First-class cursors for arrays & hashes are incomplete and under
construction.  If you can avoid them, do so!  (Array cursors might be
depreciated entirely.)

=item *

Array cursors return (index,value) pairs.  Hash cursors return
(key,value) pairs.  All cursors return the empty list () when no more
elements are available.

=item *

For hashes & arrays, you should not assume the order of iteration will
follow any particular pattern (but it probably will).

=item *

If you change membership of a collection while you're iterating
through it, something could break, so don't.

=back

=head2 Indices

SQL has this fantastic facility called indices.  C<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

Index cursors are a B<lot> more powerful than hash or array cursors.
Here are the available methods:

  $c->focus();
  $c->moveto();
  $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.
Therefore, it is not particularly useful to store pre-created cursors
in a database.  Just to create them transiently when needed.

To eliminate the possibility of indices becoming out-of-sync with
actual data, keys are marked read-only as they are indexed.  (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 our
read-only scheme.)

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 exception
  $row->{name} = "Rubber Doggie";        #READONLY exception
  $row->{owner} = $bob;                  #ok

The first key is the category's name.  The second key is the row's
name.

Indices should not be used unless other data structures prove
inadequate.  Hashes and arrays are easier in most cases.  Indices are
best suited to very large datasets that must be searchable in a
variety of ways.  If you can just iterate through every record,
indices probably aren't worth the trouble.

=head2 And Access Paths (Oh My!)

If you cross your eyes, you will see an array of references or cursors
as an access path.  Two simple implementations are provided for
manipulating access paths:

  ObjStore::Path::Ref            # access path composed of refs
  ObjStore::Path::Cursor         # cursor based access path (EXPERIMENTAL)

See the source code for details.

=head1 DATABASE DESIGN

The best design is to be flexible!

=head2 C<ospeek [-all] [-addr] [-refcnt] [-raw] E<lt>databaseE<gt>>

While there is no formalized schema for a perl database, the C<ospeek>
utility generates a sample of data content and structure.  C<ospeek>
never outputs more than a short summary, without regard to the size of
your database.

You can also get the same thing from within perl:

  ObjStore::peek($whatever);

=head2 Wait!  No Schema?!  How Can This Scale?  Wont I get lost in a
morass of disorganization?

How can a relational database scale?!  B<When you write down a central
schema, you are violating the principle of encapsulation.> This is
dumb.  None of the usual database management operations require a
central schema.  Why create artificial dependencies between your
classes when you can avoid it?

=head2 The Theory of Lazy Evolution

When you practice lazy evolution, you avoid changing data layouts in
favor of making queries smarter.  Since data usually out-bulks code,
this is the correct trade.  And since there isn't a artificial split
between the implementation language and some goofy database language,
schema evolution is reduced to the same problem as source code
compatibility.  (Database are essentially 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 partition
your data into manageable chunks.  Fortunately, databases interoperate
and can be used simultaniously.  Therefore, it is entirely unnecessary
to store all data in one database.  By splitting your data into
logical chunks, you should be able to minimize the impact of
structural changes.  (This is the same problem as designing good
APIs.)

The way you split up your database generally depends on three things
(wisdom gleened from developing a real-time trading system):

=over 4

=item * LOCALITY OF REFERENCE

The less data you have, the faster you can access it.  Work towards
perfect awareness of nothing.

=item * 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 is a
major performance advantage).

=item * COUPLING TIGHTNESS

Loosely coupled data can easily (and should) be split into multiple
databases.  (The most exciting data is tightly coupled.  Keep this
data close together. :-)

=back

Additional considerations can be found in the C<ObjectStore>
documentation, but that's about it.  The power and simplicity is hard
to describe because there's just not much to it.  (Just the absolute
minimum to meet every requirement. :-)

(For extra integrity verification, see the C<iscorrupt> method.)

=head2 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
C<ObjStore::Index> and C<ObjStore::Table3>.

=head1 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.  In general, the API mostly
mirrors the C<C++> API.  Refer to the C<ObjectStore> documentation for
exact symantics.  The API for C<::UNIVERSAL> is probably of most
interest to ex-C<C++> developers.  If you need an API that isn't
available in OS/Perl, send your request to the mailing list (see the
README).  If you are just getting started, skip to the next section.

=head2 C<ObjStore>

=over 4

=item * $db = ObjStore::open($pathname, $read_only, $mode);

Also see C<ObjStore::HV::Database> & C<ObjStore::Table3::Database>.

=item * $name = ObjStore::release_name()

=item * $major = ObjStore::release_major()

=item * $minor = ObjStore::release_minor()

=item * $maintenance = ObjStore::release_maintenance()

=item * $yes = ObjStore::network_servers_available();

=item * $num = ObjStore::return_all_pages();

=item * $size = ObjStore::get_page_size();

=item * @Servers = ObjStore::get_all_servers();

=item * $in_abort = ObjStore::abort_in_progress();

=item * $num = ObjStore::get_n_databases();

=back

=head2 C<::Server>

=over 4

=item * $name = $s->get_host_name();

=item * $is_broken = $s->connection_is_broken();

=item * $s->disconnect();

=item * $s->reconnect();

=item * @Databases = $s->get_databases();

=back

=head2 C<::Database>

See C<ObjStore::HV::Database>, C<ObjStore::Table3::Database>

=over 4

=item * $open_mode = $db->is_open();

=item * $s = $db->create_segment($comment);

=item * $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
like a necessary but annoying accounting detail.  It is much better
practice to use or inherit C<ObjStore::HV::Database> or
C<ObjStore::ServerDB>.

=item * $s = $db->get_segment($segment_number);

Note 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 C<get_all_segments>.

=item * @Segments = $db->get_all_segments();

=item * $db->close();

=item * $db->destroy();

=item * $db->get_default_segment_size();

=item * $db->get_sector_size();

=item * $db->size();

=item * $db->size_in_sectors();

=item * $ctime = $db->time_created();

=item * $can_write = $db->is_writable();

=item * $db->set_fetch_policy(policy[, blocksize]);

Policy can be one of C<segment>, C<page>, or C<stream>.

=item * $db->set_lock_whole_segment(policy);

Policy can be one of C<as_used>, C<read>, or C<write>.

=item * @Roots = $db->get_all_roots();

=item * $root = $db->create_root($root_name);

=item * $root = $db->find_root($root_name);

=item * $db->destroy_root($root_name);

Destroys the root with the given name if it exists.

=back

=head2 C<::Root>

=over 4

=item * $root->get_name();

=item * $root->get_value();

=item * $root->set_value($new_value);

=item * $root->destroy();

=back

=head2 C<::Transaction>

C<ObjectStore> transactions and exceptions are seemlessly integrated into
perl.  C<ObjectStore> exceptions cause a C<die> in perl just as perl
exceptions cause a I<transaction abort>.

    begin 'update', sub {
        $top = $db->root('top');
        $top->{abc} = 3;
        die "Oops!  abc should not change!";       # aborts the transaction
    };

There are three types of transactions: C<read>, C<update>, and
C<abort_only>.  The default is C<read>.  Read transaction are
blindingly fast.

    begin 'read', sub {
	my $var = $db->root('top');
	$var->{abc} = 7;	# write to $var triggers die(...)
    };

(In a read transaction, you are not allowed to modify persistent data.)

=over 4

=item * $T = ObjStore::Transaction::get_current();

=item * $type = $T->get_type();

=item * $pop = $T->get_parent();

=item * $T->prepare_to_commit();

=item * $yes = $T->is_prepare_to_commit_invoked();

=item * $yes = $T->is_prepare_to_commit_completed();

=item * $ObjStore::TRANSACTION_PRIORITY

=item * ObjStore::set_max_retries($oops);

=item * ObjStore::fatal_exceptions($yes);

=item * my $oops = ObjStore::get_max_retries();

=item * my $yes = ObjStore::is_lock_contention();

=item * my $type = ObjStore::get_lock_status($ref);

=item * my $tm = ObjStore::lock_timeout($rw);

C<$rw> should be either 'read' or 'write'.  Return value of 1 == 1
second.  Undef indicates that there is no timeout.

=item * ObjStore::lock_timeout($rw, $tm);

Set lock timeouts.

=back

Dynamic transactions are also available.  See C<ObjStore::Process>.

=head2 C<::Segment>

=over 4

=item * $s->set_comment($comment);

=item * $s->destroy();

=item * $size = $s->size();

=item * $yes = $s->is_empty();

=item * $yes = $s->is_deleted();

=item * $num = $s->get_number();

=item * $comment = $s->get_comment();

=item * $s->lock_into_cache();

=item * $s->unlock_from_cache();

=item * $s->set_fetch_policy($policy[, $size]);

Policy can be one of C<segment>, C<page>, or C<stream>.

=item * $s->set_lock_whole_segment($policy);

Policy can be one of C<as_used>, C<read>, or C<write>.

=back

=head2 C<::Notification>

Instant, effortless event dispatching for network distributed objects.

=over 4

=item * ObjStore::subscribe(...);

=item * ObjStore::unsubscribe(...);

=item * set_queue_size($size);

=item * ($size, $pending, $overflow) = queue_status();

=item * $fd = _get_fd();

=item * $n = receive([$timeout]);

=item * Receive();

=item * $db = $n->get_database;

=item * $p = $n->focus;

=item * $why = $n->why;

=back

=head2 C<::UNIVERSAL>

All persistent objects inherit from C<ObjStore::UNIVERSAL>.

=over 4

=item * I<overload>

Stringify, boolean coersion, and equality tests.

=item * C<os_class>

Reports the natural persistent class of the object.  All persistent
objects must have this class in their C<@ISA> tree.

=item * C<rep_class>

Reports the representation's class.

=item * C<bless>

C<bless> stores the current C<@ISA> tree and the version of every
member of the C<@ISA> tree.  (In addition to the usual meaning of
bless.)

=item * C<$o->isa($baseclass)>

Whether the $baseclass was part of the C<@ISA> tree (at the moment of
blessing).  (C<UNIVERSAL::can> remains un-modified.)

=item * C<$o->versionof($baseclass)>

Returns the version of the $baseclass (at the moment of blessing).

=item * C<$o->subscribe()> and C<$o->unsubscribe()>

These might not be available per-object.  Only per-segment or
per-database.

=item * C<$o->notify($why, $when)>

Sends a notification to subscribers.  When can be either 'now' or
'commit'.  The $when parameter might be required.  Also being
considered is a means to bunch notifications together for batch send.

=item * C<$errs = $o-E<gt>iscorrupt($verbosity_level)>

Application specific integrity checking can be achieved by providing
an C<_iscorrupt> method.

=item * C<$o->is_evolved>

By default, checks version numbers of every class in the old C<@ISA>
tree.  Your C<$o-E<gt>evolve()> method should bring stuff up-to-date.
You may be able to simply re-C<bless> the object to accomplish the
evolve.

=item * Of

C<database_of> and C<segment_of> are always available as methods.

=item * C<posh>

C<posh> behavior can be customized by adding special methods.
See the section on C<posh>.

=back

To make everything seem apparently consistent, C<ObjStore::Database>
(while not really being a storable object) is lavishly special-cased
to support most (maybe all!) of the above features.

=head1 THE ADVANCED CHAPTER

=head2 Performance Check List

The word I<tuning> implies too high a brain-level requirement.
B<Getting performance out of C<ObjectStore> is not rocket science.>

=over 4

=item * 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 less than twice the size of it's un-compressed ASCII
dump; i.e., less than 2 times expansion.  (See the section on
representation.)

=item * DO AS MUCH AS POSSIBLE PER TRANSACTION

Transactions, especially update transactions, involve a good deal of
setup/cleanup.  The more you do per transaction the better.

=item * 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.

=item * SEGMENTS

Is your data partitioned into as many segments as reasonable?

=item * AVOID THE NETWORK

Run your program on the same machine as the C<ObjectStore> server.

=item * DO STUFF IN PARALLEL

If you have an MP machine, you can do reads/updates in parallel (even
without kernel threads).

=item * WHERE IS THE REAL BOTTLENECK?

Use C<Devel::*Prof> or a similar tools to analyze your program.  Make
your client-side cache bigger/smaller.

=item * SPEED UP PERL

Try using the perl compiler.  See http://www.perl.com

=item * LOCKING AND CACHING

Object Design claims that caching and locking parameters also impact
performance.  (See C<os_segment::set_lock_whole_segment> and
C<os_database::set_fetch_policy>.)

=item * THROW MONEY AT THE PROBLEM

Get a more memory, more CPUs, upgrade to your network, or hire C<C++>
programmers and redo your project in C<C++>.  Perl isn't the solution
to everything (yet :-).

=back

=head2 Transactions Redux

=over 4

=item * A BRIEF HISTORY OF TRANSACTIONAL MEMORY USAGE

Each time you access a persistent object, a small amount of transient
memory is reserved until the transaction completes (to cope with perl
scoping rules).  For this reason, and for speed, you should avoid
repeating long access paths.

  ++ $at->{bob}{house}{fridge}{beer};  #go to the minimart
  -- $at->{bob}{house}{fridge}{beer};  #big gulp

Instead, use a lexical variable to keep the fridge door open:

  my $fridge = $at->{bob}{house}{fridge};
  ++ $fridge->{beer};
  -- $fridge->{beer};

=item * NESTING

Nested transactions are supported but transaction modes must match.
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 a read or the same mode as the parent.
      ...
    };
  }

=item * MIXING WITH EVAL

It is possible to use C<eval> within transactions, but B<you
absolutely must not> use the C<ObjectStore> API or access any
persistent memory.

  begin('read', sub {
    ...
    eval { $db->root('new root' => [1,2,3]); };
    ...
  });

In the above code, the update in a read transaction will cause an
exception that crashes perl.  This is due to the excellent but
imperfect integration of C<ObjectStore> exceptions and perl
exceptions.  I understand how to fix it, just haven't had time.  In
general, you should global replace C<eval>s with C<begin>s.

=item * RELAXING EXCEPTION SEVERITY

Transactions are always executed within an implicit C<eval>.  By
default, ObjectStore exceptions are fatal (by demand of my
co-workers).  If you do not want your program to become suicidal when
an C<ObjectStore> exception occurs, you should indicate that you want
to have control over your own reflexive behavior:

  ObjStore::fatal_exceptions(0);

This is global to the whole process.  If you want control, however,
then you have to accept responsibility: after a transaction you
absolutely must remember to check the value of C<$@> to see if
anything went wrong.

  begin(sub {
     ...
  });
  die if $@;    # Don't forget to remember!  Always check for errors!

Is it recommended that any perl extensions explicitly check for
errors, just in case exceptions are not automatically re-thrown.

=item * DEADLOCK

Top level transactions are automatically retried in the case of a
deadlock.  You can increase the number of retries with
C<ObjStore::set_max_retries($retries)>.  Or if you need to handle
deadlocks yourself, you can set the number of retries to zero.  (There
is not much point to retrying I<non->top-level transactions because
locks are released only at the top-level [OS 4-5.0.*].)

=back

=head2 Stargate Mechanics

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 address 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 C<ObjStore.pm> for inspiration.  (Not recommended. :-)

=head2 How Can I Rescue Persistent Objects From Oblivion?

All data stored in C<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 get one chance to save the object: the C<NOREFS>
method is invoked just prior to deletion.  You must create a new
persistent reference to it or kiss the object goodbye.

Note that the C<DESTROY> method is still invoked every time an object
becomes unreachable from the current scope.  However, contrary to
transient objects, this method does not truly preview object
destruction.  (Hacking C<DESTROY> such that it can be used as
C<NOREFS> is desirable, but would require changes to the core perl
code-base.  This change is under consideration...)

=head2 C<posh>

C<posh> is your interactive window into databases.

It is designed treat your data in an application specific manner.
Customize by providing your own implementation for these methods:

=over 4

=item * C<$o->help();>

=item * C<$o-E<gt>POSH_PEEK($peeker, $o_name);>

=item * C<$o-E<gt>POSH_CD($path);>

=item * C<$o-E<gt>POSH_ENTER();>

=back

There are lots of good examples throughout the standard C<ObjStore::>
libraries.

=head2 Arrays-as-Hashes

Fantastically efficient records:

  use base 'ObjStore::AVHV';
  use fields qw(f1 f2 f3);

$ObjStore::COMPILE_TIME XXX

See C<ObjStore::AVHV> XXX

=head2 Autoloading

When you use a database, ObjStore tries to C<require> each class that
doesn't seem loaded.  This means that you can write generic data
processing programs that load the appropriate libraries to manipulate
data in application specific ways.

To disable class autoloading behavior call this function before you
open any databases:

  ObjStore::disable_class_auto_loading();

This mechanism is orthogonal to the C<AUTOLOAD> mechanism for
autoloading functions.

=head2 Where's the Hard Part?

I don't know.  I haven't found it yet!

=head1 DIRECTION

=over 4

=item * 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 is ease of use.  No detail will be overlooked,
I<all> must conform to effortless styistic perfection.

=item * MORE APIs

Support for any other interesting C<ObjectStore> APIs.

=item * MORE BUILT-IN DATA TYPES

Support for bit vectors (Bit::Vector) and matrices (PDL)?

=back

=head2 How Does CORBA Fit In?

C<CORBA> standardizes remote method invokation (RMI).  C<ObjectStore>
greatly reduces the need for remote method invokation and also
provides a simple but effective RMI mechanism (see
C<ObjStore::Notification> and C<ObjStore::ServerDB>).  The two
technologies address different problems, but here is a rough
comparison:

                      CORBA                     ObjectStore
 -------------------- ------------------------- -------------------------
 flow                 you follow the data       the data comes to you
 network              important                 what network?
 flexibility          brittle                   up to you
 object-oriented      yes                       up to you
 data copying         2-4 times                 0-2 times
 complex data         no                        yes
 custom types         no                        yes
 binary portability   yes                       partially
 reference counted    no (does not store data)  yes
 multivendor          yes                       not yet

=head2 Why Is Perl a Better Fit For Databases Than C<SQL>, C<C++>, or C<Java>?

  struct CXX_or_Java_style {
	char *name;
	char *title;
	double size;
  };

When you write a structure declaration in C<C++> or C<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 C<SQL>-style language is needed.
When you create a table in C<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 C<SQL> gives you far less expressive power
than C<C++> or C<Java>.  Applications end up being written in C<C++>
or C<Java>, while their data is stored with C<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 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.  This declaration is actually even
more flexible than C<SQL> because the field-types are left dynamic.  But
not only is perl more flexible, it's also fast.  Malcolm Beattie is
working on a perl compiler which is currently in beta.  Here is his
brief description of a new hybrid hash-array that is supported: I<An
array ref $a can be dereferenced as if it were a hash ref.
$a-E<gt>{foo} looks up the key "foo" in %{$a-E<gt>[0]}. The value is
the index in the true underlying array @$a. As an addition, if the
array ref is in a lexical variable tagged with a classname ("my CXX
$obj" to match your example above) then constant key dereferences of
the form $obj-E<gt>{foo} are mapped to $obj-E<gt>[123] at compile time
by looking up the index in %CXX::FIELDS.>

For example:

  my $schema_hashref = { 'field1' => 1, 'field2' => 2 };
  my $arr = [$schema_hashref, 'fwaz', 'snorf'];
  print "$arr->{field1} : $arr->{field2}\n";      # "fwaz : snorf"

So perl will soon compile to optimized C<C> (with C<C>-like data access
times!).  It's almost too good to be true.

=head2 Why Is Perl Easier Than Other Programming Languages?

I have no idea!

=head2 Summary (LONG)

=over 4

=item * C<SQL>

All perl databases use the same flexible schema that can be examined
and updated with generic tools.  This is the I<key> advantage of
C<SQL>, now available in perl.  In addition, Perl / C<ObjectStore> is
blatantly faster than C<SQL> / C<C++>.  (Not to mention that perl is a
fun programming language while C<SQL> is at best a clunky I<query
language> and C<C++> is at best an I<engineering language>.)

=item * C<C++>

Special purpose data types can be coded in C<C++> and dynamically
linked into perl.  Since C<C++> will always be able to beat C<Java>
benchmarks, this gives perl an edge in the long run.  Perl is to
C<C/C++> as C<C/C++> is to assembly language.

=item * JAVA

C<Java> has the buzz, but:

=over 4

=item *

Just like C<C++>, the lack of a universal generic schema limits use to
single applications.  Without some sort of C<tie> mechanism, I can't
imagine how this could be remedied.  (Even with C<tie>, it might
already be too late.  Java was not conceived to evolve quite as
rapidly as is perl.  Imagine that: "designed to evolve"!)

=item *

All C<Java> databases must serialize data to store and retrieve it.
Until C<Java> supports memory-mapped persistent allocation, database
operations will always be sluggish compared to C<C++>.  Not even
god-like compiler technology can completely cure poor language design.

=item *

Perl integrates with C<Java> and the C<SwingSet / AWT> API.  (Of
course, this is a moot point if you can use C<Qt> -
http://www.troll.no/.)

=back

=back

=head2 Summary (SHORT)

Perl can store data

=over 4

=item *

optimized for flexibility and/or for speed

=item * 

in transient memory and persistent memory

=back

without violating the principle of encapsulation or obstructing
general ease of use.

=head2 ETA: 1-3 Months

  perl compiler
  kernel-managed perl threads
  dynamically loaded application schemas

=head1 EXPORTS

C<bless> and C<begin> by default.  Most other static methods can also
be exported.

=head1 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)

Perl / C<ObjectStore> extension is available via any CPAN mirror site.
See http://www.perl.com/CPAN/authors/id/JPRIT/ !

Portions of the collection code were snapped from I<splash>, Jim
Morris's delightful C<C++> library
ftp://ftp.wolfman.com/users/morris/public/splash .

Also, a poignant thanks to all the wonderful teachers with which I've
had the opportunity of studying.  If you have never had a teacher, I
highly recommend it!

=head1 SEE ALSO

C<ObjStore::Tutorial>, C<ObjStore::Table3>, examples in the t/
directory, C<ObjStore::Internals>, C<Event>, C<PerlQt>, and C<The SQL
Reference Manual> (I<just kidding> :-)

=cut
