kernel/EntryCache: Allocate and free entries without locks held.
Avoids some contention, but doesn't seem to speed things up much. Change-Id: I25be31ba4d91d5013bd09cf8c32635654aed2db2 Reviewed-on: https://review.haiku-os.org/c/haiku/+/9532 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
360544ed44
commit
b53996dc7f
@@ -108,44 +108,49 @@ EntryCache::Add(ino_t dirID, const char* name, ino_t nodeID, bool missing)
|
||||
{
|
||||
EntryCacheKey key(dirID, name);
|
||||
|
||||
WriteLocker _(fLock);
|
||||
|
||||
if (fGenerationCount == 0)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
EntryCacheEntry* entry = fEntries.Lookup(key);
|
||||
if (entry != NULL) {
|
||||
entry->node_id = nodeID;
|
||||
entry->missing = missing;
|
||||
if (entry->generation != fCurrentGeneration) {
|
||||
if (entry->index >= 0) {
|
||||
fGenerations[entry->generation].entries[entry->index] = NULL;
|
||||
_AddEntryToCurrentGeneration(entry);
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Avoid deadlock if system had to wait for free memory
|
||||
const size_t nameLen = strlen(name);
|
||||
entry = (EntryCacheEntry*)malloc_etc(sizeof(EntryCacheEntry) + nameLen,
|
||||
CACHE_DONT_WAIT_FOR_MEMORY);
|
||||
EntryCacheEntry* entry = (EntryCacheEntry*)malloc(sizeof(EntryCacheEntry) + nameLen);
|
||||
|
||||
if (entry == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
entry->node_id = nodeID;
|
||||
entry->dir_id = dirID;
|
||||
entry->hash = EntryCacheKey::Hash(dirID, name);
|
||||
entry->hash = key.hash;
|
||||
entry->missing = missing;
|
||||
entry->generation = fCurrentGeneration;
|
||||
entry->index = kEntryNotInArray;
|
||||
entry->generation = -1;
|
||||
memcpy(entry->name, name, nameLen + 1);
|
||||
|
||||
WriteLocker writeLocker(fLock);
|
||||
|
||||
if (fGenerationCount == 0) {
|
||||
free(entry);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
EntryCacheEntry* existingEntry = fEntries.Lookup(key);
|
||||
if (existingEntry != NULL) {
|
||||
free(entry);
|
||||
entry = existingEntry;
|
||||
|
||||
entry->node_id = nodeID;
|
||||
entry->missing = missing;
|
||||
if (entry->generation != fCurrentGeneration) {
|
||||
if (entry->index >= 0) {
|
||||
fGenerations[entry->generation].entries[entry->index] = NULL;
|
||||
|
||||
writeLocker.Detach();
|
||||
_AddEntryToCurrentGeneration(entry);
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
fEntries.Insert(entry);
|
||||
|
||||
writeLocker.Detach();
|
||||
_AddEntryToCurrentGeneration(entry);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -166,6 +171,7 @@ EntryCache::Remove(ino_t dirID, const char* name)
|
||||
if (entry->index >= 0) {
|
||||
// remove the entry from its generation and delete it
|
||||
fGenerations[entry->generation].entries[entry->index] = NULL;
|
||||
writeLocker.Unlock();
|
||||
free(entry);
|
||||
} else {
|
||||
// We can't free it, since another thread is about to try to move it
|
||||
@@ -221,14 +227,16 @@ EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID,
|
||||
|
||||
if (entry->index == kEntryRemoved) {
|
||||
// the entry has been removed in the meantime
|
||||
writeLocker.Unlock();
|
||||
free(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
_AddEntryToCurrentGeneration(entry);
|
||||
|
||||
_nodeID = entry->node_id;
|
||||
_missing = entry->missing;
|
||||
|
||||
writeLocker.Detach();
|
||||
_AddEntryToCurrentGeneration(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -252,7 +260,7 @@ EntryCache::DebugReverseLookup(ino_t nodeID, ino_t& _dirID)
|
||||
void
|
||||
EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
|
||||
{
|
||||
ASSERT_WRITE_LOCKED_RW_LOCK(&fLock);
|
||||
WriteLocker locker(fLock, true);
|
||||
|
||||
// the generation might not be full yet
|
||||
int32 index = fGenerations[fCurrentGeneration].next_index++;
|
||||
@@ -264,6 +272,7 @@ EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
|
||||
}
|
||||
|
||||
// we have to clear the oldest generation
|
||||
EntryCacheEntry* entriesToFree = NULL;
|
||||
const int32 newGeneration = (fCurrentGeneration + 1) % fGenerationCount;
|
||||
for (int32 i = 0; i < fGenerations[newGeneration].entries_size; i++) {
|
||||
EntryCacheEntry* otherEntry = fGenerations[newGeneration].entries[i];
|
||||
@@ -272,7 +281,9 @@ EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
|
||||
|
||||
fGenerations[newGeneration].entries[i] = NULL;
|
||||
fEntries.Remove(otherEntry);
|
||||
free(otherEntry);
|
||||
|
||||
otherEntry->hash_link = entriesToFree;
|
||||
entriesToFree = otherEntry;
|
||||
}
|
||||
|
||||
// set the new generation and add the entry
|
||||
@@ -281,4 +292,12 @@ EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
|
||||
fGenerations[newGeneration].next_index = 1;
|
||||
entry->generation = newGeneration;
|
||||
entry->index = 0;
|
||||
|
||||
// free the old entries
|
||||
locker.Unlock();
|
||||
while (entriesToFree != NULL) {
|
||||
EntryCacheEntry* next = entriesToFree->hash_link;
|
||||
free(entriesToFree);
|
||||
entriesToFree = next;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user