Made CachedNode::SetTo[Header]() return a const node/header. Made some other methods

that were supposed to be const const as well.
Found one bug this way: in one case, a duplicate node might not have been part of a
transaction (and thus, was not written back). This bug only affected the Haiku version
of BFS, though.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14083 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-08-29 21:57:08 +00:00
parent 1509c79696
commit 0afc66fa69
2 changed files with 139 additions and 105 deletions
+116 -85
View File
@@ -25,7 +25,7 @@
#ifdef DEBUG
class NodeChecker {
public:
NodeChecker(bplustree_node *node, int32 nodeSize, const char *text)
NodeChecker(const bplustree_node *node, int32 nodeSize, const char *text)
:
fNode(node),
fSize(nodeSize),
@@ -47,7 +47,7 @@ class NodeChecker {
}
private:
bplustree_node *fNode;
const bplustree_node *fNode;
int32 fSize;
const char *fText;
};
@@ -95,7 +95,7 @@ CachedNode::Unset()
}
bplustree_node *
const bplustree_node *
CachedNode::SetTo(off_t offset, bool check)
{
if (fTree == NULL || fTree->fStream == NULL) {
@@ -155,18 +155,28 @@ CachedNode::SetToWritable(Transaction &transaction, off_t offset, bool check)
}
status_t
bplustree_node *
CachedNode::MakeWritable(Transaction &transaction)
{
if (fNode == NULL)
return B_NO_INIT;
return NULL;
return block_cache_make_writable(transaction.GetVolume()->BlockCache(),
fBlockNumber, transaction.ID());
if (block_cache_make_writable(transaction.GetVolume()->BlockCache(),
fBlockNumber, transaction.ID()) == B_OK)
return fNode;
return NULL;
}
bplustree_header *
CachedNode::MakeWritableHeader(Transaction &transaction)
{
return (bplustree_header *)MakeWritable(transaction);
}
const bplustree_header *
CachedNode::SetToHeader()
{
if (fTree == NULL || fTree->fStream == NULL) {
@@ -242,8 +252,8 @@ CachedNode::Free(Transaction &transaction, off_t offset)
// function is called, perhaps it should be done when the directory
// inode is closed or based on some calculation or whatever...
bplustree_header *header = fTree->fHeader;
if (fTree->fCachedHeader.MakeWritable(transaction) != B_OK)
bplustree_header *header = fTree->fCachedHeader.MakeWritableHeader(transaction);
if (header == NULL)
return B_IO_ERROR;
// if the node is the last one in the tree, we shrink
@@ -275,12 +285,13 @@ CachedNode::Allocate(Transaction &transaction, bplustree_node **_node, off_t *_o
Unset();
bplustree_header *header = fTree->fHeader;
bplustree_header *header;
status_t status;
// if there are any free nodes, recycle them
if (SetToWritable(transaction, header->FreeNode(), false) != NULL) {
if (fTree->fCachedHeader.MakeWritable(transaction) != B_OK)
if (SetToWritable(transaction, fTree->fHeader->FreeNode(), false) != NULL) {
header = fTree->fCachedHeader.MakeWritableHeader(transaction);
if (header == NULL)
return B_IO_ERROR;
// set new free node pointer
@@ -297,7 +308,8 @@ CachedNode::Allocate(Transaction &transaction, bplustree_node **_node, off_t *_o
if ((status = stream->Append(transaction, fTree->fNodeSize)) < B_OK)
return status;
if (fTree->fCachedHeader.MakeWritable(transaction) != B_OK)
header = fTree->fCachedHeader.MakeWritableHeader(transaction);
if (header == NULL)
return B_IO_ERROR;
// the maximum_size has to be changed before the call to SetTo() - or
@@ -379,18 +391,19 @@ BPlusTree::SetTo(Transaction &transaction, Inode *stream, int32 nodeSize)
fStream = stream;
fHeader = fCachedHeader.SetToWritableHeader(transaction);
if (fHeader == NULL) {
bplustree_header *header = fCachedHeader.SetToWritableHeader(transaction);
if (header == NULL) {
// allocate space for new header + node!
fStatus = stream->SetFileSize(transaction, nodeSize * 2);
if (fStatus < B_OK)
RETURN_ERROR(fStatus);
fHeader = fCachedHeader.SetToWritableHeader(transaction);
if (fHeader == NULL)
header = fCachedHeader.SetToWritableHeader(transaction);
if (header == NULL)
RETURN_ERROR(fStatus = B_ERROR);
}
fHeader = header;
fAllowDuplicates = ((stream->Mode() & S_INDEX_DIR) == S_INDEX_DIR
&& stream->BlockRun() != stream->Parent())
|| (stream->Mode() & S_ALLOW_DUPS) != 0;
@@ -398,17 +411,17 @@ BPlusTree::SetTo(Transaction &transaction, Inode *stream, int32 nodeSize)
fNodeSize = nodeSize;
// initialize b+tree header
fHeader->magic = HOST_ENDIAN_TO_BFS_INT32(BPLUSTREE_MAGIC);
fHeader->node_size = HOST_ENDIAN_TO_BFS_INT32(fNodeSize);
fHeader->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1);
fHeader->data_type = HOST_ENDIAN_TO_BFS_INT32(ModeToKeyType(stream->Mode()));
fHeader->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(nodeSize);
fHeader->free_node_pointer = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(nodeSize * 2);
header->magic = HOST_ENDIAN_TO_BFS_INT32(BPLUSTREE_MAGIC);
header->node_size = HOST_ENDIAN_TO_BFS_INT32(fNodeSize);
header->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1);
header->data_type = HOST_ENDIAN_TO_BFS_INT32(ModeToKeyType(stream->Mode()));
header->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(nodeSize);
header->free_node_pointer = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(nodeSize * 2);
// initialize b+tree root node
CachedNode cached(this);
cached.SetToWritable(transaction, fHeader->RootNode(), false);
cached.SetToWritable(transaction, header->RootNode(), false);
if (cached.Node() == NULL)
RETURN_ERROR(B_IO_ERROR);
@@ -437,7 +450,8 @@ BPlusTree::SetTo(Inode *stream)
if (fHeader->MaximumSize() != stream->Size()) {
FATAL(("B+tree header size doesn't fit file size!\n"));
fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(stream->Size());
// we can't change the header since we don't have a transaction
//fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(stream->Size());
}
if (fHeader->Magic() != BPLUSTREE_MAGIC
|| (fHeader->RootNode() % fHeader->NodeSize()) != 0
@@ -614,7 +628,7 @@ BPlusTree::CompareKeys(const void *key1, int keyLength1, const void *key2, int k
status_t
BPlusTree::FindKey(bplustree_node *node, const uint8 *key, uint16 keyLength,
BPlusTree::FindKey(const bplustree_node *node, const uint8 *key, uint16 keyLength,
uint16 *_index, off_t *_next)
{
#ifdef DEBUG
@@ -684,7 +698,7 @@ BPlusTree::SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLeng
nodeAndKey.nodeOffset = fHeader->RootNode();
CachedNode cached(this);
bplustree_node *node;
const bplustree_node *node;
while ((node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) {
// if we are already on leaf level, we're done
if (node->OverflowLink() == BPLUSTREE_NULL) {
@@ -713,11 +727,12 @@ BPlusTree::SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLeng
/** This will find a free duplicate fragment in the given bplustree_node.
* The CachedNode will be set to the readable fragment on success.
* The CachedNode will be set to the writable fragment on success.
*/
status_t
BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode &cached,
BPlusTree::FindFreeDuplicateFragment(Transaction &transaction,
const bplustree_node *node, CachedNode &cached,
off_t *_offset, bplustree_node **_fragment, uint32 *_index)
{
off_t *values = node->Values();
@@ -726,8 +741,8 @@ BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode &cached,
if (bplustree_node::LinkType(values[i]) != BPLUSTREE_DUPLICATE_FRAGMENT)
continue;
bplustree_node *fragment = cached.SetTo(bplustree_node::FragmentOffset(values[i]),
false);
const bplustree_node *fragment = cached.SetTo(
bplustree_node::FragmentOffset(values[i]), false);
if (fragment == NULL) {
FATAL(("Could not get duplicate fragment at %Ld\n", values[i]));
continue;
@@ -740,8 +755,11 @@ BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode &cached,
if (array->count == 0) {
// found an unused fragment
*_fragment = cached.MakeWritable(transaction);
if (*_fragment == NULL)
return B_IO_ERROR;
*_offset = bplustree_node::FragmentOffset(values[i]);
*_fragment = fragment;
*_index = j;
return B_OK;
}
@@ -753,7 +771,7 @@ BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode &cached,
status_t
BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
bplustree_node *node, uint16 index, off_t value)
const bplustree_node *node, uint16 index, off_t value)
{
CachedNode cachedDuplicate(this);
off_t *values = node->Values();
@@ -819,7 +837,7 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
}
// update the main pointer to link to a duplicate node
if (cached.MakeWritable(transaction) != B_OK)
if (cached.MakeWritable(transaction) == NULL)
return B_IO_ERROR;
values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_NODE, offset);
@@ -834,7 +852,7 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
// search for free space in the duplicate nodes of that key
duplicate_array *array;
bplustree_node *duplicate;
const bplustree_node *duplicate;
off_t duplicateOffset;
do {
duplicateOffset = bplustree_node::FragmentOffset(oldValue);
@@ -851,10 +869,12 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
} while (array->count >= NUM_DUPLICATE_VALUES
&& (oldValue = duplicate->RightLink()) != BPLUSTREE_NULL);
if (array->count < NUM_DUPLICATE_VALUES) {
cachedDuplicate.MakeWritable(transaction);
array = duplicate->DuplicateArray();
bplustree_node *writableDuplicate = cachedDuplicate.MakeWritable(transaction);
if (writableDuplicate == NULL)
return B_IO_ERROR;
if (array->count < NUM_DUPLICATE_VALUES) {
array = writableDuplicate->DuplicateArray();
array->Insert(value);
} else {
// no space left - add a new duplicate node
@@ -865,7 +885,7 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
return status;
// link the two nodes together
duplicate->right_link = HOST_ENDIAN_TO_BFS_INT64(offset);
writableDuplicate->right_link = HOST_ENDIAN_TO_BFS_INT64(offset);
newDuplicate->left_link = HOST_ENDIAN_TO_BFS_INT64(duplicateOffset);
array = newDuplicate->DuplicateArray();
@@ -882,10 +902,8 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
uint32 fragmentIndex = 0;
bplustree_node *fragment;
if (FindFreeDuplicateFragment(node, cachedDuplicate, &offset, &fragment, &fragmentIndex) == B_OK) {
if (cachedDuplicate.MakeWritable(transaction) != B_OK)
return B_IO_ERROR;
} else {
if (FindFreeDuplicateFragment(transaction, node, cachedDuplicate,
&offset, &fragment, &fragmentIndex) != B_OK) {
// allocate a new duplicate fragment node
if ((status = cachedDuplicate.Allocate(transaction, &fragment, &offset)) < B_OK)
return status;
@@ -897,7 +915,7 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
array->Insert(oldValue);
array->Insert(value);
if (cached.MakeWritable(transaction) != B_OK)
if (cached.MakeWritable(transaction) == NULL)
return B_IO_ERROR;
values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_FRAGMENT, offset, fragmentIndex);
@@ -947,6 +965,11 @@ BPlusTree::InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyL
}
/** Splits the \a node into two halves - the other half will be put into \a other.
* It also takes care to create a new overflow link if the node to split is an
* index node.
*/
status_t
BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *other,
off_t otherOffset, uint16 *_keyIndex, uint8 *key, uint16 *_keyLength, off_t *_value)
@@ -1178,6 +1201,10 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
{
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH)
RETURN_ERROR(B_BAD_VALUE);
#ifdef DEBUG
if (value < 0)
panic("tried to insert invalid value %Ld!\n", value);
#endif
// lock access to stream
WriteLocked locked(fStream->Lock());
@@ -1192,7 +1219,7 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
keyBuffer[keyLength] = 0;
node_and_key nodeAndKey;
bplustree_node *node;
const bplustree_node *node;
CachedNode cached(this);
while (stack.Pop(&nodeAndKey) && (node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) {
@@ -1212,14 +1239,15 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
}
}
if (cached.MakeWritable(transaction) != B_OK)
bplustree_node *writableNode = cached.MakeWritable(transaction);
if (writableNode == NULL)
return B_IO_ERROR;
// is the node big enough to hold the pair?
if (int32(round_up(sizeof(bplustree_node) + node->AllKeyLength() + keyLength)
+ (node->NumKeys() + 1) * (sizeof(uint16) + sizeof(off_t))) < fNodeSize)
if (int32(round_up(sizeof(bplustree_node) + writableNode->AllKeyLength() + keyLength)
+ (writableNode->NumKeys() + 1) * (sizeof(uint16) + sizeof(off_t))) < fNodeSize)
{
InsertKey(node, nodeAndKey.keyIndex, keyBuffer, keyLength, value);
InsertKey(writableNode, nodeAndKey.keyIndex, keyBuffer, keyLength, value);
UpdateIterators(nodeAndKey.nodeOffset, BPLUSTREE_NULL, nodeAndKey.keyIndex, 0, 1);
return B_OK;
@@ -1253,7 +1281,7 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
RETURN_ERROR(status);
}
if (SplitNode(node, nodeAndKey.nodeOffset, other, otherOffset,
if (SplitNode(writableNode, nodeAndKey.nodeOffset, other, otherOffset,
&nodeAndKey.keyIndex, keyBuffer, &keyLength, &value) < B_OK) {
// free root node & other node here
cachedOther.Free(transaction, otherOffset);
@@ -1267,7 +1295,7 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
#endif
UpdateIterators(nodeAndKey.nodeOffset, otherOffset, nodeAndKey.keyIndex,
node->NumKeys(), 1);
writableNode->NumKeys(), 1);
// update the right link of the node in the left of the new node
if ((other = cachedOther.SetToWritable(transaction, other->LeftLink())) != NULL) {
@@ -1278,10 +1306,10 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
if (newRoot != BPLUSTREE_NULL) {
bplustree_node *root = cachedNewRoot.Node();
InsertKey(root, 0, keyBuffer, keyLength, node->LeftLink());
InsertKey(root, 0, keyBuffer, keyLength, writableNode->LeftLink());
root->overflow_link = HOST_ENDIAN_TO_BFS_INT64(nodeAndKey.nodeOffset);
bplustree_header *header = fCachedHeader.SetToWritableHeader(transaction);
bplustree_header *header = fCachedHeader.MakeWritableHeader(transaction);
if (header == NULL)
return B_IO_ERROR;
@@ -1302,7 +1330,7 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
*/
status_t
BPlusTree::RemoveDuplicate(Transaction &transaction, bplustree_node *node,
BPlusTree::RemoveDuplicate(Transaction &transaction, const bplustree_node *node,
CachedNode &cached, uint16 index, off_t value)
{
off_t *values = node->Values();
@@ -1334,7 +1362,7 @@ BPlusTree::RemoveDuplicate(Transaction &transaction, bplustree_node *node,
// remove the array from the fragment node if it is empty
if (array->count == 1) {
// set the link to the remaining value
if (cached.MakeWritable(transaction) != B_OK)
if (cached.MakeWritable(transaction) == NULL)
return B_IO_ERROR;
values[index] = array->values[0];
@@ -1399,7 +1427,7 @@ BPlusTree::RemoveDuplicate(Transaction &transaction, bplustree_node *node,
if (left == BPLUSTREE_NULL) {
// the duplicate link points to us
if (cached.MakeWritable(transaction) != B_OK)
if (cached.MakeWritable(transaction) == NULL)
return B_IO_ERROR;
if (array->count == 1) {
@@ -1453,11 +1481,9 @@ BPlusTree::RemoveDuplicate(Transaction &transaction, bplustree_node *node,
bplustree_node *fragment = NULL;
uint32 fragmentIndex = 0;
off_t offset;
if (FindFreeDuplicateFragment(node, cachedOther, &offset, &fragment, &fragmentIndex) == B_OK) {
if (FindFreeDuplicateFragment(transaction, node, cachedOther,
&offset, &fragment, &fragmentIndex) == B_OK) {
// move to other node
if (cachedOther.MakeWritable(transaction) != B_OK)
return B_IO_ERROR;
duplicate_array *target = fragment->FragmentAt(fragmentIndex);
memcpy(target, array, (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
@@ -1470,7 +1496,7 @@ BPlusTree::RemoveDuplicate(Transaction &transaction, bplustree_node *node,
fNodeSize - (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
}
if (cached.MakeWritable(transaction) != B_OK)
if (cached.MakeWritable(transaction) == NULL)
return B_IO_ERROR;
values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_FRAGMENT,
@@ -1559,7 +1585,7 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
RETURN_ERROR(B_ERROR);
node_and_key nodeAndKey;
bplustree_node *node;
const bplustree_node *node;
CachedNode cached(this);
while (stack.Pop(&nodeAndKey) && (node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) {
@@ -1591,7 +1617,8 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
}
}
if (cached.MakeWritable(transaction) != B_OK)
bplustree_node *writableNode = cached.MakeWritable(transaction);
if (writableNode == NULL)
return B_IO_ERROR;
// if it's an empty root node, we have to convert it
@@ -1600,17 +1627,18 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
if (nodeAndKey.nodeOffset == fHeader->RootNode()
&& node->NumKeys() == 0
|| node->NumKeys() == 1 && node->IsLeaf()) {
node->overflow_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
node->all_key_count = 0;
node->all_key_length = 0;
writableNode->overflow_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
writableNode->all_key_count = 0;
writableNode->all_key_length = 0;
// if we've cleared the root node, reset the maximum
// number of levels in the header
if (nodeAndKey.nodeOffset == fHeader->RootNode()) {
if (fCachedHeader.MakeWritable(transaction) != B_OK)
bplustree_header *header = fCachedHeader.MakeWritableHeader(transaction);
if (header == NULL)
return B_IO_ERROR;
fHeader->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1);
header->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1);
}
return B_OK;
}
@@ -1618,9 +1646,9 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
// if there is only one key left, we don't have to remove
// it, we can just dump the node (index nodes still have
// the overflow link, so we have to drop the last key)
if (node->NumKeys() > 1
|| !node->IsLeaf() && node->NumKeys() == 1) {
RemoveKey(node, nodeAndKey.keyIndex);
if (writableNode->NumKeys() > 1
|| !writableNode->IsLeaf() && writableNode->NumKeys() == 1) {
RemoveKey(writableNode, nodeAndKey.keyIndex);
return B_OK;
}
@@ -1628,12 +1656,13 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
// we have to update the right/left link of the
// siblings first
CachedNode otherCached(this);
bplustree_node *other = otherCached.SetToWritable(transaction, node->LeftLink());
bplustree_node *other = otherCached.SetToWritable(transaction,
writableNode->LeftLink());
if (other != NULL)
other->right_link = node->right_link;
other->right_link = writableNode->right_link;
if ((other = otherCached.SetToWritable(transaction, node->RightLink())) != NULL)
other->left_link = node->left_link;
other->left_link = writableNode->left_link;
cached.Free(transaction, nodeAndKey.nodeOffset);
}
@@ -1665,7 +1694,7 @@ BPlusTree::Replace(Transaction &transaction, const uint8 *key, uint16 keyLength,
off_t nodeOffset = fHeader->RootNode();
CachedNode cached(this);
bplustree_node *node;
const bplustree_node *node;
while ((node = cached.SetTo(nodeOffset)) != NULL) {
uint16 keyIndex = 0;
@@ -1674,9 +1703,11 @@ BPlusTree::Replace(Transaction &transaction, const uint8 *key, uint16 keyLength,
if (node->OverflowLink() == BPLUSTREE_NULL) {
if (status == B_OK) {
status = cached.MakeWritable(transaction);
if (status == B_OK)
node->Values()[keyIndex] = value;
bplustree_node *writableNode = cached.MakeWritable(transaction);
if (writableNode != NULL)
writableNode->Values()[keyIndex] = value;
else
status = B_IO_ERROR;
}
return status;
@@ -1716,7 +1747,7 @@ BPlusTree::Find(const uint8 *key, uint16 keyLength, off_t *_value)
off_t nodeOffset = fHeader->RootNode();
CachedNode cached(this);
bplustree_node *node;
const bplustree_node *node;
#ifdef DEBUG
int32 levels = 0;
@@ -1780,7 +1811,7 @@ TreeIterator::Goto(int8 to)
off_t nodeOffset = fTree->fHeader->RootNode();
CachedNode cached(fTree);
bplustree_node *node;
const bplustree_node *node;
while ((node = cached.SetTo(nodeOffset)) != NULL) {
// is the node a leaf node?
@@ -1845,7 +1876,7 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxL
ReadLocked locked(fTree->fStream->Lock());
CachedNode cached(fTree);
bplustree_node *node;
const bplustree_node *node;
if (fDuplicateNode != BPLUSTREE_NULL) {
// regardless of traverse direction the duplicates are always presented in
@@ -1981,7 +2012,7 @@ TreeIterator::Find(const uint8 *key, uint16 keyLength)
off_t nodeOffset = fTree->fHeader->RootNode();
CachedNode cached(fTree);
bplustree_node *node;
const bplustree_node *node;
while ((node = cached.SetTo(nodeOffset)) != NULL) {
uint16 keyIndex = 0;
off_t nextOffset;
@@ -2121,7 +2152,7 @@ bplustree_node::DuplicateAt(off_t offset, bool isFragment, int8 index) const
*/
uint32
bplustree_node::FragmentsUsed(uint32 nodeSize)
bplustree_node::FragmentsUsed(uint32 nodeSize) const
{
uint32 used = 0;
for (uint32 i = 0; i < MaxFragments(nodeSize); i++) {
@@ -2135,7 +2166,7 @@ bplustree_node::FragmentsUsed(uint32 nodeSize)
#ifdef DEBUG
status_t
bplustree_node::CheckIntegrity(uint32 nodeSize)
bplustree_node::CheckIntegrity(uint32 nodeSize) const
{
if (NumKeys() > nodeSize || AllKeyLength() > nodeSize)
DEBUGGER(("invalid node: key/length count"));
+21 -18
View File
@@ -41,8 +41,8 @@ struct bplustree_header {
off_t MaximumSize() const { return BFS_ENDIAN_TO_HOST_INT64(maximum_size); }
uint32 MaxNumberOfLevels() const { return BFS_ENDIAN_TO_HOST_INT32(max_number_of_levels); }
inline bool CheckNode(bplustree_node *node);
inline bool IsValidLink(off_t link);
inline bool CheckNode(bplustree_node *node) const;
inline bool IsValidLink(off_t link) const;
} _PACKED;
#define BPLUSTREE_MAGIC 0x69f6c2e8
@@ -87,9 +87,9 @@ struct bplustree_node {
void Initialize();
uint8 CountDuplicates(off_t offset, bool isFragment) const;
off_t DuplicateAt(off_t offset, bool isFragment, int8 index) const;
uint32 FragmentsUsed(uint32 nodeSize);
inline duplicate_array *FragmentAt(int8 index);
inline duplicate_array *DuplicateArray();
uint32 FragmentsUsed(uint32 nodeSize) const;
inline duplicate_array *FragmentAt(int8 index) const;
inline duplicate_array *DuplicateArray() const;
static inline uint8 LinkType(off_t link);
static inline off_t MakeLink(uint8 type, off_t link, uint32 fragmentIndex = 0);
@@ -99,7 +99,7 @@ struct bplustree_node {
static inline uint32 MaxFragments(uint32 nodeSize);
#ifdef DEBUG
status_t CheckIntegrity(uint32 nodeSize);
status_t CheckIntegrity(uint32 nodeSize) const;
#endif
} _PACKED;
@@ -160,11 +160,13 @@ class CachedNode {
Unset();
}
bplustree_node *SetTo(off_t offset, bool check = true);
const bplustree_node *SetTo(off_t offset, bool check = true);
bplustree_node *SetToWritable(Transaction &transaction, off_t offset, bool check = true);
bplustree_node *MakeWritable(Transaction &transaction);
const bplustree_header *SetToHeader();
bplustree_header *SetToWritableHeader(Transaction &transaction);
bplustree_header *SetToHeader();
status_t MakeWritable(Transaction &transaction);
bplustree_header *MakeWritableHeader(Transaction &transaction);
void UnsetUnchanged(Transaction &transaction);
void Unset();
@@ -225,21 +227,22 @@ class BPlusTree {
// no implementation
int32 CompareKeys(const void *key1, int keylength1, const void *key2, int keylength2);
status_t FindKey(bplustree_node *node, const uint8 *key, uint16 keyLength,
status_t FindKey(const bplustree_node *node, const uint8 *key, uint16 keyLength,
uint16 *index = NULL, off_t *next = NULL);
status_t SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLength);
status_t FindFreeDuplicateFragment(bplustree_node *node, CachedNode &cached,
status_t FindFreeDuplicateFragment(Transaction &transaction,
const bplustree_node *node, CachedNode &cached,
off_t *_offset, bplustree_node **_fragment, uint32 *_index);
status_t InsertDuplicate(Transaction &transaction, CachedNode &cached,
bplustree_node *node, uint16 index, off_t value);
const bplustree_node *node, uint16 index, off_t value);
void InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyLength,
off_t value);
status_t SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *other,
off_t otherOffset, uint16 *_keyIndex, uint8 *key, uint16 *_keyLength,
off_t *_value);
status_t RemoveDuplicate(Transaction &transaction, bplustree_node *node,
status_t RemoveDuplicate(Transaction &transaction, const bplustree_node *node,
CachedNode &cached, uint16 keyIndex, off_t value);
void RemoveKey(bplustree_node *node, uint16 index);
@@ -253,7 +256,7 @@ class BPlusTree {
friend class CachedNode;
Inode *fStream;
bplustree_header *fHeader;
const bplustree_header *fHeader;
CachedNode fCachedHeader;
int32 fNodeSize;
bool fAllowDuplicates;
@@ -402,7 +405,7 @@ TreeIterator::GetPreviousEntry(void *key, uint16 *keyLength, uint16 maxLength,
inline bool
bplustree_header::CheckNode(bplustree_node *node)
bplustree_header::CheckNode(bplustree_node *node) const
{
// sanity checks (links, all_key_count)
return IsValidLink(node->LeftLink())
@@ -413,7 +416,7 @@ bplustree_header::CheckNode(bplustree_node *node)
inline bool
bplustree_header::IsValidLink(off_t link)
bplustree_header::IsValidLink(off_t link) const
{
return link == BPLUSTREE_NULL || (link > 0 && link <= MaximumSize() - NodeSize());
}
@@ -459,14 +462,14 @@ bplustree_node::IsLeaf() const
inline duplicate_array *
bplustree_node::FragmentAt(int8 index)
bplustree_node::FragmentAt(int8 index) const
{
return (duplicate_array *)((off_t *)this + index * (NUM_FRAGMENT_VALUES + 1));
}
inline duplicate_array *
bplustree_node::DuplicateArray()
bplustree_node::DuplicateArray() const
{
return (duplicate_array *)&this->overflow_link;
}