Add NameIndex class and create instance in Volume

This commit is contained in:
Ingo Weinhold 2011-07-05 22:57:29 +02:00
parent 804a92da7a
commit 3897e7298e
4 changed files with 432 additions and 0 deletions

View File

@ -18,6 +18,7 @@ HAIKU_PACKAGE_FS_SOURCES =
GlobalFactory.cpp
Index.cpp
kernel_interface.cpp
NameIndex.cpp
Node.cpp
NodeListener.cpp
Package.cpp

View File

@ -0,0 +1,370 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <TypeConstants.h>
#include <util/TwoKeyAVLTree.h>
#include "DebugSupport.h"
#include "IndexImpl.h"
#include "NameIndex.h"
#include "Node.h"
#include "Volume.h"
// #pragma mark - NameIndexPrimaryKey
class NameIndexPrimaryKey {
public:
NameIndexPrimaryKey(const Node* entry, const char* name = NULL)
:
entry(entry),
name(name ? name : entry->Name())
{
}
NameIndexPrimaryKey(const char* name)
:
entry(NULL),
name(name)
{
}
const Node* entry;
const char* name;
};
// #pragma mark - NameIndexGetPrimaryKey
class NameIndexGetPrimaryKey {
public:
inline NameIndexPrimaryKey operator()(const Node* a)
{
return NameIndexPrimaryKey(a);
}
inline NameIndexPrimaryKey operator()(const Node* a) const
{
return NameIndexPrimaryKey(a);
}
};
// #pragma mark - NameIndexPrimaryKeyCompare
class NameIndexPrimaryKeyCompare
{
public:
inline int operator()(const NameIndexPrimaryKey &a,
const NameIndexPrimaryKey &b) const
{
if (a.entry != NULL && a.entry == b.entry)
return 0;
return strcmp(a.name, b.name) != 0;
}
};
// #pragma mark - EntryTree
typedef TwoKeyAVLTree<Node*, NameIndexPrimaryKey, NameIndexPrimaryKeyCompare,
NameIndexGetPrimaryKey> _EntryTree;
class NameIndex::EntryTree : public _EntryTree {
};
// #pragma mark - NameIndexIterator
class NameIndexIterator : public AbstractIndexIterator,
public NodeListener {
public:
NameIndexIterator();
virtual ~NameIndexIterator();
virtual Node* Current();
virtual Node* Current(void* buffer, size_t* _keyLength);
virtual Node* Previous();
virtual Node* Next();
virtual status_t Suspend();
virtual status_t Resume();
bool SetTo(NameIndex* index, const char* name,
bool ignoreValue = false);
virtual void NodeRemoved(Node* node);
private:
friend class NameIndex;
typedef AbstractIndexIterator BaseClass;
private:
NameIndex* fIndex;
NameIndex::EntryTree::Iterator fIterator;
bool fSuspended;
bool fIsNext;
};
// #pragma mark - NameIndex
NameIndex::NameIndex()
:
Index(),
fEntries(NULL)
{
}
NameIndex::~NameIndex()
{
if (fVolume != NULL)
fVolume->RemoveNodeListener(this);
delete fEntries;
// Actually we would need to maintain a list of iterators and unset the
// still existing iterators here. But since the name index is deleted
// when the volume is unmounted, there shouldn't be any iterators left
// anymore.
}
status_t
NameIndex::Init(Volume* volume)
{
status_t error = Index::Init(volume, "name", B_STRING_TYPE, false);
if (error != B_OK)
return error;
fEntries = new(std::nothrow) EntryTree;
if (fEntries == NULL)
return B_NO_MEMORY;
fVolume = volume;
fVolume->AddNodeListener(this, NULL);
return B_OK;
}
int32
NameIndex::CountEntries() const
{
return fEntries->CountItems();
}
void
NameIndex::NodeAdded(Node* node)
{
fEntries->Insert(node);
// udpate live queries
_UpdateLiveQueries(node, NULL, node->Name());
}
void
NameIndex::NodeRemoved(Node* node)
{
fEntries->Remove(node, node);
// udpate live queries
_UpdateLiveQueries(node, node->Name(), NULL);
}
void
NameIndex::NodeChanged(Node* node, uint32 statFields)
{
// nothing to do -- the name remains the same
}
AbstractIndexIterator*
NameIndex::InternalGetIterator()
{
NameIndexIterator* iterator = new(std::nothrow) NameIndexIterator;
if (iterator != NULL) {
if (!iterator->SetTo(this, NULL, true)) {
delete iterator;
iterator = NULL;
}
}
return iterator;
}
AbstractIndexIterator*
NameIndex::InternalFind(const void* _key, size_t length)
{
if (_key == NULL || length == 0)
return NULL;
const char* key = (const char*)_key;
// if the key is not null-terminated, copy it
char clonedKey[kMaxIndexKeyLength];
if (key[length - 1] != '\0') {
if (length >= kMaxIndexKeyLength)
length = kMaxIndexKeyLength - 1;
memcpy(clonedKey, key, length);
clonedKey[length] = '\0';
length++;
key = clonedKey;
}
NameIndexIterator* iterator = new(std::nothrow) NameIndexIterator;
if (iterator != NULL) {
if (!iterator->SetTo(this, (const char*)key)) {
delete iterator;
iterator = NULL;
}
}
return iterator;
}
void
NameIndex::_UpdateLiveQueries(Node* entry, const char* oldName,
const char* newName)
{
fVolume->UpdateLiveQueries(entry, Name(), Type(),
oldName, oldName ? strlen(oldName) : 0,
newName, newName ? strlen(newName) : 0);
}
// #pragma mark - NameIndexIterator
NameIndexIterator::NameIndexIterator()
:
AbstractIndexIterator(),
fIndex(NULL),
fIterator(),
fSuspended(false),
fIsNext(false)
{
}
NameIndexIterator::~NameIndexIterator()
{
SetTo(NULL, NULL);
}
Node*
NameIndexIterator::Current()
{
return fIndex != NULL
&& fIterator.Current() != NULL ? *fIterator.Current() : NULL;
}
Node*
NameIndexIterator::Current(void* buffer, size_t* _keyLength)
{
Node* entry = Current();
if (entry != NULL) {
strlcpy((char*)buffer, entry->Name(), kMaxIndexKeyLength);
*_keyLength = strlen(entry->Name());
}
return entry;
}
Node*
NameIndexIterator::Previous()
{
if (fSuspended)
return NULL;
if (!(fIterator.Current() != NULL && fIsNext))
fIterator.Previous();
fIsNext = false;
return fIndex != NULL
&& fIterator.Current() != NULL ? *fIterator.Current() : NULL;
}
Node*
NameIndexIterator::Next()
{
if (fSuspended)
return NULL;
if (!(fIterator.Current() != NULL && fIsNext))
fIterator.Next();
fIsNext = false;
return fIndex != NULL
&& fIterator.Current() != NULL ? *fIterator.Current() : NULL;
}
status_t
NameIndexIterator::Suspend()
{
status_t error = !fSuspended ? B_OK : B_BAD_VALUE;
if (error == B_OK) {
if (fIterator.Current() != NULL)
fIndex->GetVolume()->AddNodeListener(this, *fIterator.Current());
fSuspended = true;
}
return error;
}
status_t
NameIndexIterator::Resume()
{
status_t error = fSuspended ? B_OK : B_BAD_VALUE;
if (error == B_OK) {
if (fIterator.Current() != NULL)
fIndex->GetVolume()->RemoveNodeListener(this);
fSuspended = false;
}
return error;
}
bool
NameIndexIterator::SetTo(NameIndex* index, const char* name, bool ignoreValue)
{
Resume();
fIndex = index;
fSuspended = false;
fIsNext = false;
if (fIndex != NULL) {
if (ignoreValue) {
fIndex->fEntries->GetIterator(&fIterator);
return fIterator.Current() != NULL;
}
return fIndex->fEntries->FindFirst(name, &fIterator);
}
return false;
}
void
NameIndexIterator::NodeRemoved(Node* node)
{
Resume();
fIsNext = Next();
Suspend();
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef NAME_INDEX_H
#define NAME_INDEX_H
#include "Index.h"
#include "NodeListener.h"
class NameIndexIterator;
class NameIndex : public Index, private NodeListener {
public:
NameIndex();
virtual ~NameIndex();
status_t Init(Volume* volume);
virtual int32 CountEntries() const;
private:
virtual void NodeAdded(Node* node);
virtual void NodeRemoved(Node* node);
virtual void NodeChanged(Node* node, uint32 statFields);
protected:
virtual AbstractIndexIterator* InternalGetIterator();
virtual AbstractIndexIterator* InternalFind(const void* key,
size_t length);
private:
class EntryTree;
friend class NameIndexIterator;
void _UpdateLiveQueries(Node* entry,
const char* oldName, const char* newName);
private:
EntryTree* fEntries;
};
#endif // NAME_INDEX_H

View File

@ -32,6 +32,7 @@
#include "DebugSupport.h"
#include "kernel_interface.h"
#include "NameIndex.h"
#include "PackageDirectory.h"
#include "PackageFile.h"
#include "PackageFSRoot.h"
@ -507,6 +508,19 @@ Volume::Mount(const char* parameterString)
if (error != B_OK)
RETURN_ERROR(error);
// create the name index
NameIndex* index = new(std::nothrow) NameIndex;
if (index == NULL)
RETURN_ERROR(B_NO_MEMORY);
error = index->Init(this);
if (error != B_OK) {
delete index;
RETURN_ERROR(error);
}
fIndices.Insert(index);
// get the mount parameters
const char* packages = NULL;
const char* volumeName = NULL;