diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index 676e35f790..119c77b67f 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -18,6 +18,7 @@ HAIKU_PACKAGE_FS_SOURCES = GlobalFactory.cpp Index.cpp kernel_interface.cpp + LastModifiedIndex.cpp NameIndex.cpp Node.cpp NodeListener.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp new file mode 100644 index 0000000000..0ce010f316 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp @@ -0,0 +1,290 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "LastModifiedIndex.h" + +#include + +#include + +#include +#include + +#include "DebugSupport.h" +#include "IndexImpl.h" +#include "Node.h" +#include "Volume.h" + + +// #pragma mark - LastModifiedIndexPrimaryKey + + +class LastModifiedIndexPrimaryKey { +public: + LastModifiedIndexPrimaryKey(Node* node, time_t modified) + : + node(node), + modified(modified) + { + } + + LastModifiedIndexPrimaryKey(Node* node) + : + node(node), + modified(node->ModifiedTime().tv_sec) + { + } + + LastModifiedIndexPrimaryKey(time_t modified) + : + node(NULL), + modified(modified) + { + } + + Node* node; + time_t modified; +}; + + +// #pragma mark - LastModifiedIndexGetPrimaryKey + + +class LastModifiedIndexGetPrimaryKey { +public: + inline LastModifiedIndexPrimaryKey operator()(Node* a) + { + return LastModifiedIndexPrimaryKey(a); + } + + inline LastModifiedIndexPrimaryKey operator()(Node* a) const + { + return LastModifiedIndexPrimaryKey(a); + } +}; + + +// #pragma mark - LastModifiedIndexPrimaryKeyCompare + + +class LastModifiedIndexPrimaryKeyCompare { +public: + inline int operator()(const LastModifiedIndexPrimaryKey &a, + const LastModifiedIndexPrimaryKey &b) const + { + if (a.node != NULL && a.node == b.node) + return 0; + if (a.modified < b.modified) + return -1; + if (a.modified > b.modified) + return 1; + return 0; + } +}; + + +// #pragma mark - NodeTree + + +typedef TwoKeyAVLTree + _NodeTree; +class LastModifiedIndex::NodeTree : public _NodeTree {}; + + +// #pragma mark - IteratorList + + +class LastModifiedIndex::IteratorList : public SinglyLinkedList {}; + + +// #pragma mark - Iterator + + +struct LastModifiedIndex::IteratorPolicy { + typedef LastModifiedIndex Index; + typedef time_t Value; + typedef LastModifiedIndex::NodeTree NodeTree; + + static NodeTree* GetNodeTree(Index* index) + { + return index->fNodes; + } + + static void GetNodeValue(Node* node, void* buffer, size_t* _keyLength) + { + *(time_t*)buffer = node->ModifiedTime().tv_sec; + *_keyLength = sizeof(time_t); + } +}; + + +class LastModifiedIndex::Iterator : public GenericIndexIterator, + public SinglyLinkedListLinkImpl { +public: + virtual void NodeChanged(Node* node, uint32 statFields, + const OldNodeAttributes& oldAttributes); +}; + + +// #pragma mark - LastModifiedIndex + + +LastModifiedIndex::LastModifiedIndex() + : + Index(), + fNodes(NULL), + fIteratorsToUpdate(NULL) +{ +} + + +LastModifiedIndex::~LastModifiedIndex() +{ + if (IsListening()) + fVolume->RemoveNodeListener(this); + + ASSERT(fIteratorsToUpdate->IsEmpty()); + + delete fIteratorsToUpdate; + delete fNodes; +} + + +status_t +LastModifiedIndex::Init(Volume* volume) +{ + status_t error = Index::Init(volume, "last_modified", B_INT32_TYPE, true, + sizeof(time_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 +LastModifiedIndex::CountEntries() const +{ + return fNodes->CountItems(); +} + + +void +LastModifiedIndex::NodeAdded(Node* node) +{ + fNodes->Insert(node); +} + + +void +LastModifiedIndex::NodeRemoved(Node* node) +{ + fNodes->Remove(node, node); +} + + +void +LastModifiedIndex::NodeChanged(Node* node, uint32 statFields, + const OldNodeAttributes& oldAttributes) +{ + IteratorList iterators; + iterators.MoveFrom(fIteratorsToUpdate); + + time_t oldLastModified = oldAttributes.ModifiedTime().tv_sec; + time_t newLastModified = node->ModifiedTime().tv_sec; + if (newLastModified == oldLastModified) + return; + + NodeTree::Iterator nodeIterator; + Node** foundNode = fNodes->Find( + LastModifiedIndexPrimaryKey(node, oldLastModified), 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*)&oldLastModified, sizeof(oldLastModified), + (const uint8*)&newLastModified, sizeof(newLastModified)); +} + + +AbstractIndexIterator* +LastModifiedIndex::InternalGetIterator() +{ + Iterator* iterator = new(std::nothrow) Iterator; + if (iterator != NULL) { + if (!iterator->SetTo(this, 0, true)) { + delete iterator; + iterator = NULL; + } + } + return iterator; +} + + +AbstractIndexIterator* +LastModifiedIndex::InternalFind(const void* key, size_t length) +{ + if (!key || length != sizeof(time_t)) + return NULL; + Iterator* iterator = new(std::nothrow) Iterator; + if (iterator != NULL) { + if (!iterator->SetTo(this, *(const time_t*)key)) { + delete iterator; + iterator = NULL; + } + } + return iterator; +} + + +void +LastModifiedIndex::_AddIteratorToUpdate(Iterator* iterator) +{ + fIteratorsToUpdate->Add(iterator); +} + + +// #pragma mark - Iterator + + +void +LastModifiedIndex::Iterator::NodeChanged(Node* node, uint32 statFields, + const OldNodeAttributes& oldAttributes) +{ + fIndex->_AddIteratorToUpdate(this); +} diff --git a/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.h b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.h new file mode 100644 index 0000000000..5b64241a8c --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.h @@ -0,0 +1,50 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef LAST_MODIFIED_INDEX_H +#define LAST_MODIFIED_INDEX_H + + +#include "Index.h" +#include "NodeListener.h" + + +class LastModifiedIndex : public Index, private NodeListener { +public: + LastModifiedIndex(); + virtual ~LastModifiedIndex(); + + 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); + +private: + NodeTree* fNodes; + IteratorList* fIteratorsToUpdate; +}; + + +#endif // LAST_MODIFIED_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 b386265b0f..04d993404d 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -32,6 +32,7 @@ #include "DebugSupport.h" #include "kernel_interface.h" +#include "LastModifiedIndex.h" #include "NameIndex.h" #include "OldUnpackingNodeAttributes.h" #include "PackageDirectory.h" @@ -540,6 +541,21 @@ Volume::Mount(const char* parameterString) fIndices.Insert(index); } + // create the last modified index + { + LastModifiedIndex* index = new(std::nothrow) LastModifiedIndex; + 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; const char* volumeName = NULL;