Skip to content

Commit 6088e73

Browse files
authored
Pool / cache in-memory SQLite databases (#1234)
* Pool / cache in-meory SQLite databases * Update CHANGELOG * Used named memory in tests where in-memory catalogs should be distinct
1 parent f7da02e commit 6088e73

File tree

5 files changed

+22
-10
lines changed

5 files changed

+22
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Write the date in place of the "Unreleased" in the case a new version is release
2020
documentation and one test.
2121
- Deletion of nodes or metadata revisions now requires deletion scopes,
2222
rather than writing scopes.
23+
- In-memory SQLite databases are connection pooled / cached.
2324

2425
## Fixed
2526

tiled/_tests/test_sync.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import asyncio
22
import contextlib
33
import tempfile
4+
import uuid
45

56
import awkward
67
import h5py
@@ -24,7 +25,9 @@
2425
def client_factory(readable_storage=None):
2526
with tempfile.TemporaryDirectory() as tempdir:
2627
catalog = in_memory(
27-
writable_storage=str(tempdir), readable_storage=readable_storage
28+
named_memory=str(uuid.uuid4())[:8],
29+
writable_storage=str(tempdir),
30+
readable_storage=readable_storage,
2831
)
2932
app = build_app(catalog)
3033
with Context.from_app(app) as context:

tiled/_tests/test_validation.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""
22
This tests tiled's validation registry
33
"""
4+
import uuid
5+
46
import numpy as np
57
import pandas as pd
68
import pytest
@@ -50,7 +52,10 @@ def client(tmpdir_module):
5052
{
5153
"tree": "tiled.catalog:in_memory",
5254
"path": "/",
53-
"args": {"writable_storage": str(tmpdir_module)},
55+
"args": {
56+
"named_memory": str(uuid.uuid4())[:8],
57+
"writable_storage": str(tmpdir_module),
58+
},
5459
},
5560
],
5661
"specs": [
@@ -104,7 +109,10 @@ def test_unknown_spec_strict(tmpdir):
104109
{
105110
"tree": "tiled.catalog:in_memory",
106111
"path": "/",
107-
"args": {"writable_storage": str(tmpdir)},
112+
"args": {
113+
"named_memory": str(uuid.uuid4())[:8],
114+
"writable_storage": str(tmpdir),
115+
},
108116
},
109117
],
110118
"specs": [

tiled/server/app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,13 +562,13 @@ async def startup_event():
562562
make_admin_by_identity,
563563
purge_expired,
564564
)
565-
from .connection_pool import open_database_connection_pool
565+
from .connection_pool import is_memory_sqlite, open_database_connection_pool
566566

567567
# This creates a connection pool and stashes it in a module-global
568568
# registry, keyed on database_settings, where it can be retrieved by
569569
# the Dependency get_database_session.
570570
engine = open_database_connection_pool(settings.database_settings)
571-
if not engine.url.database or engine.url.query.get("mode") == "memory":
571+
if is_memory_sqlite(engine.url):
572572
# Special-case for in-memory SQLite: Because it is transient we can
573573
# skip over anything related to migrations.
574574
await initialize_database(engine)

tiled/server/connection_pool.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from sqlalchemy import event
88
from sqlalchemy.engine import URL, make_url
99
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, create_async_engine
10-
from sqlalchemy.pool import AsyncAdaptedQueuePool
10+
from sqlalchemy.pool import AsyncAdaptedQueuePool, StaticPool
1111

1212
from ..server.settings import DatabaseSettings, Settings, get_settings
1313
from ..utils import ensure_specified_sql_driver, safe_json_dump, sanitize_uri
@@ -60,8 +60,8 @@ def open_database_connection_pool(database_settings: DatabaseSettings) -> AsyncE
6060
ensure_specified_sql_driver(database_settings.uri),
6161
echo=DEFAULT_ECHO,
6262
json_serializer=json_serializer,
63+
poolclass=StaticPool,
6364
)
64-
6565
else:
6666
engine = create_async_engine(
6767
ensure_specified_sql_driver(database_settings.uri),
@@ -73,9 +73,9 @@ def open_database_connection_pool(database_settings: DatabaseSettings) -> AsyncE
7373
pool_pre_ping=database_settings.pool_pre_ping,
7474
)
7575

76-
# Cache the engine so we don't create more than one pool per database_settings.
77-
monitor_db_pool(engine.pool, sanitize_uri(database_settings.uri)[0])
78-
_connection_pools[database_settings] = engine
76+
# Cache the engine so we don't create more than one pool per database_settings.
77+
monitor_db_pool(engine.pool, sanitize_uri(database_settings.uri)[0])
78+
_connection_pools[database_settings] = engine
7979

8080
# For SQLite, ensure that foreign key constraints are enforced.
8181
if engine.dialect.name == "sqlite":

0 commit comments

Comments
 (0)