* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "LastModifiedIndex.h"
#include <new>
#include <TypeConstants.h>
#include <util/SinglyLinkedList.h>
#include "DebugSupport.h"
#include "IndexImpl.h"
#include "Node.h"
#include "TwoKeyAVLTree.h"
#include "Volume.h"
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;
};
class LastModifiedIndexGetPrimaryKey {
public:
inline LastModifiedIndexPrimaryKey operator()(Node* a)
{
return LastModifiedIndexPrimaryKey(a);
}
inline LastModifiedIndexPrimaryKey operator()(Node* a) const
{
return LastModifiedIndexPrimaryKey(a);
}
};
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;
}
};
typedef TwoKeyAVLTree<Node*, LastModifiedIndexPrimaryKey,
LastModifiedIndexPrimaryKeyCompare, LastModifiedIndexGetPrimaryKey>
_NodeTree;
class LastModifiedIndex::NodeTree : public _NodeTree {};
class LastModifiedIndex::IteratorList : public SinglyLinkedList<Iterator> {};
struct LastModifiedIndex::IteratorPolicy {
typedef LastModifiedIndex Index;
typedef time_t Value;
typedef LastModifiedIndex::NodeTree NodeTree;
typedef GenericIndexIteratorTreePolicy<IteratorPolicy> TreePolicy;
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<IteratorPolicy>,
public SinglyLinkedListLinkImpl<Iterator> {
public:
virtual void NodeChanged(Node* node, uint32 statFields,
const OldNodeAttributes& oldAttributes);
};
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.TakeFrom(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;
for (IteratorList::ConstIterator it = iterators.GetIterator();
Iterator* iterator = it.Next();) {
iterator->NodeChangeBegin(node);
}
nodeIterator.Remove();
if (fNodes->Insert(node) != B_OK) {
fIteratorsToUpdate->MakeEmpty();
return;
}
for (IteratorList::ConstIterator it = iterators.GetIterator();
Iterator* iterator = it.Next();) {
iterator->NodeChangeEnd(node);
}
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 (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);
}
void
LastModifiedIndex::Iterator::NodeChanged(Node* node, uint32 statFields,
const OldNodeAttributes& oldAttributes)
{
fIndex->_AddIteratorToUpdate(this);
}