diff --git a/src/add-ons/kernel/file_systems/bfs/BPlusTree.cpp b/src/add-ons/kernel/file_systems/bfs/BPlusTree.cpp index 8e6b1de89c..d31274d237 100644 --- a/src/add-ons/kernel/file_systems/bfs/BPlusTree.cpp +++ b/src/add-ons/kernel/file_systems/bfs/BPlusTree.cpp @@ -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) diff --git a/src/add-ons/kernel/file_systems/bfs/BPlusTree.h b/src/add-ons/kernel/file_systems/bfs/BPlusTree.h index ab15b1604e..1300558571 100644 --- a/src/add-ons/kernel/file_systems/bfs/BPlusTree.h +++ b/src/add-ons/kernel/file_systems/bfs/BPlusTree.h @@ -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; diff --git a/src/add-ons/kernel/file_systems/bfs/Jamfile b/src/add-ons/kernel/file_systems/bfs/Jamfile index ec249f1ca8..5389516ee2 100644 --- a/src/add-ons/kernel/file_systems/bfs/Jamfile +++ b/src/add-ons/kernel/file_systems/bfs/Jamfile @@ -39,7 +39,6 @@ KernelAddon bfs : Inode.cpp Journal.cpp Query.cpp - Utility.cpp Volume.cpp kernel_interface.cpp diff --git a/src/add-ons/kernel/file_systems/bfs/Utility.cpp b/src/add-ons/kernel/file_systems/bfs/Utility.cpp deleted file mode 100644 index 95f57dab58..0000000000 --- a/src/add-ons/kernel/file_systems/bfs/Utility.cpp +++ /dev/null @@ -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; -} - diff --git a/src/add-ons/kernel/file_systems/bfs/Utility.h b/src/add-ons/kernel/file_systems/bfs/Utility.h index e1bc780dcd..9a06eed0b5 100644 --- a/src/add-ons/kernel/file_systems/bfs/Utility.h +++ b/src/add-ons/kernel/file_systems/bfs/Utility.h @@ -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 diff --git a/src/tools/bfs_shell/Jamfile b/src/tools/bfs_shell/Jamfile index 1b04be7474..264275edb5 100644 --- a/src/tools/bfs_shell/Jamfile +++ b/src/tools/bfs_shell/Jamfile @@ -54,7 +54,6 @@ local bfsSource = Inode.cpp Journal.cpp Query.cpp - Utility.cpp Volume.cpp kernel_interface.cpp