235 lines
6.2 KiB
C++
235 lines
6.2 KiB
C++
/*
|
|
----
|
|
This file is part of SECONDO.
|
|
|
|
Copyright (C) 2004, University in Hagen, Department of Computer Science,
|
|
Database Systems for New Applications.
|
|
|
|
SECONDO is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
SECONDO is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with SECONDO; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
----
|
|
|
|
//[_] [\_]
|
|
//characters [1] verbatim: [$] [$]
|
|
//characters [2] formula: [$] [$]
|
|
//characters [3] capital: [\textsc{] [}]
|
|
//characters [4] teletype: [\texttt{] [}]
|
|
|
|
1 Implementation file "GTree[_]FileNode.cpp"[4]
|
|
|
|
January-May 2008, Mirko Dibbert
|
|
|
|
*/
|
|
#include "GTree_FileNode.h"
|
|
|
|
using namespace gtree;
|
|
/*
|
|
Method ~getNodeId~:
|
|
|
|
*/
|
|
SmiRecordId
|
|
FileNode::getNodeId()
|
|
{
|
|
// append new record, if no record exists
|
|
if (!m_nodeId)
|
|
{
|
|
SmiRecord record;
|
|
m_nodeMngr->file()->AppendRecord(m_nodeId, record);
|
|
}
|
|
|
|
return m_nodeId;
|
|
}
|
|
|
|
/*
|
|
Method ~put~:
|
|
|
|
*/
|
|
void
|
|
FileNode::put()
|
|
{
|
|
if (!m_node->isModified())
|
|
return;
|
|
|
|
if (!m_nodeId)
|
|
Msg::noNodeRecord_Error();
|
|
|
|
// add/remove extension pages, if pagecount has been changed
|
|
if (m_node->m_pagecount != (m_extPageCnt + 1))
|
|
{
|
|
// remove extension pages, if neccesary
|
|
while (m_extPageCnt + 1 > m_node->m_pagecount)
|
|
{
|
|
m_nodeMngr->file()->DeleteRecord(
|
|
m_extensionId + (m_extPageCnt - 1));
|
|
--m_extPageCnt;
|
|
}
|
|
|
|
/*
|
|
Append node records, if neccessary (could only happen, if no records has been removed in the previously while-loop). All existing extension pages would be removed before, to assure that the extension pages are located in a continues area, to avoid the need to store the record-id of every extension record (furthermore, continues data could usually be read faster from disc than fragmented data).
|
|
|
|
*/
|
|
if (m_extPageCnt + 1 < m_node->m_pagecount)
|
|
{
|
|
// remove all extension records
|
|
for (SmiRecordId rec_no = m_extensionId;
|
|
rec_no < m_extensionId + m_extPageCnt; ++rec_no)
|
|
{
|
|
m_nodeMngr->file()->DeleteRecord(rec_no);
|
|
}
|
|
|
|
// add new extension records
|
|
SmiRecordId rec_no;
|
|
SmiRecord rec;
|
|
m_nodeMngr->file()->AppendRecord(rec_no, rec);
|
|
m_extensionId = rec_no;
|
|
m_extPageCnt = 1;
|
|
|
|
for (; m_extPageCnt < m_node->pagecount() - 1;
|
|
++m_extPageCnt)
|
|
{
|
|
m_nodeMngr->file()->AppendRecord(rec_no, rec);
|
|
assert(rec_no == m_extensionId + m_extPageCnt);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// create write buffer
|
|
char buffer[PAGESIZE * m_node->m_pagecount];
|
|
|
|
// write count of extension pages to buffer
|
|
memcpy(buffer, &m_extPageCnt, sizeof(unsigned));
|
|
int offset = sizeof(unsigned);
|
|
|
|
// write id of first extension page to buffer
|
|
memcpy(buffer + offset, &m_extensionId, sizeof(SmiRecordId));
|
|
offset += sizeof(SmiRecordId);
|
|
|
|
// write node type-id to buffer
|
|
NodeTypeId type = m_node->typeId();
|
|
memcpy(buffer + offset, &type, sizeof(NodeTypeId));
|
|
offset += sizeof(NodeTypeId);
|
|
|
|
// write node to buffer
|
|
m_node->write(buffer, offset);
|
|
|
|
// write header record
|
|
SmiRecord record;
|
|
m_nodeMngr->file()->SelectRecord(m_nodeId, record, SmiFile::Update);
|
|
record.Write(buffer, PAGESIZE, 0);
|
|
|
|
// write extension records, if exist
|
|
for (unsigned i = 0; i < m_extPageCnt; ++i)
|
|
{
|
|
m_nodeMngr->file()->SelectRecord(
|
|
m_extensionId + i , record, SmiFile::Update);
|
|
record.Write(buffer + ((i + 1)*PAGESIZE), PAGESIZE, 0);
|
|
offset += PAGESIZE;
|
|
}
|
|
|
|
// reset modified flag
|
|
m_node->resetModified();
|
|
}
|
|
|
|
/*
|
|
Method ~get~:
|
|
|
|
*/
|
|
void
|
|
FileNode::get(SmiRecordId nodeId)
|
|
{
|
|
// write current node to disc, if exist
|
|
if (m_node.defined())
|
|
put();
|
|
|
|
assert(nodeId);
|
|
|
|
// read header page
|
|
char headerBuf[PAGESIZE];
|
|
SmiRecord record;
|
|
m_nodeMngr->file()->SelectRecord(nodeId, record, SmiFile::ReadOnly);
|
|
record.Read(headerBuf, PAGESIZE, 0);
|
|
|
|
// read count of extension pages
|
|
memcpy(&m_extPageCnt, headerBuf, sizeof(unsigned));
|
|
int offset = sizeof(unsigned);
|
|
|
|
// read id of first extension page (=0, if no exensions exist)
|
|
memcpy(&m_extensionId, headerBuf + offset, sizeof(SmiRecordId));
|
|
offset += sizeof(SmiRecordId);
|
|
|
|
// create read buffer
|
|
char buffer[PAGESIZE * (m_extPageCnt+1)];
|
|
|
|
// copy header buffer into buffer
|
|
memcpy(buffer, headerBuf, PAGESIZE);
|
|
|
|
// read extension pages, if exist
|
|
for (unsigned i = 0; i < m_extPageCnt; ++i)
|
|
{
|
|
m_nodeMngr->file()->SelectRecord(
|
|
m_extensionId + i, record, SmiFile::ReadOnly);
|
|
record.Read(buffer + ((i + 1)*PAGESIZE), PAGESIZE, 0);
|
|
}
|
|
|
|
// read node type from buffer
|
|
NodeTypeId typeId;
|
|
memcpy(&typeId, buffer + offset, sizeof(NodeTypeId));
|
|
offset += sizeof(NodeTypeId);
|
|
|
|
// create new node of type "typeId"[4]
|
|
createNode(typeId);
|
|
m_nodeId = nodeId;
|
|
|
|
// read the node values from buffer
|
|
m_node->read(buffer, offset);
|
|
|
|
// set m_pagecount and update m_size
|
|
m_node->m_pagecount = m_extPageCnt + 1;
|
|
|
|
// reset modified flag
|
|
m_node->resetModified();
|
|
}
|
|
|
|
/*
|
|
Method ~drop~:
|
|
|
|
*/
|
|
void
|
|
FileNode::drop()
|
|
{
|
|
m_node->clear();
|
|
m_node->resetModified();
|
|
|
|
if (!m_nodeId)
|
|
{
|
|
// no record(s) created or record(s) already removed
|
|
return;
|
|
}
|
|
|
|
// remove extension pages
|
|
for (SmiRecordId rec_no = m_extensionId;
|
|
rec_no < m_extensionId + m_extPageCnt; ++rec_no)
|
|
{
|
|
m_nodeMngr->file()->DeleteRecord(rec_no);
|
|
}
|
|
|
|
// remove header page
|
|
m_nodeMngr->file()->DeleteRecord(m_nodeId);
|
|
m_nodeId = 0;
|
|
}
|
|
|
|
|
|
|