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