Add Query class and query management in Volume
This commit is contained in:
parent
331b89b3a5
commit
617ac41c60
@ -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
|
||||
|
282
src/add-ons/kernel/file_systems/packagefs/Query.cpp
Normal file
282
src/add-ons/kernel/file_systems/packagefs/Query.cpp
Normal 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;
|
||||
}
|
60
src/add-ons/kernel/file_systems/packagefs/Query.h
Normal file
60
src/add-ons/kernel/file_systems/packagefs/Query.h
Normal 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
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user