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);
|
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);
|
const size_t nameLen = strlen(name);
|
||||||
entry = (EntryCacheEntry*)malloc_etc(sizeof(EntryCacheEntry) + nameLen,
|
EntryCacheEntry* entry = (EntryCacheEntry*)malloc(sizeof(EntryCacheEntry) + nameLen);
|
||||||
CACHE_DONT_WAIT_FOR_MEMORY);
|
|
||||||
|
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
entry->node_id = nodeID;
|
entry->node_id = nodeID;
|
||||||
entry->dir_id = dirID;
|
entry->dir_id = dirID;
|
||||||
entry->hash = EntryCacheKey::Hash(dirID, name);
|
entry->hash = key.hash;
|
||||||
entry->missing = missing;
|
entry->missing = missing;
|
||||||
entry->generation = fCurrentGeneration;
|
|
||||||
entry->index = kEntryNotInArray;
|
entry->index = kEntryNotInArray;
|
||||||
|
entry->generation = -1;
|
||||||
memcpy(entry->name, name, nameLen + 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);
|
fEntries.Insert(entry);
|
||||||
|
|
||||||
|
writeLocker.Detach();
|
||||||
_AddEntryToCurrentGeneration(entry);
|
_AddEntryToCurrentGeneration(entry);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,6 +171,7 @@ EntryCache::Remove(ino_t dirID, const char* name)
|
|||||||
if (entry->index >= 0) {
|
if (entry->index >= 0) {
|
||||||
// remove the entry from its generation and delete it
|
// remove the entry from its generation and delete it
|
||||||
fGenerations[entry->generation].entries[entry->index] = NULL;
|
fGenerations[entry->generation].entries[entry->index] = NULL;
|
||||||
|
writeLocker.Unlock();
|
||||||
free(entry);
|
free(entry);
|
||||||
} else {
|
} else {
|
||||||
// We can't free it, since another thread is about to try to move it
|
// 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) {
|
if (entry->index == kEntryRemoved) {
|
||||||
// the entry has been removed in the meantime
|
// the entry has been removed in the meantime
|
||||||
|
writeLocker.Unlock();
|
||||||
free(entry);
|
free(entry);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_AddEntryToCurrentGeneration(entry);
|
|
||||||
|
|
||||||
_nodeID = entry->node_id;
|
_nodeID = entry->node_id;
|
||||||
_missing = entry->missing;
|
_missing = entry->missing;
|
||||||
|
|
||||||
|
writeLocker.Detach();
|
||||||
|
_AddEntryToCurrentGeneration(entry);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +260,7 @@ EntryCache::DebugReverseLookup(ino_t nodeID, ino_t& _dirID)
|
|||||||
void
|
void
|
||||||
EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
|
EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
|
||||||
{
|
{
|
||||||
ASSERT_WRITE_LOCKED_RW_LOCK(&fLock);
|
WriteLocker locker(fLock, true);
|
||||||
|
|
||||||
// the generation might not be full yet
|
// the generation might not be full yet
|
||||||
int32 index = fGenerations[fCurrentGeneration].next_index++;
|
int32 index = fGenerations[fCurrentGeneration].next_index++;
|
||||||
@@ -264,6 +272,7 @@ EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we have to clear the oldest generation
|
// we have to clear the oldest generation
|
||||||
|
EntryCacheEntry* entriesToFree = NULL;
|
||||||
const int32 newGeneration = (fCurrentGeneration + 1) % fGenerationCount;
|
const int32 newGeneration = (fCurrentGeneration + 1) % fGenerationCount;
|
||||||
for (int32 i = 0; i < fGenerations[newGeneration].entries_size; i++) {
|
for (int32 i = 0; i < fGenerations[newGeneration].entries_size; i++) {
|
||||||
EntryCacheEntry* otherEntry = fGenerations[newGeneration].entries[i];
|
EntryCacheEntry* otherEntry = fGenerations[newGeneration].entries[i];
|
||||||
@@ -272,7 +281,9 @@ EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
|
|||||||
|
|
||||||
fGenerations[newGeneration].entries[i] = NULL;
|
fGenerations[newGeneration].entries[i] = NULL;
|
||||||
fEntries.Remove(otherEntry);
|
fEntries.Remove(otherEntry);
|
||||||
free(otherEntry);
|
|
||||||
|
otherEntry->hash_link = entriesToFree;
|
||||||
|
entriesToFree = otherEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the new generation and add the entry
|
// set the new generation and add the entry
|
||||||
@@ -281,4 +292,12 @@ EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
|
|||||||
fGenerations[newGeneration].next_index = 1;
|
fGenerations[newGeneration].next_index = 1;
|
||||||
entry->generation = newGeneration;
|
entry->generation = newGeneration;
|
||||||
entry->index = 0;
|
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