Commit d2f195c509c6bd320e14ede5acde3dcc6370530f
Merge pull request #133 from primea/chunker
added chunking for code stored in the statewanderer authored on 7/27/2017, 11:05:34 PM
GitHub committed on 7/27/2017, 11:05:34 PM
Parent: 6723a3ab125343529593a107313cd31c8eb38d7a
Parent: 88bcb9d3485311c1a0878dbe733373a1e5750698
Files changed
index.js | changed |
kernel.js | changed |
package.json | changed |
tests/index.js | changed |
index.js | ||
---|---|---|
@@ -2,11 +2,10 @@ | ||
2 | 2 | const Message = require('primea-message') |
3 | 3 | const Kernel = require('./kernel.js') |
4 | 4 | const Scheduler = require('./scheduler.js') |
5 | 5 | const DFSchecker = require('./dfsChecker.js') |
6 | +const chunk = require('chunk') | |
6 | 7 | |
7 | -const ROOT_ID = 'zdpuAm6aTdLVMUuiZypxkwtA7sKm7BWERy8MPbaCrFsmiyzxr' | |
8 | - | |
9 | 8 | module.exports = class Hypervisor { |
10 | 9 | /** |
11 | 10 | * The Hypervisor manages the container instances by instantiating them and |
12 | 11 | * destorying them when possible. It also facilitates localating Containers |
@@ -18,8 +17,11 @@ | ||
18 | 17 | this.scheduler = new Scheduler() |
19 | 18 | this.state = state |
20 | 19 | this._containerTypes = {} |
21 | 20 | this._nodesToCheck = new Set() |
21 | + | |
22 | + this.ROOT_ID = 'zdpuAm6aTdLVMUuiZypxkwtA7sKm7BWERy8MPbaCrFsmiyzxr' | |
23 | + this.MAX_DATA_BYTES = 65533 | |
22 | 24 | } |
23 | 25 | |
24 | 26 | /** |
25 | 27 | * add a potaintail node in the state graph to check for garbage collection |
@@ -56,13 +58,24 @@ | ||
56 | 58 | // loads an instance of a container from the state |
57 | 59 | async _loadInstance (id) { |
58 | 60 | const state = await this.graph.get(this.state, id) |
59 | 61 | const container = this._containerTypes[state.type] |
62 | + let code | |
60 | 63 | |
64 | + // checks if the code stored in the state is an array and that the elements | |
65 | + // are merkle link | |
66 | + if (state.code && state.code[0]['/']) { | |
67 | + await this.graph.tree(state.code, 1) | |
68 | + code = state.code.map(a => a['/']).reduce((a, b) => a + b) | |
69 | + } else { | |
70 | + code = state.code | |
71 | + } | |
72 | + | |
61 | 73 | // create a new kernel instance |
62 | 74 | const kernel = new Kernel({ |
63 | 75 | hypervisor: this, |
64 | 76 | state: state, |
77 | + code: code, | |
65 | 78 | container: container, |
66 | 79 | id: id |
67 | 80 | }) |
68 | 81 | |
@@ -114,16 +127,28 @@ | ||
114 | 127 | ports: {}, |
115 | 128 | type: type |
116 | 129 | } |
117 | 130 | |
131 | + if (message.data.length) { | |
132 | + state.code = message.data | |
133 | + } | |
134 | + | |
118 | 135 | // save the container in the state |
119 | 136 | await this.graph.set(this.state, idHash, state) |
120 | 137 | // create the container instance |
121 | 138 | const instance = await this._loadInstance(idHash) |
122 | 139 | resolve(instance) |
123 | 140 | // send the intialization message |
124 | 141 | await instance.initialize(message) |
125 | 142 | |
143 | + if (state.code && state.code.length > this.MAX_DATA_BYTES) { | |
144 | + state.code = chunk(state.code, this.MAX_DATA_BYTES).map(chk => { | |
145 | + return { | |
146 | + '/': chk | |
147 | + } | |
148 | + }) | |
149 | + } | |
150 | + | |
126 | 151 | return instance |
127 | 152 | } |
128 | 153 | |
129 | 154 | /** |
@@ -133,9 +158,9 @@ | ||
133 | 158 | * @returns {Promise} |
134 | 159 | */ |
135 | 160 | async createStateRoot (ticks) { |
136 | 161 | await this.scheduler.wait(ticks) |
137 | - const unlinked = await DFSchecker(this.graph, this.state, ROOT_ID, this._nodesToCheck) | |
162 | + const unlinked = await DFSchecker(this.graph, this.state, this.ROOT_ID, this._nodesToCheck) | |
138 | 163 | unlinked.forEach(id => { |
139 | 164 | delete this.state[id] |
140 | 165 | }) |
141 | 166 | return this.graph.flush(this.state) |
kernel.js | ||
---|---|---|
@@ -14,8 +14,9 @@ | ||
14 | 14 | * @param {Object} opts.container - the container constuctor and argments |
15 | 15 | */ |
16 | 16 | constructor (opts) { |
17 | 17 | this.state = opts.state |
18 | + this.code = opts.code | |
18 | 19 | this.hypervisor = opts.hypervisor |
19 | 20 | this.id = opts.id |
20 | 21 | this.container = new opts.container.Constructor(this, opts.container.args) |
21 | 22 | this.timeout = 0 |
package.json | ||
---|---|---|
@@ -31,10 +31,11 @@ | ||
31 | 31 | "license": "MPL-2.0", |
32 | 32 | "dependencies": { |
33 | 33 | "binary-search-insert": "^1.0.3", |
34 | 34 | "bn.js": "^4.11.6", |
35 | + "chunk": "0.0.2", | |
35 | 36 | "ipld-graph-builder": "1.2.2", |
36 | - "primea-abstract-container": "0.0.1", | |
37 | + "primea-abstract-container": "0.0.2", | |
37 | 38 | "primea-message": "0.0.1" |
38 | 39 | }, |
39 | 40 | "devDependencies": { |
40 | 41 | "coveralls": "^2.13.1", |
tests/index.js | ||
---|---|---|
@@ -1,7 +1,8 @@ | ||
1 | 1 | const tape = require('tape') |
2 | 2 | const IPFS = require('ipfs') |
3 | 3 | const AbstractContainer = require('primea-abstract-container') |
4 | +const Message = require('primea-message') | |
4 | 5 | const Hypervisor = require('../') |
5 | 6 | |
6 | 7 | // start ipfs |
7 | 8 | const node = new IPFS({ |
@@ -1070,5 +1071,19 @@ | ||
1070 | 1071 | |
1071 | 1072 | rootContainer.send(portRef1, message) |
1072 | 1073 | rootContainer.ports.bind('response', rPort) |
1073 | 1074 | }) |
1075 | + | |
1076 | + tape('large code size', async t => { | |
1077 | + t.plan(1) | |
1078 | + const content = Buffer.from(new ArrayBuffer(1000000)) | |
1079 | + class testVMContainer extends BaseContainer { | |
1080 | + run () {} | |
1081 | + } | |
1082 | + | |
1083 | + const hypervisor = new Hypervisor(node.dag) | |
1084 | + hypervisor.registerContainer('test', testVMContainer) | |
1085 | + await hypervisor.createInstance('test', new Message({data: content})) | |
1086 | + const instance = await hypervisor.getInstance(hypervisor.ROOT_ID) | |
1087 | + t.equals(content.length, instance.code.length) | |
1088 | + }) | |
1074 | 1089 | }) |
Built with git-ssb-web