From 0ebeb1e6433147faf1b52c0ec636e5fc3cc99ac0 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sun, 23 Oct 2016 04:45:52 -0700 Subject: [PATCH] lru: atomic batches. --- lib/utils/lru.js | 120 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/lib/utils/lru.js b/lib/utils/lru.js index 82065f74..839d6aec 100644 --- a/lib/utils/lru.js +++ b/lib/utils/lru.js @@ -30,6 +30,7 @@ function LRU(maxSize, getSize) { this.size = 0; this.head = null; this.tail = null; + this.pending = null; } /** @@ -325,6 +326,74 @@ LRU.prototype.toArray = function toArray() { return items; }; +/** + * Create an atomic batch for the lru + * (used for caching database writes). + * @returns {LRUBatch} + */ + +LRU.prototype.batch = function batch() { + return new LRUBatch(this); +}; + +/** + * Start the pending LRU batch. + */ + +LRU.prototype.start = function start() { + assert(!this.pending); + this.pending = this.batch(); +}; + +/** + * Clear the pending LRU batch. + */ + +LRU.prototype.clear = function clear() { + assert(this.pending); + this.pending = this.batch(); +}; + +/** + * Drop the pending LRU batch. + */ + +LRU.prototype.drop = function drop() { + assert(this.pending); + this.pending = null; +}; + +/** + * Commit the pending LRU batch. + */ + +LRU.prototype.commit = function commit() { + assert(this.pending); + this.pending.commit(); + this.pending = null; +}; + +/** + * Push an item onto the pending LRU batch. + * @param {String} key + * @param {Object} value + */ + +LRU.prototype.push = function push(key, value) { + assert(this.pending); + this.pending.set(key, value); +}; + +/** + * Push a removal onto the pending LRU batch. + * @param {String} key + */ + +LRU.prototype.unpush = function unpush(key) { + assert(this.pending); + this.pending.remove(key); +}; + /** * Represents an LRU item. * @constructor @@ -340,6 +409,50 @@ function LRUItem(key, value) { this.prev = null; } +/** + * LRU Batch + * @constructor + */ + +function LRUBatch(lru) { + this.lru = lru; + this.ops = []; +} + +LRUBatch.prototype.set = function set(key, value) { + this.ops.push(new LRUOp(false, key, value)); +}; + +LRUBatch.prototype.remove = function remove(key) { + this.ops.push(new LRUOp(true, key)); +}; + +LRUBatch.prototype.commit = function commit() { + var i, op; + + for (i = 0; i < this.ops.length; i++) { + op = this.ops[i]; + if (op.remove) { + this.lru.remove(op.key); + continue; + } + this.lru.set(op.key, op.value); + } + + this.ops.length = 0; +}; + +/** + * LRU Op + * @constructor + */ + +function LRUOp(remove, key, value) { + this.remove = remove; + this.key = key; + this.value = value; +} + /** * A null cache. Every method is a NOP. * @constructor @@ -356,6 +469,13 @@ NullCache.prototype.reset = function reset() {}; NullCache.prototype.keys = function keys(key) { return []; }; NullCache.prototype.values = function values(key) { return []; }; NullCache.prototype.toArray = function toArray(key) { return []; }; +NullCache.prototype.batch = function batch() { return new LRUBatch(this); }; +NullCache.prototype.start = function start() {}; +NullCache.prototype.clear = function clear() {}; +NullCache.prototype.drop = function drop() {}; +NullCache.prototype.commit = function commit() {}; +NullCache.prototype.push = function push(key, value) {}; +NullCache.prototype.unpush = function unpush(key) {}; /* * Expose