DeleteObjects.cpp
// DeleteObjects.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2012
@import "Store.h"
#include "Ceda/cxUtils/Environ.h"
#include "Ceda/cxUtils/HPTime.h"
/*
Example generated output:
DeleteObjects
{
Create new store
Num check points = 0
Num recoveries = 0
Num transactions = 2
Segment size = 512 kB
Num serial elements = 5
Num live overflow packets = 0
Num live RPM packets = 0
Num obsolete packets = 2
Total utilisation = 0000000000000083 = 131
File size = 0000000000080000 = 524288
% utilisation = 0.025%
Open store and insert a child object
root = X(100,01010101.01010106:DeleteObjects::X:0000000001D7B960)
Open store and delete the child object
root = X(100,01010101.01010106:DeleteObjects::X:0000000001D7B840)
c = X(0,null)
}
*/
namespace DeleteObjects
{
$struct X isa ceda::IPersistable :
model
{
ceda::int32 m_value;
ceda::cref<X> m_child;
}
{
};
void Run()
{
ceda::TraceGroup g("DeleteObjects");
ceda::xstring path = ceda::GetCedaTestPath("DeleteObjects.ced");
{
Tracer() << "Create new store\n";
ceda::TraceIndenter indent;
Store store(path, ceda::OM_CREATE_ALWAYS);
X* root = store.BootstrapRoot<X>();
#if CEDA_LSS_USE_CONTIGUOUS_SEID_SPACE
/*
The PersistStore creates two special serial elements:
RootPersistStoreObject: oid = 1.0
PSpaceMap : oid = 1.1
The PSpace creates two special serial elements:
PSpaceRoots : oid = 1.2
DeletionQueue : oid = 1.3
The call to BootstrapRoot<X> allocates another oid:
root : oid = 1.4
*/
cxAssert(GetOid(root) == ceda::OID(4,1));
#else
/*
The PersistStore creates two special serial elements:
RootPersistStoreObject: oid = 01010101.01010101
PSpaceMap : oid = 01010101.01010102
The PSpace creates two special serial elements:
PSpaceRoots : oid = 01010101.01010103
DeletionQueue : oid = 01010101.01010104
The call to BootstrapRoot<X> allocates another oid:
root : oid = 01010101.01010105
*/
cxAssert(GetOid(root) == ceda::OID(0x01010105, 0x01010101));
#endif
cxAssert(store.GetNumPersistableObjects() == 1);
cxAssert(store.GetNumPSpaces() == 1);
store.ShowLssStats();
}
{
Tracer() << "Open store and insert a child object\n";
ceda::TraceIndenter indent;
Store store(path);
X* root = store.BootstrapRoot<X>();
{
ceda::CSpaceTxn txn;
root->m_value = 100;
// Create an object. This is registered in the CSpace but is not yet reachable
// from the persitent store so doesn't have an OID yet
X* c = $new X;
cxAssert(!GetOid(c));
// This assignment causes the object to become persistent, so it is allocated an OID
// (in this case 00000001.00000006).
root->m_child = c;
Tracer() << "GetOid(c) = " << GetOid(c) << '\n';
#if CEDA_LSS_USE_CONTIGUOUS_SEID_SPACE
// todo : this is no longer the case. Why?
/*
// The object with OID 00000001.00000005 is the ceda::WorkingSetMgr
ceda::pref<ceda::IPersistable> p;
p.SetOid( ceda::OID(5,1) );
Tracer() << "Object with oid 00000001.00000005 = " << p.Get() << '\n';
*/
cxAssert(GetOid(c) == ceda::OID(5,1));
#else
cxAssert(GetOid(c) == ceda::OID(0x01010106, 0x01010101));
#endif
Tracer() << "root = " << *root << '\n';
}
cxAssert(store.GetNumPersistableObjects() == 2);
}
{
Tracer() << "Open store and delete the child object\n";
ceda::TraceIndenter indent;
Store store(path);
X* root = store.BootstrapRoot<X>();
{
ceda::CSpaceTxn txn;
cxAssert(root->m_value == 100);
X* c = root->m_child.Get();
cxAssert(c);
Tracer() << "root = " << *root << '\n';
Tracer() << "c = " << *c << '\n';
// The following assignment causes the child object to be permanently deleted from
// the store, but this happens asychronously.
root->m_child = nullptr;
}
cxAssert(store.GetNumPersistableObjects() == 2);
// Set the period for the DosWriter to 100msec, and wait for long enough for the async
// deletion to be completed.
cxAssert( GetDosPeriod(store.m_store) == 1000 );
SetDosPeriod(store.m_store, 100);
Sleep(200);
cxAssert(store.GetNumPersistableObjects() == 1);
}
}
}
/*
Example generated output:
DeleteObjects2
{
Create new store
Open store and insert a child object
root = (100,(0,null))
Open store and delete the child object
root = (100,(0,null))
c = (0,null)
root = (100,null)
}
*/
namespace DeleteObjects2
{
$struct X <<os>> isa ceda::IPersistable
{
X() : m_value(0) {}
explicit X(int v) : m_value(v) {}
// Implementation of IObject
void VisitObjects(ceda::IObjectVisitor& v) const { v << m_child; }
// Implementation of IPersistable
void VisitPrefs(ceda::IPrefVisitor& v) const { v << m_child; }
void Write(ceda::xostream& os) const
{
os << '(' << m_value << ',';
if (m_child)
{
m_child->Write(os);
}
else
{
os << "null";
}
os << ')';
}
void Serialise(ceda::Archive& ar) const
{
ar << m_value << m_child;
}
void Deserialise(ceda::InputArchive& ar)
{
ar >> m_value >> m_child;
}
ceda::int32 m_value;
ceda::cref<X> m_child;
};
void Run()
{
ceda::TraceGroup g("DeleteObjects2");
ceda::xstring path = ceda::GetCedaTestPath("DeleteObjects2.ced");
{
Tracer() << "Create new store\n";
ceda::TraceIndenter indent;
Store store(path, ceda::OM_CREATE_ALWAYS);
X* root = store.BootstrapRoot<X>();
#if CEDA_LSS_USE_CONTIGUOUS_SEID_SPACE
cxAssert(GetOid(root) == ceda::OID(4,1));
#else
cxAssert(GetOid(root) == ceda::OID(0x01010105, 0x01010101));
#endif
cxAssert(store.GetNumPersistableObjects() == 1);
}
{
Tracer() << "Open store and insert a child object\n";
ceda::TraceIndenter indent;
Store store(path);
X* root = store.BootstrapRoot<X>();
{
ceda::CSpaceTxn txn;
// Create an object. This is registered in the CSpace but is not yet reachable
// from the persitent store so doesn't have an OID yet
X* c = $new X(25);
cxAssert(!GetOid(c));
cxAssert(!c->IsDirty());
// These assignments don't mark the root as dirty, nor do they cause c to be allocated
// an oid.
root->m_value = 100;
root->m_child = c;
cxAssert(!root->IsDirty());
cxAssert(!GetOid(c));
root->MarkAsDirtyWithoutTrace();
cxAssert(root->IsDirty());
// Causes c to become persistent, so it is allocated an OID (in this case
// 00000001.00000005 (was 01010101.01010106)).
DeclareReachable(root,c);
#if CEDA_LSS_USE_CONTIGUOUS_SEID_SPACE
ceda::OID EXPECTED_OID_OF_CHILD(5,1);
#else
ceda::OID EXPECTED_OID_OF_CHILD(0x01010106, 0x01010101);
#endif
cxAssert(GetOid(c) == EXPECTED_OID_OF_CHILD);
Tracer() << "root = " << *root << '\n';
}
cxAssert(store.GetNumPersistableObjects() == 2);
}
{
Tracer() << "Open store and delete the child object\n";
ceda::TraceIndenter indent;
Store store(path);
X* root = store.BootstrapRoot<X>();
{
ceda::CSpaceTxn txn;
cxAssert(root->m_value == 100);
X* c = root->m_child.Get();
cxAssert(c);
Tracer() << "root = " << *root << '\n';
Tracer() << "c = " << *c << '\n';
// This assignment doesn't mark the root as dirty, nor does it cause c to be
// deleted from the store.
root->m_child = nullptr;
cxAssert(!root->IsDirty());
#if CEDA_LSS_USE_CONTIGUOUS_SEID_SPACE
ceda::OID EXPECTED_OID_OF_CHILD(5,1);
#else
ceda::OID EXPECTED_OID_OF_CHILD(0x01010106, 0x01010101);
#endif
cxAssert(GetOid(c) == EXPECTED_OID_OF_CHILD);
root->MarkAsDirtyWithoutTrace();
cxAssert(root->IsDirty());
Tracer() << "root = " << *root << '\n';
cxAssert(TryBindObjectGivenOid(EXPECTED_OID_OF_CHILD) == c);
cxAssert(TryBindObjectGivenOid(EXPECTED_OID_OF_CHILD) != root);
cxAssert(store.GetNumPersistableObjects() == 2);
SyncPermanentlyDeleteObject(c);
// After the call to SyncPermanentlyDeleteObject(c) the following conditions are met:
// 1) c no longer has an oid
// 2) c is marked as clean
// 2) TryBindObjectGivenOid() now returns null
//cxAssert(!GetOid(c)); todo: still has the same oid
cxAssert(TryBindObjectGivenOid(EXPECTED_OID_OF_CHILD) == ceda::null);
// This works because GetNumPersistableObjects() first ensures all changes to the PSpace
// are flushed to the LSS
cxAssert(store.GetNumPersistableObjects() == 1);
}
}
}
}