diff --git a/.gitignore b/.gitignore index 8f154ba..b1b15ce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ /target -Cargo.lock # misc .DS_Store diff --git a/BENCHMARKS-120m.md b/BENCHMARKS-120m.md deleted file mode 100644 index 90d5aa3..0000000 --- a/BENCHMARKS-120m.md +++ /dev/null @@ -1,23 +0,0 @@ -# Benchmarks - -## Table of Contents - -- [Benchmark Results](#benchmark-results) - - [Exact](#exact) - -## Benchmark Results - -The following tests were conducted on a single table in Postgres containing 120 million rows of data. - -### Exact - -| | `plaintext_linear` | `plaintext_btree` | `ore_linear` | `ore_btree` | -|:---------------|:----------------------------|:---------------------------------|:---------------------------------|:--------------------------------- | -| **`0`** | `252.51 us` | `142.67 us` | `1.25 ms` | `742.45 us` | -| **`1000`** | `127.88 us` | `142.96 us` | `433.50 us` | `754.43 us` | -| **`5000000`** | `229.21 us` | `143.07 us` | `1.76 ms` | `715.12 us` | -| **`19000000`** | `176.13 us` | `140.96 us` | `775.20 us` | `761.21 us` | - ---- -Made with [criterion-table](https://github.com/nu11ptr/criterion-table) - diff --git a/BENCHMARKS-20m.md b/BENCHMARKS-20m.md deleted file mode 100644 index 4c60881..0000000 --- a/BENCHMARKS-20m.md +++ /dev/null @@ -1,21 +0,0 @@ -# Benchmarks - -## Table of Contents - -- [Benchmark Results](#benchmark-results) - - [Exact](#exact) - -## Benchmark Results - -### Exact - -| | `plaintext_linear` | `plaintext_btree` | `ore_linear` | `ore_btree` | -|:---------------|:----------------------------|:---------------------------------|:---------------------------------|:--------------------------------- | -| **`0`** | `119.54 us` (✅ **1.00x**) | `117.54 us` (✅ **1.02x faster**) | `115.82 us` (✅ **1.03x faster**) | `684.23 us` (❌ *5.72x slower*) | -| **`1000`** | `176.59 us` (✅ **1.00x**) | `127.14 us` (✅ **1.39x faster**) | `1.65 ms` (❌ *9.33x slower*) | `683.09 us` (❌ *3.87x slower*) | -| **`5000000`** | `262.09 us` (✅ **1.00x**) | `130.15 us` (🚀 **2.01x faster**) | `822.92 us` (❌ *3.14x slower*) | `711.04 us` (❌ *2.71x slower*) | -| **`19000000`** | `194.78 us` (✅ **1.00x**) | `120.15 us` (✅ **1.62x faster**) | `1.09 ms` (❌ *5.60x slower*) | `695.32 us` (❌ *3.57x slower*) | - ---- -Made with [criterion-table](https://github.com/nu11ptr/criterion-table) - diff --git a/BENCHMARKS.md b/BENCHMARKS.md deleted file mode 100644 index 4c60881..0000000 --- a/BENCHMARKS.md +++ /dev/null @@ -1,21 +0,0 @@ -# Benchmarks - -## Table of Contents - -- [Benchmark Results](#benchmark-results) - - [Exact](#exact) - -## Benchmark Results - -### Exact - -| | `plaintext_linear` | `plaintext_btree` | `ore_linear` | `ore_btree` | -|:---------------|:----------------------------|:---------------------------------|:---------------------------------|:--------------------------------- | -| **`0`** | `119.54 us` (✅ **1.00x**) | `117.54 us` (✅ **1.02x faster**) | `115.82 us` (✅ **1.03x faster**) | `684.23 us` (❌ *5.72x slower*) | -| **`1000`** | `176.59 us` (✅ **1.00x**) | `127.14 us` (✅ **1.39x faster**) | `1.65 ms` (❌ *9.33x slower*) | `683.09 us` (❌ *3.87x slower*) | -| **`5000000`** | `262.09 us` (✅ **1.00x**) | `130.15 us` (🚀 **2.01x faster**) | `822.92 us` (❌ *3.14x slower*) | `711.04 us` (❌ *2.71x slower*) | -| **`19000000`** | `194.78 us` (✅ **1.00x**) | `120.15 us` (✅ **1.62x faster**) | `1.09 ms` (❌ *5.60x slower*) | `695.32 us` (❌ *3.57x slower*) | - ---- -Made with [criterion-table](https://github.com/nu11ptr/criterion-table) - diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..e43fd89 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,5031 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures", + "zeroize", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher 0.4.4", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.9", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "array-init" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", + "zeroize", +] + +[[package]] +name = "async-compression" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d10e4f991a553474232bc0a31799f6d24b034a84c0971d80d2e2f78b2e576e40" +dependencies = [ + "compression-codecs", + "compression-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-mutex" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73112ce9e1059d8604242af62c7ec8e5975ac58ac251686c8403b45e8a6fe778" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "aws-lc-rs" +version = "1.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e84ce723ab67259cfeb9877c6a639ee9eb7a27b28123abd71db7f0d5d0cc9d86" +dependencies = [ + "aws-lc-sys", + "untrusted 0.7.1", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a442ece363113bd4bd4c8b18977a7798dd4d3c3383f34fb61936960e8f4ad8" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "backtrace-ext" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base32" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022dfe9eb35f19ebbcb51e0b40a5ab759f46ad60cadf7297e0bd085afb50e076" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "base85" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36915bbaca237c626689b5bd14d02f2ba7a5a359d30a2a08be697392e3718079" +dependencies = [ + "thiserror 1.0.69", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +dependencies = [ + "serde_core", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures", + "zeroize", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-modes" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" +dependencies = [ + "block-padding", + "cipher 0.3.0", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "brotli" +version = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +dependencies = [ + "serde", +] + +[[package]] +name = "cached" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9718806c4a2fe9e8a56fd736f97b340dd10ed1be8ed733ed50449f351dc33cae" +dependencies = [ + "ahash 0.8.12", + "cached_proc_macro", + "cached_proc_macro_types", + "hashbrown 0.14.5", + "once_cell", + "thiserror 1.0.69", + "web-time", +] + +[[package]] +name = "cached_proc_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f42a145ed2d10dce2191e1dcf30cfccfea9026660e143662ba5eec4017d5daa" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "cached_proc_macro_types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.2.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "ciborium" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" + +[[package]] +name = "ciborium-ll" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "cipherstash-client" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd8ee3770269505a5673c268ed54421e46091374c9ad1a9163d558f704d98cf1" +dependencies = [ + "aes-gcm-siv", + "anyhow", + "async-mutex", + "async-trait", + "base16ct", + "base64", + "base85", + "blake3", + "cfg-if", + "chrono", + "cipherstash-config", + "cipherstash-core", + "cllw-ore", + "cts-common", + "derive_more 1.0.0", + "dirs", + "futures", + "hex", + "hmac", + "itertools 0.12.1", + "lazy_static", + "log", + "miette", + "opaque-debug", + "open", + "ore-rs 0.8.0", + "percent-encoding", + "rand 0.8.5", + "rand_chacha 0.3.1", + "recipher", + "reqwest", + "reqwest-middleware", + "reqwest-retry", + "rmp-serde", + "rust-stemmers", + "rust_decimal", + "serde", + "serde_bytes", + "serde_cbor", + "serde_json", + "serdect", + "sha2", + "static_assertions", + "thiserror 1.0.69", + "tokio", + "toml 0.8.23", + "tracing", + "url", + "uuid", + "winnow 0.6.26", + "zeroize", + "zerokms-protocol", +] + +[[package]] +name = "cipherstash-config" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd94f7826557fa825161118a5b06d1ed60a66185e4f4d5766b9e5ae39669177" +dependencies = [ + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "cipherstash-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd56dfac0a35146968ef6696fb822b22f70a664a8739874385876d5452844b7a" +dependencies = [ + "hmac", + "lazy_static", + "num-bigint", + "rand 0.8.5", + "regex", + "sha2", + "thiserror 1.0.69", +] + +[[package]] +name = "clap" +version = "3.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +dependencies = [ + "bitflags 1.3.2", + "clap_lex", + "indexmap 1.9.3", + "textwrap", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "cllw-ore" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61894ceda17ee0b19d2255a7813c878d283ef55c35ca6c6f64e7220cacc1f72f" +dependencies = [ + "bit-vec", + "bitvec", + "blake3", + "hex", + "postgres-derive", + "postgres-types", + "regex", + "subtle", + "thiserror 1.0.69", + "unicode-normalization", + "vitaminc", +] + +[[package]] +name = "cmac" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8543454e3c3f5126effff9cd44d562af4e31fb8ce1cc0d3dcd8f084515dbc1aa" +dependencies = [ + "cipher 0.4.4", + "dbl", + "digest", +] + +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + +[[package]] +name = "compression-codecs" +version = "0.4.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a" +dependencies = [ + "brotli", + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-hex" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" +dependencies = [ + "cfg-if", + "cpufeatures", + "proptest", + "serde_core", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +dependencies = [ + "anes", + "atty", + "cast", + "ciborium", + "clap", + "criterion-plot", + "futures", + "itertools 0.10.5", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "tokio", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "criterion-table" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e29a4fbf3270d102140a8ebe7c9e1619afe0796724f0dda152ec103f93d041" +dependencies = [ + "anyhow", + "flexstr", + "indexmap 1.9.3", + "serde", + "serde_json", + "toml 0.5.11", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher 0.4.4", +] + +[[package]] +name = "cts-common" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1b0b629ef1939040e09625a0c70045650149f5b6be7bd0935fc0c4a50129b54" +dependencies = [ + "arrayvec", + "base32", + "cached", + "chrono", + "derive_more 2.1.1", + "either", + "miette", + "nom", + "regex", + "serde", + "thiserror 1.0.69", + "url", + "utoipa", + "uuid", + "vitaminc", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.114", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "dbbenches" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "cipherstash-client", + "criterion", + "criterion-table", + "fake 4.4.0", + "hex", + "hex-literal", + "ore-rs 0.7.0", + "rand 0.8.5", + "serde", + "serde_json", + "sqlx", + "tokio", +] + +[[package]] +name = "dbl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd2735a791158376708f9347fe8faba9667589d82427ef3aed6794a8981de3d9" +dependencies = [ + "generic-array", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl 2.1.1", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "unicode-xid", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.114", + "unicode-xid", +] + +[[package]] +name = "deunicode" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "dummy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac124e13ae9aa56acc4241f8c8207501d93afdd8d8e62f0c1f2e12f6508c65" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "fake" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d391ba4af7f1d93f01fcf7b2f29e2bc9348e109dfdbf4dcbdc51dfa38dab0b6" +dependencies = [ + "deunicode", + "dummy", + "rand 0.8.5", + "uuid", +] + +[[package]] +name = "fake" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b0902eb36fbab51c14eda1c186bda119fcff91e5e4e7fc2dd2077298197ce8" +dependencies = [ + "chrono", + "deunicode", + "either", + "rand 0.9.2", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" + +[[package]] +name = "flate2" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flexstr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44498e554d7c8e2f2949d1652c3bfb5dbd4a2d801c54560b76a4697c7edace2" +dependencies = [ + "serde", +] + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin 0.9.8", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot 0.12.1", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.12", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[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", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "is_ci" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f508063cc7bb32987c71511216bd5a32be15bccb6a80b52df8b9d7f01fc3aa2" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "md-5" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +dependencies = [ + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "backtrace", + "backtrace-ext", + "cfg-if", + "miette-derive", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "open" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2078c0039e6a54a0c42c28faa984e115fb4c2d5bf2208f77d1961002df8576f8" +dependencies = [ + "pathdiff", + "windows-sys 0.42.0", +] + +[[package]] +name = "openssl" +version = "0.10.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ore-rs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969bed0f20e494e630c925f86a10e94de8f6ef31bef0d3ed13e6945e9cf6c566" +dependencies = [ + "aes", + "block-modes", + "byteorder", + "hex", + "hex-literal", + "lazy_static", + "num", + "rand 0.8.5", + "rand_chacha 0.3.1", + "subtle-ng", + "zeroize", +] + +[[package]] +name = "ore-rs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17ced859adc3f4a6a80568b0b33519a496b00609b0be3b94d9dff136b5f3ec8" +dependencies = [ + "aes", + "block-modes", + "byteorder", + "hex", + "hex-literal", + "lazy_static", + "num", + "rand 0.8.5", + "rand_chacha 0.3.1", + "subtle-ng", + "thiserror 1.0.69", + "zeroize", +] + +[[package]] +name = "os_str_bytes" +version = "6.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" + +[[package]] +name = "owo-colors" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.7", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "windows-sys 0.45.0", +] + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "plotters" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-svg" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "postgres-derive" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56df96f5394370d1b20e49de146f9e6c25aa9ae750f449c9d665eafecb3ccae6" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "postgres-protocol" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ee9dd5fe15055d2b6806f4736aa0c9637217074e224bbec46d4041b91bb9491" +dependencies = [ + "base64", + "byteorder", + "bytes", + "fallible-iterator", + "hmac", + "md-5", + "memchr", + "rand 0.9.2", + "sha2", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b858f82211e84682fecd373f68e1ceae642d8d751a1ebd13f33de6257b3e20" +dependencies = [ + "array-init", + "bytes", + "fallible-iterator", + "postgres-derive", + "postgres-protocol", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit 0.23.10+spec-1.0.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" +dependencies = [ + "bitflags 2.10.0", + "num-traits", + "rand 0.9.2", + "rand_chacha 0.9.0", + "rand_xorshift", + "regex-syntax", + "unarray", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quote" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.9", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "recipher" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72aa0940c8f5b753bfd3ed212d60896760579324c59194b7e51fcec35e5c1b0f" +dependencies = [ + "aes", + "async-trait", + "cmac", + "hex", + "hex-literal", + "opaque-debug", + "rand 0.8.5", + "rand_chacha 0.3.1", + "serde", + "serde_cbor", + "sha2", + "thiserror 1.0.69", + "zeroize", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.9", + "redox_syscall 0.2.16", + "thiserror 1.0.69", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "reqwest" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +dependencies = [ + "async-compression", + "base64", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.26.11", + "winreg", +] + +[[package]] +name = "reqwest-middleware" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562ceb5a604d3f7c885a792d42c199fd8af239d0a51b2fa6a78aafa092452b04" +dependencies = [ + "anyhow", + "async-trait", + "http", + "reqwest", + "serde", + "thiserror 1.0.69", + "tower-service", +] + +[[package]] +name = "reqwest-retry" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40f342894422862af74c50e1e9601cf0931accc9c6981e5eb413c46603b616b5" +dependencies = [ + "anyhow", + "async-trait", + "chrono", + "futures", + "getrandom 0.2.9", + "http", + "hyper", + "parking_lot 0.11.2", + "reqwest", + "reqwest-middleware", + "retry-policies", + "tokio", + "tracing", + "wasm-timer", +] + +[[package]] +name = "retry-policies" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "493b4243e32d6eedd29f9a398896e35c6943a123b55eec97dcaee98310d25810" +dependencies = [ + "anyhow", + "chrono", + "rand 0.8.5", +] + +[[package]] +name = "ring" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e" +dependencies = [ + "cc", + "getrandom 0.2.9", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", +] + +[[package]] +name = "rkyv" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rmp" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "rmp-serde" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155" +dependencies = [ + "rmp", + "serde", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rust-stemmers" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "rust_decimal" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.37.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "722529a737f5a942fdbac3a46cee213053196737c5eaa3386d52e85b786f2659" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.2", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags 2.10.0", + "errno", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted 0.9.0", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "security-framework" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serdect" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f42f67da2385b51a5f9652db9c93d78aeaf7610bf5ec366080b6de810604af53" +dependencies = [ + "base16ct", + "serde", + "zeroize", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlx" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +dependencies = [ + "base64", + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener 5.4.1", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.5", + "hashlink", + "indexmap 2.13.0", + "log", + "memchr", + "native-tls", + "once_cell", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror 2.0.17", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.114", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.114", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +dependencies = [ + "atoi", + "base64", + "bitflags 2.10.0", + "byteorder", + "bytes", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand 0.8.5", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.17", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64", + "bitflags 2.10.0", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.17", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror 2.0.17", + "tracing", + "url", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stringprep" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + +[[package]] +name = "supports-color" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" +dependencies = [ + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" + +[[package]] +name = "supports-unicode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix 0.37.12", + "windows-sys 0.45.0", +] + +[[package]] +name = "terminal_size" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" +dependencies = [ + "rustix 1.1.3", + "windows-sys 0.60.2", +] + +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +dependencies = [ + "unicode-linebreak", + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot 0.12.1", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.6.1", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "indexmap 1.9.3", + "serde", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.13.0", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.14", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap 2.13.0", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "winnow 0.7.14", +] + +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ + "winnow 0.7.14", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utoipa" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fcc29c80c21c31608227e0912b2d7fddba57ad76b606890627ba8ee7964e993" +dependencies = [ + "indexmap 2.13.0", + "serde", + "serde_json", + "utoipa-gen", +] + +[[package]] +name = "utoipa-gen" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d79d08d92ab8af4c5e8a6da20c47ae3f61a0f1dabc1997cdf2d082b757ca08b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "url", + "uuid", +] + +[[package]] +name = "uuid" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +dependencies = [ + "atomic", + "getrandom 0.3.4", + "js-sys", + "md-5", + "serde_core", + "sha1_smol", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vitaminc" +version = "0.1.0-pre4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f800bb9d02311571a8de172d63a4c9c10e07869089e3ddd84a8b05f3bef2d93" +dependencies = [ + "vitaminc-encrypt", + "vitaminc-protected", + "vitaminc-random", + "vitaminc-traits", +] + +[[package]] +name = "vitaminc-aead" +version = "0.1.0-pre4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2b9f64cfbcc0c8d781e2a7d33beb183fd8f58735bed8c662286548042de820" +dependencies = [ + "bytes", + "serde", + "vitaminc-protected", + "vitaminc-random", + "zeroize", +] + +[[package]] +name = "vitaminc-encrypt" +version = "0.1.0-pre4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc871c8b8c61e5d2e4e097526e9cf7bc99913a45c23f31c2f6d5f1f2d0b8eec7" +dependencies = [ + "aws-lc-rs", + "vitaminc-aead", + "vitaminc-protected", + "vitaminc-random", + "zeroize", +] + +[[package]] +name = "vitaminc-protected" +version = "0.1.0-pre4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1af28bfb95686a7f5f95e845f99523ca8f7e3bf4a3c82f90554965ddf52e451" +dependencies = [ + "bitvec", + "digest", + "opaque-debug", + "serde", + "serde_bytes", + "subtle", + "vitaminc-protected-derive", + "zeroize", +] + +[[package]] +name = "vitaminc-protected-derive" +version = "0.1.0-pre4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c9713b5849b9ba2260d1e36fc956909c7832b69365ce15d29895e9257676c77" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "vitaminc-random" +version = "0.1.0-pre4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed841b58f676dc55a49d65284c91a2da2b71e57508c646a77c91f4dd31eb96" +dependencies = [ + "rand 0.8.5", + "rand_chacha 0.3.1", + "thiserror 1.0.69", + "vitaminc-protected", + "vitaminc-random-derives", + "zeroize", +] + +[[package]] +name = "vitaminc-random-derives" +version = "0.1.0-pre4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "172cdde4c52be52584990097655de39d835e9bcca5593c2b3517c8978ac87e89" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "vitaminc-traits" +version = "0.1.0-pre4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb63364ce6b2a33176d2a1aba75d6b77d982518654e84192419d18b8c97f36b5" +dependencies = [ + "anyhow", + "bytes", + "rmp-serde", + "serde", + "thiserror 1.0.69", + "vitaminc-protected", + "vitaminc-random", + "zeroize", +] + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.114", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.5", +] + +[[package]] +name = "webpki-roots" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c70234412ca409cc04e864e89523cb0fc37f5e1344ebed5a3ebf4192b6b9f68" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +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", +] + +[[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", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +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", +] + +[[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-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +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" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +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_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[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_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[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_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e90edd2ac1aa278a5c4599b1d89cf03074b610800f866d4026dc199d7929a28" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zerokms-protocol" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe46b7fa449d5d14d9941ca83e3e92faa44e5f15ffb4b8fcc71158571279b7" +dependencies = [ + "async-trait", + "base64", + "cipherstash-config", + "const-hex", + "cts-common", + "fake 2.10.0", + "opaque-debug", + "rand 0.8.5", + "serde", + "static_assertions", + "thiserror 1.0.69", + "uuid", + "zeroize", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zmij" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" diff --git a/Cargo.toml b/Cargo.toml index b79e7bd..261120c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,14 +6,45 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -sqlx = { version = "0.6", features = [ "runtime-tokio-native-tls" , "postgres" ] } -tokio = { version = "1", features = ["full"] } +sqlx = { version = "0.8", features = [ "runtime-tokio-native-tls" , "postgres", "json" ] } +tokio = { version = "1.47.1", features = ["full"] } criterion = { version = "0.4.0", features = [ "async_tokio" ]} criterion-table = "0.4.2" -ore-rs = "0.4.0" +ore-rs = "0.7.0" hex = "0.4.3" hex-literal = "0.3.4" +rand = "0.8.5" +cipherstash-client = { version = "0.32.2", features = ["tokio"] } +anyhow = "1.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +chrono = "0.4" +fake = { version = "4.4.0", features = ["chrono"] } + +[[bin]] +name = "generate_data" +path = "src/bin/generate_data.rs" + +[[bin]] +name = "encrypt_int" +path = "src/bin/encrypt_int.rs" + +[[bin]] +name = "encrypt_string" +path = "src/bin/encrypt_string.rs" + +[[bin]] +name = "combine_benchmark" +path = "src/bin/combine_benchmark.rs" + +[[bench]] +name = "ore" +harness = false + +[[bench]] +name = "match" +harness = false [[bench]] -name = "exact_lookup" +name = "exact" harness = false \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..eb1c0cb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 CipherStash + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..58dcba2 --- /dev/null +++ b/README.md @@ -0,0 +1,334 @@ +# ORE Benchmarks + +Performance benchmarks for CipherStash's searchable encryption operations using Order-Revealing Encryption (ORE) and the Encrypt Query Language (EQL). + +## 📊 View Results + +The latest benchmark results are available in the [`report/`](report/) directory: + +- **[Benchmark Report](report/BENCHMARK_REPORT.md)** - Comprehensive report with performance tables and charts +- Includes ingest throughput, query performance, SQL statements, and index configurations +- Performance indicators (⚠️) highlight queries exceeding 100ms + +## 🔧 Test Setup + +### Hardware & Software + +The benchmarks are designed to run on a local development machine with the following stack: + +- **Database**: PostgreSQL 17 (running in Docker) +- **Language**: Rust (latest stable) +- **Framework**: Criterion.rs for benchmarking +- **Encryption**: CipherStash EQL v2 with ORE support + +### Database Configuration + +```yaml +PostgreSQL 17 +Port: 5400 (mapped from container port 5432) +User: postgres +Database: postgres +``` + +### Test Data + +The benchmarks use three types of encrypted data: + +1. **Integer values** - ORE-encrypted integers for range queries +2. **String values** - Encrypted strings for exact and pattern matching +3. **JSON objects** - Small encrypted JSON documents + +### Data Set Sizes + +Benchmarks are run against multiple data set sizes: +- 10,000 rows +- 100,000 rows +- 1,000,000 rows +- 10,000,000 rows (optional) + +### Query Types + +Three categories of queries are benchmarked: + +**EXACT Queries** - Exact match lookups +- Using EQL cast operator +- Using EQL HMAC-256 hash + +**MATCH Queries** - Pattern matching +- LIKE queries with EQL cast +- Bloom filter containment queries + +**ORE Queries** - Range queries on encrypted integers +- Exact match +- Range queries (>, <) +- Ordered range queries with ORDER BY + +Each query is tested with and without decryption of results. + +## 🚀 Running Benchmarks + +### Prerequisites + +1. **Install mise** (tool version manager): + ```bash + curl https://mise.run | sh + ``` + +2. **Install Rust** (via mise): + ```bash + mise install + ``` + +3. **Set up environment variables**: + ```bash + cp .env.example .env + # Edit .env with your CipherStash credentials + ``` + +### Quick Start + +```bash +# Start PostgreSQL +mise run postgres + +# Set up database (creates tables and installs EQL extension) +mise run setup-db + +# Run all ingest benchmarks +mise run bench:ingest + +# Run query benchmarks for a specific row count +mise run bench:query:exact 10000 +mise run bench:query:match 10000 +mise run bench:query:ore 10000 + +# Run all query benchmarks (all row counts) +mise run bench:query:all + +# Generate report +mise run report +``` + +### Step-by-Step Guide + +#### 1. Start PostgreSQL + +```bash +mise run postgres +``` + +This starts PostgreSQL 17 in a Docker container on port 5400. + +#### 2. Initialize Database + +```bash +mise run reset-db # Reset database (if needed) +mise run setup-db # Install EQL extension and create tables +``` + +#### 3. Run Ingest Benchmarks + +```bash +# Run individual ingest benchmarks +mise run bench:ingest:encrypt_int +mise run bench:ingest:encrypt_string +mise run bench:ingest:encrypt_json_small + +# Or run all at once +mise run bench:ingest +``` + +Results are saved to `results/ingest/*.json` + +#### 4. Prepare Tables for Query Benchmarks + +Before running query benchmarks, tables need to be populated and indexed: + +```bash +# Prepare string_encrypted table with 10,000 rows +mise run prepare:string_encrypted 10000 + +# Prepare integer_encrypted table with 10,000 rows +mise run prepare:integer_encrypted 10000 +``` + +This process: +1. Checks current row count +2. Drops indexes +3. Inserts additional rows if needed +4. Creates indexes + +#### 5. Run Query Benchmarks + +```bash +# Run specific query benchmark with specific row count +mise run bench:query:exact 10000 +mise run bench:query:match 100000 +mise run bench:query:ore 1000000 + +# Run all query benchmarks for all row counts (10k, 100k, 1M, 10M) +mise run bench:query:all +``` + +Results are saved to `results/query/*.json` + +#### 6. Generate Report + +```bash +mise run report +``` + +This generates: +- `report/BENCHMARK_REPORT.md` - Markdown report +- `report/*_chart.png` - Performance charts (requires matplotlib) + +To enable chart generation: +```bash +pip3 install matplotlib +``` + +## 📁 Project Structure + +``` +ore-benches/ +├── benches/ # Criterion benchmark definitions +│ ├── exact.rs # EXACT query benchmarks +│ ├── match.rs # MATCH query benchmarks +│ └── ore.rs # ORE range query benchmarks +├── src/ +│ ├── bin/ # Binary utilities +│ │ ├── encrypt_int.rs +│ │ ├── encrypt_string.rs +│ │ └── combine_benchmark.rs +│ └── lib.rs # Shared benchmark code +├── sql/ +│ ├── schema.sql # Database schema +│ └── indexes/ # Index creation scripts +├── results/ # Benchmark results (JSON) +│ ├── ingest/ # Ingest throughput results +│ └── query/ # Query performance results +├── report/ # Generated reports +│ ├── BENCHMARK_REPORT.md +│ └── *.png # Charts +├── report_benchmarks.py # Report generator script +├── mise.toml # Task definitions +└── README.md # This file +``` + +## 🛠️ Advanced Usage + +### Custom Row Counts + +```bash +# Prepare and benchmark custom row count +mise run prepare:string_encrypted 50000 +TARGET_ROWS=50000 cargo criterion --bench exact +``` + +### Individual Benchmark Runs + +```bash +# Build in release mode +mise run bench:build + +# Run specific benchmark manually +TARGET_ROWS=10000 cargo criterion --bench ore --message-format json > results/query/ore_rows_10000.json +``` + +### Database Management + +```bash +# Connect to database +mise run psql + +# View PostgreSQL logs +mise run postgres-logs + +# Stop PostgreSQL +mise run postgres-stop +``` + +### Report Generation Options + +```bash +# Generate report with custom filename +mise run report custom_report.md + +# Or use Python script directly +python3 report_benchmarks.py --output report/my_report.md + +# Specify custom directories +python3 report_benchmarks.py \ + --results-dir results \ + --sql-dir sql \ + --output report/BENCHMARK_REPORT.md +``` + +## 📈 Understanding Results + +### Ingest Throughput + +Measures how many encrypted records can be inserted per second. Higher is better. + +### Query Performance + +Query times are reported both: +- **Without decryption** - Time to execute query and retrieve encrypted results +- **With decryption** - Time including client-side decryption + +Times exceeding 100ms are marked with ⚠️ for easy identification. + +### Performance Factors + +Query performance is affected by: +1. **Data set size** - Larger datasets generally increase query time +2. **Index type** - Hash indexes are faster for exact matches; ORE indexes enable range queries +3. **Query complexity** - Pattern matching is slower than exact lookups +4. **Result set size** - LIMIT clause affects decryption overhead + +## 🔍 Troubleshooting + +### PostgreSQL Connection Issues + +```bash +# Check if PostgreSQL is running +docker ps | grep postgres + +# Restart PostgreSQL +mise run postgres-stop +mise run postgres +``` + +### Missing EQL Extension + +```bash +mise run setup-db +``` + +### Benchmark Failures + +Check that: +1. Database is running and accessible +2. Tables have been prepared with correct row counts +3. Environment variables are set in `.env` +4. CipherStash credentials are valid + +## 📚 Additional Documentation + +- [Report Generator Documentation](README_REPORT.md) - Detailed guide for the report generation script +- [Report Directory](report/README.md) - Information about generated reports +- [CipherStash Documentation](https://cipherstash.com/docs) - Official CipherStash docs + +## 🤝 Contributing + +When adding new benchmarks: + +1. Add benchmark definition to `benches/` +2. Update `mise.toml` with new tasks +3. Add query descriptions to `report_benchmarks.py` +4. Document the benchmark in this README +5. Run benchmarks and commit results to `report/` + +## 📄 License + +MIT License - see [LICENSE](LICENSE) for details. diff --git a/README_REPORT.md b/README_REPORT.md new file mode 100644 index 0000000..132ecc0 --- /dev/null +++ b/README_REPORT.md @@ -0,0 +1,245 @@ +# Benchmark Report Generator + +This project includes a Python script to generate comprehensive reports from benchmark results. + +## Quick Start + +Generate a report from existing benchmark results: + +```bash +mise run report +``` + +This will create `report/BENCHMARK_REPORT.md` and associated chart images in the `report/` directory. + +## Usage + +### Via Mise Task + +```bash +# Generate report with default location (report/BENCHMARK_REPORT.md) +mise run report + +# Generate report with custom location +mise run report custom_dir/my_report.md +``` + +### Direct Script Usage + +```bash +# Basic usage (creates report/BENCHMARK_REPORT.md) +python3 report_benchmarks.py + +# Custom output file +python3 report_benchmarks.py --output custom_dir/report.md + +# Custom results directory and SQL directory +python3 report_benchmarks.py --results-dir path/to/results --sql-dir path/to/sql --output report/report.md + +# Show help +python3 report_benchmarks.py --help +``` + +## Report Contents + +The generated report includes: + +### 1. Ingest Throughput + +Performance metrics for inserting encrypted records: +- **Int**: Encrypted integer values +- **JSON Small**: Small encrypted JSON objects +- **String**: Encrypted string values + +For each type, the report shows: +- Number of records +- Throughput (records/sec) +- Total time +- Average memory usage + +### 2. Query Performance + +Performance metrics for queries across different data set sizes (10K, 100K, 1M rows): + +#### EXACT Queries +- **eql_cast**: Exact match using EQL cast operator + - SQL: `SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1` + - Parameter: `Bob Johnson` +- **eql_hash**: Exact match using EQL HMAC-256 hash function + - SQL: `SELECT value FROM {TABLE} WHERE eql_v2.hmac_256(value) = eql_v2.hmac_256($1::jsonb) LIMIT 1` + - Parameter: `Bob Johnson` + +#### MATCH Queries +- **eql_cast_firstname**: Pattern matching on first name using LIKE + - SQL: `SELECT id,value::jsonb FROM {TABLE} WHERE value LIKE $1 LIMIT 10` + - Parameter: `Bob` +- **eql_cast_lastname**: Pattern matching on last name using LIKE + - SQL: `SELECT id,value::jsonb FROM {TABLE} WHERE value LIKE $1 LIMIT 10` + - Parameter: `Johnson` +- **eql_bloom**: Pattern matching using bloom filter containment + - SQL: `SELECT id,value::jsonb FROM {TABLE} WHERE eql_v2.bloom_filter(value) @> eql_v2.bloom_filter($1) LIMIT 10` + - Parameter: `Johnson` + +#### ORE Queries +- **exact**: Exact match on encrypted integer + - SQL: `SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1` + - Parameter: `5000` +- **range_gt_10**: Range query (>) returning 10 results + - SQL: `SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 10` + - Parameter: `5000` +- **range_gt_100**: Range query (>) returning 100 results + - SQL: `SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 100` + - Parameter: `5000` +- **range_lt_10**: Range query (<) returning 10 results + - SQL: `SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 10` + - Parameter: `5000` +- **range_lt_100**: Range query (<) returning 100 results + - SQL: `SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 100` + - Parameter: `5000` +- **range_lt_ordered_10**: Ordered range query with ORDER BY + - SQL: `SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 ORDER BY value LIMIT 10` + - Parameter: `5000` + +Each query shows: +- The actual SQL query used +- The parameter value passed to the query +- Database indexes available on the table +- Performance both with and without decryption of results +- ⚠️ Warning indicator for query times exceeding 100ms + +## Charts (Optional) + +The script can generate PNG charts for visualizing benchmark results. To enable charts: + +```bash +pip3 install matplotlib +``` + +When matplotlib is available: +- Ingest benchmarks will include bar charts showing throughput +- Query benchmarks will include line charts showing performance vs data set size + +Charts are saved as PNG files in the same directory as the report (by default, the `report/` directory). + +## Report Format + +The report is generated as a Markdown file with: +- Table of contents with anchor links +- Tables showing performance metrics +- SQL queries and parameters for each benchmark +- Database index definitions (read from `sql/indexes/` directory) +- Performance indicators (⚠️ emoji) for query times exceeding 100ms +- Embedded chart images (when matplotlib is available) +- Descriptions of what each benchmark tests + +## Input Files + +The script expects benchmark results and SQL files in the following structure: + +``` +results/ +├── ingest/ +│ ├── encrypt_int_combined.json +│ ├── encrypt_json_small_combined.json +│ └── encrypt_string_combined.json +└── query/ + ├── exact_rows_10000.json + ├── exact_rows_100000.json + ├── exact_rows_1000000.json + ├── match_rows_10000.json + ├── match_rows_100000.json + ├── match_rows_1000000.json + ├── ore_rows_10000.json + ├── ore_rows_100000.json + └── ore_rows_1000000.json + +sql/ +├── schema.sql +└── indexes/ + ├── string_encrypted_10000_up.sql + ├── string_encrypted_100000_up.sql + ├── string_encrypted_1000000_up.sql + ├── integer_encrypted_10000_up.sql + ├── integer_encrypted_100000_up.sql + └── integer_encrypted_1000000_up.sql +``` + +### Ingest Result Format + +Ingest results should be JSON files with: +```json +{ + "metadata": { ... }, + "results": [ + { + "num_records": 500, + "total_time_seconds": 0.91, + "throughput_records_per_second": 544.83, + "average_memory_usage_mb": 15.25 + } + ] +} +``` + +### Query Result Format + +Query results should be Criterion JSON output (one JSON object per line) with benchmark results. + +### Index SQL Files + +Index definitions should be in `sql/indexes/{table_name}_up.sql` files. For example: +```sql +CREATE INDEX +string_encrypted_10000_hash_index +ON string_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000_gin_index +ON string_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(value) +); + +CREATE INDEX +string_encrypted_10000_eql_index +ON string_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); +``` + +## Customization + +The script can be modified to: +- Add new query descriptions +- Change chart formatting +- Modify table layouts +- Add additional metrics +- Change output format (e.g., HTML, PDF) + +See the `BenchmarkReporter` class in `report_benchmarks.py` for customization points. + +## Requirements + +- Python 3.7+ +- matplotlib (optional, for charts) + +## Why Python? + +Python was chosen for this script because it provides: +- Simple JSON parsing with the standard library +- Flexible text/markdown generation +- Rich ecosystem of charting libraries (matplotlib, plotly, etc.) +- Easy extensibility for different output formats +- Cross-platform compatibility + +This makes it easier to add features like: +- Interactive HTML reports +- PDF generation +- Statistical analysis +- Different visualization styles +- Export to other formats (CSV, Excel, etc.) + +## Output Directory + +By default, reports are generated in the `report/` directory. This keeps generated files organized and separate from source code. The generated files in `report/` are tracked in git to provide a historical record of benchmark performance. diff --git a/benches/exact.rs b/benches/exact.rs new file mode 100644 index 0000000..f7d9ec7 --- /dev/null +++ b/benches/exact.rs @@ -0,0 +1,101 @@ +use cipherstash_client::{ + credentials::ServiceCredentials, + encryption::ScopedCipher, + eql::Identifier, + schema::{column::Index, ColumnConfig, ColumnType}, +}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use dbbenches::{init_scoped_cipher, EncryptedQuery, EncryptedQueryBuilder}; +use sqlx::postgres::PgPoolOptions; +use std::sync::Arc; +use tokio::runtime::Runtime; + +static QUERY_TEMPLATES: &[(&str, &str, &str)] = &[ + ("SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1", "Bob Johnson", "eql_cast"), + ("SELECT value FROM {TABLE} WHERE eql_v2.hmac_256(value) = eql_v2.hmac_256($1::jsonb) LIMIT 1", "Bob Johnson", "eql_hash"), +]; + +async fn build_query( + cipher: Arc>, + query: &str, + x: &str, + table_name: &str, +) -> EncryptedQuery { + let column_config = ColumnConfig::build("value") + .casts_as(ColumnType::Utf8Str) + .add_index(Index::new_unique()); + + let identifier = Identifier::new(table_name, "value"); + + EncryptedQueryBuilder::new(column_config, identifier) + .index_type(Index::new_unique().index_type) + .statement(query) + .build_query(x, cipher) + .await + .expect("Failed to build encrypted query") +} + +fn criterion_benchmark(c: &mut Criterion) { + let rt = Runtime::new().unwrap(); + + let target_rows = std::env::var("TARGET_ROWS") + .unwrap_or_else(|_| "unknown".to_string()); + + // Determine table suffix based on TARGET_ROWS + let table_suffix = match target_rows.as_str() { + "10000" | "100000" | "1000000" | "10000000" => format!("_{}", target_rows), + _ => String::new(), // fallback to base table for unknown values + }; + let table_name = format!("string_encrypted{}", table_suffix); + + let (pool, cipher) = rt.block_on(async { + let database_url = + std::env::var("DATABASE_URL").expect("DATABASE_URL environment variable must be set"); + + let pool = PgPoolOptions::new() + .max_connections(5) + .connect(&database_url) + .await + .expect("Failed to connect to database"); + + let cipher = init_scoped_cipher() + .await + .expect("Failed to initialize ScopedCipher"); + + (pool, cipher) + }); + + let queries = rt.block_on(async { + let mut queries = Vec::with_capacity(QUERY_TEMPLATES.len()); + for (query_template, x, _) in QUERY_TEMPLATES { + let query_str = query_template.replace("{TABLE}", &table_name); + let query = build_query(Arc::clone(&cipher), &query_str, *x, &table_name).await; + queries.push(query); + } + queries + }); + + let mut group = c.benchmark_group("EXACT"); + group.sample_size(10); + + for (i, query) in queries.into_iter().enumerate() { + let (_, _, scenario) = QUERY_TEMPLATES[i]; + + group.bench_function(format!("exact/{}/{}", scenario, target_rows), |b| { + b.to_async(&rt).iter(|| async { + let _: Vec<_> = query.execute(&pool).await.unwrap(); + }) + }); + + group.bench_function(format!("exact_decrypt/{}/{}", scenario, target_rows), |b| { + b.to_async(&rt).iter(|| async { + let _r: Vec = black_box(query.execute_and_decrypt(&pool).await.unwrap()); + }) + }); + } + + group.finish(); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/benches/exact_lookup.rs b/benches/exact_lookup.rs deleted file mode 100644 index df594cc..0000000 --- a/benches/exact_lookup.rs +++ /dev/null @@ -1,70 +0,0 @@ - -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use ore_rs::{ORECipher, scheme::bit2::OREAES128, OREEncrypt}; -use sqlx::{postgres::PgPoolOptions, Postgres, Pool}; -use tokio::runtime::Runtime; -use hex_literal::hex; - -#[inline] -async fn query(pool: &Pool, q: &str) { - sqlx::query(q) - .fetch_one(pool) - .await - .unwrap(); -} - -fn criterion_benchmark(c: &mut Criterion) { - let rt = Runtime::new().unwrap(); - - let k1 = hex!("00010203 04050607 08090a0b 0c0d0e0f"); - let k2 = hex!("d0d007a5 3f9a6848 83bc1f21 0f6595a3"); - - let queries: Vec = vec![0, 1000, 5_000_000, 19_000_000]; - let ore: OREAES128 = ORECipher::init(&k1, &k2).unwrap(); - let ore_queries: Vec = queries.iter().map(|&val| { - hex::encode(val.encrypt(&ore).unwrap().to_bytes()) - }).collect(); - - let pool = rt.block_on(async { - PgPoolOptions::new() - .max_connections(1) - .connect("postgres://dan@localhost/ore_perf") - .await - .expect("Could not connect to the DB") - }); - - let mut group = c.benchmark_group("Exact"); - - for q in queries.iter() { - group.bench_function(format!("plaintext_linear/{}", q), |b| { - b.to_async(&rt).iter(|| async { - query(&pool, &format!("SELECT * FROM test_linear WHERE value = {} LIMIT 1", q)).await - }) - }); - - group.bench_function(format!("plaintext_btree/{}", q), |b| { - b.to_async(&rt).iter(|| async { - query(&pool, "SELECT * FROM test_btree WHERE value = 500000 LIMIT 1").await - }) - }); - } - - for (q, ore_q) in queries.iter().zip(ore_queries) { - group.bench_function(format!("ore_linear/{}", q), |b| { - b.to_async(&rt).iter(|| async { - query(&pool, &format!("SELECT * FROM test_ore_64_linear WHERE value = '(\\\\x{})' LIMIT 1", ore_q)).await - }) - }); - - group.bench_function(format!("ore_btree/{}", q), |b| { - b.to_async(&rt).iter(|| async { - query(&pool, "SELECT * FROM test_ore_64_btree WHERE value = '(\\\\x7272727272198fe17bb2dad40deb782edcdadcc2172941d70a2db2e2807efabd59d54ba32ed389ffccd18bd60f569bbb81b0734fb241f75d4f30387f511f2f2f790e9252c6de6c8395177a72ea1599bfb6240c753820ad42e11a24f0b01270aecab31db48f9c21c483941be86b1cab25cafba20c0c825b613e726b43e97c28853c4da0782af4855855e03b5edda54fdb4c91be5ad110193948615cda02340adac8b809a0e81df95399d9cc223919261821bd3e94429788d0064a05c045100cf660d969bd18c33784dedef8280a6013b5a9149e1855105237e5d77a072e609595d62a00bf6fe096716f773278608847fe40cd1cb9858fd59fa737dd463b9c8c67ff34319bc0175023096f38917f9cf77f8d6eb1431caf6076df3646b1d7baf95025f1c81763dbf54a8ee2b6f9328daab4d4c93edbd4111fcaf96c75c3a12bd8b6d2f14e2f808b5129dbaec03ae3f070fea73e6c440d188f6b04c08d3659a13ea96135b2626d4e887b1d6904c1846186bdd17a5831a30a393c09a63a28e803b3f3628e43e4e236dd57bc836a558e129dda2e8299189c0dad46)' LIMIT 1").await - }) - }); - } - - group.finish(); -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); \ No newline at end of file diff --git a/benches/match.rs b/benches/match.rs new file mode 100644 index 0000000..cea485f --- /dev/null +++ b/benches/match.rs @@ -0,0 +1,102 @@ +use cipherstash_client::{ + credentials::ServiceCredentials, + encryption::ScopedCipher, + eql::Identifier, + schema::{column::Index, ColumnConfig, ColumnType}, +}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use dbbenches::{init_scoped_cipher, EncryptedQuery, EncryptedQueryBuilder}; +use sqlx::postgres::PgPoolOptions; +use std::sync::Arc; +use tokio::runtime::Runtime; + +static QUERY_TEMPLATES: &[(&str, &str, &str)] = &[ + ("SELECT id,value::jsonb FROM {TABLE} WHERE value LIKE $1 LIMIT 10", "Bob", "eql_cast_firstname"), + ("SELECT id,value::jsonb FROM {TABLE} WHERE value LIKE $1 LIMIT 10", "Johnson", "eql_cast_lastname"), + ("SELECT id,value::jsonb FROM {TABLE} WHERE eql_v2.bloom_filter(value) @> eql_v2.bloom_filter($1) LIMIT 10", "Johnson", "eql_bloom"), +]; + +async fn build_query( + cipher: Arc>, + query: &str, + x: &str, + table_name: &str, +) -> EncryptedQuery { + let column_config = ColumnConfig::build("value") + .casts_as(ColumnType::Utf8Str) + .add_index(Index::new_match()); + + let identifier = Identifier::new(table_name, "value"); + + EncryptedQueryBuilder::new(column_config, identifier) + .index_type(Index::new_match().index_type) + .statement(query) + .build_query(x, cipher) + .await + .expect("Failed to build encrypted query") +} + +fn criterion_benchmark(c: &mut Criterion) { + let rt = Runtime::new().unwrap(); + + let target_rows = std::env::var("TARGET_ROWS") + .unwrap_or_else(|_| "unknown".to_string()); + + // Determine table suffix based on TARGET_ROWS + let table_suffix = match target_rows.as_str() { + "10000" | "100000" | "1000000" | "10000000" => format!("_{}", target_rows), + _ => String::new(), // fallback to base table for unknown values + }; + let table_name = format!("string_encrypted{}", table_suffix); + + let (pool, cipher) = rt.block_on(async { + let database_url = + std::env::var("DATABASE_URL").expect("DATABASE_URL environment variable must be set"); + + let pool = PgPoolOptions::new() + .max_connections(5) + .connect(&database_url) + .await + .expect("Failed to connect to database"); + + let cipher = init_scoped_cipher() + .await + .expect("Failed to initialize ScopedCipher"); + + (pool, cipher) + }); + + let queries = rt.block_on(async { + let mut queries = Vec::with_capacity(QUERY_TEMPLATES.len()); + for (query_template, x, _) in QUERY_TEMPLATES { + let query_str = query_template.replace("{TABLE}", &table_name); + let query = build_query(Arc::clone(&cipher), &query_str, x, &table_name).await; + queries.push(query); + } + queries + }); + + let mut group = c.benchmark_group("MATCH"); + group.sample_size(10); + + for (i, query) in queries.into_iter().enumerate() { + let (_, _, scenario) = QUERY_TEMPLATES[i]; + + group.bench_function(format!("match/{}/{}", scenario, target_rows), |b| { + b.to_async(&rt).iter(|| async { + let _: Vec<_> = query.execute(&pool).await.unwrap(); + }) + }); + + group.bench_function(format!("match_decrypt/{}/{}", scenario, target_rows), |b| { + b.to_async(&rt).iter(|| async { + let _r: Vec = black_box(query.execute_and_decrypt(&pool).await.unwrap()); + }) + }); + } + + group.finish(); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/benches/ore.rs b/benches/ore.rs new file mode 100644 index 0000000..7995655 --- /dev/null +++ b/benches/ore.rs @@ -0,0 +1,132 @@ +use cipherstash_client::{ + credentials::ServiceCredentials, + encryption::ScopedCipher, + eql::Identifier, + schema::{ + column::{Index, IndexType}, + ColumnConfig, ColumnType, + }, +}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use dbbenches::{init_scoped_cipher, EncryptedQuery, EncryptedQueryBuilder}; +use sqlx::postgres::PgPoolOptions; +use std::sync::Arc; +use tokio::runtime::Runtime; + +static QUERY_TEMPLATES: &[(&str, i32, &str)] = &[ + ( + "SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1", + 5000, + "exact", + ), + ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 10", + 5000, + "range_gt_10", + ), + ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 100", + 5000, + "range_gt_100", + ), + ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 10", + 5000, + "range_lt_10", + ), + ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 100", + 5000, + "range_lt_100", + ), + ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 ORDER BY value LIMIT 10", + 5000, + "range_lt_ordered_10", + ), +]; + +async fn build_query( + cipher: Arc>, + query: &str, + x: i32, + table_name: &str, +) -> EncryptedQuery { + let column_config = ColumnConfig::build("value") + .casts_as(ColumnType::Int) + .add_index(Index::new_ore()); + + let identifier = Identifier::new(table_name, "value"); + + EncryptedQueryBuilder::new(column_config, identifier) + .index_type(IndexType::Ore) + .statement(query) + .build_query(x, cipher) + .await + .expect("Failed to build encrypted query") +} + +fn criterion_benchmark(c: &mut Criterion) { + let rt = Runtime::new().unwrap(); + + let target_rows = std::env::var("TARGET_ROWS") + .unwrap_or_else(|_| "unknown".to_string()); + + // Determine table suffix based on TARGET_ROWS + let table_suffix = match target_rows.as_str() { + "10000" | "100000" | "1000000" | "10000000" => format!("_{}", target_rows), + _ => String::new(), // fallback to base table for unknown values + }; + let table_name = format!("integer_encrypted{}", table_suffix); + + let (pool, cipher) = rt.block_on(async { + let database_url = + std::env::var("DATABASE_URL").expect("DATABASE_URL environment variable must be set"); + + let pool = PgPoolOptions::new() + .max_connections(5) + .connect(&database_url) + .await + .expect("Failed to connect to database"); + + let cipher = init_scoped_cipher() + .await + .expect("Failed to initialize ScopedCipher"); + + (pool, cipher) + }); + + let queries = rt.block_on(async { + let mut queries = Vec::with_capacity(QUERY_TEMPLATES.len()); + for (query_template, x, _) in QUERY_TEMPLATES { + let query_str = query_template.replace("{TABLE}", &table_name); + let query = build_query(Arc::clone(&cipher), &query_str, *x, &table_name).await; + queries.push(query); + } + queries + }); + + let mut group = c.benchmark_group("ORE"); + group.sample_size(10); + + for (i, query) in queries.into_iter().enumerate() { + let (_, _, scenario) = QUERY_TEMPLATES[i]; + + group.bench_function(format!("ore/{}/{}", scenario, target_rows), |b| { + b.to_async(&rt).iter(|| async { + let _: Vec<_> = query.execute(&pool).await.unwrap(); + }) + }); + + group.bench_function(format!("ore_decrypt/{}/{}", scenario, target_rows), |b| { + b.to_async(&rt).iter(|| async { + let _r: Vec = black_box(query.execute_and_decrypt(&pool).await.unwrap()); + }) + }); + } + + group.finish(); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ae40242 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +version: '3.8' + +services: + postgres: + image: postgres:17 + container_name: ore-benches-postgres + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - "5400:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..1d23fba --- /dev/null +++ b/mise.toml @@ -0,0 +1,345 @@ +[tools] +python = "latest" +rust = "latest" + +[tasks.postgres] +description = "Start PostgreSQL via Docker Compose" +run = "docker compose up -d postgres" + +[tasks.postgres-stop] +description = "Stop PostgreSQL Docker container" +run = "docker compose down" + +[tasks.postgres-logs] +description = "View PostgreSQL logs" +run = "docker compose logs -f postgres" + +[tasks.psql] +description = "Connect to PostgreSQL via psql" +run = "docker exec -it ore-benches-postgres psql -U postgres -d postgres" + +[tasks.reset-db] +description = "Reset the database (drop and recreate)" +depends = ["postgres"] +run = """ +#!/usr/bin/env bash +set -e + +echo "Waiting for PostgreSQL to be ready..." +until docker exec ore-benches-postgres pg_isready -U postgres > /dev/null 2>&1; do + sleep 1 +done + +echo "Dropping and recreating database..." +docker exec -i ore-benches-postgres psql -U postgres -d template1 -c "DROP DATABASE IF EXISTS postgres WITH (FORCE);" +docker exec -i ore-benches-postgres psql -U postgres -d template1 -c "CREATE DATABASE postgres;" + +echo "Database reset complete. Run 'mise run setup-db' to set up tables and data." +""" + +[tasks.setup-db] +description = "Set up the test database (create tables and load data)" +depends = ["postgres"] +run = """ +#!/usr/bin/env bash +set -e + +echo "Waiting for PostgreSQL to be ready..." +until docker exec ore-benches-postgres pg_isready -U postgres > /dev/null 2>&1; do + sleep 1 +done + +echo "Downloading EQL..." +curl -sLo /tmp/cipherstash-encrypt.sql https://github.com/cipherstash/encrypt-query-language/releases/latest/download/cipherstash-encrypt.sql + +echo "Installing EQL..." +docker exec -i ore-benches-postgres psql -v ON_ERROR_STOP=1 -U postgres -d postgres < /tmp/cipherstash-encrypt.sql + +echo "Creating tables..." +docker exec -i ore-benches-postgres psql -v ON_ERROR_STOP=1 -U postgres -d postgres < sql/schema.sql + +echo "Database setup complete!" +""" + +[tasks."bench:build"] +description = "Build all binaries in release mode" +run = """ +#!/usr/bin/env bash +set -e + +echo "Building binaries in release mode..." +cargo build --release +""" + +[tasks."bench:ingest:_run"] +description = "Internal: Run a generic ingest benchmark" +depends = ["bench:build"] +run = """ +#!/usr/bin/env bash +set -e + +BENCH_NAME="$1" + +if [ -z "$BENCH_NAME" ]; then + echo "Error: BENCH_NAME argument must be provided" + exit 1 +fi + +echo "Running $BENCH_NAME ingest benchmark..." +mise x -- hyperfine --export-json target/${BENCH_NAME}_hyperfine.json -L num_records 500,1000,10000 --runs 2 "NUM_RECORDS={num_records} ./target/release/$BENCH_NAME" + +echo "Combining results..." +./target/release/combine_benchmark "$BENCH_NAME" + +echo "Benchmark complete! Results written to results/ingest/${BENCH_NAME}_combined.json" +""" + +[tasks."bench:ingest:encrypt_int"] +description = "Run encrypt_int ingest benchmark and combine results" +run = "mise run bench:ingest:_run encrypt_int" + +[tasks."bench:ingest:encrypt_string"] +description = "Run encrypt_string ingest benchmark and combine results" +run = "mise run bench:ingest:_run encrypt_string" + +[tasks."bench:ingest:encrypt_json_small"] +description = "Run encrypt_json_small ingest benchmark and combine results" +run = "mise run bench:ingest:_run encrypt_json_small" + +[tasks."bench:ingest"] +description = "Run all ingest benchmarks sequentially" +depends = ["bench:ingest:encrypt_int", "bench:ingest:encrypt_string", "bench:ingest:encrypt_json_small"] + +[tasks."prepare:_table"] +description = "Internal: Prepare a table with target row count" +depends = ["postgres", "bench:build"] +run = """ +#!/usr/bin/env bash +set -e + +BASE_TABLE="$1" +BINARY_NAME="$2" +TARGET_ROWS="$3" + +if [ -z "$BASE_TABLE" ] || [ -z "$BINARY_NAME" ] || [ -z "$TARGET_ROWS" ]; then + echo "Error: BASE_TABLE, BINARY_NAME, and TARGET_ROWS arguments required" + echo "Usage: mise run prepare:_table " + exit 1 +fi + +# Validate TARGET_ROWS is one of the allowed values +case "$TARGET_ROWS" in + 10000|100000|1000000|10000000) + ;; + *) + echo "Error: TARGET_ROWS must be one of: 10000, 100000, 1000000, 10000000" + exit 1 + ;; +esac + +# Construct table name with suffix +TABLE_NAME="${BASE_TABLE}_${TARGET_ROWS}" + +echo "Waiting for PostgreSQL to be ready..." +until docker exec ore-benches-postgres pg_isready -U postgres > /dev/null 2>&1; do + sleep 1 +done + +echo "Counting rows in $TABLE_NAME table..." +CURRENT_ROWS=$(docker exec ore-benches-postgres psql -U postgres -d postgres -t -c "SELECT COUNT(*) FROM $TABLE_NAME;" | tr -d ' ') + +echo "Current rows: $CURRENT_ROWS" +echo "Target rows: $TARGET_ROWS" + +if [ "$CURRENT_ROWS" -ge "$TARGET_ROWS" ]; then + echo "Table already has $CURRENT_ROWS rows (>= $TARGET_ROWS). No action needed." + exit 0 +fi + +echo "Dropping indexes..." +docker exec -i ore-benches-postgres psql -U postgres -d postgres < sql/indexes/${TABLE_NAME}_down.sql + +ROWS_TO_INSERT=$((TARGET_ROWS - CURRENT_ROWS)) +echo "Inserting $ROWS_TO_INSERT additional rows..." +NUM_RECORDS=$ROWS_TO_INSERT TABLE_SUFFIX="_${TARGET_ROWS}" ./target/release/$BINARY_NAME + +echo "Creating indexes..." +docker exec -i ore-benches-postgres psql -U postgres -d postgres < sql/indexes/${TABLE_NAME}_up.sql + +FINAL_ROWS=$(docker exec ore-benches-postgres psql -U postgres -d postgres -t -c "SELECT COUNT(*) FROM $TABLE_NAME;" | tr -d ' ') +echo "Preparation complete! Final row count: $FINAL_ROWS" +""" + +[tasks."prepare:string_encrypted"] +description = "Prepare string_encrypted table with target row count" +run = "mise run prepare:_table string_encrypted encrypt_string $1" + +[tasks."prepare:integer_encrypted"] +description = "Prepare integer_encrypted table with target row count" +run = "mise run prepare:_table integer_encrypted encrypt_int $1" + +[tasks."bench:query:ore"] +description = "Run ORE query benchmark" +run = """ +#!/usr/bin/env bash +set -e + +TARGET_ROWS="$1" + +if [ -z "$TARGET_ROWS" ]; then + echo "Error: target row count argument required" + echo "Usage: mise run bench:query:ore " + exit 1 +fi + +if ! [[ "$TARGET_ROWS" =~ ^[0-9]+$ ]]; then + echo "Error: target row count must be a positive integer" + exit 1 +fi + +echo "Preparing integer_encrypted table with $TARGET_ROWS rows..." +mise run prepare:integer_encrypted "$TARGET_ROWS" + +echo "Cleaning old benchmark data..." +rm -rf target/criterion/ORE + +echo "Running ORE query benchmark..." +mkdir -p results/query +OUTPUT_FILE="results/query/ore_rows_${TARGET_ROWS}.json" +TARGET_ROWS="$TARGET_ROWS" cargo criterion --bench ore --message-format json > "$OUTPUT_FILE" + +echo "Benchmark complete! Results written to $OUTPUT_FILE" +""" + +[tasks."bench:query:match"] +description = "Run MATCH query benchmark" +run = """ +#!/usr/bin/env bash +set -e + +TARGET_ROWS="$1" + +if [ -z "$TARGET_ROWS" ]; then + echo "Error: target row count argument required" + echo "Usage: mise run bench:query:match " + exit 1 +fi + +if ! [[ "$TARGET_ROWS" =~ ^[0-9]+$ ]]; then + echo "Error: target row count must be a positive integer" + exit 1 +fi + +echo "Preparing string_encrypted table with $TARGET_ROWS rows..." +mise run prepare:string_encrypted "$TARGET_ROWS" + +echo "Cleaning old benchmark data..." +rm -rf target/criterion/MATCH + +echo "Running MATCH query benchmark..." +mkdir -p results/query +OUTPUT_FILE="results/query/match_rows_${TARGET_ROWS}.json" +TARGET_ROWS="$TARGET_ROWS" cargo criterion --bench match --message-format json > "$OUTPUT_FILE" + +echo "Benchmark complete! Results written to $OUTPUT_FILE" +""" + +[tasks."bench:query:exact"] +description = "Run EXACT query benchmark" +run = """ +#!/usr/bin/env bash +set -e + +TARGET_ROWS="$1" + +if [ -z "$TARGET_ROWS" ]; then + echo "Error: target row count argument required" + echo "Usage: mise run bench:query:exact " + exit 1 +fi + +if ! [[ "$TARGET_ROWS" =~ ^[0-9]+$ ]]; then + echo "Error: target row count must be a positive integer" + exit 1 +fi + +echo "Preparing string_encrypted table with $TARGET_ROWS rows..." +mise run prepare:string_encrypted "$TARGET_ROWS" + +echo "Cleaning old benchmark data..." +rm -rf target/criterion/EXACT + +echo "Running EXACT query benchmark..." +mkdir -p results/query +OUTPUT_FILE="results/query/exact_rows_${TARGET_ROWS}.json" +TARGET_ROWS="$TARGET_ROWS" cargo criterion --bench exact --message-format json > "$OUTPUT_FILE" + +echo "Benchmark complete! Results written to $OUTPUT_FILE" +""" + +[tasks."bench:query:all"] +description = "Run all query benchmarks with multiple row counts (10k, 100k, 1M, 10M)" +run = """ +#!/usr/bin/env bash +set -e + +ROW_COUNTS=(10000 100000 1000000 10000000) + +echo "========================================" +echo "Starting comprehensive benchmark suite" +echo "Row counts: ${ROW_COUNTS[*]}" +echo "Benchmarks: exact, match, ore" +echo "========================================" +echo "" + +START_TIME=$(date +%s) + +for ROWS in "${ROW_COUNTS[@]}"; do + echo "========================================" + echo "Running benchmarks with $ROWS rows" + echo "========================================" + echo "" + + echo "[1/3] Running EXACT benchmark with $ROWS rows..." + mise run bench:query:exact "$ROWS" + echo "" + + echo "[2/3] Running MATCH benchmark with $ROWS rows..." + mise run bench:query:match "$ROWS" + echo "" + + echo "[3/3] Running ORE benchmark with $ROWS rows..." + mise run bench:query:ore "$ROWS" + echo "" + + echo "Completed benchmarks for $ROWS rows" + echo "" +done + +END_TIME=$(date +%s) +ELAPSED=$((END_TIME - START_TIME)) +HOURS=$((ELAPSED / 3600)) +MINUTES=$(((ELAPSED % 3600) / 60)) +SECONDS=$((ELAPSED % 60)) + +echo "========================================" +echo "All benchmarks complete!" +echo "Total time: ${HOURS}h ${MINUTES}m ${SECONDS}s" +echo "Results saved in results/query/" +echo "========================================" +""" + +[tasks.report] +description = "Generate benchmark report from results" +run = """ +#!/usr/bin/env bash +set -e + +OUTPUT_FILE="${1:-report/BENCHMARK_REPORT.md}" + +echo "Generating benchmark report..." +python3 report_benchmarks.py --output "$OUTPUT_FILE" + +echo "" +echo "Report saved to: $OUTPUT_FILE" +""" diff --git a/report/BENCHMARK_REPORT.md b/report/BENCHMARK_REPORT.md new file mode 100644 index 0000000..6f22926 --- /dev/null +++ b/report/BENCHMARK_REPORT.md @@ -0,0 +1,472 @@ +# Benchmark Report + +This report summarizes the performance benchmarks for encrypted database operations. + +## Table of Contents + +1. [Ingest Throughput](#ingest-throughput) +2. [Query Performance](#query-performance) + - [EXACT Queries](#exact-queries) + - [MATCH Queries](#match-queries) + - [ORE Queries](#ore-queries) + +--- + +## Ingest Throughput + +This section measures the throughput of inserting encrypted records into the database. + +### Int + +Tests insertion of encrypted integer values. + +| Records | Throughput (records/sec) | Total Time | Avg Memory | +|---------|--------------------------|------------|------------| +| 500 | 544.83 | 0.92s | 15.25 MB | +| 1,000 | 1.11K | 0.90s | 17.83 MB | +| 10,000 | 1.34K | 7.48s | 20.34 MB | + +![Ingest Throughput - int](ingest_int_chart.png) + +### Json Small + +Tests insertion of small encrypted JSON objects. + +| Records | Throughput (records/sec) | Total Time | Avg Memory | +|---------|--------------------------|------------|------------| +| 500 | 565.55 | 0.88s | 18.70 MB | +| 1,000 | 1.45K | 0.69s | 27.47 MB | +| 10,000 | 2.22K | 4.51s | 45.33 MB | + +![Ingest Throughput - json_small](ingest_json_small_chart.png) + +### String + +Tests insertion of encrypted string values. + +| Records | Throughput (records/sec) | Total Time | Avg Memory | +|---------|--------------------------|------------|------------| +| 500 | 559.65 | 0.89s | 14.12 MB | +| 1,000 | 1.86K | 0.54s | 16.19 MB | +| 10,000 | 2.83K | 3.54s | 18.23 MB | + +![Ingest Throughput - string](ingest_string_chart.png) + +## Query Performance + +This section measures query performance across different data set sizes. Each query is tested with and without decryption of results. + +### EXACT Queries + +#### eql_cast + +**Description:** Exact match using EQL cast operator + +**SQL Query:** +```sql +SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1 +``` + +**Parameter:** `Bob Johnson` + +**Table: `string_encrypted_{rows}` with encrypted string values. Index: UNIQUE index on the encrypted value column.** + +**Indexes:** +```sql +CREATE INDEX +string_encrypted_10000_hash_index +ON string_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000_gin_index +ON string_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(value) +); + +CREATE INDEX +string_encrypted_10000_eql_index +ON string_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); +``` + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|-------------------------|---------------------------| +| 10,000 | ⚠️ 119.93ms | ⚠️ 122.15ms | +| 100,000 | ⚠️ 1.669s | ⚠️ 787.01ms | +| 1,000,000 | ⚠️ 7.827s | ⚠️ 7.836s | + +![Query Performance - EXACT/eql_cast](query_exact_eql_cast_chart.png) + +#### eql_hash + +**Description:** Exact match using EQL HMAC-256 hash function + +**SQL Query:** +```sql +SELECT value FROM {TABLE} WHERE eql_v2.hmac_256(value) = eql_v2.hmac_256($1::jsonb) LIMIT 1 +``` + +**Parameter:** `Bob Johnson` + +**Table: `string_encrypted_{rows}` with encrypted string values. Index: Hash-based unique index using `eql_v2.hmac_256`.** + +**Indexes:** +```sql +CREATE INDEX +string_encrypted_10000_hash_index +ON string_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000_gin_index +ON string_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(value) +); + +CREATE INDEX +string_encrypted_10000_eql_index +ON string_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); +``` + +| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|-------------------------|---------------------------| +| 10,000 | 410.44μs | 414.48μs | +| 100,000 | 395.17μs | 395.38μs | +| 1,000,000 | 399.96μs | 404.21μs | + +![Query Performance - EXACT/eql_hash](query_exact_eql_hash_chart.png) + +### MATCH Queries + +#### eql_bloom + +**Description:** Pattern matching using EQL bloom filter containment + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE eql_v2.bloom_filter(value) @> eql_v2.bloom_filter($1) LIMIT 10 +``` + +**Parameter:** `Johnson` + +**Table: `string_encrypted_{rows}` with encrypted string values. Index: Bloom filter index using `eql_v2.bloom_filter`. Query returns LIMIT 10 results.** + +**Indexes:** +```sql +CREATE INDEX +string_encrypted_10000_hash_index +ON string_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000_gin_index +ON string_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(value) +); + +CREATE INDEX +string_encrypted_10000_eql_index +ON string_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); +``` + +| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|-------------------------|---------------------------| +| 10,000 | 930.90μs | 63.38ms | +| 100,000 | 3.35ms | 68.21ms | +| 1,000,000 | 21.23ms | 83.97ms | + +![Query Performance - MATCH/eql_bloom](query_match_eql_bloom_chart.png) + +#### eql_cast_firstname + +**Description:** Pattern matching on first name using EQL cast and LIKE + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value LIKE $1 LIMIT 10 +``` + +**Parameter:** `Bob` + +**Table: `string_encrypted_{rows}` with encrypted string values. Index: MATCH index for substring searches. Query returns LIMIT 10 results.** + +**Indexes:** +```sql +CREATE INDEX +string_encrypted_10000_hash_index +ON string_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000_gin_index +ON string_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(value) +); + +CREATE INDEX +string_encrypted_10000_eql_index +ON string_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); +``` + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|-------------------------|---------------------------| +| 10,000 | ⚠️ 263.49ms | ⚠️ 321.93ms | +| 100,000 | ⚠️ 341.72ms | ⚠️ 401.96ms | +| 1,000,000 | ⚠️ 399.14ms | ⚠️ 450.21ms | + +![Query Performance - MATCH/eql_cast_firstname](query_match_eql_cast_firstname_chart.png) + +#### eql_cast_lastname + +**Description:** Pattern matching on last name using EQL cast and LIKE + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value LIKE $1 LIMIT 10 +``` + +**Parameter:** `Johnson` + +**Table: `string_encrypted_{rows}` with encrypted string values. Index: MATCH index for substring searches. Query returns LIMIT 10 results.** + +**Indexes:** +```sql +CREATE INDEX +string_encrypted_10000_hash_index +ON string_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000_gin_index +ON string_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(value) +); + +CREATE INDEX +string_encrypted_10000_eql_index +ON string_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); +``` + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|-------------------------|---------------------------| +| 10,000 | ⚠️ 146.33ms | ⚠️ 205.98ms | +| 100,000 | ⚠️ 119.51ms | ⚠️ 177.16ms | +| 1,000,000 | ⚠️ 127.20ms | ⚠️ 190.63ms | + +![Query Performance - MATCH/eql_cast_lastname](query_match_eql_cast_lastname_chart.png) + +### ORE Queries + +#### exact + +**Description:** Exact match query on encrypted integer + +**SQL Query:** +```sql +SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1 +``` + +**Parameter:** `5000` + +**Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. Index: ORE index supporting equality and range queries. Query returns LIMIT 1 result.** + +**Indexes:** +```sql +CREATE INDEX +integer_encrypted_10000_eql_index +ON integer_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); +``` + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|-------------------------|---------------------------| +| 10,000 | ⚠️ 276.65ms | ⚠️ 276.72ms | +| 100,000 | ⚠️ 1.858s | ⚠️ 1.868s | +| 1,000,000 | ⚠️ 18.466s | ⚠️ 18.618s | + +![Query Performance - ORE/exact](query_ore_exact_chart.png) + +#### range_gt_10 + +**Description:** Range query (greater than) returning 10 results + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 10 +``` + +**Parameter:** `5000` + +**Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. Index: ORE index supporting equality and range queries. Query: WHERE value > 5000 LIMIT 10.** + +**Indexes:** +```sql +CREATE INDEX +integer_encrypted_10000_eql_index +ON integer_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); +``` + +| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|-------------------------|---------------------------| +| 10,000 | 2.23ms | 60.19ms | +| 100,000 | 1.78ms | 63.88ms | +| 1,000,000 | 1.88ms | 66.87ms | + +![Query Performance - ORE/range_gt_10](query_ore_range_gt_10_chart.png) + +#### range_gt_100 + +**Description:** Range query (greater than) returning 100 results + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 100 +``` + +**Parameter:** `5000` + +**Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. Index: ORE index supporting equality and range queries. Query: WHERE value > 5000 LIMIT 100.** + +**Indexes:** +```sql +CREATE INDEX +integer_encrypted_10000_eql_index +ON integer_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); +``` + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|-------------------------|---------------------------| +| 10,000 | 13.67ms | ⚠️ 115.66ms | +| 100,000 | 12.56ms | ⚠️ 124.67ms | +| 1,000,000 | 13.08ms | ⚠️ 110.90ms | + +![Query Performance - ORE/range_gt_100](query_ore_range_gt_100_chart.png) + +#### range_lt_10 + +**Description:** Range query (less than) returning 10 results + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 10 +``` + +**Parameter:** `5000` + +**Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. Index: ORE index supporting equality and range queries. Query: WHERE value < 5000 LIMIT 10.** + +**Indexes:** +```sql +CREATE INDEX +integer_encrypted_10000_eql_index +ON integer_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); +``` + +| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|-------------------------|---------------------------| +| 10,000 | 1.92ms | 61.12ms | +| 100,000 | 1.93ms | 70.41ms | +| 1,000,000 | 2.56ms | 61.29ms | + +![Query Performance - ORE/range_lt_10](query_ore_range_lt_10_chart.png) + +#### range_lt_100 + +**Description:** Range query (less than) returning 100 results + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 100 +``` + +**Parameter:** `5000` + +**Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. Index: ORE index supporting equality and range queries. Query: WHERE value < 5000 LIMIT 100.** + +**Indexes:** +```sql +CREATE INDEX +integer_encrypted_10000_eql_index +ON integer_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); +``` + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|-------------------------|---------------------------| +| 10,000 | 10.82ms | ⚠️ 114.77ms | +| 100,000 | 12.85ms | ⚠️ 133.00ms | +| 1,000,000 | 12.27ms | ⚠️ 118.33ms | + +![Query Performance - ORE/range_lt_100](query_ore_range_lt_100_chart.png) + +#### range_lt_ordered_10 + +**Description:** Ordered range query (less than) with ORDER BY + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 ORDER BY value LIMIT 10 +``` + +**Parameter:** `5000` + +**Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. Index: ORE index supporting equality and range queries. Query: WHERE value < 5000 ORDER BY value LIMIT 10.** + +**Indexes:** +```sql +CREATE INDEX +integer_encrypted_10000_eql_index +ON integer_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); +``` + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|-------------------------|---------------------------| +| 10,000 | ⚠️ 542.65ms | ⚠️ 597.87ms | +| 100,000 | ⚠️ 5.422s | ⚠️ 5.483s | +| 1,000,000 | ⚠️ 62.364s | ⚠️ 66.031s | + +![Query Performance - ORE/range_lt_ordered_10](query_ore_range_lt_ordered_10_chart.png) + + +--- + +*Report generated by `report_benchmarks.py`* diff --git a/report/README.md b/report/README.md new file mode 100644 index 0000000..5d9820e --- /dev/null +++ b/report/README.md @@ -0,0 +1,23 @@ +# Benchmark Reports + +This directory contains generated benchmark reports and associated charts. + +## Files + +- `BENCHMARK_REPORT.md` - Main benchmark report (generated) +- `ingest_*_chart.png` - Ingest throughput charts (generated, requires matplotlib) +- `query_*_chart.png` - Query performance charts (generated, requires matplotlib) + +## Generating Reports + +To generate or update the report: + +```bash +mise run report +``` + +This will create/update `BENCHMARK_REPORT.md` and associated chart images in this directory. + +## Version Control + +These generated files are tracked in git to provide a historical record of benchmark performance over time. diff --git a/report/ingest_int_chart.png b/report/ingest_int_chart.png new file mode 100644 index 0000000..f3438f5 Binary files /dev/null and b/report/ingest_int_chart.png differ diff --git a/report/ingest_json_small_chart.png b/report/ingest_json_small_chart.png new file mode 100644 index 0000000..037ad2e Binary files /dev/null and b/report/ingest_json_small_chart.png differ diff --git a/report/ingest_string_chart.png b/report/ingest_string_chart.png new file mode 100644 index 0000000..f25b46e Binary files /dev/null and b/report/ingest_string_chart.png differ diff --git a/report/query_exact_eql_cast_chart.png b/report/query_exact_eql_cast_chart.png new file mode 100644 index 0000000..904be8c Binary files /dev/null and b/report/query_exact_eql_cast_chart.png differ diff --git a/report/query_exact_eql_hash_chart.png b/report/query_exact_eql_hash_chart.png new file mode 100644 index 0000000..6c7e069 Binary files /dev/null and b/report/query_exact_eql_hash_chart.png differ diff --git a/report/query_match_eql_bloom_chart.png b/report/query_match_eql_bloom_chart.png new file mode 100644 index 0000000..1702819 Binary files /dev/null and b/report/query_match_eql_bloom_chart.png differ diff --git a/report/query_match_eql_cast_firstname_chart.png b/report/query_match_eql_cast_firstname_chart.png new file mode 100644 index 0000000..4559f33 Binary files /dev/null and b/report/query_match_eql_cast_firstname_chart.png differ diff --git a/report/query_match_eql_cast_lastname_chart.png b/report/query_match_eql_cast_lastname_chart.png new file mode 100644 index 0000000..4c8e606 Binary files /dev/null and b/report/query_match_eql_cast_lastname_chart.png differ diff --git a/report/query_ore_exact_chart.png b/report/query_ore_exact_chart.png new file mode 100644 index 0000000..36d4b4f Binary files /dev/null and b/report/query_ore_exact_chart.png differ diff --git a/report/query_ore_range_gt_100_chart.png b/report/query_ore_range_gt_100_chart.png new file mode 100644 index 0000000..87b11db Binary files /dev/null and b/report/query_ore_range_gt_100_chart.png differ diff --git a/report/query_ore_range_gt_10_chart.png b/report/query_ore_range_gt_10_chart.png new file mode 100644 index 0000000..95ab307 Binary files /dev/null and b/report/query_ore_range_gt_10_chart.png differ diff --git a/report/query_ore_range_lt_100_chart.png b/report/query_ore_range_lt_100_chart.png new file mode 100644 index 0000000..81e51e9 Binary files /dev/null and b/report/query_ore_range_lt_100_chart.png differ diff --git a/report/query_ore_range_lt_10_chart.png b/report/query_ore_range_lt_10_chart.png new file mode 100644 index 0000000..ee42aaa Binary files /dev/null and b/report/query_ore_range_lt_10_chart.png differ diff --git a/report/query_ore_range_lt_ordered_10_chart.png b/report/query_ore_range_lt_ordered_10_chart.png new file mode 100644 index 0000000..144b097 Binary files /dev/null and b/report/query_ore_range_lt_ordered_10_chart.png differ diff --git a/report_benchmarks.py b/report_benchmarks.py new file mode 100755 index 0000000..35c7700 --- /dev/null +++ b/report_benchmarks.py @@ -0,0 +1,589 @@ +#!/usr/bin/env python3 +""" +Benchmark Report Generator + +Generates a comprehensive report from benchmark results including: +- Ingest throughput for int, json_small, and string tests +- Query performance charts across different data set sizes +""" + +import json +import sys +from pathlib import Path +from typing import Dict, List, Tuple, Optional +from dataclasses import dataclass +import argparse +import re + +try: + import matplotlib.pyplot as plt + import matplotlib + matplotlib.use('Agg') # Non-interactive backend + HAS_MATPLOTLIB = True +except ImportError: + HAS_MATPLOTLIB = False + print("Warning: matplotlib not available. Charts will be skipped.", file=sys.stderr) + print("Install with: pip3 install matplotlib", file=sys.stderr) + + +@dataclass +class IngestResult: + """Results from an ingest benchmark""" + bench_type: str + num_records: int + throughput: float + total_time: float + avg_memory_mb: float + + +@dataclass +class QueryResult: + """Results from a query benchmark""" + query_type: str # e.g., "EXACT", "MATCH", "ORE" + query_name: str # e.g., "eql_cast", "range_gt_10" + row_count: int + decrypt: bool + mean_ns: float + median_ns: float + + +class BenchmarkReporter: + def __init__(self, results_dir: Path, output_file: Path, sql_dir: Optional[Path] = None): + self.results_dir = results_dir + self.output_file = output_file + self.sql_dir = sql_dir or Path("sql") + self.ingest_results: List[IngestResult] = [] + self.query_results: List[QueryResult] = [] + self.index_cache: Dict[str, str] = {} # Cache for index SQL + + def load_ingest_results(self): + """Load ingest benchmark results""" + ingest_dir = self.results_dir / "ingest" + + for bench_type in ["int", "json_small", "string"]: + file_path = ingest_dir / f"encrypt_{bench_type}_combined.json" + + if not file_path.exists(): + print(f"Warning: {file_path} not found, skipping", file=sys.stderr) + continue + + with open(file_path) as f: + data = json.load(f) + + for result in data.get("results", []): + self.ingest_results.append(IngestResult( + bench_type=bench_type, + num_records=result["num_records"], + throughput=result["throughput_records_per_second"], + total_time=result["total_time_seconds"], + avg_memory_mb=result["average_memory_usage_mb"] + )) + + def load_query_results(self): + """Load query benchmark results from criterion JSON output""" + query_dir = self.results_dir / "query" + + for json_file in query_dir.glob("*.json"): + # Parse filename: {query_type}_rows_{count}.json + parts = json_file.stem.split("_rows_") + if len(parts) != 2: + continue + + query_type = parts[0].upper() # EXACT, MATCH, ORE + row_count = int(parts[1]) + + with open(json_file) as f: + for line in f: + line = line.strip() + if not line: + continue + + try: + data = json.loads(line) + except json.JSONDecodeError: + continue + + if data.get("reason") != "benchmark-complete": + continue + + # Parse benchmark ID: "QUERY_TYPE/query_variant/scenario/rows" + bench_id = data.get("id", "") + parts = bench_id.split("/") + + if len(parts) < 3: + continue + + # Determine if this is a decrypt variant + decrypt = "decrypt" in parts[1] + + # Get scenario name (e.g., "eql_cast", "range_gt_10") + scenario = parts[2] + + # Extract mean timing + mean_ns = data.get("mean", {}).get("estimate", 0) + median_ns = data.get("median", {}).get("estimate", 0) + + self.query_results.append(QueryResult( + query_type=query_type, + query_name=scenario, + row_count=row_count, + decrypt=decrypt, + mean_ns=mean_ns, + median_ns=median_ns + )) + + def format_time(self, ns: float, include_indicator: bool = True) -> str: + """Format nanoseconds into human-readable time with performance indicator + + Args: + ns: Time in nanoseconds + include_indicator: If True, adds emoji indicator for times > 100ms + """ + # Convert to milliseconds for threshold check + ms = ns / 1_000_000 + + # Format the time + if ns >= 1_000_000_000: + formatted = f"{ns / 1_000_000_000:.3f}s" + elif ns >= 1_000_000: + formatted = f"{ns / 1_000_000:.2f}ms" + elif ns >= 1_000: + formatted = f"{ns / 1_000:.2f}μs" + else: + formatted = f"{ns:.0f}ns" + + # Add indicator if time exceeds 100ms + if include_indicator and ms > 100: + return f"⚠️ {formatted}" + + return formatted + + def format_throughput(self, throughput: float) -> str: + """Format throughput with appropriate units""" + if throughput >= 1_000_000: + return f"{throughput / 1_000_000:.2f}M" + elif throughput >= 1_000: + return f"{throughput / 1_000:.2f}K" + else: + return f"{throughput:.2f}" + + def get_query_sql_and_param(self, query_type: str, query_name: str) -> Tuple[str, str]: + """Get the SQL query template and parameter value for a query""" + # Map from bench files + sql_map = { + "EXACT": { + "eql_cast": ( + "SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1", + "Bob Johnson" + ), + "eql_hash": ( + "SELECT value FROM {TABLE} WHERE eql_v2.hmac_256(value) = eql_v2.hmac_256($1::jsonb) LIMIT 1", + "Bob Johnson" + ) + }, + "MATCH": { + "eql_cast_firstname": ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value LIKE $1 LIMIT 10", + "Bob" + ), + "eql_cast_lastname": ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value LIKE $1 LIMIT 10", + "Johnson" + ), + "eql_bloom": ( + "SELECT id,value::jsonb FROM {TABLE} WHERE eql_v2.bloom_filter(value) @> eql_v2.bloom_filter($1) LIMIT 10", + "Johnson" + ) + }, + "ORE": { + "exact": ( + "SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1", + "5000" + ), + "range_gt_10": ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 10", + "5000" + ), + "range_gt_100": ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 100", + "5000" + ), + "range_lt_10": ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 10", + "5000" + ), + "range_lt_100": ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 100", + "5000" + ), + "range_lt_ordered_10": ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 ORDER BY value LIMIT 10", + "5000" + ) + } + } + + return sql_map.get(query_type, {}).get(query_name, ("", "")) + + def get_query_description(self, query_type: str, query_name: str) -> Tuple[str, str]: + """Get description and table info for a query""" + descriptions = { + "EXACT": { + "eql_cast": ( + "Exact match using EQL cast operator", + "Table: `string_encrypted_{rows}` with encrypted string values. " + "Index: UNIQUE index on the encrypted value column." + ), + "eql_hash": ( + "Exact match using EQL HMAC-256 hash function", + "Table: `string_encrypted_{rows}` with encrypted string values. " + "Index: Hash-based unique index using `eql_v2.hmac_256`." + ) + }, + "MATCH": { + "eql_cast_firstname": ( + "Pattern matching on first name using EQL cast and LIKE", + "Table: `string_encrypted_{rows}` with encrypted string values. " + "Index: MATCH index for substring searches. " + "Query returns LIMIT 10 results." + ), + "eql_cast_lastname": ( + "Pattern matching on last name using EQL cast and LIKE", + "Table: `string_encrypted_{rows}` with encrypted string values. " + "Index: MATCH index for substring searches. " + "Query returns LIMIT 10 results." + ), + "eql_bloom": ( + "Pattern matching using EQL bloom filter containment", + "Table: `string_encrypted_{rows}` with encrypted string values. " + "Index: Bloom filter index using `eql_v2.bloom_filter`. " + "Query returns LIMIT 10 results." + ) + }, + "ORE": { + "exact": ( + "Exact match query on encrypted integer", + "Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. " + "Index: ORE index supporting equality and range queries. " + "Query returns LIMIT 1 result." + ), + "range_gt_10": ( + "Range query (greater than) returning 10 results", + "Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. " + "Index: ORE index supporting equality and range queries. " + "Query: WHERE value > 5000 LIMIT 10." + ), + "range_gt_100": ( + "Range query (greater than) returning 100 results", + "Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. " + "Index: ORE index supporting equality and range queries. " + "Query: WHERE value > 5000 LIMIT 100." + ), + "range_lt_10": ( + "Range query (less than) returning 10 results", + "Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. " + "Index: ORE index supporting equality and range queries. " + "Query: WHERE value < 5000 LIMIT 10." + ), + "range_lt_100": ( + "Range query (less than) returning 100 results", + "Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. " + "Index: ORE index supporting equality and range queries. " + "Query: WHERE value < 5000 LIMIT 100." + ), + "range_lt_ordered_10": ( + "Ordered range query (less than) with ORDER BY", + "Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. " + "Index: ORE index supporting equality and range queries. " + "Query: WHERE value < 5000 ORDER BY value LIMIT 10." + ) + } + } + + return descriptions.get(query_type, {}).get(query_name, ("Unknown query", "")) + + def get_table_indexes(self, table_name: str) -> Optional[str]: + """Get index SQL for a table by reading from sql/indexes directory""" + # Check cache first + if table_name in self.index_cache: + return self.index_cache[table_name] + + # Try to find the index file + index_file = self.sql_dir / "indexes" / f"{table_name}_up.sql" + + if not index_file.exists(): + # Try without row count suffix (base table) + # e.g., string_encrypted_10000 -> string_encrypted + base_table = re.sub(r'_(\d+)$', '', table_name) + index_file = self.sql_dir / "indexes" / f"{base_table}_up.sql" + + if not index_file.exists(): + return None + + try: + with open(index_file) as f: + content = f.read().strip() + self.index_cache[table_name] = content + return content + except Exception as e: + print(f"Warning: Could not read index file {index_file}: {e}", file=sys.stderr) + return None + + def generate_report(self): + """Generate the full benchmark report""" + with open(self.output_file, 'w') as f: + self._write_header(f) + self._write_ingest_section(f) + self._write_query_sections(f) + self._write_footer(f) + + def _write_header(self, f): + f.write("# Benchmark Report\n\n") + f.write("This report summarizes the performance benchmarks for encrypted database operations.\n\n") + f.write("## Table of Contents\n\n") + f.write("1. [Ingest Throughput](#ingest-throughput)\n") + f.write("2. [Query Performance](#query-performance)\n") + + # Add subsections for each query type + query_types = set(r.query_type for r in self.query_results) + for qt in sorted(query_types): + f.write(f" - [{qt} Queries](#{qt.lower()}-queries)\n") + + f.write("\n---\n\n") + + def _write_ingest_section(self, f): + f.write("## Ingest Throughput\n\n") + f.write("This section measures the throughput of inserting encrypted records into the database.\n\n") + + # Group by bench_type + types = ["int", "json_small", "string"] + + for bench_type in types: + results = [r for r in self.ingest_results if r.bench_type == bench_type] + if not results: + continue + + # Sort by num_records + results.sort(key=lambda x: x.num_records) + + f.write(f"### {bench_type.replace('_', ' ').title()}\n\n") + + if bench_type == "int": + f.write("Tests insertion of encrypted integer values.\n\n") + elif bench_type == "json_small": + f.write("Tests insertion of small encrypted JSON objects.\n\n") + elif bench_type == "string": + f.write("Tests insertion of encrypted string values.\n\n") + + # Table + f.write("| Records | Throughput (records/sec) | Total Time | Avg Memory |\n") + f.write("|---------|--------------------------|------------|------------|\n") + + for r in results: + f.write(f"| {r.num_records:,} | {self.format_throughput(r.throughput)} | " + f"{r.total_time:.2f}s | {r.avg_memory_mb:.2f} MB |\n") + + f.write("\n") + + # Generate chart if matplotlib is available + if HAS_MATPLOTLIB: + chart_path = self.output_file.parent / f"ingest_{bench_type}_chart.png" + self._create_ingest_chart(results, bench_type, chart_path) + f.write(f"![Ingest Throughput - {bench_type}]({chart_path.name})\n\n") + + def _create_ingest_chart(self, results: List[IngestResult], bench_type: str, output_path: Path): + """Create a bar chart for ingest throughput""" + fig, ax = plt.subplots(figsize=(10, 6)) + + records = [r.num_records for r in results] + throughput = [r.throughput for r in results] + + ax.bar(range(len(records)), throughput, color='steelblue') + ax.set_xlabel('Number of Records') + ax.set_ylabel('Throughput (records/sec)') + ax.set_title(f'Ingest Throughput - {bench_type.replace("_", " ").title()}') + ax.set_xticks(range(len(records))) + ax.set_xticklabels([f"{r:,}" for r in records]) + ax.grid(axis='y', alpha=0.3) + + plt.tight_layout() + plt.savefig(output_path, dpi=100, bbox_inches='tight') + plt.close() + + def _write_query_sections(self, f): + f.write("## Query Performance\n\n") + f.write("This section measures query performance across different data set sizes. " + "Each query is tested with and without decryption of results.\n\n") + + # Group by query type (EXACT, MATCH, ORE) + query_types = sorted(set(r.query_type for r in self.query_results)) + + for query_type in query_types: + self._write_query_type_section(f, query_type) + + def _write_query_type_section(self, f, query_type: str): + f.write(f"### {query_type} Queries\n\n") + + # Get all unique query names for this type + type_results = [r for r in self.query_results if r.query_type == query_type] + query_names = sorted(set(r.query_name for r in type_results)) + + for query_name in query_names: + self._write_query_subsection(f, query_type, query_name) + + def _write_query_subsection(self, f, query_type: str, query_name: str): + # Get results for this specific query + results = [r for r in self.query_results + if r.query_type == query_type and r.query_name == query_name] + + if not results: + return + + # Sort by row count + results.sort(key=lambda x: (x.row_count, x.decrypt)) + + # Get description + description, table_info = self.get_query_description(query_type, query_name) + sql_query, param = self.get_query_sql_and_param(query_type, query_name) + + f.write(f"#### {query_name}\n\n") + f.write(f"**Description:** {description}\n\n") + + # Add SQL query and parameter + if sql_query: + f.write(f"**SQL Query:**\n```sql\n{sql_query}\n```\n\n") + f.write(f"**Parameter:** `{param}`\n\n") + + f.write(f"**{table_info}**\n\n") + + # Add index information for one of the row counts (they all use same indexes) + if results: + # Determine table name based on query type + sample_row_count = results[0].row_count + if query_type in ["EXACT", "MATCH"]: + table_name = f"string_encrypted_{sample_row_count}" + elif query_type == "ORE": + table_name = f"integer_encrypted_{sample_row_count}" + else: + table_name = "" + + if table_name: + indexes_sql = self.get_table_indexes(table_name) + if indexes_sql: + f.write(f"**Indexes:**\n```sql\n{indexes_sql}\n```\n\n") + + # Create table with legend if any results exceed 100ms + has_slow_queries = any((r.mean_ns / 1_000_000) > 100 for r in results) + + if has_slow_queries: + f.write("*⚠️ = Query time exceeds 100ms*\n\n") + + f.write("| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) |\n") + f.write("|---------------|-------------------------|---------------------------|\n") + + # Group by row_count + row_counts = sorted(set(r.row_count for r in results)) + + for row_count in row_counts: + no_decrypt = next((r for r in results if r.row_count == row_count and not r.decrypt), None) + with_decrypt = next((r for r in results if r.row_count == row_count and r.decrypt), None) + + no_decrypt_str = self.format_time(no_decrypt.mean_ns) if no_decrypt else "N/A" + with_decrypt_str = self.format_time(with_decrypt.mean_ns) if with_decrypt else "N/A" + + f.write(f"| {row_count:,} | {no_decrypt_str} | {with_decrypt_str} |\n") + + f.write("\n") + + # Generate chart if matplotlib is available + if HAS_MATPLOTLIB and len(row_counts) > 1: + chart_path = self.output_file.parent / f"query_{query_type.lower()}_{query_name}_chart.png" + self._create_query_chart(results, query_type, query_name, chart_path) + f.write(f"![Query Performance - {query_type}/{query_name}]({chart_path.name})\n\n") + + def _create_query_chart(self, results: List[QueryResult], query_type: str, + query_name: str, output_path: Path): + """Create a line chart for query performance""" + fig, ax = plt.subplots(figsize=(12, 6)) + + # Separate no-decrypt and with-decrypt results + row_counts = sorted(set(r.row_count for r in results)) + + no_decrypt_times = [] + with_decrypt_times = [] + + for row_count in row_counts: + no_decrypt = next((r for r in results if r.row_count == row_count and not r.decrypt), None) + with_decrypt = next((r for r in results if r.row_count == row_count and r.decrypt), None) + + # Convert to milliseconds for better readability + no_decrypt_times.append(no_decrypt.mean_ns / 1_000_000 if no_decrypt else None) + with_decrypt_times.append(with_decrypt.mean_ns / 1_000_000 if with_decrypt else None) + + # Plot lines + if any(t is not None for t in no_decrypt_times): + ax.plot(row_counts, no_decrypt_times, marker='o', label='Without Decryption', linewidth=2) + + if any(t is not None for t in with_decrypt_times): + ax.plot(row_counts, with_decrypt_times, marker='s', label='With Decryption', linewidth=2) + + ax.set_xlabel('Data Set Size (rows)', fontsize=12) + ax.set_ylabel('Query Time (ms)', fontsize=12) + ax.set_title(f'{query_type} - {query_name}', fontsize=14, fontweight='bold') + ax.set_xscale('log') + ax.grid(True, alpha=0.3) + ax.legend(fontsize=10) + + # Format x-axis labels + ax.set_xticks(row_counts) + ax.set_xticklabels([f"{r:,}" for r in row_counts]) + + plt.tight_layout() + plt.savefig(output_path, dpi=100, bbox_inches='tight') + plt.close() + + def _write_footer(self, f): + f.write("\n---\n\n") + f.write("*Report generated by `report_benchmarks.py`*\n") + + +def main(): + parser = argparse.ArgumentParser(description="Generate benchmark report") + parser.add_argument("--results-dir", type=Path, default=Path("results"), + help="Directory containing benchmark results (default: results)") + parser.add_argument("--sql-dir", type=Path, default=Path("sql"), + help="Directory containing SQL schema and index files (default: sql)") + parser.add_argument("--output", "-o", type=Path, default=Path("report/BENCHMARK_REPORT.md"), + help="Output file path (default: report/BENCHMARK_REPORT.md)") + + args = parser.parse_args() + + if not args.results_dir.exists(): + print(f"Error: Results directory '{args.results_dir}' does not exist", file=sys.stderr) + sys.exit(1) + + # Create output directory if it doesn't exist + args.output.parent.mkdir(parents=True, exist_ok=True) + + reporter = BenchmarkReporter(args.results_dir, args.output, args.sql_dir) + + print("Loading ingest results...") + reporter.load_ingest_results() + print(f" Found {len(reporter.ingest_results)} ingest results") + + print("Loading query results...") + reporter.load_query_results() + print(f" Found {len(reporter.query_results)} query results") + + print(f"Generating report: {args.output}") + reporter.generate_report() + + print(f"\n✓ Report generated successfully: {args.output}") + + if not HAS_MATPLOTLIB: + print("\nNote: Charts were not generated. Install matplotlib to enable charts:") + print(" pip3 install matplotlib") + + +if __name__ == "__main__": + main() diff --git a/results/ingest/encrypt_int_combined.json b/results/ingest/encrypt_int_combined.json new file mode 100644 index 0000000..5821dad --- /dev/null +++ b/results/ingest/encrypt_int_combined.json @@ -0,0 +1,42 @@ +{ + "metadata": { + "timestamp": "2026-01-17T04:29:17.128696+00:00", + "rust_version": "rustc 1.92.0 (ded5c06cf 2025-12-08)", + "postgres_version": "psql (PostgreSQL) 17.2 (Debian 17.2-1.pgdg120+1)", + "host_info": { + "os": "macOS", + "cpu_model": "Apple M1 Max", + "cpu_cores": 10, + "total_memory_gb": 64.0 + } + }, + "results": [ + { + "num_records": 500, + "total_time_seconds": 0.91770989926, + "total_records": 500, + "throughput_records_per_second": 544.8344846265443, + "average_memory_usage_bytes": 15990784, + "average_memory_usage_mb": 15.25, + "num_runs": 2 + }, + { + "num_records": 1000, + "total_time_seconds": 0.89783371126, + "total_records": 1000, + "throughput_records_per_second": 1113.7919945071144, + "average_memory_usage_bytes": 18694144, + "average_memory_usage_mb": 17.828125, + "num_runs": 2 + }, + { + "num_records": 10000, + "total_time_seconds": 7.47776600326, + "total_records": 10000, + "throughput_records_per_second": 1337.2977966468072, + "average_memory_usage_bytes": 21331968, + "average_memory_usage_mb": 20.34375, + "num_runs": 2 + } + ] +} \ No newline at end of file diff --git a/results/ingest/encrypt_json_small_combined.json b/results/ingest/encrypt_json_small_combined.json new file mode 100644 index 0000000..b833253 --- /dev/null +++ b/results/ingest/encrypt_json_small_combined.json @@ -0,0 +1,42 @@ +{ + "metadata": { + "timestamp": "2026-01-17T04:28:56.732565+00:00", + "rust_version": "rustc 1.92.0 (ded5c06cf 2025-12-08)", + "postgres_version": "psql (PostgreSQL) 17.2 (Debian 17.2-1.pgdg120+1)", + "host_info": { + "os": "macOS", + "cpu_model": "Apple M1 Max", + "cpu_cores": 10, + "total_memory_gb": 64.0 + } + }, + "results": [ + { + "num_records": 500, + "total_time_seconds": 0.88409081262, + "total_records": 500, + "throughput_records_per_second": 565.5527609412112, + "average_memory_usage_bytes": 19611648, + "average_memory_usage_mb": 18.703125, + "num_runs": 2 + }, + { + "num_records": 1000, + "total_time_seconds": 0.68817570812, + "total_records": 1000, + "throughput_records_per_second": 1453.1172608981803, + "average_memory_usage_bytes": 28803072, + "average_memory_usage_mb": 27.46875, + "num_runs": 2 + }, + { + "num_records": 10000, + "total_time_seconds": 4.51195397912, + "total_records": 10000, + "throughput_records_per_second": 2216.3346626045095, + "average_memory_usage_bytes": 47529984, + "average_memory_usage_mb": 45.328125, + "num_runs": 2 + } + ] +} \ No newline at end of file diff --git a/results/ingest/encrypt_string_combined.json b/results/ingest/encrypt_string_combined.json new file mode 100644 index 0000000..99de5f3 --- /dev/null +++ b/results/ingest/encrypt_string_combined.json @@ -0,0 +1,42 @@ +{ + "metadata": { + "timestamp": "2026-01-17T04:29:08.757747+00:00", + "rust_version": "rustc 1.92.0 (ded5c06cf 2025-12-08)", + "postgres_version": "psql (PostgreSQL) 17.2 (Debian 17.2-1.pgdg120+1)", + "host_info": { + "os": "macOS", + "cpu_model": "Apple M1 Max", + "cpu_cores": 10, + "total_memory_gb": 64.0 + } + }, + "results": [ + { + "num_records": 500, + "total_time_seconds": 0.89342341718, + "total_records": 500, + "throughput_records_per_second": 559.6450578586793, + "average_memory_usage_bytes": 14811136, + "average_memory_usage_mb": 14.125, + "num_runs": 2 + }, + { + "num_records": 1000, + "total_time_seconds": 0.5364343956800001, + "total_records": 1000, + "throughput_records_per_second": 1864.160851826756, + "average_memory_usage_bytes": 16973824, + "average_memory_usage_mb": 16.1875, + "num_runs": 2 + }, + { + "num_records": 10000, + "total_time_seconds": 3.53578697968, + "total_records": 10000, + "throughput_records_per_second": 2828.224680239371, + "average_memory_usage_bytes": 19111936, + "average_memory_usage_mb": 18.2265625, + "num_runs": 2 + } + ] +} \ No newline at end of file diff --git a/results/query/exact_rows_10000.json b/results/query/exact_rows_10000.json new file mode 100644 index 0000000..9cd7f03 --- /dev/null +++ b/results/query/exact_rows_10000.json @@ -0,0 +1,5 @@ +{"reason":"benchmark-complete","id":"EXACT/exact/eql_cast/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT/exact_eql_cast_10000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[118826833.0,238982750.0,359795292.0,483753333.0,597647083.0,724623417.0,840462584.0,955748750.0,1083499625.0,1199220292.0],"unit":"ns","throughput":[],"typical":{"estimate":120052195.04155844,"lower_bound":119747021.46097562,"upper_bound":120382362.11947724,"unit":"ns"},"mean":{"estimate":119933384.49507937,"lower_bound":119556215.01785715,"upper_bound":120316607.24238889,"unit":"ns"},"median":{"estimate":119926896.6,"lower_bound":119491375.0,"upper_bound":120418326.46428572,"unit":"ns"},"median_abs_dev":{"estimate":662592.0530216307,"lower_bound":56400.475158682566,"upper_bound":1089517.8720071912,"unit":"ns"},"slope":{"estimate":120052195.04155844,"lower_bound":119747021.46097562,"upper_bound":120382362.11947724,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_cast/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT/exact_decrypt_eql_cast_10000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[120773334.0,251015541.0,380783666.0,503314667.0,616267750.0,726498292.0,835808083.0,961445416.0,1074176667.0,1191531042.0],"unit":"ns","throughput":[],"typical":{"estimate":120373669.91168831,"lower_bound":119626541.17181467,"upper_bound":122123286.66824645,"unit":"ns"},"mean":{"estimate":122146215.74976191,"lower_bound":120479997.54476193,"upper_bound":123964555.810625,"unit":"ns"},"median":{"estimate":120928191.33333334,"lower_bound":119401154.71428572,"upper_bound":125507770.5,"unit":"ns"},"median_abs_dev":{"estimate":2483588.811347497,"lower_bound":237880.38590177894,"upper_bound":4570660.200979549,"unit":"ns"},"slope":{"estimate":120373669.91168831,"lower_bound":119626541.17181467,"upper_bound":122123286.66824645,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact/eql_hash/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT/exact_eql_hash_10000","iteration_count":[219,438,657,876,1095,1314,1533,1752,1971,2190],"measured_values":[85865417.0,179477334.0,270862542.0,354126958.0,443473708.0,548717750.0,643415292.0,720024209.0,837525042.0,893248375.0],"unit":"ns","throughput":[],"typical":{"estimate":414136.27974856197,"lower_bound":408610.4492960426,"upper_bound":420140.90834268136,"unit":"ns"},"mean":{"estimate":410444.61613883456,"lower_bound":404866.79594748863,"upper_bound":415700.971950424,"unit":"ns"},"median":{"estimate":410369.16238584474,"lower_bound":404998.8200913242,"upper_bound":417593.4170471842,"unit":"ns"},"median_abs_dev":{"estimate":8513.82027867822,"lower_bound":1857.8094697570023,"upper_bound":15813.251868836272,"unit":"ns"},"slope":{"estimate":414136.27974856197,"lower_bound":408610.4492960426,"upper_bound":420140.90834268136,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_hash/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT/exact_decrypt_eql_hash_10000","iteration_count":[214,428,642,856,1070,1284,1498,1712,1926,2140],"measured_values":[93314667.0,182802958.0,256688167.0,355292458.0,458942875.0,506505375.0,614097875.0,709556250.0,790326250.0,874334542.0],"unit":"ns","throughput":[],"typical":{"estimate":410429.8863454303,"lower_bound":405808.2088070459,"upper_bound":415510.32154488814,"unit":"ns"},"mean":{"estimate":414475.88851320284,"lower_bound":406924.0893602582,"upper_bound":422211.6244193647,"unit":"ns"},"median":{"estimate":412403.1752985462,"lower_bound":404885.4910992434,"upper_bound":427109.71495327103,"unit":"ns"},"median_abs_dev":{"estimate":12166.958396758124,"lower_bound":1318.3139635423447,"upper_bound":23122.229268540406,"unit":"ns"},"slope":{"estimate":410429.8863454303,"lower_bound":405808.2088070459,"upper_bound":415510.32154488814,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"EXACT","benchmarks":["EXACT/exact/eql_cast/10000","EXACT/exact_decrypt/eql_cast/10000","EXACT/exact/eql_hash/10000","EXACT/exact_decrypt/eql_hash/10000"],"report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT"} diff --git a/results/query/exact_rows_100000.json b/results/query/exact_rows_100000.json new file mode 100644 index 0000000..f77387c --- /dev/null +++ b/results/query/exact_rows_100000.json @@ -0,0 +1,5 @@ +{"reason":"benchmark-complete","id":"EXACT/exact/eql_cast/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT/exact_eql_cast_100000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[2226706583.0,2232892584.0,2268101083.0,2246566500.0,2264623000.0,2297535292.0,792799084.0,789093083.0,786227042.0,786248750.0],"unit":"ns","throughput":[],"typical":{"estimate":1669079300.1,"lower_bound":1226363034.7475,"upper_bound":2109575945.35,"unit":"ns"},"mean":{"estimate":1669079300.1,"lower_bound":1226363034.7475,"upper_bound":2109575945.35,"unit":"ns"},"median":{"estimate":2229799583.5,"lower_bound":789093083.0,"upper_bound":2264623000.0,"unit":"ns"},"median_abs_dev":{"estimate":78605380.89487553,"lower_bound":2747258.492526412,"upper_bound":1082533528.856188,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":1.0821770710920071,"lower_bound":0.5317507124767805,"upper_bound":1.6322918963249116,"unit":"%"},"median":{"estimate":1.8131021075166807,"lower_bound":-0.01080120365119941,"upper_bound":1.8556867350680801,"unit":"%"},"change":"Regressed"}} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_cast/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT/exact_decrypt_eql_cast_100000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[785234375.0,786807875.0,789513792.0,786937083.0,785404708.0,788597542.0,786320000.0,787885709.0,786388458.0,786983125.0],"unit":"ns","throughput":[],"typical":{"estimate":787007266.7,"lower_bound":786254766.0775,"upper_bound":787824404.3,"unit":"ns"},"mean":{"estimate":787007266.7,"lower_bound":786254766.0775,"upper_bound":787824404.3,"unit":"ns"},"median":{"estimate":786872479.0,"lower_bound":785896583.0,"upper_bound":787885709.0,"unit":"ns"},"median_abs_dev":{"estimate":1160660.0610941648,"lower_bound":129912.82269358635,"upper_bound":2366847.802180052,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.011438205517971811,"lower_bound":-0.018382542818075047,"upper_bound":-0.006952975280970615,"unit":"%"},"median":{"estimate":-0.008080558716772934,"lower_bound":-0.011726210000173043,"upper_bound":-0.0060771350544630565,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"EXACT/exact/eql_hash/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT/exact_eql_hash_100000","iteration_count":[228,456,684,912,1140,1368,1596,1824,2052,2280],"measured_values":[97675833.0,177415250.0,267972708.0,355621708.0,451815291.0,529358709.0,627333041.0,698861042.0,818122750.0,899109084.0],"unit":"ns","throughput":[],"typical":{"estimate":392464.74380268855,"lower_bound":387490.280285254,"upper_bound":396186.4823717949,"unit":"ns"},"mean":{"estimate":395172.238151281,"lower_bound":389361.4155378115,"upper_bound":403437.82070346,"unit":"ns"},"median":{"estimate":392419.390037594,"lower_bound":388447.1019736842,"upper_bound":396520.6933723197,"unit":"ns"},"median_abs_dev":{"estimate":5382.336006023391,"lower_bound":1907.457203504301,"upper_bound":11264.70033507735,"unit":"ns"},"slope":{"estimate":392464.74380268855,"lower_bound":387490.280285254,"upper_bound":396186.4823717949,"unit":"ns"},"change":{"mean":{"estimate":0.0038309686175277413,"lower_bound":-0.03543929795740816,"upper_bound":0.04999583557512697,"unit":"%"},"median":{"estimate":-0.012129107638038539,"lower_bound":-0.056227049069459745,"upper_bound":0.05752458802684912,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_hash/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT/exact_decrypt_eql_hash_100000","iteration_count":[230,460,690,920,1150,1380,1610,1840,2070,2300],"measured_values":[88908083.0,189682917.0,248279834.0,358953708.0,466513750.0,548206625.0,646396000.0,765311417.0,823069083.0,889971250.0],"unit":"ns","throughput":[],"typical":{"estimate":397801.62997176737,"lower_bound":390092.8003488227,"upper_bound":406877.01083299477,"unit":"ns"},"mean":{"estimate":395379.95311853004,"lower_bound":385310.46172619046,"upper_bound":404065.16614130436,"unit":"ns"},"median":{"estimate":397434.54601449275,"lower_bound":386944.02173913043,"upper_bound":406921.1830745342,"unit":"ns"},"median_abs_dev":{"estimate":13877.216329717108,"lower_bound":2676.2347664004224,"upper_bound":25042.54445241682,"unit":"ns"},"slope":{"estimate":397801.62997176737,"lower_bound":390092.8003488227,"upper_bound":406877.01083299477,"unit":"ns"},"change":{"mean":{"estimate":-0.1657708077966994,"lower_bound":-0.2069057858039744,"upper_bound":-0.12596233095501927,"unit":"%"},"median":{"estimate":-0.13056625672198086,"lower_bound":-0.21456575328027727,"upper_bound":-0.1005070356060741,"unit":"%"},"change":"Improved"}} +{"reason":"group-complete","group_name":"EXACT","benchmarks":["EXACT/exact_decrypt/eql_hash/1000000","EXACT/exact/eql_hash/1000000","EXACT/exact_decrypt/eql_hash/10000","EXACT/exact_decrypt/eql_cast/10000","EXACT/exact/eql_cast/10000","EXACT/exact_decrypt/eql_cast/1000000","EXACT/exact/eql_hash/10000","EXACT/exact/eql_cast/1000000","EXACT/exact/eql_cast/100000","EXACT/exact_decrypt/eql_cast/100000","EXACT/exact/eql_hash/100000","EXACT/exact_decrypt/eql_hash/100000"],"report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT"} diff --git a/results/query/exact_rows_1000000.json b/results/query/exact_rows_1000000.json new file mode 100644 index 0000000..b975915 --- /dev/null +++ b/results/query/exact_rows_1000000.json @@ -0,0 +1,5 @@ +{"reason":"benchmark-complete","id":"EXACT/exact/eql_cast/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT/exact_eql_cast_1000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[7794910917.0,7847044333.0,7826574083.0,7846632750.0,7850080958.0,7778334209.0,7831018958.0,7832623500.0,7823451084.0,7841608250.0],"unit":"ns","throughput":[],"typical":{"estimate":7827227904.2,"lower_bound":7812460171.764999,"upper_bound":7839756729.1,"unit":"ns"},"mean":{"estimate":7827227904.2,"lower_bound":7812460171.764999,"upper_bound":7839756729.1,"unit":"ns"},"median":{"estimate":7831821229.0,"lower_bound":7810742500.0,"upper_bound":7846632750.0,"unit":"ns"},"median_abs_dev":{"estimate":18234898.86086583,"lower_bound":2861263.017502427,"upper_bound":34915321.301329136,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.06580308882706754,"lower_bound":-0.13044208181724798,"upper_bound":-0.00711368718855289,"unit":"%"},"median":{"estimate":-0.006990923816915573,"lower_bound":-0.10426205723839044,"upper_bound":-0.0002419052399255106,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_cast/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT/exact_decrypt_eql_cast_1000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[7892146708.0,7845590042.0,7787141334.0,7876417250.0,7833345250.0,7805187833.0,7798594875.0,7858726666.0,7837164459.0,7827918459.0],"unit":"ns","throughput":[],"typical":{"estimate":7836223287.6,"lower_bound":7816715978.085,"upper_bound":7856038262.4,"unit":"ns"},"mean":{"estimate":7836223287.6,"lower_bound":7816715978.085,"upper_bound":7856038262.4,"unit":"ns"},"median":{"estimate":7835254854.5,"lower_bound":7805187833.0,"upper_bound":7861003646.0,"unit":"ns"},"median_abs_dev":{"estimate":39688336.19829118,"lower_bound":6854059.678316116,"upper_bound":58541789.111575484,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.06379454403335438,"lower_bound":-0.12979460258953904,"upper_bound":-0.008264883902907881,"unit":"%"},"median":{"estimate":-0.013995900188117916,"lower_bound":-0.10087076805157302,"upper_bound":-0.0021169777977717574,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"EXACT/exact/eql_hash/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT/exact_eql_hash_1000000","iteration_count":[242,484,726,968,1210,1452,1694,1936,2178,2420],"measured_values":[112582750.0,187592792.0,284154333.0,374796875.0,488359875.0,567604833.0,688413875.0,756858917.0,824551417.0,962653791.0],"unit":"ns","throughput":[],"typical":{"estimate":392917.423312225,"lower_bound":385307.9026706972,"upper_bound":400099.82387718046,"unit":"ns"},"mean":{"estimate":399960.1914759609,"lower_bound":389007.2664805522,"upper_bound":416239.8739998279,"unit":"ns"},"median":{"estimate":391168.3380681818,"lower_bound":387588.4132231405,"upper_bound":403603.20247933886,"unit":"ns"},"median_abs_dev":{"estimate":7860.721626787294,"lower_bound":359.33291572799925,"upper_bound":20302.746926207063,"unit":"ns"},"slope":{"estimate":392917.423312225,"lower_bound":385307.9026706972,"upper_bound":400099.82387718046,"unit":"ns"},"change":{"mean":{"estimate":-0.06166549964054446,"lower_bound":-0.09194162191101579,"upper_bound":-0.02172591691090822,"unit":"%"},"median":{"estimate":-0.07903392802485731,"lower_bound":-0.09762779181843995,"upper_bound":-0.04563441280126179,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_hash/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT/exact_decrypt_eql_hash_1000000","iteration_count":[229,458,687,916,1145,1374,1603,1832,2061,2290],"measured_values":[89273333.0,179984167.0,275245500.0,368231625.0,474885000.0,600276208.0,646071708.0,737296208.0,837799667.0,899969958.0],"unit":"ns","throughput":[],"typical":{"estimate":404749.67524527875,"lower_bound":397595.50098925346,"upper_bound":415779.13877354196,"unit":"ns"},"mean":{"estimate":404209.03466867685,"lower_bound":397240.2340412074,"upper_bound":413092.51304429193,"unit":"ns"},"median":{"estimate":402226.92631004367,"lower_bound":392999.98165938864,"upper_bound":408892.9220212102,"unit":"ns"},"median_abs_dev":{"estimate":10008.702524027629,"lower_bound":770.6024931967961,"upper_bound":17797.001524214735,"unit":"ns"},"slope":{"estimate":404749.67524527875,"lower_bound":397595.50098925346,"upper_bound":415779.13877354196,"unit":"ns"},"change":{"mean":{"estimate":-0.04194576318258125,"lower_bound":-0.06294309007153405,"upper_bound":-0.017708831519658654,"unit":"%"},"median":{"estimate":-0.04645034105982293,"lower_bound":-0.0695802079401262,"upper_bound":-0.02744686726729806,"unit":"%"},"change":"Improved"}} +{"reason":"group-complete","group_name":"EXACT","benchmarks":["EXACT/exact_decrypt/eql_hash/10000","EXACT/exact_decrypt/eql_hash/100000","EXACT/exact_decrypt/eql_cast/10000","EXACT/exact_decrypt/eql_cast/100000","EXACT/exact/eql_cast/100000","EXACT/exact/eql_cast/10000","EXACT/exact/eql_hash/100000","EXACT/exact/eql_hash/10000","EXACT/exact/eql_cast/1000000","EXACT/exact_decrypt/eql_cast/1000000","EXACT/exact/eql_hash/1000000","EXACT/exact_decrypt/eql_hash/1000000"],"report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/EXACT"} diff --git a/results/query/match_rows_10000.json b/results/query/match_rows_10000.json new file mode 100644 index 0000000..6086fd3 --- /dev/null +++ b/results/query/match_rows_10000.json @@ -0,0 +1,7 @@ +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_firstname/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_eql_cast_firstname_10000","iteration_count":[2,2,2,2,2,2,2,2,2,2],"measured_values":[549967209.0,522408792.0,522610916.0,533452125.0,522659958.0,530380291.0,523578458.0,521967291.0,519652958.0,523130542.0],"unit":"ns","throughput":[],"typical":{"estimate":263490427.0,"lower_bound":261281130.88375,"upper_bound":266521191.19375002,"unit":"ns"},"mean":{"estimate":263490427.0,"lower_bound":261281130.88375,"upper_bound":266521191.19375002,"unit":"ns"},"median":{"estimate":261447625.0,"lower_bound":261144551.75,"upper_bound":265190145.5,"unit":"ns"},"median_abs_dev":{"estimate":597179.0379479527,"lower_bound":111272.09322452545,"upper_bound":5475735.408586264,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":0.00411839240065226,"lower_bound":-0.005103544058760912,"upper_bound":0.01625680424275525,"unit":"%"},"median":{"estimate":-0.0024254769195483084,"lower_bound":-0.0066926737032416694,"upper_bound":0.011036581585437633,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_firstname/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_firstname_10000","iteration_count":[2,2,2,2,2,2,2,2,2,2],"measured_values":[640625000.0,640482958.0,644418458.0,657455583.0,639379916.0,656839458.0,641870417.0,638167917.0,639747000.0,639686167.0],"unit":"ns","throughput":[],"typical":{"estimate":321933643.7,"lower_bound":320069153.8625,"upper_bound":324295331.1,"unit":"ns"},"mean":{"estimate":321933643.7,"lower_bound":320069153.8625,"upper_bound":324295331.1,"unit":"ns"},"median":{"estimate":320276989.5,"lower_bound":319781729.0,"upper_bound":324677468.75,"unit":"ns"},"median_abs_dev":{"estimate":923104.1792616248,"lower_bound":158607.43323415518,"upper_bound":4832210.295461118,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":0.012344242202025901,"lower_bound":0.003794713957270091,"upper_bound":0.02252717258175262,"unit":"%"},"median":{"estimate":0.003073725774062286,"lower_bound":-0.00036689719429994216,"upper_bound":0.020556756161327794,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_lastname/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_eql_cast_lastname_10000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[146245084.0,295872959.0,443916750.0,587987500.0,728427708.0,872962750.0,1017171917.0,1163290709.0,1325489875.0,1449314250.0],"unit":"ns","throughput":[],"typical":{"estimate":145845939.63116884,"lower_bound":145235541.8751711,"upper_bound":146738811.85555556,"unit":"ns"},"mean":{"estimate":146325971.20265874,"lower_bound":145683299.45145932,"upper_bound":147015006.13805556,"unit":"ns"},"median":{"estimate":145965312.8,"lower_bound":145402032.76190478,"upper_bound":147466677.25,"unit":"ns"},"median_abs_dev":{"estimate":1250277.4050031325,"lower_bound":142144.22305643852,"upper_bound":1868332.8405179551,"unit":"ns"},"slope":{"estimate":145845939.63116884,"lower_bound":145235541.8751711,"upper_bound":146738811.85555556,"unit":"ns"},"change":{"mean":{"estimate":-0.09949002706393062,"lower_bound":-0.10588153925086316,"upper_bound":-0.09316597688089202,"unit":"%"},"median":{"estimate":-0.10046285880637762,"lower_bound":-0.10706960981148506,"upper_bound":-0.08911108364547715,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_lastname/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_lastname_10000","iteration_count":[3,3,3,3,3,3,3,3,3,3],"measured_values":[603732417.0,634628917.0,638508333.0,602931583.0,626376125.0,612382208.0,604289791.0,617886875.0,637976792.0,600594500.0],"unit":"ns","throughput":[],"typical":{"estimate":205976918.03333336,"lower_bound":203043511.03333333,"upper_bound":209020872.96750003,"unit":"ns"},"mean":{"estimate":205976918.03333336,"lower_bound":203043511.03333333,"upper_bound":209020872.96750003,"unit":"ns"},"median":{"estimate":205044847.16666666,"lower_bound":201203562.33333334,"upper_bound":211542972.33333334,"unit":"ns"},"median_abs_dev":{"estimate":5832815.905746795,"lower_bound":395772.15577362495,"upper_bound":8093430.724912897,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.06641038156867207,"lower_bound":-0.08097641812845884,"upper_bound":-0.05235134787026992,"unit":"%"},"median":{"estimate":-0.0668888082306004,"lower_bound":-0.08612205073177293,"upper_bound":-0.038121986912353356,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"MATCH/match/eql_bloom/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_eql_bloom_10000","iteration_count":[99,198,297,396,495,594,693,792,891,990],"measured_values":[91544875.0,186955292.0,279397875.0,376272958.0,454820625.0,552104833.0,714247541.0,697129250.0,797567834.0,885948667.0],"unit":"ns","throughput":[],"typical":{"estimate":918531.7329660238,"lower_bound":894820.8764178094,"upper_bound":966017.296611058,"unit":"ns"},"mean":{"estimate":930904.057413019,"lower_bound":908801.805649551,"upper_bound":957744.9392150673,"unit":"ns"},"median":{"estimate":927082.5614478115,"lower_bound":895137.8608305275,"upper_bound":945458.9116161617,"unit":"ns"},"median_abs_dev":{"estimate":29828.25165731121,"lower_bound":7005.767843804558,"upper_bound":59656.85399693973,"unit":"ns"},"slope":{"estimate":918531.7329660238,"lower_bound":894820.8764178094,"upper_bound":966017.296611058,"unit":"ns"},"change":{"mean":{"estimate":-0.0548037778990319,"lower_bound":-0.10441034450229317,"upper_bound":-0.0029689179600222563,"unit":"%"},"median":{"estimate":-0.07155098311515917,"lower_bound":-0.11108131094639317,"upper_bound":0.020482671002415298,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_bloom/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_decrypt_eql_bloom_10000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[122343458.0,334219417.0,353727042.0,479038875.0,603157916.0,740124083.0,867214417.0,981954417.0,1080337084.0,1298517750.0],"unit":"ns","throughput":[],"typical":{"estimate":62154546.11298701,"lower_bound":60574551.62908497,"upper_bound":63885780.60477386,"unit":"ns"},"mean":{"estimate":63381440.05216269,"lower_bound":60430689.266051576,"upper_bound":68179809.42043054,"unit":"ns"},"median":{"estimate":61271940.03125,"lower_bound":60018726.88888889,"upper_bound":63301447.20833333,"unit":"ns"},"median_abs_dev":{"estimate":1637799.705441159,"lower_bound":323156.55265532545,"upper_bound":3859653.9411274483,"unit":"ns"},"slope":{"estimate":62154546.11298701,"lower_bound":60574551.62908497,"upper_bound":63885780.60477386,"unit":"ns"},"change":{"mean":{"estimate":0.056606095271677814,"lower_bound":-0.005013792901696573,"upper_bound":0.14339745757159747,"unit":"%"},"median":{"estimate":0.028798406179642688,"lower_bound":-0.003135587502578585,"upper_bound":0.06511579083276398,"unit":"%"},"change":"NoChange"}} +{"reason":"group-complete","group_name":"MATCH","benchmarks":["MATCH/match/eql_cast_firstname/1000000","MATCH/match/eql_cast_firstname/100000","MATCH/match_decrypt/eql_cast_firstname/100000","MATCH/match/eql_cast_lastname/100000","MATCH/match_decrypt/eql_bloom/100000","MATCH/match/eql_bloom/100000","MATCH/match_decrypt/eql_cast_lastname/100000","MATCH/match_decrypt/eql_cast_firstname/1000000","MATCH/match/eql_bloom/1000000","MATCH/match/eql_cast_lastname/1000000","MATCH/match_decrypt/eql_cast_lastname/1000000","MATCH/match_decrypt/eql_bloom/1000000","MATCH/match/eql_cast_firstname/10000","MATCH/match_decrypt/eql_cast_firstname/10000","MATCH/match/eql_cast_lastname/10000","MATCH/match_decrypt/eql_cast_lastname/10000","MATCH/match/eql_bloom/10000","MATCH/match_decrypt/eql_bloom/10000"],"report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH"} diff --git a/results/query/match_rows_100000.json b/results/query/match_rows_100000.json new file mode 100644 index 0000000..c3faa66 --- /dev/null +++ b/results/query/match_rows_100000.json @@ -0,0 +1,7 @@ +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_firstname/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_eql_cast_firstname_100000","iteration_count":[2,2,2,2,2,2,2,2,2,2],"measured_values":[695995875.0,585418500.0,781715167.0,825201041.0,540133209.0,596981875.0,872340083.0,789185625.0,478776875.0,668576666.0],"unit":"ns","throughput":[],"typical":{"estimate":341716245.8,"lower_bound":302761422.95,"upper_bound":380116606.2,"unit":"ns"},"mean":{"estimate":341716245.8,"lower_bound":302761422.95,"upper_bound":380116606.2,"unit":"ns"},"median":{"estimate":341143135.25,"lower_bound":284278771.0,"upper_bound":401729052.0,"unit":"ns"},"median_abs_dev":{"estimate":76475564.87543732,"lower_bound":16118038.911947608,"upper_bound":109876008.8897109,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.2740049441579807,"lower_bound":-0.3855150098051601,"upper_bound":-0.1567897030054098,"unit":"%"},"median":{"estimate":-0.28554712601770804,"lower_bound":-0.43973144549374843,"upper_bound":-0.041325011101800535,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_firstname/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_firstname_100000","iteration_count":[2,2,2,2,2,2,2,2,2,2],"measured_values":[919855292.0,960610500.0,619136458.0,778823292.0,860762875.0,881919833.0,576849583.0,681795500.0,859207083.0,900180375.0],"unit":"ns","throughput":[],"typical":{"estimate":401957039.55,"lower_bound":360681456.2,"upper_bound":439027235.35,"unit":"ns"},"mean":{"estimate":401957039.55,"lower_bound":360681456.2,"upper_bound":439027235.35,"unit":"ns"},"median":{"estimate":429992489.5,"lower_bound":340897750.0,"upper_bound":450443781.25,"unit":"ns"},"median_abs_dev":{"estimate":52273509.87195969,"lower_bound":8418480.638042092,"upper_bound":110139464.31048363,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.2024658685576134,"lower_bound":-0.31538422090523294,"upper_bound":-0.06229372786639084,"unit":"%"},"median":{"estimate":-0.20266957804408203,"lower_bound":-0.37577292967425735,"upper_bound":-0.0018567571131447025,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_lastname/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_eql_cast_lastname_100000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[114522083.0,271359000.0,433365667.0,417898625.0,638228250.0,614820041.0,821219834.0,967801292.0,1004117333.0,1160155458.0],"unit":"ns","throughput":[],"typical":{"estimate":115944293.06753246,"lower_bound":111498552.52538943,"upper_bound":120962228.16813281,"unit":"ns"},"mean":{"estimate":119512353.74150793,"lower_bound":112120351.22234128,"upper_bound":127630040.8111111,"unit":"ns"},"median":{"estimate":116666332.47142857,"lower_bound":109498369.625,"upper_bound":128327330.75,"unit":"ns"},"median_abs_dev":{"estimate":11917922.47198125,"lower_bound":2189422.427596651,"upper_bound":22652074.81459529,"unit":"ns"},"slope":{"estimate":115944293.06753246,"lower_bound":111498552.52538943,"upper_bound":120962228.16813281,"unit":"ns"},"change":{"mean":{"estimate":-0.08143820231998111,"lower_bound":-0.1813702780020383,"upper_bound":0.03159466734863331,"unit":"%"},"median":{"estimate":-0.10073271834924291,"lower_bound":-0.23868927508683002,"upper_bound":0.07626963406477372,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_lastname/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_lastname_100000","iteration_count":[3,3,3,3,3,3,3,3,3,3],"measured_values":[482076125.0,517081500.0,618354000.0,443344125.0,475255125.0,521193084.0,517811333.0,567961916.0,652738875.0,519027916.0],"unit":"ns","throughput":[],"typical":{"estimate":177161466.63333333,"lower_bound":165193545.83333334,"upper_bound":190429662.43333334,"unit":"ns"},"mean":{"estimate":177161466.63333333,"lower_bound":165193545.83333334,"upper_bound":190429662.43333334,"unit":"ns"},"median":{"estimate":172806541.5,"lower_bound":160692041.66666666,"upper_bound":189924514.0,"unit":"ns"},"median_abs_dev":{"estimate":19646426.20410622,"lower_bound":535013.0033016353,"upper_bound":36441010.078042746,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.026741742036183958,"lower_bound":-0.12136940388333457,"upper_bound":0.07538698822175584,"unit":"%"},"median":{"estimate":-0.05795397494906429,"lower_bound":-0.14185969528839737,"upper_bound":0.12771570931057696,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"MATCH/match/eql_bloom/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_eql_bloom_100000","iteration_count":[28,56,84,112,140,168,196,224,252,280],"measured_values":[101529125.0,186289666.0,295933250.0,373816333.0,461137708.0,562301208.0,595278375.0,734334875.0,866471208.0,931792917.0],"unit":"ns","throughput":[],"typical":{"estimate":3311175.045825603,"lower_bound":3205612.7402758133,"upper_bound":3391340.2094992637,"unit":"ns"},"mean":{"estimate":3353579.875412415,"lower_bound":3259778.789961735,"upper_bound":3444577.8297708337,"unit":"ns"},"median":{"estimate":3332738.838392857,"lower_bound":3293840.7714285715,"upper_bound":3438377.8095238097,"unit":"ns"},"median_abs_dev":{"estimate":69204.95975949091,"lower_bound":8187.400223394442,"upper_bound":269570.9603391588,"unit":"ns"},"slope":{"estimate":3311175.045825603,"lower_bound":3205612.7402758133,"upper_bound":3391340.2094992637,"unit":"ns"},"change":{"mean":{"estimate":-0.029044810217253025,"lower_bound":-0.06828248497977868,"upper_bound":0.010984549273723667,"unit":"%"},"median":{"estimate":-0.019560620798880213,"lower_bound":-0.07245473582204764,"upper_bound":0.014617688604529722,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_bloom/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_decrypt_eql_bloom_100000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[138469750.0,265178125.0,426540584.0,576850375.0,676561541.0,744317834.0,999890709.0,1079071917.0,1203583792.0,1359678917.0],"unit":"ns","throughput":[],"typical":{"estimate":67747295.52987012,"lower_bound":66055190.66165414,"upper_bound":69497368.52262443,"unit":"ns"},"mean":{"estimate":68212091.25382936,"lower_bound":66397740.024662696,"upper_bound":69874054.16875647,"unit":"ns"},"median":{"estimate":67820049.975,"lower_bound":66865766.222222224,"upper_bound":71090097.33333333,"unit":"ns"},"median_abs_dev":{"estimate":2179676.7831780016,"lower_bound":401748.29696628754,"upper_bound":5495044.308357216,"unit":"ns"},"slope":{"estimate":67747295.52987012,"lower_bound":66055190.66165414,"upper_bound":69497368.52262443,"unit":"ns"},"change":{"mean":{"estimate":0.09409326986461841,"lower_bound":0.049661047440397586,"upper_bound":0.13859350604925724,"unit":"%"},"median":{"estimate":0.10340363221258642,"lower_bound":0.05342399648444962,"upper_bound":0.17246519130079374,"unit":"%"},"change":"Regressed"}} +{"reason":"group-complete","group_name":"MATCH","benchmarks":["MATCH/match/eql_cast_firstname/1000000","MATCH/match/eql_cast_lastname/10000","MATCH/match_decrypt/eql_cast_firstname/10000","MATCH/match/eql_cast_firstname/10000","MATCH/match_decrypt/eql_cast_firstname/1000000","MATCH/match/eql_bloom/1000000","MATCH/match/eql_cast_lastname/1000000","MATCH/match_decrypt/eql_bloom/10000","MATCH/match_decrypt/eql_cast_lastname/1000000","MATCH/match_decrypt/eql_cast_lastname/10000","MATCH/match_decrypt/eql_bloom/1000000","MATCH/match/eql_bloom/10000","MATCH/match/eql_cast_firstname/100000","MATCH/match_decrypt/eql_cast_firstname/100000","MATCH/match/eql_cast_lastname/100000","MATCH/match_decrypt/eql_cast_lastname/100000","MATCH/match/eql_bloom/100000","MATCH/match_decrypt/eql_bloom/100000"],"report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH"} diff --git a/results/query/match_rows_1000000.json b/results/query/match_rows_1000000.json new file mode 100644 index 0000000..b744f3e --- /dev/null +++ b/results/query/match_rows_1000000.json @@ -0,0 +1,7 @@ +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_firstname/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_eql_cast_firstname_1000000","iteration_count":[2,2,2,2,2,2,2,2,2,2],"measured_values":[1090875750.0,756854209.0,465250292.0,655697000.0,1258982417.0,676868041.0,847896750.0,519412958.0,875749666.0,835150292.0],"unit":"ns","throughput":[],"typical":{"estimate":399136868.75,"lower_bound":330682500.92,"upper_bound":473264023.525,"unit":"ns"},"mean":{"estimate":399136868.75,"lower_bound":330682500.92,"upper_bound":473264023.525,"unit":"ns"},"median":{"estimate":398001125.25,"lower_bound":299070249.75,"upper_bound":484693125.0,"unit":"ns"},"median_abs_dev":{"estimate":96161234.14179683,"lower_bound":15694092.414674163,"upper_bound":211812680.09437323,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.06289538519782645,"lower_bound":-0.2541363535369519,"upper_bound":0.1733246968851381,"unit":"%"},"median":{"estimate":-0.03987647449912768,"lower_bound":-0.31491648512688897,"upper_bound":0.2570604692421703,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_firstname/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_firstname_1000000","iteration_count":[2,2,2,2,2,2,2,2,2,2],"measured_values":[978876125.0,1039871833.0,960755875.0,880510667.0,940179125.0,739549333.0,759747125.0,919120625.0,880569000.0,904925042.0],"unit":"ns","throughput":[],"typical":{"estimate":450205237.5,"lower_bound":422009214.09749997,"upper_bound":476172294.495,"unit":"ns"},"mean":{"estimate":450205237.5,"lower_bound":422009214.09749997,"upper_bound":476172294.495,"unit":"ns"},"median":{"estimate":456011416.75,"lower_bound":410079031.25,"upper_bound":480377937.5,"unit":"ns"},"median_abs_dev":{"estimate":29742885.817158222,"lower_bound":9049187.9330948,"upper_bound":81220162.40805387,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.1311516084693528,"lower_bound":-0.24964788249274014,"upper_bound":0.005630844408828099,"unit":"%"},"median":{"estimate":-0.12325701236693942,"lower_bound":-0.243271158070533,"upper_bound":0.07717536151979942,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_lastname/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_eql_cast_lastname_1000000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[117403209.0,226370084.0,391453500.0,522123708.0,562306583.0,720595708.0,798208333.0,1184225791.0,1409644208.0,1291659416.0],"unit":"ns","throughput":[],"typical":{"estimate":134111071.59220779,"lower_bound":119895067.55710785,"upper_bound":145895283.47822586,"unit":"ns"},"mean":{"estimate":127201534.08210316,"lower_bound":118958636.41045237,"upper_bound":136566251.59354267,"unit":"ns"},"median":{"estimate":124632613.13333333,"lower_bound":114029761.85714285,"upper_bound":139256361.9375,"unit":"ns"},"median_abs_dev":{"estimate":13219050.70039493,"lower_bound":1011863.6590558335,"upper_bound":25743723.909877542,"unit":"ns"},"slope":{"estimate":134111071.59220779,"lower_bound":119895067.55710785,"upper_bound":145895283.47822586,"unit":"ns"},"change":{"mean":{"estimate":-0.18665851390208854,"lower_bound":-0.30285818330698766,"upper_bound":-0.0647647345826599,"unit":"%"},"median":{"estimate":-0.1761768151469053,"lower_bound":-0.2897125608561202,"upper_bound":-0.02759620533612861,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_lastname/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_lastname_1000000","iteration_count":[3,3,3,3,3,3,3,3,3,3],"measured_values":[664314458.0,475894125.0,662133084.0,577233709.0,523390292.0,577835916.0,619468959.0,619671583.0,498752708.0,500269042.0],"unit":"ns","throughput":[],"typical":{"estimate":190632129.2,"lower_bound":177066848.62666667,"upper_bound":204212060.79916665,"unit":"ns"},"mean":{"estimate":190632129.2,"lower_bound":177066848.62666667,"upper_bound":204212060.79916665,"unit":"ns"},"median":{"estimate":192511604.1666667,"lower_bound":166756347.33333334,"upper_bound":213600340.5,"unit":"ns"},"median_abs_dev":{"estimate":32471482.32961598,"lower_bound":1078035.011661038,"upper_bound":38934115.352681324,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.24270391989655538,"lower_bound":-0.39968202477480114,"upper_bound":-0.04940620214757167,"unit":"%"},"median":{"estimate":-0.16167425513306855,"lower_bound":-0.3784285778987142,"upper_bound":0.012900962896206458,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"MATCH/match/eql_bloom/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_eql_bloom_1000000","iteration_count":[5,10,15,20,25,30,35,40,45,50],"measured_values":[111262708.0,218296125.0,316091959.0,413629458.0,540187667.0,629994792.0,727861791.0,848310958.0,936660834.0,1054346000.0],"unit":"ns","throughput":[],"typical":{"estimate":21031939.46025974,"lower_bound":20883987.08482758,"upper_bound":21206391.605172433,"unit":"ns"},"mean":{"estimate":21234918.76680952,"lower_bound":20959788.44088095,"upper_bound":21551175.901666664,"unit":"ns"},"median":{"estimate":21079858.633333333,"lower_bound":20814685.2,"upper_bound":21607506.68,"unit":"ns"},"median_abs_dev":{"estimate":406959.53041502315,"lower_bound":64562.48453378788,"upper_bound":791681.7139708424,"unit":"ns"},"slope":{"estimate":21031939.46025974,"lower_bound":20883987.08482758,"upper_bound":21206391.605172433,"unit":"ns"},"change":{"mean":{"estimate":-0.03288784036231562,"lower_bound":-0.04922555803357187,"upper_bound":-0.01562724569795044,"unit":"%"},"median":{"estimate":-0.03715317481860947,"lower_bound":-0.052592981621914836,"upper_bound":-0.010468125208645485,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_bloom/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH/match_decrypt_eql_bloom_1000000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[158191708.0,319613083.0,481495708.0,660083125.0,818121667.0,960787625.0,1180228542.0,1260107084.0,1514446292.0,2177843834.0],"unit":"ns","throughput":[],"typical":{"estimate":88946081.84025975,"lower_bound":80331644.27808511,"upper_bound":99322055.34675615,"unit":"ns"},"mean":{"estimate":83972343.04337302,"lower_bound":80325898.29861112,"upper_bound":89950596.91813493,"unit":"ns"},"median":{"estimate":81030725.68333334,"lower_bound":79580744.70833334,"upper_bound":84135905.1111111,"unit":"ns"},"median_abs_dev":{"estimate":2531195.955174789,"lower_bound":256500.11187121642,"upper_bound":5154048.277532352,"unit":"ns"},"slope":{"estimate":88946081.84025975,"lower_bound":80331644.27808511,"upper_bound":99322055.34675615,"unit":"ns"},"change":{"mean":{"estimate":0.028527985767776265,"lower_bound":-0.026462062304566415,"upper_bound":0.10901466780160374,"unit":"%"},"median":{"estimate":0.005673415957825556,"lower_bound":-0.021475971028100727,"upper_bound":0.04442913076921928,"unit":"%"},"change":"NoChange"}} +{"reason":"group-complete","group_name":"MATCH","benchmarks":["MATCH/match/eql_cast_lastname/10000","MATCH/match/eql_cast_firstname/100000","MATCH/match_decrypt/eql_cast_firstname/10000","MATCH/match_decrypt/eql_cast_firstname/100000","MATCH/match/eql_cast_lastname/100000","MATCH/match_decrypt/eql_bloom/100000","MATCH/match/eql_bloom/100000","MATCH/match/eql_cast_firstname/10000","MATCH/match_decrypt/eql_cast_lastname/100000","MATCH/match_decrypt/eql_bloom/10000","MATCH/match_decrypt/eql_cast_lastname/10000","MATCH/match/eql_bloom/10000","MATCH/match/eql_cast_firstname/1000000","MATCH/match_decrypt/eql_cast_firstname/1000000","MATCH/match/eql_cast_lastname/1000000","MATCH/match_decrypt/eql_cast_lastname/1000000","MATCH/match/eql_bloom/1000000","MATCH/match_decrypt/eql_bloom/1000000"],"report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/MATCH"} diff --git a/results/query/ore_rows_10000.json b/results/query/ore_rows_10000.json new file mode 100644 index 0000000..1cc82f7 --- /dev/null +++ b/results/query/ore_rows_10000.json @@ -0,0 +1,13 @@ +{"reason":"benchmark-complete","id":"ORE/ore/exact/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_exact_10000","iteration_count":[2,2,2,2,2,2,2,2,2,2],"measured_values":[555991542.0,554330750.0,553355042.0,551002084.0,551516667.0,551910042.0,556069792.0,552744417.0,554012959.0,552113792.0],"unit":"ns","throughput":[],"typical":{"estimate":276652354.35,"lower_bound":276152714.41625,"upper_bound":277192796.05,"unit":"ns"},"mean":{"estimate":276652354.35,"lower_bound":276152714.41625,"upper_bound":277192796.05,"unit":"ns"},"median":{"estimate":276524864.75,"lower_bound":275907614.75,"upper_bound":277501125.25,"unit":"ns"},"median_abs_dev":{"estimate":897235.4042708874,"lower_bound":221324.37732070684,"upper_bound":1541811.3101273775,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.004566024165571503,"lower_bound":-0.013503050962924897,"upper_bound":0.002279841494447675,"unit":"%"},"median":{"estimate":0.0016567515821162004,"lower_bound":-0.009428418320856169,"upper_bound":0.004489274860162595,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/exact/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_exact_10000","iteration_count":[2,2,2,2,2,2,2,2,2,2],"measured_values":[554540917.0,551406750.0,559683958.0,550947208.0,555709625.0,550455458.0,554200708.0,551601291.0,553122167.0,552716625.0],"unit":"ns","throughput":[],"typical":{"estimate":276719235.35,"lower_bound":275980858.2,"upper_bound":277595664.5,"unit":"ns"},"mean":{"estimate":276719235.35,"lower_bound":275980858.2,"upper_bound":277595664.5,"unit":"ns"},"median":{"estimate":276459698.0,"lower_bound":275637124.75,"upper_bound":277477583.25,"unit":"ns"},"median_abs_dev":{"estimate":1161678.9779260755,"lower_bound":252196.92722260952,"upper_bound":2138156.7562401295,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.007630343733100675,"lower_bound":-0.013969607972443883,"upper_bound":-0.0013941100907434933,"unit":"%"},"median":{"estimate":-0.006729394148801582,"lower_bound":-0.014414897318855813,"upper_bound":-0.0010903418618160021,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_gt_10_10000","iteration_count":[42,84,126,168,210,252,294,336,378,420],"measured_values":[96652375.0,204280750.0,285002917.0,382696625.0,448071750.0,534559958.0,633315292.0,741342000.0,835738417.0,931733666.0],"unit":"ns","throughput":[],"typical":{"estimate":2197999.5721088434,"lower_bound":2167311.451388221,"upper_bound":2221513.81636742,"unit":"ns"},"mean":{"estimate":2231785.9732634164,"lower_bound":2181578.1115823416,"upper_bound":2289614.950527731,"unit":"ns"},"median":{"estimate":2214680.8417989416,"lower_bound":2154133.646258503,"upper_bound":2281587.4682539683,"unit":"ns"},"median_abs_dev":{"estimate":91789.58421148072,"lower_bound":9196.067553403953,"upper_bound":153194.0813813329,"unit":"ns"},"slope":{"estimate":2197999.5721088434,"lower_bound":2167311.451388221,"upper_bound":2221513.81636742,"unit":"ns"},"change":{"mean":{"estimate":-0.07905040881532144,"lower_bound":-0.13757265893907342,"upper_bound":-0.012560055753672764,"unit":"%"},"median":{"estimate":-0.11136228669854453,"lower_bound":-0.16298860549098548,"upper_bound":0.032811254609281804,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_gt_10_10000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[116220916.0,239779042.0,354916208.0,466290292.0,637991375.0,721542583.0,843299250.0,959518416.0,1107401583.0,1215334750.0],"unit":"ns","throughput":[],"typical":{"estimate":60706629.85714286,"lower_bound":59976359.48026316,"upper_bound":61395001.35699065,"unit":"ns"},"mean":{"estimate":60191650.17976191,"lower_bound":59295757.440952376,"upper_bound":61219795.0047619,"unit":"ns"},"median":{"estimate":60049224.79166667,"lower_bound":59115523.5,"upper_bound":60878985.440476194,"unit":"ns"},"median_abs_dev":{"estimate":1196484.9891081434,"lower_bound":136242.1037562265,"upper_bound":2595095.6125028506,"unit":"ns"},"slope":{"estimate":60706629.85714286,"lower_bound":59976359.48026316,"upper_bound":61395001.35699065,"unit":"ns"},"change":{"mean":{"estimate":-0.034829877631672446,"lower_bound":-0.07588819522741966,"upper_bound":0.0009508776605389598,"unit":"%"},"median":{"estimate":-0.006301025146838279,"lower_bound":-0.06271315518211695,"upper_bound":0.012437241643051822,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_gt_100_10000","iteration_count":[7,14,21,28,35,42,49,56,63,70],"measured_values":[101085000.0,187161292.0,291649042.0,383354583.0,475399541.0,574380875.0,655472000.0,749479833.0,856729875.0,957145834.0],"unit":"ns","throughput":[],"typical":{"estimate":13570770.269387756,"lower_bound":13463547.72686433,"upper_bound":13665088.595891612,"unit":"ns"},"mean":{"estimate":13668018.873112243,"lower_bound":13506107.885867348,"upper_bound":13875685.929928571,"unit":"ns"},"median":{"estimate":13636199.40952381,"lower_bound":13383568.44642857,"upper_bound":13781892.36904762,"unit":"ns"},"median_abs_dev":{"estimate":227494.5189261649,"lower_bound":12329.119838258182,"upper_bound":436402.55729623267,"unit":"ns"},"slope":{"estimate":13570770.269387756,"lower_bound":13463547.72686433,"upper_bound":13665088.595891612,"unit":"ns"},"change":{"mean":{"estimate":-0.00016092757081098696,"lower_bound":-0.03137397115144966,"upper_bound":0.028416777639421836,"unit":"%"},"median":{"estimate":0.013184528398539008,"lower_bound":-0.03094582211328889,"upper_bound":0.032723859396800004,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_gt_100_10000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[97489417.0,244229834.0,350571750.0,485409667.0,605754417.0,698455500.0,821698375.0,916249834.0,1018242583.0,1161800250.0],"unit":"ns","throughput":[],"typical":{"estimate":116007483.45974027,"lower_bound":114607636.04081632,"upper_bound":118043310.2106284,"unit":"ns"},"mean":{"estimate":115660893.53206348,"lower_bound":111021704.28918847,"upper_bound":119103421.80822022,"unit":"ns"},"median":{"estimate":116633250.0,"lower_bound":114531229.25,"upper_bound":121150883.4,"unit":"ns"},"median_abs_dev":{"estimate":4149208.713545155,"lower_bound":502026.8835872412,"upper_bound":7698441.4366403585,"unit":"ns"},"slope":{"estimate":116007483.45974027,"lower_bound":114607636.04081632,"upper_bound":118043310.2106284,"unit":"ns"},"change":{"mean":{"estimate":-0.06397679356281971,"lower_bound":-0.12641777278933752,"upper_bound":-6.612078876204225e-6,"unit":"%"},"median":{"estimate":-0.03352839344381753,"lower_bound":-0.11507138022737076,"upper_bound":0.017022196253142274,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_lt_10_10000","iteration_count":[48,96,144,192,240,288,336,384,432,480],"measured_values":[85569083.0,194709125.0,273924208.0,383927542.0,447740541.0,519754625.0,670385167.0,744327667.0,804779167.0,975579167.0],"unit":"ns","throughput":[],"typical":{"estimate":1939167.871103896,"lower_bound":1870799.96970943,"upper_bound":1996863.3919513458,"unit":"ns"},"mean":{"estimate":1921199.1072032074,"lower_bound":1867161.4694791667,"upper_bound":1974252.0487045303,"unit":"ns"},"median":{"estimate":1920302.3719618055,"lower_bound":1835144.5732638887,"upper_bound":2011707.0007440476,"unit":"ns"},"median_abs_dev":{"estimate":114317.22018426574,"lower_bound":24339.83141288166,"upper_bound":150082.53795341885,"unit":"ns"},"slope":{"estimate":1939167.871103896,"lower_bound":1870799.96970943,"upper_bound":1996863.3919513458,"unit":"ns"},"change":{"mean":{"estimate":0.11312268838907302,"lower_bound":0.03816614122997209,"upper_bound":0.19696326352585852,"unit":"%"},"median":{"estimate":0.0870490464019289,"lower_bound":0.008904622671221052,"upper_bound":0.2522935262762691,"unit":"%"},"change":"Regressed"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_lt_10_10000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[121105084.0,242622541.0,358797125.0,518728167.0,626176750.0,755342166.0,856819709.0,941123959.0,1081154792.0,1195023750.0],"unit":"ns","throughput":[],"typical":{"estimate":60555780.8025974,"lower_bound":59756923.98548094,"upper_bound":61961331.16964286,"unit":"ns"},"mean":{"estimate":61124857.22926588,"lower_bound":60124606.28111607,"upper_bound":62253487.657919146,"unit":"ns"},"median":{"estimate":60604088.625,"lower_bound":59799520.833333336,"upper_bound":62617675.0,"unit":"ns"},"median_abs_dev":{"estimate":1228681.6861115377,"lower_bound":242779.82283979654,"upper_bound":3053552.7129136026,"unit":"ns"},"slope":{"estimate":60555780.8025974,"lower_bound":59756923.98548094,"upper_bound":61961331.16964286,"unit":"ns"},"change":{"mean":{"estimate":-0.04185164742365266,"lower_bound":-0.07984956052851694,"upper_bound":-0.0037859743428518963,"unit":"%"},"median":{"estimate":-0.03874177556768976,"lower_bound":-0.09036689217197236,"upper_bound":0.01610361532684923,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_lt_100_10000","iteration_count":[9,18,27,36,45,54,63,72,81,90],"measured_values":[94291917.0,186891750.0,296623125.0,393983375.0,485781792.0,582240208.0,686551167.0,804993042.0,893708500.0,968268333.0],"unit":"ns","throughput":[],"typical":{"estimate":10917197.932178931,"lower_bound":10789169.30882353,"upper_bound":11047667.451487519,"unit":"ns"},"mean":{"estimate":10823722.777266312,"lower_bound":10675030.621661376,"upper_bound":10960867.064834436,"unit":"ns"},"median":{"estimate":10846394.252380952,"lower_bound":10629552.87037037,"upper_bound":10988710.455246914,"unit":"ns"},"median_abs_dev":{"estimate":175862.89600614193,"lower_bound":35121.371178694244,"upper_bound":412576.8865160374,"unit":"ns"},"slope":{"estimate":10917197.932178931,"lower_bound":10789169.30882353,"upper_bound":11047667.451487519,"unit":"ns"},"change":{"mean":{"estimate":-0.16646548425362673,"lower_bound":-0.19100159508060735,"upper_bound":-0.14070212491943754,"unit":"%"},"median":{"estimate":-0.15957371257660902,"lower_bound":-0.19938550485508344,"upper_bound":-0.13114357878114258,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_lt_100_10000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[142634166.0,220171959.0,359183625.0,421388125.0,554921333.0,607929958.0,755456708.0,900005292.0,1000335041.0,1260263834.0],"unit":"ns","throughput":[],"typical":{"estimate":113927690.57922077,"lower_bound":107408316.53296168,"upper_bound":120308907.70613107,"unit":"ns"},"mean":{"estimate":114769874.76626985,"lower_bound":108536150.51388888,"upper_bound":122497644.6340476,"unit":"ns"},"median":{"estimate":111066302.24444444,"lower_bound":107716505.375,"upper_bound":119727875.0,"unit":"ns"},"median_abs_dev":{"estimate":6570279.948142552,"lower_bound":909152.303996001,"upper_bound":16485705.395310232,"unit":"ns"},"slope":{"estimate":113927690.57922077,"lower_bound":107408316.53296168,"upper_bound":120308907.70613107,"unit":"ns"},"change":{"mean":{"estimate":-0.05463357248328682,"lower_bound":-0.1099210420072943,"upper_bound":0.006825880860379326,"unit":"%"},"median":{"estimate":-0.0804687767251353,"lower_bound":-0.1222210613194441,"upper_bound":-0.010506267630167598,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_ordered_10/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_lt_ordered_10_10000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[538411083.0,546542792.0,540864917.0,545722500.0,538505000.0,545123708.0,537896500.0,550726042.0,544214959.0,538512250.0],"unit":"ns","throughput":[],"typical":{"estimate":542651975.1,"lower_bound":540140087.6,"upper_bound":545318371.1,"unit":"ns"},"mean":{"estimate":542651975.1,"lower_bound":540140087.6,"upper_bound":545318371.1,"unit":"ns"},"median":{"estimate":542539938.0,"lower_bound":538461666.5,"upper_bound":545833250.0,"unit":"ns"},"median_abs_dev":{"estimate":5953040.678912401,"lower_bound":139241.34172797203,"upper_bound":8306020.2409386635,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.002635727441795299,"lower_bound":-0.00838228434025974,"upper_bound":0.003240184374811569,"unit":"%"},"median":{"estimate":-0.0012393449598022688,"lower_bound":-0.013115477583909962,"upper_bound":0.006047266874367185,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_ordered_10/10000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_lt_ordered_10_10000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[599779792.0,581447417.0,599291667.0,599406625.0,599611166.0,601384042.0,598819584.0,601277917.0,598870958.0,598835500.0],"unit":"ns","throughput":[],"typical":{"estimate":597872466.8,"lower_bound":594013404.185,"upper_bound":600144912.8,"unit":"ns"},"mean":{"estimate":597872466.8,"lower_bound":594013404.185,"upper_bound":600144912.8,"unit":"ns"},"median":{"estimate":599349146.0,"lower_bound":598835500.0,"upper_bound":600444541.5,"unit":"ns"},"median_abs_dev":{"estimate":735246.5311467648,"lower_bound":49882.07611441612,"upper_bound":2510567.33712852,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.009997739995133537,"lower_bound":-0.020325140255370383,"upper_bound":-0.0012466351875751024,"unit":"%"},"median":{"estimate":-0.004405685123564429,"lower_bound":-0.017567547286085006,"upper_bound":0.0009231403104172919,"unit":"%"},"change":"NoChange"}} +{"reason":"group-complete","group_name":"ORE","benchmarks":["ORE/ore/exact/10000","ORE/ore_decrypt/exact/10000","ORE/ore/range_gt_10/10000","ORE/ore_decrypt/range_gt_10/10000","ORE/ore/range_gt_100/10000","ORE/ore_decrypt/range_gt_100/10000","ORE/ore/range_lt_10/10000","ORE/ore_decrypt/range_lt_10/10000","ORE/ore/range_lt_100/10000","ORE/ore_decrypt/range_lt_100/10000","ORE/ore/range_lt_ordered_10/10000","ORE/ore_decrypt/range_lt_ordered_10/10000"],"report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE"} diff --git a/results/query/ore_rows_100000.json b/results/query/ore_rows_100000.json new file mode 100644 index 0000000..e63005f --- /dev/null +++ b/results/query/ore_rows_100000.json @@ -0,0 +1,13 @@ +{"reason":"benchmark-complete","id":"ORE/ore/exact/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_exact_100000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[1848759625.0,1879388917.0,1853749166.0,1856375292.0,1854809208.0,1852368333.0,1855487708.0,1850737917.0,1855425708.0,1872310333.0],"unit":"ns","throughput":[],"typical":{"estimate":1857941220.7,"lower_bound":1852912679.1,"upper_bound":1864282183.4,"unit":"ns"},"mean":{"estimate":1857941220.7,"lower_bound":1852912679.1,"upper_bound":1864282183.4,"unit":"ns"},"median":{"estimate":1855117458.0,"lower_bound":1852243541.5,"upper_bound":1863899020.5,"unit":"ns"},"median_abs_dev":{"estimate":3052241.167911887,"lower_bound":548932.6402544975,"upper_bound":12470611.691102386,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.19109618459689992,"lower_bound":-0.2857000768750406,"upper_bound":-0.08812626983880038,"unit":"%"},"median":{"estimate":-0.10395279642830246,"lower_bound":-0.2926000528713725,"upper_bound":-0.02712193552408837,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/exact/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_exact_100000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[1893093417.0,1879446958.0,1851051833.0,1852171292.0,1848114959.0,1854357083.0,1935087708.0,1871263000.0,1849756625.0,1850441709.0],"unit":"ns","throughput":[],"typical":{"estimate":1868478458.4,"lower_bound":1854246362.8,"upper_bound":1886763370.245,"unit":"ns"},"mean":{"estimate":1868478458.4,"lower_bound":1854246362.8,"upper_bound":1886763370.245,"unit":"ns"},"median":{"estimate":1853264187.5,"lower_bound":1850404229.0,"upper_bound":1882178208.5,"unit":"ns"},"median_abs_dev":{"estimate":6417279.0543705225,"lower_bound":1015705.5203676224,"upper_bound":39169085.95080972,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":0.0002734590190298647,"lower_bound":-0.008875904192565226,"upper_bound":0.01132696177451975,"unit":"%"},"median":{"estimate":-0.006033787554215464,"lower_bound":-0.011668410515270122,"upper_bound":0.008942220913680243,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_gt_10_100000","iteration_count":[52,104,156,208,260,312,364,416,468,520],"measured_values":[97465625.0,198613792.0,258850166.0,356624041.0,469956917.0,547336209.0,602822541.0,730178125.0,808471708.0,1027749667.0],"unit":"ns","throughput":[],"typical":{"estimate":1795527.7991508492,"lower_bound":1708111.9171270719,"upper_bound":1893877.004330107,"unit":"ns"},"mean":{"estimate":1783501.7938011293,"lower_bound":1723330.780660867,"upper_bound":1848499.4256730764,"unit":"ns"},"median":{"estimate":1754759.2992788462,"lower_bound":1693399.7927350427,"upper_bound":1874338.9423076923,"unit":"ns"},"median_abs_dev":{"estimate":109883.39219956443,"lower_bound":20557.900126290457,"upper_bound":181003.66957562903,"unit":"ns"},"slope":{"estimate":1795527.7991508492,"lower_bound":1708111.9171270719,"upper_bound":1893877.004330107,"unit":"ns"},"change":{"mean":{"estimate":-0.26519564704656295,"lower_bound":-0.29852758072688135,"upper_bound":-0.22868449043153335,"unit":"%"},"median":{"estimate":-0.2895911065239577,"lower_bound":-0.31770247369044724,"upper_bound":-0.22072169647396422,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_gt_10_100000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[125830792.0,256031875.0,400987000.0,499192375.0,658565542.0,771684125.0,859931167.0,1036199667.0,1143984459.0,1255560709.0],"unit":"ns","throughput":[],"typical":{"estimate":63533948.34805195,"lower_bound":62715142.038461536,"upper_bound":64579440.40315789,"unit":"ns"},"mean":{"estimate":63883600.449821435,"lower_bound":62947876.48757886,"upper_bound":64858838.59291221,"unit":"ns"},"median":{"estimate":63781330.45833333,"lower_bound":62657221.4375,"upper_bound":65081782.30833334,"unit":"ns"},"median_abs_dev":{"estimate":1471068.1164920682,"lower_bound":443359.1671287977,"upper_bound":2738485.485169664,"unit":"ns"},"slope":{"estimate":63533948.34805195,"lower_bound":62715142.038461536,"upper_bound":64579440.40315789,"unit":"ns"},"change":{"mean":{"estimate":-0.11269753953702377,"lower_bound":-0.1419019403372004,"upper_bound":-0.08059653159835517,"unit":"%"},"median":{"estimate":-0.11433705789769177,"lower_bound":-0.1556615483221354,"upper_bound":-0.08349801200297258,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_gt_100_100000","iteration_count":[8,16,24,32,40,48,56,64,72,80],"measured_values":[102877792.0,203490625.0,293629666.0,406037750.0,507540542.0,611091500.0,688612375.0,793434834.0,885333833.0,1013736000.0],"unit":"ns","throughput":[],"typical":{"estimate":12497493.683116883,"lower_bound":12359947.268034693,"upper_bound":12645556.65182419,"unit":"ns"},"mean":{"estimate":12558279.570426589,"lower_bound":12422941.626884922,"upper_bound":12687173.41,"unit":"ns"},"median":{"estimate":12680106.775,"lower_bound":12296649.55357143,"upper_bound":12718164.0625,"unit":"ns"},"median_abs_dev":{"estimate":170931.44667535918,"lower_bound":12587.042120285332,"upper_bound":336631.9377923389,"unit":"ns"},"slope":{"estimate":12497493.683116883,"lower_bound":12359947.268034693,"upper_bound":12645556.65182419,"unit":"ns"},"change":{"mean":{"estimate":-0.01818944407124168,"lower_bound":-0.0315304386007346,"upper_bound":-0.005409989801822747,"unit":"%"},"median":{"estimate":-0.0033739731552000496,"lower_bound":-0.04018411522714771,"upper_bound":0.004483505275459487,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_gt_100_100000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[100198916.0,218912042.0,404811875.0,495993667.0,602741333.0,750284667.0,938810709.0,1067269875.0,1211013125.0,1304156375.0],"unit":"ns","throughput":[],"typical":{"estimate":130655490.38441558,"lower_bound":126692297.7217262,"upper_bound":132970389.19961977,"unit":"ns"},"mean":{"estimate":124668355.7851984,"lower_bound":117221889.12964287,"upper_bound":130951602.32825395,"unit":"ns"},"median":{"estimate":127731541.0,"lower_bound":116727218.875,"upper_bound":134115815.57142857,"unit":"ns"},"median_abs_dev":{"estimate":9792385.618483739,"lower_bound":851219.5885336697,"upper_bound":18280305.3912597,"unit":"ns"},"slope":{"estimate":130655490.38441558,"lower_bound":126692297.7217262,"upper_bound":132970389.19961977,"unit":"ns"},"change":{"mean":{"estimate":-0.018325050124571307,"lower_bound":-0.07623020336302841,"upper_bound":0.039307907730569,"unit":"%"},"median":{"estimate":0.005195744118460022,"lower_bound":-0.07036651205815603,"upper_bound":0.06925350261246388,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_lt_10_100000","iteration_count":[47,94,141,188,235,282,329,376,423,470],"measured_values":[95682834.0,194227541.0,267099417.0,370542000.0,451088542.0,489081000.0,625139167.0,711263959.0,829166750.0,927565083.0],"unit":"ns","throughput":[],"typical":{"estimate":1921070.477922078,"lower_bound":1858052.858083659,"upper_bound":1959833.6476694841,"unit":"ns"},"mean":{"estimate":1934672.7430842624,"lower_bound":1877930.0363146109,"upper_bound":1985857.4205731384,"unit":"ns"},"median":{"estimate":1939865.3966903074,"lower_bound":1894322.1063829786,"upper_bound":2003386.5319148935,"unit":"ns"},"median_abs_dev":{"estimate":63225.20779781217,"lower_bound":6271.08891978308,"upper_bound":151993.5015199268,"unit":"ns"},"slope":{"estimate":1921070.477922078,"lower_bound":1858052.858083659,"upper_bound":1959833.6476694841,"unit":"ns"},"change":{"mean":{"estimate":-0.4208918138320068,"lower_bound":-0.5250883521774202,"upper_bound":-0.29059647096919305,"unit":"%"},"median":{"estimate":-0.33934875286921184,"lower_bound":-0.5252852190259583,"upper_bound":-0.23668771812314404,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_lt_10_100000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[142236834.0,261992875.0,475058042.0,505860667.0,740757167.0,898500584.0,912717458.0,1141036083.0,1278898833.0,1371486208.0],"unit":"ns","throughput":[],"typical":{"estimate":70067391.12207793,"lower_bound":67997474.60045542,"upper_bound":72385114.31655844,"unit":"ns"},"mean":{"estimate":70410942.97220238,"lower_bound":67579224.85607144,"upper_bound":73342336.46875,"unit":"ns"},"median":{"estimate":71084176.08333334,"lower_bound":65498218.75,"upper_bound":74075716.7,"unit":"ns"},"median_abs_dev":{"estimate":5027802.815898648,"lower_bound":247076.66010725507,"upper_bound":8652725.845452175,"unit":"ns"},"slope":{"estimate":70067391.12207793,"lower_bound":67997474.60045542,"upper_bound":72385114.31655844,"unit":"ns"},"change":{"mean":{"estimate":0.06855058204256359,"lower_bound":-0.05661511194396754,"upper_bound":0.18878160521412088,"unit":"%"},"median":{"estimate":0.15668544122517725,"lower_bound":-0.0028662493633172526,"upper_bound":0.23838409149225903,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_lt_100_100000","iteration_count":[8,16,24,32,40,48,56,64,72,80],"measured_values":[106639459.0,211461000.0,299683542.0,405517125.0,506538083.0,603736042.0,705841625.0,824286875.0,941392708.0,1040297375.0],"unit":"ns","throughput":[],"typical":{"estimate":12862494.07435065,"lower_bound":12658027.54172293,"upper_bound":12978191.612009238,"unit":"ns"},"mean":{"estimate":12850916.862832341,"lower_bound":12684111.385522567,"upper_bound":13025905.412624007,"unit":"ns"},"median":{"estimate":12775946.2890625,"lower_bound":12604314.732142856,"upper_bound":13110014.84375,"unit":"ns"},"median_abs_dev":{"estimate":315707.04685132904,"lower_bound":50479.13699444314,"upper_bound":483646.62840105593,"unit":"ns"},"slope":{"estimate":12862494.07435065,"lower_bound":12658027.54172293,"upper_bound":12978191.612009238,"unit":"ns"},"change":{"mean":{"estimate":-0.00008172382647331222,"lower_bound":-0.020010693202339568,"upper_bound":0.02171369467041855,"unit":"%"},"median":{"estimate":-0.013707044743426655,"lower_bound":-0.03275924600861868,"upper_bound":0.0213260715414158,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_lt_100_100000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[161745083.0,277836583.0,422854542.0,539200250.0,675798375.0,739195292.0,802362459.0,958459292.0,1205018917.0,1268694000.0],"unit":"ns","throughput":[],"typical":{"estimate":126683813.77662338,"lower_bound":121500093.0890411,"upper_bound":132119225.98959805,"unit":"ns"},"mean":{"estimate":132996485.20396826,"lower_bound":125696271.62301588,"upper_bound":141192429.65,"unit":"ns"},"median":{"estimate":134345526.6388889,"lower_bound":123199215.33333333,"upper_bound":138918291.5,"unit":"ns"},"median_abs_dev":{"estimate":10439070.922869444,"lower_bound":1207056.3387537897,"upper_bound":21554209.12225297,"unit":"ns"},"slope":{"estimate":126683813.77662338,"lower_bound":121500093.0890411,"upper_bound":132119225.98959805,"unit":"ns"},"change":{"mean":{"estimate":0.17297604659856036,"lower_bound":0.09096902690547966,"upper_bound":0.264521960851587,"unit":"%"},"median":{"estimate":0.16733961428623534,"lower_bound":0.042216633046819,"upper_bound":0.28978401654262576,"unit":"%"},"change":"Regressed"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_ordered_10/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_lt_ordered_10_100000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[5405387917.0,5452011167.0,5421261583.0,5388722750.0,5413404667.0,5397228083.0,5445349291.0,5440807958.0,5408532792.0,5450068958.0],"unit":"ns","throughput":[],"typical":{"estimate":5422277516.6,"lower_bound":5408756609.190001,"upper_bound":5435871675.0,"unit":"ns"},"mean":{"estimate":5422277516.6,"lower_bound":5408756609.190001,"upper_bound":5435871675.0,"unit":"ns"},"median":{"estimate":5417333125.0,"lower_bound":5402880437.5,"upper_bound":5445438458.0,"unit":"ns"},"median_abs_dev":{"estimate":32305760.763958097,"lower_bound":5824331.727397442,"upper_bound":38415307.66129196,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":0.001210527357005775,"lower_bound":-0.00456616383630032,"upper_bound":0.006302502341199255,"unit":"%"},"median":{"estimate":0.0023719678574927183,"lower_bound":-0.0055289293474898304,"upper_bound":0.011146873858361772,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_ordered_10/100000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_lt_ordered_10_100000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[5477338875.0,5460186542.0,5481207500.0,5509203667.0,5519006792.0,5462065417.0,5456039417.0,5443730500.0,5477298333.0,5539629209.0],"unit":"ns","throughput":[],"typical":{"estimate":5482570625.2,"lower_bound":5465510768.815,"upper_bound":5501389197.77,"unit":"ns"},"mean":{"estimate":5482570625.2,"lower_bound":5465510768.815,"upper_bound":5501389197.77,"unit":"ns"},"median":{"estimate":5477318604.0,"lower_bound":5459052417.0,"upper_bound":5509203667.0,"unit":"ns"},"median_abs_dev":{"estimate":28474258.37818086,"lower_bound":2897865.445652604,"upper_bound":49477696.97159529,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.11569970783606986,"lower_bound":-0.15537613655093518,"upper_bound":-0.0685032399227389,"unit":"%"},"median":{"estimate":-0.15464969386771998,"lower_bound":-0.16342718254156408,"upper_bound":-0.00061863563588338,"unit":"%"},"change":"Improved"}} +{"reason":"group-complete","group_name":"ORE","benchmarks":["ORE/ore/range_gt_100/1000000","ORE/ore_decrypt/range_lt_10/1000000","ORE/ore_decrypt/range_gt_100/10000","ORE/ore_decrypt/range_lt_ordered_10/10000","ORE/ore/range_gt_10/1000000","ORE/ore/exact/1000000","ORE/ore/range_lt_100/1000000","ORE/ore/range_lt_100/10000","ORE/ore_decrypt/exact/10000","ORE/ore_decrypt/range_gt_100/1000000","ORE/ore_decrypt/range_lt_ordered_10/1000000","ORE/ore_decrypt/exact/1000000","ORE/ore_decrypt/range_gt_10/10000","ORE/ore/range_gt_10/10000","ORE/ore/range_gt_100/10000","ORE/ore/range_lt_10/10000","ORE/ore_decrypt/range_lt_10/10000","ORE/ore/range_lt_ordered_10/1000000","ORE/ore/range_lt_ordered_10/10000","ORE/ore_decrypt/range_lt_100/1000000","ORE/ore/range_lt_10/1000000","ORE/ore_decrypt/range_lt_100/10000","ORE/ore_decrypt/range_gt_10/1000000","ORE/ore/exact/10000","ORE/ore/exact/100000","ORE/ore_decrypt/exact/100000","ORE/ore/range_gt_10/100000","ORE/ore_decrypt/range_gt_10/100000","ORE/ore/range_gt_100/100000","ORE/ore_decrypt/range_gt_100/100000","ORE/ore/range_lt_10/100000","ORE/ore_decrypt/range_lt_10/100000","ORE/ore/range_lt_100/100000","ORE/ore_decrypt/range_lt_100/100000","ORE/ore/range_lt_ordered_10/100000","ORE/ore_decrypt/range_lt_ordered_10/100000"],"report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE"} diff --git a/results/query/ore_rows_1000000.json b/results/query/ore_rows_1000000.json new file mode 100644 index 0000000..8053488 --- /dev/null +++ b/results/query/ore_rows_1000000.json @@ -0,0 +1,13 @@ +{"reason":"benchmark-complete","id":"ORE/ore/exact/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_exact_1000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[18552143541.0,18416422500.0,18452985792.0,18498167041.0,18453926333.0,18403969208.0,18498081292.0,18445438417.0,18428553833.0,18507314333.0],"unit":"ns","throughput":[],"typical":{"estimate":18465700229.0,"lower_bound":18439153766.7,"upper_bound":18493617745.5,"unit":"ns"},"mean":{"estimate":18465700229.0,"lower_bound":18439153766.7,"upper_bound":18493617745.5,"unit":"ns"},"median":{"estimate":18453456062.5,"lower_bound":18428553833.0,"upper_bound":18498167041.0,"unit":"ns"},"median_abs_dev":{"estimate":60533661.43491268,"lower_bound":6292092.019093037,"upper_bound":78708638.05264235,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.07684884507973988,"lower_bound":-0.11940512259695935,"upper_bound":-0.035117178883203606,"unit":"%"},"median":{"estimate":-0.04221232106134398,"lower_bound":-0.13306968176110034,"upper_bound":-0.011800161189673974,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/exact/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_exact_1000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[18481063917.0,18454722000.0,18532150750.0,18502887958.0,19683452084.0,18574521583.0,18455517584.0,18431763375.0,18533762959.0,18531336667.0],"unit":"ns","throughput":[],"typical":{"estimate":18618117887.7,"lower_bound":18478770512.8,"upper_bound":18863945567.0,"unit":"ns"},"mean":{"estimate":18618117887.7,"lower_bound":18478770512.8,"upper_bound":18863945567.0,"unit":"ns"},"median":{"estimate":18517112312.5,"lower_bound":18455517584.0,"upper_bound":18553336166.5,"unit":"ns"},"median_abs_dev":{"estimate":69280166.57583117,"lower_bound":1798610.2276682854,"upper_bound":113602616.58605039,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.06528825108761838,"lower_bound":-0.10098203535209396,"upper_bound":-0.03422371297298862,"unit":"%"},"median":{"estimate":-0.0470176984915156,"lower_bound":-0.08917936649140157,"upper_bound":-0.03515277992835886,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_gt_10_1000000","iteration_count":[48,96,144,192,240,288,336,384,432,480],"measured_values":[92331541.0,183205542.0,265712000.0,379895541.0,431949875.0,527657875.0,613254375.0,717114083.0,816091375.0,906692167.0],"unit":"ns","throughput":[],"typical":{"estimate":1869188.0274891774,"lower_bound":1840784.2698175043,"upper_bound":1889855.0890804597,"unit":"ns"},"mean":{"estimate":1875843.5051248348,"lower_bound":1845851.7365932541,"upper_bound":1908437.269341084,"unit":"ns"},"median":{"estimate":1878213.3028645832,"lower_bound":1832145.3993055555,"upper_bound":1908391.0625,"unit":"ns"},"median_abs_dev":{"estimate":58082.00195425493,"lower_bound":14417.578964661761,"upper_bound":92870.34806059697,"unit":"ns"},"slope":{"estimate":1869188.0274891774,"lower_bound":1840784.2698175043,"upper_bound":1889855.0890804597,"unit":"ns"},"change":{"mean":{"estimate":-0.08244695531911939,"lower_bound":-0.13148579150213316,"upper_bound":-0.03159741153680967,"unit":"%"},"median":{"estimate":-0.06998842406834993,"lower_bound":-0.16033410644252988,"upper_bound":0.007525734668192063,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_gt_10_1000000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[140530000.0,279558042.0,398783834.0,485166542.0,633570709.0,861178292.0,982028208.0,1017560833.0,1179392916.0,1341668542.0],"unit":"ns","throughput":[],"typical":{"estimate":66516224.46103896,"lower_bound":64553101.34266463,"upper_bound":68571023.87371135,"unit":"ns"},"mean":{"estimate":66873390.897916675,"lower_bound":64681306.19833334,"upper_bound":68956894.9395,"unit":"ns"},"median":{"estimate":66773699.71666667,"lower_bound":63597552.0625,"upper_bound":70144872.0,"unit":"ns"},"median_abs_dev":{"estimate":4853528.1835014,"lower_bound":356537.36519269866,"upper_bound":6232692.219477599,"unit":"ns"},"slope":{"estimate":66516224.46103896,"lower_bound":64553101.34266463,"upper_bound":68571023.87371135,"unit":"ns"},"change":{"mean":{"estimate":0.09085253910266244,"lower_bound":0.04058366868494484,"upper_bound":0.13511750246685203,"unit":"%"},"median":{"estimate":0.11350086733825093,"lower_bound":0.045636210936014,"upper_bound":0.1706779339734814,"unit":"%"},"change":"Regressed"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_100/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_gt_100_1000000","iteration_count":[8,16,24,32,40,48,56,64,72,80],"measured_values":[107006459.0,204317750.0,323258417.0,410508208.0,523629125.0,637597209.0,735639708.0,825889375.0,937861042.0,1036086792.0],"unit":"ns","throughput":[],"typical":{"estimate":13029022.459415585,"lower_bound":12956603.18598434,"upper_bound":13140842.216710113,"unit":"ns"},"mean":{"estimate":13083502.981790675,"lower_bound":12950104.577224206,"upper_bound":13223835.018593749,"unit":"ns"},"median":{"estimate":13058287.965277778,"lower_bound":12889733.2,"upper_bound":13283275.1875,"unit":"ns"},"median_abs_dev":{"estimate":280770.11514189653,"lower_bound":81969.65493641348,"upper_bound":388955.0993196666,"unit":"ns"},"slope":{"estimate":13029022.459415585,"lower_bound":12956603.18598434,"upper_bound":13140842.216710113,"unit":"ns"},"change":{"mean":{"estimate":-0.056318523847986635,"lower_bound":-0.07146715354810661,"upper_bound":-0.04160679922176208,"unit":"%"},"median":{"estimate":-0.06188587770722909,"lower_bound":-0.07778872442293616,"upper_bound":-0.033731437680352694,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_100/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_gt_100_1000000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[100628959.0,216942042.0,319082416.0,441704583.0,542051417.0,638663458.0,720689583.0,900531958.0,1158549792.0,1240434125.0],"unit":"ns","throughput":[],"typical":{"estimate":116574515.78961039,"lower_bound":106701196.42502731,"upper_bound":122916604.17168675,"unit":"ns"},"mean":{"estimate":110903444.07809524,"lower_bound":106145365.56452383,"upper_bound":116519228.6197619,"unit":"ns"},"median":{"estimate":108440652.2,"lower_bound":104699782.1904762,"upper_bound":117234779.125,"unit":"ns"},"median_abs_dev":{"estimate":4600277.4829037525,"lower_bound":1494358.7335248247,"upper_bound":14495845.1701723,"unit":"ns"},"slope":{"estimate":116574515.78961039,"lower_bound":106701196.42502731,"upper_bound":122916604.17168675,"unit":"ns"},"change":{"mean":{"estimate":-0.627361180873824,"lower_bound":-0.8345929966499501,"upper_bound":-0.014664173518557467,"unit":"%"},"median":{"estimate":-0.0910316588954787,"lower_bound":-0.14558147869494542,"upper_bound":-0.031877989603001144,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_lt_10_1000000","iteration_count":[37,74,111,148,185,222,259,296,333,370],"measured_values":[96466708.0,186889417.0,278256792.0,367736958.0,536331792.0,579835667.0,640293208.0,725973500.0,834145208.0,925893833.0],"unit":"ns","throughput":[],"typical":{"estimate":2526691.637065637,"lower_bound":2481244.757396991,"upper_bound":2616524.615972569,"unit":"ns"},"mean":{"estimate":2556737.5302917203,"lower_bound":2495146.5739424066,"upper_bound":2644200.013091913,"unit":"ns"},"median":{"estimate":2505879.2552552554,"lower_bound":2484709.1756756757,"upper_bound":2607208.3243243243,"unit":"ns"},"median_abs_dev":{"estimate":40678.67856384534,"lower_bound":3743.267968318887,"upper_bound":143739.9917751323,"unit":"ns"},"slope":{"estimate":2526691.637065637,"lower_bound":2481244.757396991,"upper_bound":2616524.615972569,"unit":"ns"},"change":{"mean":{"estimate":0.24516972700188555,"lower_bound":0.20006151820078313,"upper_bound":0.30078550079416155,"unit":"%"},"median":{"estimate":0.19157175346728672,"lower_bound":0.18054353037908122,"upper_bound":0.2601431564420158,"unit":"%"},"change":"Regressed"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_lt_10_1000000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[120491042.0,240116708.0,382063375.0,497495667.0,621045666.0,720565375.0,857792375.0,962829875.0,1118922125.0,1219111334.0],"unit":"ns","throughput":[],"typical":{"estimate":61213137.55974026,"lower_bound":60626994.6392573,"upper_bound":61880335.981481485,"unit":"ns"},"mean":{"estimate":61285622.48188492,"lower_bound":60600793.695375994,"upper_bound":62033369.4155754,"unit":"ns"},"median":{"estimate":61113225.31428571,"lower_bound":60146317.79166667,"upper_bound":62162340.277777776,"unit":"ns"},"median_abs_dev":{"estimate":1512590.1906828282,"lower_bound":61077.021723165,"upper_bound":2245974.226792652,"unit":"ns"},"slope":{"estimate":61213137.55974026,"lower_bound":60626994.6392573,"upper_bound":61880335.981481485,"unit":"ns"},"change":{"mean":{"estimate":-0.006557907598646051,"lower_bound":-0.031357311102208296,"upper_bound":0.02008889511692757,"unit":"%"},"median":{"estimate":-0.00922979802004087,"lower_bound":-0.05038073669938248,"upper_bound":0.025032890501313965,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_100/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_lt_100_1000000","iteration_count":[8,16,24,32,40,48,56,64,72,80],"measured_values":[100019167.0,195923833.0,298314708.0,394645541.0,494364083.0,579871042.0,674200125.0,781909125.0,876781375.0,981648333.0],"unit":"ns","throughput":[],"typical":{"estimate":12207347.197402596,"lower_bound":12135002.810149586,"upper_bound":12273688.9282453,"unit":"ns"},"mean":{"estimate":12265457.816135911,"lower_bound":12180101.888577875,"upper_bound":12351148.756798364,"unit":"ns"},"median":{"estimate":12257921.8625,"lower_bound":12148988.393229168,"upper_bound":12381226.328125,"unit":"ns"},"median_abs_dev":{"estimate":134607.45903690616,"lower_bound":39492.078046062685,"upper_bound":258812.13386766566,"unit":"ns"},"slope":{"estimate":12207347.197402596,"lower_bound":12135002.810149586,"upper_bound":12273688.9282453,"unit":"ns"},"change":{"mean":{"estimate":-0.09684209803067856,"lower_bound":-0.1058305680974634,"upper_bound":-0.08715473921646978,"unit":"%"},"median":{"estimate":-0.09949687808691965,"lower_bound":-0.11075578412984921,"upper_bound":-0.08395744028278239,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_100/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_lt_100_1000000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[99816584.0,241466458.0,377929542.0,439947667.0,617424250.0,702921667.0,838419250.0,1003105417.0,1105104875.0,1181616083.0],"unit":"ns","throughput":[],"typical":{"estimate":120615228.14805195,"lower_bound":117967700.39348371,"upper_bound":123156030.46271929,"unit":"ns"},"mean":{"estimate":118326509.94686508,"lower_bound":113214724.00733629,"upper_bound":122451545.06984127,"unit":"ns"},"median":{"estimate":120253703.78571428,"lower_bound":114074262.525,"upper_bound":124088803.84027778,"unit":"ns"},"median_abs_dev":{"estimate":4693347.263826426,"lower_bound":1421888.1401564458,"upper_bound":11372569.215186538,"unit":"ns"},"slope":{"estimate":120615228.14805195,"lower_bound":117967700.39348371,"upper_bound":123156030.46271929,"unit":"ns"},"change":{"mean":{"estimate":-0.000553042638222534,"lower_bound":-0.06680316128712162,"upper_bound":0.06417143162147178,"unit":"%"},"median":{"estimate":0.04322571318814572,"lower_bound":-0.0529087867900786,"upper_bound":0.09516360588810602,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_ordered_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_range_lt_ordered_10_1000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[53164901208.0,62765459542.0,65442200375.0,63025703541.0,63162961666.0,63109415708.0,63075897500.0,63340631041.0,63297718000.0,63252550916.0],"unit":"ns","throughput":[],"typical":{"estimate":62363743949.7,"lower_bound":60141913373.2075,"upper_bound":63793709880.6325,"unit":"ns"},"mean":{"estimate":62363743949.7,"lower_bound":60141913373.2075,"upper_bound":63793709880.6325,"unit":"ns"},"median":{"estimate":63136188687.0,"lower_bound":62920678521.0,"upper_bound":63297718000.0,"unit":"ns"},"median_abs_dev":{"estimate":206000996.42735124,"lower_bound":62055828.29538882,"upper_bound":1791349071.2413967,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.07182137631227425,"lower_bound":-0.11148470663338966,"upper_bound":-0.025388338266350365,"unit":"%"},"median":{"estimate":-0.0860665134374492,"lower_bound":-0.08954903468343856,"upper_bound":-0.049692942733929324,"unit":"%"},"change":"Improved"}} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_ordered_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE/ore_decrypt_range_lt_ordered_10_1000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[66440666125.0,66350871958.0,66754950458.0,67019326709.0,66536834667.0,67341184625.0,66738836458.0,65961977458.0,63763653542.0,63404514500.0],"unit":"ns","throughput":[],"typical":{"estimate":66031281650.0,"lower_bound":65160299575.0,"upper_bound":66731704783.40501,"unit":"ns"},"mean":{"estimate":66031281650.0,"lower_bound":65160299575.0,"upper_bound":66731704783.40501,"unit":"ns"},"median":{"estimate":66488750396.0,"lower_bound":65057262750.0,"upper_bound":66879081583.5,"unit":"ns"},"median_abs_dev":{"estimate":587830874.4639158,"lower_bound":137854153.73429954,"upper_bound":1895847257.107383,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":-0.04386863793297602,"lower_bound":-0.06205944376615574,"upper_bound":-0.025618212236110768,"unit":"%"},"median":{"estimate":-0.04262675332399868,"lower_bound":-0.06289452265679885,"upper_bound":-0.01146251102359308,"unit":"%"},"change":"Improved"}} +{"reason":"group-complete","group_name":"ORE","benchmarks":["ORE/ore_decrypt/range_lt_ordered_10/100000","ORE/ore/range_lt_10/100000","ORE/ore_decrypt/range_gt_100/10000","ORE/ore_decrypt/range_lt_ordered_10/10000","ORE/ore_decrypt/range_lt_100/100000","ORE/ore_decrypt/range_gt_10/100000","ORE/ore/range_lt_ordered_10/100000","ORE/ore/range_gt_100/100000","ORE/ore/range_lt_100/10000","ORE/ore_decrypt/exact/10000","ORE/ore/range_lt_100/100000","ORE/ore_decrypt/range_gt_10/10000","ORE/ore/range_gt_10/10000","ORE/ore_decrypt/range_gt_100/100000","ORE/ore_decrypt/range_lt_10/100000","ORE/ore/range_gt_100/10000","ORE/ore/range_lt_10/10000","ORE/ore_decrypt/range_lt_10/10000","ORE/ore/range_lt_ordered_10/10000","ORE/ore/exact/100000","ORE/ore_decrypt/exact/100000","ORE/ore/range_gt_10/100000","ORE/ore_decrypt/range_lt_100/10000","ORE/ore/exact/10000","ORE/ore/exact/1000000","ORE/ore_decrypt/exact/1000000","ORE/ore/range_gt_10/1000000","ORE/ore_decrypt/range_gt_10/1000000","ORE/ore/range_gt_100/1000000","ORE/ore_decrypt/range_gt_100/1000000","ORE/ore/range_lt_10/1000000","ORE/ore_decrypt/range_lt_10/1000000","ORE/ore/range_lt_100/1000000","ORE/ore_decrypt/range_lt_100/1000000","ORE/ore/range_lt_ordered_10/1000000","ORE/ore_decrypt/range_lt_ordered_10/1000000"],"report_directory":"/Users/dan/Projects/CipherStash/ore-benches/target/criterion/reports/ORE"} diff --git a/sql/indexes/integer_encrypted_10000000_down.sql b/sql/indexes/integer_encrypted_10000000_down.sql new file mode 100644 index 0000000..ad69b5d --- /dev/null +++ b/sql/indexes/integer_encrypted_10000000_down.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS integer_encrypted_10000000_eql_index; diff --git a/sql/indexes/integer_encrypted_10000000_up.sql b/sql/indexes/integer_encrypted_10000000_up.sql new file mode 100644 index 0000000..080226f --- /dev/null +++ b/sql/indexes/integer_encrypted_10000000_up.sql @@ -0,0 +1,5 @@ +CREATE INDEX +integer_encrypted_10000000_eql_index +ON integer_encrypted_10000000 ( + value eql_v2.encrypted_operator_class +); diff --git a/sql/indexes/integer_encrypted_1000000_down.sql b/sql/indexes/integer_encrypted_1000000_down.sql new file mode 100644 index 0000000..dfb01b7 --- /dev/null +++ b/sql/indexes/integer_encrypted_1000000_down.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS integer_encrypted_1000000_eql_index; diff --git a/sql/indexes/integer_encrypted_1000000_up.sql b/sql/indexes/integer_encrypted_1000000_up.sql new file mode 100644 index 0000000..21d89b7 --- /dev/null +++ b/sql/indexes/integer_encrypted_1000000_up.sql @@ -0,0 +1,5 @@ +CREATE INDEX +integer_encrypted_1000000_eql_index +ON integer_encrypted_1000000 ( + value eql_v2.encrypted_operator_class +); diff --git a/sql/indexes/integer_encrypted_100000_down.sql b/sql/indexes/integer_encrypted_100000_down.sql new file mode 100644 index 0000000..d22397b --- /dev/null +++ b/sql/indexes/integer_encrypted_100000_down.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS integer_encrypted_100000_eql_index; diff --git a/sql/indexes/integer_encrypted_100000_up.sql b/sql/indexes/integer_encrypted_100000_up.sql new file mode 100644 index 0000000..b356598 --- /dev/null +++ b/sql/indexes/integer_encrypted_100000_up.sql @@ -0,0 +1,5 @@ +CREATE INDEX +integer_encrypted_100000_eql_index +ON integer_encrypted_100000 ( + value eql_v2.encrypted_operator_class +); diff --git a/sql/indexes/integer_encrypted_10000_down.sql b/sql/indexes/integer_encrypted_10000_down.sql new file mode 100644 index 0000000..0625716 --- /dev/null +++ b/sql/indexes/integer_encrypted_10000_down.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS integer_encrypted_10000_eql_index; diff --git a/sql/indexes/integer_encrypted_10000_up.sql b/sql/indexes/integer_encrypted_10000_up.sql new file mode 100644 index 0000000..fb2a9f4 --- /dev/null +++ b/sql/indexes/integer_encrypted_10000_up.sql @@ -0,0 +1,5 @@ +CREATE INDEX +integer_encrypted_10000_eql_index +ON integer_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); diff --git a/sql/indexes/integer_encrypted_down.sql b/sql/indexes/integer_encrypted_down.sql new file mode 100644 index 0000000..ecf0064 --- /dev/null +++ b/sql/indexes/integer_encrypted_down.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS integer_encrypted_eql_index; diff --git a/sql/indexes/integer_encrypted_up.sql b/sql/indexes/integer_encrypted_up.sql new file mode 100644 index 0000000..c1de77b --- /dev/null +++ b/sql/indexes/integer_encrypted_up.sql @@ -0,0 +1,5 @@ +CREATE INDEX +integer_encrypted_eql_index +ON integer_encrypted ( + value eql_v2.encrypted_operator_class +); diff --git a/sql/indexes/string_encrypted_10000000_down.sql b/sql/indexes/string_encrypted_10000000_down.sql new file mode 100644 index 0000000..78304e4 --- /dev/null +++ b/sql/indexes/string_encrypted_10000000_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS string_encrypted_10000000_hash_index; +DROP INDEX IF EXISTS string_encrypted_10000000_gin_index; +DROP INDEX IF EXISTS string_encrypted_10000000_eql_index; diff --git a/sql/indexes/string_encrypted_10000000_up.sql b/sql/indexes/string_encrypted_10000000_up.sql new file mode 100644 index 0000000..600e376 --- /dev/null +++ b/sql/indexes/string_encrypted_10000000_up.sql @@ -0,0 +1,17 @@ +CREATE INDEX +string_encrypted_10000000_hash_index +ON string_encrypted_10000000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000000_gin_index +ON string_encrypted_10000000 USING GIN ( + eql_v2.bloom_filter(value) +); + +CREATE INDEX +string_encrypted_10000000_eql_index +ON string_encrypted_10000000 ( + value eql_v2.encrypted_operator_class +); diff --git a/sql/indexes/string_encrypted_1000000_down.sql b/sql/indexes/string_encrypted_1000000_down.sql new file mode 100644 index 0000000..15e46e7 --- /dev/null +++ b/sql/indexes/string_encrypted_1000000_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS string_encrypted_1000000_hash_index; +DROP INDEX IF EXISTS string_encrypted_1000000_gin_index; +DROP INDEX IF EXISTS string_encrypted_1000000_eql_index; diff --git a/sql/indexes/string_encrypted_1000000_up.sql b/sql/indexes/string_encrypted_1000000_up.sql new file mode 100644 index 0000000..e75d40b --- /dev/null +++ b/sql/indexes/string_encrypted_1000000_up.sql @@ -0,0 +1,17 @@ +CREATE INDEX +string_encrypted_1000000_hash_index +ON string_encrypted_1000000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_1000000_gin_index +ON string_encrypted_1000000 USING GIN ( + eql_v2.bloom_filter(value) +); + +CREATE INDEX +string_encrypted_1000000_eql_index +ON string_encrypted_1000000 ( + value eql_v2.encrypted_operator_class +); diff --git a/sql/indexes/string_encrypted_100000_down.sql b/sql/indexes/string_encrypted_100000_down.sql new file mode 100644 index 0000000..c583126 --- /dev/null +++ b/sql/indexes/string_encrypted_100000_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS string_encrypted_100000_hash_index; +DROP INDEX IF EXISTS string_encrypted_100000_gin_index; +DROP INDEX IF EXISTS string_encrypted_100000_eql_index; diff --git a/sql/indexes/string_encrypted_100000_up.sql b/sql/indexes/string_encrypted_100000_up.sql new file mode 100644 index 0000000..8fda3f0 --- /dev/null +++ b/sql/indexes/string_encrypted_100000_up.sql @@ -0,0 +1,17 @@ +CREATE INDEX +string_encrypted_100000_hash_index +ON string_encrypted_100000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_100000_gin_index +ON string_encrypted_100000 USING GIN ( + eql_v2.bloom_filter(value) +); + +CREATE INDEX +string_encrypted_100000_eql_index +ON string_encrypted_100000 ( + value eql_v2.encrypted_operator_class +); diff --git a/sql/indexes/string_encrypted_10000_down.sql b/sql/indexes/string_encrypted_10000_down.sql new file mode 100644 index 0000000..b1d168c --- /dev/null +++ b/sql/indexes/string_encrypted_10000_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS string_encrypted_10000_hash_index; +DROP INDEX IF EXISTS string_encrypted_10000_gin_index; +DROP INDEX IF EXISTS string_encrypted_10000_eql_index; diff --git a/sql/indexes/string_encrypted_10000_up.sql b/sql/indexes/string_encrypted_10000_up.sql new file mode 100644 index 0000000..c6ed969 --- /dev/null +++ b/sql/indexes/string_encrypted_10000_up.sql @@ -0,0 +1,17 @@ +CREATE INDEX +string_encrypted_10000_hash_index +ON string_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000_gin_index +ON string_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(value) +); + +CREATE INDEX +string_encrypted_10000_eql_index +ON string_encrypted_10000 ( + value eql_v2.encrypted_operator_class +); diff --git a/sql/indexes/string_encrypted_down.sql b/sql/indexes/string_encrypted_down.sql new file mode 100644 index 0000000..14013bb --- /dev/null +++ b/sql/indexes/string_encrypted_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS string_encrypted_hash_index; +DROP INDEX IF EXISTS string_encrypted_gin_index; +DROP INDEX IF EXISTS string_encrypted_eql_index; \ No newline at end of file diff --git a/sql/indexes/string_encrypted_up.sql b/sql/indexes/string_encrypted_up.sql new file mode 100644 index 0000000..3afdc44 --- /dev/null +++ b/sql/indexes/string_encrypted_up.sql @@ -0,0 +1,18 @@ +CREATE INDEX +string_encrypted_hash_index +ON string_encrypted using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_gin_index +ON string_encrypted USING GIN ( + eql_v2.bloom_filter(value) +); + +CREATE INDEX +string_encrypted_eql_index +ON string_encrypted ( + value eql_v2.encrypted_operator_class +); + diff --git a/sql/schema.sql b/sql/schema.sql new file mode 100644 index 0000000..1df34b5 --- /dev/null +++ b/sql/schema.sql @@ -0,0 +1,79 @@ +CREATE TABLE IF NOT EXISTS integer_plaintext ( + id SERIAL PRIMARY KEY, + value INT NOT NULL +); + +CREATE TABLE IF NOT EXISTS integer_encrypted ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS integer_encrypted_10000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS integer_encrypted_100000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS integer_encrypted_1000000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS integer_encrypted_10000000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS string_plaintext ( + id SERIAL PRIMARY KEY, + value TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS string_encrypted ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS string_encrypted_10000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS string_encrypted_100000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS string_encrypted_1000000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS string_encrypted_10000000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS json_small_plaintext ( + id SERIAL PRIMARY KEY, + value JSONB NOT NULL +); + +CREATE TABLE IF NOT EXISTS json_small_encrypted ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS json_large_plaintext ( + id SERIAL PRIMARY KEY, + value JSONB NOT NULL +); + +CREATE TABLE IF NOT EXISTS json_large_encrypted ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); \ No newline at end of file diff --git a/src/bin/combine_benchmark.rs b/src/bin/combine_benchmark.rs new file mode 100644 index 0000000..b3a1a9f --- /dev/null +++ b/src/bin/combine_benchmark.rs @@ -0,0 +1,266 @@ +//! Combine benchmark results from hyperfine into a single summary file +//! +//! This binary processes hyperfine benchmark results and combines them with +//! system metadata (CPU, memory, OS) and validation data from individual runs +//! to produce a comprehensive benchmark summary. +//! +//! The output includes: +//! - Metadata: timestamp, Rust version, PostgreSQL version, host information +//! - Results: throughput, timing, and memory usage for each benchmark run +//! +//! Usage: +//! combine_benchmark +//! +//! Example: +//! combine_benchmark encrypt_int +//! +//! This reads: +//! - target/{benchmark_name}_hyperfine.json (hyperfine results) +//! - target/{benchmark_name}-{num_records}_{run_idx}.json (validation files) +//! +//! And outputs to: +//! - results/ingest/{benchmark_name}_combined.json + +use anyhow::{bail, Context, Result}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::env; +use std::fs; +use std::path::Path; +use std::process::Command; + +#[derive(Debug, Deserialize)] +struct HyperfineResult { + results: Vec, +} + +#[derive(Debug, Deserialize)] +struct BenchmarkResult { + mean: f64, + times: Vec, + memory_usage_byte: Vec, + parameters: HashMap, +} + +#[derive(Debug, Deserialize)] +struct OutputFile { + inserted: u64, +} + +#[derive(Debug, Serialize)] +struct CombinedResult { + num_records: u64, + total_time_seconds: f64, + total_records: u64, + throughput_records_per_second: f64, + average_memory_usage_bytes: u64, + average_memory_usage_mb: f64, + num_runs: usize, +} + +#[derive(Debug, Serialize)] +struct Metadata { + timestamp: String, + rust_version: String, + postgres_version: Option, + host_info: HostInfo, +} + +#[derive(Debug, Serialize)] +struct HostInfo { + os: String, + cpu_model: Option, + cpu_cores: Option, + total_memory_gb: Option, +} + +#[derive(Debug, Serialize)] +struct CombinedOutput { + metadata: Metadata, + results: Vec, +} + +fn get_command_output(cmd: &str, args: &[&str]) -> Option { + Command::new(cmd) + .args(args) + .output() + .ok() + .and_then(|output| { + if output.status.success() { + String::from_utf8(output.stdout).ok() + } else { + None + } + }) + .map(|s| s.trim().to_string()) +} + +fn get_rust_version() -> String { + get_command_output("rustc", &["--version"]).unwrap_or_else(|| "unknown".to_string()) +} + +fn get_postgres_version() -> Option { + // Try to get version from running Docker container + get_command_output( + "docker", + &["exec", "ore-benches-postgres", "psql", "--version"], + ) +} + +fn get_host_info() -> HostInfo { + let os = if cfg!(target_os = "macos") { + "macOS".to_string() + } else if cfg!(target_os = "linux") { + "Linux".to_string() + } else if cfg!(target_os = "windows") { + "Windows".to_string() + } else { + "Unknown".to_string() + }; + + let cpu_model = if cfg!(target_os = "macos") { + get_command_output("sysctl", &["-n", "machdep.cpu.brand_string"]) + } else if cfg!(target_os = "linux") { + get_command_output("grep", &["-m", "1", "model name", "/proc/cpuinfo"]).map(|s| { + s.split(':') + .nth(1) + .map(|s| s.trim().to_string()) + .unwrap_or(s) + }) + } else { + None + }; + + let cpu_cores = if cfg!(target_os = "macos") { + get_command_output("sysctl", &["-n", "hw.ncpu"]).and_then(|s| s.parse().ok()) + } else if cfg!(target_os = "linux") { + get_command_output("nproc", &[]).and_then(|s| s.parse().ok()) + } else { + None + }; + + let total_memory_gb = if cfg!(target_os = "macos") { + get_command_output("sysctl", &["-n", "hw.memsize"]) + .and_then(|s| s.parse::().ok()) + .map(|bytes| bytes as f64 / (1024.0 * 1024.0 * 1024.0)) + } else if cfg!(target_os = "linux") { + get_command_output("grep", &["MemTotal", "/proc/meminfo"]).and_then(|s| { + s.split_whitespace() + .nth(1) + .and_then(|kb| kb.parse::().ok()) + .map(|kb| kb as f64 / (1024.0 * 1024.0)) + }) + } else { + None + }; + + HostInfo { + os, + cpu_model, + cpu_cores, + total_memory_gb, + } +} + +fn main() -> Result<()> { + let args: Vec = env::args().collect(); + if args.len() != 2 { + anyhow::bail!( + "Usage: {} ", + args.get(0) + .map(|s| s.as_str()) + .unwrap_or("combine_benchmark") + ); + } + + let benchmark_name = &args[1]; + let hyperfine_file = format!("target/{}_hyperfine.json", benchmark_name); + + // Read hyperfine results + let hyperfine_data = fs::read_to_string(&hyperfine_file).context(format!( + "Failed to read hyperfine results from {}", + hyperfine_file + ))?; + let hyperfine: HyperfineResult = + serde_json::from_str(&hyperfine_data).context("Failed to parse hyperfine JSON")?; + + let mut combined_results = Vec::new(); + + for result in hyperfine.results { + let num_records: u64 = result + .parameters + .get("num_records") + .context("Missing num_records parameter")? + .parse() + .context("Failed to parse num_records as u64")?; + + let num_runs = result.times.len(); + + // Validate output files exist and contain correct data + for run_idx in 0..num_runs { + let output_file = format!("target/{}-{}_{}.json", benchmark_name, num_records, run_idx); + + if !Path::new(&output_file).exists() { + bail!("Expected output file {} does not exist", output_file); + } + + let output_data = fs::read_to_string(&output_file) + .context(format!("Failed to read output file {}", output_file))?; + let output: OutputFile = serde_json::from_str(&output_data) + .context(format!("Failed to parse output file {}", output_file))?; + + if output.inserted != num_records { + bail!( + "Mismatch in {}: expected {} records but file contains {}", + output_file, + num_records, + output.inserted + ); + } + } + + // Calculate average memory usage + let avg_memory = if !result.memory_usage_byte.is_empty() { + result.memory_usage_byte.iter().sum::() / result.memory_usage_byte.len() as u64 + } else { + 0 + }; + + let total_time = result.mean; + let throughput = num_records as f64 / total_time; + + combined_results.push(CombinedResult { + num_records, + total_time_seconds: total_time, + total_records: num_records, + throughput_records_per_second: throughput, + average_memory_usage_bytes: avg_memory, + average_memory_usage_mb: avg_memory as f64 / (1024.0 * 1024.0), + num_runs, + }); + } + + // Sort by num_records for consistent output + combined_results.sort_by_key(|r| r.num_records); + + let metadata = Metadata { + timestamp: chrono::Utc::now().to_rfc3339(), + rust_version: get_rust_version(), + postgres_version: get_postgres_version(), + host_info: get_host_info(), + }; + + let output = CombinedOutput { + metadata, + results: combined_results, + }; + + let json = serde_json::to_string_pretty(&output)?; + + let output_file = format!("results/ingest/{}_combined.json", benchmark_name); + fs::write(&output_file, json).context(format!("Failed to write output to {}", output_file))?; + + println!("Results written to {}", output_file); + + Ok(()) +} diff --git a/src/bin/encrypt_int.rs b/src/bin/encrypt_int.rs new file mode 100644 index 0000000..d223366 --- /dev/null +++ b/src/bin/encrypt_int.rs @@ -0,0 +1,54 @@ +//! Encrypt integer data binary - encrypts generated integers using CipherStash +//! +//! This binary generates random integers using the fake crate and encrypts them +//! using the cipherstash-client library with ORE (Order-Revealing Encryption), +//! storing the encrypted values in the integer_encrypted table (or a suffixed +//! variant based on TABLE_SUFFIX). +//! +//! The encrypted integers support: +//! - Exact match queries +//! - Range queries (>, <, >=, <=) +//! - Ordered queries (ORDER BY) +//! +//! Environment variables: +//! - DATABASE_URL: PostgreSQL connection string +//! - NUM_RECORDS: Number of records to generate (default: 10000) +//! - TABLE_SUFFIX: Optional suffix for table name (e.g., _10000) +//! - CS_CLIENT_ID: CipherStash client ID +//! - CS_CLIENT_KEY: CipherStash client key +//! - CS_WORKSPACE_CRN: CipherStash workspace CRN + +use anyhow::Result; +use cipherstash_client::{ + eql::Identifier, + schema::{column::Index, ColumnConfig, ColumnType}, +}; +use dbbenches::IngestOptionsBuilder; +use fake::Faker; +use std::env; + +#[tokio::main] +async fn main() -> Result<()> { + let num_records: i32 = env::var("NUM_RECORDS") + .unwrap_or_else(|_| "10000".to_string()) + .parse() + .expect("NUM_RECORDS must be a valid integer"); + + let table_suffix = env::var("TABLE_SUFFIX").unwrap_or_default(); + let table_name = format!("integer_encrypted{}", table_suffix); + + IngestOptionsBuilder::new("encrypt_int") + .num_records(num_records) + .batch_size(1000) + .identifier(Identifier::new(&table_name, "value")) + .column_config( + ColumnConfig::build("value") + .casts_as(ColumnType::Int) + .add_index(Index::new_ore()), + ) + .build()? + .ingest::(Faker) + .await?; + + Ok(()) +} diff --git a/src/bin/encrypt_json_large.rs b/src/bin/encrypt_json_large.rs new file mode 100644 index 0000000..3bca947 --- /dev/null +++ b/src/bin/encrypt_json_large.rs @@ -0,0 +1,159 @@ +//! Encrypt large JSON data binary - encrypts generated complex JSON objects using CipherStash +//! +//! This binary generates large, complex JSON objects containing user information, company +//! details, addresses, and order history using the fake crate. The objects are encrypted +//! using the cipherstash-client library with SteVec indexing and stored in the +//! json_large_encrypted table. +//! +//! The encrypted JSON objects support: +//! - Searchable encrypted vectors (SteVec) for term-based searches +//! +//! Environment variables: +//! - DATABASE_URL: PostgreSQL connection string +//! - NUM_RECORDS: Number of records to generate (default: 10000) +//! - CS_CLIENT_ID: CipherStash client ID +//! - CS_CLIENT_KEY: CipherStash client key +//! - CS_WORKSPACE_CRN: CipherStash workspace CRN + +use anyhow::Result; +use cipherstash_client::{ + eql::Identifier, + schema::{ + column::{Index, IndexType}, + ColumnConfig, ColumnType, + }, +}; +use dbbenches::{IngestOptionsBuilder, WrappedJson}; +use fake::{ + faker::{address, chrono, company, internet, name, phone_number}, + Dummy, Fake, Rng, +}; +use serde_json::json; +use std::env; + +struct FakeJsonLarge; + +// FIXME: cipherstash-client doesn't have a From for Plaintext impl yet, so we use String here +impl Dummy for WrappedJson { + fn dummy_with_rng(_config: &FakeJsonLarge, _: &mut R) -> Self { + let department = [ + "Engineering", + "Sales", + "Marketing", + "HR", + "Finance", + "Operations", + ] + .iter() + .take((1..6).fake()) + .last() + .unwrap() + .to_string(); + let type_ = ["Home", "Work", "Billing", "Shipping"] + .iter() + .take((1..4).fake()) + .last() + .unwrap() + .to_string(); + let status = [ + "Pending", + "Processing", + "Shipped", + "Delivered", + "Cancelled", + "Returned", + ] + .iter() + .take((1..6).fake()) + .last() + .unwrap() + .to_string(); + let relationship = ["Spouse", "Parent", "Sibling", "Friend", "Other"] + .iter() + .take((1..5).fake()) + .last() + .unwrap() + .to_string(); + + let value = json!({ + "user": { + "first_name": name::en::FirstName().fake::(), + "last_name": name::en::LastName().fake::(), + "age": (18..=99).fake::(), + "email": internet::en::FreeEmail().fake::(), + "username": internet::en::Username().fake::(), + "contact": { + "phone": phone_number::en::PhoneNumber().fake::(), + "mobile": phone_number::en::CellNumber().fake::(), + "emergency_contact": { + "name": name::en::Name().fake::(), + "phone": phone_number::en::PhoneNumber().fake::(), + "relationship": relationship + } + } + }, + "company": { + "name": company::en::CompanyName().fake::(), + "industry": company::en::Industry().fake::(), + "position": company::en::Profession().fake::(), + "department": department, + "salary": (40000..=300000).fake::(), + "start_date": chrono::en::Date().fake::() + }, + "addresses": (0..(1..4).fake::()).map(|_| { + json!({ + "type": type_, + "street": address::en::StreetName().fake::(), + "city": address::en::CityName().fake::(), + "state": address::en::StateName().fake::(), + "zip": address::en::ZipCode().fake::(), + "country": "United States" + }) + }).collect::>(), + "orders": (0..(5..=20).fake::()).map(|_| { + json!({ + "order_id": format!("ORD-{}", (100000..=999999).fake::()), + "date": chrono::en::Date().fake::(), + "total": (10.0..=5000.0).fake::(), + "status": status, + "items": (0..(1..=8).fake::()).map(|_| { + json!({ + "product": company::en::Buzzword().fake::(), + "quantity": (1..=10).fake::(), + "price": (5.0..=500.0).fake::() + }) + }).collect::>() + }) + }).collect::>() + }); + + WrappedJson(value) + } +} + +#[tokio::main] +async fn main() -> Result<()> { + let num_records: i32 = env::var("NUM_RECORDS") + .unwrap_or_else(|_| "10000".to_string()) + .parse() + .expect("NUM_RECORDS must be a valid integer"); + + IngestOptionsBuilder::new("encrypt_json_large") + .num_records(num_records) + .batch_size(1000) + .identifier(Identifier::new("json_large_encrypted", "value")) + .column_config( + ColumnConfig::build("value") + .casts_as(ColumnType::JsonB) + // FIXME: There is no convenience method for SteVec yet on Index + .add_index(Index::new(IndexType::SteVec { + prefix: "value".to_string(), + term_filters: Default::default(), + })), + ) + .build()? + .ingest::(FakeJsonLarge) + .await?; + + Ok(()) +} diff --git a/src/bin/encrypt_json_small.rs b/src/bin/encrypt_json_small.rs new file mode 100644 index 0000000..5e9ed89 --- /dev/null +++ b/src/bin/encrypt_json_small.rs @@ -0,0 +1,73 @@ +//! Encrypt small JSON data binary - encrypts generated JSON objects using CipherStash +//! +//! This binary generates small JSON objects (first_name, last_name, age, email) using +//! the fake crate and encrypts them using the cipherstash-client library with SteVec +//! indexing, storing the encrypted values in the json_small_encrypted table. +//! +//! The encrypted JSON objects support: +//! - Searchable encrypted vectors (SteVec) for term-based searches +//! +//! Environment variables: +//! - DATABASE_URL: PostgreSQL connection string +//! - NUM_RECORDS: Number of records to generate (default: 10000) +//! - CS_CLIENT_ID: CipherStash client ID +//! - CS_CLIENT_KEY: CipherStash client key +//! - CS_WORKSPACE_CRN: CipherStash workspace CRN + +use anyhow::Result; +use cipherstash_client::{ + eql::Identifier, + schema::{ + column::{Index, IndexType}, + ColumnConfig, ColumnType, + }, +}; +use dbbenches::{IngestOptionsBuilder, WrappedJson}; +use fake::{ + faker::{internet, name}, + Dummy, Fake, Rng, +}; +use serde_json::json; +use std::env; + +struct FakeJsonSmall; + +// FIXME: cipherstash-client doesn't have a From for Plaintext impl yet, so we use String here +impl Dummy for WrappedJson { + fn dummy_with_rng(_config: &FakeJsonSmall, _: &mut R) -> Self { + let value = json!({ + "first_name": name::en::FirstName().fake::(), + "last_name": name::en::LastName().fake::(), + "age": (18..=99).fake::(), + "email": internet::en::FreeEmail().fake::(), + }); + WrappedJson(value) + } +} + +#[tokio::main] +async fn main() -> Result<()> { + let num_records: i32 = env::var("NUM_RECORDS") + .unwrap_or_else(|_| "10000".to_string()) + .parse() + .expect("NUM_RECORDS must be a valid integer"); + + IngestOptionsBuilder::new("encrypt_json_small") + .num_records(num_records) + .batch_size(1000) + .identifier(Identifier::new("json_small_encrypted", "value")) + .column_config( + ColumnConfig::build("value") + .casts_as(ColumnType::JsonB) + // FIXME: There is no convenience method for SteVec yet on Index + .add_index(Index::new(IndexType::SteVec { + prefix: "value".to_string(), + term_filters: Default::default(), + })), + ) + .build()? + .ingest::(FakeJsonSmall) + .await?; + + Ok(()) +} diff --git a/src/bin/encrypt_string.rs b/src/bin/encrypt_string.rs new file mode 100644 index 0000000..c27afe5 --- /dev/null +++ b/src/bin/encrypt_string.rs @@ -0,0 +1,53 @@ +//! Encrypt string data binary - encrypts generated string names using CipherStash +//! +//! This binary generates random names using the fake crate and encrypts them +//! using the cipherstash-client library, storing the encrypted values in the +//! string_encrypted table (or a suffixed variant based on TABLE_SUFFIX). +//! +//! The encrypted strings support: +//! - Exact match queries (using unique index) +//! - Pattern matching queries (using match index) +//! +//! Environment variables: +//! - DATABASE_URL: PostgreSQL connection string +//! - NUM_RECORDS: Number of records to generate (default: 10000) +//! - TABLE_SUFFIX: Optional suffix for table name (e.g., _10000) +//! - CS_CLIENT_ID: CipherStash client ID +//! - CS_CLIENT_KEY: CipherStash client key +//! - CS_WORKSPACE_CRN: CipherStash workspace CRN + +use anyhow::Result; +use cipherstash_client::{ + eql::Identifier, + schema::{column::Index, ColumnConfig, ColumnType}, +}; +use dbbenches::IngestOptionsBuilder; +use fake::{faker::name::raw::Name, locales::EN}; +use std::env; + +#[tokio::main] +async fn main() -> Result<()> { + let num_records: i32 = env::var("NUM_RECORDS") + .unwrap_or_else(|_| "10000".to_string()) + .parse() + .expect("NUM_RECORDS must be a valid integer"); + + let table_suffix = env::var("TABLE_SUFFIX").unwrap_or_default(); + let table_name = format!("string_encrypted{}", table_suffix); + + IngestOptionsBuilder::new("encrypt_string") + .num_records(num_records) + .batch_size(1000) + .identifier(Identifier::new(&table_name, "value")) + .column_config( + ColumnConfig::build("value") + .casts_as(ColumnType::Utf8Str) + .add_index(Index::new_unique()) + .add_index(Index::new_match()), + ) + .build()? + .ingest::>(Name(EN)) + .await?; + + Ok(()) +} diff --git a/src/bin/generate_data.rs b/src/bin/generate_data.rs new file mode 100644 index 0000000..3035950 --- /dev/null +++ b/src/bin/generate_data.rs @@ -0,0 +1,75 @@ +//! Generate random plaintext data for benchmarking +//! +//! This binary generates random integer values and inserts them into the +//! integer_plaintext table. This is used for testing and development purposes. +//! +//! Note: This binary is not currently used in the main benchmark workflow. +//! The ingest benchmarks (encrypt_int, encrypt_string, etc.) generate and +//! encrypt data directly rather than reading from plaintext tables. +//! +//! Environment variables: +//! - DATABASE_URL: PostgreSQL connection string +//! - NUM_RECORDS: Number of records to generate (default: 10000) + +use anyhow::{Context, Result}; +use rand::Rng; +use sqlx::postgres::PgPoolOptions; +use std::env; + +#[tokio::main] +async fn main() -> Result<()> { + let database_url = + env::var("DATABASE_URL").context("DATABASE_URL environment variable must be set")?; + + let num_records: i32 = env::var("NUM_RECORDS") + .unwrap_or_else(|_| "10000".to_string()) + .parse() + .expect("NUM_RECORDS must be a valid integer"); + + println!("Connecting to database..."); + let pool = PgPoolOptions::new() + .max_connections(5) + .connect(&database_url) + .await?; + + println!( + "Generating and inserting {} random integers...", + num_records + ); + + let mut rng = rand::thread_rng(); + let batch_size = 1000; + + for batch_start in (0..num_records).step_by(batch_size) { + let batch_end = (batch_start + batch_size as i32).min(num_records); + let batch_count = batch_end - batch_start; + + // Build bulk insert query + let mut query = "INSERT INTO integer_plaintext (value) VALUES ".to_string(); + let mut values = Vec::new(); + + for i in 0..batch_count { + if i > 0 { + query.push_str(", "); + } + query.push_str(&format!("(${})", i + 1)); + values.push(rng.gen::()); + } + + let mut query_builder = sqlx::query(&query); + for value in values { + query_builder = query_builder.bind(value); + } + + query_builder.execute(&pool).await?; + + println!("Inserted {} / {} records", batch_end, num_records); + } + + println!( + "Successfully inserted {} records into integer_plaintext", + num_records + ); + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ac52ec5 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,267 @@ +use anyhow::{Context, Result}; +use cipherstash_client::{ + config::EnvSource, + credentials::ServiceCredentials, + encryption::{Plaintext, QueryOp, ScopedCipher}, + eql::{decrypt_eql, encrypt_eql, EqlCiphertext, EqlOperation, Identifier, PreparedPlaintext}, + schema::{column::IndexType, ColumnConfig}, + ZeroKMSConfig, +}; +use fake::{Dummy, Fake}; +use serde_json::json; +use sqlx::{postgres::PgPoolOptions, types::Json, QueryBuilder}; +use std::borrow::Cow; +use std::env; +use std::fmt::Debug; +use std::sync::Arc; + +pub async fn init_scoped_cipher() -> Result>> { + let client = ZeroKMSConfig::builder() + .add_source(EnvSource::new()) + .build_with_client_key() + .context("failed to build config")? + .create_client(); + + let scoped_cipher = ScopedCipher::init_default(Arc::new(client)).await?; + Ok(Arc::new(scoped_cipher)) +} + +pub struct IngestOptions { + pub bench_name: String, + pub num_records: i32, + pub batch_size: usize, + pub identifier: Identifier, + pub column_config: ColumnConfig, +} + +pub struct IngestOptionsBuilder { + bench_name: String, + num_records: Option, + batch_size: Option, + identifier: Option, + column_config: Option, +} + +impl IngestOptionsBuilder { + const DEFAULT_BATCH_SIZE: usize = 1000; + const DEFAULT_NUM_RECORDS: i32 = 100_000; + + pub fn new(bench_name: impl Into) -> Self { + Self { + bench_name: bench_name.into(), + num_records: None, + batch_size: None, + identifier: None, + column_config: None, + } + } + + pub fn num_records(mut self, num_records: i32) -> Self { + self.num_records = Some(num_records); + self + } + + pub fn batch_size(mut self, batch_size: usize) -> Self { + self.batch_size = Some(batch_size); + self + } + + pub fn identifier(mut self, identifier: Identifier) -> Self { + self.identifier = Some(identifier); + self + } + + pub fn column_config(mut self, column_config: ColumnConfig) -> Self { + self.column_config = Some(column_config); + self + } + + pub fn build(self) -> Result { + Ok(IngestOptions { + bench_name: self.bench_name, + num_records: self.num_records.unwrap_or(Self::DEFAULT_NUM_RECORDS), + batch_size: self.batch_size.unwrap_or(Self::DEFAULT_BATCH_SIZE), + identifier: self.identifier.context("identifier is required")?, + column_config: self.column_config.context("column_config is required")?, + }) + } +} + +impl IngestOptions { + pub async fn ingest(self, f: F) -> Result<()> + where + T: Into + Dummy<F> + Send + Debug, + { + let database_url = + env::var("DATABASE_URL").context("DATABASE_URL environment variable must be set")?; + + let num_records: i32 = env::var("NUM_RECORDS") + .unwrap_or_else(|_| "10000".to_string()) + .parse() + .expect("NUM_RECORDS must be a valid integer"); + + let hf_iteration: i32 = env::var("HYPERFINE_ITERATION") + .unwrap_or_else(|_| "0".to_string()) + .parse() + .expect("HYPERFINE_ITERATION must be a valid integer"); + + let pool = PgPoolOptions::new() + .max_connections(5) + .connect(&database_url) + .await?; + + let client = ZeroKMSConfig::builder() + .add_source(EnvSource::new()) + .build_with_client_key() + .expect("failed to build config") + .create_client(); + + let scoped_cipher = ScopedCipher::init_default(Arc::new(client)).await?; + let scoped_cipher = Arc::new(scoped_cipher); + + let column_config = Cow::Borrowed(&self.column_config); + + for batch_start in (0..self.num_records).step_by(self.batch_size) { + let batch_end = (batch_start + self.batch_size as i32).min(self.num_records); + let batch_count = batch_end - batch_start; + + let prepared = (0..batch_count) + .map(|_| { + let x: T = f.fake(); + + PreparedPlaintext::new( + // FIXME: take a reference instead of using Cow? + column_config.clone(), + // FIXME: take a reference instead of owning the identifier + self.identifier.clone(), + Plaintext::new(x), + EqlOperation::Store, + ) + }) + .collect::<Vec<_>>(); + + let out = encrypt_eql(scoped_cipher.clone(), prepared, &Default::default()).await?; + + QueryBuilder::new(format!("INSERT INTO {} (value) ", self.identifier.table())) + .push_values(out.into_iter(), |mut b, v| { + b.push_bind(Json(v)); + }) + .build() + .execute(&pool) + .await?; + } + + let result = json!({ + "inserted": num_records + }); + let filename = format!( + "target/{}-{num_records}_{hf_iteration}.json", + self.bench_name + ); + std::fs::write(&filename, serde_json::to_string(&result)?)?; + + Ok(()) + } +} + +#[derive(Debug)] +pub struct WrappedJson(pub serde_json::Value); + +impl From<WrappedJson> for Plaintext { + fn from(WrappedJson(value): WrappedJson) -> Self { + Plaintext::JsonB(Some(value)) + } +} + +pub struct EncryptedQueryBuilder { + pub column_config: ColumnConfig, + pub identifier: Identifier, + pub index_type: Option<IndexType>, + pub statement: Option<String>, +} + +impl EncryptedQueryBuilder { + pub fn new(column_config: ColumnConfig, identifier: Identifier) -> Self { + Self { + column_config, + identifier, + index_type: None, + statement: None, + } + } + + pub fn index_type(mut self, index_type: IndexType) -> Self { + self.index_type = Some(index_type); + self + } + + pub fn statement(mut self, statement: impl Into<String>) -> Self { + self.statement = Some(statement.into()); + self + } + + pub async fn build_query<T>( + self, + plaintext: T, + cipher: Arc<ScopedCipher<ServiceCredentials>>, + ) -> Result<EncryptedQuery> + where + T: Into<Plaintext> + Send + Debug, + { + let index_type = self + .index_type + .context("index_type must be set to build query")?; + + let prepared = PreparedPlaintext::new( + Cow::Owned(self.column_config), + self.identifier.clone(), + plaintext.into(), + EqlOperation::Query(&index_type, QueryOp::Default), + ); + + let mut out = encrypt_eql(Arc::clone(&cipher), vec![prepared], &Default::default()).await?; + + Ok(EncryptedQuery { + eql: out.remove(0), + statement: self.statement.context("statement must be set")?, + scoped_cipher: cipher, + }) + } +} + +pub struct EncryptedQuery { + pub eql: EqlCiphertext, + pub statement: String, + scoped_cipher: Arc<ScopedCipher<ServiceCredentials>>, +} + +impl EncryptedQuery { + pub async fn execute(&self, pool: &sqlx::PgPool) -> Result<Vec<(i32, Json<EqlCiphertext>)>> { + let results: Vec<(i32, Json<EqlCiphertext>)> = sqlx::query_as(&self.statement) + .bind(Json(&self.eql)) + .fetch_all(pool) + .await?; + + Ok(results) + } + + pub async fn execute_and_decrypt<T>(&self, pool: &sqlx::PgPool) -> Result<Vec<T>> + where + T: TryFrom<Plaintext>, + <T as TryFrom<Plaintext>>::Error: Debug, + { + let results: Vec<(i32, Json<EqlCiphertext>)> = self.execute(pool).await?; + + let decrypted = decrypt_eql( + Arc::clone(&self.scoped_cipher), + results.into_iter().map(|(_, value)| value.0), + &Default::default(), + ) + .await? + .into_iter() + .map(|pt| T::try_from(pt).expect("failed to convert plaintext")) + .collect(); + + Ok(decrypted) + } +} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index ab37d56..0000000 --- a/src/main.rs +++ /dev/null @@ -1,24 +0,0 @@ -use sqlx::postgres::PgPoolOptions; - -#[tokio::main] -// or #[tokio::main] -// or #[actix_web::main] -async fn main() -> Result<(), sqlx::Error> { - // Create a connection pool - // for MySQL, use MySqlPoolOptions::new() - // for SQLite, use SqlitePoolOptions::new() - // etc. - let pool = PgPoolOptions::new() - .max_connections(1) - .connect("postgres://dan@localhost/ore_perf").await?; - - // Make a simple query to return the given parameter (use a question mark `?` instead of `$1` for MySQL) - let row: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM test") - //.bind(150_i64) - .fetch_one(&pool).await?; - - println!("ROW: {:?}", row); - //assert_eq!(row.0, 150); - - Ok(()) -}