Add Query class and query management in Volume

This commit is contained in:
Ingo Weinhold 2011-07-05 22:58:58 +02:00
parent 331b89b3a5
commit 617ac41c60
5 changed files with 381 additions and 1 deletions

View File

@ -3,7 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel file_systems packagefs ;
UseLibraryHeaders zlib ;
UsePrivateKernelHeaders ;
UsePrivateHeaders shared ;
UsePrivateHeaders shared storage ;
HAIKU_PACKAGE_FS_SOURCES =
@ -21,6 +21,7 @@ HAIKU_PACKAGE_FS_SOURCES =
NameIndex.cpp
Node.cpp
NodeListener.cpp
Query.cpp
Package.cpp
PackageDirectory.cpp
PackageDomain.cpp

View File

@ -0,0 +1,282 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "Query.h"
#include <file_systems/QueryParser.h>
#include "AttributeCookie.h"
#include "Directory.h"
#include "Index.h"
#include "Node.h"
#include "Volume.h"
// #pragma mark - QueryPolicy
struct Query::QueryPolicy {
typedef Query Context;
typedef ::Node Entry;
typedef ::Node Node;
struct Index {
Query* query;
::Index* index;
Index(Context* context)
:
query(context)
{
}
};
struct IndexIterator : ::IndexIterator {
::Index* index;
IndexIterator(::Index* index)
:
index(index)
{
}
};
static const int32 kMaxFileNameLength = B_FILE_NAME_LENGTH;
// Entry interface
static ino_t EntryGetParentID(Entry* entry)
{
return entry->Parent()->ID();
}
static Node* EntryGetNode(Entry* entry)
{
return entry;
}
static ino_t EntryGetNodeID(Entry* entry)
{
return entry->ID();
}
static ssize_t EntryGetName(Entry* entry, void* buffer, size_t bufferSize)
{
const char* name = entry->Name();
size_t nameLength = strlen(name);
if (nameLength >= bufferSize)
return B_BUFFER_OVERFLOW;
memcpy(buffer, name, nameLength + 1);
return nameLength + 1;
}
static const char* EntryGetNameNoCopy(Entry* entry, void* buffer,
size_t bufferSize)
{
return entry->Name();
}
// Index interface
static status_t IndexSetTo(Index& index, const char* attribute)
{
index.index = index.query->fVolume->FindIndex(attribute);
return index.index != NULL ? B_OK : B_ENTRY_NOT_FOUND;
}
static void IndexUnset(Index& index)
{
index.index = NULL;
}
static int32 IndexGetWeightedScore(Index& index, int32 score)
{
// should be inversely proportional to the index size; max input score
// is 2048
static const int32 maxFactor = 1024 * 1024;
return score * (maxFactor
/ std::min(maxFactor,
std::max((int32)1, index.index->CountEntries())));
}
static type_code IndexGetType(Index& index)
{
return index.index->Type();
}
static int32 IndexGetKeySize(Index& index)
{
return index.index->KeyLength();
}
static IndexIterator* IndexCreateIterator(Index& index)
{
IndexIterator* iterator = new(std::nothrow) IndexIterator(index.index);
if (iterator == NULL)
return NULL;
if (!index.index->GetIterator(iterator)) {
delete iterator;
return NULL;
}
return iterator;
}
// IndexIterator interface
static void IndexIteratorDelete(IndexIterator* indexIterator)
{
delete indexIterator;
}
static status_t IndexIteratorFind(IndexIterator* indexIterator,
const void* value, size_t size)
{
if (!indexIterator->index->Find(value, size, indexIterator))
return B_ENTRY_NOT_FOUND;
return B_OK;
}
static status_t IndexIteratorGetNextEntry(IndexIterator* indexIterator,
void* value, size_t* _valueLength, size_t bufferSize, Entry** _entry)
{
Node* node = indexIterator->Next(value, _valueLength);
if (node == NULL)
return B_ENTRY_NOT_FOUND;
*_entry = node;
return B_OK;
}
// Node interface
static const off_t NodeGetSize(Node* node)
{
return node->FileSize();
}
static bigtime_t NodeGetLastModifiedTime(Node* node)
{
timespec time = node->ModifiedTime();
return (bigtime_t)time.tv_sec * 1000000 + time.tv_nsec / 1000;
}
static status_t NodeGetAttribute(Node* node, const char* attribute,
void* buffer, size_t* _size, int32* _type)
{
// TODO: Creating a cookie is quite a bit of overhead.
AttributeCookie* cookie;
status_t error = node->OpenAttribute(attribute, O_RDONLY, cookie);
if (error != B_OK)
return error;
error = cookie->ReadAttribute(0, buffer, _size);
cookie->Close();
delete cookie;
return error;
}
static Entry* NodeGetFirstReferrer(Node* node)
{
return node;
}
static Entry* NodeGetNextReferrer(Node* node, Entry* entry)
{
return NULL;
}
// Volume interface
static dev_t ContextGetVolumeID(Context* context)
{
return context->fVolume->ID();
}
};
// #pragma mark - Query
Query::Query(Volume* volume)
:
fVolume(volume),
fImpl(NULL)
{
}
Query::~Query()
{
if (fImpl != NULL) {
if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
fVolume->RemoveQuery(this);
delete fImpl;
}
}
/*static*/ status_t
Query::Create(Volume* volume, const char* queryString, uint32 flags,
port_id port, uint32 token, Query*& _query)
{
Query* query = new(std::nothrow) Query(volume);
if (query == NULL)
return B_NO_MEMORY;
status_t error = query->_Init(queryString, flags, port, token);
if (error != B_OK) {
delete query;
return error;
}
_query = query;
return B_OK;
}
status_t
Query::Rewind()
{
return fImpl->Rewind();
}
status_t
Query::GetNextEntry(struct dirent* entry, size_t size)
{
return fImpl->GetNextEntry(entry, size);
}
void
Query::LiveUpdate(Node* node, const char* attribute, int32 type,
const void* oldKey, size_t oldLength, const void* newKey, size_t newLength)
{
fImpl->LiveUpdate(node, node, attribute, type, (const uint8*)oldKey,
oldLength, (const uint8*)newKey, newLength);
}
status_t
Query::_Init(const char* queryString, uint32 flags, port_id port, uint32 token)
{
status_t error = QueryImpl::Create(this, queryString, flags, port, token,
fImpl);
if (error != B_OK)
return error;
if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
fVolume->AddQuery(this);
return B_OK;
}

View File

@ -0,0 +1,60 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef QUERY_H
#define QUERY_H
#include <SupportDefs.h>
#include <util/DoublyLinkedList.h>
struct dirent;
namespace QueryParser {
template<typename QueryPolicy> class Query;
};
class Node;
class Volume;
class Query : public DoublyLinkedListLinkImpl<Query> {
public:
~Query();
static status_t Create(Volume* volume, const char* queryString,
uint32 flags, port_id port, uint32 token,
Query*& _query);
status_t Rewind();
status_t GetNextEntry(struct dirent* entry, size_t size);
void LiveUpdate(Node* node,
const char* attribute, int32 type,
const void* oldKey, size_t oldLength,
const void* newKey, size_t newLength);
private:
struct QueryPolicy;
friend struct QueryPolicy;
typedef QueryParser::Query<QueryPolicy> QueryImpl;
private:
Query(Volume* volume);
status_t _Init(const char* queryString, uint32 flags,
port_id port, uint32 token);
private:
Volume* fVolume;
QueryImpl* fImpl;
};
typedef DoublyLinkedList<Query> QueryList;
#endif // QUERY_H

View File

@ -676,6 +676,33 @@ Volume::RemoveNodeListener(NodeListener* listener)
}
void
Volume::AddQuery(Query* query)
{
fQueries.Add(query);
}
void
Volume::RemoveQuery(Query* query)
{
fQueries.Remove(query);
}
void
Volume::UpdateLiveQueries(Node* node, const char* attribute, int32 type,
const void* oldKey, size_t oldLength, const void* newKey,
size_t newLength)
{
for (QueryList::Iterator it = fQueries.GetIterator();
Query* query = it.Next();) {
query->LiveUpdate(node, attribute, type, oldKey, oldLength, newKey,
newLength);
}
}
status_t
Volume::GetVNode(ino_t nodeID, Node*& _node)
{

View File

@ -19,6 +19,7 @@
#include "NodeListener.h"
#include "PackageDomain.h"
#include "PackageLinksListener.h"
#include "Query.h"
class Directory;
@ -72,6 +73,14 @@ public:
Node* node);
void RemoveNodeListener(NodeListener* listener);
// query support -- volume must be write-locked
void AddQuery(Query* query);
void RemoveQuery(Query* query);
void UpdateLiveQueries(Node* node,
const char* attribute, int32 type,
const void* oldKey, size_t oldLength,
const void* newKey, size_t newLength);
Index* FindIndex(const char* name) const
{ return fIndices.Lookup(name); }
@ -192,6 +201,7 @@ private:
NodeIDHashTable fNodes;
NodeListenerHashTable fNodeListeners;
QueryList fQueries;
IndexHashTable fIndices;
JobList fJobQueue;