xref: /haiku/src/add-ons/kernel/file_systems/netfs/client/QueryManager.cpp (revision 88e38c178a96634d52920e2de8bb3cbd49869f93)
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