* Missing locking initialization in Volume::Mount().
* Added missing locking in the query hooks. * Added live query support similarly as done in BFS: - Volume manages a doubly-linked list of live queries. - Volume::UpdateLiveQueries() invoked from several places where it makes sense (standard indices, Attribute::WriteAt(), and BVolume::NodeAttributeRemoved()) notifies the live Query objects. - Adjusted Query to be able to deal with hard links. Unfortunately Tracker is a bit broken with respect to hard links, particularly in the query windows. E.g. only one entry referring to a node is shown, and the renaming method RamFS uses (link new entry, then unlink old one) causes renamed entries to fall out of queries, even if they should still be in. (Want a bug report for this, Axel? :-P) git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20203 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
b0f302e45b
commit
0d427dec46
@ -52,19 +52,30 @@ status_t
|
||||
Attribute::WriteAt(off_t offset, const void *buffer, size_t size,
|
||||
size_t *bytesWritten)
|
||||
{
|
||||
status_t error = B_OK;
|
||||
if (offset < kMaxIndexKeyLength && size > 0 && fIndex) {
|
||||
// There is an index and a change will be made within the key.
|
||||
uint8 oldKey[kMaxIndexKeyLength];
|
||||
size_t oldLength;
|
||||
GetKey(oldKey, &oldLength);
|
||||
error = DataContainer::WriteAt(offset, buffer, size, bytesWritten);
|
||||
// get the current key for the attribute
|
||||
uint8 oldKey[kMaxIndexKeyLength];
|
||||
size_t oldLength;
|
||||
GetKey(oldKey, &oldLength);
|
||||
|
||||
// write the new value
|
||||
status_t error = DataContainer::WriteAt(offset, buffer, size, bytesWritten);
|
||||
|
||||
// If there is an index and a change has been made within the key, notify
|
||||
// the index.
|
||||
if (offset < kMaxIndexKeyLength && size > 0 && fIndex)
|
||||
fIndex->Changed(this, oldKey, oldLength);
|
||||
} else
|
||||
error = DataContainer::WriteAt(offset, buffer, size, bytesWritten);
|
||||
|
||||
// update live queries
|
||||
const uint8* newKey;
|
||||
size_t newLength;
|
||||
GetKey(&newKey, &newLength);
|
||||
GetVolume()->UpdateLiveQueries(NULL, fNode, GetName(), fType, oldKey,
|
||||
oldLength, newKey, newLength);
|
||||
|
||||
// node has been changed
|
||||
if (fNode)
|
||||
if (fNode && size > 0)
|
||||
fNode->MarkModified();
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -156,17 +156,17 @@ Directory::CreateEntry(Node *node, const char *name, Entry **_entry)
|
||||
if (entry) {
|
||||
error = entry->InitCheck();
|
||||
if (error == B_OK) {
|
||||
// add the entry
|
||||
error = AddEntry(entry);
|
||||
// link to the node
|
||||
error = entry->Link(node);
|
||||
if (error == B_OK) {
|
||||
// link to the node
|
||||
error = entry->Link(node);
|
||||
// add the entry
|
||||
error = AddEntry(entry);
|
||||
if (error == B_OK) {
|
||||
if (_entry)
|
||||
*_entry = entry;
|
||||
} else {
|
||||
// failure: remove the entry
|
||||
RemoveEntry(entry);
|
||||
// failure: unlink the node
|
||||
entry->Unlink();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,9 +157,15 @@ LastModifiedIndex::Changed(Node *node, time_t oldModified)
|
||||
if (iterator->GetCurrentNode() == node)
|
||||
iterator->NodeRemoved(node);
|
||||
}
|
||||
// remove the node
|
||||
// remove and re-insert the node
|
||||
fNodes->Remove(it);
|
||||
error = fNodes->Insert(node);
|
||||
|
||||
// udpate live queries
|
||||
time_t newModified = node->GetMTime();
|
||||
fVolume->UpdateLiveQueries(NULL, node, GetName(), GetType(),
|
||||
(const uint8*)&oldModified, sizeof(oldModified),
|
||||
(const uint8*)&newModified, sizeof(newModified));
|
||||
}
|
||||
}
|
||||
return error;
|
||||
|
@ -139,6 +139,9 @@ NameIndex::Changed(Entry *entry, const char *oldName)
|
||||
if (foundEntry && *foundEntry == entry) {
|
||||
fEntries->Remove(it);
|
||||
error = fEntries->Insert(entry);
|
||||
|
||||
// udpate live queries
|
||||
_UpdateLiveQueries(entry, oldName, entry->GetName());
|
||||
}
|
||||
}
|
||||
return error;
|
||||
@ -148,16 +151,24 @@ NameIndex::Changed(Entry *entry, const char *oldName)
|
||||
void
|
||||
NameIndex::EntryAdded(Entry *entry)
|
||||
{
|
||||
if (entry)
|
||||
if (entry) {
|
||||
fEntries->Insert(entry);
|
||||
|
||||
// udpate live queries
|
||||
_UpdateLiveQueries(entry, NULL, entry->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
// EntryRemoved
|
||||
void
|
||||
NameIndex::EntryRemoved(Entry *entry)
|
||||
{
|
||||
if (entry)
|
||||
if (entry) {
|
||||
fEntries->Remove(entry, entry);
|
||||
|
||||
// udpate live queries
|
||||
_UpdateLiveQueries(entry, entry->GetName(), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// InternalGetIterator
|
||||
@ -190,6 +201,16 @@ NameIndex::InternalFind(const uint8 *key, size_t length)
|
||||
return iterator;
|
||||
}
|
||||
|
||||
// _UpdateLiveQueries
|
||||
void
|
||||
NameIndex::_UpdateLiveQueries(Entry* entry, const char* oldName,
|
||||
const char* newName)
|
||||
{
|
||||
fVolume->UpdateLiveQueries(entry, entry->GetNode(), GetName(),
|
||||
GetType(), (const uint8*)oldName, (oldName ? strlen(oldName) : 0),
|
||||
(const uint8*)newName, (newName ? strlen(newName) : 0));
|
||||
}
|
||||
|
||||
|
||||
// NameIndexEntryIterator
|
||||
|
||||
|
@ -32,6 +32,9 @@ private:
|
||||
class EntryTree;
|
||||
friend class NameIndexEntryIterator;
|
||||
|
||||
void _UpdateLiveQueries(Entry* entry, const char* oldName,
|
||||
const char* newName);
|
||||
|
||||
private:
|
||||
EntryTree *fEntries;
|
||||
};
|
||||
|
@ -128,8 +128,6 @@ IndexIterator::GetNextEntry(uint8 *buffer, uint16 *_keyLength,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// compare_integral
|
||||
template<typename Key>
|
||||
static inline
|
||||
@ -258,8 +256,9 @@ class Term {
|
||||
void SetParent(Term *parent) { fParent = parent; }
|
||||
Term *Parent() const { return fParent; }
|
||||
|
||||
virtual status_t Match(Entry *entry,const char *attribute = NULL,int32 type = 0,
|
||||
const uint8 *key = NULL,size_t size = 0) = 0;
|
||||
virtual status_t Match(Entry *entry, Node* node,
|
||||
const char *attribute = NULL, int32 type = 0,
|
||||
const uint8 *key = NULL, size_t size = 0) = 0;
|
||||
virtual void Complement() = 0;
|
||||
|
||||
virtual void CalculateScore(IndexWrapper &index) = 0;
|
||||
@ -267,6 +266,8 @@ class Term {
|
||||
|
||||
virtual status_t InitCheck() = 0;
|
||||
|
||||
virtual bool NeedsEntry() = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void PrintToStream() = 0;
|
||||
#endif
|
||||
@ -295,8 +296,9 @@ class Equation : public Term {
|
||||
status_t ParseQuotedString(char **_start, char **_end);
|
||||
char *CopyString(char *start, char *end);
|
||||
|
||||
virtual status_t Match(Entry *entry, const char *attribute = NULL, int32 type = 0,
|
||||
const uint8 *key = NULL, size_t size = 0);
|
||||
virtual status_t Match(Entry *entry, Node* node,
|
||||
const char *attribute = NULL, int32 type = 0,
|
||||
const uint8 *key = NULL, size_t size = 0);
|
||||
virtual void Complement();
|
||||
|
||||
status_t PrepareQuery(Volume *volume, IndexWrapper &index, IndexIterator **iterator,
|
||||
@ -307,6 +309,8 @@ class Equation : public Term {
|
||||
virtual void CalculateScore(IndexWrapper &index);
|
||||
virtual int32 Score() const { return fScore; }
|
||||
|
||||
virtual bool NeedsEntry();
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void PrintToStream();
|
||||
#endif
|
||||
@ -340,7 +344,8 @@ class Operator : public Term {
|
||||
Term *Left() const { return fLeft; }
|
||||
Term *Right() const { return fRight; }
|
||||
|
||||
virtual status_t Match(Entry *entry, const char *attribute = NULL, int32 type = 0,
|
||||
virtual status_t Match(Entry *entry, Node* node,
|
||||
const char *attribute = NULL, int32 type = 0,
|
||||
const uint8 *key = NULL, size_t size = 0);
|
||||
virtual void Complement();
|
||||
|
||||
@ -349,6 +354,8 @@ class Operator : public Term {
|
||||
|
||||
virtual status_t InitCheck();
|
||||
|
||||
virtual bool NeedsEntry();
|
||||
|
||||
//Term *Copy() const;
|
||||
#ifdef DEBUG
|
||||
virtual void PrintToStream();
|
||||
@ -940,7 +947,8 @@ Equation::MatchEmptyString()
|
||||
*/
|
||||
|
||||
status_t
|
||||
Equation::Match(Entry *entry, const char *attributeName, int32 type, const uint8 *key, size_t size)
|
||||
Equation::Match(Entry *entry, Node* node, const char *attributeName, int32 type,
|
||||
const uint8 *key, size_t size)
|
||||
{
|
||||
// get a pointer to the attribute in question
|
||||
union value value;
|
||||
@ -949,14 +957,23 @@ Equation::Match(Entry *entry, const char *attributeName, int32 type, const uint8
|
||||
// first, check if we are matching for a live query and use that value
|
||||
if (attributeName != NULL && !strcmp(fAttribute, attributeName)) {
|
||||
if (key == NULL) {
|
||||
if (type == B_STRING_TYPE)
|
||||
if (type == B_STRING_TYPE) {
|
||||
// special case: a NULL "name" means the entry has been removed
|
||||
// or not yet been added -- we refuse to match, whatever the
|
||||
// pattern
|
||||
if (!strcmp(fAttribute, "name"))
|
||||
return NO_MATCH;
|
||||
|
||||
return MatchEmptyString();
|
||||
}
|
||||
|
||||
return NO_MATCH;
|
||||
}
|
||||
buffer = const_cast<uint8 *>(key);
|
||||
} else if (!strcmp(fAttribute, "name")) {
|
||||
// if not, check for "fake" attributes, "name", "size", "last_modified",
|
||||
if (!entry)
|
||||
return B_ERROR;
|
||||
buffer = (uint8 *)entry->GetName();
|
||||
if (buffer == NULL)
|
||||
return B_ERROR;
|
||||
@ -964,18 +981,18 @@ Equation::Match(Entry *entry, const char *attributeName, int32 type, const uint8
|
||||
type = B_STRING_TYPE;
|
||||
size = strlen((const char *)buffer);
|
||||
} else if (!strcmp(fAttribute,"size")) {
|
||||
value.Int64 = entry->GetNode()->GetSize();
|
||||
value.Int64 = node->GetSize();
|
||||
buffer = (uint8 *)&value;
|
||||
type = B_INT64_TYPE;
|
||||
} else if (!strcmp(fAttribute,"last_modified")) {
|
||||
value.Int32 = entry->GetNode()->GetMTime();
|
||||
value.Int32 = node->GetMTime();
|
||||
buffer = (uint8 *)&value;
|
||||
type = B_INT32_TYPE;
|
||||
} else {
|
||||
// then for attributes
|
||||
Attribute *attribute = NULL;
|
||||
|
||||
if (entry->GetNode()->FindAttribute(fAttribute, &attribute) == B_OK) {
|
||||
if (node->FindAttribute(fAttribute, &attribute) == B_OK) {
|
||||
attribute->GetKey(&buffer, &size);
|
||||
type = attribute->GetType();
|
||||
} else
|
||||
@ -1151,7 +1168,7 @@ Equation::GetNextMatching(Volume *volume, IndexIterator *iterator,
|
||||
status = MATCH_OK;
|
||||
|
||||
if (!fHasIndex)
|
||||
status = Match(entry);
|
||||
status = Match(entry, entry->GetNode());
|
||||
|
||||
while (term != NULL && status == MATCH_OK) {
|
||||
Operator *parent = (Operator *)term->Parent();
|
||||
@ -1168,7 +1185,7 @@ Equation::GetNextMatching(Volume *volume, IndexIterator *iterator,
|
||||
FATAL(("&&-operator has only one child... (parent = %p)\n", parent));
|
||||
break;
|
||||
}
|
||||
status = other->Match(entry);
|
||||
status = other->Match(entry, entry->GetNode());
|
||||
if (status < 0) {
|
||||
REPORT_ERROR(status);
|
||||
status = NO_MATCH;
|
||||
@ -1196,6 +1213,13 @@ Equation::GetNextMatching(Volume *volume, IndexIterator *iterator,
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Equation::NeedsEntry()
|
||||
{
|
||||
return strcmp(fAttribute, "name") == 0;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
@ -1219,22 +1243,24 @@ Operator::~Operator()
|
||||
|
||||
|
||||
status_t
|
||||
Operator::Match(Entry *entry, const char *attribute, int32 type, const uint8 *key, size_t size)
|
||||
Operator::Match(Entry *entry, Node* node, const char *attribute,
|
||||
int32 type, const uint8 *key, size_t size)
|
||||
{
|
||||
if (fOp == OP_AND) {
|
||||
status_t status = fLeft->Match(entry, attribute, type, key, size);
|
||||
status_t status = fLeft->Match(entry, node, attribute, type, key, size);
|
||||
if (status != MATCH_OK)
|
||||
return status;
|
||||
|
||||
return fRight->Match(entry, attribute, type, key, size);
|
||||
return fRight->Match(entry, node, attribute, type, key, size);
|
||||
} else {
|
||||
// choose the term with the better score for OP_OR
|
||||
if (fRight->Score() > fLeft->Score()) {
|
||||
status_t status = fRight->Match(entry, attribute, type, key, size);
|
||||
status_t status = fRight->Match(entry, node, attribute, type, key,
|
||||
size);
|
||||
if (status != NO_MATCH)
|
||||
return status;
|
||||
}
|
||||
return fLeft->Match(entry, attribute, type, key, size);
|
||||
return fLeft->Match(entry, node, attribute, type, key, size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1291,6 +1317,13 @@ Operator::InitCheck()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Operator::NeedsEntry()
|
||||
{
|
||||
return ((fLeft && fLeft->NeedsEntry()) || (fRight && fRight->NeedsEntry()));
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
Term *
|
||||
Operator::Copy() const
|
||||
@ -1529,7 +1562,8 @@ Query::Query(Volume *volume, Expression *expression, uint32 flags)
|
||||
fIterator(NULL),
|
||||
fIndex(volume),
|
||||
fFlags(flags),
|
||||
fPort(-1)
|
||||
fPort(-1),
|
||||
fNeedsEntry(false)
|
||||
{
|
||||
// if the expression has a valid root pointer, the whole tree has
|
||||
// already passed the sanity check, so that we don't have to check
|
||||
@ -1541,6 +1575,8 @@ Query::Query(Volume *volume, Expression *expression, uint32 flags)
|
||||
fExpression->Root()->CalculateScore(fIndex);
|
||||
fIndex.Unset();
|
||||
|
||||
fNeedsEntry = fExpression->Root()->NeedsEntry();
|
||||
|
||||
Rewind();
|
||||
|
||||
if (fFlags & B_LIVE_QUERY)
|
||||
@ -1639,16 +1675,35 @@ Query::SetLiveMode(port_id port, int32 token)
|
||||
|
||||
|
||||
void
|
||||
Query::LiveUpdate(Entry *entry, const char *attribute, int32 type, const uint8 *oldKey,
|
||||
size_t oldLength, const uint8 *newKey, size_t newLength)
|
||||
Query::LiveUpdate(Entry *entry, Node* node, const char *attribute, int32 type,
|
||||
const uint8 *oldKey, size_t oldLength, const uint8 *newKey,
|
||||
size_t newLength)
|
||||
{
|
||||
if (fPort < 0 || fExpression == NULL || attribute == NULL)
|
||||
PRINT(("%p->Query::LiveUpdate(%p, %p, \"%s\", 0x%lx, %p, %lu, %p, %lu)\n",
|
||||
this, entry, node, attribute, type, oldKey, oldLength, newKey, newLength));
|
||||
if (fPort < 0 || fExpression == NULL || node == NULL || attribute == NULL)
|
||||
return;
|
||||
|
||||
// ToDo: check if the attribute is part of the query at all...
|
||||
|
||||
status_t oldStatus = fExpression->Root()->Match(entry, attribute, type, oldKey, oldLength);
|
||||
status_t newStatus = fExpression->Root()->Match(entry, attribute, type, newKey, newLength);
|
||||
// If no entry has been supplied, but the we need one for the evaluation
|
||||
// (i.e. the "name" attribute is used), we invoke ourselves for all entries
|
||||
// referring to the given node.
|
||||
if (!entry && fNeedsEntry) {
|
||||
entry = node->GetFirstReferrer();
|
||||
while (entry) {
|
||||
LiveUpdate(entry, node, attribute, type, oldKey, oldLength, newKey,
|
||||
newLength);
|
||||
entry = node->GetNextReferrer(entry);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
status_t oldStatus = fExpression->Root()->Match(entry, node, attribute,
|
||||
type, oldKey, oldLength);
|
||||
status_t newStatus = fExpression->Root()->Match(entry, node, attribute,
|
||||
type, newKey, newLength);
|
||||
PRINT((" oldStatus: 0x%lx, newStatus: 0x%lx\n", oldStatus, newStatus));
|
||||
|
||||
int32 op;
|
||||
if (oldStatus == MATCH_OK && newStatus == MATCH_OK) {
|
||||
@ -1656,8 +1711,14 @@ Query::LiveUpdate(Entry *entry, const char *attribute, int32 type, const uint8 *
|
||||
if (oldKey == NULL || strcmp(attribute,"name"))
|
||||
return;
|
||||
|
||||
send_notification(fPort, fToken, B_QUERY_UPDATE, B_ENTRY_REMOVED, fVolume->GetID(), 0,
|
||||
entry->GetParent()->GetID(), 0, entry->GetNode()->GetID(), (const char *)oldKey);
|
||||
if (entry) {
|
||||
// entry should actually always be given, when the changed
|
||||
// attribute is the entry name
|
||||
PRINT(("send_notification(): old: B_ENTRY_REMOVED\n"));
|
||||
send_notification(fPort, fToken, B_QUERY_UPDATE, B_ENTRY_REMOVED,
|
||||
fVolume->GetID(), 0, entry->GetParent()->GetID(), 0,
|
||||
entry->GetNode()->GetID(), (const char *)oldKey);
|
||||
}
|
||||
op = B_ENTRY_CREATED;
|
||||
} else if (oldStatus != MATCH_OK && newStatus != MATCH_OK) {
|
||||
// nothing has changed
|
||||
@ -1667,12 +1728,21 @@ Query::LiveUpdate(Entry *entry, const char *attribute, int32 type, const uint8 *
|
||||
else
|
||||
op = B_ENTRY_CREATED;
|
||||
|
||||
// if "value" is NULL, send_notification() crashes...
|
||||
const char *value = (const char *)newKey;
|
||||
if (type != B_STRING_TYPE || value == NULL)
|
||||
value = "";
|
||||
|
||||
send_notification(fPort, fToken, B_QUERY_UPDATE, op, fVolume->GetID(), 0,
|
||||
entry->GetParent()->GetID(), 0, entry->GetNode()->GetID(), value);
|
||||
// We send a notification for the given entry, if any, or otherwise for
|
||||
// all entries referring to the node;
|
||||
if (entry) {
|
||||
PRINT(("send_notification(): new: %s\n", (op == B_ENTRY_REMOVED ? "B_ENTRY_REMOVED" : "B_ENTRY_CREATED")));
|
||||
send_notification(fPort, fToken, B_QUERY_UPDATE, op, fVolume->GetID(),
|
||||
0, entry->GetParent()->GetID(), 0, entry->GetNode()->GetID(),
|
||||
entry->GetName());
|
||||
} else {
|
||||
entry = node->GetFirstReferrer();
|
||||
while (entry) {
|
||||
send_notification(fPort, fToken, B_QUERY_UPDATE, op,
|
||||
fVolume->GetID(), 0, entry->GetParent()->GetID(), 0,
|
||||
entry->GetNode()->GetID(), entry->GetName());
|
||||
entry = node->GetNextReferrer(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <OS.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "DLList.h"
|
||||
#include "Index.h"
|
||||
#include "Stack.h"
|
||||
#include "ramfs.h"
|
||||
@ -19,6 +20,7 @@
|
||||
class Entry;
|
||||
class Equation;
|
||||
class IndexIterator;
|
||||
class Node;
|
||||
class Query;
|
||||
class Term;
|
||||
class Volume;
|
||||
@ -90,7 +92,7 @@ class Expression {
|
||||
Term *fTerm;
|
||||
};
|
||||
|
||||
class Query {
|
||||
class Query : public DLListLinkImpl<Query> {
|
||||
public:
|
||||
Query(Volume *volume, Expression *expression, uint32 flags);
|
||||
~Query();
|
||||
@ -99,11 +101,15 @@ class Query {
|
||||
status_t GetNextEntry(struct dirent *, size_t size);
|
||||
|
||||
void SetLiveMode(port_id port, int32 token);
|
||||
void LiveUpdate(Entry *entry, const char *attribute, int32 type,
|
||||
const uint8 *oldKey, size_t oldLength, const uint8 *newKey, size_t newLength);
|
||||
void LiveUpdate(Entry *entry, Node* node, const char *attribute,
|
||||
int32 type, const uint8 *oldKey, size_t oldLength,
|
||||
const uint8 *newKey, size_t newLength);
|
||||
|
||||
Expression *GetExpression() const { return fExpression; }
|
||||
|
||||
private:
|
||||
// void SendNotification(Entry* entry)
|
||||
|
||||
private:
|
||||
Volume *fVolume;
|
||||
Expression *fExpression;
|
||||
@ -115,6 +121,7 @@ class Query {
|
||||
uint32 fFlags;
|
||||
port_id fPort;
|
||||
int32 fToken;
|
||||
bool fNeedsEntry;
|
||||
};
|
||||
|
||||
#endif /* QUERY_H */
|
||||
|
@ -155,9 +155,16 @@ SizeIndex::Changed(Node *node, off_t oldSize)
|
||||
if (iterator->GetCurrentNode() == node)
|
||||
iterator->NodeRemoved(node);
|
||||
}
|
||||
// remove the node
|
||||
|
||||
// remove and re-insert the node
|
||||
fNodes->Remove(it);
|
||||
error = fNodes->Insert(node);
|
||||
|
||||
// udpate live queries
|
||||
off_t newSize = node->GetSize();
|
||||
fVolume->UpdateLiveQueries(NULL, node, GetName(), GetType(),
|
||||
(const uint8*)&oldSize, sizeof(oldSize), (const uint8*)&newSize,
|
||||
sizeof(newSize));
|
||||
}
|
||||
}
|
||||
return error;
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "Entry.h"
|
||||
#include "EntryListener.h"
|
||||
#include "IndexDirectory.h"
|
||||
#include "Locking.h"
|
||||
#include "Misc.h"
|
||||
#include "NameIndex.h"
|
||||
#include "Node.h"
|
||||
@ -140,8 +141,9 @@ Volume::Volume()
|
||||
fIndexDirectory(NULL),
|
||||
fRootDirectory(NULL),
|
||||
fName(kDefaultVolumeName),
|
||||
fLocker(),
|
||||
fIteratorLocker(),
|
||||
fLocker("volume"),
|
||||
fIteratorLocker("iterators"),
|
||||
fQueryLocker("queries"),
|
||||
fNodeListeners(NULL),
|
||||
fAnyNodeListeners(),
|
||||
fEntryListeners(NULL),
|
||||
@ -165,6 +167,15 @@ status_t
|
||||
Volume::Mount(nspace_id id)
|
||||
{
|
||||
Unmount();
|
||||
|
||||
// check the locker's semaphores
|
||||
if (fLocker.Sem() < 0)
|
||||
return fLocker.Sem();
|
||||
if (fIteratorLocker.Sem() < 0)
|
||||
return fIteratorLocker.Sem();
|
||||
if (fQueryLocker.Sem() < 0)
|
||||
return fQueryLocker.Sem();
|
||||
|
||||
status_t error = B_OK;
|
||||
fID = id;
|
||||
// create a block allocator
|
||||
@ -659,6 +670,15 @@ Volume::NodeAttributeRemoved(vnode_id id, Attribute *attribute)
|
||||
index->Removed(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
// update live queries
|
||||
if (error == B_OK && attribute->GetNode()) {
|
||||
const uint8* oldKey;
|
||||
size_t oldLength;
|
||||
attribute->GetKey(&oldKey, &oldLength);
|
||||
UpdateLiveQueries(NULL, attribute->GetNode(), attribute->GetName(),
|
||||
attribute->GetType(), oldKey, oldLength, NULL, 0);
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
@ -712,6 +732,42 @@ Volume::FindAttributeIndex(const char *name, uint32 type)
|
||||
? fIndexDirectory->FindAttributeIndex(name, type) : NULL);
|
||||
}
|
||||
|
||||
// AddQuery
|
||||
void
|
||||
Volume::AddQuery(Query *query)
|
||||
{
|
||||
AutoLocker<Locker> _(fQueryLocker);
|
||||
|
||||
if (query)
|
||||
fQueries.Insert(query);
|
||||
}
|
||||
|
||||
// RemoveQuery
|
||||
void
|
||||
Volume::RemoveQuery(Query *query)
|
||||
{
|
||||
AutoLocker<Locker> _(fQueryLocker);
|
||||
|
||||
if (query)
|
||||
fQueries.Remove(query);
|
||||
}
|
||||
|
||||
// UpdateLiveQueries
|
||||
void
|
||||
Volume::UpdateLiveQueries(Entry *entry, Node* node, const char *attribute,
|
||||
int32 type, const uint8 *oldKey, size_t oldLength, const uint8 *newKey,
|
||||
size_t newLength)
|
||||
{
|
||||
AutoLocker<Locker> _(fQueryLocker);
|
||||
|
||||
for (Query* query = fQueries.GetFirst();
|
||||
query;
|
||||
query = fQueries.GetNext(query)) {
|
||||
query->LiveUpdate(entry, node, attribute, type, oldKey, oldLength,
|
||||
newKey, newLength);
|
||||
}
|
||||
}
|
||||
|
||||
// AllocateBlock
|
||||
status_t
|
||||
Volume::AllocateBlock(size_t size, BlockReference **block)
|
||||
|
@ -22,12 +22,14 @@
|
||||
#ifndef VOLUME_H
|
||||
#define VOLUME_H
|
||||
|
||||
#include <fsproto.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "DLList.h"
|
||||
#include "Entry.h"
|
||||
#include "fsproto.h"
|
||||
#include "List.h"
|
||||
#include "Locker.h"
|
||||
#include "Query.h"
|
||||
#include "String.h"
|
||||
|
||||
class AllocationInfo;
|
||||
@ -48,7 +50,6 @@ class NodeAttributeTable;
|
||||
class NodeListener;
|
||||
class NodeListenerTree;
|
||||
class NodeTable;
|
||||
class Query;
|
||||
class SizeIndex;
|
||||
|
||||
const vnode_id kRootParentID = 0;
|
||||
@ -146,11 +147,11 @@ public:
|
||||
AttributeIndex *FindAttributeIndex(const char *name, uint32 type);
|
||||
|
||||
// queries
|
||||
// TODO: Implement.
|
||||
// status_t AddQuery(Query */*query*/) { return B_ERROR; }
|
||||
// status_t RemoveQuery(Query */*query*/) { return B_ERROR; }
|
||||
status_t AddQuery(Query */*query*/) { return B_OK; }
|
||||
status_t RemoveQuery(Query */*query*/) { return B_OK; }
|
||||
void AddQuery(Query *query);
|
||||
void RemoveQuery(Query *query);
|
||||
void UpdateLiveQueries(Entry *entry, Node* node, const char *attribute,
|
||||
int32 type, const uint8 *oldKey, size_t oldLength,
|
||||
const uint8 *newKey, size_t newLength);
|
||||
|
||||
vnode_id NextNodeID() { return fNextNodeID++; }
|
||||
|
||||
@ -173,6 +174,8 @@ public:
|
||||
void IteratorUnlock();
|
||||
|
||||
private:
|
||||
typedef DLList<Query> QueryList;
|
||||
|
||||
nspace_id fID;
|
||||
vnode_id fNextNodeID;
|
||||
NodeTable *fNodeTable;
|
||||
@ -183,10 +186,12 @@ private:
|
||||
String fName;
|
||||
Locker fLocker;
|
||||
Locker fIteratorLocker;
|
||||
Locker fQueryLocker;
|
||||
NodeListenerTree *fNodeListeners;
|
||||
NodeListenerList fAnyNodeListeners;
|
||||
EntryListenerTree *fEntryListeners;
|
||||
EntryListenerList fAnyEntryListeners;
|
||||
QueryList fQueries;
|
||||
BlockAllocator *fBlockAllocator;
|
||||
off_t fBlockSize;
|
||||
off_t fAllocatedBlocks;
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "AllocationInfo.h"
|
||||
#include "AttributeIndex.h"
|
||||
#include "AttributeIterator.h"
|
||||
#include "AutoDeleter.h"
|
||||
#include "Debug.h"
|
||||
#include "Directory.h"
|
||||
#include "Entry.h"
|
||||
@ -249,6 +250,10 @@ notify_if_stat_changed(Volume *volume, Node *node)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - FS
|
||||
|
||||
|
||||
// ramfs_mount
|
||||
static
|
||||
int
|
||||
@ -323,6 +328,10 @@ ramfs_sync(void */*_ns*/)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - VNodes
|
||||
|
||||
|
||||
// ramfs_read_vnode
|
||||
static
|
||||
int
|
||||
@ -375,6 +384,10 @@ FUNCTION(("node: %Ld\n", ((Node*)_node)->GetID()));
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Nodes
|
||||
|
||||
|
||||
// ramfs_walk
|
||||
static
|
||||
int
|
||||
@ -562,6 +575,10 @@ ramfs_write_stat(void *ns, void *_node, struct stat *st, long mask)
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Files
|
||||
|
||||
|
||||
// FileCookie
|
||||
class FileCookie {
|
||||
public:
|
||||
@ -841,6 +858,11 @@ ramfs_access(void *ns, void *_node, int mode)
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #pragma mark - Directories
|
||||
|
||||
|
||||
// ramfs_rename
|
||||
static
|
||||
int
|
||||
@ -1330,7 +1352,11 @@ ramfs_free_dir_cookie(void */*ns*/, void */*_node*/, void *_cookie)
|
||||
delete cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #pragma mark - FS Stats
|
||||
|
||||
|
||||
// ramfs_read_fs_stat
|
||||
static
|
||||
int
|
||||
@ -1354,6 +1380,7 @@ ramfs_read_fs_stat(void *ns, struct fs_info *info)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// ramfs_write_fs_stat
|
||||
static
|
||||
int
|
||||
@ -1370,6 +1397,10 @@ ramfs_write_fs_stat(void *ns, struct fs_info *info, long mask)
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Symlinks
|
||||
|
||||
|
||||
// ramfs_symlink
|
||||
static
|
||||
int
|
||||
@ -1455,6 +1486,10 @@ ramfs_read_link(void *ns, void *_node, char *buffer, size_t *bufferSize)
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Attributes
|
||||
|
||||
|
||||
// ramfs_open_attrdir
|
||||
static
|
||||
int
|
||||
@ -1703,6 +1738,10 @@ ramfs_stat_attr(void *ns, void *_node, const char *name,
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Indices
|
||||
|
||||
|
||||
// IndexDirCookie
|
||||
class IndexDirCookie {
|
||||
public:
|
||||
@ -1905,9 +1944,9 @@ ramfs_stat_index(void *ns, const char *name, struct index_info *indexInfo)
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Queries
|
||||
|
||||
// Query implementation by Axel Dörfler. Slightly adjusted.
|
||||
//
|
||||
// TODO: Locking!
|
||||
|
||||
// ramfs_open_query
|
||||
int
|
||||
@ -1922,21 +1961,30 @@ ramfs_open_query(void *ns, const char *queryString, ulong flags, port_id port,
|
||||
|
||||
Volume *volume = (Volume *)ns;
|
||||
|
||||
// lock the volume
|
||||
VolumeReadLocker 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) {
|
||||
FATAL(("Could not parse query, stopped at: \"%s\"\n", expression->Position()));
|
||||
delete expression;
|
||||
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) {
|
||||
delete expression;
|
||||
if (query == NULL)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
}
|
||||
expressionDeleter.Detach();
|
||||
// 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);
|
||||
@ -1956,12 +2004,19 @@ ramfs_close_query(void */*ns*/, void */*cookie*/)
|
||||
|
||||
// ramfs_free_query_cookie
|
||||
int
|
||||
ramfs_free_query_cookie(void */*ns*/, void */*node*/, void *cookie)
|
||||
ramfs_free_query_cookie(void *ns, void */*node*/, void *cookie)
|
||||
{
|
||||
FUNCTION_START();
|
||||
if (cookie == NULL)
|
||||
if (ns == NULL || cookie == NULL)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
Volume *volume = (Volume *)ns;
|
||||
|
||||
// lock the volume
|
||||
VolumeReadLocker locker(volume);
|
||||
if (!locker.IsLocked())
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
Query *query = (Query *)cookie;
|
||||
Expression *expression = query->GetExpression();
|
||||
delete query;
|
||||
@ -1972,14 +2027,21 @@ ramfs_free_query_cookie(void */*ns*/, void */*node*/, void *cookie)
|
||||
|
||||
// ramfs_read_query
|
||||
int
|
||||
ramfs_read_query(void */*ns*/, void *cookie, long *count,
|
||||
ramfs_read_query(void *ns, void *cookie, long *count,
|
||||
struct dirent *buffer, size_t bufferSize)
|
||||
{
|
||||
FUNCTION_START();
|
||||
Query *query = (Query *)cookie;
|
||||
if (query == NULL)
|
||||
if (ns == NULL || query == NULL)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
Volume *volume = (Volume *)ns;
|
||||
|
||||
// lock the volume
|
||||
VolumeReadLocker locker(volume);
|
||||
if (!locker.IsLocked())
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
status_t status = query->GetNextEntry(buffer, bufferSize);
|
||||
if (status == B_OK)
|
||||
*count = 1;
|
||||
|
Loading…
Reference in New Issue
Block a user