From 41b91c28df60556456435efd8b018a8676cc7c8c Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 7 Apr 2023 15:39:21 +0200 Subject: [PATCH] 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. --- doc/api/v8.md | 83 +++++++++++-------- .../snapshot/v8-startup-snapshot-api.js | 82 +++++++++++------- test/parallel/test-snapshot-api.js | 20 ++++- 3 files changed, 118 insertions(+), 67 deletions(-) diff --git a/doc/api/v8.md b/doc/api/v8.md index 9ce500bf19c71d..0e7171afe0b569 100644 --- a/doc/api/v8.md +++ b/doc/api/v8.md @@ -921,15 +921,12 @@ added: > Stability: 1 - Experimental The `v8.startupSnapshot` interface can be used to add serialization and -deserialization hooks for custom startup snapshots. Currently the startup -snapshots can only be built into the Node.js binary from source. +deserialization hooks for custom startup snapshots. ```console -$ cd /path/to/node -$ ./configure --node-snapshot-main=entry.js -$ make node -# This binary contains the result of the execution of entry.js -$ out/Release/node +$ node --snapshot-blob snapshot.blob --build-snapshot entry.js +# This launches a process with the snapshot +$ node --snapshot-blob snapshot.blob ``` In the example above, `entry.js` can use methods from the `v8.startupSnapshot` @@ -946,43 +943,63 @@ const zlib = require('node:zlib'); const path = require('node:path'); const assert = require('node:assert'); -const { - isBuildingSnapshot, - addSerializeCallback, - addDeserializeCallback, - setDeserializeMainFunction, -} = require('node:v8').startupSnapshot; +const v8 = require('node:v8'); -const filePath = path.resolve(__dirname, '../x1024.txt'); -const storage = {}; +class BookShelf { + storage = new Map(); -assert(isBuildingSnapshot()); + // Reading a series of files from directory and store them into storage. + constructor(directory, books) { + for (const book of books) { + this.storage.set(book, fs.readFileSync(path.join(directory, book))); + } + } -addSerializeCallback(({ filePath }) => { - storage[filePath] = zlib.gzipSync(fs.readFileSync(filePath)); -}, { filePath }); + static compressAll(shelf) { + for (const [ book, content ] of shelf.storage) { + shelf.storage.set(book, zlib.gzipSync(content)); + } + } -addDeserializeCallback(({ filePath }) => { - storage[filePath] = zlib.gunzipSync(storage[filePath]); -}, { filePath }); + static decompressAll(shelf) { + for (const [ book, content ] of shelf.storage) { + shelf.storage.set(book, zlib.gunzipSync(content)); + } + } +} -setDeserializeMainFunction(({ filePath }) => { - console.log(storage[filePath].toString()); -}, { filePath }); +// __dirname here is where the snapshot script is placed +// during snapshot building time. +const shelf = new BookShelf(__dirname, [ + 'book1.en_US.txt', + 'book1.es_ES.txt', + 'book2.zh_CN.txt', +]); + +assert(v8.startupSnapshot.isBuildingSnapshot()); +// On snapshot serialization, compress the books to reduce size. +v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf); +// On snapshot deserialization, decompress the books. +v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf); +v8.startupSnapshot.setDeserializeMainFunction((shelf) => { + // process.env and process.argv are refreshed during snapshot + // deserialization. + const lang = process.env.BOOK_LANG || 'en_US'; + const book = process.argv[1]; + const name = `${book}.${lang}.txt`; + console.log(shelf.storage.get(name)); +}, shelf); ``` -The resulted binary will simply print the data deserialized from the snapshot -during start up: +The resulted binary will get print the data deserialized from the snapshot +during start up, using the refreshed `process.env` and `process.argv` of +the launched process: ```console -$ out/Release/node -# Prints content of ./test/fixtures/x1024.txt +$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1 +# Prints content of book1.es_ES.txt deserialized from the snapshot. ``` -Currently the API is only available to a Node.js instance launched from the -default snapshot, that is, the application deserialized from a user-land -snapshot cannot use these APIs again. - ### `v8.startupSnapshot.addSerializeCallback(callback[, data])`