-
Notifications
You must be signed in to change notification settings - Fork 308
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
Pagecount #819
base: main
Are you sure you want to change the base?
Pagecount #819
Conversation
That's what sqlite does. For example, for an empty database: $ sqlite3 file:memory "pragma page_count" 0
It is partially supported - only on the existing database.
To do that, we also have to implement the vdbe opcode Pagecount.
core/storage/sqlite3_ondisk.rs
Outdated
@@ -223,7 +223,7 @@ impl Default for DatabaseHeader { | |||
min_embed_frac: 32, | |||
min_leaf_frac: 32, | |||
change_counter: 1, | |||
database_size: 1, | |||
database_size: 0, |
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.
I don't think this is true. The SQLite file always has the database header but more important the sqlite_schema
table on page 1. @pereman2, @jussisaurio, please do correct me if i am wrong.
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.
yeah tests are failing and it seems to be because of that.
On an empty db page_count returns 0 on sqlite - I am investigating why
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.
Yes, page 1 is allocated with db initialization and never deallocated. One of the reasons why balancing becomes a bit complicated.
PragmaName::PageCount => { | ||
query_pragma("page_count", header, program)?; | ||
Ok(()) |
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.
Why do we have a transform from PragmaName
to str
to then PragmaName
again. Quite unnecessary. (no need to solve it here)
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.
#823 created an issue
#[test] | ||
fn test_pragma_page_count() -> Result<(), Error> { | ||
let mut child = spawn_command(run_cli(), Some(1000))?; | ||
child.exp_regex("limbo>")?; // skip everything until limbo cursor appear | ||
child.exp_regex(".?")?; | ||
child.send_line("pragma page_count;")?; | ||
child.exp_string("0")?; | ||
child.exp_regex("limbo>")?; | ||
child.send_line("create table foo(bar); pragma page_count;")?; | ||
child.exp_string("2")?; | ||
quit(&mut child) | ||
} | ||
|
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 this wizardy. Can we just have a TCL test? You should be able to add the equivalent of this test in testing/pragma.test
.
Something like:
do_execsql_test pragma-cache-size {
PRAGMA page_count
} {2}
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.
I won't be able to do this in the pragma.test. This is because that test is ran with two different databases as an input (testing.db and testing_norowidalias), and they each have a different page count.
I will see if I can come up with a simpler unit test somewhere.
@pereman2 and @penberg , before I touch this again, I am getting a different number of pages than SQLite almost every time. Sometimes it is a simple off-by-one, sometimes it is not. The SQLite implementation of the relevant function is quite straightforward:
That is a property of the BTree, though, not of the database file, and it gets updated in multiple places. It will be very hard for me to trust the result of me just reading through the SQLite code and trying to understand in which situations this is kept updated. I assume we have some infra in place to fuzz a bunch of potential databases so we can compare them? What's your suggestion here? |
@glommer In which scenarios do you see differences? In a simple new database I see this: Enter ".help" for usage hints.
sqlite> pragma page_count;
0
sqlite> PRAGMA journal_mode=WAL;
wal
sqlite> pragma page_count;
1
sqlite> CREATE TABLE t(x);
sqlite> pragma page_count;
2
sqlite> insert into t values(1);
sqlite> pragma page_count;
2
sqlite> I interpret this as we have 0 on an empty database without wal, 1 with wal and rest as expected. Meaning, if we start with WAL anyways, we could assume we have size 1 and initialize the header anyways. |
But then I see this on SQLite:
This query, btw, crashes Limbo if database_size is set to start at 0. So if we go back to 1, and subtract one before returning, and run it in-memory:
The problem is that if we save this to a file with SQLite, and then open it with Limbo,
it could be that this is just a matter of special casing database loading, but then the following in-memory schema seems wrong:
vs
And for full reference, I am running this with the following code atop:
|
And then, subtract one when returning
BTW, I think that this comes from the fact that SQLite does, in fact, write It's the last byte:
Limbo writes 3:
So my tl;dr is that I think our logic to tracking this is broken today. |
This PR implements the Pagecount pragma, as well as its associated bytecode opcode