introduce Meteor.deps.ContextSet, use in Session

This commit is contained in:
David Greenspan
2012-09-16 02:28:41 -07:00
parent ffd6461e58
commit d78481c1ce
3 changed files with 64 additions and 52 deletions

View File

@@ -0,0 +1,42 @@
(function () {
// Constructor for an empty ContextSet.
var ContextSet = function () {
this._contextsById = {};
};
// Adds the Context `ctx` to the set (if it is
// not already present). The Context will only
// remain in the set as long as it has not been
// invalidated.
// Returns true if the context was newly added.
ContextSet.prototype.add = function (ctx) {
var self = this;
if (ctx && ! (ctx.id in self._contextsById)) {
self._contextsById[ctx.id] = ctx;
ctx.on_invalidate(function () {
delete self._contextsById[ctx.id];
});
return true;
}
return false;
};
// Invalidate all Contexts in the set and remove
// them from the set.
ContextSet.prototype.invalidateAll = function () {
var self = this;
for (var id in self._contextsById)
self._contextsById[id].invalidate();
};
// Returns true if there are no Contexts in this set.
ContextSet.prototype.isEmpty = function () {
var self = this;
for(var id in self._contextsById)
return false;
return true;
};
Meteor.deps.ContextSet = ContextSet;
})();

View File

@@ -9,5 +9,5 @@ Package.on_use(function (api, where) {
where = where || ['client', 'server'];
api.use('underscore', where);
api.add_files('deps.js', where);
api.add_files(['deps.js', 'deps-utils.js'], where);
});

View File

@@ -1,31 +1,9 @@
// XXX could use some tests
Session = _.extend({}, {
keys: {},
key_deps: {}, // key -> context id -> context
key_value_deps: {}, // key -> value -> context id -> context
// XXX remove debugging method (or improve it, but anyway, don't
// ship it in production)
dump_state: function () {
var self = this;
console.log("=== Session state ===");
for (var key in self.key_deps) {
var ids = _.keys(self.key_deps[key]);
if (!ids.length)
continue;
console.log(key + ": " + _.reject(ids, function (x) {return x === "_once"}).join(' '));
}
for (var key in self.key_value_deps) {
for (var value in self.key_value_deps[key]) {
var ids = _.keys(self.key_value_deps[key][value]);
if (!ids.length)
continue;
console.log(key + "(" + value + "): " + _.reject(ids, function (x) {return x === "_once";}).join(' '));
}
}
},
keys: {}, // key -> value
key_deps: {}, // key -> ContextSet
key_value_deps: {}, // key -> value -> ContextSet
set: function (key, value) {
var self = this;
@@ -35,30 +13,24 @@ Session = _.extend({}, {
return;
self.keys[key] = value;
var invalidate = function (map) {
if (map)
for (var id in map)
map[id].invalidate();
var invalidateAll = function (set) {
set && set.invalidateAll();
};
self._ensureKey(key);
invalidate(self.key_deps[key]);
invalidate(self.key_value_deps[key][old_value]);
invalidate(self.key_value_deps[key][value]);
invalidateAll(self.key_deps[key]);
if (self.key_value_deps[key]) {
invalidateAll(self.key_value_deps[key][old_value]);
invalidateAll(self.key_value_deps[key][value]);
}
},
get: function (key) {
var self = this;
var context = Meteor.deps.Context.current;
self._ensureKey(key);
if (context && !(context.id in self.key_deps[key])) {
self.key_deps[key][context.id] = context;
context.on_invalidate(function () {
delete self.key_deps[key][context.id];
});
if (context) {
self._ensureKey(key);
self.key_deps[key].add(context);
}
return self.keys[key];
},
@@ -74,19 +46,17 @@ Session = _.extend({}, {
if (context) {
self._ensureKey(key);
if (!(value in self.key_value_deps[key]))
self.key_value_deps[key][value] = {};
self.key_value_deps[key][value] = new Meteor.deps.ContextSet;
if (!(context.id in self.key_value_deps[key][value])) {
self.key_value_deps[key][value][context.id] = context;
var isNew = self.key_value_deps[key][value].add(context);
if (isNew) {
context.on_invalidate(function () {
delete self.key_value_deps[key][value][context.id];
// clean up [key][value] if it's now empty, so we don't use
// O(n) memory for n = values seen ever
for (var x in self.key_value_deps[key][value])
return;
delete self.key_value_deps[key][value];
if (self.key_value_deps[key][value].isEmpty())
delete self.key_value_deps[key][value];
});
}
}
@@ -97,8 +67,8 @@ Session = _.extend({}, {
_ensureKey: function (key) {
var self = this;
if (!(key in self.key_deps)) {
self.key_deps[key] = {};
self.key_value_deps[key] = {};
self.key_deps[key] = new Meteor.deps.ContextSet;
self.key_value_deps[key] = new Meteor.deps.ContextSet;
}
}
});