Add size index support

* Add class SizeIndex.
* Create and add an instance of it in Volume mount.
This commit is contained in:
Ingo Weinhold
2011-07-17 16:55:07 +02:00
parent d56e19fb9e
commit d35565bed0
4 changed files with 366 additions and 8 deletions
@@ -38,6 +38,7 @@ HAIKU_PACKAGE_FS_SOURCES =
PackageSymlink.cpp
Resolvable.cpp
ResolvableFamily.cpp
SizeIndex.cpp
UnpackingAttributeCookie.cpp
UnpackingAttributeDirectoryCookie.cpp
UnpackingDirectory.cpp
@@ -0,0 +1,288 @@
/*
* Copyright 2011, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "SizeIndex.h"
#include <new>
#include <TypeConstants.h>
#include <util/SinglyLinkedList.h>
#include <util/TwoKeyAVLTree.h>
#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<Node*, SizeIndexPrimaryKey, SizeIndexPrimaryKeyCompare,
SizeIndexGetPrimaryKey> _NodeTree;
class SizeIndex::NodeTree : public _NodeTree {};
// #pragma mark - IteratorList
class SizeIndex::IteratorList : public SinglyLinkedList<Iterator> {};
// #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<IteratorPolicy>,
public SinglyLinkedListLinkImpl<Iterator> {
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);
}
@@ -0,0 +1,51 @@
/*
* Copyright 2011, Ingo Weinhold, [email protected].
* 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
@@ -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;