Made the duplicate_array endian safe. Cleanup.

* Renamed the sorted_array to duplicate_array (which was only a typedef
  before), and moved it into the BPlusTree.cpp file, as its specific to
  that one.
* Utilities.cpp is no longer needed.
* Introduced endian safe getters/setters so that little endian BFS volumes
  should now work fine on a big endian architecture.
This commit is contained in:
Axel Dörfler
2012-03-09 21:18:35 +01:00
parent 6307c1ebb1
commit 87d5beae86
6 changed files with 150 additions and 135 deletions
+147 -38
View File
@@ -16,6 +16,47 @@
#include "Utility.h"
/*! Simple array used for the duplicate handling in the B+Tree. This is an
on disk structure.
*/
struct duplicate_array {
off_t count;
off_t values[0];
inline bool IsEmpty() const
{
return count == 0;
}
inline int32 Count() const
{
return (int32)BFS_ENDIAN_TO_HOST_INT64(count);
}
inline off_t ValueAt(uint32 index) const
{
return BFS_ENDIAN_TO_HOST_INT64(values[index]);
}
inline void SetValueAt(uint32 index, off_t value)
{
values[index] = HOST_ENDIAN_TO_BFS_INT64(value);
}
inline int32 Find(off_t value) const
{
int32 i;
return _FindInternal(value, i) ? i : -1;
}
void Insert(off_t value);
bool Remove(off_t value);
private:
bool _FindInternal(off_t value, int32& index) const;
} _PACKED;
#ifdef DEBUG
class NodeChecker {
public:
@@ -991,7 +1032,7 @@ BPlusTree::_FindFreeDuplicateFragment(Transaction& transaction,
for (uint32 j = 0; j < num; j++) {
duplicate_array* array = fragment->FragmentAt(j);
if (array->count == 0) {
if (array->IsEmpty()) {
// found an unused fragment
*_fragment = cached.MakeWritable(transaction);
if (*_fragment == NULL)
@@ -1030,16 +1071,16 @@ BPlusTree::_InsertDuplicate(Transaction& transaction, CachedNode& cached,
duplicate_array* array = duplicate->FragmentAt(
bplustree_node::FragmentIndex(oldValue));
if (array->count > NUM_FRAGMENT_VALUES
|| array->count < 1) {
int32 arrayCount = array->Count();
if (arrayCount > NUM_FRAGMENT_VALUES || arrayCount < 1) {
FATAL(("insertDuplicate: Invalid array[%d] size in fragment "
"%" B_PRIdOFF " == %" B_PRIdOFF "!\n",
"%" B_PRIdOFF " == %" B_PRId32 "!\n",
(int)bplustree_node::FragmentIndex(oldValue),
bplustree_node::FragmentOffset(oldValue), array->count));
bplustree_node::FragmentOffset(oldValue), arrayCount));
return B_BAD_DATA;
}
if (array->count < NUM_FRAGMENT_VALUES) {
if (arrayCount < NUM_FRAGMENT_VALUES) {
array->Insert(value);
} else {
// Test if the fragment will be empty if we remove this key's
@@ -1071,10 +1112,9 @@ BPlusTree::_InsertDuplicate(Transaction& transaction, CachedNode& cached,
// Copy the array from the fragment node to the duplicate
// node and free the old entry (by zero'ing all values)
newDuplicate->overflow_link = HOST_ENDIAN_TO_BFS_INT64(
array->count);
newDuplicate->overflow_link = array->count;
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));
array = newDuplicate->DuplicateArray();
@@ -1097,6 +1137,7 @@ BPlusTree::_InsertDuplicate(Transaction& transaction, CachedNode& cached,
// search for free space in the duplicate nodes of that key
duplicate_array* array;
int32 arrayCount;
const bplustree_node* duplicate;
off_t duplicateOffset;
do {
@@ -1106,13 +1147,14 @@ BPlusTree::_InsertDuplicate(Transaction& transaction, CachedNode& cached,
return B_IO_ERROR;
array = duplicate->DuplicateArray();
if (array->count > NUM_DUPLICATE_VALUES || array->count < 0) {
arrayCount =array->Count();
if (arrayCount > NUM_DUPLICATE_VALUES || arrayCount < 0) {
FATAL(("removeDuplicate: Invalid array size in duplicate %"
B_PRIdOFF " == %" B_PRIdOFF "!\n", duplicateOffset,
array->count));
B_PRIdOFF " == %" B_PRId32 "!\n", duplicateOffset,
arrayCount));
return B_BAD_DATA;
}
} while (array->count >= NUM_DUPLICATE_VALUES
} while (arrayCount >= NUM_DUPLICATE_VALUES
&& (oldValue = duplicate->RightLink()) != BPLUSTREE_NULL);
bplustree_node* writableDuplicate
@@ -1120,7 +1162,7 @@ BPlusTree::_InsertDuplicate(Transaction& transaction, CachedNode& cached,
if (writableDuplicate == NULL)
return B_IO_ERROR;
if (array->count < NUM_DUPLICATE_VALUES) {
if (arrayCount < NUM_DUPLICATE_VALUES) {
array = writableDuplicate->DuplicateArray();
array->Insert(value);
} else {
@@ -1655,13 +1697,13 @@ BPlusTree::_RemoveDuplicate(Transaction& transaction,
if (bplustree_node::LinkType(oldValue) == BPLUSTREE_DUPLICATE_FRAGMENT) {
duplicate_array* array = duplicate->FragmentAt(
bplustree_node::FragmentIndex(oldValue));
int32 arrayCount = array->Count();
if (array->count > NUM_FRAGMENT_VALUES
|| array->count < 1) {
if (arrayCount > NUM_FRAGMENT_VALUES || arrayCount < 1) {
FATAL(("removeDuplicate: Invalid array[%d] size in fragment %"
B_PRIdOFF " == %" B_PRIdOFF "!\n",
B_PRIdOFF " == %" B_PRId32 "!\n",
(int)bplustree_node::FragmentIndex(oldValue), duplicateOffset,
array->count));
arrayCount));
return B_BAD_DATA;
}
if (!array->Remove(value)) {
@@ -1671,7 +1713,7 @@ BPlusTree::_RemoveDuplicate(Transaction& transaction,
}
// remove the array from the fragment node if it is empty
if (array->count == 1) {
if (arrayCount == 1) {
// set the link to the remaining value
if (cached.MakeWritable(transaction) == NULL)
return B_IO_ERROR;
@@ -1694,6 +1736,7 @@ BPlusTree::_RemoveDuplicate(Transaction& transaction,
// Remove value from a duplicate node!
duplicate_array* array = NULL;
int32 arrayCount = 0;
if (duplicate->LeftLink() != BPLUSTREE_NULL) {
FATAL(("invalid duplicate node: first left link points to %" B_PRIdOFF
@@ -1704,11 +1747,11 @@ BPlusTree::_RemoveDuplicate(Transaction& transaction,
// Search the duplicate nodes until the entry could be found (and removed)
while (duplicate != NULL) {
array = duplicate->DuplicateArray();
if (array->count > NUM_DUPLICATE_VALUES
|| array->count < 0) {
arrayCount = array->Count();
if (arrayCount > NUM_DUPLICATE_VALUES || arrayCount < 0) {
FATAL(("removeDuplicate: Invalid array size in duplicate %"
B_PRIdOFF " == %" B_PRIdOFF "!\n", duplicateOffset,
array->count));
B_PRIdOFF " == %" B_PRId32 "!\n", duplicateOffset, arrayCount));
return B_BAD_DATA;
}
@@ -1733,7 +1776,7 @@ BPlusTree::_RemoveDuplicate(Transaction& transaction,
off_t right = duplicate->RightLink();
bool isLast = left == BPLUSTREE_NULL && right == BPLUSTREE_NULL;
if ((isLast && array->count == 1) || array->count == 0) {
if ((isLast && arrayCount == 1) || arrayCount == 0) {
// Free empty duplicate page, link their siblings together, and
// update the duplicate link if needed (ie. when we either remove
// the last duplicate node or have a new first one)
@@ -1743,7 +1786,7 @@ BPlusTree::_RemoveDuplicate(Transaction& transaction,
if (cached.MakeWritable(transaction) == NULL)
return B_IO_ERROR;
if (array->count == 1) {
if (arrayCount == 1) {
// This is the last node, and there is only one value left;
// replace the duplicate link with that value, it's no
// duplicate anymore
@@ -1769,9 +1812,10 @@ BPlusTree::_RemoveDuplicate(Transaction& transaction,
// If the next node is the last node, we need to free that node
// and convert the duplicate entry back into a normal entry
array = duplicate->DuplicateArray();
arrayCount = array->Count();
if (right == BPLUSTREE_NULL
&& duplicate->LeftLink() == BPLUSTREE_NULL
&& array->count <= NUM_FRAGMENT_VALUES) {
&& arrayCount <= NUM_FRAGMENT_VALUES) {
duplicateOffset = left;
continue;
}
@@ -1784,15 +1828,16 @@ BPlusTree::_RemoveDuplicate(Transaction& transaction,
// Again, we may need to turn the duplicate entry back into a
// normal entry
array = duplicate->DuplicateArray();
arrayCount = array->Count();
if (left == BPLUSTREE_NULL
&& duplicate->RightLink() == BPLUSTREE_NULL
&& array->count <= NUM_FRAGMENT_VALUES) {
&& arrayCount <= NUM_FRAGMENT_VALUES) {
duplicateOffset = right;
continue;
}
}
return B_OK;
} else if (isLast && array->count <= NUM_FRAGMENT_VALUES) {
} else if (isLast && arrayCount <= NUM_FRAGMENT_VALUES) {
// If the number of entries fits in a duplicate fragment, then
// either find a free fragment node, or convert this node to a
// fragment node.
@@ -2173,7 +2218,7 @@ BPlusTree::_ValidateChildren(TreeCheck& check, uint32 level, off_t offset,
}
}
off_t childOffset = values[i];
off_t childOffset = BFS_ENDIAN_TO_HOST_INT64(values[i]);
if (bplustree_node::IsDuplicate(childOffset)) {
// Walk the duplicate nodes
off_t duplicateOffset = bplustree_node::FragmentOffset(childOffset);
@@ -2206,7 +2251,7 @@ BPlusTree::_ValidateChildren(TreeCheck& check, uint32 level, off_t offset,
check.SetVisitedFragment(duplicateOffset);
duplicate_array* array;
uint32 maxSize;
int32 maxSize;
if (isFragmentNode) {
array = node->FragmentAt(
bplustree_node::FragmentIndex(childOffset));
@@ -2215,21 +2260,22 @@ BPlusTree::_ValidateChildren(TreeCheck& check, uint32 level, off_t offset,
array = node->DuplicateArray();
maxSize = NUM_DUPLICATE_VALUES;
}
int32 arrayCount = array->Count();
if (array->count == 0 || array->count > maxSize) {
if (arrayCount < 1 || arrayCount > maxSize) {
dprintf("inode %" B_PRIdOFF ": duplicate at %" B_PRIdOFF
" has invalid array size %" B_PRIdOFF "!\n",
fStream->BlockNumber(), duplicateOffset, array->count);
" has invalid array size %" B_PRId32 "!\n",
fStream->BlockNumber(), duplicateOffset, arrayCount);
check.FoundError();
} else {
// Simple check if the values in the array may be valid
for (int32 j = 0; j < array->count; j++) {
for (int32 j = 0; j < arrayCount; j++) {
if (!fStream->GetVolume()->IsValidInodeBlock(
array->values[j])) {
array->ValueAt(j))) {
dprintf("inode %" B_PRIdOFF ": duplicate at %"
B_PRIdOFF " contains invalid block %" B_PRIdOFF
" at %" B_PRId32 "!\n", fStream->BlockNumber(),
duplicateOffset, array->values[j], j);
duplicateOffset, array->ValueAt(j), j);
check.FoundError();
break;
}
@@ -2255,7 +2301,7 @@ BPlusTree::_ValidateChildren(TreeCheck& check, uint32 level, off_t offset,
// Test a regular child node recursively
off_t nextOffset = parent->OverflowLink();
if (i < count - 1)
nextOffset = values[i + 1];
nextOffset = BFS_ENDIAN_TO_HOST_INT64(values[i + 1]);
if (i == 0 && lastOffset != BPLUSTREE_NULL) {
// Test right link of the previous node
@@ -2736,7 +2782,7 @@ bplustree_node::FragmentsUsed(uint32 nodeSize) const
uint32 used = 0;
for (uint32 i = 0; i < MaxFragments(nodeSize); i++) {
duplicate_array* array = FragmentAt(i);
if (array->count > 0 && ++used > 1)
if (array->Count() > 0 && ++used > 1)
return used;
}
return used;
@@ -2823,6 +2869,69 @@ BitmapArray::Set(size_t index, bool set)
// #pragma mark -
bool
duplicate_array::_FindInternal(off_t value, int32& index) const
{
int32 min = 0, max = Count() - 1;
off_t cmp;
while (min <= max) {
index = (min + max) / 2;
cmp = ValueAt(index) - value;
if (cmp < 0)
min = index + 1;
else if (cmp > 0)
max = index - 1;
else
return true;
}
return false;
}
void
duplicate_array::Insert(off_t value)
{
// if there are more than 8 values in this array, use a
// binary search, if not, just iterate linearly to find
// the insertion point
int32 size = Count();
int32 i;
if (size > 8 ) {
if (!_FindInternal(value, i) && ValueAt(i) <= value)
i++;
} else {
for (i = 0; i < size; i++) {
if (ValueAt(i) > value)
break;
}
}
memmove(&values[i + 1], &values[i], (size - i) * sizeof(off_t));
values[i] = HOST_ENDIAN_TO_BFS_INT64(value);
count = HOST_ENDIAN_TO_BFS_INT64(size + 1);
}
bool
duplicate_array::Remove(off_t value)
{
int32 index = Find(value);
if (index == -1)
return false;
int32 newSize = Count() - 1;
memmove(&values[index], &values[index + 1],
(newSize - index) * sizeof(off_t));
count = HOST_ENDIAN_TO_BFS_INT64(newSize);
return true;
}
// #pragma mark -
int32
compareKeys(type_code type, const void* key1, int keyLength1,
const void* key2, int keyLength2)
@@ -57,8 +57,9 @@ enum bplustree_types {
BPLUSTREE_DOUBLE_TYPE = 6
};
struct sorted_array;
typedef sorted_array duplicate_array;
struct duplicate_array;
struct bplustree_node {
int64 left_link;
@@ -39,7 +39,6 @@ KernelAddon bfs :
Inode.cpp
Journal.cpp
Query.cpp
Utility.cpp
Volume.cpp
kernel_interface.cpp
@@ -1,69 +0,0 @@
/*
* Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
//! Some helper classes
#include "Utility.h"
#include "Debug.h"
bool
sorted_array::_FindInternal(off_t value, int32& index) const
{
int32 min = 0, max = count - 1;
off_t cmp;
while (min <= max) {
index = (min + max) / 2;
cmp = values[index] - value;
if (cmp < 0)
min = index + 1;
else if (cmp > 0)
max = index - 1;
else
return true;
}
return false;
}
void
sorted_array::Insert(off_t value)
{
// if there are more than 8 values in this array, use a
// binary search, if not, just iterate linearly to find
// the insertion point
int32 i;
if (count > 8 ) {
if (!_FindInternal(value, i) && values[i] <= value)
i++;
} else {
for (i = 0; i < count; i++) {
if (values[i] > value)
break;
}
}
memmove(&values[i + 1], &values[i], (count - i) * sizeof(off_t));
values[i] = value;
count++;
}
bool
sorted_array::Remove(off_t value)
{
int32 index = Find(value);
if (index == -1)
return false;
count--;
memmove(&values[index], &values[index + 1],
(count - index) * sizeof(off_t));
return true;
}
@@ -24,30 +24,6 @@ enum inode_type {
};
// Simple array, used for the duplicate handling in the B+Tree
// TODO: this is not endian safe!!!
struct sorted_array {
off_t count;
off_t values[0];
inline int32 Find(off_t value) const;
void Insert(off_t value);
bool Remove(off_t value);
private:
bool _FindInternal(off_t value, int32& index) const;
};
inline int32
sorted_array::Find(off_t value) const
{
int32 i;
return _FindInternal(value, i) ? i : -1;
}
/*! \a to must be a power of 2.
*/
template<typename IntType, typename RoundType>
-1
View File
@@ -54,7 +54,6 @@ local bfsSource =
Inode.cpp
Journal.cpp
Query.cpp
Utility.cpp
Volume.cpp
kernel_interface.cpp