152 lines
4.2 KiB
JavaScript
152 lines
4.2 KiB
JavaScript
/*
|
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
|
Author Tobias Koppers @sokra
|
|
*/
|
|
function Storage(duration) {
|
|
this.duration = duration;
|
|
this.running = {};
|
|
this.data = {};
|
|
this.levels = [];
|
|
if(duration > 0) {
|
|
this.levels.push([], [], [], [], [], [], [], [], []);
|
|
for(var i = 8000; i < duration; i+=500)
|
|
this.levels.push([]);
|
|
}
|
|
this.count = 0;
|
|
this.interval = null;
|
|
this.needTickCheck = false;
|
|
this.nextTick = null;
|
|
this.passive = true;
|
|
}
|
|
|
|
Storage.prototype.ensureTick = function() {
|
|
if(!this.interval && this.duration > 0 && !this.nextTick)
|
|
this.interval = setInterval(this.tick.bind(this), Math.floor(this.duration / this.levels.length));
|
|
};
|
|
|
|
Storage.prototype.finished = function(name) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
var callbacks = this.running[name];
|
|
delete this.running[name];
|
|
if(this.duration > 0) {
|
|
this.count++;
|
|
this.data[name] = args;
|
|
this.levels[0].push(name);
|
|
this.ensureTick();
|
|
}
|
|
for(var i = 0; i < callbacks.length; i++) {
|
|
callbacks[i].apply(null, args);
|
|
}
|
|
};
|
|
|
|
Storage.prototype.provide = function(name, provider, callback) {
|
|
var running = this.running[name];
|
|
if(running) {
|
|
running.push(callback);
|
|
return;
|
|
}
|
|
if(this.duration > 0) {
|
|
this.checkTicks();
|
|
var data = this.data[name];
|
|
if(data) {
|
|
return callback.apply(null, data);
|
|
}
|
|
}
|
|
this.running[name] = running = [callback];
|
|
provider(name, this.finished.bind(this, name));
|
|
};
|
|
|
|
Storage.prototype.tick = function() {
|
|
var decay = this.levels.pop();
|
|
for(var i = decay.length - 1; i >= 0; i--) {
|
|
delete this.data[decay[i]];
|
|
}
|
|
this.count -= decay.length;
|
|
decay.length = 0;
|
|
this.levels.unshift(decay);
|
|
if(this.count == 0) {
|
|
clearInterval(this.interval);
|
|
this.interval = null;
|
|
this.nextTick = null;
|
|
return true;
|
|
} else if(this.nextTick) {
|
|
this.nextTick += Math.floor(this.duration / this.levels.length);
|
|
var time = new Date().getTime();
|
|
if(this.nextTick > time) {
|
|
this.nextTick = null;
|
|
this.interval = setInterval(this.tick.bind(this), Math.floor(this.duration / this.levels.length));
|
|
return true;
|
|
}
|
|
} else if(this.passive) {
|
|
clearInterval(this.interval);
|
|
this.interval = null;
|
|
this.nextTick = new Date().getTime() + Math.floor(this.duration / this.levels.length);
|
|
} else {
|
|
this.passive = true;
|
|
}
|
|
};
|
|
|
|
Storage.prototype.checkTicks = function() {
|
|
this.passive = false;
|
|
if(this.nextTick) {
|
|
while(!this.tick());
|
|
}
|
|
};
|
|
|
|
Storage.prototype.purge = function(what) {
|
|
if(!what) {
|
|
this.count = 0;
|
|
clearInterval(this.interval);
|
|
this.nextTick = null;
|
|
this.data = {};
|
|
this.levels.forEach(function(level) {
|
|
level.length = 0;
|
|
});
|
|
} else if(typeof what === "string") {
|
|
Object.keys(this.data).forEach(function(key) {
|
|
if(key.indexOf(what) === 0)
|
|
delete this.data[key];
|
|
}, this);
|
|
} else {
|
|
for(var i = what.length - 1; i >= 0; i--) {
|
|
this.purge(what[i]);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
function CachedInputFileSystem(fileSystem, duration) {
|
|
this.fileSystem = fileSystem;
|
|
this._statStorage = new Storage(duration);
|
|
this._readdirStorage = new Storage(duration);
|
|
this._readFileStorage = new Storage(duration);
|
|
this._readlinkStorage = new Storage(duration);
|
|
}
|
|
module.exports = CachedInputFileSystem;
|
|
|
|
CachedInputFileSystem.prototype.isSync = function() {
|
|
return this.fileSystem.isSync();
|
|
};
|
|
|
|
CachedInputFileSystem.prototype.stat = function(path, callback) {
|
|
this._statStorage.provide(path, this.fileSystem.stat.bind(this.fileSystem), callback);
|
|
};
|
|
|
|
CachedInputFileSystem.prototype.readdir = function(path, callback) {
|
|
this._readdirStorage.provide(path, this.fileSystem.readdir.bind(this.fileSystem), callback);
|
|
};
|
|
|
|
CachedInputFileSystem.prototype.readFile = function(path, callback) {
|
|
this._readFileStorage.provide(path, this.fileSystem.readFile.bind(this.fileSystem), callback);
|
|
};
|
|
|
|
CachedInputFileSystem.prototype.readlink = function(path, callback) {
|
|
this._readlinkStorage.provide(path, this.fileSystem.readlink.bind(this.fileSystem), callback);
|
|
};
|
|
|
|
CachedInputFileSystem.prototype.purge = function(what) {
|
|
this._statStorage.purge(what);
|
|
this._readdirStorage.purge(what);
|
|
this._readFileStorage.purge(what);
|
|
this._readlinkStorage.purge(what);
|
|
}; |