The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Pogo - Perl GOODS interface

SYNOPSIS

  use Pogo;

  $pogo = new Pogo 'sample.cfg';  # connect to a database
  $root = $pogo->root_tie;        # get a reference to root hash in the database
  
  $root->{key1} = "string";       # store a string into the database
  $value = $root->{key1};         # $value is "string"
  
  $root->{key2} = [1,2,3];        # store a array into the database
  $arrayref = $root->{key1};      # get a reference to the array in the database
  $value = $root->{key2}->[0];    # $value is 1
  
  $root->{key3} = {a=>1,b=>2};    # store a hash into the database
  $hashref = $root->{key3};       # get a reference to the hash in the database
  $value = $root->{key3}->{b};    # $value is 2
  
  $root->{key4} = new Pogo::Btree;# make a B-tree hash
  $hashref = $root->{key5};       # B-tree is accessed as hash
  
  $root->{key5} = new Pogo::Htree;# make a H-tree(see below) hash
  $hashref = $root->{key6};       # H-tree is accessed as hash
  
  $root->{key6} = new Aclass;     # store a object into the database
  $obj = $root->{key4};           # $obj is a Aclass object in the database

DESCRIPTION

Overview

Pogo is a Perl interface of GOODS (Generic Object Oriented Database System). Pogo maps Perl's scalars, arrays, hashes and objects directly to the database objects. Pogo has the data types as follows.

  - scalar
  - array
  - hash
  - B-tree
  - H-tree (hash that hash entry table is placed as B-tree)
  - N-tree (same as B-tree but key is treated as number)

The value of a scalar data or an element of a collection type data is a string or a reference to another data. Pogo uses Perl's tieing mechanism and provide transparent accessibility to persistent data in the database. Each data in the database can have class name string internally, so Perl objects (i.e. reference which is blessed by a class name) can be stored in the database.

GOODS server

GOODS which is the base of Pogo is a client-server type database. A Pogo application needs a running GOODS server process in the same machine or another machine which is connected with TCP/IP network. The GOODS server program is 'goodsrv' which is installed in /usr/local/goods/bin/. The Pogo application and the corresponding goodsrv must use the same TCP port to communicate with each other, so both use the same configuration file which specifies goodsrv's hostname and TCP port number. The configuration file must have a filename extension '.cfg'. Typical configuration file for a local goodsrv as follows.

  1
  0: localhost:6100

The '1' at the first line means that this database uses one goodsrv (two or more goodsrv's are available but Pogo uses always one). The '0: localhost:6100' at the second line means that first goodsrv is at localhost and uses port number 6100.

If this configuration file is saved as 'test.cfg', goodsrv can be executed as follows.

  goodsrv test

And the goodsrv creates a set of database files as follows. You must NOT delete or edit directly these database files.

  test.his
  test.idx
  test.log
  test.map
  test.odb

The running goodsrv waits commands from your console while providing database services through the specified TCP port. You can see the database statistics or backup the database by sending commands to the running goodsrv. See readme.htm of GOODS.

For practical use, goodsrv will be executed as a background process. Pogo has two utility scripts for starting goodsrv at the background and sending commands to the goodsrv. To start goodsrv with test.cfg, type:

  startgoodsrv test &

This goodsrv's outputs are saved in test.goodsrv.log. And to terminate the goodsrv, type:

  cmdgoodsrv test exit

Tie interface

Connect

First of all, connect to a running GOODS server.

  $pogo = new Pogo $cfgfilename;

The $cfgfilename is a configuration filename which specifies GOODS server. The gotten Pogo object will be used after.

Get root

Then, get a hash reference to the root B-tree data in the database.

  $root = $pogo->root_tie;

NOTE: A persistent data in a GOODS database must be refered by another persistent data. If a data is not refered by another persistent data, it will be recovered by the GOODS garbage collection system. It means that at least one absolutely persistent data is necessary in each database. Such data is called 'root'. Pogo database's root is a B-tree data. The root_tie method returns a hash reference to the root B-tree data in the database.

String and number

To store a data into the database, simply assign a perl data through $root. Note that $root is a hash reference.

  $root->{key} = "value";
  $root->{pi} = 3.14;

NOTE: Data value strings in the Pogo database can include null character ("\x00"). But hash key strings in the Pogo database cannot include null character.

NOTE: The number 3.14 is stored as string "3.14" in the database. (This data conversion is an overhead. In the future revision of Pogo, it will be stored as number.)

Now, you can get the values of the data in the database.

  $value = $root->{key};  # $value is "value"
  $pi = $root->{pi};      # $pi is "3.14"
Array and hash

To store an array or a hash, assign its reference.

  $root->{key1} = \@array;
  $root->{key2} = [1,2,3];
  $root->{key3} = \%hash;
  $root->{key4} = {a=>1,b=>2,c=>3};
  $root->{key5} = {a=>[1,2],b=>{c=>3,d=>4}};

Note that these assignments cause storing the contents of the array or hash into the database, not only the reference. Because a persistent data in a database cannot refer to a non persitent (i.e. only on memory) data. That is to say, the array or hash is copied into the database and its reference is assigned. In the above example, changing @array or %hash after assignment does not change the array of $root->{key1} or the hash of $root->{key3}.

To fetch the value, normally use ->,[],{}'s.

  $value = $root->{key5}->{a}->[1];  # $value is 2
  $value = $root->{key5}{a}[1];      # -> between {} or [] can be omitted

If the specfied value is a reference to another data in the database, an appropriate type reference is returned. You can use such references to store into and fetch from the database.

  $hashref = $root->{key4};     # get a hash reference in the database
  $hashref->{d} = 4;            # store a data
  $value = $hashref->{c};       # $value is 3

NOTE: A CODE or IO reference cannot be stored into the database.

Array size

Pogo's array is automatically enlarged when needed. But the enlargement causes reassignment of the data in the database. When an array reference is assigned, the array size in the database is set to the size of the assigned array. If you can estimate the maximum array size, setting the array size beforehand is recommended. To make a specified size array, use Pogo::Array::new method.

  $root->{sqrt} = new Pogo::Array 1000;
  for(0..999) { $root->{sqrt}->[$_] = sqrt $_; }
Hash size

Pogo's hash has a static size hash entry table and cannot resize it. Note that the hash entry table size does not limit numbers of stored keys. But if too many keys against the hash entry table size are stored into a Pogo's hash, it will slow down. So choose appropriate hash entry table size for your purpose of using hash. (In the future revision of Pogo, automatic hash resizing will be supported.) When a hash reference is assigned, the hash entry table size in the database is set to it of the assigned hash. To make a hash of specified hash entry table size, use Pogo::Hash::new method.

  $root->{smallhash} = new Pogo::Hash 8;
  $root->{largehash} = new Pogo::Hash 1024;

If the size defaults, 256 is used.

H-tree

A hash entry table of Pogo's hash is a static size of array, so too large table size is not useful. If you want to use very large hash, use H-tree. A hash entry table of H-tree is placed as B-tree, so huge size table is available. To make a H-tree hash of specified hash entry table size, use Pogo::Htree::new method.

  $root->{hugehash} = new Pogo::Htree 131072;

If the size defaults, 65536 is used.

B-tree

Another way to make huge hash is to use B-tree. In B-tree, a hash key itself is used as B-tree key. So hash keys are sorted automatically. And B-tree has no hash entry table size problem. On the other hand, the key indexes of Pogo's B-tree is made by the first 8 bytes of the hash key string. So if many keys have same first 8 bytes, searching such keys slows down. To make a B-tree hash, use Pogo::Btree::new method.

  $root->{btree} = new Pogo::Btree;

Note that no size is required.

By the tie interface of Pogo, you cannot search key that partially matches the specified string. You can do it by Pogo::tied_object function and Pogo::Btree::find_key method.

  $foundkey = Pogo::tied_object($root->{btree})->find_key($string);

Pogo::tied_object returns the behind object which is tied to the specified data's referent. If $root->{btree} is a B-tree, Pogo::tied_object($root->{btree}) returns a Pogo::Btree object. And Pogo::Btree::find_key method returns a key string that matches front-partially to the specified string.

N-tree

By B-tree, key string is sorted as character string. So '10' is smaller than '2'. By N-tree, key string is sorted as long integer. So '2' is smaller than '10'. Except this feature, N-tree is same as B-tree.

  $root->{ntree} = new Pogo::Ntree;
Object

A Perl object which uses only SCALAR/ARRAY/HASH references can be stored into the database.

  sub Foo::new { bless {name => $_[1]}, $_[0]; }
  sub Foo::name { $_[0]->{name}; }
  $root->{obj} = new Foo "bar";
  $obj = $root->{obj};            # $obj is a Foo object
  $name = $obj->name;             # $name is "bar"

If you want to set hash entry table size or use H-tree or B-tree for a object, use Pogo::Hash::new_tie, Pogo::Htree::new_tie or Pogo::Btree::new_tie method.

  sub Bar::new {
      my($class, $name) = @_;
      my $self = new_tie Pogo::Htree 10000;
      $self->{name} = $name;
      bless $self, $class;
  }

Note that a class using Pogo::*::new_tie is only for using with Pogo database.

Transaction

Pogo has a transaction mechanism. If there is a sequence of operations with a database and you want to make it atomic, use transaction mechanism. The term 'atomic' means that the sequence of operations are all done successfully or nothing is done. It means also that another database client cannot interrupt the sequence.

To make a per database transaction, use Pogo::begin_transaction, Pogo::abort_transaction and Pogo::end_transaction methods.

  $root->{key} = 1;
  
  $pogo->begin_transaction;
  $root->{key} = 2;
  $pogo->abort_transaction;    # abort: cancel above assignment
  $value = $root->{key};       # $value is 1
  
  $pogo->begin_transaction;
  $root->{key} = 3;
  $pogo->end_transaction;      # end: above assignment is valid
  $value = $root->{key};       # $value is 3

Note that these methods must be called through a concrete Pogo object. Calling as class method is not available.

This transaction locks a whole database. So a long time transaction lowers concurrent database access performance.

To make a per data transaction, use Pogo::atomic_call method.

  $root->{key} = \@array;
  Pogo::atomic_call(\&sortarray, $root->{key});
  sub sortarray { my $aref = shift; @$aref = sort @$aref; }

While calling sortarray, $root->{key} is locked. So another databse client cannot disturb the sorting. And the sorting is done without halfway fail.

An abortion by the user is not supported for a per data transaction.

Passive action

If you need a script which watches a data in the database and does some jobs when the data is modified by another database client, use Pogo::wait_modification function.

  $result = Pogo::wait_modification($root->{key}, 5);

When this sentence is executed, execution stops until the data $root->{key} is modified by another database client or 5 seconds passes. $result is 1 by data modification, 0 by timeout.

If the timeout seconds defaults, it waits forever.

Database browser

Pogo has a database browsing script 'browse'. To browse the database of test.cfg, type:

  browse test

Then browse displays as follows and wait for your command.

  test.cfg opened
  root=(HASH(Btree)(10000))>

Type 'ls' to list the root B-tree hash contents. It displays as follows for example. For a reference to another data, it displays class name, data type and object id.

  {aobj} = Aclass(HASH(Hash)(1012d))
  {index} = (HASH(Btree)(10282))
  {list} = (ARRAY(10036))
  {name} = "test"

Type 'cd index' to change current data to $root->{index}. Then the prompt is changed as follows for example.

  root{index}=(HASH(Btree))>

Type 'cd' to return root. Type 'cd ..' to change to parent. And type 'exit' to terminate browse.

Methods

All but indicated as 'class method' are object methods. The symbol [] means optional argument.

$pogo = Pogo->new [config_filename]

Class method. This makes and returns a Pogo object. If specified config_filename, connect to the running GOODS server which is specified by config_filename. The corresponding GOODS server must be already running.

$pogo->open config_filename

If a Pogo object does not connect to the GOODS server yet, this method does it.

$pogo->close

This disconnects to the GOODS server. You may not use this method, because it is called when the Pogo object is destroyed automatically.

$pogo->opened

Returns 1 for already opened $pogo or 0 for not opened.

$pogo->root

This makes and returns a Pogo::Btree object corresponding to the root B-tree.

$pogo->root_tie

This makes and returns a reference to a hash which is tied to a Pogo::Btree object corresponding to the root B-tree.

$pogo->begin_transaction

This starts a database global transacion.

$pogo->abort_transaction

This aborts the transacion which was started by Pogo::begin_transaction.

$pogo->end_transaction

This ends the transacion which was started by Pogo::begin_transaction.

$obj = Pogo::Scalar->new [pogoobj]

Class method. Makes and returns a Pogo::Scalar object. If Pogo::* object pogoobj is specified and it is already attached to a database, the created object is attached to the same database.

$scalarref = Pogo::Scalar->new_tie [pogovar ,class]

Class method. Makes a Pogo::Scalar object and ties a scalar to it and returns a reference to the tied scalar. If reference variable pogovar is specified and it is already attached to a database, the created object is attached to the same database. If class name class is specified, the reference is blessed by the class.

$obj = Pogo::Array->new [size ,pogoobj]

Class method. Makes and returns a Pogo::Array object of specified size. If size defaults, 0 is used. If Pogo::* object pogoobj is specified and it is already attached to a database, the created object is attached to the same database.

$arrayref = Pogo::Array->new_tie [size ,pogovar ,class]

Class method. Makes a Pogo::Array object of specified size and ties a array to it and returns a reference to the tied array. If size defaults, 0 is used. If reference variable pogovar is specified and it is already attached to a database, the created object is attached to the same database. If class name class is specified, the reference is blessed by the class.

$obj = Pogo::Hash->new [size ,pogoobj]

Class method. Makes and returns a Pogo::Hash object of specified hash entry table size. If size defaults, 256 is used. If Pogo::* object pogoobj is specified and it is already attached to a database, the created object is attached to the same database.

$hashref = Pogo::Hash->new_tie [size ,pogovar ,class]

Class method. Makes a Pogo::Hash object of specified hash entry table size and ties a hash to it and returns a reference to the tied hash. If size defaults, 256 is used. If reference variable pogovar is specified and it is already attached to a database, the created object is attached to the same database. If class name class is specified, the reference is blessed by the class.

$obj = Pogo::Htree->new [size ,pogoobj]

Class method. Makes and returns a Pogo::Htree object of specified hash entry table size. If size defaults, 65536 is used. If Pogo::* object pogoobj is specified and it is already attached to a database, the created object is attached to the same database.

$hashref = Pogo::Htree->new_tie [size ,pogovar ,class]

Class method. Makes a Pogo::Htree object of specified hash entry table size and ties a hash to it and returns a reference to the tied hash. If size defaults, 65536 is used. If reference variable pogovar is specified and it is already attached to a database, the created object is attached to the same database. If class name class is specified, the reference is blessed by the class.

$obj = Pogo::Btree->new [pogoobj]

Class method. Makes and returns a Pogo::Btree object. If Pogo::* object pogoobj is specified and it is already attached to a database, the created object is attached to the same database.

$hashref = Pogo::Btree->new_tie [pogovar ,class]

Class method. Makes a Pogo::Btree object and ties a hash to it and returns a reference to the tied hash. If reference variable pogovar is specified and it is already attached to a database, the created object is attached to the same database. If class name class is specified, the reference is blessed by the class.

$obj = Pogo::Ntree->new [pogoobj]

Class method. Makes and returns a Pogo::Ntree object. If Pogo::* object pogoobj is specified and it is already attached to a database, the created object is attached to the same database.

$hashref = Pogo::Ntree->new_tie [pogovar ,class]

Class method. Makes a Pogo::Ntree object and ties a hash to it and returns a reference to the tied hash. If reference variable pogovar is specified and it is already attached to a database, the created object is attached to the same database. If class name class is specified, the reference is blessed by the class.

NOTE: An object created by these Pogo::*::new and Pogo::*::new_tie is on the memory, not yet persistent. When it is refered by a existing persistent data in a database, it becomes persistent. When Pogo object is specified as an argument, the gotten object is attached to the database, but it is not yet persistent too.

Utility functions

Pogo::type_of

This returns an array of reference type, class name, tied class name of the specfied data.

  ($reftype, $class, $tiedclass) = Pogo::type_of($root->{key});

Typical return values are:

  () : not a reference
  ('ARRAY', '', 'Pogo::Array') : an array
  ('HASH', '', 'Pogo::Btree') : a B-tree hash
  ('HASH', 'Aclass', 'Pogo::Hash') : an Aclass object
Pogo::tied_object

This returns a Pogo::* object which is tied to the referent of the specified Pogo data.

Pogo::equal

This requires two arguments of Pogo data and returns 1 if its datatabase objects are same, 0 if different.

Pogo::object_id

This returns a database object id of the specified Pogo data.

Pogo::atomic_call

This calls the specified function atomicly and returns its return value.

  $result = Pogo::atomic_call(\&func, $data, @args);

The first argument \&func is a reference to a subroutine. The second argument $data is a Pogo data. This data is locked between calling. This is same as below exept the locking.

  $result = func($data, @args);

The func is called in a scalar context, and returned value is convert to a integer number.

Pogo::wait_modification

This waits the modification of the specified data by another database client until the specified seconds passes. And returns 1 by data modification, 0 by timeout.

  $result = Pogo::wait_modification($data, $sec);

If the timeout seconds defaults, it waits forever.

Pogo::get_root_tie

This function takes one reference argument which refer to a database data and returns the hash reference to the root B-tree in the database.

  $root = Pogo::get_root_tie($pogovar);

Low level (non-tie) interface

The tie interface of Pogo is very convenient. But it causes much overheads. If you want to construct large and complex database application by Pogo, using low level (non-tie) interface is recommended.

For exmple, as follows by tie interface:

  $root = $pogo->root_tie;    # $root is a hash reference
  $root->{key} = "value";
  $value = $root->{key};      # $value is "value"

It is same as follows by low level interface:

  $root = $pogo->root;        # $root is a Pogo::Btree object
  $root->set(key => "value");
  $value = $root->get('key'); # $value is "value"

Low level classes and methods

These low level classes and methods below are used by tie interaface internally and you can use its directly.

Pogo::Var

Pogo::Var is a abstract base class of all Pogo::* classes below. No Pogo::Var object is available.

  Pogo::Var::get_class
  Pogo::Var::set_class
  Pogo::Var::begin_transaction
  Pogo::Var::abort_transaction
  Pogo::Var::end_transaction
  Pogo::Var::root
  Pogo::Var::root_tie
  Pogo::Var::call
  Pogo::Var::equal
  Pogo::Var::wait_modification
  Pogo::Var::object_id
Pogo::Scalar
  Pogo::Scalar::get
  Pogo::Scalar::set
Pogo::Array
  Pogo::Array::get
  Pogo::Array::set
  Pogo::Array::get_size
  Pogo::Array::set_size
  Pogo::Array::clear
  Pogo::Array::push
  Pogo::Array::pop
  Pogo::Array::insert
  Pogo::Array::remove
Pogo::Hash
  Pogo::Hash::get
  Pogo::Hash::set
  Pogo::Hash::exists
  Pogo::Hash::remove
  Pogo::Hash::clear
  Pogo::Hash::first_key
  Pogo::Hash::next_key
Pogo::Htree
  Pogo::Htree::get
  Pogo::Htree::set
  Pogo::Htree::exists
  Pogo::Htree::remove
  Pogo::Htree::clear
  Pogo::Htree::first_key
  Pogo::Htree::next_key
Pogo::Btree, Pogo::Ntree

These methods below are same in Pogo::Ntree.

  Pogo::Btree::get
  Pogo::Btree::set
  Pogo::Btree::exists
  Pogo::Btree::remove
  Pogo::Btree::clear
  Pogo::Btree::first_key
  Pogo::Btree::last_key
  Pogo::Btree::next_key
  Pogo::Btree::prev_key
  Pogo::Btree::find_key

Deriving low level classes and hooking methods

You can derive low level classes and override some methods. Instead of entire overriding, Pogo provides a hook mechanism for low level methods.

For example if you want to hook Pogo::Array::set method, do:

  # MyArray.pm
  package MyArray;
  @ISA = qw(Pogo::Array);
  %HOOK = (set => \&set_hook);  # hook set() method by set_hook()
  sub set_hook {
    my($self, $idx, $value) = @_;
    do_something($self, $idx, $value);
    1;     # if returns false, original method not called
  }
  ...
  1;

Then do:

  use MyArray;
  $obj = new MyArray;
  $obj->set(0, "value"); # set_hook($obj, 0, "value") and Pogo::Array::set($obj, 0, "value")

AUTHOR

Sey Nakajima <nakajima@netstock.co.jp>

SEE ALSO

readme.htm of GOODS