Add Query class and query management in Volume
This commit is contained in:
@@ -3,7 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel file_systems packagefs ;
|
|||||||
|
|
||||||
UseLibraryHeaders zlib ;
|
UseLibraryHeaders zlib ;
|
||||||
UsePrivateKernelHeaders ;
|
UsePrivateKernelHeaders ;
|
||||||
UsePrivateHeaders shared ;
|
UsePrivateHeaders shared storage ;
|
||||||
|
|
||||||
|
|
||||||
HAIKU_PACKAGE_FS_SOURCES =
|
HAIKU_PACKAGE_FS_SOURCES =
|
||||||
@@ -21,6 +21,7 @@ HAIKU_PACKAGE_FS_SOURCES =
|
|||||||
NameIndex.cpp
|
NameIndex.cpp
|
||||||
Node.cpp
|
Node.cpp
|
||||||
NodeListener.cpp
|
NodeListener.cpp
|
||||||
|
Query.cpp
|
||||||
Package.cpp
|
Package.cpp
|
||||||
PackageDirectory.cpp
|
PackageDirectory.cpp
|
||||||
PackageDomain.cpp
|
PackageDomain.cpp
|
||||||
|
|||||||
@@ -0,0 +1,282 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Ingo Weinhold, [email protected].
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Ingo Weinhold, [email protected].
|
||||||
|
* 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
|
||||||
@@ -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
|
status_t
|
||||||
Volume::GetVNode(ino_t nodeID, Node*& _node)
|
Volume::GetVNode(ino_t nodeID, Node*& _node)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "NodeListener.h"
|
#include "NodeListener.h"
|
||||||
#include "PackageDomain.h"
|
#include "PackageDomain.h"
|
||||||
#include "PackageLinksListener.h"
|
#include "PackageLinksListener.h"
|
||||||
|
#include "Query.h"
|
||||||
|
|
||||||
|
|
||||||
class Directory;
|
class Directory;
|
||||||
@@ -72,6 +73,14 @@ public:
|
|||||||
Node* node);
|
Node* node);
|
||||||
void RemoveNodeListener(NodeListener* listener);
|
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
|
Index* FindIndex(const char* name) const
|
||||||
{ return fIndices.Lookup(name); }
|
{ return fIndices.Lookup(name); }
|
||||||
|
|
||||||
@@ -192,6 +201,7 @@ private:
|
|||||||
|
|
||||||
NodeIDHashTable fNodes;
|
NodeIDHashTable fNodes;
|
||||||
NodeListenerHashTable fNodeListeners;
|
NodeListenerHashTable fNodeListeners;
|
||||||
|
QueryList fQueries;
|
||||||
IndexHashTable fIndices;
|
IndexHashTable fIndices;
|
||||||
|
|
||||||
JobList fJobQueue;
|
JobList fJobQueue;
|
||||||
|
|||||||
Reference in New Issue
Block a user