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

Add Env Var to disable WAL journaling #11464

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Add Env Var to disable WAL journaling #11464

wants to merge 2 commits into from

Conversation

gnattu
Copy link
Member

@gnattu gnattu commented Apr 29, 2024

Changes

SQLite WAL journaling is not compatible with all filesystems/VFS extensions, causing the database being locked up in certain conditions.

It's worth noting that database lockup is just one potential issue that can arise from compatibility issues with certain filesystems. In some cases, the use of WAL can even lead to the database being saved in a non-consistent state, resulting in database corruption.

Add an env var to let the user to choose the Journal mode for better compatibility.

For example, when the default WAL is causing problems:

export JELLYFIN_SQLITE__JOURNALMODE=TRUNCATE

Issues

SQLite WAL journaling is not compatible with all filesystems/VFS extensions, causing the database being locked up in certain conditions. Add an env var to disable WAL journaling for better compatibility.

Signed-off-by: gnattu <gnattuoc@me.com>
@gnattu gnattu requested a review from a team April 29, 2024 20:09
@Bond-009
Copy link
Member

Why not make the option a string so users can set any journalmode they want?

@gnattu
Copy link
Member Author

gnattu commented Apr 29, 2024

Why not make the option a string so users can set any journalmode they want?

Because of too many potential user errors?

@joshuaboniface
Copy link
Member

I agree with making it an option. On supported systems this can improve DB performance right? So it can be beneficial in those cases.

@joshuaboniface
Copy link
Member

Also do we know exactly which filesysts have the issue? We can adjust packaging defaults if we know that.

@gnattu
Copy link
Member Author

gnattu commented Apr 29, 2024

Also do we know exactly which filesysts have the issue? We can adjust packaging defaults if we know that.

You cannot predict this, the user can literally use any filesystem they want.

@cvium
Copy link
Member

cvium commented Apr 29, 2024

Will enabling pooling fix it?

@gnattu
Copy link
Member Author

gnattu commented Apr 29, 2024

Will enabling pooling fix it?

I'm not very sure because I don't have the exact environment of the users. Probably this needs to be an extra option to let the user choose.

Signed-off-by: gnattu <gnattuoc@me.com>
@memehammad
Copy link

Any easy way to try this out?

@gnattu
Copy link
Member Author

gnattu commented Apr 30, 2024

Any easy way to try this out?

I compiled a tarball for the docker image: https://github.com/gnattu/jellyfin/releases/tag/env-disable-wal

Sorry but this is probably the easiest way I can prepare for you.

@jmqm
Copy link
Contributor

jmqm commented May 7, 2024

Wouldn't it be better if TRUNCATE is the default value if WAL can be problematic on some filesystems?

@gitdeath
Copy link

gitdeath commented May 11, 2024

Any easy way to try this out?

I compiled a tarball for the docker image: https://github.com/gnattu/jellyfin/releases/tag/env-disable-wal

Sorry but this is probably the easiest way I can prepare for you.

Attempted to test this with a known Database is Locked file system use case, but the below compose seems to create a database still using WAL - jellyfin.db-wal file is created in the config/data directory and PRAGMA journal_mode; returns wal

version: '3.8'
services:

  jellyfin-dev:
    image: jellyfin-disable-wal
    user: 0:100
    environment:
     - TZ=America/Chicago
     - JELLYFIN_SQLITE__JOURNALMODE=TRUNCATE

    networks:
     - default
    ports:
     - 8097:8096
     - 8927:8920
     - 1907:1900

    volumes:
     - jellyfin_dev_config:/config
     - jellyfin_dev_cache:/cache
     - media:/media:ro
host:~$ docker load < jellyfin-test-disable-wal.tar.xz
73242b419cec: Loading layer [==================================================>]  454.6MB/454.6MB
2d40ebc031c5: Loading layer [==================================================>]  295.6MB/295.6MB
5f70bf18a086: Loading layer [==================================================>]  1.024kB/1.024kB
87d78ce7befa: Loading layer [==================================================>]  2.048kB/2.048kB
f99821c77d4a: Loading layer [==================================================>]  155.1MB/155.1MB
0aa5721c5e74: Loading layer [==================================================>]  57.34MB/57.34MB
Loaded image ID: sha256:b7f31f02c71da06562117ab162a95cfa4ae28288a18f9ca2b4bb3644528f8d2d
host:~$ docker tag b7f31f02c71d jellyfin-disable-wal
host:~$ docker image ls
REPOSITORY                                     TAG       IMAGE ID       CREATED        SIZE
jellyfin-disable-wal                           latest    b7f31f02c71d   11 days ago    1.03GB

@memehammad
Copy link

That'd explain why this didn't fix my issue lol

@gitdeath
Copy link

gitdeath commented May 12, 2024

That'd explain why this didn't fix my issue lol

I'm very interested to see if this does in fact improve the situation. Because from what I can tell, for use cases that work in 10.8, but not 10.9, the problem is the switch to MS.SQL from SQL.pretty - it seems MS has a performance hit compared to SQL.pretty on some FS setups that results in the database is locked issues (example NFSv3 storage with nolocks parameter - #11387.)

Now the MS.SQL change needs to happen, if the plan is to open up other database backends - but that isn't available yet, so I don't know if this was required to do before that.

If this WAL to TRUNCATE doesn't pan out, then I'll fork Jelly and reverse the changes from the below PR for a test.

#10138

@crobibero
Copy link
Member

After testing I can confirm that Jellyfin does set the journal_mode correctly, but it is only available during the connection- not from the cli. I verified with the following patch:

Index: Emby.Server.Implementations/Data/BaseSqliteRepository.cs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
--- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs	(revision 8d8fcada18674becfcde6875d11e78a32d06c04d)
+++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs	(date 1715531783505)
@@ -121,6 +121,12 @@
             if (!string.IsNullOrWhiteSpace(JournalMode))
             {
                 connection.Execute("PRAGMA journal_mode=" + JournalMode);
+
+                using var cmd = connection.CreateCommand();
+                cmd.CommandText = "PRAGMA journal_mode;";
+                using var reader = cmd.ExecuteReader();
+                reader.Read();
+                var currentJournalMode = reader.GetString(0);
             }
 
             if (JournalSizeLimit.HasValue)

@gitdeath
Copy link

After testing I can confirm that Jellyfin does set the journal_mode correctly, but it is only available during the connection- not from the cli. I verified with the following patch:

Index: Emby.Server.Implementations/Data/BaseSqliteRepository.cs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
--- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs	(revision 8d8fcada18674becfcde6875d11e78a32d06c04d)
+++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs	(date 1715531783505)
@@ -121,6 +121,12 @@
             if (!string.IsNullOrWhiteSpace(JournalMode))
             {
                 connection.Execute("PRAGMA journal_mode=" + JournalMode);
+
+                using var cmd = connection.CreateCommand();
+                cmd.CommandText = "PRAGMA journal_mode;";
+                using var reader = cmd.ExecuteReader();
+                reader.Read();
+                var currentJournalMode = reader.GetString(0);
             }
 
             if (JournalSizeLimit.HasValue)

I've was unable to produce a state with this package (fresh install) that doesn't end with the creation of the WAL file. Is it possible Jellyfin is making multiple connections to the database? It would seem that if any connection sets to WAL then all will see WAL unless they specifically change for their connection.

https://www.sqlite.org/wal.html - Section 3.3

3.3. Persistence of WAL mode
Unlike the other journaling modes, [PRAGMA journal_mode=WAL](https://www.sqlite.org/pragma.html#pragma_journal_mode) is persistent. If a process sets WAL mode, then closes and reopens the database, the database will come back in WAL mode. In contrast, if a process sets (for example) PRAGMA journal_mode=TRUNCATE and then closes and reopens the database will come back up in the default rollback mode of DELETE rather than the previous TRUNCATE setting.

The persistence of WAL mode means that applications can be converted to using SQLite in WAL mode without making any changes to the application itself. One has merely to run "PRAGMA journal_mode=WAL;" on the database file(s) using the [command-line shell](https://www.sqlite.org/cli.html) or other utility, then restart the application.

The WAL journal mode will be set on all connections to the same database file if it is set on any one connection.

@gnattu
Copy link
Member Author

gnattu commented May 14, 2024

After testing I can confirm that Jellyfin does set the journal_mode correctly, but it is only available during the connection- not from the cli. I verified with the following patch:

Index: Emby.Server.Implementations/Data/BaseSqliteRepository.cs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
--- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs	(revision 8d8fcada18674becfcde6875d11e78a32d06c04d)
+++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs	(date 1715531783505)
@@ -121,6 +121,12 @@
             if (!string.IsNullOrWhiteSpace(JournalMode))
             {
                 connection.Execute("PRAGMA journal_mode=" + JournalMode);
+
+                using var cmd = connection.CreateCommand();
+                cmd.CommandText = "PRAGMA journal_mode;";
+                using var reader = cmd.ExecuteReader();
+                reader.Read();
+                var currentJournalMode = reader.GetString(0);
             }
 
             if (JournalSizeLimit.HasValue)

I've was unable to produce a state with this package (fresh install) that doesn't end with the creation of the WAL file. Is it possible Jellyfin is making multiple connections to the database? It would seem that if any connection sets to WAL then all will see WAL unless they specifically change for their connection.

https://www.sqlite.org/wal.html - Section 3.3

3.3. Persistence of WAL mode
Unlike the other journaling modes, [PRAGMA journal_mode=WAL](https://www.sqlite.org/pragma.html#pragma_journal_mode) is persistent. If a process sets WAL mode, then closes and reopens the database, the database will come back in WAL mode. In contrast, if a process sets (for example) PRAGMA journal_mode=TRUNCATE and then closes and reopens the database will come back up in the default rollback mode of DELETE rather than the previous TRUNCATE setting.

The persistence of WAL mode means that applications can be converted to using SQLite in WAL mode without making any changes to the application itself. One has merely to run "PRAGMA journal_mode=WAL;" on the database file(s) using the [command-line shell](https://www.sqlite.org/cli.html) or other utility, then restart the application.

The WAL journal mode will be set on all connections to the same database file if it is set on any one connection.

If I understand it right the persistency is stored into the database itself and the connection will be created in WAL on default.

It should not affect the rest of the connection after marking it with TRUNCATE though.

@jellyfin-bot jellyfin-bot added the merge conflict Merge conflicts should be resolved before a merge label May 15, 2024
@jellyfin-bot
Copy link
Contributor

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

@jellyfin-bot jellyfin-bot removed the merge conflict Merge conflicts should be resolved before a merge label May 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants