Skip to content

Commit

Permalink
Merge pull request #426 from HarperDB/aakers/cache-table-data
Browse files Browse the repository at this point in the history
Caching Describe Table Call, Reducing Expensive Call To Backend
  • Loading branch information
BboyAkers authored Dec 6, 2024
2 parents 8521ab6 + e44c6eb commit 99f1689
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 12 deletions.
33 changes: 24 additions & 9 deletions src/components/instance/browse/BrowseDatatable.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useContext } from 'react';

Check warning on line 1 in src/components/instance/browse/BrowseDatatable.js

View workflow job for this annotation

GitHub Actions / publishStageStudio

'useContext' is defined but never used
import { useNavigate, useParams } from 'react-router-dom';
import useInterval from 'use-interval';
import { Card, CardBody } from 'reactstrap';
Expand All @@ -12,6 +12,7 @@ import DataTable from '../../shared/DataTable';
import getTableData from '../../../functions/instance/getTableData';
import getTablePagination from '../../../functions/instance/getTablePagination';
import usePersistedUser from '../../../functions/state/persistedUser';
import { clearTableDescriptionCache } from '../../../functions/instance/state/describeTableCache';

let controller;
let controller2;
Expand Down Expand Up @@ -47,7 +48,7 @@ function BrowseDatatable({ tableState, setTableState, activeTable, tableDescript
schema,
table,
filtered: tableState.filtered,
pageSize: tableState.pageSize,
pageSize: parseInt(tableState.pageSize, 10),
auth,
url,
signal: controller3.signal,
Expand Down Expand Up @@ -78,7 +79,7 @@ function BrowseDatatable({ tableState, setTableState, activeTable, tableDescript
schema,
table,
filtered: tableState.filtered,
pageSize: tableState.pageSize,
pageSize: parseInt(tableState.pageSize, 10),
sorted: tableState.sorted,
onlyCached: persistedUser?.onlyCached?.[activeTable],
page: tableState.page,
Expand Down Expand Up @@ -154,10 +155,18 @@ function BrowseDatatable({ tableState, setTableState, activeTable, tableDescript
loadingFilter={loadingFilter}
autoRefresh={tableState.autoRefresh}
onlyCached={persistedUser?.onlyCached?.[activeTable]}
refresh={() => setLastUpdate(Date.now())}
toggleAutoRefresh={() => setTableState({ ...tableState, autoRefresh: !tableState.autoRefresh })}
refresh={() => {
clearTableDescriptionCache();
setLastUpdate(Date.now());
}}
toggleAutoRefresh={() => {
setTableState({ ...tableState, autoRefresh: !tableState.autoRefresh });
clearTableDescriptionCache();
}}
toggleOnlyCached={toggleOnlyCached}
toggleFilter={() => setTableState({ ...tableState, showFilter: !tableState.showFilter })}
toggleFilter={() => {
setTableState({ ...tableState, showFilter: !tableState.showFilter });
}}
/>
<Card className="my-3">
<CardBody className="react-table-holder">
Expand All @@ -177,9 +186,15 @@ function BrowseDatatable({ tableState, setTableState, activeTable, tableDescript
onFilteredChange={(value) => {
setTableState({ ...tableState, page: 0, filtered: value });
}}
onSortedChange={(value) => setTableState({ ...tableState, page: 0, sorted: value })}
onPageChange={(value) => setTableState({ ...tableState, page: value })}
onPageSizeChange={(value) => setTableState({ ...tableState, page: 0, pageSize: value })}
onSortedChange={(value) => {
setTableState({ ...tableState, page: 0, sorted: value });
}}
onPageChange={(value) => {
setTableState({ ...tableState, page: value });
}}
onPageSizeChange={(value) => {
setTableState({ ...tableState, page: 0, pageSize: value });
}}
onRowClick={(rowData) => {
// encode schema, table and hashValue because they can contain uri components
const hashValue = rowData[tableState.hashAttribute];
Expand Down
6 changes: 5 additions & 1 deletion src/components/instance/browse/BrowseDatatableHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Col, Row, Button } from 'reactstrap';
import { useNavigate, useParams } from 'react-router-dom';

import commaNumbers from '../../../functions/util/commaNumbers';
import { clearTableDescriptionCache } from '../../../functions/instance/state/describeTableCache';

function BrowseDatatableHeader({
totalRecords,
Expand Down Expand Up @@ -82,7 +83,10 @@ function BrowseDatatableHeader({
tabIndex="0"
title={`Add new record to table ${table}`}
className="me-3"
onClick={() => navigate(`/o/${customer_id}/i/${compute_stack_id}/browse/${schema}/${table}/add`)}
onClick={() => {
clearTableDescriptionCache();
navigate(`/o/${customer_id}/i/${compute_stack_id}/browse/${schema}/${table}/add`);
}}
>
<i className="fa fa-plus" />
</Button>
Expand Down
8 changes: 8 additions & 0 deletions src/components/instance/browse/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import addError from '../../../functions/api/lms/addError';
import useInstanceAuth from '../../../functions/state/instanceAuths';
import EmptyPrompt from '../../shared/EmptyPrompt';
import buildInstanceStructure from '../../../functions/instance/browse/buildInstanceStructure';
import { clearTableDescriptionCache } from '../../../functions/instance/state/describeTableCache';

const DataTable = lazy(() => import(/* webpackChunkName: "browse-datatable" */ './BrowseDatatable'));
const EntityManager = lazy(() => import(/* webpackChunkName: "browse-entitymanager" */ './EntityManager'));
Expand Down Expand Up @@ -147,6 +148,13 @@ function BrowseIndex() {
// eslint-disable-next-line
useEffect(validate, [structure, schema, table, compute_stack_id]);
useEffect(syncInstanceStructure, [auth, url, schema, table]);
useEffect(() => {
const clearTableDescriptionCacheInterval = setInterval(() => {
clearTableDescriptionCache();
}, 60000);

return () => clearInterval(clearTableDescriptionCacheInterval);
}, []);

return (
<Row id="browse">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import FileMenu, {
} from './FileMenu';

import EditorMenu, { SaveButton, RestartInstanceButton, RestartOnSaveToggle, RevertFileButton } from './EditorMenu';
import { clearTableDescriptionCache } from '../../../../../functions/instance/state/describeTableCache';

// TODO:
//
Expand Down Expand Up @@ -272,7 +273,10 @@ function WebIDE({

<NameProjectWindow
active={activeEditorWindow === EDITOR_WINDOWS.NAME_PROJECT_WINDOW}
onConfirm={addProject}
onConfirm={(newProjectName) => {
addProject(newProjectName);
clearTableDescriptionCache();
}}
onCancel={toDefaultWindow}
/>

Expand Down
7 changes: 6 additions & 1 deletion src/functions/instance/getTableData.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import describeTable from '../api/instance/describeTable';
import searchByValue from '../api/instance/searchByValue';
import searchByConditions from '../api/instance/searchByConditions';
import { getTableDescriptionFromCache, setTableDescriptionInCache } from './state/describeTableCache';

const getAttributesFromTableData = (tableData, existingAttributes) => {
if (!tableData.length) return [];
Expand Down Expand Up @@ -33,7 +34,11 @@ export default async ({ schema, table, filtered, pageSize, onlyCached, sorted, p
const offset = page * pageSize;

try {
const result = await describeTable({ auth, url, schema, table, signal: signal2 });
let result = getTableDescriptionFromCache(schema, table);
if (!result) {
result = await describeTable({ auth, url, schema, table, signal: signal2 });
setTableDescriptionInCache(schema, table, result);
}

if (result.error) {
allAttributes = [];
Expand Down
20 changes: 20 additions & 0 deletions src/functions/instance/state/describeTableCache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const descriptionCache = new Map();

const getTableKey = (schema, table) => `${schema}/${table}`;

const getTableDescriptionFromCache = (schema, table) => {
const tableKey = getTableKey(schema, table);
return descriptionCache.get(tableKey) ?? undefined;
};

const setTableDescriptionInCache = (schema, table, description) => {
const tableKey = getTableKey(schema, table);
descriptionCache.set(tableKey, description);
};

const clearTableDescriptionCache = () => {
if (!descriptionCache.size) return;
descriptionCache.clear();
};

export { descriptionCache, getTableDescriptionFromCache, setTableDescriptionInCache, clearTableDescriptionCache };

0 comments on commit 99f1689

Please sign in to comment.