ramfs: Rewrite Query system to use the common Query parser-evaluator.

The common version was also derived from BFS' original implementation,
but was genericized during packagefs development, and has more recent
fixes and additions.

Only lightly tested, but arbitrary-attribute-indexed queries seem to be
working just fine.
This commit is contained in:
Augustin Cavalier
2023-08-24 18:01:46 -04:00
parent 5b5b829f2c
commit b89f11999a
5 changed files with 252 additions and 1846 deletions
@@ -1,7 +1,7 @@
SubDir HAIKU_TOP src add-ons kernel file_systems ramfs ;
UsePrivateKernelHeaders ;
UsePrivateHeaders file_systems ;
UsePrivateHeaders file_systems storage ;
DEFINES += DEBUG_APP="\\\"ramfs\\\"" ;
@@ -13,7 +13,6 @@ KernelAddon ramfs
AttributeIndexImpl.cpp
AttributeIterator.cpp
DataContainer.cpp
DebugSupport.cpp
Directory.cpp
Entry.cpp
EntryIterator.cpp
@@ -31,7 +30,10 @@ KernelAddon ramfs
SizeIndex.cpp
SymLink.cpp
Volume.cpp
DebugSupport.cpp
QueryParserUtils.cpp
;
SEARCH on [ FGristFiles DebugSupport.cpp ]
SEARCH on [ FGristFiles DebugSupport.cpp QueryParserUtils.cpp ]
+= [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] ;
File diff suppressed because it is too large Load Diff
+29 -93
View File
@@ -15,115 +15,51 @@
#include <util/DoublyLinkedList.h>
#include "Index.h"
#include "Stack.h"
#include "ramfs.h"
class Entry;
class Equation;
class IndexIterator;
namespace QueryParser {
template<typename QueryPolicy> class Query;
};
class Node;
class Query;
class Term;
class Volume;
#define B_QUERY_NON_INDEXED 0x00000002
// Wraps the RAM FS Index to provide the interface required by the Query
// implementation. At least most of it.
//
// IndexWrapper
class IndexWrapper {
public:
IndexWrapper(Volume *volume);
status_t SetTo(const char *name);
void Unset();
uint32 Type() const;
off_t GetSize() const;
int32 KeySize() const;
private:
friend class IndexIterator;
Volume *fVolume;
Index *fIndex;
};
// IndexIterator
class IndexIterator {
public:
IndexIterator(IndexWrapper *indexWrapper);
status_t Find(const uint8 *const key, size_t keyLength);
status_t Rewind();
status_t GetNextEntry(uint8 *buffer, uint16 *keyLength, size_t bufferSize,
Entry **entry);
private:
IndexWrapper *fIndexWrapper;
IndexEntryIterator fIterator;
bool fInitialized;
};
class Expression {
public:
Expression(char *expr);
~Expression();
status_t InitCheck();
const char *Position() const { return fPosition; }
Term *Root() const { return fTerm; }
protected:
Term *ParseOr(char **expr);
Term *ParseAnd(char **expr);
Term *ParseEquation(char **expr);
bool IsOperator(char **expr,char op);
private:
Expression(const Expression &);
Expression &operator=(const Expression &);
// no implementation
char *fPosition;
Term *fTerm;
};
class Query : public DoublyLinkedListLinkImpl<Query> {
public:
Query(Volume *volume, Expression *expression, uint32 flags);
~Query();
public:
~Query();
status_t Rewind();
status_t GetNextEntry(struct dirent *, size_t size);
static status_t Create(Volume* volume, const char* queryString,
uint32 flags, port_id port, uint32 token,
Query*& _query);
void SetLiveMode(port_id port, int32 token);
void LiveUpdate(Entry *entry, Node* node, const char *attribute,
int32 type, const uint8 *oldKey, size_t oldLength,
const uint8 *newKey, size_t newLength);
status_t Rewind();
status_t GetNextEntry(struct dirent* entry, size_t size);
Expression *GetExpression() const { return fExpression; }
void LiveUpdate(Entry* entry, Node* node,
const char* attribute, int32 type,
const void* oldKey, size_t oldLength,
const void* newKey, size_t newLength);
private:
// void SendNotification(Entry* entry)
private:
struct QueryPolicy;
friend struct QueryPolicy;
typedef QueryParser::Query<QueryPolicy> QueryImpl;
private:
Volume *fVolume;
Expression *fExpression;
Equation *fCurrent;
IndexIterator *fIterator;
IndexWrapper fIndex;
Stack<Equation *> fStack;
private:
Query(Volume* volume);
uint32 fFlags;
port_id fPort;
int32 fToken;
bool fNeedsEntry;
status_t _Init(const char* queryString, uint32 flags,
port_id port, uint32 token);
private:
Volume* fVolume;
QueryImpl* fImpl;
};
#endif /* QUERY_H */
@@ -1,78 +0,0 @@
/* Stack - a template stack class (plus some handy methods)
*
* Copyright 2001-2005, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License.
*/
#ifndef KERNEL_UTIL_STACK_H
#define KERNEL_UTIL_STACK_H
#include <SupportDefs.h>
template<class T> class Stack {
public:
Stack()
:
fArray(NULL),
fUsed(0),
fMax(0)
{
}
~Stack()
{
free(fArray);
}
bool IsEmpty() const
{
return fUsed == 0;
}
void MakeEmpty()
{
// could also free the memory
fUsed = 0;
}
status_t Push(T value)
{
if (fUsed >= fMax) {
fMax += 16;
T *newArray = (T *)realloc(fArray, fMax * sizeof(T));
if (newArray == NULL)
return B_NO_MEMORY;
fArray = newArray;
}
fArray[fUsed++] = value;
return B_OK;
}
bool Pop(T *value)
{
if (fUsed == 0)
return false;
*value = fArray[--fUsed];
return true;
}
T *Array()
{
return fArray;
}
int32 CountItems() const
{
return fUsed;
}
private:
T *fArray;
int32 fUsed;
int32 fMax;
};
#endif /* KERNEL_UTIL_STACK_H */
@@ -2039,33 +2039,17 @@ ramfs_open_query(fs_volume* _volume, const char *queryString, uint32 flags,
Volume* volume = (Volume*)_volume->private_volume;
// lock the volume
VolumeReadLocker locker(volume);
VolumeWriteLocker locker(volume);
if (!locker.IsLocked())
RETURN_ERROR(B_ERROR);
// parse the query expression
Expression *expression = new Expression((char *)queryString);
if (expression == NULL)
RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<Expression> expressionDeleter(expression);
if (expression->InitCheck() < B_OK) {
WARN("Could not parse query, stopped at: \"%s\"\n",
expression->Position());
RETURN_ERROR(B_BAD_VALUE);
}
// create the query
Query *query = new Query(volume, expression, flags);
if (query == NULL)
RETURN_ERROR(B_NO_MEMORY);
expressionDeleter.Detach();
Query* query;
status_t error = Query::Create(volume, queryString, flags, port, token, query);
if (error != B_OK)
return error;
// TODO: The Query references an Index, but nothing prevents the Index
// from being deleted, while the Query is in existence.
if (flags & B_LIVE_QUERY)
query->SetLiveMode(port, token);
*_cookie = (void *)query;
return B_OK;
@@ -2090,14 +2074,12 @@ ramfs_free_query_cookie(fs_volume* _volume, void* _cookie)
Volume* volume = (Volume*)_volume->private_volume;
// lock the volume
VolumeReadLocker locker(volume);
VolumeWriteLocker locker(volume);
if (!locker.IsLocked())
RETURN_ERROR(B_ERROR);
Query *query = (Query *)_cookie;
Expression *expression = query->GetExpression();
delete query;
delete expression;
return B_OK;
}