* 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
|
* Roughly based on 'btlib' written by Marcus J. Ranum - it shares
|
||||||
* no code but achieves binary compatibility with the on disk format.
|
* 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 "Debug.h"
|
||||||
#include "BPlusTree.h"
|
#include "BPlusTree.h"
|
||||||
@@ -215,7 +216,8 @@ CachedNode::InternalSetTo(Transaction *transaction, off_t offset)
|
|||||||
uint8 *block;
|
uint8 *block;
|
||||||
|
|
||||||
if (transaction != NULL) {
|
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;
|
fWritable = true;
|
||||||
} else {
|
} else {
|
||||||
block = (uint8 *)block_cache_get(volume->BlockCache(), fBlockNumber);
|
block = (uint8 *)block_cache_get(volume->BlockCache(), fBlockNumber);
|
||||||
@@ -270,7 +272,8 @@ CachedNode::Free(Transaction &transaction, off_t offset)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
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)
|
if (fTree == NULL || fTree->fHeader == NULL || fTree->fStream == NULL)
|
||||||
RETURN_ERROR(B_BAD_VALUE);
|
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
|
// 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
|
// else it will fail because the requested node is out of bounds
|
||||||
off_t offset = header->MaximumSize();
|
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) {
|
if (SetToWritable(transaction, offset, false) != NULL) {
|
||||||
fNode->Initialize();
|
fNode->Initialize();
|
||||||
@@ -318,7 +322,8 @@ CachedNode::Allocate(Transaction &transaction, bplustree_node **_node, off_t *_o
|
|||||||
}
|
}
|
||||||
|
|
||||||
// revert header size to old value
|
// 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);
|
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
|
status_t
|
||||||
BPlusTree::SetTo(Transaction &transaction, Inode *stream, int32 nodeSize)
|
BPlusTree::SetTo(Transaction &transaction, Inode *stream, int32 nodeSize)
|
||||||
{
|
{
|
||||||
@@ -460,13 +464,16 @@ BPlusTree::SetTo(Inode *stream)
|
|||||||
fNodeSize = fHeader->NodeSize();
|
fNodeSize = fHeader->NodeSize();
|
||||||
|
|
||||||
{
|
{
|
||||||
uint32 toMode[] = {S_STR_INDEX, S_INT_INDEX, S_UINT_INDEX, S_LONG_LONG_INDEX,
|
uint32 toMode[] = {S_STR_INDEX, S_INT_INDEX, S_UINT_INDEX,
|
||||||
S_ULONG_LONG_INDEX, S_FLOAT_INDEX, S_DOUBLE_INDEX};
|
S_LONG_LONG_INDEX, S_ULONG_LONG_INDEX, S_FLOAT_INDEX,
|
||||||
uint32 mode = stream->Mode() & (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX | S_LONG_LONG_INDEX
|
S_DOUBLE_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
|
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()) {
|
|| !stream->IsContainer()) {
|
||||||
D( dump_bplustree_header(fHeader);
|
D( dump_bplustree_header(fHeader);
|
||||||
dump_inode(&stream->Node());
|
dump_inode(&stream->Node());
|
||||||
@@ -548,8 +555,8 @@ BPlusTree::ModeToKeyType(mode_t mode)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BPlusTree::UpdateIterators(off_t offset, off_t nextOffset, uint16 keyIndex, uint16 splitAt,
|
BPlusTree::_UpdateIterators(off_t offset, off_t nextOffset, uint16 keyIndex,
|
||||||
int8 change)
|
uint16 splitAt, int8 change)
|
||||||
{
|
{
|
||||||
// Although every iterator which is affected by this update currently
|
// Although every iterator which is affected by this update currently
|
||||||
// waits on a semaphore, other iterators could be added/removed at
|
// 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
|
void
|
||||||
BPlusTree::AddIterator(TreeIterator *iterator)
|
BPlusTree::_AddIterator(TreeIterator *iterator)
|
||||||
{
|
{
|
||||||
if (fIteratorLock.Lock() < B_OK)
|
if (fIteratorLock.Lock() < B_OK)
|
||||||
return;
|
return;
|
||||||
@@ -578,7 +585,7 @@ BPlusTree::AddIterator(TreeIterator *iterator)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BPlusTree::RemoveIterator(TreeIterator *iterator)
|
BPlusTree::_RemoveIterator(TreeIterator *iterator)
|
||||||
{
|
{
|
||||||
if (fIteratorLock.Lock() < B_OK)
|
if (fIteratorLock.Lock() < B_OK)
|
||||||
return;
|
return;
|
||||||
@@ -590,7 +597,8 @@ BPlusTree::RemoveIterator(TreeIterator *iterator)
|
|||||||
|
|
||||||
|
|
||||||
int32
|
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;
|
type_code type = 0;
|
||||||
switch (fHeader->data_type) {
|
switch (fHeader->data_type) {
|
||||||
@@ -621,8 +629,8 @@ BPlusTree::CompareKeys(const void *key1, int keyLength1, const void *key2, int k
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
BPlusTree::FindKey(const bplustree_node *node, const uint8 *key, uint16 keyLength,
|
BPlusTree::_FindKey(const bplustree_node *node, const uint8 *key,
|
||||||
uint16 *_index, off_t *_next)
|
uint16 keyLength, uint16 *_index, off_t *_next)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
NodeChecker checker(node, fNodeSize, "find");
|
NodeChecker checker(node, fNodeSize, "find");
|
||||||
@@ -645,13 +653,14 @@ BPlusTree::FindKey(const bplustree_node *node, const uint8 *key, uint16 keyLengt
|
|||||||
|
|
||||||
uint16 searchLength;
|
uint16 searchLength;
|
||||||
uint8 *searchKey = node->KeyAt(i, &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) {
|
|| searchLength > BPLUSTREE_MAX_KEY_LENGTH) {
|
||||||
fStream->GetVolume()->Panic();
|
fStream->GetVolume()->Panic();
|
||||||
RETURN_ERROR(B_BAD_DATA);
|
RETURN_ERROR(B_BAD_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 cmp = CompareKeys(key, keyLength, searchKey, searchLength);
|
int32 cmp = _CompareKeys(key, keyLength, searchKey, searchLength);
|
||||||
if (cmp < 0) {
|
if (cmp < 0) {
|
||||||
last = i - 1;
|
last = i - 1;
|
||||||
saveIndex = i;
|
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
|
Prepares the stack to contain all nodes that were passed while
|
||||||
* or should contain that key.
|
following the key, from the root node to the leaf node that could
|
||||||
*/
|
or should contain that key.
|
||||||
|
*/
|
||||||
status_t
|
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
|
// set the root node to begin with
|
||||||
node_and_key nodeAndKey;
|
node_and_key nodeAndKey;
|
||||||
@@ -703,7 +713,8 @@ BPlusTree::SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLeng
|
|||||||
}
|
}
|
||||||
|
|
||||||
off_t nextOffset;
|
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)
|
if (status == B_ENTRY_NOT_FOUND && nextOffset == nodeAndKey.nodeOffset)
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
@@ -714,17 +725,18 @@ BPlusTree::SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLeng
|
|||||||
nodeAndKey.nodeOffset = nextOffset;
|
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;
|
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
|
status_t
|
||||||
BPlusTree::FindFreeDuplicateFragment(Transaction &transaction,
|
BPlusTree::_FindFreeDuplicateFragment(Transaction &transaction,
|
||||||
const bplustree_node *node, CachedNode &cached,
|
const bplustree_node *node, CachedNode &cached,
|
||||||
off_t *_offset, bplustree_node **_fragment, uint32 *_index)
|
off_t *_offset, bplustree_node **_fragment, uint32 *_index)
|
||||||
{
|
{
|
||||||
@@ -765,7 +777,7 @@ BPlusTree::FindFreeDuplicateFragment(Transaction &transaction,
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
BPlusTree::_InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
||||||
const bplustree_node *node, uint16 index, off_t value)
|
const bplustree_node *node, uint16 index, off_t value)
|
||||||
{
|
{
|
||||||
CachedNode cachedDuplicate(this);
|
CachedNode cachedDuplicate(this);
|
||||||
@@ -784,7 +796,8 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
|||||||
if (duplicate == NULL)
|
if (duplicate == NULL)
|
||||||
return B_IO_ERROR;
|
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
|
if (array->count > NUM_FRAGMENT_VALUES
|
||||||
|| array->count < 1) {
|
|| array->count < 1) {
|
||||||
FATAL(("insertDuplicate: Invalid array[%d] size in fragment %Ld == %Ld!\n",
|
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
|
// reuse it as a duplicate node
|
||||||
offset = bplustree_node::FragmentOffset(oldValue);
|
offset = bplustree_node::FragmentOffset(oldValue);
|
||||||
|
|
||||||
memmove(duplicate->DuplicateArray(), array, (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
memmove(duplicate->DuplicateArray(), array,
|
||||||
duplicate->left_link = duplicate->right_link = HOST_ENDIAN_TO_BFS_INT64(
|
(NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
||||||
(uint64)BPLUSTREE_NULL);
|
duplicate->left_link = duplicate->right_link
|
||||||
|
= HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
|
||||||
|
|
||||||
array = duplicate->DuplicateArray();
|
array = duplicate->DuplicateArray();
|
||||||
array->Insert(value);
|
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
|
// the old duplicate has not been touched, so we can reuse it
|
||||||
|
|
||||||
bplustree_node *newDuplicate;
|
bplustree_node *newDuplicate;
|
||||||
status = cachedDuplicate.Allocate(transaction, &newDuplicate, &offset);
|
status = cachedDuplicate.Allocate(transaction,
|
||||||
|
&newDuplicate, &offset);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
RETURN_ERROR(status);
|
RETURN_ERROR(status);
|
||||||
|
|
||||||
// copy the array from the fragment node to the duplicate node
|
// copy the array from the fragment node to the duplicate node
|
||||||
// and free the old entry (by zero'ing all values)
|
// 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],
|
memcpy(&newDuplicate->all_key_count, &array->values[0],
|
||||||
array->count * sizeof(off_t));
|
array->count * sizeof(off_t));
|
||||||
memset(array, 0, (NUM_FRAGMENT_VALUES + 1) * 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;
|
uint32 fragmentIndex = 0;
|
||||||
bplustree_node *fragment;
|
bplustree_node *fragment;
|
||||||
if (FindFreeDuplicateFragment(transaction, node, cachedDuplicate,
|
if (_FindFreeDuplicateFragment(transaction, node, cachedDuplicate,
|
||||||
&offset, &fragment, &fragmentIndex) != B_OK) {
|
&offset, &fragment, &fragmentIndex) != B_OK) {
|
||||||
// allocate a new duplicate fragment node
|
// 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);
|
RETURN_ERROR(status);
|
||||||
|
|
||||||
memset(fragment, 0, fNodeSize);
|
memset(fragment, 0, fNodeSize);
|
||||||
@@ -918,8 +935,8 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BPlusTree::InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyLength,
|
BPlusTree::_InsertKey(bplustree_node *node, uint16 index, uint8 *key,
|
||||||
off_t value)
|
uint16 keyLength, off_t value)
|
||||||
{
|
{
|
||||||
// should never happen, but who knows?
|
// should never happen, but who knows?
|
||||||
if (index > node->NumKeys())
|
if (index > node->NumKeys())
|
||||||
@@ -930,13 +947,15 @@ BPlusTree::InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyL
|
|||||||
uint8 *keys = node->Keys();
|
uint8 *keys = node->Keys();
|
||||||
|
|
||||||
node->all_key_count = HOST_ENDIAN_TO_BFS_INT16(node->NumKeys() + 1);
|
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();
|
off_t *newValues = node->Values();
|
||||||
uint16 *newKeyLengths = node->KeyLengths();
|
uint16 *newKeyLengths = node->KeyLengths();
|
||||||
|
|
||||||
// move values and copy new value into them
|
// 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);
|
memmove(newValues, values, sizeof(off_t) * index);
|
||||||
|
|
||||||
newValues[index] = HOST_ENDIAN_TO_BFS_INT64(value);
|
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;
|
int32 keyStart;
|
||||||
newKeyLengths[index] = HOST_ENDIAN_TO_BFS_INT16(keyLength
|
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
|
// move keys and copy new key into them
|
||||||
uint16 length = BFS_ENDIAN_TO_HOST_INT16(newKeyLengths[index]);
|
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
|
Splits the \a node into two halves - the other half will be put into \a other.
|
||||||
* index node.
|
It also takes care to create a new overflow link if the node to split is an
|
||||||
*/
|
index node.
|
||||||
|
*/
|
||||||
status_t
|
status_t
|
||||||
BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *other,
|
BPlusTree::_SplitNode(bplustree_node *node, off_t nodeOffset,
|
||||||
off_t otherOffset, uint16 *_keyIndex, uint8 *key, uint16 *_keyLength, off_t *_value)
|
bplustree_node *other, off_t otherOffset, uint16 *_keyIndex, uint8 *key,
|
||||||
|
uint16 *_keyLength, off_t *_value)
|
||||||
{
|
{
|
||||||
if (*_keyIndex > node->NumKeys() + 1)
|
if (*_keyIndex > node->NumKeys() + 1)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -992,14 +1013,18 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
|
|||||||
size_t size = fNodeSize >> 1;
|
size_t size = fNodeSize >> 1;
|
||||||
int32 out, in;
|
int32 out, in;
|
||||||
for (in = out = 0; in < node->NumKeys() + 1;) {
|
for (in = out = 0; in < node->NumKeys() + 1;) {
|
||||||
if (!bytes)
|
if (!bytes) {
|
||||||
bytesBefore = in > 0 ? BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in - 1]) : 0;
|
bytesBefore = in > 0
|
||||||
|
? BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in - 1]) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (in == keyIndex && !bytes) {
|
if (in == keyIndex && !bytes) {
|
||||||
bytes = *_keyLength;
|
bytes = *_keyLength;
|
||||||
} else {
|
} else {
|
||||||
if (keyIndex < out)
|
if (keyIndex < out) {
|
||||||
bytesAfter = BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in]) - bytesBefore;
|
bytesAfter = BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in])
|
||||||
|
- bytesBefore;
|
||||||
|
}
|
||||||
|
|
||||||
in++;
|
in++;
|
||||||
}
|
}
|
||||||
@@ -1022,7 +1047,8 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
|
|||||||
|
|
||||||
other->left_link = node->left_link;
|
other->left_link = node->left_link;
|
||||||
other->right_link = HOST_ENDIAN_TO_BFS_INT64(nodeOffset);
|
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);
|
other->all_key_count = HOST_ENDIAN_TO_BFS_INT16(out);
|
||||||
|
|
||||||
uint16 *outKeyLengths = other->KeyLengths();
|
uint16 *outKeyLengths = other->KeyLengths();
|
||||||
@@ -1043,13 +1069,15 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
|
|||||||
|
|
||||||
if (bytesAfter) {
|
if (bytesAfter) {
|
||||||
// copy the keys after the new key
|
// 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;
|
keys = out - keyIndex - 1;
|
||||||
for (int32 i = 0;i < keys;i++) {
|
for (int32 i = 0;i < keys;i++) {
|
||||||
outKeyLengths[keyIndex + i + 1] = HOST_ENDIAN_TO_BFS_INT16(
|
outKeyLengths[keyIndex + i + 1] = HOST_ENDIAN_TO_BFS_INT16(
|
||||||
BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[keyIndex + i]) + bytes);
|
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
|
// If a key is dropped (is not the new key), we have to copy
|
||||||
// it, because it would be lost if not.
|
// it, because it would be lost if not.
|
||||||
uint8 *droppedKey = node->KeyAt(in, &newLength);
|
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) {
|
|| newLength > BPLUSTREE_MAX_KEY_LENGTH) {
|
||||||
fStream->GetVolume()->Panic();
|
fStream->GetVolume()->Panic();
|
||||||
RETURN_ERROR(B_BAD_DATA);
|
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
|
// it's enough to set bytesBefore once here, because we do
|
||||||
// not need to know the exact length of all keys in this
|
// not need to know the exact length of all keys in this
|
||||||
// loop
|
// 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;
|
bytes = *_keyLength;
|
||||||
} else {
|
} else {
|
||||||
if (in < node->NumKeys()) {
|
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)
|
// adjust the byte counts (since we were a bit lazy in the loop)
|
||||||
if (keyIndex >= in && keyIndex - skip < out)
|
if (keyIndex >= in && keyIndex - skip < out) {
|
||||||
bytesAfter = BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in]) - bytesBefore - total;
|
bytesAfter = BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[in])
|
||||||
else if (keyIndex < skip)
|
- bytesBefore - total;
|
||||||
|
} else if (keyIndex < skip)
|
||||||
bytesBefore = node->AllKeyLength() - total;
|
bytesBefore = node->AllKeyLength() - total;
|
||||||
|
|
||||||
if (bytesBefore < 0 || bytesAfter < 0)
|
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);
|
node->left_link = HOST_ENDIAN_TO_BFS_INT64(otherOffset);
|
||||||
// right link, and overflow link can stay the same
|
// 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);
|
node->all_key_count = HOST_ENDIAN_TO_BFS_INT16(out - 1);
|
||||||
|
|
||||||
// array positions have changed
|
// array positions have changed
|
||||||
@@ -1157,19 +1189,25 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
|
|||||||
|
|
||||||
if (bytesBefore)
|
if (bytesBefore)
|
||||||
memmove(inKeys, inKeys + total, bytesBefore);
|
memmove(inKeys, inKeys + total, bytesBefore);
|
||||||
if (bytesAfter)
|
if (bytesAfter) {
|
||||||
memmove(inKeys + bytesBefore + bytes, inKeys + total + bytesBefore, bytesAfter);
|
memmove(inKeys + bytesBefore + bytes, inKeys + total + bytesBefore,
|
||||||
|
bytesAfter);
|
||||||
|
}
|
||||||
|
|
||||||
if (bytesBefore)
|
if (bytesBefore)
|
||||||
memmove(outKeyLengths, inKeyLengths + skip, keys * sizeof(uint16));
|
memmove(outKeyLengths, inKeyLengths + skip, keys * sizeof(uint16));
|
||||||
in = out - keyIndex - 1;
|
in = out - keyIndex - 1;
|
||||||
if (bytesAfter)
|
if (bytesAfter) {
|
||||||
memmove(outKeyLengths + keyIndex + 1, inKeyLengths + skip + keyIndex, in * sizeof(uint16));
|
memmove(outKeyLengths + keyIndex + 1, inKeyLengths + skip + keyIndex,
|
||||||
|
in * sizeof(uint16));
|
||||||
|
}
|
||||||
|
|
||||||
if (bytesBefore)
|
if (bytesBefore)
|
||||||
memmove(outKeyValues, inKeyValues + skip, keys * sizeof(off_t));
|
memmove(outKeyValues, inKeyValues + skip, keys * sizeof(off_t));
|
||||||
if (bytesAfter)
|
if (bytesAfter) {
|
||||||
memmove(outKeyValues + keyIndex + 1, inKeyValues + skip + keyIndex, in * sizeof(off_t));
|
memmove(outKeyValues + keyIndex + 1, inKeyValues + skip + keyIndex,
|
||||||
|
in * sizeof(off_t));
|
||||||
|
}
|
||||||
|
|
||||||
if (bytes) {
|
if (bytes) {
|
||||||
// finally, copy the newly inserted key (don't overwrite anything)
|
// 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
|
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);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
@@ -1214,7 +1254,7 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
|
|||||||
WriteLocked locked(fStream->Lock());
|
WriteLocked locked(fStream->Lock());
|
||||||
|
|
||||||
Stack<node_and_key> stack;
|
Stack<node_and_key> stack;
|
||||||
if (SeekDown(stack, key, keyLength) != B_OK)
|
if (_SeekDown(stack, key, keyLength) != B_OK)
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
uint8 keyBuffer[BPLUSTREE_MAX_KEY_LENGTH + 1];
|
uint8 keyBuffer[BPLUSTREE_MAX_KEY_LENGTH + 1];
|
||||||
@@ -1226,18 +1266,21 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
|
|||||||
const bplustree_node *node;
|
const bplustree_node *node;
|
||||||
|
|
||||||
CachedNode cached(this);
|
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
|
#ifdef DEBUG
|
||||||
NodeChecker checker(node, fNodeSize, "insert");
|
NodeChecker checker(node, fNodeSize, "insert");
|
||||||
#endif
|
#endif
|
||||||
if (node->IsLeaf()) {
|
if (node->IsLeaf()) {
|
||||||
// first round, check for duplicate entries
|
// 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?
|
// is this a duplicate entry?
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
if (fAllowDuplicates) {
|
if (fAllowDuplicates) {
|
||||||
status = InsertDuplicate(transaction, cached, node, nodeAndKey.keyIndex, value);
|
status = _InsertDuplicate(transaction, cached, node,
|
||||||
|
nodeAndKey.keyIndex, value);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
RETURN_ERROR(status);
|
RETURN_ERROR(status);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -1252,11 +1295,14 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
|
|||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
|
|
||||||
// is the node big enough to hold the pair?
|
// is the node big enough to hold the pair?
|
||||||
if (int32(round_up(sizeof(bplustree_node) + writableNode->AllKeyLength() + keyLength)
|
if (int32(round_up(sizeof(bplustree_node)
|
||||||
+ (writableNode->NumKeys() + 1) * (sizeof(uint16) + sizeof(off_t))) < fNodeSize)
|
+ writableNode->AllKeyLength() + keyLength)
|
||||||
{
|
+ (writableNode->NumKeys() + 1) * (sizeof(uint16)
|
||||||
InsertKey(writableNode, nodeAndKey.keyIndex, keyBuffer, keyLength, value);
|
+ sizeof(off_t))) < fNodeSize) {
|
||||||
UpdateIterators(nodeAndKey.nodeOffset, BPLUSTREE_NULL, nodeAndKey.keyIndex, 0, 1);
|
_InsertKey(writableNode, nodeAndKey.keyIndex,
|
||||||
|
keyBuffer, keyLength, value);
|
||||||
|
_UpdateIterators(nodeAndKey.nodeOffset, BPLUSTREE_NULL,
|
||||||
|
nodeAndKey.keyIndex, 0, 1);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
} else {
|
} else {
|
||||||
@@ -1268,7 +1314,8 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
|
|||||||
off_t newRoot = BPLUSTREE_NULL;
|
off_t newRoot = BPLUSTREE_NULL;
|
||||||
if (nodeAndKey.nodeOffset == fHeader->RootNode()) {
|
if (nodeAndKey.nodeOffset == fHeader->RootNode()) {
|
||||||
bplustree_node *root;
|
bplustree_node *root;
|
||||||
status_t status = cachedNewRoot.Allocate(transaction, &root, &newRoot);
|
status_t status = cachedNewRoot.Allocate(transaction, &root,
|
||||||
|
&newRoot);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
// The tree is most likely corrupted!
|
// The tree is most likely corrupted!
|
||||||
// But it's still sane at leaf level - we could set
|
// 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
|
// reserve space for the other node
|
||||||
bplustree_node *other;
|
bplustree_node *other;
|
||||||
off_t otherOffset;
|
off_t otherOffset;
|
||||||
status_t status = cachedOther.Allocate(transaction, &other, &otherOffset);
|
status_t status = cachedOther.Allocate(transaction, &other,
|
||||||
|
&otherOffset);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
cachedNewRoot.Free(transaction, newRoot);
|
cachedNewRoot.Free(transaction, newRoot);
|
||||||
RETURN_ERROR(status);
|
RETURN_ERROR(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SplitNode(writableNode, nodeAndKey.nodeOffset, other, otherOffset,
|
if (_SplitNode(writableNode, nodeAndKey.nodeOffset, other,
|
||||||
&nodeAndKey.keyIndex, keyBuffer, &keyLength, &value) < B_OK) {
|
otherOffset, &nodeAndKey.keyIndex, keyBuffer, &keyLength,
|
||||||
|
&value) < B_OK) {
|
||||||
// free root node & other node here
|
// free root node & other node here
|
||||||
cachedOther.Free(transaction, otherOffset);
|
cachedOther.Free(transaction, otherOffset);
|
||||||
cachedNewRoot.Free(transaction, newRoot);
|
cachedNewRoot.Free(transaction, newRoot);
|
||||||
@@ -1302,11 +1351,12 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
|
|||||||
NodeChecker otherChecker(other, fNodeSize, "insert split other");
|
NodeChecker otherChecker(other, fNodeSize, "insert split other");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
UpdateIterators(nodeAndKey.nodeOffset, otherOffset, nodeAndKey.keyIndex,
|
_UpdateIterators(nodeAndKey.nodeOffset, otherOffset,
|
||||||
writableNode->NumKeys(), 1);
|
nodeAndKey.keyIndex, writableNode->NumKeys(), 1);
|
||||||
|
|
||||||
// update the right link of the node in the left of the new node
|
// 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);
|
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) {
|
if (newRoot != BPLUSTREE_NULL) {
|
||||||
bplustree_node *root = cachedNewRoot.Node();
|
bplustree_node *root = cachedNewRoot.Node();
|
||||||
|
|
||||||
InsertKey(root, 0, keyBuffer, keyLength, writableNode->LeftLink());
|
_InsertKey(root, 0, keyBuffer, keyLength,
|
||||||
root->overflow_link = HOST_ENDIAN_TO_BFS_INT64(nodeAndKey.nodeOffset);
|
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)
|
if (header == NULL)
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
|
|
||||||
// finally, update header to point to the new root
|
// finally, update header to point to the new root
|
||||||
header->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(newRoot);
|
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;
|
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
|
status_t
|
||||||
BPlusTree::RemoveDuplicate(Transaction &transaction, const bplustree_node *node,
|
BPlusTree::_RemoveDuplicate(Transaction &transaction,
|
||||||
CachedNode &cached, uint16 index, off_t value)
|
const bplustree_node *node, CachedNode &cached, uint16 index,
|
||||||
|
off_t value)
|
||||||
{
|
{
|
||||||
off_t *values = node->Values();
|
off_t *values = node->Values();
|
||||||
off_t oldValue = BFS_ENDIAN_TO_HOST_INT64(values[index]);
|
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 it's a duplicate fragment, remove the entry from there
|
||||||
if (bplustree_node::LinkType(oldValue) == BPLUSTREE_DUPLICATE_FRAGMENT) {
|
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
|
if (array->count > NUM_FRAGMENT_VALUES
|
||||||
|| array->count < 1) {
|
|| array->count < 1) {
|
||||||
@@ -1488,7 +1544,7 @@ BPlusTree::RemoveDuplicate(Transaction &transaction, const bplustree_node *node,
|
|||||||
bplustree_node *fragment = NULL;
|
bplustree_node *fragment = NULL;
|
||||||
uint32 fragmentIndex = 0;
|
uint32 fragmentIndex = 0;
|
||||||
off_t offset;
|
off_t offset;
|
||||||
if (FindFreeDuplicateFragment(transaction, node, cachedOther,
|
if (_FindFreeDuplicateFragment(transaction, node, cachedOther,
|
||||||
&offset, &fragment, &fragmentIndex) == B_OK) {
|
&offset, &fragment, &fragmentIndex) == B_OK) {
|
||||||
// move to other node
|
// move to other node
|
||||||
duplicate_array *target = fragment->FragmentAt(fragmentIndex);
|
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
|
Removes the key with the given index from the specified node.
|
||||||
* pointer), it's not needed to pass the key & its length, although
|
Since it has to get the key from the node anyway (to obtain it's
|
||||||
* the calling method (BPlusTree::Remove()) have this data.
|
pointer), it's not needed to pass the key & its length, although
|
||||||
*/
|
the calling method (BPlusTree::Remove()) have this data.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
BPlusTree::RemoveKey(bplustree_node *node, uint16 index)
|
BPlusTree::_RemoveKey(bplustree_node *node, uint16 index)
|
||||||
{
|
{
|
||||||
// should never happen, but who knows?
|
// should never happen, but who knows?
|
||||||
if (index > node->NumKeys() && node->NumKeys() > 0) {
|
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.
|
Removes the specified key from the tree. The "value" parameter is only used
|
||||||
* It's not an optional parameter, so at least you have to think about it.
|
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
|
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);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
// lock access to stream
|
// lock access to stream
|
||||||
WriteLocked locked(fStream->Lock());
|
WriteLocked locked(fStream->Lock());
|
||||||
|
|
||||||
Stack<node_and_key> stack;
|
Stack<node_and_key> stack;
|
||||||
if (SeekDown(stack, key, keyLength) != B_OK)
|
if (_SeekDown(stack, key, keyLength) != B_OK)
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
node_and_key nodeAndKey;
|
node_and_key nodeAndKey;
|
||||||
const bplustree_node *node;
|
const bplustree_node *node;
|
||||||
|
|
||||||
CachedNode cached(this);
|
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
|
#ifdef DEBUG
|
||||||
NodeChecker checker(node, fNodeSize, "remove");
|
NodeChecker checker(node, fNodeSize, "remove");
|
||||||
#endif
|
#endif
|
||||||
if (node->IsLeaf()) {
|
if (node->IsLeaf()) {
|
||||||
// first round, check for duplicate entries
|
// 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)
|
if (status < B_OK)
|
||||||
RETURN_ERROR(status);
|
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
|
// to the next node after the current - if there aren't any
|
||||||
// more nodes, we need a way to prevent the TreeIterators to
|
// more nodes, we need a way to prevent the TreeIterators to
|
||||||
// touch the old node again, we use BPLUSTREE_FREE for this
|
// touch the old node again, we use BPLUSTREE_FREE for this
|
||||||
off_t next = node->RightLink() == BPLUSTREE_NULL ? BPLUSTREE_FREE : node->RightLink();
|
off_t next = node->RightLink() == BPLUSTREE_NULL
|
||||||
UpdateIterators(nodeAndKey.nodeOffset, node->NumKeys() == 1 ?
|
? BPLUSTREE_FREE : node->RightLink();
|
||||||
next : BPLUSTREE_NULL, nodeAndKey.keyIndex, 0 , -1);
|
_UpdateIterators(nodeAndKey.nodeOffset, node->NumKeys() == 1
|
||||||
|
? next : BPLUSTREE_NULL, nodeAndKey.keyIndex, 0 , -1);
|
||||||
|
|
||||||
// is this a duplicate entry?
|
// is this a duplicate entry?
|
||||||
if (bplustree_node::IsDuplicate(BFS_ENDIAN_TO_HOST_INT64(
|
if (bplustree_node::IsDuplicate(BFS_ENDIAN_TO_HOST_INT64(
|
||||||
node->Values()[nodeAndKey.keyIndex]))) {
|
node->Values()[nodeAndKey.keyIndex]))) {
|
||||||
if (fAllowDuplicates) {
|
if (fAllowDuplicates) {
|
||||||
return RemoveDuplicate(transaction, node, cached,
|
return _RemoveDuplicate(transaction, node, cached,
|
||||||
nodeAndKey.keyIndex, value);
|
nodeAndKey.keyIndex, value);
|
||||||
} else {
|
} else {
|
||||||
FATAL(("dupliate node found where no duplicates are allowed!\n"));
|
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)
|
// the overflow link, so we have to drop the last key)
|
||||||
if (writableNode->NumKeys() > 1
|
if (writableNode->NumKeys() > 1
|
||||||
|| !writableNode->IsLeaf() && writableNode->NumKeys() == 1) {
|
|| !writableNode->IsLeaf() && writableNode->NumKeys() == 1) {
|
||||||
RemoveKey(writableNode, nodeAndKey.keyIndex);
|
_RemoveKey(writableNode, nodeAndKey.keyIndex);
|
||||||
return B_OK;
|
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,
|
Replaces the value for the key in the tree.
|
||||||
* B_ENTRY_NOT_FOUND if the key couldn't be found, and other errors
|
Returns B_OK if the key could be found and its value replaced,
|
||||||
* to indicate that something went terribly wrong.
|
B_ENTRY_NOT_FOUND if the key couldn't be found, and other errors
|
||||||
* Note that this doesn't work with duplicates - it will just
|
to indicate that something went terribly wrong.
|
||||||
* return B_BAD_TYPE if you call this function on a tree where
|
Note that this doesn't work with duplicates - it will just
|
||||||
* duplicates are allowed.
|
return B_BAD_TYPE if you call this function on a tree where
|
||||||
*/
|
duplicates are allowed.
|
||||||
|
*/
|
||||||
status_t
|
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)
|
|| key == NULL)
|
||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
@@ -1709,7 +1771,7 @@ BPlusTree::Replace(Transaction &transaction, const uint8 *key, uint16 keyLength,
|
|||||||
while ((node = cached.SetTo(nodeOffset)) != NULL) {
|
while ((node = cached.SetTo(nodeOffset)) != NULL) {
|
||||||
uint16 keyIndex = 0;
|
uint16 keyIndex = 0;
|
||||||
off_t nextOffset;
|
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 (node->OverflowLink() == BPLUSTREE_NULL) {
|
||||||
if (status == B_OK) {
|
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.
|
Searches the key in the tree, and stores the offset found in
|
||||||
* It's very similar to BPlusTree::SeekDown(), but doesn't fill
|
_value, if successful.
|
||||||
* a stack while it descends the tree.
|
It's very similar to BPlusTree::SeekDown(), but doesn't fill
|
||||||
* Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND
|
a stack while it descends the tree.
|
||||||
* if not. It can also return other errors to indicate that
|
Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND
|
||||||
* something went wrong.
|
if not. It can also return other errors to indicate that
|
||||||
* Note that this doesn't work with duplicates - it will just
|
something went wrong.
|
||||||
* return B_BAD_TYPE if you call this function on a tree where
|
Note that this doesn't work with duplicates - it will just
|
||||||
* duplicates are allowed.
|
return B_BAD_TYPE if you call this function on a tree where
|
||||||
*/
|
duplicates are allowed.
|
||||||
|
*/
|
||||||
status_t
|
status_t
|
||||||
BPlusTree::Find(const uint8 *key, uint16 keyLength, off_t *_value)
|
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)
|
|| key == NULL)
|
||||||
RETURN_ERROR(B_BAD_VALUE);
|
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) {
|
while ((node = cached.SetTo(nodeOffset)) != NULL) {
|
||||||
uint16 keyIndex = 0;
|
uint16 keyIndex = 0;
|
||||||
off_t nextOffset;
|
off_t nextOffset;
|
||||||
status_t status = FindKey(node, key, keyLength, &keyIndex, &nextOffset);
|
status_t status = _FindKey(node, key, keyLength, &keyIndex, &nextOffset);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
levels++;
|
levels++;
|
||||||
@@ -1799,14 +1862,14 @@ TreeIterator::TreeIterator(BPlusTree *tree)
|
|||||||
fCurrentNodeOffset(BPLUSTREE_NULL),
|
fCurrentNodeOffset(BPLUSTREE_NULL),
|
||||||
fNext(NULL)
|
fNext(NULL)
|
||||||
{
|
{
|
||||||
tree->AddIterator(this);
|
tree->_AddIterator(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TreeIterator::~TreeIterator()
|
TreeIterator::~TreeIterator()
|
||||||
{
|
{
|
||||||
if (fTree)
|
if (fTree)
|
||||||
fTree->RemoveIterator(this);
|
fTree->_RemoveIterator(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1840,7 +1903,8 @@ TreeIterator::Goto(int8 to)
|
|||||||
nextOffset = node->OverflowLink();
|
nextOffset = node->OverflowLink();
|
||||||
else {
|
else {
|
||||||
if (node->AllKeyLength() > fTree->fNodeSize
|
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);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
nextOffset = BFS_ENDIAN_TO_HOST_INT64(node->Values()[0]);
|
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
|
Iterates through the tree in the specified direction.
|
||||||
* first entry - if you need to know when this happens, use the "duplicate"
|
When it iterates through duplicates, the "key" is only updated for the
|
||||||
* parameter which is 0 for no duplicate, 1 for the first, and 2 for all
|
first entry - if you need to know when this happens, use the "duplicate"
|
||||||
* the other duplicates.
|
parameter which is 0 for no duplicate, 1 for the first, and 2 for all
|
||||||
* That's not too nice, but saves the 256 bytes that would be needed to
|
the other duplicates.
|
||||||
* store the last key - if this will ever become an issue, it will be
|
That's not too nice, but saves the 256 bytes that would be needed to
|
||||||
* easy to change.
|
store the last key - if this will ever become an issue, it will be
|
||||||
* The other advantage of this is, that the queries can skip all duplicates
|
easy to change.
|
||||||
* at once when they are not relevant to them.
|
The other advantage of this is, that the queries can skip all duplicates
|
||||||
*/
|
at once when they are not relevant to them.
|
||||||
|
*/
|
||||||
status_t
|
status_t
|
||||||
TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxLength,
|
TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength,
|
||||||
off_t *value, uint16 *duplicate)
|
uint16 maxLength, off_t *value, uint16 *duplicate)
|
||||||
{
|
{
|
||||||
if (fTree == NULL)
|
if (fTree == NULL)
|
||||||
return B_INTERRUPTED;
|
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
|
This is more or less a copy of BPlusTree::Find() - but it just
|
||||||
* key could be found or not.
|
sets the current position in the iterator, regardless of if the
|
||||||
*/
|
key could be found or not.
|
||||||
|
*/
|
||||||
status_t
|
status_t
|
||||||
TreeIterator::Find(const uint8 *key, uint16 keyLength)
|
TreeIterator::Find(const uint8 *key, uint16 keyLength)
|
||||||
{
|
{
|
||||||
@@ -2031,7 +2095,8 @@ TreeIterator::Find(const uint8 *key, uint16 keyLength)
|
|||||||
while ((node = cached.SetTo(nodeOffset)) != NULL) {
|
while ((node = cached.SetTo(nodeOffset)) != NULL) {
|
||||||
uint16 keyIndex = 0;
|
uint16 keyIndex = 0;
|
||||||
off_t nextOffset;
|
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) {
|
if (node->OverflowLink() == BPLUSTREE_NULL) {
|
||||||
fCurrentNodeOffset = nodeOffset;
|
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
|
/*! 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
|
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
|
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.
|
used, and 2 if there are at least 2 fragments used.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint32
|
uint32
|
||||||
bplustree_node::FragmentsUsed(uint32 nodeSize) const
|
bplustree_node::FragmentsUsed(uint32 nodeSize) const
|
||||||
{
|
{
|
||||||
@@ -2210,14 +2274,11 @@ bplustree_node::CheckIntegrity(uint32 nodeSize) const
|
|||||||
|
|
||||||
|
|
||||||
int32
|
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 one of the keys is NULL, bail out gracefully
|
||||||
if (key1 == NULL || key2 == NULL) {
|
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
|
// even if it's most probably a bug in the calling code, we try to
|
||||||
// give a meaningful result
|
// give a meaningful result
|
||||||
if (key1 == NULL && key2 != NULL)
|
if (key1 == NULL && key2 != NULL)
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
/* BPlusTree - BFS B+Tree implementation
|
/*
|
||||||
*
|
* Copyright 2001-2007, Axel Dörfler, [email protected].
|
||||||
* 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].
|
|
||||||
* This file may be used under the terms of the MIT License.
|
* This file may be used under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef B_PLUS_TREE_H
|
#ifndef B_PLUS_TREE_H
|
||||||
@@ -15,7 +11,7 @@
|
|||||||
#include "Chain.h"
|
#include "Chain.h"
|
||||||
|
|
||||||
|
|
||||||
//****************** on-disk structures ********************
|
// #pragma mark - on-disk structures
|
||||||
|
|
||||||
struct bplustree_node;
|
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 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 FreeNode() const { return BFS_ENDIAN_TO_HOST_INT64(free_node_pointer); }
|
||||||
off_t MaximumSize() const { return BFS_ENDIAN_TO_HOST_INT64(maximum_size); }
|
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 CheckNode(bplustree_node *node) const;
|
||||||
inline bool IsValidLink(off_t link) 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;
|
template<class T> class Stack;
|
||||||
class BPlusTree;
|
class BPlusTree;
|
||||||
@@ -134,8 +131,6 @@ struct node_and_key {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//***** Cache handling *****
|
|
||||||
|
|
||||||
class CachedNode {
|
class CachedNode {
|
||||||
public:
|
public:
|
||||||
CachedNode(BPlusTree *tree)
|
CachedNode(BPlusTree *tree)
|
||||||
@@ -159,7 +154,8 @@ class CachedNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bplustree_node *SetTo(off_t offset, bool check = true);
|
const bplustree_node *SetTo(off_t offset, bool check = true);
|
||||||
bplustree_node *SetToWritable(Transaction &transaction, off_t offset, bool check = true);
|
bplustree_node *SetToWritable(Transaction &transaction, off_t offset,
|
||||||
|
bool check = true);
|
||||||
bplustree_node *MakeWritable(Transaction &transaction);
|
bplustree_node *MakeWritable(Transaction &transaction);
|
||||||
const bplustree_header *SetToHeader();
|
const bplustree_header *SetToHeader();
|
||||||
bplustree_header *SetToWritableHeader(Transaction &transaction);
|
bplustree_header *SetToWritableHeader(Transaction &transaction);
|
||||||
@@ -169,7 +165,8 @@ class CachedNode {
|
|||||||
void Unset();
|
void Unset();
|
||||||
|
|
||||||
status_t Free(Transaction &transaction, off_t offset);
|
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; }
|
bool IsWritable() const { return fWritable; }
|
||||||
bplustree_node *Node() const { return fNode; }
|
bplustree_node *Node() const { return fNode; }
|
||||||
@@ -185,27 +182,31 @@ class CachedNode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//******** B+tree class *********
|
|
||||||
|
|
||||||
class BPlusTree {
|
class BPlusTree {
|
||||||
public:
|
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(Inode *stream);
|
||||||
BPlusTree();
|
BPlusTree();
|
||||||
~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 SetTo(Inode *stream);
|
||||||
status_t SetStream(Inode *stream);
|
status_t SetStream(Inode *stream);
|
||||||
|
|
||||||
status_t InitCheck();
|
status_t InitCheck();
|
||||||
status_t Validate();
|
status_t Validate();
|
||||||
|
|
||||||
status_t Remove(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value);
|
status_t Remove(Transaction &transaction, const uint8 *key,
|
||||||
status_t Insert(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value);
|
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 Remove(Transaction &transaction, const char *key,
|
||||||
status_t Insert(Transaction &transaction, const char *key, off_t value);
|
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, int32 key, off_t value);
|
||||||
status_t Insert(Transaction &transaction, uint32 key, off_t value);
|
status_t Insert(Transaction &transaction, uint32 key, off_t value);
|
||||||
status_t Insert(Transaction &transaction, int64 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, float key, off_t value);
|
||||||
status_t Insert(Transaction &transaction, double 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);
|
status_t Find(const uint8 *key, uint16 keyLength, off_t *value);
|
||||||
|
|
||||||
static int32 TypeCodeToKeyType(type_code code);
|
static int32 TypeCodeToKeyType(type_code code);
|
||||||
@@ -224,30 +226,37 @@ class BPlusTree {
|
|||||||
BPlusTree &operator=(const BPlusTree &);
|
BPlusTree &operator=(const BPlusTree &);
|
||||||
// no implementation
|
// no implementation
|
||||||
|
|
||||||
int32 CompareKeys(const void *key1, int keylength1, const void *key2, int keylength2);
|
int32 _CompareKeys(const void *key1, int keylength1,
|
||||||
status_t FindKey(const bplustree_node *node, const uint8 *key, uint16 keyLength,
|
const void *key2, int keylength2);
|
||||||
uint16 *index = NULL, off_t *next = NULL);
|
status_t _FindKey(const bplustree_node *node, const uint8 *key,
|
||||||
status_t SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLength);
|
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,
|
const bplustree_node *node, CachedNode &cached,
|
||||||
off_t *_offset, bplustree_node **_fragment, uint32 *_index);
|
off_t *_offset, bplustree_node **_fragment,
|
||||||
status_t InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
uint32 *_index);
|
||||||
const bplustree_node *node, uint16 index, off_t value);
|
status_t _InsertDuplicate(Transaction &transaction,
|
||||||
void InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyLength,
|
CachedNode &cached, const bplustree_node *node,
|
||||||
off_t value);
|
uint16 index, off_t value);
|
||||||
status_t SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *other,
|
void _InsertKey(bplustree_node *node, uint16 index, uint8 *key,
|
||||||
off_t otherOffset, uint16 *_keyIndex, uint8 *key, uint16 *_keyLength,
|
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);
|
off_t *_value);
|
||||||
|
|
||||||
status_t RemoveDuplicate(Transaction &transaction, const bplustree_node *node,
|
status_t _RemoveDuplicate(Transaction &transaction,
|
||||||
CachedNode &cached, uint16 keyIndex, off_t value);
|
const bplustree_node *node, CachedNode &cached,
|
||||||
void RemoveKey(bplustree_node *node, uint16 index);
|
uint16 keyIndex, off_t value);
|
||||||
|
void _RemoveKey(bplustree_node *node, uint16 index);
|
||||||
|
|
||||||
void UpdateIterators(off_t offset, off_t nextOffset, uint16 keyIndex,
|
void _UpdateIterators(off_t offset, off_t nextOffset,
|
||||||
uint16 splitAt, int8 change);
|
uint16 keyIndex, uint16 splitAt, int8 change);
|
||||||
void AddIterator(TreeIterator *iterator);
|
void _AddIterator(TreeIterator *iterator);
|
||||||
void RemoveIterator(TreeIterator *iterator);
|
void _RemoveIterator(TreeIterator *iterator);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class TreeIterator;
|
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,
|
extern int32 compareKeys(type_code type, const void *key1, int keyLength1,
|
||||||
const void *key2, int keyLength2);
|
const void *key2, int keyLength2);
|
||||||
@@ -275,15 +284,17 @@ class TreeIterator {
|
|||||||
~TreeIterator();
|
~TreeIterator();
|
||||||
|
|
||||||
status_t Goto(int8 to);
|
status_t Goto(int8 to);
|
||||||
status_t Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxLength,
|
status_t Traverse(int8 direction, void *key, uint16 *keyLength,
|
||||||
off_t *value, uint16 *duplicate = NULL);
|
uint16 maxLength, off_t *value,
|
||||||
|
uint16 *duplicate = NULL);
|
||||||
status_t Find(const uint8 *key, uint16 keyLength);
|
status_t Find(const uint8 *key, uint16 keyLength);
|
||||||
|
|
||||||
status_t Rewind();
|
status_t Rewind();
|
||||||
status_t GetNextEntry(void *key, uint16 *keyLength, uint16 maxLength,
|
status_t GetNextEntry(void *key, uint16 *keyLength, uint16 maxLength,
|
||||||
off_t *value, uint16 *duplicate = NULL);
|
off_t *value, uint16 *duplicate = NULL);
|
||||||
status_t GetPreviousEntry(void *key, uint16 *keyLength, uint16 maxLength,
|
status_t GetPreviousEntry(void *key, uint16 *keyLength,
|
||||||
off_t *value, uint16 *duplicate = NULL);
|
uint16 maxLength, off_t *value,
|
||||||
|
uint16 *duplicate = NULL);
|
||||||
void SkipDuplicates();
|
void SkipDuplicates();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@@ -303,12 +314,16 @@ class TreeIterator {
|
|||||||
friend class Chain<TreeIterator>;
|
friend class Chain<TreeIterator>;
|
||||||
friend class BPlusTree;
|
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();
|
void Stop();
|
||||||
TreeIterator *fNext;
|
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
|
inline status_t
|
||||||
BPlusTree::Remove(Transaction &transaction, const char *key, off_t value)
|
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 - TreeIterator inline functions
|
||||||
// #pragma mark -
|
|
||||||
|
|
||||||
inline status_t
|
inline status_t
|
||||||
TreeIterator::Rewind()
|
TreeIterator::Rewind()
|
||||||
@@ -398,8 +413,8 @@ TreeIterator::GetPreviousEntry(void *key, uint16 *keyLength, uint16 maxLength,
|
|||||||
return Traverse(BPLUSTREE_BACKWARD, key, keyLength, maxLength, value, duplicate);
|
return Traverse(BPLUSTREE_BACKWARD, key, keyLength, maxLength, value, duplicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************ bplustree_header inline functions ************************/
|
|
||||||
// #pragma mark -
|
// #pragma mark - bplustree_header inline functions
|
||||||
|
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
@@ -420,14 +435,14 @@ bplustree_header::IsValidLink(off_t link) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************ bplustree_node inline functions ************************/
|
// #pragma mark - bplustree_node inline functions
|
||||||
// #pragma mark -
|
|
||||||
|
|
||||||
|
|
||||||
inline uint16 *
|
inline uint16 *
|
||||||
bplustree_node::KeyLengths() const
|
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
|
inline int32
|
||||||
bplustree_node::Used() const
|
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 *
|
inline duplicate_array *
|
||||||
bplustree_node::FragmentAt(int8 index) const
|
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
|
inline off_t
|
||||||
bplustree_node::MakeLink(uint8 type, off_t link, uint32 fragmentIndex)
|
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
|
inline bool
|
||||||
bplustree_node::IsDuplicate(off_t link)
|
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));
|
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"
|
#include "system_dependencies.h"
|
||||||
|
|
||||||
#ifdef USER
|
|
||||||
# define spawn_kernel_thread spawn_thread
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// Things the BlockAllocator should do:
|
// Things the BlockAllocator should do:
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* Debug - debug stuff
|
/*
|
||||||
*
|
* Copyright 2001-2007, Axel Dörfler, [email protected].
|
||||||
* Copyright 2001-2006, Axel Dörfler, [email protected].
|
|
||||||
* Some code is based on work previously done by Marcus Overhagen.
|
* Some code is based on work previously done by Marcus Overhagen.
|
||||||
*
|
*
|
||||||
* This file may be used under the terms of the MIT License.
|
* 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 -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
#ifndef USER
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
dbg_inode(int argc, char **argv)
|
debug_inode(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
kprintf("usage: bfsinode ptr-to-inode\n");
|
kprintf("usage: bfsinode <ptr-to-inode>\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,22 +255,17 @@ dbg_inode(int argc, char **argv)
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
void
|
||||||
remove_debugger_commands()
|
remove_debugger_commands()
|
||||||
{
|
{
|
||||||
#ifndef USER
|
remove_debugger_command("bfsinode", debug_inode);
|
||||||
remove_debugger_command("bfsinode", dbg_inode);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
add_debugger_commands()
|
add_debugger_commands()
|
||||||
{
|
{
|
||||||
#ifndef USER
|
add_debugger_command("bfsinode", debug_inode, "dump an Inode object");
|
||||||
add_debugger_command("bfsinode", dbg_inode, "dump an Inode object");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,10 @@
|
|||||||
// Configure here if and when real benaphores should be used
|
// Configure here if and when real benaphores should be used
|
||||||
#define USE_BENAPHORE
|
#define USE_BENAPHORE
|
||||||
// if defined, benaphores are used for the Semaphore/RecursiveLock classes
|
// if defined, benaphores are used for the Semaphore/RecursiveLock classes
|
||||||
#ifdef USER
|
|
||||||
//# define FAST_LOCK
|
//# define FAST_LOCK
|
||||||
// the ReadWriteLock class uses a second Semaphore to
|
// the ReadWriteLock class uses a second Semaphore to
|
||||||
// speed up locking - only makes sense if USE_BENAPHORE
|
// speed up locking - only makes sense if USE_BENAPHORE
|
||||||
// is defined, too.
|
// is defined, too.
|
||||||
#endif
|
|
||||||
#ifdef FAST_LOCK
|
#ifdef FAST_LOCK
|
||||||
# error implement recursive write locking first
|
# error implement recursive write locking first
|
||||||
#endif
|
#endif
|
||||||
@@ -37,9 +35,6 @@ class Semaphore {
|
|||||||
fSemaphore(create_sem(1, name))
|
fSemaphore(create_sem(1, name))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#ifndef USER
|
|
||||||
set_sem_owner(fSemaphore, B_SYSTEM_TEAM);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~Semaphore()
|
~Semaphore()
|
||||||
@@ -126,9 +121,6 @@ class RecursiveLock {
|
|||||||
#endif
|
#endif
|
||||||
fOwner(-1)
|
fOwner(-1)
|
||||||
{
|
{
|
||||||
#ifndef USER
|
|
||||||
set_sem_owner(fSemaphore, B_SYSTEM_TEAM);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t LockWithTimeout(bigtime_t timeout)
|
status_t LockWithTimeout(bigtime_t timeout)
|
||||||
@@ -276,9 +268,6 @@ class ReadWriteLock {
|
|||||||
{
|
{
|
||||||
fSemaphore = create_sem(0, name);
|
fSemaphore = create_sem(0, name);
|
||||||
fCount = MAX_READERS;
|
fCount = MAX_READERS;
|
||||||
#ifndef USER
|
|
||||||
set_sem_owner(fSemaphore, B_SYSTEM_TEAM);
|
|
||||||
#endif
|
|
||||||
return fSemaphore;
|
return fSemaphore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,9 +349,6 @@ class ReadWriteLock {
|
|||||||
status_t Initialize(const char *name = "bfs r/w lock")
|
status_t Initialize(const char *name = "bfs r/w lock")
|
||||||
{
|
{
|
||||||
fSemaphore = create_sem(MAX_READERS, name);
|
fSemaphore = create_sem(MAX_READERS, name);
|
||||||
#ifndef USER
|
|
||||||
set_sem_owner(fSemaphore, B_SYSTEM_TEAM);
|
|
||||||
#endif
|
|
||||||
return fSemaphore;
|
return fSemaphore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -273,9 +273,7 @@ Volume::Panic()
|
|||||||
{
|
{
|
||||||
FATAL(("we have to panic... switch to read-only mode!\n"));
|
FATAL(("we have to panic... switch to read-only mode!\n"));
|
||||||
fFlags |= VOLUME_READ_ONLY;
|
fFlags |= VOLUME_READ_ONLY;
|
||||||
#ifdef USER
|
#ifdef DEBUG
|
||||||
debugger("BFS panics!");
|
|
||||||
#elif defined(DEBUG)
|
|
||||||
kernel_debugger("BFS panics!");
|
kernel_debugger("BFS panics!");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user