* Fixed two bugs in BPlusTree::Remove(): it could update the tree iterators

incorrectly in case of duplicates. And also, more importantly, it did not
  check if the entry to remove had the same value -- it would happily remove
  any entry with the same attribute content. This could only happen in the
  reindex case, though, and was the cause of bug #3854.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30616 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2009-05-03 20:29:50 +00:00
parent 719e2a8fe5
commit aee4b7e237

View File

@ -1,5 +1,5 @@
/*
* Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*
* Roughly based on 'btlib' written by Marcus J. Ranum - it shares
@ -899,7 +899,7 @@ BPlusTree::_InsertDuplicate(Transaction& transaction, CachedNode& cached,
bplustree_node* newDuplicate;
status = cachedDuplicate.Allocate(transaction, &newDuplicate,
&offset);
if (status < B_OK)
if (status != B_OK)
RETURN_ERROR(status);
// link the two nodes together
@ -921,8 +921,8 @@ BPlusTree::_InsertDuplicate(Transaction& transaction, CachedNode& cached,
if (_FindFreeDuplicateFragment(transaction, node, cachedDuplicate,
&offset, &fragment, &fragmentIndex) != B_OK) {
// allocate a new duplicate fragment node
if ((status = cachedDuplicate.Allocate(transaction, &fragment,
&offset)) < B_OK)
status = cachedDuplicate.Allocate(transaction, &fragment, &offset);
if (status != B_OK)
RETURN_ERROR(status);
memset(fragment, 0, fNodeSize);
@ -1692,19 +1692,10 @@ BPlusTree::Remove(Transaction& transaction, const uint8* key, uint16 keyLength,
// first round, check for duplicate entries
status_t status = _FindKey(node, key, keyLength,
&nodeAndKey.keyIndex);
if (status < B_OK)
if (status != B_OK)
RETURN_ERROR(status);
// If we will remove the last key, the iterator will be set
// to the next node after the current - if there aren't any
// more nodes, we need a way to prevent the TreeIterators to
// touch the old node again, we use BPLUSTREE_FREE for this
off_t next = node->RightLink() == BPLUSTREE_NULL
? BPLUSTREE_FREE : node->RightLink();
_UpdateIterators(nodeAndKey.nodeOffset, node->NumKeys() == 1
? next : BPLUSTREE_NULL, nodeAndKey.keyIndex, 0 , -1);
// is this a duplicate entry?
// Is this a duplicate entry?
if (bplustree_node::IsDuplicate(BFS_ENDIAN_TO_HOST_INT64(
node->Values()[nodeAndKey.keyIndex]))) {
if (fAllowDuplicates) {
@ -1715,6 +1706,18 @@ BPlusTree::Remove(Transaction& transaction, const uint8* key, uint16 keyLength,
FATAL(("dupliate node found where no duplicates are "
"allowed!\n"));
RETURN_ERROR(B_ERROR);
} else {
if (node->Values()[nodeAndKey.keyIndex] != value)
return B_ENTRY_NOT_FOUND;
// If we will remove the last key, the iterator will be set
// to the next node after the current - if there aren't any
// more nodes, we need a way to prevent the TreeIterators to
// touch the old node again, we use BPLUSTREE_FREE for this
off_t next = node->RightLink() == BPLUSTREE_NULL
? BPLUSTREE_FREE : node->RightLink();
_UpdateIterators(nodeAndKey.nodeOffset, node->NumKeys() == 1
? next : BPLUSTREE_NULL, nodeAndKey.keyIndex, 0 , -1);
}
}