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
'Mass file loader' for use in skin and asset loading #6727
Conversation
I would like to know if it's wanted in the DDNet code & if the way I'm doing it is considered to be the 'right approach' before I go on making the multi-threaded implementation & replacing the asset and skin loading systems with it. I will wait for feedback before making major changes. |
Would it make sense to use aio for that? |
I don't know aio. I hear it doesn't work on Windows. If it only works file-by-file, this still has the benefit of being batch-oriented |
Sounds like a good idea in general. High-level: I think stuff like "is_readable" shouldn't be used, rather, the file can be opened in the background thread and the resulting error can be reported. Is there a reason for denying symlinks by default or at all? |
Recursing through symlinks presents the risk of looping forever. |
In this commit I've changed it so that error checking is only done in the load step & removed |
I have to say that symlinks is what I use typically for own stuff. It seems to be a bad idea to work on graphics directly in the game folder (I don't want to have extra (editor, e.g. I'd say: "please keep the current behavior as it have nothing to do with how the game opens files (one-by-one or 'massively')". Disabled symlinks would be a regression for my personal UX. |
I planned to have them on for skins. What's the big deal |
I just don't see the need in implementing the loader and special symlinks processing in one MR.
It would be a 100% user fault, and it does not look like a new problem. Why we'd mix it into a new feature.
Oh, now I see. The current implementation is single-threaded and you want to add the proper API first. |
I'll start the async implementation soon if there are no more complaints. |
Status: Draft. |
src/engine/shared/file_loader.cpp
Outdated
UserData->m_pThis->m_PathCollection.insert({AbsolutePath, new std::vector<std::string>}); | ||
// Note that adding data to a SORTED container that is currently being iterated on higher in scope would invalidate the iterator. This is not sorted | ||
SListDirectoryCallbackUserInfo Data{&AbsolutePath, UserData->m_pThis, UserData->m_pContinue}; | ||
UserData->m_pThis->m_pStorage->ListDirectory(IStorage::TYPE_ALL, AbsolutePath.c_str(), ListDirectoryCallback, &Data); // Directory item is a directory, must be recursed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The storage type has to be the one used initially instead of TYPE_ALL
every time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you mean. It's TYPE_ALL initially as well, in the direct ListDirectory invocation in the load function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is mean is that the loader should have a parameter int StorageType
so the storage type that is listed can be adjusted, same as the existing ListDirectory
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's why the ":" exists on a per-directory basis. That is the solution I came up with and thought everyone was happy with when I realized it would be tricky to provide the storage type for each path.
…out std strings in favor of char ptrs when not justified by a container or other major convenience
Advice? |
I can see how regex could be considered overkill, but maybe I should add the ability to filter by more than one extension. Sort of like how most file dialog APIs work. If so, multiple strings or one string separated by semicolons? Thoughts? |
Not sure it's useful anywhere to list files of multiple extensions at the same time. Unless we can identify a clear use case, I think it's better to keep it simple with only one file extension being filtered. |
Async implementation pretty much finished. Changed the mutex tug-of-war to a mostly lockfree system else using an Waiting for review, I think that this is the final iteration of the file loader itself so that would probably be the best thing to look at. Skins loading also works and could use some review, not 100% sure if that's how it'll end up looking but it works. Still have to do the assets loading. |
2f5aab8
to
a071edd
Compare
…cs(), removed cskins dtor in favor of OnShutdown()
|
||
std::vector<std::string> m_RequestedPaths; | ||
std::unordered_map<std::string, std::vector<std::string> *> m_PathCollection; | ||
char *m_pExtension = nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m_aExtension[IO_MAX_PATH_LENGTH]
There's no need for dynamic memory allocation for this. We know the extension can only have a certain maximum size.
f8347ad
to
2d8c571
Compare
Status: Not done, waiting for author. |
Doesn't seem like a high demand feature. Especially considering how much work it is just to get it working. I will consider a simpler/less versatile approach for async skins and assets in the future. Closing for now |
Summary:
Currently, asset and skin loading are quite slow if you have a decent amount of them, even on a fast disk. I would like to create a generic, multi-threaded file loader system that can lessen the impact of some necessary disk blocks, and implement it into the skin and asset systems so the brunt of this wait time can be avoided (most or all skins and assets loaded by the time a user finds and joins a server from the browser). This file loader will also be available (and hopefully encouraged) for similar future tasks requiring a lot of files to be loaded & used in a similar way.
This is a relatively big-picture feature, if my goal is at all unclear to you, I am happy to clarify.
Goals:
io_*
/fs_*
/IStorage::*
- functions.At the moment, I have gotten the interface and reference implementation (single-threaded) to a stage where they are ready for review, after which I plan to create the multi-threaded implementation and then add to skin and asset loading.
Just for the sake of it, here is a checklist.
Misc. stuff:
At the moment, the API is described in
src/game/client/file_loader.h
. It is not formatted as proper documentation, I could use some help with that. Maybe it's not needed?2 functions have been added to
src/base/system.cpp
/.h
in order to allow for enhanced error checking. It is not strictly needed, but I would like for it to be kept. They have been tested and seen as working on Windows and LinuxThere is a simple temporary test case in
src/engine/client.cpp
. Up to this point I have been using a test file/directory schema that looks like thisI am trying my best to stick to DDNet code convention. Please let me know if there's something you think doesn't fit.
Checklist