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: 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 32 class LastModifiedIndexGetPrimaryKey { 33 public: 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 46 class LastModifiedIndexPrimaryKeyCompare 47 { 48 public: 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 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 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 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 141 LastModifiedIndex::CountEntries() const 142 { 143 return fNodes->CountItems(); 144 } 145 146 // Changed 147 status_t 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 179 LastModifiedIndex::NodeAdded(Node *node) 180 { 181 if (node) 182 fNodes->Insert(node); 183 } 184 185 // NodeRemoved 186 void 187 LastModifiedIndex::NodeRemoved(Node *node) 188 { 189 if (node) 190 fNodes->Remove(node, node); 191 } 192 193 // InternalGetIterator 194 AbstractIndexEntryIterator * 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 * 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 225 LastModifiedIndex::_AddIterator(Iterator *iterator) 226 { 227 fIterators->Insert(iterator); 228 } 229 230 // _RemoveIterator 231 void 232 LastModifiedIndex::_RemoveIterator(Iterator *iterator) 233 { 234 fIterators->Remove(iterator); 235 } 236 237 238 // Iterator 239 240 // constructor 241 LastModifiedIndex::Iterator::Iterator() 242 : BaseClass(), 243 fIndex(NULL) 244 { 245 } 246 247 // destructor 248 LastModifiedIndex::Iterator::~Iterator() 249 { 250 SetTo(NULL, 0); 251 } 252 253 // GetCurrent 254 Entry * 255 LastModifiedIndex::Iterator::GetCurrent() 256 { 257 return BaseClass::GetCurrent(); 258 } 259 260 // GetCurrent 261 Entry * 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 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 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 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 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 360 LastModifiedIndex::Iterator::EntryRemoved(Entry */*entry*/) 361 { 362 Resume(); 363 fIsNext = BaseClass::GetNext(); 364 Suspend(); 365 } 366 367 // NodeRemoved 368 void 369 LastModifiedIndex::Iterator::NodeRemoved(Node */*node*/) 370 { 371 Resume(); 372 fEntry = NULL; 373 fIsNext = BaseClass::GetNext(); 374 Suspend(); 375 } 376 377