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 Attribute from './attribute.js';
|
||||
import noteAttributeCache from "../services/note_attribute_cache.js";
|
||||
|
||||
const LABEL = 'label';
|
||||
const LABEL_DEFINITION = 'label-definition';
|
||||
@ -156,9 +157,9 @@ class NoteShort {
|
||||
getOwnedAttributes(type, name) {
|
||||
const attrs = this.attributes
|
||||
.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
|
||||
*/
|
||||
getAttributes(type, name) {
|
||||
const ownedAttributes = this.getOwnedAttributes();
|
||||
if (!(this.noteId in noteAttributeCache)) {
|
||||
const ownedAttributes = this.getOwnedAttributes();
|
||||
|
||||
const attrArrs = [
|
||||
ownedAttributes
|
||||
];
|
||||
const attrArrs = [
|
||||
ownedAttributes
|
||||
];
|
||||
|
||||
for (const templateAttr of ownedAttributes.filter(oa => oa.type === 'relation' && oa.name === 'template')) {
|
||||
const templateNote = this.treeCache.getNoteFromCache(templateAttr.value);
|
||||
for (const templateAttr of ownedAttributes.filter(oa => oa.type === 'relation' && oa.name === 'template')) {
|
||||
const templateNote = this.treeCache.notes[templateAttr.value];
|
||||
|
||||
if (templateNote) {
|
||||
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 (templateNote) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
noteAttributeCache.attributes[this.noteId] = attrArrs.flat();
|
||||
}
|
||||
|
||||
const attributes = attrArrs.flat();
|
||||
|
||||
return this.__filterAttrs(attributes, type, name);
|
||||
return this.__filterAttrs(noteAttributeCache.attributes[this.noteId], 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);
|
||||
} else if (type) {
|
||||
return attributes.filter(attr => attr.type === type);
|
||||
} else if (name) {
|
||||
return attributes.filter(attr => attr.name === name);
|
||||
} else {
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,15 @@ export default class LoadResults {
|
||||
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() {
|
||||
return Object.keys(this.noteIdToSourceId).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 options from "./options.js";
|
||||
import treeCache from "./tree_cache.js";
|
||||
import noteAttributeCache from "./note_attribute_cache.js";
|
||||
|
||||
const $outstandingSyncsCount = $("#outstanding-syncs-count");
|
||||
|
||||
@ -359,6 +360,10 @@ async function processSyncRows(syncRows) {
|
||||
});
|
||||
|
||||
if (!loadResults.isEmpty()) {
|
||||
if (loadResults.hasAttributeRelatedChanges()) {
|
||||
noteAttributeCache.invalidate();
|
||||
}
|
||||
|
||||
const appContext = (await import("./app_context.js")).default;
|
||||
await appContext.triggerEvent('entitiesReloaded', {loadResults});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user