Made CachedNode::SetTo[Header]() return a const node/header. Made some other methods

that were supposed to be const const as well.
Found one bug this way: in one case, a duplicate node might not have been part of a
transaction (and thus, was not written back). This bug only affected the Haiku version
of BFS, though.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14083 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-08-29 21:57:08 +00:00
parent 1509c79696
commit 0afc66fa69
2 changed files with 139 additions and 105 deletions
+118 -87
View File
@@ -25,7 +25,7 @@
#ifdef DEBUG #ifdef DEBUG
class NodeChecker { class NodeChecker {
public: public:
NodeChecker(bplustree_node *node, int32 nodeSize, const char *text) NodeChecker(const bplustree_node *node, int32 nodeSize, const char *text)
: :
fNode(node), fNode(node),
fSize(nodeSize), fSize(nodeSize),
@@ -47,9 +47,9 @@ class NodeChecker {
} }
private: private:
bplustree_node *fNode; const bplustree_node *fNode;
int32 fSize; int32 fSize;
const char *fText; const char *fText;
}; };
#endif #endif
@@ -95,7 +95,7 @@ CachedNode::Unset()
} }
bplustree_node * const bplustree_node *
CachedNode::SetTo(off_t offset, bool check) CachedNode::SetTo(off_t offset, bool check)
{ {
if (fTree == NULL || fTree->fStream == NULL) { if (fTree == NULL || fTree->fStream == NULL) {
@@ -155,18 +155,28 @@ CachedNode::SetToWritable(Transaction &transaction, off_t offset, bool check)
} }
status_t bplustree_node *
CachedNode::MakeWritable(Transaction &transaction) CachedNode::MakeWritable(Transaction &transaction)
{ {
if (fNode == NULL) if (fNode == NULL)
return B_NO_INIT; return NULL;
return block_cache_make_writable(transaction.GetVolume()->BlockCache(), if (block_cache_make_writable(transaction.GetVolume()->BlockCache(),
fBlockNumber, transaction.ID()); fBlockNumber, transaction.ID()) == B_OK)
return fNode;
return NULL;
} }
bplustree_header * bplustree_header *
CachedNode::MakeWritableHeader(Transaction &transaction)
{
return (bplustree_header *)MakeWritable(transaction);
}
const bplustree_header *
CachedNode::SetToHeader() CachedNode::SetToHeader()
{ {
if (fTree == NULL || fTree->fStream == NULL) { if (fTree == NULL || fTree->fStream == NULL) {
@@ -242,8 +252,8 @@ CachedNode::Free(Transaction &transaction, off_t offset)
// function is called, perhaps it should be done when the directory // function is called, perhaps it should be done when the directory
// inode is closed or based on some calculation or whatever... // inode is closed or based on some calculation or whatever...
bplustree_header *header = fTree->fHeader; bplustree_header *header = fTree->fCachedHeader.MakeWritableHeader(transaction);
if (fTree->fCachedHeader.MakeWritable(transaction) != B_OK) if (header == NULL)
return B_IO_ERROR; return B_IO_ERROR;
// if the node is the last one in the tree, we shrink // if the node is the last one in the tree, we shrink
@@ -275,12 +285,13 @@ CachedNode::Allocate(Transaction &transaction, bplustree_node **_node, off_t *_o
Unset(); Unset();
bplustree_header *header = fTree->fHeader; bplustree_header *header;
status_t status; status_t status;
// if there are any free nodes, recycle them // if there are any free nodes, recycle them
if (SetToWritable(transaction, header->FreeNode(), false) != NULL) { if (SetToWritable(transaction, fTree->fHeader->FreeNode(), false) != NULL) {
if (fTree->fCachedHeader.MakeWritable(transaction) != B_OK) header = fTree->fCachedHeader.MakeWritableHeader(transaction);
if (header == NULL)
return B_IO_ERROR; return B_IO_ERROR;
// set new free node pointer // set new free node pointer
@@ -297,7 +308,8 @@ CachedNode::Allocate(Transaction &transaction, bplustree_node **_node, off_t *_o
if ((status = stream->Append(transaction, fTree->fNodeSize)) < B_OK) if ((status = stream->Append(transaction, fTree->fNodeSize)) < B_OK)
return status; return status;
if (fTree->fCachedHeader.MakeWritable(transaction) != B_OK) header = fTree->fCachedHeader.MakeWritableHeader(transaction);
if (header == NULL)
return B_IO_ERROR; return B_IO_ERROR;
// 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
@@ -379,18 +391,19 @@ BPlusTree::SetTo(Transaction &transaction, Inode *stream, int32 nodeSize)
fStream = stream; fStream = stream;
fHeader = fCachedHeader.SetToWritableHeader(transaction); bplustree_header *header = fCachedHeader.SetToWritableHeader(transaction);
if (fHeader == NULL) { if (header == NULL) {
// allocate space for new header + node! // allocate space for new header + node!
fStatus = stream->SetFileSize(transaction, nodeSize * 2); fStatus = stream->SetFileSize(transaction, nodeSize * 2);
if (fStatus < B_OK) if (fStatus < B_OK)
RETURN_ERROR(fStatus); RETURN_ERROR(fStatus);
fHeader = fCachedHeader.SetToWritableHeader(transaction); header = fCachedHeader.SetToWritableHeader(transaction);
if (fHeader == NULL) if (header == NULL)
RETURN_ERROR(fStatus = B_ERROR); RETURN_ERROR(fStatus = B_ERROR);
} }
fHeader = header;
fAllowDuplicates = ((stream->Mode() & S_INDEX_DIR) == S_INDEX_DIR fAllowDuplicates = ((stream->Mode() & S_INDEX_DIR) == S_INDEX_DIR
&& stream->BlockRun() != stream->Parent()) && stream->BlockRun() != stream->Parent())
|| (stream->Mode() & S_ALLOW_DUPS) != 0; || (stream->Mode() & S_ALLOW_DUPS) != 0;
@@ -398,17 +411,17 @@ BPlusTree::SetTo(Transaction &transaction, Inode *stream, int32 nodeSize)
fNodeSize = nodeSize; fNodeSize = nodeSize;
// initialize b+tree header // initialize b+tree header
fHeader->magic = HOST_ENDIAN_TO_BFS_INT32(BPLUSTREE_MAGIC); header->magic = HOST_ENDIAN_TO_BFS_INT32(BPLUSTREE_MAGIC);
fHeader->node_size = HOST_ENDIAN_TO_BFS_INT32(fNodeSize); header->node_size = HOST_ENDIAN_TO_BFS_INT32(fNodeSize);
fHeader->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1); header->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1);
fHeader->data_type = HOST_ENDIAN_TO_BFS_INT32(ModeToKeyType(stream->Mode())); header->data_type = HOST_ENDIAN_TO_BFS_INT32(ModeToKeyType(stream->Mode()));
fHeader->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(nodeSize); header->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(nodeSize);
fHeader->free_node_pointer = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL); header->free_node_pointer = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(nodeSize * 2); header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(nodeSize * 2);
// initialize b+tree root node // initialize b+tree root node
CachedNode cached(this); CachedNode cached(this);
cached.SetToWritable(transaction, fHeader->RootNode(), false); cached.SetToWritable(transaction, header->RootNode(), false);
if (cached.Node() == NULL) if (cached.Node() == NULL)
RETURN_ERROR(B_IO_ERROR); RETURN_ERROR(B_IO_ERROR);
@@ -437,7 +450,8 @@ BPlusTree::SetTo(Inode *stream)
if (fHeader->MaximumSize() != stream->Size()) { if (fHeader->MaximumSize() != stream->Size()) {
FATAL(("B+tree header size doesn't fit file size!\n")); FATAL(("B+tree header size doesn't fit file size!\n"));
fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(stream->Size()); // we can't change the header since we don't have a transaction
//fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(stream->Size());
} }
if (fHeader->Magic() != BPLUSTREE_MAGIC if (fHeader->Magic() != BPLUSTREE_MAGIC
|| (fHeader->RootNode() % fHeader->NodeSize()) != 0 || (fHeader->RootNode() % fHeader->NodeSize()) != 0
@@ -614,7 +628,7 @@ BPlusTree::CompareKeys(const void *key1, int keyLength1, const void *key2, int k
status_t status_t
BPlusTree::FindKey(bplustree_node *node, const uint8 *key, uint16 keyLength, BPlusTree::FindKey(const bplustree_node *node, const uint8 *key, uint16 keyLength,
uint16 *_index, off_t *_next) uint16 *_index, off_t *_next)
{ {
#ifdef DEBUG #ifdef DEBUG
@@ -684,7 +698,7 @@ BPlusTree::SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLeng
nodeAndKey.nodeOffset = fHeader->RootNode(); nodeAndKey.nodeOffset = fHeader->RootNode();
CachedNode cached(this); CachedNode cached(this);
bplustree_node *node; const bplustree_node *node;
while ((node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) { while ((node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) {
// if we are already on leaf level, we're done // if we are already on leaf level, we're done
if (node->OverflowLink() == BPLUSTREE_NULL) { if (node->OverflowLink() == BPLUSTREE_NULL) {
@@ -713,11 +727,12 @@ BPlusTree::SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLeng
/** This will find a free duplicate fragment in the given bplustree_node. /** This will find a free duplicate fragment in the given bplustree_node.
* The CachedNode will be set to the readable fragment on success. * The CachedNode will be set to the writable fragment on success.
*/ */
status_t status_t
BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode &cached, BPlusTree::FindFreeDuplicateFragment(Transaction &transaction,
const bplustree_node *node, CachedNode &cached,
off_t *_offset, bplustree_node **_fragment, uint32 *_index) off_t *_offset, bplustree_node **_fragment, uint32 *_index)
{ {
off_t *values = node->Values(); off_t *values = node->Values();
@@ -726,8 +741,8 @@ BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode &cached,
if (bplustree_node::LinkType(values[i]) != BPLUSTREE_DUPLICATE_FRAGMENT) if (bplustree_node::LinkType(values[i]) != BPLUSTREE_DUPLICATE_FRAGMENT)
continue; continue;
bplustree_node *fragment = cached.SetTo(bplustree_node::FragmentOffset(values[i]), const bplustree_node *fragment = cached.SetTo(
false); bplustree_node::FragmentOffset(values[i]), false);
if (fragment == NULL) { if (fragment == NULL) {
FATAL(("Could not get duplicate fragment at %Ld\n", values[i])); FATAL(("Could not get duplicate fragment at %Ld\n", values[i]));
continue; continue;
@@ -740,8 +755,11 @@ BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode &cached,
if (array->count == 0) { if (array->count == 0) {
// found an unused fragment // found an unused fragment
*_fragment = cached.MakeWritable(transaction);
if (*_fragment == NULL)
return B_IO_ERROR;
*_offset = bplustree_node::FragmentOffset(values[i]); *_offset = bplustree_node::FragmentOffset(values[i]);
*_fragment = fragment;
*_index = j; *_index = j;
return B_OK; return B_OK;
} }
@@ -753,7 +771,7 @@ BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode &cached,
status_t status_t
BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached, BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
bplustree_node *node, uint16 index, off_t value) const bplustree_node *node, uint16 index, off_t value)
{ {
CachedNode cachedDuplicate(this); CachedNode cachedDuplicate(this);
off_t *values = node->Values(); off_t *values = node->Values();
@@ -819,7 +837,7 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
} }
// update the main pointer to link to a duplicate node // update the main pointer to link to a duplicate node
if (cached.MakeWritable(transaction) != B_OK) if (cached.MakeWritable(transaction) == NULL)
return B_IO_ERROR; return B_IO_ERROR;
values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_NODE, offset); values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_NODE, offset);
@@ -834,7 +852,7 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
// search for free space in the duplicate nodes of that key // search for free space in the duplicate nodes of that key
duplicate_array *array; duplicate_array *array;
bplustree_node *duplicate; const bplustree_node *duplicate;
off_t duplicateOffset; off_t duplicateOffset;
do { do {
duplicateOffset = bplustree_node::FragmentOffset(oldValue); duplicateOffset = bplustree_node::FragmentOffset(oldValue);
@@ -851,10 +869,12 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
} while (array->count >= NUM_DUPLICATE_VALUES } while (array->count >= NUM_DUPLICATE_VALUES
&& (oldValue = duplicate->RightLink()) != BPLUSTREE_NULL); && (oldValue = duplicate->RightLink()) != BPLUSTREE_NULL);
if (array->count < NUM_DUPLICATE_VALUES) { bplustree_node *writableDuplicate = cachedDuplicate.MakeWritable(transaction);
cachedDuplicate.MakeWritable(transaction); if (writableDuplicate == NULL)
array = duplicate->DuplicateArray(); return B_IO_ERROR;
if (array->count < NUM_DUPLICATE_VALUES) {
array = writableDuplicate->DuplicateArray();
array->Insert(value); array->Insert(value);
} else { } else {
// no space left - add a new duplicate node // no space left - add a new duplicate node
@@ -865,7 +885,7 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
return status; return status;
// link the two nodes together // link the two nodes together
duplicate->right_link = HOST_ENDIAN_TO_BFS_INT64(offset); writableDuplicate->right_link = HOST_ENDIAN_TO_BFS_INT64(offset);
newDuplicate->left_link = HOST_ENDIAN_TO_BFS_INT64(duplicateOffset); newDuplicate->left_link = HOST_ENDIAN_TO_BFS_INT64(duplicateOffset);
array = newDuplicate->DuplicateArray(); array = newDuplicate->DuplicateArray();
@@ -882,10 +902,8 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
uint32 fragmentIndex = 0; uint32 fragmentIndex = 0;
bplustree_node *fragment; bplustree_node *fragment;
if (FindFreeDuplicateFragment(node, cachedDuplicate, &offset, &fragment, &fragmentIndex) == B_OK) { if (FindFreeDuplicateFragment(transaction, node, cachedDuplicate,
if (cachedDuplicate.MakeWritable(transaction) != B_OK) &offset, &fragment, &fragmentIndex) != B_OK) {
return B_IO_ERROR;
} else {
// 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 status; return status;
@@ -897,7 +915,7 @@ BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached,
array->Insert(oldValue); array->Insert(oldValue);
array->Insert(value); array->Insert(value);
if (cached.MakeWritable(transaction) != B_OK) if (cached.MakeWritable(transaction) == NULL)
return B_IO_ERROR; return B_IO_ERROR;
values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_FRAGMENT, offset, fragmentIndex); values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_FRAGMENT, offset, fragmentIndex);
@@ -947,6 +965,11 @@ BPlusTree::InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyL
} }
/** Splits the \a node into two halves - the other half will be put into \a other.
* It also takes care to create a new overflow link if the node to split is an
* index node.
*/
status_t status_t
BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *other, BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *other,
off_t otherOffset, uint16 *_keyIndex, uint8 *key, uint16 *_keyLength, off_t *_value) off_t otherOffset, uint16 *_keyIndex, uint8 *key, uint16 *_keyLength, off_t *_value)
@@ -1178,6 +1201,10 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
{ {
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH) if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH)
RETURN_ERROR(B_BAD_VALUE); RETURN_ERROR(B_BAD_VALUE);
#ifdef DEBUG
if (value < 0)
panic("tried to insert invalid value %Ld!\n", value);
#endif
// lock access to stream // lock access to stream
WriteLocked locked(fStream->Lock()); WriteLocked locked(fStream->Lock());
@@ -1192,7 +1219,7 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
keyBuffer[keyLength] = 0; keyBuffer[keyLength] = 0;
node_and_key nodeAndKey; node_and_key nodeAndKey;
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) {
@@ -1212,14 +1239,15 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
} }
} }
if (cached.MakeWritable(transaction) != B_OK) bplustree_node *writableNode = cached.MakeWritable(transaction);
if (writableNode == NULL)
return B_IO_ERROR; 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) + node->AllKeyLength() + keyLength) if (int32(round_up(sizeof(bplustree_node) + writableNode->AllKeyLength() + keyLength)
+ (node->NumKeys() + 1) * (sizeof(uint16) + sizeof(off_t))) < fNodeSize) + (writableNode->NumKeys() + 1) * (sizeof(uint16) + sizeof(off_t))) < fNodeSize)
{ {
InsertKey(node, nodeAndKey.keyIndex, keyBuffer, keyLength, value); InsertKey(writableNode, nodeAndKey.keyIndex, keyBuffer, keyLength, value);
UpdateIterators(nodeAndKey.nodeOffset, BPLUSTREE_NULL, nodeAndKey.keyIndex, 0, 1); UpdateIterators(nodeAndKey.nodeOffset, BPLUSTREE_NULL, nodeAndKey.keyIndex, 0, 1);
return B_OK; return B_OK;
@@ -1253,7 +1281,7 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
RETURN_ERROR(status); RETURN_ERROR(status);
} }
if (SplitNode(node, nodeAndKey.nodeOffset, other, otherOffset, if (SplitNode(writableNode, nodeAndKey.nodeOffset, other, otherOffset,
&nodeAndKey.keyIndex, keyBuffer, &keyLength, &value) < B_OK) { &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);
@@ -1267,7 +1295,7 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
#endif #endif
UpdateIterators(nodeAndKey.nodeOffset, otherOffset, nodeAndKey.keyIndex, UpdateIterators(nodeAndKey.nodeOffset, otherOffset, nodeAndKey.keyIndex,
node->NumKeys(), 1); writableNode->NumKeys(), 1);
// update the right link of the node in the left of the new node // 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) {
@@ -1278,10 +1306,10 @@ 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, node->LeftLink()); InsertKey(root, 0, keyBuffer, keyLength, writableNode->LeftLink());
root->overflow_link = HOST_ENDIAN_TO_BFS_INT64(nodeAndKey.nodeOffset); root->overflow_link = HOST_ENDIAN_TO_BFS_INT64(nodeAndKey.nodeOffset);
bplustree_header *header = fCachedHeader.SetToWritableHeader(transaction); bplustree_header *header = fCachedHeader.MakeWritableHeader(transaction);
if (header == NULL) if (header == NULL)
return B_IO_ERROR; return B_IO_ERROR;
@@ -1302,7 +1330,7 @@ BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength,
*/ */
status_t status_t
BPlusTree::RemoveDuplicate(Transaction &transaction, bplustree_node *node, BPlusTree::RemoveDuplicate(Transaction &transaction, const bplustree_node *node,
CachedNode &cached, uint16 index, off_t value) CachedNode &cached, uint16 index, off_t value)
{ {
off_t *values = node->Values(); off_t *values = node->Values();
@@ -1334,7 +1362,7 @@ BPlusTree::RemoveDuplicate(Transaction &transaction, bplustree_node *node,
// remove the array from the fragment node if it is empty // remove the array from the fragment node if it is empty
if (array->count == 1) { if (array->count == 1) {
// set the link to the remaining value // set the link to the remaining value
if (cached.MakeWritable(transaction) != B_OK) if (cached.MakeWritable(transaction) == NULL)
return B_IO_ERROR; return B_IO_ERROR;
values[index] = array->values[0]; values[index] = array->values[0];
@@ -1399,7 +1427,7 @@ BPlusTree::RemoveDuplicate(Transaction &transaction, bplustree_node *node,
if (left == BPLUSTREE_NULL) { if (left == BPLUSTREE_NULL) {
// the duplicate link points to us // the duplicate link points to us
if (cached.MakeWritable(transaction) != B_OK) if (cached.MakeWritable(transaction) == NULL)
return B_IO_ERROR; return B_IO_ERROR;
if (array->count == 1) { if (array->count == 1) {
@@ -1453,11 +1481,9 @@ BPlusTree::RemoveDuplicate(Transaction &transaction, 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(node, cachedOther, &offset, &fragment, &fragmentIndex) == B_OK) { if (FindFreeDuplicateFragment(transaction, node, cachedOther,
&offset, &fragment, &fragmentIndex) == B_OK) {
// move to other node // move to other node
if (cachedOther.MakeWritable(transaction) != B_OK)
return B_IO_ERROR;
duplicate_array *target = fragment->FragmentAt(fragmentIndex); duplicate_array *target = fragment->FragmentAt(fragmentIndex);
memcpy(target, array, (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t)); memcpy(target, array, (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
@@ -1470,7 +1496,7 @@ BPlusTree::RemoveDuplicate(Transaction &transaction, bplustree_node *node,
fNodeSize - (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t)); fNodeSize - (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
} }
if (cached.MakeWritable(transaction) != B_OK) if (cached.MakeWritable(transaction) == NULL)
return B_IO_ERROR; return B_IO_ERROR;
values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_FRAGMENT, values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_FRAGMENT,
@@ -1559,7 +1585,7 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
RETURN_ERROR(B_ERROR); RETURN_ERROR(B_ERROR);
node_and_key nodeAndKey; node_and_key nodeAndKey;
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) {
@@ -1591,7 +1617,8 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
} }
} }
if (cached.MakeWritable(transaction) != B_OK) bplustree_node *writableNode = cached.MakeWritable(transaction);
if (writableNode == NULL)
return B_IO_ERROR; return B_IO_ERROR;
// if it's an empty root node, we have to convert it // if it's an empty root node, we have to convert it
@@ -1600,17 +1627,18 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
if (nodeAndKey.nodeOffset == fHeader->RootNode() if (nodeAndKey.nodeOffset == fHeader->RootNode()
&& node->NumKeys() == 0 && node->NumKeys() == 0
|| node->NumKeys() == 1 && node->IsLeaf()) { || node->NumKeys() == 1 && node->IsLeaf()) {
node->overflow_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL); writableNode->overflow_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
node->all_key_count = 0; writableNode->all_key_count = 0;
node->all_key_length = 0; writableNode->all_key_length = 0;
// if we've cleared the root node, reset the maximum // if we've cleared the root node, reset the maximum
// number of levels in the header // number of levels in the header
if (nodeAndKey.nodeOffset == fHeader->RootNode()) { if (nodeAndKey.nodeOffset == fHeader->RootNode()) {
if (fCachedHeader.MakeWritable(transaction) != B_OK) bplustree_header *header = fCachedHeader.MakeWritableHeader(transaction);
if (header == NULL)
return B_IO_ERROR; return B_IO_ERROR;
fHeader->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1); header->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1);
} }
return B_OK; return B_OK;
} }
@@ -1618,9 +1646,9 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
// if there is only one key left, we don't have to remove // if there is only one key left, we don't have to remove
// it, we can just dump the node (index nodes still have // it, we can just dump the node (index nodes still have
// the overflow link, so we have to drop the last key) // the overflow link, so we have to drop the last key)
if (node->NumKeys() > 1 if (writableNode->NumKeys() > 1
|| !node->IsLeaf() && node->NumKeys() == 1) { || !writableNode->IsLeaf() && writableNode->NumKeys() == 1) {
RemoveKey(node, nodeAndKey.keyIndex); RemoveKey(writableNode, nodeAndKey.keyIndex);
return B_OK; return B_OK;
} }
@@ -1628,12 +1656,13 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
// we have to update the right/left link of the // we have to update the right/left link of the
// siblings first // siblings first
CachedNode otherCached(this); CachedNode otherCached(this);
bplustree_node *other = otherCached.SetToWritable(transaction, node->LeftLink()); bplustree_node *other = otherCached.SetToWritable(transaction,
writableNode->LeftLink());
if (other != NULL) if (other != NULL)
other->right_link = node->right_link; other->right_link = writableNode->right_link;
if ((other = otherCached.SetToWritable(transaction, node->RightLink())) != NULL) if ((other = otherCached.SetToWritable(transaction, node->RightLink())) != NULL)
other->left_link = node->left_link; other->left_link = writableNode->left_link;
cached.Free(transaction, nodeAndKey.nodeOffset); cached.Free(transaction, nodeAndKey.nodeOffset);
} }
@@ -1665,7 +1694,7 @@ BPlusTree::Replace(Transaction &transaction, const uint8 *key, uint16 keyLength,
off_t nodeOffset = fHeader->RootNode(); off_t nodeOffset = fHeader->RootNode();
CachedNode cached(this); CachedNode cached(this);
bplustree_node *node; const bplustree_node *node;
while ((node = cached.SetTo(nodeOffset)) != NULL) { while ((node = cached.SetTo(nodeOffset)) != NULL) {
uint16 keyIndex = 0; uint16 keyIndex = 0;
@@ -1674,9 +1703,11 @@ BPlusTree::Replace(Transaction &transaction, const uint8 *key, uint16 keyLength,
if (node->OverflowLink() == BPLUSTREE_NULL) { if (node->OverflowLink() == BPLUSTREE_NULL) {
if (status == B_OK) { if (status == B_OK) {
status = cached.MakeWritable(transaction); bplustree_node *writableNode = cached.MakeWritable(transaction);
if (status == B_OK) if (writableNode != NULL)
node->Values()[keyIndex] = value; writableNode->Values()[keyIndex] = value;
else
status = B_IO_ERROR;
} }
return status; return status;
@@ -1716,7 +1747,7 @@ BPlusTree::Find(const uint8 *key, uint16 keyLength, off_t *_value)
off_t nodeOffset = fHeader->RootNode(); off_t nodeOffset = fHeader->RootNode();
CachedNode cached(this); CachedNode cached(this);
bplustree_node *node; const bplustree_node *node;
#ifdef DEBUG #ifdef DEBUG
int32 levels = 0; int32 levels = 0;
@@ -1780,7 +1811,7 @@ TreeIterator::Goto(int8 to)
off_t nodeOffset = fTree->fHeader->RootNode(); off_t nodeOffset = fTree->fHeader->RootNode();
CachedNode cached(fTree); CachedNode cached(fTree);
bplustree_node *node; const bplustree_node *node;
while ((node = cached.SetTo(nodeOffset)) != NULL) { while ((node = cached.SetTo(nodeOffset)) != NULL) {
// is the node a leaf node? // is the node a leaf node?
@@ -1845,7 +1876,7 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxL
ReadLocked locked(fTree->fStream->Lock()); ReadLocked locked(fTree->fStream->Lock());
CachedNode cached(fTree); CachedNode cached(fTree);
bplustree_node *node; const bplustree_node *node;
if (fDuplicateNode != BPLUSTREE_NULL) { if (fDuplicateNode != BPLUSTREE_NULL) {
// regardless of traverse direction the duplicates are always presented in // regardless of traverse direction the duplicates are always presented in
@@ -1981,7 +2012,7 @@ TreeIterator::Find(const uint8 *key, uint16 keyLength)
off_t nodeOffset = fTree->fHeader->RootNode(); off_t nodeOffset = fTree->fHeader->RootNode();
CachedNode cached(fTree); CachedNode cached(fTree);
bplustree_node *node; const bplustree_node *node;
while ((node = cached.SetTo(nodeOffset)) != NULL) { while ((node = cached.SetTo(nodeOffset)) != NULL) {
uint16 keyIndex = 0; uint16 keyIndex = 0;
off_t nextOffset; off_t nextOffset;
@@ -2121,7 +2152,7 @@ bplustree_node::DuplicateAt(off_t offset, bool isFragment, int8 index) const
*/ */
uint32 uint32
bplustree_node::FragmentsUsed(uint32 nodeSize) bplustree_node::FragmentsUsed(uint32 nodeSize) const
{ {
uint32 used = 0; uint32 used = 0;
for (uint32 i = 0; i < MaxFragments(nodeSize); i++) { for (uint32 i = 0; i < MaxFragments(nodeSize); i++) {
@@ -2135,7 +2166,7 @@ bplustree_node::FragmentsUsed(uint32 nodeSize)
#ifdef DEBUG #ifdef DEBUG
status_t status_t
bplustree_node::CheckIntegrity(uint32 nodeSize) bplustree_node::CheckIntegrity(uint32 nodeSize) const
{ {
if (NumKeys() > nodeSize || AllKeyLength() > nodeSize) if (NumKeys() > nodeSize || AllKeyLength() > nodeSize)
DEBUGGER(("invalid node: key/length count")); DEBUGGER(("invalid node: key/length count"));
+21 -18
View File
@@ -41,8 +41,8 @@ struct bplustree_header {
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); inline bool CheckNode(bplustree_node *node) const;
inline bool IsValidLink(off_t link); inline bool IsValidLink(off_t link) const;
} _PACKED; } _PACKED;
#define BPLUSTREE_MAGIC 0x69f6c2e8 #define BPLUSTREE_MAGIC 0x69f6c2e8
@@ -87,9 +87,9 @@ struct bplustree_node {
void Initialize(); void Initialize();
uint8 CountDuplicates(off_t offset, bool isFragment) const; uint8 CountDuplicates(off_t offset, bool isFragment) const;
off_t DuplicateAt(off_t offset, bool isFragment, int8 index) const; off_t DuplicateAt(off_t offset, bool isFragment, int8 index) const;
uint32 FragmentsUsed(uint32 nodeSize); uint32 FragmentsUsed(uint32 nodeSize) const;
inline duplicate_array *FragmentAt(int8 index); inline duplicate_array *FragmentAt(int8 index) const;
inline duplicate_array *DuplicateArray(); inline duplicate_array *DuplicateArray() const;
static inline uint8 LinkType(off_t link); static inline uint8 LinkType(off_t link);
static inline off_t MakeLink(uint8 type, off_t link, uint32 fragmentIndex = 0); static inline off_t MakeLink(uint8 type, off_t link, uint32 fragmentIndex = 0);
@@ -99,7 +99,7 @@ struct bplustree_node {
static inline uint32 MaxFragments(uint32 nodeSize); static inline uint32 MaxFragments(uint32 nodeSize);
#ifdef DEBUG #ifdef DEBUG
status_t CheckIntegrity(uint32 nodeSize); status_t CheckIntegrity(uint32 nodeSize) const;
#endif #endif
} _PACKED; } _PACKED;
@@ -160,11 +160,13 @@ class CachedNode {
Unset(); Unset();
} }
bplustree_node *SetTo(off_t offset, bool check = true); const bplustree_node *SetTo(off_t offset, bool check = true);
bplustree_node *SetToWritable(Transaction &transaction, off_t offset, bool check = true); bplustree_node *SetToWritable(Transaction &transaction, off_t offset, bool check = true);
bplustree_node *MakeWritable(Transaction &transaction);
const bplustree_header *SetToHeader();
bplustree_header *SetToWritableHeader(Transaction &transaction); bplustree_header *SetToWritableHeader(Transaction &transaction);
bplustree_header *SetToHeader(); bplustree_header *MakeWritableHeader(Transaction &transaction);
status_t MakeWritable(Transaction &transaction);
void UnsetUnchanged(Transaction &transaction); void UnsetUnchanged(Transaction &transaction);
void Unset(); void Unset();
@@ -225,21 +227,22 @@ class BPlusTree {
// no implementation // no implementation
int32 CompareKeys(const void *key1, int keylength1, const void *key2, int keylength2); int32 CompareKeys(const void *key1, int keylength1, const void *key2, int keylength2);
status_t FindKey(bplustree_node *node, const uint8 *key, uint16 keyLength, status_t FindKey(const bplustree_node *node, const uint8 *key, uint16 keyLength,
uint16 *index = NULL, off_t *next = NULL); uint16 *index = NULL, off_t *next = NULL);
status_t SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLength); status_t SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLength);
status_t FindFreeDuplicateFragment(bplustree_node *node, CachedNode &cached, status_t FindFreeDuplicateFragment(Transaction &transaction,
const bplustree_node *node, CachedNode &cached,
off_t *_offset, bplustree_node **_fragment, uint32 *_index); off_t *_offset, bplustree_node **_fragment, uint32 *_index);
status_t InsertDuplicate(Transaction &transaction, CachedNode &cached, status_t InsertDuplicate(Transaction &transaction, CachedNode &cached,
bplustree_node *node, uint16 index, off_t value); const bplustree_node *node, uint16 index, off_t value);
void InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyLength, void InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyLength,
off_t value); off_t value);
status_t SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *other, status_t SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *other,
off_t otherOffset, uint16 *_keyIndex, uint8 *key, uint16 *_keyLength, off_t otherOffset, uint16 *_keyIndex, uint8 *key, uint16 *_keyLength,
off_t *_value); off_t *_value);
status_t RemoveDuplicate(Transaction &transaction, bplustree_node *node, status_t RemoveDuplicate(Transaction &transaction, const bplustree_node *node,
CachedNode &cached, uint16 keyIndex, off_t value); CachedNode &cached, uint16 keyIndex, off_t value);
void RemoveKey(bplustree_node *node, uint16 index); void RemoveKey(bplustree_node *node, uint16 index);
@@ -253,7 +256,7 @@ class BPlusTree {
friend class CachedNode; friend class CachedNode;
Inode *fStream; Inode *fStream;
bplustree_header *fHeader; const bplustree_header *fHeader;
CachedNode fCachedHeader; CachedNode fCachedHeader;
int32 fNodeSize; int32 fNodeSize;
bool fAllowDuplicates; bool fAllowDuplicates;
@@ -402,7 +405,7 @@ TreeIterator::GetPreviousEntry(void *key, uint16 *keyLength, uint16 maxLength,
inline bool inline bool
bplustree_header::CheckNode(bplustree_node *node) bplustree_header::CheckNode(bplustree_node *node) const
{ {
// sanity checks (links, all_key_count) // sanity checks (links, all_key_count)
return IsValidLink(node->LeftLink()) return IsValidLink(node->LeftLink())
@@ -413,7 +416,7 @@ bplustree_header::CheckNode(bplustree_node *node)
inline bool inline bool
bplustree_header::IsValidLink(off_t link) bplustree_header::IsValidLink(off_t link) const
{ {
return link == BPLUSTREE_NULL || (link > 0 && link <= MaximumSize() - NodeSize()); return link == BPLUSTREE_NULL || (link > 0 && link <= MaximumSize() - NodeSize());
} }
@@ -459,14 +462,14 @@ bplustree_node::IsLeaf() const
inline duplicate_array * inline duplicate_array *
bplustree_node::FragmentAt(int8 index) bplustree_node::FragmentAt(int8 index) const
{ {
return (duplicate_array *)((off_t *)this + index * (NUM_FRAGMENT_VALUES + 1)); return (duplicate_array *)((off_t *)this + index * (NUM_FRAGMENT_VALUES + 1));
} }
inline duplicate_array * inline duplicate_array *
bplustree_node::DuplicateArray() bplustree_node::DuplicateArray() const
{ {
return (duplicate_array *)&this->overflow_link; return (duplicate_array *)&this->overflow_link;
} }