From d35565bed0f5c64aa02e5e69b5ffa3ae7bd484e8 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 7 Jul 2011 11:42:31 +0200 Subject: [PATCH] Add size index support * Add class SizeIndex. * Create and add an instance of it in Volume mount. --- .../kernel/file_systems/packagefs/Jamfile | 1 + .../file_systems/packagefs/SizeIndex.cpp | 288 ++++++++++++++++++ .../kernel/file_systems/packagefs/SizeIndex.h | 51 ++++ .../kernel/file_systems/packagefs/Volume.cpp | 34 ++- 4 files changed, 366 insertions(+), 8 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/SizeIndex.h diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index f07377cf06..676e35f790 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -38,6 +38,7 @@ HAIKU_PACKAGE_FS_SOURCES = PackageSymlink.cpp Resolvable.cpp ResolvableFamily.cpp + SizeIndex.cpp UnpackingAttributeCookie.cpp UnpackingAttributeDirectoryCookie.cpp UnpackingDirectory.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp new file mode 100644 index 0000000000..a8c7860c0e --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp @@ -0,0 +1,288 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "SizeIndex.h" + +#include + +#include + +#include +#include + +#include "DebugSupport.h" +#include "IndexImpl.h" +#include "Node.h" +#include "Volume.h" + + +// #pragma mark - SizeIndexPrimaryKey + + +class SizeIndexPrimaryKey { +public: + SizeIndexPrimaryKey(Node* node, off_t size) + : + node(node), + size(size) + { + } + + SizeIndexPrimaryKey(Node* node) + : + node(node), + size(node->FileSize()) + { + } + + SizeIndexPrimaryKey(off_t size) + : + node(NULL), + size(size) + { + } + + Node* node; + off_t size; +}; + + +// #pragma mark - SizeIndexGetPrimaryKey + + +class SizeIndexGetPrimaryKey { +public: + inline SizeIndexPrimaryKey operator()(Node* a) + { + return SizeIndexPrimaryKey(a); + } + + inline SizeIndexPrimaryKey operator()(Node* a) const + { + return SizeIndexPrimaryKey(a); + } +}; + + +// #pragma mark - SizeIndexPrimaryKeyCompare + + +class SizeIndexPrimaryKeyCompare { +public: + inline int operator()(const SizeIndexPrimaryKey &a, + const SizeIndexPrimaryKey &b) const + { + if (a.node != NULL && a.node == b.node) + return 0; + if (a.size < b.size) + return -1; + if (a.size > b.size) + return 1; + return 0; + } +}; + + +// #pragma mark - NodeTree + + +typedef TwoKeyAVLTree _NodeTree; +class SizeIndex::NodeTree : public _NodeTree {}; + + +// #pragma mark - IteratorList + + +class SizeIndex::IteratorList : public SinglyLinkedList {}; + + +// #pragma mark - Iterator + + +struct SizeIndex::IteratorPolicy { + typedef SizeIndex Index; + typedef off_t Value; + typedef SizeIndex::NodeTree NodeTree; + + static NodeTree* GetNodeTree(Index* index) + { + return index->fNodes; + } + + static void GetNodeValue(Node* node, void* buffer, size_t* _keyLength) + { + *(off_t*)buffer = node->FileSize(); + *_keyLength = sizeof(off_t); + } +}; + + +class SizeIndex::Iterator : public GenericIndexIterator, + public SinglyLinkedListLinkImpl { +public: + virtual void NodeChanged(Node* node, uint32 statFields, + const OldNodeAttributes& oldAttributes); +}; + + +// #pragma mark - SizeIndex + + +SizeIndex::SizeIndex() + : + Index(), + fNodes(NULL), + fIteratorsToUpdate(NULL) +{ +} + + +SizeIndex::~SizeIndex() +{ + if (IsListening()) + fVolume->RemoveNodeListener(this); + + ASSERT(fIteratorsToUpdate->IsEmpty()); + + delete fIteratorsToUpdate; + delete fNodes; +} + + +status_t +SizeIndex::Init(Volume* volume) +{ + status_t error = Index::Init(volume, "size", B_INT64_TYPE, true, + sizeof(off_t)); + if (error != B_OK) + return error; + + fVolume->AddNodeListener(this, NULL); + + fNodes = new(std::nothrow) NodeTree; + fIteratorsToUpdate = new(std::nothrow) IteratorList; + if (fNodes == NULL || fIteratorsToUpdate == NULL) + return B_NO_MEMORY; + + return B_OK; +} + + +int32 +SizeIndex::CountEntries() const +{ + return fNodes->CountItems(); +} + + +void +SizeIndex::NodeAdded(Node* node) +{ + fNodes->Insert(node); +} + + +void +SizeIndex::NodeRemoved(Node* node) +{ + fNodes->Remove(node, node); +} + + +void +SizeIndex::NodeChanged(Node* node, uint32 statFields, + const OldNodeAttributes& oldAttributes) +{ + IteratorList iterators; + iterators.MoveFrom(fIteratorsToUpdate); + + off_t oldSize = oldAttributes.FileSize(); + off_t newSize = node->FileSize(); + if (newSize == oldSize) + return; + + NodeTree::Iterator nodeIterator; + Node** foundNode = fNodes->Find(SizeIndexPrimaryKey(node, oldSize), node, + &nodeIterator); + + if (foundNode == NULL || *foundNode != node) + return; + + // move the iterators that point to the node to the previous node + for (IteratorList::Iterator it = iterators.GetIterator(); + Iterator* iterator = it.Next();) { + iterator->NodeChangeBegin(node); + } + + // remove and re-insert the node + nodeIterator.Remove(); + if (fNodes->Insert(node) != B_OK) { + fIteratorsToUpdate->MakeEmpty(); + return; + } + + // Move the iterators to the next node again. If the node hasn't changed + // its place, they will point to it again, otherwise to the node originally + // succeeding it. + for (IteratorList::Iterator it = iterators.GetIterator(); + Iterator* iterator = it.Next();) { + iterator->NodeChangeEnd(node); + } + + // update live queries + fVolume->UpdateLiveQueries(node, Name(), Type(), + (const uint8*)&oldSize, sizeof(oldSize), (const uint8*)&newSize, + sizeof(newSize)); +} + + +AbstractIndexIterator* +SizeIndex::InternalGetIterator() +{ + Iterator* iterator = new(std::nothrow) Iterator; + if (iterator != NULL) { + if (!iterator->SetTo(this, 0, true)) { + delete iterator; + iterator = NULL; + } + } + return iterator; +} + + +AbstractIndexIterator* +SizeIndex::InternalFind(const void* key, size_t length) +{ + if (!key || length != sizeof(off_t)) + return NULL; + Iterator* iterator = new(std::nothrow) Iterator; + if (iterator != NULL) { + if (!iterator->SetTo(this, *(const off_t*)key)) { + delete iterator; + iterator = NULL; + } + } + return iterator; +} + + +void +SizeIndex::_AddIteratorToUpdate(Iterator* iterator) +{ + fIteratorsToUpdate->Add(iterator); +} + + +// #pragma mark - Iterator + + +void +SizeIndex::Iterator::NodeChanged(Node* node, uint32 statFields, + const OldNodeAttributes& oldAttributes) +{ + fIndex->_AddIteratorToUpdate(this); +} diff --git a/src/add-ons/kernel/file_systems/packagefs/SizeIndex.h b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.h new file mode 100644 index 0000000000..3c8cb438f5 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.h @@ -0,0 +1,51 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef SIZE_INDEX_H +#define SIZE_INDEX_H + + +#include "Index.h" +#include "NodeListener.h" + + +class SizeIndex : public Index, private NodeListener { +public: + SizeIndex(); + virtual ~SizeIndex(); + + status_t Init(Volume* volume); + + virtual int32 CountEntries() const; + +private: + virtual void NodeAdded(Node* node); + virtual void NodeRemoved(Node* node); + virtual void NodeChanged(Node* node, uint32 statFields, + const OldNodeAttributes& oldAttributes); + +protected: + virtual AbstractIndexIterator* InternalGetIterator(); + virtual AbstractIndexIterator* InternalFind(const void* key, + size_t length); + +private: + struct IteratorPolicy; + class Iterator; + class IteratorList; + class NodeTree; + friend class Iterator; + friend struct IteratorPolicy; + +private: + void _AddIteratorToUpdate(Iterator* iterator); +// void _RemoveIterator(Iterator* iterator); + +private: + NodeTree* fNodes; + IteratorList* fIteratorsToUpdate; +}; + + +#endif // SIZE_INDEX_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 96966895c4..b386265b0f 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -41,6 +41,7 @@ #include "PackageLinksDirectory.h" #include "PackageSymlink.h" #include "Resolvable.h" +#include "SizeIndex.h" #include "UnpackingLeafNode.h" #include "UnpackingDirectory.h" #include "Version.h" @@ -510,17 +511,34 @@ Volume::Mount(const char* parameterString) RETURN_ERROR(error); // create the name index - NameIndex* index = new(std::nothrow) NameIndex; - if (index == NULL) - RETURN_ERROR(B_NO_MEMORY); + { + NameIndex* index = new(std::nothrow) NameIndex; + if (index == NULL) + RETURN_ERROR(B_NO_MEMORY); - error = index->Init(this); - if (error != B_OK) { - delete index; - RETURN_ERROR(error); + error = index->Init(this); + if (error != B_OK) { + delete index; + RETURN_ERROR(error); + } + + fIndices.Insert(index); } - fIndices.Insert(index); + // create the size index + { + SizeIndex* index = new(std::nothrow) SizeIndex; + if (index == NULL) + RETURN_ERROR(B_NO_MEMORY); + + error = index->Init(this); + if (error != B_OK) { + delete index; + RETURN_ERROR(error); + } + + fIndices.Insert(index); + } // get the mount parameters const char* packages = NULL;