

QUESTION:
 
  For each database, there is a unique segment set aside for allocating pooled
  objects of a particular type.  If so, then won't the application have a lot
  of inter segment pointers.

ANSWER:
  Actually, the pooled allocator doesn't create segments on its own.
  The interface to the overloaded operator new lets the caller specify
  the segment in which to allocate the object.  If there's already a
  pool for this data type in this segment, it uses it.  Otherwise, a new pool
  is created.

  The current design of the pool allocator *should not* have a major impact
  on address space usage because of inter-segment pointers.  Here are the
  associations between the different classes of persistent objects:

	PoolMgr			1 <-----> n	PersistentPoolType
	PersistentPoolType	1 <-----> n	PoolSeg
	PoolSeg			1 <-----> 1	Pool
	Pool			1 <-----> n	PoolChunk

  There's 1 PoolMgr instance per database which pool allocates any data types.
  This instance is allocated in the default segment (segment 2, unless the
  application changes os_database::default_segment).  There's 1 instance of
  PersistentPoolType for each distinct data type which uses pooled allocation,
  and 1 instance of PoolSeg for each combination of data type and database
  segment in which pooled allocation occurs.  The instances of both of these
  classes are allocated in the same segment as their parent (i.e. the default
  segment).  So far, no cross-segment pointers.

  For every instance of PoolSeg, there's a corresponding instance of the
  Pool class which lives in the segment where the allocation occurs.  The
  PoolSeg uses an os_Reference_this_DB to refer to its partner Pool instance.
  The Pool instance uses an ordinary pointer to point back at its PoolSeg.
  As a result, each data segment where pooled allocation is done will have
  cross-segment pointers back to the default segment only.  Pooled allocation
  will not contribute cross-segment pointers to the default segment.  This
  strategy should minimize the impact on address space reservation.

 > In the alloc() member of the PoolChunk class, initially pointers are handed
 > out in a linear fashion from the chunk and when all pointers from the chunk
 > are exhausted, you use the BitVector class to find out holes (deleted
 > objects) which can be re-used. Right ?
 > 

Right.

 > While an polled object allocated is deleted, you iterate over all
 > the PoolChunks of the Pool, each time checking if the object was
 > allocated from that chunk, till you find the right chunk - after which you
 > mark the corresponding index in the BitVector for that chunk as a hole 
 > (empty/available). Right ?
 >

That's the way it's currently done.
 
 > For what are the hash_hash and hash_compare functions used in poolhash.hh
 > used.  What is the phash facility of Object Store.
 >

phash is a simple (but undocumented) hash table implementation used internally
within ObjectStore.  It was used instead of ObjectStore collections to reduce
the overhead (both storage and execution time) added by the pooled allocator,
since it only needs to perform simple equality lookups against a set of
arbitrary size.  A PoolMgr object needs to find a PersistentPoolType object
by name, and the PersistentPoolType needs to find a PoolSeg by its segment
number.

 > This is a suggestion - if we could have a pointer to the PoolChunk in each
 > object being allocated, then the deletion time could come down to a
 > constant, rather than increasing with the number of chunks allocated.
 > 

This would require an intrusive change to the storage layout of objects which
could support pooled allocation (either via inheritance from a base class
which could maintain the backpointer to the PoolChunk, or by insertion of
a data member by the OS_POOLED_ALLOC_DECL macro).  The current design limits
changes to a user class to the addition of member functions and static data
members.  It would also add 4 bytes per object allocated which most likely
would eliminate any space savings.

A crude solution is to take advantage (if possible) of application-specific
knowledge of the number of objects per segment, and adjust the value of
the static data member 'chunk_sz' to limit the number of PoolChunk instances.

Another alternative would be to implement the 1-many relationship between
Pool and PoolChunk using a structure like a b-tree which would be more
suitable to efficient ordered lookup against a large set.  Since all PoolChunk
objects of interest live in the same database segment, the b-tree could be
based on byte offsets between the addresses of the PoolChunk::items and their
parent Pool.
FAQ_reference: pool_allocation
