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
14class SizeIndexPrimaryKey {
15public:
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
28class SizeIndexGetPrimaryKey {
29public:
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
42class SizeIndexPrimaryKeyCompare
43{
44public:
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
60typedef TwoKeyAVLTree<Node*, SizeIndexPrimaryKey,
61					  SizeIndexPrimaryKeyCompare,
62					  SizeIndexGetPrimaryKey>
63		_NodeTree;
64class SizeIndex::NodeTree : public _NodeTree {};
65
66
67// IteratorList
68class SizeIndex::IteratorList : public DoublyLinkedList<Iterator> {};
69
70
71// Iterator
72class SizeIndex::Iterator
73	: public NodeEntryIterator<SizeIndex::NodeTree::Iterator>,
74	  public DoublyLinkedListLinkImpl<Iterator>, public EntryListener,
75	  public NodeListener {
76public:
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
92private:
93	typedef NodeEntryIterator<SizeIndex::NodeTree::Iterator> BaseClass;
94
95private:
96	SizeIndex						*fIndex;
97};
98
99
100// SizeIndex
101
102// constructor
103SizeIndex::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
117SizeIndex::~SizeIndex()
118{
119	if (fVolume)
120		fVolume->RemoveNodeListener(this, NULL);
121	if (fIterators) {
122		// unset the iterators
123		for (Iterator *iterator = fIterators->First();
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
135int32
136SizeIndex::CountEntries() const
137{
138	return fNodes->CountItems();
139}
140
141// Changed
142status_t
143SizeIndex::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->First();
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
174void
175SizeIndex::NodeAdded(Node *node)
176{
177	if (node)
178		fNodes->Insert(node);
179}
180
181// NodeRemoved
182void
183SizeIndex::NodeRemoved(Node *node)
184{
185	if (node)
186		fNodes->Remove(node, node);
187}
188
189// InternalGetIterator
190AbstractIndexEntryIterator *
191SizeIndex::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
204AbstractIndexEntryIterator *
205SizeIndex::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
220void
221SizeIndex::_AddIterator(Iterator *iterator)
222{
223	fIterators->Insert(iterator);
224}
225
226// _RemoveIterator
227void
228SizeIndex::_RemoveIterator(Iterator *iterator)
229{
230	fIterators->Remove(iterator);
231}
232
233
234// Iterator
235
236// constructor
237SizeIndex::Iterator::Iterator()
238	: BaseClass(),
239	  fIndex(NULL)
240{
241}
242
243// destructor
244SizeIndex::Iterator::~Iterator()
245{
246	SetTo(NULL, 0);
247}
248
249// GetCurrent
250Entry *
251SizeIndex::Iterator::GetCurrent()
252{
253	return BaseClass::GetCurrent();
254}
255
256// GetCurrent
257Entry *
258SizeIndex::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
269status_t
270SizeIndex::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
291status_t
292SizeIndex::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
309bool
310SizeIndex::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
343void
344SizeIndex::Iterator::Unset()
345{
346	if (fIndex) {
347		fIndex->_RemoveIterator(this);
348		fIndex = NULL;
349	}
350	BaseClass::Unset();
351}
352
353// EntryRemoved
354void
355SizeIndex::Iterator::EntryRemoved(Entry */*entry*/)
356{
357	Resume();
358	fIsNext = BaseClass::GetNext();
359	Suspend();
360}
361
362// NodeRemoved
363void
364SizeIndex::Iterator::NodeRemoved(Node */*node*/)
365{
366	Resume();
367	fEntry = NULL;
368	fIsNext = BaseClass::GetNext();
369	Suspend();
370}
371
372