Skip to content
This repository has been archived by the owner on Apr 18, 2020. It is now read-only.

Commit

Permalink
Working on getting the time based cache up to snuff.
Browse files Browse the repository at this point in the history
  • Loading branch information
J. T. L committed Nov 19, 2015
1 parent fa5d668 commit b71bf9d
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 66 deletions.
129 changes: 86 additions & 43 deletions index.js
Expand Up @@ -34,55 +34,98 @@ exports.once = function(func) {
};
};

/* FIXME: why have an inProgress field? just set callbacks to null initially
* have it be an array only when we're in progress... */
exports.timeBasedWithGrace = function(func, soft, hard) {
var cache = undefined,
softLimit = 0,
hardLimit = 0,
inProgress = false,
callbacks = []

return function(now, callback) {
/* If we're before the hardlimit, just call the callback immediately with
* cached data. Otherwise, if we're after it, we'll have to defer the
* callback until later on. */
if(now < hardLimit)
callback(null, cache)

else
callbacks.push(callback)

/* If there's nothing more to do (because we're before the soft limit or
* because somebody else is already doing it), check out. */
if(now < softLimit || inProgress)
return
var f, handler;

/* Okay, so no we have to update the cache. Mark that we're doing something
* so that nobody else tries to. */
inProgress = true
/* "Hard" handler. */
handler = function(time, callback) {
var list;

/* Call the backing function. */
return func(function(err, data) {
/* If nothing went wrong, update the cache and timeouts. */
if(!err) {
cache = data
softLimit = now + soft
hardLimit = now + hard
list = [callback];

f = function(time, callback) {
list.push(callback);
};

func(function(err, result) {
var hard_time, i, sandler, soft_time;

if(err) {
f = handler;
}

/* Call each of the callbacks that we buffered up. (We just pass `err` to
* them because if there was no error, it's just going to be null anyway.
* Vice-versa applies as well.) */
while(callbacks.length)
callbacks.pop()(err, data)
else {
soft_time = time + soft;
hard_time = time + hard;

sandler = function(time, callback) {
var list;

if(time >= hard_time) {
handler(time, callback);
}

else {
if(time >= soft_time) {
list = null;

f = function(time, callback) {
if(time >= hard_time) {
if(!list) {
list = [];
}

list.push(callback);
}

else {
process.nextTick(function() {
callback(err, result);
});
}
};

func(function(new_err, new_result) {
var i;

if(!new_err) {
err = new_err;
result = new_result;
soft_time = time + soft;
hard_time = time + hard;
}

f = sandler;

if(list) {
for(i = 0; i < list.length; i++) {
list[i](err, result);
}
}
});
}

/* Finally, the last thing we do is mark that we're no longer in
* progress, since we just finished. */
inProgress = false
})
}
}
process.nextTick(function() {
callback(err, result);
});
}
};

f = sandler;
}

for(i = 0; i < list.length; i++) {
list[i](err, result);
}
});
};

f = handler;

return function(time, callback) {
f(time, callback);
};
};

exports.sizeBasedKeyValue = function(func, size) {
var cache = [],
Expand Down
53 changes: 30 additions & 23 deletions test.js
Expand Up @@ -69,39 +69,46 @@ describe("cache", function() {
});

describe("timeBasedWithGrace", function() {
it("should only update the cache as appropriate", function() {
var cinc = cache.timeBasedWithGrace(inc, 100, 1000)
it("should only update the cache as appropriate", function(done) {
var cinc = cache.timeBasedWithGrace(inc, 100, 1000);

/* First datapoint. */
cinc(0, function(err, n) {
assert.deepEqual(n, 0)
})
assert.ifError(err);
assert.deepEqual(n, 0);

/* Read cached. */
cinc(50, function(err, n) {
assert.deepEqual(n, 0)
})
/* Read cached. */
cinc(50, function(err, n) {
assert.ifError(err);
assert.deepEqual(n, 0);

/* Soft timeout: return cached but update in the background. */
cinc(200, function(err, n) {
assert.deepEqual(n, 0)
})
/* Soft timeout: return cached but update in the background. */
cinc(200, function(err, n) {
assert.ifError(err);
assert.deepEqual(n, 0);

/* Read cached. */
cinc(250, function(err, n) {
assert.deepEqual(n, 1)
})
/* Read cached. */
cinc(210, function(err, n) {
assert.ifError(err);
assert.deepEqual(n, 1);

/* Hard timeout: update n before returning. */
cinc(2500, function(err, n) {
assert.deepEqual(n, 2)
})
})
/* Hard timeout: update n before returning. */
cinc(2500, function(err, n) {
assert.ifError(err);
assert.deepEqual(n, 2);

done(null);
});
});
});
});
});
});

/* FIXME: Ensure that calling the function a bajillion times causes each
* callback to get called. */
})
})
});
});

describe("key-value", function() {
var n
Expand Down

0 comments on commit b71bf9d

Please sign in to comment.