From 09994438e58bef3c04dfb851f54fb547d9c22f02 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 13 Jan 2011 02:09:03 -0800 Subject: [PATCH] Expose link-list from timers.js; add tests --- lib/timers.js | 115 +++++++++++++++---------- test/simple/test-timers-linked-list.js | 94 ++++++++++++++++++++ 2 files changed, 165 insertions(+), 44 deletions(-) create mode 100644 test/simple/test-timers-linked-list.js diff --git a/lib/timers.js b/lib/timers.js index c1b8a0291fd..d0ec0c8d9da 100644 --- a/lib/timers.js +++ b/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); } } }; diff --git a/test/simple/test-timers-linked-list.js b/test/simple/test-timers-linked-list.js new file mode 100644 index 00000000000..9caa909d010 --- /dev/null +++ b/test/simple/test-timers-linked-list.js @@ -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)); +