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