EntryCache: Add entry_cache_add_missing() for negative caching.
It provides a way for filesystems to cache a lookup failure and therefore prevents repeated lookups of missing entries. This is a common scenario for example in command lookup and compiling, where each directory in PATH or each include directory is searched for the given entry.
This commit is contained in:
@@ -104,6 +104,8 @@ extern status_t file_map_translate(void *map, off_t offset, size_t size,
|
|||||||
/* entry cache */
|
/* entry cache */
|
||||||
extern status_t entry_cache_add(dev_t mountID, ino_t dirID, const char* name,
|
extern status_t entry_cache_add(dev_t mountID, ino_t dirID, const char* name,
|
||||||
ino_t nodeID);
|
ino_t nodeID);
|
||||||
|
extern status_t entry_cache_add_missing(dev_t mountID, ino_t dirID,
|
||||||
|
const char* name);
|
||||||
extern status_t entry_cache_remove(dev_t mountID, ino_t dirID,
|
extern status_t entry_cache_remove(dev_t mountID, ino_t dirID,
|
||||||
const char* name);
|
const char* name);
|
||||||
|
|
||||||
|
|||||||
@@ -871,6 +871,7 @@
|
|||||||
|
|
||||||
/* entry cache */
|
/* entry cache */
|
||||||
#define entry_cache_add fssh_entry_cache_add
|
#define entry_cache_add fssh_entry_cache_add
|
||||||
|
#define entry_cache_add_missing fssh_entry_cache_add_missing
|
||||||
#define entry_cache_remove fssh_entry_cache_remove
|
#define entry_cache_remove fssh_entry_cache_remove
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -126,6 +126,8 @@ extern fssh_status_t fssh_file_map_translate(void *_map, fssh_off_t offset,
|
|||||||
extern fssh_status_t fssh_entry_cache_add(fssh_dev_t mountID,
|
extern fssh_status_t fssh_entry_cache_add(fssh_dev_t mountID,
|
||||||
fssh_ino_t dirID, const char* name,
|
fssh_ino_t dirID, const char* name,
|
||||||
fssh_ino_t nodeID);
|
fssh_ino_t nodeID);
|
||||||
|
extern fssh_status_t fssh_entry_cache_add_missing(fssh_dev_t mountID,
|
||||||
|
fssh_ino_t dirID, const char* name);
|
||||||
extern fssh_status_t fssh_entry_cache_remove(fssh_dev_t mountID,
|
extern fssh_status_t fssh_entry_cache_remove(fssh_dev_t mountID,
|
||||||
fssh_ino_t dirID, const char* name);
|
fssh_ino_t dirID, const char* name);
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ entry_cache_add(dev_t mountID, ino_t dirID, const char* name, ino_t nodeID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
entry_cache_add_missing(dev_t mountID, ino_t dirID, const char* name)
|
||||||
|
{
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
entry_cache_remove(dev_t mountID, ino_t dirID, const char* name)
|
entry_cache_remove(dev_t mountID, ino_t dirID, const char* name)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ EntryCache::Init()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
EntryCache::Add(ino_t dirID, const char* name, ino_t nodeID)
|
EntryCache::Add(ino_t dirID, const char* name, ino_t nodeID, bool missing)
|
||||||
{
|
{
|
||||||
EntryCacheKey key(dirID, name);
|
EntryCacheKey key(dirID, name);
|
||||||
|
|
||||||
@@ -99,6 +99,7 @@ EntryCache::Add(ino_t dirID, const char* name, ino_t nodeID)
|
|||||||
EntryCacheEntry* entry = fEntries.Lookup(key);
|
EntryCacheEntry* entry = fEntries.Lookup(key);
|
||||||
if (entry != NULL) {
|
if (entry != NULL) {
|
||||||
entry->node_id = nodeID;
|
entry->node_id = nodeID;
|
||||||
|
entry->missing = missing;
|
||||||
if (entry->generation != fCurrentGeneration) {
|
if (entry->generation != fCurrentGeneration) {
|
||||||
if (entry->index >= 0) {
|
if (entry->index >= 0) {
|
||||||
fGenerations[entry->generation].entries[entry->index] = NULL;
|
fGenerations[entry->generation].entries[entry->index] = NULL;
|
||||||
@@ -114,6 +115,7 @@ EntryCache::Add(ino_t dirID, const char* name, ino_t nodeID)
|
|||||||
|
|
||||||
entry->node_id = nodeID;
|
entry->node_id = nodeID;
|
||||||
entry->dir_id = dirID;
|
entry->dir_id = dirID;
|
||||||
|
entry->missing = missing;
|
||||||
entry->generation = fCurrentGeneration;
|
entry->generation = fCurrentGeneration;
|
||||||
entry->index = kEntryNotInArray;
|
entry->index = kEntryNotInArray;
|
||||||
strcpy(entry->name, name);
|
strcpy(entry->name, name);
|
||||||
@@ -155,7 +157,8 @@ EntryCache::Remove(ino_t dirID, const char* name)
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID)
|
EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID,
|
||||||
|
bool& _missing)
|
||||||
{
|
{
|
||||||
EntryCacheKey key(dirID, name);
|
EntryCacheKey key(dirID, name);
|
||||||
|
|
||||||
@@ -171,6 +174,7 @@ EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID)
|
|||||||
// The entry is already in the current generation or is being moved to
|
// The entry is already in the current generation or is being moved to
|
||||||
// it by another thread.
|
// it by another thread.
|
||||||
_nodeID = entry->node_id;
|
_nodeID = entry->node_id;
|
||||||
|
_missing = entry->missing;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,6 +188,7 @@ EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID)
|
|||||||
fGenerations[fCurrentGeneration].entries[index] = entry;
|
fGenerations[fCurrentGeneration].entries[index] = entry;
|
||||||
entry->index = index;
|
entry->index = index;
|
||||||
_nodeID = entry->node_id;
|
_nodeID = entry->node_id;
|
||||||
|
_missing = entry->missing;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,6 +206,7 @@ EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID)
|
|||||||
_AddEntryToCurrentGeneration(entry);
|
_AddEntryToCurrentGeneration(entry);
|
||||||
|
|
||||||
_nodeID = entry->node_id;
|
_nodeID = entry->node_id;
|
||||||
|
_missing = entry->missing;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ struct EntryCacheEntry {
|
|||||||
ino_t dir_id;
|
ino_t dir_id;
|
||||||
int32 generation;
|
int32 generation;
|
||||||
int32 index;
|
int32 index;
|
||||||
|
bool missing;
|
||||||
char name[1];
|
char name[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -87,12 +88,12 @@ public:
|
|||||||
status_t Init();
|
status_t Init();
|
||||||
|
|
||||||
status_t Add(ino_t dirID, const char* name,
|
status_t Add(ino_t dirID, const char* name,
|
||||||
ino_t nodeID);
|
ino_t nodeID, bool missing);
|
||||||
|
|
||||||
status_t Remove(ino_t dirID, const char* name);
|
status_t Remove(ino_t dirID, const char* name);
|
||||||
|
|
||||||
bool Lookup(ino_t dirID, const char* name,
|
bool Lookup(ino_t dirID, const char* name,
|
||||||
ino_t& nodeID);
|
ino_t& nodeID, bool& missing);
|
||||||
|
|
||||||
const char* DebugReverseLookup(ino_t nodeID, ino_t& _dirID);
|
const char* DebugReverseLookup(ino_t nodeID, ino_t& _dirID);
|
||||||
|
|
||||||
|
|||||||
@@ -2089,9 +2089,12 @@ static status_t
|
|||||||
lookup_dir_entry(struct vnode* dir, const char* name, struct vnode** _vnode)
|
lookup_dir_entry(struct vnode* dir, const char* name, struct vnode** _vnode)
|
||||||
{
|
{
|
||||||
ino_t id;
|
ino_t id;
|
||||||
|
bool missing;
|
||||||
|
|
||||||
if (dir->mount->entry_cache.Lookup(dir->id, name, id))
|
if (dir->mount->entry_cache.Lookup(dir->id, name, id, missing)) {
|
||||||
return get_vnode(dir->device, id, _vnode, true, false);
|
return missing ? B_ENTRY_NOT_FOUND
|
||||||
|
: get_vnode(dir->device, id, _vnode, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
status_t status = FS_CALL(dir, lookup, name, &id);
|
status_t status = FS_CALL(dir, lookup, name, &id);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
@@ -4011,7 +4014,22 @@ entry_cache_add(dev_t mountID, ino_t dirID, const char* name, ino_t nodeID)
|
|||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
return mount->entry_cache.Add(dirID, name, nodeID);
|
return mount->entry_cache.Add(dirID, name, nodeID, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" status_t
|
||||||
|
entry_cache_add_missing(dev_t mountID, ino_t dirID, const char* name)
|
||||||
|
{
|
||||||
|
// lookup mount -- the caller is required to make sure that the mount
|
||||||
|
// won't go away
|
||||||
|
MutexLocker locker(sMountMutex);
|
||||||
|
struct fs_mount* mount = find_mount(mountID);
|
||||||
|
if (mount == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
return mount->entry_cache.Add(dirID, name, -1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2277,6 +2277,15 @@ fssh_entry_cache_add(fssh_dev_t mountID, fssh_ino_t dirID, const char* name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" fssh_status_t
|
||||||
|
fssh_entry_cache_add_missing(fssh_dev_t mountID, fssh_ino_t dirID,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
// We don't implement an entry cache in the FS shell.
|
||||||
|
return FSSH_B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" fssh_status_t
|
extern "C" fssh_status_t
|
||||||
fssh_entry_cache_remove(fssh_dev_t mountID, fssh_ino_t dirID, const char* name)
|
fssh_entry_cache_remove(fssh_dev_t mountID, fssh_ino_t dirID, const char* name)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user