git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: e10327188504fa350697ac7abbb620cb1df69554

Files: e10327188504fa350697ac7abbb620cb1df69554 / index.js

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

Built with git-ssb-web