-
Notifications
You must be signed in to change notification settings - Fork 324
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
Persistent session storage #614
Changes from 5 commits
3812cf5
a5e1e86
2c289bb
fe3658d
fb4f33c
425632e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
"""A base class session manager.""" | ||
# Copyright (c) Jupyter Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||
import os | ||
import pathlib | ||
import uuid | ||
|
||
try: | ||
|
@@ -13,13 +15,48 @@ | |
|
||
from traitlets.config.configurable import LoggingConfigurable | ||
from traitlets import Instance | ||
from traitlets import Unicode | ||
from traitlets import validate | ||
from traitlets import TraitError | ||
|
||
from jupyter_server.utils import ensure_async | ||
from jupyter_server.traittypes import InstanceFromClasses | ||
|
||
|
||
class SessionManager(LoggingConfigurable): | ||
|
||
database_filepath = Unicode( | ||
default_value=":memory:", | ||
help=( | ||
"Th filesystem path to SQLite Database file " | ||
"(e.g. /path/to/session_database.db). By default, the session " | ||
"database is stored in-memory (i.e. `:memory:` setting from sqlite3) " | ||
"and does not persist when the current Jupyter Server shuts down." | ||
), | ||
).tag(config=True) | ||
|
||
@validate("database_filepath") | ||
def _validate_database_filepath(self, proposal): | ||
value = proposal["value"] | ||
if value == ":memory:": | ||
return value | ||
path = pathlib.Path(value) | ||
if path.exists(): | ||
# Verify that the database path is not a directory. | ||
if path.is_dir(): | ||
raise TraitError( | ||
"`database_filepath` expected a file path, but the given path is a directory." | ||
) | ||
# If the file exists, but it's empty, its a valid entry. | ||
if os.stat(path).st_size == 0: | ||
return value | ||
# Verify that database path is an SQLite 3 Database by checking its header. | ||
with open(value, "rb") as f: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I meant also for the contents validation piece, rather than inspecting the file There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, yup, confirmed. |
||
header = f.read(100) | ||
if not header.startswith(b"SQLite format 3"): | ||
raise TraitError("The file does not look like ") | ||
return value | ||
|
||
kernel_manager = Instance("jupyter_server.services.kernels.kernelmanager.MappingKernelManager") | ||
contents_manager = InstanceFromClasses( | ||
[ | ||
|
@@ -39,7 +76,7 @@ def cursor(self): | |
if self._cursor is None: | ||
self._cursor = self.connection.cursor() | ||
self._cursor.execute( | ||
"""CREATE TABLE session | ||
"""CREATE TABLE IF NOT EXISTS session | ||
(session_id, path, name, type, kernel_id)""" | ||
) | ||
return self._cursor | ||
|
@@ -48,7 +85,8 @@ def cursor(self): | |
def connection(self): | ||
"""Start a database connection""" | ||
if self._connection is None: | ||
self._connection = sqlite3.connect(":memory:") | ||
# Set isolation level to None to autocommit all changes to the database. | ||
self._connection = sqlite3.connect(self.database_filepath, isolation_level=None) | ||
self._connection.row_factory = sqlite3.Row | ||
return self._connection | ||
|
||
|
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'd say just try to connect to the file here and let the error propagate. I verified that you can connect to an empty file.