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

fix: sqlite pragma order for auto_vacuum #3230

Merged
merged 2 commits into from
May 18, 2024

Conversation

jasonish
Copy link
Contributor

Setting the auto_vacuum pragma must come before setting the journal mode otherwise it won't apply.

Simple test app:

use sqlx::sqlite::SqliteAutoVacuum;
use sqlx::sqlite::SqliteJournalMode;
use sqlx::sqlite::SqliteSynchronous;
use sqlx::Connection;
use sqlx::SqliteConnection;

#[tokio::main]
async fn main() {
    let options = sqlx::sqlite::SqliteConnectOptions::new()
        .create_if_missing(true)
        .filename("./test.sqlite")
        .synchronous(SqliteSynchronous::Off)
        .auto_vacuum(SqliteAutoVacuum::Full)
        .journal_mode(SqliteJournalMode::Wal);
    let mut conn = SqliteConnection::connect_with(&options).await.unwrap();
    let auto_vacuum: u8 = sqlx::query_scalar("PRAGMA auto_vacuum")
        .fetch_one(&mut conn)
        .await
        .unwrap();
    println!("auto_vacuum = {auto_vacuum}");
}

In current git main, if journal_mode option is set, auto_vacuum will not take affect. Work-around is to execute a PRAGMA auto_vacuum = 1; VACUUM on the connection, but that shouldn't be needed for a newly created database.

@abonander
Copy link
Collaborator

The SQLite docs don't say anything about the relative ordering with journal_mode, but they do say the following: https://www.sqlite.org/pragma.html#pragma_auto_vacuum

The database connection can be changed between full and incremental autovacuum mode at any time. However, changing from "none" to "full" or "incremental" can only occur when the database is new (no tables have yet been created) or by running the VACUUM command. To change auto-vacuum modes, first use the auto_vacuum pragma to set the new desired mode, then invoke the VACUUM command to reorganize the entire database file. To change from "full" or "incremental" back to "none" always requires running VACUUM even on an empty database.

@jasonish
Copy link
Contributor Author

Yeah, I went looking for the docs on this but it's not mentioned. But this issue is visible with the SQLite command line tool as well.

For example:

$ rm -f ./new.db && sqlite3 ./new.db
SQLite version 3.42.0 2023-05-16 12:36:15
Enter ".help" for usage hints.
sqlite> pragma auto_vacuum = 1;
sqlite> pragma auto_vacuum;
1

Now enable wal mode first:

$ rm -f ./new.db && sqlite3 ./new.db
SQLite version 3.42.0 2023-05-16 12:36:15
Enter ".help" for usage hints.
sqlite> pragma journal_mode = 'wal';
wal
sqlite> pragma auto_vacuum = 1;
sqlite> pragma auto_vacuum;
0

So by choosing the ordering that SQLx is choosing, auto_vacuum may be enabled, but not always. Which is probably not expected behavior. If I'm opening a new database and select the options for auto_vacuum of FULL, and journal_mode of wal, I wouldn't expect to also have to go run a vacuum immediately - which is what I'm doing as a workaround, but only if the database file doesn't exist already on startup.

@abonander
Copy link
Collaborator

I can reproduce that, but going back to what the SQLite docs say, if I then run a vacuum it actually updates the auto_vacuum pragma:

$ sqlite3 ./test.db
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> pragma auto_vacuum;
0
sqlite> pragma journal_mode = 'wal';
wal
sqlite> pragma auto_vacuum = 1;
sqlite> pragma auto_vacuum;
0
sqlite> vacuum;
sqlite> pragma auto_vacuum;
1

I think this is SQLite behaving as documented: changing the journal mode marks the database as "dirty" and so it needs an explicit vacuum for the change to the auto_vacuum pragma to apply.

@abonander
Copy link
Collaborator

The exact same behavior occurs when doing anything else in the database that marks it as dirty (using a fresh database file here):

$ sqlite3 ./test.db
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> create table foo(bar integer, baz text);
sqlite> pragma auto_vacuum;
0
sqlite> pragma auto_vacuum = 1;
sqlite> pragma auto_vacuum;
0
sqlite> vacuum;
sqlite> pragma auto_vacuum;
1

@jasonish
Copy link
Contributor Author

I think there is an expecation that if I'm only setting options, and creating a new database, then I don't need to follow the note about existing databases. I'd expect to if I had created tables.

Perhaps a documentation update on auto_vacuum:

For existing databases, or new databases combined with options such as setting a journal mode, a change to this value does not take effect unless a VACUUM command is executed.

@abonander
Copy link
Collaborator

Yeah, I suppose there's no reason not to send the auto_vacuum pragma first either way.

jasonish and others added 2 commits May 15, 2024 10:00
Setting the auto_vacuum pragma must come before setting the journal
mode otherwise it won't apply.
Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
@jasonish jasonish force-pushed the sqlite-auto-vacuum-order/v1 branch from 1c200bc to fbc253d Compare May 15, 2024 16:00
@abonander abonander merged commit 0449ac5 into launchbadge:main May 18, 2024
4 checks passed
jayy-lmao pushed a commit to jayy-lmao/sqlx that referenced this pull request Jun 6, 2024
* fix: sqlite pragma order for auto_vacuum

Setting the auto_vacuum pragma must come before setting the journal
mode otherwise it won't apply.

* fix: better documentation for auto_vacuum

Co-authored-by: Austin Bonander <austin.bonander@gmail.com>

---------

Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
jrasanen pushed a commit to jrasanen/sqlx that referenced this pull request Oct 14, 2024
* fix: sqlite pragma order for auto_vacuum

Setting the auto_vacuum pragma must come before setting the journal
mode otherwise it won't apply.

* fix: better documentation for auto_vacuum

Co-authored-by: Austin Bonander <austin.bonander@gmail.com>

---------

Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
jrasanen pushed a commit to jrasanen/sqlx that referenced this pull request Oct 14, 2024
* fix: sqlite pragma order for auto_vacuum

Setting the auto_vacuum pragma must come before setting the journal
mode otherwise it won't apply.

* fix: better documentation for auto_vacuum

Co-authored-by: Austin Bonander <austin.bonander@gmail.com>

---------

Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
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.

2 participants