ROD Objects

The objects under the Universal Tree of a WorkingSet can either be mutable or immutable.

Only the mutable objects can be the target of update operations.

The immutable objects are called Replicate On Demand (ROD) objects, because they aren't sent in the operations ("deltas") which created them (i.e. in the deltas which are written or read by a DeltaRW session object).

Rather the propagation of ROD objects is handled by a different session object called a RodSession (or at a lower level with RodWriter and RodReader objects).

Under the hood, the sending/receiving of ROD objects is straightforward because they are immutable. There is no need to be concerned with versions, vector times, operations and Operational Transformation.

A WorkingSetMachine has a boolean flag which determines whether it is a custodian of the ROD objects. A custodian is eagerly sent ROD objects from its peers so it tends to get its own copy of them all.

A concrete class which implements interface IPersistable determines whether object instances of that class are ROD objects using the <<rod>> directive. For example:


$struct+ TBuffer <<rod>> isa ceda::IPersistable :
    model
    {
        ceda::string8 Buffer;
    }
{
};

Example

RImage

Consider a ROD object data type such as RImage:


$struct+ RImage <<rod>> isa IPersistable :
    model
    {
        JPeg jpeg;
    }
{
};

where JPeg is a reflected data type suitable for use in models of IPersistable objects (for example it needs to support default construction and serialisation).

PImage

It's often appropriate to cref a ROD object from a mutable object. This is perhaps what James Coplien calls the Envelope and Letter Idiom. For example:


$struct+ PImage isa IPersistable :
    model
    {
        xstring Name;
        int32 Width;
        int32 Height;
        cref<RImage> Ref;
    }
{
};

ImageView

Consider a class ImageView which caches an OpenGL texture using a $cache function.

The return value of this function uses std::optional to account for the fact that the texture is uploaded into video memory asynchronously.

The implementation of this function calls AsyncGet() on a cref variable that points at a ROD object.

This can cause a request for the ROD object to be sent by a RodSession to a peer, and the Texture is uploaded as soon as the ROD object is received.


class ImageView
{
    $cache^ std::optional<Texture> GetOpenGLTexture() const
    {
        if (const RImage* i = image.Ref.read().AsyncGet())
        {
            return UploadTexture(i->jpeg);
        }
        else
        {
            return std::nullopt;
        }
    }

    PImage& image;
};

Note that AsyncGet() on a cref calls AsyncBind on the PSpace.