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