From 617ac41c601a395ce3065e44cc8355d792c33765 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 5 Jul 2011 22:58:58 +0200 Subject: [PATCH] Add Query class and query management in Volume --- .../kernel/file_systems/packagefs/Jamfile | 3 +- .../kernel/file_systems/packagefs/Query.cpp | 282 ++++++++++++++++++ .../kernel/file_systems/packagefs/Query.h | 60 ++++ .../kernel/file_systems/packagefs/Volume.cpp | 27 ++ .../kernel/file_systems/packagefs/Volume.h | 10 + 5 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/Query.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/Query.h diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index e361a074c8..5c7584a97e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -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 diff --git a/src/add-ons/kernel/file_systems/packagefs/Query.cpp b/src/add-ons/kernel/file_systems/packagefs/Query.cpp new file mode 100644 index 0000000000..0c9078944e --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/Query.cpp @@ -0,0 +1,282 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "Query.h" + +#include + +#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; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Query.h b/src/add-ons/kernel/file_systems/packagefs/Query.h new file mode 100644 index 0000000000..0cd7c93744 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/Query.h @@ -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 + +#include + + +struct dirent; + +namespace QueryParser { + template class Query; +}; + +class Node; +class Volume; + + +class Query : public DoublyLinkedListLinkImpl { +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 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 QueryList; + + +#endif // QUERY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index ccc99ee8ef..166ef61618 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -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) { diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h index 438b134ecf..8986913791 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h @@ -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;