

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.1.1.260726 (26 July 2026)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2026
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
/*! @file MemoryManager.cpp
    @brief Implementation of MemoryManager, MasterMemory, PsycloneIndex and the legacy MemoryManagerX page allocator.

    Contains the segment creation/attachment logic, the background management thread
    (MemoryManagement) that expires end-of-life data, and the platform-specific shared
    memory calls (Windows named file mappings vs POSIX shm/mmap) behind the accessors
    declared in MemoryManager.h.
    @ingroup Memory */

#include "MemoryManager.h"
#include "PsyTime.h"
#include "UnitTestFramework.h"

namespace cmlabs {

MemoryManager* MemoryManager::Singleton = NULL;


bool PsycloneIndex::GetStatus(uint16 port, uint8& status, uint64& heartbeat) {
	PsycloneIndexStruct* index = (PsycloneIndexStruct*) utils::OpenSharedMemorySegment("PsycloneIndex", PSYCLONE_INDEX_SIZE);
	if (!index) {
	//	LogPrint(0,0,0,"Couldn't open shared PsycloneIndex memory segment...");
		return false;
	}
	PsycloneIndexEntry* e = (PsycloneIndexEntry*)(((char*)index)+sizeof(PsycloneIndexStruct));
	for (uint32 n=0; n<PSYCLONE_INDEX_MAXCOUNT; n++, e++) {
		if (e->port == port) {
			status = e->status;
			heartbeat = e->heartbeat;
			return true;
		}
	}
	//LogPrint(0,0,0,"Couldn't find Psyclone port %u in shared PsycloneIndex memory segment...", port);
	status = PSYCLONE_STATUS_NONE;
	heartbeat = 0;
	return false;
}

PsycloneIndex::PsycloneIndex() {
	index = NULL;
	entry = NULL;
}

PsycloneIndex::~PsycloneIndex() {
	if (!index)
		setStatus(PSYCLONE_STATUS_ENDED);
	entry = NULL;
	utils::CloseSharedMemorySegment((char*) index, PSYCLONE_INDEX_SIZE);
	index = NULL;
}

bool PsycloneIndex::init(uint16 port, uint64 instID) {
	index = (PsycloneIndexStruct*) utils::OpenSharedMemorySegment("PsycloneIndex", PSYCLONE_INDEX_SIZE);
	if (!index) {
		index = (PsycloneIndexStruct*) utils::CreateSharedMemorySegment("PsycloneIndex", PSYCLONE_INDEX_SIZE);
		if (!index)
			return false;
		memset(index, 0, PSYCLONE_INDEX_SIZE);
		index->size = PSYCLONE_INDEX_SIZE;
		index->cid = PSYCLONEINDEXID;
	}

	PsycloneIndexEntry* firstEmpty = NULL;
	PsycloneIndexEntry* e = (PsycloneIndexEntry*)(((char*)index)+sizeof(PsycloneIndexStruct));
	for (uint32 n=0; n<PSYCLONE_INDEX_MAXCOUNT; n++, e++) {
		if (e->port == port) {
			entry = e;
			break;
		}
		else if (!firstEmpty && !e->port)
			firstEmpty = e;
	}
	if (!entry) {
		if  (!firstEmpty)
			return false;
		entry = firstEmpty;
		entry->port = port;
		entry->instanceID = instID;
	}

	return true;
}

bool PsycloneIndex::setStatus(uint8 status) {
	if (!entry)
		return false;
	entry->status = status;
	entry->heartbeat = GetTimeNow();
	return true;
}



MasterMemory::MasterMemory() {
	mutex = NULL;
	master = NULL;
	port = 0;
}

MasterMemory::~MasterMemory() {
	if (mutex)
		mutex->enter(5000, __FUNCTION__);
	utils::CloseSharedMemorySegment((char*) master, PSYCLONE_INDEX_SIZE);
	master = NULL;
	if (mutex)
		mutex->leave();
	delete(mutex);
	mutex = NULL;
}

bool MasterMemory::create(uint16 port) {
	mutex = new utils::Mutex(utils::StringFormat("PsycloneNodeMutex_%u", port).c_str(), true);
	if (!mutex->enter(5000, __FUNCTION__)) {
		return false;
	}
	
	//master = (MemoryMasterStruct*) utils::OpenSharedMemorySegment(utils::StringFormat("PsycloneNode_%u", port).c_str(), sizeof(MemoryMasterStruct));
	//if (master) {
	//	utils::CloseSharedMemorySegment((char*)master, sizeof(MemoryMasterStruct));
	//	LogPrint(0,LOG_MEMORY,2,"MemoryManager removing stale shared memory (%u)...", port);
	//}

	master = (MemoryMasterStruct*) utils::CreateSharedMemorySegment(utils::StringFormat("PsycloneNode_%u", port).c_str(), sizeof(MemoryMasterStruct), true);
	if (!master) {
		mutex->leave();
		return false;
	}
	memset(master, 0, sizeof(MemoryMasterStruct));
	master->size = sizeof(MemoryMasterStruct);
	master->cid = PSYCLONEMASTERID;
	master->status = 1; // init
	master->createdTime = GetTimeNow();
	this->port = port;
	mutex->leave();
	return true;
}

bool MasterMemory::open(uint16 port) {
	mutex = new utils::Mutex(utils::StringFormat("PsycloneNodeMutex_%u", port).c_str());
	if (!mutex->enter(5000, __FUNCTION__))
		return false;
	
	master = (MemoryMasterStruct*) utils::OpenSharedMemorySegment(utils::StringFormat("PsycloneNode_%u", port).c_str(), sizeof(MemoryMasterStruct));
	if (!master) {
		mutex->leave();
		return false;
	}
	if (master->cid != PSYCLONEMASTERID) {
		utils::CloseSharedMemorySegment((char*)master, sizeof(MemoryMasterStruct));
		mutex->leave();
		return false;
	}
	this->port = port;
	mutex->leave();
	return true;
}


uint16 MasterMemory::getNodeID() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint16 res = master->nodeID;
	mutex->leave();
	return res;
}

uint64 MasterMemory::getCreatedTime() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint64 res = master->createdTime;
	mutex->leave();
	return res;
}

bool MasterMemory::setNodeID(uint16 id) {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	master->nodeID = id;
	mutex->leave();
	return true;
}

uint32 MasterMemory::getDynamicShmemSerial() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint32 res = master->dynamicShmemSerial;
	mutex->leave();
	return res;
}

uint32 MasterMemory::getProcessShmemSerial() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint32 res = master->processShmemSerial;
	mutex->leave();
	return res;
}

uint32 MasterMemory::getComponentShmemSerial() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint32 res = master->componentShmemSerial;
	mutex->leave();
	return res;
}

uint32 MasterMemory::getDataMapsShmemSerial() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint32 res = master->datamapsShmemSerial;
	mutex->leave();
	return res;
}



uint32 MasterMemory::incrementDynamicShmemSerial() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint32 res = ++master->dynamicShmemSerial;
	mutex->leave();
	return res;
}

uint32 MasterMemory::incrementProcessShmemSerial() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint32 res = ++master->processShmemSerial;
	mutex->leave();
	return res;
}

uint32 MasterMemory::incrementComponentShmemSerial() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint32 res = ++master->componentShmemSerial;
	mutex->leave();
	return res;
}

uint32 MasterMemory::incrementDataMapsShmemSerial() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint32 res = ++master->datamapsShmemSerial;
	mutex->leave();
	return res;
}


uint64 MasterMemory::getDynamicShmemSize() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint64 res = master->dynamicShmemSize;
	mutex->leave();
	return res;
}

uint64 MasterMemory::getProcessShmemSize() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint64 res = master->processShmemSize;
	mutex->leave();
	return res;
}

uint64 MasterMemory::getComponentShmemSize() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint64 res = master->componentShmemSize;
	mutex->leave();
	return res;
}

uint64 MasterMemory::getDataMapsShmemSize() {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return 0;
	uint64 res = master->datamapsShmemSize;
	mutex->leave();
	return res;
}

bool MasterMemory::setDynamicShmemSize(uint64 size) {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return false;
	master->dynamicShmemSize = size;
	mutex->leave();
	return true;
}

bool MasterMemory::setProcessShmemSize(uint64 size) {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return false;
	master->processShmemSize = size;
	mutex->leave();
	return true;
}

bool MasterMemory::setComponentShmemSize(uint64 size) {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return false;
	master->componentShmemSize = size;
	mutex->leave();
	return true;
}

bool MasterMemory::setDataMapsShmemSize(uint64 size) {
	if (!mutex || !master || !mutex->enter(5000, __FUNCTION__))
		return false;
	master->datamapsShmemSize = size;
	mutex->leave();
	return true;
}

bool MasterMemory::setID(uint16 id) {
	port = id;
	return true;
}

uint16 MasterMemory::getID() {
	return port;
}










// static
//bool MemoryManager::GetMemoryUsage(uint32& total, uint32& usage, uint32& sysTotal, uint32& sysUsage, uint32& staticTotal, uint32& staticUsage, uint32& dynamicTotal, uint32& dynamicUsage) {
//	if (!MemoryManager::Singleton)
//		return false;
//	//if (!MemoryManager::Singleton->pageMasterMutex->enter())
//	//	return false;
//	//sysTotal = MemoryManager::Singleton->pageMaster->dataSize[MP_SYSTEMPAGE];
//	//sysUsage = MemoryManager::Singleton->pageMaster->dataUsage[MP_SYSTEMPAGE];
//	//staticTotal = MemoryManager::Singleton->pageMaster->dataSize[MP_STATICPAGE];
//	//staticUsage = MemoryManager::Singleton->pageMaster->dataUsage[MP_STATICPAGE];
//	//dynamicTotal = MemoryManager::Singleton->pageMaster->dataSize[MP_DYNAMICPAGE];
//	//dynamicUsage = MemoryManager::Singleton->pageMaster->dataUsage[MP_DYNAMICPAGE];
//	//total = sysTotal + staticTotal + dynamicTotal;
//	//usage = sysUsage + staticUsage + dynamicUsage;
//	//MemoryManager::Singleton->pageMasterMutex->leave();
//	return true;
//}
























MemoryManager::MemoryManager() {
	psycloneIndex = NULL;
	masterMemory = NULL;
	temporalMemory = NULL;
	processMemory = NULL;
	componentMemory = NULL;
	dataMapsMemory = NULL;

	shouldContinue = true;
	isRunning = false;
	isLocalMaster = false;
	managementThreadID = 0;
	thisInstance = 0;
}

MemoryManager::~MemoryManager() {
//	MemoryManager::Singleton = NULL;
	shouldContinue = false;
	uint32 c = 0;
	while (isRunning) {
		utils::Sleep(50);
		if (c++ > 10)
			break;
	}
	if (isLocalMaster) {
		ThreadManager::Shutdown();
	}

	delete(temporalMemory);
	temporalMemory = NULL;
	delete(processMemory);
	processMemory = NULL;
	delete(componentMemory);
	componentMemory = NULL;
	delete(dataMapsMemory);
	dataMapsMemory = NULL;
	delete(masterMemory);
	masterMemory = NULL;
	if (psycloneIndex)
		psycloneIndex->setStatus(PSYCLONE_STATUS_ENDED);
	delete(psycloneIndex);
	psycloneIndex = NULL;
}

bool MemoryManager::getMemoryUsage(uint64& sysAlloc, uint64& sysUsage, uint64& dataAlloc, uint64& dataUsage) {
	if (!masterMemory)
		return false;

	uint64 alloc = 0, usage = 0;
	if (temporalMemory && temporalMemory->getMemoryUsage(alloc, usage)) {
		dataAlloc = alloc;
		dataUsage = usage;
	}

	sysAlloc = sysUsage = sizeof(MemoryMasterStruct);

	if (processMemory && processMemory->getMemoryUsage(alloc, usage)) {
		sysAlloc += alloc;
		sysUsage += usage;
	}
	if (componentMemory && processMemory->getMemoryUsage(alloc, usage)) {
		sysAlloc += alloc;
		sysUsage += usage;
	}
	if (dataMapsMemory && dataMapsMemory->getMemoryUsage(alloc, usage)) {
		sysAlloc += alloc;
		sysUsage += usage;
	}
	return true;
}


uint8 MemoryManager::getNodeStatus(uint64& lastseen, uint64& createdTime) {
	lastseen = 0;
	if (!masterMemory)
		return PSYCLONE_STATUS_NONE;
	uint8 status = 0;
	PsycloneIndex::GetStatus(masterMemory->port, status, lastseen);
	createdTime = masterMemory->getCreatedTime();
	return status;
}

// Connect to existing PageMaster in shared memory
bool MemoryManager::connect(uint16 port, bool isLocalMaster) {
	uint8 status = 0;
	uint64 heartbeat = 0;
	if ((!PsycloneIndex::GetStatus(port, status, heartbeat)) || (status == PSYCLONE_STATUS_NONE) || (!heartbeat)) {
		LogPrint(0,LOG_MEMORY,3,"Cannot find node running on port %u...", port);
		return false;
	}
	else if (status <= PSYCLONE_STATUS_ENDED) {
		LogPrint(0,LOG_MEMORY,3,"Node no longer running on port %u...", port);
		return false;
	}
	else if (GetTimeAgeMS(heartbeat) > 5000) {
		LogPrint(0,LOG_MEMORY,3,"Node on port %u is no longer responding...", port);
		return false;
	}
	else if (status == PSYCLONE_STATUS_INIT) {
		LogPrint(0,LOG_MEMORY,3,"Node starting up on port %u, please try again in a little while...", port);
		return false;
	}

	this->isLocalMaster = isLocalMaster;
	masterMemory = new MasterMemory();
	if (!masterMemory->open(port)) {
		LogPrint(0,LOG_MEMORY,0,"Cannot open MasterMemory on port %u...", port);
		delete(masterMemory);
		masterMemory = NULL;
		return false;
	}

	temporalMemory = new TemporalMemory(masterMemory);
	if (!temporalMemory->open()) {
		LogPrint(0,LOG_MEMORY,0,"Cannot open TemporalMemory on port %u...", port);
		delete(temporalMemory);
		temporalMemory = NULL;
		delete(masterMemory);
		masterMemory = NULL;
		return false;
	}
	temporalMemory->setNodeID(masterMemory->getNodeID());

	componentMemory = new ComponentMemory(masterMemory);
	if (!componentMemory->open()) {
		LogPrint(0,LOG_MEMORY,0,"Cannot open ComponentMemory on port %u...", port);
		delete(componentMemory);
		componentMemory = NULL;
		delete(masterMemory);
		masterMemory = NULL;
		return false;
	}

	dataMapsMemory = new DataMapsMemory(masterMemory);
	if (!dataMapsMemory->open()) {
		LogPrint(0,LOG_MEMORY,0,"Cannot open DataMapsMemory on port %u...", port);
		delete(dataMapsMemory);
		dataMapsMemory = NULL;
		delete(masterMemory);
		masterMemory = NULL;
		return false;
	}

	processMemory = new ProcessMemory(masterMemory);
	if (!processMemory->open()) {
		LogPrint(0,LOG_MEMORY,0,"Cannot open ProcessMemory on port %u...", port);
		delete(processMemory);
		processMemory = NULL;
		delete(masterMemory);
		masterMemory = NULL;
		return false;
	}

	if (!ThreadManager::CreateThread(MemoryManagement, this, managementThreadID)) {
		return false;
	}

	return true;
}

// Create a new PageMaster in shared memory
bool MemoryManager::create(uint16 sysID, uint32 slotCount, uint16 binCount, uint32 minBlockSize, uint32 maxBlockSize, uint64 initSize, uint64 maxSize, bool force) {

	this->isLocalMaster = true;
	uint8 status = 0;
	uint64 heartbeat = 0;
	if (PsycloneIndex::GetStatus(sysID, status, heartbeat) && (GetTimeAgeMS(heartbeat) < 500)) {
		if (status == PSYCLONE_STATUS_INIT) {
			LogPrint(0,LOG_MEMORY,0,"Another node is currently (%ums ago) starting up on port %u...", GetTimeAgeMS(heartbeat), sysID);
			return false;
		}
		else if (status == PSYCLONE_STATUS_READY) {
			LogPrint(0,LOG_MEMORY,0,"Another node is currently running or crashed %s ago on port %u...", PrintTimeDifString(GetTimeAge(heartbeat)).c_str(), sysID);
			return false;
		}
	}

	psycloneIndex = new PsycloneIndex();
	if (!psycloneIndex->init(sysID, GetTimeNow())) {
		LogPrint(0, LOG_MEMORY, 0, "Cannot init index memory on port %u...", sysID);
		return false;
	}

	masterMemory = new MasterMemory();
	if (!masterMemory->create(sysID)) {
		LogPrint(0, LOG_MEMORY, 0, "Cannot create MasterMemory...");
		return false;
	}

	temporalMemory = new TemporalMemory(masterMemory);
	if (!temporalMemory->create(slotCount, binCount, minBlockSize, maxBlockSize, initSize, maxSize)) {
		LogPrint(0, LOG_MEMORY, 0, "Cannot create TemporalMemory...");
		return false;
	}

	componentMemory = new ComponentMemory(masterMemory);
	// Create initial room for 1024 average components
	// Will expand as needed
	if (!componentMemory->create(1024)) {
		LogPrint(0, LOG_MEMORY, 0, "Cannot create ComponentMemory...");
		return false;
	}

	dataMapsMemory = new DataMapsMemory(masterMemory);
	// Create initial room for 1024 typelevels, contextlevels, tags, cranks, requests
	// Will expand as needed
	if (!dataMapsMemory->create(1024, 1024, 1024, 1024, 1024)) {
		LogPrint(0, LOG_MEMORY, 0, "Cannot create DataMapsMemory...");
		return false;
	}

	processMemory = new ProcessMemory(masterMemory);
	// Create initial room for 16 processes
	// Will expand as needed
	if (!processMemory->create(16)) {
		LogPrint(0, LOG_MEMORY, 0, "Cannot create ProcessMemory...");
		return false;
	}

	psycloneIndex->setStatus(PSYCLONE_STATUS_READY);

	if (!ThreadManager::CreateThread(MemoryManagement, this, managementThreadID)) {
		return false;
	}

	return true;
}

uint16 MemoryManager::getNodeID() {
	return masterMemory->getNodeID();
}

bool MemoryManager::setNodeID(uint16 id) {
	masterMemory->setNodeID(id);
	temporalMemory->setNodeID(id);
	return true;
}

DataMessage* MemoryManager::retrieveAllSystemIDs() {
	DataMessage* msg = new DataMessage();
	if (!this->componentMemory->writeComponentNamesToMsg(msg)) {
		delete msg;
		return NULL;
	}
	if (!this->dataMapsMemory->writeIDsToMsg(msg)) {
		delete msg;
		return NULL;
	}
	return msg;
}



bool MemoryManager::getTimeSyncData(uint64& tmc, int64& adjust) {
	tmc = masterMemory->master->currentTMC;
	adjust = masterMemory->master->localSyncAdjustment;
	return true;
}

bool MemoryManager::setTimeSyncData(uint64 tmc, int64 adjust) {
	masterMemory->master->currentTMC = tmc;
	masterMemory->master->localSyncAdjustment = adjust;
	return true;
}

// Insert new block of memory and return full id
bool MemoryManager::insertMessage(DataMessage* msg, uint64& id) {
	if (!temporalMemory)
		return false;
	return temporalMemory->insertMessage(msg, id);
}

// Get copy of block of memory
DataMessage* MemoryManager::getCopyOfMessage(uint64 id) {
	if (!temporalMemory)
		return NULL;
	return temporalMemory->getCopyOfMessage(id);
}

std::string MemoryManager::typeToText(PsyType type) {
	if (!type[0])
		return "NOTYPE";
	if (type[0] == 1)
		return utils::StringFormat("PsyControlMessage %u.%u", type[1], type[2]);
	std::string str = subTypeToText(type[0]);
	uint8 level = 0;
	while (type[level+1])
		str += std::string(".") + subTypeToText(type[++level]);
	return str;
}

std::string MemoryManager::subTypeToText(uint16 subtype) {
	if (!subtype)
		return "-";
	else if (subtype == 0xFFFF)
		return "*";
	std::string str;
	char* data = new char[MAXKEYNAMELEN+1];
	if (dataMapsMemory->getTypeLevelName(subtype, data, MAXKEYNAMELEN))
		str = data;
	delete [] data;
	return str;
}

std::string MemoryManager::contextToText(PsyContext context) {
	if (!context[0])
		return "NOCONTEXT";
	std::string str = subContextToText(context[0]);
	uint8 level = 0;
	while (context[level+1])
		str += std::string(".") + subContextToText(context[++level]);
	return str;
}

std::string MemoryManager::subContextToText(uint16 subcontext) {
	if (!subcontext)
		return "-";
	else if (subcontext == 0xFFFF)
		return "*";
	std::string str;
	char* data = new char[MAXKEYNAMELEN+1];
	if (dataMapsMemory->getContextLevelName(subcontext, data, MAXKEYNAMELEN))
		str = data;
	delete [] data;
	return str;
}

std::string MemoryManager::getComponentName(uint32 compID) {
	std::string str;
	char* data = new char[MAXKEYNAMELEN+1];
	if (componentMemory->getComponentName(compID, data, MAXKEYNAMELEN))
		str = data;
	delete [] data;
	return str;
}



































THREAD_RET THREAD_FUNCTION_CALL MemoryManagement(THREAD_ARG arg) {
	thread_ret_val(((MemoryManager*)arg)->runManager());
}

// Continuous management of eol pages
uint32 MemoryManager::runManager() {
	//LogPrint(0, LOG_SYSTEM, 0, "Memory Management (%p) running...\n\n", this);
	isRunning = true;
	uint64 tmc;
	int64 netTimeSync;

	uint64 nextPageCheck = 0; //, now;

	while (shouldContinue) {
		if (isLocalMaster) {
			if (GetCurrentTimeSyncData(tmc, netTimeSync))
				setTimeSyncData(tmc, netTimeSync);
			dataMapsMemory->maintenance();
			if (psycloneIndex)
				psycloneIndex->setStatus(PSYCLONE_STATUS_READY);
		}
		else {
			//  Update Sync Time
			if (getTimeSyncData(tmc, netTimeSync) )
				SetCurrentTimeSyncData(tmc, netTimeSync);
		}

		utils::Sleep(100);
	}

	isRunning = false;
	//LogPrint(0, LOG_SYSTEM, 0, "Memory Management (%p) stopped running...\n\n", this);
	return 0;
}

bool MemoryManager::UnitTest() {

	// Create and initialise the MemoryManager (static memory management)
	unittest::progress(5, "create manager");
	MemoryManager* manager = new MemoryManager();
	uint32 maxPageCount = 15;
	if (!manager->create(0)) {
		unittest::fail("MemoryManager test: create() failed");
		delete(manager);
		return false;
	}

	uint64 eol = GetTimeNow() + 100000000; // +100sec
	uint32 size = 4096;
	char* data = new char[size];

	// we should be able to add this many blocks
	uint32 expectedCount = 100; // CalcBlockTableSize(size);
	uint32 expectedMaxCount = (maxPageCount-10) * expectedCount;
	uint32 count = expectedMaxCount;
	uint64* ids = new uint64[count];

	DataMessage* msg = new DataMessage();
	msg->setData("data", data, size);
	msg->setEOL(eol);
	uint32 n;
	uint64 id;

	// Write phase
	unittest::progress(20, "insert messages");
	uint64 t1 = GetTimeNow();
	for (n=0; n<count; n++) {
		msg->setInt("Test", n);
		if (!manager->insertMessage(msg, id)) {
			unittest::fail("MemoryManager test: insert %u failed", n);
			delete [] ids;
			delete [] data;
			delete(msg);
			delete(manager);
			return false;
		}
		ids[n] = id;
	}
	uint64 t2 = GetTimeNow();

	// Read-back phase
	unittest::progress(60, "read back messages");
	DataMessage* msg2;
	for (n=0; n<count; n++) {
		msg2 = manager->getCopyOfMessage(ids[n]);
		if (msg2 == NULL) {
			unittest::fail("MemoryManager test: getCopyOfMessage %u failed", n);
			delete [] ids;
			delete [] data;
			delete(msg);
			delete(manager);
			return false;
		}
		if (msg->getSize() != msg2->getSize()) {
			unittest::fail("MemoryManager test: getCopyOfMessage wrong size (%u != %u)", msg->getSize(), msg2->getSize());
			delete [] ids;
			delete [] data;
			delete(msg);
			delete(msg2);
			delete(manager);
			return false;
		}
		int64 val64;
		if ((!msg2->getInt("Test", val64)) || (val64 != n)) {
			unittest::fail("MemoryManager test: getCopyOfMessage wrong data (%lld != %u)", val64, n);
			delete [] ids;
			delete [] data;
			delete(msg);
			delete(msg2);
			delete(manager);
			return false;
		}
		delete(msg2);
	}
	uint64 t3 = GetTimeNow();

	unittest::progress(90, "record metrics");
	double writeUs = (double)(t2 - t1);
	double readUs = (double)(t3 - t2);
	if (writeUs > 0.0) {
		unittest::metric("write_throughput", (1.0*size*count)/writeUs, "MB/s", true);
		unittest::metric("write_rate", (1000000.0*count)/writeUs, "msg/s", true);
		unittest::metric("avg_write_latency", writeUs/count, "us", false);
	}
	if (readUs > 0.0) {
		unittest::metric("read_throughput", (1.0*size*count)/readUs, "MB/s", true);
		unittest::metric("read_rate", (1000000.0*count)/readUs, "msg/s", true);
		unittest::metric("avg_read_latency", readUs/count, "us", false);
	}
	unittest::detail("Writing %u: %.3f MB/s / %.3f msg/s (%u us) [%u b]",
		count, (1.0*size*count)/writeUs, (1000000.0*count)/writeUs, (uint32)writeUs, size);
	unittest::detail("Reading %u: %.3f MB/s / %.3f msg/s (%u us) [%u b]",
		count, (1.0*size*count)/readUs, (1000000.0*count)/readUs, (uint32)readUs, size);

	delete [] ids;
	delete [] data;
	delete(msg);
	delete(manager);

	unittest::progress(100, "done");
	return true;
}



















//bool MemoryManagerX::GetMemoryUsage(uint32& total, uint32& usage, uint32& sysTotal, uint32& sysUsage, uint32& staticTotal, uint32& staticUsage, uint32& dynamicTotal, uint32& dynamicUsage) {
//	if (!MemoryManagerX::Singleton)
//		return false;
//	if (!MemoryManagerX::Singleton->pageMasterMutex->enter())
//		return false;
//	sysTotal = MemoryManagerX::Singleton->pageMaster->dataSize[MP_SYSTEMPAGE];
//	sysUsage = MemoryManagerX::Singleton->pageMaster->dataUsage[MP_SYSTEMPAGE];
//	staticTotal = MemoryManagerX::Singleton->pageMaster->dataSize[MP_STATICPAGE];
//	staticUsage = MemoryManagerX::Singleton->pageMaster->dataUsage[MP_STATICPAGE];
//	dynamicTotal = MemoryManagerX::Singleton->pageMaster->dataSize[MP_DYNAMICPAGE];
//	dynamicUsage = MemoryManagerX::Singleton->pageMaster->dataUsage[MP_DYNAMICPAGE];
//	total = sysTotal + staticTotal + dynamicTotal;
//	usage = sysUsage + staticUsage + dynamicUsage;
//	MemoryManagerX::Singleton->pageMasterMutex->leave();
//	return true;
//}
//
//
//MemoryManagerX::MemoryManagerX() {
//	shouldContinue = true;
//	isRunning = false;
//	isMaster = false;
//	pageMaster = NULL;
//	pageMasterMutex = NULL;
//	pageCache = NULL;
//
//}
//
//MemoryManagerX::~MemoryManagerX() {
//	if (pageMaster == NULL)
//		return;
//	pageMasterMutex->enter();
//	MemoryManagerX::Singleton = NULL;
//	shouldContinue = false;
//	uint32 c = 0;
//	while (isRunning) {
//		utils::Sleep(50);
//		if (c++ > 10)
//			break;
//	}
//	ThreadManager::Shutdown();
//	destroyAllPages();
//
//	utils::DestroySharedMemorySegment((char*)pageMaster, pageMaster->size);
//	pageMaster = NULL;
//	pageMasterMutex->leave();
//	delete(pageMasterMutex);
//	pageMaster = NULL;
//	pageMasterMutex = NULL;
//	free(pageCache);
//}
//
//// Connect to existing PageMaster in shared memory
//bool MemoryManagerX::connect(uint16 sysID) {
////	char name[MAXKEYNAMELEN];
//	uint32 size = sizeof(MemoryPageMaster);
//	isMaster = false;
//
//	utils::SetSharedSystemInstance(sysID);
//
//	pageMasterMutex = new utils::Mutex("PageMaster");
//	if (!pageMasterMutex->enter())
//		return false;
//
//	pageMaster = (MemoryPageMaster*) utils::OpenSharedMemorySegment("CMSysMemory", size);
//	if (pageMaster == NULL) {
//		fprintf(stderr, "MemoryManager could not open shared memory id '%u'\n", sysID);
//		pageMasterMutex->leave();
//		return false;
//	}
//
//	MemoryManagerX::Singleton = this;
//
//	LocalSyncAdjustment = pageMaster->timesync;
//
//	if (!ThreadManager::CreateThread(MemoryManagement, NULL, managementThreadID)) {
//		pageMasterMutex->leave();
//		return false;
//	}
//
//	// Unlock the Mutex
//	pageMasterMutex->leave();
//	return true;
//}
//
//// Create a new PageMaster in shared memory
//bool MemoryManagerX::create(uint16 sysID, uint32 staticPageTableSize, uint32 slotCount, uint32 slotDuration, uint32 bufferSlots, uint32 pagesPerSlot, bool force) {
//	isMaster = true;
//
//	utils::SetSharedSystemInstance(sysID);
//
//	uint32 size = sizeof(MemoryPageMaster);
//
//	char* data;
//	if (force) {
//		// Destroy CMSysMemory first...
//		if ( (data = utils::OpenSharedMemorySegment("CMSysMemory", size)) != NULL)
//			utils::DestroySharedMemorySegment(data, size);
//	}
//
//	pageMasterMutex = new utils::Mutex("PageMaster");
//	if (!pageMasterMutex->enter())
//		return false;
//
//	uint32 maxPageCount = staticPageTableSize + ( (slotCount+bufferSlots) * pagesPerSlot );
//
////	fprintf(stderr, "MemoryManager init() 3...\n");
//	// Add the bitfield size = max count / 32
//	uint32 bitFieldSize = (uint32)ceil((double)maxPageCount / 8);
//	// Add the table size
//	uint32 datasize = maxPageCount * sizeof(MemoryPageEntry);
//	size += bitFieldSize + datasize;
//
//	pageMaster = (MemoryPageMaster*) utils::CreateSharedMemorySegment("CMSysMemory", size);
//	if (pageMaster == NULL) {
//		fprintf(stderr, "MemoryManager could not create shared memory\n");
//		pageMasterMutex->leave();
//		pageMasterMutex->destroy();
//		return false;
//	}
//
//	// Initialise the PageMaster structure
//	pageMaster->status = 1; // 10 means fully initialised
////	fprintf(stderr, "MemoryManager init status %u...\n", pageMaster->status);
//
//	pageMaster->size = size; // total size of PageMaster in bytes
//	pageMaster->sysID = sysID; // global node id
//	pageMaster->dataSize[MP_SYSTEMPAGE] = 0; // total size of data space in bytes
//	pageMaster->dataSize[MP_STATICPAGE] = 0; // total size of data space in bytes
//	pageMaster->dataSize[MP_DYNAMICPAGE] = 0; // total size of data space in bytes
//	pageMaster->dataUsage[MP_SYSTEMPAGE] = 0; // current usage of all pages in bytes, for info only
//	pageMaster->dataUsage[MP_STATICPAGE] = 0; // current usage of all pages in bytes, for info only
//	pageMaster->dataUsage[MP_DYNAMICPAGE] = 0; // current usage of all pages in bytes, for info only
//	pageMaster->count[MP_SYSTEMPAGE] = 0; // current number of pages in use, for info only
//	pageMaster->count[MP_STATICPAGE] = 0; // current number of pages in use, for info only
//	pageMaster->count[MP_DYNAMICPAGE] = 0; // current number of pages in use, for info only
//	pageMaster->bitFieldSize = bitFieldSize; // number of bytes in the bitfield
//	pageMaster->pageTableSize = maxPageCount; // maximum entries in page table and number of bits in bit field
//	memset((void*)MP_GetBitFieldLoc(pageMaster), 255, bitFieldSize);
//	memset((void*)MP_GetPageTableLoc(pageMaster), 0, datasize);
//
//	MemoryManagerX::Singleton = this;
//
//	pageMaster->status = 2; // 10 means fully initialised
////	fprintf(stderr, "MemoryManager init status %u...\n", pageMaster->status);
//
//	pageMaster->timesync = LocalSyncAdjustment;
//
//	pageMaster->createdTime = GetTimeNow();
//
//	pageMaster->status = 3; // 10 means fully initialised
////	fprintf(stderr, "MemoryManager init status %u...\n", pageMaster->status);
//
//	// Create and initialise the EOL Page
//	if (!resizeEOLPage(slotCount, pagesPerSlot, slotDuration, bufferSlots)) {
//		fprintf(stderr, "MemoryManager could not resize EOL page\n");
//		pageMasterMutex->leave();
//		return false;
//	}
//
//	pageMaster->status = 4; // 10 means fully initialised
////	fprintf(stderr, "MemoryManager init status %u...\n", pageMaster->status);
//
//	if (!createSystemPages()) {
//		fprintf(stderr, "MemoryManager could not create system pages\n");
//		pageMasterMutex->leave();
//		return false;
//	}
//
//	pageMaster->status = 5; // 10 means fully initialised
////	fprintf(stderr, "MemoryManager init status %u...\n", pageMaster->status);
//
//	pageMaster->lastCreatedStaticPage = RESERVEDPAGECOUNT-1; // id of last created static page
//	// printBitFieldAsString("Initial Bitfield");
//
//	pageMaster->status = 6; // 10 means fully initialised
////	fprintf(stderr, "MemoryManager init status %u...\n", pageMaster->status);
//
//	if (!ThreadManager::CreateThread(MemoryManagement, NULL, managementThreadID)) {
//		pageMasterMutex->leave();
//		return false;
//	}
//
//	pageMaster->status = 7; // 10 means fully initialised
////	fprintf(stderr, "MemoryManager init status %u...\n", pageMaster->status);
//
//	pageMaster->status = 10; // 10 means fully initialised
//	// Unlock the Mutex
//	pageMasterMutex->leave();
//	return true;
//}
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
////bool MemoryManagerX::init(uint16 nodeID, uint32 pageTableSize, uint32 slotCount, uint32 slotDuration, uint32 bufferSlots, uint32 pagesPerSlot) {
////	// First obtain the PageMaster Mutex, if it exists
////	char name[MAXKEYNAMELEN];
////	utils::GetSystemName(nodeID, "PsyNode", name, MAXKEYNAMELEN);
////	char mutexName[MAXKEYNAMELEN];
////	utils::GetSystemName(nodeID, "PsyNodeMutex", mutexName, MAXKEYNAMELEN);
////
////	fprintf(stderr, "MemoryManager init() 1\n");
//////	if (!utils::GetMutex(mutexName, pageMasterMutex))
////
//////	printf("Mutex %s (%p/%u)\n", mutexName, (NMutex*)&pageMasterMutex, *(uint32*)&pageMasterMutex);
////
////	if (!utils::CreateMutex(mutexName, &pageMasterMutex))
////		return false;
////
//////	printf("Mutex %s (%p/%u)\n", mutexName, &pageMasterMutex, *(uint32*)&pageMasterMutex);
////
////	fprintf(stderr, "MemoryManager init() 2\n");
////	// Lock the Mutex
////	if (!pageMasterMutex->enter())
////		return false;
////
////	fprintf(stderr, "MemoryManager init() 3\n");
////
////	// Calculate the size
////	// Set the initial page size
////	// First calculate the size of the header
////	uint32 size = sizeof(MemoryPageMaster);
////	
////	// Add the bitfield size = max count / 32
////	uint32 bitFieldSize = (uint32)ceil((double)pageTableSize / 8);
////	// Add the table size
////	uint32 datasize = pageTableSize * sizeof(MemoryPageEntry);
////	
////	size += bitFieldSize + datasize;
////
////	// Temporary test...
////	utils::DestroySharedMemorySegment(name, size);
////
////	// Find the existing shared memory segment, if it exists...
////	pageMaster = (MemoryPageMaster*) utils::GetSharedMemorySegment(name, size);
////	if (pageMaster == NULL) {
////
////		fprintf(stderr, "MemoryManager init() 4\n");
////		// if not, create it
////		// create the memory segment
////		pageMaster = (MemoryPageMaster*) utils::CreateSharedMemorySegment(name, size);
////		// if fail, return false
////		if (pageMaster == NULL) {
////			fprintf(stderr, "MemoryManager could not create shared memory\n");
////			pageMasterMutex->leave();
////			return false;
////		}
////
////		fprintf(stderr, "MemoryManager init() 5\n");
////
////		// Initialise the PageMaster structure
////		pageMaster->nodeID = nodeID; // global node id
////		pageMaster->size = size; // total size of PageMaster in bytes
////		pageMaster->dataSize[MP_SYSTEMPAGE] = 0; // total size of data space in bytes
////		pageMaster->dataSize[MP_STATICPAGE] = 0; // total size of data space in bytes
////		pageMaster->dataSize[MP_DYNAMICPAGE] = 0; // total size of data space in bytes
////		pageMaster->dataUsage[MP_SYSTEMPAGE] = 0; // current usage of all pages in bytes, for info only
////		pageMaster->dataUsage[MP_STATICPAGE] = 0; // current usage of all pages in bytes, for info only
////		pageMaster->dataUsage[MP_DYNAMICPAGE] = 0; // current usage of all pages in bytes, for info only
////		pageMaster->count[MP_SYSTEMPAGE] = 0; // current number of pages in use, for info only
////		pageMaster->count[MP_STATICPAGE] = 0; // current number of pages in use, for info only
////		pageMaster->count[MP_DYNAMICPAGE] = 0; // current number of pages in use, for info only
////		pageMaster->bitFieldSize = bitFieldSize; // number of bytes in the bitfield
////		pageMaster->pageTableSize = pageTableSize; // maximum entries in page table and number of bits in bit field
////		memset((void*)MP_GetBitFieldLoc(pageMaster), 255, bitFieldSize);
////		memset((void*)MP_GetPageTableLoc(pageMaster), 0, datasize);
////
////		fprintf(stderr, "MemoryManager init() 6\n");
////
////		MemoryManagerX::Singleton = this;
////
////		fprintf(stderr, "MemoryManager init() 7\n");
////
////		pageMaster->createdTime = GetTimeNow();
////
////		fprintf(stderr, "MemoryManager init() 8\n");
////
////		// Create and initialise the EOL Page
////		if (!resizeEOLPage(slotCount, pagesPerSlot, slotDuration, bufferSlots)) {
////			fprintf(stderr, "MemoryManager could not resize EOL page\n");
////			pageMasterMutex->leave();
////			return false;
////		}
////
////		fprintf(stderr, "MemoryManager init() 8\n");
////
////		if (!createSystemPages()) {
////			fprintf(stderr, "MemoryManager could not create system pages\n");
////			pageMasterMutex->leave();
////			return false;
////		}
////
////		pageMaster->lastCreatedStaticPage = RESERVEDPAGECOUNT-1; // id of last created static page
////		// printBitFieldAsString("Initial Bitfield");
////	}
////	fprintf(stderr, "MemoryManager init() 10\n");
////
////	// Unlock the Mutex
////	pageMasterMutex->leave();
////
////	fprintf(stderr, "MemoryManager init() 11\n");
////	// Then startup the ThreadManager
////	ThreadManager* threadManager = new ThreadManager();
////	if (!threadManager->init()) {
////		fprintf(stderr, "ThreadManager init() failed...\n");
////		delete(threadManager);
////		return false;
////	}
////
////	fprintf(stderr, "MemoryManager init() 12\n");
////	return ThreadManager::CreateThread(MemoryManagement, NULL, managementThreadID, 0);
////}
//
//// Creates a System Page
//char* MemoryManagerX::createSystemPage(uint32 id, uint32 size, uint64& memID) {
//
//	// Mutex is still locked from callar
//	uint32 pageID = id;
//	MemoryPage* page = createPage(size+sizeof(MemoryBlock), 1, 0, pageID);
//	if (page == NULL)
//		return NULL;
//	if (pageID != id) {
//		destroyPage(pageID);
//		return NULL;
//	}
//
//	if (!insertMemoryBlockIntoPage(pageID, NULL, size, 0, memID))
//		return NULL;
//
//	return getSystemBlock(pageID, size);
//}
//
//
//// Return a system memory block	
//char* MemoryManagerX::getSystemBlock(uint32 pageID, uint32& size) {
//	char* data = NULL;
//	// We assume manager already locked
////	MemoryPage* page = MP_GetPageLoc(pageMaster, pageID);
//	MemoryPage* page = getCachedPage(pageID);
//	if (page == NULL)
//		return NULL;
//	MemoryBlock* block = (MemoryBlock*)MP_GetBlockDataStartLoc(page);
//	if (block == NULL)
//		return NULL;
//	size = block->size - sizeof(MemoryBlock);
//	return (char*)(block + sizeof(MemoryBlock));
//}
//
//
//
//
//// Return a system memory block	and lock it
//char* MemoryManagerX::getAndLockSystemBlock(uint32 pageID, uint32& size) {
//	// Lock Manager
//	if (!pageMasterMutex->enter())
//		return NULL;
//	MemoryPageEntry* entry = (MemoryPageEntry*)MP_GetPageEntryLoc(pageMaster, pageID);
//	if (!lockPage(entry)) {
//		pageMasterMutex->leave();
//		return NULL;
//	}
//
//	MemoryPage* page = getCachedPage(entry);
//	if (page == NULL) {
//		// Unlock Manager
//		pageMasterMutex->leave();
//		return NULL;
//	}
//	char* data = getLockedSystemBlock(page, size);
//	pageMasterMutex->leave();
//	return data;
//}
//
//char* MemoryManagerX::getLockedSystemBlock(uint32 pageID, uint32& size) {
//	// Manager should be locked
////	MemoryPage* page = MP_GetPageLoc(pageMaster, pageID);
//	MemoryPage* page = getCachedPage(pageID);
//	if (page == NULL)
//		return NULL;
//	return getLockedSystemBlock(page, size);
//}
//
//char* MemoryManagerX::getLockedSystemBlock(MemoryPage* page, uint32& size) {
//	MemoryBlock* block = (MemoryBlock*)MP_GetBlockDataStartLoc(page);
//	if (block == NULL)
//		return NULL;
//	size = block->size - sizeof(MemoryBlock);
//	return (char*)(block + sizeof(MemoryBlock));
//}
//
//bool MemoryManagerX::unlockSystemBlock(uint32 pageID) {
//	unlockPage(pageID);
//	return true;
//}
//
//
//
//// Creates a new System Page with the next id
//char* MemoryManagerX::createAndLockNewSystemPage(uint32 size, uint32& pageID) {
//
//	// Lock Manager
//	if (!pageMasterMutex->enter())
//		return NULL;
//	pageID = 0; // provide new id
//	MemoryPage* page = createPage(size+sizeof(MemoryBlock), 1, 0, pageID);
//	if (page == NULL) {
//		pageMasterMutex->leave();
//		return NULL;
//	}
//
//	// createPage now keeps the page locked
//	//if (!lockPage(pageID)) {
//	//	pageMasterMutex->leave();
//	//	return NULL;
//	//}
//
//	uint64 memID; // not required for full page memory blocks, but required for function call
//	if (!insertMemoryBlockIntoPage(pageID, NULL, size, 0, memID))
//		return NULL;
//
//	char* data = getLockedSystemBlock(pageID, size);
//	// Unlock Manager
//	pageMasterMutex->leave();
//	return data;
//}
//
//// Resize an existing System Page
//char* MemoryManagerX::resizeSystemPage(uint32 pageID, uint32 newSize) {
//
//	uint32 oldSize = 0;
//	char* oldData = getAndLockSystemBlock(pageID, oldSize);
//	if (oldData == NULL)
//		return NULL;
//
//	int32 difSize = newSize - oldSize;
//	if (difSize <= 0) {
//		// Unlock Manager
//		pageMasterMutex->leave();
//		return oldData;
//	}
//
//	char* tempData = new char[oldSize];
//	memcpy(tempData, oldData, oldSize);
//
//	UnlockSystemBlock(pageID);
//	destroyPage(pageID);
//
//	uint32 newPageID = pageID;
//	char* newData = createAndLockNewSystemPage(newSize, newPageID);
//	if (newData == NULL) {
//		delete [] tempData;
//		return NULL;
//	}
//
//	memcpy(newData, tempData, oldSize);
//	delete [] tempData;
//	return newData;
//}
//
//bool MemoryManagerX::InsertMemoryBlock(const char* data, uint32 size, uint64 eol, uint64& id) {
//	if (!MemoryManagerX::Singleton)
//		return 0;
//	return MemoryManagerX::Singleton->insertMemoryBlock(data, size, eol, id);
//}
//
//bool MemoryManagerX::OverwriteMemoryBlock(uint64 id, const char* data, uint32 size, uint64 eol) {
//	if (!MemoryManagerX::Singleton)
//		return 0;
//	return MemoryManagerX::Singleton->overwriteMemoryBlock(id, data, size, eol);
//}
//
//char* MemoryManagerX::GetAndLockMemoryBlock(uint64 id, uint32& size, uint64& eol) {
//	if (!MemoryManagerX::Singleton)
//		return 0;
//	return MemoryManagerX::Singleton->getAndLockMemoryBlock(id, size, eol);
//}
//
//bool MemoryManagerX::UnlockMemoryBlock(uint64 id) {
//	if (!MemoryManagerX::Singleton)
//		return 0;
//	return MemoryManagerX::Singleton->unlockMemoryBlock(id);
//}
//
//char* MemoryManagerX::GetCopyMemoryBlock(uint64 id, uint32& size, uint64& eol) {
//	if (!MemoryManagerX::Singleton)
//		return 0;
//	return MemoryManagerX::Singleton->getCopyMemoryBlock(id, size, eol);
//}
//
//
//
//// Static
//// Return a system memory block	and lock it
//char* MemoryManagerX::GetAndLockSystemBlock(uint32 pageID, uint32& size) {
//	if (!MemoryManagerX::Singleton)
//		return 0;
//	return MemoryManagerX::Singleton->getAndLockSystemBlock(pageID, size);
//}
//
//// Static
//// Unlock System Block
//bool MemoryManagerX::UnlockSystemBlock(uint32 pageID) {
//	if (!MemoryManagerX::Singleton)
//		return 0;
//	return MemoryManagerX::Singleton->unlockSystemBlock(pageID);
//}
//
//// Static
//// Creates a new System Page with the next id
//char* MemoryManagerX::CreateAndLockNewSystemPage(uint32 size, uint32& id) {
//	if (!MemoryManagerX::Singleton)
//		return 0;
//	return MemoryManagerX::Singleton->createAndLockNewSystemPage(size, id);
//}
//
//// Static
//// Resize an existing System Page
//char* MemoryManagerX::ResizeSystemPage(uint32 pageID, uint32 size) {
//	if (!MemoryManagerX::Singleton)
//		return 0;
//	return MemoryManagerX::Singleton->resizeSystemPage(pageID, size);
//}
//
//// Static
//// Destroys an exising System Page by id
//bool MemoryManagerX::DestroySystemPage(uint32 pageID) {
//	if (!MemoryManagerX::Singleton)
//		return 0;
//	return MemoryManagerX::Singleton->destroyPage(pageID);
//}
//
//
//// Create the Manager System Pages
//bool MemoryManagerX::createSystemPages() {
//
//	// Create main system page
//	char* data;
//	uint32 size = 1024*512; // ############# Need better size calc
//	uint64 memID;
//	// Create and initialise the System Page
//	if ( (data = createSystemPage(ID_SYSPAGE, size, memID)) == NULL) {
//		fprintf(stderr, "MemoryManager could not create the System page\n");
//		return false;
//	}
//	initSystemPage(data, size);
//	unlockSystemBlock(ID_SYSPAGE);
//
//	// Create and initialise the Page Pool
//	size = 1024*512; // ############# Need better size calc
//	if ( (data = createSystemPage(ID_PAGEPOOL, size, memID)) == NULL) {
//		fprintf(stderr, "MemoryManager could not create the Page Pool page\n");
//		return false;
//	}
//	initPagePool(data, size);
//	unlockSystemBlock(ID_PAGEPOOL);
//
//	// Create and initialise the Queue Page
//	size = 1024*512; // ############# Need better size calc
//	if ( (data = createSystemPage(ID_QUEUEPAGE, size, memID)) == NULL) {
//		fprintf(stderr, "MemoryManager could not create the Queue page\n");
//		return false;
//	}
//	initQueuePage(data, size);
//	unlockSystemBlock(ID_QUEUEPAGE);
//
//	// Create and initialise the Component Map Page
//	uint32 count = 0xFFFF;
//	uint32 bitFieldSize = (uint32)ceil((double)count / 8);
//	size = sizeof(ComponentMapHeader) + bitFieldSize + count*sizeof(ComponentMapEntry);
//	if ( (data = createSystemPage(ID_COMPMAPPAGE, size, memID)) == NULL) {
//		fprintf(stderr, "MemoryManager could not create the Component page\n");
//		return false;
//	}
//	ComponentMapHeader* cmHeader = (ComponentMapHeader*)data;
//	cmHeader->size = size;
//	cmHeader->bitFieldSize = bitFieldSize;
//	cmHeader->count = count;
//	memset(data+sizeof(ComponentMapHeader), 255, bitFieldSize);
//	memset(data+sizeof(ComponentMapHeader)+bitFieldSize, 0, size-sizeof(ComponentMapHeader)-bitFieldSize);
//	// Position 0 is not allowed, used to indicate error or unused	
//	utils::SetBit(0, BITOCCUPIED, (uint32*)((char*)cmHeader + sizeof(ComponentMapHeader)), cmHeader->bitFieldSize);
//	unlockSystemBlock(ID_COMPMAPPAGE);
//
//	// Create and initialise the Type Map Page
//	count = 0xFFFF;
//	bitFieldSize = (uint32)ceil((double)count / 8);
//	size = sizeof(TypeMapHeader) + bitFieldSize + count*sizeof(TypeMapEntry);
//	if ( (data = createSystemPage(ID_TYPEMAPPAGE, size, memID)) == NULL) {
//		fprintf(stderr, "MemoryManager could not create the TypeMap page\n");
//		return false;
//	}
//	TypeMapHeader* typeHeader = (TypeMapHeader*)data;
//	typeHeader->size = size;
//	typeHeader->bitFieldSize = bitFieldSize;
//	typeHeader->count = count;
//	memset((char*)typeHeader+sizeof(TypeMapHeader), 255, bitFieldSize);
//	memset((char*)typeHeader+sizeof(TypeMapHeader)+bitFieldSize, 0, size-sizeof(TypeMapHeader)-bitFieldSize);
//	// Position 0 is not allowed, used to indicate error or unused	
//	utils::SetBit(0, BITOCCUPIED, (uint32*)((char*)typeHeader + sizeof(TypeMapHeader)), typeHeader->bitFieldSize);
//	unlockSystemBlock(ID_TYPEMAPPAGE);
//
//	// Create and initialise the Context Map Page
//	count = 0xFFFF;
//	bitFieldSize = (uint32)ceil((double)count / 8);
//	size = sizeof(ContextMapHeader) + bitFieldSize + count*sizeof(ContextMapEntry);
//	if ( (data = createSystemPage(ID_CONTEXTMAPPAGE, size, memID)) == NULL) {
//		fprintf(stderr, "MemoryManager could not create the ContextMap page\n");
//		return false;
//	}
//	ContextMapHeader* contextHeader = (ContextMapHeader*)data;
//	contextHeader->size = size;
//	contextHeader->bitFieldSize = bitFieldSize;
//	contextHeader->count = count;
//	memset((char*)contextHeader+sizeof(ContextMapHeader), 255, bitFieldSize);
//	memset((char*)contextHeader+sizeof(ContextMapHeader)+bitFieldSize, 0, size-sizeof(ContextMapHeader)-bitFieldSize);
//	// Position 0 is not allowed, used to indicate error or unused	
//	utils::SetBit(0, BITOCCUPIED, (uint32*)((char*)contextHeader + sizeof(ContextMapHeader)), contextHeader->bitFieldSize);
//	unlockSystemBlock(ID_CONTEXTMAPPAGE);
//
//	//// Create and initialise the Tag Map Page
//	//count = 4096;
//	//bitFieldSize = (uint32)ceil((double)count / 8);
//	//size = sizeof(TagMapHeader) + bitFieldSize + count*sizeof(TagMapEntry);
//	//if ( (data = createSystemPage(ID_TAGMAPPAGE, size, memID)) == NULL) {
//	//	fprintf(stderr, "MemoryManager could not create the TagMap page\n");
//	//	return false;
//	//}
//	//TagMapHeader* tagHeader = (TagMapHeader*)data;
//	//tagHeader->size = size;
//	//tagHeader->bitFieldSize = bitFieldSize;
//	//tagHeader->count = count;
//	//memset((char*)tagHeader+sizeof(TagMapHeader), 255, bitFieldSize);
//	//memset((char*)tagHeader+sizeof(TagMapHeader)+bitFieldSize, 0, size-sizeof(TagMapHeader)-bitFieldSize);
//	//// Position 0 is not allowed, used to indicate error or unused	
//	//utils::SetBit(0, BITOCCUPIED, (uint32*)((char*)tagHeader + sizeof(TagMapHeader)), tagHeader->bitFieldSize);
//	//unlockSystemBlock(ID_TAGMAPPAGE);
//
//	//// Create and initialise the Node Map Page
//	//count = 4096;
//	//bitFieldSize = (uint32)ceil((double)count / 8);
//	//size = sizeof(NodeMapHeader) + bitFieldSize + count*sizeof(NodeMapEntry);
//	//if ( (data = createSystemPage(ID_NODEMAPPAGE, size, memID)) == NULL) {
//	//	fprintf(stderr, "MemoryManager could not create the NodeMap page\n");
//	//	return false;
//	//}
//	//NodeMapHeader* nodeHeader = (NodeMapHeader*)data;
//	//nodeHeader->size = size;
//	//nodeHeader->bitFieldSize = bitFieldSize;
//	//nodeHeader->count = count;
//	//memset((char*)nodeHeader+sizeof(NodeMapHeader), 255, bitFieldSize);
//	//memset((char*)nodeHeader+sizeof(NodeMapHeader)+bitFieldSize, 0, size-sizeof(NodeMapHeader)-bitFieldSize);
//	//// Position 0 is not allowed, used to indicate error or unused	
//	//utils::SetBit(0, BITOCCUPIED, (uint32*)((char*)nodeHeader + sizeof(NodeMapHeader)), nodeHeader->bitFieldSize);
//	//unlockSystemBlock(ID_NODEMAPPAGE);
//
//	// Create and initialise the Crank Map Page
//	count = 0xFFFF;
//	bitFieldSize = (uint32)ceil((double)count / 8);
//	size = sizeof(CrankMapHeader) + bitFieldSize + count*sizeof(CrankMapEntry);
//	if ( (data = createSystemPage(ID_CRANKMAPPAGE, size, memID)) == NULL) {
//		fprintf(stderr, "MemoryManager could not create the CrankMap page\n");
//		return false;
//	}
//	CrankMapHeader* crankHeader = (CrankMapHeader*)data;
//	crankHeader->size = size;
//	crankHeader->bitFieldSize = bitFieldSize;
//	crankHeader->count = count;
//	memset((char*)crankHeader+sizeof(CrankMapHeader), 255, bitFieldSize);
//	memset((char*)crankHeader+sizeof(CrankMapHeader)+bitFieldSize, 0, size-sizeof(CrankMapHeader)-bitFieldSize);
//	// Position 0 is not allowed, used to indicate error or unused	
//	utils::SetBit(0, BITOCCUPIED, (uint32*)((char*)crankHeader + sizeof(CrankMapHeader)), crankHeader->bitFieldSize);
//	unlockSystemBlock(ID_CRANKMAPPAGE);
//
//	// Create and initialise the Queue Map Page
//	count = 0xFFFF;
//	bitFieldSize = (uint32)ceil((double)count / 8);
//	size = sizeof(QueueMapHeader) + bitFieldSize + count*sizeof(QueueMapEntry);
//	if ( (data = createSystemPage(ID_QUEUEMAPPAGE, size, memID)) == NULL) {
//		fprintf(stderr, "MemoryManager could not create the QueueMap page\n");
//		return false;
//	}
//	QueueMapHeader* queueHeader = (QueueMapHeader*)data;
//	queueHeader->size = size;
//	queueHeader->bitFieldSize = bitFieldSize;
//	queueHeader->count = count;
//	memset((char*)queueHeader+sizeof(QueueMapHeader), 255, bitFieldSize);
//	memset((char*)queueHeader+sizeof(QueueMapHeader)+bitFieldSize, 0, size-sizeof(QueueMapHeader)-bitFieldSize);
//	// Position 0 is not allowed, used to indicate error or unused	
//	utils::SetBit(0, BITOCCUPIED, (uint32*)((char*)queueHeader + sizeof(QueueMapHeader)), queueHeader->bitFieldSize);
//	unlockSystemBlock(ID_QUEUEMAPPAGE);
//
//	// Create and initialise the Process Map Page
//	count = 256;
//	bitFieldSize = (uint32)ceil((double)count / 8);
//	size = sizeof(ProcessMapHeader) + bitFieldSize + count*sizeof(ProcessMapEntry);
//	if ( (data = createSystemPage(ID_PROCESSMAPPAGE, size, memID)) == NULL) {
//		fprintf(stderr, "MemoryManager could not create the ProcessMap page\n");
//		return false;
//	}
//	ProcessMapHeader* processHeader = (ProcessMapHeader*)data;
//	processHeader->size = size;
//	processHeader->bitFieldSize = bitFieldSize;
//	processHeader->count = count;
//	memset((char*)processHeader+sizeof(ProcessMapHeader), 0, size-sizeof(ProcessMapHeader));
//	memset((char*)processHeader+sizeof(ProcessMapHeader), 255, bitFieldSize);
//	// Position 0 is not allowed, used to indicate error or unused	
//	utils::SetBit(0, BITOCCUPIED, (uint32*)((char*)processHeader + sizeof(ProcessMapHeader)), processHeader->bitFieldSize);
//	unlockSystemBlock(ID_PROCESSMAPPAGE);
//
//	// Create and initialise the Request Map Page
//	count = 256;
//	bitFieldSize = (uint32)ceil((double)count / 8);
//	size = sizeof(RequestMapHeader) + bitFieldSize + count*sizeof(RequestMapEntry);
//	if ( (data = createSystemPage(ID_REQUESTMAPPAGE, size, memID)) == NULL) {
//		fprintf(stderr, "MemoryManager could not create the RequestMap page\n");
//		return false;
//	}
//	RequestMapHeader* requestHeader = (RequestMapHeader*)data;
//	requestHeader->size = size;
//	requestHeader->bitFieldSize = bitFieldSize;
//	requestHeader->count = count;
//	memset((char*)requestHeader+sizeof(RequestMapHeader), 0, size-sizeof(RequestMapHeader));
//	memset((char*)requestHeader+sizeof(RequestMapHeader), 255, bitFieldSize);
//	// Position 0 is not allowed, used to indicate error or unused	
//	utils::SetBit(0, BITOCCUPIED, (uint32*)((char*)requestHeader + sizeof(RequestMapHeader)), requestHeader->bitFieldSize);
//	unlockSystemBlock(ID_REQUESTMAPPAGE);
//
//	uint16 pid;
//	if ( (!MemoryMaps::CreateNewProcess("Node Process", pid)) || (pid != NODE_PROCESS_ID) ) {
//		fprintf(stderr, "MemoryManager could not register own process (%u != %u)\n", pid, NODE_PROCESS_ID);
//		return false;
//	}
//
//	return true;
//}
//
//// Insert new block of memory and return full id
//bool MemoryManagerX::insertMemoryBlock(const char* data, uint32 size, uint64 eol, uint64& id) {
////	uint64 start = GetTimeNow();
//	// Lock Manager
//	if (!pageMasterMutex->enter())
//		return false;
//	uint32 pageID = 0;
//	// First find an appropriate page
//	MemoryPage* page = findPageForBlock(size, eol, pageID);
//	if (page == NULL) {
//		// Create a new page
//		uint16 blockTableSize = CalcBlockTableSize(size);
//		if (blockTableSize == 0) {
//			pageMasterMutex->leave();
//			return false;
//		}
//		page = createPage((size+sizeof(MemoryBlock))*blockTableSize, blockTableSize, eol, pageID);
//		if (page == NULL) {
//			pageMasterMutex->leave();
//			return false;
//		}
//		unlockPage(pageID);
//	}
//	// printf(">>>>>> Inserting block into page ID %u...\n", pageID);
//	if (!insertMemoryBlockIntoPage(pageID, data, size, eol, id)) {
//		pageMasterMutex->leave();
//		return false;
//	}
//	pageMasterMutex->leave();
////	uint64 end = GetTimeNow();
////	printf("insertMemoryBlock      pageID: %d    %d usec\n", pageID, (int32)(end-start));
//	return true;
//}
//
//// Insert new block of memory into a specific page and return full id
//bool MemoryManagerX::insertMemoryBlockIntoPage(uint32 pageID, const char* data, uint32 size, uint64 eol, uint64& id) {
//	// Assume page and Manager locked
////	MemoryPage* page = MP_GetPageLoc(pageMaster, pageID);
//	MemoryPage* page = getCachedPage(pageID);
//	if (page == NULL)
//		return false;
//	pageMasterMutex->leave();
//
//	// printf("PageID %u EOL %lu {%p}...\n", pageID, page->eol, page);
//
//	uint32 totalSize = sizeof(MemoryBlock) + size;
//
//	// Now we have a page, check for room
//	if (page->count >= page->blockTableSize) {
//		return false;
//	}
//	if ( (int64)page->dataSize - (int64)page->dataUsage < (int64)totalSize ) {
//		return false;
//	}
//	// Find location of first available byte
//	MemoryBlock* newBlock, *lastBlock;
//	uint32 offset;
//	uint16 blockID;
//	uint32* offsetTable = (uint32*)MP_GetBlockIndexStartLoc(page);
//	MemoryBlock* dataTable = (MemoryBlock*)MP_GetBlockDataStartLoc(page);
//	if (page->count == 0) {
//		newBlock = dataTable;
//		blockID = 0;
//		offset = 0;
//	}
//	else {
//		lastBlock = (MemoryBlock*) ( (char*)dataTable + offsetTable[page->count-1] );
//		// insert memory block
//		newBlock = (MemoryBlock*) ( (char*)lastBlock + lastBlock->size );
//		blockID = page->count;
//		//offsetLoc = MP_GetBlockOffsetLoc(page, page->count-1);
//		//offsetLoc = (uint32*)MP_GetBlockIndexStartLoc(page) + ((page->count-1) * sizeof(uint32));
//		offset = (uint32) ((char*)newBlock - (char*)dataTable);
//	}
//	newBlock->size = totalSize;
//	if (data != NULL)
//		memcpy((char*)newBlock + sizeof(MemoryBlock), data, size);
//	else
//		memset((char*)newBlock + sizeof(MemoryBlock), 0, size);
//	page->count++;
//	page->dataUsage += newBlock->size;
//	offsetTable[page->count-1] = offset;
//	// Lock Manager
//	if (!pageMasterMutex->enter())
//		return false;
//	pageMaster->dataUsage[MP_GetPageType(pageID, eol)] += newBlock->size;
//	MemoryID* mid = (MemoryID*) &id;
//	mid->blockID = blockID;
//	mid->sysID = pageMaster->sysID;
//	mid->pageID = pageID;
////	printf("[%u][%u][%u] ", MP_GetNodeID(id), MP_GetPageID(id), MP_GetBlockID(id));
////	printBitFieldAsString("Bitfield After Insert");
//	// Leave Manager locked
//	return true;
//}
//
//char* MemoryManagerX::getAndLockMemoryBlock(uint64 id, uint32& size, uint64& eol) {
//	// Lock Manager
//	if (!pageMasterMutex->enter())
//		return NULL;
//	uint32 pageID = MP_GetPageID(id);
//	//printf(">>>>>> Getting block from page ID %u...\n", pageID);
//
//	MemoryPageEntry* entry = (MemoryPageEntry*)MP_GetPageEntryLoc(pageMaster, pageID);
//	if (!lockPage(entry)) {
//		pageMasterMutex->leave();
//		return NULL;
//	}
//
//	MemoryPage* page = getCachedPage(entry);
//	if (page == NULL) {
//		pageMasterMutex->leave();
//		return NULL;
//	}
//	// printf("PageID %u EOL %lu {%p}...\n", pageID, entry->page->eol, entry->page);
//	pageMasterMutex->leave();
//	return getLockedMemoryBlock(page, id, size, eol);
//}
//
//char* MemoryManagerX::getLockedMemoryBlock(MemoryPage* page, uint64 id, uint32& size, uint64& eol) {
//	char* data = NULL;
//	uint32* offsetTable = (uint32*)MP_GetBlockIndexStartLoc(page);
//	MemoryBlock* dataTable = (MemoryBlock*)MP_GetBlockDataStartLoc(page);
//
//	uint16 blockID = MP_GetBlockID(id);
//	MemoryBlock* block = (MemoryBlock*) ( (char*)dataTable + offsetTable[blockID] );
//	if (block == NULL) {
//		// Unlock page
//		unlockPage(MP_GetPageID(id));
//		return NULL;
//	}
//	size = block->size - sizeof(MemoryBlock);
//	eol = page->eol;
//	return ((char*)block + sizeof(MemoryBlock));
//}
//
//bool MemoryManagerX::unlockMemoryBlock(uint64 id) {
//	uint32 pageID = MP_GetPageID(id);
//	unlockPage(pageID);
//	return true;
//}
//
//char* MemoryManagerX::getCopyMemoryBlock(uint64 id, uint32& size, uint64& eol) {
//	char* data = getAndLockMemoryBlock(id, size, eol);
//	if (data == NULL)
//		return false;
//	char* output = new char[size];
//	memcpy(output, data, size);
//	unlockMemoryBlock(id);
//	return output;
//}
//
//// Overwrite existing block of memory
//bool MemoryManagerX::overwriteMemoryBlock(uint64 id, const char* data, uint32 size, uint64 eol) {
//	uint32 existingSize;
//	uint64 existingEOL;
//	char* existingData = getAndLockMemoryBlock(id, existingSize, existingEOL);
//	if ((existingData == NULL) || (existingSize != size) || (existingEOL != eol) )
//		return false;
//	memcpy(existingData, data, size);
//	unlockMemoryBlock(id);
//	return true;
//}
//
//// Create new MemoryPage
//MemoryPage* MemoryManagerX::createPage(uint32 size, uint16 tableSize, uint64 eol, uint32& pageID) {
////	uint64 start = GetTimeNow();
//	// Lock Manager
//	if (!pageMasterMutex->enter())
//		return NULL;
//
//	// First calculate total size
//	uint32 pageSize = sizeof(MemoryPage) + (tableSize*sizeof(uint32)) + size;
//
//	MemoryPageEntry* entry = NULL;
//	// Now check if caller is requesting a particular id
//	if (pageID > 0) {
//		entry = (MemoryPageEntry*)MP_GetPageEntryLoc(pageMaster, pageID);
//		if ((entry == NULL) || (entry->pageSize != 0))
//			return NULL;
//	}
//	else {
//		// Get a page from the pool with the right data size
//		if (getPageFromPool(size, pageID)) {
//			//printf("CreateFromPool %u...\n", pageID);
//			// We have a valid page from the pool
//		}
//		// Find first available Page Entry
//		else if (!utils::GetFirstFreeBitLoc((uint32*)MP_GetBitFieldLoc(pageMaster), pageMaster->pageTableSize, pageID)) {
//			pageMasterMutex->leave();
//			return NULL;
//		}
//	}
//
//	if (pageID >= pageMaster->pageTableSize) {
//		// ############## should resize pagetable ##############
//		LogPrint(0,0,0,"Page Table needs resizing!");
//		pageMasterMutex->leave();
//		return NULL;
//	}
//
//	entry = (MemoryPageEntry*)MP_GetPageEntryLoc(pageMaster, pageID);
//	if (entry->pageSize == 0)
//		entry->pageID = pageID;
//	if (!lockPage(entry)) {
//		pageMasterMutex->leave();
//		return NULL;
//	}
//
//	MemoryPage* page = NULL;
//	// If the page already exists, use it
//	// if not, create it
//	if (entry->pageSize == 0) {
//		char* pageName = new char[MAXKEYNAMELEN];
//		sprintf(pageName, "Page_%u", pageID);
//		// Allocate from shared memory
//		page = (MemoryPage*) utils::CreateSharedMemorySegment(pageName, pageSize);
//		delete [] pageName;
//		if (page == NULL) {
//			unlockPage(entry);
//			pageMasterMutex->leave();
//			return NULL;
//		}
//		entry->cacheSerial = 1;
//		page->blockTableSize = tableSize;
//		page->size = pageSize;
//		page->dataSize = size;
//		entry->pageSize = pageSize;
//		// entry->pageID = pageID;
//		page->eol = 0;
//	//	printf("CreateFromNew %u EOL %lu...\n", pageID, entry->page->eol);
//	}
//	else {
//		page = getCachedPage(entry);
//		if (page == NULL) {
//			unlockPage(entry);
//			pageMasterMutex->leave();
//			return NULL;
//		}
//	}
//
//	utils::SetBit(pageID, BITOCCUPIED, (uint32*)MP_GetBitFieldLoc(pageMaster), pageMaster->bitFieldSize);
//	if (eol == 0)
//		pageMaster->lastCreatedStaticPage = pageID;
//	else 
//		insertPageIntoEOL(pageID, eol, page->eol);
//
//	// Initialise page
//	page->count = 0;
//	page->dataUsage = 0;
////	memset((void*)MP_GetBlockIndexStartLoc(entry->page), 0, (tableSize*sizeof(uint32)) + size);
//	memset((void*)MP_GetBlockIndexStartLoc(page), 0, (tableSize*sizeof(uint32)));
//
//	entry->pageSerial++;
//	pageMaster->count[MP_GetPageType(pageID, eol)]++;
//	pageMaster->pagesSize += page->size;
//	pageMaster->dataSize[MP_GetPageType(pageID, eol)] += page->dataSize;
//
//	updateCachedPage(entry, page);
//
//	// Unlock page mutex
////	unlockPage(entry); ######################
//	// Unlock Manager
//	pageMasterMutex->leave();
////	uint64 end = GetTimeNow();
////	printf("createPage      pageID: %d    %d usec\n", pageID, (int32)(end-start));
//	return page;
//}
//
//// Free up a page and put it into the pool
//bool MemoryManagerX::freePageIntoPool(uint32 pageID) {
//	uint32 dataSize = 0;
//	if (!removePageFromStats(pageID, dataSize))
//		return false;
//	if (!insertPageIntoPool(pageID, dataSize))
//		return false;
//	return true;
//}
//
//// Remove page from list, but do not delete
//bool MemoryManagerX::removePageFromStats(uint32 pageID, uint32& dataSize) {
//	// Lock Manager
//	if (!pageMasterMutex->enter())
//		return false;
//	MemoryPageEntry* entry = (MemoryPageEntry*) MP_GetPageEntryLoc(pageMaster, pageID);
//	// Lock page
//	if (!lockPage(entry)) {
//		pageMasterMutex->leave();
//		return false;
//	}
//
//	MemoryPage* page = getCachedPage(entry);
//	if (page == NULL) {
//		pageMasterMutex->leave();
//		return true;
//	}
//
////	printf("Freeing page of datasize %u/%u...\n", entry->page->dataSize, entry->page->dataUsage);
//
//	dataSize = page->dataSize;
//	pageMaster->count[MP_GetPageType(pageID, page->eol)]--;
//	pageMaster->dataSize[MP_GetPageType(pageID, page->eol)] -= page->dataSize;
//	pageMaster->dataUsage[MP_GetPageType(pageID, page->eol)] -= page->dataUsage;
//	pageMaster->pagesSize -= page->size;
//	// Do not destroy shared memory segment at entry->page
//	// and leave page link in there
//	// entry->page = NULL;
//	// Unlock page
//	unlockPage(entry);
//	// destroyPageMutex(pageID);
//	// Page location remains in use
//	// utils::SetBit(pageID, BITFREE, (uint32*)MP_GetBitFieldLoc(pageMaster), pageMaster->bitFieldSize);
//	// Unlock Manager
//	pageMasterMutex->leave();
//	return true;
//}
//
//// Insert a page into the idle pool
//bool MemoryManagerX::insertPageIntoPool(uint32 pageID, uint32 dataSize) {
//	uint32 sbSize = 0;
//	PagePoolHeader* header = (PagePoolHeader*) getSystemBlock(ID_PAGEPOOL, sbSize);
//	// Find empty spot
//	PagePoolEntry* entry = (PagePoolEntry*) ((char*)header + sizeof(PagePoolHeader));
//	while ((char*)entry < (char*)header + header->size) {
//		if (entry->dataSize == 0) {
//			//printf("Freeing to pool page id %d\n", pageID);
//			//fflush(stdout);
//			entry->dataSize = dataSize;
//			entry->time = GetTimeNow();
//			entry->pageID = pageID;
//			return true;
//		}
//		else
//			entry += 1;
//			//entry += sizeof(PagePoolEntry);
//	}
//
//	// no free entry was found, remove the oldest one, then...
//	entry = (PagePoolEntry*) ((char*)header + sizeof(PagePoolHeader));
//	//printf("No free Pool Entries available for id %d, destroying id %d first\n", pageID, entry->pageID);
//	//fflush(stdout);
//	// Delete actual page
//	destroyPage(entry->pageID, false);
//	// Put in new one
//	entry->dataSize = dataSize;
//	entry->time = GetTimeNow();
//	entry->pageID = pageID;
//	return true;
//}
//
//// Get page with required size from the idle pool
//bool MemoryManagerX::getPageFromPool(uint32 size, uint32& pageID) {
//	uint32 sbSize = 0;
//	PagePoolHeader* header = (PagePoolHeader*) getSystemBlock(ID_PAGEPOOL, sbSize);
//	if (header == NULL)
//		return false;
//	// Find empty spot
//	PagePoolEntry* entry = (PagePoolEntry*) ((char*)header + sizeof(PagePoolHeader));
//	while ((char*)entry < (char*)header + header->size) {
//		if (entry->dataSize >= size) {
//			pageID = entry->pageID;
//			//printf("Got from pool page id %d\n", pageID);
//			//fflush(stdout);
//			// Remove from pool
//			memset(entry, 0, sizeof(PagePoolEntry));
//			return true;
//		}
//		else
//			entry += 1;
//			//entry += sizeof(PagePoolEntry);
//	}
//	return false;
//}
//
//// Destroy all Memory Pages
//bool MemoryManagerX::destroyAllPages() {
//	// Lock Manager
//	if (!pageMasterMutex->enter())
//		return false;
//	if (pageMaster == NULL) {
//		pageMasterMutex->leave();
//		return true;
//	}
//
//	// MemoryPageEntry* entry = (MemoryPageEntry*) MP_GetPageTableLoc(pageMaster);
//	for (uint32 n=0; n<pageMaster->pageTableSize; n++)
//		destroyPage(n);
//	// Unlock Manager
//	pageMasterMutex->leave();
//	return true;
//}
//
//// Destroy a Memory Page
//bool MemoryManagerX::destroyPage(uint32 pageID, bool updateStats) {
//	// Lock Manager
//	if (!pageMasterMutex->enter())
//		return false;
//	MemoryPageEntry* entry = (MemoryPageEntry*) MP_GetPageEntryLoc(pageMaster, pageID);
//	// Lock page
//	if (!lockPage(entry)) {
//		pageMasterMutex->leave();
//		return false;
//	}
//
//	MemoryPage* page = getCachedPage(entry);
//	if (page == NULL) {
//		pageMasterMutex->leave();
//		return true;
//	}
//
//	if (updateStats) {
//		pageMaster->count[MP_GetPageType(pageID, page->eol)]--;
//		pageMaster->dataSize[MP_GetPageType(pageID, page->eol)] -= page->dataSize;
//		pageMaster->dataUsage[MP_GetPageType(pageID, page->eol)] -= page->dataUsage;
//		pageMaster->pagesSize -= page->size;
//	}
//	// Destroy shared memory segment at entry->page
//	//printf("Closing cached page %d...\n", pageID);
//	//fflush(stdout);
//	utils::DestroySharedMemorySegment((char*)(page), page->size);
//	page = NULL;
//	entry->cacheSerial = 0;
//	entry->pageSize = 0;
//	updateCachedPage(entry, NULL);
//	// Unlock page
//	unlockPage(entry);
//	utils::SetBit(pageID, BITFREE, (uint32*)MP_GetBitFieldLoc(pageMaster), pageMaster->bitFieldSize);
//	// Unlock Manager
//	pageMasterMutex->leave();
//	return true;
//}
//
//// Create a new Page Mutex
////Mutex MemoryManagerX::createPageMutex(uint32 pageID) {
////	char name[MAXKEYNAMELEN];
////	utils::GetSystemName(pageID, "PageMutex", name, MAXKEYNAMELEN);
////	return utils::CreateMutex(name);
////}
//
//// Get an existing Page Mutex or creates it
////bool MemoryManagerX::getPageMutex(uint32 pageID, NMutex &mutex) {
////	char name[MAXKEYNAMELEN];
////	utils::GetSystemName(pageID, "PageMutex", name, MAXKEYNAMELEN);
////	return (utils::GetMutex(name, &mutex));
////}
//
//// Destroy a Page Mutex
////bool MemoryManagerX::destroyPageMutex(uint32 pageID) {
////	char name[MAXKEYNAMELEN];
////	utils::GetSystemName(pageID, "PageMutex", name, MAXKEYNAMELEN);
////	return utils::DestroyMutex(name);
////}
//
//// Get an existing Page Semaphore or creates it
////utils::Semaphore* MemoryManagerX::getPageSemaphore(uint32 pageID) {
////	char* pageName = new char[MAXKEYNAMELEN+1];
////	sprintf(pageName, "Page_%u", pageID);
////	utils::Semaphore* sem = new utils::Semaphore(pageName);
////	delete [] pageName;
////	return sem;
////}
//
////utils::Mutex* MemoryManagerX::getPageMutex(uint32 pageID) {
////	char* pageName = new char[MAXKEYNAMELEN+1];
////	sprintf(pageName, "Page_%u", pageID);
////	utils::Mutex* mutex = new utils::Mutex(pageName);
////	delete [] pageName;
////	return mutex;
////}
//
//bool MemoryManagerX::lockPage(uint32 pageID) {
//	if (!utils::EnterMutex(pageID, 5000)) {
//		LogPrint(0,0,0,"Mutex lock timeout for memory page %u", pageID);
//		return false;
//	}
//	return true;
//
////	return lockPage((MemoryPageEntry*)MP_GetPageEntryLoc(pageMaster, pageID));
//}
//
//bool MemoryManagerX::unlockPage(uint32 pageID) {
//	return utils::LeaveMutex(pageID);
////	return unlockPage((MemoryPageEntry*)MP_GetPageEntryLoc(pageMaster, pageID));
//}
//
////bool MemoryManagerX::lockPage(MemoryPage* page) {
////}
//
////bool MemoryManagerX::unlockPage(MemoryPage* page) {
////}
//
//bool MemoryManagerX::lockPage(MemoryPageEntry* entry) {
//	// Assume that pageMasterMutex is locked
//	if (entry == NULL)
//		return false;
//
//	if (!utils::EnterMutex(entry->pageID, 5000)) {
//		LogPrint(0,0,0,"Mutex lock timeout for memory page %u", entry->pageID);
//		return false;
//	}
//	return true;
//
//	//uint64 t1, t2;
//	//uint32 myID = 0;
//	//if (!utils::GetCurrentThreadOSID(myID) || !myID)
//	//	return false;
//
//	//// wait until it reaches 0
//	//utils::Semaphore* sem;
//	//while ( (entry->lockCount > 0) && (entry->lockID != myID) ) {
//	////	printf("[%u] Waiting for page %u locked by %u\n", myID, entry->pageID, entry->lockID);
//	//	// if we are waiting the page semaphore exists
//	//	if (!(sem = getPageSemaphore(entry->pageID)))
//	//		return false;
//	//	pageMasterMutex->leave();
//	//	t1 = GetTimeNow();
//	//	if (!sem->wait(1000)) {
//	//		t2 = GetTimeNow();
//	//		delete(sem);
//	//		return false;
//	//	}
//	//	else
//	//		delete(sem);
//	//	if (!pageMasterMutex->enter())
//	//		return false;
//	//}
//
//	////if (entry->lockCount)
//	////	printf("[%u] Locked page %u AGAIN: %u\n", myID, entry->pageID, entry->lockCount);
//	////else
//	////	printf("[%u] Locked page %u\n", myID, entry->pageID);
//
//	//entry->lockCount++;
//	//entry->lockTime = GetTimeNow();
//	//entry->lockID = myID;
//	//return true;
//}
//
//bool MemoryManagerX::unlockPage(MemoryPageEntry* entry) {
//	if (entry == NULL)
//		return false;
//
//	return utils::LeaveMutex(entry->pageID);
//
////	if (!entry->lockCount)
////		return true;
////
////	uint32 myID = 0;
////	if (!utils::GetCurrentThreadOSID(myID))
////		return false;
////
////	if (entry->lockID != myID)
////		return false;
////
////	utils::Semaphore* sem = getPageSemaphore(entry->pageID);
////	if (!sem)
////		return false;
////
////	entry->lockCount--;
////	if (!entry->lockCount) {
////		entry->lockID = entry->lockTime = 0;
////		//printf("[%u] Unlocked page %u\n", myID, entry->pageID);
////	}
//////	else
//////		printf("[%u] Decreased lock count to %u page %u\n", myID, entry->lockCount, entry->pageID);
////	sem->signal();
////
////
////	delete(sem);
////	return true;
//}
//
//
//
//// Find an available page appropriate for the block size and ttl
//MemoryPage* MemoryManagerX::findPageForBlock(uint32 size, uint64 eol, uint32& id) {
//	MemoryPage* page = NULL;
//	if (eol > 0) {
//		// search only in eol pages
//		uint32 sbSize = 0;
//		EOLHeader* header = (EOLHeader*) getSystemBlock(ID_EOLPAGE, sbSize);
//		if (header == NULL)
//			return NULL;
//
//		EOLEntry* entry = NULL;
//		// Find the appropriate slot
//		uint64 now = GetTimeNow();
//		uint64 difTime = 0;
//		if (eol - now > 0)
//			difTime = eol - header->startTime;
//		uint32 difSlot = (uint32)(difTime / header->slotDuration);
//		// If too far in the future, choose end slot - buffer slot
//		if (difSlot >= (header->slotCount - header->bufferSlots))
//			difSlot = header->slotCount - 1 - header->bufferSlots;
//		// Find actual slot...
//		uint32 actualSlot = header->startSlot + difSlot;
//		if (actualSlot >= header->slotCount)
//			actualSlot -= header->slotCount;
//		entry = (EOLEntry*)((char*)header + sizeof(EOLHeader) +
//			(actualSlot * header->pagesPerSlot * sizeof(EOLEntry)));
//		char* endEntry = (char*) entry + header->pagesPerSlot*sizeof(EOLEntry);
//		while ((char*) entry <= endEntry) {
//			if (entry->eol > 0) {
//				// page = MP_GetPageLoc(pageMaster, entry->pageID);
//				page = getCachedPage(entry->pageID);
//				if ((page != NULL) && ( (int64)page->dataSize - (int64)page->dataUsage >= (int64)(size+sizeof(MemoryBlock)) ) ) {
//					id = entry->pageID;
//					return page;
//				}
//			}
//			entry += 1;
//			//entry += sizeof(EOLEntry);
//		}
//	}
//	else {
//		// search in non-eol pages
//		// First check the last created page
//		//page = MP_GetPageLoc(pageMaster, pageMaster->lastCreatedStaticPage);
//		page = getCachedPage(pageMaster->lastCreatedStaticPage);
//		if ((page != NULL) && ( (int64)page->dataSize - (int64)page->dataUsage >= (int64)(size+sizeof(MemoryBlock)) ) ) {
//			id = pageMaster->lastCreatedStaticPage;
//			return page;
//		}
//		// Since we don't (yet) support deletion of memory within static pages, 
//		// there is no need to look further
//	}
//
//	return NULL;
//}
//
//
//// Calculate the new page size based on incoming block size
//uint16 MemoryManagerX::CalcBlockTableSize(uint32 size) {
//	if (size >= 10*1024*1024) // 10 MB
//		return 10;
//	else if (size >= 1024*1024) // 1 MB
//		return 100;
//	else if (size >= 256*1024) // 256 kB
//		return 512;
//	else if (size >= 16*1024) // 16 kB
//		return 1024;
//	else
//		return 4096;
//
//}
//
//// Return string representing the bitfield
//char* MemoryManagerX::getBitFieldAsString(uint32& size) {
//	size = this->pageMaster->bitFieldSize * 16;
//	char* str = new char[size];
//	
//	char* src = (char*)MP_GetBitFieldLoc(pageMaster);
//	uint32 bfsize = pageMaster->bitFieldSize;
//
//	uint32 n=0, p=0,i,j;
//	for(i=0;i<bfsize;i++) {
//		for(j=0;j<8;j++) {
//			str[n++] = (src[i] & (1<<j)) ? '_' : '0' + (uint8)(getPageUsage(p)*10);
//			if (++p >= pageMaster->pageTableSize)
//				break;
//		}
//		str[n++] = ' ';
//	};
//	str[n] = 0;
//	return str;
//}
//
//// Print string representing the bitfield
//bool MemoryManagerX::printBitFieldAsString(char* title) {
//	uint32 size = 0;
//	char* str = getBitFieldAsString(size);
//	if (str == NULL)
//		return false;
//	if (size < 73) {
//		if (title != NULL)
//			printf("%s [%u]: %s\n", title, pageMaster->pageTableSize, str);
//		else
//			printf("%s\n", str);
//	}
//	else {
//		if (title != NULL)
//			printf("%s [%u]:\n", title, pageMaster->pageTableSize);
//		uint32 loc = 35;
//		while (loc < size-1) {
//			str[loc] = '\n';
//			loc += 36;
//		}
//		printf("%s\n", str);
//	}
//	delete [] str;
//	return true;
//}
//
//// Get the percentage in use of a page
//bool MemoryManagerX::getPageUsage(uint32 pageID, double& val) {
////	MemoryPage* page = MP_GetPageLoc(pageMaster, pageID);
//	MemoryPage* page = getCachedPage(pageID);
//	if (page == NULL)
//		return false;
//	val = ((double)page->dataUsage)/page->dataSize;
//	return true;
//}
//
//// Get the percentage in use of a page
//double MemoryManagerX::getPageUsage(uint32 pageID) {
////	MemoryPage* page = MP_GetPageLoc(pageMaster, pageID);
//	MemoryPage* page = getCachedPage(pageID);
//	if (page == NULL)
//		return 0;
//	return ((double)page->dataUsage)/page->dataSize;
//}
//
//// Get the number of bytes free of a page
//bool MemoryManagerX::getPageFree(uint32 pageID, uint32& bytes) {
////	MemoryPage* page = MP_GetPageLoc(pageMaster, pageID);
//	MemoryPage* page = getCachedPage(pageID);
//	if (page == NULL)
//		return false;
//	bytes = page->dataSize - page->dataUsage;
//	return true;
//}
//
//// Get the total size in bytes a page
//bool MemoryManagerX::getPageSize(uint32 pageID, uint32& bytes) {
////	MemoryPage* page = MP_GetPageLoc(pageMaster, pageID);
//	MemoryPage* page = getCachedPage(pageID);
//	if (page == NULL)
//		return false;
//	bytes = page->dataSize;
//	return true;
//}
//
//// Initialise the System Page
//bool MemoryManagerX::initSystemPage(char* data, uint32 size) {
//	memset(data, 0, size);
//	return true;
//}
//
//// Initialise the Page Pool
//bool MemoryManagerX::initPagePool(char* data, uint32 size) {
//	PagePoolHeader* header = (PagePoolHeader*) data;
//	header->size = size;
//	memset(data+sizeof(PagePoolHeader), 0, size-sizeof(PagePoolHeader));
//	return true;
//}
//
//// Resize the EOL Page
//bool MemoryManagerX::resizeEOLPage(uint32 slotCount, uint32 pagesPerSlot, uint32 slotDuration, uint32 bufferSlots) {
//
//	if ( (slotCount < 5) || (pagesPerSlot < 5) || (slotDuration < 100000) || (bufferSlots < 1) )
//		return false;
//
//	uint32 oldSize = 0, newSize = (slotCount+bufferSlots)*pagesPerSlot*sizeof(EOLEntry) + sizeof(EOLHeader);
//	MemoryPageEntry* oldEntry = (MemoryPageEntry*)MP_GetPageEntryLoc(pageMaster, ID_EOLPAGE);
////	MemoryPage* oldPage = MP_GetPageLoc(pageMaster, ID_EOLPAGE);
//	char* oldData = NULL;
//	if ((oldEntry != NULL) && (oldEntry->pageSize != 0)) {
//		// Make copy...
//		char* eolData = getSystemBlock(ID_EOLPAGE, oldSize);
//		if (newSize <= oldSize)
//			return false;
//		oldData = new char[oldSize];
//		memcpy(eolData, oldData, oldSize);
//		destroyPage(ID_EOLPAGE);
//	}
//	uint64 memID;
//	char* data = createSystemPage(ID_EOLPAGE, newSize, memID);
//	if (data == NULL)
//		return false;
////	printf("New EOL struct: %p - %p ...\n", data, data+newSize);
//	memset(data, 0, newSize);
//	EOLHeader* header = (EOLHeader*) data;
//	header->slotCount = slotCount+bufferSlots;
//	header->pagesPerSlot = pagesPerSlot;
//	header->slotDuration = slotDuration;
//	header->startSlot = 0;
//	header->startTime = GetTimeNow();
//	header->bufferSlots = bufferSlots;
//
//	uint64 slotEOL = 0;
//	if (oldData != NULL) {
//		EOLHeader* oldHeader = (EOLHeader*) oldData;
//		// Copy old data back in...
//		EOLEntry* entry = (EOLEntry*) oldHeader + sizeof(EOLHeader);
//		uint64 endHeader = (uint64) oldHeader + (oldHeader->slotCount*oldHeader->pagesPerSlot*sizeof(EOLEntry)) + sizeof(EOLHeader);
//		while ((uint64) entry <= endHeader) {
//			if (entry->eol > 0) {
//				// Insert entry in new structure
//				insertPageIntoEOL(entry->pageID, entry->eol, slotEOL);
//			}
//			entry += 1;
//			//entry += sizeof(EOLEntry);
//		}
//		// Delete copy
//		delete [] oldData;
//	}
//	return true;
//}
//
//// Insert page into EOL Structure
//bool MemoryManagerX::insertPageIntoEOL(uint32 pageID, uint64 eol, uint64& slotEOL) {
//	uint32 sbSize = 0;
//	EOLHeader* header = (EOLHeader*) getSystemBlock(ID_EOLPAGE, sbSize);
//	if (header == NULL)
//		return false;
//
//	EOLEntry* entry = NULL;
//	// Find the appropriate slot
//	uint64 now = GetTimeNow();
//	uint64 difTime = 0;
//	if (eol - now > 0)
//		difTime = eol - now;
//	// If too far in the future, choose end slot
//	uint32 difSlot = (uint32)(difTime / header->slotDuration);
//	// If too far in the future, choose end slot - buffer slot
//	if (difSlot >= (header->slotCount - header->bufferSlots))
//		difSlot = header->slotCount - 1 - header->bufferSlots;
//	// Calc end time of actual slot
//	slotEOL = difSlot * header->slotDuration;
//	// Find actual slot, possible wrap-around...
//	uint32 actualSlot = header->startSlot + difSlot;
//	if (actualSlot >= header->slotCount)
//		actualSlot -= header->slotCount;
//
////	printf(">>> Creating page ID %u in EOL slot %u...\n", pageID, actualSlot);
//
//	entry = (EOLEntry*)((char*)header + sizeof(EOLHeader) +
//		(actualSlot * header->pagesPerSlot * sizeof(EOLEntry)));
//	char* endEntry = (char*) entry + header->pagesPerSlot*sizeof(EOLEntry);
//	while ((char*) entry < endEntry) {
//		if (entry->eol == 0) {
//			entry->eol = eol;
//			entry->pageID = pageID;
//			return true;
//		}
//		else
//			entry += 1;
//			//entry += sizeof(EOLEntry);
//	}
//	// Out of room in current slot, try the next slot
//	if (difSlot < header->slotCount - 1)
//		return insertPageIntoEOL(pageID, eol+header->slotDuration, slotEOL);
//	else {
//		// we need to resize the EOL structure
//		resizeEOLPage(header->slotCount, header->pagesPerSlot * 4, header->slotDuration, header->bufferSlots);
//		return insertPageIntoEOL(pageID, eol, slotEOL);
//	}
//}
//
//
//// Initialise the Queue Page
//bool MemoryManagerX::initQueuePage(char* data, uint32 size) {
//	memset(data, 0, size);
//	return true;
//}
//
//
//MemoryPage* MemoryManagerX::getCachedPage(uint32 pageID) {
//	return getCachedPage((MemoryPageEntry*)MP_GetPageEntryLoc(pageMaster, pageID));
//}
//
//MemoryPage* MemoryManagerX::getCachedPage(MemoryPageEntry *entry) {
//	if (entry == NULL)
//		return NULL;
//
//	if (pageCache == NULL) {
//		uint32 size = sizeof(MemoryPageCache) + pageMaster->pageTableSize*sizeof(MemoryPageCacheEntry);
//		pageCache = (MemoryPageCache*) malloc(size);
//		pageCache->size = size;
//		pageCache->count = pageMaster->pageTableSize;
//		memset((char*)pageCache + sizeof(MemoryPageCache), 0, size - sizeof(MemoryPageCache));
//	}
//
//	// Find CachedEntry
//	MemoryPageCacheEntry* cEntry = (MemoryPageCacheEntry*) ((char*)pageCache + sizeof(MemoryPageCache) + (entry->pageID * sizeof(MemoryPageCacheEntry)));
//	if (cEntry == NULL)
//		return NULL;
//	else if ( (cEntry->page == NULL) || (cEntry->cacheSerial != entry->cacheSerial) || (cEntry->pageSerial != entry->pageSerial) ) {
//		// Cache needs updating
//		if (cEntry->page != NULL)
//			utils::DestroySharedMemorySegment((char*)cEntry->page, cEntry->pageSize);
//		// Map page memory location
//
//		char* pageName = new char[MAXKEYNAMELEN];
//		sprintf(pageName, "Page_%u", entry->pageID);
//		cEntry->page = (MemoryPage*) utils::OpenSharedMemorySegment(pageName, entry->pageSize);
//		delete [] pageName;
//		if (cEntry->page == NULL)
//			return NULL;
//		cEntry->cacheSerial = entry->cacheSerial;
//		cEntry->pageID = entry->pageID;
//		cEntry->pageSerial = entry->pageSerial;
//		cEntry->pageSize = entry->pageSize;
//	}
//	//printf("Got cached page id %d:  %p\n", entry->pageID, cEntry->page);
//	//fflush(stdout);
//	return cEntry->page;
//}
//
//bool MemoryManagerX::updateCachedPage(MemoryPageEntry *entry, MemoryPage *page) {
//	if (entry == NULL)
//		return false;
//
//	if (pageCache == NULL) {
//		uint32 size = sizeof(MemoryPageCache) + pageMaster->pageTableSize*sizeof(MemoryPageCacheEntry);
//		pageCache = (MemoryPageCache*)malloc(size);
//		pageCache->size = size;
//		pageCache->count = pageMaster->pageTableSize;
//		memset((char*)pageCache + sizeof(MemoryPageCache), 0, size - sizeof(MemoryPageCache));
//	}
//
//	// Find CachedEntry
//	MemoryPageCacheEntry* cEntry = (MemoryPageCacheEntry*) ((char*)pageCache + sizeof(MemoryPageCache) + (entry->pageID * sizeof(MemoryPageCacheEntry)));
//	if (cEntry == NULL)
//		return NULL;
//
//	// Should existing page be removed?
//	if ( (cEntry->page != NULL) && (cEntry->page != page) && ( (page != NULL) || (entry->pageSize == 0) ) ) {
//		utils::DestroySharedMemorySegment((char*)cEntry->page, cEntry->pageSize);
//		cEntry->page = NULL;
//	}
//	if (page != NULL)
//		cEntry->page = page;
//	cEntry->cacheSerial = entry->cacheSerial;
//	cEntry->pageID = entry->pageID;
//	cEntry->pageSerial = entry->pageSerial;
//	cEntry->pageSize = entry->pageSize;
//
//	return true;
//}
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
////THREAD_RET THREAD_FUNCTION_CALL MemoryManagement(THREAD_ARG arg) {
////	if (!MemoryManagerX::Singleton)
////		thread_ret_val(0);
////	thread_ret_val(MemoryManagerX::Singleton->runManager());
////}
//
//// Continuous management of eol pages
//uint32 MemoryManagerX::runManager() {
//	LogPrint(0, LOG_SYSTEM, 5, "Memory Management running...\n\n");
//	isRunning = true;
//
//	uint64 nextPageCheck = 0, now;
//
//	while (shouldContinue) {
//		if (!pageMasterMutex->enter())
//			break;
//
//		if (isMaster)
//			pageMaster->timesync = LocalSyncAdjustment;
//		else
//			LocalSyncAdjustment = pageMaster->timesync;
//
//		now = GetTimeNow();
//
//		if (!nextPageCheck || (now >= nextPageCheck) ) {
//
//			uint32 sbSize = 0;
//			EOLHeader* header = (EOLHeader*) getSystemBlock(ID_EOLPAGE, sbSize);
//			if (header == NULL) {
//				pageMasterMutex->leave();
//				break;
//			}
//
//			EOLEntry* entry;
//			char* endEntry;
//			int32 delSlot;
//			// Check if we should tick the current EOL startSlot to the next slot
//			while ( now - header->startTime > header->slotDuration) {
//				// Move the current slot one forward
//				header->startSlot++;
//				if (header->startSlot > header->slotCount)
//					header->startSlot -= header->slotCount;
//				header->startTime += header->slotDuration;
//			//	printf("New startSlot: %u (%d)...\n", header->startSlot, GetTimeNow() - header->startTime);
//				// Find the slot minus bufferSlots
//				delSlot = header->startSlot - header->bufferSlots;
//				if (delSlot < 0)
//					delSlot += header->slotCount;
//
//				// Free all pages in the slot
//				entry = (EOLEntry*)((char*)header + sizeof(EOLHeader) +
//					(delSlot * header->pagesPerSlot * sizeof(EOLEntry)));
//				endEntry = (char*) entry + header->pagesPerSlot*sizeof(EOLEntry);
//				while ((char*) entry < endEntry) {
//					if (entry->eol > 0) {
//					//	printf("--------- Freeing page ID %u, slot %u, eol %llu...\n", entry->pageID, delSlot, entry->eol);
//						freePageIntoPool(entry->pageID);
//						entry->eol = 0;
//						entry->pageID = 0;
//					}
//					entry += 1;
//				}
//
//			}
//			nextPageCheck = header->startTime + header->slotDuration + 20000;
//			// sleep = header->startTime + header->slotDuration - GetTimeNow() + 20000;
//			pageMasterMutex->leave();
//		}
//		else {
//			pageMasterMutex->leave();
//			utils::Sleep(20);
//		}
//	}
//
//	isRunning = false;
//	return 0;
//}
//
//bool MemoryManagerX::UnitTest() {
//	printf("Testing Static Memory Management...\n\n");
//
//	// First create and initialise the MemoryManager
//	MemoryManagerX* manager = new MemoryManagerX();
//	uint32 maxPageCount = 15;
//	// fprintf(stderr, "MemoryManager init() 0...\n");
//	if (!manager->create(0, maxPageCount)) {
//		fprintf(stderr, "MemoryManager init() failed...\n");
//		delete(manager);
//		return false;
//	}
//	// fprintf(stderr, "MemoryManager init() success...\n");
//
//	uint64 eol = 0;
//	uint32 size = 4096;
//	char* data = new char[size];
//
//	// we should be able to add 
//	uint32 expectedCount = CalcBlockTableSize(size);
//	uint32 expectedMaxCount = (maxPageCount-RESERVEDPAGECOUNT) * expectedCount;
//	uint32 count = expectedMaxCount;
//	uint64* ids = new uint64[count];
//
//	// printf("\n\n>>>>>> Inserting %lu blocks ...\n\n", count);
//
//	uint32 n;
//	uint64 id;
//	uint64 t1 = GetTimeNow();
//	for (n=0; n<count; n++) {
//		strcpy(data, "Test");
//		utils::Int2Ascii(n, data+4, size-4, 10);
//		if (!manager->insertMemoryBlock(data, size, eol, id)) {
//			fprintf(stderr, "MemoryManager insert %d failed...\n", n);
//			delete [] ids;
//			delete [] data;
//			delete(manager);
//			return false;
//		}
//		ids[n] = id;
//	}
//	uint64 t2 = GetTimeNow();
//
//	uint32 size2 = 0;
//	uint64 eol2 = 0;
//	char* data2;
//
//	// printf("\n\n>>>>>> Getting %lu blocks ...\n\n", count);
//	for (n=0; n<count; n++) {
//		data2 = manager->getCopyMemoryBlock(ids[n], size2, eol2);
//		if (data2 == NULL) {
//			fprintf(stderr, "MemoryManager getcopy failed...\n");
//			delete [] ids;
//			delete [] data;
//			delete(manager);
//			return false;
//		}
//		if (size2 != size) {
//			fprintf(stderr, "MemoryManager getcopy got wrong size back...\n");
//			delete [] ids;
//			delete [] data;
//			delete [] data2;
//			delete(manager);
//			return false;
//		}
//		strcpy(data, "Test");
//		utils::Int2Ascii(n, data+4, size-4, 10);
//		if (strcmp(data2, data) != 0) {
//			fprintf(stderr, "MemoryManager getcopy got wrong data back...\n");
//			delete [] ids;
//			delete [] data;
//			delete [] data2;
//			delete(manager);
//			return false;
//		}
//		if (eol2 != eol) {
//			fprintf(stderr, "MemoryManager getcopy got wrong eol back (%llu != %llu) [%u]...\n", eol2, eol, n);
//			delete [] ids;
//			delete [] data;
//			delete [] data2;
//			delete(manager);
//			return false;
//		}
//		delete [] data2;
//	}
//	uint64 t3 = GetTimeNow();
//
//	printf("Performance:\n  Writing %u: %.3f MB/s / %.3f entries/s (%u us) [%u b]\n",
//		count, (1.0*size*count)/(t2-t1), (1000000.0*count)/(t2-t1), (uint32)(t2-t1), size);
//	printf("  Reading %u: %.3f MB/s / %.3f entries/s (%u us) [%u b]\n\n",
//		count, (1.0*size*count)/(t3-t2), (1000000.0*count)/(t3-t2), (uint32)(t3-t2), size);
//
//	delete [] ids;
//	delete [] data;
//	delete(manager);
//	fprintf(stdout, "*** Static Memory Management test ran successfully ***\n\n\n");
//
////	return true;
//
//	printf("Testing Dynamic Memory Management...\n\n");
//
//	manager = new MemoryManagerX();
//	// Initialise for 10 slots of 1 sec each, 0 buffer = 10 second max keep
//	// fprintf(stderr, "MemoryManager init() 0...\n");
//	if (!manager->create(0, 100, 10, 100000, 1)) {
//		fprintf(stderr, "MemoryManager init() failed...\n");
//		delete(manager);
//		return false;
//	}
//	// fprintf(stderr, "MemoryManager init() success...\n");
//
//	uint64 now = GetTimeNow();
//
//	uint32 total, usage, sysTotal, sysUsage, staticTotal, staticUsage, dynamicTotal, dynamicUsage;
//	if (GetMemoryUsage(total, usage, sysTotal, sysUsage, staticTotal, staticUsage, dynamicTotal, dynamicUsage))
//		printf("Dynamic Memory in use before test: %u (%u allocated))\n", dynamicUsage, dynamicTotal);
//
//	char* mem;
//	for (n=0; n<30; n++) {
//		mem = new char[1024];
//		if (!manager->insertMemoryBlock(mem, 1024, now+1000000, id)) {
//			fprintf(stderr, "MemoryManager insert memory failed...\n");
//			delete(manager);
//			return false;
//		}
//		delete [] mem;
//		if (GetMemoryUsage(total, usage, sysTotal, sysUsage, staticTotal, staticUsage, dynamicTotal, dynamicUsage))
//			printf("Dynamic Memory in use add %u: %u (%u allocated))\n", n, dynamicUsage, dynamicTotal);
//		utils::Sleep(100);
//		now = GetTimeNow();
//	}
//
//	for (n=0; n<20; n++) {
//		if (GetMemoryUsage(total, usage, sysTotal, sysUsage, staticTotal, staticUsage, dynamicTotal, dynamicUsage))
//			printf("Dynamic Memory in use idle %u: %u (%u allocated))\n", n, dynamicUsage, dynamicTotal);
//		utils::Sleep(100);
//	}
//
//
//	delete(manager);
//	fprintf(stdout, "*** Dynamic Memory Management test ran successfully ***\n\n\n");
//
//	return true;
//}

//#define SEGSIZE ((size_t)1024)
//
//int server() {
//
//  int shmFD;
//  void *shmAdd;
//  int i, useMode=1;   /* 1=use segment, not create it. */
//
//  /* We get "open" a shared memory segment with the given name.  The
//	 flags work just as they do with open: O_CREAT creates the segment
//	 if it doesn't exist, O_EXCL errors out if the segment already
//	 exists, and O_RDRW opens it for read and write.  The perms are as
//	 with chmod.  Normally, things opened with shm_open do now appear
//	 in the filesystem; however, it is best to specify a path to a
//	 file you can write to! */
//  shmFD = shm_open("foobar", O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
//  if(shmFD < 0) {
//	/* I have a case for all of the interesting cases, even the ones
//	   that can not happen in this situation... */
//	switch(errno) {
//	  case EACCES:       printf("shm_open failed: The requested permissions were denied or create denied .\n");
//		break;
//	  case EEXIST:       printf("shm_open failed: Object already exists and O_CREAT and O_EXCL were specified.\n");
//		useMode=1;
//		break;
//	  case EINTR:        printf("shm_open failed: The operation was interrupted by a signal.\n");
//		break;
//	  case EINVAL:       printf("shm_open failed: The operation is not supported.\n");
//		break;
//	  case EMFILE:       printf("shm_open failed: Too many file descriptors were already open.\n");
//		break;
//	  case ENAMETOOLONG: printf("shm_open failed: Name was too long (longer than SHM_NAME_MAX chars).\n");
//		break;
//	  case ENFILE:       printf("shm_open failed: The system file table is full.\n");
//		break;
//	  case ENOENT:       printf("shm_open failed: Object doesn't exist (O_CREAT was not specified).\n");
//		break;
//	  case ENOSPC:       printf("shm_open failed: No memory to create object (O_CREAT was specified).\n");
//		break;
//	  default:           printf("shm_open failed: Duno why...\n");
//		break;
//	} /* end switch */
//
//  exit(1);
//  } /* end if */
//
//
//	/* Use ftruncate() to size the region -- IMO an only semi-intuitive
//	   choice on the part of the POSIX committee. */
//	if(ftruncate(shmFD, SEGSIZE) < 0) {
//	  /* I have included all typically supported error cases below, even
//		 if they don't apply here. */
//	  switch(errno) {
//		case EBADF:  printf("ftruncate failed: The fd is not a valid descriptor.\n");
//		  break;
//		case EINVAL: printf("ftruncate failed: Not open for writing, or references a socket, not a file.\n");
//		  break;
//		default:     printf("ftruncate failed: Duno why...\n");
//		  break;
//	  } /* end switch */
//	  exit(1);
//	} /* end if */
//
//  shmAdd = (char *)mmap(NULL,                    // Almost always not used
//						SEGSIZE,                 // Length of the mapped space
//						PROT_READ | PROT_WRITE,  // Access type 
//						MAP_SHARED,              // Write changes to device (see: MAP_PRIVATE)
//						shmFD,                   // FD of the shared memory segment
//						0);                      // Offset into segment.
//
//  /* For more info on the strange return and possible error conditions
//	 of mmap(), see the mmap.c example program. */
//  if(shmAdd == MAP_FAILED) {
//	switch(errno) {
//	  case EACCES:    printf("mmap failed: The FD was not open for read, or for write with (PROT_WRITE or MAP_SHARED)\n");
//		break;
//	  case EAGAIN:    printf("mmap failed: The mapping could not be locked in memory\n");
//		break;
//	  case EBADF:     printf("mmap failed: The FD not a valid open file descriptor.\n");
//		break;
//	  case EINVAL:    printf("mmap failed: The value of len is zero, addr is not valid, bad combination of args\n");
//		break;
//	  case EMFILE:    printf("mmap failed: The too many regions mapped already\n");
//		break;
//	  case ENODEV:    printf("mmap failed: The FD file type is not supported by mmap().\n");
//		break;
//	  case ENOMEM:    printf("mmap failed: Not enough memory\n");
//		break;
//	  case ENOTSUP:   printf("mmap failed: Options not supported on this platform\n");
//		break;
//	  case ENXIO:     printf("mmap failed: Range [off,off+len) are invalid for the FD, MAP_FIXED & invalid addresses, or FD not accessible\n");
//		break;
//	  case EOVERFLOW: printf("mmap failed: File is too big!\n");
//		break;
//	  default:        printf("mmap failed: Duno why! (errno: %d)\n", errno);
//		break;
//	} /* end switch */
//	exit(1);
//  } /* end if */
//
//	/* We copy some stuff into the segment so that we can read it out later... */
//	printf("Write 'Hello' into the segment.\n");
//	strcpy((char*)shmAdd, "Hello");
//
//  return 0;
//} /* end func main() */
//
//
//int client() {
//  int shmFD;
//  void *shmAdd;
//  int i, useMode=0;   /* 1=use segment, not create it. */
//
//  /* If we failed before because the segment already existed, then we try to open it
//	 up and use it -- thus combining the "make" and "use" example programs. */
//	  shmFD = shm_open("foobar", O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);
//	  if(shmFD < 0) {
//		switch(errno) {
//		  case EACCES:       printf("shm_open failed: The requested permissions were denied or create denied .\n");
//			break;
//		  case EEXIST:       printf("shm_open failed: Object already exists and O_CREAT and O_EXCL were specified.\n");
//			useMode=1;
//			break;
//		  case EINTR:        printf("shm_open failed: The operation was interrupted by a signal.\n");
//			break;
//		  case EINVAL:       printf("shm_open failed: The operation is not supported.\n");
//			break;
//		  case EMFILE:       printf("shm_open failed: Too many file descriptors were already open.\n");
//			break;
//		  case ENAMETOOLONG: printf("shm_open failed: Name was too long (longer than SHM_NAME_MAX chars).\n");
//			break;
//		  case ENFILE:       printf("shm_open failed: The system file table is full.\n");
//			break;
//		  case ENOENT:       printf("shm_open failed: Object doesn't exist (O_CREAT was not specified).\n");
//			break;
//		  case ENOSPC:       printf("shm_open failed: No memory to create object (O_CREAT was specified).\n");
//			break;
//		  default:           printf("shm_open failed: Duno why...\n");
//			break;
//		} /* end switch */
//	  exit(1);
//	  } /* end if */
//
//  
//  shmAdd = (char *)mmap(NULL,                    // Almost always not used
//						SEGSIZE,                 // Length of the mapped space
//						PROT_READ | PROT_WRITE,  // Access type 
//						MAP_SHARED,              // Write changes to device (see: MAP_PRIVATE)
//						shmFD,                   // FD of the shared memory segment
//						0);                      // Offset into segment.
//
//  /* For more info on the strange return and possible error conditions
//	 of mmap(), see the mmap.c example program. */
//  if(shmAdd == MAP_FAILED) {
//	switch(errno) {
//	  case EACCES:    printf("mmap failed: The FD was not open for read, or for write with (PROT_WRITE or MAP_SHARED)\n");
//		break;
//	  case EAGAIN:    printf("mmap failed: The mapping could not be locked in memory\n");
//		break;
//	  case EBADF:     printf("mmap failed: The FD not a valid open file descriptor.\n");
//		break;
//	  case EINVAL:    printf("mmap failed: The value of len is zero, addr is not valid, bad combination of args\n");
//		break;
//	  case EMFILE:    printf("mmap failed: The too many regions mapped already\n");
//		break;
//	  case ENODEV:    printf("mmap failed: The FD file type is not supported by mmap().\n");
//		break;
//	  case ENOMEM:    printf("mmap failed: Not enough memory\n");
//		break;
//	  case ENOTSUP:   printf("mmap failed: Options not supported on this platform\n");
//		break;
//	  case ENXIO:     printf("mmap failed: Range [off,off+len) are invalid for the FD, MAP_FIXED & invalid addresses, or FD not accessible\n");
//		break;
//	  case EOVERFLOW: printf("mmap failed: File is too big!\n");
//		break;
//	  default:        printf("mmap failed: Duno why! (errno: %d)\n", errno);
//		break;
//	} /* end switch */
//	exit(1);
//  } /* end if */
//
//	/* The segment already existed, so we print out it's contents and change them. */
//	/* Just print the printable chars in case the segment has binary junk in it... */
//	printf("The segment content: \n");
//	for(i=0;(i<SEGSIZE)&&(((char *)shmAdd)[i]!=0);i++)
//	  if(isalpha(((char *)shmAdd)[i]) || isdigit(((char *)shmAdd)[i]))
//		printf("%c", ((char *)shmAdd)[i]);
//	printf("\n");
//
//	/* Now we change the data to "Goodbye" */
//	printf("Change the contents to: 'Goodbye'..\n");
//	strcpy((char*)shmAdd, "Goodbye");
//
//  /* While not required, one should unmap from segments when done with them. */
//  if(munmap(shmAdd, SEGSIZE) < 0) {
//	switch(errno) {
//	  case EINVAL:  printf("munmap failed: The address range [addr,addr+len) is invalid.\n"
//						   "               munmap failed: The len argument is 0.\n"
//						   "               munmap failed: The addr argument is not a multiple of page size.\n");
//		break;
//	  default:      printf("munmap failed: Duno why!  (errno %d).\n", errno);
//		break;
//	} /* end switch */
//	exit(1);
//  } /* end if */
//
//  /* One should also close FDs opened with shm_open (again, not
//	 necessarily required, but good practice). */
//  if(close(shmFD) < 0) {
//	switch(errno) {
//	  case EBADF:   printf("close failed: The FD is not an active descriptor.\n");
//		break;
//	  case EINTR:   printf("close failed: An interrupt was received.\n"); // Should try again... :)
//		break;
//	} /* end switch */
//  } /* end if */
//
//  return 0;
//} /* end func main() */

bool MemoryManager::ShmUnitTest() {

	// NOTE: the original shared-memory exercise (CreateSharedMemorySegment /
	// OpenSharedMemorySegment / server() / client()) is disabled in this build,
	// so this test is currently a smoke check that the entry point is callable.
	unittest::progress(10, "shared memory smoke check");

	//char *data = utils::CreateSharedMemorySegment("foobar", 1024);
	//if (!data)
	//	unittest::detail("Couldn't create test shared memory segment...");

	//char* data2 = utils::OpenSharedMemorySegment("foobar", 1024);
	//if (!data2)
	//	unittest::detail("Couldn't open test shared memory segment...");

	unittest::progress(100, "done");
	return true;

//	server();
//	client();
}


void Register_MemoryManager_Tests() {
	UnitTestRunner::instance().registerTest("memorymanager", MemoryManager::UnitTest,
		"Static memory management insert/read-back throughput", "memory");
	UnitTestRunner::instance().registerTest("sharedmemory", MemoryManager::ShmUnitTest,
		"Shared memory segment smoke check", "memory");
}


} // namespace cmlabs













