git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 9d0e76ab27a7c7ca239e1ef71f84447d37f4acc4

Files: 9d0e76ab27a7c7ca239e1ef71f84447d37f4acc4 / index.js

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

Built with git-ssb-web