mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-30 12:13:52 +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 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,6 +168,7 @@ 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) { | ||||||
|  |         if (!(this.noteId in noteAttributeCache)) { | ||||||
|             const ownedAttributes = this.getOwnedAttributes(); |             const ownedAttributes = this.getOwnedAttributes(); | ||||||
| 
 | 
 | ||||||
|             const attrArrs = [ |             const attrArrs = [ | ||||||
| @ -174,7 +176,7 @@ class NoteShort { | |||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             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()); | ||||||
| @ -190,20 +192,21 @@ class NoteShort { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         const attributes = attrArrs.flat(); |             noteAttributeCache.attributes[this.noteId] = attrArrs.flat(); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         return this.__filterAttrs(attributes, type, name); |         return this.__filterAttrs(noteAttributeCache.attributes[this.noteId], 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
	 zadam
						zadam