Please confirm the following.
What version of the Modrinth App are you using?
0.18.2
What operating systems are you seeing the problem on?
Linux
Describe the bug
The cache table in app.db grows without bound. The expires column is populated correctly, but nothing ever deletes rows once they are past it, so every entry the app has written stays in the file permanently.
This matters because most cached types are short lived. Measuring the remaining TTL on my install:
data_type rows remaining TTL
version 1114 3 to 11 minutes
user 74 3 to 11 minutes
team 60 3 to 12 minutes
project 54 3 to 11 minutes
version_v3 54 3 to 12 minutes
file_hash 69 ~30 days
file 54 ~30 days
So version entries live about half an hour, yet after a few days of ordinary use my cache table held 16792 version rows totalling 74.4 MB. Almost all of it was data that had expired long before.
Resulting state
app.db had reached 97 MB, of which 85 MB was the cache table:
data_type rows size
version 16792 74.4 MB
project_versions 20 4.5 MB
search_results_v3 48 3.8 MB
project 113 1.0 MB
loader_manifest 4 0.8 MB
4796 rows (16.6 MB) were already past their expires timestamp.
app.db-wal was also sitting at 54 MB, and was still 54 MB after a clean application shutdown, so it does not appear to be checkpointed on exit.
Clearing it
I closed the app, ran DELETE FROM cache, PRAGMA wal_checkpoint(TRUNCATE) and VACUUM. app.db went from 97 MB to 639 kB. PRAGMA integrity_check returned ok before and after, and no user data was affected: instances, content entries, settings and Java versions all survived, and the cache repopulated from the network normally.
It refills quickly. Within about an hour of ordinary use it was back to roughly 4000 rows and 10 MB.
Scale context
This is not a heavy install. 3 instances, 134 total content entries. The 16792 cached version rows came from ordinary catalogue browsing over a few days.
Suggested fixes
- Evict rows where
expires has passed, on startup or periodically.
- Cap the
cache table, for example by row count or total size per data_type, evicting least recently used entries.
- Checkpoint the WAL on shutdown so it does not persist at tens of MB.
Scope
To be clear about what this issue is and is not: I am reporting unbounded growth of an on-disk cache. I separately see high CPU and multi-GB memory growth in the app while browsing (#7276), but I measured the cache table growing by only about 5 MB during a window where RSS grew 4.3 GB, so I have no evidence the two are connected and I am not claiming they are.
Steps to reproduce
1. Note the starting state
sqlite3 ~/.local/share/ModrinthApp/app.db \
"select count(*), sum(length(data))/1048576.0 from cache;"
2. Use the app normally for a few minutes. Open Discover, search for a few mods, open some project pages. Nothing unusual is needed.
3. Check the TTLs.
sqlite3 ~/.local/share/ModrinthApp/app.db \
"select data_type, count(*), min(expires - strftime('%s','now'))/60 as min_ttl_minutes
from cache group by data_type order by count(*) desc;"
Most data_type values are short lived. On my install version, user, team, project and version_v3 entries expire about half an hour after being written.
4. Wait until those TTLs have passed, then count the expired rows.
sqlite3 ~/.local/share/ModrinthApp/app.db \
"select count(*), sum(length(data))/1048576.0 from cache
where expires < strftime('%s','now');"
They are all still present. Nothing removes them. This is the bug: the count only ever goes up, so the table accumulates every short lived entry the app has ever written. After a few days of ordinary use mine held 16792 version rows totalling 74.4 MB, of which 4796 rows (16.6 MB) were already expired.
5. Observe the idle read amplification. With the app open and doing nothing, watch the backend process:
watch -n1 'grep rchar /proc/$(pgrep -x ModrinthApp)/io'
With a ~100 MB app.db this climbed at 24 to 42 MB/s continuously. After clearing the cache it dropped to 1 to 2 MB/s.
Note on how fast this refills. After I cleared the cache completely, it was back to 1578 rows and 6.4 MB in under half an hour, with app.db going from 639 kB to 8.0 MB. I am quoting that as an upper bound on elapsed time rather than a controlled measurement, since the app was not running for that entire window.
Expected behavior
Expired rows should be removed from the cache table, either on startup, periodically, or lazily on read. app.db should stay bounded in size regardless of how long the app has been in use.
Idle disk reads should be close to zero when the app is open with no interaction and no install running, rather than scaling with the accumulated cache size.
app.db-wal should be checkpointed on a clean shutdown rather than persisting at tens of MB.
Additional context
Hardware: Intel Core Ultra 9 185H + RTX 4060, 30 GB RAM, Fedora 44, KDE Plasma on Wayland. Native RPM package.
The expires values are unix epoch seconds, so expired rows can be counted with:
sqlite3 ~/.local/share/ModrinthApp/app.db \
"select count(*), sum(length(data))/1048576.0 from cache
where expires < strftime('%s','now');"
On my install that returned 4796 rows and 16.6 MB before I cleared the table. The count only ever goes up.
Please confirm the following.
What version of the Modrinth App are you using?
0.18.2
What operating systems are you seeing the problem on?
Linux
Describe the bug
The
cachetable inapp.dbgrows without bound. Theexpirescolumn is populated correctly, but nothing ever deletes rows once they are past it, so every entry the app has written stays in the file permanently.This matters because most cached types are short lived. Measuring the remaining TTL on my install:
So
versionentries live about half an hour, yet after a few days of ordinary use mycachetable held 16792versionrows totalling 74.4 MB. Almost all of it was data that had expired long before.Resulting state
app.dbhad reached 97 MB, of which 85 MB was thecachetable:4796 rows (16.6 MB) were already past their
expirestimestamp.app.db-walwas also sitting at 54 MB, and was still 54 MB after a clean application shutdown, so it does not appear to be checkpointed on exit.Clearing it
I closed the app, ran
DELETE FROM cache,PRAGMA wal_checkpoint(TRUNCATE)andVACUUM.app.dbwent from 97 MB to 639 kB.PRAGMA integrity_checkreturnedokbefore and after, and no user data was affected: instances, content entries, settings and Java versions all survived, and the cache repopulated from the network normally.It refills quickly. Within about an hour of ordinary use it was back to roughly 4000 rows and 10 MB.
Scale context
This is not a heavy install. 3 instances, 134 total content entries. The 16792 cached
versionrows came from ordinary catalogue browsing over a few days.Suggested fixes
expireshas passed, on startup or periodically.cachetable, for example by row count or total size perdata_type, evicting least recently used entries.Scope
To be clear about what this issue is and is not: I am reporting unbounded growth of an on-disk cache. I separately see high CPU and multi-GB memory growth in the app while browsing (#7276), but I measured the
cachetable growing by only about 5 MB during a window where RSS grew 4.3 GB, so I have no evidence the two are connected and I am not claiming they are.Steps to reproduce
1. Note the starting state
2. Use the app normally for a few minutes. Open Discover, search for a few mods, open some project pages. Nothing unusual is needed.
3. Check the TTLs.
Most
data_typevalues are short lived. On my installversion,user,team,projectandversion_v3entries expire about half an hour after being written.4. Wait until those TTLs have passed, then count the expired rows.
They are all still present. Nothing removes them. This is the bug: the count only ever goes up, so the table accumulates every short lived entry the app has ever written. After a few days of ordinary use mine held 16792
versionrows totalling 74.4 MB, of which 4796 rows (16.6 MB) were already expired.5. Observe the idle read amplification. With the app open and doing nothing, watch the backend process:
With a ~100 MB
app.dbthis climbed at 24 to 42 MB/s continuously. After clearing the cache it dropped to 1 to 2 MB/s.Note on how fast this refills. After I cleared the cache completely, it was back to 1578 rows and 6.4 MB in under half an hour, with
app.dbgoing from 639 kB to 8.0 MB. I am quoting that as an upper bound on elapsed time rather than a controlled measurement, since the app was not running for that entire window.Expected behavior
Expired rows should be removed from the
cachetable, either on startup, periodically, or lazily on read.app.dbshould stay bounded in size regardless of how long the app has been in use.Idle disk reads should be close to zero when the app is open with no interaction and no install running, rather than scaling with the accumulated cache size.
app.db-walshould be checkpointed on a clean shutdown rather than persisting at tens of MB.Additional context
Hardware: Intel Core Ultra 9 185H + RTX 4060, 30 GB RAM, Fedora 44, KDE Plasma on Wayland. Native RPM package.
The
expiresvalues are unix epoch seconds, so expired rows can be counted with:On my install that returned 4796 rows and 16.6 MB before I cleared the table. The count only ever goes up.