xref: /haiku/src/add-ons/kernel/file_systems/packagefs/indices/LastModifiedIndex.cpp (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
1 /*
2  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "LastModifiedIndex.h"
8 
9 #include <new>
10 
11 #include <TypeConstants.h>
12 
13 #include <util/SinglyLinkedList.h>
14 
15 #include "DebugSupport.h"
16 #include "IndexImpl.h"
17 #include "Node.h"
18 #include "TwoKeyAVLTree.h"
19 #include "Volume.h"
20 
21 
22 // #pragma mark - LastModifiedIndexPrimaryKey
23 
24 
25 class LastModifiedIndexPrimaryKey {
26 public:
27 	LastModifiedIndexPrimaryKey(Node* node, time_t modified)
28 		:
29 		node(node),
30 		modified(modified)
31 	{
32 	}
33 
34 	LastModifiedIndexPrimaryKey(Node* node)
35 		:
36 		node(node),
37 		modified(node->ModifiedTime().tv_sec)
38 	{
39 	}
40 
41 	LastModifiedIndexPrimaryKey(time_t modified)
42 		:
43 		node(NULL),
44 		modified(modified)
45 	{
46 	}
47 
48 	Node*	node;
49 	time_t	modified;
50 };
51 
52 
53 // #pragma mark - LastModifiedIndexGetPrimaryKey
54 
55 
56 class LastModifiedIndexGetPrimaryKey {
57 public:
58 	inline LastModifiedIndexPrimaryKey operator()(Node* a)
59 	{
60 		return LastModifiedIndexPrimaryKey(a);
61 	}
62 
63 	inline LastModifiedIndexPrimaryKey operator()(Node* a) const
64 	{
65 		return LastModifiedIndexPrimaryKey(a);
66 	}
67 };
68 
69 
70 // #pragma mark - LastModifiedIndexPrimaryKeyCompare
71 
72 
73 class LastModifiedIndexPrimaryKeyCompare {
74 public:
75 	inline int operator()(const LastModifiedIndexPrimaryKey &a,
76 		const LastModifiedIndexPrimaryKey &b) const
77 	{
78 		if (a.node != NULL && a.node == b.node)
79 			return 0;
80 		if (a.modified < b.modified)
81 			return -1;
82 		if (a.modified > b.modified)
83 			return 1;
84 		return 0;
85 	}
86 };
87 
88 
89 // #pragma mark - NodeTree
90 
91 
92 typedef TwoKeyAVLTree<Node*, LastModifiedIndexPrimaryKey,
93 		LastModifiedIndexPrimaryKeyCompare, LastModifiedIndexGetPrimaryKey>
94 	_NodeTree;
95 class LastModifiedIndex::NodeTree : public _NodeTree {};
96 
97 
98 // #pragma mark - IteratorList
99 
100 
101 class LastModifiedIndex::IteratorList : public SinglyLinkedList<Iterator> {};
102 
103 
104 // #pragma mark - Iterator
105 
106 
107 struct LastModifiedIndex::IteratorPolicy {
108 	typedef LastModifiedIndex								Index;
109 	typedef time_t											Value;
110 	typedef LastModifiedIndex::NodeTree						NodeTree;
111 	typedef GenericIndexIteratorTreePolicy<IteratorPolicy>	TreePolicy;
112 
113 	static NodeTree* GetNodeTree(Index* index)
114 	{
115 		return index->fNodes;
116 	}
117 
118 	static void GetNodeValue(Node* node, void* buffer, size_t* _keyLength)
119 	{
120 		*(time_t*)buffer = node->ModifiedTime().tv_sec;
121 		*_keyLength = sizeof(time_t);
122 	}
123 };
124 
125 
126 class LastModifiedIndex::Iterator : public GenericIndexIterator<IteratorPolicy>,
127 	public SinglyLinkedListLinkImpl<Iterator> {
128 public:
129 	virtual	void				NodeChanged(Node* node, uint32 statFields,
130 									const OldNodeAttributes& oldAttributes);
131 };
132 
133 
134 // #pragma mark - LastModifiedIndex
135 
136 
137 LastModifiedIndex::LastModifiedIndex()
138 	:
139 	Index(),
140 	fNodes(NULL),
141 	fIteratorsToUpdate(NULL)
142 {
143 }
144 
145 
146 LastModifiedIndex::~LastModifiedIndex()
147 {
148 	if (IsListening())
149 		fVolume->RemoveNodeListener(this);
150 
151 	ASSERT(fIteratorsToUpdate->IsEmpty());
152 
153 	delete fIteratorsToUpdate;
154 	delete fNodes;
155 }
156 
157 
158 status_t
159 LastModifiedIndex::Init(Volume* volume)
160 {
161 	status_t error = Index::Init(volume, "last_modified", B_INT32_TYPE, true,
162 		sizeof(time_t));
163 	if (error != B_OK)
164 		return error;
165 
166 	fVolume->AddNodeListener(this, NULL);
167 
168 	fNodes = new(std::nothrow) NodeTree;
169 	fIteratorsToUpdate = new(std::nothrow) IteratorList;
170 	if (fNodes == NULL || fIteratorsToUpdate == NULL)
171 		return B_NO_MEMORY;
172 
173 	return B_OK;
174 }
175 
176 
177 int32
178 LastModifiedIndex::CountEntries() const
179 {
180 	return fNodes->CountItems();
181 }
182 
183 
184 void
185 LastModifiedIndex::NodeAdded(Node* node)
186 {
187 	fNodes->Insert(node);
188 }
189 
190 
191 void
192 LastModifiedIndex::NodeRemoved(Node* node)
193 {
194 	fNodes->Remove(node, node);
195 }
196 
197 
198 void
199 LastModifiedIndex::NodeChanged(Node* node, uint32 statFields,
200 	const OldNodeAttributes& oldAttributes)
201 {
202 	IteratorList iterators;
203 	iterators.MoveFrom(fIteratorsToUpdate);
204 
205 	time_t oldLastModified = oldAttributes.ModifiedTime().tv_sec;
206 	time_t newLastModified = node->ModifiedTime().tv_sec;
207 	if (newLastModified == oldLastModified)
208 		return;
209 
210 	NodeTree::Iterator nodeIterator;
211 	Node** foundNode = fNodes->Find(
212 		LastModifiedIndexPrimaryKey(node, oldLastModified), node,
213 		&nodeIterator);
214 
215 	if (foundNode == NULL || *foundNode != node)
216 		return;
217 
218 	// move the iterators that point to the node to the previous node
219 	for (IteratorList::ConstIterator it = iterators.GetIterator();
220 			Iterator* iterator = it.Next();) {
221 		iterator->NodeChangeBegin(node);
222 	}
223 
224 	// remove and re-insert the node
225 	nodeIterator.Remove();
226 	if (fNodes->Insert(node) != B_OK) {
227 		fIteratorsToUpdate->MakeEmpty();
228 		return;
229 	}
230 
231 	// Move the iterators to the next node again. If the node hasn't changed
232 	// its place, they will point to it again, otherwise to the node originally
233 	// succeeding it.
234 	for (IteratorList::ConstIterator it = iterators.GetIterator();
235 			Iterator* iterator = it.Next();) {
236 		iterator->NodeChangeEnd(node);
237 	}
238 
239 	// update live queries
240 	fVolume->UpdateLiveQueries(node, Name(), Type(),
241 		(const uint8*)&oldLastModified, sizeof(oldLastModified),
242 		(const uint8*)&newLastModified, sizeof(newLastModified));
243 }
244 
245 
246 AbstractIndexIterator*
247 LastModifiedIndex::InternalGetIterator()
248 {
249 	Iterator* iterator = new(std::nothrow) Iterator;
250 	if (iterator != NULL) {
251 		if (!iterator->SetTo(this, 0, true)) {
252 			delete iterator;
253 			iterator = NULL;
254 		}
255 	}
256 	return iterator;
257 }
258 
259 
260 AbstractIndexIterator*
261 LastModifiedIndex::InternalFind(const void* key, size_t length)
262 {
263 	if (length != sizeof(time_t))
264 		return NULL;
265 	Iterator* iterator = new(std::nothrow) Iterator;
266 	if (iterator != NULL) {
267 		if (!iterator->SetTo(this, *(const time_t*)key)) {
268 			delete iterator;
269 			iterator = NULL;
270 		}
271 	}
272 	return iterator;
273 }
274 
275 
276 void
277 LastModifiedIndex::_AddIteratorToUpdate(Iterator* iterator)
278 {
279 	fIteratorsToUpdate->Add(iterator);
280 }
281 
282 
283 // #pragma mark - Iterator
284 
285 
286 void
287 LastModifiedIndex::Iterator::NodeChanged(Node* node, uint32 statFields,
288 	const OldNodeAttributes& oldAttributes)
289 {
290 	fIndex->_AddIteratorToUpdate(this);
291 }
292