* 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:
@@ -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.
|
||||
*
|
||||
* Roughly based on 'btlib' written by Marcus J. Ranum - it shares
|
||||
* no code but achieves binary compatibility with the on disk format.
|
||||
*/
|
||||
|
||||
|
||||
//! B+Tree implementation
|
||||
|
||||
|
||||
@@ -82,6 +83,12 @@ CachedNode::Unset()
|
||||
return;
|
||||
|
||||
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(),
|
||||
fBlockNumber);
|
||||
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
|
||||
// even access the b+tree header with this method (use SetToHeader()
|
||||
// instead)
|
||||
if (offset > fTree->fHeader->MaximumSize() - fTree->fNodeSize
|
||||
if (offset > fTree->fHeader.MaximumSize() - fTree->fNodeSize
|
||||
|| offset <= 0
|
||||
|| (offset % fTree->fNodeSize) != 0)
|
||||
return NULL;
|
||||
|
||||
if (InternalSetTo(NULL, offset) != NULL && check) {
|
||||
// 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 %"
|
||||
B_PRIdOFF "), inode at %" B_PRIdINO "\n", fNode, offset,
|
||||
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
|
||||
// even access the b+tree header with this method (use SetToHeader()
|
||||
// instead)
|
||||
if (offset > fTree->fHeader->MaximumSize() - fTree->fNodeSize
|
||||
if (offset > fTree->fHeader.MaximumSize() - fTree->fNodeSize
|
||||
|| offset <= 0
|
||||
|| (offset % fTree->fNodeSize) != 0)
|
||||
return NULL;
|
||||
|
||||
if (InternalSetTo(&transaction, offset) != NULL && check) {
|
||||
// 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 %"
|
||||
B_PRIdOFF "), inode at %" B_PRIdINO "\n", fNode, offset,
|
||||
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*
|
||||
CachedNode::SetToHeader()
|
||||
{
|
||||
@@ -250,8 +250,8 @@ CachedNode::Free(Transaction& transaction, off_t offset)
|
||||
// function is called, perhaps it should be done when the directory
|
||||
// inode is closed or based on some calculation or whatever...
|
||||
|
||||
bplustree_header* header
|
||||
= fTree->fCachedHeader.MakeWritableHeader(transaction);
|
||||
CachedNode cached(fTree);
|
||||
bplustree_header* header = cached.SetToWritableHeader(transaction);
|
||||
if (header == NULL)
|
||||
return B_IO_ERROR;
|
||||
|
||||
@@ -284,7 +284,7 @@ status_t
|
||||
CachedNode::Allocate(Transaction& transaction, bplustree_node** _node,
|
||||
off_t* _offset)
|
||||
{
|
||||
if (fTree == NULL || fTree->fHeader == NULL || fTree->fStream == NULL)
|
||||
if (fTree == NULL || fTree->fStream == NULL)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
Unset();
|
||||
@@ -293,8 +293,9 @@ CachedNode::Allocate(Transaction& transaction, bplustree_node** _node,
|
||||
status_t status;
|
||||
|
||||
// if there are any free nodes, recycle them
|
||||
if (SetToWritable(transaction, fTree->fHeader->FreeNode(), false) != NULL) {
|
||||
header = fTree->fCachedHeader.MakeWritableHeader(transaction);
|
||||
if (SetToWritable(transaction, fTree->fHeader.FreeNode(), false) != NULL) {
|
||||
CachedNode cached(fTree);
|
||||
header = cached.SetToWritableHeader(transaction);
|
||||
if (header == NULL)
|
||||
return B_IO_ERROR;
|
||||
|
||||
@@ -312,7 +313,8 @@ CachedNode::Allocate(Transaction& transaction, bplustree_node** _node,
|
||||
if ((status = stream->Append(transaction, fTree->fNodeSize)) < B_OK)
|
||||
return status;
|
||||
|
||||
header = fTree->fCachedHeader.MakeWritableHeader(transaction);
|
||||
CachedNode cached(fTree);
|
||||
header = cached.SetToWritableHeader(transaction);
|
||||
if (header == NULL)
|
||||
return B_IO_ERROR;
|
||||
|
||||
@@ -342,9 +344,7 @@ CachedNode::Allocate(Transaction& transaction, bplustree_node** _node,
|
||||
|
||||
BPlusTree::BPlusTree(Transaction& transaction, Inode* stream, int32 nodeSize)
|
||||
:
|
||||
fStream(NULL),
|
||||
fHeader(NULL),
|
||||
fCachedHeader(this)
|
||||
fStream(NULL)
|
||||
{
|
||||
mutex_init(&fIteratorLock, "bfs b+tree iterator");
|
||||
SetTo(transaction, stream);
|
||||
@@ -353,9 +353,7 @@ BPlusTree::BPlusTree(Transaction& transaction, Inode* stream, int32 nodeSize)
|
||||
|
||||
BPlusTree::BPlusTree(Inode* stream)
|
||||
:
|
||||
fStream(NULL),
|
||||
fHeader(NULL),
|
||||
fCachedHeader(this)
|
||||
fStream(NULL)
|
||||
{
|
||||
mutex_init(&fIteratorLock, "bfs b+tree iterator");
|
||||
SetTo(stream);
|
||||
@@ -365,8 +363,6 @@ BPlusTree::BPlusTree(Inode* stream)
|
||||
BPlusTree::BPlusTree()
|
||||
:
|
||||
fStream(NULL),
|
||||
fHeader(NULL),
|
||||
fCachedHeader(this),
|
||||
fNodeSize(BPLUSTREE_NODE_SIZE),
|
||||
fAllowDuplicates(true),
|
||||
fStatus(B_NO_INIT)
|
||||
@@ -399,19 +395,19 @@ BPlusTree::SetTo(Transaction& transaction, Inode* stream, int32 nodeSize)
|
||||
|
||||
fStream = stream;
|
||||
|
||||
bplustree_header* header = fCachedHeader.SetToWritableHeader(transaction);
|
||||
CachedNode cached(this);
|
||||
bplustree_header* header = cached.SetToWritableHeader(transaction);
|
||||
if (header == NULL) {
|
||||
// allocate space for new header + node!
|
||||
fStatus = stream->SetFileSize(transaction, nodeSize * 2);
|
||||
if (fStatus < B_OK)
|
||||
RETURN_ERROR(fStatus);
|
||||
|
||||
header = fCachedHeader.SetToWritableHeader(transaction);
|
||||
header = cached.SetToWritableHeader(transaction);
|
||||
if (header == NULL)
|
||||
RETURN_ERROR(fStatus = B_ERROR);
|
||||
}
|
||||
|
||||
fHeader = header;
|
||||
fAllowDuplicates = stream->IsIndex()
|
||||
|| (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);
|
||||
header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(nodeSize * 2);
|
||||
|
||||
memcpy(&fHeader, header, sizeof(bplustree_header));
|
||||
|
||||
// initialize b+tree root node
|
||||
CachedNode cached(this);
|
||||
cached.SetToWritable(transaction, header->RootNode(), false);
|
||||
cached.SetToWritable(transaction, fHeader.RootNode(), false);
|
||||
if (cached.Node() == NULL)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
|
||||
@@ -445,35 +442,37 @@ BPlusTree::SetTo(Inode* stream)
|
||||
if (stream == NULL)
|
||||
RETURN_ERROR(fStatus = B_BAD_VALUE);
|
||||
|
||||
// get on-disk B+Tree header
|
||||
|
||||
fCachedHeader.Unset();
|
||||
fStream = stream;
|
||||
|
||||
fHeader = fCachedHeader.SetToHeader();
|
||||
if (fHeader == NULL)
|
||||
RETURN_ERROR(fStatus = B_NO_INIT);
|
||||
// get on-disk B+Tree header
|
||||
|
||||
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?
|
||||
|
||||
if (fHeader->MaximumSize() != stream->Size()) {
|
||||
if (fHeader.MaximumSize() != stream->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
|
||||
//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
|
||||
|| (fHeader->RootNode() % fHeader->NodeSize()) != 0
|
||||
|| !fHeader->IsValidLink(fHeader->RootNode())
|
||||
|| !fHeader->IsValidLink(fHeader->FreeNode())) {
|
||||
if (fHeader.Magic() != BPLUSTREE_MAGIC
|
||||
|| (fHeader.RootNode() % fHeader.NodeSize()) != 0
|
||||
|| !fHeader.IsValidLink(fHeader.RootNode())
|
||||
|| !fHeader.IsValidLink(fHeader.FreeNode())) {
|
||||
#ifdef DEBUG
|
||||
dump_bplustree_header(fHeader);
|
||||
dump_block((const char*)fHeader, 128);
|
||||
dump_bplustree_header(&fHeader);
|
||||
dump_block((const char*)&fHeader, 128);
|
||||
#endif
|
||||
RETURN_ERROR(fStatus = B_BAD_DATA);
|
||||
}
|
||||
|
||||
fNodeSize = fHeader->NodeSize();
|
||||
fNodeSize = fHeader.NodeSize();
|
||||
|
||||
// validity check
|
||||
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_FLOAT_INDEX | S_DOUBLE_INDEX);
|
||||
|
||||
if (fHeader->DataType() > BPLUSTREE_DOUBLE_TYPE
|
||||
if (fHeader.DataType() > BPLUSTREE_DOUBLE_TYPE
|
||||
|| ((stream->Mode() & S_INDEX_DIR) != 0
|
||||
&& kToMode[fHeader->DataType()] != mode)
|
||||
&& kToMode[fHeader.DataType()] != mode)
|
||||
|| !stream->IsContainer()) {
|
||||
D( dump_bplustree_header(fHeader);
|
||||
D( dump_bplustree_header(&fHeader);
|
||||
dump_inode(&stream->Node());
|
||||
);
|
||||
RETURN_ERROR(fStatus = B_BAD_TYPE);
|
||||
@@ -498,7 +497,7 @@ BPlusTree::SetTo(Inode* stream)
|
||||
fAllowDuplicates = stream->IsIndex()
|
||||
|| (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);
|
||||
}
|
||||
|
||||
@@ -601,7 +600,7 @@ BPlusTree::_CompareKeys(const void* key1, int keyLength1, const void* key2,
|
||||
int keyLength2)
|
||||
{
|
||||
type_code type = 0;
|
||||
switch (fHeader->data_type) {
|
||||
switch (fHeader.DataType()) {
|
||||
case BPLUSTREE_STRING_TYPE:
|
||||
type = B_STRING_TYPE;
|
||||
break;
|
||||
@@ -697,7 +696,7 @@ BPlusTree::_SeekDown(Stack<node_and_key>& stack, const uint8* key,
|
||||
{
|
||||
// set the root node to begin with
|
||||
node_and_key nodeAndKey;
|
||||
nodeAndKey.nodeOffset = fHeader->RootNode();
|
||||
nodeAndKey.nodeOffset = fHeader.RootNode();
|
||||
|
||||
CachedNode cached(this);
|
||||
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)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
if ((uint32)stack.CountItems() > fHeader->MaxNumberOfLevels()) {
|
||||
if ((uint32)stack.CountItems() > fHeader.MaxNumberOfLevels()) {
|
||||
dprintf("BPlusTree::_SeekDown() node walked too deep.\n");
|
||||
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
|
||||
// it now
|
||||
off_t newRoot = BPLUSTREE_NULL;
|
||||
if (nodeAndKey.nodeOffset == fHeader->RootNode()) {
|
||||
if (nodeAndKey.nodeOffset == fHeader.RootNode()) {
|
||||
bplustree_node* root;
|
||||
status_t status = cachedNewRoot.Allocate(transaction, &root,
|
||||
&newRoot);
|
||||
@@ -1388,8 +1387,9 @@ BPlusTree::Insert(Transaction& transaction, const uint8* key, uint16 keyLength,
|
||||
root->overflow_link = HOST_ENDIAN_TO_BFS_INT64(
|
||||
nodeAndKey.nodeOffset);
|
||||
|
||||
CachedNode cached(this);
|
||||
bplustree_header* header
|
||||
= fCachedHeader.MakeWritableHeader(transaction);
|
||||
= cached.SetToWritableHeader(transaction);
|
||||
if (header == NULL)
|
||||
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
|
||||
// to a leaf node by dropping the overflow link, or,
|
||||
// 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() == 1 && node->IsLeaf()))) {
|
||||
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
|
||||
// to reset the maximum number of levels in the header
|
||||
if (fHeader->MaxNumberOfLevels() != 1) {
|
||||
if (fHeader.MaxNumberOfLevels() != 1) {
|
||||
CachedNode cached(this);
|
||||
bplustree_header* header
|
||||
= fCachedHeader.MakeWritableHeader(transaction);
|
||||
= cached.SetToWritableHeader(transaction);
|
||||
if (header == NULL)
|
||||
return B_IO_ERROR;
|
||||
|
||||
@@ -1807,7 +1808,7 @@ BPlusTree::Replace(Transaction& transaction, const uint8* key, uint16 keyLength,
|
||||
|
||||
ASSERT_WRITE_LOCKED_INODE(fStream);
|
||||
|
||||
off_t nodeOffset = fHeader->RootNode();
|
||||
off_t nodeOffset = fHeader.RootNode();
|
||||
CachedNode cached(this);
|
||||
const bplustree_node* node;
|
||||
|
||||
@@ -1861,7 +1862,7 @@ BPlusTree::Find(const uint8* key, uint16 keyLength, off_t* _value)
|
||||
|
||||
ASSERT_READ_LOCKED_INODE(fStream);
|
||||
|
||||
off_t nodeOffset = fHeader->RootNode();
|
||||
off_t nodeOffset = fHeader.RootNode();
|
||||
CachedNode cached(this);
|
||||
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]);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (levels != (int32)fHeader->MaxNumberOfLevels())
|
||||
if (levels != (int32)fHeader.MaxNumberOfLevels())
|
||||
DEBUGGER(("levels don't match"));
|
||||
#endif
|
||||
return status;
|
||||
@@ -1919,13 +1920,13 @@ TreeIterator::~TreeIterator()
|
||||
status_t
|
||||
TreeIterator::Goto(int8 to)
|
||||
{
|
||||
if (fTree == NULL || fTree->fHeader == NULL)
|
||||
if (fTree == NULL || fTree->fStream == NULL)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
// lock access to stream
|
||||
InodeReadLocker locker(fTree->fStream);
|
||||
|
||||
off_t nodeOffset = fTree->fHeader->RootNode();
|
||||
off_t nodeOffset = fTree->fHeader.RootNode();
|
||||
CachedNode cached(fTree);
|
||||
const bplustree_node* node;
|
||||
|
||||
@@ -2079,7 +2080,7 @@ TreeIterator::Traverse(int8 direction, void* key, uint16* keyLength,
|
||||
length = min_c(length, maxLength);
|
||||
memcpy(key, keyStart, length);
|
||||
|
||||
if (fTree->fHeader->data_type == BPLUSTREE_STRING_TYPE) {
|
||||
if (fTree->fHeader.DataType() == BPLUSTREE_STRING_TYPE) {
|
||||
// terminate string type
|
||||
if (length == maxLength)
|
||||
length--;
|
||||
@@ -2138,7 +2139,7 @@ TreeIterator::Find(const uint8* key, uint16 keyLength)
|
||||
// lock access to stream
|
||||
InodeReadLocker locker(fTree->fStream);
|
||||
|
||||
off_t nodeOffset = fTree->fHeader->RootNode();
|
||||
off_t nodeOffset = fTree->fHeader.RootNode();
|
||||
|
||||
CachedNode cached(fTree);
|
||||
const bplustree_node* node;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
#ifndef B_PLUS_TREE_H
|
||||
@@ -60,45 +60,55 @@ struct sorted_array;
|
||||
typedef sorted_array duplicate_array;
|
||||
|
||||
struct bplustree_node {
|
||||
int64 left_link;
|
||||
int64 right_link;
|
||||
int64 overflow_link;
|
||||
uint16 all_key_count;
|
||||
uint16 all_key_length;
|
||||
int64 left_link;
|
||||
int64 right_link;
|
||||
int64 overflow_link;
|
||||
uint16 all_key_count;
|
||||
uint16 all_key_length;
|
||||
|
||||
off_t LeftLink() const { return BFS_ENDIAN_TO_HOST_INT64(left_link); }
|
||||
off_t RightLink() const { return BFS_ENDIAN_TO_HOST_INT64(right_link); }
|
||||
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); }
|
||||
off_t LeftLink() const
|
||||
{ return BFS_ENDIAN_TO_HOST_INT64(
|
||||
left_link); }
|
||||
off_t RightLink() const
|
||||
{ return BFS_ENDIAN_TO_HOST_INT64(
|
||||
right_link); }
|
||||
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 off_t* Values() const;
|
||||
inline uint8* Keys() const;
|
||||
inline int32 Used() const;
|
||||
uint8* KeyAt(int32 index, uint16* keyLength) const;
|
||||
inline uint16* KeyLengths() const;
|
||||
inline off_t* Values() const;
|
||||
inline uint8* Keys() const;
|
||||
inline int32 Used() const;
|
||||
uint8* KeyAt(int32 index, uint16* keyLength) const;
|
||||
|
||||
inline bool IsLeaf() const;
|
||||
inline bool IsLeaf() const;
|
||||
|
||||
void Initialize();
|
||||
uint8 CountDuplicates(off_t offset, bool isFragment) const;
|
||||
off_t DuplicateAt(off_t offset, bool isFragment, int8 index) const;
|
||||
uint32 FragmentsUsed(uint32 nodeSize) const;
|
||||
inline duplicate_array* FragmentAt(int8 index) const;
|
||||
inline duplicate_array* DuplicateArray() const;
|
||||
void Initialize();
|
||||
uint8 CountDuplicates(off_t offset,
|
||||
bool isFragment) const;
|
||||
off_t DuplicateAt(off_t offset, bool isFragment,
|
||||
int8 index) 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 off_t MakeLink(uint8 type, off_t link,
|
||||
uint32 fragmentIndex = 0);
|
||||
static inline bool IsDuplicate(off_t link);
|
||||
static inline off_t FragmentOffset(off_t link);
|
||||
static inline uint32 FragmentIndex(off_t link);
|
||||
static inline uint32 MaxFragments(uint32 nodeSize);
|
||||
static inline uint8 LinkType(off_t link);
|
||||
static inline off_t MakeLink(uint8 type, off_t link,
|
||||
uint32 fragmentIndex = 0);
|
||||
static inline bool IsDuplicate(off_t link);
|
||||
static inline off_t FragmentOffset(off_t link);
|
||||
static inline uint32 FragmentIndex(off_t link);
|
||||
static inline uint32 MaxFragments(uint32 nodeSize);
|
||||
|
||||
#ifdef DEBUG
|
||||
status_t CheckIntegrity(uint32 nodeSize) const;
|
||||
status_t CheckIntegrity(uint32 nodeSize) const;
|
||||
#endif
|
||||
} _PACKED;
|
||||
|
||||
@@ -157,128 +167,137 @@ public:
|
||||
Unset();
|
||||
}
|
||||
|
||||
const bplustree_node* SetTo(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* MakeWritableHeader(Transaction& transaction);
|
||||
const bplustree_node* SetTo(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);
|
||||
|
||||
void UnsetUnchanged(Transaction& transaction);
|
||||
void Unset();
|
||||
void UnsetUnchanged(Transaction& transaction);
|
||||
void Unset();
|
||||
|
||||
status_t Free(Transaction& transaction, off_t offset);
|
||||
status_t Allocate(Transaction& transaction, bplustree_node** node,
|
||||
off_t* offset);
|
||||
status_t Free(Transaction& transaction, off_t offset);
|
||||
status_t Allocate(Transaction& transaction,
|
||||
bplustree_node** _node, off_t* _offset);
|
||||
|
||||
bool IsWritable() const { return fWritable; }
|
||||
bplustree_node* Node() const { return fNode; }
|
||||
bool IsWritable() const { return fWritable; }
|
||||
bplustree_node* Node() const { return fNode; }
|
||||
|
||||
protected:
|
||||
bplustree_node* InternalSetTo(Transaction* transaction, off_t offset);
|
||||
bplustree_node* InternalSetTo(Transaction* transaction,
|
||||
off_t offset);
|
||||
|
||||
BPlusTree* fTree;
|
||||
bplustree_node* fNode;
|
||||
off_t fOffset;
|
||||
off_t fBlockNumber;
|
||||
bool fWritable;
|
||||
BPlusTree* fTree;
|
||||
bplustree_node* fNode;
|
||||
off_t fOffset;
|
||||
off_t fBlockNumber;
|
||||
bool fWritable;
|
||||
};
|
||||
|
||||
|
||||
class BPlusTree {
|
||||
public:
|
||||
BPlusTree(Transaction& transaction, Inode* stream,
|
||||
int32 nodeSize = BPLUSTREE_NODE_SIZE);
|
||||
BPlusTree(Inode* stream);
|
||||
BPlusTree();
|
||||
~BPlusTree();
|
||||
BPlusTree(Transaction& transaction,
|
||||
Inode* stream,
|
||||
int32 nodeSize = BPLUSTREE_NODE_SIZE);
|
||||
BPlusTree(Inode* stream);
|
||||
BPlusTree();
|
||||
~BPlusTree();
|
||||
|
||||
status_t SetTo(Transaction& transaction, Inode* stream,
|
||||
int32 nodeSize = BPLUSTREE_NODE_SIZE);
|
||||
status_t SetTo(Inode* stream);
|
||||
status_t SetStream(Inode* stream);
|
||||
status_t SetTo(Transaction& transaction, Inode* stream,
|
||||
int32 nodeSize = BPLUSTREE_NODE_SIZE);
|
||||
status_t SetTo(Inode* stream);
|
||||
status_t SetStream(Inode* stream);
|
||||
|
||||
status_t InitCheck();
|
||||
status_t Validate();
|
||||
status_t InitCheck();
|
||||
status_t Validate();
|
||||
|
||||
status_t Remove(Transaction& transaction, const uint8* key,
|
||||
uint16 keyLength, off_t value);
|
||||
status_t Insert(Transaction& transaction, const uint8* key,
|
||||
uint16 keyLength, off_t value);
|
||||
status_t Remove(Transaction& transaction,
|
||||
const uint8* key, 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,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, const char* key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, int32 key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, uint32 key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, int64 key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, uint64 key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, float key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, double key,
|
||||
off_t value);
|
||||
status_t Remove(Transaction& transaction, const char* key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, const char* key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, int32 key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, uint32 key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, int64 key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, uint64 key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, float key,
|
||||
off_t value);
|
||||
status_t Insert(Transaction& transaction, double key,
|
||||
off_t value);
|
||||
|
||||
status_t Replace(Transaction& transaction, const uint8* key,
|
||||
uint16 keyLength, off_t value);
|
||||
status_t Find(const uint8* key, uint16 keyLength, off_t* value);
|
||||
status_t Replace(Transaction& transaction,
|
||||
const uint8* key, uint16 keyLength,
|
||||
off_t value);
|
||||
status_t Find(const uint8* key, uint16 keyLength,
|
||||
off_t* value);
|
||||
|
||||
static int32 TypeCodeToKeyType(type_code code);
|
||||
static int32 ModeToKeyType(mode_t mode);
|
||||
static int32 TypeCodeToKeyType(type_code code);
|
||||
static int32 ModeToKeyType(mode_t mode);
|
||||
|
||||
private:
|
||||
BPlusTree(const BPlusTree& other);
|
||||
BPlusTree& operator=(const BPlusTree& other);
|
||||
// no implementation
|
||||
BPlusTree(const BPlusTree& other);
|
||||
BPlusTree& operator=(const BPlusTree& other);
|
||||
// no implementation
|
||||
|
||||
int32 _CompareKeys(const void* key1, int keylength1,
|
||||
const void* key2, int keylength2);
|
||||
status_t _FindKey(const bplustree_node* node, const uint8* key,
|
||||
uint16 keyLength, uint16* index = NULL,
|
||||
off_t* next = NULL);
|
||||
status_t _SeekDown(Stack<node_and_key>& stack, const uint8* key,
|
||||
uint16 keyLength);
|
||||
int32 _CompareKeys(const void* key1, int keylength1,
|
||||
const void* key2, int keylength2);
|
||||
status_t _FindKey(const bplustree_node* node,
|
||||
const uint8* key, uint16 keyLength,
|
||||
uint16* index = NULL, off_t* next = NULL);
|
||||
status_t _SeekDown(Stack<node_and_key>& stack,
|
||||
const uint8* key, uint16 keyLength);
|
||||
|
||||
status_t _FindFreeDuplicateFragment(Transaction& transaction,
|
||||
const bplustree_node* node, CachedNode& cached,
|
||||
off_t* _offset, bplustree_node** _fragment,
|
||||
uint32* _index);
|
||||
status_t _InsertDuplicate(Transaction& transaction,
|
||||
CachedNode& cached, const bplustree_node* node,
|
||||
uint16 index, off_t value);
|
||||
void _InsertKey(bplustree_node* node, uint16 index,
|
||||
uint8* key, uint16 keyLength, off_t value);
|
||||
status_t _SplitNode(bplustree_node* node, off_t nodeOffset,
|
||||
bplustree_node* other, off_t otherOffset,
|
||||
uint16* _keyIndex, uint8* key, uint16* _keyLength,
|
||||
off_t* _value);
|
||||
status_t _FindFreeDuplicateFragment(
|
||||
Transaction& transaction,
|
||||
const bplustree_node* node,
|
||||
CachedNode& cached, off_t* _offset,
|
||||
bplustree_node** _fragment, uint32* _index);
|
||||
status_t _InsertDuplicate(Transaction& transaction,
|
||||
CachedNode& cached,
|
||||
const bplustree_node* node, uint16 index,
|
||||
off_t value);
|
||||
void _InsertKey(bplustree_node* node, uint16 index,
|
||||
uint8* key, uint16 keyLength, off_t value);
|
||||
status_t _SplitNode(bplustree_node* node,
|
||||
off_t nodeOffset, bplustree_node* other,
|
||||
off_t otherOffset, uint16* _keyIndex,
|
||||
uint8* key, uint16* _keyLength,
|
||||
off_t* _value);
|
||||
|
||||
status_t _RemoveDuplicate(Transaction& transaction,
|
||||
const bplustree_node* node, CachedNode& cached,
|
||||
uint16 keyIndex, off_t value);
|
||||
void _RemoveKey(bplustree_node* node, uint16 index);
|
||||
status_t _RemoveDuplicate(Transaction& transaction,
|
||||
const bplustree_node* node,
|
||||
CachedNode& cached, uint16 keyIndex,
|
||||
off_t value);
|
||||
void _RemoveKey(bplustree_node* node, uint16 index);
|
||||
|
||||
void _UpdateIterators(off_t offset, off_t nextOffset,
|
||||
uint16 keyIndex, uint16 splitAt, int8 change);
|
||||
void _AddIterator(TreeIterator* iterator);
|
||||
void _RemoveIterator(TreeIterator* iterator);
|
||||
void _UpdateIterators(off_t offset, off_t nextOffset,
|
||||
uint16 keyIndex, uint16 splitAt,
|
||||
int8 change);
|
||||
void _AddIterator(TreeIterator* iterator);
|
||||
void _RemoveIterator(TreeIterator* iterator);
|
||||
|
||||
private:
|
||||
friend class TreeIterator;
|
||||
friend class CachedNode;
|
||||
friend class TreeIterator;
|
||||
friend class CachedNode;
|
||||
|
||||
Inode* fStream;
|
||||
const bplustree_header* fHeader;
|
||||
CachedNode fCachedHeader;
|
||||
int32 fNodeSize;
|
||||
bool fAllowDuplicates;
|
||||
status_t fStatus;
|
||||
mutex fIteratorLock;
|
||||
Inode* fStream;
|
||||
bplustree_header fHeader;
|
||||
int32 fNodeSize;
|
||||
bool fAllowDuplicates;
|
||||
status_t fStatus;
|
||||
mutex fIteratorLock;
|
||||
SinglyLinkedList<TreeIterator> fIterators;
|
||||
};
|
||||
|
||||
@@ -290,46 +309,48 @@ extern int32 compareKeys(type_code type, const void* key1, int keyLength1,
|
||||
|
||||
class TreeIterator : public SinglyLinkedListLinkImpl<TreeIterator> {
|
||||
public:
|
||||
TreeIterator(BPlusTree* tree);
|
||||
~TreeIterator();
|
||||
TreeIterator(BPlusTree* tree);
|
||||
~TreeIterator();
|
||||
|
||||
status_t Goto(int8 to);
|
||||
status_t Traverse(int8 direction, void* key, uint16* keyLength,
|
||||
uint16 maxLength, off_t* value,
|
||||
uint16* duplicate = NULL);
|
||||
status_t Find(const uint8* key, uint16 keyLength);
|
||||
status_t Goto(int8 to);
|
||||
status_t Traverse(int8 direction, void* key,
|
||||
uint16* keyLength, uint16 maxLength,
|
||||
off_t* value, uint16* duplicate = NULL);
|
||||
status_t Find(const uint8* key, uint16 keyLength);
|
||||
|
||||
status_t Rewind();
|
||||
status_t GetNextEntry(void* key, uint16* keyLength,
|
||||
uint16 maxLength, off_t* value,
|
||||
uint16* duplicate = NULL);
|
||||
status_t GetPreviousEntry(void* key, uint16* keyLength,
|
||||
uint16 maxLength, off_t* value,
|
||||
uint16* duplicate = NULL);
|
||||
void SkipDuplicates();
|
||||
status_t Rewind();
|
||||
status_t GetNextEntry(void* key, uint16* keyLength,
|
||||
uint16 maxLength, off_t* value,
|
||||
uint16* duplicate = NULL);
|
||||
status_t GetPreviousEntry(void* key, uint16* keyLength,
|
||||
uint16 maxLength, off_t* value,
|
||||
uint16* duplicate = NULL);
|
||||
void SkipDuplicates();
|
||||
|
||||
BPlusTree* Tree() const { return fTree; }
|
||||
BPlusTree* Tree() const { return fTree; }
|
||||
|
||||
#ifdef DEBUG
|
||||
void Dump();
|
||||
void Dump();
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class BPlusTree;
|
||||
friend class BPlusTree;
|
||||
|
||||
// called by BPlusTree
|
||||
void Update(off_t offset, off_t nextOffset, uint16 keyIndex,
|
||||
uint16 splitAt, int8 change);
|
||||
void Stop();
|
||||
void Update(off_t offset, off_t nextOffset,
|
||||
uint16 keyIndex, uint16 splitAt,
|
||||
int8 change);
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
BPlusTree* fTree;
|
||||
off_t fCurrentNodeOffset;
|
||||
// traverse position
|
||||
int32 fCurrentKey;
|
||||
off_t fDuplicateNode;
|
||||
uint16 fDuplicate, fNumDuplicates;
|
||||
bool fIsFragment;
|
||||
BPlusTree* fTree;
|
||||
off_t fCurrentNodeOffset;
|
||||
// traverse position
|
||||
int32 fCurrentKey;
|
||||
off_t fDuplicateNode;
|
||||
uint16 fDuplicate;
|
||||
uint16 fNumDuplicates;
|
||||
bool fIsFragment;
|
||||
};
|
||||
|
||||
|
||||
@@ -340,7 +361,7 @@ private:
|
||||
inline status_t
|
||||
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 Remove(transaction, (uint8*)key, strlen(key), value);
|
||||
}
|
||||
@@ -348,7 +369,7 @@ BPlusTree::Remove(Transaction& transaction, const char* key, off_t value)
|
||||
inline status_t
|
||||
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 Insert(transaction, (uint8*)key, strlen(key), value);
|
||||
}
|
||||
@@ -356,7 +377,7 @@ BPlusTree::Insert(Transaction& transaction, const char* key, off_t value)
|
||||
inline status_t
|
||||
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 Insert(transaction, (uint8*)&key, sizeof(key), value);
|
||||
}
|
||||
@@ -364,7 +385,7 @@ BPlusTree::Insert(Transaction& transaction, int32 key, off_t value)
|
||||
inline status_t
|
||||
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 Insert(transaction, (uint8*)&key, sizeof(key), value);
|
||||
}
|
||||
@@ -372,7 +393,7 @@ BPlusTree::Insert(Transaction& transaction, uint32 key, off_t value)
|
||||
inline status_t
|
||||
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 Insert(transaction, (uint8*)&key, sizeof(key), value);
|
||||
}
|
||||
@@ -380,7 +401,7 @@ BPlusTree::Insert(Transaction& transaction, int64 key, off_t value)
|
||||
inline status_t
|
||||
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 Insert(transaction, (uint8*)&key, sizeof(key), value);
|
||||
}
|
||||
@@ -388,7 +409,7 @@ BPlusTree::Insert(Transaction& transaction, uint64 key, off_t value)
|
||||
inline status_t
|
||||
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 Insert(transaction, (uint8*)&key, sizeof(key), value);
|
||||
}
|
||||
@@ -396,7 +417,7 @@ BPlusTree::Insert(Transaction& transaction, float key, off_t value)
|
||||
inline status_t
|
||||
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 Insert(transaction, (uint8*)&key, sizeof(key), value);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user