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