Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e4539e1

Browse filesBrowse files
joyeecheungMoLow
authored andcommitted
doc,test: update the v8.startupSnapshot doc and test the example
The API is now available to user-land run-time snapshots. So update the example. This also makes the intention of the examples a bit clearer and test it in our test suite. PR-URL: #47468 Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent be49669 commit e4539e1
Copy full SHA for e4539e1

File tree

Expand file treeCollapse file tree

3 files changed

+124
-67
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+124
-67
lines changed
Open diff view settings
Collapse file

‎doc/api/v8.md‎

Copy file name to clipboardExpand all lines: doc/api/v8.md
+53-32Lines changed: 53 additions & 32 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -899,15 +899,12 @@ added: v18.6.0
899899
> Stability: 1 - Experimental
900900
901901
The `v8.startupSnapshot` interface can be used to add serialization and
902-
deserialization hooks for custom startup snapshots. Currently the startup
903-
snapshots can only be built into the Node.js binary from source.
902+
deserialization hooks for custom startup snapshots.
904903

905904
```console
906-
$ cd /path/to/node
907-
$ ./configure --node-snapshot-main=entry.js
908-
$ make node
909-
# This binary contains the result of the execution of entry.js
910-
$ out/Release/node
905+
$ node --snapshot-blob snapshot.blob --build-snapshot entry.js
906+
# This launches a process with the snapshot
907+
$ node --snapshot-blob snapshot.blob
911908
```
912909

913910
In the example above, `entry.js` can use methods from the `v8.startupSnapshot`
@@ -924,42 +921,66 @@ const zlib = require('node:zlib');
924921
const path = require('node:path');
925922
const assert = require('node:assert');
926923

927-
const {
928-
isBuildingSnapshot,
929-
addSerializeCallback,
930-
addDeserializeCallback,
931-
setDeserializeMainFunction,
932-
} = require('node:v8').startupSnapshot;
924+
const v8 = require('node:v8');
933925

934-
const filePath = path.resolve(__dirname, '../x1024.txt');
935-
const storage = {};
926+
class BookShelf {
927+
storage = new Map();
936928

937-
assert(isBuildingSnapshot());
929+
// Reading a series of files from directory and store them into storage.
930+
constructor(directory, books) {
931+
for (const book of books) {
932+
this.storage.set(book, fs.readFileSync(path.join(directory, book)));
933+
}
934+
}
938935

939-
addSerializeCallback(({ filePath }) => {
940-
storage[filePath] = zlib.gzipSync(fs.readFileSync(filePath));
941-
}, { filePath });
936+
static compressAll(shelf) {
937+
for (const [ book, content ] of shelf.storage) {
938+
shelf.storage.set(book, zlib.gzipSync(content));
939+
}
940+
}
942941

943-
addDeserializeCallback(({ filePath }) => {
944-
storage[filePath] = zlib.gunzipSync(storage[filePath]);
945-
}, { filePath });
942+
static decompressAll(shelf) {
943+
for (const [ book, content ] of shelf.storage) {
944+
shelf.storage.set(book, zlib.gunzipSync(content));
945+
}
946+
}
947+
}
946948

947-
setDeserializeMainFunction(({ filePath }) => {
948-
console.log(storage[filePath].toString());
949-
}, { filePath });
949+
// __dirname here is where the snapshot script is placed
950+
// during snapshot building time.
951+
const shelf = new BookShelf(__dirname, [
952+
'book1.en_US.txt',
953+
'book1.es_ES.txt',
954+
'book2.zh_CN.txt',
955+
]);
956+
957+
assert(v8.startupSnapshot.isBuildingSnapshot());
958+
// On snapshot serialization, compress the books to reduce size.
959+
v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf);
960+
// On snapshot deserialization, decompress the books.
961+
v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf);
962+
v8.startupSnapshot.setDeserializeMainFunction((shelf) => {
963+
// process.env and process.argv are refreshed during snapshot
964+
// deserialization.
965+
const lang = process.env.BOOK_LANG || 'en_US';
966+
const book = process.argv[1];
967+
const name = `${book}.${lang}.txt`;
968+
console.log(shelf.storage.get(name));
969+
}, shelf);
950970
```
951971

952-
The resulted binary will simply print the data deserialized from the snapshot
953-
during start up:
972+
The resulted binary will get print the data deserialized from the snapshot
973+
during start up, using the refreshed `process.env` and `process.argv` of
974+
the launched process:
954975

955976
```console
956-
$ out/Release/node
957-
# Prints content of ./test/fixtures/x1024.txt
977+
$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1
978+
# Prints content of book1.es_ES.txt deserialized from the snapshot.
958979
```
959980

960-
Currently the API is only available to a Node.js instance launched from the
961-
default snapshot, that is, the application deserialized from a user-land
962-
snapshot cannot use these APIs again.
981+
Currently the application deserialized from a user-land snapshot cannot
982+
be snapshotted again, so these APIs are only available to applications
983+
that are not deserialized from a user-land snapshot.
963984

964985
### `v8.startupSnapshot.addSerializeCallback(callback[, data])`
965986

Collapse file

‎test/fixtures/snapshot/v8-startup-snapshot-api.js‎

Copy file name to clipboardExpand all lines: test/fixtures/snapshot/v8-startup-snapshot-api.js
+55-31Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,60 @@
11
'use strict';
22

3-
const fs = require('fs');
4-
const zlib = require('zlib');
5-
const path = require('path');
6-
const assert = require('assert');
7-
8-
const {
9-
isBuildingSnapshot,
10-
addSerializeCallback,
11-
addDeserializeCallback,
12-
setDeserializeMainFunction
13-
} = require('v8').startupSnapshot;
14-
15-
const filePath = path.resolve(__dirname, '../x1024.txt');
16-
const storage = {};
17-
18-
assert(isBuildingSnapshot());
19-
20-
addSerializeCallback(({ filePath }) => {
21-
console.error('serializing', filePath);
22-
storage[filePath] = zlib.gzipSync(fs.readFileSync(filePath));
23-
}, { filePath });
24-
25-
addDeserializeCallback(({ filePath }) => {
26-
console.error('deserializing', filePath);
27-
storage[filePath] = zlib.gunzipSync(storage[filePath]);
28-
}, { filePath });
29-
30-
setDeserializeMainFunction(({ filePath }) => {
31-
console.log(storage[filePath].toString());
32-
}, { filePath });
33-
assert.throws(() => setDeserializeMainFunction(() => {
3+
const fs = require('node:fs');
4+
const zlib = require('node:zlib');
5+
const path = require('node:path');
6+
const assert = require('node:assert');
7+
8+
const v8 = require('node:v8');
9+
10+
class BookShelf {
11+
storage = new Map();
12+
13+
// Reading a series of files from directory and store them into storage.
14+
constructor(directory, books) {
15+
for (const book of books) {
16+
this.storage.set(book, fs.readFileSync(path.join(directory, book)));
17+
};
18+
}
19+
20+
static compressAll(shelf) {
21+
for (const [ book, content ] of shelf.storage) {
22+
shelf.storage.set(book, zlib.gzipSync(content));
23+
}
24+
}
25+
26+
static decompressAll(shelf) {
27+
for (const [ book, content ] of shelf.storage) {
28+
shelf.storage.set(book, zlib.gunzipSync(content));
29+
}
30+
}
31+
}
32+
33+
// __dirname here is where the snapshot script is placed
34+
// during snapshot building time.
35+
const shelf = new BookShelf(__dirname, [
36+
'book1.en_US.txt',
37+
'book1.es_ES.txt',
38+
'book2.zh_CN.txt',
39+
]);
40+
41+
assert(v8.startupSnapshot.isBuildingSnapshot());
42+
43+
// On snapshot serialization, compress the books to reduce size.
44+
v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf);
45+
// On snapshot deserialization, decompress the books.
46+
v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf);
47+
v8.startupSnapshot.setDeserializeMainFunction((shelf) => {
48+
// process.env and process.argv are refreshed during snapshot
49+
// deserialization.
50+
const lang = process.env.BOOK_LANG || 'en_US';
51+
const book = process.argv[1];
52+
const name = `${book}.${lang}.txt`;
53+
console.error('Reading', name);
54+
console.log(shelf.storage.get(name).toString());
55+
}, shelf);
56+
57+
assert.throws(() => v8.startupSnapshot.setDeserializeMainFunction(() => {
3458
assert.fail('unreachable duplicated main function');
3559
}), {
3660
code: 'ERR_DUPLICATE_STARTUP_SNAPSHOT_MAIN_FUNCTION',
Collapse file

‎test/parallel/test-snapshot-api.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-snapshot-api.js
+16-4Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
// This tests snapshot JS API
3+
// This tests snapshot JS API using the example in the docs.
44

55
require('../common');
66
const assert = require('assert');
@@ -20,11 +20,20 @@ tmpdir.refresh();
2020
const blobPath = path.join(tmpdir.path, 'snapshot.blob');
2121
const entry = fixtures.path('snapshot', 'v8-startup-snapshot-api.js');
2222
{
23+
for (const book of [
24+
'book1.en_US.txt',
25+
'book1.es_ES.txt',
26+
'book2.zh_CN.txt',
27+
]) {
28+
const content = `This is ${book}`;
29+
fs.writeFileSync(path.join(tmpdir.path, book), content, 'utf8');
30+
}
31+
fs.copyFileSync(entry, path.join(tmpdir.path, 'entry.js'));
2332
const child = spawnSync(process.execPath, [
2433
'--snapshot-blob',
2534
blobPath,
2635
'--build-snapshot',
27-
entry,
36+
'entry.js',
2837
], {
2938
cwd: tmpdir.path
3039
});
@@ -41,15 +50,18 @@ const entry = fixtures.path('snapshot', 'v8-startup-snapshot-api.js');
4150
const child = spawnSync(process.execPath, [
4251
'--snapshot-blob',
4352
blobPath,
53+
'book1',
4454
], {
4555
cwd: tmpdir.path,
4656
env: {
4757
...process.env,
58+
BOOK_LANG: 'en_US',
4859
}
4960
});
5061

5162
const stdout = child.stdout.toString().trim();
52-
const file = fs.readFileSync(fixtures.path('x1024.txt'), 'utf8');
53-
assert.strictEqual(stdout, file);
63+
const stderr = child.stderr.toString().trim();
64+
assert.strictEqual(stderr, 'Reading book1.en_US.txt');
65+
assert.strictEqual(stdout, 'This is book1.en_US.txt');
5466
assert.strictEqual(child.status, 0);
5567
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.