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 18class LastModifiedIndexPrimaryKey { 19public: 20 LastModifiedIndexPrimaryKey(Node *node, time_t modified) 21 : node(node), modified(modified) {} 22 LastModifiedIndexPrimaryKey(Node *node) 23 : node(node), modified(node->GetMTime()) {} 24 LastModifiedIndexPrimaryKey(time_t modified) 25 : node(NULL), modified(modified) {} 26 27 Node *node; 28 time_t modified; 29}; 30 31// LastModifiedIndexGetPrimaryKey 32class LastModifiedIndexGetPrimaryKey { 33public: 34 inline LastModifiedIndexPrimaryKey operator()(Node *a) 35 { 36 return LastModifiedIndexPrimaryKey(a); 37 } 38 39 inline LastModifiedIndexPrimaryKey operator()(Node *a) const 40 { 41 return LastModifiedIndexPrimaryKey(a); 42 } 43}; 44 45// LastModifiedIndexPrimaryKeyCompare 46class LastModifiedIndexPrimaryKeyCompare 47{ 48public: 49 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 64typedef TwoKeyAVLTree<Node*, LastModifiedIndexPrimaryKey, 65 LastModifiedIndexPrimaryKeyCompare, 66 LastModifiedIndexGetPrimaryKey> 67 _NodeTree; 68class LastModifiedIndex::NodeTree : public _NodeTree {}; 69 70 71// IteratorList 72class LastModifiedIndex::IteratorList : public DoublyLinkedList<Iterator> {}; 73 74 75// Iterator 76class LastModifiedIndex::Iterator 77 : public NodeEntryIterator<LastModifiedIndex::NodeTree::Iterator>, 78 public DoublyLinkedListLinkImpl<Iterator>, public EntryListener, 79 public NodeListener { 80public: 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 97private: 98 typedef NodeEntryIterator<LastModifiedIndex::NodeTree::Iterator> BaseClass; 99 100private: 101 LastModifiedIndex *fIndex; 102}; 103 104 105// LastModifiedIndex 106 107// constructor 108LastModifiedIndex::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 122LastModifiedIndex::~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 140int32 141LastModifiedIndex::CountEntries() const 142{ 143 return fNodes->CountItems(); 144} 145 146// Changed 147status_t 148LastModifiedIndex::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 178void 179LastModifiedIndex::NodeAdded(Node *node) 180{ 181 if (node) 182 fNodes->Insert(node); 183} 184 185// NodeRemoved 186void 187LastModifiedIndex::NodeRemoved(Node *node) 188{ 189 if (node) 190 fNodes->Remove(node, node); 191} 192 193// InternalGetIterator 194AbstractIndexEntryIterator * 195LastModifiedIndex::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 208AbstractIndexEntryIterator * 209LastModifiedIndex::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 224void 225LastModifiedIndex::_AddIterator(Iterator *iterator) 226{ 227 fIterators->Insert(iterator); 228} 229 230// _RemoveIterator 231void 232LastModifiedIndex::_RemoveIterator(Iterator *iterator) 233{ 234 fIterators->Remove(iterator); 235} 236 237 238// Iterator 239 240// constructor 241LastModifiedIndex::Iterator::Iterator() 242 : BaseClass(), 243 fIndex(NULL) 244{ 245} 246 247// destructor 248LastModifiedIndex::Iterator::~Iterator() 249{ 250 SetTo(NULL, 0); 251} 252 253// GetCurrent 254Entry * 255LastModifiedIndex::Iterator::GetCurrent() 256{ 257 return BaseClass::GetCurrent(); 258} 259 260// GetCurrent 261Entry * 262LastModifiedIndex::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 273status_t 274LastModifiedIndex::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 295status_t 296LastModifiedIndex::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 313bool 314LastModifiedIndex::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 348void 349LastModifiedIndex::Iterator::Unset() 350{ 351 if (fIndex) { 352 fIndex->_RemoveIterator(this); 353 fIndex = NULL; 354 } 355 BaseClass::Unset(); 356} 357 358// EntryRemoved 359void 360LastModifiedIndex::Iterator::EntryRemoved(Entry */*entry*/) 361{ 362 Resume(); 363 fIsNext = BaseClass::GetNext(); 364 Suspend(); 365} 366 367// NodeRemoved 368void 369LastModifiedIndex::Iterator::NodeRemoved(Node */*node*/) 370{ 371 Resume(); 372 fEntry = NULL; 373 fIsNext = BaseClass::GetNext(); 374 Suspend(); 375} 376 377