git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: dca4a828fc87c8fdcf30901362c346ff179401d4

Files: dca4a828fc87c8fdcf30901362c346ff179401d4 / index.js

4782 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 this.ROOT_ID = 'zdpuAm6aTdLVMUuiZypxkwtA7sKm7BWERy8MPbaCrFsmiyzxr'
36 }
37
38 /**
39 * add a potaintail node in the state graph to check for garbage collection
40 * @param {string} id
41 */
42 addNodeToCheck (id) {
43 this._nodesToCheck.add(id)
44 }
45
46 /**
47 * given a port, this finds the corridsponeding endpoint port of the channel
48 * @param {object} port
49 * @returns {Promise}
50 */
51 async getDestPort (port) {
52 if (port.destPort) {
53 return port.destPort
54 } else {
55 const instance = await this.scheduler.getInstance(port.destId)
56 let containerState
57 if (instance) {
58 containerState = instance.state
59 } else {
60 containerState = await this.tree.get(port.destId)
61 }
62 return this.graph.get(containerState, `ports/${port.destName}`)
63 }
64 }
65
66 async send (port, message) {
67 const id = port.destId
68 if (id !== undefined) {
69 const instance = await this.getInstance(id)
70 return instance.queue(port, message)
71 } else {
72 // port is unbound
73 port.destPort.messages.push(message)
74 }
75 }
76
77 // loads an instance of a container from the state
78 async _loadInstance (id, state) {
79 if (!state) {
80 state = await this.tree.get(id)
81 }
82 const container = this._containerTypes[state.type]
83 let code
84
85 // checks if the code stored in the state is an array and that the elements
86 // are merkle link
87 if (state.code && state.code[0]['/']) {
88 await this.graph.tree(state.code, 1)
89 code = state.code.map(a => a['/']).reduce((a, b) => a + b)
90 } else {
91 code = state.code
92 }
93
94 // create a new kernel instance
95 const kernel = new Kernel({
96 hypervisor: this,
97 state: state,
98 code: code,
99 container: container,
100 id: id
101 })
102
103 // save the newly created instance
104 this.scheduler.update(kernel)
105 return kernel
106 }
107
108 /**
109 * gets an existsing container instances
110 * @param {string} id - the containers ID
111 * @returns {Promise}
112 */
113 async getInstance (id) {
114 let instance = this.scheduler.getInstance(id)
115 if (instance) {
116 return instance
117 } else {
118 const resolve = this.scheduler.lock(id)
119 const instance = await this._loadInstance(id)
120 await instance.startup()
121 resolve(instance)
122 return instance
123 }
124 }
125
126 createInstance (message, id) {
127 return this.creationService.createInstance(message, id)
128 }
129
130 createChannel () {
131 const port1 = {
132 messages: []
133 }
134
135 const port2 = {
136 messages: [],
137 destPort: port1
138 }
139
140 port1.destPort = port2
141 return [port1, port2]
142 }
143
144 /**
145 * creates a state root starting from a given container and a given number of
146 * ticks
147 * @param {Number} ticks the number of ticks at which to create the state root
148 * @returns {Promise}
149 */
150 async createStateRoot (ticks) {
151 await this.scheduler.wait(ticks)
152
153 const unlinked = await DFSchecker(this.tree, this._nodesToCheck, (id) => {
154 return this.pinnedIds.has(id)
155 })
156 for (const id of unlinked) {
157 await this.tree.delete(id)
158 }
159 return this.graph.flush(this.state)
160 }
161
162 /**
163 * regirsters a container with the hypervisor
164 * @param {Class} Constructor - a Class for instantiating the container
165 * @param {*} args - any args that the contructor takes
166 * @param {interger} typeId - the container's type identification ID
167 */
168 registerContainer (Constructor, args, typeId = Constructor.typeId) {
169 this._containerTypes[typeId] = {
170 Constructor: Constructor,
171 args: args
172 }
173 }
174
175 pin (instance) {
176 this.pinnedIds.add(instance.id)
177 }
178}
179

Built with git-ssb-web