#ifndef _NSRSPACE_ //-*-c++-*-
#define _NSRSPACE_

//----------------------------------------------------------------------
//  nsrSpace.h
//   Space Resource Classes
//
//      Unpublished Confidential Information of Hewlett-Packard
//      Company. Do not disclose.  Copyright (c) Hewlett-Packard
//      Company 1995. All rights reserved
// 
// The contents of this software are proprietary and confidential to
// the Hewlett- Packard Company, and are limited in distribution to
// those with a direct need to know.  Individuals having access to
// this software are responsible for maintaining the confidentiality
// of the content and for keeping the software secure when not in use.
// Transfer to any party is strictly forbidden other than as expressly
// permitted in writing by Hewlett-Packard Company.  Unauthorized
// transfer to or possession by any unauthorized party may be a
// criminal offense.
//
//                  RESTRICTED RIGHTS LEGEND
//
//      Use,  duplication,  or disclosure by the U. S. Government is
//      subject to restrictions as set forth in subparagraph (c) (1)
//      (ii) in the Rights in Technical Data and Computer Software
//      clause in DFARS 252.227-7013 or any other successor clause.
//
//                      HEWLETT-PACKARD COMPANY
//                      3000 Hanover St.
//                      Palo Alto, CA  94304 U.S.A.
//
//      Rights for non-DOD U.S. Government Departments and Agencies
//      are as set forth in FAR 52.227-19 (c) (1,2) or any other
//      successor clause.
//  ENUMS:
//   SRSpaceType
//   SRDescType
//  CLASSES:
//   SpaceResource
//   LELSpaceResource
//   ISOSpaceResource
//   TableSpaceResource
//   BitmapSpaceResource
//   MasterSpaceResource
//  
//----------------------------------------------------------------------
// $Source: /projects/HMS/nsr/udfCore/ss/nsrSpace.h,v $
// $Revision: 1.26 $    $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/05/21 23:21:47 $

//----------------------------------------------------------------------
// ENUM: SRSpaceType
//
//  Indicates the type of space that may be held by SpaceResource
//
// DEFINITIONS:
//  srSpace_ErasedOnly
//  srSpace_UnerasedOnly
//  srSpace_ErasedAndUnerased
//
// USES:
//  Each SpaceResource MUST have one of these three associated with it.
//
// ABUSES:
//  Note that this says NOTHING of how the space is stored on disk or
//  otherwise represented.
//
// NOTES:
//  optional
//
//----------------------------------------------------------------------
// Private comments go here - will not be extracted into HTML.
//----------------------------------------------------------------------
enum SRSpaceType {
    srSpace_ErasedOnly,
    srSpace_UnerasedOnly,
    srSpace_ErasedAndUnerased
};

//----------------------------------------------------------------------
// CLASS: SpaceResource     --DVM
//
//  Pure Virtual base class for Space Resources.
//
//  All SpaceResources must be derived from this class.
//
// PUBLIC METHODS:
// NON-VIRTUAL methods:
// logVolume()
//    Gets or sets the data member. Setter is protected.
// blockSize()
//    Returns the size of the block for this SR.
// spaceType()
//    returns the type of space this SR may hold.
// allowsErased()
//    returns True if Erased space may be placed in this SR.
// validateExtent()
//    Returns an error if the supplied LE's space type is not allowed
//    in this SR, or it is from a different LogicalVolume.
// VIRTUAL methods
// allowsUnerased()
//    returns True if Unerased space may be placed in this SR.
// availBytes()
//    This returns the number of bytes currently available in
//    SpaceResource.
// maxExtLen()
//    This returns the size in bytes of the longest extent available
//    in the SpaceResource.
// error()
//    Must return any error state
// takeLogExtent(), takeLogExtentList()
//    These both allocate space from the SpaceResource, and accept a
//    byte count specifying the needed length, which is rounded up to
//    the nearest block boundary. takeLogExtent() allocates contiguous
//    space, and takeLogExtentList() allocates space which may not be
//    contiguous.
//    If more space is requested than is available, an empty LogExtent
//    or LogExtentList is returned. This may be avoided by calling
//    availBytes() first.
// putLogExtent(), putLogExtentList()
//    These both free space to the SpaceResource, accepting a
//    LogExtent and a LogExtentList, respectively.
//
// USAGE NOTES:
// 
//----------------------------------------------------------------------
// COLLABORATORS:  
//  Each SpaceResource points to a LogicalVolume.
//
// PRIVATE METHODS:
//  None.
//
// IMPLEMENTATION NOTES:
//  None. Just a template.
//
//----------------------------------------------------------------------
class SpaceResource {

private:
    // This value is NEVER NULL!
    // NOTE: We store this value as a pointer, not a reference,
    // because we want a default operator=(const SpaceResource&) to be
    // defined. (That's not done if a reference, see ANSI C++
    // standard).
    SRSpaceType    spaceType_  ;
    LogicalVolume* logVolumep_ ;

public:

    SpaceResource(LogicalVolume& lv,
                  SRSpaceType st = srSpace_ErasedAndUnerased ) :
            spaceType_(st),
            logVolumep_(&lv) {
    }
    virtual ~SpaceResource(void) {}

    UINT32 blockSize(void) const {
        return logVolumep_->blockSize(); }
    LogicalVolume & logVolume(void) const {
        return *logVolumep_; }
protected:
    // Only derived classes may change these.
    void logVolume(LogicalVolume & lv) {
        logVolumep_ = &lv; }
    // This one is especially provided for MasterSpaceResource
    void spaceType(SRSpaceType st) {
        spaceType_ = st; }

public:
    // First, those non-virtual functions indicating what type of
    // space this one may hold.

    SRSpaceType spaceType(void) const { return spaceType_; }

    Boolean allowsErased(void) const { return True; }
    
    virtual Boolean allowsUnerased(void) const {
        return Boolean(spaceType_ != srSpace_ErasedOnly); }

    // Next, a method to indicate if an extent type is illegal
    Error validateExtent(const LogExtent & le ) const {
        Error err(error_None);
        if ( !allowsUnerased() &&
             ( le.extentType() == Unerased ||
               le.extentType() == Recorded )) {
            err = error_SR_Incompatible_extent_type;
        } else if ( logVolumep_ != le.logVolumep() ) {
            err = error_SR_Extent_from_wrong_logVolume;
        } else
            err = le.validateLength();
        return err;
    }

    // Now, the virtual functions. These MUST be overloaded.
    virtual UINT64 availBytes(void) const = 0;
    virtual UINT32 maxExtLen(void) const = 0;

    virtual Error error() const = 0;
    virtual void takeLogExtent( LogExtent& lext,
                                UINT32 bc,
                                Error& err ) = 0;
    virtual void takeLogExtentList( LogExtentList& list,
                                    UINT64 bc,
                                    Error& err ) = 0;
    virtual void putLogExtent( const LogExtent& lext,
                               Error& err ) = 0;
    virtual void putLogExtentList( const LogExtentList& list,
                                   Error& err ) = 0;
};

//----------------------------------------------------------------------
//CLASS: LELSpaceResource --CSB
//
//  Usable space resouce that does not go to disk, but does manage
//  space in a LogExtentList manner.  (Space is coalesced and sorted
//  on insert).
//
// PUBLIC METHODS:
//
//  LELSpaceResource()  - Constructs an empty SR given a
//                        LogicalVolume. SpaceType is optional second
//                        argument.
//  blockSize()         - See SpaceResource
//  spaceType()         - See SpaceResource
//  allowsErased()      - See SpaceResource
//  allowsUnerased()    - See SpaceResource
//  validateExtent()    - See SpaceResource
//  LogVolume()         - See SpaceResource
//  availBytes()        - See SpaceResource
//  maxExtLen()         - See SpaceResource
//  takeLogExtent()     - See SpaceResource
//  takeLogExtentList() - See SpaceResource
//  putLogExtent()      - See SpaceResource
//  putLogExtentList()  - See SpaceResource
//
// BONUS METHODS:
//
//  takeLogExtentFromTail()     - Special control provided
//  takeLogExtentListFromTail() - Special control provided
//
// TESTING METHODS:
//
//  clear()                   - zeroes out all space.
//  numLogExtents()           - returns number of extents available.
//  at_()                     - accesses individual extents.
//  operator LogExtentList&() - Casts to LogExtentList.
//  operator!=()              - Compares two.
//
// USAGE NOTES:
//----------------------------------------------------------------------
// COLLABORATORS: Contains a PackedLogExtentList.
//
// PRIVATE METHODS:
//
// IMPLEMENTATION NOTES:
// 
//  This is the arbitrary pool of space that we manage.  We ALWAYS
//  keep the pool of space sorted (low blocks to high blocks), and the
//  pool is always coalesced for the largest possible contiguous
//  space.
//
//----------------------------------------------------------------------
class LELSpaceResource : public SpaceResource {

    PackedLogExtentList spacePool_;

public:

    LELSpaceResource(LogicalVolume& logVolume,
                     SRSpaceType st = srSpace_ErasedAndUnerased) :
            SpaceResource(logVolume,st),
            spacePool_(logVolume)
    {}

    // The requisite virtual functions
    virtual ~LELSpaceResource(void) {}
    
    virtual Error error(void) const {
        return spacePool_.error();
    }
    virtual UINT64 availBytes(void) const {
        return spacePool_.infoLen(); 
    }
    virtual UINT32 maxExtLen(void) const {
        return spacePool_.maxExtentLen(); 
    }

    virtual void takeLogExtent( LogExtent& lext,
                                UINT32 bc,
                                Error& err ) ;
    virtual void takeLogExtentList( LogExtentList& list,
                                    UINT64 bc,
                                    Error& err ) ;
    virtual void putLogExtent( const LogExtent& lext,
                               Error& err );
    virtual void putLogExtentList( const LogExtentList& list,
                                   Error& err );
    // These are supplemental methods, so that LELs do not have
    // more functionality than LELSRs.
    void takeLogExtentFromTail( LogExtent& lext,
                                UINT32 bc,
                                Error& err ) ;
    void takeLogExtentListFromTail( LogExtentList& list,
                                    UINT64 bc,
                                    Error& err ) ;
    // Methods used for testing
    void clear(void) { spacePool_.clear(); }
    UINT32 numLogExtents(void) const {
        return spacePool_.numLogExtents(); }
    const LogExtent* at_(UINT32 index, Error& err) const {
        return spacePool_.at(index, err); }

    // Do we want more than just a const version of this?
    operator const LogExtentList& (void) const {
        return spacePool_;
    }
    UINT16 operator!=(const LELSpaceResource& other) const {
        return spacePool_ != other.spacePool_;
    }
};

class Partition;                // Forward declaration

//----------------------------------------------------------------------
// CLASS: ISOSpaceResource      --DVM
//
//  A space resource which suports an on-disk ISO form.
// 
// NOTE: This is an ABSTRACT BASE CLASS, because we merely specify
//   the interface for reading and writing to disk; we do not
//   implement it.   For example, derived classes can write to the 
//   surface with either a bitmap or LogExtentList implementation.
//
// PUBLIC METHODS:
//
// ISOSpaceResource()
//    The constructor for this base class simply initializes the data
//    members. Derived classes have other requirements, however:
//    - After construction, the SpaceResource must be able to perform
//      a put or a take.
//    - At least two signatures should be provided for construction,
//      which should roughly match the signatures of the init()
//      methods mentioned below. They should call the init() methods
//      as part of their construction.
//    While this is more functionality than is typically provided in a
//    constructor, since the on-disk image may be altered as part of
//    this operation, this approach minimizes the state information
//    which must be held both by this class and by its users, and
//    yields a very simple overall interface.
//
// INHERITED methods:
//
// logicalVolume()  - See SpaceResource
// blockSize()      - See SpaceResource
// spaceType()      - See SpaceResource
// allowsErased()   - See SpaceResource
// allowsUnerased() - See SpaceResource
// validateExtent() - See SpaceResource
//
// VIRTUAL methods:
//
// error()
//    This is inherited from SpaceResource. It returns an error if
//    the ISOSpaceResource is in error. It should be called
//    immediately after construction to make sure that there were
//    no problems with it.
// initFromDisk()
//    This reads the free space information from the disk, leaving
//    the object ready for put/take calls. Any errors are detected by
//    a call to the error() method.
// initWithNewSpace()
//    This initializes the object with the space from the supplied
//    space information, leaving it ready for put/take calls. The
//    user should call syncToDisk() to complete the initialization
//    of the on-disk representation of free space. The user should
//    ALSO then make sure that the Partition object, which holds the
//    spaceForDesc, should be written to disk as well. Any errors are
//    detected by a call to the error() method.
// syncToDisk()
//    This makes sure that the on-disk representation properly
//    reflects the in-memory state of the SR. It may or may not
//    perform any writing when it is called.
//    It is intended for multiple put/take calls to be made (if
//    desired) without calling syncToDisk() between each one. Thus,
//    it should be called on a periodic basis and/or just before
//    the media is removed or taken offline.
//    NOTE that the user may not wish to call syncToDisk() after
//    some error conditions.
//
// USAGE NOTES:
// 
//    If the constructor or initWithNewSpace() methods are called
//    which initialize the object from supplied information,
//    syncToDisk() should be called in order for the on-disk copy
//    to be initialized as well. This allows the init() method to
//    write or defer writing of exactly as much information as it
//    desires. It also keeps the interface simple.
//
//----------------------------------------------------------------------
// COLLABORATORS:  
//  Derived from SpaceResource.
//
// PROTECTED METHODS:
//  validateSingleSpaceType() - returns an error if mixed space type.
//
// IMPLEMENTATION NOTES:
//
//----------------------------------------------------------------------
class ISOSpaceResource : public SpaceResource {

protected:
    
    // These are protected, so that only derived classes may access
    // them. 
    Partition*  partp_  ;

// INLINE: ISOSpaceResource::ISOSpaceResource()
    ISOSpaceResource(Partition& partp,
                     SRSpaceType st) :
        SpaceResource(*partp.logVolumep(),st),
        partp_(&partp)
    {}

    Error validateSingleSpaceType(void) {
        if ( spaceType() == srSpace_ErasedAndUnerased ) {
            return Error(error_SR_Cannot_mix_space_types);
        } else {
            return Error(error_None);
        }
    }
    
public:

    virtual ~ISOSpaceResource(void) {}
    virtual void initWithNewSpace(LogExtentList & initialSpace) = 0;
    virtual void initFromDisk(void) = 0;
    virtual void syncToDiskUsingSR(SpaceResource & mdsr,
                                   Error & err) = 0;
    // This one needn't be overridden, since it is the same for all.
    void syncToDisk(Error & err) {
        syncToDiskUsingSR(*this,err);
    }
};

//-----------------------------------------------------------------------------
// METHOD:  ISOSpaceResource::ISOSpaceResource()
//
// Constructor for the ISOSpaceResource class.
//
// ARGS:
//
// Partition   *pp IN   A valid Partition pointer.
// SRSpaceType st  IN   Type of space to be allowed in it.
//
// RETURNS:    none
// PRE-CONDS:  none
// POST-CONDS:
//
// --If the argument Partition pointer is NULL, the bitmap will have size 0.
//   Otherwise, the bitmap will be sized to encompass the entirety of the
//   partition.
//
//-----------------------------------------------------------------------------

//----------------------------------------------------------------------
// CLASS: TableSpaceResource            --CSB
//
//  Usable space resource that goes to disk, and does manage
//  space in an LELSpaceResource manner.  (Space is coalesced and
//  sorted on insert).
//
// PUBLIC METHODS:
//
// error()             - returns error.
// availBytes()        - See SpaceResource
// maxExtLen()         - See SpaceResource
// takeLogExtent()     - See SpaceResource
// takeLogExtentList() - See SpaceResource
// putLogExtent()      - See SpaceResource
// putLogExtentList()  - See SpaceResource
//
// STATIC METHODS:
//
// descBytes()    - Returns number of bytes required to hold a
//                  SpaceTable with the supplied number of blocks in
//                  the supplied partition. This is static, so that it
//                  may be called BEFORE construction.
//
// BONUS METHODS:
//
// clear()                     - zeroes out all space
// numLogExtents()             - returns number of extents
//                               available. 
// takeLogExtentFromTail()     - Special
// takeLogExtentListFromTail() - Special
//
// ISO METHODS:
//
// initFromDisk()      - Initializes from descriptors on the disk
// initWithNewSpace()  - Initialize from supplied space
// syncToDisk()        - Make disk image consistent with internal
//                       space. 
//
// USAGE NOTES:
//----------------------------------------------------------------------
// COLLABORATORS:
//  Derived from ISOSpaceResource
//
// PRIVATE METHODS:
//
// IMPLEMENTATION NOTES:
//  This class simply contains an LELSpaceResource, and passes the
//  allocation and freeing calls down to it.
//  
//  The toISO/fromISO code is VERY close to that of the Node, except
//  it writes a USE plus AEDs instead of an FE plus AEDs.
//
//----------------------------------------------------------------------
class TableSpaceResource : public ISOSpaceResource {

    LELSpaceResource spacePool_;
    Error            error_;
    
    // copy constructor
    TableSpaceResource( const TableSpaceResource &obj) :
            ISOSpaceResource(obj),
            spacePool_(obj.spacePool_)
    {}

    // operator=()
    TableSpaceResource &operator= ( const TableSpaceResource &obj )
    {
        return *this;
    }

public:
// INLINE: TableSpaceResource::TableSpaceResource()
    TableSpaceResource(Partition& part,
                       SRSpaceType st) :
            ISOSpaceResource(part, st),
            spacePool_(*part.logVolumep()),
            error_(error_None)
    {
        if ( error_ = validateSingleSpaceType() )
            return;
        if ( ! (error_ = spacePool_.error()))
            initFromDisk();
    }
// INLINE: TableSpaceResource::TableSpaceResource()
    TableSpaceResource(Partition& part,
                       SRSpaceType st,
                       LogExtentList & initialSpace) :
            ISOSpaceResource(part, st),
            spacePool_(*part.logVolumep()),
            error_(error_None)
    {
        if ( error_ = validateSingleSpaceType() )
            return;
        if ( ! (error_ = spacePool_.error()))
            initWithNewSpace(initialSpace);
    }

    virtual ~TableSpaceResource(void) {}

    // Status methods
    virtual Error error(void) const {
        if (error_) {
            return error_;
        } else {
            return spacePool_.error();
        }
    }

    virtual UINT64 availBytes(void) const
    {
        return spacePool_.availBytes();
    }

    virtual UINT32 maxExtLen(void) const
    {
        return spacePool_.maxExtLen();
    }

    // Allocation methods
    virtual void takeLogExtent( LogExtent& lext,
                                UINT32 bc,
                                Error& err )  {
        spacePool_.takeLogExtent(lext, bc, err);
    }

    virtual void takeLogExtentList( LogExtentList& list,
                                    UINT64 bc,
                                    Error& err )  {
        spacePool_.takeLogExtentList(list, bc, err);
    }

    // Deallocation methods
    virtual void putLogExtent( const LogExtent& lext,
                               Error& err ) {
        spacePool_.putLogExtent(lext, err);
    }

    virtual void putLogExtentList( const LogExtentList& list,
                                   Error& err ) {
        spacePool_.putLogExtentList(list, err);
    }

    // Bonus allocation methods
    void takeLogExtentFromTail( LogExtent& lext,
                                UINT32 bc,
                                Error& err )  {
        spacePool_.takeLogExtentFromTail(lext, bc, err);
    }
    void takeLogExtentListFromTail( LogExtentList& list,
                                    UINT64 bc,
                                    Error& err )  {
        spacePool_.takeLogExtentListFromTail(list, bc, err);
    }

    // Static methods
    static UINT32 descBytes(Partition * partp) {
        return partp->blockSize();
    }
    
    // ISO methods
    virtual void initFromDisk(void);
    virtual void initWithNewSpace(LogExtentList & initialSpace);
    virtual void syncToDiskUsingSR(SpaceResource & mdsr,
                                   Error & err);
};

//----------------------------------------------------------------------
// METHOD: TableSpaceResource::TableSpaceResource  --DVM
//      
//  Constructor for TableSpaceResource
//
//  Two forms of this constructor are supplied:
//  - Constructs from the information on the disk.
//  - Constructs from supplied space information.
//
// ARGS:
//  Partition&      part          IN  Reference to associated
//                                    partition.
//  SRType          t             IN  Type of SR: sr_Unerased
//                                    or sr_Erased
// (second form only)
// 
//  LogExtentList&& initialSpace  IN  Space for descriptor and to be
//                                    placed into SR.
//
// RETURNS:
//  none.
// 
// PRE-CONDITIONS:
//  none.
// 
// POST-CONDITIONS:
//  SR is ready for allocation and/or deallocation.
// 
// ERRORS:
//  error_
//  error_
//  error_
// 
// NOTES:
//
// If initialSpace is provided, the first LogExtent in it, starting at
// the head, is used to hold the descriptor for it. Users wanting to
// place this structure in a specific place will need to use use the
// descBytes() method and the LogExtentList manipulators
// (head,tail,append) in order to accomplish this.
//
//----------------------------------------------------------------------
// Private comments go here - will not be extracted into HTML.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
// CLASS: BitmapSpaceResource           --GKG
//
//  The bitmap space resource divides the bitmap image into a series of
//  pages which may be read into memory or synchronized to media
//  independently.  This accomodates platforms with restrictive memory
//  management subsystems that would have difficulty manipulating a
//  single large bitmap.  Space allocation is first-fit, and allocations
//  that straddle or span page boundaries are permitted.
//
// PUBLIC METHODS:
//  error()
//    Returns the error state.
//  takeLogExtent()
//    Allocates a contiguous range of space.
//  takeLogExtentList()
//    Allocates a (potentially) disjoint range of space.
//  putLogExtent()
//    Deallocates a contiguous range of space.
//  putLogExtentList()
//    Deallocates a disjoint range of space.
//  availBytes()
//    Returns the total available space in this space resource (in bytes).
//  maxExtLen()
//    Returns the largest contiguous available space in this space resource
//    (in bytes).
//  blockLength()
//    The logical blockSize (in bytes) for this partition.
//  initFromDisk()
//    Initialize a new SpaceResourceBitmap, reading an existing bitmap image
//    from the media.
//  initWithNewSpace()
//    Initialize a new BitmapSpaceResource, given a logical extent containing
//    the intial free space, and writing the resulting bitmap image to disk.
//  syncToDisk()
//    Synchronize the bitmap memory buffers to the disk image.
//
// STATIC METHODS:
//  descBytes()
//    Returns number of bytes required to hold a SpaceBitmap with the supplied
//    number of blocks in the supplied partition. This is static, so that it
//    may be called BEFORE construction. Always a multiple of the logical block
//    length.
//
// ISO METHODS:
//  initFromDisk()
//    Initializes from descriptors on the disk.
//  initWithNewSpace()
//    Initialize from supplied space
//  syncToDisk()
//    Make disk image consistent with internal space.
//
// PRIVATE METHODS:
//   pageSize()
//    Get the fixed page size (from the PagedSpaceBitmapMap).
//  getPartition()
//    Get a reference to the OSTA Partition.
//  getBitmapMap()
//    Get a reference to the PagedSpaceBitmapMap.
//  totalBlocks()
//    The total number of blocks.
//  findFirstFree()
//    Find the first page with available blocks (from a specified start page).
//  findLargestExtent()
//    Find the length and location of the largest run of contiguous available
//    space (may straddle or span page boundaries).
//  findBitmapData()
//    Calculate the meta-data for the entire space resource.
//  findBoundaryExtent()
//    Find the length of extent straddling the end of the specified page (may
//    span multiple pages).
//  linkBuffer()
//    Link a BufferPage to a BitmapBuffer.
//  clearAuditTrail()
//    Remove all nodes from the audit trail.
//  pushAuditTrail()
//    Add a node to the audit trail.
//  popAuditTrail()
//    Remove a node from the audit trail.
//  disasterRecovery()
//    Something bad has happened.  This traverses the audit trail and attempts
//    to "roll back" the state of the bitmap to its previous condition.
//  free()
//    Releases all objects instatiated by the BitmapSpaceResource.
//
// USAGE NOTES:
//----------------------------------------------------------------------
// COLLABORATORS:
//  Derived from ISOSpaceResource
//
// IMPLEMENTATION NOTES:
//
//----------------------------------------------------------------------
class BitmapSpaceResource: public ISOSpaceResource
{
private:

  // NOTE:  The classes "Extent", "AuditTrailNode", "BitmapBuffer",
  //   "BitmapBufferCache" and "BitmapPage" are private member classes to
  //   the BitmapSpaceResource class.  No outside entity needs to access
  //   these classes.

//----------------------------------------------------------------------
// Class: Extent     --GKG
// NOTE:  THIS CLASS IS A PRIVATE MEMBER TYPE OF CLASS BITMAPSPACERESOURCE.
//  This is a minimal extent data type used to transfer extent data
//    between the internal objects of the BitmapSpaceResource.
//
// COLLABORATORS:
//  This is a private class member of BitmapSpaceResource.
//----------------------------------------------------------------------
// NOTES:
//  NONE
//----------------------------------------------------------------------

    class Extent {
    public:
        // Notice data members are "public".
        UINT32 location;
        UINT32 length;

        // INLINE: Extent::Extent()
        Extent(UINT32 nLocation = 0, UINT32 nLength = 0):
                location(nLocation),
                length(nLength)
        {}
    };

//----------------------------------------------------------------------
// Class: AuditTrailNode     --GKG
// NOTE:  THIS CLASS IS A PRIVATE MEMBER TYPE OF CLASS BITMAPSPACERESOURCE.
//  This is a node in a linked list of extents and there respective page
//    numbers.  The list is built during allocation or deallocation requests
//    (i.e. "put" and "take").  This information is used to "roll back" the
//    state of the bitmap should an unexpected error prevent the completion
//    of the request.
//
// PUBLIC METHODS:
//  getLocation()
//    Get the start block of the extent.
//  getLenth()
//    Get the length (in blocks) of the extent.
//  getPage()
//    Get the page number.
//  getNext()
//    Get the next node in the linked list (used by BitmapSpaceResource).
//
// COLLABORATORS:
//  This is a private class member of BitmapSpaceResource.
//----------------------------------------------------------------------
// NOTES:
//  List construction and management is performed by BitmapSpaceResource.
//----------------------------------------------------------------------
    class AuditTrailNode: public Extent {

        UINT32          page_;
        AuditTrailNode* nextNode_;

    public:

        // INLINE: AuditTrailNode::AuditTrailNode()
        AuditTrailNode(const Extent& clExt,
                       UINT32 nPage,
                       AuditTrailNode* pNext):
                Extent(clExt.location, clExt.length)
        {
            page_ = nPage;
            nextNode_ = pNext;
        }

        UINT32 getLocation() const
        { return location; }

        UINT32 getLength() const
        { return length; }

        UINT32 getPage() const
        { return page_; }

        AuditTrailNode* getNext() const
        { return nextNode_; }
    };

//----------------------------------------------------------------------
// Class: BitmapBuffer     --GKG
// NOTE:  THIS CLASS IS A PRIVATE MEMBER TYPE OF CLASS BITMAPSPACERESOURCE.
//  The bitmap buffer manages the memory-image of an individual page of
//    the bitmap.  The class links to an associated BitmapPage object that
//    contains the meta-data associated with that page.  This object is
//    responsible for read and writing the bitmap data to physical media,
//    and also performs the actual bit manipulations.  "Dirty" blocks are
//    recorded to minimize the overhead of synchronizing the page to disk.
//
// PUBLIC METHODS:
//  error()
//    Return the error state.
//  linkBuffer()
//    Link this buffer to a BitmapPage and read the page data from media.
//  unlinkBuffer()
//    Break the link to the BitmapPage, updating any "dirty" blocks.
//  syncBuffer()
//    Update any "dirty" blocks on media.
//  clearBits()
//    Clear a range of bits in the memory buffer (set to zeroes).
//  setBits()
//    Set a range of bits in the memory buffer (set to ones).
//  getBit()
//    Determine the state of a particular bit in the memory buffer.
//  findSetRunLength()
//    Find the number of contiguous set bits starting from a specified location,
//    upto a specified maximum.  If the maximum is zero, continue until the
//    first zero bit or the page boundary is reached.
//  findClearRunLength()
//    Find the number of contiguous clear bits starting from a specified
//    location, upto a specified maximum.  If the maximum is zero, continue
//    until the first set bit or the page boundary is reached.
//  findSetRunReverse()
//    Find the number of contiguous set bits starting from a specifed location,
//    continuing backward until the first zero bit or the beginning page
//    boundary.
//  clearDirty()
//    Mark the range of dirty blocks to indicate no dirty blocks (set
//    firstDirty_ > lastDirty_).
//  markDirty()
//    Mark a specified range of blocks as dirty, growing the existing range if
//    necessary.
//  isDirty()
//    Are there any dirty blocks in this page?
//  isActive()
//    Is this buffer currently linked to a BitmapPage?
//  getNext()
//    Get the next buffer object in the linked list (used by BitmapBufferCache).
//  setNext()
//    Get the next buffer object in the linked list (used by BitmapBufferCache).
//  pagePosition()
//    Get the block offset of a given bit position in the buffer.
//
//
// COLLABORATORS:
//  This is a private class member of BitmapSpaceResource and is cross-
//    linked with a BitmapPage object.
//----------------------------------------------------------------------
// NOTES:
//  The associated BitmapPage object is not static, it may be reassigned
//    during runtime.  When the buffer is associated with a new BitmapPage
//    object, the buffer must update any "dirty" blocks in the original
//    page and read the new page data from media.
//----------------------------------------------------------------------

    class BitmapPage;  // forward declaration

    class BitmapBuffer
    {
    private:

        ByteArray bufferArray_;
        UINT32 firstDirty_;
        UINT32 lastDirty_;
        UINT32 bitSize_;
        Error err_;
        BitmapPage* bmPage_;
        BitmapBuffer* nextBuffer_;

    public:

        BitmapBuffer(UINT32 nPageSize);

        ~BitmapBuffer();

        Error error()
        { return err_; }

        void linkBuffer(BitmapPage* pPage, Error& err);

        void unlinkBuffer(Error& err);

        void syncBuffer(Error& err);

        void clear(Error& err);

        void clearBits(UINT32 nStart, UINT32 nLength, Error& err);

        void setBits(UINT32 nStart, UINT32 nLength, Error& err);

        Boolean getBit(UINT32 nPosition)
        {
            const BYTE* buffer = (CONST_BYTE_PTR)bufferArray_;
            return (nPosition > bmPage_->totalBlocks()) ? False :
                Boolean((buffer[SpaceBitmapMap::byteComponent(nPosition)] &
                         (1 << SpaceBitmapMap::bitComponent(nPosition))) != 0);
        }

        UINT32 findSetRunLength(UINT32 nPosition, UINT32 nMaxLength = 0) const;

        UINT32 findClearRunLength(UINT32 nPosition, UINT32 nMaxLength = 0) const;

        UINT32 findSetRunReverse(UINT32 nPosition) const;

        void clearDirty()
        {
            firstDirty_ = bmPage_->pageBlockSize();
            lastDirty_ = 0;
        }

        void markDirty(UINT32 nStartBlock, UINT32 nEndBlock)
        {
            if (nStartBlock < firstDirty_)
                firstDirty_ = nStartBlock;
            if (nEndBlock > lastDirty_)
                lastDirty_ = nEndBlock;
        }

        Boolean isDirty() const
        { return (Boolean(bmPage_ && firstDirty_ <= lastDirty_)); }

        Boolean isActive() const
        { return Boolean(bmPage_ != NULL); }

        BitmapBuffer* getNext() const
        { return nextBuffer_; }

        void setNext(BitmapBuffer* pNext)
        { nextBuffer_ = pNext; }

        UINT32 pagePosition(UINT32 nPosition)
        { return bmPage_->getBitmapMap().bufferBlockOffset(nPosition); }
    };

//----------------------------------------------------------------------
// Class: BitmapBufferCache     --GKG
// NOTE:  THIS CLASS IS A PRIVATE MEMBER TYPE OF CLASS BITMAPSPACERESOURCE.
//  This is a linked list of BitmapBuffer objects that assigns a buffer to
//    a BitmapPage object.  Buffers are assigned on a least-recently used
//    basis.
//
// PUBLIC METHODS:
//  linkBuffer()
//    Link a BitmapPage to a BitmapBuffer using the least-recently used
//    technique.
//  syncCache()
//    Update the "dirty" blocks of ALL buffers in the cache to media.
//  error()
//    Return the error state.
//
// COLLABORATORS:
//  This is a private class member of BitmapSpaceResource containg a list
//    of BitmapBuffer objects.
//----------------------------------------------------------------------
// NOTES:
//  The number of buffers in the linked list is determined at construction,
//    and remains static throughout the lifetime of this object.
//----------------------------------------------------------------------

    class BitmapBufferCache
    {
    private:

        BitmapBuffer* firstBuffer_;
        BitmapBuffer* lastBuffer_;
        Error err_;

    public:

        BitmapBufferCache(UINT32 nPageSize, UINT32 nNumBuffers);

        ~BitmapBufferCache();

        void linkBuffer(BitmapPage* pPage, Error& err);

        void syncCache(Error& err);

        Error error() const
        { return err_; }
    };

//----------------------------------------------------------------------
// Class: BitmapPage     --GKG
// NOTE:  THIS CLASS IS A PRIVATE MEMBER TYPE OF CLASS BITMAPSPACERESOURCE.
//  This object contains the meta-data associated with a single page of the
//    bitmap.  The BitmapSpaceResource creates an array of these, one for
//    each page.  This object is cross-linked with a BitmapBuffer object
//    when the associated bitmap data must be read or modified.
//
//
// PUBLIC METHODS:
//  initialize()
//    Post-construction initialization routine.
//  pageNumber()
//    The number of this page.
//  freeBlocks()
//    The number of available blocks in this page.
//  totalBlocks()
//    The total number of blocks in this page.
//  largestExtent()
//    The largest number of contiguous available blocks in this page.
//  takeExtent()
//    Allocates a specified number of contiguous available blocks from this
//    page.  Fails if the request cannot be satisfied.
//  takeExtent()
//    Allocates a particular extent from this page.  Fails if all or part
//    of the specified extent is already allocated.
//  takeNextExtent()
//    Allocates up to a specified number of blocks from the next available
//    extent on this page.  The request may be partially satisfied by this
//    call.
//   takeBeginExtent()
//    Allocates blocks from the extent adjoining the beginning of this page.
//    Fails if the request cannot be fulfilled.
//   takeEndExtent()
//    Allocates blocks from the extent adjoining the end of this page. Fails
//    if the request cannot be fulfilled.
//   putExtent()
//    Deallocates a particular extent to this page.  Fails if all or part of
//    the specified extent is already deallocated.
//  syncPage()
//    Updates this page on the physical media (if there are any "dirty"
//    blocks.
//  isEndExtent()
//    Is the specifed extent end on the page boundary?
//  linkBuffer()
//    Links the page to a BitmapBuffer and reads the data from disk.
//  unlinkBuffer()
//    Releases the link to a BitmapBuffer and updates any "dirty" blocks.
//  isDirty()
//    Does the linked buffer contain any "dirty" blocks?
//  pageFree()
//    Are ALL the blocks in this page available?
//  pageBeginExtent()
//    How many contiguous available blocks are adjacent the beginning page
//    boundary?
//  pageEndExtent()
//    How many contiguous available blocks are adjacent the ending page
//    boundary?
//  locLargestExtent()
//    Location of the largest run of available blocks in this page.
//  startByteOffset()
//    Offset to start of bitmap data in this page (from PagedSpaceBitmapMap).
//  pageBlockSize()
//    Size of this page in logical blocks (from PagedSpaceBitmapMap).
//  bitToBufferPos()
//    Take a bit number and find the associated bit offset in the buffer
//    (using the PagedSpaceBitmapMap).
//  bufferPosToBitPos()
//    Take a bit offset in the buffer and find the associated bit number
//    (using the PagedSpacebitmapMap).
//  getPartition()
//    Get a reference to the current OSTA partition.
//  getSpaceResource()
//    Get a reference to the BitmapSpaceResource that contains this page.
//  getBitmapMap()
//    Get a reference to the PagedSpaceBitmapMap.
//  getPageBuffer()
//    Get a pointer to the linked BitmapBuffer (if any).
//  setPageBuffer()
//    Set the linked BitmapBuffer.
//
// PRIVATE METHODS:
//  scanPage()
//    Read this page from disk and calculate all necessary meta-data items.
//  findLargestExtent()
//    Scan the page image for the length an location of the largest run of
//    contiguous available blocks.
//  takeExtentCommon()
//    The code common to all "take" methods of this class.
//
// COLLABORATORS:
//  This is a private class member of BitmapSpaceResource.
//----------------------------------------------------------------------
// NOTES:
//  NONE
//----------------------------------------------------------------------

    class BitmapPage
    {
    private:

        UINT32 numBlocks_;
        UINT32 pageNum_;
        UINT32 freeBlocks_;
        UINT32 locFirstFree_;
        UINT32 largestExtent_;
        UINT32 locLargestExtent_;
        UINT32 pageBeginExtent_;
        UINT32 pageEndExtent_;
        BitmapSpaceResource* bitmapSR_;
        BitmapBuffer* pageBuf_;

        void scanPage(Error& err);

        void findLargestExtent(Error& err);

        void takeExtentCommon(Extent& clExt, UINT32 nPosition, UINT32 nBlocks, Error& err);

    public:

        BitmapPage();

        ~BitmapPage();

        void initialize(BitmapSpaceResource* pSR, UINT32 nPageNum, Boolean nInit, Error& err);

        UINT32 pageNumber() const
        { return pageNum_; }

        UINT32 freeBlocks() const
        { return (freeBlocks_); }

        UINT32 totalBlocks() const
        { return bitmapSR_->getBitmapMap().pageNumBits(pageNum_); }

        UINT32 startBlock() const
        { return bitmapSR_->getBitmapMap().pageStartBlock(pageNum_); }

        UINT32 largestExtent() const
        { return (largestExtent_); }

        void takeExtent(Extent& clExt, UINT32 nBlocks, Error& err);

        void takeExtent(const Extent& clExt, Error& err);

        void takeNextExtent(Extent& clExt, UINT32 nBlocks, Error& err);

        void takeBeginExtent(Extent& clExt, UINT32 nBlocks, Error& err);

        void takeEndExtent(Extent& clExt, UINT32 nBlocks, Error& err);

        void putExtent(const Extent& clExt, Error& err);

        void syncPage(Error& err);

        Boolean isEndExtent(const Extent& clExt)
        { return Boolean(clExt.location + clExt.length == totalBlocks()); }

        void linkBuffer(Error& err)
        { bitmapSR_->linkBuffer(this, err); }

        void unlinkBuffer(Error& err)
        {
            err = error_None;
            if (pageBuf_)
                pageBuf_->unlinkBuffer(err);
        }

        Boolean isDirty() const
        { return (pageBuf_) ? pageBuf_->isDirty() : False; }

        Boolean pageFree() const
        { return Boolean(pageBeginExtent_ == pageEndExtent_ &&
                         pageBeginExtent_ == totalBlocks()); }

        UINT32 pageBeginExtent() const
        { return pageBeginExtent_; }

        UINT32 pageEndExtent() const
        { return pageEndExtent_; }

        UINT32 locLargestExtent() const
        { return locLargestExtent_; }

        UINT32 startByteOffset() const
        { return (bitmapSR_->getBitmapMap().pageStartByteOffset(pageNum_)); }

        UINT32 pageBlockSize() const
        { return bitmapSR_->getBitmapMap().pageBlockSize(pageNum_); }

        UINT32 bitToBufferPos(UINT32 nBit) const
        { return (bitmapSR_->getBitmapMap().pageOffsetToBufferPos(pageNum_, nBit)); }

        UINT32 bufferPosToBit(UINT32 nPosition) const
        { return (bitmapSR_->getBitmapMap().bufferPosToPageOffset(pageNum_, nPosition)); }

        Partition& getPartition() const
        { return (bitmapSR_->getPartition()); }

        BitmapSpaceResource& getSpaceResource() const
        { return *bitmapSR_; }

        PagedSpaceBitmapMap& getBitmapMap() const
        { return getSpaceResource().getBitmapMap(); }

        BitmapBuffer* getPageBuffer() const
        { return pageBuf_; }

        void setPageBuffer(BitmapBuffer* pBuffer)
        { pageBuf_ = pBuffer; }
    };

    friend class BitmapPage;

private:

    enum
    {
        maxCachePages =         4
    };

    Error err_;
    UINT32 freeBlocks_;
    UINT32 pageFirstFree_;
    UINT32 largestExtent_;
    UINT32 locLargestExtent_;
    PagedSpaceBitmapMap* bmMap_;
    BitmapPage* bmPages_;
    BitmapBufferCache* bufferCache_;
    AuditTrailNode* auditTrail_;

    UINT32 pageSize() const
    { return bmMap_->pageSize(); }

    Partition& getPartition() const
    { return *partp_; }

    PagedSpaceBitmapMap& getBitmapMap() const
    { return *bmMap_; }

    UINT32 totalBlocks() const
    { return bmMap_->numBits(); }

    void findFirstFree(UINT32 nStartPage = 0);

    void findLargestExtent();

    void findBitmapData()
    {
        // Tally up the free blocks page by page.
        freeBlocks_ = 0;
        for (UINT32 nCount = 0; nCount < bmMap_->numPages(); nCount++)
            freeBlocks_ += bmPages_[nCount].freeBlocks();
        findFirstFree();
        findLargestExtent();
    }

    UINT32 findBoundaryExtent(UINT32 nPage) const;

    void linkBuffer(BitmapPage* pPage, Error& err) const
    { bufferCache_->linkBuffer(pPage, err); }

    void clearAuditTrail()
    {
        AuditTrailNode* pNode = auditTrail_;
        auditTrail_ = NULL;
        while (pNode)
        {
            AuditTrailNode* pNext = pNode->getNext();
            delete pNode;
            pNode = pNext;
        }
    }

    void pushAuditTrail(const Extent& clExt, UINT32 nPage, Error& err)
    {
        AuditTrailNode* pNode = new AuditTrailNode(clExt, nPage, auditTrail_);
        if (pNode == NULL)
        {
            err_ = err = error_No_free_store;
            return;
        }
        auditTrail_ = pNode;
    }

    void popAuditTrail();

    void disasterRecovery(Boolean nTake);

    void free();

public:

    BitmapSpaceResource(Partition& clPart, SRSpaceType nType);

    BitmapSpaceResource(Partition& clPart, SRSpaceType nType, LogExtentList& clInitSpace);

    virtual ~BitmapSpaceResource();

    Error error() const
    { return err_; }

    static UINT32 descBytes(Partition* pPart)
    { return (24 + (pPart ? ((pPart->numBlocks() + 7) >> 3) : 0) + pPart->blockSize() - 1) / pPart->blockSize() * pPart->blockSize(); }

    virtual void takeLogExtent(LogExtent& clLogExt, UINT32 nLength, Error& err);

    virtual void takeLogExtentList(LogExtentList& clLEList, UINT64 nLength, Error& err);

    virtual void putLogExtent(const LogExtent& clLogExt, Error& err);

    virtual void putLogExtentList(const LogExtentList& clLEList, Error& err);

    virtual UINT64 availBytes() const
    { return (UINT64(freeBlocks_) * UINT64(blockLength())); }

    virtual UINT32 maxExtLen() const
    {
        // Make sure that the value is less than the maximum length for a
        // single logical extent.
        UINT32 nBlocks = bmMap_->maxExtentBlocks();
        if (largestExtent_ < nBlocks)
            nBlocks = largestExtent_;

        return (nBlocks * blockLength());
    }

    virtual UINT32 blockLength() const
    { return partp_->blockSize(); }

    virtual void initWithNewSpace(LogExtentList& clInitSpace);

    virtual void initFromDisk(void);

    virtual void syncToDiskUsingSR(SpaceResource& /*clSR*/, Error& err)
    {
        err = err_;
        if (err)
            return;

        bufferCache_->syncCache(err);
        err_ = err;

        return;
    }
};

//----------------------------------------------------------------------
// ENUM: SRDescType
//
//  The different types of descriptors allowed for SpaceResources
//
// DEFINITIONS:
//  srDesc_Table  - TableSpaceResources are used.
//  srDesc_Bitmap - BitmapSpaceResources are used.
//
// USES:
//  Used solely by the MasterSpaceResource to set and get the type of
//  structure to use on the disk.
//
//----------------------------------------------------------------------
// Private comments go here - will not be extracted into HTML.
//----------------------------------------------------------------------

enum SRDescType {
    srDesc_Table,
    srDesc_Bitmap
};

//----------------------------------------------------------------------
// CLASS: MasterSpaceResource           --DVM
//
//  This combines either or both SRs associated with a single
//  partition.
//
//  This is the more public SR, which we expect users to design to,
//  although they may likely end up modifying it, by overloading its
//  allocation and/or construction methods.
//
//  It is to be used instead of the other more restricted
//  ISOSpaceResources. It allocates and frees from and to the
//  appropriate other ISOSRs.
//
//  It is derived from ISOSpaceResource, and holds a pointer to two
//  other ISOSpaceResources.
//
//  Its purpose is to provide a simpler use model (for both
//  initialization and allocation/deallocation) as well as to
//  consolidate all switch statements concerning SR types.
//
//  Separate access to the SRs it contains is not currently offered.
//  
// PUBLIC METHODS:
//
// MasterSpaceResource() - Constructor with two forms:
//
//  One calls initFromDisk(), instantiating the appropriate types of
//  SRs and initializing them from the disk. Unlike all other ISOSR
//  constructors, it does not require a spaceType argument, since that
//  will be gotten from the disk. Additionally, it does not require a
//  descType arg either, because the on-disk structure will dictate
//  that.
//   
//  The other form calls initWithNewSpace, and thus requires both a
//  spaceType and a descType argument, as well as the standard
//  Partition pointer and a LogExtentList, holding space for the
//  descriptors as well as all initial free space.
//
// error()               - returns error.
// availBytes()          - See SpaceResource
// maxExtLen()           - See SpaceResource
// takeLogExtent()
// takeLogExtentList()
//  See SpaceResource.
// putLogExtent()
// putLogExtentList()
//  Note that these two will never error on extentType mismatch. That
//  is, if an unerased extent is freed to an ErasedOnly MasterSR, the
//  extent will be automatically erased before it is added. Also note
//  that if the SR is ErasedAndUnerased, LogExtentLists which are
//  mixed in nature will have their space diverted to the appropriate
//  Erased or Unerased SR. 
//
// STATIC METHODS:
//
// descBytes()   - Returns number of bytes required to hold a
//                 SpaceTable with the supplied number of blocks in
//                 the supplied partition. This is static, so that it
//                 may be called BEFORE construction.
//
// INITIALIZATION AND ISO METHODS:
//
// initFromDisk()
//  This is just like the other ISOSpaceResources, except that the
//  spaceType will also be dictated by what is found on the disk.
//  Also, the descType will be set based upon whether bitmaps or
//  tables have been found. It sets the error_ member, rather than
//  returning an error.
// initWithNewSpace()
//  This is just like the other ISOSpaceResources, except that if it
//  holds both types of space (spaceType_ == ErasedAndUnerased), the
//  first extent in the supplied LEL will be given to the Erased SR,
//  and the second to the Unerased SR. The rest will go to the
//  appropriate SR. It sets the error_ member, rather than returning
//  an error.
// syncToDisk()
//  Make disk image consistent with internal space. This will
//  basically propagate the call down to its constituent SRs.
//
// USAGE NOTES:
//----------------------------------------------------------------------
// COLLABORATORS:
//  Derived from ISOSpaceResource. Owns one or two TableSRs and/or
//  BitmapSRs.
//
// PRIVATE METHODS:
//
// IMPLEMENTATION NOTES:
//
//----------------------------------------------------------------------

class MasterSpaceResource : public ISOSpaceResource {

    SRDescType         descType_    ;
    Error              error_       ;
    ISOSpaceResource * unerasedSRp_ ;
    ISOSpaceResource * erasedSRp_   ;

    void free(void) {
        if (erasedSRp_ != NULL)   {
            delete erasedSRp_;
            erasedSRp_ = NULL;
        }
        if (unerasedSRp_ != NULL) {
            delete unerasedSRp_;
            unerasedSRp_ = NULL;
        }
    }

    void copy( const MasterSpaceResource & obj ) {
        descType_ = obj.descType_;
        error_    = obj.error_; // Error is propagated.
        if (obj.unerasedSRp_ != NULL) {
            *unerasedSRp_ = *obj.unerasedSRp_;
        } else {
            unerasedSRp_ = NULL;
        }
        if (obj.erasedSRp_ != NULL) {
            *erasedSRp_ = *obj.erasedSRp_;
        } else {
            erasedSRp_ = NULL;
        }
    }
        
    // copy constructor
    MasterSpaceResource( const MasterSpaceResource &obj) :
            ISOSpaceResource(obj)
    {
        copy(obj);
    }

    // operator=()
    MasterSpaceResource &operator=  ( const MasterSpaceResource &obj )
    {
        if (this != &obj) {
            free();
            copy(obj);
        }
        return *this;
    }

public:
// INLINE: MasterSpaceResource::MasterSpaceResource()
    MasterSpaceResource(Partition& part ) :
            ISOSpaceResource(part,
                             srSpace_ErasedAndUnerased), // temp value
            descType_(srDesc_Table), // bogus temporary value
            error_(error_None),
            unerasedSRp_(NULL),
            erasedSRp_(NULL)
    {
        initFromDisk();
    }
// INLINE: MasterSpaceResource::MasterSpaceResource()
    MasterSpaceResource(Partition& part,
                        SRDescType dt,
                        SRSpaceType st, 
                        LogExtentList & initialSpace) :
            ISOSpaceResource(part, st),
            descType_(dt),
            error_(error_None),
            unerasedSRp_(NULL),
            erasedSRp_(NULL)
    {
        initWithNewSpace( initialSpace );
    }

    // Destructor
    virtual ~MasterSpaceResource()
    {
        free();
    }

    // Status methods
    virtual Error error(void) const {
        if (error_)
            return error_;
        Error err(error_None);
        if (erasedSRp_) {
            if (err = erasedSRp_->error())
                return err;
        }
        if (unerasedSRp_) {
            if (err = unerasedSRp_->error())
                return err;
        }
        return err;
    }

    // Override allowsUnerased. Even if ErasedOnly, simply erases it first.
    virtual Boolean allowsUnerased(void) const { return True; }

    virtual UINT64 availBytes(void) const  {
        // Add up the two availBytes().
        UINT64 ab = 0;
        if (erasedSRp_)
            ab += erasedSRp_->availBytes();
        if (unerasedSRp_)
            ab += unerasedSRp_->availBytes();
        return ab;
    }
    virtual UINT32 maxExtLen(void) const  {
        // Take the Max of the Max.
        UINT32 maxE = 0;
        UINT32 maxU = 0;
        if (erasedSRp_)
            maxE = erasedSRp_->maxExtLen();
        if (unerasedSRp_)
            maxU = unerasedSRp_->maxExtLen();
        return (maxE > maxU ? maxE : maxU);
    }

    // Allocation methods
    virtual void takeLogExtent( LogExtent& lext,
                                UINT32 bc,
                                Error& err );
    virtual void takeLogExtentList( LogExtentList& list,
                                    UINT64 bc,
                                    Error& err );

    // Deallocation methods
    virtual void putLogExtent( const LogExtent& lext,
                               Error& err );
    virtual void putLogExtentList( const LogExtentList& list,
                                   Error& err );

    // Static methods
    static UINT32 descBytes(Partition * partp,
                            SRSpaceType st,
                            SRDescType dt) {
        // Determine how many SRs and how many bytes per SR.
        UINT16 numSRs   = (st == srSpace_ErasedAndUnerased ? 2 : 1 );
        UINT32 numDescBytes = (dt == srDesc_Bitmap ? 
                               BitmapSpaceResource::descBytes(partp):
                               TableSpaceResource::descBytes(partp));
        return numSRs * numDescBytes;
    }
    
    // ISO methods
    virtual void initFromDisk(void) {
        // First, free existing SRs.
        free();
        
        // Then, have partition checked for valid information
        if ( error_ = partp_->validateSpaceExtents() )
            return;
        
        // Take inventory
        Boolean hasEST = (partp_->erasedSpaceTblExt().infoLen()    != 0 ?
                          True : False );
        Boolean hasESB = (partp_->erasedSpaceBMapExt().infoLen()   != 0 ?
                          True : False );
        Boolean hasUST = (partp_->unerasedSpaceTblExt().infoLen()  != 0 ?
                          True : False );
        Boolean hasUSB = (partp_->unerasedSpaceBMapExt().infoLen() != 0 ?
                          True : False );

        // Set error if no SR space.
        if (! (hasEST || hasESB || hasUST || hasUSB)) {
            error_ = error_SR_has_no_descriptor_space;
            return;
        }

        // Set spaceType
        if (hasEST && hasUST || hasESB && hasUSB)
            spaceType(srSpace_ErasedAndUnerased);
        else if (hasEST || hasESB)
            spaceType(srSpace_ErasedOnly);
        else if (hasUST || hasUSB)
            spaceType(srSpace_UnerasedOnly);

        // Set descType
        if (hasEST || hasUST)
            descType_ = srDesc_Table;
        else
            descType_ = srDesc_Bitmap;
            
        // Next, instantiate the proper SRs, having them grab their
        // contents from disk, and hold pointers to them in erasedSRp_
        // and unerasedSRp_.

        if (spaceType() == srSpace_ErasedAndUnerased ||
            spaceType() == srSpace_ErasedOnly) {

            // First, instantiate Erased SR
            if (hasEST) {
                erasedSRp_ = new TableSpaceResource(*partp_,srSpace_ErasedOnly);
            }
            if (hasESB) {
                erasedSRp_ = new BitmapSpaceResource(*partp_,srSpace_ErasedOnly);
            }
            // Now, set appropriate errors
            if (erasedSRp_ == NULL) {
                error_ = error_No_free_store;
                return;
            }
            if (error_ = erasedSRp_->error())
                return;
        }

        if (spaceType() == srSpace_ErasedAndUnerased ||
            spaceType() == srSpace_UnerasedOnly) {

            // Now, instantiate Unerased SR
            if (hasUST) {
                unerasedSRp_ = new TableSpaceResource(*partp_,srSpace_UnerasedOnly);
            }
            if (hasUSB) {
                unerasedSRp_ = new BitmapSpaceResource(*partp_,srSpace_UnerasedOnly);
            }
            // Now, set appropriate errors
            if (unerasedSRp_ == NULL) {
                error_ = error_No_free_store;
                return;
            }
            if (error_ = unerasedSRp_->error())
                return;
        }
    }

    virtual void initWithNewSpace(LogExtentList & initialSpace) {
        // First, free existing SRs.
        free();
        
        // Exit if initialSpace is in error.
        if ( error_ = initialSpace.error() ) {
            return;
        }
        // Instantiate LELs for both
        // (can't be conditional, or will go out of scope)
        LogExtentList initialErased(logVolume());
        if ( error_ = initialErased.error() ) {
            return;
        }
        LogExtentList initialUnerased(logVolume());
        if ( error_ = initialErased.error() ) {
            return;
        }
        
        // Hold the descBytes for later.
        UINT32 numDescBytes  = (descType_ == srDesc_Bitmap ? 
                                BitmapSpaceResource::descBytes(partp_):
                                TableSpaceResource::descBytes(partp_));

        // Cannot depend upon pointers being valid
        Boolean hasErased = ( spaceType() == srSpace_ErasedOnly ||
                              spaceType() == srSpace_ErasedAndUnerased ?
                              True : False);
        Boolean hasUnerased = ( spaceType() == srSpace_UnerasedOnly ||
                                spaceType() == srSpace_ErasedAndUnerased ?
                                True : False);

        // First, grab room for Erased Descriptor if any.
        if ( hasErased ) {
            // Extract room for the descriptor
            LogExtent erasedDescSpace;
            if ( error_ = erasedDescSpace.error() ) {
                return;
            }
            initialSpace.extractLogExtentFromHead(erasedDescSpace,
                                                  numDescBytes,
                                                  error_);
            if ( error_ ) {
                return;
            }
            // Place it at head of initialErased list.
            initialErased.append(erasedDescSpace, error_);
            if ( error_ ) {
                return;
            }
        }
        // Next, grab room for Unerased Descriptor if any.
        if ( hasUnerased ) {
            // Extract room for the descriptor
            LogExtent unerasedDescSpace;
            if ( error_ = unerasedDescSpace.error() ) {
                return;
            }
            initialSpace.extractLogExtentFromHead(unerasedDescSpace,
                                                  numDescBytes,
                                                  error_);
            if ( error_ ) {
                return;
            }
            // Place it at head of initialUnerased list.
            initialUnerased.append(unerasedDescSpace, error_);
            if ( error_ ) {
                return;
            }
        }
        // Next, build the extent list(s)
        // NOTE that this does a non-destructive take(), and could
        // rather do a destructive one if it is more desirable for any
        // reason, as long as at() works properly with a list whose
        // head is disappearing. Otherwise, it could grab extents
        // starting at the tail...
        LogExtent * le;
        for (UINT32 i = 0;i<initialSpace.numExtents() ;i++ ) {
            le = initialSpace.at(i,error_);
            if (error_)
                return;
            if ( le->extentType() == Erased && hasErased )
                initialErased.append(*le,error_);
            else
                initialUnerased.append(*le,error_);
            if (error_)
                return;
        }

        // Finally, instantiate the proper SRs, initializing them from
        // the initial space lists.
        if (hasErased) {        // Erased
            if (descType_ == srDesc_Table) {
                // Instantiate a Table
                erasedSRp_ = new TableSpaceResource(*partp_,
                                                    srSpace_ErasedOnly,
                                                    initialErased);
            } else {
                // Instantiate a Bitmap
                erasedSRp_ = new BitmapSpaceResource(*partp_,
                                                     srSpace_ErasedOnly,
                                                     initialErased);
            }
            // Now, set appropriate errors.
            if (erasedSRp_ == NULL) {
                error_ = error_No_free_store;
                return;
            }
            if (error_ = erasedSRp_->error())
                return;
        }
        if (hasUnerased) {      // Unerased
            if (descType_ == srDesc_Table) {
                // Instantiate a Table
                unerasedSRp_ = new TableSpaceResource(*partp_,
                                                      srSpace_UnerasedOnly,
                                                      initialUnerased);
            } else {
                // Instantiate a Bitmap
                unerasedSRp_ = new BitmapSpaceResource(*partp_,
                                                       srSpace_UnerasedOnly,
                                                       initialUnerased);
            }
            // Now, set appropriate errors
            if (unerasedSRp_ == NULL) {
                error_ = error_No_free_store;
                return;
            }
            if (error_ = unerasedSRp_->error())
                return;
        }
    }
    
    virtual void syncToDiskUsingSR(SpaceResource & mdsr,
                                   Error & err) {
        // Clear out error
        err = error_None;
        // First sync erased
        if (erasedSRp_)
            erasedSRp_->syncToDiskUsingSR(mdsr,err);
        // Return if any errors
        if (err)
            return;
        // Next, sync unerased
        if (unerasedSRp_)
            unerasedSRp_->syncToDiskUsingSR(mdsr,err);
        return;
    }
};

#endif
