buildtools/jam/StatCacheServerImpl.h
Ingo Weinhold f4194f2ee8 StatCacheServer changes:
* A Node can no longer have a referring "." or ".." Entry (except the root
  directory), not even temporarily. This rules out cycles when resolving
  paths.
* Made the code more robust against missed node monitoring messages. If
  an entry is encountered that shouldn't be there, it is removed. As
  implemented before, a Node could end up with a NULL referring Entry,
  leading to a crash when an Entry that references the Node was moved.
  Missing node monitoring messages is actually virtually impossible,
  since a dedicated looper does nothing else but pushing those into a
  separate queue, but nevertheless Stippi seems to have managed the trick. :-)


git-svn-id: file:///srv/svn/repos/haiku/buildtools/trunk@21307 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-06-03 16:25:35 +00:00

267 lines
4.9 KiB
C++

// StatCacheServerImpl.h
#ifndef STAT_CACHE_SERVER_IMPL_H
#define STAT_CACHE_SERVER_IMPL_H
#include <hash_map>
#include <string>
#include <Entry.h>
#include <MessageQueue.h>
#include <Node.h>
#include <OS.h>
class Directory;
class Entry;
class Node;
class SymLink;
// NodeRefHash
struct NodeRefHash
{
size_t operator()(const node_ref &nodeRef) const;
};
// EntryRefHash
struct EntryRefHash
{
size_t operator()(const entry_ref &entryRef) const;
};
// Referencable
class Referencable {
public:
Referencable()
: fReferenceCount(1),
fReferenceBaseCount(0)
{
}
virtual ~Referencable()
{
}
void AddReference()
{
fReferenceCount++;
}
bool RemoveReference()
{
if (--fReferenceCount <= fReferenceBaseCount) {
Unreferenced();
return true;
}
return false;
}
int32 CountReferences() const
{
return fReferenceCount;
}
protected:
virtual void Unreferenced() {};
protected:
int32 fReferenceCount;
int32 fReferenceBaseCount;
bool fDeleteWhenUnreferenced;
};
// Entry
class Entry : public Referencable {
public:
Entry();
~Entry();
status_t SetTo(Directory *parent, const char *name);
Directory *GetParent() const;
const char *GetName() const;
void SetNode(Node *node);
Node *GetNode() const;
void SetPrevious(Entry *entry);
Entry *GetPrevious() const;
void SetNext(Entry *entry);
Entry *GetNext() const;
entry_ref GetEntryRef() const;
status_t GetPath(string& path);
protected:
virtual void Unreferenced();
private:
Directory *fParent;
string fName;
Node *fNode;
Entry *fPrevious;
Entry *fNext;
};
// Node
class Node : public Referencable {
public:
Node(const struct stat &st);
virtual ~Node();
virtual status_t SetTo(Entry *entry);
status_t GetPath(string& path);
const struct stat &GetStat() const;
status_t GetStat(struct stat *st);
status_t UpdateStat();
void MarkStatInvalid();
void SetEntry(Entry *entry);
Entry *GetEntry() const;
node_ref GetNodeRef() const;
protected:
virtual void Unreferenced();
protected:
Entry *fEntry;
struct stat fStat;
bool fStatValid;
};
// Directory
class Directory : public Node {
public:
Directory(const struct stat &st);
~Directory();
virtual status_t SetTo(Entry *entry);
status_t FindEntry(const char *name, Entry **entry);
Entry *GetFirstEntry() const;
Entry *GetNextEntry(Entry *entry) const;
status_t ReadAllEntries();
bool IsComplete() const;
void AddEntry(Entry *entry);
void RemoveEntry(Entry *entry);
private:
Entry *fFirstEntry;
Entry *fLastEntry;
bool fIsComplete;
};
// SymLink
class SymLink : public Node {
public:
SymLink(const struct stat &st);
~SymLink();
virtual status_t SetTo(Entry *entry);
const char *GetTarget() const;
private:
string fTarget;
};
// NodeMonitor
class NodeMonitor : public BLooper {
public:
NodeMonitor();
virtual ~NodeMonitor();
status_t Init();
virtual void MessageReceived(BMessage *message);
status_t StartWatching(Node *node);
status_t StopWatching(Node *node);
status_t GetNextMonitoringMessage(BMessage **message);
private:
int32 fCurrentNodeMonitorLimit;
BMessageQueue fMessageQueue;
sem_id fMessageCountSem;
};
// PathResolver
class PathResolver {
public:
PathResolver();
status_t FindEntry(const char *path, bool traverse, Entry **_entry);
status_t FindEntry(Entry *entry, const char *path, bool traverse,
Entry **_entry);
status_t FindNode(const char *path, bool traverse, Node **node);
status_t ResolveSymlink(Node *node, Node **_node);
status_t ResolveSymlink(Node *node, Entry **entry);
status_t ResolveSymlink(Entry *entry, Entry **_entry);
private:
int32 fSymLinkCounter;
};
// NodeManager
class NodeManager : public BLocker {
public:
NodeManager();
~NodeManager();
static NodeManager *GetDefault();
status_t Init();
Directory *GetRootDirectory() const;
Node *GetNode(const node_ref &nodeRef);
Entry *GetEntry(const entry_ref &entryRef);
status_t CreateEntry(const entry_ref &entryRef, const node_ref *nodeRef,
Entry **_entry);
status_t CreateDirectory(const node_ref &nodeRef, Directory **_dir);
void RemoveEntry(Entry *entry);
void MoveEntry(Entry *entry, const entry_ref &newRef,
const node_ref &nodeRef);
void EntryUnreferenced(Entry *entry);
void NodeUnreferenced(Node *node);
status_t StartWatching(Node *node);
status_t StopWatching(Node *node);
private:
static int32 _NodeMonitoringProcessorEntry(void *data);
int32 _NodeMonitoringProcessor();
status_t _CreateNode(Entry *entry, Node **_node);
void _EntryCreated(BMessage *message);
void _EntryRemoved(BMessage *message);
void _EntryMoved(BMessage *message);
void _StatChanged(BMessage *message);
private:
typedef hash_map<entry_ref, Entry*, EntryRefHash> EntryMap;
typedef hash_map<node_ref, Node*, NodeRefHash> NodeMap;
EntryMap fEntries;
NodeMap fNodes;
Directory *fRootDirectory;
NodeMonitor *fNodeMonitor;
thread_id fNodeMonitoringProcessor;
static NodeManager sManager;
};
#endif // STAT_CACHE_SERVER_IMPL_H