=head1 NAME

ObjStore - Perl extension for ObjectStore OODBMS

=head1 SYNOPSIS

    use ObjStore;

    my $osdir = ObjStore->schema_dir;
    my $DB = ObjStore::Database->open($osdir . "/perltest.db", 0, 0666);

    try_update {
        my $top = $DB->root('whiteboard');
        $top ||= $DB->root('whiteboard', new ObjStore::HV($DB, 1000));
        for (my $x=1; $x < 10000; $x++) {
	    $top->{$x} ||= {
	        id => $x,
	        m1 => "I will not talk in ObjectStore/Perl class.",
	        m2 => "I will study the documentation before asking questions.",
	    };
        }
	print "Very impressive.  I see you are already an expert.\n";
    };
    print "[Abort] $@\n" if $@;

=head1 DESCRIPTION

The new SQL and the sunset of relational databases.

ObjectStore is the leading object-oriented database.  It is produced
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.  Object Design's
Persistent Storage Engine has been licensed by Microsoft, Netscape,
and Symantic for inclusion in their Java development environments.

Prior to this joining of forces, ObjectStore was too radical a design
decision for many applications.  And Perl5 did not have a simple way
of storing complex data persistently.

I<Now there is an easy way to build databases, especially in the
circumstance that the schema changes rapidly.>

=head1 OBJECTSTORE PHILOSOPHY

ObjectStore is outrageously powerful, sophisticated, even
over-engineered.  It does way too much for the average
get-the-job-done programmer.  The theme of this interface for
ObjectStore is simplicity and easy of use.  I<If it's not fun, why
bother?> Life is suppose to be fun and exciting, all the time!  And 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.

Specifically, this module is optimized for flexibility, then memory
performance, then speed.  If you really want speed, wait 3-6 months
for Perl5 to get support for kernel threads.  Or see the TODO list
about dynamic linking your own custom C++ objects.

=head1 OBJECTSTORE API

Much of this API is a direct interface to the C++ API.  Refer to the
ObjectStore documentation for exact symantics.

=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 * $size = ObjStore::get_page_size();

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

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

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

=item * $DB->close();

=item * $DB->destroy();

=item * $DB->get_default_segment_size();

=item * $DB->get_sector_size();

=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]);

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.

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

There are three types of transactions: C<try_read>, C<try_abort_only>,
and C<try_update>.  Each execute the given block within an implicit
C<eval>.  After a transaction, be sure to check the value of C<$@> to
see if anything went wrong.  For example,

    try_read {
	my $var = $DB->root('top');
	$var->{abc} = 7;	# write to $var triggers exception
    };
    die if $@;			# exception rethrown to top-level

Needless to say, you cannot access or modify persistent data outside
of a transaction.

=over 4

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

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

=back

=head2 ::SEGMENT

=over 4

=item * $Seg->destroy();

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

=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

=over 4

=item * SEGMENTS

Databases are composed of segments.  Segments dynamically resize from
around 32k to as big as you want.  You should split your data into
lots segments when it makes sense.  Segments are a good thing.  They
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 via 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!

=item * BLESS

The ObjStore module overloads C<'bless'>.  Once you create a
container, you may C<bless> it in your own package.  The blessing is
persistent.  For example,

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

=back

=head2 SETS

The following code snippet creates a set with an expected cardinality
of ten elements.

    my $set = new ObjStore::Set($store, 10);

Sets are simple collections.  They do not allow duplicates.  The
following methods are supported:

    $set->a($obj, { hello=>1 });
    $set->r($obj);
    $yes = $set->contains($obj);
    for (my $obj = $set->first; $obj; $obj = $set->next) {
	# do something with $obj
    }

An array representation is used for low cardinalities.  Arrays are not
efficient, but they are compact.  ObjectStore's C<os_set> is
used for large cardinalities.

Changing the membership of a set while iterating over the members
has undefined results.

=head2 ARRAYS

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

=head2 HASHES

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

    my $h1 = 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.

Hashes are created implicitly during assignment.  Implicitly created
hashes assume an expected cardinality of around ten and are created in
the same segment as the enclosing hash.

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

This tidy single line is short-hand for the 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.

=head1 OSPEEK

While no official schema is need to create a database, the C<ospeek>
utility can be used to generate a sample of data content and
structure.  The following output was snapped from a database that
supports a CGI application we have developed.  Note how circular
references and pointers between objects are summarized.

 ObjStore::Root=SCALAR(0x18aa6c) Bright = Node {
    VERSION => 5,
    center => 1,
    ctime => '19970814113317',
    daily_hits => ObjStore::HV {
      19970814 => 1,
    },
    desc => 'We are what we think.  All that we are arises with our thoughts.  With our thoughts we make the world.',
    hits => 1,
    name => 'Bright',
    owner => '0',
    reflected => '0',
    rel => ObjStore::Set [
      Node {
        ctime => '19970814113317',
        daily_hits => ObjStore::HV {
          19970814 => 8,
        },
        desc => '',
        hits => 8,
        n_anon => 6,
        name => 'Joe's Store',
        owner => Node { ... }
        reflected => 1,
        rel => ObjStore::Set [
          Node { ... }
          Node {
            ctime => '19970814113317',
            desc => 'New users arrive here.',
            hits => '0',
            index => ObjStore::HV {
              Anon-4 => User {
                ctime => '19970814130657',
                daily_hits => ObjStore::HV {
                  19970814 => 1,
                },
                desc => 'Anonymous temporary login.',
                expire => '19970915130657',
                hits => 1,
                name => 'Anon-4',
                owner => User { ... }
                reflected => 3,
                rel => ObjStore::Set [
                  Node { ... }
                ],
                views => ObjStore::HV {
                  1 => User::View {
                    at => Node {
                      color => 'light green',
                      ctime => '19970814124048',
                      daily_hits => ObjStore::HV {
                        19970814 => 8,
                      },
                      desc => '',
                      hits => 8,
                      name => 'Research',
                      owner => Node { ... }
                      reflected => 1,
                      rel => ObjStore::Set [
                        Node { ... }
                        Node { ... }
                        Node { ... }
                        Node { ... }
                      ],
                      url => '',
                    },
                    prior => ObjStore::HV {
                      0 => Node { ... }
                      1 => Node { ... }
                      2 => User { ... }
                    },
                  },
                  2 => User::View {
                    at => User { ... }
                  },
                },
              },
              Anon-5 => User {
                ctime => '19970814191636',
                desc => 'Anonymous temporary login.',
                expire => '19971013191636',
                hits => '0',
                name => 'Anon-5',
                owner => User { ... }
                reflected => 3,
                rel => ObjStore::Set [
                  Node { ... }
                ],
                views => ObjStore::HV {
                  1 => User::View {
                    at => User { ... }
                    prior => ObjStore::HV {
                      0 => User { ... }
                    },
                  },
                  2 => User::View {
                    at => User { ... }
                  },
                },
              },
              Anon-6 => User {
                ctime => '19970814191724',
                desc => 'Anonymous temporary login.',
                expire => '19971013191724',
                hits => '0',
                name => 'Anon-6',
                owner => User { ... }
                reflected => 3,
                rel => ObjStore::Set [
                  Node { ... }
                ],
                views => ObjStore::HV {
                  1 => User::View { ... }
                  2 => User::View { ... }
                },
              },
              joshua => User {
                ctime => '19970814113317',
                daily_hits => ObjStore::HV {
                  19970814 => 13,
                },
                desc => '',
                dreamer => 1,
                expire => '19971013182157',
                hits => 13,
                name => 'joshua',
                owner => User { ... }
                passwd => 'zzReR55rX6.JA',
                proposals => ObjStore::Set [
                  User::Proposal {
                    about => Node { ... }
                    ctime => '19970814195243',
                    from => User { ... }
                    to => User { ... }
                  },
                ],
                reflected => 3,
                rel => ObjStore::Set [
                  Node { ... }
                ],
                url => '',
                views => ObjStore::HV {
                  1 => User::View { ... }
                  2 => User::View { ... }
                },
              },
            },
            name => 'Users',
            owner => Node { ... }
            reflected => 2,
            rel => ObjStore::Set [
              Node { ... }
              User { ... }
              User { ... }
              User { ... }
              User { ... }
            ],
          },
          Node { ... }
        ],
      },
      Node { ... }
      Node { ... }
    ],
  },


=head1 PERSISTENT REPRESENTATION

It is not practical to simply make perl's internal data structures
persistent.  For one thing, there are horrendous technical problems.
But more importantly, values in the database have different
requirements than transient values.  Upscale, New York style attire is
needed.

=over 4

=item * MEMORY

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.

=item * REFERENCE COUNTING

Persistent data is reference counted differently from transient data.

=back

Fortunately, you don't have to think about or understand anything
about the persistent representation unless you want to have precise
control of your database activities.

=head1 GO BEYOND

Here is an outline of how to go extension crazy.

C<ObjStore::UNIVERSAL> is the base class for all persistent types.

In general, 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 used for objects (or
collections).  The C<'_at'> method can be used to access scalars as
C<'ObjStore::Raw'> objects in certain cases, but there are no methods
to manipulate them except from C++.  Currently, only C<bless> makes
use of the C<_at> method.

C<ObjStore::Set> is the base class for sets.

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

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

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> has a C<$PICK_REP> coderef.  It
takes a location and a representation, calls C<ObjStore::UNIVERSAL::new>,
and returns a persistent object of the appropriate configuration.  If
you'd like, you can replace the default function with your own!

How does the ObjStore module know how to translate nested transient
structures into nested persistent structures?  By default,
C<ObjStore::DEFAULT_GATEWAY> makes the determination.  You can replace
it with your own code by using C<my $oldgw =
ObjStore::gateway($coderef)>.

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

You can add new types 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
facility will be available in the next release.

=head2 OSSV_MAGIC

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

The struct C<ossv_magic> is used to bridge between perl and C++
objects.  It contains transient cursors and transient pointers to
persistent data.  C<OSSV>'s are scalars.  C<OSSVPV> provides
implementations for non-scalars.  An instance of C<ossv_magic> stores
pointers to both an C<OSSV> and C<OSSVPV>.  Only one pointer need be
set and if both are set, they must refer to the same persistent
object.  It is preferred that the C<OSSV> be set, but there are cases
where the C<OSSV> may become invalid (e.g. array resize).  In these
cases, the C<OSSVPV> should be used.

=head1 FUTURE PLANS

=over 4

=item * Text objects implemented using osmmtype and subclassed from
IO::Handle.  Support for the Verity Text Object Manager.

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

=item * Java integration.

=item * Better documentation.

=back

=head1 QUIRKS & MISFEATURES

=over 4

=item * TROMPED KEYWORDS

The ObjStore version of C<bless> replaces the built-in and is imported
by default.

=item * STRING CAVEAT

The length of string values are not stored in the database.  Since
lengths are calculated at each access, lengthy strings should be
stored in a text object.  Text objects will be available in a future
release.

=item * NUMERICS

Numbers (integers and doubles) are stored in separately allocated
memory blocks.  This is probably not as efficient as a union, but
unions are nearly impossible to manage in ObjectStore.

=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 will need to re-bless
each to fix the broken pointers.

=item * REFERENCE CAVEAT

Object reference counts are 32 bits wide, but scalar (C<OSSV>)
reference counts are only 16 bits.  This does not restrict perl
developers from creating zillions of references to a single hash (a
hash is not a scalar), but it can cause some confusion in arcane
cases.  [Give example and work-around.]

=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.  Perl / ObjectStore is available
via any CPAN mirror site.  See
http://www.perl.org/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 .

=head1 SEE ALSO

Examples in the t/ directory, sack.pl, Perl5, ObjectStore, I<and fortunately not SQL!>

=cut

