Skip to content

Commit

Permalink
perf: Reduce GC pressure by avoiding EJSON.clone
Browse files Browse the repository at this point in the history
  • Loading branch information
alisnic committed Sep 20, 2024
1 parent 24b43a6 commit 18e4dad
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 8 deletions.
5 changes: 3 additions & 2 deletions lib/cache/ObservableCollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,12 @@ export default class ObservableCollection {
* @param safe {Boolean} If this is set to true, it assumes that the object is cleaned
*/
add(doc, safe = false) {
doc = EJSON.clone(doc);

if (!safe) {
if (this.fieldsArray) {
// projection function clones the document already.
doc = this.projectFieldsOnDoc(doc);
} else {
doc = EJSON.clone(doc);
}
}

Expand Down
19 changes: 14 additions & 5 deletions lib/mongo/ObserveMultiplex.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ export function ObserveMultiplexer(options) {
});
}

function strictFreeze(obj) {
return new Proxy(obj, {
set() {
throw new Error('Cannot mutate a frozen object');
}
});
}
const freezeObject = Meteor.isProduction ? Object.freeze : strictFreeze

Object.assign(ObserveMultiplexer.prototype, {
addHandleAndSendInitialAdds: function(handle) {
var self = this;
Expand Down Expand Up @@ -213,24 +222,25 @@ Object.assign(ObserveMultiplexer.prototype, {
// can continue until these are done. (But we do have to be careful to not
// use a handle that got removed, because removeHandle does not use the
// queue; thus, we iterate over an array of keys that we control.)
const safeArgs = freezeObject(args);

Object.keys(self._handles).forEach(function(handleId) {
var handle = self._handles && self._handles[handleId];
if (!handle) return;
var callback = handle['_' + callbackName];
// clone arguments so that callbacks can mutate their arguments

// We silence out removed exceptions
if (callback === 'removed') {
try {
callback.apply(null, EJSON.clone(args));
callback.apply(null, safeArgs);
} catch (e) {
// Supressing `removed non-existent exceptions`
if (!isRemovedNonExistent(e)) {
throw e;
}
}
} else {
callback && callback.apply(null, EJSON.clone(args));
callback && callback.apply(null, safeArgs);
}
});
});
Expand All @@ -250,8 +260,7 @@ Object.assign(ObserveMultiplexer.prototype, {
self._cache.docs.forEach(function(doc, id) {
if (!_.has(self._handles, handle._id))
throw Error('handle got removed before sending initial adds!');
var fields = EJSON.clone(doc);
delete fields._id;
const { _id, ...fields } = doc
if (self._ordered) add(id, fields, null);
// we're going in order, so add at end
else add(id, fields);
Expand Down
2 changes: 1 addition & 1 deletion package.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package.describe({
name: 'cultofcoders:redis-oplog',
version: '2.2.2',
version: '2.3.0',
// Brief, one-line summary of the package.
summary: "Replacement for Meteor's MongoDB oplog implementation",
// URL to the Git repository containing the source code for this package.
Expand Down

0 comments on commit 18e4dad

Please sign in to comment.