Rewrite the scheduler: more efficient and always finite

master
Paul Loyd 2017-11-05 21:40:15 +03:00
parent 112693ad3e
commit bdd83fee1c
3 changed files with 86 additions and 20 deletions

View File

@ -7,14 +7,16 @@ const pathlib = require('path');
const extractors = require('./extractors');
const Command = require('./commands');
const {Scope, Module} = require('./scope');
const CircularList = require('./list');
class Collector {
constructor(parser, root = '.') {
this.root = root;
this.parser = parser;
this.schemas = [];
this.tasks = [];
this.tasks = new CircularList;
this.taskCount = 0;
this.active = true;
this.modules = new Map;
this.global = Scope.global([]);
this.running = false;
@ -82,7 +84,7 @@ class Collector {
if (type && type in extractors) {
const task = this._collect(node, scope);
this.tasks.push(task);
this.tasks.add(task);
++this.taskCount;
continue;
@ -109,6 +111,8 @@ class Collector {
let result = null;
while (true) {
this.active = true;
const {done, value} = iter.next(result);
if (done) {
@ -199,17 +203,28 @@ class Collector {
}
_schedule() {
// TODO: prevent infinite loop.
const {tasks} = this;
for (let i = 0; tasks.length > 0; i = ++i % tasks.length) {
const {done} = tasks[i].next();
let marker = null;
while (!tasks.isEmpty) {
const task = tasks.remove();
const {done} = task.next();
if (done) {
// TODO: use linked list instead.
tasks.splice(i, 1);
--i;
marker = null;
continue;
}
tasks.add(task);
if (this.active) {
marker = task;
this.active = false;
} else if (task === marker) {
// TODO: warning.
return;
}
}
}

51
lib/list.js Normal file
View File

@ -0,0 +1,51 @@
'use strict';
const assert = require('assert');
class CircularList {
constructor() {
this.mark = Symbol();
this.prev = null;
this.walk = null;
}
get isEmpty() {
return !this.walk;
}
add(entry) {
assert(!entry[this.mark]);
if (this.prev) {
assert(this.walk);
this.prev = this.prev[this.mark] = entry;
} else {
assert(!this.walk);
this.walk = this.prev = entry;
}
entry[this.mark] = this.walk;
assert(!this.prev || this.prev[this.mark] === this.walk);
}
remove() {
assert(this.walk);
const removed = this.walk;
if (removed === this.prev) {
this.walk = this.prev = null;
} else {
this.walk = this.prev[this.mark] = removed[this.mark];
}
removed[this.mark] = null;
return removed;
}
}
module.exports = CircularList;

View File

@ -24,6 +24,17 @@
"namespace": "externals.first",
"fields": [{"name": "d", "type": "double"}]
},
{
"type": "record",
"name": "X",
"namespace": "externals",
"fields": [
{"name": "a", "type": "externals.first.A"},
{"name": "b", "type": "externals.first.B"},
{"name": "c", "type": "externals.first.CC"},
{"name": "d", "type": "externals.first.D"}
]
},
{
"type": "record",
"name": "N",
@ -48,17 +59,6 @@
"namespace": "externals.second",
"fields": [{"name": "p", "type": "double"}]
},
{
"type": "record",
"name": "X",
"namespace": "externals",
"fields": [
{"name": "a", "type": "externals.first.A"},
{"name": "b", "type": "externals.first.B"},
{"name": "c", "type": "externals.first.CC"},
{"name": "d", "type": "externals.first.D"}
]
},
{
"type": "record",
"name": "Y",