mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
add note attribute cache to speed up tree loading
This commit is contained in:
parent
ed52f93bbb
commit
9be1d1f697
@ -1,5 +1,6 @@
|
|||||||
import server from '../services/server.js';
|
import server from '../services/server.js';
|
||||||
import Attribute from './attribute.js';
|
import Attribute from './attribute.js';
|
||||||
|
import noteAttributeCache from "../services/note_attribute_cache.js";
|
||||||
|
|
||||||
const LABEL = 'label';
|
const LABEL = 'label';
|
||||||
const LABEL_DEFINITION = 'label-definition';
|
const LABEL_DEFINITION = 'label-definition';
|
||||||
@ -156,9 +157,9 @@ class NoteShort {
|
|||||||
getOwnedAttributes(type, name) {
|
getOwnedAttributes(type, name) {
|
||||||
const attrs = this.attributes
|
const attrs = this.attributes
|
||||||
.map(attributeId => this.treeCache.attributes[attributeId])
|
.map(attributeId => this.treeCache.attributes[attributeId])
|
||||||
.filter(attr => !!attr);
|
.filter(Boolean); // filter out nulls;
|
||||||
|
|
||||||
return this.__filterAttrs(attrs, type, name)
|
return this.__filterAttrs(attrs, type, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,43 +168,45 @@ class NoteShort {
|
|||||||
* @returns {Attribute[]} all note's attributes, including inherited ones
|
* @returns {Attribute[]} all note's attributes, including inherited ones
|
||||||
*/
|
*/
|
||||||
getAttributes(type, name) {
|
getAttributes(type, name) {
|
||||||
const ownedAttributes = this.getOwnedAttributes();
|
if (!(this.noteId in noteAttributeCache)) {
|
||||||
|
const ownedAttributes = this.getOwnedAttributes();
|
||||||
|
|
||||||
const attrArrs = [
|
const attrArrs = [
|
||||||
ownedAttributes
|
ownedAttributes
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const templateAttr of ownedAttributes.filter(oa => oa.type === 'relation' && oa.name === 'template')) {
|
for (const templateAttr of ownedAttributes.filter(oa => oa.type === 'relation' && oa.name === 'template')) {
|
||||||
const templateNote = this.treeCache.getNoteFromCache(templateAttr.value);
|
const templateNote = this.treeCache.notes[templateAttr.value];
|
||||||
|
|
||||||
if (templateNote) {
|
if (templateNote) {
|
||||||
attrArrs.push(templateNote.getAttributes());
|
attrArrs.push(templateNote.getAttributes());
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.noteId !== 'root') {
|
|
||||||
for (const parentNote of this.getParentNotes()) {
|
|
||||||
// these virtual parent-child relationships are also loaded into frontend tree cache
|
|
||||||
if (parentNote.type !== 'search') {
|
|
||||||
attrArrs.push(parentNote.getInheritableAttributes());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.noteId !== 'root') {
|
||||||
|
for (const parentNote of this.getParentNotes()) {
|
||||||
|
// these virtual parent-child relationships are also loaded into frontend tree cache
|
||||||
|
if (parentNote.type !== 'search') {
|
||||||
|
attrArrs.push(parentNote.getInheritableAttributes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
noteAttributeCache.attributes[this.noteId] = attrArrs.flat();
|
||||||
}
|
}
|
||||||
|
|
||||||
const attributes = attrArrs.flat();
|
return this.__filterAttrs(noteAttributeCache.attributes[this.noteId], type, name);
|
||||||
|
|
||||||
return this.__filterAttrs(attributes, type, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__filterAttrs(attributes, type, name) {
|
__filterAttrs(attributes, type, name) {
|
||||||
if (type && name) {
|
if (!type && !name) {
|
||||||
|
return attributes;
|
||||||
|
} else if (type && name) {
|
||||||
return attributes.filter(attr => attr.type === type && attr.name === name);
|
return attributes.filter(attr => attr.type === type && attr.name === name);
|
||||||
} else if (type) {
|
} else if (type) {
|
||||||
return attributes.filter(attr => attr.type === type);
|
return attributes.filter(attr => attr.type === type);
|
||||||
} else if (name) {
|
} else if (name) {
|
||||||
return attributes.filter(attr => attr.name === name);
|
return attributes.filter(attr => attr.name === name);
|
||||||
} else {
|
|
||||||
return attributes;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +101,15 @@ export default class LoadResults {
|
|||||||
this.options.includes(name);
|
this.options.includes(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean} true if there are changes which could affect the attributes (including inherited ones)
|
||||||
|
*/
|
||||||
|
hasAttributeRelatedChanges() {
|
||||||
|
return Object.keys(this.noteIdToSourceId).length === 0
|
||||||
|
&& this.branches.length === 0
|
||||||
|
&& this.attributes.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
isEmpty() {
|
isEmpty() {
|
||||||
return Object.keys(this.noteIdToSourceId).length === 0
|
return Object.keys(this.noteIdToSourceId).length === 0
|
||||||
&& this.branches.length === 0
|
&& this.branches.length === 0
|
||||||
|
20
src/public/app/services/note_attribute_cache.js
Normal file
20
src/public/app/services/note_attribute_cache.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Purpose of this class is to cache list of attributes for notes.
|
||||||
|
*
|
||||||
|
* Cache invalidation granularity is global - whenever a write operation is detected to notes, branches or attributes
|
||||||
|
* we invalidate the whole cache. That's OK, since the purpose for this is to speed up batch read-only operations, such
|
||||||
|
* as loading the tree which uses attributes heavily.
|
||||||
|
*/
|
||||||
|
class NoteAttributeCache {
|
||||||
|
constructor() {
|
||||||
|
this.attributes = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate() {
|
||||||
|
this.attributes = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const noteAttributeCache = new NoteAttributeCache();
|
||||||
|
|
||||||
|
export default noteAttributeCache;
|
@ -6,6 +6,7 @@ import Branch from "../entities/branch.js";
|
|||||||
import Attribute from "../entities/attribute.js";
|
import Attribute from "../entities/attribute.js";
|
||||||
import options from "./options.js";
|
import options from "./options.js";
|
||||||
import treeCache from "./tree_cache.js";
|
import treeCache from "./tree_cache.js";
|
||||||
|
import noteAttributeCache from "./note_attribute_cache.js";
|
||||||
|
|
||||||
const $outstandingSyncsCount = $("#outstanding-syncs-count");
|
const $outstandingSyncsCount = $("#outstanding-syncs-count");
|
||||||
|
|
||||||
@ -359,6 +360,10 @@ async function processSyncRows(syncRows) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!loadResults.isEmpty()) {
|
if (!loadResults.isEmpty()) {
|
||||||
|
if (loadResults.hasAttributeRelatedChanges()) {
|
||||||
|
noteAttributeCache.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
const appContext = (await import("./app_context.js")).default;
|
const appContext = (await import("./app_context.js")).default;
|
||||||
await appContext.triggerEvent('entitiesReloaded', {loadResults});
|
await appContext.triggerEvent('entitiesReloaded', {loadResults});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user