mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-30 04:01:31 +08: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
	 zadam
						zadam