Expose link-list from timers.js; add tests
This commit is contained in:
parent
4e1e6a2d15
commit
09994438e5
115
lib/timers.js
115
lib/timers.js
@ -9,6 +9,69 @@ if (process.env.NODE_debug && /timer/.test(process.env.NODE_debug)) {
|
||||
}
|
||||
|
||||
|
||||
// Export the linklist code for testing.
|
||||
|
||||
|
||||
exports.linkedList = {};
|
||||
|
||||
|
||||
function init(list) {
|
||||
list._idleNext = list;
|
||||
list._idlePrev = list;
|
||||
}
|
||||
exports.linkedList.init = init;
|
||||
|
||||
|
||||
// show the most idle item
|
||||
function peek(list) {
|
||||
if (list._idlePrev == list) return null;
|
||||
return list._idlePrev;
|
||||
}
|
||||
exports.linkedList.peek = peek;
|
||||
|
||||
|
||||
// remove the most idle item from the list
|
||||
function shift(list) {
|
||||
var first = list._idlePrev;
|
||||
remove(first);
|
||||
return first;
|
||||
}
|
||||
exports.linkedList.shift = shift;
|
||||
|
||||
|
||||
// remove a item from its list
|
||||
function remove(item) {
|
||||
if (item._idleNext) {
|
||||
item._idleNext._idlePrev = item._idlePrev;
|
||||
}
|
||||
|
||||
if (item._idlePrev) {
|
||||
item._idlePrev._idleNext = item._idleNext;
|
||||
}
|
||||
|
||||
item._idleNext = null;
|
||||
item._idlePrev = null;
|
||||
}
|
||||
exports.linkedList.remove = remove;
|
||||
|
||||
|
||||
// remove a item from its list and place at the end.
|
||||
function append(list, item) {
|
||||
remove(item);
|
||||
item._idleNext = list._idleNext;
|
||||
list._idleNext._idlePrev = item;
|
||||
item._idlePrev = list;
|
||||
list._idleNext = item;
|
||||
}
|
||||
exports.linkedList.append = append;
|
||||
|
||||
|
||||
function isEmpty(list) {
|
||||
return list._idleNext === list;
|
||||
}
|
||||
exports.linkedList.isEmpty = isEmpty;
|
||||
|
||||
|
||||
// IDLE TIMEOUTS
|
||||
//
|
||||
// Because often many sockets will have the same idle timeout we will not
|
||||
@ -22,36 +85,6 @@ if (process.env.NODE_debug && /timer/.test(process.env.NODE_debug)) {
|
||||
// value = list
|
||||
var lists = {};
|
||||
|
||||
// show the most idle item
|
||||
function peek(list) {
|
||||
if (list._idlePrev == list) return null;
|
||||
return list._idlePrev;
|
||||
}
|
||||
|
||||
|
||||
// remove the most idle item from the list
|
||||
function shift(list) {
|
||||
var first = list._idlePrev;
|
||||
remove(first);
|
||||
return first;
|
||||
}
|
||||
|
||||
|
||||
// remove a item from its list
|
||||
function remove(item) {
|
||||
item._idleNext._idlePrev = item._idlePrev;
|
||||
item._idlePrev._idleNext = item._idleNext;
|
||||
}
|
||||
|
||||
|
||||
// remove a item from its list and place at the end.
|
||||
function append(list, item) {
|
||||
item._idleNext = list._idleNext;
|
||||
list._idleNext._idlePrev = item;
|
||||
item._idlePrev = list;
|
||||
list._idleNext = item;
|
||||
}
|
||||
|
||||
|
||||
// the main function - creates lists on demand and the watchers associated
|
||||
// with them.
|
||||
@ -67,8 +100,7 @@ function insert(item, msecs) {
|
||||
list = lists[msecs];
|
||||
} else {
|
||||
list = new Timer();
|
||||
list._idleNext = list;
|
||||
list._idlePrev = list;
|
||||
init(list);
|
||||
|
||||
lists[msecs] = list;
|
||||
|
||||
@ -78,6 +110,7 @@ function insert(item, msecs) {
|
||||
// just set its repeat
|
||||
var now = new Date();
|
||||
debug('now: ' + now);
|
||||
|
||||
var first;
|
||||
while (first = peek(list)) {
|
||||
var diff = now - first._idleStart;
|
||||
@ -91,8 +124,9 @@ function insert(item, msecs) {
|
||||
if (first._onTimeout) first._onTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
debug(msecs + ' list empty');
|
||||
assert(list._idleNext === list); // list is empty
|
||||
assert(isEmpty(list));
|
||||
list.stop();
|
||||
};
|
||||
}
|
||||
@ -103,7 +137,7 @@ function insert(item, msecs) {
|
||||
}
|
||||
|
||||
append(list, item);
|
||||
assert(list._idleNext !== list); // list is not empty
|
||||
assert(!isEmpty(list)); // list is not empty
|
||||
}
|
||||
|
||||
|
||||
@ -114,7 +148,7 @@ var unenroll = exports.unenroll = function(item) {
|
||||
var list = lists[item._idleTimeout];
|
||||
// if empty then stop the watcher
|
||||
debug('unenroll');
|
||||
if (list && list._idlePrev == list) {
|
||||
if (list && isEmpty(list)) {
|
||||
debug('unenroll: list empty');
|
||||
list.stop();
|
||||
}
|
||||
@ -129,8 +163,7 @@ exports.enroll = function(item, msecs) {
|
||||
if (item._idleNext) unenroll(item);
|
||||
|
||||
item._idleTimeout = msecs;
|
||||
item._idleNext = item;
|
||||
item._idlePrev = item;
|
||||
init(item);
|
||||
};
|
||||
|
||||
// call this whenever the item is active (not idle)
|
||||
@ -142,14 +175,8 @@ exports.active = function(item) {
|
||||
if (item._idleNext == item) {
|
||||
insert(item, msecs);
|
||||
} else {
|
||||
// inline append
|
||||
item._idleStart = new Date();
|
||||
item._idleNext._idlePrev = item._idlePrev;
|
||||
item._idlePrev._idleNext = item._idleNext;
|
||||
item._idleNext = list._idleNext;
|
||||
item._idleNext._idlePrev = item;
|
||||
item._idlePrev = list;
|
||||
list._idleNext = item;
|
||||
append(list, item);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
94
test/simple/test-timers-linked-list.js
Normal file
94
test/simple/test-timers-linked-list.js
Normal file
@ -0,0 +1,94 @@
|
||||
var common = require('../common');
|
||||
var assert = require('assert');
|
||||
var L = require('timers').linkedList;
|
||||
|
||||
|
||||
var list = { name: "list" };
|
||||
var A = { name: "A" };
|
||||
var B = { name: "B" };
|
||||
var C = { name: "C" };
|
||||
var D = { name: "D" };
|
||||
|
||||
|
||||
L.init(list);
|
||||
assert.ok(L.isEmpty(list));
|
||||
assert.equal(null, L.peek(list));
|
||||
|
||||
L.append(list, A);
|
||||
// list -> A
|
||||
assert.equal(A, L.peek(list));
|
||||
|
||||
L.append(list, B);
|
||||
// list -> A -> B
|
||||
assert.equal(A, L.peek(list));
|
||||
|
||||
L.append(list, C);
|
||||
// list -> A -> B -> C
|
||||
assert.equal(A, L.peek(list));
|
||||
|
||||
L.append(list, D);
|
||||
// list -> A -> B -> C -> D
|
||||
assert.equal(A, L.peek(list));
|
||||
|
||||
var x = L.shift(list);
|
||||
assert.equal(A, x);
|
||||
// list -> B -> C -> D
|
||||
assert.equal(B, L.peek(list));
|
||||
|
||||
x = L.shift(list);
|
||||
assert.equal(B, x);
|
||||
// list -> C -> D
|
||||
assert.equal(C, L.peek(list));
|
||||
|
||||
// B is already removed, so removing it again shouldn't hurt.
|
||||
L.remove(B);
|
||||
// list -> C -> D
|
||||
assert.equal(C, L.peek(list));
|
||||
|
||||
// Put B back on the list
|
||||
L.append(list, B);
|
||||
// list -> C -> D -> B
|
||||
assert.equal(C, L.peek(list));
|
||||
|
||||
L.remove(C);
|
||||
// list -> D -> B
|
||||
assert.equal(D, L.peek(list));
|
||||
|
||||
L.remove(B);
|
||||
// list -> D
|
||||
assert.equal(D, L.peek(list));
|
||||
|
||||
L.remove(D);
|
||||
// list
|
||||
assert.equal(null, L.peek(list));
|
||||
|
||||
|
||||
assert.ok(L.isEmpty(list));
|
||||
|
||||
|
||||
L.append(list, D);
|
||||
// list -> D
|
||||
assert.equal(D, L.peek(list));
|
||||
|
||||
L.append(list, C);
|
||||
L.append(list, B);
|
||||
L.append(list, A);
|
||||
// list -> D -> C -> B -> A
|
||||
|
||||
// Append should REMOVE C from the list and append it to the end.
|
||||
L.append(list, C);
|
||||
|
||||
// list -> D -> B -> A -> C
|
||||
assert.equal(D, L.shift(list));
|
||||
// list -> B -> A -> C
|
||||
assert.equal(B, L.peek(list));
|
||||
assert.equal(B, L.shift(list));
|
||||
// list -> A -> C
|
||||
assert.equal(A, L.peek(list));
|
||||
assert.equal(A, L.shift(list));
|
||||
// list -> C
|
||||
assert.equal(C, L.peek(list));
|
||||
assert.equal(C, L.shift(list));
|
||||
// list
|
||||
assert.ok(L.isEmpty(list));
|
||||
|
Loading…
x
Reference in New Issue
Block a user