Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ResourceLoader: Fix handling of uncached loads #93540

Merged
merged 1 commit into from
Jun 24, 2024

Conversation

RandomShaper
Copy link
Member

  • CACHE_MODE_IGNORE_DEEP is checked in addition to CACHE_MODE_IGNORE to determine if a load is uncached. This avoids crashes in uncached loads due to prematurely freed load tasks.
  • Cached load tasks are isolated (not registered in the task map ever). This avoids regular loads from reusing in-flight cached loads, which is not correct.

- `CACHE_MODE_IGNORE_DEEP` is checked in addition to `CACHE_MODE_IGNORE` to determine if a load is uncached. This avoids crashes in uncached loads due to prematurely freed load tasks.
- Cached load tasks are isolated (not registered in the task map ever). This avoids regular loads from reusing in-flight cached loads, which is not correct.
@RandomShaper RandomShaper added this to the 4.3 milestone Jun 24, 2024
@RandomShaper RandomShaper requested a review from a team as a code owner June 24, 2024 09:28
@akien-mga akien-mga merged commit e78dc83 into godotengine:master Jun 24, 2024
16 checks passed
@akien-mga
Copy link
Member

Thanks!

@RandomShaper RandomShaper deleted the res_load_uncached branch June 24, 2024 15:24
@mrTag
Copy link
Contributor

mrTag commented Jul 9, 2024

Since we merged in the latest master a few days ago, we had errors in our game every now and then (like "play the game for at least 5 minutes and they started occurring" kind of frequency). They were in the resource_parser_text and errors like "could not parse" or "error loading dependency" or even "no resource found at path". We use the threaded resource loader quite a lot, so this could be a rare problem for others...

We traced the problem back to this PR through bisecting. And while looking at the changes I found it odd that the new code returns the load_token even when it is invalid:

if (!load_token.is_valid()) {
// The token is dying (reached 0 on another thread).
// Ensure it's killed now so the path can be safely reused right away.
thread_load_tasks[local_path].load_token->clear();
}
return load_token;

while the old code only returned in an else (so only when the token is valid) and otherwise populated the load_token later on in the function before returning:

if (!load_token.is_valid()) {
	// The token is dying (reached 0 on another thread).
	// Ensure it's killed now so the path can be safely reused right away.
	thread_load_tasks[local_path].load_token->clear();
} else {
	if (p_cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
		return load_token;
	}
}

So I tried just adding the else back to the condition and the errors went away:

if (!load_token.is_valid()) {
	// The token is dying (reached 0 on another thread).
	// Ensure it's killed now so the path can be safely reused right away.
	thread_load_tasks[local_path].load_token->clear();
} else {
	return load_token;
}

I am totally unsure if that is correct in any way, though 😀 Can you look into this @RandomShaper ?

@RandomShaper
Copy link
Member Author

Excellent catch. I'm preparing a PR that fixes a few other issues and will include the fix there. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants