1// QueryManager.cpp 2 3#include <new> 4 5#include <fsproto.h> 6 7#include <AutoLocker.h> 8#include <HashMap.h> 9 10#include "DebugSupport.h" 11#include "Locker.h" 12#include "QueryManager.h" 13#include "Volume.h" 14#include "VolumeManager.h" 15 16typedef DoublyLinkedList<QueryIterator, QueryIterator::GetVolumeLink> 17 IteratorList; 18 19// IteratorMap 20struct QueryManager::IteratorMap : HashMap<HashKey64<vnode_id>, IteratorList*> { 21}; 22 23 24// constructor 25QueryManager::QueryManager(VolumeManager* volumeManager) 26 : fLock("query manager"), 27 fVolumeManager(volumeManager), 28 fIterators(NULL) 29{ 30} 31 32// destructor 33QueryManager::~QueryManager() 34{ 35 // delete all iterator lists (there shouldn't be any, though) 36 for (IteratorMap::Iterator it = fIterators->GetIterator(); it.HasNext();) { 37 IteratorList* iteratorList = it.Next().value; 38 delete iteratorList; 39 } 40 delete fIterators; 41} 42 43// Init 44status_t 45QueryManager::Init() 46{ 47 // check lock 48 if (fLock.Sem() < 0) 49 return fLock.Sem(); 50 51 // allocate iterator map 52 fIterators = new(std::nothrow) IteratorMap; 53 if (!fIterators) 54 return B_NO_MEMORY; 55 status_t error = fIterators->InitCheck(); 56 if (error != B_OK) 57 return error; 58 59 return B_OK; 60} 61 62// AddIterator 63status_t 64QueryManager::AddIterator(QueryIterator* iterator) 65{ 66 if (!iterator || !iterator->GetVolume()) 67 return B_BAD_VALUE; 68 69 AutoLocker<Locker> _(fLock); 70 71 // get the iterator list for the volume 72 vnode_id nodeID = iterator->GetVolume()->GetRootID(); 73 IteratorList* iteratorList = fIterators->Get(nodeID); 74 if (!iteratorList) { 75 // no list yet: create one 76 iteratorList = new(std::nothrow) IteratorList; 77 if (!iteratorList) 78 return B_NO_MEMORY; 79 80 // add it to the map 81 status_t error = fIterators->Put(nodeID, iteratorList); 82 if (error != B_OK) { 83 delete iteratorList; 84 return error; 85 } 86 } 87 88 // add the iterator 89 iteratorList->Insert(iterator); 90 91 // get a volume reference for the iterator 92 iterator->GetVolume()->AcquireReference(); 93 94 return B_OK; 95} 96 97// AddSubIterator 98status_t 99QueryManager::AddSubIterator(HierarchicalQueryIterator* iterator, 100 QueryIterator* subIterator) 101{ 102 if (!iterator || !subIterator) 103 return B_BAD_VALUE; 104 105 AutoLocker<Locker> _(fLock); 106 if (subIterator->GetVolume()->IsUnmounting()) 107 return B_BAD_VALUE; 108 109 iterator->AddSubIterator(subIterator); 110 111 return B_OK; 112} 113 114// RemoveSubIterator 115status_t 116QueryManager::RemoveSubIterator(HierarchicalQueryIterator* iterator, 117 QueryIterator* subIterator) 118{ 119 if (!iterator || !subIterator) 120 return B_BAD_VALUE; 121 122 AutoLocker<Locker> _(fLock); 123 if (subIterator->GetParentIterator() != iterator) 124 return B_BAD_VALUE; 125 126 iterator->RemoveSubIterator(subIterator); 127 128 return B_OK; 129} 130 131// GetCurrentSubIterator 132QueryIterator* 133QueryManager::GetCurrentSubIterator(HierarchicalQueryIterator* iterator) 134{ 135 if (!iterator) 136 return NULL; 137 138 AutoLocker<Locker> _(fLock); 139 QueryIterator* subIterator = iterator->GetCurrentSubIterator(); 140 if (subIterator) 141 subIterator->AcquireReference(); 142 return subIterator; 143} 144 145// NextSubIterator 146void 147QueryManager::NextSubIterator(HierarchicalQueryIterator* iterator, 148 QueryIterator* subIterator) 149{ 150 if (iterator) { 151 AutoLocker<Locker> _(fLock); 152 if (iterator->GetCurrentSubIterator() == subIterator) 153 iterator->NextSubIterator(); 154 } 155} 156 157// RewindSubIterator 158void 159QueryManager::RewindSubIterator(HierarchicalQueryIterator* iterator) 160{ 161 if (iterator) { 162 AutoLocker<Locker> _(fLock); 163 iterator->RewindSubIterator(); 164 } 165} 166 167// PutIterator 168void 169QueryManager::PutIterator(QueryIterator* iterator) 170{ 171 if (!iterator) 172 return; 173 174 AutoLocker<Locker> locker(fLock); 175 if (iterator->ReleaseReference()) { 176 // last reference removed: remove the iterator 177 178 // remove its subiterators (if any) 179 DoublyLinkedList<QueryIterator> subIterators; 180 if (HierarchicalQueryIterator* hIterator 181 = dynamic_cast<HierarchicalQueryIterator*>(iterator)) { 182 hIterator->RemoveAllSubIterators(subIterators); 183 } 184 185 // remove from the parent iterator 186 HierarchicalQueryIterator* parentIterator 187 = iterator->GetParentIterator(); 188 if (parentIterator) 189 parentIterator->RemoveSubIterator(iterator); 190 191 // remove from the list 192 vnode_id nodeID = iterator->GetVolume()->GetRootID(); 193 IteratorList* iteratorList = fIterators->Get(nodeID); 194 if (iteratorList) { 195 iteratorList->Remove(iterator); 196 197 // if the list is empty, remove it completely 198 if (!iteratorList->First()) { 199 fIterators->Remove(nodeID); 200 delete iteratorList; 201 } 202 } else { 203 ERROR("QueryManager::PutIterator(): ERROR: No iterator list " 204 "for volume %p!\n", iterator->GetVolume()); 205 } 206 207 // free the iterator and surrender its volume reference 208 Volume* volume = iterator->GetVolume(); 209 locker.Unlock(); 210 volume->FreeQueryIterator(iterator); 211 volume->PutVolume(); 212 213 // put the subiterators 214 while (QueryIterator* subIterator = subIterators.First()) { 215 subIterators.Remove(subIterator); 216 PutIterator(subIterator); 217 } 218 } 219} 220 221// VolumeUnmounting 222// 223// Removes all subiterators belonging to the volume from their parent iterators 224// and puts the respective reference. 225void 226QueryManager::VolumeUnmounting(Volume* volume) 227{ 228 if (!volume || !volume->IsUnmounting()) 229 return; 230 231 vnode_id nodeID = volume->GetRootID(); 232 IteratorList iterators; 233 DoublyLinkedList<QueryIterator> subIterators; 234 AutoLocker<Locker> locker(fLock); 235 if (IteratorList* iteratorList = fIterators->Get(nodeID)) { 236 // Unset the parent of all iterators and remove one reference. 237 // If the iterators are unreference, remove them. 238 QueryIterator* iterator = iteratorList->First(); 239 while (iterator) { 240 QueryIterator* nextIterator = iteratorList->GetNext(iterator); 241 242 if (iterator->GetParentIterator()) { 243 // remove its subiterators (if any) 244 if (HierarchicalQueryIterator* hIterator 245 = dynamic_cast<HierarchicalQueryIterator*>(iterator)) { 246 hIterator->RemoveAllSubIterators(subIterators); 247 } 248 249 // remove from parent 250 iterator->GetParentIterator()->RemoveSubIterator(iterator); 251 252 // remove reference 253 if (iterator->ReleaseReference()) { 254 // no more reference: move to our local list 255 iteratorList->Remove(iterator); 256 iterators.Insert(iterator); 257 } 258 } 259 260 iterator = nextIterator; 261 } 262 263 // if the list is empty now, remove it completely 264 if (!iteratorList->First()) { 265 fIterators->Remove(nodeID); 266 delete iteratorList; 267 } 268 269 // free the iterators we have removed and surrender their volume 270 // references 271 locker.Unlock(); 272 while (QueryIterator* iterator = iterators.First()) { 273 iterators.Remove(iterator); 274 volume->FreeQueryIterator(iterator); 275 volume->PutVolume(); 276 } 277 278 // put the subiterators 279 while (QueryIterator* subIterator = subIterators.First()) { 280 subIterators.Remove(subIterator); 281 PutIterator(subIterator); 282 } 283 } 284} 285 286