Refactor placeholder cacheing
This commit is contained in:
@@ -24,6 +24,87 @@
|
||||
|
||||
namespace sts::ncm::impl {
|
||||
|
||||
Result PlaceHolderAccessor::Open(FILE** out_handle, PlaceHolderId placeholder_id) {
|
||||
if (this->LoadFromCache(out_handle, placeholder_id)) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
char placeholder_path[FS_MAX_PATH] = {0};
|
||||
this->MakePath(placeholder_path, placeholder_id);
|
||||
|
||||
FILE* f = nullptr;
|
||||
R_TRY(OpenFile(&f, placeholder_path, FS_OPEN_WRITE));
|
||||
|
||||
*out_handle = f;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
bool PlaceHolderAccessor::LoadFromCache(FILE** out_handle, PlaceHolderId placeholder_id) {
|
||||
std::scoped_lock lk(this->cache_mutex);
|
||||
CacheEntry *entry = this->FindInCache(placeholder_id);
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
*out_handle = entry->handle;
|
||||
entry->id = InvalidUuid;
|
||||
entry->handle = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
PlaceHolderAccessor::CacheEntry *PlaceHolderAccessor::FindInCache(PlaceHolderId placeholder_id) {
|
||||
for (size_t i = 0; i < MaxCaches; i++) {
|
||||
if (placeholder_id == this->caches[i].id) {
|
||||
return &this->caches[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PlaceHolderAccessor::CacheEntry *PlaceHolderAccessor::GetFreeEntry() {
|
||||
/* Try to find an already free entry. */
|
||||
CacheEntry* entry = this->FindInCache(InvalidUuid);
|
||||
|
||||
if (entry) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Get the oldest entry. */
|
||||
{
|
||||
entry = &this->caches[0];
|
||||
for (size_t i = 1; i < MaxCaches; i++) {
|
||||
if (entry->counter > this->caches[i].counter) {
|
||||
entry = &this->caches[i];
|
||||
}
|
||||
}
|
||||
this->Invalidate(entry);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
void PlaceHolderAccessor::StoreToCache(FILE* handle, PlaceHolderId placeholder_id) {
|
||||
std::scoped_lock lk(this->cache_mutex);
|
||||
CacheEntry *entry = this->GetFreeEntry();
|
||||
entry->id = placeholder_id;
|
||||
entry->handle = handle;
|
||||
entry->counter = this->cur_counter++;
|
||||
}
|
||||
|
||||
void PlaceHolderAccessor::Invalidate(CacheEntry *entry) {
|
||||
if (entry != nullptr) {
|
||||
if (entry->handle != nullptr) {
|
||||
fflush(entry->handle);
|
||||
fclose(entry->handle);
|
||||
entry->handle = nullptr;
|
||||
}
|
||||
entry->id = InvalidUuid;
|
||||
}
|
||||
}
|
||||
|
||||
void PlaceHolderAccessor::Initialize(char* root, MakePlaceHolderPathFunc path_func, bool delay_flush) {
|
||||
this->root_path = root;
|
||||
this->make_placeholder_path_func = path_func;
|
||||
this->delay_flush = delay_flush;
|
||||
}
|
||||
|
||||
unsigned int PlaceHolderAccessor::GetDirectoryDepth() {
|
||||
if (this->make_placeholder_path_func == static_cast<MakePlaceHolderPathFunc>(path::MakePlaceHolderPathFlat)) {
|
||||
return 1;
|
||||
@@ -34,37 +115,18 @@ namespace sts::ncm::impl {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
void PlaceHolderAccessor::GetPlaceHolderPathUncached(char* placeholder_path_out, PlaceHolderId placeholder_id) {
|
||||
std::scoped_lock<HosMutex> lock(this->cache_mutex);
|
||||
|
||||
if (placeholder_id != InvalidUuid) {
|
||||
CacheEntry* found_cache = NULL;
|
||||
|
||||
for (size_t i = 0; i < PlaceHolderAccessor::MaxCaches; i++) {
|
||||
CacheEntry* cache = &this->caches[i];
|
||||
|
||||
if (placeholder_id == cache->id) {
|
||||
found_cache = cache;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_cache) {
|
||||
/* Flush and close */
|
||||
fflush(found_cache->handle);
|
||||
fclose(found_cache->handle);
|
||||
std::fill(found_cache->id.uuid, found_cache->id.uuid + sizeof(PlaceHolderId), 0);
|
||||
}
|
||||
}
|
||||
|
||||
this->GetPlaceHolderPath(placeholder_path_out, placeholder_id);
|
||||
void PlaceHolderAccessor::GetPath(char* placeholder_path_out, PlaceHolderId placeholder_id) {
|
||||
std::scoped_lock lock(this->cache_mutex);
|
||||
CacheEntry* entry = this->FindInCache(placeholder_id);
|
||||
this->Invalidate(entry);
|
||||
this->MakePath(placeholder_path_out, placeholder_id);
|
||||
}
|
||||
|
||||
Result PlaceHolderAccessor::Create(PlaceHolderId placeholder_id, size_t size) {
|
||||
char placeholder_path[FS_MAX_PATH] = {0};
|
||||
|
||||
this->EnsureRecursively(placeholder_id);
|
||||
this->GetPlaceHolderPathUncached(placeholder_path, placeholder_id);
|
||||
this->GetPath(placeholder_path, placeholder_id);
|
||||
|
||||
debug::DebugLog("Creating %s\n", placeholder_path);
|
||||
R_TRY_CATCH(fsdevCreateFile(placeholder_path, size, FS_CREATE_BIG_FILE)) {
|
||||
@@ -79,7 +141,7 @@ namespace sts::ncm::impl {
|
||||
Result PlaceHolderAccessor::Delete(PlaceHolderId placeholder_id) {
|
||||
char placeholder_path[FS_MAX_PATH] = {0};
|
||||
|
||||
this->GetPlaceHolderPathUncached(placeholder_path, placeholder_id);
|
||||
this->GetPath(placeholder_path, placeholder_id);
|
||||
|
||||
debug::DebugLog("Deleting %s\n", placeholder_path);
|
||||
if (std::remove(placeholder_path) != 0) {
|
||||
@@ -93,24 +155,26 @@ namespace sts::ncm::impl {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result PlaceHolderAccessor::Open(FILE** out_handle, PlaceHolderId placeholder_id) {
|
||||
if (this->LoadFromCache(out_handle, placeholder_id)) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
char placeholder_path[FS_MAX_PATH] = {0};
|
||||
|
||||
this->GetPlaceHolderPath(placeholder_path, placeholder_id);
|
||||
|
||||
Result PlaceHolderAccessor::Write(PlaceHolderId placeholder_id, size_t offset, const void* buffer, size_t size) {
|
||||
FILE* f = nullptr;
|
||||
R_TRY(OpenFile(&f, placeholder_path, FS_OPEN_WRITE));
|
||||
|
||||
*out_handle = f;
|
||||
R_TRY_CATCH(this->Open(&f, placeholder_id)) {
|
||||
R_CATCH(ResultFsPathNotFound) {
|
||||
return ResultNcmPlaceHolderNotFound;
|
||||
}
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
ON_SCOPE_EXIT {
|
||||
this->StoreToCache(f, placeholder_id);
|
||||
};
|
||||
|
||||
R_TRY(WriteFile(f, offset, buffer, size, !this->delay_flush));
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result PlaceHolderAccessor::SetSize(PlaceHolderId placeholder_id, size_t size) {
|
||||
char placeholder_path[FS_MAX_PATH] = {0};
|
||||
this->GetPlaceHolderPath(placeholder_path, placeholder_id);
|
||||
this->MakePath(placeholder_path, placeholder_id);
|
||||
if (truncate(placeholder_path, size) == -1) {
|
||||
R_TRY_CATCH(fsdevGetLastResult()) {
|
||||
R_CATCH(ResultFsPathNotFound) {
|
||||
@@ -127,7 +191,7 @@ namespace sts::ncm::impl {
|
||||
|
||||
/* Set the scope for the scoped_lock. */
|
||||
{
|
||||
std::scoped_lock<HosMutex> lock(this->cache_mutex);
|
||||
std::scoped_lock lock(this->cache_mutex);
|
||||
|
||||
if (placeholder_id == InvalidUuid) {
|
||||
*found_in_cache = false;
|
||||
@@ -162,73 +226,15 @@ namespace sts::ncm::impl {
|
||||
|
||||
Result PlaceHolderAccessor::EnsureRecursively(PlaceHolderId placeholder_id) {
|
||||
char placeholder_path[FS_MAX_PATH] = {0};
|
||||
this->GetPlaceHolderPath(placeholder_path, placeholder_id);
|
||||
this->MakePath(placeholder_path, placeholder_id);
|
||||
R_TRY(EnsureParentDirectoryRecursively(placeholder_path));
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
bool PlaceHolderAccessor::LoadFromCache(FILE** out_handle, PlaceHolderId placeholder_id) {
|
||||
std::scoped_lock<HosMutex> lk(this->cache_mutex);
|
||||
CacheEntry *entry = this->FindInCache(placeholder_id);
|
||||
if (entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
entry->id = InvalidUuid;
|
||||
*out_handle = entry->handle;
|
||||
return true;
|
||||
}
|
||||
|
||||
PlaceHolderAccessor::CacheEntry *PlaceHolderAccessor::FindInCache(PlaceHolderId placeholder_id) {
|
||||
if (placeholder_id == InvalidUuid) {
|
||||
return nullptr;
|
||||
}
|
||||
for (size_t i = 0; i < MaxCaches; i++) {
|
||||
if (placeholder_id == this->caches[i].id) {
|
||||
return &this->caches[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PlaceHolderAccessor::StoreToCache(FILE* handle, PlaceHolderId placeholder_id) {
|
||||
std::scoped_lock<HosMutex> lk(this->cache_mutex);
|
||||
CacheEntry* cache = nullptr;
|
||||
|
||||
/* Find an empty cache */
|
||||
for (size_t i = 0; i < MaxCaches; i++) {
|
||||
if (placeholder_id == InvalidUuid) {
|
||||
cache = &this->caches[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* No empty caches found. Let's clear cache 0. */
|
||||
if (cache == nullptr) {
|
||||
cache = &this->caches[0];
|
||||
|
||||
/* Flush and close any handles. */
|
||||
if (cache->handle) {
|
||||
fflush(cache->handle);
|
||||
fclose(cache->handle);
|
||||
}
|
||||
cache->id = InvalidUuid;
|
||||
}
|
||||
|
||||
/* Cache the new placeholder id and its file handle. */
|
||||
cache->id = placeholder_id;
|
||||
cache->handle = handle;
|
||||
cache->counter = this->cur_counter;
|
||||
this->cur_counter++;
|
||||
}
|
||||
|
||||
void PlaceHolderAccessor::ClearAllCaches() {
|
||||
for (size_t i = 0; i < MaxCaches; i++) {
|
||||
CacheEntry* cache = &this->caches[i];
|
||||
|
||||
if (cache->id != InvalidUuid) {
|
||||
fflush(cache->handle);
|
||||
fclose(cache->handle);
|
||||
cache->id = InvalidUuid;
|
||||
void PlaceHolderAccessor::InvalidateAll() {
|
||||
for (auto &entry : this->caches) {
|
||||
if (entry.id != InvalidUuid) {
|
||||
this->Invalidate(&entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user