Files
secondo/Algebras/BTree2/BTree2Node.h
2026-01-23 17:03:45 +08:00

1217 lines
33 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2004-2010, University in Hagen, Faculty of Mathematics and
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 Fre 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
----
1 Template Header File: BTree2Node
Jan. 2010 M.Klocke, O.Feuer, K.Teufel
1.1 Overview
This class represents a single node of the btree. When representing an
internal node, this class should be instantiated with VALUETYPE=NodeId.
*/
#ifndef _BTREE2_NODE_H_
#define _BTREE2_NODE_H_
#include "BTree2Types.h"
#include "BTree2Entry.h"
#include "BTree2.h"
#include <vector>
#include <algorithm>
namespace BTree2Algebra {
/*
2 Class ~BTreeNode~
*/
template <typename KEYTYPE, typename VALUETYPE>
class BTreeNode
{
public:
BTreeNode(const bool internal, NodeId nid, BTree2* parent);
/*
Creates a new node of the btree given by ~parent~. The node is
initialized as an empty node.
*/
~BTreeNode();
/*
The destructor takes care of writing the contents back to disk.
*/
static bool ProbeIsInternal(SmiRecordFile* btreefile, NodeId id);
/*
This method opens a node on disk to check, whether it is an internal node.
Should be avoided, if node is in memory.
*/
inline int GetSizeInRecord() const;
/*
The size of this node in bytes when stored in a record.
*/
inline size_t GetMemoryUsage() { return memoryUsage; }
/*
The size of this node in bytes in memory.
*/
static int GetSizeOfEmptyNode();
/*
Gives the overhead of the node's disk usage.
*/
static int GetEntrySizeInRecord(int maxk, int maxv);
/*
Gives the size of a single entry in bytes (can be used without an
actual instance of a node)
*/
int GetEntrySizeInRecord() const;
/*
Gives the size of a single entry in bytes.
*/
static inline int GetMaxEntries(int recSize, int maxk, int maxv);
/*
Returns the maximum number of entries. The node can
hold one entry more in memory, but not store on disk.
This version can be called without an instance of BTreeNode.
*/
inline int GetMaxEntries() const { return maxEntries; }
/*
Returns the maximum number of entries.
*/
static inline int GetMinEntries(int recSize, double f, int maxk, int maxv);
/*
Returns the minimum number of entries.
This version can be called without an instance of BTreeNode.
*/
inline int GetMinEntries() const { return minEntries; }
/*
Returns the minimum number of entries.
*/
NodeId GetNodeId() { return myNodeId; }
/*
Returns the node id.
*/
int GetCount() const { return count; }
/*
Returns the current number of entries.
*/
bool IsOverflow() const { return count == GetMaxEntries()+1; }
/*
Returns true, if this node has one entry more than it can store.
*/
bool IsUnderflow() const { return count < GetMinEntries(); }
/*
Returns true, if this node has less entries than it should have.
*/
bool IsInternal() const { return internal; }
/*
Returns true, if this node is an internal node.
*/
bool ChildNodeIsLeaf() const { return childNodeIsLeaf; }
/*
Returns true, if this (internal) node's children are leaf nodes.
*/
void SetChildNodeIsLeaf(bool x) { childNodeIsLeaf = x; }
/*
Set the flag, which indicates, whether this (internal) node's children
are leaf nodes.
*/
bool IsLeaf() const { return !internal; }
/*
Returns true, if this node is a leaf node.
*/
BTreeEntry<KEYTYPE,VALUETYPE> const& GetEntry(int index) {
return *entries[index];
}
/*
Returns a reference to the entry at ~index~. The key and the value
cannot be altered, use ~SetKey~, ~SetValue~ or ~SetChildNode~ instead.
*/
BTreeEntry<KEYTYPE,VALUETYPE> const& GetLastEntry() {
return *entries[count - 1];
}
/*
Returns a reference to the rightmost entry. See also ~GetEntry~.
*/
BTreeEntry<KEYTYPE,VALUETYPE> const* GetEntryPtr(int index) {
return entries[index];
}
/*
Returns a pointer to the entry given by ~index~. See also ~GetEntry~.
*/
inline BTreeEntry<KEYTYPE,VALUETYPE> const*
GetEntryPtrByValue(const VALUETYPE& n);
/*
Returns a reference of the leftmost entry having a value as given by ~n~.
The key and the value cannot be altered, use ~SetKey~, ~SetValue~ or
~SetChildNode~ instead.
*/
inline int GetLeftmostEntryIndexByKey(const KEYTYPE& key);
/*
Returns the index of the leftmost entry which is greater or equals ~key~.
Note that there might be no entry with the speficied key.
*/
inline int GetRightmostEntryIndexByKey(const KEYTYPE& key);
/*
Returns the index of the rightmost entry which is greater or equals ~key~.
Note that there might be no entry with the speficied key.
*/
inline int GetEntryIndexByKeyValue(const KEYTYPE& key,
const VALUETYPE& val);
/*
Returns the index of the leftmost entry which matches ~key~ and ~value~.
*/
inline int GetEntryIndexByValue(NodeId n);
/*
Returns the index of the leftmost entry which points to node ~n~. This
method must only be called if class is instantiated as internal node
(e.g. VALUETYPE == NodeId).
*/
KEYTYPE const& GetKey(int index) {
return entries[index]->GetKey();
}
/*
Returns a reference to the key at ~index~.
*/
NodeId GetChildNodeByIndex(int index) {
return (index == count) ? rightPointer : entries[index]->GetValue();
}
/*
Returns the node id which is referenced to at ~index~. If ~index~ is
set to the index of the last entry plus one, the right pointer is returned.
*/
inline NodeId GetLeftmostChildNodeByKey(const KEYTYPE& key);
/*
Returns the child node id according to ~key~ (the leftmost entry
with a key greater or equals to ~key~ will be used).
*/
inline NodeId GetRightmostChildNodeByKey(const KEYTYPE& key);
/*
Returns the child node id according to ~key~ (the first entry
with a key greater than ~key~ will be used).
*/
inline void GetLeftmostChildNodeAndIndexByKey(
const KEYTYPE& key, NodeId& res, int& entry);
/*
See ~GetLeftmostChildNodeByKey~ but this method also returns the index of the
entry found.
*/
inline void GetRightmostChildNodeAndIndexByKey(
const KEYTYPE& key, NodeId& res, int& entry);
/*
See ~GetRightmostChildNodeByKey~ but this method also returns the index of the
entry found.
*/
inline bool HasKey(const KEYTYPE& key);
/*
Returns true, if an entry with ~key~ exists.
*/
inline bool HasEntry(const KEYTYPE& ent, const VALUETYPE& value);
/*
Returns true, if an entry with ~key~ and ~value~ exists.
*/
bool HasIndex(int i) { return (i >= 0) && (i <= count); }
/*
Returns true, if ~i~ is within valid entry bounds. Care! This includes
the index ~count~, which is out of the entry array bound but stands for
the right pointer in some methods (extended index).
*/
void SetKey(int index, const KEYTYPE& key) {
modified = true;
entries[index]->SetKey(key);
}
/*
Replaces the key at ~index~ with ~key~. The caller of this method
must ensure, that this will not destroy the order of the array.
*/
void SetValue(int index, const VALUETYPE& v) {
modified = true;
entries[index]->SetValue(v);
}
/*
Replaces the value at ~index~ with ~value~.
*/
inline void SetChildNode(int index, const NodeId& v);
/*
Replaces the value at ~index~ with ~value~. This method can be
called with extended indexing (index == count is rightPointer).
*/
void Read(SmiRecordFile *file, const NodeId pointer);
/*
Read node from disk.
*/
void ReadInternals(char* buffer, int& offset);
/*
Part 1 of reading from disk: internal flags and values.
*/
void ReadRecord(SmiRecord& record);
/*
Part 2 of reading from disk: read entries.
*/
void Write(SmiRecordFile *file, const NodeId pointer );
/*
Write node to disk.
*/
void WriteRecord(SmiRecord& record );
/*
Write node to disk.
*/
int GetWaste() { return bytesWasted; }
/*
Returns the difference between used bytes and record size
*/
inline void InsertLeftmost(const KEYTYPE& key, const VALUETYPE& value);
/*
Insert a new entry with ~key~ and ~value~.
It will be added at the leftmost position which key is greater or equals
to ~key~. This method runs in N log N time.
*/
inline void InsertUnsorted(const KEYTYPE& key, const VALUETYPE& value);
/*
Insert a new entry with ~key~ and ~value~ at the end of the entry array.
This method runs in constant time, but it sets the state of the node to
unsorted, so that before writing this node to disc or splitting it, it
is necessary to call a sorting algorithm on the entries (see checkSort).
*/
inline void InsertRightmost(const KEYTYPE& key, const VALUETYPE& value);
/*
Insert a new entry with ~key~ and ~value~.
It will be added at the position right to the rightmost entry with ~key~
(or the biggest entry which is smaller than ~key~).
This method runs in N log N time.
*/
inline void InsertAt(int idx, const KEYTYPE& key, const VALUETYPE& value);
/*
Insert a new entry with ~key~ and ~value~, so that it is at index ~idx~
afterwards. The caller must ensure that the order is not disturbed.
This method runs in linear time.
*/
inline bool InsertUnique(const KEYTYPE& key, const VALUETYPE& value);
/*
See ~Insert~, but this method rejects inserting if ~key~ already exists (in
this case, false is returned).
This method runs in N log N time.
*/
typename std::vector<BTreeEntry<KEYTYPE,VALUETYPE>* >::iterator
sortedRangeEnd;
/*
Point up to which the entries are sorted, the rest of the entry array is then
supposed to be unsorted. This way, we do not need to sort the whole array but
just the rest and merge it. This sorting/merging process is (currently) not stable.
*/
struct pred {
bool operator() (BTreeEntry<KEYTYPE,VALUETYPE>* i,
BTreeEntry<KEYTYPE,VALUETYPE>* j) {
return i->keyLessThan(j->GetKey());
}
} sortPred;
/*
Predicate function object for sorting the entries by key, used by checkSort method.
*/
inline void checkSort();
/*
Check, if the node is in an unsorted state and sort it if necessary.
Unsorted states can only occur after calls to InsertUnsorted.
*/
inline int MoveEntryToLeftmost(BTreeNode<KEYTYPE,VALUETYPE>* src,
int srcidx);
/*
Moves the entry at ~idx~ from source node to this node.
The moved entry is inserted at the leftmost position which key is
greater or equals to the key of the source node.
*/
inline int MoveEntryToRightmost(BTreeNode<KEYTYPE,VALUETYPE>* src,
int srcidx);
/*
Moves the entry at ~idx~ from source node to this node.
It will be added at the position right to the rightmost entry with ~key~
(or the biggest entry which is smaller than ~key~).
*/
inline int MoveEntry(BTreeNode<KEYTYPE,VALUETYPE>* src, int srcidx,
int dstidx);
/*
Moves the entry at ~idx~ from source node to this node, inserting it at
index ~dstidx~. The caller must ensure, that this does not disturb the
order of the array.
*/
void MoveEntries(BTreeNode<KEYTYPE,VALUETYPE>* src, int start, int end);
/*
Moves a range of entries from source node to this node,starting
at index ~start~, ending (including) at index ~end~. Currently, the
implementation is limited: the destination node must be empty.
*/
inline bool DeleteEntry(int index);
/*
Removes the entry at ~index~ and discards its contents from memory.
*/
inline bool RemoveEntry(int index);
/*
Removes the entry at ~index~. Its contents is not discarded from memory.
*/
inline void RemoveEntries(int startidx, int endidx);
/*
Removes the entries starting at ~startidx~, ending (including) at ~endidx~.
The contents of the entries are not discarded from memory.
*/
NodeId GetRightPointer() { return rightPointer; }
/*
Returns the node id of the right pointer.
*/
inline void SetRightPointer(NodeId _rightPointer);
/*
Sets the right pointer.
*/
bool HasRightPointer() { return rightPointer != 0; }
/*
Returs true, if the right pointer has been set.
*/
void SetHasRightPointer(bool x) { if (!x) { rightPointer = 0; } }
/*
Set the right pointer set flag to ~x~.
*/
NodeId GetLeftPointer() { return leftPointer; }
/*
Returns the node id of the left pointer.
*/
void SetLeftPointer(NodeId _leftPointer);
/*
Sets the left pointer.
*/
bool HasLeftPointer() { return leftPointer != 0; }
/*
Returs true, if the left pointer has been set.
*/
void SetHasLeftPointer(bool x) { if (!x) { leftPointer = 0; } }
/*
Set the left pointer set flag to ~x~.
*/
private:
bool internal; // Flag, if this is an internal node
NodeId myNodeId; // Id of this node
int recordSize; // RecordSize of the btree
int count; // number of entries
double fill; // Fill factor of the btree
int maxEntries;
int minEntries;
int maxKeysize; // max. keysize for direct storage
int maxValuesize; // max. valuesize for direct storage
ListExpr keyTypeListExpr; // copy of the type description (for creating
// Attributes)
ListExpr valueTypeListExpr; // copy of the type description (for creating
// Attributes)
SmiRecordFile* btreeFile; // BTree Main File, where node is stored
SmiRecordFile* extendedKeysFile; // Extended Keys File
SmiRecordFile* extendedValuesFile;// Extended Values File
std::vector<BTreeEntry<KEYTYPE,VALUETYPE>*> entries; // Entries
NodeId rightPointer; // Right pointer
NodeId leftPointer; // Left pointer
bool childNodeIsLeaf; // Flag, if children are leaf nodes
bool modified; // Indicates, that changes must be written back
bool dbgPrintNodeLoading; // Debug-flag: prints loading/unloading msg.
size_t memoryUsage; // Memory usage of this node
int bytesWasted; // Number of wasted bytes
bool unsorted; // Node is in unsorted state
bool multipleUnsorted; // For speed up: false, if there is just one
// entry unsorted
};
/*
3 Class ~BTreeNode~: Implementation
*/
template<class KEYTYPE,typename VALUETYPE>
BTreeNode<KEYTYPE,VALUETYPE>::BTreeNode(const bool _internal,
NodeId nid,
BTree2* parent)
: entries(
GetMaxEntries(
parent->GetRecordSize(),
parent->GetMaxKeysize(),
parent->GetMaxValuesize())
+1)
// Initialization of the entries array: add MaxEntries+1 null pointers
{
myNodeId = nid;
internal = _internal;
unsorted = false;
multipleUnsorted = false;
// entries = new BTreeEntry<KEYTYPE,VALUETYPE>*[
// GetMaxEntries(
// parent->GetRecordSize(),
// parent->GetMaxKeysize(),
// parent->GetMaxValuesize())+1];
// Store information of btree locally
recordSize = parent->GetRecordSize();
fill = parent->GetFill();
maxKeysize = parent->GetMaxKeysize();
maxValuesize = parent->GetMaxValuesize();
extendedKeysFile = parent->GetExtendedKeysFile();
extendedValuesFile = parent->GetExtendedValuesFile();
btreeFile = parent->GetBTreeFile();
keyTypeListExpr = parent->GetKeyTypeListExpr();
valueTypeListExpr = parent->GetValueTypeListExpr();
dbgPrintNodeLoading = parent->dbgPrintNodeLoading();
maxEntries = GetMaxEntries(recordSize,maxKeysize,maxValuesize);
minEntries = GetMinEntries(recordSize,fill,maxKeysize,maxValuesize);
// Initialize memory usage with sizeof BTreeNode
memoryUsage = sizeof(*this);
count = 0;
modified = true; // store at least the node structure
bytesWasted = recordSize - GetSizeOfEmptyNode();
// Initialize left and right pointer
rightPointer = 0;
leftPointer = 0;
childNodeIsLeaf = false; // must default to false
}
template<class KEYTYPE,typename VALUETYPE>
BTreeNode<KEYTYPE,VALUETYPE>::~BTreeNode()
{
// Write back, if necessary
Write(btreeFile, myNodeId);
// Remove all entries from memory
for (int i = 0; i < count; i++) {
delete entries[i];
}
if (dbgPrintNodeLoading) {
cout << "Removed node " << myNodeId << endl;
}
}
template<class KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::GetSizeInRecord() const
{
int size = GetSizeOfEmptyNode();
size += GetEntrySizeInRecord() * GetMaxEntries();
return size;
}
template<class KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::GetSizeOfEmptyNode()
{
// This method is bad, I know...
// Here, the sizes of all internal storage entries must be added
return sizeof( bool ) + // internal
sizeof( int ) + // count
sizeof( NodeId ) + // rightPointer
std::max(sizeof(NodeId),sizeof(bool)); // leftpointer (for leafs),
// children are leafs (for internl)
}
template<typename KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::GetEntrySizeInRecord() const {
return BTreeEntry<KEYTYPE,VALUETYPE>::GetKeySizeInRecord(maxKeysize)
+ BTreeEntry<KEYTYPE,VALUETYPE>::GetValueSizeInRecord(maxValuesize);
}
template<typename KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::GetEntrySizeInRecord(int maxk, int maxv) {
return BTreeEntry<KEYTYPE,VALUETYPE>::GetKeySizeInRecord(maxk)
+ BTreeEntry<KEYTYPE,VALUETYPE>::GetValueSizeInRecord(maxv);
}
//template<class KEYTYPE,typename VALUETYPE>
//int BTreeNode<KEYTYPE,VALUETYPE>::GetMaxEntries() const {
// return GetMaxEntries(recordSize,maxKeysize,maxValuesize);
//}
template<class KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::GetMaxEntries(int recsize,
int maxk, int maxv) {
return (int) floor((recsize - GetSizeOfEmptyNode()) /
GetEntrySizeInRecord(maxk,maxv));
}
//template<class KEYTYPE,typename VALUETYPE>
//int BTreeNode<KEYTYPE,VALUETYPE>::GetMinEntries() const {
// return GetMinEntries(recordSize,fill,maxKeysize,maxValuesize);
//}
template<class KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::GetMinEntries(int recsize,double fillf,
int maxk, int maxv) {
// At least one entry must be in the node
// (= internal nodes have minimum degree of 2)
int minEntries = (int) ceil(fillf * GetMaxEntries(recsize,maxk,maxv));
return (minEntries == 0) ? 1 : minEntries;
}
template<class KEYTYPE,typename VALUETYPE>
NodeId BTreeNode<KEYTYPE,VALUETYPE>::GetLeftmostChildNodeByKey(
const KEYTYPE& key) {
int idx = GetLeftmostEntryIndexByKey(key);
return GetChildNodeByIndex(idx);
}
template<class KEYTYPE,typename VALUETYPE>
NodeId BTreeNode<KEYTYPE,VALUETYPE>::GetRightmostChildNodeByKey(
const KEYTYPE& key) {
int idx = GetRightmostEntryIndexByKey(key);
return GetChildNodeByIndex(idx);
}
template<class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::GetLeftmostChildNodeAndIndexByKey(
const KEYTYPE& key, NodeId& res, int& entry) {
entry = GetLeftmostEntryIndexByKey(key);
res = GetChildNodeByIndex(entry);
}
template<class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::GetRightmostChildNodeAndIndexByKey(
const KEYTYPE& key, NodeId& res, int& entry) {
entry = GetRightmostEntryIndexByKey(key);
res = GetChildNodeByIndex(entry);
}
template<class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::SetChildNode(int index, const NodeId& v) {
modified = true;
if (index == count) { // extended index: if index is out of entry bounds
rightPointer = v;
} else {
entries[index]->SetValue(v);
}
}
template<class KEYTYPE,typename VALUETYPE>
bool BTreeNode<KEYTYPE,VALUETYPE>::RemoveEntry(int index) {
assert( index >= 0 && index < count ); // Extended index not valid here
memoryUsage -= entries[index]->GetValueSizeInMemory() +
entries[index]->GetKeySizeInMemory();
// Shift entries linearly
for (int i = index; i < count - 1; i++) {
entries[i] = entries[i+1];
}
count -= 1;
modified = true;
return (count >= GetMinEntries());
}
template<class KEYTYPE,typename VALUETYPE>
bool BTreeNode<KEYTYPE,VALUETYPE>::DeleteEntry(int index) {
assert( index >= 0 && index < count );
BTreeEntry<KEYTYPE,VALUETYPE>* todel = entries[index];
memoryUsage -= entries[index]->GetValueSizeInMemory() +
entries[index]->GetKeySizeInMemory();
// Shift entries linearly
for (int i = index; i < count - 1; i++) {
entries[i] = entries[i+1];
}
count -= 1;
delete todel;
modified = true;
return (count >= GetMinEntries());
}
template <class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::RemoveEntries(int start, int end) {
// Shift entries linearly
for (int i = 0; i < count-end-1; i++) {
memoryUsage -= entries[i+start]->GetValueSizeInMemory() +
entries[i+start]->GetKeySizeInMemory();
entries[start+i] = entries[end+i+1];
}
count -= (end-start+1);
modified = true;
}
template<class KEYTYPE,typename VALUETYPE>
bool BTreeNode<KEYTYPE,VALUETYPE>::HasKey(const KEYTYPE& ent) {
int i = GetLeftmostEntryIndexByKey(ent);
// i is extended index (i==count possible)
return ((i < count) && (entries[i]->keyEquals(ent)));
}
template<class KEYTYPE,typename VALUETYPE>
bool BTreeNode<KEYTYPE,VALUETYPE>::HasEntry(const KEYTYPE& ent,
const VALUETYPE& val) {
int i;
// Simple sweep
for (i = 0; i < count; i++) {
if ((entries[i]->keyEquals(ent)) && (entries[i]->valueEquals(val))) {
return true;
}
}
return false;
}
template<class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::InsertAt(int idx, const KEYTYPE& key,
const VALUETYPE& value) {
// Insert space for new entry at index findA
// memmove(entries+idx+1,entries+idx,count-idx);
for (int i = count; i > idx; i--) {
entries[i] = entries[i-1];
}
// Create a new entry
BTreeEntry<KEYTYPE,VALUETYPE>* newentry = new BTreeEntry<KEYTYPE,VALUETYPE>();
newentry->SetKey(key);
newentry->SetValue(value);
entries[idx] = newentry;
// Update counter
count++;
memoryUsage += newentry->GetValueSizeInMemory() +
newentry->GetKeySizeInMemory();
modified = true;
}
template<class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::InsertLeftmost(const KEYTYPE& key,
const VALUETYPE& value) {
// Find suited position
int findA = GetLeftmostEntryIndexByKey(key);
InsertAt(findA,key,value);
}
template<class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::InsertRightmost(const KEYTYPE& key,
const VALUETYPE& value) {
// Find suited position
int findA = GetRightmostEntryIndexByKey(key);
InsertAt(findA,key,value);
}
template<class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::InsertUnsorted(const KEYTYPE& key,
const VALUETYPE& value) {
if (!unsorted) {
sortedRangeEnd = entries.begin() + count;
unsorted = true;
} else {
multipleUnsorted = true;
}
InsertAt(count,key,value);
}
template<class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::checkSort() {
if (multipleUnsorted) {
typename std::vector<BTreeEntry<KEYTYPE,VALUETYPE>* >::iterator it =
entries.begin() + count;
std::sort(sortedRangeEnd, it,sortPred);
std::inplace_merge(entries.begin(),sortedRangeEnd,it,sortPred);
unsorted = false;
multipleUnsorted = false;
} else if (unsorted) {
if (count > 1) {
BTreeEntry<KEYTYPE,VALUETYPE>* lastX = entries[count-1];
count--;
int idx = GetRightmostEntryIndexByKey(lastX->GetKey());
count++;
for (int i = count-1; i > idx; i--) {
entries[i] = entries[i-1];
}
entries[idx] = lastX;
}
unsorted = false;
}
}
template<class KEYTYPE,typename VALUETYPE>
bool BTreeNode<KEYTYPE,VALUETYPE>::InsertUnique(const KEYTYPE& key,
const VALUETYPE& value) {
int findA = GetLeftmostEntryIndexByKey(key);
// Do not add, if key already exists
if ((findA < count) && (entries[findA]->keyEquals(key))) {
return false;
} else {
InsertAt(findA,key,value);
return true;
}
}
template<class KEYTYPE,typename VALUETYPE>
bool BTreeNode<KEYTYPE,VALUETYPE>::ProbeIsInternal(SmiRecordFile *file,
const NodeId pointer)
{
SmiRecord record;
int RecordSelected = file->SelectRecord(pointer, record, SmiFile::ReadOnly );
assert(RecordSelected);
bool result;
// Just read the first byte, which contains the internal flag
int RecordRead = record.Read(&result, sizeof(bool), 0);
assert( RecordRead );
return result;
}
template<class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::Read(SmiRecordFile *file,
const NodeId pointer)
{
SmiRecord record;
int RecordSelected = file->SelectRecord(pointer, record, SmiFile::ReadOnly );
assert(RecordSelected);
ReadRecord(record);
if (dbgPrintNodeLoading) {
cout << "Loaded node " << myNodeId << endl;
}
}
template <class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::ReadInternals(char* buffer, int& offset)
{
// Caveat! ProbeIsInternal depends on the order here
// Caveat! SizeOfEmptyNode() depends on entries here
bool in;
memcpy( &in, buffer + offset, sizeof( internal ) );
offset += sizeof( internal );
assert(in == internal);
memcpy( &count, buffer + offset, sizeof( count ) );
offset += sizeof( count );
memcpy( &rightPointer, buffer + offset, sizeof( NodeId ) );
offset += sizeof( NodeId );
if (internal) {
memcpy( &childNodeIsLeaf, buffer + offset, sizeof( bool ) );
offset += sizeof( bool );
leftPointer = 0;
} else {
memcpy( &leftPointer, buffer + offset, sizeof( NodeId ) );
offset += sizeof( NodeId );
childNodeIsLeaf = false; // but has basically no meaning
}
assert(count >= 0);
assert(count <= GetMaxEntries() );
}
template <class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::ReadRecord(SmiRecord& record)
{
int offset = 0;
int size = GetSizeInRecord();
char buffer[size + 1];
int RecordRead = record.Read(buffer, size, offset);
assert(RecordRead == size);
ReadInternals(buffer, offset);
for( int i = 0; i < count; i++ ) {
entries[i] = new BTreeEntry<KEYTYPE,VALUETYPE>();
entries[i]->Read(buffer,offset,keyTypeListExpr,valueTypeListExpr,
extendedKeysFile, extendedValuesFile);
memoryUsage += entries[i]->GetValueSizeInMemory() +
entries[i]->GetKeySizeInMemory();
}
bytesWasted = recordSize - offset;
modified = false;
}
template<class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::Write( SmiRecordFile *file,
const SmiRecordId pointer )
{
if (modified) {
SmiRecord record;
int RecordSelected = file->SelectRecord( pointer, record, SmiFile::Update );
assert( RecordSelected );
WriteRecord( record );
modified = false;
}
}
template<class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::WriteRecord( SmiRecord& record ) {
if( modified ) {
int offset = 0;
int size = GetSizeInRecord();
char buffer[size + 1];
memset( buffer, 0, size + 1 );
// Caveat! ProbeIsInternal depends on the order here
// Caveat! SizeOfEmptyNode() depends on entries here
// Writes internals
memcpy( buffer + offset, &internal, sizeof( internal) );
offset += sizeof( internal );
memcpy( buffer + offset, &count, sizeof( count ) );
offset += sizeof( count );
memcpy( buffer + offset, &rightPointer, sizeof( NodeId ) );
offset += sizeof( NodeId );
if (internal) {
memcpy( buffer + offset, &childNodeIsLeaf, sizeof( bool ) );
offset += sizeof( bool );
} else {
memcpy( buffer + offset, &leftPointer, sizeof( NodeId ) );
offset += sizeof( NodeId );
}
assert(offset <= GetSizeOfEmptyNode());
assert(count <= GetMaxEntries() );
// Now write the entry array.
checkSort();
for( int i = 0; i < count; i++ ) {
entries[i]->Write(buffer, offset, keyTypeListExpr,valueTypeListExpr,
extendedKeysFile, extendedValuesFile,
maxKeysize, maxValuesize);
}
bytesWasted = recordSize - offset;
assert(offset <= size);
assert(size <= recordSize);
int RecordWritten = record.Write( buffer, size, 0 );
assert( RecordWritten == size );
modified = false;
}
}
template <class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::MoveEntries(
BTreeNode<KEYTYPE,VALUETYPE>* src, int start, int end) {
if (count == 0) { // Easy: just copy
for (int i = start; i <= end; i++) {
entries[i-start] = src->entries[i];
memoryUsage += entries[i-start]->GetValueSizeInMemory() +
entries[i-start]->GetKeySizeInMemory();
}
count = end-start+1;
modified = true;
src->RemoveEntries(start,end);
} else {
// TODO: insert and sort entries array
const bool TODO = false;
assert(TODO);
}
}
template <class KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::MoveEntryToLeftmost(
BTreeNode<KEYTYPE,VALUETYPE>* src, int srcidx) {
return MoveEntry(src,srcidx,-1);
}
template <class KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::MoveEntryToRightmost(
BTreeNode<KEYTYPE,VALUETYPE>* src, int srcidx) {
return MoveEntry(src,srcidx,-2);
}
template <class KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::MoveEntry(
BTreeNode<KEYTYPE,VALUETYPE>* src, int srcidx,
int dstidx) {
int i;
BTreeEntry<KEYTYPE,VALUETYPE> const& ent = src->GetEntry(srcidx);
int findA;
if (dstidx == -1) {
findA = GetLeftmostEntryIndexByKey(ent.GetKey());
} else if (dstidx == -2) {
findA = GetRightmostEntryIndexByKey(ent.GetKey());
} else {
findA = dstidx;
}
for (i = count; i > findA; i--) {
entries[i] = entries[i-1];
}
entries[i] = src->entries[srcidx];
src->RemoveEntry(srcidx);
count++;
modified = true;
memoryUsage += entries[findA]->GetValueSizeInMemory() +
entries[findA]->GetKeySizeInMemory();
return i;
}
template <class KEYTYPE,typename VALUETYPE>
BTreeEntry<KEYTYPE,VALUETYPE> const*
BTreeNode<KEYTYPE,VALUETYPE>::GetEntryPtrByValue(const VALUETYPE& ns) {
for (int i = 0; i < count; i++) {
if (entries[i]->valueEquals(ns)) {
return entries[i];
}
}
return 0;
}
template <class KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::GetEntryIndexByValue(NodeId nid) {
// Using extended index
if (rightPointer == nid) {
return count;
} else {
for (int i = 0; i < count; i++) {
if (entries[i]->valueEquals(nid)) {
return i;
}
}
}
assert(false);
return -1;
}
template <class KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::GetLeftmostEntryIndexByKey(
const KEYTYPE& ent) {
int i;
int findA = 0;
int findB = count - 1;
// Fast find of right index:
// after this loop, findA == findB+1
// and findA is the first/leftmost entry where all keys left are smaller
while (findB >= findA) {
i = (findB+findA)/2;
if (entries[i]->keyLessThan(ent)) {
findA = i+1;
} else {
findB = i-1;
}
}
return findA;
}
template <class KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::GetRightmostEntryIndexByKey(
const KEYTYPE& ent) {
int i;
int findA = 0;
int findB = count - 1;
// Fast find of right index:
// after this loop, findA == findB+1
// and findA is the first/leftmost entry where all keys left are smaller
// or equal
while (findB >= findA) {
i = (findB+findA)/2;
if (entries[i]->keyGreaterThan(ent)) {
findB = i-1;
} else {
findA = i+1;
}
}
return findA;
}
template <class KEYTYPE,typename VALUETYPE>
int BTreeNode<KEYTYPE,VALUETYPE>::GetEntryIndexByKeyValue(const KEYTYPE& key,
const VALUETYPE& value) {
int i;
for (i = 0; i < count; i++) {
if (entries[i]->keyEquals(key)) {
if (entries[i]->valueEquals(value)) {
return i;
}
}
}
return -1;
}
template <class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::SetRightPointer(NodeId _rightPointer) {
assert(_rightPointer != myNodeId);
rightPointer = _rightPointer;
modified = true;
}
template <class KEYTYPE,typename VALUETYPE>
void BTreeNode<KEYTYPE,VALUETYPE>::SetLeftPointer(NodeId _leftPointer) {
assert(_leftPointer != myNodeId);
assert(!internal);
leftPointer = _leftPointer;
modified = true;
}
} // end namespace
#endif