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
17class SizeIndexPrimaryKey {
18public:
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
31class SizeIndexGetPrimaryKey {
32public:
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
45class SizeIndexPrimaryKeyCompare
46{
47public:
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
63typedef TwoKeyAVLTree<Node*, SizeIndexPrimaryKey,
64					  SizeIndexPrimaryKeyCompare,
65					  SizeIndexGetPrimaryKey>
66		_NodeTree;
67class SizeIndex::NodeTree : public _NodeTree {};
68
69
70// IteratorList
71class SizeIndex::IteratorList : public DoublyLinkedList<Iterator> {};
72
73
74// Iterator
75class SizeIndex::Iterator
76	: public NodeEntryIterator<SizeIndex::NodeTree::Iterator>,
77	  public DoublyLinkedListLinkImpl<Iterator>, public EntryListener,
78	  public NodeListener {
79public:
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
95private:
96	typedef NodeEntryIterator<SizeIndex::NodeTree::Iterator> BaseClass;
97
98private:
99	SizeIndex						*fIndex;
100};
101
102
103// SizeIndex
104
105// constructor
106SizeIndex::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
120SizeIndex::~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
138int32
139SizeIndex::CountEntries() const
140{
141	return fNodes->CountItems();
142}
143
144// Changed
145status_t
146SizeIndex::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
177void
178SizeIndex::NodeAdded(Node *node)
179{
180	if (node)
181		fNodes->Insert(node);
182}
183
184// NodeRemoved
185void
186SizeIndex::NodeRemoved(Node *node)
187{
188	if (node)
189		fNodes->Remove(node, node);
190}
191
192// InternalGetIterator
193AbstractIndexEntryIterator *
194SizeIndex::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
207AbstractIndexEntryIterator *
208SizeIndex::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
223void
224SizeIndex::_AddIterator(Iterator *iterator)
225{
226	fIterators->Insert(iterator);
227}
228
229// _RemoveIterator
230void
231SizeIndex::_RemoveIterator(Iterator *iterator)
232{
233	fIterators->Remove(iterator);
234}
235
236
237// Iterator
238
239// constructor
240SizeIndex::Iterator::Iterator()
241	: BaseClass(),
242	  fIndex(NULL)
243{
244}
245
246// destructor
247SizeIndex::Iterator::~Iterator()
248{
249	SetTo(NULL, 0);
250}
251
252// GetCurrent
253Entry *
254SizeIndex::Iterator::GetCurrent()
255{
256	return BaseClass::GetCurrent();
257}
258
259// GetCurrent
260Entry *
261SizeIndex::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
272status_t
273SizeIndex::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
294status_t
295SizeIndex::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
312bool
313SizeIndex::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
346void
347SizeIndex::Iterator::Unset()
348{
349	if (fIndex) {
350		fIndex->_RemoveIterator(this);
351		fIndex = NULL;
352	}
353	BaseClass::Unset();
354}
355
356// EntryRemoved
357void
358SizeIndex::Iterator::EntryRemoved(Entry */*entry*/)
359{
360	Resume();
361	fIsNext = BaseClass::GetNext();
362	Suspend();
363}
364
365// NodeRemoved
366void
367SizeIndex::Iterator::NodeRemoved(Node */*node*/)
368{
369	Resume();
370	fEntry = NULL;
371	fIsNext = BaseClass::GetNext();
372	Suspend();
373}
374
375