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