* 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)
+79 -60
View File
@@ -1,9 +1,5 @@
/* BPlusTree - BFS B+Tree implementation
*
* Roughly based on 'btlib' written by Marcus J. Ranum - it shares
* no code but achieves binary compatibility with the on disk format.
*
* Copyright 2001-2005, Axel Dörfler, [email protected].
/*
* Copyright 2001-2007, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License.
*/
#ifndef B_PLUS_TREE_H
@@ -15,7 +11,7 @@
#include "Chain.h"
//****************** on-disk structures ********************
// #pragma mark - on-disk structures
struct bplustree_node;
@@ -37,7 +33,8 @@ struct bplustree_header {
off_t RootNode() const { return BFS_ENDIAN_TO_HOST_INT64(root_node_pointer); }
off_t FreeNode() const { return BFS_ENDIAN_TO_HOST_INT64(free_node_pointer); }
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); }
uint32 MaxNumberOfLevels() const
{ return BFS_ENDIAN_TO_HOST_INT32(max_number_of_levels); }
inline bool CheckNode(bplustree_node *node) const;
inline bool IsValidLink(off_t link) const;
@@ -119,7 +116,7 @@ enum bplustree_traversing {
};
//****************** in-memory structures ********************
// #pragma mark - in-memory structures
template<class T> class Stack;
class BPlusTree;
@@ -134,8 +131,6 @@ struct node_and_key {
};
//***** Cache handling *****
class CachedNode {
public:
CachedNode(BPlusTree *tree)
@@ -159,7 +154,8 @@ class CachedNode {
}
const bplustree_node *SetTo(off_t offset, bool check = true);
bplustree_node *SetToWritable(Transaction &transaction, 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);
@@ -169,7 +165,8 @@ class CachedNode {
void Unset();
status_t Free(Transaction &transaction, off_t offset);
status_t Allocate(Transaction &transaction, bplustree_node **node, off_t *offset);
status_t Allocate(Transaction &transaction, bplustree_node **node,
off_t *offset);
bool IsWritable() const { return fWritable; }
bplustree_node *Node() const { return fNode; }
@@ -185,27 +182,31 @@ class CachedNode {
};
//******** B+tree class *********
class BPlusTree {
public:
BPlusTree(Transaction &transaction, Inode *stream, int32 nodeSize = BPLUSTREE_NODE_SIZE);
BPlusTree(Transaction &transaction, Inode *stream,
int32 nodeSize = BPLUSTREE_NODE_SIZE);
BPlusTree(Inode *stream);
BPlusTree();
~BPlusTree();
status_t SetTo(Transaction &transaction, Inode *stream, int32 nodeSize = BPLUSTREE_NODE_SIZE);
status_t SetTo(Transaction &transaction, Inode *stream,
int32 nodeSize = BPLUSTREE_NODE_SIZE);
status_t SetTo(Inode *stream);
status_t SetStream(Inode *stream);
status_t InitCheck();
status_t Validate();
status_t Remove(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value);
status_t Insert(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value);
status_t Remove(Transaction &transaction, const uint8 *key,
uint16 keyLength, off_t value);
status_t Insert(Transaction &transaction, const uint8 *key,
uint16 keyLength, off_t value);
status_t Remove(Transaction &transaction, const char *key, off_t value);
status_t Insert(Transaction &transaction, const char *key, off_t value);
status_t Remove(Transaction &transaction, const char *key,
off_t value);
status_t Insert(Transaction &transaction, const char *key,
off_t value);
status_t Insert(Transaction &transaction, int32 key, off_t value);
status_t Insert(Transaction &transaction, uint32 key, off_t value);
status_t Insert(Transaction &transaction, int64 key, off_t value);
@@ -213,7 +214,8 @@ class BPlusTree {
status_t Insert(Transaction &transaction, float key, off_t value);
status_t Insert(Transaction &transaction, double key, off_t value);
status_t Replace(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value);
status_t Replace(Transaction &transaction, const uint8 *key,
uint16 keyLength, off_t value);
status_t Find(const uint8 *key, uint16 keyLength, off_t *value);
static int32 TypeCodeToKeyType(type_code code);
@@ -224,30 +226,37 @@ class BPlusTree {
BPlusTree &operator=(const BPlusTree &);
// no implementation
int32 CompareKeys(const void *key1, int keylength1, const void *key2, int keylength2);
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);
int32 _CompareKeys(const void *key1, int keylength1,
const void *key2, int keylength2);
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(Transaction &transaction,
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,
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 *_offset, bplustree_node **_fragment,
uint32 *_index);
status_t _InsertDuplicate(Transaction &transaction,
CachedNode &cached, 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, const bplustree_node *node,
CachedNode &cached, uint16 keyIndex, off_t value);
void RemoveKey(bplustree_node *node, uint16 index);
status_t _RemoveDuplicate(Transaction &transaction,
const bplustree_node *node, CachedNode &cached,
uint16 keyIndex, off_t value);
void _RemoveKey(bplustree_node *node, uint16 index);
void UpdateIterators(off_t offset, off_t nextOffset, uint16 keyIndex,
uint16 splitAt, int8 change);
void AddIterator(TreeIterator *iterator);
void RemoveIterator(TreeIterator *iterator);
void _UpdateIterators(off_t offset, off_t nextOffset,
uint16 keyIndex, uint16 splitAt, int8 change);
void _AddIterator(TreeIterator *iterator);
void _RemoveIterator(TreeIterator *iterator);
private:
friend class TreeIterator;
@@ -264,7 +273,7 @@ class BPlusTree {
};
//***** helper classes/functions *****
// #pragma mark - helper classes/functions
extern int32 compareKeys(type_code type, const void *key1, int keyLength1,
const void *key2, int keyLength2);
@@ -275,15 +284,17 @@ class TreeIterator {
~TreeIterator();
status_t Goto(int8 to);
status_t Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxLength,
off_t *value, uint16 *duplicate = NULL);
status_t Traverse(int8 direction, void *key, uint16 *keyLength,
uint16 maxLength, off_t *value,
uint16 *duplicate = NULL);
status_t Find(const uint8 *key, uint16 keyLength);
status_t Rewind();
status_t GetNextEntry(void *key, uint16 *keyLength, uint16 maxLength,
off_t *value, uint16 *duplicate = NULL);
status_t GetPreviousEntry(void *key, uint16 *keyLength, uint16 maxLength,
off_t *value, uint16 *duplicate = NULL);
status_t GetPreviousEntry(void *key, uint16 *keyLength,
uint16 maxLength, off_t *value,
uint16 *duplicate = NULL);
void SkipDuplicates();
#ifdef DEBUG
@@ -303,12 +314,16 @@ class TreeIterator {
friend class Chain<TreeIterator>;
friend class BPlusTree;
void Update(off_t offset, off_t nextOffset, uint16 keyIndex, uint16 splitAt, int8 change);
void Update(off_t offset, off_t nextOffset, uint16 keyIndex,
uint16 splitAt, int8 change);
void Stop();
TreeIterator *fNext;
};
// BPlusTree's inline functions (most of them may not be needed)
// #pragma mark - BPlusTree's inline functions
// (most of them may not be needed)
inline status_t
BPlusTree::Remove(Transaction &transaction, const char *key, off_t value)
@@ -375,8 +390,8 @@ BPlusTree::Insert(Transaction &transaction, double key, off_t value)
}
/************************ TreeIterator inline functions ************************/
// #pragma mark -
// #pragma mark - TreeIterator inline functions
inline status_t
TreeIterator::Rewind()
@@ -398,8 +413,8 @@ TreeIterator::GetPreviousEntry(void *key, uint16 *keyLength, uint16 maxLength,
return Traverse(BPLUSTREE_BACKWARD, key, keyLength, maxLength, value, duplicate);
}
/************************ bplustree_header inline functions ************************/
// #pragma mark -
// #pragma mark - bplustree_header inline functions
inline bool
@@ -420,14 +435,14 @@ bplustree_header::IsValidLink(off_t link) const
}
/************************ bplustree_node inline functions ************************/
// #pragma mark -
// #pragma mark - bplustree_node inline functions
inline uint16 *
bplustree_node::KeyLengths() const
{
return (uint16 *)(((char *)this) + round_up(sizeof(bplustree_node) + AllKeyLength()));
return (uint16 *)(((char *)this) + round_up(sizeof(bplustree_node)
+ AllKeyLength()));
}
@@ -448,7 +463,8 @@ bplustree_node::Keys() const
inline int32
bplustree_node::Used() const
{
return round_up(sizeof(bplustree_node) + AllKeyLength()) + NumKeys() * (sizeof(uint16) + sizeof(off_t));
return round_up(sizeof(bplustree_node) + AllKeyLength()) + NumKeys()
* (sizeof(uint16) + sizeof(off_t));
}
@@ -462,7 +478,8 @@ bplustree_node::IsLeaf() const
inline duplicate_array *
bplustree_node::FragmentAt(int8 index) const
{
return (duplicate_array *)((off_t *)this + index * (NUM_FRAGMENT_VALUES + 1));
return (duplicate_array *)((off_t *)this
+ index * (NUM_FRAGMENT_VALUES + 1));
}
@@ -483,14 +500,16 @@ bplustree_node::LinkType(off_t link)
inline off_t
bplustree_node::MakeLink(uint8 type, off_t link, uint32 fragmentIndex)
{
return ((off_t)type << 62) | (link & 0x3ffffffffffffc00LL) | (fragmentIndex & 0x3ff);
return ((off_t)type << 62) | (link & 0x3ffffffffffffc00LL)
| (fragmentIndex & 0x3ff);
}
inline bool
bplustree_node::IsDuplicate(off_t link)
{
return (LinkType(link) & (BPLUSTREE_DUPLICATE_NODE | BPLUSTREE_DUPLICATE_FRAGMENT)) > 0;
return (LinkType(link)
& (BPLUSTREE_DUPLICATE_NODE | BPLUSTREE_DUPLICATE_FRAGMENT)) > 0;
}
@@ -514,4 +533,4 @@ bplustree_node::MaxFragments(uint32 nodeSize)
return nodeSize / ((NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
}
#endif /* B_PLUS_TREE_H */
#endif // B_PLUS_TREE_H
@@ -15,10 +15,6 @@
#include "system_dependencies.h"
#ifdef USER
# define spawn_kernel_thread spawn_thread
#endif
// Things the BlockAllocator should do:
+6 -14
View File
@@ -1,6 +1,5 @@
/* Debug - debug stuff
*
* Copyright 2001-2006, Axel Dörfler, axeld@pinc-software.de.
/*
* Copyright 2001-2007, Axel Dörfler, axeld@pinc-software.de.
* Some code is based on work previously done by Marcus Overhagen.
*
* This file may be used under the terms of the MIT License.
@@ -242,13 +241,11 @@ dump_bplustree_node(const bplustree_node *node, const bplustree_header *header,
// #pragma mark -
#ifndef USER
static int
dbg_inode(int argc, char **argv)
debug_inode(int argc, char **argv)
{
if (argc < 2) {
kprintf("usage: bfsinode ptr-to-inode\n");
kprintf("usage: bfsinode <ptr-to-inode>\n");
return 0;
}
@@ -258,22 +255,17 @@ dbg_inode(int argc, char **argv)
return B_OK;
}
#endif
void
remove_debugger_commands()
{
#ifndef USER
remove_debugger_command("bfsinode", dbg_inode);
#endif
remove_debugger_command("bfsinode", debug_inode);
}
void
add_debugger_commands()
{
#ifndef USER
add_debugger_command("bfsinode", dbg_inode, "dump an Inode object");
#endif
add_debugger_command("bfsinode", debug_inode, "dump an Inode object");
}
@@ -16,12 +16,10 @@
// Configure here if and when real benaphores should be used
#define USE_BENAPHORE
// if defined, benaphores are used for the Semaphore/RecursiveLock classes
#ifdef USER
//# define FAST_LOCK
// the ReadWriteLock class uses a second Semaphore to
// speed up locking - only makes sense if USE_BENAPHORE
// is defined, too.
#endif
#ifdef FAST_LOCK
# error implement recursive write locking first
#endif
@@ -37,9 +35,6 @@ class Semaphore {
fSemaphore(create_sem(1, name))
#endif
{
#ifndef USER
set_sem_owner(fSemaphore, B_SYSTEM_TEAM);
#endif
}
~Semaphore()
@@ -126,9 +121,6 @@ class RecursiveLock {
#endif
fOwner(-1)
{
#ifndef USER
set_sem_owner(fSemaphore, B_SYSTEM_TEAM);
#endif
}
status_t LockWithTimeout(bigtime_t timeout)
@@ -276,9 +268,6 @@ class ReadWriteLock {
{
fSemaphore = create_sem(0, name);
fCount = MAX_READERS;
#ifndef USER
set_sem_owner(fSemaphore, B_SYSTEM_TEAM);
#endif
return fSemaphore;
}
@@ -360,9 +349,6 @@ class ReadWriteLock {
status_t Initialize(const char *name = "bfs r/w lock")
{
fSemaphore = create_sem(MAX_READERS, name);
#ifndef USER
set_sem_owner(fSemaphore, B_SYSTEM_TEAM);
#endif
return fSemaphore;
}
@@ -273,9 +273,7 @@ Volume::Panic()
{
FATAL(("we have to panic... switch to read-only mode!\n"));
fFlags |= VOLUME_READ_ONLY;
#ifdef USER
debugger("BFS panics!");
#elif defined(DEBUG)
#ifdef DEBUG
kernel_debugger("BFS panics!");
#endif
}