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

Introduce RESET request #435

Closed
wants to merge 2 commits into from
Closed

Conversation

cole-miller
Copy link
Contributor

This PR implements a new RESET request that allows a dqlite client to restore the database it has opened to a pristine state. Instead of deleting the in-memory database "file", we use the SQLITE_DBCONFIG_RESET_DATABASE method described here, which goes through the normal VFS channels. This still requires a separate request because of the out-of-band sqlite3_db_config calls. The implementation of the new request mimics what would happen if we did EXEC_SQL("VACUUM"), with some simplifications since we don't need to run a barrier or bind parameters.

Closes #422

Signed-off-by: Cole Miller cole.miller@canonical.com

@cole-miller
Copy link
Contributor Author

I am unsure about this remark in the SQLite docs:

If the database connection is newly opened, make sure it has read the database schema by preparing then discarding some query against the database, or calling sqlite3_table_column_metadata(), ignoring any errors. This step is only necessary if the application desires to keep the database in WAL mode after the reset if it was in WAL mode before the reset.

I think we do want to keep the database in WAL mode after the reset, but it's unclear to me how the server can implement "touching" the schema in this way without knowing what tables (if any) are present in the DB.

@codecov
Copy link

codecov bot commented Nov 18, 2022

Codecov Report

Merging #435 (8dc07ed) into master (0c38457) will decrease coverage by 13.15%.
The diff coverage is 44.08%.

❗ Current head 8dc07ed differs from pull request most recent head 8550472. Consider uploading reports for the commit 8550472 to get more accurate results

@@             Coverage Diff             @@
##           master     #435       +/-   ##
===========================================
- Coverage   73.47%   60.32%   -13.16%     
===========================================
  Files          31       31               
  Lines        4679     4771       +92     
  Branches     1462     1413       -49     
===========================================
- Hits         3438     2878      -560     
- Misses        745     1022      +277     
- Partials      496      871      +375     
Impacted Files Coverage Δ
src/leader.c 49.52% <35.08%> (-20.59%) ⬇️
src/gateway.c 43.80% <42.30%> (-14.93%) ⬇️
src/vfs.c 79.04% <100.00%> (-7.10%) ⬇️
src/message.c 0.00% <0.00%> (-100.00%) ⬇️
src/request.c 0.00% <0.00%> (-100.00%) ⬇️
src/response.c 0.00% <0.00%> (-100.00%) ⬇️
src/transport.c 45.75% <0.00%> (-24.19%) ⬇️
src/conn.c 49.24% <0.00%> (-23.62%) ⬇️
src/client.c 52.84% <0.00%> (-20.21%) ⬇️
src/db.c 42.37% <0.00%> (-20.13%) ⬇️
... and 19 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@cole-miller
Copy link
Contributor Author

cole-miller commented Nov 18, 2022

Ah, it looks like SQLITE_DBCONFIG_RESET_DATABASE was added in SQLite v3.24.0, which is not available on Bionic. We could do some #ifdef stuff to detect an old SQLite and just fail RESET requests in this case?

@freeekanayaka
Copy link
Contributor

Ah, it looks like SQLITE_DBCONFIG_RESET_DATABASE was added in SQLite v3.24.0, which is not available on Bionic. We could do some #ifdef stuff to detect an old SQLite and just fail RESET requests in this case?

+1

@freeekanayaka
Copy link
Contributor

sqlite3_table_column_metadata

I'm not entirely sure why this requirement is there, but maybe you can use sqlite3_table_column_metadata against one of the virtual tables/columns that are guaranteed to be there, e.g. sqlite3_table_column_metadata(db, NULL, "sqlite_master", "name", ...).

@MathieuBordere
Copy link
Contributor

MathieuBordere commented Nov 21, 2022

Ah, it looks like SQLITE_DBCONFIG_RESET_DATABASE was added in SQLite v3.24.0, which is not available on Bionic. We could do some #ifdef stuff to detect an old SQLite and just fail RESET requests in this case?

I would maybe check it at runtime too, with sqlite3_version or sqlite3_libversion.

src/leader.c Outdated Show resolved Hide resolved
rv = sqlite3_db_config(l->conn, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
assert(rv == 0);
exec->status = sqlite3_exec(l->conn, "VACUUM", NULL, NULL, NULL);
rv = sqlite3_db_config(l->conn, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, does dqlite's memory footprint shrink after resetting a DB? If it's not shrinking, we should look into it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that would be a good thing to measure. Let me see if I can add some basic tracing of memory consumption before and after the VACUUM.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I don't see any change in number of DB pages, number of WAL frames, or number of shm regions after leaderApplyFrames returns vs. before VACUUM. @freeekanayaka, can you think of anything that would be preventing our VFS from dropping allocated memory when SQLite is done using it? (I could also just be looking in the wrong places -- I don't fully understand the VFS subsystem yet.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the VACUUM actually succeed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it does -- I just tried adding an extra tracef to confirm.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I don't see any change in number of DB pages, number of WAL frames, or number of shm regions after leaderApplyFrames returns vs. before VACUUM. @freeekanayaka, can you think of anything that would be preventing our VFS from dropping allocated memory when SQLite is done using it? (I could also just be looking in the wrong places -- I don't fully understand the VFS subsystem yet.)

Not on the top of my head, but I also don't have a clear picture of the changes that are being made. The SQLite memory allocator has some helper functions to track the amount of allocated memory, perhaps that could be useful to check.

@cole-miller
Copy link
Contributor Author

Latest push:

  • gates RESET request on SQLite version check (compile-time and run-time)
  • runs a barrier before VACUUM
  • traces the state of memory allocations before and after a DB reset -- I'm not necessarily proposing the way I set this up as a permanent addition, just enabling others to reproduce what I saw (allocations not being dropped after VACUUM)

Signed-off-by: Cole Miller <cole.miller@canonical.com>
Signed-off-by: Cole Miller <cole.miller@canonical.com>
@MathieuBordere
Copy link
Contributor

MathieuBordere commented Nov 22, 2022

Okay, we should first figure out why the database is not shrinking before merging this. Maybe it waits until a checkpoint command, not sure.

@cole-miller
Copy link
Contributor Author

This implementation of RESET doesn't work when I rebase on top of #440. That's expected, since one of the first things done in the implementation of VACUUM is to ATTACH an additional temporary database to the given connection. I don't think we should merge this unless and until we can support ATTACH DATABASE properly.

@cole-miller
Copy link
Contributor Author

Closing in favor of an issue

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.

Support deletion of database
3 participants