62 Deprecated MakeMemoryResident

Status: This chapter records a deprecated ROT design and is retained for historical reference.

A few years ago the ROT supported a function named MakeMemoryResident. It no longer works.

/*
todo: this currently does a cxAssert(0).  Should it be removed?

MakeMemoryResident() is normally called without a lock on the PSpace.  The idea is to allow
a worker thread to be tied up loading an object from disk without tieing up more important
threads (such as the main GUI thread).  The general rule is: don't do I/O whilst holding a
lock on the PSpace!

This function consults the ROT and does nothing if the object is already resident.  Otherwise
it either blocks on an event in the CacheMap or else takes on responsibility for loading the
object into memory.  In the latter case it will have created one or more objects in a
temporary CSpace.  After loading from disk it declares a shared read lock on the PSpace and
transfers the created objects from the temporary CSpace to the PSpace.  It returns after
having made sure the object was memory resident.  However assuming this has been called
without a lock on the PSpace, clients cannot assume that the object is still memory resident
at the time the function returns because the GC may have evicted it!

Currently called:
    -   from PSpace::MakeMemoryResident(OID oid)
*/

void ROT::MakeMemoryResident(OID oid)
{
    // This function is currently called from the MultiResImage, but can no longer work this way
    // because FindOrLoadResidentObject() asserts there is a CSpace lock.
    cxAssert(0);

    /*
    Typically called by a thread without a lock on the PSpace

    We want to call FindOrLoadResidentObject(oid).  However the problem is that if the object needs to be
    loaded, dynamic creation will occur and that will fail because this thread isn't associated
    with a PSpace.

    Our solution is to declare a local CSpace and then transfer all objects into the PSpace
    */

    CSpaceCreator src(CEDA_GC_THREAD_DONT_START);
    CSpaceLock lock(src);

    // Calling FindOrLoadResidentObject() could appear rather dangerous since we don't have any lock on
    // the CSpace, so therefore for example we could bind to an object in the ROT on which
    // the GC thread is calling Destroy() and is about to call ROT::Remove(). I.e. we
    // return an object that has been deleted.
    // However we completely ignore the return value, so there is no problem!
    // The purpose of this function is to take action because there is no entry in the ROT
    // and we want this thread to take on the responsibility to load the object from disk.
    FindOrLoadResidentObject(oid);

    // Transfer objects from the cspace (if any)
    if (GetNumObjects(src) > 0)
    {
        CSpace* dst = pspace_.GetCSpace();
        CSpaceLock lock(dst);
        TransferCSpace(src,dst);  // Must only be called with exclusive write lock on both CSpaces
    }
}