diff --git a/common/content/dactyl.js b/common/content/dactyl.js index cde35162..f0061c17 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -1250,7 +1250,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { ["toc", { start: "2" }], body]); - }); + }, true); cache.register("help/index.xml", function () { return '\n' + @@ -1259,7 +1259,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { ["dl", { insertafter: name + "-index" }, template.map(iter(), util.identity)], "\n\n")]); - }); + }, true); cache.register("help/gui.xml", function () { return '\n' + @@ -1271,7 +1271,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { ["dd", {}, val[0]]] : undefined, "\n")]]); - }); + }, true); cache.register("help/privacy.xml", function () { return '\n' + @@ -1284,7 +1284,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { [["dt", {}, name], ["dd", {}, template.linkifyHelp(description, true)]], "\n")]]); - }); + }, true); }, events: function initEvents() { events.listen(window, dactyl, "events", true); diff --git a/common/content/modes.js b/common/content/modes.js index cd51ca69..40246f42 100644 --- a/common/content/modes.js +++ b/common/content/modes.js @@ -563,9 +563,10 @@ var Modes = Module("modes", { return rec(roots); } - cache.register("modes.dtd", () => - util.makeDTD(iter({ "modes.tree": makeTree() }, - config.dtd))); + cache.register("modes.dtd", + () => util.makeDTD(iter({ "modes.tree": makeTree() }, + config.dtd)), + true); }, mappings: function initMappings() { mappings.add([modes.BASE, modes.NORMAL], diff --git a/common/modules/cache.jsm b/common/modules/cache.jsm index 38e3c6f6..ca5d6dd6 100644 --- a/common/modules/cache.jsm +++ b/common/modules/cache.jsm @@ -10,37 +10,39 @@ defineModule("cache", { }); lazyRequire("overlay", ["overlay"]); -lazyRequire("storage", ["File"]); +lazyRequire("storage", ["File", "storage"]); var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), { init: function init() { this.queue = []; - this.cache = {}; + this.storage = storage.newMap("cache", { store: true }); this.providers = {}; this.globalProviders = this.providers; this.providing = RealSet(); - this.localProviders = {}; + this.localProviders = RealSet(); if (JSMLoader.cacheFlush) this.flush(); update(services["dactyl:"].providers, { - "cache": function (uri, path) { + "cache": (uri, path) => { let contentType = "text/plain"; try { contentType = services.mime.getTypeFromURI(uri); } catch (e) {} - if (!cache.cacheReader || !cache.cacheReader.hasEntry(path)) - return [contentType, cache.force(path)]; + if (this.storage.has(path) || + !this.cacheReader || + !this.cacheReader.hasEntry(path)) + return [contentType, this.force(path)]; let channel = services.StreamChannel(uri); try { - channel.contentStream = cache.cacheReader.getInputStream(path); + channel.contentStream = this.cacheReader.getInputStream(path); } catch (e if e.result = Cr.NS_ERROR_FILE_CORRUPTED) { - cache.flushDiskCache(); + this.flushDiskCache(); throw e; } channel.contentType = contentType; @@ -137,7 +139,7 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), { }), flush: function flush() { - cache.cache = {}; + this.storage.clear(); this.flushDiskCache(); }, @@ -164,7 +166,7 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), { cache.processQueue(); } - delete this.cache[name]; + this.storage.remove(name); }, flushJAR: function flushJAR(file) { @@ -176,6 +178,9 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), { }, force: function force(name, localOnly) { + if (this.storage.has(name)) + return this.storage.get(name); + util.waitFor(() => !this.inQueue); if (this.cacheReader && this.cacheReader.hasEntry(name)) { @@ -188,7 +193,7 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), { } } - if (hasOwnProperty(this.localProviders, name) && !this.isLocal) { + if (this.localProviders.has(name) && !this.isLocal) { for each (let { cache } in overlay.modules) if (cache._has(name)) return cache.force(name, true); @@ -200,49 +205,54 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), { false); this.providing.add(name); + let [func, long] = this.providers[name]; try { - let [func, self] = this.providers[name]; - this.cache[name] = func.call(self || this, name); + var value = func.call(this, name); } finally { this.providing.delete(name); } - cache.queue.push([Date.now(), name]); - cache.processQueue(); + if (!long) + this.storage.set(name, value); + else { + cache.queue.push([Date.now(), name, value]); + cache.processQueue(); + } - return this.cache[name]; + return value; } if (this.isLocal && !localOnly) return cache.force(name); }, - get: function get(name, callback, self) { - if (!hasOwnProperty(this.cache, name)) { - if (callback && !(hasOwnProperty(this.providers, name) || - hasOwnProperty(this.localProviders, name))) - this.register(name, callback, self); + get: function get(name, callback, long) { + if (this.storage.has(name)) + return this.storage.get(name); - this.cache[name] = this.force(name); - util.assert(this.cache[name] !== undefined, - "No such cache key", false); - } + if (callback && !(hasOwnProperty(this.providers, name) || + this.localProviders.has(name))) + this.register(name, callback, long); - return this.cache[name]; + var result = this.force(name); + util.assert(result !== undefined, "No such cache key", false); + + return result; }, _has: function _has(name) hasOwnProperty(this.providers, name) - || hasOwnProperty(this.cache, name), + || this.storage.has(name), - has: function has(name) [this.globalProviders, this.cache, this.localProviders] - .some(obj => hasOwnProperty(obj, name)), + has: function has(name) [this.globalProviders, this.localProviders] + .some(obj => isinstance(obj, ["Set"]) ? obj.has(name) + : hasOwnProperty(obj, name)), - register: function register(name, callback, self) { + register: function register(name, callback, long) { if (this.isLocal) - this.localProviders[name] = true; + this.localProviders.add(name); - this.providers[name] = [callback, self]; + this.providers[name] = [callback, long]; }, processQueue: function processQueue() { @@ -257,13 +267,15 @@ var Cache = Module("Cache", XPCOM(Ci.nsIRequestObserver), { this.getCacheWriter().removeEntry(entry, false); removed++; } - if (removed) + if (removed) { this.closeWriter(); + util.flushCache(this.cacheFile); + } - this.queue.splice(0).forEach(function ([time, entry]) { - if (time && hasOwnProperty(this.cache, entry)) { + this.queue.splice(0).forEach(function ([time, entry, value]) { + if (time && value != null) { let stream = services.CharsetConv("UTF-8") - .convertToInputStream(this.stringify(this.cache[entry])); + .convertToInputStream(this.stringify(value)); this.getCacheWriter().addEntryStream(entry, time * 1000, this.compression, stream, diff --git a/common/modules/config.jsm b/common/modules/config.jsm index c460bcb0..bd5d37be 100644 --- a/common/modules/config.jsm +++ b/common/modules/config.jsm @@ -60,7 +60,8 @@ var ConfigBase = Class("ConfigBase", { this.protocolLoaded = true; this.timeout(function () { - cache.register("config.dtd", () => util.makeDTD(config.dtd)); + cache.register("config.dtd", () => util.makeDTD(config.dtd), + true); }); services["dactyl:"].pages["dtd"] = () => [null, cache.get("config.dtd")]; diff --git a/common/modules/help.jsm b/common/modules/help.jsm index 1b5096e4..eca255ba 100644 --- a/common/modules/help.jsm +++ b/common/modules/help.jsm @@ -201,7 +201,7 @@ var Help = Module("Help", { ["toc", { start: "2" }], body]); - }); + }, true); }, initialize: function initialize() { diff --git a/common/modules/options.jsm b/common/modules/options.jsm index 241d746e..af16f43f 100644 --- a/common/modules/options.jsm +++ b/common/modules/options.jsm @@ -826,17 +826,18 @@ var Options = Module("options", { opt.set(opt.globalValue, Option.SCOPE_GLOBAL, true); }, window); - modules.cache.register("options.dtd", () => - util.makeDTD( - iter(([["option", o.name, "default"].join("."), - o.type === "string" ? o.defaultValue.replace(/'/g, "''") : - o.defaultValue === true ? "on" : - o.defaultValue === false ? "off" : o.stringDefaultValue] - for (o in self)), + modules.cache.register("options.dtd", + () => util.makeDTD( + iter(([["option", o.name, "default"].join("."), + o.type === "string" ? o.defaultValue.replace(/'/g, "''") : + o.defaultValue === true ? "on" : + o.defaultValue === false ? "off" : o.stringDefaultValue] + for (o in self)), - ([["option", o.name, "type"].join("."), o.type] for (o in self)), + ([["option", o.name, "type"].join("."), o.type] for (o in self)), - config.dtd))); + config.dtd)), + true); }, signals: { diff --git a/common/modules/storage.jsm b/common/modules/storage.jsm index b488a244..2c28b3f4 100644 --- a/common/modules/storage.jsm +++ b/common/modules/storage.jsm @@ -136,11 +136,13 @@ var ObjectStore = Class("ObjectStore", StoreBase, { }, get: function get(key, default_) { - return key in this._object ? this._object[key] : + return this.has(key) ? this._object[key] : arguments.length > 1 ? this.set(key, default_) : undefined; }, + has: function has(key) hasOwnProperty(this._object, key), + keys: function keys() Object.keys(this._object), remove: function remove(key) { @@ -240,7 +242,7 @@ var Storage = Module("Storage", { } }, - newObject: function newObject(key, constructor, params) { + newObject: function newObject(key, constructor, params={}) { if (params == null || !isObject(params)) throw Error("Invalid argument type"); @@ -269,11 +271,11 @@ var Storage = Module("Storage", { return this.keys[key]; }, - newMap: function newMap(key, options) { + newMap: function newMap(key, options={}) { return this.newObject(key, ObjectStore, options); }, - newArray: function newArray(key, options) { + newArray: function newArray(key, options={}) { return this.newObject(key, ArrayStore, update({ type: Array }, options)); },