xref: /haiku/src/add-ons/kernel/file_systems/ramfs/SizeIndex.cpp (revision 3af8011358bd4c624a0979336d48dabb466171ed)
1 /*
2  * Copyright 2007, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * All rights reserved. Distributed under the terms of the MIT license.
4  */
5 
6 #include <TypeConstants.h>
7 
8 #include "Entry.h"
9 #include "EntryListener.h"
10 #include "IndexImpl.h"
11 #include "Node.h"
12 #include "NodeListener.h"
13 #include "SizeIndex.h"
14 #include "Volume.h"
15 
16 // SizeIndexPrimaryKey
17 class SizeIndexPrimaryKey {
18 public:
19 	SizeIndexPrimaryKey(Node *node, off_t size)
20 		: node(node), size(size) {}
21 	SizeIndexPrimaryKey(Node *node)
22 		: node(node), size(node->GetSize()) {}
23 	SizeIndexPrimaryKey(off_t size)
24 		: node(NULL), size(size) {}
25 
26 	Node	*node;
27 	off_t	size;
28 };
29 
30 // SizeIndexGetPrimaryKey
31 class SizeIndexGetPrimaryKey {
32 public:
33 	inline SizeIndexPrimaryKey operator()(Node *a)
34 	{
35 		return SizeIndexPrimaryKey(a);
36 	}
37 
38 	inline SizeIndexPrimaryKey operator()(Node *a) const
39 	{
40 		return SizeIndexPrimaryKey(a);
41 	}
42 };
43 
44 // SizeIndexPrimaryKeyCompare
45 class SizeIndexPrimaryKeyCompare
46 {
47 public:
48 	inline int operator()(const SizeIndexPrimaryKey &a,
49 						  const SizeIndexPrimaryKey &b) const
50 	{
51 		if (a.node != NULL && a.node == b.node)
52 			return 0;
53 		if (a.size < b.size)
54 			return -1;
55 		if (a.size > b.size)
56 			return 1;
57 		return 0;
58 	}
59 };
60 
61 
62 // NodeTree
63 typedef TwoKeyAVLTree<Node*, SizeIndexPrimaryKey,
64 					  SizeIndexPrimaryKeyCompare,
65 					  SizeIndexGetPrimaryKey>
66 		_NodeTree;
67 class SizeIndex::NodeTree : public _NodeTree {};
68 
69 
70 // IteratorList
71 class SizeIndex::IteratorList : public DoublyLinkedList<Iterator> {};
72 
73 
74 // Iterator
75 class SizeIndex::Iterator
76 	: public NodeEntryIterator<SizeIndex::NodeTree::Iterator>,
77 	  public DoublyLinkedListLinkImpl<Iterator>, public EntryListener,
78 	  public NodeListener {
79 public:
80 	Iterator();
81 	virtual ~Iterator();
82 
83 	virtual Entry *GetCurrent();
84 	virtual Entry *GetCurrent(uint8 *buffer, size_t *keyLength);
85 
86 	virtual status_t Suspend();
87 	virtual status_t Resume();
88 
89 	bool SetTo(SizeIndex *index, off_t size, bool ignoreValue = false);
90 	void Unset();
91 
92 	virtual void EntryRemoved(Entry *entry);
93 	virtual void NodeRemoved(Node *node);
94 
95 private:
96 	typedef NodeEntryIterator<SizeIndex::NodeTree::Iterator> BaseClass;
97 
98 private:
99 	SizeIndex						*fIndex;
100 };
101 
102 
103 // SizeIndex
104 
105 // constructor
106 SizeIndex::SizeIndex(Volume *volume)
107 	: Index(volume, "size", B_INT64_TYPE, true, sizeof(off_t)),
108 	  fNodes(new(nothrow) NodeTree),
109 	  fIterators(new(nothrow) IteratorList)
110 {
111 	if (fInitStatus == B_OK && (!fNodes || !fIterators))
112 		fInitStatus = B_NO_MEMORY;
113 	if (fInitStatus == B_OK) {
114 		fInitStatus = fVolume->AddNodeListener(this,
115 			NULL, NODE_LISTEN_ANY_NODE | NODE_LISTEN_ALL);
116 	}
117 }
118 
119 // destructor
120 SizeIndex::~SizeIndex()
121 {
122 	if (fVolume)
123 		fVolume->RemoveNodeListener(this, NULL);
124 	if (fIterators) {
125 		// unset the iterators
126 		for (Iterator *iterator = fIterators->First();
127 			 iterator;
128 			 iterator = fIterators->GetNext(iterator)) {
129 			iterator->SetTo(NULL, 0);
130 		}
131 		delete fIterators;
132 	}
133 	if (fNodes)
134 		delete fNodes;
135 }
136 
137 // CountEntries
138 int32
139 SizeIndex::CountEntries() const
140 {
141 	return fNodes->CountItems();
142 }
143 
144 // Changed
145 status_t
146 SizeIndex::Changed(Node *node, off_t oldSize)
147 {
148 	status_t error = B_BAD_VALUE;
149 	if (node) {
150 		NodeTree::Iterator it;
151 		Node **foundNode = fNodes->Find(SizeIndexPrimaryKey(node, oldSize),
152 										node, &it);
153 		if (foundNode && *foundNode == node) {
154 			// update the iterators
155 			for (Iterator *iterator = fIterators->First();
156 				 iterator;
157 				 iterator = fIterators->GetNext(iterator)) {
158 				if (iterator->GetCurrentNode() == node)
159 					iterator->NodeRemoved(node);
160 			}
161 
162 			// remove and re-insert the node
163 			it.Remove();
164 			error = fNodes->Insert(node);
165 
166 			// udpate live queries
167 			off_t newSize = node->GetSize();
168 			fVolume->UpdateLiveQueries(NULL, node, GetName(), GetType(),
169 				(const uint8*)&oldSize, sizeof(oldSize), (const uint8*)&newSize,
170 				sizeof(newSize));
171 		}
172 	}
173 	return error;
174 }
175 
176 // NodeAdded
177 void
178 SizeIndex::NodeAdded(Node *node)
179 {
180 	if (node)
181 		fNodes->Insert(node);
182 }
183 
184 // NodeRemoved
185 void
186 SizeIndex::NodeRemoved(Node *node)
187 {
188 	if (node)
189 		fNodes->Remove(node, node);
190 }
191 
192 // InternalGetIterator
193 AbstractIndexEntryIterator *
194 SizeIndex::InternalGetIterator()
195 {
196 	Iterator *iterator = new(nothrow) Iterator;
197 	if (iterator) {
198 		if (!iterator->SetTo(this, 0, true)) {
199 			delete iterator;
200 			iterator = NULL;
201 		}
202 	}
203 	return iterator;
204 }
205 
206 // InternalFind
207 AbstractIndexEntryIterator *
208 SizeIndex::InternalFind(const uint8 *key, size_t length)
209 {
210 	if (!key || length != sizeof(off_t))
211 		return NULL;
212 	Iterator *iterator = new(nothrow) Iterator;
213 	if (iterator) {
214 		if (!iterator->SetTo(this, *(const off_t*)key)) {
215 			delete iterator;
216 			iterator = NULL;
217 		}
218 	}
219 	return iterator;
220 }
221 
222 // _AddIterator
223 void
224 SizeIndex::_AddIterator(Iterator *iterator)
225 {
226 	fIterators->Insert(iterator);
227 }
228 
229 // _RemoveIterator
230 void
231 SizeIndex::_RemoveIterator(Iterator *iterator)
232 {
233 	fIterators->Remove(iterator);
234 }
235 
236 
237 // Iterator
238 
239 // constructor
240 SizeIndex::Iterator::Iterator()
241 	: BaseClass(),
242 	  fIndex(NULL)
243 {
244 }
245 
246 // destructor
247 SizeIndex::Iterator::~Iterator()
248 {
249 	SetTo(NULL, 0);
250 }
251 
252 // GetCurrent
253 Entry *
254 SizeIndex::Iterator::GetCurrent()
255 {
256 	return BaseClass::GetCurrent();
257 }
258 
259 // GetCurrent
260 Entry *
261 SizeIndex::Iterator::GetCurrent(uint8 *buffer, size_t *keyLength)
262 {
263 	Entry *entry = GetCurrent();
264 	if (entry) {
265 		*(off_t*)buffer = entry->GetNode()->GetSize();
266 		*keyLength = sizeof(size_t);
267 	}
268 	return entry;
269 }
270 
271 // Suspend
272 status_t
273 SizeIndex::Iterator::Suspend()
274 {
275 	status_t error = BaseClass::Suspend();
276 	if (error == B_OK) {
277 		if (fNode) {
278 			error = fIndex->GetVolume()->AddNodeListener(this, fNode,
279 														 NODE_LISTEN_REMOVED);
280 			if (error == B_OK && fEntry) {
281 				error = fIndex->GetVolume()->AddEntryListener(this, fEntry,
282 					ENTRY_LISTEN_REMOVED);
283 				if (error != B_OK)
284 					fIndex->GetVolume()->RemoveNodeListener(this, fNode);
285 			}
286 			if (error != B_OK)
287 				BaseClass::Resume();
288 		}
289 	}
290 	return error;
291 }
292 
293 // Resume
294 status_t
295 SizeIndex::Iterator::Resume()
296 {
297 	status_t error = BaseClass::Resume();
298 	if (error == B_OK) {
299 		if (fEntry)
300 			error = fIndex->GetVolume()->RemoveEntryListener(this, fEntry);
301 		if (fNode) {
302 			if (error == B_OK)
303 				error = fIndex->GetVolume()->RemoveNodeListener(this, fNode);
304 			else
305 				fIndex->GetVolume()->RemoveNodeListener(this, fNode);
306 		}
307 	}
308 	return error;
309 }
310 
311 // SetTo
312 bool
313 SizeIndex::Iterator::SetTo(SizeIndex *index, off_t size, bool ignoreValue)
314 {
315 	Resume();
316 	Unset();
317 	// set the new values
318 	fIndex = index;
319 	if (fIndex)
320 		fIndex->_AddIterator(this);
321 	fInitialized = fIndex;
322 	// get the node's first entry
323 	if (fIndex) {
324 		// get the first node
325 		bool found = true;
326 		if (ignoreValue)
327 			fIndex->fNodes->GetIterator(&fIterator);
328 		else
329 			found = fIndex->fNodes->FindFirst(size, &fIterator);
330 		// get the first entry
331 		if (found) {
332 			if (Node **nodeP = fIterator.GetCurrent()) {
333 				fNode = *nodeP;
334 				fEntry = fNode->GetFirstReferrer();
335 				if (!fEntry)
336 					BaseClass::GetNext();
337 				if (!ignoreValue && fNode && fNode->GetSize() != size)
338 					Unset();
339 			}
340 		}
341 	}
342 	return fEntry;
343 }
344 
345 // Unset
346 void
347 SizeIndex::Iterator::Unset()
348 {
349 	if (fIndex) {
350 		fIndex->_RemoveIterator(this);
351 		fIndex = NULL;
352 	}
353 	BaseClass::Unset();
354 }
355 
356 // EntryRemoved
357 void
358 SizeIndex::Iterator::EntryRemoved(Entry */*entry*/)
359 {
360 	Resume();
361 	fIsNext = BaseClass::GetNext();
362 	Suspend();
363 }
364 
365 // NodeRemoved
366 void
367 SizeIndex::Iterator::NodeRemoved(Node */*node*/)
368 {
369 	Resume();
370 	fEntry = NULL;
371 	fIsNext = BaseClass::GetNext();
372 	Suspend();
373 }
374 
375