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