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:
@@ -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"));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user