t_rc INXM_IndexHandle::CreateLastDataPage(STORM_PageHandle &pageHandle) {
	t_rc rc;
	int pageID;
	
	rc = this->sfh.ReservePage(pageHandle);
	if (rc != OK) { return rc; }
	
	rc = pageHandle.GetPageID(pageID);
	if (rc != OK) { return rc; }
	
	char *pageData;
	
	rc = pageHandle.GetDataPtr(&pageData);
	if (rc != OK) { return rc; }
	
	/* Write index init page header */
	INXM_InitPageHeader pageHeader = { 1, 0 };
	
	memcpy(pageData, &pageHeader, INXM_INITPAGEHEADER_SIZE);
	
	/* Update file header (new lastDataPage). */
	this->inxmFileHeader.lastDataPage = pageID;
	memcpy(this->pData_FileHeader, &this->inxmFileHeader, INXM_FILEHEADER_SIZE);
	
	rc = this->sfh.FlushPage(this->pageNum_FileHeader);
	if (rc != OK) { return rc; }
	
	return(OK);
}
t_rc INXM_IndexHandle::CreateNodePage(STORM_PageHandle &pageHandle, int &pageID, int parent, int next, int previous, bool isLeaf) {
	t_rc rc;
	
	rc = this->sfh.ReservePage(pageHandle);
	if (rc != OK) { return rc; }
	
	rc = pageHandle.GetPageID(pageID);
	if (rc != OK) { return rc; }
	
	char *pageData;
	
	rc = pageHandle.GetDataPtr(&pageData);
	if (rc != OK) { return rc; }
	
	/* Write index init page header */
	INXM_InitPageHeader pageHeader = { 0, 0 };
	
	memcpy(pageData, &pageHeader, INXM_INITPAGEHEADER_SIZE);
	
	/* Write index node page header */
	INXM_NodePageHeader nPageHeader = { isLeaf, parent, next, previous };
	
	memcpy(&pageData[INXM_INITPAGEHEADER_SIZE], &nPageHeader, INXM_NODEPAGEHEADER_SIZE);
	
	return(OK);
}
/* We have a const problem with the method. We call GetPage from STORM which is not const!!! */
t_rc REM_RecordFileHandle::ReadRecord(const REM_RecordID &rid, REM_RecordHandle &rh)	{
    /* Check is file is open. */
    if (!this->isOpen) {
        return REM_FHCLOSED;
    }
    t_rc rc;

    /* Get pageID and slot number to find the record. */
    int pageID, slot;

    rc = rid.GetPageID(pageID);
    if (rc != OK) {
        return rc;
    }

    rc = rid.GetSlot(slot);
    if (rc != OK) {
        return rc;
    }

    /* Get the STORM page that contains the record we need. */
    STORM_PageHandle pageHandle;

    rc = this->sfh.GetPage(pageID, pageHandle);
    if (rc != OK) {
        return rc;
    }

    /* Check if REM Record Handler has data. If it doesn't, allocate the needed space. */
    if (rh.pData == NULL) {
        rh.pData = new char[this->remFileHeader.recordSize];
    }
    else {
        delete rh.pData;
        rh.pData = new char[this->remFileHeader.recordSize];
    }

    char *pData;
    REM_PageHeader pageHeader;

    pageHandle.GetDataPtr(&pData);

    /* Check if slot number is not correct. */
    memcpy(&pageHeader, pData, REM_PAGEHEADER_SIZE);
    if (slot > pageHeader.nRecords) {
        return REM_INVALIDRID;
    }

    /* Find the record we want and copy the data to the record handler.  */
    memcpy(rh.pData, &pData[REM_PAGEHEADER_SIZE+((slot-1)*this->remFileHeader.recordSize)], this->remFileHeader.recordSize);

    /* Add the recordID to the record handler. */
    rh.rid = rid;

    /* Make Record Handler valid. */
    rh.isValid = true;

    return (OK);
}
t_rc REM_RecordFileHandle::UpdateRecord(const REM_RecordHandle &rh)	{
    /* Check is file is open. */
    if (!this->isOpen) {
        return REM_FHCLOSED;
    }
    t_rc rc;

    /* Exctract RID and get pageID and slot numbers. */
    REM_RecordID rid;
    int pageID, slot;

    rc = rh.GetRecordID(rid);
    if (rc != OK) {
        return rc;
    }

    rc = rid.GetPageID(pageID);
    if (rc != OK) {
        return rc;
    }
    rc = rid.GetSlot(slot);
    if (rc != OK) {
        return rc;
    }

    /* Get the record and a pointer to the data inside. */
    STORM_PageHandle pageHandle;
    char *pData;

    rc = this->sfh.GetPage(pageID, pageHandle);
    if (rc != OK) {
        return rc;
    }

    rc = pageHandle.GetDataPtr(&pData);
    if (rc != OK) {
        return rc;
    }

    /* Copy the new data. */
    memcpy(&pData[REM_PAGEHEADER_SIZE+((slot-1)*this->remFileHeader.recordSize)], rh.pData, this->remFileHeader.recordSize);

    /* Mark the page as dirty because we modified it */
    rc = this->sfh.MarkPageDirty(pageID);
    if (rc != OK) {
        return rc;
    }
    /* Unpin the page */
    rc = this->sfh.UnpinPage(pageID);
    if (rc != OK) {
        return rc;
    }

    return (OK);
}
// Δημιουργία νέου κόμβου/ρίζα
t_rc INXM_IndexHandle::makeRoot(void *pData, const REM_RecordID &rid){
	t_rc rc;
	int pageID;
	STORM_PageHandle myPageHandle;


	// Δέσμευση σελίδας
	rc = this->fh.ReservePage(myPageHandle);
	if (rc != OK) return rc;
	
	rc = this->fh.GetNextPage(this->fileHeaderPageID, myPageHandle);
	if (rc != OK) return rc;

	rc = myPageHandle.GetPageID(pageID);
	if (rc != OK) { return rc; }
	
	char* rData;
	rc = myPageHandle.GetDataPtr(&rData);
	if (rc != OK) { return rc; }

	this->fileHeader.rootPage = pageID;

	// Δημιουργία header για τη σελίδα
	// Κάθε σελίδα είναι και node
	NodeHeader nh;
	nh.numberOfItems = 1;
	for (int i = 0; i < 1200; i++)
		nh.sStatus.set(i,false);
	nh.sStatus.set(0, true);
	nh.left = -1;
	nh.right = -1;
	nh.parent = -1;
	nh.leaf = true;	

	LeafItem item = { pData, rid };
	// Εγγραφή του αντικειμένου
	memcpy(&rData[sizeof(NodeHeader)], this->getLeafItemData(item), this->getLeafItemSize());
	this->fileHeader.numberOfNodes++;
	this->fileHeader.numberOfLeafNodes++;

	// Εγγραφή του nodeheader
	memcpy(&rData[0], &nh, sizeof(NodeHeader));

	rc = this->fh.MarkPageDirty(pageID);
	if (rc != OK) return rc;

	rc = this->fh.FlushPage(pageID);
	if (rc != OK) return rc;

	rc = this->fh.UnpinPage(pageID);
	if (rc != OK) return rc;

	return(OK);
}
t_rc INXM_IndexHandle::InsertEntry(void *pData, const REM_RecordID &rid){
	t_rc rc;
	STORM_PageHandle pageHandle;	
	/* 
	 * Έλεγχος αν υπάρχει δέντρο
	 * Δημιουργία νέου δέντρου/ρίζας
	 */	
	if( this->isOpen && this->fileHeader.numberOfNodes == 0 ){
		makeRoot(pData, rid);
		return(OK);
	}

	/*
	 * Υπάρχει ήδη δέντρο
	 */

	// Αναζήτηση για την εύρεση της ΣΩΣΤΗΣ σελίδας/φύλλου όπου θα μπεί ή νέα εγγραφή
	int rightPageID = searchRightPage( fileHeader.rootPage , pData);
	
	// Διαβάζω τον header αυτής της σελίδας
	
	char* data;

	rc = fh.GetPage(rightPageID, pageHandle);
	if (rc != OK) return rc;

	rc = pageHandle.GetDataPtr(&data);
	if (rc != OK) return rc;

	NodeHeader rightPageHeader;
	memcpy(&rightPageHeader, &data[0], sizeof(NodeHeader));

	// Έλεγχος αν η σελίδα έχει χώρο
	bool freeSpace = checkLeafNodeForSpace(rightPageHeader);

	if(freeSpace){		// περίπτωση που η σελίδα έχει χώρο

		insert(rightPageID, pData, rid);
		return (OK);

	} else {			// περίπτωση που η σελίδα ΔΕΝ έχει χώρο

		rc = splitLeafNode(rightPageID);
		if (rc != OK) return rc;

		int pageAfterSplitID = searchRightPage( fileHeader.rootPage , pData);
		insert(pageAfterSplitID, pData, rid);
		return (OK);

	}
}
//-----------------------------------------------------------------------------------------------
// GetPage
//
// Updates the page handle with the page with the given pageID
//-----------------------------------------------------------------------------------------------
t_rc STORM_FileHandle::GetPage(int pageID, STORM_PageHandle &pageHandle)
{
	STORM_Frame *pFrame;
	t_rc rc;

	if (!m_isOpened)
		return (STORM_FILENOTOPENED);

	// Check if page is not valid.
	if (pageID < 1)
		return (STORM_INVALIDPAGE);
		
	if (pageID > m_fileSubHeader.numAllocatedPages)
		return (STORM_INVALIDPAGE); 
		
	if (!IsPageReserved(pageID)) 
		return (STORM_INVALIDPAGE);

	rc = m_pBfrMgr->NeedPage(m_fileID, pageID, &pFrame);
	if (rc != OK) return (rc);

	rc = pageHandle.Open(pFrame);
	m_filePos = pageID;

	return (rc);
}
//-----------------------------------------------------------------------------------------------
// ReservePage
//
// Reserves a new page for the file.
//-----------------------------------------------------------------------------------------------
t_rc STORM_FileHandle::ReservePage(STORM_PageHandle &pageHandle)
{
	if (!m_isOpened)
		return (STORM_FILENOTOPENED);

	t_rc rc;
	int newPageID = INVALID_PAGEID; 

	for (int pageCounter=1; pageCounter<=MAX_PAGES_PER_FILE; pageCounter++)
	{
		if (!IsPageReserved(pageCounter))
		{
			newPageID = pageCounter;
			break;
		}
	}

	STORM_Frame *pFrame;

	if (newPageID == INVALID_PAGEID)  // all pages are reserved
	{
		if (m_fileSubHeader.numAllocatedPages == MAX_PAGES_PER_FILE)
			return STORM_FILELIMITREACHED;

		// Reserve frame in buffer.
		rc = m_pBfrMgr->ReserveFrame(m_fileID, newPageID, &pFrame);
		if (rc != OK) return (rc);
		m_fileSubHeader.numAllocatedPages++;
		m_fileSubHeader.numReservedPages++;
		UpdateHeaderFrame();

		rc = m_pBfrMgr->WritePage(pFrame);
		if (rc != OK) return (rc);
	}
	else  // a free page has been found
	{
		// Reserve frame in buffer.
		rc = m_pBfrMgr->ReserveFrame(m_fileID, newPageID, &pFrame);
		if (rc != OK) return (rc);
		m_fileSubHeader.numReservedPages++;
		UpdateHeaderFrame();

		if (newPageID > m_fileSubHeader.numAllocatedPages)
		{
			rc = m_pBfrMgr->WritePage(pFrame);
			if (rc != OK) return (rc);
			m_fileSubHeader.numAllocatedPages++;
			UpdateHeaderFrame();
		}
	}

	SetPageReservationFlag(newPageID, true);  // page is reserved now

	rc = pageHandle.Open(pFrame);
	if (rc != OK) return (rc);

	return (OK);
}
t_rc INXM_IndexHandle::WriteData(STORM_PageHandle pageHandle, const REM_RecordID &rid, int &slot) {
	t_rc rc;
	
	INXM_Data *inxmData = new INXM_Data();
	
	rid.GetPageID(inxmData->pageID);
	rid.GetSlot(inxmData->slot);
	
	char *leafPageData;
	
	rc = pageHandle.GetDataPtr(&leafPageData);
	if (rc != OK) { return rc; }
	
	/* Read leaf header. */
	INXM_InitPageHeader pageHeader;
	
	memcpy(&pageHeader, leafPageData, INXM_INITPAGEHEADER_SIZE);
	
	/* Write data to correct place. */
	memcpy(&leafPageData[INXM_INITPAGEHEADER_SIZE+pageHeader.nItems*INXM_DATA_SIZE], inxmData, INXM_DATA_SIZE);
	
	/* Update page header. */
	slot = pageHeader.nItems;
	pageHeader.nItems++;
	
	memcpy(leafPageData, &pageHeader, INXM_INITPAGEHEADER_SIZE);
	
	int pageID;
	rc = pageHandle.GetPageID(pageID);
	if (rc != OK) { return rc; }
	
	/* Mark the page as dirty because we modified it */
	rc = this->sfh.MarkPageDirty(pageID);
	if (rc != OK) { return rc; }
	
	rc = this->sfh.FlushPage(pageID);
	if (rc != OK) { return rc; }
	
	/* Unpin the page */
	rc = this->sfh.UnpinPage (pageID);
	if (rc != OK) { return rc; }
	
	return(OK);
}
t_rc INXM_IndexHandle::WriteNode(STORM_PageHandle pageHandle, int insertPoint, void *key, int left, int slot) {
	t_rc rc;
	INXM_Node *node = new INXM_Node();
	
	node->left = left;
	node->slot = slot;
	
	char *nodePageData;
	
	rc = pageHandle.GetDataPtr(&nodePageData);
	if (rc != OK) { return rc; }
	
	/* Write data to correct place. */
	memcpy(&nodePageData[INXM_INITPAGEHEADER_SIZE+INXM_NODEPAGEHEADER_SIZE+insertPoint*(INXM_NODE_SIZE+this->inxmFileHeader.attrLength)], node, INXM_NODE_SIZE);
	memcpy(&nodePageData[INXM_INITPAGEHEADER_SIZE+INXM_NODEPAGEHEADER_SIZE+insertPoint*(INXM_NODE_SIZE+this->inxmFileHeader.attrLength)+INXM_NODE_SIZE], key, this->inxmFileHeader.attrLength);
	
	/* Update page header. */
	INXM_InitPageHeader pageHeader;
	
	rc = LoadInitHeaders(pageHandle, pageHeader);
	if (rc != OK) { return rc; }
	
	pageHeader.nItems++;
	
	memcpy(nodePageData, &pageHeader, INXM_INITPAGEHEADER_SIZE);
	
	int pageID;
	rc = pageHandle.GetPageID(pageID);
	if (rc != OK) { return rc; }
	
	/* Mark the page as dirty because we modified it */
	rc = this->sfh.MarkPageDirty(pageID);
	if (rc != OK) { return rc; }
	
	rc = this->sfh.FlushPage(pageID);
	if (rc != OK) { return rc; }
	
	/* Unpin the page */
	rc = this->sfh.UnpinPage (pageID);
	if (rc != OK) { return rc; }
	
	return(OK);
}
// Επιστρέφει το id της σελίδας που θα πρέπει να γίνει η
// εισαγωγή του νέου στοιχείου
int INXM_IndexHandle::searchRightPage(int pageID, void* key){

	STORM_PageHandle pageHandle;
	char* data;

	// Διαβάζουμε τον header της σελίδας
	fh.GetPage(pageID, pageHandle);	
	pageHandle.GetDataPtr(&data);

	NodeHeader currentHeader;
	memcpy(&currentHeader, &data[0], sizeof(NodeHeader));

	if( currentHeader.leaf == true ){
		// ο κόμβος που μόλις διάβασα είναι φύλλο, τελειώνει η αναζήτηση
		return pageID;
	} else {
		// ο κόμβος που μόλις διάβασα είναι ενδιάμεσος, ελέγχω τις τιμές
		
		for(int i = 0; i < currentHeader.numberOfItems; i++){	
			InterItem currentItem, nextItem;
			char* currentData = new char[this->getInterItemSize()];

			memcpy(currentData, &data[sizeof(NodeHeader)+i*this->getInterItemSize()], this->getInterItemSize());
			currentItem = this->getInterItemStruct(currentData);

			memcpy(currentData, &data[sizeof(NodeHeader)+(i+1)*this->getInterItemSize()], this->getInterItemSize());
			nextItem = this->getInterItemStruct(currentData);

			if(keyCompare(key, currentItem.key) < 0 ){
				// akoloutha aristero paidi
				searchRightPage(currentItem.leftChild, key);
			} else if ( (keyCompare(key, currentItem.key) > 0) && ((keyCompare(key, nextItem.key) == 0) || (keyCompare(key, nextItem.key) < 0))) {
				// akoloutha aristero paidi
				searchRightPage(nextItem.leftChild, key);
			} else if ((keyCompare(key, currentItem.key) > 0) || (keyCompare(key, currentItem.key) == 0)){
				//akoloutha deksi paidi
				searchRightPage(currentItem.leftChild, key);
			}

		}		
	}
}
t_rc INXM_IndexHandle::EditNode(STORM_PageHandle pageHandle, int slot, INXM_Node node) {
	t_rc rc;
	
	char *dataPageData;
	
	rc = pageHandle.GetDataPtr(&dataPageData);
	if (rc != OK) { return rc; }
	
	memcpy(&dataPageData[INXM_INITPAGEHEADER_SIZE+INXM_NODEPAGEHEADER_SIZE+(slot*(INXM_NODE_SIZE+this->inxmFileHeader.attrLength))], &node, INXM_NODE_SIZE+this->inxmFileHeader.attrLength);
	
	return(OK);
}
t_rc INXM_IndexHandle::EditData(STORM_PageHandle pageHandle, int slot, INXM_Data data) {
	t_rc rc;
	
	char *dataPageData;
	
	rc = pageHandle.GetDataPtr(&dataPageData);
	if (rc != OK) { return rc; }
	
	memcpy(&dataPageData[INXM_INITPAGEHEADER_SIZE+(slot*INXM_DATA_SIZE)], &data, INXM_DATA_SIZE);
	
	return(OK);
}
t_rc INXM_IndexHandle::LoadInitHeaders(STORM_PageHandle pageHandle, INXM_InitPageHeader &initPageHeader) {
	t_rc rc;
	
	/* Read headers. */
	char *nodePage;
	
	rc = pageHandle.GetDataPtr(&nodePage);
	if (rc != OK) { return rc; }
	
	/* init page header. */	
	memcpy(&initPageHeader, nodePage, INXM_INITPAGEHEADER_SIZE);
	
	return(OK);
}
t_rc INXM_IndexHandle::ReadData(STORM_PageHandle pageHandle, int slot, INXM_Data &data) {
	t_rc rc;
	
	/* Read headers. */
	char *dataPage;
	
	rc = pageHandle.GetDataPtr(&dataPage);
	if (rc != OK) { return rc; }
	
	/* Read data. */
	memcpy(&data, &dataPage[INXM_INITPAGEHEADER_SIZE+slot*INXM_DATA_SIZE], INXM_DATA_SIZE);
		
	return(OK);
}
t_rc INXM_IndexHandle::InsertIntoLeaf(STORM_PageHandle leafPageHandle, void *key, const REM_RecordID &rid) {
	t_rc rc;
	/* Find correct point for the new key. */
	INXM_InitPageHeader initPageHeader;
	
	LoadInitHeaders(leafPageHandle, initPageHeader);
	
	INXM_Node node;
	int insertPoint = 0;

	rc = ReadNode(leafPageHandle, insertPoint, node);
	if (rc != OK) { return rc; }
	
	while (insertPoint < initPageHeader.nItems && KeyCmp(node.key, key) < 0) {
		insertPoint++;
		
		rc = ReadNode(leafPageHandle, insertPoint, node);
		if (rc != OK) { return rc; }
	}
		
	/* Open needed space at correct point. */
	
	int point = INXM_INITPAGEHEADER_SIZE + INXM_NODEPAGEHEADER_SIZE + insertPoint*(INXM_NODE_SIZE+this->inxmFileHeader.attrLength);
	
	char *leafData;
	
	rc = leafPageHandle.GetDataPtr(&leafData);
	if (rc != OK) { return rc; }
	
	memcpy(&leafData[point + INXM_NODE_SIZE+this->inxmFileHeader.attrLength],
		   &leafData[point],
		   (initPageHeader.nItems-insertPoint)*(INXM_NODE_SIZE+this->inxmFileHeader.attrLength));
	
	/* Write new data. */
	int slot;
	STORM_PageHandle lastDataPageHandle;

	rc = this->sfh.GetPage(this->inxmFileHeader.lastDataPage, lastDataPageHandle);
	if (rc != OK) { return rc; }
	
 	rc = WriteData(lastDataPageHandle, rid, slot);
	if (rc != OK) { return rc; }
	
	/* Write new node. */
	rc = WriteNode(leafPageHandle, insertPoint, key, this->inxmFileHeader.lastDataPage, slot);
	if (rc != OK) { return rc; }
	
	return(OK);
}
t_rc INXM_IndexManager::OpenIndex(const char *fname, int indexNo, INXM_IndexHandle &ih) {
	/* Close index file handler if it's already open */
	if (ih.isOpen) {
		CloseIndex(ih);
	}
	
	char buffer[128];
	snprintf(buffer, sizeof(buffer), "%s.%d", fname, indexNo);
	/* Open file with STORM and assign a STORM File Handler to INXM Handler given in arguments */
	t_rc rc = this->sm->OpenFile(buffer, ih.sfh);
	if (rc != OK) { return rc; }
	
	
	/* Use the STORM File Handler from INXM Handler given in arguments to get the first page. */
	STORM_PageHandle pageHandle;
	
	rc = ih.sfh.GetFirstPage(pageHandle);
	if (rc != OK) { return rc; }
	
	/* Get data from first page. Those first data are the INXM File Header. */
	rc = pageHandle.GetDataPtr(&ih.pData_FileHeader);
	if (rc != OK) { return rc; }
	
	rc = pageHandle.GetPageID(ih.pageNum_FileHeader);
	if (rc != OK) { return rc; }
	
	/* We keep File Header as a seperated copy inside the INXM Handler. 
	 * Using just a pointer in a sequence of dytes would be difficult.
	 */
	memcpy(&ih.inxmFileHeader, &ih.pData_FileHeader[0], INXM_FILEHEADER_SIZE);
		
	/* Successfully opened a record file handler */ 
	ih.isOpen = true;
	
	return(OK);
}
//-----------------------------------------------------------------------------------------------
// GetFirstPage
//
// Updates the page handle with the first reserved page of the file.
//-----------------------------------------------------------------------------------------------
t_rc STORM_FileHandle::GetFirstPage(STORM_PageHandle &pageHandle) 
{
	t_rc rc;

	if (!m_isOpened)
		return (STORM_FILENOTOPENED);

	rc = GetNextPage(0, pageHandle);
	if (rc != OK) return (rc);

	int curPageID;

	pageHandle.GetPageID(curPageID);
	m_filePos = curPageID;

	return (OK);
}
t_rc INXM_IndexHandle::UpdateNodeHeaders(STORM_PageHandle pageHandle, INXM_InitPageHeader initPageHeader, INXM_NodePageHeader nodePageHeader) {
	t_rc rc;
	
	/* Get page data pointer. */
	char *nodePage;
	
	rc = pageHandle.GetDataPtr(&nodePage);
	if (rc != OK) { return rc; }
	
	/* init page header. */	
	memcpy(nodePage, &initPageHeader, INXM_INITPAGEHEADER_SIZE);
	
	/* node page header. */	
	memcpy(&nodePage[INXM_INITPAGEHEADER_SIZE], &nodePageHeader, INXM_NODEPAGEHEADER_SIZE);
	return(OK);
	
}
t_rc INXM_IndexHandle::ReadNode(STORM_PageHandle pageHandle, int slot, INXM_Node &node) {
	t_rc rc;
	
	/* Read headers. */
	char *nodePage;
	
	rc = pageHandle.GetDataPtr(&nodePage);
	if (rc != OK) { return rc; }
	
	/* Read node. */
	memcpy(&node, &nodePage[INXM_INITPAGEHEADER_SIZE+INXM_NODEPAGEHEADER_SIZE+slot*(INXM_NODE_SIZE+this->inxmFileHeader.attrLength)], INXM_NODE_SIZE);
	
	/* Read key. */
	void *key = malloc(this->inxmFileHeader.attrLength);
	
	memcpy(key, &nodePage[INXM_INITPAGEHEADER_SIZE+INXM_NODEPAGEHEADER_SIZE+slot*(INXM_NODE_SIZE+this->inxmFileHeader.attrLength)+INXM_NODE_SIZE], this->inxmFileHeader.attrLength);
	
	/* Update key pointer. */
	node.key = key;
	
	return(OK);
}
t_rc INXM_IndexHandle::insert(int rightPageID, void* key, const REM_RecordID &rid){
	t_rc rc;

	// Δημιουργία leaf item
	LeafItem newItem;
	newItem.key = key;
	newItem.rid = rid;

	// Διαβάζω τον header και τα δεδομένα της σελίδας ( rightPage )
	STORM_PageHandle pageHandle;
	char* hData;

	rc = fh.GetPage(rightPageID, pageHandle);
	if (rc != OK) return rc;

	rc = pageHandle.GetDataPtr(&hData);
	if (rc != OK) return rc;

	NodeHeader rightPageHeader;
	memcpy(&rightPageHeader, &hData[0], sizeof(NodeHeader));


	bool posFound = false;
	LeafItem tempItem1 = newItem;
	LeafItem tempItem2;
	int i;
	for (i = 0; i < rightPageHeader.numberOfItems; i++) {

		// Διαβάζω ένα ένα τα αντικείμενα της σελίδας
		char* currentData = new char[this->getLeafItemSize()];
		memcpy(currentData, &hData[sizeof(NodeHeader) + i*this->getLeafItemSize()], this->getLeafItemSize());

		LeafItem currentItem;
		currentItem = this->getLeafItemStruct(currentData);

		if (keyCompare(newItem.key, currentItem.key) < 0 ) posFound = true;

		// Βρέθηκε η σωστή θέση μετακίνηση όλων των δεξίων item
		// μία θέση δεξιά
		if (posFound) {
			tempItem2 = currentItem;
			currentItem = tempItem1;
			tempItem1 = tempItem2;
			 
			int j = rightPageHeader.numberOfItems ;
			rightPageHeader.sStatus.set(j,true);
			while( j != i ){
				char* myCurrentData = new char[this->getLeafItemSize()];
				memcpy(myCurrentData, &hData[sizeof(NodeHeader) + (j-1)*this->getLeafItemSize()], this->getLeafItemSize());

				LeafItem myCurrentItem;
				myCurrentItem = this->getLeafItemStruct(myCurrentData);

				memcpy(&hData[sizeof(NodeHeader) + j*this->getLeafItemSize()], this->getLeafItemData(myCurrentItem), this->getLeafItemSize());
				j--;
			}
			memcpy(&hData[sizeof(NodeHeader) + i*this->getLeafItemSize()], this->getLeafItemData(currentItem), this->getLeafItemSize());
			break;
		}
	}

	if (!posFound){
		memcpy(&hData[sizeof(NodeHeader) + i*this->getLeafItemSize()], this->getLeafItemData(newItem),this->getLeafItemSize());
		rightPageHeader.sStatus.set(i,true);
	}
	
	rightPageHeader.numberOfItems++;

	// Εγγραφή του header
	memcpy(&hData[0], &rightPageHeader, sizeof(NodeHeader));

	rc = this->fh.MarkPageDirty(rightPageID);
	if (rc != OK) return rc;

	rc = this->fh.FlushPage(rightPageID);
	if (rc != OK) return rc;

	rc = this->fh.UnpinPage(rightPageID);
	if (rc != OK) return rc;

	return (OK);
}
t_rc INXM_IndexHandle::InsertIntoParent(int rootID, STORM_PageHandle leftPage, INXM_Node &keyNode, STORM_PageHandle rightPage) {
	t_rc rc;
	INXM_InitPageHeader leftInitPageHeader;
	INXM_NodePageHeader leftNodePageHeader;
	LoadNodeHeaders(leftPage, leftInitPageHeader, leftNodePageHeader);
	
	/* Case: new root. */
	if (leftNodePageHeader.parent == 0) {
		int rightPageID;
		rc = rightPage.GetPageID(rightPageID);
		if (rc != OK) { return rc; }
		
		STORM_PageHandle newRootPageHandle;
		CreateNodePage(newRootPageHandle, this->inxmFileHeader.treeRoot, 0, rightPageID, 0, 0);
		
		int leftPageID;
		rc = leftPage.GetPageID(leftPageID);
		if (rc != OK) { return rc; }
		
		rc = WriteNode(newRootPageHandle, keyNode.key, leftPageID, 0);
		if (rc != OK) { return rc; }
		
		/* Update inxm file header. */
		memcpy(this->pData_FileHeader, &this->inxmFileHeader, INXM_FILEHEADER_SIZE);
		
		rc = this->sfh.FlushPage(this->pageNum_FileHeader);
		if (rc != OK) { return rc; }
		
		/* Write all. */
		rc = this->sfh.FlushAllPages();
		if (rc != OK) { return rc; }
		
		return(OK);
	}
		
	/* Case: leaf or node. (Remainder of
	 * function body.)  
	 */
	
	/* Find the parent's node index to the left 
	 * page.
	 */
	
	int leftPageID;
	rc = leftPage.GetPageID(leftPageID);
	if (rc != OK) { return rc; }
	
	int rightPageID;
	rc = rightPage.GetPageID(rightPageID);
	if (rc != OK) { return rc; }
	
	int left_index = 0;
	INXM_Node node;
	INXM_InitPageHeader parentInitPageHeader;
	INXM_NodePageHeader parentNodePageHeader;
	LoadNodeHeaders(leftNodePageHeader.parent, parentInitPageHeader, parentNodePageHeader);
	
	while (left_index < parentInitPageHeader.nItems) {
		ReadNode(leftNodePageHeader.parent, left_index, node);
		if (node.left == leftPageID) {
			break;
		}
		left_index++;
	}
	
	/* Simple case: the new key fits into the page. */
	STORM_PageHandle parentPageHandle;
	
	rc = this->sfh.GetPage(leftNodePageHeader.parent, parentPageHandle);
	if (rc != OK) { return rc; }
	
	if (LeafHasRoom(parentPageHandle)) {
		return InsertIntoNoLeaf(parentPageHandle, left_index, keyNode.key, rightPageID);
	}
	
	/* Harder case:  split a not leaf page, in order 
	 * to preserve the B+ tree properties.
	 */
	
//	return insert_into_node_after_splitting(root, parent, left_index, key, right);
	
	return(OK);
}
// Διαχωρισμός ΕΝΔΙΑΜΕΣΟΥ κόμβου ο οποίος έχει γεμίσει
// Χρειάζομαι μόνο το id της σελίδας του κόμβου
t_rc INXM_IndexHandle::splitInterNode(int pageToSplitID){
	t_rc rc;
	
	// Διαβάζω τον Inter Node Header της σελίδας
	STORM_PageHandle pageHandle;
	char* data;

	rc = fh.GetPage(pageToSplitID, pageHandle);
	if (rc != OK) return rc;

	rc = pageHandle.GetDataPtr(&data);
	if (rc != OK) return rc;

	NodeHeader nh;		// o header της σελίδας πρός διάσπαση
	memcpy(&nh, &data[0], sizeof(NodeHeader));

	// Δημιουργία ΝΕΟΥ inter node
	// Δέσμευση σελίδας
	this->fh.ReservePage(pageHandle);
	if (rc != OK) return rc;

	int newInterPageID;
	rc = pageHandle.GetPageID(newInterPageID);
	if (rc != OK) { return rc; }
	
	char* newInterData;
	rc = pageHandle.GetDataPtr(&newInterData);
	if (rc != OK) { return rc; }
	
	// Αρχικοποίηση του νέου inter node header
	NodeHeader nhNew;
	nhNew.leaf = false;
	nhNew.parent = nh.parent;
	nhNew.right = -1;
	nhNew.left = -1;
	for (int i = 0; i < 1200; i++)
		nhNew.sStatus.set(i,false);

	// Μετακίνηση των μισών αντικειμένων από τον γεμάτο κόμβο
	// στον καινούριο
	for (int i = nh.numberOfItems/2; i < nh.numberOfItems; i++) {
		memcpy(
			&newInterData[sizeof(NodeHeader)+(i-nh.numberOfItems/2)*this->getInterItemSize()],
			&data[sizeof(NodeHeader)+i*this->getInterItemSize()],
			this->getInterItemSize());
		
		// Μείωση πλήθους αντικειμένων στον έναν κόμβο
		nh.numberOfItems--;
		nh.sStatus.set(i, false);

		// Αύξηση πλήθους αντικειμένων στον άλλο κόμβο
		nhNew.numberOfItems++;
		nhNew.sStatus.set(i-nh.numberOfItems/2, true);
	}

	

	// Δημιουργία του ΠΑΤΕΡΑ ενδιάμεσου κόμβου
	// Δημιουργία του header
	NodeHeader nhParent;

	// Διαβάζω το ΠΡΩΤΟ item από το νέο ενδιάμεσο κόμβο που μόλις δημιούργησα
	char* firstItemData = new char[this->getInterItemSize()];
	memcpy(&firstItemData, &newInterData[sizeof(NodeHeader)], this->getInterItemSize());

	InterItem firstLeftItem = this->getInterItemStruct(firstItemData);

	// Δεικτόδοτηση του item που θα μπεί στον κόμβο πατέρα
	InterItem iItemNew;
	iItemNew.key = firstLeftItem.key;
	iItemNew.rightChild = newInterPageID;
	iItemNew.leftChild = pageToSplitID;

	if ( nh.parent > 0) {		// Περίπτωση που ο προς διάσπαση κόμβος έχει πατέρα, δλδ δεν είναι ρίζα
		int parentPageID = nh.parent;
		char* parentData;

		rc = fh.GetPage(parentPageID, pageHandle);
		if (rc != OK) return rc;

		rc = pageHandle.GetDataPtr(&parentData);
		if (rc != OK) return rc;

		memcpy(&nhParent, &parentData[0], sizeof(NodeHeader));

		if(checkInterNodeForSpace(nhParent)){		// περίπτωση που ο πατέρας έχει χώρο
			bool posFound = false;
			InterItem tempItem1 = iItemNew;
			InterItem tempItem2;
			int i;

			// Αντιγραφή του πρώτου item του δεξίου παιδιού
			// στον πατέρα
			for (i = 0; i < nhParent.numberOfItems+1; i++) {
				
				char* currentData = new char[this->getInterItemSize()];
				InterItem currentItem;

				memcpy(currentData, &parentData[sizeof(NodeHeader)+i*this->getInterItemSize()], this->getInterItemSize());
				currentItem = this->getInterItemStruct(currentData);

				if (keyCompare(iItemNew.key, currentItem.key) < 0 ) posFound = true;

				// Βρέθηκε η σωστή θέση μετακίνηση όλων των δεξίων item
				// μία θέση δεξιά
				if (posFound) {
					tempItem2 = currentItem;
					currentItem = tempItem1;
					tempItem1 = tempItem2;

					memcpy(&parentData[sizeof(NodeHeader)+i*this->getInterItemSize()],this->getInterItemData(currentItem),this->getInterItemSize());
				}
			}

			nhParent.numberOfItems++;
			nhParent.sStatus.set(i-1,true);

		} else {	// περίπτωση που ο πατέρας δεν έχει χώρο
			// **
			// Anadromika splitInterNode(parentPageID); 
			// **
		}

	} else {		// Περίπτωση που ο προς διάσπαση κόμβος ΔΕΝ έχει πατέρα, δλδ είναι ρίζα
		// Δημιουργία inter node
		// Δέσμευση σελίδας
		this->fh.ReservePage(pageHandle);
		if (rc != OK) return rc;

		int interPageID;
		rc = pageHandle.GetPageID(interPageID);
		if (rc != OK) { return rc; }
	
		char* interData;
		rc = pageHandle.GetDataPtr(&interData);
		if (rc != OK) { return rc; }

		nh.parent = interPageID;
		nhNew.parent = interPageID;
		for (int i = 0; i < 1200; i++)
			nhParent.sStatus.set(i,false);
		
		nhParent.parent = -1;
		nhParent.leaf = false;
		nhParent.sStatus.set(0,true);
		nhParent.numberOfItems++;
		nhParent.left = -1;
		nhParent.right = -1;

		// Εγγραφή του interItem
		memcpy(&interData[sizeof(NodeHeader)], this->getInterItemData(iItemNew), this->getInterItemSize());

		// Ενημέρωση του header
		memcpy(&interData[0], &nhParent, sizeof(NodeHeader));

		rc = this->fh.MarkPageDirty(interPageID);
		if (rc != OK) return rc;

		rc = this->fh.FlushPage(interPageID);
		if (rc != OK) return rc;

		rc = this->fh.UnpinPage(interPageID);
		if (rc != OK) return rc;
	}

	memcpy(&data[0], &nh, sizeof(NodeHeader));
	memcpy(&newInterData[0], &nhNew, sizeof(NodeHeader));

	return (OK);

}
Exemple #24
0
void testStorm() {
	
	STORM_StorageManager mgr;
	STORM_FileHandle fh;
	t_rc rc;
	int nAllocPages, nResPages;
	STORM_PageHandle ph;
	char *data;
	int val;
	int pid;
	int nreqs, nreads, nwrites, npinned, nframes;
	
	// ====================== STEP 1 =======================================//
	// Create the file. 
	// Open the file.
	// Reserve 100 pages.
	// Store something in each page.
	// Close the file.
	//======================================================================//
	
	rc = mgr.CreateFile("test.dat");
	if (rc != OK) {DisplayReturnCode(rc); Pause(); exit(-1);}
	
	rc = mgr.OpenFile("test.dat", fh);
	if (rc != OK) {DisplayReturnCode(rc); Pause(); exit(-1);}
	
	nAllocPages = fh.GetNumAllocatedPages();
	nResPages = fh.GetNumReservedPages();
	
	for (int i=1; i<=100; i++)
	{
		rc = fh.ReservePage(ph);
		if (rc != OK) {DisplayReturnCode(rc); Pause(); exit(-1);}
		
		// Copy something to the page.
		rc = ph.GetDataPtr(&data);
		memcpy(data, &i, sizeof(int));  
		
		// Mark the page as dirty.
		rc = ph.GetPageID(pid);
		if (rc != OK) {DisplayReturnCode(rc); exit(-1);}
		
		rc = fh.MarkPageDirty(pid);
		if (rc != OK) {DisplayReturnCode(rc); exit(-1);}
		
		// Unpin the page
		rc = fh.UnpinPage(pid);
		if (rc != OK) {DisplayReturnCode(rc); exit(-1);}
	}
	
	mgr.GetStats(nreqs, nreads, nwrites, npinned, nframes);
	printf("reqs: %d, reads: %d, writes: %d, pinned: %d, frames: %d\n", nreqs, nreads, nwrites, npinned, nframes);
	printf("allocated pages: %d, reserved pages: %d\n", fh.GetNumAllocatedPages(), fh.GetNumReservedPages());
	
	rc = mgr.CloseFile(fh);
	if (rc != OK) {DisplayReturnCode(rc); exit(-1);}
	
	Pause();
	
	// ====================== STEP 2 =======================================//
	// Open the file again. 
	// Read every page of the file and print the page contents.
	// Release the first 50 pages.
	// Close the file.
	//======================================================================//
	
	rc = mgr.OpenFile("test.dat", fh);
	if (rc != OK){DisplayReturnCode(rc); exit(-1);}
	
	printf("allocated pages: %d, reserved pages: %d\n", fh.GetNumAllocatedPages(), fh.GetNumReservedPages());
	
	// Display page contents.
	while (fh.GetNextPage(ph) != STORM_EOF)
	{
		rc = ph.GetDataPtr(&data);
		if (rc != OK) {DisplayReturnCode(rc);exit(-1);}
		memcpy(&val, data, sizeof(int));
		
		ph.GetPageID(pid);
		printf("contents of page %d = %d\n", pid, val);
		
		// Unpin the page
		rc = fh.UnpinPage(pid);
		if (rc != OK) {DisplayReturnCode(rc); exit(-1);}
	}
	
	// Release pages from 1 to 50.
	for (int p=1; p<=50; p++)
	{
		rc = fh.ReleasePage(p);
		if (rc != OK) {DisplayReturnCode(rc); exit(-1);}
	}
	
	printf("allocated pages: %d, reserved pages: %d\n", fh.GetNumAllocatedPages(), fh.GetNumReservedPages());
	
	rc = mgr.CloseFile(fh);
	if (rc != OK) {DisplayReturnCode(rc); exit(-1);}
	
	Pause();
	
	// ====================== STEP 3 =======================================//
	// Open the file again. 
	// Read every page of the file and print the page contents.
	// Close the file.
	// Finally, destroy the file.
	//
	// We expect to see only 50 pages staring from 51 up to 100, since the
	// first 50 have been released in the previous step.
	//======================================================================//
	
	rc = mgr.OpenFile("test.dat", fh);
	if (rc != OK){DisplayReturnCode(rc); exit(-1);}
	
	// Display page contents.
	while (fh.GetNextPage(ph) != STORM_EOF)
	{
		rc = ph.GetDataPtr(&data);
		if (rc != OK) {DisplayReturnCode(rc);exit(-1);}
		memcpy(&val, data, sizeof(int));
		
		ph.GetPageID(pid);
		printf("contents of page %d = %d\n", pid, val);
		
		// Unpin the page
		fh.UnpinPage(pid);
	}
	
	printf("allocated pages: %d, reserved pages: %d\n", fh.GetNumAllocatedPages(), fh.GetNumReservedPages());
	
	rc = mgr.CloseFile(fh);
	if (rc != OK) {DisplayReturnCode(rc); exit(-1);}
	
	Pause();
	
	rc = mgr.DestroyFile("test.dat");
	if (rc != OK) {DisplayReturnCode(rc);exit(-1);}
	
}
t_rc REM_RecordFileHandle::InsertRecord(const char *pData, REM_RecordID &rid)	{
    /* Check is file is open. */
    if (!this->isOpen) {
        return REM_FHCLOSED;
    }
    t_rc rc;

    /* Find an empty page to write the new record. */
    STORM_PageHandle targetPage;
    REM_PageHeader pageHeader = {0}; // The default number of records in a page is 0.
    char *pageData;

    /*	If there is no free space (lastPageID=-1) then we reserve a new page. */
    if (this->remFileHeader.isLastPageFull) {

        rc = sfh.ReservePage(targetPage);	// Reserve the new page.
        if (rc != OK) {
            return rc;
        }

        /* We mark the last page as not full. */
        this->remFileHeader.isLastPageFull = false;

        /* We update the file header and mark as dirty. */
        memcpy(this->pData_FileHeader, &this->remFileHeader, REM_FILEHEADER_SIZE);

        rc = this->sfh.MarkPageDirty(this->pageNum_FileHeader);
        if (rc != OK) {
            return rc;
        }

        /* Get a pointer to the data of the new page to write the new data. */
        rc = targetPage.GetDataPtr(&pageData);
        if (rc != OK) {
            return rc;
        }

    }
    /* If we have free space in a page, we just get the page. */
    else {
        rc = this->sfh.GetLastPage(targetPage);
        if (rc != OK) {
            return rc;
        }

        /* Get a pointer to the data of the the page to read the REM Page Header. */
        rc = targetPage.GetDataPtr(&pageData);
        if (rc != OK) {
            return rc;
        }

        memcpy(&pageHeader, pageData, REM_PAGEHEADER_SIZE);

    }

    /* We write the data to the proper position. The new record offset must be the page header size + the offset of each record there
     * is inside the page. We always place the new record at the end of the page.
     */
    memcpy(&pageData[REM_PAGEHEADER_SIZE+(pageHeader.nRecords*this->remFileHeader.recordSize)], pData, this->remFileHeader.recordSize);

    /* Increase the number of records in the page header. This number is also the slot number of the record. */
    int slotNum = ++pageHeader.nRecords;
    /* Declare page number, which is the pageID we are currently working on. */
    int pageNum;
    rc = targetPage.GetPageID(pageNum);
    if (rc != OK) {
        return rc;
    }

    /* Check if page is full. */
    if (pageHeader.nRecords == this->remFileHeader.recordsPerPage) {
        this->remFileHeader.isLastPageFull = true;

        /* We update the file header and mark as dirty. */
        memcpy(this->pData_FileHeader, &this->remFileHeader, REM_FILEHEADER_SIZE);

        rc = this->sfh.MarkPageDirty(this->pageNum_FileHeader);
        if (rc != OK) {
            return rc;
        }

        /* Get a pointer to the data of the new page to write the new data. */
        rc = targetPage.GetDataPtr(&pageData);
        if (rc != OK) {
            return rc;
        }
    }

    /* Write the new REM Page Header. */
    memcpy(pageData, &pageHeader, REM_PAGEHEADER_SIZE);


    /* Mark the page as dirty because we modified it */
    rc = this->sfh.MarkPageDirty(pageNum);
    if (rc != OK) {
        return rc;
    }

    this->sfh.FlushPage(pageNum);	// We should reconsider when we are flushing pages!!!

    /* Unpin the page */
    rc = this->sfh.UnpinPage (pageNum);
    if (rc != OK) {
        return rc;
    }

    /* Set the passed RID's page number and slot number */
    rc = rid.SetPageID(pageNum);
    if (rc != OK) {
        return rc;
    }
    rc = rid.SetSlot(slotNum);
    if (rc != OK) {
        return rc;
    }

    /* Successfuly inserted record */
    return (OK);
}
t_rc INXM_IndexHandle::InsertIntoLeafAfterSplitting(int rootID, STORM_PageHandle leafPageHandle, void *key, const REM_RecordID &rid) {
	t_rc rc;
	STORM_PageHandle newLeafPageHandle;
	int newLeafPageID;
	rc = CreateNodePage(newLeafPageHandle, newLeafPageID, 0, 0, 0, true);
	if (rc != OK) { return rc; }
	
	/* Read leaf page headers. */
	INXM_InitPageHeader leafPageHeader;
	rc = LoadInitHeaders(leafPageHandle, leafPageHeader);
	if (rc != OK) { return rc; }
	
	int insertPoint = 0;
	INXM_Node node;
	ReadNode(leafPageHandle, insertPoint, node);
	while (insertPoint < leafPageHeader.nItems  && KeyCmp(node.key, key) < 0) {
		ReadNode(leafPageHandle, insertPoint, node);
		insertPoint++;
	}
	
	INXM_Node **temp_nodes = (INXM_Node **)malloc(INXM_NODE_SIZE*leafPageHeader.nItems);
	
	int i,j;
	for (i=0, j=0; i < leafPageHeader.nItems; i++, j++) {
		if (j == insertPoint) j++;
		ReadNode(leafPageHandle, i, *(temp_nodes[j]));
	}
	
	/* Write new data to last page. */
	int newDataSlot;
	STORM_PageHandle lastDataPageHandle;
	rc = this->sfh.GetPage(this->inxmFileHeader.lastDataPage, lastDataPageHandle);
	if (rc != OK) { return rc; }
	
	rc = WriteData(lastDataPageHandle, rid, newDataSlot);
	if (rc != OK) { return rc; }
	
	/* Place new node to temp array. */
	INXM_Node *newNode = new INXM_Node();
	newNode->key = key;
	newNode->left = this->inxmFileHeader.lastDataPage;
	newNode->slot = newDataSlot;
	temp_nodes[insertPoint] = newNode;
	
	/* Reset leaf's nItems */
	char *tmpData;
	leafPageHandle.GetDataPtr(&tmpData);
	leafPageHeader.nItems = 0;
	memcpy(tmpData, &leafPageHeader, INXM_INITPAGEHEADER_SIZE);
	
	int maxNodeRoom = (PAGE_DATA_SIZE-INXM_INITPAGEHEADER_SIZE-INXM_NODEPAGEHEADER_SIZE)/(INXM_NODE_SIZE+this->inxmFileHeader.attrLength);
	int split = Cut(maxNodeRoom);
	
	/* Write new data. */
	for (i = 0; i < split; i++) {
		WriteNode(leafPageHandle, i, temp_nodes[i]->key, temp_nodes[i]->left, temp_nodes[i]->slot);
	}
	
	for (i = split, j = 0; i < maxNodeRoom; i++, j++) {
		WriteNode(newLeafPageHandle, j, temp_nodes[i]->key, temp_nodes[i]->left, temp_nodes[i]->slot);
	}

	free(temp_nodes); // This is not enough!
	
	INXM_NodePageHeader leafNodePageHeader;
	LoadNodeHeaders(leafPageHandle, leafPageHeader, leafNodePageHeader);

	INXM_NodePageHeader newLeafNodePageHeader;
	INXM_InitPageHeader newLeafPageHeader;
	rc = LoadNodeHeaders(newLeafPageHandle, newLeafPageHeader, newLeafNodePageHeader);
	if (rc != OK) { return rc; }
	
	int leafPageID;
	rc = leafPageHandle.GetPageID(leafPageID);
	if (rc != OK) { return rc; }
	
	newLeafNodePageHeader.next = leafNodePageHeader.next;
	newLeafNodePageHeader.previous = leafPageID;
	leafNodePageHeader.next = newLeafPageID;
	
	if (newLeafNodePageHeader.next != 0) {
		STORM_PageHandle nextLeafPageHandle;
		rc = this->sfh.GetPage(newLeafNodePageHeader.next, nextLeafPageHandle);
		if (rc != OK) { return rc; }
		
		INXM_InitPageHeader nextInitPageHeader;
		INXM_NodePageHeader nextNodePageHeader;
		LoadNodeHeaders(nextLeafPageHandle, nextInitPageHeader, nextNodePageHeader);
		
		nextNodePageHeader.previous = newLeafPageID;
		
		UpdateNodeHeaders(nextLeafPageHandle, nextInitPageHeader, nextNodePageHeader);
	}
	
	rc = UpdateNodeHeaders(leafPageHandle, leafPageHeader, leafNodePageHeader);
	if (rc != OK) { return rc; }
	rc = UpdateNodeHeaders(newLeafPageHandle, newLeafPageHeader, newLeafNodePageHeader);
	if (rc != OK) { return rc; }
	
	INXM_Node keyNode;
	rc = ReadNode(newLeafPageHandle, 0, keyNode);
	if (rc != OK) { return rc; }
	
	rc = InsertIntoParent(this->inxmFileHeader.treeRoot, leafPageHandle, keyNode, newLeafPageHandle);
	if (rc != OK) { return rc; }
	
	return(OK);
}
t_rc REM_RecordFileHandle::DeleteRecord(const REM_RecordID &rid)	{
    /* Check is file is open. */
    if (!this->isOpen) {
        return REM_FHCLOSED;
    }
    t_rc rc;

    /* Read page and slot we want to delete. */
    int pageID, slot;

    rc = rid.GetPageID(pageID);
    if (rc != OK) {
        return rc;
    }

    rc = rid.GetSlot(slot);
    if (rc != OK) {
        return rc;
    }

    /* Get wanted page. */
    STORM_PageHandle wantedPageHandle;
    rc = this->sfh.GetPage(pageID, wantedPageHandle);
    if (rc != OK) {
        return rc;
    }

    /* Get the wanted page header. */
    char *wantedData;
    REM_PageHeader wantedPageHeader;

    rc = wantedPageHandle.GetDataPtr(&wantedData);
    if (rc != OK) {
        return rc;
    }

    memcpy(&wantedPageHeader, wantedData, REM_PAGEHEADER_SIZE);
    if (slot > wantedPageHeader.nRecords) {
        return REM_INVALIDRID;
    }

    STORM_PageHandle lastPageHandle;
    int lastPageID;

    rc = this->sfh.GetLastPage(lastPageHandle);
    if (rc != OK) {
        return rc;
    }

    rc = lastPageHandle.GetPageID(lastPageID);
    if (rc != OK) {
        return rc;
    }

    /* Determine if we need to retrive an other page to replace the record. */
    if (lastPageID == pageID) {

        /* Determine if our record is the last. */
        if (wantedPageHeader.nRecords == slot) {

            /* Check if we need to release the page. */
            if (wantedPageHeader.nRecords == 1) {
                rc = this->sfh.ReleasePage(pageID);
                if (rc != OK) {
                    return rc;
                }

                /* We must change the lastPageID in REM File Header. */
                this->remFileHeader.isLastPageFull = true;
                /* Copy new file header at memory */
                memcpy(this->pData_FileHeader, &this->remFileHeader, REM_FILEHEADER_SIZE);
                /* Mark REM File Header frame as dirty */
                rc = this->sfh.MarkPageDirty(this->pageNum_FileHeader);
                if (rc != OK) {
                    return rc;
                }
            }
            else {
                /* If our record is the last one in the row but more data exist, we just decrease the number of records the page has. */
                wantedPageHeader.nRecords--;

                /* Copy header back. */
                memcpy(wantedData, &wantedPageHeader, REM_PAGEHEADER_SIZE);
            }
        }
        else {
            /* Copy the last record of this page (last page) in the position of the record we want to erase. */
            memcpy(&wantedData[REM_PAGEHEADER_SIZE+((slot-1)*this->remFileHeader.recordSize)],
                   &wantedData[REM_PAGEHEADER_SIZE+((wantedPageHeader.nRecords-1)*this->remFileHeader.recordSize)],
                   this->remFileHeader.recordSize);

            /* Decrease the number of records the pages has. */
            wantedPageHeader.nRecords--;

            /* Copy header back. */
            memcpy(wantedData, &wantedPageHeader, REM_PAGEHEADER_SIZE);
        }
    }
    else {
        /* Get last record from last page to replace the asked record. */
        char *lastData;

        rc = lastPageHandle.GetDataPtr(&lastData);
        if (rc != OK) {
            return rc;
        }

        /* Get last's page header. */
        REM_PageHeader lastPageHeader;

        memcpy(&lastPageHeader, lastData, REM_PAGEHEADER_SIZE);

        /* Copy the data between the two pages */
        memcpy(&wantedData[REM_PAGEHEADER_SIZE+((slot-1)*this->remFileHeader.recordSize)],
               &lastData[REM_PAGEHEADER_SIZE+((lastPageHeader.nRecords-1)*this->remFileHeader.recordSize)],
               this->remFileHeader.recordSize);

        /* Check if last page has no more records. */
        if (lastPageHeader.nRecords == 1) {
            /* If we copied the last record we can safely release the last page. */
            rc = this->sfh.ReleasePage(lastPageID);
            if (rc != OK) {
                return rc;
            }

            /* We must change the lastPageID in REM File Header. */
            this->remFileHeader.isLastPageFull = true;
            /* Copy new file header at memory */
            memcpy(this->pData_FileHeader, &this->remFileHeader, REM_FILEHEADER_SIZE);
            /* Mark REM File Header frame as dirty */
            rc = this->sfh.MarkPageDirty(this->pageNum_FileHeader);
            if (rc != OK) {
                return rc;
            }
        }
        else {
            /* Decrease last page record number in its page header. */
            lastPageHeader.nRecords--;

            memcpy(lastData, &lastPageHeader, REM_PAGEHEADER_SIZE);

            /* Mark last page as dirty due to last record removal. */
            rc = sfh.MarkPageDirty(lastPageID);
            if (rc != OK) {
                return rc;
            }

            /* Unpin last page. */
            rc = sfh.UnpinPage (lastPageID);
            if (rc != OK) {
                return rc;
            }
        }
    }


    /* Mark the page as dirty because we modified it */
    rc = sfh.MarkPageDirty(pageID);
    if (rc != OK) {
        return rc;
    }
    /* Unpin the page */
    rc = sfh.UnpinPage (pageID);
    if (rc != OK) {
        return rc;
    }

    sfh.FlushPage(pageID);

    /* Record successfully deleted */
    return (OK);
}
t_rc INXM_IndexManager::CreateIndex(const char *fname, int indexNo, t_attrType attrType, int attrLength) {
	
	// We need to find the number of records that fit in a page.
	int recordsPerPage = (PAGE_SIZE - INXM_INITPAGEHEADER_SIZE + INXM_NODEPAGEHEADER_SIZE)/(INXM_NODE_SIZE + attrLength);	// We need only the integer part or we can "floor" the number.
	
	if (recordsPerPage < 1) {
		return (INXM_INVALIDRECSIZE);
	}
	
	char buffer[128];
	snprintf(buffer, sizeof(buffer), "%s.%d", fname, indexNo);

	/* Create file by using STORM */
	t_rc rc = this->sm->CreateFile(buffer);
	if (rc != OK) { return rc; }

	/* Open the created file */
	STORM_FileHandle stormFileHandle;
	
	rc = this->sm->OpenFile(buffer, stormFileHandle);
	if (rc != OK) { return rc; }	
	
	/* Allocate a new page for the INXM file header page. */
	STORM_PageHandle stormPageHandle;
	
	rc = stormFileHandle.ReservePage(stormPageHandle);
	if (rc != OK) { return rc; }

	/* Get pointer to the contents (data) of the INXM file header page */
	char *pData;
	int pageID;
	
	rc = stormPageHandle.GetDataPtr(&pData);
	if (rc != OK) { return rc; }
	
	/* Get the page number of the INXM file header page */
	rc = stormPageHandle.GetPageID(pageID);
	if (rc != OK) { return rc; }
	
	/* Construct INXM File Header */
	INXM_FileHeader 
	fileHeader = {
		attrType,
		attrLength,
		0,
		0
	};
	
	/* Copy	the INXM File Header to the first page */
	memcpy(pData, &fileHeader, INXM_FILEHEADER_SIZE);

	/* Because we modified the INXM file header page, we write it to disk */
	rc = stormFileHandle.MarkPageDirty(pageID);
	if (rc != OK) { return rc; }
	rc = stormFileHandle.FlushPage(pageID);
	if (rc != OK) { return rc; }
	
	
	/* We now unpin the header page because we are done modifying it. (We really need this?) */
	rc = stormFileHandle.UnpinPage(pageID);
	if (rc != OK) { return rc; }	
	
	/* We now close the file because we are done modifying it. (We really need this too?) */
	rc = this->sm->CloseFile(stormFileHandle);
	if (rc != OK) { return rc; }	
	
	return(OK);
}