diff --git a/Cargo.lock b/Cargo.lock index d751846b..64891b6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,7 +37,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -47,14 +47,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arrayvec" @@ -126,6 +126,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "block-buffer" version = "0.10.4" @@ -177,14 +183,17 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -194,20 +203,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.4.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c8d502cbaec4595d2e7d5f61e318f05417bd2b66fdc3809498f0d3fdf0bea27" +checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.4.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5891c7bc0edb3e1c2204fc5e94009affabeb1821c9e5fdc3959536c5c0bb984d" +checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" dependencies = [ "anstream", "anstyle", @@ -217,14 +225,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.0" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] @@ -257,14 +265,14 @@ checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ "is-terminal", "lazy_static", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -306,9 +314,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "equivalent" @@ -318,13 +326,13 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -339,12 +347,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] name = "fnv" @@ -364,21 +369,15 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", "wasi", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.0" @@ -393,9 +392,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -434,6 +433,7 @@ dependencies = [ name = "ic-stable-structures" version = "0.6.0" dependencies = [ + "bit-vec", "candid", "clap", "colored", @@ -456,16 +456,6 @@ version = "0.18.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "576c539151d4769fb4d1a0c25c4108dd18facd04c5695b02cf2d226ab4e43aa5" -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.0.0" @@ -473,46 +463,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", - "hashbrown 0.14.0", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", + "hashbrown", ] [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "io-lifetimes", "rustix", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "lazy_static" @@ -528,9 +497,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libm" @@ -540,9 +509,9 @@ checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "linux-raw-sys" -version = "0.3.8" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "maplit" @@ -552,15 +521,15 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -580,9 +549,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", "libm", @@ -606,20 +575,20 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] name = "once_cell" -version = "1.17.2" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "ppv-lite86" @@ -650,9 +619,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -671,7 +640,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65" dependencies = [ "bit-set", - "bitflags", + "bitflags 1.3.2", "byteorder", "lazy_static", "num-traits", @@ -701,9 +670,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -753,7 +722,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -764,23 +733,22 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "rustix" -version = "0.37.25" +version = "0.38.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4eb579851244c2c03e7c24f501c3432bed80b8f720af1d6e5b0e0f01555a035" +checksum = "bdf14a7a466ce88b5eac3da815b53aefc208ce7e74d1c263aabb04d88c4abeb1" dependencies = [ - "bitflags", + "bitflags 2.4.0", "errno", - "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "rusty-fork" @@ -796,37 +764,37 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "serde" -version = "1.0.163" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.9" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] @@ -846,7 +814,7 @@ version = "0.9.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" dependencies = [ - "indexmap 2.0.0", + "indexmap", "itoa", "ryu", "serde", @@ -855,9 +823,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -892,7 +860,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] @@ -903,7 +871,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] @@ -919,9 +887,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" dependencies = [ "proc-macro2", "quote", @@ -930,15 +898,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.5.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", - "windows-sys 0.45.0", + "windows-sys", ] [[package]] @@ -959,27 +927,27 @@ dependencies = [ "proc-macro2", "quote", "structmeta", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] @@ -990,17 +958,17 @@ checksum = "d63628286617a0c67ee3c4ef92ccf62044e3813ed7376bb82a4586d2ff7974dd" [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.10" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ - "indexmap 1.9.3", + "indexmap", "toml_datetime", "winnow", ] @@ -1025,9 +993,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-segmentation" @@ -1105,143 +1073,77 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.4.6" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 316414f6..0932bc70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ repository = "https://github.com/dfinity/stable-structures" bench = false [dependencies] +bit-vec = "0.6" # An optional dependency to profile parts of the code. profiler = { path = "./profiler", optional = true } diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 145f8d22..761821ab 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arrayvec" @@ -64,6 +64,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "block-buffer" version = "0.10.4" @@ -115,14 +121,17 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -169,9 +178,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -224,9 +233,15 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "generic-array" @@ -246,9 +261,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" [[package]] name = "hex" @@ -286,6 +301,9 @@ dependencies = [ [[package]] name = "ic-stable-structures" version = "0.6.0" +dependencies = [ + "bit-vec", +] [[package]] name = "ic0" @@ -295,11 +313,11 @@ checksum = "576c539151d4769fb4d1a0c25c4108dd18facd04c5695b02cf2d226ab4e43aa5" [[package]] name = "indexmap" -version = "1.9.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ - "autocfg", + "equivalent", "hashbrown", ] @@ -317,21 +335,21 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -351,9 +369,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] @@ -376,20 +394,20 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] name = "once_cell" -version = "1.17.2" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pretty" @@ -414,9 +432,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -444,46 +462,46 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "serde" -version = "1.0.163" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.9" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] @@ -499,9 +517,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -534,9 +552,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" dependencies = [ "proc-macro2", "quote", @@ -565,35 +583,35 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.31", ] [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.10" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ "indexmap", "toml_datetime", @@ -614,9 +632,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-segmentation" @@ -679,9 +697,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winnow" -version = "0.4.6" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] diff --git a/src/memory_manager.rs b/src/memory_manager.rs index 567d3559..b611509e 100644 --- a/src/memory_manager.rs +++ b/src/memory_manager.rs @@ -40,18 +40,21 @@ //! memory_1.read(0, &mut bytes); //! assert_eq!(bytes, vec![4, 5, 6]); //! ``` +use bit_vec::BitVec; + use crate::{ read_struct, types::{Address, Bytes}, write, write_struct, Memory, WASM_PAGE_SIZE, }; -use std::cell::RefCell; use std::cmp::min; use std::collections::BTreeMap; use std::rc::Rc; +use std::{cell::RefCell, collections::BTreeSet}; const MAGIC: &[u8; 3] = b"MGR"; -const LAYOUT_VERSION: u8 = 1; +const LAYOUT_VERSION_V1: u8 = 1; +const LAYOUT_VERSION_V2: u8 = 2; // The maximum number of memories that can be created. const MAX_NUM_MEMORIES: u8 = 255; @@ -72,6 +75,9 @@ const BUCKETS_OFFSET_IN_BYTES: u64 = BUCKETS_OFFSET_IN_PAGES * WASM_PAGE_SIZE; // Reserved bytes in the header for future extensions. const HEADER_RESERVED_BYTES: usize = 32; +// Size of the bucket ID in the header. +const BUCKET_ID_LEN_IN_BITS: usize = 15; + /// A memory manager simulates multiple memories within a single memory. /// /// The memory manager can return up to 255 unique instances of [`VirtualMemory`], and each can be @@ -127,6 +133,58 @@ const HEADER_RESERVED_BYTES: usize = 32; /// ... /// -------------------------------------------------- <- Page ((MAX_NUM_BUCKETS - 1) * N + 1) /// Bucket MAX_NUM_BUCKETS ↕ N pages +/// +/// # V2 layout +/// +/// ```text +/// -------------------------------------------------- <- Address 0 +/// Magic "MGR" ↕ 3 bytes +/// -------------------------------------------------- +/// Layout version ↕ 1 byte +/// -------------------------------------------------- +/// Number of allocated buckets ↕ 2 bytes +/// -------------------------------------------------- +/// Bucket size (in pages) = N ↕ 2 bytes +/// -------------------------------------------------- +/// Reserved space ↕ 32 bytes +/// -------------------------------------------------- +/// Size of memory 0 (in pages) ↕ 8 bytes +/// -------------------------------------------------- +/// Size of memory 1 (in pages) ↕ 8 bytes +/// -------------------------------------------------- +/// ... +/// -------------------------------------------------- +/// Size of memory 254 (in pages) ↕ 8 bytes +/// -------------------------------------------------- <- IDs of buckets +/// Bucket 1 belonging to memory 0 ↕ 15 bits +/// -------------------------------------------------- +/// Bucket 2 belonging to memory 0 ↕ 15 bits +/// -------------------------------------------------- +/// ... +/// -------------------------------------------------- +/// Bucket 1 belonging to memory 1 ↕ 15 bits +/// -------------------------------------------------- +/// Bucket 2 belonging to memory 1 ↕ 15 bits +/// -------------------------------------------------- +/// ... +/// -------------------------------------------------- +/// ... +/// --------------------------------------------------- +/// Bucket 1 belonging to memory 254 ↕ 15 bits +/// -------------------------------------------------- +/// Bucket 2 belonging to memory 254 ↕ 15 bits +/// -------------------------------------------------- +/// ... +/// -------------------------------------------------- +/// Unallocated space ↕ 2'016 bytes +/// -------------------------------------------------- <- Buckets (Page 1) +/// Bucket 1 ↕ N pages +/// -------------------------------------------------- <- Page N + 1 +/// Bucket 2 ↕ N pages +/// -------------------------------------------------- +/// ... +/// -------------------------------------------------- <- Page ((MAX_NUM_BUCKETS - 1) * N + 1) +/// Bucket MAX_NUM_BUCKETS ↕ N pages /// ``` pub struct MemoryManager { inner: Rc>>, @@ -148,6 +206,16 @@ impl MemoryManager { } } + #[cfg(test)] + pub fn init_with_bucket_size_v1(memory: M, bucket_size_in_pages: u16) -> Self { + Self { + inner: Rc::new(RefCell::new(MemoryManagerInner::init_v1( + memory, + bucket_size_in_pages, + ))), + } + } + /// Returns the memory associated with the given ID. pub fn get(&self, id: MemoryId) -> VirtualMemory { VirtualMemory { @@ -155,6 +223,13 @@ impl MemoryManager { memory_manager: self.inner.clone(), } } + + /// Frees the specified memory. + /// Note that the underlying physical memory doesn't shrink, but the space previously + /// occupied by the given memory will be reused. + pub fn free(&mut self, id: MemoryId) { + self.inner.borrow_mut().free(id); + } } #[repr(C, packed)] @@ -220,6 +295,10 @@ struct MemoryManagerInner { // A map mapping each managed memory to the bucket ids that are allocated to it. memory_buckets: BTreeMap>, + + // Tracks the buckets that were freed to be reused in future calls to `grow`. + // NOTE: A BTreeSet is used so that bucket IDs are maintained in sorted order. + freed_buckets: BTreeSet, } impl MemoryManagerInner { @@ -248,10 +327,46 @@ impl MemoryManagerInner { memory_sizes_in_pages: [0; MAX_NUM_MEMORIES as usize], memory_buckets: BTreeMap::new(), bucket_size_in_pages, + freed_buckets: BTreeSet::new(), }; mem_mgr.save_header(); + mem_mgr + } + + #[cfg(test)] + fn init_v1(memory: M, bucket_size_in_pages: u16) -> Self { + if memory.size() == 0 { + // Memory is empty. Create a new map. + return Self::new(memory, bucket_size_in_pages); + } + + // Check if the magic in the memory corresponds to this object. + let mut dst = vec![0; 3]; + memory.read(0, &mut dst); + if dst != MAGIC { + // No memory manager found. Create a new instance. + MemoryManagerInner::new_v1(memory, bucket_size_in_pages) + } else { + // The memory already contains a memory manager. Load it. + MemoryManagerInner::load(memory) + } + } + + #[cfg(test)] + fn new_v1(memory: M, bucket_size_in_pages: u16) -> Self { + let mem_mgr = Self { + memory, + allocated_buckets: 0, + memory_sizes_in_pages: [0; MAX_NUM_MEMORIES as usize], + memory_buckets: BTreeMap::new(), + bucket_size_in_pages, + freed_buckets: BTreeSet::new(), + }; + + mem_mgr.save_header_v1(); + // Mark all the buckets as unallocated. write( &mem_mgr.memory, @@ -262,16 +377,11 @@ impl MemoryManagerInner { mem_mgr } - fn load(memory: M) -> Self { - // Read the header from memory. - let header: Header = read_struct(Address::from(0), &memory); - assert_eq!(&header.magic, MAGIC, "Bad magic."); - assert_eq!(header.version, LAYOUT_VERSION, "Unsupported version."); - + fn load_layout_v1(memory: M, header: Header) -> Self { let mut buckets = vec![0; MAX_NUM_BUCKETS as usize]; memory.read(bucket_allocations_address(BucketId(0)).get(), &mut buckets); - let mut memory_buckets = BTreeMap::new(); + for (bucket_idx, memory) in buckets.into_iter().enumerate() { if memory != UNALLOCATED_BUCKET_MARKER { memory_buckets @@ -287,13 +397,88 @@ impl MemoryManagerInner { bucket_size_in_pages: header.bucket_size_in_pages, memory_sizes_in_pages: header.memory_sizes_in_pages, memory_buckets, + freed_buckets: BTreeSet::new(), + } + } + + fn load_layout_v2(memory: M, header: Header) -> Self { + let mut memory_size_in_buckets = vec![]; + let mut number_of_used_buckets = 0; + + // Translate memory sizes expressed in pages to sizes expressed in buckets. + for memory_size_in_pages in header.memory_sizes_in_pages.into_iter() { + let size_in_buckets = memory_size_in_pages.div_ceil(header.bucket_size_in_pages as u64); + memory_size_in_buckets.push(size_in_buckets); + number_of_used_buckets += size_in_buckets; + } + + // Load the buckets. + let buckets = { + const BYTE_SIZE_IN_BITS: usize = 8; + let buckets_index_size_in_bytes: usize = (number_of_used_buckets as usize + * BUCKET_ID_LEN_IN_BITS) + .div_ceil(BYTE_SIZE_IN_BITS); + + let mut buckets = vec![0; buckets_index_size_in_bytes]; + memory.read(bucket_indexes_offset().get(), &mut buckets); + + bytes_to_bucket_indexes(&buckets) + }; + + // Map of all memories with their assigned buckets. + let mut memory_buckets = BTreeMap::new(); + + // The last bucket that's accessed. + let mut max_bucket_id: u16 = 0; + + let mut bucket_idx: usize = 0; + + // Assign buckets to the memories they are part of. + for (memory, size_in_buckets) in memory_size_in_buckets.into_iter().enumerate() { + let mut vec_buckets = vec![]; + for _ in 0..size_in_buckets { + let bucket = buckets[bucket_idx]; + max_bucket_id = std::cmp::max(bucket.0, max_bucket_id); + vec_buckets.push(bucket); + bucket_idx += 1; + } + memory_buckets + .entry(MemoryId(memory as u8)) + .or_insert(vec_buckets); + } + + // Set of all buckets with ID smaller than 'max_bucket_id' which were allocated and freed. + let mut freed_buckets: BTreeSet = (0..max_bucket_id).map(BucketId).collect(); + + for id in buckets.iter() { + freed_buckets.remove(id); + } + + Self { + memory, + allocated_buckets: header.num_allocated_buckets, + bucket_size_in_pages: header.bucket_size_in_pages, + memory_sizes_in_pages: header.memory_sizes_in_pages, + memory_buckets, + freed_buckets, + } + } + + fn load(memory: M) -> Self { + // Read the header from memory. + let header: Header = read_struct(Address::from(0), &memory); + assert_eq!(&header.magic, MAGIC, "Bad magic."); + match header.version { + LAYOUT_VERSION_V1 => MemoryManagerInner::load_layout_v1(memory, header), + LAYOUT_VERSION_V2 => MemoryManagerInner::load_layout_v2(memory, header), + _ => panic!("Unsupported version."), } } fn save_header(&self) { let header = Header { magic: *MAGIC, - version: LAYOUT_VERSION, + version: LAYOUT_VERSION_V2, num_allocated_buckets: self.allocated_buckets, bucket_size_in_pages: self.bucket_size_in_pages, _reserved: [0; HEADER_RESERVED_BYTES], @@ -317,28 +502,28 @@ impl MemoryManagerInner { let required_buckets = self.num_buckets_needed(new_size); let new_buckets_needed = required_buckets - current_buckets; - if new_buckets_needed + self.allocated_buckets as u64 > MAX_NUM_BUCKETS { + if new_buckets_needed + self.allocated_buckets as u64 - self.freed_buckets.len() as u64 + > MAX_NUM_BUCKETS + { // Exceeded the memory that can be managed. return -1; } // Allocate new buckets as needed. for _ in 0..new_buckets_needed { - let new_bucket_id = BucketId(self.allocated_buckets); + let new_bucket_id = match self.freed_buckets.pop_first() { + Some(t) => t, + None => { + let new_id = self.allocated_buckets; + self.allocated_buckets += 1; + BucketId(new_id) + } + }; self.memory_buckets .entry(id) .or_default() .push(new_bucket_id); - - // Write in stable store that this bucket belongs to the memory with the provided `id`. - write( - &self.memory, - bucket_allocations_address(new_bucket_id).get(), - &[id.0], - ); - - self.allocated_buckets += 1; } // Grow the underlying memory if necessary. @@ -355,11 +540,35 @@ impl MemoryManagerInner { // Update the memory with the new size. self.memory_sizes_in_pages[id.0 as usize] = new_size; - // Update the header and return the old size. + // Update the header. self.save_header(); + + // Write in stable store that this bucket belongs to the memory with the provided `id`. + write( + &self.memory, + bucket_indexes_offset().get(), + self.get_bucket_ids_in_bytes().as_ref(), + ); + + // Return the old size. old_size as i64 } + fn get_bucket_ids_in_bytes(&self) -> Vec { + let mut bit_vec = BitVec::new(); + for memory in self.memory_buckets.iter() { + for bucket in memory.1 { + let bucket_ind = bucket.0; + // Splits bit_vec returning the slice [1, .., bit_vec.size() - 1]. + // This is precisely what we need since the BucketId can be represented + // using only 15 bits, instead of 16. + let mut bit_vec_temp = BitVec::from_bytes(&bucket_ind.to_be_bytes()).split_off(1); + bit_vec.append(&mut bit_vec_temp); + } + } + bit_vec.to_bytes() + } + fn write(&self, id: MemoryId, offset: u64, src: &[u8]) { if (offset + src.len() as u64) > self.memory_size(id) * WASM_PAGE_SIZE { panic!("{id:?}: write out of bounds"); @@ -419,6 +628,56 @@ impl MemoryManagerInner { // Ceiling division. (num_pages + self.bucket_size_in_pages as u64 - 1) / self.bucket_size_in_pages as u64 } + + fn free(&mut self, id: MemoryId) { + self.memory_sizes_in_pages[id.0 as usize] = 0; + let buckets = self.memory_buckets.remove(&id); + if let Some(vec_buckets) = buckets { + for bucket in vec_buckets { + self.freed_buckets.insert(bucket); + } + } + // Update the header. + self.save_header(); + + // Write in stable store that no bucket belongs to the memory with the provided `id`. + write( + &self.memory, + bucket_indexes_offset().get(), + self.get_bucket_ids_in_bytes().as_ref(), + ); + } + + #[cfg(test)] + fn save_header_v1(&self) { + let header = Header { + magic: *MAGIC, + version: LAYOUT_VERSION_V1, + num_allocated_buckets: self.allocated_buckets, + bucket_size_in_pages: self.bucket_size_in_pages, + _reserved: [0; HEADER_RESERVED_BYTES], + memory_sizes_in_pages: self.memory_sizes_in_pages, + }; + + write_struct(&header, Address::from(0), &self.memory); + } +} + +fn bytes_to_bucket_indexes(input: &[u8]) -> Vec { + let mut bucket_ids = vec![]; + let bit_vec = BitVec::from_bytes(input); + for bucket_order_number in 0..bit_vec.len() / BUCKET_ID_LEN_IN_BITS { + let mut bucket_id: u16 = 0; + for bucket_id_bit in 0..BUCKET_ID_LEN_IN_BITS { + let next_bit = BUCKET_ID_LEN_IN_BITS * bucket_order_number + bucket_id_bit; + bucket_id <<= 1; + if bit_vec.get(next_bit) == Some(true) { + bucket_id |= 1; + } + } + bucket_ids.push(BucketId(bucket_id)); + } + bucket_ids } struct Segment { @@ -519,13 +778,17 @@ impl MemoryId { } // Referring to a bucket. -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] struct BucketId(u16); fn bucket_allocations_address(id: BucketId) -> Address { Address::from(0) + Header::size() + Bytes::from(id.0) } +fn bucket_indexes_offset() -> Address { + Address::from(0) + Header::size() +} + #[cfg(test)] mod test { use super::*; @@ -853,4 +1116,266 @@ mod test { memory_1.read(0, &mut buf); assert_eq!(buf, vec![2; 1000]); } + + #[test] + fn free_memory_works() { + let mem = make_memory(); + let mut mem_mgr = MemoryManager::init(mem.clone()); + let memory_0 = mem_mgr.get(MemoryId(0)); + let memory_1 = mem_mgr.get(MemoryId(1)); + + // Grow the memory by 1 page. + assert_eq!(memory_0.grow(1), 0); + assert_eq!(mem.size(), BUCKET_SIZE_IN_PAGES + 1); + + // Grow the memory by 1 page. + assert_eq!(memory_1.grow(1), 0); + assert_eq!(mem.size(), 2 * BUCKET_SIZE_IN_PAGES + 1); + + // Grow the memory by BUCKET_SIZE_IN_PAGES more pages, which will cause the underlying + // allocation to increase. + assert_eq!(memory_0.grow(BUCKET_SIZE_IN_PAGES), 1); + assert_eq!(mem.size(), 1 + BUCKET_SIZE_IN_PAGES * 3); + assert_eq!(memory_1.grow(BUCKET_SIZE_IN_PAGES), 1); + assert_eq!(mem.size(), 1 + BUCKET_SIZE_IN_PAGES * 4); + assert_eq!(mem_mgr.get(MemoryId(1)).size(), 1 + BUCKET_SIZE_IN_PAGES); + + // Free Memory ID 1. + mem_mgr.free(MemoryId(1)); + assert_eq!(mem_mgr.get(MemoryId(1)).size(), 0); + assert_eq!(mem.size(), 1 + BUCKET_SIZE_IN_PAGES * 4); + + let memory_2 = mem_mgr.get(MemoryId(2)); + // When growing memory_2, mem.size() should stay the same since + // MemoryManager should use the memory that is freed above. + assert_eq!(memory_2.grow(1), 0); + assert_eq!(mem_mgr.get(MemoryId(2)).size(), 1); + assert_eq!(mem.size(), 1 + BUCKET_SIZE_IN_PAGES * 4); + assert_eq!(memory_2.grow(BUCKET_SIZE_IN_PAGES), 1); + assert_eq!(mem_mgr.get(MemoryId(2)).size(), 1 + BUCKET_SIZE_IN_PAGES); + assert_eq!(mem.size(), 1 + BUCKET_SIZE_IN_PAGES * 4); + + // When trying to grow memory_2 again, we need more pages, + // because we have already used all that is left from Memory ID 1. + assert_ne!(memory_2.grow(BUCKET_SIZE_IN_PAGES), 0); + assert_eq!( + mem_mgr.get(MemoryId(2)).size(), + 1 + 2 * BUCKET_SIZE_IN_PAGES + ); + assert_eq!(mem.size(), 1 + BUCKET_SIZE_IN_PAGES * 5); + } + + #[test] + #[should_panic = "MemoryId(1): read out of bounds"] + fn reading_freed_memory_panics() { + let mem = make_memory(); + let mem_mgr = MemoryManager::init(mem.clone()); + let memory_0 = mem_mgr.get(MemoryId(0)); + let memory_1 = mem_mgr.get(MemoryId(1)); + let memory_2 = mem_mgr.get(MemoryId(2)); + + assert_eq!(memory_0.grow(1), 0); + assert_eq!(memory_1.grow(1), 0); + assert_eq!(memory_2.grow(1), 0); + + memory_0.write(0, &[1, 2, 3]); + memory_1.write(0, &[4, 5, 6]); + memory_2.write(0, &[7, 8, 9]); + + let mut mem_mgr = MemoryManager::init(mem); + let memory_0 = mem_mgr.get(MemoryId(0)); + let memory_1 = mem_mgr.get(MemoryId(1)); + let memory_2 = mem_mgr.get(MemoryId(2)); + + let mut bytes = vec![0; 3]; + // Check that data is correctly reinitialized. + memory_0.read(0, &mut bytes); + assert_eq!(bytes, vec![1, 2, 3]); + + memory_1.read(0, &mut bytes); + assert_eq!(bytes, vec![4, 5, 6]); + + memory_2.read(0, &mut bytes); + assert_eq!(bytes, vec![7, 8, 9]); + + // Free MemoryId 1. + mem_mgr.free(MemoryId(1)); + + // Check that data of MemoryId 0 and 2 is correctly reinitialized. + memory_0.read(0, &mut bytes); + assert_eq!(bytes, vec![1, 2, 3]); + + memory_2.read(0, &mut bytes); + assert_eq!(bytes, vec![7, 8, 9]); + + // Check that date of MemoryId 1 is freed. + assert_eq!(memory_1.size(), 0); + memory_1.read(0, &mut bytes); + } + + #[test] + fn freeing_already_free_memory() { + let mut mem_mgr = MemoryManager::init(make_memory()); + let memory_0 = mem_mgr.get(MemoryId(0)); + + assert_eq!(memory_0.grow(1), 0); + + assert_eq!(mem_mgr.get(MemoryId(0)).size(), 1); + + mem_mgr.free(MemoryId(0)); + + assert_eq!(mem_mgr.get(MemoryId(0)).size(), 0); + + mem_mgr.free(MemoryId(0)); + + assert_eq!(mem_mgr.get(MemoryId(0)).size(), 0); + } + + #[test] + fn grow_memory_after_freeing_it() { + let mut mem_mgr = MemoryManager::init(make_memory()); + let memory_0 = mem_mgr.get(MemoryId(0)); + + // grow and write to memory + assert_eq!(memory_0.grow(1), 0); + memory_0.write(0, &[7, 1, 5]); + + assert_eq!(mem_mgr.get(MemoryId(0)).size(), 1); + + let mut bytes = vec![0; 3]; + + // read from memory + memory_0.read(0, &mut bytes); + assert_eq!(bytes, &[7, 1, 5]); + + // free memory + mem_mgr.free(MemoryId(0)); + + assert_eq!(mem_mgr.get(MemoryId(0)).size(), 0); + + // grow memory + assert_eq!(memory_0.grow(1), 0); + + assert_eq!(mem_mgr.get(MemoryId(0)).size(), 1); + + // check that old bucket is reassign to the memory + memory_0.read(0, &mut bytes); + assert_eq!(bytes, &[7, 1, 5]); + + // try growing once more + assert_eq!(memory_0.grow(1), 1); + assert_eq!(mem_mgr.get(MemoryId(0)).size(), 2); + } + + #[test] + fn test_freed_buckets_assignment_order() { + let mut mem_mgr = MemoryManager::init(make_memory()); + let memory_a: VirtualMemory>>> = mem_mgr.get(MemoryId(0)); + let memory_b: VirtualMemory>>> = mem_mgr.get(MemoryId(1)); + + // grow and write to memory + assert_eq!(memory_a.grow(1), 0); + assert_eq!(memory_b.grow(1), 0); + memory_a.write(0, &[7, 1, 5]); + memory_b.write(0, &[9, 4, 8]); + + assert_eq!(mem_mgr.get(MemoryId(0)).size(), 1); + assert_eq!(mem_mgr.get(MemoryId(1)).size(), 1); + + let mut bytes = vec![0; 3]; + + // free memory + mem_mgr.free(MemoryId(0)); + mem_mgr.free(MemoryId(1)); + + assert_eq!(mem_mgr.get(MemoryId(0)).size(), 0); + assert_eq!(mem_mgr.get(MemoryId(1)).size(), 0); + + let memory_c: VirtualMemory>>> = mem_mgr.get(MemoryId(2)); + let memory_d: VirtualMemory>>> = mem_mgr.get(MemoryId(3)); + + // grow memory + assert_eq!(memory_c.grow(1), 0); + assert_eq!(memory_d.grow(1), 0); + + assert_eq!(mem_mgr.get(MemoryId(2)).size(), 1); + assert_eq!(mem_mgr.get(MemoryId(3)).size(), 1); + + // check that old bucket is reassign to the memory + memory_c.read(0, &mut bytes); + assert_eq!(bytes, &[7, 1, 5]); + + // check that old bucket is reassign to the memory + memory_d.read(0, &mut bytes); + assert_eq!(bytes, &[9, 4, 8]); + } + + #[test] + fn free_memory_that_was_not_used() { + let mut mem_mgr = MemoryManager::init(make_memory()); + let memory_0 = mem_mgr.get(MemoryId(0)); + assert_eq!(memory_0.grow(1), 0); + + mem_mgr.free(MemoryId(5)); + } + + #[test] + fn freed_memories_are_tracked() { + let mem = make_memory(); + let mut mem_mgr = MemoryManager::init(mem.clone()); + mem_mgr.get(MemoryId(0)).grow(1); + mem_mgr.get(MemoryId(1)).grow(1); + mem_mgr.get(MemoryId(2)).grow(1); + mem_mgr.get(MemoryId(3)).grow(1); + mem_mgr.get(MemoryId(4)).grow(1); + + mem_mgr.free(MemoryId(0)); + mem_mgr.free(MemoryId(2)); + mem_mgr.free(MemoryId(4)); + + let mem_mgr = MemoryManager::init(mem); + // Only Memory 0 and 2 buckets should be counted as freed_buckets. + // The bucket belonging to Memory 4 should not be counted as + // freed because it has the biggest Bucket ID of all allocated + // buckets hence it should become part of unallocated buckets. + assert_eq!( + mem_mgr.inner.borrow().freed_buckets, + maplit::btreeset! { BucketId(0), BucketId(2) } + ); + } + + #[test] + fn upgrade_from_v1_to_v2() { + let mem = make_memory(); + // Initialize with layout v1. + let mem_mgr = MemoryManager::init_with_bucket_size_v1(mem.clone(), 1); // very small bucket size. + + let memories_v1: Vec<_> = (0..MAX_NUM_MEMORIES) + .map(|id| mem_mgr.get(MemoryId(id))) + .collect(); + + proptest!(|( + num_memories in 0..255usize, + data in proptest::collection::vec(0..u8::MAX, 0..2*WASM_PAGE_SIZE as usize), + offset in 0..10*WASM_PAGE_SIZE + )| { + for memory_v1 in memories_v1.iter().take(num_memories) { + // Write a random blob into the memory, growing the memory as it needs to. + write(memory_v1, offset, &data); + } + + // Load layout v1 and convert it to layout v2. + let mem_mgr_v2 = MemoryManager::init_with_bucket_size(mem.clone(), 1); + let memories_v2: Vec<_> = (0..MAX_NUM_MEMORIES) + .map(|id| mem_mgr_v2.get(MemoryId(id))) + .collect(); + + for memory_v2 in memories_v2.iter().take(num_memories) { + // Verify the blob can be read back. + let mut bytes = vec![0; data.len()]; + memory_v2.read(offset, &mut bytes); + assert_eq!(bytes, data); + } + }); + } }