* BPlusTree no longer caches the header in its own block, instead, it aggregates

a copy of its structure. CachedNode is only used to write to the header, now.
  This should cause the block_cache to no longer have any referenced blocks
  outside of any I/O.
* Coding style cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35473 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2010-02-15 16:39:54 +00:00
parent 87e7b978aa
commit a05e4ed330
2 changed files with 253 additions and 231 deletions
@@ -1,11 +1,12 @@
/* /*
* Copyright 2001-2009, Axel Dörfler, [email protected]. * Copyright 2001-2010, 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.
* *
* 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.
*/ */
//! B+Tree implementation //! B+Tree implementation
@@ -82,6 +83,12 @@ CachedNode::Unset()
return; return;
if (fNode != NULL) { if (fNode != NULL) {
if (fWritable && fOffset == 0) {
// The B+tree header has been updated - we need to update the
// BPlusTrees copy of it, as well.
memcpy(&fTree->fHeader, fNode, sizeof(bplustree_header));
}
block_cache_put(fTree->fStream->GetVolume()->BlockCache(), block_cache_put(fTree->fStream->GetVolume()->BlockCache(),
fBlockNumber); fBlockNumber);
fNode = NULL; fNode = NULL;
@@ -102,14 +109,14 @@ CachedNode::SetTo(off_t offset, bool check)
// You can only ask for nodes at valid positions - you can't // You can only ask for nodes at valid positions - you can't
// even access the b+tree header with this method (use SetToHeader() // even access the b+tree header with this method (use SetToHeader()
// instead) // instead)
if (offset > fTree->fHeader->MaximumSize() - fTree->fNodeSize if (offset > fTree->fHeader.MaximumSize() - fTree->fNodeSize
|| offset <= 0 || offset <= 0
|| (offset % fTree->fNodeSize) != 0) || (offset % fTree->fNodeSize) != 0)
return NULL; return NULL;
if (InternalSetTo(NULL, offset) != NULL && check) { if (InternalSetTo(NULL, offset) != NULL && check) {
// sanity checks (links, all_key_count) // sanity checks (links, all_key_count)
if (!fTree->fHeader->CheckNode(fNode)) { if (!fTree->fHeader.CheckNode(fNode)) {
FATAL(("invalid node [%p] read from offset %" B_PRIdOFF " (block %" FATAL(("invalid node [%p] read from offset %" B_PRIdOFF " (block %"
B_PRIdOFF "), inode at %" B_PRIdINO "\n", fNode, offset, B_PRIdOFF "), inode at %" B_PRIdINO "\n", fNode, offset,
fBlockNumber, fTree->fStream->ID())); fBlockNumber, fTree->fStream->ID()));
@@ -133,14 +140,14 @@ CachedNode::SetToWritable(Transaction& transaction, off_t offset, bool check)
// You can only ask for nodes at valid positions - you can't // You can only ask for nodes at valid positions - you can't
// even access the b+tree header with this method (use SetToHeader() // even access the b+tree header with this method (use SetToHeader()
// instead) // instead)
if (offset > fTree->fHeader->MaximumSize() - fTree->fNodeSize if (offset > fTree->fHeader.MaximumSize() - fTree->fNodeSize
|| offset <= 0 || offset <= 0
|| (offset % fTree->fNodeSize) != 0) || (offset % fTree->fNodeSize) != 0)
return NULL; return NULL;
if (InternalSetTo(&transaction, offset) != NULL && check) { if (InternalSetTo(&transaction, offset) != NULL && check) {
// sanity checks (links, all_key_count) // sanity checks (links, all_key_count)
if (!fTree->fHeader->CheckNode(fNode)) { if (!fTree->fHeader.CheckNode(fNode)) {
FATAL(("invalid node [%p] read from offset %" B_PRIdOFF " (block %" FATAL(("invalid node [%p] read from offset %" B_PRIdOFF " (block %"
B_PRIdOFF "), inode at %" B_PRIdINO "\n", fNode, offset, B_PRIdOFF "), inode at %" B_PRIdINO "\n", fNode, offset,
fBlockNumber, fTree->fStream->ID())); fBlockNumber, fTree->fStream->ID()));
@@ -165,13 +172,6 @@ CachedNode::MakeWritable(Transaction& transaction)
} }
bplustree_header*
CachedNode::MakeWritableHeader(Transaction& transaction)
{
return (bplustree_header*)MakeWritable(transaction);
}
const bplustree_header* const bplustree_header*
CachedNode::SetToHeader() CachedNode::SetToHeader()
{ {
@@ -250,8 +250,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 CachedNode cached(fTree);
= fTree->fCachedHeader.MakeWritableHeader(transaction); bplustree_header* header = cached.SetToWritableHeader(transaction);
if (header == NULL) if (header == NULL)
return B_IO_ERROR; return B_IO_ERROR;
@@ -284,7 +284,7 @@ status_t
CachedNode::Allocate(Transaction& transaction, bplustree_node** _node, CachedNode::Allocate(Transaction& transaction, bplustree_node** _node,
off_t* _offset) off_t* _offset)
{ {
if (fTree == NULL || fTree->fHeader == NULL || fTree->fStream == NULL) if (fTree == NULL || fTree->fStream == NULL)
RETURN_ERROR(B_BAD_VALUE); RETURN_ERROR(B_BAD_VALUE);
Unset(); Unset();
@@ -293,8 +293,9 @@ CachedNode::Allocate(Transaction& transaction, bplustree_node** _node,
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, fTree->fHeader->FreeNode(), false) != NULL) { if (SetToWritable(transaction, fTree->fHeader.FreeNode(), false) != NULL) {
header = fTree->fCachedHeader.MakeWritableHeader(transaction); CachedNode cached(fTree);
header = cached.SetToWritableHeader(transaction);
if (header == NULL) if (header == NULL)
return B_IO_ERROR; return B_IO_ERROR;
@@ -312,7 +313,8 @@ CachedNode::Allocate(Transaction& transaction, bplustree_node** _node,
if ((status = stream->Append(transaction, fTree->fNodeSize)) < B_OK) if ((status = stream->Append(transaction, fTree->fNodeSize)) < B_OK)
return status; return status;
header = fTree->fCachedHeader.MakeWritableHeader(transaction); CachedNode cached(fTree);
header = cached.SetToWritableHeader(transaction);
if (header == NULL) if (header == NULL)
return B_IO_ERROR; return B_IO_ERROR;
@@ -342,9 +344,7 @@ CachedNode::Allocate(Transaction& transaction, bplustree_node** _node,
BPlusTree::BPlusTree(Transaction& transaction, Inode* stream, int32 nodeSize) BPlusTree::BPlusTree(Transaction& transaction, Inode* stream, int32 nodeSize)
: :
fStream(NULL), fStream(NULL)
fHeader(NULL),
fCachedHeader(this)
{ {
mutex_init(&fIteratorLock, "bfs b+tree iterator"); mutex_init(&fIteratorLock, "bfs b+tree iterator");
SetTo(transaction, stream); SetTo(transaction, stream);
@@ -353,9 +353,7 @@ BPlusTree::BPlusTree(Transaction& transaction, Inode* stream, int32 nodeSize)
BPlusTree::BPlusTree(Inode* stream) BPlusTree::BPlusTree(Inode* stream)
: :
fStream(NULL), fStream(NULL)
fHeader(NULL),
fCachedHeader(this)
{ {
mutex_init(&fIteratorLock, "bfs b+tree iterator"); mutex_init(&fIteratorLock, "bfs b+tree iterator");
SetTo(stream); SetTo(stream);
@@ -365,8 +363,6 @@ BPlusTree::BPlusTree(Inode* stream)
BPlusTree::BPlusTree() BPlusTree::BPlusTree()
: :
fStream(NULL), fStream(NULL),
fHeader(NULL),
fCachedHeader(this),
fNodeSize(BPLUSTREE_NODE_SIZE), fNodeSize(BPLUSTREE_NODE_SIZE),
fAllowDuplicates(true), fAllowDuplicates(true),
fStatus(B_NO_INIT) fStatus(B_NO_INIT)
@@ -399,19 +395,19 @@ BPlusTree::SetTo(Transaction& transaction, Inode* stream, int32 nodeSize)
fStream = stream; fStream = stream;
bplustree_header* header = fCachedHeader.SetToWritableHeader(transaction); CachedNode cached(this);
bplustree_header* header = cached.SetToWritableHeader(transaction);
if (header == 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);
header = fCachedHeader.SetToWritableHeader(transaction); header = cached.SetToWritableHeader(transaction);
if (header == NULL) if (header == NULL)
RETURN_ERROR(fStatus = B_ERROR); RETURN_ERROR(fStatus = B_ERROR);
} }
fHeader = header;
fAllowDuplicates = stream->IsIndex() fAllowDuplicates = stream->IsIndex()
|| (stream->Mode() & S_ALLOW_DUPS) != 0; || (stream->Mode() & S_ALLOW_DUPS) != 0;
@@ -427,9 +423,10 @@ BPlusTree::SetTo(Transaction& transaction, Inode* stream, int32 nodeSize)
= HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL); = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(nodeSize * 2); header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(nodeSize * 2);
memcpy(&fHeader, header, sizeof(bplustree_header));
// initialize b+tree root node // initialize b+tree root node
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);
@@ -445,35 +442,37 @@ BPlusTree::SetTo(Inode* stream)
if (stream == NULL) if (stream == NULL)
RETURN_ERROR(fStatus = B_BAD_VALUE); RETURN_ERROR(fStatus = B_BAD_VALUE);
// get on-disk B+Tree header
fCachedHeader.Unset();
fStream = stream; fStream = stream;
fHeader = fCachedHeader.SetToHeader(); // get on-disk B+Tree header
if (fHeader == NULL)
RETURN_ERROR(fStatus = B_NO_INIT); CachedNode cached(this);
const bplustree_header* header = cached.SetToHeader();
if (header != NULL)
memcpy(&fHeader, header, sizeof(bplustree_header));
else
RETURN_ERROR(fStatus = B_IO_ERROR);
// is header valid? // is header valid?
if (fHeader->MaximumSize() != stream->Size()) { if (fHeader.MaximumSize() != stream->Size()) {
dprintf("B+tree header size %" B_PRIdOFF " doesn't fit file size %" dprintf("B+tree header size %" B_PRIdOFF " doesn't fit file size %"
B_PRIdOFF "!\n", fHeader->MaximumSize(), stream->Size()); B_PRIdOFF "!\n", fHeader.MaximumSize(), stream->Size());
// we can't change the header since we don't have a transaction // we can't change the header since we don't have a transaction
//fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(stream->Size()); //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
|| !fHeader->IsValidLink(fHeader->RootNode()) || !fHeader.IsValidLink(fHeader.RootNode())
|| !fHeader->IsValidLink(fHeader->FreeNode())) { || !fHeader.IsValidLink(fHeader.FreeNode())) {
#ifdef DEBUG #ifdef DEBUG
dump_bplustree_header(fHeader); dump_bplustree_header(&fHeader);
dump_block((const char*)fHeader, 128); dump_block((const char*)&fHeader, 128);
#endif #endif
RETURN_ERROR(fStatus = B_BAD_DATA); RETURN_ERROR(fStatus = B_BAD_DATA);
} }
fNodeSize = fHeader->NodeSize(); fNodeSize = fHeader.NodeSize();
// validity check // validity check
static const uint32 kToMode[] = {S_STR_INDEX, S_INT_INDEX, S_UINT_INDEX, static const uint32 kToMode[] = {S_STR_INDEX, S_INT_INDEX, S_UINT_INDEX,
@@ -483,11 +482,11 @@ BPlusTree::SetTo(Inode* stream)
| S_UINT_INDEX | S_LONG_LONG_INDEX | S_ULONG_LONG_INDEX | S_UINT_INDEX | S_LONG_LONG_INDEX | S_ULONG_LONG_INDEX
| S_FLOAT_INDEX | S_DOUBLE_INDEX); | S_FLOAT_INDEX | S_DOUBLE_INDEX);
if (fHeader->DataType() > BPLUSTREE_DOUBLE_TYPE if (fHeader.DataType() > BPLUSTREE_DOUBLE_TYPE
|| ((stream->Mode() & S_INDEX_DIR) != 0 || ((stream->Mode() & S_INDEX_DIR) != 0
&& kToMode[fHeader->DataType()] != mode) && kToMode[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());
); );
RETURN_ERROR(fStatus = B_BAD_TYPE); RETURN_ERROR(fStatus = B_BAD_TYPE);
@@ -498,7 +497,7 @@ BPlusTree::SetTo(Inode* stream)
fAllowDuplicates = stream->IsIndex() fAllowDuplicates = stream->IsIndex()
|| (stream->Mode() & S_ALLOW_DUPS) != 0; || (stream->Mode() & S_ALLOW_DUPS) != 0;
CachedNode cached(this, fHeader->RootNode()); cached.SetTo(fHeader.RootNode());
RETURN_ERROR(fStatus = cached.Node() ? B_OK : B_BAD_DATA); RETURN_ERROR(fStatus = cached.Node() ? B_OK : B_BAD_DATA);
} }
@@ -601,7 +600,7 @@ BPlusTree::_CompareKeys(const void* key1, int keyLength1, const void* key2,
int keyLength2) int keyLength2)
{ {
type_code type = 0; type_code type = 0;
switch (fHeader->data_type) { switch (fHeader.DataType()) {
case BPLUSTREE_STRING_TYPE: case BPLUSTREE_STRING_TYPE:
type = B_STRING_TYPE; type = B_STRING_TYPE;
break; break;
@@ -697,7 +696,7 @@ BPlusTree::_SeekDown(Stack<node_and_key>& stack, const uint8* key,
{ {
// set the root node to begin with // set the root node to begin with
node_and_key nodeAndKey; node_and_key nodeAndKey;
nodeAndKey.nodeOffset = fHeader->RootNode(); nodeAndKey.nodeOffset = fHeader.RootNode();
CachedNode cached(this); CachedNode cached(this);
const bplustree_node* node; const bplustree_node* node;
@@ -718,7 +717,7 @@ BPlusTree::_SeekDown(Stack<node_and_key>& stack, const uint8* key,
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);
if ((uint32)stack.CountItems() > fHeader->MaxNumberOfLevels()) { if ((uint32)stack.CountItems() > fHeader.MaxNumberOfLevels()) {
dprintf("BPlusTree::_SeekDown() node walked too deep.\n"); dprintf("BPlusTree::_SeekDown() node walked too deep.\n");
break; break;
} }
@@ -1331,7 +1330,7 @@ BPlusTree::Insert(Transaction& transaction, const uint8* key, uint16 keyLength,
// do we need to allocate a new root node? if so, then do // do we need to allocate a new root node? if so, then do
// it now // it now
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, status_t status = cachedNewRoot.Allocate(transaction, &root,
&newRoot); &newRoot);
@@ -1388,8 +1387,9 @@ BPlusTree::Insert(Transaction& transaction, const uint8* key, uint16 keyLength,
root->overflow_link = HOST_ENDIAN_TO_BFS_INT64( root->overflow_link = HOST_ENDIAN_TO_BFS_INT64(
nodeAndKey.nodeOffset); nodeAndKey.nodeOffset);
CachedNode cached(this);
bplustree_header* header bplustree_header* header
= fCachedHeader.MakeWritableHeader(transaction); = cached.SetToWritableHeader(transaction);
if (header == NULL) if (header == NULL)
return B_IO_ERROR; return B_IO_ERROR;
@@ -1734,7 +1734,7 @@ BPlusTree::Remove(Transaction& transaction, const uint8* key, uint16 keyLength,
// if it's an empty root node, we have to convert it // if it's an empty root node, we have to convert it
// to a leaf node by dropping the overflow link, or, // to a leaf node by dropping the overflow link, or,
// if it's already a leaf node, just empty it // if it's already a leaf node, just empty it
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()))) {
writableNode->overflow_link writableNode->overflow_link
@@ -1744,9 +1744,10 @@ BPlusTree::Remove(Transaction& transaction, const uint8* key, uint16 keyLength,
// if we've made a leaf node out of the root node, we need // if we've made a leaf node out of the root node, we need
// to reset the maximum number of levels in the header // to reset the maximum number of levels in the header
if (fHeader->MaxNumberOfLevels() != 1) { if (fHeader.MaxNumberOfLevels() != 1) {
CachedNode cached(this);
bplustree_header* header bplustree_header* header
= fCachedHeader.MakeWritableHeader(transaction); = cached.SetToWritableHeader(transaction);
if (header == NULL) if (header == NULL)
return B_IO_ERROR; return B_IO_ERROR;
@@ -1807,7 +1808,7 @@ BPlusTree::Replace(Transaction& transaction, const uint8* key, uint16 keyLength,
ASSERT_WRITE_LOCKED_INODE(fStream); ASSERT_WRITE_LOCKED_INODE(fStream);
off_t nodeOffset = fHeader->RootNode(); off_t nodeOffset = fHeader.RootNode();
CachedNode cached(this); CachedNode cached(this);
const bplustree_node* node; const bplustree_node* node;
@@ -1861,7 +1862,7 @@ BPlusTree::Find(const uint8* key, uint16 keyLength, off_t* _value)
ASSERT_READ_LOCKED_INODE(fStream); ASSERT_READ_LOCKED_INODE(fStream);
off_t nodeOffset = fHeader->RootNode(); off_t nodeOffset = fHeader.RootNode();
CachedNode cached(this); CachedNode cached(this);
const bplustree_node* node; const bplustree_node* node;
@@ -1883,7 +1884,7 @@ BPlusTree::Find(const uint8* key, uint16 keyLength, off_t* _value)
*_value = BFS_ENDIAN_TO_HOST_INT64(node->Values()[keyIndex]); *_value = BFS_ENDIAN_TO_HOST_INT64(node->Values()[keyIndex]);
#ifdef DEBUG #ifdef DEBUG
if (levels != (int32)fHeader->MaxNumberOfLevels()) if (levels != (int32)fHeader.MaxNumberOfLevels())
DEBUGGER(("levels don't match")); DEBUGGER(("levels don't match"));
#endif #endif
return status; return status;
@@ -1919,13 +1920,13 @@ TreeIterator::~TreeIterator()
status_t status_t
TreeIterator::Goto(int8 to) TreeIterator::Goto(int8 to)
{ {
if (fTree == NULL || fTree->fHeader == NULL) if (fTree == NULL || fTree->fStream == NULL)
RETURN_ERROR(B_BAD_VALUE); RETURN_ERROR(B_BAD_VALUE);
// lock access to stream // lock access to stream
InodeReadLocker locker(fTree->fStream); InodeReadLocker locker(fTree->fStream);
off_t nodeOffset = fTree->fHeader->RootNode(); off_t nodeOffset = fTree->fHeader.RootNode();
CachedNode cached(fTree); CachedNode cached(fTree);
const bplustree_node* node; const bplustree_node* node;
@@ -2079,7 +2080,7 @@ TreeIterator::Traverse(int8 direction, void* key, uint16* keyLength,
length = min_c(length, maxLength); length = min_c(length, maxLength);
memcpy(key, keyStart, length); memcpy(key, keyStart, length);
if (fTree->fHeader->data_type == BPLUSTREE_STRING_TYPE) { if (fTree->fHeader.DataType() == BPLUSTREE_STRING_TYPE) {
// terminate string type // terminate string type
if (length == maxLength) if (length == maxLength)
length--; length--;
@@ -2138,7 +2139,7 @@ TreeIterator::Find(const uint8* key, uint16 keyLength)
// lock access to stream // lock access to stream
InodeReadLocker locker(fTree->fStream); InodeReadLocker locker(fTree->fStream);
off_t nodeOffset = fTree->fHeader->RootNode(); off_t nodeOffset = fTree->fHeader.RootNode();
CachedNode cached(fTree); CachedNode cached(fTree);
const bplustree_node* node; const bplustree_node* node;
+186 -165
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
* 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
@@ -60,45 +60,55 @@ struct sorted_array;
typedef sorted_array duplicate_array; typedef sorted_array duplicate_array;
struct bplustree_node { struct bplustree_node {
int64 left_link; int64 left_link;
int64 right_link; int64 right_link;
int64 overflow_link; int64 overflow_link;
uint16 all_key_count; uint16 all_key_count;
uint16 all_key_length; uint16 all_key_length;
off_t LeftLink() const { return BFS_ENDIAN_TO_HOST_INT64(left_link); } off_t LeftLink() const
off_t RightLink() const { return BFS_ENDIAN_TO_HOST_INT64(right_link); } { return BFS_ENDIAN_TO_HOST_INT64(
off_t OverflowLink() const left_link); }
{ return BFS_ENDIAN_TO_HOST_INT64(overflow_link); } off_t RightLink() const
uint16 NumKeys() const { return BFS_ENDIAN_TO_HOST_INT16(all_key_count); } { return BFS_ENDIAN_TO_HOST_INT64(
uint16 AllKeyLength() const right_link); }
{ return BFS_ENDIAN_TO_HOST_INT16(all_key_length); } off_t OverflowLink() const
{ return BFS_ENDIAN_TO_HOST_INT64(
overflow_link); }
uint16 NumKeys() const
{ return BFS_ENDIAN_TO_HOST_INT16(
all_key_count); }
uint16 AllKeyLength() const
{ return BFS_ENDIAN_TO_HOST_INT16(
all_key_length); }
inline uint16* KeyLengths() const; inline uint16* KeyLengths() const;
inline off_t* Values() const; inline off_t* Values() const;
inline uint8* Keys() const; inline uint8* Keys() const;
inline int32 Used() const; inline int32 Used() const;
uint8* KeyAt(int32 index, uint16* keyLength) const; uint8* KeyAt(int32 index, uint16* keyLength) const;
inline bool IsLeaf() const; inline bool IsLeaf() const;
void Initialize(); void Initialize();
uint8 CountDuplicates(off_t offset, bool isFragment) const; uint8 CountDuplicates(off_t offset,
off_t DuplicateAt(off_t offset, bool isFragment, int8 index) const; bool isFragment) const;
uint32 FragmentsUsed(uint32 nodeSize) const; off_t DuplicateAt(off_t offset, bool isFragment,
inline duplicate_array* FragmentAt(int8 index) const; int8 index) const;
inline duplicate_array* DuplicateArray() const; uint32 FragmentsUsed(uint32 nodeSize) const;
inline duplicate_array* FragmentAt(int8 index) const;
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, static inline off_t MakeLink(uint8 type, off_t link,
uint32 fragmentIndex = 0); uint32 fragmentIndex = 0);
static inline bool IsDuplicate(off_t link); static inline bool IsDuplicate(off_t link);
static inline off_t FragmentOffset(off_t link); static inline off_t FragmentOffset(off_t link);
static inline uint32 FragmentIndex(off_t link); static inline uint32 FragmentIndex(off_t link);
static inline uint32 MaxFragments(uint32 nodeSize); static inline uint32 MaxFragments(uint32 nodeSize);
#ifdef DEBUG #ifdef DEBUG
status_t CheckIntegrity(uint32 nodeSize) const; status_t CheckIntegrity(uint32 nodeSize) const;
#endif #endif
} _PACKED; } _PACKED;
@@ -157,128 +167,137 @@ public:
Unset(); Unset();
} }
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, bplustree_node* SetToWritable(Transaction& transaction,
bool check = true); 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);
bplustree_header* MakeWritableHeader(Transaction& transaction);
void UnsetUnchanged(Transaction& transaction); void UnsetUnchanged(Transaction& transaction);
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, status_t Allocate(Transaction& transaction,
off_t* offset); 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; }
protected: protected:
bplustree_node* InternalSetTo(Transaction* transaction, off_t offset); bplustree_node* InternalSetTo(Transaction* transaction,
off_t offset);
BPlusTree* fTree; BPlusTree* fTree;
bplustree_node* fNode; bplustree_node* fNode;
off_t fOffset; off_t fOffset;
off_t fBlockNumber; off_t fBlockNumber;
bool fWritable; bool fWritable;
}; };
class BPlusTree { class BPlusTree {
public: public:
BPlusTree(Transaction& transaction, Inode* stream, BPlusTree(Transaction& transaction,
int32 nodeSize = BPLUSTREE_NODE_SIZE); Inode* stream,
BPlusTree(Inode* stream); int32 nodeSize = BPLUSTREE_NODE_SIZE);
BPlusTree(); BPlusTree(Inode* stream);
~BPlusTree(); BPlusTree();
~BPlusTree();
status_t SetTo(Transaction& transaction, Inode* stream, status_t SetTo(Transaction& transaction, Inode* stream,
int32 nodeSize = BPLUSTREE_NODE_SIZE); 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, status_t Remove(Transaction& transaction,
uint16 keyLength, off_t value); const uint8* key, uint16 keyLength,
status_t Insert(Transaction& transaction, const uint8* key, 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, status_t Remove(Transaction& transaction, const char* key,
off_t value); off_t value);
status_t Insert(Transaction& transaction, const char* key, status_t Insert(Transaction& transaction, const char* key,
off_t value); off_t value);
status_t Insert(Transaction& transaction, int32 key, status_t Insert(Transaction& transaction, int32 key,
off_t value); off_t value);
status_t Insert(Transaction& transaction, uint32 key, status_t Insert(Transaction& transaction, uint32 key,
off_t value); off_t value);
status_t Insert(Transaction& transaction, int64 key, status_t Insert(Transaction& transaction, int64 key,
off_t value); off_t value);
status_t Insert(Transaction& transaction, uint64 key, status_t Insert(Transaction& transaction, uint64 key,
off_t value); off_t value);
status_t Insert(Transaction& transaction, float key, status_t Insert(Transaction& transaction, float key,
off_t value); off_t value);
status_t Insert(Transaction& transaction, double key, status_t Insert(Transaction& transaction, double key,
off_t value); off_t value);
status_t Replace(Transaction& transaction, const uint8* key, status_t Replace(Transaction& transaction,
uint16 keyLength, off_t value); const uint8* key, uint16 keyLength,
status_t Find(const uint8* key, uint16 keyLength, off_t* value); 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);
static int32 ModeToKeyType(mode_t mode); static int32 ModeToKeyType(mode_t mode);
private: private:
BPlusTree(const BPlusTree& other); BPlusTree(const BPlusTree& other);
BPlusTree& operator=(const BPlusTree& other); BPlusTree& operator=(const BPlusTree& other);
// no implementation // no implementation
int32 _CompareKeys(const void* key1, int keylength1, int32 _CompareKeys(const void* key1, int keylength1,
const void* key2, int keylength2); const void* key2, int keylength2);
status_t _FindKey(const bplustree_node* node, const uint8* key, status_t _FindKey(const bplustree_node* node,
uint16 keyLength, uint16* index = NULL, const uint8* key, uint16 keyLength,
off_t* next = NULL); uint16* index = NULL, off_t* next = NULL);
status_t _SeekDown(Stack<node_and_key>& stack, const uint8* key, status_t _SeekDown(Stack<node_and_key>& stack,
uint16 keyLength); const uint8* key, uint16 keyLength);
status_t _FindFreeDuplicateFragment(Transaction& transaction, status_t _FindFreeDuplicateFragment(
const bplustree_node* node, CachedNode& cached, Transaction& transaction,
off_t* _offset, bplustree_node** _fragment, const bplustree_node* node,
uint32* _index); CachedNode& cached, off_t* _offset,
status_t _InsertDuplicate(Transaction& transaction, bplustree_node** _fragment, uint32* _index);
CachedNode& cached, const bplustree_node* node, status_t _InsertDuplicate(Transaction& transaction,
uint16 index, off_t value); CachedNode& cached,
void _InsertKey(bplustree_node* node, uint16 index, const bplustree_node* node, uint16 index,
uint8* key, uint16 keyLength, off_t value); off_t value);
status_t _SplitNode(bplustree_node* node, off_t nodeOffset, void _InsertKey(bplustree_node* node, uint16 index,
bplustree_node* other, off_t otherOffset, uint8* key, uint16 keyLength, off_t value);
uint16* _keyIndex, uint8* key, uint16* _keyLength, status_t _SplitNode(bplustree_node* node,
off_t* _value); off_t nodeOffset, bplustree_node* other,
off_t otherOffset, uint16* _keyIndex,
uint8* key, uint16* _keyLength,
off_t* _value);
status_t _RemoveDuplicate(Transaction& transaction, status_t _RemoveDuplicate(Transaction& transaction,
const bplustree_node* node, CachedNode& cached, const bplustree_node* node,
uint16 keyIndex, off_t value); CachedNode& cached, uint16 keyIndex,
void _RemoveKey(bplustree_node* node, uint16 index); off_t value);
void _RemoveKey(bplustree_node* node, uint16 index);
void _UpdateIterators(off_t offset, off_t nextOffset, void _UpdateIterators(off_t offset, off_t nextOffset,
uint16 keyIndex, uint16 splitAt, int8 change); uint16 keyIndex, uint16 splitAt,
void _AddIterator(TreeIterator* iterator); int8 change);
void _RemoveIterator(TreeIterator* iterator); void _AddIterator(TreeIterator* iterator);
void _RemoveIterator(TreeIterator* iterator);
private: private:
friend class TreeIterator; friend class TreeIterator;
friend class CachedNode; friend class CachedNode;
Inode* fStream; Inode* fStream;
const bplustree_header* fHeader; bplustree_header fHeader;
CachedNode fCachedHeader; int32 fNodeSize;
int32 fNodeSize; bool fAllowDuplicates;
bool fAllowDuplicates; status_t fStatus;
status_t fStatus; mutex fIteratorLock;
mutex fIteratorLock;
SinglyLinkedList<TreeIterator> fIterators; SinglyLinkedList<TreeIterator> fIterators;
}; };
@@ -290,46 +309,48 @@ extern int32 compareKeys(type_code type, const void* key1, int keyLength1,
class TreeIterator : public SinglyLinkedListLinkImpl<TreeIterator> { class TreeIterator : public SinglyLinkedListLinkImpl<TreeIterator> {
public: public:
TreeIterator(BPlusTree* tree); TreeIterator(BPlusTree* tree);
~TreeIterator(); ~TreeIterator();
status_t Goto(int8 to); status_t Goto(int8 to);
status_t Traverse(int8 direction, void* key, uint16* keyLength, status_t Traverse(int8 direction, void* key,
uint16 maxLength, off_t* value, uint16* keyLength, uint16 maxLength,
uint16* duplicate = NULL); 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, status_t GetNextEntry(void* key, uint16* keyLength,
uint16 maxLength, off_t* value, uint16 maxLength, off_t* value,
uint16* duplicate = NULL); uint16* duplicate = NULL);
status_t GetPreviousEntry(void* key, uint16* keyLength, status_t GetPreviousEntry(void* key, uint16* keyLength,
uint16 maxLength, off_t* value, uint16 maxLength, off_t* value,
uint16* duplicate = NULL); uint16* duplicate = NULL);
void SkipDuplicates(); void SkipDuplicates();
BPlusTree* Tree() const { return fTree; } BPlusTree* Tree() const { return fTree; }
#ifdef DEBUG #ifdef DEBUG
void Dump(); void Dump();
#endif #endif
private: private:
friend class BPlusTree; friend class BPlusTree;
// called by BPlusTree // called by BPlusTree
void Update(off_t offset, off_t nextOffset, uint16 keyIndex, void Update(off_t offset, off_t nextOffset,
uint16 splitAt, int8 change); uint16 keyIndex, uint16 splitAt,
void Stop(); int8 change);
void Stop();
private: private:
BPlusTree* fTree; BPlusTree* fTree;
off_t fCurrentNodeOffset; off_t fCurrentNodeOffset;
// traverse position // traverse position
int32 fCurrentKey; int32 fCurrentKey;
off_t fDuplicateNode; off_t fDuplicateNode;
uint16 fDuplicate, fNumDuplicates; uint16 fDuplicate;
bool fIsFragment; uint16 fNumDuplicates;
bool fIsFragment;
}; };
@@ -340,7 +361,7 @@ private:
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)
{ {
if (fHeader->data_type != BPLUSTREE_STRING_TYPE) if (fHeader.DataType() != BPLUSTREE_STRING_TYPE)
return B_BAD_TYPE; return B_BAD_TYPE;
return Remove(transaction, (uint8*)key, strlen(key), value); return Remove(transaction, (uint8*)key, strlen(key), value);
} }
@@ -348,7 +369,7 @@ BPlusTree::Remove(Transaction& transaction, const char* key, off_t value)
inline status_t inline status_t
BPlusTree::Insert(Transaction& transaction, const char* key, off_t value) BPlusTree::Insert(Transaction& transaction, const char* key, off_t value)
{ {
if (fHeader->data_type != BPLUSTREE_STRING_TYPE) if (fHeader.DataType() != BPLUSTREE_STRING_TYPE)
return B_BAD_TYPE; return B_BAD_TYPE;
return Insert(transaction, (uint8*)key, strlen(key), value); return Insert(transaction, (uint8*)key, strlen(key), value);
} }
@@ -356,7 +377,7 @@ BPlusTree::Insert(Transaction& transaction, const char* key, off_t value)
inline status_t inline status_t
BPlusTree::Insert(Transaction& transaction, int32 key, off_t value) BPlusTree::Insert(Transaction& transaction, int32 key, off_t value)
{ {
if (fHeader->data_type != BPLUSTREE_INT32_TYPE) if (fHeader.DataType() != BPLUSTREE_INT32_TYPE)
return B_BAD_TYPE; return B_BAD_TYPE;
return Insert(transaction, (uint8*)&key, sizeof(key), value); return Insert(transaction, (uint8*)&key, sizeof(key), value);
} }
@@ -364,7 +385,7 @@ BPlusTree::Insert(Transaction& transaction, int32 key, off_t value)
inline status_t inline status_t
BPlusTree::Insert(Transaction& transaction, uint32 key, off_t value) BPlusTree::Insert(Transaction& transaction, uint32 key, off_t value)
{ {
if (fHeader->data_type != BPLUSTREE_UINT32_TYPE) if (fHeader.DataType() != BPLUSTREE_UINT32_TYPE)
return B_BAD_TYPE; return B_BAD_TYPE;
return Insert(transaction, (uint8*)&key, sizeof(key), value); return Insert(transaction, (uint8*)&key, sizeof(key), value);
} }
@@ -372,7 +393,7 @@ BPlusTree::Insert(Transaction& transaction, uint32 key, off_t value)
inline status_t inline status_t
BPlusTree::Insert(Transaction& transaction, int64 key, off_t value) BPlusTree::Insert(Transaction& transaction, int64 key, off_t value)
{ {
if (fHeader->data_type != BPLUSTREE_INT64_TYPE) if (fHeader.DataType() != BPLUSTREE_INT64_TYPE)
return B_BAD_TYPE; return B_BAD_TYPE;
return Insert(transaction, (uint8*)&key, sizeof(key), value); return Insert(transaction, (uint8*)&key, sizeof(key), value);
} }
@@ -380,7 +401,7 @@ BPlusTree::Insert(Transaction& transaction, int64 key, off_t value)
inline status_t inline status_t
BPlusTree::Insert(Transaction& transaction, uint64 key, off_t value) BPlusTree::Insert(Transaction& transaction, uint64 key, off_t value)
{ {
if (fHeader->data_type != BPLUSTREE_UINT64_TYPE) if (fHeader.DataType() != BPLUSTREE_UINT64_TYPE)
return B_BAD_TYPE; return B_BAD_TYPE;
return Insert(transaction, (uint8*)&key, sizeof(key), value); return Insert(transaction, (uint8*)&key, sizeof(key), value);
} }
@@ -388,7 +409,7 @@ BPlusTree::Insert(Transaction& transaction, uint64 key, off_t value)
inline status_t inline status_t
BPlusTree::Insert(Transaction& transaction, float key, off_t value) BPlusTree::Insert(Transaction& transaction, float key, off_t value)
{ {
if (fHeader->data_type != BPLUSTREE_FLOAT_TYPE) if (fHeader.DataType() != BPLUSTREE_FLOAT_TYPE)
return B_BAD_TYPE; return B_BAD_TYPE;
return Insert(transaction, (uint8*)&key, sizeof(key), value); return Insert(transaction, (uint8*)&key, sizeof(key), value);
} }
@@ -396,7 +417,7 @@ BPlusTree::Insert(Transaction& transaction, float key, off_t value)
inline status_t inline status_t
BPlusTree::Insert(Transaction& transaction, double key, off_t value) BPlusTree::Insert(Transaction& transaction, double key, off_t value)
{ {
if (fHeader->data_type != BPLUSTREE_DOUBLE_TYPE) if (fHeader.DataType() != BPLUSTREE_DOUBLE_TYPE)
return B_BAD_TYPE; return B_BAD_TYPE;
return Insert(transaction, (uint8*)&key, sizeof(key), value); return Insert(transaction, (uint8*)&key, sizeof(key), value);
} }