// QueryManager.cpp #include #include #include #include #include "DebugSupport.h" #include "Locker.h" #include "QueryManager.h" #include "Volume.h" #include "VolumeManager.h" typedef DoublyLinkedList IteratorList; // IteratorMap struct QueryManager::IteratorMap : HashMap, IteratorList*> { }; // constructor QueryManager::QueryManager(VolumeManager* volumeManager) : fLock("query manager"), fVolumeManager(volumeManager), fIterators(NULL) { } // destructor QueryManager::~QueryManager() { // delete all iterator lists (there shouldn't be any, though) for (IteratorMap::Iterator it = fIterators->GetIterator(); it.HasNext();) { IteratorList* iteratorList = it.Next().value; delete iteratorList; } delete fIterators; } // Init status_t QueryManager::Init() { // check lock if (fLock.Sem() < 0) return fLock.Sem(); // allocate iterator map 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; } // AddIterator status_t QueryManager::AddIterator(QueryIterator* iterator) { if (!iterator || !iterator->GetVolume()) return B_BAD_VALUE; AutoLocker _(fLock); // get the iterator list for the volume vnode_id nodeID = iterator->GetVolume()->GetRootID(); IteratorList* iteratorList = fIterators->Get(nodeID); if (!iteratorList) { // no list yet: create one iteratorList = new(std::nothrow) IteratorList; if (!iteratorList) return B_NO_MEMORY; // add it to the map status_t error = fIterators->Put(nodeID, iteratorList); if (error != B_OK) { delete iteratorList; return error; } } // add the iterator iteratorList->Insert(iterator); // get a volume reference for the iterator iterator->GetVolume()->AcquireReference(); return B_OK; } // AddSubIterator status_t QueryManager::AddSubIterator(HierarchicalQueryIterator* iterator, QueryIterator* subIterator) { if (!iterator || !subIterator) return B_BAD_VALUE; AutoLocker _(fLock); if (subIterator->GetVolume()->IsUnmounting()) return B_BAD_VALUE; iterator->AddSubIterator(subIterator); return B_OK; } // RemoveSubIterator status_t QueryManager::RemoveSubIterator(HierarchicalQueryIterator* iterator, QueryIterator* subIterator) { if (!iterator || !subIterator) return B_BAD_VALUE; AutoLocker _(fLock); if (subIterator->GetParentIterator() != iterator) return B_BAD_VALUE; iterator->RemoveSubIterator(subIterator); return B_OK; } // GetCurrentSubIterator QueryIterator* QueryManager::GetCurrentSubIterator(HierarchicalQueryIterator* iterator) { if (!iterator) return NULL; AutoLocker _(fLock); QueryIterator* subIterator = iterator->GetCurrentSubIterator(); if (subIterator) subIterator->AcquireReference(); return subIterator; } // NextSubIterator void QueryManager::NextSubIterator(HierarchicalQueryIterator* iterator, QueryIterator* subIterator) { if (iterator) { AutoLocker _(fLock); if (iterator->GetCurrentSubIterator() == subIterator) iterator->NextSubIterator(); } } // RewindSubIterator void QueryManager::RewindSubIterator(HierarchicalQueryIterator* iterator) { if (iterator) { AutoLocker _(fLock); iterator->RewindSubIterator(); } } // PutIterator void QueryManager::PutIterator(QueryIterator* iterator) { if (!iterator) return; AutoLocker locker(fLock); if (iterator->ReleaseReference()) { // last reference removed: remove the iterator // remove its subiterators (if any) DoublyLinkedList subIterators; if (HierarchicalQueryIterator* hIterator = dynamic_cast(iterator)) { hIterator->RemoveAllSubIterators(subIterators); } // remove from the parent iterator HierarchicalQueryIterator* parentIterator = iterator->GetParentIterator(); if (parentIterator) parentIterator->RemoveSubIterator(iterator); // remove from the list vnode_id nodeID = iterator->GetVolume()->GetRootID(); IteratorList* iteratorList = fIterators->Get(nodeID); if (iteratorList) { iteratorList->Remove(iterator); // if the list is empty, remove it completely if (!iteratorList->First()) { fIterators->Remove(nodeID); delete iteratorList; } } else { ERROR("QueryManager::PutIterator(): ERROR: No iterator list " "for volume %p!\n", iterator->GetVolume()); } // free the iterator and surrender its volume reference Volume* volume = iterator->GetVolume(); locker.Unlock(); volume->FreeQueryIterator(iterator); volume->PutVolume(); // put the subiterators while (QueryIterator* subIterator = subIterators.First()) { subIterators.Remove(subIterator); PutIterator(subIterator); } } } // VolumeUnmounting // // Removes all subiterators belonging to the volume from their parent iterators // and puts the respective reference. void QueryManager::VolumeUnmounting(Volume* volume) { if (!volume || !volume->IsUnmounting()) return; vnode_id nodeID = volume->GetRootID(); IteratorList iterators; DoublyLinkedList subIterators; AutoLocker locker(fLock); if (IteratorList* iteratorList = fIterators->Get(nodeID)) { // Unset the parent of all iterators and remove one reference. // If the iterators are unreference, remove them. QueryIterator* iterator = iteratorList->First(); while (iterator) { QueryIterator* nextIterator = iteratorList->GetNext(iterator); if (iterator->GetParentIterator()) { // remove its subiterators (if any) if (HierarchicalQueryIterator* hIterator = dynamic_cast(iterator)) { hIterator->RemoveAllSubIterators(subIterators); } // remove from parent iterator->GetParentIterator()->RemoveSubIterator(iterator); // remove reference if (iterator->ReleaseReference()) { // no more reference: move to our local list iteratorList->Remove(iterator); iterators.Insert(iterator); } } iterator = nextIterator; } // if the list is empty now, remove it completely if (!iteratorList->First()) { fIterators->Remove(nodeID); delete iteratorList; } // free the iterators we have removed and surrender their volume // references locker.Unlock(); while (QueryIterator* iterator = iterators.First()) { iterators.Remove(iterator); volume->FreeQueryIterator(iterator); volume->PutVolume(); } // put the subiterators while (QueryIterator* subIterator = subIterators.First()) { subIterators.Remove(subIterator); PutIterator(subIterator); } } }