git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 0872f0354cc0cdb87c143bd22c75598169e7c206

Files: 0872f0354cc0cdb87c143bd22c75598169e7c206 / index.js

4345 bytesRaw
1const Kernel = require('./kernel.js')
2const Scheduler = require('./scheduler.js')
3const DFSchecker = require('./dfsChecker.js')
4const CreationService = require('./creationService.js')
5
6const CREATION_ID = 0
7
8module.exports = class Hypervisor {
9 /**
10 * The Hypervisor manages the container instances by instantiating them and
11 * destorying them when possible. It also facilitates localating Containers
12 * @param {Graph} dag an instance of [ipfs.dag](https://github.com/ipfs/interface-ipfs-core/tree/master/API/dag#dag-api)
13 * @param {object} state - the starting state
14 */
15 constructor (tree) {
16 this.tree = tree
17 this.scheduler = new Scheduler()
18 this._containerTypes = {}
19 this._nodesToCheck = new Set()
20
21 this.creationService = new CreationService({
22 hypervisor: this
23 })
24 this.scheduler.systemServices.set(CREATION_ID, this.creationService)
25 this.pinnedIds = new Set()
26 }
27
28 /**
29 * add a potaintail node in the state graph to check for garbage collection
30 * @param {string} id
31 */
32 addNodeToCheck (id) {
33 this._nodesToCheck.add(id)
34 }
35
36 /**
37 * given a port, this finds the corridsponeding endpoint port of the channel
38 * @param {object} port
39 * @returns {Promise}
40 */
41 async getDestPort (port) {
42 if (port.destPort) {
43 return port.destPort
44 } else {
45 const instance = await this.scheduler.getInstance(port.destId)
46 let containerState
47 if (instance) {
48 containerState = instance.state
49 } else {
50 let {value} = await this.tree.get(port.destId, true)
51 containerState = value
52 }
53 return this.tree.graph.get(containerState, `ports/${port.destName}`)
54 }
55 }
56
57 async send (port, message) {
58 const id = port.destId
59 if (id !== undefined) {
60 const instance = await this.getInstance(id)
61 return instance.queue(port, message)
62 } else {
63 // port is unbound
64 port.destPort.messages.push(message)
65 }
66 }
67
68 // loads an instance of a container from the state
69 async _loadInstance (id) {
70 const state = await this.tree.get(id, true)
71 const container = this._containerTypes[state.value.type]
72
73 // create a new kernel instance
74 const kernel = new Kernel({
75 hypervisor: this,
76 state: state.value,
77 node: state.node,
78 code: state.value.code,
79 container: container,
80 id: id
81 })
82
83 // save the newly created instance
84 this.scheduler.update(kernel)
85 return kernel
86 }
87
88 /**
89 * gets an existsing container instances
90 * @param {string} id - the containers ID
91 * @returns {Promise}
92 */
93 async getInstance (id) {
94 let instance = this.scheduler.getInstance(id)
95 if (instance) {
96 return instance
97 } else {
98 const resolve = this.scheduler.lock(id)
99 const instance = await this._loadInstance(id)
100 await instance.startup()
101 resolve(instance)
102 return instance
103 }
104 }
105
106 getResponsePort (message) {
107 if (message.responsePort) {
108 return message.responsePort.destPort
109 } else {
110 const [portRef1, portRef2] = this.createChannel()
111 message.responsePort = portRef2
112 return portRef1
113 }
114 }
115
116 createChannel () {
117 const port1 = {
118 messages: []
119 }
120
121 const port2 = {
122 messages: [],
123 destPort: port1
124 }
125
126 port1.destPort = port2
127 return [port1, port2]
128 }
129
130 /**
131 * creates a state root starting from a given container and a given number of
132 * ticks
133 * @param {Number} ticks the number of ticks at which to create the state root
134 * @returns {Promise}
135 */
136 async createStateRoot (ticks) {
137 await this.scheduler.wait(ticks)
138
139 const unlinked = await DFSchecker(this.tree, this._nodesToCheck, (id) => {
140 return this.pinnedIds.has(id)
141 })
142 for (const id of unlinked) {
143 await this.tree.delete(id)
144 }
145
146 return this.tree.flush()
147 }
148
149 /**
150 * regirsters a container with the hypervisor
151 * @param {Class} Constructor - a Class for instantiating the container
152 * @param {*} args - any args that the contructor takes
153 * @param {interger} typeId - the container's type identification ID
154 */
155 registerContainer (Constructor, args, typeId = Constructor.typeId) {
156 this._containerTypes[typeId] = {
157 Constructor: Constructor,
158 args: args
159 }
160 }
161
162 pin (instance) {
163 this.pinnedIds.add(instance.id)
164 }
165}
166

Built with git-ssb-web