From ea32c54f57cd700a87dac91081d3c4903bd33489 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Mon, 25 Apr 2022 13:57:39 +0200 Subject: [PATCH 1/3] Fixed massive writes to creature.variables on calc Now only writes changed variables, preventing oplog from being polluted with massive updates --- .../engine/computation/CreatureComputation.js | 3 ++- .../computation/buildCreatureComputation.js | 2 +- .../writeComputation/writeScope.js | 27 ++++++++++++++++--- app/imports/api/engine/computeCreature.js | 2 +- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/app/imports/api/engine/computation/CreatureComputation.js b/app/imports/api/engine/computation/CreatureComputation.js index 90e28f44..278b3276 100644 --- a/app/imports/api/engine/computation/CreatureComputation.js +++ b/app/imports/api/engine/computation/CreatureComputation.js @@ -2,7 +2,7 @@ import { EJSON } from 'meteor/ejson'; import createGraph from 'ngraph.graph'; export default class CreatureComputation { - constructor(properties){ + constructor(properties, creature){ // Set up fields this.originalPropsById = {}; this.propsById = {}; @@ -11,6 +11,7 @@ export default class CreatureComputation { this.props = properties; this.dependencyGraph = createGraph(); this.errors = []; + this.creature = creature; // Store properties for easy access later properties.forEach(prop => { diff --git a/app/imports/api/engine/computation/buildCreatureComputation.js b/app/imports/api/engine/computation/buildCreatureComputation.js index 8e81e314..ebf06518 100644 --- a/app/imports/api/engine/computation/buildCreatureComputation.js +++ b/app/imports/api/engine/computation/buildCreatureComputation.js @@ -54,7 +54,7 @@ function getCreature(creatureId){ export function buildComputationFromProps(properties, creature){ - const computation = new CreatureComputation(properties); + const computation = new CreatureComputation(properties, creature); // Dependency graph where edge(a, b) means a depends on b // The graph includes all dependencies even of inactive properties // such that any properties changing without changing their dependencies diff --git a/app/imports/api/engine/computation/writeComputation/writeScope.js b/app/imports/api/engine/computation/writeComputation/writeScope.js index 3661df4a..c318fb9e 100644 --- a/app/imports/api/engine/computation/writeComputation/writeScope.js +++ b/app/imports/api/engine/computation/writeComputation/writeScope.js @@ -1,10 +1,31 @@ import Creatures from '/imports/api/creature/creatures/Creatures.js'; +import { EJSON } from 'meteor/ejson'; -export default function writeScope(creatureId, scope){ - // Remove large properties that aren't likely to be accessed +export default function writeScope(creatureId, computation) { + const scope = computation.scope; + const variables = computation.creature.variables || {}; + let $set; for (const key in scope){ + // Remove large properties that aren't likely to be accessed delete scope[key].parent; delete scope[key].ancestors; + + // Remove empty keys + for (const subKey in scope[key]) { + if (scope[key][subKey] === undefined) { + delete scope[key][subKey] + } + } + + // Only update changed fields + if (!EJSON.equals(variables[key], scope[key])) { + if (!$set) $set = {}; + + // Set the changed key in the creature variables + $set[`variables.${key}`] = scope[key]; + } + } + if ($set) { + Creatures.update(creatureId, {$set}); } - Creatures.update(creatureId, {$set: {variables: scope}}); } diff --git a/app/imports/api/engine/computeCreature.js b/app/imports/api/engine/computeCreature.js index a45188bf..cc3c0da9 100644 --- a/app/imports/api/engine/computeCreature.js +++ b/app/imports/api/engine/computeCreature.js @@ -10,7 +10,7 @@ export default function computeCreature(creatureId){ try { computeCreatureComputation(computation); writeAlteredProperties(computation); - writeScope(creatureId, computation.scope); + writeScope(creatureId, computation); } catch (e){ const errorText = e.reason || e.message || e.toString(); computation.errors.push({ From 0b7c20e61632046e86374ee298546f09006cbcaa Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Mon, 2 May 2022 18:48:41 +0200 Subject: [PATCH 2/3] Added APM monitoring --- app/.meteor/packages | 1 + app/.meteor/versions | 3 +++ 2 files changed, 4 insertions(+) diff --git a/app/.meteor/packages b/app/.meteor/packages index f87dac0b..8535b3b5 100644 --- a/app/.meteor/packages +++ b/app/.meteor/packages @@ -47,3 +47,4 @@ meteortesting:mocha ostrio:files simple:rest-bearer-token-parser simple:rest-json-error-handler +mdg:meteor-apm-agent diff --git a/app/.meteor/versions b/app/.meteor/versions index b8171bc3..8195b39a 100644 --- a/app/.meteor/versions +++ b/app/.meteor/versions @@ -51,8 +51,10 @@ id-map@1.1.1 inter-process-messaging@0.1.1 lai:collection-extensions@0.3.0 launch-screen@1.3.0 +livedata@1.0.18 localstorage@1.2.0 logging@1.3.1 +mdg:meteor-apm-agent@3.5.0 mdg:validated-method@1.2.0 meteor@1.10.0 meteor-base@1.5.1 @@ -72,6 +74,7 @@ mongo@1.14.6 mongo-decimal@0.1.2 mongo-dev-server@1.1.0 mongo-id@1.0.8 +mongo-livedata@1.0.12 npm-mongo@4.3.1 oauth@2.1.1 oauth2@1.3.1 From df7889edd9c47554d18788af45087d9bdce30192 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Mon, 9 May 2022 11:23:46 +0200 Subject: [PATCH 3/3] Reduced fields loaded by library tree view This should improve performance a little for large libraries, at the expense of loading when a property is selected --- app/imports/server/publications/library.js | 56 ++++++++++++++++- app/imports/ui/library/LibraryNodeDialog.vue | 63 ++++++++++++------- .../treeNodeViews/AdjustmentTreeNode.vue | 2 +- 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/app/imports/server/publications/library.js b/app/imports/server/publications/library.js index 41e2b080..10553aab 100644 --- a/app/imports/server/publications/library.js +++ b/app/imports/server/publications/library.js @@ -1,7 +1,7 @@ import SimpleSchema from 'simpl-schema'; import Libraries from '/imports/api/library/Libraries.js'; import LibraryNodes from '/imports/api/library/LibraryNodes.js'; -import { assertViewPermission } from '/imports/api/sharing/sharingPermissions.js'; +import { assertViewPermission, assertDocViewPermission } from '/imports/api/sharing/sharingPermissions.js'; Meteor.publish('libraries', function(){ this.autorun(function (){ @@ -63,12 +63,64 @@ Meteor.publish('libraryNodes', function(libraryId){ LibraryNodes.find({ 'ancestors.id': libraryId, }, { - sort: {order: 1}, + sort: { order: 1 }, + fields: { + _id: 1, + name: 1, + type: 1, + icon: 1, + color: 1, + order: 1, + parent: 1, + ancestors: 1, + // Effect + operation: 1, + targetTags: 1, + stats: 1, + // Item + quantity: 1, + plural: 1, + equipped: 1, + // Branch + branchType: 1, + // Damage: + damageType: 1, + stat: 1, + amount: 1, + // Class level + level: 1, + // Proficiency + value: 1, + // Reference + cache: 1, + } }), ]; }); }); +const nodeIdSchema = new SimpleSchema({ + libraryNodeId: { + type: String, + regEx: SimpleSchema.RegEx.Id, + }, +}); + +Meteor.publish('libraryNode', function (libraryNodeId) { + if (!libraryNodeId) return []; + nodeIdSchema.validate({ libraryNodeId }); + this.autorun(function () { + const userId = this.userId; + const nodeCursor = LibraryNodes.find({_id: libraryNodeId}); + let node = nodeCursor.fetch()[0]; + try { assertDocViewPermission(node, userId) } + catch (e) { + return this.error(e); + } + return [ nodeCursor ]; + }); +}); + Meteor.publish('softRemovedLibraryNodes', function(libraryId){ if (!libraryId) return []; libraryIdSchema.validate({libraryId}); diff --git a/app/imports/ui/library/LibraryNodeDialog.vue b/app/imports/ui/library/LibraryNodeDialog.vue index 99006a69..e67c0cc2 100644 --- a/app/imports/ui/library/LibraryNodeDialog.vue +++ b/app/imports/ui/library/LibraryNodeDialog.vue @@ -5,6 +5,7 @@ :model="model" :editing="editing" :flat="flat" + :embedded="embedded" @duplicate="duplicate" @move="move" @remove="remove" @@ -12,32 +13,41 @@ @color-changed="value => change({path: ['color'], value})" /> - + + + +

+ This property can't be viewed yet. +

+