* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "AttributeIndex.h"
#include <new>
#include <TypeConstants.h>
#include <util/AVLTree.h>
#include <util/SinglyLinkedList.h>
#include <file_systems/QueryParserUtils.h>
#include "AttributeIndexer.h"
#include "DebugSupport.h"
#include "IndexImpl.h"
#include "Node.h"
#include "Volume.h"
struct AttributeIndexTreeKey {
const void* data;
size_t length;
AttributeIndexTreeKey()
{
}
AttributeIndexTreeKey(const void* data, size_t length)
:
data(data),
length(length)
{
}
};
struct AttributeIndexTreeValue : AVLTreeNode {
Node* node;
IndexedAttributeOwner* owner;
void* attributeCookie;
size_t length;
uint8 data[0];
static AttributeIndexTreeValue* Create(IndexedAttributeOwner* owner,
void* attributeCookie, size_t length)
{
AttributeIndexTreeValue* self = (AttributeIndexTreeValue*)malloc(
sizeof(AttributeIndexTreeValue) + length);
if (self == NULL)
return NULL;
self->owner = owner;
self->attributeCookie = attributeCookie;
self->length = length;
return self;
}
void Delete()
{
free(this);
}
};
struct AttributeIndex::TreeDefinition {
typedef TreeKey Key;
typedef TreeValue Value;
TreeDefinition(uint32 type)
:
fType(type)
{
}
AVLTreeNode* GetAVLTreeNode(Value* value) const
{
return value;
}
Value* GetValue(AVLTreeNode* node) const
{
return static_cast<Value*>(node);
}
int Compare(const Key& a, const Value* b) const
{
int cmp = QueryParser::compareKeys(fType, a.data, a.length, b->data,
b->length);
if (cmp != 0)
return cmp;
return -1;
}
int Compare(const Value* a, const Value* b) const
{
if (a == b)
return 0;
int cmp = QueryParser::compareKeys(fType, a->data, a->length, b->data,
b->length);
if (cmp != 0)
return cmp;
return a < b ? -1 : 1;
}
private:
uint32 fType;
};
struct AttributeIndex::NodeTree : public AVLTree<TreeDefinition> {
typedef TreeValue Node;
NodeTree(const TreeDefinition& definition)
:
AVLTree<TreeDefinition>(definition)
{
}
};
class AttributeIndex::IteratorList : public SinglyLinkedList<Iterator> {};
struct AttributeIndex::IteratorPolicy {
typedef AttributeIndex Index;
typedef TreeKey Value;
typedef AttributeIndex::NodeTree NodeTree;
typedef TreeValue TreeNode;
typedef IteratorPolicy TreePolicy;
static NodeTree* GetNodeTree(Index* index)
{
return index->fNodes;
}
static void GetTreeNodeValue(TreeNode* node, void* buffer,
size_t* _keyLength)
{
if (node->length > 0)
memcpy(buffer, node->data, node->length);
*_keyLength = node->length;
}
static Node* GetNode(TreeNode* treeNode)
{
return treeNode->node;
}
static TreeNode* GetFirstTreeNode(Index* index)
{
return index->fNodes->GetIterator().Next();
}
static TreeNode* FindClosestTreeNode(Index* index, const Value& value)
{
return index->fNodes->FindClosest(value, false);
}
};
class AttributeIndex::Iterator : public GenericIndexIterator<IteratorPolicy>,
public SinglyLinkedListLinkImpl<Iterator> {
public:
virtual void NodeChanged(Node* node, uint32 statFields,
const OldNodeAttributes& oldAttributes);
};
AttributeIndexer::AttributeIndexer(AttributeIndex* index)
:
fIndex(index),
fIndexName(index->Name()),
fIndexType(index->Type()),
fCookie(NULL)
{
}
AttributeIndexer::~AttributeIndexer()
{
}
status_t
AttributeIndexer::CreateCookie(IndexedAttributeOwner* owner,
void* attributeCookie, uint32 attributeType, size_t attributeSize,
void*& _data, size_t& _toRead)
{
if (attributeType != fIndexType)
return B_ERROR;
if (fIndex->HasFixedKeyLength()) {
if (attributeSize != fIndex->KeyLength())
return B_ERROR;
} else if (attributeSize > kMaxIndexKeyLength)
attributeSize = kMaxIndexKeyLength;
fCookie = AttributeIndexTreeValue::Create(owner, attributeCookie,
attributeSize);
if (fCookie == NULL)
return B_NO_MEMORY;
_data = fCookie->data;
_toRead = attributeSize;
return B_OK;
}
void
AttributeIndexer::DeleteCookie()
{
fCookie->Delete();
fCookie = NULL;
}
AttributeIndex::AttributeIndex()
:
Index(),
fNodes(NULL),
fIteratorsToUpdate(NULL),
fIndexer(NULL)
{
}
AttributeIndex::~AttributeIndex()
{
if (IsListening())
fVolume->RemoveNodeListener(this);
ASSERT(fIteratorsToUpdate->IsEmpty());
delete fIteratorsToUpdate;
delete fNodes;
delete fIndexer;
}
status_t
AttributeIndex::Init(Volume* volume, const char* name, uint32 type,
size_t keyLength)
{
status_t error = Index::Init(volume, name, type, keyLength > 0, keyLength);
if (error != B_OK)
return error;
fVolume->AddNodeListener(this, NULL);
fNodes = new(std::nothrow) NodeTree(TreeDefinition(type));
fIteratorsToUpdate = new(std::nothrow) IteratorList;
fIndexer = new(std::nothrow) AttributeIndexer(this);
if (fNodes == NULL || fIteratorsToUpdate == NULL || fIndexer == NULL)
return B_NO_MEMORY;
return B_OK;
}
int32
AttributeIndex::CountEntries() const
{
return fNodes->Count();
}
void
AttributeIndex::NodeAdded(Node* node)
{
if (node->IndexAttribute(fIndexer) != B_OK)
return;
TreeValue* treeValue = fIndexer->Cookie();
treeValue->node = node;
fNodes->Insert(treeValue);
}
void
AttributeIndex::NodeRemoved(Node* node)
{
TreeValue* treeValue = (TreeValue*)node->IndexCookieForAttribute(Name());
if (treeValue == NULL)
return;
treeValue->owner->UnsetIndexCookie(treeValue->attributeCookie);
fNodes->Remove(treeValue);
}
void
AttributeIndex::NodeChanged(Node* node, uint32 statFields,
const OldNodeAttributes& oldAttributes)
{
IteratorList iterators;
iterators.TakeFrom(fIteratorsToUpdate);
TreeValue* oldTreeValue
= (TreeValue*)oldAttributes.IndexCookieForAttribute(Name());
TreeValue* treeValue = (TreeValue*)node->IndexCookieForAttribute(Name());
if (treeValue == NULL && oldTreeValue == NULL)
return;
if (oldTreeValue != NULL) {
for (IteratorList::ConstIterator it = iterators.GetIterator();
Iterator* iterator = it.Next();) {
iterator->NodeChangeBegin(node);
}
fNodes->Remove(oldTreeValue);
}
if (treeValue != NULL)
fNodes->Insert(treeValue);
if (oldTreeValue != NULL) {
for (IteratorList::ConstIterator it = iterators.GetIterator();
Iterator* iterator = it.Next();) {
iterator->NodeChangeEnd(node);
}
}
fVolume->UpdateLiveQueries(node, Name(), Type(),
oldTreeValue != NULL ? oldTreeValue->data : NULL,
oldTreeValue != NULL ? oldTreeValue->length : 0,
treeValue != NULL ? treeValue->data : NULL,
treeValue != NULL ? treeValue->length : 0);
if (oldTreeValue != NULL)
oldTreeValue->Delete();
}
AbstractIndexIterator*
AttributeIndex::InternalGetIterator()
{
Iterator* iterator = new(std::nothrow) Iterator;
if (iterator != NULL) {
if (!iterator->SetTo(this, TreeKey(), true)) {
delete iterator;
iterator = NULL;
}
}
return iterator;
}
AbstractIndexIterator*
AttributeIndex::InternalFind(const void* key, size_t length)
{
if (HasFixedKeyLength() && length != KeyLength())
return NULL;
Iterator* iterator = new(std::nothrow) Iterator;
if (iterator != NULL) {
if (!iterator->SetTo(this, TreeKey(key, length))) {
delete iterator;
iterator = NULL;
}
}
return iterator;
}
void
AttributeIndex::_AddIteratorToUpdate(Iterator* iterator)
{
fIteratorsToUpdate->Add(iterator);
}
void
AttributeIndex::Iterator::NodeChanged(Node* node, uint32 statFields,
const OldNodeAttributes& oldAttributes)
{
fIndex->_AddIteratorToUpdate(this);
}