#include <new>
#include <fsproto.h>
#include <AutoLocker.h>
#include <HashMap.h>
#include "DebugSupport.h"
#include "Locker.h"
#include "QueryManager.h"
#include "Volume.h"
#include "VolumeManager.h"
typedef DoublyLinkedList<QueryIterator, QueryIterator::GetVolumeLink>
IteratorList;
struct QueryManager::IteratorMap : HashMap<HashKey64<vnode_id>, IteratorList*> {
};
QueryManager::QueryManager(VolumeManager* volumeManager)
: fLock("query manager"),
fVolumeManager(volumeManager),
fIterators(NULL)
{
}
QueryManager::~QueryManager()
{
for (IteratorMap::Iterator it = fIterators->GetIterator(); it.HasNext();) {
IteratorList* iteratorList = it.Next().value;
delete iteratorList;
}
delete fIterators;
}
status_t
QueryManager::Init()
{
if (fLock.Sem() < 0)
return fLock.Sem();
fIterators = new(std::nothrow) IteratorMap;
if (!fIterators)
return B_NO_MEMORY;
status_t error = fIterators->InitCheck();
if (error != B_OK)
return error;
return B_OK;
}
status_t
QueryManager::AddIterator(QueryIterator* iterator)
{
if (!iterator || !iterator->GetVolume())
return B_BAD_VALUE;
AutoLocker<Locker> _(fLock);
vnode_id nodeID = iterator->GetVolume()->GetRootID();
IteratorList* iteratorList = fIterators->Get(nodeID);
if (!iteratorList) {
iteratorList = new(std::nothrow) IteratorList;
if (!iteratorList)
return B_NO_MEMORY;
status_t error = fIterators->Put(nodeID, iteratorList);
if (error != B_OK) {
delete iteratorList;
return error;
}
}
iteratorList->Insert(iterator);
iterator->GetVolume()->AcquireReference();
return B_OK;
}
status_t
QueryManager::AddSubIterator(HierarchicalQueryIterator* iterator,
QueryIterator* subIterator)
{
if (!iterator || !subIterator)
return B_BAD_VALUE;
AutoLocker<Locker> _(fLock);
if (subIterator->GetVolume()->IsUnmounting())
return B_BAD_VALUE;
iterator->AddSubIterator(subIterator);
return B_OK;
}
status_t
QueryManager::RemoveSubIterator(HierarchicalQueryIterator* iterator,
QueryIterator* subIterator)
{
if (!iterator || !subIterator)
return B_BAD_VALUE;
AutoLocker<Locker> _(fLock);
if (subIterator->GetParentIterator() != iterator)
return B_BAD_VALUE;
iterator->RemoveSubIterator(subIterator);
return B_OK;
}
QueryIterator*
QueryManager::GetCurrentSubIterator(HierarchicalQueryIterator* iterator)
{
if (!iterator)
return NULL;
AutoLocker<Locker> _(fLock);
QueryIterator* subIterator = iterator->GetCurrentSubIterator();
if (subIterator)
subIterator->AcquireReference();
return subIterator;
}
void
QueryManager::NextSubIterator(HierarchicalQueryIterator* iterator,
QueryIterator* subIterator)
{
if (iterator) {
AutoLocker<Locker> _(fLock);
if (iterator->GetCurrentSubIterator() == subIterator)
iterator->NextSubIterator();
}
}
void
QueryManager::RewindSubIterator(HierarchicalQueryIterator* iterator)
{
if (iterator) {
AutoLocker<Locker> _(fLock);
iterator->RewindSubIterator();
}
}
void
QueryManager::PutIterator(QueryIterator* iterator)
{
if (!iterator)
return;
AutoLocker<Locker> locker(fLock);
if (iterator->ReleaseReference()) {
DoublyLinkedList<QueryIterator> subIterators;
if (HierarchicalQueryIterator* hIterator
= dynamic_cast<HierarchicalQueryIterator*>(iterator)) {
hIterator->RemoveAllSubIterators(subIterators);
}
HierarchicalQueryIterator* parentIterator
= iterator->GetParentIterator();
if (parentIterator)
parentIterator->RemoveSubIterator(iterator);
vnode_id nodeID = iterator->GetVolume()->GetRootID();
IteratorList* iteratorList = fIterators->Get(nodeID);
if (iteratorList) {
iteratorList->Remove(iterator);
if (!iteratorList->First()) {
fIterators->Remove(nodeID);
delete iteratorList;
}
} else {
ERROR("QueryManager::PutIterator(): ERROR: No iterator list "
"for volume %p!\n", iterator->GetVolume());
}
Volume* volume = iterator->GetVolume();
locker.Unlock();
volume->FreeQueryIterator(iterator);
volume->PutVolume();
while (QueryIterator* subIterator = subIterators.First()) {
subIterators.Remove(subIterator);
PutIterator(subIterator);
}
}
}
void
QueryManager::VolumeUnmounting(Volume* volume)
{
if (!volume || !volume->IsUnmounting())
return;
vnode_id nodeID = volume->GetRootID();
IteratorList iterators;
DoublyLinkedList<QueryIterator> subIterators;
AutoLocker<Locker> locker(fLock);
if (IteratorList* iteratorList = fIterators->Get(nodeID)) {
QueryIterator* iterator = iteratorList->First();
while (iterator) {
QueryIterator* nextIterator = iteratorList->GetNext(iterator);
if (iterator->GetParentIterator()) {
if (HierarchicalQueryIterator* hIterator
= dynamic_cast<HierarchicalQueryIterator*>(iterator)) {
hIterator->RemoveAllSubIterators(subIterators);
}
iterator->GetParentIterator()->RemoveSubIterator(iterator);
if (iterator->ReleaseReference()) {
iteratorList->Remove(iterator);
iterators.Insert(iterator);
}
}
iterator = nextIterator;
}
if (!iteratorList->First()) {
fIterators->Remove(nodeID);
delete iteratorList;
}
locker.Unlock();
while (QueryIterator* iterator = iterators.First()) {
iterators.Remove(iterator);
volume->FreeQueryIterator(iterator);
volume->PutVolume();
}
while (QueryIterator* subIterator = subIterators.First()) {
subIterators.Remove(subIterator);
PutIterator(subIterator);
}
}
}