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 17class SizeIndexPrimaryKey { 18public: 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 31class SizeIndexGetPrimaryKey { 32public: 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 45class SizeIndexPrimaryKeyCompare 46{ 47public: 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 63typedef TwoKeyAVLTree<Node*, SizeIndexPrimaryKey, 64 SizeIndexPrimaryKeyCompare, 65 SizeIndexGetPrimaryKey> 66 _NodeTree; 67class SizeIndex::NodeTree : public _NodeTree {}; 68 69 70// IteratorList 71class SizeIndex::IteratorList : public DoublyLinkedList<Iterator> {}; 72 73 74// Iterator 75class SizeIndex::Iterator 76 : public NodeEntryIterator<SizeIndex::NodeTree::Iterator>, 77 public DoublyLinkedListLinkImpl<Iterator>, public EntryListener, 78 public NodeListener { 79public: 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 95private: 96 typedef NodeEntryIterator<SizeIndex::NodeTree::Iterator> BaseClass; 97 98private: 99 SizeIndex *fIndex; 100}; 101 102 103// SizeIndex 104 105// constructor 106SizeIndex::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 120SizeIndex::~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 138int32 139SizeIndex::CountEntries() const 140{ 141 return fNodes->CountItems(); 142} 143 144// Changed 145status_t 146SizeIndex::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 177void 178SizeIndex::NodeAdded(Node *node) 179{ 180 if (node) 181 fNodes->Insert(node); 182} 183 184// NodeRemoved 185void 186SizeIndex::NodeRemoved(Node *node) 187{ 188 if (node) 189 fNodes->Remove(node, node); 190} 191 192// InternalGetIterator 193AbstractIndexEntryIterator * 194SizeIndex::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 207AbstractIndexEntryIterator * 208SizeIndex::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 223void 224SizeIndex::_AddIterator(Iterator *iterator) 225{ 226 fIterators->Insert(iterator); 227} 228 229// _RemoveIterator 230void 231SizeIndex::_RemoveIterator(Iterator *iterator) 232{ 233 fIterators->Remove(iterator); 234} 235 236 237// Iterator 238 239// constructor 240SizeIndex::Iterator::Iterator() 241 : BaseClass(), 242 fIndex(NULL) 243{ 244} 245 246// destructor 247SizeIndex::Iterator::~Iterator() 248{ 249 SetTo(NULL, 0); 250} 251 252// GetCurrent 253Entry * 254SizeIndex::Iterator::GetCurrent() 255{ 256 return BaseClass::GetCurrent(); 257} 258 259// GetCurrent 260Entry * 261SizeIndex::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 272status_t 273SizeIndex::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 294status_t 295SizeIndex::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 312bool 313SizeIndex::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 346void 347SizeIndex::Iterator::Unset() 348{ 349 if (fIndex) { 350 fIndex->_RemoveIterator(this); 351 fIndex = NULL; 352 } 353 BaseClass::Unset(); 354} 355 356// EntryRemoved 357void 358SizeIndex::Iterator::EntryRemoved(Entry */*entry*/) 359{ 360 Resume(); 361 fIsNext = BaseClass::GetNext(); 362 Suspend(); 363} 364 365// NodeRemoved 366void 367SizeIndex::Iterator::NodeRemoved(Node */*node*/) 368{ 369 Resume(); 370 fEntry = NULL; 371 fIsNext = BaseClass::GetNext(); 372 Suspend(); 373} 374 375