xref: /haiku/src/add-ons/kernel/file_systems/ramfs/LastModifiedIndex.cpp (revision 2b76973fa2401f7a5edf68e6470f3d3210cbcff3)
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
15 class LastModifiedIndexPrimaryKey {
16 public:
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
29 class LastModifiedIndexGetPrimaryKey {
30 public:
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
43 class LastModifiedIndexPrimaryKeyCompare
44 {
45 public:
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
61 typedef TwoKeyAVLTree<Node*, LastModifiedIndexPrimaryKey,
62 					  LastModifiedIndexPrimaryKeyCompare,
63 					  LastModifiedIndexGetPrimaryKey>
64 		_NodeTree;
65 class LastModifiedIndex::NodeTree : public _NodeTree {};
66 
67 
68 // IteratorList
69 class LastModifiedIndex::IteratorList : public DoublyLinkedList<Iterator> {};
70 
71 
72 // Iterator
73 class LastModifiedIndex::Iterator
74 	: public NodeEntryIterator<LastModifiedIndex::NodeTree::Iterator>,
75 	  public DoublyLinkedListLinkImpl<Iterator>, public EntryListener,
76 	  public NodeListener {
77 public:
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 
94 private:
95 	typedef NodeEntryIterator<LastModifiedIndex::NodeTree::Iterator> BaseClass;
96 
97 private:
98 	LastModifiedIndex						*fIndex;
99 };
100 
101 
102 // LastModifiedIndex
103 
104 // constructor
105 LastModifiedIndex::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
119 LastModifiedIndex::~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
137 int32
138 LastModifiedIndex::CountEntries() const
139 {
140 	return fNodes->CountItems();
141 }
142 
143 // Changed
144 status_t
145 LastModifiedIndex::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 			it.Remove();
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
175 void
176 LastModifiedIndex::NodeAdded(Node *node)
177 {
178 	if (node)
179 		fNodes->Insert(node);
180 }
181 
182 // NodeRemoved
183 void
184 LastModifiedIndex::NodeRemoved(Node *node)
185 {
186 	if (node)
187 		fNodes->Remove(node, node);
188 }
189 
190 // InternalGetIterator
191 AbstractIndexEntryIterator *
192 LastModifiedIndex::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
205 AbstractIndexEntryIterator *
206 LastModifiedIndex::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
221 void
222 LastModifiedIndex::_AddIterator(Iterator *iterator)
223 {
224 	fIterators->Insert(iterator);
225 }
226 
227 // _RemoveIterator
228 void
229 LastModifiedIndex::_RemoveIterator(Iterator *iterator)
230 {
231 	fIterators->Remove(iterator);
232 }
233 
234 
235 // Iterator
236 
237 // constructor
238 LastModifiedIndex::Iterator::Iterator()
239 	: BaseClass(),
240 	  fIndex(NULL)
241 {
242 }
243 
244 // destructor
245 LastModifiedIndex::Iterator::~Iterator()
246 {
247 	SetTo(NULL, 0);
248 }
249 
250 // GetCurrent
251 Entry *
252 LastModifiedIndex::Iterator::GetCurrent()
253 {
254 	return BaseClass::GetCurrent();
255 }
256 
257 // GetCurrent
258 Entry *
259 LastModifiedIndex::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
270 status_t
271 LastModifiedIndex::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
292 status_t
293 LastModifiedIndex::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
310 bool
311 LastModifiedIndex::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
345 void
346 LastModifiedIndex::Iterator::Unset()
347 {
348 	if (fIndex) {
349 		fIndex->_RemoveIterator(this);
350 		fIndex = NULL;
351 	}
352 	BaseClass::Unset();
353 }
354 
355 // EntryRemoved
356 void
357 LastModifiedIndex::Iterator::EntryRemoved(Entry */*entry*/)
358 {
359 	Resume();
360 	fIsNext = BaseClass::GetNext();
361 	Suspend();
362 }
363 
364 // NodeRemoved
365 void
366 LastModifiedIndex::Iterator::NodeRemoved(Node */*node*/)
367 {
368 	Resume();
369 	fEntry = NULL;
370 	fIsNext = BaseClass::GetNext();
371 	Suspend();
372 }
373 
374