384 lines
11 KiB
C++
384 lines
11 KiB
C++
/*
|
|
implementation of MemUpdateStorage
|
|
|
|
*/
|
|
|
|
#include "MemUpdateStorage.h"
|
|
#include "MPoint2.h"
|
|
|
|
#include "SecondoSMI.h"
|
|
|
|
|
|
namespace temporal2algebra {
|
|
using namespace boost::interprocess;
|
|
|
|
|
|
std::ostream &operator<<(std::ostream &os, SharedData const &l) {
|
|
Unit u;
|
|
l.finalUnit.createUnit(&u);
|
|
os << "[SharedData: backReference: " << l.backReference <<
|
|
", finalUnit:" << u <<"]";
|
|
SharedUnits::const_iterator it;
|
|
for (it = l.units.begin(); it != l.units.end(); ++it) {
|
|
it->createUnit(&u);
|
|
os << endl << u;
|
|
}
|
|
return os;
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, SharedDataMapValue const &l) {
|
|
return os << "[SharedDataMapValue: id: " << l.first << " ]\n"
|
|
<< l.second;
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, SharedMemStorage const &l) {
|
|
os << "[SharedMemStorage: numOfUsers: " << l.numOfUsers
|
|
<< ", lastKnownStorageId: " << l.lastKnownStorageId << "]";
|
|
SharedDataMap::const_iterator it;
|
|
for (it = l.dataMap.begin(); it != l.dataMap.end(); ++it) {
|
|
os << "\n" << *it;
|
|
}
|
|
return os;
|
|
}
|
|
|
|
//Try to find or create the shared_memory.
|
|
//If the caller is interested if the shared mem was found or created
|
|
//she can use the isNewlyCreated() method to find out
|
|
|
|
|
|
void MemUpdateStorage::initMem() {
|
|
// assume either there is no shared_memory at all
|
|
// then initialize from log
|
|
// or
|
|
// the shared memory has been completely constructed
|
|
// then do nothing
|
|
|
|
try {
|
|
segment = boost::interprocess::managed_shared_memory
|
|
(boost::interprocess::create_only,
|
|
memStorageName.c_str(),
|
|
storage_size );
|
|
VoidAllocator allocator(segment.get_segment_manager());
|
|
cout << "creating SharedMemStorage:" << shMemDataName.c_str() << "\n";
|
|
|
|
memdata = segment.construct<SharedMemStorage>
|
|
(shMemDataName.c_str())
|
|
(allocator);
|
|
|
|
newly_created=true;
|
|
}
|
|
catch (const boost::interprocess::interprocess_exception ex) {
|
|
cout << "couldn't create shm - someone else did. Try to open.\n";
|
|
cout << ex.what() << endl;;
|
|
segment = boost::interprocess::managed_shared_memory
|
|
(boost::interprocess::open_only,
|
|
memStorageName.c_str());
|
|
|
|
cout << "finding MemData: " << shMemDataName.c_str() << "\n";
|
|
memdata = segment.find<SharedMemStorage>(shMemDataName.c_str()).first;
|
|
cout << "memdata->dataMap.size(): "
|
|
<< memdata->dataMap.size() << endl;
|
|
|
|
return;
|
|
} catch (const std::exception ex) {
|
|
cout << "Ups: MemUpdateStorage::initMem() - unhandled exeption:\n"
|
|
<< ex.what() << endl;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
bool MemUpdateStorage::isNewlyCreated() const {
|
|
return newly_created;
|
|
}
|
|
|
|
void MemUpdateStorage::assertSameDb() const {
|
|
assert (SmiEnvironment::IsDatabaseOpen());
|
|
assert (currentDbName == SmiEnvironment::CurrentDatabase());
|
|
}
|
|
|
|
MemUpdateStorage::~MemUpdateStorage() {
|
|
cout << "MemUpdateStorage::~MemUpdateStorage()\n";
|
|
|
|
if (!memdata) {
|
|
cout << "no memdata to clean up.\n";
|
|
return;
|
|
}
|
|
cout << "contents of SharedMemStorage:\n";
|
|
cout << *memdata << endl;
|
|
|
|
memdata->numOfUsers--;
|
|
|
|
if (memdata->numOfUsers == 0) {
|
|
cout << "we are the last remaining user, cleaning up...\n";
|
|
segment.destroy<SharedMemStorage>(shMemDataName.c_str());
|
|
cout << "SharedMemStorage destroyed\n";
|
|
boost::interprocess::shared_memory_object::remove(
|
|
memStorageName.c_str());
|
|
cout << "SharedMemory destroyed\n";
|
|
} else {
|
|
cout << "there are other users - skip cleanup...\n";
|
|
}
|
|
}
|
|
|
|
MemUpdateStorage::MemUpdateStorage(std::string database) :
|
|
currentDbName(database),
|
|
newly_created(false)
|
|
{
|
|
cout << "MemUpdateStorage::MemUpdateStorage(\""
|
|
<< database << "\")\n";
|
|
|
|
memStorageName = "MemUpdateStorage_SHM_" + currentDbName + "_" +"MPoint2";
|
|
shMemDataName = "data";
|
|
|
|
memQueueName = "MemUpdateStorage_Queue_" + currentDbName + "_" +"MPoint2";
|
|
|
|
initMem();
|
|
memdata->numOfUsers++;
|
|
}
|
|
|
|
const MemStorageId MemUpdateStorage::memCreateId() {
|
|
cout << "MemUpdateStorage::memCreateId()\n";
|
|
assertSameDb();
|
|
MemStorageId newId = ++(memdata->lastKnownStorageId);
|
|
cout << "MemUpdateStorage::memCreateId()\n: " << newId << endl;
|
|
return newId;
|
|
}
|
|
|
|
void MemUpdateStorage::memCreateId(MemStorageId id) {
|
|
cout << "MemUpdateStorage::memCreateId("<< id << ")\n";
|
|
assertSameDb();
|
|
assert (id > memdata->lastKnownStorageId);
|
|
memdata->lastKnownStorageId = id;
|
|
cout << "MemUpdateStorage::memCreateId("<< id << ")\n";
|
|
}
|
|
|
|
void MemUpdateStorage::memSetBackRef(const MemStorageId& id,
|
|
const BackReference& backRef, const Unit& finalUnit) {
|
|
cout << "MemUpdateStorage::memSetBackRef(id: " << id
|
|
<< ", backRef: " << backRef << ")\n";
|
|
assertSameDb();
|
|
|
|
// id should not have a backref:
|
|
assert(!memHasMemoryUnits(id));
|
|
|
|
VoidAllocator allocator(segment.get_segment_manager());
|
|
memdata->dataMap.insert(
|
|
SharedDataMapValue(id, SharedData(backRef, finalUnit, allocator)));
|
|
cout << "createMem():" << backRef << endl;
|
|
}
|
|
|
|
bool MemUpdateStorage::memHasMemoryUnits(const MemStorageId id) const {
|
|
return (memdata->dataMap.count(id) > 0);
|
|
}
|
|
|
|
Unit MemUpdateStorage::memGet(const MemStorageId id, size_t memIndex) {
|
|
cout << "MemUpdateStorage::memGet(id: " << id
|
|
<< ", memIndex: " << memIndex << ")\n";
|
|
assert (id > 0);
|
|
assertSameDb();
|
|
SharedDataMap::iterator it = memdata->dataMap.find(id);
|
|
assert(it != memdata->dataMap.end());
|
|
assert(memIndex < it->second.units.size());
|
|
Unit result;
|
|
it->second.units.at(memIndex).createUnit(&result);
|
|
return result;
|
|
}
|
|
|
|
Unit MemUpdateStorage::memGetFinalUnit(const MemStorageId id) {
|
|
cout << "MemUpdateStorage::memGet(id: " << id << ")\n";
|
|
assert (id > 0);
|
|
assertSameDb();
|
|
SharedDataMap::iterator it = memdata->dataMap.find(id);
|
|
assert(it != memdata->dataMap.end());
|
|
Unit result;
|
|
it->second.finalUnit.createUnit(&result);
|
|
return result;
|
|
}
|
|
|
|
MemStorageId MemUpdateStorage::memGetId(const BackReference& backRef) const {
|
|
SharedDataMap::iterator it;
|
|
for (it = memdata->dataMap.begin();
|
|
it != memdata->dataMap.end();
|
|
++it) {
|
|
if (it->second.backReference == backRef) {
|
|
return it->first;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int MemUpdateStorage::memSize(const MemStorageId id) {
|
|
cout << "MemUpdateStorage::memSize(id: " << id << ")\n";
|
|
assert (id > 0);
|
|
assertSameDb();
|
|
SharedDataMap::iterator it = memdata->dataMap.find(id);
|
|
assert(it != memdata->dataMap.end());
|
|
return (int) it->second.units.size();
|
|
}
|
|
|
|
void MemUpdateStorage::memAppend
|
|
(MemStorageId id, const temporalalgebra::UPoint& unit) {
|
|
cout << "MemUpdateStorage::memAppend(" << id << ", " << unit << ")\n";
|
|
assert (id > 0);
|
|
assertSameDb();
|
|
|
|
SharedDataMap::iterator it = memdata->dataMap.find(id);
|
|
if (it == memdata->dataMap.end()) {
|
|
cout << "no Storage for id :" << id << endl;
|
|
assert(false);
|
|
}
|
|
FlatUnit u(unit);
|
|
it->second.units.push_back(u);
|
|
it->second.finalUnit = u;
|
|
}
|
|
|
|
void MemUpdateStorage::memClear (const MemStorageId id) {
|
|
cout << "MemUpdateStorage::memClear(" << id << ")\n";
|
|
assert (id>0);
|
|
assertSameDb(); // probably can be removed if we check for id=0;
|
|
|
|
SharedDataMap::iterator it = memdata->dataMap.find(id);
|
|
if (it != memdata->dataMap.end()) {
|
|
memdata->dataMap.erase(it);
|
|
}
|
|
}
|
|
|
|
MemStorageIds MemUpdateStorage::getIdsToPush() const {
|
|
cout << "MemUpdateStorage::getIdsToPush()\n";
|
|
assertSameDb();
|
|
MemStorageIds res(0);
|
|
|
|
SharedDataMap::iterator it;
|
|
for (it = memdata->dataMap.begin();
|
|
it != memdata->dataMap.end();
|
|
++it) {
|
|
res.push_back(it->first);
|
|
}
|
|
|
|
cout << "found " << res.size() << " entries\n";
|
|
return res;
|
|
}
|
|
|
|
const BackReference
|
|
MemUpdateStorage::getBackReference(const MemStorageId id) {
|
|
cout << "MemUpdateStorage::memGetBackReference(" << id << ")\n";
|
|
assert (id>0);
|
|
assertSameDb(); // probably can be removed if we check for id=0;
|
|
|
|
SharedDataMap::iterator it = memdata->dataMap.find(id);
|
|
if (it != memdata->dataMap.end()) {
|
|
return it->second.backReference;
|
|
}
|
|
return BackReference();
|
|
}
|
|
|
|
|
|
int MemUpdateStorage::memPushToFlobs(
|
|
const MemStorageId idToPush, bool keep_reference ) {
|
|
cout << "MemUpdateStorage::memPushToFlobs(idToPush: "
|
|
<< idToPush << ")\n";
|
|
|
|
assert (idToPush > 0);
|
|
|
|
if (!memdata) {
|
|
cout << "no MemStorage\n";
|
|
assert (false);
|
|
return 0;
|
|
}
|
|
|
|
SharedDataMap::iterator it = memdata->dataMap.find(idToPush);
|
|
if (it == memdata->dataMap.end()) {
|
|
cout << "no MemDate with idToPush: " << idToPush << endl;
|
|
assert (false);
|
|
return 0;
|
|
}
|
|
|
|
// we found some MemData:
|
|
|
|
|
|
cout << "finding Backreference:\n";
|
|
BackReference* backref_it = &(it->second.backReference);
|
|
|
|
|
|
std::string relationName = backref_it->relationName;
|
|
SecondoCatalog* catalog = SecondoSystem::GetCatalog();
|
|
if (!catalog->IsObjectName(relationName)) {
|
|
cout << "no secondo object with name '" << relationName
|
|
<< "' found\n";
|
|
memClear(idToPush);
|
|
return 0;
|
|
}
|
|
|
|
Word relationWord;
|
|
bool defined;
|
|
catalog->GetObject(relationName, relationWord, defined);
|
|
Relation* relation = static_cast<Relation*>(relationWord.addr);
|
|
if (!relation) {
|
|
cout << "couldn't get Relation* for '"
|
|
<< relationName << "'\n";
|
|
memClear(idToPush);
|
|
return 0;
|
|
}
|
|
|
|
cout << "retrieving tuple with TID " << backref_it->tupleId << endl;
|
|
Tuple* tuple = relation->GetTuple(backref_it->tupleId, true);
|
|
|
|
if (!tuple) {
|
|
cout << "no tuple found\n";
|
|
memClear(idToPush);
|
|
return 0;
|
|
}
|
|
|
|
cout << "found target tuple: " << *tuple << endl;
|
|
|
|
// GetAttribute just gives us a pointer to the existing Attr
|
|
// read: do not delete, do not deleteIfAllowed; better not touch
|
|
MPoint2* moving = static_cast<MPoint2*>(
|
|
tuple->GetAttribute(backref_it->attrPos));
|
|
|
|
if (moving->getMemId() != idToPush) {
|
|
cout << "mismatch between storageIds! "
|
|
<< "moving: " << moving->getMemId()
|
|
<< "idToPush: " << idToPush << endl;
|
|
tuple->DeleteIfAllowed();
|
|
memClear(idToPush);
|
|
return 0;
|
|
}
|
|
|
|
// this implicitly creates a new moving with all data
|
|
// pushed to the flobs and empty backreference
|
|
MPoint2* moving_for_update = moving->Clone();
|
|
if (keep_reference) {
|
|
moving_for_update->setMemId(moving->getMemId());
|
|
}
|
|
|
|
std::vector<int> changedIndices(1);
|
|
changedIndices[0] = backref_it->attrPos;
|
|
std::vector<Attribute*> newAttrs(1);
|
|
newAttrs[0] = moving_for_update;
|
|
// it seems that UpdateTuple does not incr ref count
|
|
// for newAttrs -> so do not delete(IfAllowed) moving.
|
|
relation->UpdateTuple(tuple,
|
|
changedIndices,
|
|
newAttrs);
|
|
|
|
catalog->ModifyObject(backref_it->relationName,
|
|
relationWord);
|
|
catalog->CleanUp(false, false);
|
|
|
|
relation->Close();
|
|
relation = 0;
|
|
|
|
memClear(idToPush);
|
|
|
|
tuple->DeleteIfAllowed();
|
|
|
|
return 1;
|
|
}
|
|
|
|
int MemUpdateStorage::getNumberOfUsers() const {
|
|
return memdata?memdata->numOfUsers:-1;
|
|
}
|
|
|
|
} /* namespace temporal2algebra */
|