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 16 typedef DoublyLinkedList<QueryIterator, QueryIterator::GetVolumeLink> 17 IteratorList; 18 19 // IteratorMap 20 struct QueryManager::IteratorMap : HashMap<HashKey64<vnode_id>, IteratorList*> { 21 }; 22 23 24 // constructor 25 QueryManager::QueryManager(VolumeManager* volumeManager) 26 : fLock("query manager"), 27 fVolumeManager(volumeManager), 28 fIterators(NULL) 29 { 30 } 31 32 // destructor 33 QueryManager::~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 44 status_t 45 QueryManager::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 63 status_t 64 QueryManager::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 98 status_t 99 QueryManager::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 115 status_t 116 QueryManager::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 132 QueryIterator* 133 QueryManager::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 146 void 147 QueryManager::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 158 void 159 QueryManager::RewindSubIterator(HierarchicalQueryIterator* iterator) 160 { 161 if (iterator) { 162 AutoLocker<Locker> _(fLock); 163 iterator->RewindSubIterator(); 164 } 165 } 166 167 // PutIterator 168 void 169 QueryManager::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. 225 void 226 QueryManager::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