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