* 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.
*
* 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;
+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.
*/
#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);
}