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

Datasette plugin that copies file into memory on startup #1

Closed
simonw opened this issue Apr 28, 2022 · 5 comments
Closed

Datasette plugin that copies file into memory on startup #1

simonw opened this issue Apr 28, 2022 · 5 comments

Comments

@simonw
Copy link
Owner

simonw commented Apr 28, 2022

Related:

Idea from SQLite forum discussion: https://sqlite.org/forum/forumpost/652a9402eb5ea505

Maybe I should investigate the performance benefits of copying the entire database into a :memory: SQLite database on server startup, then serving queries from that.

Based on the observation that SQLite is often I/O bound.

@simonw
Copy link
Owner Author

simonw commented Apr 28, 2022

Would use this: https://www.sqlite.org/lang_vacuum.html#vacuuminto

I think like this:

VACUUM INTO 'file:name_of_copy?mode=memory&cache=shared'

@simonw
Copy link
Owner Author

simonw commented Apr 28, 2022

datasette-copy-to-memory as the plugin name.

@simonw
Copy link
Owner Author

simonw commented Apr 28, 2022

Clue in https://stackoverflow.com/a/67637492/6083

A few tries later... It seems to work if you ping the memory base before the vacuum. I guess the in-memory db is not really initialized without a first contact.

Not sure what "ping" means there - but it wasn't working for me when I tried with an empty database.

@simonw
Copy link
Owner Author

simonw commented Apr 28, 2022

This also failed because you can't vacuum into main:

from datasette import hookimpl


@hookimpl
def startup(datasette):
    async def inner():
        for db in datasette.databases.values():
            if db.path:
                memory_name = "{}_memory".format(db.name)
                memory_db = datasette.add_memory_database(memory_name)

                def vacuum_into(conn):
                    conn.execute("ATTACH DATABASE ? AS _copy_from", [db.path])
                    conn.execute("VACUUM _copy_from INTO main")

                await memory_db.execute_write_fn(vacuum_into)

    return inner

@simonw
Copy link
Owner Author

simonw commented Apr 28, 2022

This totally works!

from datasette import hookimpl


@hookimpl
def startup(datasette):
    async def inner():
        for db in datasette.databases.values():
            if db.path:
                memory_name = "{}_memory".format(db.name)
                memory_db = datasette.add_memory_database(memory_name)
                # Ensure the in-memory database is initalized
                await memory_db.execute("select 1 + 1")

                def vacuum_into(conn):
                    conn.execute(
                        "VACUUM INTO ?",
                        ["file:{}?mode=memory&cache=shared".format(memory_name)],
                    )

                await db.execute_write_fn(vacuum_into)

    return inner

CleanShot 2022-04-28 at 12 43 30@2x

@simonw simonw transferred this issue from another repository Apr 28, 2022
@simonw simonw transferred this issue from simonw/temp Apr 28, 2022
@simonw simonw closed this as completed in 60218ad Apr 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant