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