#include "Block.h"
#include <stdlib.h>
#include "BlockCache.h"
#include "Item.h"
#include "Key.h"
\class Block
\brief Represents a cached disk block.
A block can either be formatted, i.e. a node in the S+Tree, or
unformatted containing raw data. When formatted, it can be converted to
a Node via the ToNode() method.
*/
Block::Block()
: fCache(NULL),
fNumber(0),
fData(NULL),
fFlags(KIND_UNKNOWN),
fRefCount(0)
{
}
Block::~Block()
{
_Unset();
}
BlockCache *
Block::GetCache() const
{
return fCache;
}
uint32
Block::GetBlockSize() const
{
return fCache->GetBlockSize();
}
void
Block::Get()
{
if (fCache)
fCache->GetBlock(this);
}
void
Block::Put()
{
if (fCache)
fCache->PutBlock(this);
}
uint64
Block::GetNumber() const
{
return fNumber;
}
void *
Block::GetData() const
{
return fData;
}
void
Block::SetKind(uint32 kind)
{
fFlags = (fFlags & ~(uint32)KIND_MASK) | (kind & KIND_MASK);
}
void
Block::SetChecked(bool checked)
{
if (checked)
fFlags |= CHECKED;
else
fFlags &= ~(uint32)CHECKED;
}
Node *
Block::ToNode()
{
Node *node = NULL;
if (IsFormatted())
node = static_cast<Node*>(this);
return node;
}
InternalNode *
Block::ToInternalNode()
{
InternalNode *internalNode = NULL;
if (Node *node = ToNode()) {
if (node->IsInternal())
internalNode = static_cast<InternalNode*>(node);
}
return internalNode;
}
LeafNode *
Block::ToLeafNode()
{
LeafNode *leafNode = NULL;
if (Node *node = ToNode()) {
if (node->IsLeaf())
leafNode = static_cast<LeafNode*>(node);
}
return leafNode;
}
bool
Block::IsFormatted() const
{
return (GetKind() == KIND_FORMATTED);
}
bool
Block::IsLeaf() const
{
if (Node *node = const_cast<Block*>(this)->ToNode())
return node->IsLeaf();
return false;
}
bool
Block::IsInternal() const
{
if (Node *node = const_cast<Block*>(this)->ToNode())
return node->IsInternal();
return false;
}
status_t
Block::_SetTo(BlockCache *cache, uint64 number)
{
_Unset();
status_t error = (cache ? B_OK : B_BAD_VALUE);
fCache = cache;
fNumber = number;
if (error == B_OK) {
fData = fCache->_GetBlock(fNumber);
if (!fData)
error = B_BAD_VALUE;
}
return error;
}
void
Block::_Unset()
{
if (fCache && fData)
fCache->_ReleaseBlock(fNumber, fData);
fData = NULL;
fCache = NULL;
fNumber = 0;
fData = NULL;
fFlags = KIND_UNKNOWN;
fRefCount = 0;
}
void
Block::_Get()
{
fRefCount++;
}
bool
Block::_Put()
{
return (--fRefCount == 0);
}
\class Node
\brief Represents a formatted cached disk block.
A Node can be converted to an InternalNode or LeafNode, depending on
its kind. Leaf nodes are located at level 1 only.
*/
Node::Node()
: Block()
{
}
uint16
Node::GetLevel() const
{
return le2h(GetHeader()->blk_level);
}
If the node is a leaf node, this number is indeed the number of the
items it contains. For internal node it is the number of keys, as oposed
to the number of child nodes, which is CountItems() + 1.
\return The number of child "items" the node contains/refers to.
*/
uint16
Node::CountItems() const
{
return le2h(GetHeader()->blk_nr_item);
}
uint16
Node::GetFreeSpace() const
{
return le2h(GetHeader()->blk_free_space);
}
bool
Node::IsLeaf() const
{
return (GetLevel() == 1);
}
bool
Node::IsInternal() const
{
return (GetLevel() > 1);
}
status_t
Node::Check() const
{
if (GetFreeSpace() + sizeof(block_head) > GetBlockSize()) {
FATAL(("WARNING: bad node %" B_PRIu64
": it declares more free space than "
"possibly being available (%u vs %lu)!\n", GetNumber(),
GetFreeSpace(), GetBlockSize() - sizeof(block_head)));
return B_BAD_DATA;
}
return B_OK;
}
block_head *
Node::GetHeader() const
{
return (block_head*)fData;
}
\class InternalNode
\brief Represents an internal tree node.
Internal tree node refer to its child nodes via DiskChilds.
*/
const Key *
InternalNode::GetKeys() const
{
return (const Key*)((uint8*)fData + sizeof(block_head));
}
const Key *
InternalNode::KeyAt(int32 index) const
{
const Key *k = NULL;
if (index >= 0 && index < CountItems())
k = GetKeys() + index;
return k;
}
const DiskChild *
InternalNode::GetChilds() const
{
return (DiskChild*)(GetKeys() + CountItems());
}
const DiskChild *
InternalNode::ChildAt(int32 index) const
{
const DiskChild *child = NULL;
if (index >= 0 && index <= CountItems())
child = GetChilds() + index;
return child;
}
status_t
InternalNode::Check() const
{
uint32 size = (const uint8*)(GetChilds() + (CountItems() + 1))
- (const uint8*)GetData();
if (size + GetFreeSpace() > GetBlockSize()) {
FATAL(("WARNING: bad internal node %" B_PRIu64
": it declares more free space "
"than possibly being available (size: %" B_PRIu32 ", "
"block size: %" B_PRIu32 ", "
"free space: %u)!\n", GetNumber(), size, GetBlockSize(),
GetFreeSpace()));
return B_BAD_DATA;
}
return B_OK;
}
\class LeafNode
\brief Represents an tree leaf node.
Leaf nodes contain items.
*/
const ItemHeader *
LeafNode::GetItemHeaders() const
{
return (ItemHeader*)((uint8*)fData + sizeof(block_head));
}
const ItemHeader *
LeafNode::ItemHeaderAt(int32 index) const
{
const ItemHeader *header = NULL;
if (index >= 0 && index < CountItems())
header = GetItemHeaders() + index;
return header;
}
status_t
LeafNode::GetLeftKey(VKey *k) const
{
status_t error = (k ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
if (const ItemHeader *header = ItemHeaderAt(0))
header->GetKey(k);
else
error = B_ERROR;
}
return error;
}
status_t
LeafNode::GetRightKey(VKey *k) const
{
status_t error = (k ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
if (const ItemHeader *header = ItemHeaderAt(CountItems() - 1))
header->GetKey(k);
else
error = B_ERROR;
}
return error;
}
status_t
LeafNode::Check() const
{
uint32 size = GetItemSpaceOffset();
if (size + GetFreeSpace() > GetBlockSize()) {
FATAL(("WARNING: bad leaf node %" B_PRIu64
": it declares more free space "
"than possibly being available "
"(min size: %" B_PRIu32 ", block size: "
"%" B_PRIu32 ", free space: %u)!\n",
GetNumber(), size, GetBlockSize(), GetFreeSpace()));
return B_BAD_DATA;
}
return B_OK;
}
uint32
LeafNode::GetItemSpaceOffset() const
{
return sizeof(ItemHeader) * CountItems() + sizeof(block_head);
}
\class DiskChild
\brief A structure referring to a child node of an internal node.
*/