Skip to content

Commit

Permalink
Issue #442
Browse files Browse the repository at this point in the history
  • Loading branch information
bindeali committed Sep 8, 2022
1 parent 8f369ee commit b80bffb
Show file tree
Hide file tree
Showing 30 changed files with 499 additions and 421 deletions.
7 changes: 5 additions & 2 deletions src/components/InterfaceNotification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface Props {
message: string;
error: boolean;
retry: boolean;
performTransaction: (...queries: string[]) => void;
performTransaction: (parallelize: boolean, ...queries: string[]) => void;
}

export default class InterfaceNotification extends React.Component<Props> {
Expand All @@ -27,7 +27,10 @@ export default class InterfaceNotification extends React.Component<Props> {
<button
className={"buttonlink"}
onClick={() => {
this.props.performTransaction(...AppSettings.lastTransactions);
this.props.performTransaction(
false,
...AppSettings.lastTransactions
);
}}
>
{Locale[AppSettings.interfaceLanguage].retry}
Expand Down
5 changes: 4 additions & 1 deletion src/components/modals/CreationModals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export type LinkCreationConfiguration = { sourceID: string; targetID: string };
interface Props {
update: () => void;
projectLanguage: string;
performTransaction: (...queries: string[]) => void;
performTransaction: (parallelize: boolean, ...queries: string[]) => void;
elemConfiguration: ElemCreationConfiguration;
linkConfiguration: LinkCreationConfiguration;
}
Expand All @@ -55,6 +55,7 @@ export const CreationModals: React.FC<Props> = (props) => {
setModalAddLink(false);
if (selectedLink) {
props.performTransaction(
true,
...saveNewLink(
selectedLink,
props.linkConfiguration.sourceID,
Expand All @@ -72,6 +73,7 @@ export const CreationModals: React.FC<Props> = (props) => {
setModalAddLink(false);
if (conceptName && vocabulary) {
props.performTransaction(
true,
...createTerm(
conceptName,
vocabulary,
Expand Down Expand Up @@ -101,6 +103,7 @@ export const CreationModals: React.FC<Props> = (props) => {
setModalAddElem(false);
if (conceptName && vocabulary) {
props.performTransaction(
true,
...createTerm(
conceptName,
vocabulary,
Expand Down
5 changes: 4 additions & 1 deletion src/function/FunctionCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ function getSubclassConnections(
);
}

export function insertNewCacheTerms(newTerms: typeof WorkspaceTerms) {
export function insertNewCacheTerms(newTerms: typeof WorkspaceTerms): string[] {
const newVocabularies: string[] = [];
Object.assign(WorkspaceTerms, newTerms);
for (const term in newTerms) {
const vocab = Object.keys(CacheSearchVocabularies).find(
Expand All @@ -208,6 +209,7 @@ export function insertNewCacheTerms(newTerms: typeof WorkspaceTerms) {
WorkspaceVocabularies[vocab].glossary === newTerms[term].inScheme
)
) {
newVocabularies.push(vocab);
WorkspaceVocabularies[vocab] = {
labels: CacheSearchVocabularies[vocab].labels,
readOnly: true,
Expand All @@ -225,6 +227,7 @@ export function insertNewCacheTerms(newTerms: typeof WorkspaceTerms) {
`Vocabulary with glossary ${newTerms[term].inScheme} has not been found in the database; term ${term} will not be added.`
);
}
return newVocabularies;
}

export function insertNewRestrictions(values: {
Expand Down
11 changes: 9 additions & 2 deletions src/function/FunctionElem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { RepresentationConfig } from "../config/logic/RepresentationConfig";
import { updateDeleteTriples } from "../queries/update/UpdateMiscQueries";
import { updateCreateDiagram } from "../queries/update/UpdateDiagramQueries";
import { fetchRestrictions, fetchTerms } from "../queries/get/FetchQueries";
import { fetchVocabularyTermCount } from "../queries/get/CacheQueries";

export function resizeElem(id: string, highlight: boolean = true) {
let view = paper.findViewByModel(id);
Expand Down Expand Up @@ -303,7 +304,7 @@ export async function putElementsOnCanvas(
);
const terms = _.merge(
readOnlyTerms,
fetchRestrictions(
await fetchRestrictions(
AppSettings.contextEndpoint,
readOnlyTerms,
undefined,
Expand All @@ -312,7 +313,13 @@ export async function putElementsOnCanvas(
true
)
);
insertNewCacheTerms(terms);
// This fetch fires only when the added read-only terms are from vocabularies
// not considered as part of the "project".
await fetchVocabularyTermCount(
AppSettings.contextEndpoint,
AppSettings.cacheContext,
...insertNewCacheTerms(terms)
);
insertNewRestrictions(relationships);
const newElements = initElements(true);
const newConnections = initConnections().add;
Expand Down
13 changes: 9 additions & 4 deletions src/function/FunctionGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { insertNewCacheTerms, insertNewRestrictions } from "./FunctionCache";
import { updateDiagram } from "../queries/update/UpdateDiagramQueries";
import { addLink } from "./FunctionCreateVars";
import { fetchRestrictions, fetchTerms } from "../queries/get/FetchQueries";
import { fetchVocabularyTermCount } from "../queries/get/CacheQueries";

export const mvp1IRI =
"https://slovník.gov.cz/základní/pojem/má-vztažený-prvek-1";
Expand Down Expand Up @@ -86,7 +87,7 @@ export async function spreadConnections(
.filter((link) => !isUrl(link))
.map((link) => getOtherConnectionElementID(link, id));
const iris = elements.filter((iri) => isUrl(iri));
let queries: string[] = [];
const queries: string[] = [];
if (iris.length > 0) {
const readOnlyTerms = await fetchTerms(
AppSettings.contextEndpoint,
Expand All @@ -106,8 +107,12 @@ export async function spreadConnections(
true
)
);
insertNewCacheTerms(
_.merge(terms, await fetchRestrictions(AppSettings.contextEndpoint))
await fetchVocabularyTermCount(
AppSettings.contextEndpoint,
AppSettings.cacheContext,
...insertNewCacheTerms(
_.merge(terms, await fetchRestrictions(AppSettings.contextEndpoint))
)
);
insertNewRestrictions(
await fetchRestrictions(
Expand All @@ -133,7 +138,7 @@ export async function spreadConnections(
ids.forEach((id, i) => {
const x = centerX + radius * Math.cos((i * 2 * Math.PI) / length);
const y = centerY + radius * Math.sin((i * 2 * Math.PI) / length);
let newElem = new graphElement({ id: id });
const newElem = new graphElement({ id: id });
newElem.position(x, y);
WorkspaceElements[id].position[AppSettings.selectedDiagram] = {
x: x,
Expand Down
63 changes: 45 additions & 18 deletions src/interface/ContextInterface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import {
getLinksConfig,
getSettings,
} from "../queries/get/InitQueries";
import { fetchVocabularies } from "../queries/get/CacheQueries";
import {
fetchVocabularies,
fetchVocabularyTermCount,
} from "../queries/get/CacheQueries";
import { qb } from "../queries/QueryBuilder";
import {
updateProjectElement,
Expand All @@ -31,7 +34,7 @@ import {
} from "../function/FunctionEditVars";
import {
updateDeleteProjectLink,
updateProjectLinkParallel,
updateProjectLink,
} from "../queries/update/UpdateLinkQueries";
import { initConnections } from "../function/FunctionRestriction";
import { insertNewCacheTerms } from "../function/FunctionCache";
Expand Down Expand Up @@ -81,6 +84,7 @@ export async function updateContexts(): Promise<boolean> {
case ContextLoadingStrategy.RECONSTRUCT_WORKSPACE:
const ret2 = await processTransaction(
AppSettings.contextEndpoint,
false,
qb.constructQuery(await reconstructApplicationContextWithDiagrams())
);
if (!ret2) return false;
Expand All @@ -102,6 +106,7 @@ export async function updateContexts(): Promise<boolean> {
}
const ret = await processTransaction(
AppSettings.contextEndpoint,
false,
qb.constructQuery(...queries)
);
if (!ret) return false;
Expand All @@ -112,6 +117,7 @@ export async function updateContexts(): Promise<boolean> {
if (contextsMissingAppContexts.length > 1) {
const ret = await processTransaction(
AppSettings.contextEndpoint,
false,
qb.constructQuery(
...contextsMissingAppContexts.map((context) =>
INSERT.DATA`
Expand All @@ -129,6 +135,7 @@ export async function updateContexts(): Promise<boolean> {
if (contextsMissingAttachments.length > 1) {
const ret = await processTransaction(
AppSettings.contextEndpoint,
false,
qb.constructQuery(
...contextsMissingAttachments.map((context) =>
INSERT.DATA`
Expand Down Expand Up @@ -249,11 +256,15 @@ export async function retrieveVocabularyData(): Promise<boolean> {
}

export async function retrieveContextData(): Promise<boolean> {
if (!(await getElementsConfig(AppSettings.contextEndpoint))) return false;
if (!(await getLinksConfig(AppSettings.contextEndpoint))) return false;
const booleans = await Promise.all([
getElementsConfig(AppSettings.contextEndpoint),
getLinksConfig(AppSettings.contextEndpoint),
]);
if (booleans.some((b) => !b)) return false;
const missingTerms: string[] = Object.keys(WorkspaceElements).filter(
(id) => !(id in WorkspaceTerms)
);
let newVocabularies: string[] = [];
if (missingTerms.length > 0) {
const terms = await fetchTerms(
AppSettings.contextEndpoint,
Expand Down Expand Up @@ -281,7 +292,7 @@ export async function retrieveContextData(): Promise<boolean> {
// "batch" finish at around the same time.
await Promise.all(functions.splice(0, 3).map((f) => f()));
}
insertNewCacheTerms(_.merge(terms, restrictions));
newVocabularies = insertNewCacheTerms(_.merge(terms, restrictions));
}
checkForObsoleteDiagrams();
Object.keys(WorkspaceLinks)
Expand Down Expand Up @@ -310,16 +321,6 @@ export async function retrieveContextData(): Promise<boolean> {
deleteConcept(id);
});
const elements = initElements();
if (
!(await processTransaction(
AppSettings.contextEndpoint,
qb.constructQuery(
updateProjectElementNames(),
updateProjectElement(false, ...elements)
)
))
)
return false;
addToFlexSearch(...Object.keys(WorkspaceElements));
const connections = initConnections();
for (const id of connections.del) {
Expand All @@ -330,11 +331,36 @@ export async function retrieveContextData(): Promise<boolean> {
);
WorkspaceLinks[id].active = false;
}
const updates = await Promise.all([
processTransaction(
AppSettings.contextEndpoint,
false,
qb.constructQuery(updateProjectElementNames())
),
processTransaction(
AppSettings.contextEndpoint,
false,
qb.constructQuery(updateProjectElement(false, ...elements))
),
processTransaction(
AppSettings.contextEndpoint,
false,
qb.constructQuery(updateDeleteProjectLink(true, ...connections.del))
),
fetchVocabularyTermCount(
AppSettings.contextEndpoint,
AppSettings.cacheContext,
...newVocabularies
),
]);
if (updates.some((u) => !u)) return false;
// These updates, if run in parallel, have the ability to DoS the DB - it has to run sequentially, unfortunately.
// Such a large load is usually generated only on opening vocabularies for the first time, or a saving/loading error.
return await processTransaction(
AppSettings.contextEndpoint,
qb.constructQuery(updateDeleteProjectLink(true, ...connections.del)),
...updateProjectLinkParallel(...connections.add).map((t) =>
qb.constructQuery(t)
false,
..._.chunk(connections.add, 25).map((chunk) =>
qb.constructQuery(updateProjectLink(false, ...chunk))
)
);
}
Expand Down Expand Up @@ -387,6 +413,7 @@ function checkForObsoleteDiagrams() {
changeDiagrams();
await processTransaction(
AppSettings.contextEndpoint,
false,
qb.constructQuery(...queries)
);
},
Expand Down
26 changes: 22 additions & 4 deletions src/interface/TransactionInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import { Environment } from "../config/Environment";

export async function processTransaction(
contextEndpoint: string,
parallelize: boolean,
...transactions: string[]
): Promise<boolean> {
AppSettings.lastTransactions = transactions;
for (const transaction of transactions) {
if (!transaction) continue;
const connect: (transaction: string) => Promise<boolean> = async (
transaction: string
) => {
if (!transaction) return true;
const timeoutDeadline = 15000;
const controller = new AbortController();
const signal = controller.signal;
Expand All @@ -27,7 +30,12 @@ export async function processTransaction(
.then((headers) => {
let location = headers.get("location");
if (location) return location;
else return undefined;
else {
console.error(
"Unable to fetch location header for SPARQL UPDATE query."
);
return undefined;
}
})
.catch((e) => {
console.error(e);
Expand Down Expand Up @@ -76,13 +84,23 @@ export async function processTransaction(
window.clearTimeout(timeout);
if (resultCommit) {
AppSettings.lastTransactionID = "";
return true;
} else {
await abortTransaction(transactionID);
return false;
}
} else return false;
};
if (!parallelize) {
for (const t of transactions) {
if (!(await connect(t))) return false;
}
return true;
} else {
return await Promise.all(transactions.map((t) => connect(t))).then(
(booleans) => booleans.every((b) => b)
);
}
return true;
}

export async function abortTransaction(transaction: string): Promise<boolean> {
Expand Down
30 changes: 16 additions & 14 deletions src/main/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ export default class App extends React.Component<
});
}

performTransaction(...queries: string[]) {
performTransaction(parallelize: boolean, ...queries: string[]) {
const queriesTrimmed = queries.filter((q) => q);
if (queriesTrimmed.length === 0) {
this.handleWorkspaceReady();
Expand All @@ -220,20 +220,22 @@ export default class App extends React.Component<
false,
false
);
processTransaction(AppSettings.contextEndpoint, transaction).then(
(result) => {
if (result) {
this.handleWorkspaceReady();
} else {
this.handleStatus(
false,
Locale[AppSettings.interfaceLanguage].errorUpdating,
true,
true
);
}
processTransaction(
AppSettings.contextEndpoint,
parallelize,
transaction
).then((result) => {
if (result) {
this.handleWorkspaceReady();
} else {
this.handleStatus(
false,
Locale[AppSettings.interfaceLanguage].errorUpdating,
true,
true
);
}
);
});
}

handleStatus(
Expand Down
Loading

0 comments on commit b80bffb

Please sign in to comment.