#ifndef ENTRY_CACHE_H
#define ENTRY_CACHE_H
#include <stdlib.h>
#include <util/AutoLock.h>
#include <util/AtomicsHashTable.h>
#include <util/DoublyLinkedList.h>
#include <util/StringHash.h>
struct EntryCacheKey {
EntryCacheKey(ino_t dirID, const char* name, const uint32* _hash = NULL)
:
dir_id(dirID),
name(name)
{
if (_hash == NULL) {
hash = Hash(dirID, name);
} else {
hash = *_hash;
}
}
static uint32 Hash(ino_t dirID, const char* name)
{
return (uint32)dirID ^ (uint32)(dirID >> 32) ^ hash_hash_string(name);
}
ino_t dir_id;
const char* name;
uint32 hash;
};
struct EntryCacheEntry {
EntryCacheEntry* hash_link;
ino_t node_id;
ino_t dir_id;
uint32 hash;
int32 generation;
int32 index;
bool missing;
char name[1];
};
struct EntryCacheGeneration {
int32 next_index;
int32 entries_size;
EntryCacheEntry** entries;
EntryCacheGeneration();
~EntryCacheGeneration();
status_t Init(int32 entriesSize);
};
struct EntryCacheHashDefinition {
typedef EntryCacheKey KeyType;
typedef EntryCacheEntry ValueType;
uint32 HashKey(const EntryCacheKey& key) const
{
return key.hash;
}
uint32 Hash(const EntryCacheEntry* value) const
{
return value->hash;
}
EntryCacheKey Key(const EntryCacheEntry* value) const
{
return EntryCacheKey(value->dir_id, value->name, &value->hash);
}
bool Compare(const EntryCacheKey& key, const EntryCacheEntry* value) const
{
if (key.hash != value->hash)
return false;
return value->dir_id == key.dir_id
&& strcmp(value->name, key.name) == 0;
}
EntryCacheEntry*& GetLink(EntryCacheEntry* value) const
{
return value->hash_link;
}
};
class EntryCache {
public:
EntryCache();
~EntryCache();
status_t Init();
status_t Add(ino_t dirID, const char* name,
ino_t nodeID, bool missing);
status_t Remove(ino_t dirID, const char* name);
bool Lookup(ino_t dirID, const char* name,
ino_t& nodeID, bool& missing);
const char* DebugReverseLookup(ino_t nodeID, ino_t& _dirID);
private:
typedef AtomicsHashTable<EntryCacheHashDefinition> EntryTable;
typedef DoublyLinkedList<EntryCacheEntry> EntryList;
private:
bool _AddEntryToCurrentGeneration(
EntryCacheEntry* entry, bool move);
private:
rw_lock fLock;
EntryTable fEntries;
int32 fGenerationCount;
EntryCacheGeneration* fGenerations;
int32 fCurrentGeneration;
};
#endif