git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 59e5c5ee7cd9ec4372da75fa9427c4f06b0a6806

Files: 59e5c5ee7cd9ec4372da75fa9427c4f06b0a6806 / scheduler.js

3662 bytesRaw
1const binarySearchInsert = require('binary-search-insert')
2const LockMap = require('lockmap')
3
4module.exports = class Scheduler {
5 /**
6 * The Sceduler manages the run cycle of the containes and figures out which
7 * order they should run in
8 */
9 constructor () {
10 this._waits = []
11 this._running = new Set()
12 this._loadingInstances = new LockMap()
13 this.instances = new Map()
14 this.systemServices = new Map()
15 }
16
17 /**
18 * locks the scheduler from clearing waits untill the lock is resolved
19 * @param {string} id
20 * @return {function} the resolve function to call once it to unlock
21 */
22 lock (id) {
23 return this._loadingInstances.lock(id)
24 }
25
26 /**
27 * updates an instance with a new tick count
28 * @param {Object} instance - a container instance
29 */
30 update (instance) {
31 this._update(instance)
32 this._running.add(instance.id)
33 this._checkWaits()
34 }
35
36 _update (instance) {
37 // sorts the container instance map by tick count
38 this.instances.delete(instance.id)
39 const instanceArray = [...this.instances]
40 binarySearchInsert(instanceArray, comparator, [instance.id, instance])
41 this.instances = new Map(instanceArray)
42
43 function comparator (a, b) {
44 return a[1].ticks - b[1].ticks
45 }
46 }
47
48 /**
49 * returns a container
50 * @param {string} id
51 * @return {object}
52 */
53 getInstance (id) {
54 return this.instances.get(id) || this._loadingInstances.getLock(id) || this.systemServices.get(id)
55 }
56
57 /**
58 * deletes an instance from the scheduler
59 * @param {string} id - the containers id
60 */
61 done (id) {
62 this._running.delete(id)
63 this.instances.delete(id)
64 this._checkWaits()
65 }
66
67 /**
68 * returns a promise that resolves once all containers have reached the given
69 * number of ticks
70 * @param {interger} ticks - the number of ticks to wait
71 * @param {string} id - optional id of the container that is waiting
72 * @return {Promise}
73 */
74 wait (ticks = Infinity, id) {
75 this._running.delete(id)
76 return new Promise((resolve, reject) => {
77 binarySearchInsert(this._waits, comparator, {
78 ticks: ticks,
79 resolve: resolve,
80 id: id
81 })
82 this._checkWaits()
83 })
84
85 function comparator (a, b) {
86 return a.ticks - b.ticks
87 }
88 }
89
90 /**
91 * returns the oldest container's ticks
92 * @return {integer}
93 */
94 leastNumberOfTicks () {
95 const nextValue = this.instances.values().next().value
96 return nextValue ? nextValue.ticks : 0
97 }
98
99 // checks outstanding waits to see if they can be resolved
100 _checkWaits () {
101 // if there are no running containers
102 if (!this.instances.size) {
103 // clear any remanding waits
104 this._waits.forEach(wait => wait.resolve())
105 this._waits = []
106 } else {
107 // find the old container and see if to can resolve any of the waits
108 const least = this.leastNumberOfTicks()
109 for (const index in this._waits) {
110 const wait = this._waits[index]
111 if (wait.ticks <= least) {
112 wait.resolve()
113 this._running.add(wait.id)
114 } else {
115 this._waits.splice(0, index)
116 break
117 }
118 }
119 if (!this._running.size) {
120 // if there are no containers running find the oldest wait and update
121 // the oldest containers to it ticks
122 const oldest = this._waits[0].ticks
123 for (let instance of this.instances) {
124 instance = instance[1]
125 if (instance.ticks > oldest) {
126 break
127 } else {
128 instance.ticks = oldest
129 this._update(instance)
130 }
131 }
132 return this._checkWaits()
133 }
134 }
135 }
136}
137

Built with git-ssb-web