* Removed unused code when USER is defined - the fs_shell no longer does this, but

provides a kernel emulation layer.
* Renamed all private BPlusTree methods to have the '_' prefix.
* Removed useless set_sem_owner() from Lock.h - all semaphores created in the kernel
  always belong to the system team automatically.
* Some cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21054 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2007-05-07 12:26:21 +00:00
parent 68f08f67f5
commit 3bef51f0ae
6 changed files with 345 additions and 293 deletions
+259 -198
View File
@@ -1,12 +1,13 @@
/* BPlusTree - BFS B+Tree implementation
/*
* Copyright 2001-2007, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License.
*
* Roughly based on 'btlib' written by Marcus J. Ranum - it shares
* no code but achieves binary compatibility with the on disk format.
*
* Copyright 2001-2006, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License.
*/
//! B+Tree implementation
#include "Debug.h"
#include "BPlusTree.h"
@@ -215,7 +216,8 @@ CachedNode::InternalSetTo(Transaction *transaction, off_t offset)
uint8 *block;
if (transaction != NULL) {
block = (uint8 *)block_cache_get_writable(volume->BlockCache(), fBlockNumber, transaction->ID());
block = (uint8 *)block_cache_get_writable(volume->BlockCache(),
fBlockNumber, transaction->ID());
fWritable = true;
} else {
block = (uint8 *)block_cache_get(volume->BlockCache(), fBlockNumber);
@@ -270,7 +272,8 @@ CachedNode::Free(Transaction &transaction, off_t offset)
status_t
CachedNode::Allocate(Transaction &transaction, bplustree_node **_node, off_t *_offset)
CachedNode::Allocate(Transaction &transaction, bplustree_node **_node,
off_t *_offset)
{
if (fTree == NULL || fTree->fHeader == NULL || fTree->fStream == NULL)
RETURN_ERROR(B_BAD_VALUE);
@@ -307,7 +310,8 @@ CachedNode::Allocate(Transaction &transaction, bplustree_node **_node, off_t *_o
// the maximum_size has to be changed before the call to SetTo() - or
// else it will fail because the requested node is out of bounds
off_t offset = header->MaximumSize();
header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(header->MaximumSize() + fTree->fNodeSize);
header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(header->MaximumSize()
+ fTree->fNodeSize);
if (SetToWritable(transaction, offset, false) != NULL) {
fNode->Initialize();
@@ -318,7 +322,8 @@ CachedNode::Allocate(Transaction &transaction, bplustree_node **_node, off_t *_o
}
// revert header size to old value
header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(header->MaximumSize() - fTree->fNodeSize);
header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(header->MaximumSize()
- fTree->fNodeSize);
RETURN_ERROR(B_ERROR);
}
@@ -374,8 +379,7 @@ BPlusTree::~BPlusTree()
}
/** Create a new B+Tree on the specified stream */
/*! Create a new B+Tree on the specified stream */
status_t
BPlusTree::SetTo(Transaction &transaction, Inode *stream, int32 nodeSize)
{
@@ -397,8 +401,8 @@ BPlusTree::SetTo(Transaction &transaction, Inode *stream, int32 nodeSize)
fHeader = header;
fAllowDuplicates = ((stream->Mode() & S_INDEX_DIR) == S_INDEX_DIR
&& stream->BlockRun() != stream->Parent())
|| (stream->Mode() & S_ALLOW_DUPS) != 0;
&& stream->BlockRun() != stream->Parent())
|| (stream->Mode() & S_ALLOW_DUPS) != 0;
fNodeSize = nodeSize;
@@ -460,13 +464,16 @@ BPlusTree::SetTo(Inode *stream)
fNodeSize = fHeader->NodeSize();
{
uint32 toMode[] = {S_STR_INDEX, S_INT_INDEX, S_UINT_INDEX, S_LONG_LONG_INDEX,
S_ULONG_LONG_INDEX, S_FLOAT_INDEX, S_DOUBLE_INDEX};
uint32 mode = stream->Mode() & (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX | S_LONG_LONG_INDEX
| S_ULONG_LONG_INDEX | S_FLOAT_INDEX | S_DOUBLE_INDEX);
uint32 toMode[] = {S_STR_INDEX, S_INT_INDEX, S_UINT_INDEX,
S_LONG_LONG_INDEX, S_ULONG_LONG_INDEX, S_FLOAT_INDEX,
S_DOUBLE_INDEX};
uint32 mode = stream->Mode() & (S_STR_INDEX | S_INT_INDEX
| S_UINT_INDEX | S_LONG_LONG_INDEX | S_ULONG_LONG_INDEX
| S_FLOAT_INDEX | S_DOUBLE_INDEX);
if (fHeader->DataType() > BPLUSTREE_DOUBLE_TYPE
|| (stream->Mode() & S_INDEX_DIR) && toMode[fHeader->DataType()] != mode
|| (stream->Mode() & S_INDEX_DIR)
&& toMode[fHeader->DataType()] != mode
|| !stream->IsContainer()) {
D( dump_bplustree_header(fHeader);
dump_inode(&stream->Node());
@@ -477,8 +484,8 @@ BPlusTree::SetTo(Inode *stream)
// although it's in stat.h, the S_ALLOW_DUPS flag is obviously unused
// in the original BFS code - we will honour it nevertheless
fAllowDuplicates = ((stream->Mode() & S_INDEX_DIR) == S_INDEX_DIR
&& stream->BlockRun() != stream->Parent())
|| (stream->Mode() & S_ALLOW_DUPS) != 0;
&& stream->BlockRun() != stream->Parent())
|| (stream->Mode() & S_ALLOW_DUPS) != 0;
}
CachedNode cached(this, fHeader->RootNode());
@@ -548,8 +555,8 @@ BPlusTree::ModeToKeyType(mode_t mode)
void
BPlusTree::UpdateIterators(off_t offset, off_t nextOffset, uint16 keyIndex, uint16 splitAt,
int8 change)
BPlusTree::_UpdateIterators(off_t offset, off_t nextOffset, uint16 keyIndex,
uint16 splitAt, int8 change)
{
// Although every iterator which is affected by this update currently
// waits on a semaphore, other iterators could be added/removed at
@@ -566,7 +573,7 @@ BPlusTree::UpdateIterators(off_t offset, off_t nextOffset, uint16 keyIndex, uint
void
BPlusTree::AddIterator(TreeIterator *iterator)
BPlusTree::_AddIterator(TreeIterator *iterator)
{
if (fIteratorLock.Lock() < B_OK)
return;
@@ -578,7 +585,7 @@ BPlusTree::AddIterator(TreeIterator *iterator)
void
BPlusTree::RemoveIterator(TreeIterator *iterator)
BPlusTree::_RemoveIterator(TreeIterator *iterator)
{
if (fIteratorLock.Lock() < B_OK)
return;
@@ -590,7 +597,8 @@ BPlusTree::RemoveIterator(TreeIterator *iterator)
int32
BPlusTree::CompareKeys(const void *key1, int keyLength1, const void *key2, int keyLength2)
BPlusTree::_CompareKeys(const void *key1, int keyLength1, const void *key2,
int keyLength2)
{
type_code type = 0;
switch (fHeader->data_type) {
@@ -621,8 +629,8 @@ BPlusTree::CompareKeys(const void *key1, int keyLength1, const void *key2, int k
status_t
BPlusTree::FindKey(const bplustree_node *node, const uint8 *key, uint16 keyLength,
uint16 *_index, off_t *_next)
BPlusTree::_FindKey(const bplustree_node *node, const uint8 *key,
uint16 keyLength, uint16 *_index, off_t *_next)
{
#ifdef DEBUG
NodeChecker checker(node, fNodeSize, "find");
@@ -645,13 +653,14 @@ BPlusTree::FindKey(const bplustree_node *node, const uint8 *key, uint16 keyLengt
uint16 searchLength;
uint8 *searchKey = node->KeyAt(i, &searchLength);
if (searchKey + searchLength + sizeof(off_t) + sizeof(uint16) > (uint8 *)node + fNodeSize
if (searchKey + searchLength + sizeof(off_t) + sizeof(uint16)
> (uint8 *)node + fNodeSize
|| searchLength > BPLUSTREE_MAX_KEY_LENGTH) {
fStream->GetVolume()->Panic();
RETURN_ERROR(B_BAD_DATA);
}
int32 cmp = CompareKeys(key, keyLength, searchKey, searchLength);
int32 cmp = _CompareKeys(key, keyLength, searchKey, searchLength);
if (cmp < 0) {
last = i - 1;
saveIndex = i;
@@ -678,13 +687,14 @@ BPlusTree::FindKey(const bplustree_node *node, const uint8 *key, uint16 keyLengt
}
/** Prepares the stack to contain all nodes that were passed while
* following the key, from the root node to the leaf node that could
* or should contain that key.
*/
/*!
Prepares the stack to contain all nodes that were passed while
following the key, from the root node to the leaf node that could
or should contain that key.
*/
status_t
BPlusTree::SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLength)
BPlusTree::_SeekDown(Stack<node_and_key> &stack, const uint8 *key,
uint16 keyLength)
{
// set the root node to begin with
node_and_key nodeAndKey;
@@ -703,7 +713,8 @@ BPlusTree::SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLeng
}
off_t nextOffset;
status_t status = FindKey(node, key, keyLength, &nodeAndKey.keyIndex, &nextOffset);
status_t status = _FindKey(node, key, keyLength, &nodeAndKey.keyIndex,
&nextOffset);
if (status == B_ENTRY_NOT_FOUND && nextOffset == nodeAndKey.nodeOffset)
RETURN_ERROR(B_ERROR);
@@ -714,17 +725,18 @@ BPlusTree::SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLeng
nodeAndKey.nodeOffset = nextOffset;
}
FATAL(("BPlusTree::SeekDown() could not open node %Ld\n", nodeAndKey.nodeOffset));
FATAL(("BPlusTree::SeekDown() could not open node %Ld\n",
nodeAndKey.nodeOffset));
return B_ERROR;
}
/** This will find a free duplicate fragment in the given bplustree_node.
* The CachedNode will be set to the writable fragment on success.
*/
/*!
This will find a free duplicate fragment in the given bplustree_node.
The CachedNode will be set to the writable fragment on success.
*/
status_t
BPlusTree::FindFreeDuplicateFragment(Transaction &transaction,
BPlusTree::_FindFreeDuplicateFragment(Transaction &transaction,
const bplustree_node *node, CachedNode &cached,
off_t *_offset, bplustree_node **_fragment, uint32 *_index)
{
@@ -765,7 +777,7 @@ BPlusTree::FindFreeDuplicateFragment(Transaction &transaction,
status_t
BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
BPlusTree::_InsertDuplicate(Transaction &transaction, CachedNode &cached,
const bplustree_node *node, uint16 index, off_t value)
{
CachedNode cachedDuplicate(this);
@@ -784,7 +796,8 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
if (duplicate == NULL)
return B_IO_ERROR;
duplicate_array *array = duplicate->FragmentAt(bplustree_node::FragmentIndex(oldValue));
duplicate_array *array = duplicate->FragmentAt(
bplustree_node::FragmentIndex(oldValue));
if (array->count > NUM_FRAGMENT_VALUES
|| array->count < 1) {
FATAL(("insertDuplicate: Invalid array[%d] size in fragment %Ld == %Ld!\n",
@@ -803,9 +816,10 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
// reuse it as a duplicate node
offset = bplustree_node::FragmentOffset(oldValue);
memmove(duplicate->DuplicateArray(), array, (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
duplicate->left_link = duplicate->right_link = HOST_ENDIAN_TO_BFS_INT64(
(uint64)BPLUSTREE_NULL);
memmove(duplicate->DuplicateArray(), array,
(NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
duplicate->left_link = duplicate->right_link
= HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
array = duplicate->DuplicateArray();
array->Insert(value);
@@ -816,13 +830,15 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
// the old duplicate has not been touched, so we can reuse it
bplustree_node *newDuplicate;
status = cachedDuplicate.Allocate(transaction, &newDuplicate, &offset);
status = cachedDuplicate.Allocate(transaction,
&newDuplicate, &offset);
if (status < B_OK)
RETURN_ERROR(status);
// copy the array from the fragment node to the duplicate node
// and free the old entry (by zero'ing all values)
newDuplicate->overflow_link = HOST_ENDIAN_TO_BFS_INT64(array->count);
newDuplicate->overflow_link = HOST_ENDIAN_TO_BFS_INT64(
array->count);
memcpy(&newDuplicate->all_key_count, &array->values[0],
array->count * sizeof(off_t));
memset(array, 0, (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
@@ -894,10 +910,11 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
uint32 fragmentIndex = 0;
bplustree_node *fragment;
if (FindFreeDuplicateFragment(transaction, node, cachedDuplicate,
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)
if ((status = cachedDuplicate.Allocate(transaction, &fragment,
&offset)) < B_OK)
RETURN_ERROR(status);
memset(fragment, 0, fNodeSize);
@@ -918,8 +935,8 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
void
BPlusTree::InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyLength,
off_t value)
BPlusTree::_InsertKey(bplustree_node *node, uint16 index, uint8 *key,
uint16 keyLength, off_t value)
{
// should never happen, but who knows?
if (index > node->NumKeys())
@@ -930,13 +947,15 @@ BPlusTree::InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyL
uint8 *keys = node->Keys();
node->all_key_count = HOST_ENDIAN_TO_BFS_INT16(node->NumKeys() + 1);
node->all_key_length = HOST_ENDIAN_TO_BFS_INT16(node->AllKeyLength() + keyLength);
node->all_key_length = HOST_ENDIAN_TO_BFS_INT16(node->AllKeyLength()
+ keyLength);
off_t *newValues = node->Values();
uint16 *newKeyLengths = node->KeyLengths();
// move values and copy new value into them
memmove(newValues + index + 1, values + index, sizeof(off_t) * (node->NumKeys() - 1 - index));
memmove(newValues + index + 1, values + index,
sizeof(off_t) * (node->NumKeys() - 1 - index));
memmove(newValues, values, sizeof(off_t) * index);
newValues[index] = HOST_ENDIAN_TO_BFS_INT64(value);
@@ -950,7 +969,8 @@ BPlusTree::InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyL
int32 keyStart;
newKeyLengths[index] = HOST_ENDIAN_TO_BFS_INT16(keyLength
+ (keyStart = index > 0 ? BFS_ENDIAN_TO_HOST_INT16(newKeyLengths[index - 1]) : 0));
+ (keyStart = index > 0
? BFS_ENDIAN_TO_HOST_INT16(newKeyLengths[index - 1]) : 0));
// move keys and copy new key into them
uint16 length = BFS_ENDIAN_TO_HOST_INT16(newKeyLengths[index]);
@@ -962,14 +982,15 @@ 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.
*/
/*!
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)
BPlusTree::_SplitNode(bplustree_node *node, off_t nodeOffset,
bplustree_node *other, off_t otherOffset, uint16 *_keyIndex, uint8 *key,
uint16 *_keyLength, off_t *_value)
{
if (*_keyIndex > node->NumKeys() + 1)
return B_BAD_VALUE;
@@ -992,14 +1013,18 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
size_t size = fNodeSize >> 1;
int32 out, in;
for (in = out = 0; in < node->NumKeys() + 1;) {
if (!bytes)
bytesBefore = in > 0 ? BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in - 1]) : 0;
if (!bytes) {
bytesBefore = in > 0
? BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in - 1]) : 0;
}
if (in == keyIndex && !bytes) {
bytes = *_keyLength;
} else {
if (keyIndex < out)
bytesAfter = BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in]) - bytesBefore;
if (keyIndex < out) {
bytesAfter = BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in])
- bytesBefore;
}
in++;
}
@@ -1022,7 +1047,8 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
other->left_link = node->left_link;
other->right_link = HOST_ENDIAN_TO_BFS_INT64(nodeOffset);
other->all_key_length = HOST_ENDIAN_TO_BFS_INT16(bytes + bytesBefore + bytesAfter);
other->all_key_length = HOST_ENDIAN_TO_BFS_INT16(bytes + bytesBefore
+ bytesAfter);
other->all_key_count = HOST_ENDIAN_TO_BFS_INT16(out);
uint16 *outKeyLengths = other->KeyLengths();
@@ -1043,13 +1069,15 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
if (bytesAfter) {
// copy the keys after the new key
memcpy(outKeys + bytesBefore + bytes, inKeys + bytesBefore, bytesAfter);
memcpy(outKeys + bytesBefore + bytes, inKeys + bytesBefore,
bytesAfter);
keys = out - keyIndex - 1;
for (int32 i = 0;i < keys;i++) {
outKeyLengths[keyIndex + i + 1] = HOST_ENDIAN_TO_BFS_INT16(
BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[keyIndex + i]) + bytes);
}
memcpy(outKeyValues + keyIndex + 1, inKeyValues + keyIndex, keys * sizeof(off_t));
memcpy(outKeyValues + keyIndex + 1, inKeyValues + keyIndex,
keys * sizeof(off_t));
}
}
@@ -1080,7 +1108,8 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
// If a key is dropped (is not the new key), we have to copy
// it, because it would be lost if not.
uint8 *droppedKey = node->KeyAt(in, &newLength);
if (droppedKey + newLength + sizeof(off_t) + sizeof(uint16) > (uint8 *)node + fNodeSize
if (droppedKey + newLength + sizeof(off_t) + sizeof(uint16)
> (uint8 *)node + fNodeSize
|| newLength > BPLUSTREE_MAX_KEY_LENGTH) {
fStream->GetVolume()->Panic();
RETURN_ERROR(B_BAD_DATA);
@@ -1106,7 +1135,8 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
// it's enough to set bytesBefore once here, because we do
// not need to know the exact length of all keys in this
// loop
bytesBefore = in > skip ? BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in - 1]) : 0;
bytesBefore = in > skip
? BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in - 1]) : 0;
bytes = *_keyLength;
} else {
if (in < node->NumKeys()) {
@@ -1132,9 +1162,10 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
}
// adjust the byte counts (since we were a bit lazy in the loop)
if (keyIndex >= in && keyIndex - skip < out)
bytesAfter = BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in]) - bytesBefore - total;
else if (keyIndex < skip)
if (keyIndex >= in && keyIndex - skip < out) {
bytesAfter = BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in])
- bytesBefore - total;
} else if (keyIndex < skip)
bytesBefore = node->AllKeyLength() - total;
if (bytesBefore < 0 || bytesAfter < 0)
@@ -1142,7 +1173,8 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
node->left_link = HOST_ENDIAN_TO_BFS_INT64(otherOffset);
// right link, and overflow link can stay the same
node->all_key_length = HOST_ENDIAN_TO_BFS_INT16(bytes + bytesBefore + bytesAfter);
node->all_key_length = HOST_ENDIAN_TO_BFS_INT16(bytes + bytesBefore
+ bytesAfter);
node->all_key_count = HOST_ENDIAN_TO_BFS_INT16(out - 1);
// array positions have changed
@@ -1157,19 +1189,25 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
if (bytesBefore)
memmove(inKeys, inKeys + total, bytesBefore);
if (bytesAfter)
memmove(inKeys + bytesBefore + bytes, inKeys + total + bytesBefore, bytesAfter);
if (bytesAfter) {
memmove(inKeys + bytesBefore + bytes, inKeys + total + bytesBefore,
bytesAfter);
}
if (bytesBefore)
memmove(outKeyLengths, inKeyLengths + skip, keys * sizeof(uint16));
in = out - keyIndex - 1;
if (bytesAfter)
memmove(outKeyLengths + keyIndex + 1, inKeyLengths + skip + keyIndex, in * sizeof(uint16));
if (bytesAfter) {
memmove(outKeyLengths + keyIndex + 1, inKeyLengths + skip + keyIndex,
in * sizeof(uint16));
}
if (bytesBefore)
memmove(outKeyValues, inKeyValues + skip, keys * sizeof(off_t));
if (bytesAfter)
memmove(outKeyValues + keyIndex + 1, inKeyValues + skip + keyIndex, in * sizeof(off_t));
if (bytesAfter) {
memmove(outKeyValues + keyIndex + 1, inKeyValues + skip + keyIndex,
in * sizeof(off_t));
}
if (bytes) {
// finally, copy the newly inserted key (don't overwrite anything)
@@ -1196,14 +1234,16 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
}
/** This inserts a key into the tree. The changes made to the tree will
* all be part of the \a transaction.
*/
/*!
This inserts a key into the tree. The changes made to the tree will
all be part of the \a transaction.
*/
status_t
BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value)
BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
off_t value)
{
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH)
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH
|| keyLength > BPLUSTREE_MAX_KEY_LENGTH)
RETURN_ERROR(B_BAD_VALUE);
#ifdef DEBUG
if (value < 0)
@@ -1214,7 +1254,7 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
WriteLocked locked(fStream->Lock());
Stack<node_and_key> stack;
if (SeekDown(stack, key, keyLength) != B_OK)
if (_SeekDown(stack, key, keyLength) != B_OK)
RETURN_ERROR(B_ERROR);
uint8 keyBuffer[BPLUSTREE_MAX_KEY_LENGTH + 1];
@@ -1226,23 +1266,26 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
const bplustree_node *node;
CachedNode cached(this);
while (stack.Pop(&nodeAndKey) && (node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) {
while (stack.Pop(&nodeAndKey)
&& (node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) {
#ifdef DEBUG
NodeChecker checker(node, fNodeSize, "insert");
#endif
if (node->IsLeaf()) {
// first round, check for duplicate entries
status_t status = FindKey(node, key, keyLength, &nodeAndKey.keyIndex);
status_t status = _FindKey(node, key, keyLength,
&nodeAndKey.keyIndex);
// is this a duplicate entry?
if (status == B_OK) {
if (fAllowDuplicates) {
status = InsertDuplicate(transaction, cached, node, nodeAndKey.keyIndex, value);
status = _InsertDuplicate(transaction, cached, node,
nodeAndKey.keyIndex, value);
if (status != B_OK)
RETURN_ERROR(status);
return B_OK;
}
RETURN_ERROR(B_NAME_IN_USE);
}
}
@@ -1252,11 +1295,14 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
return B_IO_ERROR;
// is the node big enough to hold the pair?
if (int32(round_up(sizeof(bplustree_node) + writableNode->AllKeyLength() + keyLength)
+ (writableNode->NumKeys() + 1) * (sizeof(uint16) + sizeof(off_t))) < fNodeSize)
{
InsertKey(writableNode, nodeAndKey.keyIndex, keyBuffer, keyLength, value);
UpdateIterators(nodeAndKey.nodeOffset, BPLUSTREE_NULL, nodeAndKey.keyIndex, 0, 1);
if (int32(round_up(sizeof(bplustree_node)
+ writableNode->AllKeyLength() + keyLength)
+ (writableNode->NumKeys() + 1) * (sizeof(uint16)
+ sizeof(off_t))) < fNodeSize) {
_InsertKey(writableNode, nodeAndKey.keyIndex,
keyBuffer, keyLength, value);
_UpdateIterators(nodeAndKey.nodeOffset, BPLUSTREE_NULL,
nodeAndKey.keyIndex, 0, 1);
return B_OK;
} else {
@@ -1268,7 +1314,8 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
off_t newRoot = BPLUSTREE_NULL;
if (nodeAndKey.nodeOffset == fHeader->RootNode()) {
bplustree_node *root;
status_t status = cachedNewRoot.Allocate(transaction, &root, &newRoot);
status_t status = cachedNewRoot.Allocate(transaction, &root,
&newRoot);
if (status < B_OK) {
// The tree is most likely corrupted!
// But it's still sane at leaf level - we could set
@@ -1283,14 +1330,16 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
// reserve space for the other node
bplustree_node *other;
off_t otherOffset;
status_t status = cachedOther.Allocate(transaction, &other, &otherOffset);
status_t status = cachedOther.Allocate(transaction, &other,
&otherOffset);
if (status < B_OK) {
cachedNewRoot.Free(transaction, newRoot);
RETURN_ERROR(status);
}
if (SplitNode(writableNode, nodeAndKey.nodeOffset, other, otherOffset,
&nodeAndKey.keyIndex, keyBuffer, &keyLength, &value) < B_OK) {
if (_SplitNode(writableNode, nodeAndKey.nodeOffset, other,
otherOffset, &nodeAndKey.keyIndex, keyBuffer, &keyLength,
&value) < B_OK) {
// free root node & other node here
cachedOther.Free(transaction, otherOffset);
cachedNewRoot.Free(transaction, newRoot);
@@ -1302,11 +1351,12 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
NodeChecker otherChecker(other, fNodeSize, "insert split other");
#endif
UpdateIterators(nodeAndKey.nodeOffset, otherOffset, nodeAndKey.keyIndex,
writableNode->NumKeys(), 1);
_UpdateIterators(nodeAndKey.nodeOffset, otherOffset,
nodeAndKey.keyIndex, 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) {
if ((other = cachedOther.SetToWritable(transaction,
other->LeftLink())) != NULL) {
other->right_link = HOST_ENDIAN_TO_BFS_INT64(otherOffset);
}
@@ -1314,16 +1364,20 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
if (newRoot != BPLUSTREE_NULL) {
bplustree_node *root = cachedNewRoot.Node();
InsertKey(root, 0, keyBuffer, keyLength, writableNode->LeftLink());
root->overflow_link = HOST_ENDIAN_TO_BFS_INT64(nodeAndKey.nodeOffset);
_InsertKey(root, 0, keyBuffer, keyLength,
writableNode->LeftLink());
root->overflow_link = HOST_ENDIAN_TO_BFS_INT64(
nodeAndKey.nodeOffset);
bplustree_header *header = fCachedHeader.MakeWritableHeader(transaction);
bplustree_header *header
= fCachedHeader.MakeWritableHeader(transaction);
if (header == NULL)
return B_IO_ERROR;
// finally, update header to point to the new root
header->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(newRoot);
header->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(header->MaxNumberOfLevels() + 1);
header->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(
header->MaxNumberOfLevels() + 1);
return B_OK;
}
@@ -1333,13 +1387,14 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
}
/** Removes the duplicate index/value pair from the tree.
* It's part of the private tree interface.
*/
/*!
Removes the duplicate index/value pair from the tree.
It's part of the private tree interface.
*/
status_t
BPlusTree::RemoveDuplicate(Transaction &transaction, const bplustree_node *node,
CachedNode &cached, uint16 index, off_t value)
BPlusTree::_RemoveDuplicate(Transaction &transaction,
const bplustree_node *node, CachedNode &cached, uint16 index,
off_t value)
{
off_t *values = node->Values();
off_t oldValue = BFS_ENDIAN_TO_HOST_INT64(values[index]);
@@ -1353,7 +1408,8 @@ BPlusTree::RemoveDuplicate(Transaction &transaction, const bplustree_node *node,
// if it's a duplicate fragment, remove the entry from there
if (bplustree_node::LinkType(oldValue) == BPLUSTREE_DUPLICATE_FRAGMENT) {
duplicate_array *array = duplicate->FragmentAt(bplustree_node::FragmentIndex(oldValue));
duplicate_array *array = duplicate->FragmentAt(
bplustree_node::FragmentIndex(oldValue));
if (array->count > NUM_FRAGMENT_VALUES
|| array->count < 1) {
@@ -1488,7 +1544,7 @@ BPlusTree::RemoveDuplicate(Transaction &transaction, const bplustree_node *node,
bplustree_node *fragment = NULL;
uint32 fragmentIndex = 0;
off_t offset;
if (FindFreeDuplicateFragment(transaction, node, cachedOther,
if (_FindFreeDuplicateFragment(transaction, node, cachedOther,
&offset, &fragment, &fragmentIndex) == B_OK) {
// move to other node
duplicate_array *target = fragment->FragmentAt(fragmentIndex);
@@ -1514,14 +1570,14 @@ BPlusTree::RemoveDuplicate(Transaction &transaction, const bplustree_node *node,
}
/** Removes the key with the given index from the specified node.
* Since it has to get the key from the node anyway (to obtain it's
* pointer), it's not needed to pass the key & its length, although
* the calling method (BPlusTree::Remove()) have this data.
*/
/*!
Removes the key with the given index from the specified node.
Since it has to get the key from the node anyway (to obtain it's
pointer), it's not needed to pass the key & its length, although
the calling method (BPlusTree::Remove()) have this data.
*/
void
BPlusTree::RemoveKey(bplustree_node *node, uint16 index)
BPlusTree::_RemoveKey(bplustree_node *node, uint16 index)
{
// should never happen, but who knows?
if (index > node->NumKeys() && node->NumKeys() > 0) {
@@ -1575,35 +1631,38 @@ BPlusTree::RemoveKey(bplustree_node *node, uint16 index)
}
/** Removes the specified key from the tree. The "value" parameter is only used
* for trees which allow duplicates, so you may safely ignore it.
* It's not an optional parameter, so at least you have to think about it.
*/
/*!
Removes the specified key from the tree. The "value" parameter is only used
for trees which allow duplicates, so you may safely ignore it.
It's not an optional parameter, so at least you have to think about it.
*/
status_t
BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value)
BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
off_t value)
{
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH)
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH
|| keyLength > BPLUSTREE_MAX_KEY_LENGTH)
RETURN_ERROR(B_BAD_VALUE);
// lock access to stream
WriteLocked locked(fStream->Lock());
Stack<node_and_key> stack;
if (SeekDown(stack, key, keyLength) != B_OK)
if (_SeekDown(stack, key, keyLength) != B_OK)
RETURN_ERROR(B_ERROR);
node_and_key nodeAndKey;
const bplustree_node *node;
CachedNode cached(this);
while (stack.Pop(&nodeAndKey) && (node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) {
while (stack.Pop(&nodeAndKey)
&& (node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) {
#ifdef DEBUG
NodeChecker checker(node, fNodeSize, "remove");
#endif
if (node->IsLeaf()) {
// first round, check for duplicate entries
status_t status = FindKey(node, key, keyLength, &nodeAndKey.keyIndex);
status_t status = _FindKey(node, key, keyLength, &nodeAndKey.keyIndex);
if (status < B_OK)
RETURN_ERROR(status);
@@ -1611,15 +1670,16 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
// to the next node after the current - if there aren't any
// more nodes, we need a way to prevent the TreeIterators to
// touch the old node again, we use BPLUSTREE_FREE for this
off_t next = node->RightLink() == BPLUSTREE_NULL ? BPLUSTREE_FREE : node->RightLink();
UpdateIterators(nodeAndKey.nodeOffset, node->NumKeys() == 1 ?
next : BPLUSTREE_NULL, nodeAndKey.keyIndex, 0 , -1);
off_t next = node->RightLink() == BPLUSTREE_NULL
? BPLUSTREE_FREE : node->RightLink();
_UpdateIterators(nodeAndKey.nodeOffset, node->NumKeys() == 1
? next : BPLUSTREE_NULL, nodeAndKey.keyIndex, 0 , -1);
// is this a duplicate entry?
if (bplustree_node::IsDuplicate(BFS_ENDIAN_TO_HOST_INT64(
node->Values()[nodeAndKey.keyIndex]))) {
if (fAllowDuplicates) {
return RemoveDuplicate(transaction, node, cached,
return _RemoveDuplicate(transaction, node, cached,
nodeAndKey.keyIndex, value);
} else {
FATAL(("dupliate node found where no duplicates are allowed!\n"));
@@ -1658,7 +1718,7 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
// the overflow link, so we have to drop the last key)
if (writableNode->NumKeys() > 1
|| !writableNode->IsLeaf() && writableNode->NumKeys() == 1) {
RemoveKey(writableNode, nodeAndKey.keyIndex);
_RemoveKey(writableNode, nodeAndKey.keyIndex);
return B_OK;
}
@@ -1680,19 +1740,21 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
}
/** Replaces the value for the key in the tree.
* Returns B_OK if the key could be found and its value replaced,
* B_ENTRY_NOT_FOUND if the key couldn't be found, and other errors
* to indicate that something went terribly wrong.
* Note that this doesn't work with duplicates - it will just
* return B_BAD_TYPE if you call this function on a tree where
* duplicates are allowed.
*/
/*!
Replaces the value for the key in the tree.
Returns B_OK if the key could be found and its value replaced,
B_ENTRY_NOT_FOUND if the key couldn't be found, and other errors
to indicate that something went terribly wrong.
Note that this doesn't work with duplicates - it will just
return B_BAD_TYPE if you call this function on a tree where
duplicates are allowed.
*/
status_t
BPlusTree::Replace(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value)
BPlusTree::Replace(Transaction &transaction, const uint8 *key,
uint16 keyLength, off_t value)
{
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH
|| keyLength > BPLUSTREE_MAX_KEY_LENGTH
|| key == NULL)
RETURN_ERROR(B_BAD_VALUE);
@@ -1709,7 +1771,7 @@ BPlusTree::Replace(Transaction &transaction, const uint8 *key, uint16 keyLength,
while ((node = cached.SetTo(nodeOffset)) != NULL) {
uint16 keyIndex = 0;
off_t nextOffset;
status_t status = FindKey(node, key, keyLength, &keyIndex, &nextOffset);
status_t status = _FindKey(node, key, keyLength, &keyIndex, &nextOffset);
if (node->OverflowLink() == BPLUSTREE_NULL) {
if (status == B_OK) {
@@ -1730,22 +1792,23 @@ BPlusTree::Replace(Transaction &transaction, const uint8 *key, uint16 keyLength,
}
/** Searches the key in the tree, and stores the offset found in
* _value, if successful.
* It's very similar to BPlusTree::SeekDown(), but doesn't fill
* a stack while it descends the tree.
* Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND
* if not. It can also return other errors to indicate that
* something went wrong.
* Note that this doesn't work with duplicates - it will just
* return B_BAD_TYPE if you call this function on a tree where
* duplicates are allowed.
*/
/*!
Searches the key in the tree, and stores the offset found in
_value, if successful.
It's very similar to BPlusTree::SeekDown(), but doesn't fill
a stack while it descends the tree.
Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND
if not. It can also return other errors to indicate that
something went wrong.
Note that this doesn't work with duplicates - it will just
return B_BAD_TYPE if you call this function on a tree where
duplicates are allowed.
*/
status_t
BPlusTree::Find(const uint8 *key, uint16 keyLength, off_t *_value)
{
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH
|| keyLength > BPLUSTREE_MAX_KEY_LENGTH
|| key == NULL)
RETURN_ERROR(B_BAD_VALUE);
@@ -1766,7 +1829,7 @@ BPlusTree::Find(const uint8 *key, uint16 keyLength, off_t *_value)
while ((node = cached.SetTo(nodeOffset)) != NULL) {
uint16 keyIndex = 0;
off_t nextOffset;
status_t status = FindKey(node, key, keyLength, &keyIndex, &nextOffset);
status_t status = _FindKey(node, key, keyLength, &keyIndex, &nextOffset);
#ifdef DEBUG
levels++;
@@ -1799,14 +1862,14 @@ TreeIterator::TreeIterator(BPlusTree *tree)
fCurrentNodeOffset(BPLUSTREE_NULL),
fNext(NULL)
{
tree->AddIterator(this);
tree->_AddIterator(this);
}
TreeIterator::~TreeIterator()
{
if (fTree)
fTree->RemoveIterator(this);
fTree->_RemoveIterator(this);
}
@@ -1840,7 +1903,8 @@ TreeIterator::Goto(int8 to)
nextOffset = node->OverflowLink();
else {
if (node->AllKeyLength() > fTree->fNodeSize
|| (uint32)node->Values() > (uint32)node + fTree->fNodeSize - 8 * node->NumKeys())
|| (uint32)node->Values() > (uint32)node + fTree->fNodeSize
- 8 * node->NumKeys())
RETURN_ERROR(B_ERROR);
nextOffset = BFS_ENDIAN_TO_HOST_INT64(node->Values()[0]);
@@ -1856,21 +1920,21 @@ TreeIterator::Goto(int8 to)
}
/** Iterates through the tree in the specified direction.
* When it iterates through duplicates, the "key" is only updated for the
* first entry - if you need to know when this happens, use the "duplicate"
* parameter which is 0 for no duplicate, 1 for the first, and 2 for all
* the other duplicates.
* That's not too nice, but saves the 256 bytes that would be needed to
* store the last key - if this will ever become an issue, it will be
* easy to change.
* The other advantage of this is, that the queries can skip all duplicates
* at once when they are not relevant to them.
*/
/*!
Iterates through the tree in the specified direction.
When it iterates through duplicates, the "key" is only updated for the
first entry - if you need to know when this happens, use the "duplicate"
parameter which is 0 for no duplicate, 1 for the first, and 2 for all
the other duplicates.
That's not too nice, but saves the 256 bytes that would be needed to
store the last key - if this will ever become an issue, it will be
easy to change.
The other advantage of this is, that the queries can skip all duplicates
at once when they are not relevant to them.
*/
status_t
TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxLength,
off_t *value, uint16 *duplicate)
TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength,
uint16 maxLength, off_t *value, uint16 *duplicate)
{
if (fTree == NULL)
return B_INTERRUPTED;
@@ -2007,11 +2071,11 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxL
}
/** This is more or less a copy of BPlusTree::Find() - but it just
* sets the current position in the iterator, regardless of if the
* key could be found or not.
*/
/*!
This is more or less a copy of BPlusTree::Find() - but it just
sets the current position in the iterator, regardless of if the
key could be found or not.
*/
status_t
TreeIterator::Find(const uint8 *key, uint16 keyLength)
{
@@ -2031,7 +2095,8 @@ TreeIterator::Find(const uint8 *key, uint16 keyLength)
while ((node = cached.SetTo(nodeOffset)) != NULL) {
uint16 keyIndex = 0;
off_t nextOffset;
status_t status = fTree->FindKey(node, key, keyLength, &keyIndex, &nextOffset);
status_t status = fTree->_FindKey(node, key, keyLength, &keyIndex,
&nextOffset);
if (node->OverflowLink() == BPLUSTREE_NULL) {
fCurrentNodeOffset = nodeOffset;
@@ -2160,12 +2225,11 @@ bplustree_node::DuplicateAt(off_t offset, bool isFragment, int8 index) const
}
/** Although the name suggests it, this function doesn't return the real
* used fragment count; at least, it can only count to two: it returns
* 0, if there is no fragment used, 1 if there is only one fragment
* used, and 2 if there are at least 2 fragments used.
*/
/*! Although the name suggests it, this function doesn't return the real
used fragment count; at least, it can only count to two: it returns
0, if there is no fragment used, 1 if there is only one fragment
used, and 2 if there are at least 2 fragments used.
*/
uint32
bplustree_node::FragmentsUsed(uint32 nodeSize) const
{
@@ -2210,14 +2274,11 @@ bplustree_node::CheckIntegrity(uint32 nodeSize) const
int32
compareKeys(type_code type, const void *key1, int keyLength1, const void *key2, int keyLength2)
compareKeys(type_code type, const void *key1, int keyLength1,
const void *key2, int keyLength2)
{
// if one of the keys is NULL, bail out gracefully
if (key1 == NULL || key2 == NULL) {
//#if USER
// // that's here to see if it's reasonable to handle this case nicely at all
// DEBUGGER(("compareKeys() got NULL key!"));
//#endif
// even if it's most probably a bug in the calling code, we try to
// give a meaningful result
if (key1 == NULL && key2 != NULL)