TransferObjects.cpp
// TransferObjects.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2007
@import "Ceda/cxPersistStore/IPersistStore.h"
@import "Ceda/cxObject/IObjectVisitor.h"
#include "Ceda/cxUtils/TracerUtils.h"
#include "Ceda/cxUtils/Environ.h"
/*
Demonstration of transfer of objects between PSpaces
----------------------------------------------------
The main reason to use multiple PSpaces is to promote greater concurrency. This example shows
one such appproach that is appropriate when creation of new object assemblies is time consuming,
and would otherwise have negative impacts on performance.
The idea is to prepare new object assemblies in an independent "child" PSpace to avoid a lock on
the parent PSpace. Only when the assembly is completed (which could take a very long time), is
a lock gained on the parent PSpace in order to transfer the assembly into the parent PSpace. Often
this can be achieved very quickly.
*/
namespace TransferObjects
{
///////////////////////////////////////////////////////////////////////////////////////////////
// A node of a forwards linked list of ints
$struct Node isa ceda::IPersistable
{
Node(int v = 0) : m_value(v) {}
// Implementation of IObject
void VisitObjects(ceda::IObjectVisitor& v) const { v << m_next; }
// Implementation of IPersistable
void VisitPrefs(ceda::IPrefVisitor& v) const { v << m_next; }
void Serialise(ceda::Archive& ar) const
{
ar << m_next << m_value;
}
void Deserialise(ceda::InputArchive& ar)
{
ar >> m_next >> m_value;
}
ceda::cref<Node> m_next; // Next node in the forward linked list
int m_value; // Value of this node
};
///////////////////////////////////////////////////////////////////////////////////////////////
// A forwards linked list of int
$struct List <<os>> isa ceda::IPersistable
{
// Implementation of IObject
void VisitObjects(ceda::IObjectVisitor& v) const { v << m_first << m_last; }
// Implementation of IPersistable
void VisitPrefs(ceda::IPrefVisitor& v) const { v << m_first; }
void Serialise(ceda::Archive& ar) const
{
ar << m_first << m_last;
}
void Deserialise(ceda::InputArchive& ar)
{
ar >> m_first >> m_last;
}
// Initialise with values [0,1,2,...,n-1]
void Create(int n)
{
if (n > 0)
{
Node* p = $new Node(0);
cxAssert(!p->IsDirty());
DeclareReachable(this,p);
cxAssert(p->IsDirty());
m_first = p;
{
for (int i=1 ; i < n ; ++i)
{
Node* q = $new Node(i);
cxAssert(!q->IsDirty());
DeclareReachable(p,q);
cxAssert(q->IsDirty());
p->m_next = q;
p = q;
}
}
m_last = p;
}
MarkAsDirtyWithoutTrace();
}
void Append(List& rhs)
{
if (m_last)
{
m_last->m_next = rhs.m_first;
m_last->MarkAsDirtyWithoutTrace();
m_last = rhs.m_last;
}
else
{
m_first = rhs.m_first;
m_last = rhs.m_last;
}
MarkAsDirtyWithoutTrace();
rhs.m_first = ceda::null;
rhs.m_last = ceda::null;
rhs.MarkAsDirtyWithoutTrace();
}
void Write(ceda::xostream& os) const
{
os << '[';
Node* p = m_first.Get();
while(p)
{
if (m_first != p) os << ',';
os << p->m_value;
p = p->m_next.Get();
}
os << ']';
}
ceda::cref<Node> m_first;
ceda::cref<Node> m_last;
};
///////////////////////////////////////////////////////////////////////////////////////////////
/*
todo: currently have a bug that is revealed by for the foo loop below. Causes assertion in
CacheMap::Transfer() because OID is already present in P1's ROT on the second iteration.
Problem is caused by transfer being too eager in what it transfers. The following two objects
must not be transferred:
1. PSpaceRoots
2. DeletionQueue.
These objects must remain in the ROT, DOS, etc. This is a bit of a pain because it means we
need to filter them.
*/
void Run()
{
ceda::TraceGroup g("TransferObjects example");
// Open or create store
ceda::xstring path = ceda::GetCedaTestPath("TransferObjects.ced");
ceda::close_ptr<ceda::PersistStore> pstore(ceda::OpenPersistStore(path.c_str() /*, ceda::OM_CREATE_ALWAYS*/));
// Open or create main PSpace named p1
ceda::WPSpace p1(ceda::OpenPSpace(pstore.get(), "p1"));
// Bootstrap root list L1 in p1
List* L1 = ceda::BootstrapPSpaceRoot<List>("L1");
for (int i=0 ; i < 3 ; ++i)
{
// Create a subordinate PSpace named p2
ceda::WPSpace p2(ceda::OpenPSpace(pstore.get(), "p2"));
// Bootstrap root list L2 in p2
List* L2 = ceda::BootstrapPSpaceRoot<List>("L2");
// In a transaction on p2, populate L2. This illustrates a time consuming creation of
// a new object assembly, avoiding the need to lock the parent PSpace.
{
// Declare transaction on p2
ceda::CSpaceTxn txn;
// Make L2 = [0,1,2,...,9]
L2->Create(10);
cxAssert(L2->IsDirty());
Tracer() << "L2 = " << *L2 << '\n';
}
// Quickly transfer nodes from child list into parent space
@if (false) // todo
{
{
// Declare transaction on p1 and p2
ceda::PSpaceTransferTxn txn(p1,p2);
// Transfer nodes from L1 to L2
L1->Append(*L2);
cxAssert(L1->IsDirty());
Tracer() << "L1 = " << *L1 << '\n';
Tracer() << '\n';
}
}
}
}
}