#include <stdio.h>
#include "Tree.h"
#include "Block.h"
#include "BlockCache.h"
#include "Debug.h"
#include "DirItem.h"
#include "Iterators.h"
#include "StatItem.h"
#include "Volume.h"
const uint32 kMaxTreeHeight = 5;
\class Tree
\brief Represents the on-disk S+Tree.
This class actually doesn't have that much functionality. GetBlock()
and GetNode() are used to request a block/tree node from disk,
FindDirEntry() searches an entry in a directory and FindStatItem()
gets the stat data for an object. The mammoth part of the code is
located in the iterator code (Iterators.{cpp,h}).
*/
Tree::Tree()
: fVolume(NULL),
fBlockCache(NULL),
fRootNode(NULL),
fTreeHeight(0)
{
}
Tree::~Tree()
{
if (fRootNode)
fRootNode->Put();
}
status_t
Tree::Init(Volume *volume, Node *rootNode, uint32 treeHeight)
{
status_t error = (volume && volume->GetBlockCache() && rootNode
? B_OK : B_BAD_VALUE);
if (error == B_OK) {
if (treeHeight > kMaxTreeHeight) {
INFORM(("WARNING: tree height greater maximal height: %" B_PRIu32
"\n", treeHeight));
}
fVolume = volume;
fBlockCache = fVolume->GetBlockCache();
fRootNode = rootNode;
fRootNode->Get();
fTreeHeight = treeHeight;
}
return error;
}
status_t
Tree::InitCheck() const
{
return (fBlockCache && fRootNode && fTreeHeight ? B_OK : B_NO_INIT);
}
uint32
Tree::GetTreeHeight() const
{
return fTreeHeight;
}
uint32
Tree::GetBlockSize() const
{
if (fBlockCache)
return fBlockCache->GetBlockSize();
return 0;
}
BlockCache *
Tree::GetBlockCache() const
{
return fBlockCache;
}
Node *
Tree::GetRootNode() const
{
return fRootNode;
}
status_t
Tree::GetBlock(uint64 blockNumber, Block **block)
{
status_t error = (block ? InitCheck() : B_BAD_VALUE);
if (error == B_OK)
error = fBlockCache->GetBlock(blockNumber, block);
return error;
}
status_t
Tree::GetNode(uint64 blockNumber, Node **node)
{
status_t error = (node ? InitCheck() : B_BAD_VALUE);
if (error == B_OK) {
Block *block;
error = fBlockCache->GetBlock(blockNumber, &block);
if (error == B_OK) {
if (block->GetKind() == Block::KIND_UNKNOWN)
block->SetKind(Block::KIND_FORMATTED);
if (block->GetKind() == Block::KIND_FORMATTED) {
*node = block->ToNode();
if (!(*node)->IsChecked()) {
if ((*node)->IsInternal())
error = (*node)->ToInternalNode()->Check();
else if ((*node)->IsLeaf())
error = (*node)->ToLeafNode()->Check();
else
error = B_BAD_DATA;
if (error == B_OK)
(*node)->SetChecked(true);
}
} else {
block->Put();
error = B_BAD_DATA;
}
}
}
return error;
}
status_t
Tree::FindDirEntry(uint32 dirID, uint32 objectID, const char *name,
DirItem *foundItem, int32 *entryIndex)
{
status_t error = (name && foundItem && entryIndex ? InitCheck()
: B_BAD_VALUE);
if (error == B_OK) {
error = FindDirEntry(dirID, objectID, name, strlen(name), foundItem,
entryIndex);
}
return error;
}
status_t
Tree::FindDirEntry(uint32 dirID, uint32 objectID, const char *name,
size_t nameLen, DirItem *foundItem, int32 *entryIndex)
{
status_t error = (name && foundItem && entryIndex ? InitCheck()
: B_BAD_VALUE);
if (error == B_OK) {
uint64 offset = 0;
if (fVolume->GetKeyOffsetForName(name, nameLen, &offset) == B_OK) {
DirEntryIterator iterator(this, dirID, objectID, offset, true);
DirItem dirItem;
int32 index = 0;
error = B_ENTRY_NOT_FOUND;
while (iterator.GetPrevious(&dirItem, &index) == B_OK) {
size_t itemNameLen = 0;
if (const char *itemName
= dirItem.EntryNameAt(index, &itemNameLen)) {
if (itemNameLen == nameLen
&& !strncmp(name, itemName, nameLen)) {
*foundItem = dirItem;
*entryIndex = index;
error = B_OK;
break;
}
}
}
} else {
ObjectItemIterator iterator(this, dirID, objectID);
DirItem dirItem;
error = B_ENTRY_NOT_FOUND;
while (iterator.GetNext(&dirItem, TYPE_DIRENTRY) == B_OK) {
if (dirItem.Check() != B_OK)
continue;
int32 index = dirItem.IndexOfName(name);
if (index >= 0) {
*foundItem = dirItem;
*entryIndex = index;
error = B_OK;
break;
}
}
}
}
return error;
}
status_t
Tree::FindStatItem(uint32 dirID, uint32 objectID, StatItem *item)
{
status_t error = (item ? InitCheck() : B_BAD_VALUE);
if (error == B_OK) {
ItemIterator iterator(this);
error = iterator.InitCheck();
VKey k(dirID, objectID, SD_OFFSET, V1_SD_UNIQUENESS, KEY_FORMAT_3_5);
if (error == B_OK)
error = iterator.FindRightMost(&k, item);
}
return error;
}