mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
e900f39da3
Summary: Record numbers of rows, columns, cells, and bytes of marshalled data for most calls to table_data_from_db Export new function get_table_stats in the sandbox, which gives the raw numbers and totals. Get and log these stats in ActiveDoc right after loading tables, before Calculate, so they are logged even in case of errors. Tweak logging about number of tables, especially number of on-demand tables, to not only show in debug logging. Test Plan: Updated doc regression tests, that shows what the data looks like nicely. Reviewers: dsagal, paulfitz Reviewed By: dsagal Differential Revision: https://phab.getgrist.com/D3081
135 lines
4.1 KiB
Python
135 lines
4.1 KiB
Python
"""
|
|
This module defines what sandbox functions are made available to the Node controller,
|
|
and starts the grist sandbox. See engine.py for the API documentation.
|
|
"""
|
|
import os
|
|
import sys
|
|
sys.path.append('thirdparty')
|
|
# pylint: disable=wrong-import-position
|
|
|
|
import marshal
|
|
import functools
|
|
|
|
import six
|
|
|
|
import actions
|
|
import engine
|
|
import migrations
|
|
import schema
|
|
import useractions
|
|
import objtypes
|
|
from acl_formula import parse_acl_formula
|
|
from sandbox import get_default_sandbox
|
|
from imports.register import register_import_parsers
|
|
|
|
import logger
|
|
log = logger.Logger(__name__, logger.INFO)
|
|
|
|
def table_data_from_db(table_name, table_data_repr):
|
|
if table_data_repr is None:
|
|
return actions.TableData(table_name, [], {})
|
|
table_data_parsed = marshal.loads(table_data_repr)
|
|
table_data_parsed = {key.decode("utf8"): value for key, value in table_data_parsed.items()}
|
|
id_col = table_data_parsed.pop("id")
|
|
return actions.TableData(table_name, id_col,
|
|
actions.decode_bulk_values(table_data_parsed, _decode_db_value))
|
|
|
|
def _decode_db_value(value):
|
|
# Decode database values received from SQLite's allMarshal() call. These are encoded by
|
|
# marshalling certain types and storing as BLOBs (received in Python as binary strings, as
|
|
# opposed to text which is received as unicode). See also encodeValue() in DocStorage.js
|
|
t = type(value)
|
|
if t == six.binary_type:
|
|
return objtypes.decode_object(marshal.loads(value))
|
|
else:
|
|
return value
|
|
|
|
def run(sandbox):
|
|
eng = engine.Engine()
|
|
|
|
def export(method):
|
|
# Wrap each method so that it logs a message that it's being called.
|
|
@functools.wraps(method)
|
|
def wrapper(*args, **kwargs):
|
|
log.debug("calling %s" % method.__name__)
|
|
return method(*args, **kwargs)
|
|
|
|
sandbox.register(method.__name__, wrapper)
|
|
|
|
def load_and_record_table_data(table_name, table_data_repr):
|
|
result = table_data_from_db(table_name, table_data_repr)
|
|
eng.record_table_stats(result, table_data_repr)
|
|
return result
|
|
|
|
@export
|
|
def apply_user_actions(action_reprs, user=None):
|
|
action_group = eng.apply_user_actions([useractions.from_repr(u) for u in action_reprs], user)
|
|
return eng.acl_split(action_group).to_json_obj()
|
|
|
|
@export
|
|
def fetch_table(table_id, formulas=True, query=None):
|
|
return actions.get_action_repr(eng.fetch_table(table_id, formulas=formulas, query=query))
|
|
|
|
@export
|
|
def fetch_table_schema():
|
|
return eng.fetch_table_schema()
|
|
|
|
@export
|
|
def autocomplete(txt, table_id, column_id, user):
|
|
return eng.autocomplete(txt, table_id, column_id, user)
|
|
|
|
@export
|
|
def find_col_from_values(values, n, opt_table_id):
|
|
return eng.find_col_from_values(values, n, opt_table_id)
|
|
|
|
@export
|
|
def fetch_meta_tables(formulas=True):
|
|
return {table_id: actions.get_action_repr(table_data)
|
|
for (table_id, table_data) in six.iteritems(eng.fetch_meta_tables(formulas))}
|
|
|
|
@export
|
|
def load_meta_tables(meta_tables, meta_columns):
|
|
return eng.load_meta_tables(load_and_record_table_data("_grist_Tables", meta_tables),
|
|
load_and_record_table_data("_grist_Tables_column", meta_columns))
|
|
|
|
@export
|
|
def load_table(table_name, table_data):
|
|
return eng.load_table(load_and_record_table_data(table_name, table_data))
|
|
|
|
@export
|
|
def get_table_stats():
|
|
return eng.get_table_stats()
|
|
|
|
@export
|
|
def create_migrations(all_tables, metadata_only=False):
|
|
doc_actions = migrations.create_migrations(
|
|
{t: table_data_from_db(t, data) for t, data in six.iteritems(all_tables)}, metadata_only)
|
|
return [actions.get_action_repr(action) for action in doc_actions]
|
|
|
|
@export
|
|
def get_version():
|
|
return schema.SCHEMA_VERSION
|
|
|
|
@export
|
|
def set_doc_url(doc_url):
|
|
os.environ['DOC_URL'] = doc_url
|
|
|
|
@export
|
|
def get_formula_error(table_id, col_id, row_id):
|
|
return objtypes.encode_object(eng.get_formula_error(table_id, col_id, row_id))
|
|
|
|
export(parse_acl_formula)
|
|
export(eng.load_empty)
|
|
export(eng.load_done)
|
|
|
|
register_import_parsers(sandbox)
|
|
|
|
log.info("Ready") # This log message is significant for checkpointing.
|
|
sandbox.run()
|
|
|
|
def main():
|
|
run(get_default_sandbox())
|
|
|
|
if __name__ == "__main__":
|
|
main()
|