├── .gitignore ├── .cargo └── config.toml ├── pg_branch.control ├── src ├── fs │ ├── mod.rs │ └── btrfs.rs ├── lib.rs ├── database.rs └── hooks.rs ├── init.sh ├── LICENSE ├── Cargo.toml ├── .github └── workflows │ └── check.yml ├── README.md ├── Cargo.lock └── assets └── logo.svg /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/ 3 | /target 4 | *.iml 5 | **/*.rs.bk 6 | .ccls-cache 7 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.'cfg(target_os="macos")'] 2 | # Postgres symbols won't be available until runtime 3 | rustflags = ["-Clink-arg=-Wl,-undefined,dynamic_lookup"] 4 | -------------------------------------------------------------------------------- /pg_branch.control: -------------------------------------------------------------------------------- 1 | comment = 'pg_branch: Created by pgrx' 2 | default_version = '@CARGO_VERSION@' 3 | module_pathname = '$libdir/pg_branch' 4 | relocatable = false 5 | superuser = true 6 | -------------------------------------------------------------------------------- /src/fs/mod.rs: -------------------------------------------------------------------------------- 1 | pub use btrfs::Btrfs; 2 | use std::path::PathBuf; 3 | 4 | mod btrfs; 5 | 6 | /// The core of any file system's ability to support branching databases 7 | /// is its capacity for atomic snapshots. The Branching trait encapsulates 8 | /// that behavior, and can be implemented by any copy-on-write file system. 9 | pub trait Branching { 10 | /// Create a snapshot of one "subvolume" (or whatever the equivalent term might be) 11 | /// This method is expected to panic if something goes wrong. 12 | fn create_snapshot(source: PathBuf, destination: PathBuf); 13 | } 14 | -------------------------------------------------------------------------------- /init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | # 6 | # Quick script to convert a standard Postgres data directory 7 | # into a collection of branch-able snapshots using a copy-on-write 8 | # file system of choice (only btrfs supported for now). 9 | # 10 | # The target directory for this script is whatever is specified in 11 | # the $PGDATA environment variable. 12 | # 13 | 14 | # scan the args for configuration 15 | fs=btrfs 16 | for arg in "$@"; do 17 | case "$arg" in 18 | --btrfs) 19 | fs='master' 20 | ;; 21 | esac 22 | # TODO: support zfs, xfs 23 | done 24 | 25 | # convert the segment data directories in $PGDATA/base to $fs subvolumes 26 | while read -r SEGMENT; do 27 | echo "converting $SEGMENT to $fs subvolume..." 28 | mv "$SEGMENT" "${SEGMENT}_old" 29 | $fs subvolume create "$SEGMENT" 30 | cp ${SEGMENT}_old/* "$SEGMENT/" 31 | rm -rf "${SEGMENT}_old" 32 | done <<<$(find "$PGDATA/base" -maxdepth 1 -type d | tail -n +2) 33 | 34 | echo "$fs conversion of $PGDATA complete!" 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alex Pearson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/fs/btrfs.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | #![allow(unused)] 5 | 6 | use super::Branching; 7 | use std::path::PathBuf; 8 | use std::{ffi::c_char, os::unix::ffi::OsStrExt, path::Path}; 9 | 10 | /// Wrapper type used for implementing the Branching trait for the btrfs file system 11 | pub struct Btrfs; 12 | 13 | impl Branching for Btrfs { 14 | fn create_snapshot(source: PathBuf, destination: PathBuf) { 15 | let exit_code = unsafe { 16 | let source_path = 17 | std::ffi::CString::new(source.as_os_str().as_bytes()).expect("Invalid source path"); 18 | 19 | let destination_path = std::ffi::CString::new(destination.as_os_str().as_bytes()) 20 | .expect("Invalid destination path"); 21 | 22 | btrfsutil_sys::btrfs_util_create_snapshot( 23 | source_path.as_ptr(), 24 | destination_path.as_ptr(), 25 | 0, 26 | std::ptr::null_mut(), 27 | std::ptr::null_mut(), 28 | ) 29 | }; 30 | 31 | if exit_code > 0 { 32 | panic!("Failed to create a snapshot"); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pg_branch" 3 | version = "0.0.1" 4 | authors = ["Alex Pearson "] 5 | edition = "2021" 6 | license = "MIT" 7 | readme = "README.md" 8 | repository = "https://github.com/NAlexPear/pg_branch" 9 | description = "Postgres extension for quickly creating copies of databases and clusters." 10 | keywords = ["postgres", "pgrx", "btrfs"] 11 | 12 | [badges.maintenance] 13 | status = "actively-developed" 14 | 15 | [package.metadata.docs.rs] 16 | all-features = true 17 | rustdoc-args = ["--cfg", "docsrs"] 18 | 19 | [lib] 20 | crate-type = ["cdylib"] 21 | 22 | [features] 23 | default = ["pg15"] 24 | pg11 = ["pgrx/pg11", "pgrx-tests/pg11"] 25 | pg12 = ["pgrx/pg12", "pgrx-tests/pg12"] 26 | pg13 = ["pgrx/pg13", "pgrx-tests/pg13"] 27 | pg14 = ["pgrx/pg14", "pgrx-tests/pg14"] 28 | pg15 = ["pgrx/pg15", "pgrx-tests/pg15"] 29 | pg16 = ["pgrx/pg16", "pgrx-tests/pg16"] 30 | pg_test = [] 31 | 32 | [build-dependencies] 33 | bindgen = "0.68.1" 34 | toml = "0.8.2" 35 | 36 | [build-dependencies.serde] 37 | features = ["derive"] 38 | version = "1.0.173" 39 | 40 | [dependencies] 41 | btrfsutil-sys = "1.3.0" 42 | pgrx = "=0.10.2" 43 | 44 | [dev-dependencies] 45 | pgrx-tests = "=0.10.2" 46 | 47 | [profile.dev] 48 | panic = "unwind" 49 | 50 | [profile.release] 51 | panic = "unwind" 52 | opt-level = 3 53 | lto = "fat" 54 | codegen-units = 1 55 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(test), deny(unused_crate_dependencies))] 2 | 3 | use database::Database; 4 | use fs::{Branching, Btrfs}; 5 | use pgrx::{prelude::*, PgRelation}; 6 | 7 | mod database; 8 | mod fs; 9 | mod hooks; 10 | 11 | pgrx::pg_module_magic!(); 12 | 13 | /// Create a branch of a template database using file system snapshots 14 | #[pg_extern] 15 | fn branch(target: &str, template: Option<&str>) { 16 | let template = template.unwrap_or("template1"); 17 | 18 | // check that the target database doesn't already exist 19 | let no_duplicate = Spi::connect(|client| { 20 | client 21 | .select( 22 | "select oid from pg_database where datname = $1", 23 | Some(1), 24 | Some(vec![( 25 | PgOid::BuiltIn(PgBuiltInOids::TEXTOID), 26 | target.into_datum(), 27 | )]), 28 | ) 29 | .map(|result| result.is_empty()) 30 | }) 31 | .expect("Error querying pg_database table"); 32 | 33 | if !no_duplicate { 34 | error!(r#"database "{target}" already exists"#); 35 | } 36 | 37 | // generate the template fields from the template name 38 | let template_fields = Database::find(template); 39 | let template_data_path = template_fields.data(); 40 | 41 | // generate a new OID for the new database (via cluster oid generator) 42 | let target_oid = unsafe { pg_sys::GetNewObjectId() }; 43 | 44 | let target_data_path = template_data_path 45 | .parent() 46 | .expect("Invalid template data path") 47 | .join(target_oid.as_u32().to_string()); 48 | 49 | // create a snapshot of the template database using the new OID 50 | Btrfs::create_snapshot(template_data_path, target_data_path); 51 | 52 | // update the pg_database catalog table with the new database information 53 | let mut catalog_entry = Database::new( 54 | target, 55 | target_oid, 56 | template_fields.dba, 57 | template_fields.tablespace, 58 | ); 59 | let pg_database = PgRelation::open_with_name_and_share_lock("pg_database") 60 | .expect("Relation pg_database not found"); 61 | unsafe { 62 | let tuple = PgHeapTuple::from_datums(pg_database.tuple_desc(), catalog_entry.as_record()) 63 | .expect("Failed to create the new heap tuple"); 64 | pg_sys::CatalogTupleInsert(pg_database.as_ptr(), tuple.into_pg()); 65 | }; 66 | } 67 | 68 | #[pg_guard] 69 | #[allow(clippy::missing_safety_doc)] 70 | pub unsafe extern "C" fn _PG_init() { 71 | hooks::init() 72 | } 73 | 74 | #[pg_guard] 75 | pub extern "C" fn _PG_fini() { 76 | // noop 77 | } 78 | 79 | /// This module is required by `cargo pgrx test` invocations. 80 | /// It must be visible at the root of your extension crate. 81 | #[cfg(test)] 82 | pub mod pg_test { 83 | pub fn setup(_options: Vec<&str>) { 84 | // perform one-off initialization when the pg_test framework starts 85 | } 86 | 87 | pub fn postgresql_conf_options() -> Vec<&'static str> { 88 | // return any postgresql.conf settings that are required for your tests 89 | vec![] 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/database.rs: -------------------------------------------------------------------------------- 1 | use pgrx::{ 2 | pg_sys::{Datum, Name, Oid}, 3 | prelude::*, 4 | }; 5 | use std::{ 6 | ffi::{c_char, CString}, 7 | fmt::Display, 8 | path::{Path, PathBuf}, 9 | }; 10 | 11 | /// Type alias for a Record that can be inserted into a database 12 | /// when paired with a TupleDescriptor via PgHeapTuple 13 | type Record = Vec>; 14 | 15 | /// Catalog entry in the pg_database table for tracking database info 16 | pub struct Database { 17 | name: pg_sys::nameData, 18 | oid: Oid, 19 | pub dba: Oid, 20 | pub tablespace: Oid, 21 | } 22 | 23 | impl Database { 24 | /// Create a new database entry directly 25 | pub fn new(name: T, oid: Oid, dba: Oid, tablespace: Oid) -> Self 26 | where 27 | T: Into> + Display + Copy, 28 | { 29 | // convert the name to a pg-compatible name data 30 | let mut name_data = [0 as c_char; 64]; 31 | for (left, right) in name_data.iter_mut().zip( 32 | CString::new(name) 33 | .unwrap_or_else(|_| panic!("Invalid database name {name}")) 34 | .as_bytes_with_nul(), 35 | ) { 36 | *left = *right as i8; 37 | } 38 | let name = pg_sys::nameData { data: name_data }; 39 | 40 | Self { 41 | name, 42 | oid, 43 | dba, 44 | tablespace, 45 | } 46 | } 47 | 48 | /// Query the catalog tables by the name of the database, 49 | /// panicking if the database doesn't exist or has an incomplete catalog entry 50 | pub fn find(name: &str) -> Self { 51 | // get the relevant database fields from pg_database 52 | let tuple = Spi::get_three_with_args( 53 | "select oid, datdba, dattablespace from pg_database where datname = $1", 54 | vec![(PgOid::BuiltIn(PgBuiltInOids::TEXTOID), name.into_datum())], 55 | ) 56 | .expect("Error querying pg_database table"); 57 | 58 | // validate the catalog tuple fields 59 | match tuple { 60 | (Some(oid), Some(dba), Some(tablespace)) => Self::new(name, oid, dba, tablespace), 61 | _ => panic!(r#"database "{name}" does not exist in the pg_database table"#), 62 | } 63 | } 64 | 65 | /// Get the directory where this database's data is stored 66 | pub fn data(&self) -> PathBuf { 67 | Spi::get_one("select setting from pg_settings where name = 'data_directory'") 68 | .expect("Error querying pg_settings table") 69 | .map(|data_directory: &str| { 70 | Path::new(data_directory) 71 | .join("base") 72 | .join(self.oid.as_u32().to_string()) 73 | }) 74 | .expect("No data_directory found!") 75 | } 76 | 77 | /// generate a Record that can be inserted into pg_database while 78 | /// continuing to reference data from this struct (hence the exclusive reference). 79 | pub fn as_record(&mut self) -> Record { 80 | // convert the name data to a pg-compatible "name" Datum 81 | let name = Datum::from(&mut self.name as *mut pg_sys::nameData as Name); 82 | 83 | // these record fields match the order of columns in pg_database 84 | vec![ 85 | self.oid.into_datum(), 86 | Some(name), 87 | self.dba.into_datum(), 88 | 6.into_datum(), 89 | 'c'.into_datum(), 90 | false.into_datum(), 91 | true.into_datum(), 92 | (-1).into_datum(), 93 | 716.into_datum(), 94 | 1.into_datum(), 95 | self.tablespace.into_datum(), 96 | "C.UTF-8".into_datum(), 97 | "C.UTF-8".into_datum(), 98 | None, 99 | None, 100 | None, 101 | ] 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: Pre-release Checks 2 | on: 3 | push: 4 | pull_request: 5 | branches: 6 | - main 7 | workflow_call: 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | fmt: 14 | name: Format 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout sources 18 | uses: actions/checkout@v3 19 | - name: Install stable toolchain 20 | uses: dtolnay/rust-toolchain@stable 21 | with: 22 | components: rustfmt 23 | - name: Run cargo fmt 24 | run: cargo fmt --all -- --check 25 | check: 26 | name: Check 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout sources 30 | uses: actions/checkout@v3 31 | - name: ⚡ Cache 32 | uses: actions/cache@v3 33 | with: 34 | path: | 35 | ~/.cargo/bin/ 36 | ~/.cargo/registry/index/ 37 | ~/.cargo/registry/cache/ 38 | ~/.cargo/git/db/ 39 | target/ 40 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 41 | - name: Install stable toolchain 42 | uses: dtolnay/rust-toolchain@stable 43 | - name: Install cargo-pgrx 44 | run: | 45 | cargo pgrx --help 2>/dev/null 1>&2 || cargo install cargo-pgrx 46 | - name: ⚡ Cache pgrx 47 | uses: actions/cache@v3 48 | with: 49 | path: | 50 | ~/.pgrx/ 51 | key: ${{ runner.os }}-pgrx 52 | - name: Initialize pgrx 53 | run: | 54 | if [ ! -f ~/.pgrx/config.toml ]; then 55 | cargo pgrx init 56 | fi 57 | - name: Run cargo check 58 | run: cargo check 59 | test: 60 | name: Test 61 | runs-on: ubuntu-latest 62 | steps: 63 | - name: Install dependencies 64 | run: | 65 | sudo apt-get update -y && sudo apt-get install -y libbtrfsutil-dev 66 | - name: Checkout sources 67 | uses: actions/checkout@v3 68 | - name: ⚡ Cache Cargo 69 | uses: actions/cache@v3 70 | with: 71 | path: | 72 | ~/.cargo/bin/ 73 | ~/.cargo/registry/index/ 74 | ~/.cargo/registry/cache/ 75 | ~/.cargo/git/db/ 76 | target/ 77 | key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }} 78 | - name: Install stable toolchain 79 | uses: dtolnay/rust-toolchain@stable 80 | - name: Install cargo-pgrx 81 | run: | 82 | cargo pgrx --help 2>/dev/null 1>&2 || cargo install cargo-pgrx 83 | - name: ⚡ Cache pgrx 84 | uses: actions/cache@v3 85 | with: 86 | path: | 87 | ~/.pgrx/ 88 | key: ${{ runner.os }}-pgrx 89 | - name: Initialize pgrx 90 | run: | 91 | if [ ! -f ~/.pgrx/config.toml ]; then 92 | cargo pgrx init 93 | fi 94 | - name: Run cargo test 95 | run: cargo test 96 | lint: 97 | name: Lint 98 | runs-on: ubuntu-latest 99 | steps: 100 | - name: Checkout sources 101 | uses: actions/checkout@v3 102 | - name: ⚡ Cache 103 | uses: actions/cache@v3 104 | with: 105 | path: | 106 | ~/.cargo/bin/ 107 | ~/.cargo/registry/index/ 108 | ~/.cargo/registry/cache/ 109 | ~/.cargo/git/db/ 110 | target/ 111 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 112 | - name: Install stable toolchain 113 | uses: dtolnay/rust-toolchain@stable 114 | with: 115 | components: clippy 116 | - name: Install cargo-pgrx 117 | run: | 118 | cargo pgrx --help 2>/dev/null 1>&2 || cargo install cargo-pgrx 119 | - name: ⚡ Cache pgrx 120 | uses: actions/cache@v3 121 | with: 122 | path: | 123 | ~/.pgrx/ 124 | key: ${{ runner.os }}-pgrx 125 | - name: Initialize pgrx 126 | run: | 127 | if [ ! -f ~/.pgrx/config.toml ]; then 128 | cargo pgrx init 129 | fi 130 | - name: Run cargo clippy 131 | run: cargo clippy -- -D warnings 132 | -------------------------------------------------------------------------------- /src/hooks.rs: -------------------------------------------------------------------------------- 1 | use pgrx::{is_a, prelude::*}; 2 | 3 | /// All hooks needed to intercept and process CREATE DATABASE queries. 4 | struct Hooks; 5 | impl pgrx::PgHooks for Hooks { 6 | /// hook into the ProcessUtility hook to intercept CREATE DATABASE calls 7 | fn process_utility_hook( 8 | &mut self, 9 | pstmt: PgBox, 10 | query_string: &core::ffi::CStr, 11 | read_only_tree: Option, 12 | context: pg_sys::ProcessUtilityContext, 13 | params: PgBox, 14 | query_env: PgBox, 15 | dest: PgBox, 16 | completion_tag: *mut pg_sys::QueryCompletion, 17 | prev_hook: fn( 18 | pstmt: PgBox, 19 | query_string: &core::ffi::CStr, 20 | read_only_tree: Option, 21 | context: pg_sys::ProcessUtilityContext, 22 | params: PgBox, 23 | query_env: PgBox, 24 | dest: PgBox, 25 | completion_tag: *mut pg_sys::QueryCompletion, 26 | ) -> pgrx::HookResult<()>, 27 | ) -> pgrx::HookResult<()> { 28 | // only block CREATE DATABASE, forwarding all others 29 | // FIXME: check CREATEDB privilege of the user 30 | if unsafe { is_a(pstmt.utilityStmt, pg_sys::NodeTag_T_CreatedbStmt) } { 31 | let createdb = 32 | unsafe { PgBox::from_pg(pstmt.utilityStmt as *mut pg_sys::CreatedbStmt) }; 33 | 34 | // extract the target from the statement's dbname 35 | let target = unsafe { core::ffi::CStr::from_ptr(createdb.dbname) } 36 | .to_str() 37 | .expect("Invalid dbname in CREATE DATABASE"); 38 | 39 | // parse and handle relevant options 40 | let mut template = None; 41 | if !createdb.options.is_null() { 42 | let options = unsafe { PgBox::from_pg(createdb.options) }; 43 | for index in 0..options.length { 44 | let list_cell = unsafe { pg_sys::pgrx_list_nth(options.as_ptr(), index) }; 45 | let element = unsafe { PgBox::from_pg(list_cell as *mut pg_sys::DefElem) }; 46 | let defname = unsafe { core::ffi::CStr::from_ptr(element.defname) } 47 | .to_str() 48 | .expect("Invalid template name in CREATE DATABASE"); 49 | let arg = unsafe { PgBox::from_pg(element.arg) } 50 | .to_string() 51 | .replace('\"', ""); 52 | 53 | match defname { 54 | "template" => { 55 | template = Some(arg); 56 | } 57 | "strategy" if !arg.is_empty() && arg.to_lowercase() != "snapshot" => { 58 | // if a strategy is explicitly defined as something other than 59 | // "snapshot", forward the call to prev_hook instead 60 | return prev_hook( 61 | pstmt, 62 | query_string, 63 | read_only_tree, 64 | context, 65 | params, 66 | query_env, 67 | dest, 68 | completion_tag, 69 | ); 70 | } 71 | // FIXME: support more of the CREATE DATABASE options 72 | _ => (), 73 | } 74 | } 75 | }; 76 | 77 | // create the new branch using the top-level helper function 78 | crate::branch(target, template.as_deref()); 79 | pgrx::HookResult::new(()) 80 | } else { 81 | prev_hook( 82 | pstmt, 83 | query_string, 84 | read_only_tree, 85 | context, 86 | params, 87 | query_env, 88 | dest, 89 | completion_tag, 90 | ) 91 | } 92 | } 93 | } 94 | 95 | static mut HOOKS: Hooks = Hooks; 96 | 97 | /// initialize all of the hooks for use with _PG_init 98 | pub unsafe fn init() { 99 | pgrx::register_hook(&mut HOOKS) 100 | } 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AI-generated logo that confers more legitimacy than this project deserves 2 | 3 | # `pg_branch` 4 | 5 | ![Pre-release Checks](https://github.com/NAlexPear/pg_branch/actions/workflows/check.yml/badge.svg?branch=main) 6 | 7 | A Postgres extension for quickly creating "branches" of individual databases within a Postgres cluster using copy-on-write file systems like [`BTRFS`](https://wiki.archlinux.org/title/btrfs). 8 | 9 | ## Table of Contents 10 | 11 | 1. [Introduction](#introduction) 12 | 2. [Getting Started](#getting-started) 13 | 2. [Future Work](#future-work) 14 | 2. [Similar Projects](#similar-projects) 15 | 16 | ## Introduction 17 | 18 | > **Warning** 19 | > This is **pre-alpha software**, meant as an experimental proof-of-concept. Use at your own risk! 20 | 21 | Postgres makes it easy to create new, empty databases with the `CREATE DATABASE` command. It's so easy, in fact, that one would think that creating new databases from existing databases would be easy, too. [But it's not](https://stackoverflow.com/questions/876522/creating-a-copy-of-a-database-in-postgresql). 22 | 23 | Postgres provides the option to create one database from another using [`CREATE DATABASE name [WITH] [TEMPLATE template]`](https://www.postgresql.org/docs/current/sql-createdatabase.html), but doing so has two major restrictions: 24 | 25 | 1. there can be _no active connections to the `template` database_, and... 26 | 2. performance degrades rapidly as the size of the database increases 27 | 28 | `pg_branch` is a Postgres extension that solves those problems by giving `CREATE DATABASE` the power of snapshots. If your `PGDATA` directory is on a copy-on-write file system like [`BTRFS`](https://wiki.archlinux.org/title/btrfs), the `pg_branch` extension turns every `CREATE DATABASE` into an atomic file system snapshot that takes seconds instead of minutes (or hours). In addition, the copy-on-write strategy keeps disk usage low by only writing new segment data files to disk when they're modified (rather than read). 29 | 30 | TL;DR: `CREATE EXTENSION pg_branch` makes `CREATE DATABASE WITH TEMPLATE ` super fast 31 | 32 | ## Getting Started 33 | 34 | Before installing `pg_branch`, it's important to configure the file system that the database cluster will use. The following steps will get you started: 35 | 36 | > **Disclaimer**: these steps are written with Linux in mind, and have only been testing on Linux. 37 | 38 | 0. **install prerequisites** 39 | 40 | You'll need an installation of `btrfs` (usually packaged as `btrfs-progs`) as well as an up-to-date [Rust toolchain](https://rustup.rs/) and the [`pgrx` subcommand for `cargo`](https://github.com/pgcentralfoundation/pgrx/blob/master/cargo-pgrx/README.md#cargo-pgrx). 41 | 42 | 1. **format a disk as BTRFS** 43 | 44 | The easiest thing to do here is plug in a USB and check which disk it is with `lsblk`. Once you've figure out which disk you'd like to reformat, you can do so with: 45 | 46 | ````sh 47 | sudo mkfs.btrfs /dev/sdX # replace sdX with your drive 48 | ```` 49 | 50 | 2. **mount your `btrfs`-formatted disk** 51 | 52 | You need a directory to mount this disk to, first. Something like: 53 | 54 | ````sh 55 | sudo mkdir /mnt/database 56 | ```` 57 | 58 | ...which you can then use as a mount point for your new `btrfs` drive with: 59 | 60 | ````sh 61 | sudo mount /dev/sdX /mnt/database 62 | ```` 63 | 64 | 3. **intialize a Postgres cluster on your mounted disk** 65 | 66 | [`cargo pgrx` can take care of initialization](https://github.com/pgcentralfoundation/pgrx/blob/master/cargo-pgrx/README.md#cargo-pgrx) as long as it knows where to initialize the data through the `PGRX_HOME` variable. Something like: 67 | 68 | ````sh 69 | PGRX_HOME=/mnt/database cargo pgrx init 70 | ```` 71 | 72 | 4. **clone this repo** 73 | 74 | The rest of these steps will be done from within this repo, so make sure you've run `git clone git@github.com:NAlexPear/pg_branch.git` and `cd pg_branch`. 75 | 76 | 5. **convert all segment data directories to subvolumes** 77 | 78 | Before `pg_branch` can take over database creation, the subdirectories in the newly-initialized data directory of your database need to be converted to `btrfs` subvolumes. This repo provides an `init.sh` script for doing just this that, as long as it's provided a `PGDATA` variable that points to the data directory of your cluster. 79 | 80 | `pgrx` data directories have a structure of `$PGRX_HOME/data-$PG_VERSION`. So if you initialized your project as instructed in step 3, you should be able to run the `init.sh` script in this repository like so: 81 | 82 | ````sh 83 | PGDATA=/mnt/database/data-15 ./init.sh 84 | ```` 85 | 86 | ...and you should have successfully converted all of the initial databases in your cluster to subvolumes. 87 | 88 | 6. **get into `psql`** 89 | 90 | The quickest way to jump into a `psql` session that recognizes `pg_branch` is to run the following: 91 | 92 | ````sh 93 | PGX_HOME=/your/mounted/btrfs/disk cargo pgrx run 94 | ```` 95 | 96 | 7. **create the extension in `psql` with `CREATE EXTENSION pg_branch`** 97 | 98 | 8. **create some databases** 99 | 100 | After creating the extension, you can run `CREATE DATABASE WITH TEMPLATE ` commands to quickly and atomically copy databases without requiring an exclusive lock or dedicated connection. To use the default `CREATE DATABASE` behavior again, pick an explicit `STRATEGY` other than `SNAPSHOT` (i.e. `WAL_COPY` or `FILE_COPY`). 101 | 102 | ## Future Work 103 | 104 | 1. distribute as pre-compiled extension 105 | 2. implement a cluster-wide `fork` 106 | 3. support more of the options supported by `CREATE DATABASE` 107 | 4. streamline setup of the data directory and its file system 108 | 5. support additional copy-on-write file systems like `ZFS` and `XFS` 109 | 6. include an example Dockerfile 110 | 111 | ## Similar Projects 112 | 113 | This project's use of file system snapshots as a branching mechanism is heavily inspired by [`pgcow`](https://github.com/Photonios/pgcow) and [Postgres.ai](https://postgres.ai/). And credit for the concept of "forking" Postgres clusters goes to [Heroku's Database Fork](https://devcenter.heroku.com/articles/heroku-postgres-fork) feature. 114 | 115 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "1.1.1" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "anstyle" 31 | version = "1.0.4" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" 34 | 35 | [[package]] 36 | name = "anyhow" 37 | version = "1.0.75" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" 40 | 41 | [[package]] 42 | name = "async-trait" 43 | version = "0.1.73" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" 46 | dependencies = [ 47 | "proc-macro2", 48 | "quote", 49 | "syn 2.0.38", 50 | ] 51 | 52 | [[package]] 53 | name = "atomic-polyfill" 54 | version = "0.1.11" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" 57 | dependencies = [ 58 | "critical-section", 59 | ] 60 | 61 | [[package]] 62 | name = "atomic-traits" 63 | version = "0.3.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "b29ec3788e96fb4fdb275ccb9d62811f2fa903d76c5eb4dd6fe7d09a7ed5871f" 66 | dependencies = [ 67 | "cfg-if", 68 | "rustc_version 0.3.3", 69 | ] 70 | 71 | [[package]] 72 | name = "autocfg" 73 | version = "1.1.0" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 76 | 77 | [[package]] 78 | name = "backtrace" 79 | version = "0.3.69" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" 82 | dependencies = [ 83 | "addr2line", 84 | "cc", 85 | "cfg-if", 86 | "libc", 87 | "miniz_oxide", 88 | "object", 89 | "rustc-demangle", 90 | ] 91 | 92 | [[package]] 93 | name = "base64" 94 | version = "0.21.4" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" 97 | 98 | [[package]] 99 | name = "bindgen" 100 | version = "0.66.1" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" 103 | dependencies = [ 104 | "bitflags 2.4.0", 105 | "cexpr", 106 | "clang-sys", 107 | "lazy_static", 108 | "lazycell", 109 | "log", 110 | "peeking_take_while", 111 | "prettyplease", 112 | "proc-macro2", 113 | "quote", 114 | "regex", 115 | "rustc-hash", 116 | "shlex", 117 | "syn 2.0.38", 118 | "which", 119 | ] 120 | 121 | [[package]] 122 | name = "bindgen" 123 | version = "0.68.1" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" 126 | dependencies = [ 127 | "bitflags 2.4.0", 128 | "cexpr", 129 | "clang-sys", 130 | "lazy_static", 131 | "lazycell", 132 | "log", 133 | "peeking_take_while", 134 | "prettyplease", 135 | "proc-macro2", 136 | "quote", 137 | "regex", 138 | "rustc-hash", 139 | "shlex", 140 | "syn 2.0.38", 141 | "which", 142 | ] 143 | 144 | [[package]] 145 | name = "bit-set" 146 | version = "0.5.3" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" 149 | dependencies = [ 150 | "bit-vec", 151 | ] 152 | 153 | [[package]] 154 | name = "bit-vec" 155 | version = "0.6.3" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" 158 | 159 | [[package]] 160 | name = "bitflags" 161 | version = "1.3.2" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 164 | 165 | [[package]] 166 | name = "bitflags" 167 | version = "2.4.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" 170 | 171 | [[package]] 172 | name = "bitvec" 173 | version = "1.0.1" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" 176 | dependencies = [ 177 | "funty", 178 | "radium", 179 | "tap", 180 | "wyz", 181 | ] 182 | 183 | [[package]] 184 | name = "block-buffer" 185 | version = "0.10.4" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 188 | dependencies = [ 189 | "generic-array", 190 | ] 191 | 192 | [[package]] 193 | name = "btrfsutil-sys" 194 | version = "1.3.0" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "9a8e167870d01d20b1c33637b048b6654a7e8488ee08053f4b70e383fbe26113" 197 | dependencies = [ 198 | "bindgen 0.66.1", 199 | "serde", 200 | "toml 0.5.11", 201 | ] 202 | 203 | [[package]] 204 | name = "bumpalo" 205 | version = "3.14.0" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" 208 | 209 | [[package]] 210 | name = "byteorder" 211 | version = "1.5.0" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 214 | 215 | [[package]] 216 | name = "bytes" 217 | version = "1.5.0" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" 220 | 221 | [[package]] 222 | name = "cargo_toml" 223 | version = "0.16.3" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "e3f9629bc6c4388ea699781dc988c2b99766d7679b151c81990b4fa1208fafd3" 226 | dependencies = [ 227 | "serde", 228 | "toml 0.8.2", 229 | ] 230 | 231 | [[package]] 232 | name = "cc" 233 | version = "1.0.83" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 236 | dependencies = [ 237 | "libc", 238 | ] 239 | 240 | [[package]] 241 | name = "cexpr" 242 | version = "0.6.0" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 245 | dependencies = [ 246 | "nom", 247 | ] 248 | 249 | [[package]] 250 | name = "cfg-if" 251 | version = "1.0.0" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 254 | 255 | [[package]] 256 | name = "clang-sys" 257 | version = "1.6.1" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" 260 | dependencies = [ 261 | "glob", 262 | "libc", 263 | "libloading", 264 | ] 265 | 266 | [[package]] 267 | name = "clap" 268 | version = "4.4.6" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" 271 | dependencies = [ 272 | "clap_builder", 273 | "clap_derive", 274 | ] 275 | 276 | [[package]] 277 | name = "clap-cargo" 278 | version = "0.11.0" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "25122ca6ebad5f53578c26638afd9f0160426969970dc37ec6c363ff6b082ebd" 281 | dependencies = [ 282 | "clap", 283 | "doc-comment", 284 | ] 285 | 286 | [[package]] 287 | name = "clap_builder" 288 | version = "4.4.6" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" 291 | dependencies = [ 292 | "anstyle", 293 | "clap_lex", 294 | ] 295 | 296 | [[package]] 297 | name = "clap_derive" 298 | version = "4.4.2" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" 301 | dependencies = [ 302 | "heck", 303 | "proc-macro2", 304 | "quote", 305 | "syn 2.0.38", 306 | ] 307 | 308 | [[package]] 309 | name = "clap_lex" 310 | version = "0.5.1" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" 313 | 314 | [[package]] 315 | name = "convert_case" 316 | version = "0.6.0" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" 319 | dependencies = [ 320 | "unicode-segmentation", 321 | ] 322 | 323 | [[package]] 324 | name = "core-foundation-sys" 325 | version = "0.8.4" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" 328 | 329 | [[package]] 330 | name = "cpufeatures" 331 | version = "0.2.9" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" 334 | dependencies = [ 335 | "libc", 336 | ] 337 | 338 | [[package]] 339 | name = "critical-section" 340 | version = "1.1.2" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" 343 | 344 | [[package]] 345 | name = "crossbeam-deque" 346 | version = "0.8.3" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" 349 | dependencies = [ 350 | "cfg-if", 351 | "crossbeam-epoch", 352 | "crossbeam-utils", 353 | ] 354 | 355 | [[package]] 356 | name = "crossbeam-epoch" 357 | version = "0.9.15" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" 360 | dependencies = [ 361 | "autocfg", 362 | "cfg-if", 363 | "crossbeam-utils", 364 | "memoffset", 365 | "scopeguard", 366 | ] 367 | 368 | [[package]] 369 | name = "crossbeam-utils" 370 | version = "0.8.16" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" 373 | dependencies = [ 374 | "cfg-if", 375 | ] 376 | 377 | [[package]] 378 | name = "crypto-common" 379 | version = "0.1.6" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 382 | dependencies = [ 383 | "generic-array", 384 | "typenum", 385 | ] 386 | 387 | [[package]] 388 | name = "digest" 389 | version = "0.10.7" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 392 | dependencies = [ 393 | "block-buffer", 394 | "crypto-common", 395 | "subtle", 396 | ] 397 | 398 | [[package]] 399 | name = "dirs" 400 | version = "5.0.1" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" 403 | dependencies = [ 404 | "dirs-sys", 405 | ] 406 | 407 | [[package]] 408 | name = "dirs-sys" 409 | version = "0.4.1" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" 412 | dependencies = [ 413 | "libc", 414 | "option-ext", 415 | "redox_users", 416 | "windows-sys", 417 | ] 418 | 419 | [[package]] 420 | name = "doc-comment" 421 | version = "0.3.3" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" 424 | 425 | [[package]] 426 | name = "either" 427 | version = "1.9.0" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" 430 | 431 | [[package]] 432 | name = "enum-map" 433 | version = "2.6.3" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "c188012f8542dee7b3996e44dd89461d64aa471b0a7c71a1ae2f595d259e96e5" 436 | dependencies = [ 437 | "enum-map-derive", 438 | ] 439 | 440 | [[package]] 441 | name = "enum-map-derive" 442 | version = "0.14.0" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "04d0b288e3bb1d861c4403c1774a6f7a798781dfc519b3647df2a3dd4ae95f25" 445 | dependencies = [ 446 | "proc-macro2", 447 | "quote", 448 | "syn 2.0.38", 449 | ] 450 | 451 | [[package]] 452 | name = "equivalent" 453 | version = "1.0.1" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 456 | 457 | [[package]] 458 | name = "errno" 459 | version = "0.3.4" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480" 462 | dependencies = [ 463 | "errno-dragonfly", 464 | "libc", 465 | "windows-sys", 466 | ] 467 | 468 | [[package]] 469 | name = "errno-dragonfly" 470 | version = "0.1.2" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 473 | dependencies = [ 474 | "cc", 475 | "libc", 476 | ] 477 | 478 | [[package]] 479 | name = "eyre" 480 | version = "0.6.8" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" 483 | dependencies = [ 484 | "indenter", 485 | "once_cell", 486 | ] 487 | 488 | [[package]] 489 | name = "fallible-iterator" 490 | version = "0.2.0" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" 493 | 494 | [[package]] 495 | name = "fastrand" 496 | version = "2.0.1" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" 499 | 500 | [[package]] 501 | name = "finl_unicode" 502 | version = "1.2.0" 503 | source = "registry+https://github.com/rust-lang/crates.io-index" 504 | checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" 505 | 506 | [[package]] 507 | name = "fixedbitset" 508 | version = "0.4.2" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" 511 | 512 | [[package]] 513 | name = "fnv" 514 | version = "1.0.7" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 517 | 518 | [[package]] 519 | name = "form_urlencoded" 520 | version = "1.2.0" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" 523 | dependencies = [ 524 | "percent-encoding", 525 | ] 526 | 527 | [[package]] 528 | name = "funty" 529 | version = "2.0.0" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 532 | 533 | [[package]] 534 | name = "futures-channel" 535 | version = "0.3.28" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" 538 | dependencies = [ 539 | "futures-core", 540 | "futures-sink", 541 | ] 542 | 543 | [[package]] 544 | name = "futures-core" 545 | version = "0.3.28" 546 | source = "registry+https://github.com/rust-lang/crates.io-index" 547 | checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" 548 | 549 | [[package]] 550 | name = "futures-macro" 551 | version = "0.3.28" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" 554 | dependencies = [ 555 | "proc-macro2", 556 | "quote", 557 | "syn 2.0.38", 558 | ] 559 | 560 | [[package]] 561 | name = "futures-sink" 562 | version = "0.3.28" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" 565 | 566 | [[package]] 567 | name = "futures-task" 568 | version = "0.3.28" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" 571 | 572 | [[package]] 573 | name = "futures-util" 574 | version = "0.3.28" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" 577 | dependencies = [ 578 | "futures-core", 579 | "futures-macro", 580 | "futures-sink", 581 | "futures-task", 582 | "pin-project-lite", 583 | "pin-utils", 584 | "slab", 585 | ] 586 | 587 | [[package]] 588 | name = "generic-array" 589 | version = "0.14.7" 590 | source = "registry+https://github.com/rust-lang/crates.io-index" 591 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 592 | dependencies = [ 593 | "typenum", 594 | "version_check", 595 | ] 596 | 597 | [[package]] 598 | name = "getrandom" 599 | version = "0.2.10" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 602 | dependencies = [ 603 | "cfg-if", 604 | "libc", 605 | "wasi", 606 | ] 607 | 608 | [[package]] 609 | name = "gimli" 610 | version = "0.28.0" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" 613 | 614 | [[package]] 615 | name = "glob" 616 | version = "0.3.1" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 619 | 620 | [[package]] 621 | name = "half" 622 | version = "1.8.2" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" 625 | 626 | [[package]] 627 | name = "hash32" 628 | version = "0.2.1" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" 631 | dependencies = [ 632 | "byteorder", 633 | ] 634 | 635 | [[package]] 636 | name = "hashbrown" 637 | version = "0.14.1" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" 640 | 641 | [[package]] 642 | name = "heapless" 643 | version = "0.7.16" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" 646 | dependencies = [ 647 | "atomic-polyfill", 648 | "hash32", 649 | "rustc_version 0.4.0", 650 | "spin", 651 | "stable_deref_trait", 652 | ] 653 | 654 | [[package]] 655 | name = "heck" 656 | version = "0.4.1" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 659 | 660 | [[package]] 661 | name = "hmac" 662 | version = "0.12.1" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 665 | dependencies = [ 666 | "digest", 667 | ] 668 | 669 | [[package]] 670 | name = "home" 671 | version = "0.5.5" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" 674 | dependencies = [ 675 | "windows-sys", 676 | ] 677 | 678 | [[package]] 679 | name = "idna" 680 | version = "0.4.0" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" 683 | dependencies = [ 684 | "unicode-bidi", 685 | "unicode-normalization", 686 | ] 687 | 688 | [[package]] 689 | name = "indenter" 690 | version = "0.3.3" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" 693 | 694 | [[package]] 695 | name = "indexmap" 696 | version = "2.0.2" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" 699 | dependencies = [ 700 | "equivalent", 701 | "hashbrown", 702 | ] 703 | 704 | [[package]] 705 | name = "itoa" 706 | version = "1.0.9" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 709 | 710 | [[package]] 711 | name = "js-sys" 712 | version = "0.3.64" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" 715 | dependencies = [ 716 | "wasm-bindgen", 717 | ] 718 | 719 | [[package]] 720 | name = "lazy_static" 721 | version = "1.4.0" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 724 | 725 | [[package]] 726 | name = "lazycell" 727 | version = "1.3.0" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 730 | 731 | [[package]] 732 | name = "libc" 733 | version = "0.2.148" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" 736 | 737 | [[package]] 738 | name = "libloading" 739 | version = "0.7.4" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" 742 | dependencies = [ 743 | "cfg-if", 744 | "winapi", 745 | ] 746 | 747 | [[package]] 748 | name = "libm" 749 | version = "0.2.8" 750 | source = "registry+https://github.com/rust-lang/crates.io-index" 751 | checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" 752 | 753 | [[package]] 754 | name = "linux-raw-sys" 755 | version = "0.4.8" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db" 758 | 759 | [[package]] 760 | name = "lock_api" 761 | version = "0.4.10" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" 764 | dependencies = [ 765 | "autocfg", 766 | "scopeguard", 767 | ] 768 | 769 | [[package]] 770 | name = "log" 771 | version = "0.4.20" 772 | source = "registry+https://github.com/rust-lang/crates.io-index" 773 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 774 | 775 | [[package]] 776 | name = "md-5" 777 | version = "0.10.6" 778 | source = "registry+https://github.com/rust-lang/crates.io-index" 779 | checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" 780 | dependencies = [ 781 | "cfg-if", 782 | "digest", 783 | ] 784 | 785 | [[package]] 786 | name = "memchr" 787 | version = "2.6.4" 788 | source = "registry+https://github.com/rust-lang/crates.io-index" 789 | checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" 790 | 791 | [[package]] 792 | name = "memoffset" 793 | version = "0.9.0" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" 796 | dependencies = [ 797 | "autocfg", 798 | ] 799 | 800 | [[package]] 801 | name = "minimal-lexical" 802 | version = "0.2.1" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 805 | 806 | [[package]] 807 | name = "miniz_oxide" 808 | version = "0.7.1" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 811 | dependencies = [ 812 | "adler", 813 | ] 814 | 815 | [[package]] 816 | name = "mio" 817 | version = "0.8.8" 818 | source = "registry+https://github.com/rust-lang/crates.io-index" 819 | checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" 820 | dependencies = [ 821 | "libc", 822 | "wasi", 823 | "windows-sys", 824 | ] 825 | 826 | [[package]] 827 | name = "nom" 828 | version = "7.1.3" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 831 | dependencies = [ 832 | "memchr", 833 | "minimal-lexical", 834 | ] 835 | 836 | [[package]] 837 | name = "ntapi" 838 | version = "0.4.1" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" 841 | dependencies = [ 842 | "winapi", 843 | ] 844 | 845 | [[package]] 846 | name = "num-traits" 847 | version = "0.2.16" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" 850 | dependencies = [ 851 | "autocfg", 852 | "libm", 853 | ] 854 | 855 | [[package]] 856 | name = "object" 857 | version = "0.32.1" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" 860 | dependencies = [ 861 | "memchr", 862 | ] 863 | 864 | [[package]] 865 | name = "once_cell" 866 | version = "1.18.0" 867 | source = "registry+https://github.com/rust-lang/crates.io-index" 868 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 869 | 870 | [[package]] 871 | name = "option-ext" 872 | version = "0.2.0" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 875 | 876 | [[package]] 877 | name = "owo-colors" 878 | version = "3.5.0" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" 881 | 882 | [[package]] 883 | name = "parking_lot" 884 | version = "0.12.1" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 887 | dependencies = [ 888 | "lock_api", 889 | "parking_lot_core", 890 | ] 891 | 892 | [[package]] 893 | name = "parking_lot_core" 894 | version = "0.9.8" 895 | source = "registry+https://github.com/rust-lang/crates.io-index" 896 | checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" 897 | dependencies = [ 898 | "cfg-if", 899 | "libc", 900 | "redox_syscall 0.3.5", 901 | "smallvec", 902 | "windows-targets", 903 | ] 904 | 905 | [[package]] 906 | name = "pathsearch" 907 | version = "0.2.0" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | checksum = "da983bc5e582ab17179c190b4b66c7d76c5943a69c6d34df2a2b6bf8a2977b05" 910 | dependencies = [ 911 | "anyhow", 912 | "libc", 913 | ] 914 | 915 | [[package]] 916 | name = "peeking_take_while" 917 | version = "0.1.2" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" 920 | 921 | [[package]] 922 | name = "percent-encoding" 923 | version = "2.3.0" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" 926 | 927 | [[package]] 928 | name = "pest" 929 | version = "2.7.4" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" 932 | dependencies = [ 933 | "memchr", 934 | "thiserror", 935 | "ucd-trie", 936 | ] 937 | 938 | [[package]] 939 | name = "petgraph" 940 | version = "0.6.4" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" 943 | dependencies = [ 944 | "fixedbitset", 945 | "indexmap", 946 | ] 947 | 948 | [[package]] 949 | name = "pg_branch" 950 | version = "0.0.1" 951 | dependencies = [ 952 | "bindgen 0.68.1", 953 | "btrfsutil-sys", 954 | "pgrx", 955 | "pgrx-tests", 956 | "serde", 957 | "toml 0.8.2", 958 | ] 959 | 960 | [[package]] 961 | name = "pgrx" 962 | version = "0.10.2" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "dde2cf81d16772f2e75c91edd2e868de1bd67a79d6c45c3d25c62b2ed3851d70" 965 | dependencies = [ 966 | "atomic-traits", 967 | "bitflags 2.4.0", 968 | "bitvec", 969 | "enum-map", 970 | "heapless", 971 | "libc", 972 | "once_cell", 973 | "pgrx-macros", 974 | "pgrx-pg-sys", 975 | "pgrx-sql-entity-graph", 976 | "seahash", 977 | "seq-macro", 978 | "serde", 979 | "serde_cbor", 980 | "serde_json", 981 | "thiserror", 982 | "uuid", 983 | ] 984 | 985 | [[package]] 986 | name = "pgrx-macros" 987 | version = "0.10.2" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "1b9c035c16a41b126f8c2b37307f2c717b5ee72ff8e7495ff502ad35471a0b38" 990 | dependencies = [ 991 | "pgrx-sql-entity-graph", 992 | "proc-macro2", 993 | "quote", 994 | "syn 1.0.109", 995 | ] 996 | 997 | [[package]] 998 | name = "pgrx-pg-config" 999 | version = "0.10.2" 1000 | source = "registry+https://github.com/rust-lang/crates.io-index" 1001 | checksum = "16f9d9b6310ea9f13570d773d173bbcfe47ac844075bf6a3e207e7209786c631" 1002 | dependencies = [ 1003 | "cargo_toml", 1004 | "dirs", 1005 | "eyre", 1006 | "owo-colors", 1007 | "pathsearch", 1008 | "serde", 1009 | "serde_derive", 1010 | "serde_json", 1011 | "toml 0.8.2", 1012 | "url", 1013 | ] 1014 | 1015 | [[package]] 1016 | name = "pgrx-pg-sys" 1017 | version = "0.10.2" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "f821614646963302a8499b8ac8332cc0e2ae3f8715a0220986984443d8880f74" 1020 | dependencies = [ 1021 | "bindgen 0.68.1", 1022 | "eyre", 1023 | "libc", 1024 | "memoffset", 1025 | "once_cell", 1026 | "pgrx-macros", 1027 | "pgrx-pg-config", 1028 | "pgrx-sql-entity-graph", 1029 | "proc-macro2", 1030 | "quote", 1031 | "serde", 1032 | "shlex", 1033 | "sptr", 1034 | "syn 1.0.109", 1035 | ] 1036 | 1037 | [[package]] 1038 | name = "pgrx-sql-entity-graph" 1039 | version = "0.10.2" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "4743b5b23fd418cded0c2dbe4b1529628f7fa59b8d68426eafdde0cb51541c96" 1042 | dependencies = [ 1043 | "convert_case", 1044 | "eyre", 1045 | "petgraph", 1046 | "proc-macro2", 1047 | "quote", 1048 | "syn 1.0.109", 1049 | "unescape", 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "pgrx-tests" 1054 | version = "0.10.2" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "177bb8f6811bd65180c5a24a33666baed0ed5c08cc584c4bdb78f7fe19304363" 1057 | dependencies = [ 1058 | "clap-cargo", 1059 | "eyre", 1060 | "libc", 1061 | "once_cell", 1062 | "owo-colors", 1063 | "pgrx", 1064 | "pgrx-macros", 1065 | "pgrx-pg-config", 1066 | "postgres", 1067 | "proptest", 1068 | "rand", 1069 | "regex", 1070 | "serde", 1071 | "serde_json", 1072 | "sysinfo", 1073 | "thiserror", 1074 | ] 1075 | 1076 | [[package]] 1077 | name = "phf" 1078 | version = "0.11.2" 1079 | source = "registry+https://github.com/rust-lang/crates.io-index" 1080 | checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" 1081 | dependencies = [ 1082 | "phf_shared", 1083 | ] 1084 | 1085 | [[package]] 1086 | name = "phf_shared" 1087 | version = "0.11.2" 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" 1089 | checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" 1090 | dependencies = [ 1091 | "siphasher", 1092 | ] 1093 | 1094 | [[package]] 1095 | name = "pin-project-lite" 1096 | version = "0.2.13" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 1099 | 1100 | [[package]] 1101 | name = "pin-utils" 1102 | version = "0.1.0" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1105 | 1106 | [[package]] 1107 | name = "postgres" 1108 | version = "0.19.7" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "7915b33ed60abc46040cbcaa25ffa1c7ec240668e0477c4f3070786f5916d451" 1111 | dependencies = [ 1112 | "bytes", 1113 | "fallible-iterator", 1114 | "futures-util", 1115 | "log", 1116 | "tokio", 1117 | "tokio-postgres", 1118 | ] 1119 | 1120 | [[package]] 1121 | name = "postgres-protocol" 1122 | version = "0.6.6" 1123 | source = "registry+https://github.com/rust-lang/crates.io-index" 1124 | checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520" 1125 | dependencies = [ 1126 | "base64", 1127 | "byteorder", 1128 | "bytes", 1129 | "fallible-iterator", 1130 | "hmac", 1131 | "md-5", 1132 | "memchr", 1133 | "rand", 1134 | "sha2", 1135 | "stringprep", 1136 | ] 1137 | 1138 | [[package]] 1139 | name = "postgres-types" 1140 | version = "0.2.6" 1141 | source = "registry+https://github.com/rust-lang/crates.io-index" 1142 | checksum = "8d2234cdee9408b523530a9b6d2d6b373d1db34f6a8e51dc03ded1828d7fb67c" 1143 | dependencies = [ 1144 | "bytes", 1145 | "fallible-iterator", 1146 | "postgres-protocol", 1147 | ] 1148 | 1149 | [[package]] 1150 | name = "ppv-lite86" 1151 | version = "0.2.17" 1152 | source = "registry+https://github.com/rust-lang/crates.io-index" 1153 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1154 | 1155 | [[package]] 1156 | name = "prettyplease" 1157 | version = "0.2.15" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" 1160 | dependencies = [ 1161 | "proc-macro2", 1162 | "syn 2.0.38", 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "proc-macro2" 1167 | version = "1.0.68" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "5b1106fec09662ec6dd98ccac0f81cef56984d0b49f75c92d8cbad76e20c005c" 1170 | dependencies = [ 1171 | "unicode-ident", 1172 | ] 1173 | 1174 | [[package]] 1175 | name = "proptest" 1176 | version = "1.3.1" 1177 | source = "registry+https://github.com/rust-lang/crates.io-index" 1178 | checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e" 1179 | dependencies = [ 1180 | "bit-set", 1181 | "bit-vec", 1182 | "bitflags 2.4.0", 1183 | "lazy_static", 1184 | "num-traits", 1185 | "rand", 1186 | "rand_chacha", 1187 | "rand_xorshift", 1188 | "regex-syntax", 1189 | "rusty-fork", 1190 | "tempfile", 1191 | "unarray", 1192 | ] 1193 | 1194 | [[package]] 1195 | name = "quick-error" 1196 | version = "1.2.3" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 1199 | 1200 | [[package]] 1201 | name = "quote" 1202 | version = "1.0.33" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 1205 | dependencies = [ 1206 | "proc-macro2", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "radium" 1211 | version = "0.7.0" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 1214 | 1215 | [[package]] 1216 | name = "rand" 1217 | version = "0.8.5" 1218 | source = "registry+https://github.com/rust-lang/crates.io-index" 1219 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1220 | dependencies = [ 1221 | "libc", 1222 | "rand_chacha", 1223 | "rand_core", 1224 | ] 1225 | 1226 | [[package]] 1227 | name = "rand_chacha" 1228 | version = "0.3.1" 1229 | source = "registry+https://github.com/rust-lang/crates.io-index" 1230 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1231 | dependencies = [ 1232 | "ppv-lite86", 1233 | "rand_core", 1234 | ] 1235 | 1236 | [[package]] 1237 | name = "rand_core" 1238 | version = "0.6.4" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1241 | dependencies = [ 1242 | "getrandom", 1243 | ] 1244 | 1245 | [[package]] 1246 | name = "rand_xorshift" 1247 | version = "0.3.0" 1248 | source = "registry+https://github.com/rust-lang/crates.io-index" 1249 | checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" 1250 | dependencies = [ 1251 | "rand_core", 1252 | ] 1253 | 1254 | [[package]] 1255 | name = "rayon" 1256 | version = "1.8.0" 1257 | source = "registry+https://github.com/rust-lang/crates.io-index" 1258 | checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" 1259 | dependencies = [ 1260 | "either", 1261 | "rayon-core", 1262 | ] 1263 | 1264 | [[package]] 1265 | name = "rayon-core" 1266 | version = "1.12.0" 1267 | source = "registry+https://github.com/rust-lang/crates.io-index" 1268 | checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" 1269 | dependencies = [ 1270 | "crossbeam-deque", 1271 | "crossbeam-utils", 1272 | ] 1273 | 1274 | [[package]] 1275 | name = "redox_syscall" 1276 | version = "0.2.16" 1277 | source = "registry+https://github.com/rust-lang/crates.io-index" 1278 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 1279 | dependencies = [ 1280 | "bitflags 1.3.2", 1281 | ] 1282 | 1283 | [[package]] 1284 | name = "redox_syscall" 1285 | version = "0.3.5" 1286 | source = "registry+https://github.com/rust-lang/crates.io-index" 1287 | checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" 1288 | dependencies = [ 1289 | "bitflags 1.3.2", 1290 | ] 1291 | 1292 | [[package]] 1293 | name = "redox_users" 1294 | version = "0.4.3" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" 1297 | dependencies = [ 1298 | "getrandom", 1299 | "redox_syscall 0.2.16", 1300 | "thiserror", 1301 | ] 1302 | 1303 | [[package]] 1304 | name = "regex" 1305 | version = "1.9.6" 1306 | source = "registry+https://github.com/rust-lang/crates.io-index" 1307 | checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" 1308 | dependencies = [ 1309 | "aho-corasick", 1310 | "memchr", 1311 | "regex-automata", 1312 | "regex-syntax", 1313 | ] 1314 | 1315 | [[package]] 1316 | name = "regex-automata" 1317 | version = "0.3.9" 1318 | source = "registry+https://github.com/rust-lang/crates.io-index" 1319 | checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" 1320 | dependencies = [ 1321 | "aho-corasick", 1322 | "memchr", 1323 | "regex-syntax", 1324 | ] 1325 | 1326 | [[package]] 1327 | name = "regex-syntax" 1328 | version = "0.7.5" 1329 | source = "registry+https://github.com/rust-lang/crates.io-index" 1330 | checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" 1331 | 1332 | [[package]] 1333 | name = "rustc-demangle" 1334 | version = "0.1.23" 1335 | source = "registry+https://github.com/rust-lang/crates.io-index" 1336 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 1337 | 1338 | [[package]] 1339 | name = "rustc-hash" 1340 | version = "1.1.0" 1341 | source = "registry+https://github.com/rust-lang/crates.io-index" 1342 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1343 | 1344 | [[package]] 1345 | name = "rustc_version" 1346 | version = "0.3.3" 1347 | source = "registry+https://github.com/rust-lang/crates.io-index" 1348 | checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" 1349 | dependencies = [ 1350 | "semver 0.11.0", 1351 | ] 1352 | 1353 | [[package]] 1354 | name = "rustc_version" 1355 | version = "0.4.0" 1356 | source = "registry+https://github.com/rust-lang/crates.io-index" 1357 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1358 | dependencies = [ 1359 | "semver 1.0.19", 1360 | ] 1361 | 1362 | [[package]] 1363 | name = "rustix" 1364 | version = "0.38.17" 1365 | source = "registry+https://github.com/rust-lang/crates.io-index" 1366 | checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7" 1367 | dependencies = [ 1368 | "bitflags 2.4.0", 1369 | "errno", 1370 | "libc", 1371 | "linux-raw-sys", 1372 | "windows-sys", 1373 | ] 1374 | 1375 | [[package]] 1376 | name = "rusty-fork" 1377 | version = "0.3.0" 1378 | source = "registry+https://github.com/rust-lang/crates.io-index" 1379 | checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" 1380 | dependencies = [ 1381 | "fnv", 1382 | "quick-error", 1383 | "tempfile", 1384 | "wait-timeout", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "ryu" 1389 | version = "1.0.15" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 1392 | 1393 | [[package]] 1394 | name = "scopeguard" 1395 | version = "1.2.0" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1398 | 1399 | [[package]] 1400 | name = "seahash" 1401 | version = "4.1.0" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" 1404 | 1405 | [[package]] 1406 | name = "semver" 1407 | version = "0.11.0" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" 1410 | dependencies = [ 1411 | "semver-parser", 1412 | ] 1413 | 1414 | [[package]] 1415 | name = "semver" 1416 | version = "1.0.19" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" 1419 | 1420 | [[package]] 1421 | name = "semver-parser" 1422 | version = "0.10.2" 1423 | source = "registry+https://github.com/rust-lang/crates.io-index" 1424 | checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" 1425 | dependencies = [ 1426 | "pest", 1427 | ] 1428 | 1429 | [[package]] 1430 | name = "seq-macro" 1431 | version = "0.3.5" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" 1434 | 1435 | [[package]] 1436 | name = "serde" 1437 | version = "1.0.188" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" 1440 | dependencies = [ 1441 | "serde_derive", 1442 | ] 1443 | 1444 | [[package]] 1445 | name = "serde_cbor" 1446 | version = "0.11.2" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" 1449 | dependencies = [ 1450 | "half", 1451 | "serde", 1452 | ] 1453 | 1454 | [[package]] 1455 | name = "serde_derive" 1456 | version = "1.0.188" 1457 | source = "registry+https://github.com/rust-lang/crates.io-index" 1458 | checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" 1459 | dependencies = [ 1460 | "proc-macro2", 1461 | "quote", 1462 | "syn 2.0.38", 1463 | ] 1464 | 1465 | [[package]] 1466 | name = "serde_json" 1467 | version = "1.0.107" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" 1470 | dependencies = [ 1471 | "itoa", 1472 | "ryu", 1473 | "serde", 1474 | ] 1475 | 1476 | [[package]] 1477 | name = "serde_spanned" 1478 | version = "0.6.3" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" 1481 | dependencies = [ 1482 | "serde", 1483 | ] 1484 | 1485 | [[package]] 1486 | name = "sha2" 1487 | version = "0.10.8" 1488 | source = "registry+https://github.com/rust-lang/crates.io-index" 1489 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1490 | dependencies = [ 1491 | "cfg-if", 1492 | "cpufeatures", 1493 | "digest", 1494 | ] 1495 | 1496 | [[package]] 1497 | name = "shlex" 1498 | version = "1.2.0" 1499 | source = "registry+https://github.com/rust-lang/crates.io-index" 1500 | checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" 1501 | 1502 | [[package]] 1503 | name = "siphasher" 1504 | version = "0.3.11" 1505 | source = "registry+https://github.com/rust-lang/crates.io-index" 1506 | checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" 1507 | 1508 | [[package]] 1509 | name = "slab" 1510 | version = "0.4.9" 1511 | source = "registry+https://github.com/rust-lang/crates.io-index" 1512 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1513 | dependencies = [ 1514 | "autocfg", 1515 | ] 1516 | 1517 | [[package]] 1518 | name = "smallvec" 1519 | version = "1.11.1" 1520 | source = "registry+https://github.com/rust-lang/crates.io-index" 1521 | checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" 1522 | 1523 | [[package]] 1524 | name = "socket2" 1525 | version = "0.5.4" 1526 | source = "registry+https://github.com/rust-lang/crates.io-index" 1527 | checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" 1528 | dependencies = [ 1529 | "libc", 1530 | "windows-sys", 1531 | ] 1532 | 1533 | [[package]] 1534 | name = "spin" 1535 | version = "0.9.8" 1536 | source = "registry+https://github.com/rust-lang/crates.io-index" 1537 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1538 | dependencies = [ 1539 | "lock_api", 1540 | ] 1541 | 1542 | [[package]] 1543 | name = "sptr" 1544 | version = "0.3.2" 1545 | source = "registry+https://github.com/rust-lang/crates.io-index" 1546 | checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" 1547 | 1548 | [[package]] 1549 | name = "stable_deref_trait" 1550 | version = "1.2.0" 1551 | source = "registry+https://github.com/rust-lang/crates.io-index" 1552 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1553 | 1554 | [[package]] 1555 | name = "stringprep" 1556 | version = "0.1.4" 1557 | source = "registry+https://github.com/rust-lang/crates.io-index" 1558 | checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" 1559 | dependencies = [ 1560 | "finl_unicode", 1561 | "unicode-bidi", 1562 | "unicode-normalization", 1563 | ] 1564 | 1565 | [[package]] 1566 | name = "subtle" 1567 | version = "2.5.0" 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" 1569 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" 1570 | 1571 | [[package]] 1572 | name = "syn" 1573 | version = "1.0.109" 1574 | source = "registry+https://github.com/rust-lang/crates.io-index" 1575 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1576 | dependencies = [ 1577 | "proc-macro2", 1578 | "quote", 1579 | "unicode-ident", 1580 | ] 1581 | 1582 | [[package]] 1583 | name = "syn" 1584 | version = "2.0.38" 1585 | source = "registry+https://github.com/rust-lang/crates.io-index" 1586 | checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" 1587 | dependencies = [ 1588 | "proc-macro2", 1589 | "quote", 1590 | "unicode-ident", 1591 | ] 1592 | 1593 | [[package]] 1594 | name = "sysinfo" 1595 | version = "0.29.10" 1596 | source = "registry+https://github.com/rust-lang/crates.io-index" 1597 | checksum = "0a18d114d420ada3a891e6bc8e96a2023402203296a47cdd65083377dad18ba5" 1598 | dependencies = [ 1599 | "cfg-if", 1600 | "core-foundation-sys", 1601 | "libc", 1602 | "ntapi", 1603 | "once_cell", 1604 | "rayon", 1605 | "winapi", 1606 | ] 1607 | 1608 | [[package]] 1609 | name = "tap" 1610 | version = "1.0.1" 1611 | source = "registry+https://github.com/rust-lang/crates.io-index" 1612 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 1613 | 1614 | [[package]] 1615 | name = "tempfile" 1616 | version = "3.8.0" 1617 | source = "registry+https://github.com/rust-lang/crates.io-index" 1618 | checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" 1619 | dependencies = [ 1620 | "cfg-if", 1621 | "fastrand", 1622 | "redox_syscall 0.3.5", 1623 | "rustix", 1624 | "windows-sys", 1625 | ] 1626 | 1627 | [[package]] 1628 | name = "thiserror" 1629 | version = "1.0.49" 1630 | source = "registry+https://github.com/rust-lang/crates.io-index" 1631 | checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" 1632 | dependencies = [ 1633 | "thiserror-impl", 1634 | ] 1635 | 1636 | [[package]] 1637 | name = "thiserror-impl" 1638 | version = "1.0.49" 1639 | source = "registry+https://github.com/rust-lang/crates.io-index" 1640 | checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" 1641 | dependencies = [ 1642 | "proc-macro2", 1643 | "quote", 1644 | "syn 2.0.38", 1645 | ] 1646 | 1647 | [[package]] 1648 | name = "tinyvec" 1649 | version = "1.6.0" 1650 | source = "registry+https://github.com/rust-lang/crates.io-index" 1651 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1652 | dependencies = [ 1653 | "tinyvec_macros", 1654 | ] 1655 | 1656 | [[package]] 1657 | name = "tinyvec_macros" 1658 | version = "0.1.1" 1659 | source = "registry+https://github.com/rust-lang/crates.io-index" 1660 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1661 | 1662 | [[package]] 1663 | name = "tokio" 1664 | version = "1.32.0" 1665 | source = "registry+https://github.com/rust-lang/crates.io-index" 1666 | checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" 1667 | dependencies = [ 1668 | "backtrace", 1669 | "bytes", 1670 | "libc", 1671 | "mio", 1672 | "pin-project-lite", 1673 | "socket2", 1674 | "windows-sys", 1675 | ] 1676 | 1677 | [[package]] 1678 | name = "tokio-postgres" 1679 | version = "0.7.10" 1680 | source = "registry+https://github.com/rust-lang/crates.io-index" 1681 | checksum = "d340244b32d920260ae7448cb72b6e238bddc3d4f7603394e7dd46ed8e48f5b8" 1682 | dependencies = [ 1683 | "async-trait", 1684 | "byteorder", 1685 | "bytes", 1686 | "fallible-iterator", 1687 | "futures-channel", 1688 | "futures-util", 1689 | "log", 1690 | "parking_lot", 1691 | "percent-encoding", 1692 | "phf", 1693 | "pin-project-lite", 1694 | "postgres-protocol", 1695 | "postgres-types", 1696 | "rand", 1697 | "socket2", 1698 | "tokio", 1699 | "tokio-util", 1700 | "whoami", 1701 | ] 1702 | 1703 | [[package]] 1704 | name = "tokio-util" 1705 | version = "0.7.9" 1706 | source = "registry+https://github.com/rust-lang/crates.io-index" 1707 | checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" 1708 | dependencies = [ 1709 | "bytes", 1710 | "futures-core", 1711 | "futures-sink", 1712 | "pin-project-lite", 1713 | "tokio", 1714 | "tracing", 1715 | ] 1716 | 1717 | [[package]] 1718 | name = "toml" 1719 | version = "0.5.11" 1720 | source = "registry+https://github.com/rust-lang/crates.io-index" 1721 | checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" 1722 | dependencies = [ 1723 | "serde", 1724 | ] 1725 | 1726 | [[package]] 1727 | name = "toml" 1728 | version = "0.8.2" 1729 | source = "registry+https://github.com/rust-lang/crates.io-index" 1730 | checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" 1731 | dependencies = [ 1732 | "serde", 1733 | "serde_spanned", 1734 | "toml_datetime", 1735 | "toml_edit", 1736 | ] 1737 | 1738 | [[package]] 1739 | name = "toml_datetime" 1740 | version = "0.6.3" 1741 | source = "registry+https://github.com/rust-lang/crates.io-index" 1742 | checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" 1743 | dependencies = [ 1744 | "serde", 1745 | ] 1746 | 1747 | [[package]] 1748 | name = "toml_edit" 1749 | version = "0.20.2" 1750 | source = "registry+https://github.com/rust-lang/crates.io-index" 1751 | checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" 1752 | dependencies = [ 1753 | "indexmap", 1754 | "serde", 1755 | "serde_spanned", 1756 | "toml_datetime", 1757 | "winnow", 1758 | ] 1759 | 1760 | [[package]] 1761 | name = "tracing" 1762 | version = "0.1.37" 1763 | source = "registry+https://github.com/rust-lang/crates.io-index" 1764 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 1765 | dependencies = [ 1766 | "cfg-if", 1767 | "pin-project-lite", 1768 | "tracing-core", 1769 | ] 1770 | 1771 | [[package]] 1772 | name = "tracing-core" 1773 | version = "0.1.31" 1774 | source = "registry+https://github.com/rust-lang/crates.io-index" 1775 | checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" 1776 | dependencies = [ 1777 | "once_cell", 1778 | ] 1779 | 1780 | [[package]] 1781 | name = "typenum" 1782 | version = "1.17.0" 1783 | source = "registry+https://github.com/rust-lang/crates.io-index" 1784 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1785 | 1786 | [[package]] 1787 | name = "ucd-trie" 1788 | version = "0.1.6" 1789 | source = "registry+https://github.com/rust-lang/crates.io-index" 1790 | checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" 1791 | 1792 | [[package]] 1793 | name = "unarray" 1794 | version = "0.1.4" 1795 | source = "registry+https://github.com/rust-lang/crates.io-index" 1796 | checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" 1797 | 1798 | [[package]] 1799 | name = "unescape" 1800 | version = "0.1.0" 1801 | source = "registry+https://github.com/rust-lang/crates.io-index" 1802 | checksum = "ccb97dac3243214f8d8507998906ca3e2e0b900bf9bf4870477f125b82e68f6e" 1803 | 1804 | [[package]] 1805 | name = "unicode-bidi" 1806 | version = "0.3.13" 1807 | source = "registry+https://github.com/rust-lang/crates.io-index" 1808 | checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" 1809 | 1810 | [[package]] 1811 | name = "unicode-ident" 1812 | version = "1.0.12" 1813 | source = "registry+https://github.com/rust-lang/crates.io-index" 1814 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1815 | 1816 | [[package]] 1817 | name = "unicode-normalization" 1818 | version = "0.1.22" 1819 | source = "registry+https://github.com/rust-lang/crates.io-index" 1820 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 1821 | dependencies = [ 1822 | "tinyvec", 1823 | ] 1824 | 1825 | [[package]] 1826 | name = "unicode-segmentation" 1827 | version = "1.10.1" 1828 | source = "registry+https://github.com/rust-lang/crates.io-index" 1829 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" 1830 | 1831 | [[package]] 1832 | name = "url" 1833 | version = "2.4.1" 1834 | source = "registry+https://github.com/rust-lang/crates.io-index" 1835 | checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" 1836 | dependencies = [ 1837 | "form_urlencoded", 1838 | "idna", 1839 | "percent-encoding", 1840 | ] 1841 | 1842 | [[package]] 1843 | name = "uuid" 1844 | version = "1.4.1" 1845 | source = "registry+https://github.com/rust-lang/crates.io-index" 1846 | checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" 1847 | dependencies = [ 1848 | "getrandom", 1849 | ] 1850 | 1851 | [[package]] 1852 | name = "version_check" 1853 | version = "0.9.4" 1854 | source = "registry+https://github.com/rust-lang/crates.io-index" 1855 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1856 | 1857 | [[package]] 1858 | name = "wait-timeout" 1859 | version = "0.2.0" 1860 | source = "registry+https://github.com/rust-lang/crates.io-index" 1861 | checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" 1862 | dependencies = [ 1863 | "libc", 1864 | ] 1865 | 1866 | [[package]] 1867 | name = "wasi" 1868 | version = "0.11.0+wasi-snapshot-preview1" 1869 | source = "registry+https://github.com/rust-lang/crates.io-index" 1870 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1871 | 1872 | [[package]] 1873 | name = "wasm-bindgen" 1874 | version = "0.2.87" 1875 | source = "registry+https://github.com/rust-lang/crates.io-index" 1876 | checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" 1877 | dependencies = [ 1878 | "cfg-if", 1879 | "wasm-bindgen-macro", 1880 | ] 1881 | 1882 | [[package]] 1883 | name = "wasm-bindgen-backend" 1884 | version = "0.2.87" 1885 | source = "registry+https://github.com/rust-lang/crates.io-index" 1886 | checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" 1887 | dependencies = [ 1888 | "bumpalo", 1889 | "log", 1890 | "once_cell", 1891 | "proc-macro2", 1892 | "quote", 1893 | "syn 2.0.38", 1894 | "wasm-bindgen-shared", 1895 | ] 1896 | 1897 | [[package]] 1898 | name = "wasm-bindgen-macro" 1899 | version = "0.2.87" 1900 | source = "registry+https://github.com/rust-lang/crates.io-index" 1901 | checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" 1902 | dependencies = [ 1903 | "quote", 1904 | "wasm-bindgen-macro-support", 1905 | ] 1906 | 1907 | [[package]] 1908 | name = "wasm-bindgen-macro-support" 1909 | version = "0.2.87" 1910 | source = "registry+https://github.com/rust-lang/crates.io-index" 1911 | checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" 1912 | dependencies = [ 1913 | "proc-macro2", 1914 | "quote", 1915 | "syn 2.0.38", 1916 | "wasm-bindgen-backend", 1917 | "wasm-bindgen-shared", 1918 | ] 1919 | 1920 | [[package]] 1921 | name = "wasm-bindgen-shared" 1922 | version = "0.2.87" 1923 | source = "registry+https://github.com/rust-lang/crates.io-index" 1924 | checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" 1925 | 1926 | [[package]] 1927 | name = "web-sys" 1928 | version = "0.3.64" 1929 | source = "registry+https://github.com/rust-lang/crates.io-index" 1930 | checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" 1931 | dependencies = [ 1932 | "js-sys", 1933 | "wasm-bindgen", 1934 | ] 1935 | 1936 | [[package]] 1937 | name = "which" 1938 | version = "4.4.2" 1939 | source = "registry+https://github.com/rust-lang/crates.io-index" 1940 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 1941 | dependencies = [ 1942 | "either", 1943 | "home", 1944 | "once_cell", 1945 | "rustix", 1946 | ] 1947 | 1948 | [[package]] 1949 | name = "whoami" 1950 | version = "1.4.1" 1951 | source = "registry+https://github.com/rust-lang/crates.io-index" 1952 | checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" 1953 | dependencies = [ 1954 | "wasm-bindgen", 1955 | "web-sys", 1956 | ] 1957 | 1958 | [[package]] 1959 | name = "winapi" 1960 | version = "0.3.9" 1961 | source = "registry+https://github.com/rust-lang/crates.io-index" 1962 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1963 | dependencies = [ 1964 | "winapi-i686-pc-windows-gnu", 1965 | "winapi-x86_64-pc-windows-gnu", 1966 | ] 1967 | 1968 | [[package]] 1969 | name = "winapi-i686-pc-windows-gnu" 1970 | version = "0.4.0" 1971 | source = "registry+https://github.com/rust-lang/crates.io-index" 1972 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1973 | 1974 | [[package]] 1975 | name = "winapi-x86_64-pc-windows-gnu" 1976 | version = "0.4.0" 1977 | source = "registry+https://github.com/rust-lang/crates.io-index" 1978 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1979 | 1980 | [[package]] 1981 | name = "windows-sys" 1982 | version = "0.48.0" 1983 | source = "registry+https://github.com/rust-lang/crates.io-index" 1984 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1985 | dependencies = [ 1986 | "windows-targets", 1987 | ] 1988 | 1989 | [[package]] 1990 | name = "windows-targets" 1991 | version = "0.48.5" 1992 | source = "registry+https://github.com/rust-lang/crates.io-index" 1993 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1994 | dependencies = [ 1995 | "windows_aarch64_gnullvm", 1996 | "windows_aarch64_msvc", 1997 | "windows_i686_gnu", 1998 | "windows_i686_msvc", 1999 | "windows_x86_64_gnu", 2000 | "windows_x86_64_gnullvm", 2001 | "windows_x86_64_msvc", 2002 | ] 2003 | 2004 | [[package]] 2005 | name = "windows_aarch64_gnullvm" 2006 | version = "0.48.5" 2007 | source = "registry+https://github.com/rust-lang/crates.io-index" 2008 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2009 | 2010 | [[package]] 2011 | name = "windows_aarch64_msvc" 2012 | version = "0.48.5" 2013 | source = "registry+https://github.com/rust-lang/crates.io-index" 2014 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2015 | 2016 | [[package]] 2017 | name = "windows_i686_gnu" 2018 | version = "0.48.5" 2019 | source = "registry+https://github.com/rust-lang/crates.io-index" 2020 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2021 | 2022 | [[package]] 2023 | name = "windows_i686_msvc" 2024 | version = "0.48.5" 2025 | source = "registry+https://github.com/rust-lang/crates.io-index" 2026 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2027 | 2028 | [[package]] 2029 | name = "windows_x86_64_gnu" 2030 | version = "0.48.5" 2031 | source = "registry+https://github.com/rust-lang/crates.io-index" 2032 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2033 | 2034 | [[package]] 2035 | name = "windows_x86_64_gnullvm" 2036 | version = "0.48.5" 2037 | source = "registry+https://github.com/rust-lang/crates.io-index" 2038 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2039 | 2040 | [[package]] 2041 | name = "windows_x86_64_msvc" 2042 | version = "0.48.5" 2043 | source = "registry+https://github.com/rust-lang/crates.io-index" 2044 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2045 | 2046 | [[package]] 2047 | name = "winnow" 2048 | version = "0.5.16" 2049 | source = "registry+https://github.com/rust-lang/crates.io-index" 2050 | checksum = "037711d82167854aff2018dfd193aa0fef5370f456732f0d5a0c59b0f1b4b907" 2051 | dependencies = [ 2052 | "memchr", 2053 | ] 2054 | 2055 | [[package]] 2056 | name = "wyz" 2057 | version = "0.5.1" 2058 | source = "registry+https://github.com/rust-lang/crates.io-index" 2059 | checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" 2060 | dependencies = [ 2061 | "tap", 2062 | ] 2063 | -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 63 | --------------------------------------------------------------------------------