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

Custom phar:// stream wrapper to prevent /tmp wastage #6214

Closed
dktapps opened this issue Dec 30, 2023 · 5 comments
Closed

Custom phar:// stream wrapper to prevent /tmp wastage #6214

dktapps opened this issue Dec 30, 2023 · 5 comments
Labels
Category: Core Related to internal functionality Type: Enhancement Contributes features or other improvements to PocketMine-MP
Milestone

Comments

@dktapps
Copy link
Member

dktapps commented Dec 30, 2023

Description

ext-phar decompresses compressed phar contents into temporary files in /tmp. This is problematic because the cached temporary file is not shared between different threads, leading to several MB of wasted /tmp footprint per thread started.

While this is not a unique problem to PM, it should be possible to work around this with a custom stream wrapper that either doesn't cache the files at all (the cache is only really useful when including the same file multiple times without opcache, or when loading a data file directly), or that caches them in a more thread-friendly manner.

Justification

Recently users of Pterodactyl hosts have experienced issues with tmp space being filled due to this issue.

Alternative methods

@dktapps dktapps added Category: Core Related to internal functionality Type: Enhancement Contributes features or other improvements to PocketMine-MP labels Dec 30, 2023
@dktapps
Copy link
Member Author

dktapps commented Dec 30, 2023

Apparently reading the file via manually opening the Phar causes the same problem as using phar://. There doesn't appear to be any way to read phar contents without dumping useless crap into /tmp.

@dktapps
Copy link
Member Author

dktapps commented Dec 30, 2023

Related to php/php-src#13055

@dadodasyra
Copy link

If I can add maybe something to this, I had issue in the past with some crash loops where the /tmp folder began to grow and grow. Normally the "anti crash loop system" of pocketmine is enough but if it crashs before pmmp correctly starts (for example a plugin with the wrong api version) it will create a lot of temp files, until saturation of the storage.

@dktapps
Copy link
Member Author

dktapps commented Feb 13, 2024

Yeah, the tmp spam on crash is a pretty big issue, and not easy to solve.

The main issue is that we have no way to identify which tmpfiles belong to the server after it restarts, so we don't know which ones are in use and which ones can be deleted. A few possible solutions to this:

  • Change tmpdir to /tmp/pocketmine/<pid> and then nuke the directory on the next startup based on the contents of server.lock
  • Put tmpfiles in the server's data directory - unpleasant solution, sucks for backup purposes
  • Stop compressing the phar entirely - not great, phar size jumps to 15 MB :(

dktapps added a commit that referenced this issue Mar 18, 2024
Because ext-phar sucks, tmp gets spammed by cache files for every thread when loading files from the phar on the fly.

Instead, we convert the `.phar` into a decompressed `.tar` in the tmp directory and require files from inside it. Surprisingly, this works because `ext-phar` supports `tar` and `zip` natively. No stream wrapper is required, as the `PocketMine.php` bootstrap loads files relative to its location, so the cache is automatically used for everything.

To be honest I would rather get rid of phars entirely, but they are still the easiest way to have PhpStorm load PocketMine-MP API information for now, and the alternatives are more complicated and inconvenient.

### Caveats
Everywhere that previously used `new Phar(Phar::running(false))` in the core code needs to be updated to use `PharData` for this to work correctly. Plugins don't need to do anything.

### Why not just use `Phar::decompressFiles()`?
This requires setting `phar.readonly` to `0`, which is a security issue. Technically, we could have used a subprocess to do this, but it just didn't seem right.

### WTF? `phar://` can be used on `tar` files???
Yup. I was just as surprised to find out that `require` works in such contexts.

### Relevant issues
- Closes #6214 

## Changes
### API changes
None.

### Behavioural changes
Server startup will be slightly slower, as the phar has to decompress and convert itself into a `.tar`. However, testing showed that this generally takes less than 200 ms, so it should be barely noticeable.

## Backwards compatibility
No BC issues.

## Tests
Locally tested and the CI will also verify
@dktapps
Copy link
Member Author

dktapps commented Mar 18, 2024

Fixed by #6217.

@dktapps dktapps closed this as completed Mar 18, 2024
@dktapps dktapps added this to the 5.14 milestone Mar 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Category: Core Related to internal functionality Type: Enhancement Contributes features or other improvements to PocketMine-MP
Projects
None yet
Development

No branches or pull requests

2 participants