mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-03 19:42:55 +00:00
Manage pgbouncer configuration from compute_ctl:
- add pgbouncer_settings section to compute spec; - add pgbouncer-connstr option to compute_ctl. - add pgbouncer-ini-path option to compute_ctl. Default: /etc/pgbouncer/pgbouncer.ini Apply pgbouncer config on compute start and respec to override default spec. Save pgbouncer config updates to pgbouncer.ini to preserve them across pgbouncer restarts.
This commit is contained in:
67
Cargo.lock
generated
67
Cargo.lock
generated
@@ -1168,6 +1168,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"remote_storage",
|
"remote_storage",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"rust-ini",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tar",
|
"tar",
|
||||||
@@ -1201,6 +1202,26 @@ version = "0.9.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
|
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-random"
|
||||||
|
version = "0.1.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a"
|
||||||
|
dependencies = [
|
||||||
|
"const-random-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-random-macro"
|
||||||
|
version = "0.1.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.11",
|
||||||
|
"once_cell",
|
||||||
|
"tiny-keccak",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const_fn"
|
name = "const_fn"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
@@ -1433,6 +1454,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crunchy"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-bigint"
|
name = "crypto-bigint"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
@@ -1575,6 +1602,15 @@ dependencies = [
|
|||||||
"syn 2.0.32",
|
"syn 2.0.32",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dlv-list"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
|
||||||
|
dependencies = [
|
||||||
|
"const-random",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dyn-clone"
|
name = "dyn-clone"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
@@ -3043,6 +3079,16 @@ dependencies = [
|
|||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ordered-multimap"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4d6a8c22fc714f0c2373e6091bf6f5e9b37b1bc0b1184874b7e0a4e303d318f"
|
||||||
|
dependencies = [
|
||||||
|
"dlv-list",
|
||||||
|
"hashbrown 0.14.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_info"
|
name = "os_info"
|
||||||
version = "3.7.0"
|
version = "3.7.0"
|
||||||
@@ -4216,6 +4262,16 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-ini"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"ordered-multimap",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.23"
|
version = "0.1.23"
|
||||||
@@ -5170,6 +5226,15 @@ dependencies = [
|
|||||||
"time-core",
|
"time-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tiny-keccak"
|
||||||
|
version = "2.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
|
||||||
|
dependencies = [
|
||||||
|
"crunchy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinytemplate"
|
name = "tinytemplate"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@@ -6337,6 +6402,7 @@ dependencies = [
|
|||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"getrandom 0.2.11",
|
||||||
"hex",
|
"hex",
|
||||||
"hmac",
|
"hmac",
|
||||||
"hyper",
|
"hyper",
|
||||||
@@ -6348,6 +6414,7 @@ dependencies = [
|
|||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"once_cell",
|
||||||
"prost",
|
"prost",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"regex",
|
"regex",
|
||||||
|
|||||||
@@ -39,3 +39,4 @@ remote_storage = { version = "0.1", path = "../libs/remote_storage/" }
|
|||||||
vm_monitor = { version = "0.1", path = "../libs/vm_monitor/" }
|
vm_monitor = { version = "0.1", path = "../libs/vm_monitor/" }
|
||||||
zstd = "0.13"
|
zstd = "0.13"
|
||||||
bytes = "1.0"
|
bytes = "1.0"
|
||||||
|
rust-ini = "0.20.0"
|
||||||
|
|||||||
@@ -31,7 +31,9 @@
|
|||||||
//! -C 'postgresql://cloud_admin@localhost/postgres' \
|
//! -C 'postgresql://cloud_admin@localhost/postgres' \
|
||||||
//! -S /var/db/postgres/specs/current.json \
|
//! -S /var/db/postgres/specs/current.json \
|
||||||
//! -b /usr/local/bin/postgres \
|
//! -b /usr/local/bin/postgres \
|
||||||
//! -r http://pg-ext-s3-gateway
|
//! -r http://pg-ext-s3-gateway \
|
||||||
|
//! --pgbouncer-connstr 'host=localhost port=6432 dbname=pgbouncer user=cloud_admin sslmode=disable'
|
||||||
|
//! --pgbouncer-ini-path /etc/pgbouncer.ini \
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -99,6 +101,9 @@ fn main() -> Result<()> {
|
|||||||
let spec_json = matches.get_one::<String>("spec");
|
let spec_json = matches.get_one::<String>("spec");
|
||||||
let spec_path = matches.get_one::<String>("spec-path");
|
let spec_path = matches.get_one::<String>("spec-path");
|
||||||
|
|
||||||
|
let pgbouncer_connstr = matches.get_one::<String>("pgbouncer-connstr");
|
||||||
|
let pgbouncer_ini_path = matches.get_one::<String>("pgbouncer-ini-path");
|
||||||
|
|
||||||
// Extract OpenTelemetry context for the startup actions from the
|
// Extract OpenTelemetry context for the startup actions from the
|
||||||
// TRACEPARENT and TRACESTATE env variables, and attach it to the current
|
// TRACEPARENT and TRACESTATE env variables, and attach it to the current
|
||||||
// tracing context.
|
// tracing context.
|
||||||
@@ -209,6 +214,8 @@ fn main() -> Result<()> {
|
|||||||
ext_remote_storage: ext_remote_storage.map(|s| s.to_string()),
|
ext_remote_storage: ext_remote_storage.map(|s| s.to_string()),
|
||||||
ext_download_progress: RwLock::new(HashMap::new()),
|
ext_download_progress: RwLock::new(HashMap::new()),
|
||||||
build_tag,
|
build_tag,
|
||||||
|
pgbouncer_connstr: pgbouncer_connstr.map(|s| s.to_string()),
|
||||||
|
pgbouncer_ini_path: pgbouncer_ini_path.map(|s| s.to_string()),
|
||||||
};
|
};
|
||||||
let compute = Arc::new(compute_node);
|
let compute = Arc::new(compute_node);
|
||||||
|
|
||||||
@@ -493,6 +500,23 @@ fn cli() -> clap::Command {
|
|||||||
)
|
)
|
||||||
.value_name("FILECACHE_CONNSTR"),
|
.value_name("FILECACHE_CONNSTR"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("pgbouncer-connstr")
|
||||||
|
.long("pgbouncer-connstr")
|
||||||
|
.default_value(
|
||||||
|
"host=localhost port=6432 dbname=pgbouncer user=cloud_admin sslmode=disable",
|
||||||
|
)
|
||||||
|
.value_name("PGBOUNCER_CONNSTR"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("pgbouncer-ini-path")
|
||||||
|
.long("pgbouncer-ini-path")
|
||||||
|
// Note: this doesn't match current path for pgbouncer.ini.
|
||||||
|
// Until we fix it, we need to pass the path explicitly
|
||||||
|
// or this will be effectively no-op.
|
||||||
|
.default_value("/etc/pgbouncer.ini")
|
||||||
|
.value_name("PGBOUNCER_INI_PATH"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use std::path::Path;
|
|||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Condvar, Mutex, RwLock};
|
use std::sync::{Condvar, Mutex, RwLock};
|
||||||
|
use std::thread;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
@@ -64,6 +65,10 @@ pub struct ComputeNode {
|
|||||||
// key: ext_archive_name, value: started download time, download_completed?
|
// key: ext_archive_name, value: started download time, download_completed?
|
||||||
pub ext_download_progress: RwLock<HashMap<String, (DateTime<Utc>, bool)>>,
|
pub ext_download_progress: RwLock<HashMap<String, (DateTime<Utc>, bool)>>,
|
||||||
pub build_tag: String,
|
pub build_tag: String,
|
||||||
|
// connection string to pgbouncer to change settings
|
||||||
|
pub pgbouncer_connstr: Option<String>,
|
||||||
|
// path to pgbouncer.ini to change settings
|
||||||
|
pub pgbouncer_ini_path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// store some metrics about download size that might impact startup time
|
// store some metrics about download size that might impact startup time
|
||||||
@@ -737,6 +742,31 @@ impl ComputeNode {
|
|||||||
pub fn reconfigure(&self) -> Result<()> {
|
pub fn reconfigure(&self) -> Result<()> {
|
||||||
let spec = self.state.lock().unwrap().pspec.clone().unwrap().spec;
|
let spec = self.state.lock().unwrap().pspec.clone().unwrap().spec;
|
||||||
|
|
||||||
|
if let Some(connstr) = &self.pgbouncer_connstr {
|
||||||
|
info!("tuning pgbouncer with connstr: {:?}", connstr);
|
||||||
|
|
||||||
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.expect("failed to create rt");
|
||||||
|
|
||||||
|
// Spawn a thread to do the tuning,
|
||||||
|
// so that we don't block the main thread that starts Postgres.
|
||||||
|
let pgbouncer_settings = spec.pgbouncer_settings.clone();
|
||||||
|
let connstr_clone = connstr.clone();
|
||||||
|
let pgbouncer_ini_path = self.pgbouncer_ini_path.clone();
|
||||||
|
let _handle = thread::spawn(move || {
|
||||||
|
let res = rt.block_on(tune_pgbouncer(
|
||||||
|
pgbouncer_settings,
|
||||||
|
&connstr_clone,
|
||||||
|
pgbouncer_ini_path,
|
||||||
|
));
|
||||||
|
if let Err(err) = res {
|
||||||
|
error!("error while tuning pgbouncer: {err:?}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Write new config
|
// Write new config
|
||||||
let pgdata_path = Path::new(&self.pgdata);
|
let pgdata_path = Path::new(&self.pgdata);
|
||||||
let postgresql_conf_path = pgdata_path.join("postgresql.conf");
|
let postgresql_conf_path = pgdata_path.join("postgresql.conf");
|
||||||
@@ -791,6 +821,32 @@ impl ComputeNode {
|
|||||||
pspec.timeline_id,
|
pspec.timeline_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// tune pgbouncer
|
||||||
|
if let Some(connstr) = &self.pgbouncer_connstr {
|
||||||
|
info!("tuning pgbouncer with connstr: {:?}", connstr);
|
||||||
|
|
||||||
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.expect("failed to create rt");
|
||||||
|
|
||||||
|
// Spawn a thread to do the tuning,
|
||||||
|
// so that we don't block the main thread that starts Postgres.
|
||||||
|
let pgbouncer_settings = pspec.spec.pgbouncer_settings.clone();
|
||||||
|
let connstr_clone = connstr.clone();
|
||||||
|
let pgbouncer_ini_path = self.pgbouncer_ini_path.clone();
|
||||||
|
let _handle = thread::spawn(move || {
|
||||||
|
let res = rt.block_on(tune_pgbouncer(
|
||||||
|
pgbouncer_settings,
|
||||||
|
&connstr_clone,
|
||||||
|
pgbouncer_ini_path,
|
||||||
|
));
|
||||||
|
if let Err(err) = res {
|
||||||
|
error!("error while tuning pgbouncer: {err:?}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"start_compute spec.remote_extensions {:?}",
|
"start_compute spec.remote_extensions {:?}",
|
||||||
pspec.spec.remote_extensions
|
pspec.spec.remote_extensions
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ use std::process::Child;
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
use ini::Ini;
|
||||||
use notify::{RecursiveMode, Watcher};
|
use notify::{RecursiveMode, Watcher};
|
||||||
use postgres::{Client, Transaction};
|
use postgres::{Client, Transaction};
|
||||||
use tracing::{debug, instrument};
|
use tokio_postgres::NoTls;
|
||||||
|
use tracing::{debug, error, info, instrument};
|
||||||
|
|
||||||
use compute_api::spec::{Database, GenericOption, GenericOptions, PgIdent, Role};
|
use compute_api::spec::{Database, GenericOption, GenericOptions, PgIdent, Role};
|
||||||
|
|
||||||
@@ -359,3 +361,68 @@ pub fn create_pgdata(pgdata: &str) -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update pgbouncer.ini with provided options
|
||||||
|
pub fn update_pgbouncer_ini(
|
||||||
|
pgbouncer_config: HashMap<String, String>,
|
||||||
|
pgbouncer_ini_path: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut conf = Ini::load_from_file(pgbouncer_ini_path)?;
|
||||||
|
let section = conf.section_mut(Some("pgbouncer")).unwrap();
|
||||||
|
|
||||||
|
for (option_name, value) in pgbouncer_config.iter() {
|
||||||
|
section.insert(option_name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.write_to_file(pgbouncer_ini_path)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tune pgbouncer.
|
||||||
|
/// 1. Apply new config using pgbouncer admin console
|
||||||
|
/// 2. Add new values to pgbouncer.ini to preserve them after restart
|
||||||
|
pub async fn tune_pgbouncer(
|
||||||
|
pgbouncer_settings: Option<HashMap<String, String>>,
|
||||||
|
pgbouncer_connstr: &str,
|
||||||
|
pgbouncer_ini_path: Option<String>,
|
||||||
|
) -> Result<()> {
|
||||||
|
if let Some(pgbouncer_config) = pgbouncer_settings {
|
||||||
|
// Apply new config
|
||||||
|
let connect_result = tokio_postgres::connect(pgbouncer_connstr, NoTls).await;
|
||||||
|
let (client, connection) = connect_result.unwrap();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Err(e) = connection.await {
|
||||||
|
eprintln!("connection error: {}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (option_name, value) in pgbouncer_config.iter() {
|
||||||
|
info!(
|
||||||
|
"Applying pgbouncer setting change: {} = {}",
|
||||||
|
option_name, value
|
||||||
|
);
|
||||||
|
let query = format!("SET {} = {}", option_name, value);
|
||||||
|
|
||||||
|
let result = client.simple_query(&query).await;
|
||||||
|
|
||||||
|
info!("Applying pgbouncer setting change: {}", query);
|
||||||
|
info!("pgbouncer setting change result: {:?}", result);
|
||||||
|
|
||||||
|
if let Err(err) = result {
|
||||||
|
// Don't fail on error, just print it into log
|
||||||
|
error!(
|
||||||
|
"Failed to apply pgbouncer setting change: {}, {}",
|
||||||
|
query, err
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// save values to pgbouncer.ini
|
||||||
|
// so that they are preserved after pgbouncer restart
|
||||||
|
if let Some(pgbouncer_ini_path) = pgbouncer_ini_path {
|
||||||
|
update_pgbouncer_ini(pgbouncer_config, &pgbouncer_ini_path)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -537,6 +537,7 @@ impl Endpoint {
|
|||||||
safekeeper_connstrings,
|
safekeeper_connstrings,
|
||||||
storage_auth_token: auth_token.clone(),
|
storage_auth_token: auth_token.clone(),
|
||||||
remote_extensions,
|
remote_extensions,
|
||||||
|
pgbouncer_settings: None,
|
||||||
};
|
};
|
||||||
let spec_path = self.endpoint_path().join("spec.json");
|
let spec_path = self.endpoint_path().join("spec.json");
|
||||||
std::fs::write(spec_path, serde_json::to_string_pretty(&spec)?)?;
|
std::fs::write(spec_path, serde_json::to_string_pretty(&spec)?)?;
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ allow = [
|
|||||||
"Artistic-2.0",
|
"Artistic-2.0",
|
||||||
"BSD-2-Clause",
|
"BSD-2-Clause",
|
||||||
"BSD-3-Clause",
|
"BSD-3-Clause",
|
||||||
|
"CC0-1.0",
|
||||||
"ISC",
|
"ISC",
|
||||||
"MIT",
|
"MIT",
|
||||||
"MPL-2.0",
|
"MPL-2.0",
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ pub struct ComputeSpec {
|
|||||||
|
|
||||||
// information about available remote extensions
|
// information about available remote extensions
|
||||||
pub remote_extensions: Option<RemoteExtSpec>,
|
pub remote_extensions: Option<RemoteExtSpec>,
|
||||||
|
|
||||||
|
pub pgbouncer_settings: Option<HashMap<String, String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Feature flag to signal `compute_ctl` to enable certain experimental functionality.
|
/// Feature flag to signal `compute_ctl` to enable certain experimental functionality.
|
||||||
|
|||||||
@@ -243,5 +243,9 @@
|
|||||||
"public_extensions": [
|
"public_extensions": [
|
||||||
"postgis"
|
"postgis"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"pgbouncer_settings": {
|
||||||
|
"default_pool_size": "42",
|
||||||
|
"pool_mode": "session"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ files:
|
|||||||
max_client_conn=10000
|
max_client_conn=10000
|
||||||
default_pool_size=64
|
default_pool_size=64
|
||||||
max_prepared_statements=0
|
max_prepared_statements=0
|
||||||
|
admin_users=cloud_admin
|
||||||
- filename: cgconfig.conf
|
- filename: cgconfig.conf
|
||||||
content: |
|
content: |
|
||||||
# Configuration for cgroups in VM compute nodes
|
# Configuration for cgroups in VM compute nodes
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ futures-executor = { version = "0.3" }
|
|||||||
futures-io = { version = "0.3" }
|
futures-io = { version = "0.3" }
|
||||||
futures-sink = { version = "0.3" }
|
futures-sink = { version = "0.3" }
|
||||||
futures-util = { version = "0.3", features = ["channel", "io", "sink"] }
|
futures-util = { version = "0.3", features = ["channel", "io", "sink"] }
|
||||||
|
getrandom = { version = "0.2", default-features = false, features = ["std"] }
|
||||||
hex = { version = "0.4", features = ["serde"] }
|
hex = { version = "0.4", features = ["serde"] }
|
||||||
hmac = { version = "0.12", default-features = false, features = ["reset"] }
|
hmac = { version = "0.12", default-features = false, features = ["reset"] }
|
||||||
hyper = { version = "0.14", features = ["full"] }
|
hyper = { version = "0.14", features = ["full"] }
|
||||||
@@ -50,6 +51,7 @@ nom = { version = "7" }
|
|||||||
num-bigint = { version = "0.4" }
|
num-bigint = { version = "0.4" }
|
||||||
num-integer = { version = "0.1", features = ["i128"] }
|
num-integer = { version = "0.1", features = ["i128"] }
|
||||||
num-traits = { version = "0.2", features = ["i128"] }
|
num-traits = { version = "0.2", features = ["i128"] }
|
||||||
|
once_cell = { version = "1" }
|
||||||
prost = { version = "0.11" }
|
prost = { version = "0.11" }
|
||||||
rand = { version = "0.8", features = ["small_rng"] }
|
rand = { version = "0.8", features = ["small_rng"] }
|
||||||
regex = { version = "1" }
|
regex = { version = "1" }
|
||||||
@@ -84,11 +86,13 @@ anyhow = { version = "1", features = ["backtrace"] }
|
|||||||
bytes = { version = "1", features = ["serde"] }
|
bytes = { version = "1", features = ["serde"] }
|
||||||
cc = { version = "1", default-features = false, features = ["parallel"] }
|
cc = { version = "1", default-features = false, features = ["parallel"] }
|
||||||
either = { version = "1" }
|
either = { version = "1" }
|
||||||
|
getrandom = { version = "0.2", default-features = false, features = ["std"] }
|
||||||
itertools = { version = "0.10" }
|
itertools = { version = "0.10" }
|
||||||
libc = { version = "0.2", features = ["extra_traits"] }
|
libc = { version = "0.2", features = ["extra_traits"] }
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
memchr = { version = "2" }
|
memchr = { version = "2" }
|
||||||
nom = { version = "7" }
|
nom = { version = "7" }
|
||||||
|
once_cell = { version = "1" }
|
||||||
prost = { version = "0.11" }
|
prost = { version = "0.11" }
|
||||||
regex = { version = "1" }
|
regex = { version = "1" }
|
||||||
regex-automata = { version = "0.4", default-features = false, features = ["dfa-onepass", "hybrid", "meta", "nfa-backtrack", "perf-inline", "perf-literal", "unicode"] }
|
regex-automata = { version = "0.4", default-features = false, features = ["dfa-onepass", "hybrid", "meta", "nfa-backtrack", "perf-inline", "perf-literal", "unicode"] }
|
||||||
|
|||||||
Reference in New Issue
Block a user