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
QueryManager(VolumeManager * volumeManager)25 QueryManager::QueryManager(VolumeManager* volumeManager)
26 : fLock("query manager"),
27 fVolumeManager(volumeManager),
28 fIterators(NULL)
29 {
30 }
31
32 // destructor
~QueryManager()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
Init()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
AddIterator(QueryIterator * iterator)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
AddSubIterator(HierarchicalQueryIterator * iterator,QueryIterator * subIterator)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
RemoveSubIterator(HierarchicalQueryIterator * iterator,QueryIterator * subIterator)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*
GetCurrentSubIterator(HierarchicalQueryIterator * iterator)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
NextSubIterator(HierarchicalQueryIterator * iterator,QueryIterator * subIterator)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
RewindSubIterator(HierarchicalQueryIterator * iterator)159 QueryManager::RewindSubIterator(HierarchicalQueryIterator* iterator)
160 {
161 if (iterator) {
162 AutoLocker<Locker> _(fLock);
163 iterator->RewindSubIterator();
164 }
165 }
166
167 // PutIterator
168 void
PutIterator(QueryIterator * iterator)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
VolumeUnmounting(Volume * volume)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