#include "Block.h"
#include <stdlib.h>
#include "BlockCache.h"
#include "Item.h"
#include "Key.h"
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);
}
Node::Node()
: Block()
{
}
uint16
Node::GetLevel() const
{
return le2h(GetHeader()->blk_level);
}
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;
}
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;
}
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);
}