=head1 NAME

ObjStore - Perl Extension For ObjectStore OODBMS

=head1 SYNOPSIS

  use ObjStore;
  use ObjStore::Config;

  my $db = ObjStore::open(TMP_DBDIR . "/silly.db", 0, 0666);

  try_update {
      my $wb = $db->root('whiteboard', sub {new ObjStore::AV($db, 1001)});
      for (my $x=0; $x < 1000; $x++) {
          $wb->[$x] = {
               repetition => $x,
               msgs => ["I will not talk in ObjectStore/perl class.",
                        "I will study the documentation before asking questions."]
          };
      }
  };
  print "Very impressive.  I see you are already an expert.\n";

=head1 DESCRIPTION

The new SQL and the sunset of relational databases.

ObjectStore is the leading object-oriented database.  It is engineered
by Object Design, Inc. ( http://www.odi.com ) (NASDAQ: ODIS).  The
database uses the virtual memory mechanism to make persistent data
available in the most efficient manner possible.

In case you didn't know, Object Design's Persistent Storage Engine has
been licensed by Sun, Microsoft, Netscape, and Symantic for inclusion in
their Java development environments.

Prior to this joining of forces,

=over 4

=item *

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 databases, especially if you care about
preserving your ideals of data encapsulation.  (See below!)>

=head1 API

I<Fortunately, you probably wont need to use most of the API.  It is
exhibited below mainly to make it seem like this product has a
difficult and steep learning curve.>  B<Skip to the next section.>

Mostly, the API mirrors the C++ API.  Refer to the ObjectStore
documentation for exact symantics.  If you need a function that isn't
available in perl, send mail to the OS/Perl mailing list (see the
README).

=head2 ObjStore

=over 4

=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 * ObjStore::set_auto_open_mode(mode, fp, [sz]);

=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 * $db = ObjStore::open($pathname, $read_only, $mode);

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

=back

=head2 ::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 ::Database

=over 4

=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 * $is_open = $db->is_open();

=item * $db->open_mvcc();

=item * $is_mvcc = $db->is_open_mvcc();

=item * $read_only = $db->is_open_read_only();

=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 * $db = ObjStore::Database::of($pvar);

=item * $Seg = $db->create_segment();

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

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

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

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

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

=item * $value = $db->root($root_name[, $new_value]);

This is the recommended API for roots.  If the given root is not
found, creates a new one.  Sets the root's value if $new_value is
defined.  Returns the root's current value.

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

Destroys the root with the given name if it exists.

=back

=head2 ::Root

=over 4

=item * $root->get_name();

=item * $root->get_value();

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

=item * $root->destroy();

=back

=head2 ::Transaction

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

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

There are three types of transactions: C<try_read>, C<try_update>,
and C<try_abort_only>.  In a read transaction, you are not allowed
to modify persistent data.

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

=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::set_transaction_priority($very_low);

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

=item * ObjStore::rethrow_exceptions

=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::get_readlock_timeout();

=item * my $tm = ObjStore::get_writelock_timeout();

=item * ObjStore::set_readlock_timeout($tm);

=item * ObjStore::set_writelock_timeout($tm);

=back

=head2 ::Segment

=over 4

=item * $Seg->destroy();

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

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

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

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

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

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

=item * $Seg->lock_into_cache();

=item * $Seg->unlock_from_cache();

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

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

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

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

=item * $Seg = ObjStore::Segment::of($pvar);

=back

=head1 CONTAINERS

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.  Segment improve locality of reference and can be
a unit of locking or caching.

When you create a container you must specify the segment in which it
is to be allocated.  All containers are created using the form C<'new
ObjStore::$type($store, $cardinality)'>.  You may pass any persistent
object in place of $store and the new container will be created in the
same segment as the $store object!

=head2 Arrays

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

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

None of the usually array operations are supported except fetch and
store.  (Push, pop, shift and unshift are available but not
documented..., oops!)  At least the following works:

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

Complete array support will be available as soon as Larry and friends
fix the TIEARRAY interface.  (See perltie(3) or http://www.perl.com
more info.)

=head2 Hashes

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

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

An array representation is used for low cardinalities.  Arrays do not
scale well, but they do afford a compact representation.
ObjectStore's C<os_Dictionary> is used for large cardinalities.

Data structures can be built with the normal perl syntax:

    $h7->{foo} = { 'fwaz'=> { 1=>'blort', 'snorf'=>3 }, b=>'ouph' };

Or the equally effective but unbearibly tedious:

    my $h1 = $dict->{foo} ||= new ObjStore::HV($dict);
    my $h2 = $h1->{fwaz} ||= new ObjStore::HV($h1);
    $h2->{1}='blort';
    $h2->{snorf}=3;
    $h1->{b}='ouph';

Perl saves us again!  Relief.

=head2 Sets

If you have installed older releases, you might know that sets were
supported.  They still work, but they are re-implemented in terms of
hashes.

=head2 And Cursors (Oh My!)

All containers have a method, C<new_cursor($segment)>, that creates
a persistent cursor.  A cursor is like any other object.  It is stored
in the database and you can bless it into a package.  The following
methods are always available:

  $cs = $c->new_cursor($seg);   # creates a cursor in segment $seg
  $c2 = $cs->focus;             # returns another ref to $c
  ($k,$v) = $cs->next;          # returns the next element

=over 4

=item *

Arrays return (index,value) pairs.  Hash cursors return (key,value)
pairs.  Sets do something reasonable, but they are highly depreciated.
All cursors return the empty list () when no more elements are
available.

=item *

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, anything could happen, so don't.

=item *

Depending on the collection representation, cursors may have
additional useful behavior.  Currently, there is no way to test for
this.

=item *

Cursors do not change the primary reference count; they use weak
references.  That means that you can know if the container is deleted
even while cursors are focused on it.  Use the C<deleted> method to
check.

Cursors are also the only safe way to refer across databases. XXX

=back

In the future, cursors may be extended to support the following
methods:

  $en = $cs->prev;
  $cs = $key;              # seek to $key
  $dist = $cs - $cs2;      # return the distance between two cursors

There may also be a way to test for availability of advanced
features.  (E.g. 'can_chicken_walk')

=head1 INTROSPECTION

=head2 ospeek

While there is no formalized schema for a perl database, the C<ospeek>
utility generates a sample of data content and structure.  The
following output was snapped from a database created with the
SYNOPSIS.  This is the full, complete output.  C<ospeek> outputs a
summary, not the entire database.

=head2 Wait!  No Schema?!  How Can This Scale?

How can a relational database scale?!  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 Lazy Evolution

Even schema evolution can be done piecemeal.  Give all your objects an
C<evolve> method that insures that their representation is up-to-date.

=over 4

=item *

Tag your objects with version numbers.

=item *

Or intelligently figure out how to evolve objects by examining their
current structure.

=back

The main thing is to keep an archive of prior object formats to
regression test your new C<evolve> methods.  If you can do extracts to
a mini-database, that would do the trick.  Then just run your new code
through a copy of your historical database.

=head2 ospeek Example Output

  ObjStore::Root whiteboard = ObjStore::AV [
    ObjStore::HV {
      msgs => ObjStore::AV [
        'I will not talk in ObjectStore/perl class.',
        'I will study the documentation before asking questions.',
      ],
      repetition => 0,
    },
    ObjStore::HV {
      msgs => ObjStore::AV [
        'I will not talk in ObjectStore/perl class.',
        'I will study the documentation before asking questions.',
      ],
      repetition => 1,
    },
    ObjStore::HV {
      msgs => ObjStore::AV [
        'I will not talk in ObjectStore/perl class.',
        'I will study the documentation before asking questions.',
      ],
      repetition => 2,
    },
    ...
  ],
  Examined 1022 persistent slots.

=head2 posh

You can also walk around a database from the inside.  Study the output
I snapped from this C<posh> session:

  posh 1.17 (Perl 5.00403 ObjectStore Release 5.0.1.0)
  [set for READ]

C<I</opt/os/tmp%> B<ls>>

  copier.db         perltest.db.copy  silly.db
  perltest.db       posh.db           test.db

C<I</opt/os/tmp%> B<cd silly.db>>

  $at = ObjStore::HV {
    whiteboard => ObjStore::UNIVERSAL::Ref ...
  },

C<I<%> B<cd $at-E<gt>{whiteboard}-E<gt>focus>>

C<I<$at = ObjStore::AV=ARRAY(0xe0580000)%> B<ls>>

  $at = ObjStore::AV [
    ObjStore::HV ...
    ObjStore::HV ...
    ObjStore::HV ...
    ...
  ],

C<I<$at = ObjStore::AV=ARRAY(0xe0580000)%> B<ls $at-E<gt>[0]-E<gt>{msgs}>>

  [0] = ObjStore::AV [
    'I will not talk in ObjectStore/Perl class.',
    'I will study the documentation before asking questions.',
  ],

C<I<$at = ObjStore::AV=HASH(0xe0580000)%> B<update>>

  [set for UPDATE]

C<I<$at = ObjStore::AV=ARRAY(0xe0580000)%> B<cd $at-E<gt>[0]-E<gt>{msgs}>>

C<I<$at = ObjStore::AV=ARRAY(0xe058201c)%> B<$at-E<gt>[0] = 'This is ridiculous.';>>

  $fake1 = 'This is ridiculous.',

C<I<$at = ObjStore::AV=ARRAY(0xe058201c)%> B<ls>>

  $at = ObjStore::AV [
    'This is ridiculous.',
    'I will study the documentation before asking questions.',
  ],

C<I<$at = ObjStore::AV=ARRAY(0xe058201c)%> B<cd ..>>

C<I<$at = ObjStore::AV=ARRAY(0xe0580000)%> B<ls>>

  $at = ObjStore::AV [
    ObjStore::HV ...
    ObjStore::HV ...
    ObjStore::HV ...
    ...
  ],

C<I<$at = ObjStore::AV=ARRAY(0xe0580000)%> B<for (1..100) { $at-E<gt>[$_] = $at-E<gt>[0]; }>>

  $fake2 = '',

C<I<$at = ObjStore::AV=ARRAY(0xe0580000)%> B<ls(map {$at-E<gt>[$_]-E<gt>{msgs}} 68..70)>>

  [0] = ObjStore::AV [
    'This is ridiculous.',
    'I will study the documentation before asking questions.',
  ],
  [1] = ObjStore::AV [
    'This is ridiculous.',
    'I will study the documentation before asking questions.',
  ],
  [2] = ObjStore::AV [
    'This is ridiculous.',
    'I will study the documentation before asking questions.',
  ],

=head1 WHY IS PERL A BETTER FIT FOR DATABASES THAN SQL, C++, OR JAVA?

When you write a structure declaration in C++ or Java you are
assigning both field-names, field-types, and field-order.

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

Programs almost always require a recompile to change any of these
attributes.  This is fine for small to medium size applications but is
not suitable for large databases.  It is too inflexible.  An SQL-type
language is needed.

When you create a table in SQL you are assigning only field-names and
field-types.

  create table CXX
  (name varchar(80),
   title varchar(80),
   size double)

This is a more flexible data declaration, 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 in SQL.  Managing the
syncronization between the two languages creates a lot of extra
complexity.  So much so that there are many software companies that
exist solely to help address this headache.

perl is better because it spans all the requirements in a single
language.  For example, this is similar to an SQL table:

  my $h1 = { name => undef, title => undef, size => undef };

Only the field-names are specified.

To address the other side of the spectrum, Malcolm Beattie is working
on a perl compiler which is currently in beta-test.  Here is his brief
description of a new hybrid hash-array that is supported:

	An array ref $a can be dereferenced as if it were a hash
ref.  $a->{foo} looks up the key "foo" in %{$a->[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->{foo} are mapped to $obj->[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"

I haven't done benchmarks yet, but considering the implementation,
compiled fake hashes should make perl very competitive with Java /
ObjectStore database applications in terms of raw performance.

=head2 Summary (LONG)

=over 4

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

Perl / ObjectStore is definitely faster than SQL too. Not to mention
that perl is a general purpose programming language and SQL is at best
a I<query language>.

=item * C++

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

=item * JAVA

Java has the buzz, but:

=over 4

=item *

Just like C++, the lack of a universal generic schema limits use to a
single application at a time.  Without some sort of C<tie> mechanism,
I don't see how this can be remedied.

=item *

All Java databases must serialize data to store it.  Until Java
supports persistent allocation directly, database operations will
always be slower than C++.

=item *

Perl will soon integrate with Java enough to use SwingSet - AWT.

=item *

I'd like to see some comparisions of code length when solving the same
problems in Java and in perl.  I have a strong suspicion that it is
easier to do data processing in perl.

=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

=over 4

=item * 0-3 MONTHS

Perl compiler; perl kernel threads; fake hashes

=item * 3-6 MONTHS

Dynamically loaded application schemas;
proper tied arrays; debugged tie interface;
Perl-Java integration

=back

=head1 THE ADVANCED CHAPTER

=head2 Bless

The ObjStore module installs its own version of C<bless> which assures
that blessings are persistent.  For example:

    package MyObject;
    use ObjStore;
    @ISA = qw(ObjStore::HV);
    sub new {
        my ($class, $store) = @_;
        my $o = $class->SUPER::new($store, $class);
        $o->{attribute} = 5;
        $o;
    }

    package main;
    my $o = new MyObject($db);

If you store each class in a separate C<.pm> file in your @INC path
(see C<require>), then the classes will be autoloaded as you traverse
your data.

=head2 Class Autoloading

ObjStore tries to C<require> each class as you access persistent
instances the first time.  This means that you can write generic data
processing programs that automatically load the appropriate libraries
to manipulate data as it's accessed.

To disable the class autoloading behavior:

  ObjStore::disable_class_auto_loading();

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

=head2 Transactions Redux

=over 4

=item * EVAL

Transactions are always executed within an implicit C<eval>.  If you
do not want to abort your program when an ObjectStore exception
occurs, you should indicate that you want to have control over your
own reflexive behavior:

  ObjStore::rethrow_exceptions(0);

After a transaction, you will need to check the value of C<$@> to see
if anything went wrong and determine how to proceed.

  try_update {
     ...
  };
  die if $@;    # check for errors!

=item * DEADLOCK

Transactions are automatically retried in the case of a deadlock.  If
you need to handle deadlocks specially, you can use
ObjStore::set_max_retries(0) and write the logic (or illogic)
yourself.

=back

=head2 Stargate

The stargate determines which collection representations are used to
store implicitly created hashes and arrays.  It is called recursively
on data structures in order to copy them into persistent memory.  If
you replace the default stargate with your own, make sure to dismember
the transient structures as they are processed to insure that cyclic
structures will be collected in transient memory.  (See C<ObjStore.pm>
for an example.)

=head2 Cross Database Pointers

You can allow cross database pointers with:

  $db->allow_external_pointers;

But do not do this brainlessly!  Databases that have references to
other databases affect refcnts.  Your refcnts will be wrong if you
simply C<osrm> random databases.  This will cause some of your data to
become undeletable.

To deal with this properly, you must systematically C<undef> all your
references and insure that a given database is empty before you
C<osrm> it.  C<$db->destroy> contains the appropriate logic.  However,
pay special attention to cyclic structures.  You must break all cycles
in your data to allow it to be collected by C<$db->destroy>.  It's not
hard, you just need to pay attention to detail.

=head2 Performance Check List

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

=over 4

=item * DO AS MUCH AS POSSIBLE PER TRANSACTION

=item * SEGMENTS

Is your data partitioned into as many segments as possible?  (See
the introduction to containers.)

=item * COMPACTNESS

Is your data stored as compactly as possible?  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 database should be less than twice
the size of it's ASCII dump; i.e., less than 2 times expansion.  (See
the section of data representation.)

=item * WHERE IS THE REAL BOTTLENECK?

Use the 'time' command or DProf to analyze where your program is
spending most of it's time.  osp_copy is bottlenecked by perl and the
network, not the database.  Try using the perl compiler.  (See
http://www.perl.com ) Try upgrading to your network to ATM or run
your program on the same machine as the ObjectStore server.

=item * LOCKING AND CACHING

Object Design claims that your caching and locking settings also
impact performance.  I haven't been able to verify this.  (See
os_segment::set_lock_whole_segment and os_database::set_fetch_policy.)

=back

=head1 TECHNICAL IMPLEMENTATION

You don't have to understand anything about the technical
implementation.  Just know that:

=over 4

=item *

ObjectStore is outrageously powerful, sophisticated, and over-engineered.

=item *

The perl interface is optimized for simplicity and easy of use.  I<(If it's
not fun, why bother?)>

=back

The performance of raw ObjectStore is so good that even with a gunky
perl layer, benchmarks will show that relational databases can be
safely left on the bookshelf where they belong.

=head2 Differences Between The Perl And C++ APIs

Most stuff should be roughly the same.  However,

=over 4

=item *

Some static methods sit directly under C<ObjStore::>

=item *

Transactions are simplified.

=back

=head2 Data Representation

Memory usage is much more important in a database than in transient
memory.  When databases can be as large or larger than ten million
megabytes, a few percent difference in compactness can mean a lot.

To store 32 bit signed integers and doubles, small memory blocks must
be allocated.  Integers are stored in C<OSPV_iv> and doubles are
stored in C<OSPV_nv>.  16 bit signed integers are stored much more
efficiently than other types of numbers.  However, you may need to
tell perl to C<use integer> since perl generally defaults to using
doubles.

[table of bytes per ?]

  splash collections ...

=head2 Hard Limits

=over 4

=item *

Reference counts are only 32 bits unsigned.

=item *

Weak reference counts are only 16 bits unsigned.

=item *

Strings are limited to a length of 32767 bytes.

=back

=head2 Go Extension Crazy

C<ObjStore::UNIVERSAL> is the base class for all persistent objects.
You cannot directly access persistent scalars from perl. They are
always immediately copied into transient scalars.  So the
C<ObjStore::UNIVERSAL> base class is only for objects (or
collections).

C<ObjStore::UNIVERSAL::Ref> is the base class for references.

C<ObjStore::UNIVERSAL::Container> is the base class for all
containers.

C<ObjStore::UNIVERSAL::Cursor> is the base class for cursors.

C<ObjStore::AV> is the base class for tied arrays.

C<ObjStore::HV> is the base class for tied hashes.

C<ObjStore::File> will be the base class for large binary data.

When an ObjectStore exception occurs, C<$ObjStore::EXCEPTION> is
called with an explaination.  You can replace the default handler with
your own function.

Each subclass of C<ObjStore::UNIVERSAL::Container> has a C<%REP> hash.
Persistent object implementations add their create functions to the
hash.  Each packages' C<new> method decides on the best
representation, calls the creation function, and returns the
persistent object.

You can add your own C++ representations for each of AV and HV.  If
you want to know the specifics, look at the code for the built-in
representations (C<GENERIC.*>).

You can add new families of objects that inherit from
C<ObjStore::UNIVERSAL>.  Suppose you want highly optimized, persistent
bit vectors?  Or matrics?  These would not be difficult to add.
Especially once Object Design figures out how to support multiple
application schemas within the same executable.  They claim that this
tonal facility will be available in the next release.

=head2 ossv_bridge typemap

The following explaination may be helpful to developers trying to
understand the ObjStore typemap.  If you don't know what a typemap is,
just skip to the next section.

The struct C<ossv_bridge> is used to bridge between perl and C++
objects.  It contains transient cursors and transient pointers to
persistent data.  Immediately after a transaction finishes,
C<invalidate> is invoked on all outstanding bridges.

This is necessary in order to update the reference counts properly.
This was also the most difficult part to get right.  But hey, how many
databases do ref counting?

=head1 DIRECTION

=over 4

=item * LEANER COLLECTION REPRESENTATIONS

The ObjectStore collections are weighted down with unnecessary index
and query support.  I'd like to replace them with a suite of lean
representations for large cardinality collections to compliment the
Splash collections.

=item * MORE BUILT-IN DATA TYPES

File objects implemented using osmmtype and subclassed from
IO::Handle.  Support for one of Object Design's Text Object Managers?
Support for bit vectors and matrics?

=item * APIs

Support for notification, database access control, and any other
interesting ObjectStore APIs.

=back

=head1 EXPORTS

C<bless>, C<try_read>, C<try_update>, C<try_abort_only> by default.
Most other static methods can also be exported.

=head1 BUGS

=over 4

=item * HIGH VOLITILITY

Anything not documented is subject to change without notice.  (I will
try to preserve backward compatibility when possible.)

=item * CURSED OBJECTS

The strings used to record the blessed nature of persistent objects
are allocated in a private hash in the default segment of a database
(See C<'ospeek -all'>).  If you accidentally mess up or change any of
these strings, your objects will be cursed.  You have a backup, right?

=item * NESTED TRANSACTIONS

Disabled until the transaction support is cleaned up.

=item * MOP

This is not a general purpose ObjectStore editor with complete MOP
support.  Actually, I don't think this is a bug.

=back

=head1 AUTHOR

Copyright (c) 1997 Joshua Nathaniel Pritikin.  All rights reserved.

This package is free software; you can redistribute it and/or modify
it under the same terms as perl itself.  The software is provided "as
is" without express or implied warranty.  Perl / ObjectStore is
available via any CPAN mirror site.  See
http://www.perl.com/CPAN/modules/by-module/ObjStore

Portions of the collection code snapped from I<splash>, Jim Morris's
delightful 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.

=head1 SEE ALSO

Examples in the t/ directory, perl5, ObjectStore, I<and never again
SQL!>

=cut
