Compare commits
3 commits
main
...
feat/preem
Author | SHA1 | Date | |
---|---|---|---|
1ca12a9cb6 | |||
5b6521b868 | |||
e628072d37 |
40 changed files with 434 additions and 340 deletions
28
Cargo.lock
generated
28
Cargo.lock
generated
|
@ -1304,7 +1304,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage"
|
name = "garage"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert-json-diff",
|
"assert-json-diff",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -1360,7 +1360,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_api"
|
name = "garage_api"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
"argon2",
|
"argon2",
|
||||||
|
@ -1415,7 +1415,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_block"
|
name = "garage_block"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-compression",
|
"async-compression",
|
||||||
|
@ -1442,7 +1442,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_db"
|
name = "garage_db"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"err-derive",
|
"err-derive",
|
||||||
"heed",
|
"heed",
|
||||||
|
@ -1456,7 +1456,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_model"
|
name = "garage_model"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -1486,7 +1486,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_net"
|
name = "garage_net"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -1512,7 +1512,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_rpc"
|
name = "garage_rpc"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -1548,7 +1548,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_table"
|
name = "garage_table"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -1570,7 +1570,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_util"
|
name = "garage_util"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -1604,7 +1604,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_web"
|
name = "garage_web"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"err-derive",
|
"err-derive",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -4082,9 +4082,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.36"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
"num-conv",
|
"num-conv",
|
||||||
|
@ -4102,9 +4102,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-macros"
|
name = "time-macros"
|
||||||
version = "0.2.18"
|
version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
|
checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-conv",
|
"num-conv",
|
||||||
"time-core",
|
"time-core",
|
||||||
|
|
158
Cargo.nix
158
Cargo.nix
|
@ -34,7 +34,7 @@ args@{
|
||||||
ignoreLockHash,
|
ignoreLockHash,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
nixifiedLockHash = "466643eea782cd68c6f205858bb9e053aecdb18e2e58427b0527022aad596130";
|
nixifiedLockHash = "fc41fb639a69d62c8c0fb3f9c227162162ebc8142c6fa5cd0599dc381dcd9ebb";
|
||||||
workspaceSrc = if args.workspaceSrc == null then ./. else args.workspaceSrc;
|
workspaceSrc = if args.workspaceSrc == null then ./. else args.workspaceSrc;
|
||||||
currentLockHash = builtins.hashFile "sha256" (workspaceSrc + /Cargo.lock);
|
currentLockHash = builtins.hashFile "sha256" (workspaceSrc + /Cargo.lock);
|
||||||
lockHashIgnored = if ignoreLockHash
|
lockHashIgnored = if ignoreLockHash
|
||||||
|
@ -58,17 +58,17 @@ in
|
||||||
{
|
{
|
||||||
cargo2nixVersion = "0.11.0";
|
cargo2nixVersion = "0.11.0";
|
||||||
workspace = {
|
workspace = {
|
||||||
garage_db = rustPackages.unknown.garage_db."1.0.1";
|
garage_db = rustPackages.unknown.garage_db."1.0.0";
|
||||||
garage_util = rustPackages.unknown.garage_util."1.0.1";
|
garage_util = rustPackages.unknown.garage_util."1.0.0";
|
||||||
garage_net = rustPackages.unknown.garage_net."1.0.1";
|
garage_net = rustPackages.unknown.garage_net."1.0.0";
|
||||||
garage_rpc = rustPackages.unknown.garage_rpc."1.0.1";
|
garage_rpc = rustPackages.unknown.garage_rpc."1.0.0";
|
||||||
format_table = rustPackages.unknown.format_table."0.1.1";
|
format_table = rustPackages.unknown.format_table."0.1.1";
|
||||||
garage_table = rustPackages.unknown.garage_table."1.0.1";
|
garage_table = rustPackages.unknown.garage_table."1.0.0";
|
||||||
garage_block = rustPackages.unknown.garage_block."1.0.1";
|
garage_block = rustPackages.unknown.garage_block."1.0.0";
|
||||||
garage_model = rustPackages.unknown.garage_model."1.0.1";
|
garage_model = rustPackages.unknown.garage_model."1.0.0";
|
||||||
garage_api = rustPackages.unknown.garage_api."1.0.1";
|
garage_api = rustPackages.unknown.garage_api."1.0.0";
|
||||||
garage_web = rustPackages.unknown.garage_web."1.0.1";
|
garage_web = rustPackages.unknown.garage_web."1.0.0";
|
||||||
garage = rustPackages.unknown.garage."1.0.1";
|
garage = rustPackages.unknown.garage."1.0.0";
|
||||||
k2v-client = rustPackages.unknown.k2v-client."0.0.4";
|
k2v-client = rustPackages.unknown.k2v-client."0.0.4";
|
||||||
};
|
};
|
||||||
"registry+https://github.com/rust-lang/crates.io-index".addr2line."0.21.0" = overridableMkRustCrate (profileName: rec {
|
"registry+https://github.com/rust-lang/crates.io-index".addr2line."0.21.0" = overridableMkRustCrate (profileName: rec {
|
||||||
|
@ -424,7 +424,7 @@ in
|
||||||
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."0.2.11" { inherit profileName; }).out;
|
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."0.2.11" { inherit profileName; }).out;
|
||||||
hyper = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."0.14.28" { inherit profileName; }).out;
|
hyper = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."0.14.28" { inherit profileName; }).out;
|
||||||
ring = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".ring."0.17.7" { inherit profileName; }).out;
|
ring = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".ring."0.17.7" { inherit profileName; }).out;
|
||||||
time = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" { inherit profileName; }).out;
|
time = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.34" { inherit profileName; }).out;
|
||||||
tokio = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tokio."1.36.0" { inherit profileName; }).out;
|
tokio = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tokio."1.36.0" { inherit profileName; }).out;
|
||||||
tracing = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tracing."0.1.40" { inherit profileName; }).out;
|
tracing = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tracing."0.1.40" { inherit profileName; }).out;
|
||||||
zeroize = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".zeroize."1.7.0" { inherit profileName; }).out;
|
zeroize = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".zeroize."1.7.0" { inherit profileName; }).out;
|
||||||
|
@ -643,7 +643,7 @@ in
|
||||||
ring = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".ring."0.17.7" { inherit profileName; }).out;
|
ring = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".ring."0.17.7" { inherit profileName; }).out;
|
||||||
sha2 = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".sha2."0.10.8" { inherit profileName; }).out;
|
sha2 = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".sha2."0.10.8" { inherit profileName; }).out;
|
||||||
subtle = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".subtle."2.5.0" { inherit profileName; }).out;
|
subtle = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".subtle."2.5.0" { inherit profileName; }).out;
|
||||||
time = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" { inherit profileName; }).out;
|
time = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.34" { inherit profileName; }).out;
|
||||||
tracing = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tracing."0.1.40" { inherit profileName; }).out;
|
tracing = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tracing."0.1.40" { inherit profileName; }).out;
|
||||||
zeroize = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".zeroize."1.7.0" { inherit profileName; }).out;
|
zeroize = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".zeroize."1.7.0" { inherit profileName; }).out;
|
||||||
};
|
};
|
||||||
|
@ -823,7 +823,7 @@ in
|
||||||
pin_utils = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".pin-utils."0.1.0" { inherit profileName; }).out;
|
pin_utils = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".pin-utils."0.1.0" { inherit profileName; }).out;
|
||||||
ryu = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".ryu."1.0.16" { inherit profileName; }).out;
|
ryu = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".ryu."1.0.16" { inherit profileName; }).out;
|
||||||
${ if false then "serde" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".serde."1.0.196" { inherit profileName; }).out;
|
${ if false then "serde" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".serde."1.0.196" { inherit profileName; }).out;
|
||||||
time = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" { inherit profileName; }).out;
|
time = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.34" { inherit profileName; }).out;
|
||||||
tokio = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tokio."1.36.0" { inherit profileName; }).out;
|
tokio = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tokio."1.36.0" { inherit profileName; }).out;
|
||||||
tokio_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tokio-util."0.7.10" { inherit profileName; }).out;
|
tokio_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tokio-util."0.7.10" { inherit profileName; }).out;
|
||||||
};
|
};
|
||||||
|
@ -1910,9 +1910,9 @@ in
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage."1.0.1" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage."1.0.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage";
|
name = "garage";
|
||||||
version = "1.0.1";
|
version = "1.0.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/garage");
|
src = fetchCrateLocal (workspaceSrc + "/src/garage");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
|
@ -1940,15 +1940,15 @@ in
|
||||||
format_table = (rustPackages."unknown".format_table."0.1.1" { inherit profileName; }).out;
|
format_table = (rustPackages."unknown".format_table."0.1.1" { inherit profileName; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
||||||
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.30" { inherit profileName; }).out;
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.30" { inherit profileName; }).out;
|
||||||
garage_api = (rustPackages."unknown".garage_api."1.0.1" { inherit profileName; }).out;
|
garage_api = (rustPackages."unknown".garage_api."1.0.0" { inherit profileName; }).out;
|
||||||
garage_block = (rustPackages."unknown".garage_block."1.0.1" { inherit profileName; }).out;
|
garage_block = (rustPackages."unknown".garage_block."1.0.0" { inherit profileName; }).out;
|
||||||
garage_db = (rustPackages."unknown".garage_db."1.0.1" { inherit profileName; }).out;
|
garage_db = (rustPackages."unknown".garage_db."1.0.0" { inherit profileName; }).out;
|
||||||
garage_model = (rustPackages."unknown".garage_model."1.0.1" { inherit profileName; }).out;
|
garage_model = (rustPackages."unknown".garage_model."1.0.0" { inherit profileName; }).out;
|
||||||
garage_net = (rustPackages."unknown".garage_net."1.0.1" { inherit profileName; }).out;
|
garage_net = (rustPackages."unknown".garage_net."1.0.0" { inherit profileName; }).out;
|
||||||
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.1" { inherit profileName; }).out;
|
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.0" { inherit profileName; }).out;
|
||||||
garage_table = (rustPackages."unknown".garage_table."1.0.1" { inherit profileName; }).out;
|
garage_table = (rustPackages."unknown".garage_table."1.0.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."1.0.1" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out;
|
||||||
garage_web = (rustPackages."unknown".garage_web."1.0.1" { inherit profileName; }).out;
|
garage_web = (rustPackages."unknown".garage_web."1.0.0" { inherit profileName; }).out;
|
||||||
git_version = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".git-version."0.3.9" { inherit profileName; }).out;
|
git_version = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".git-version."0.3.9" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
||||||
sodiumoxide = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".kuska-sodiumoxide."0.2.5-0" { inherit profileName; }).out;
|
sodiumoxide = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".kuska-sodiumoxide."0.2.5-0" { inherit profileName; }).out;
|
||||||
|
@ -1988,9 +1988,9 @@ in
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_api."1.0.1" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_api."1.0.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_api";
|
name = "garage_api";
|
||||||
version = "1.0.1";
|
version = "1.0.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/api");
|
src = fetchCrateLocal (workspaceSrc + "/src/api");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
|
@ -2014,12 +2014,12 @@ in
|
||||||
form_urlencoded = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".form_urlencoded."1.2.1" { inherit profileName; }).out;
|
form_urlencoded = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".form_urlencoded."1.2.1" { inherit profileName; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
||||||
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.30" { inherit profileName; }).out;
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.30" { inherit profileName; }).out;
|
||||||
garage_block = (rustPackages."unknown".garage_block."1.0.1" { inherit profileName; }).out;
|
garage_block = (rustPackages."unknown".garage_block."1.0.0" { inherit profileName; }).out;
|
||||||
garage_model = (rustPackages."unknown".garage_model."1.0.1" { inherit profileName; }).out;
|
garage_model = (rustPackages."unknown".garage_model."1.0.0" { inherit profileName; }).out;
|
||||||
garage_net = (rustPackages."unknown".garage_net."1.0.1" { inherit profileName; }).out;
|
garage_net = (rustPackages."unknown".garage_net."1.0.0" { inherit profileName; }).out;
|
||||||
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.1" { inherit profileName; }).out;
|
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.0" { inherit profileName; }).out;
|
||||||
garage_table = (rustPackages."unknown".garage_table."1.0.1" { inherit profileName; }).out;
|
garage_table = (rustPackages."unknown".garage_table."1.0.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."1.0.1" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
||||||
hmac = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hmac."0.12.1" { inherit profileName; }).out;
|
hmac = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hmac."0.12.1" { inherit profileName; }).out;
|
||||||
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."1.0.0" { inherit profileName; }).out;
|
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."1.0.0" { inherit profileName; }).out;
|
||||||
|
@ -2052,9 +2052,9 @@ in
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_block."1.0.1" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_block."1.0.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_block";
|
name = "garage_block";
|
||||||
version = "1.0.1";
|
version = "1.0.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/block");
|
src = fetchCrateLocal (workspaceSrc + "/src/block");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
|
@ -2068,11 +2068,11 @@ in
|
||||||
bytesize = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytesize."1.3.0" { inherit profileName; }).out;
|
bytesize = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytesize."1.3.0" { inherit profileName; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
||||||
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.30" { inherit profileName; }).out;
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.30" { inherit profileName; }).out;
|
||||||
garage_db = (rustPackages."unknown".garage_db."1.0.1" { inherit profileName; }).out;
|
garage_db = (rustPackages."unknown".garage_db."1.0.0" { inherit profileName; }).out;
|
||||||
garage_net = (rustPackages."unknown".garage_net."1.0.1" { inherit profileName; }).out;
|
garage_net = (rustPackages."unknown".garage_net."1.0.0" { inherit profileName; }).out;
|
||||||
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.1" { inherit profileName; }).out;
|
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.0" { inherit profileName; }).out;
|
||||||
garage_table = (rustPackages."unknown".garage_table."1.0.1" { inherit profileName; }).out;
|
garage_table = (rustPackages."unknown".garage_table."1.0.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."1.0.1" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
||||||
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
|
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
|
||||||
rand = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rand."0.8.5" { inherit profileName; }).out;
|
rand = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rand."0.8.5" { inherit profileName; }).out;
|
||||||
|
@ -2085,9 +2085,9 @@ in
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_db."1.0.1" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_db."1.0.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_db";
|
name = "garage_db";
|
||||||
version = "1.0.1";
|
version = "1.0.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/db");
|
src = fetchCrateLocal (workspaceSrc + "/src/db");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
|
@ -2114,9 +2114,9 @@ in
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_model."1.0.1" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_model."1.0.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_model";
|
name = "garage_model";
|
||||||
version = "1.0.1";
|
version = "1.0.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/model");
|
src = fetchCrateLocal (workspaceSrc + "/src/model");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
|
@ -2134,12 +2134,12 @@ in
|
||||||
err_derive = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).out;
|
err_derive = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
||||||
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.30" { inherit profileName; }).out;
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.30" { inherit profileName; }).out;
|
||||||
garage_block = (rustPackages."unknown".garage_block."1.0.1" { inherit profileName; }).out;
|
garage_block = (rustPackages."unknown".garage_block."1.0.0" { inherit profileName; }).out;
|
||||||
garage_db = (rustPackages."unknown".garage_db."1.0.1" { inherit profileName; }).out;
|
garage_db = (rustPackages."unknown".garage_db."1.0.0" { inherit profileName; }).out;
|
||||||
garage_net = (rustPackages."unknown".garage_net."1.0.1" { inherit profileName; }).out;
|
garage_net = (rustPackages."unknown".garage_net."1.0.0" { inherit profileName; }).out;
|
||||||
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.1" { inherit profileName; }).out;
|
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.0" { inherit profileName; }).out;
|
||||||
garage_table = (rustPackages."unknown".garage_table."1.0.1" { inherit profileName; }).out;
|
garage_table = (rustPackages."unknown".garage_table."1.0.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."1.0.1" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
||||||
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."1.0.0" { inherit profileName; }).out;
|
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."1.0.0" { inherit profileName; }).out;
|
||||||
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
|
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
|
||||||
|
@ -2153,9 +2153,9 @@ in
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_net."1.0.1" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_net."1.0.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_net";
|
name = "garage_net";
|
||||||
version = "1.0.1";
|
version = "1.0.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/net");
|
src = fetchCrateLocal (workspaceSrc + "/src/net");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
|
@ -2190,9 +2190,9 @@ in
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_rpc."1.0.1" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_rpc."1.0.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_rpc";
|
name = "garage_rpc";
|
||||||
version = "1.0.1";
|
version = "1.0.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/rpc");
|
src = fetchCrateLocal (workspaceSrc + "/src/rpc");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
|
@ -2214,9 +2214,9 @@ in
|
||||||
format_table = (rustPackages."unknown".format_table."0.1.1" { inherit profileName; }).out;
|
format_table = (rustPackages."unknown".format_table."0.1.1" { inherit profileName; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
||||||
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.30" { inherit profileName; }).out;
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.30" { inherit profileName; }).out;
|
||||||
garage_db = (rustPackages."unknown".garage_db."1.0.1" { inherit profileName; }).out;
|
garage_db = (rustPackages."unknown".garage_db."1.0.0" { inherit profileName; }).out;
|
||||||
garage_net = (rustPackages."unknown".garage_net."1.0.1" { inherit profileName; }).out;
|
garage_net = (rustPackages."unknown".garage_net."1.0.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."1.0.1" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out;
|
||||||
gethostname = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".gethostname."0.4.3" { inherit profileName; }).out;
|
gethostname = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".gethostname."0.4.3" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
||||||
ipnet = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".ipnet."2.9.0" { inherit profileName; }).out;
|
ipnet = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".ipnet."2.9.0" { inherit profileName; }).out;
|
||||||
|
@ -2239,9 +2239,9 @@ in
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_table."1.0.1" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_table."1.0.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_table";
|
name = "garage_table";
|
||||||
version = "1.0.1";
|
version = "1.0.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/table");
|
src = fetchCrateLocal (workspaceSrc + "/src/table");
|
||||||
dependencies = {
|
dependencies = {
|
||||||
|
@ -2250,9 +2250,9 @@ in
|
||||||
bytes = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytes."1.5.0" { inherit profileName; }).out;
|
bytes = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytes."1.5.0" { inherit profileName; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
||||||
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.30" { inherit profileName; }).out;
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.30" { inherit profileName; }).out;
|
||||||
garage_db = (rustPackages."unknown".garage_db."1.0.1" { inherit profileName; }).out;
|
garage_db = (rustPackages."unknown".garage_db."1.0.0" { inherit profileName; }).out;
|
||||||
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.1" { inherit profileName; }).out;
|
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."1.0.1" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
||||||
hexdump = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hexdump."0.1.1" { inherit profileName; }).out;
|
hexdump = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hexdump."0.1.1" { inherit profileName; }).out;
|
||||||
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
|
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
|
||||||
|
@ -2264,9 +2264,9 @@ in
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_util."1.0.1" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_util."1.0.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_util";
|
name = "garage_util";
|
||||||
version = "1.0.1";
|
version = "1.0.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/util");
|
src = fetchCrateLocal (workspaceSrc + "/src/util");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
|
@ -2282,8 +2282,8 @@ in
|
||||||
digest = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".digest."0.10.7" { inherit profileName; }).out;
|
digest = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".digest."0.10.7" { inherit profileName; }).out;
|
||||||
err_derive = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).out;
|
err_derive = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
||||||
garage_db = (rustPackages."unknown".garage_db."1.0.1" { inherit profileName; }).out;
|
garage_db = (rustPackages."unknown".garage_db."1.0.0" { inherit profileName; }).out;
|
||||||
garage_net = (rustPackages."unknown".garage_net."1.0.1" { inherit profileName; }).out;
|
garage_net = (rustPackages."unknown".garage_net."1.0.0" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
||||||
hexdump = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hexdump."0.1.1" { inherit profileName; }).out;
|
hexdump = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hexdump."0.1.1" { inherit profileName; }).out;
|
||||||
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."1.0.0" { inherit profileName; }).out;
|
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."1.0.0" { inherit profileName; }).out;
|
||||||
|
@ -2308,18 +2308,18 @@ in
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_web."1.0.1" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_web."1.0.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_web";
|
name = "garage_web";
|
||||||
version = "1.0.1";
|
version = "1.0.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/web");
|
src = fetchCrateLocal (workspaceSrc + "/src/web");
|
||||||
dependencies = {
|
dependencies = {
|
||||||
err_derive = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).out;
|
err_derive = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.30" { inherit profileName; }).out;
|
||||||
garage_api = (rustPackages."unknown".garage_api."1.0.1" { inherit profileName; }).out;
|
garage_api = (rustPackages."unknown".garage_api."1.0.0" { inherit profileName; }).out;
|
||||||
garage_model = (rustPackages."unknown".garage_model."1.0.1" { inherit profileName; }).out;
|
garage_model = (rustPackages."unknown".garage_model."1.0.0" { inherit profileName; }).out;
|
||||||
garage_table = (rustPackages."unknown".garage_table."1.0.1" { inherit profileName; }).out;
|
garage_table = (rustPackages."unknown".garage_table."1.0.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."1.0.1" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out;
|
||||||
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."1.0.0" { inherit profileName; }).out;
|
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."1.0.0" { inherit profileName; }).out;
|
||||||
http_body_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http-body-util."0.1.0" { inherit profileName; }).out;
|
http_body_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http-body-util."0.1.0" { inherit profileName; }).out;
|
||||||
hyper = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."1.1.0" { inherit profileName; }).out;
|
hyper = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."1.1.0" { inherit profileName; }).out;
|
||||||
|
@ -5781,11 +5781,11 @@ in
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" = overridableMkRustCrate (profileName: rec {
|
"registry+https://github.com/rust-lang/crates.io-index".time."0.3.34" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "time";
|
name = "time";
|
||||||
version = "0.3.36";
|
version = "0.3.34";
|
||||||
registry = "registry+https://github.com/rust-lang/crates.io-index";
|
registry = "registry+https://github.com/rust-lang/crates.io-index";
|
||||||
src = fetchCratesIo { inherit name version; sha256 = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"; };
|
src = fetchCratesIo { inherit name version; sha256 = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"; };
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
[ "alloc" ]
|
[ "alloc" ]
|
||||||
[ "default" ]
|
[ "default" ]
|
||||||
|
@ -5798,7 +5798,7 @@ in
|
||||||
powerfmt = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".powerfmt."0.2.0" { inherit profileName; }).out;
|
powerfmt = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".powerfmt."0.2.0" { inherit profileName; }).out;
|
||||||
serde = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".serde."1.0.196" { inherit profileName; }).out;
|
serde = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".serde."1.0.196" { inherit profileName; }).out;
|
||||||
time_core = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time-core."0.1.2" { inherit profileName; }).out;
|
time_core = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time-core."0.1.2" { inherit profileName; }).out;
|
||||||
time_macros = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".time-macros."0.2.18" { profileName = "__noProfile"; }).out;
|
time_macros = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".time-macros."0.2.17" { profileName = "__noProfile"; }).out;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -5809,11 +5809,11 @@ in
|
||||||
src = fetchCratesIo { inherit name version; sha256 = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"; };
|
src = fetchCratesIo { inherit name version; sha256 = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"; };
|
||||||
});
|
});
|
||||||
|
|
||||||
"registry+https://github.com/rust-lang/crates.io-index".time-macros."0.2.18" = overridableMkRustCrate (profileName: rec {
|
"registry+https://github.com/rust-lang/crates.io-index".time-macros."0.2.17" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "time-macros";
|
name = "time-macros";
|
||||||
version = "0.2.18";
|
version = "0.2.17";
|
||||||
registry = "registry+https://github.com/rust-lang/crates.io-index";
|
registry = "registry+https://github.com/rust-lang/crates.io-index";
|
||||||
src = fetchCratesIo { inherit name version; sha256 = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"; };
|
src = fetchCratesIo { inherit name version; sha256 = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"; };
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
[ "parsing" ]
|
[ "parsing" ]
|
||||||
];
|
];
|
||||||
|
|
18
Cargo.toml
18
Cargo.toml
|
@ -21,15 +21,15 @@ default-members = ["src/garage"]
|
||||||
|
|
||||||
# Internal Garage crates
|
# Internal Garage crates
|
||||||
format_table = { version = "0.1.1", path = "src/format-table" }
|
format_table = { version = "0.1.1", path = "src/format-table" }
|
||||||
garage_api = { version = "1.0.1", path = "src/api" }
|
garage_api = { version = "1.0.0", path = "src/api" }
|
||||||
garage_block = { version = "1.0.1", path = "src/block" }
|
garage_block = { version = "1.0.0", path = "src/block" }
|
||||||
garage_db = { version = "1.0.1", path = "src/db", default-features = false }
|
garage_db = { version = "1.0.0", path = "src/db", default-features = false }
|
||||||
garage_model = { version = "1.0.1", path = "src/model", default-features = false }
|
garage_model = { version = "1.0.0", path = "src/model", default-features = false }
|
||||||
garage_net = { version = "1.0.1", path = "src/net" }
|
garage_net = { version = "1.0.0", path = "src/net" }
|
||||||
garage_rpc = { version = "1.0.1", path = "src/rpc" }
|
garage_rpc = { version = "1.0.0", path = "src/rpc" }
|
||||||
garage_table = { version = "1.0.1", path = "src/table" }
|
garage_table = { version = "1.0.0", path = "src/table" }
|
||||||
garage_util = { version = "1.0.1", path = "src/util" }
|
garage_util = { version = "1.0.0", path = "src/util" }
|
||||||
garage_web = { version = "1.0.1", path = "src/web" }
|
garage_web = { version = "1.0.0", path = "src/web" }
|
||||||
k2v-client = { version = "0.0.4", path = "src/k2v-client" }
|
k2v-client = { version = "0.0.4", path = "src/k2v-client" }
|
||||||
|
|
||||||
# External crates from crates.io
|
# External crates from crates.io
|
||||||
|
|
|
@ -23,7 +23,7 @@ client = minio.Minio(
|
||||||
"GKyourapikey",
|
"GKyourapikey",
|
||||||
"abcd[...]1234",
|
"abcd[...]1234",
|
||||||
# Force the region, this is specific to garage
|
# Force the region, this is specific to garage
|
||||||
region="garage",
|
region="region",
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -335,7 +335,6 @@ From the [official Mastodon documentation](https://docs.joinmastodon.org/admin/t
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ RAILS_ENV=production bin/tootctl media remove --days 3
|
$ RAILS_ENV=production bin/tootctl media remove --days 3
|
||||||
$ RAILS_ENV=production bin/tootctl media remove --days 15 --prune-profiles
|
|
||||||
$ RAILS_ENV=production bin/tootctl media remove-orphans
|
$ RAILS_ENV=production bin/tootctl media remove-orphans
|
||||||
$ RAILS_ENV=production bin/tootctl preview_cards remove --days 15
|
$ RAILS_ENV=production bin/tootctl preview_cards remove --days 15
|
||||||
```
|
```
|
||||||
|
@ -354,6 +353,8 @@ Imports: 1.7 KB
|
||||||
Settings: 0 Bytes
|
Settings: 0 Bytes
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Unfortunately, [old avatars and headers cannot currently be cleaned up](https://github.com/mastodon/mastodon/issues/9567).
|
||||||
|
|
||||||
### Migrating your data
|
### Migrating your data
|
||||||
|
|
||||||
Data migration should be done with an efficient S3 client.
|
Data migration should be done with an efficient S3 client.
|
||||||
|
|
|
@ -96,14 +96,14 @@ to store 2 TB of data in total.
|
||||||
## Get a Docker image
|
## Get a Docker image
|
||||||
|
|
||||||
Our docker image is currently named `dxflrs/garage` and is stored on the [Docker Hub](https://hub.docker.com/r/dxflrs/garage/tags?page=1&ordering=last_updated).
|
Our docker image is currently named `dxflrs/garage` and is stored on the [Docker Hub](https://hub.docker.com/r/dxflrs/garage/tags?page=1&ordering=last_updated).
|
||||||
We encourage you to use a fixed tag (eg. `v1.0.1`) and not the `latest` tag.
|
We encourage you to use a fixed tag (eg. `v1.0.0`) and not the `latest` tag.
|
||||||
For this example, we will use the latest published version at the time of the writing which is `v1.0.1` but it's up to you
|
For this example, we will use the latest published version at the time of the writing which is `v1.0.0` but it's up to you
|
||||||
to check [the most recent versions on the Docker Hub](https://hub.docker.com/r/dxflrs/garage/tags?page=1&ordering=last_updated).
|
to check [the most recent versions on the Docker Hub](https://hub.docker.com/r/dxflrs/garage/tags?page=1&ordering=last_updated).
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo docker pull dxflrs/garage:v1.0.1
|
sudo docker pull dxflrs/garage:v1.0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
## Deploying and configuring Garage
|
## Deploying and configuring Garage
|
||||||
|
@ -171,7 +171,7 @@ docker run \
|
||||||
-v /etc/garage.toml:/etc/garage.toml \
|
-v /etc/garage.toml:/etc/garage.toml \
|
||||||
-v /var/lib/garage/meta:/var/lib/garage/meta \
|
-v /var/lib/garage/meta:/var/lib/garage/meta \
|
||||||
-v /var/lib/garage/data:/var/lib/garage/data \
|
-v /var/lib/garage/data:/var/lib/garage/data \
|
||||||
dxflrs/garage:v1.0.1
|
dxflrs/garage:v1.0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
With this command line, Garage should be started automatically at each boot.
|
With this command line, Garage should be started automatically at each boot.
|
||||||
|
@ -185,7 +185,7 @@ If you want to use `docker-compose`, you may use the following `docker-compose.y
|
||||||
version: "3"
|
version: "3"
|
||||||
services:
|
services:
|
||||||
garage:
|
garage:
|
||||||
image: dxflrs/garage:v1.0.1
|
image: dxflrs/garage:v1.0.0
|
||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
@ -50,20 +50,3 @@ locations. They use Garage themselves for the following tasks:
|
||||||
|
|
||||||
The Deuxfleurs Garage cluster is a multi-site cluster currently composed of
|
The Deuxfleurs Garage cluster is a multi-site cluster currently composed of
|
||||||
9 nodes in 3 physical locations.
|
9 nodes in 3 physical locations.
|
||||||
|
|
||||||
### Triplebit
|
|
||||||
|
|
||||||
[Triplebit](https://www.triplebit.org) is a non-profit hosting provider and
|
|
||||||
ISP focused on improving access to privacy-related services. They use
|
|
||||||
Garage themselves for the following tasks:
|
|
||||||
|
|
||||||
- Hosting of their homepage, [privacyguides.org](https://www.privacyguides.org/), and various other static sites
|
|
||||||
|
|
||||||
- As a Mastodon object storage backend for [mstdn.party](https://mstdn.party/) and [mstdn.plus](https://mstdn.plus/)
|
|
||||||
|
|
||||||
- As a PeerTube storage backend for [neat.tube](https://neat.tube/)
|
|
||||||
|
|
||||||
- As a [Matrix media backend](https://github.com/matrix-org/synapse-s3-storage-provider)
|
|
||||||
|
|
||||||
Triplebit's Garage cluster is a multi-site cluster currently composed of
|
|
||||||
10 nodes in 3 physical locations.
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ weight = 40
|
||||||
|
|
||||||
Garage is meant to work on old, second-hand hardware.
|
Garage is meant to work on old, second-hand hardware.
|
||||||
In particular, this makes it likely that some of your drives will fail, and some manual intervention will be needed.
|
In particular, this makes it likely that some of your drives will fail, and some manual intervention will be needed.
|
||||||
Fear not! Garage is fully equipped to handle drive failures, in most common cases.
|
Fear not! For Garage is fully equipped to handle drive failures, in most common cases.
|
||||||
|
|
||||||
## A note on availability of Garage
|
## A note on availability of Garage
|
||||||
|
|
||||||
|
|
|
@ -42,13 +42,6 @@ If a binary of the last version is not available for your architecture,
|
||||||
or if you want a build customized for your system,
|
or if you want a build customized for your system,
|
||||||
you can [build Garage from source](@/documentation/cookbook/from-source.md).
|
you can [build Garage from source](@/documentation/cookbook/from-source.md).
|
||||||
|
|
||||||
If none of these option work for you, you can also run Garage in a Docker
|
|
||||||
container. When using Docker, the commands used in this guide will not work
|
|
||||||
anymore. We recommend reading the tutorial on [configuring a
|
|
||||||
multi-node cluster](@/documentation/cookbook/real-world.md) to learn about
|
|
||||||
using Garage as a Docker container. For simplicity, a minimal command to launch
|
|
||||||
Garage using Docker is provided in this quick start guide as well.
|
|
||||||
|
|
||||||
|
|
||||||
## Configuring and starting Garage
|
## Configuring and starting Garage
|
||||||
|
|
||||||
|
@ -92,9 +85,6 @@ metrics_token = "$(openssl rand -base64 32)"
|
||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
See the [Configuration file format](https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/)
|
|
||||||
for complete options and values.
|
|
||||||
|
|
||||||
Now that your configuration file has been created, you may save it to the directory of your choice.
|
Now that your configuration file has been created, you may save it to the directory of your choice.
|
||||||
By default, Garage looks for **`/etc/garage.toml`.**
|
By default, Garage looks for **`/etc/garage.toml`.**
|
||||||
You can also store it somewhere else, but you will have to specify `-c path/to/garage.toml`
|
You can also store it somewhere else, but you will have to specify `-c path/to/garage.toml`
|
||||||
|
@ -121,26 +111,6 @@ garage -c path/to/garage.toml server
|
||||||
|
|
||||||
If you have placed the `garage.toml` file in `/etc` (its default location), you can simply run `garage server`.
|
If you have placed the `garage.toml` file in `/etc` (its default location), you can simply run `garage server`.
|
||||||
|
|
||||||
Alternatively, if you cannot or do not wish to run the Garage binary directly,
|
|
||||||
you may use Docker to run Garage in a container using the following command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run \
|
|
||||||
-d \
|
|
||||||
--name garaged \
|
|
||||||
-p 3900:3900 -p 3901:3901 -p 3902:3902 -p 3903:3903 \
|
|
||||||
-v /etc/garage.toml:/path/to/garage.toml \
|
|
||||||
-v /var/lib/garage/meta:/path/to/garage/meta \
|
|
||||||
-v /var/lib/garage/data:/path/to/garage/data \
|
|
||||||
dxflrs/garage:v0.9.4
|
|
||||||
```
|
|
||||||
|
|
||||||
Under Linux, you can substitute `--network host` for `-p 3900:3900 -p 3901:3901 -p 3902:3902 -p 3903:3903`
|
|
||||||
|
|
||||||
#### Troubleshooting
|
|
||||||
|
|
||||||
Ensure your configuration file, `metadata_dir` and `data_dir` are readable by the user running the `garage` server or Docker.
|
|
||||||
|
|
||||||
You can tune Garage's verbosity by setting the `RUST_LOG=` environment variable. \
|
You can tune Garage's verbosity by setting the `RUST_LOG=` environment variable. \
|
||||||
Available log levels are (from less verbose to more verbose): `error`, `warn`, `info` *(default)*, `debug` and `trace`.
|
Available log levels are (from less verbose to more verbose): `error`, `warn`, `info` *(default)*, `debug` and `trace`.
|
||||||
|
|
||||||
|
@ -161,9 +131,6 @@ It uses values from the TOML configuration file to find the Garage daemon runnin
|
||||||
local node, therefore if your configuration file is not at `/etc/garage.toml` you will
|
local node, therefore if your configuration file is not at `/etc/garage.toml` you will
|
||||||
again have to specify `-c path/to/garage.toml` at each invocation.
|
again have to specify `-c path/to/garage.toml` at each invocation.
|
||||||
|
|
||||||
If you are running Garage in a Docker container, you can set `alias garage="docker exec -ti <container name> /garage"`
|
|
||||||
to use the Garage binary inside your container.
|
|
||||||
|
|
||||||
If the `garage` CLI is able to correctly detect the parameters of your local Garage node,
|
If the `garage` CLI is able to correctly detect the parameters of your local Garage node,
|
||||||
the following command should be enough to show the status of your cluster:
|
the following command should be enough to show the status of your cluster:
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ Example response body:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"node": "b10c110e4e854e5aa3f4637681befac755154b20059ec163254ddbfae86b09df",
|
"node": "b10c110e4e854e5aa3f4637681befac755154b20059ec163254ddbfae86b09df",
|
||||||
"garageVersion": "v1.0.1",
|
"garageVersion": "v1.0.0",
|
||||||
"garageFeatures": [
|
"garageFeatures": [
|
||||||
"k2v",
|
"k2v",
|
||||||
"lmdb",
|
"lmdb",
|
||||||
|
|
84
flake.lock
84
flake.lock
|
@ -28,11 +28,11 @@
|
||||||
},
|
},
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1717312683,
|
"lastModified": 1688025799,
|
||||||
"narHash": "sha256-FrlieJH50AuvagamEvWMIE6D2OAnERuDboFDYAED/dE=",
|
"narHash": "sha256-ktpB4dRtnksm9F5WawoIkEneh1nrEvuxb5lJFt1iOyw=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "38fd3954cf65ce6faf3d0d45cd26059e059f07ea",
|
"rev": "8bf105319d44f6b9f0d764efa4fdef9f1cc9ba1c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -42,12 +42,33 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1659877975,
|
"lastModified": 1681202837,
|
||||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils_2": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681202837,
|
||||||
|
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -58,11 +79,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1724395761,
|
"lastModified": 1682109806,
|
||||||
"narHash": "sha256-zRkDV/nbrnp3Y8oCADf5ETl1sDrdmAW6/bBVJ8EbIdQ=",
|
"narHash": "sha256-d9g7RKNShMLboTWwukM+RObDWWpHKaqTYXB48clBWXI=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "ae815cee91b417be55d43781eb4b73ae1ecc396c",
|
"rev": "2362848adf8def2866fabbffc50462e929d7fffb",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -74,17 +95,17 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1724681257,
|
"lastModified": 1707091808,
|
||||||
"narHash": "sha256-EJRuc5Qp7yfXko5ZNeEMYAs4DzAvkCyALuJ/tGllhN4=",
|
"narHash": "sha256-LahKBAfGbY836gtpVNnWwBTIzN7yf/uYM/S0g393r0Y=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "0239aeb2f82ea27ccd6b61582b8f7fb8750eeada",
|
"rev": "9f2ee8c91ac42da3ae6c6a1d21555f283458247e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "0239aeb2f82ea27ccd6b61582b8f7fb8750eeada",
|
"rev": "9f2ee8c91ac42da3ae6c6a1d21555f283458247e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -101,14 +122,15 @@
|
||||||
},
|
},
|
||||||
"rust-overlay": {
|
"rust-overlay": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_2",
|
||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1724638882,
|
"lastModified": 1707271822,
|
||||||
"narHash": "sha256-ap2jIQi/FuUHR6HCht6ASWhoz8EiB99XmI8Esot38VE=",
|
"narHash": "sha256-/DZsoPH5GBzOpVEGz5PgJ7vh8Q6TcrJq5u8FcBjqAfI=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "19b70f147b9c67a759e35824b241f1ed92e46694",
|
"rev": "7a94fe7690d2bdfe1aab475382a505e14dc114a6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -116,6 +138,36 @@
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
description =
|
description =
|
||||||
"Garage, an S3-compatible distributed object store for self-hosted deployments";
|
"Garage, an S3-compatible distributed object store for self-hosted deployments";
|
||||||
|
|
||||||
# Nixpkgs 24.05 as of 2024-08-26 has rustc v1.77
|
# Nixpkgs 23.11 as of 2024-02-07, has rustc v1.73
|
||||||
inputs.nixpkgs.url =
|
inputs.nixpkgs.url =
|
||||||
"github:NixOS/nixpkgs/0239aeb2f82ea27ccd6b61582b8f7fb8750eeada";
|
"github:NixOS/nixpkgs/9f2ee8c91ac42da3ae6c6a1d21555f283458247e";
|
||||||
|
|
||||||
inputs.flake-compat.url = "github:nix-community/flake-compat";
|
inputs.flake-compat.url = "github:nix-community/flake-compat";
|
||||||
|
|
||||||
|
@ -17,9 +17,9 @@
|
||||||
# - rustc v1.66
|
# - rustc v1.66
|
||||||
# url = "github:cargo2nix/cargo2nix/8fb57a670f7993bfc24099c33eb9c5abb51f29a2";
|
# url = "github:cargo2nix/cargo2nix/8fb57a670f7993bfc24099c33eb9c5abb51f29a2";
|
||||||
|
|
||||||
# Rust overlay as of 2024-08-26
|
# Rust overlay as of 2024-02-07
|
||||||
inputs.rust-overlay.url =
|
inputs.rust-overlay.url =
|
||||||
"github:oxalica/rust-overlay/19b70f147b9c67a759e35824b241f1ed92e46694";
|
"github:oxalica/rust-overlay/7a94fe7690d2bdfe1aab475382a505e14dc114a6";
|
||||||
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
inputs.flake-compat.follows = "flake-compat";
|
inputs.flake-compat.follows = "flake-compat";
|
||||||
|
|
|
@ -20,7 +20,7 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
toolchainOptions = {
|
toolchainOptions = {
|
||||||
rustVersion = "1.77.0";
|
rustVersion = "1.73.0";
|
||||||
extraRustComponents = [ "clippy" ];
|
extraRustComponents = [ "clippy" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,10 @@ type: application
|
||||||
# This is the chart version. This version number should be incremented each time you make changes
|
# This is the chart version. This version number should be incremented each time you make changes
|
||||||
# to the chart and its templates, including the app version.
|
# to the chart and its templates, including the app version.
|
||||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||||
version: 0.5.1
|
version: 0.5.0
|
||||||
|
|
||||||
# This is the version number of the application being deployed. This version number should be
|
# This is the version number of the application being deployed. This version number should be
|
||||||
# incremented each time you make changes to the application. Versions are not expected to
|
# incremented each time you make changes to the application. Versions are not expected to
|
||||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||||
# It is recommended to use it with quotes.
|
# It is recommended to use it with quotes.
|
||||||
appVersion: "v1.0.1"
|
appVersion: "v1.0.0"
|
||||||
|
|
|
@ -76,9 +76,6 @@ spec:
|
||||||
- name: etc
|
- name: etc
|
||||||
mountPath: /etc/garage.toml
|
mountPath: /etc/garage.toml
|
||||||
subPath: garage.toml
|
subPath: garage.toml
|
||||||
{{- with .Values.extraVolumeMounts }}
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
# TODO
|
# TODO
|
||||||
# livenessProbe:
|
# livenessProbe:
|
||||||
# httpGet:
|
# httpGet:
|
||||||
|
@ -113,9 +110,6 @@ spec:
|
||||||
- name: data
|
- name: data
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- with .Values.extraVolumes }}
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.nodeSelector }}
|
{{- with .Values.nodeSelector }}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
|
|
|
@ -218,10 +218,6 @@ affinity: {}
|
||||||
|
|
||||||
environment: {}
|
environment: {}
|
||||||
|
|
||||||
extraVolumes: {}
|
|
||||||
|
|
||||||
extraVolumeMounts: {}
|
|
||||||
|
|
||||||
monitoring:
|
monitoring:
|
||||||
metrics:
|
metrics:
|
||||||
# If true, a service for monitoring is created with a prometheus.io/scrape annotation
|
# If true, a service for monitoring is created with a prometheus.io/scrape annotation
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "garage_api"
|
name = "garage_api"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|
|
@ -2,7 +2,6 @@ use std::convert::Infallible;
|
||||||
use std::fs::{self, Permissions};
|
use std::fs::{self, Permissions};
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
@ -20,7 +19,6 @@ use hyper_util::rt::TokioIo;
|
||||||
use tokio::io::{AsyncRead, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
use tokio::net::{TcpListener, TcpStream, UnixListener, UnixStream};
|
use tokio::net::{TcpListener, TcpStream, UnixListener, UnixStream};
|
||||||
use tokio::sync::watch;
|
use tokio::sync::watch;
|
||||||
use tokio::time::{sleep_until, Instant};
|
|
||||||
|
|
||||||
use opentelemetry::{
|
use opentelemetry::{
|
||||||
global,
|
global,
|
||||||
|
@ -293,7 +291,7 @@ where
|
||||||
let connection_collector = tokio::spawn({
|
let connection_collector = tokio::spawn({
|
||||||
let server_name = server_name.clone();
|
let server_name = server_name.clone();
|
||||||
async move {
|
async move {
|
||||||
let mut connections = FuturesUnordered::<tokio::task::JoinHandle<()>>::new();
|
let mut connections = FuturesUnordered::new();
|
||||||
loop {
|
loop {
|
||||||
let collect_next = async {
|
let collect_next = async {
|
||||||
if connections.is_empty() {
|
if connections.is_empty() {
|
||||||
|
@ -314,34 +312,23 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let deadline = Instant::now() + Duration::from_secs(10);
|
if !connections.is_empty() {
|
||||||
while !connections.is_empty() {
|
|
||||||
info!(
|
info!(
|
||||||
"{} server: {} connections still open, deadline in {:.2}s",
|
"{} server: {} connections still open",
|
||||||
server_name,
|
server_name,
|
||||||
connections.len(),
|
connections.len()
|
||||||
(deadline - Instant::now()).as_secs_f32(),
|
|
||||||
);
|
);
|
||||||
tokio::select! {
|
while let Some(conn_res) = connections.next().await {
|
||||||
conn_res = connections.next() => {
|
trace!(
|
||||||
trace!(
|
"{} server: HTTP connection finished: {:?}",
|
||||||
"{} server: HTTP connection finished: {:?}",
|
server_name,
|
||||||
server_name,
|
conn_res
|
||||||
conn_res.unwrap(),
|
);
|
||||||
);
|
info!(
|
||||||
}
|
"{} server: {} connections still open",
|
||||||
_ = sleep_until(deadline) => {
|
server_name,
|
||||||
warn!("{} server: exit deadline reached with {} connections still open, killing them now",
|
connections.len()
|
||||||
server_name,
|
);
|
||||||
connections.len());
|
|
||||||
for conn in connections.iter() {
|
|
||||||
conn.abort();
|
|
||||||
}
|
|
||||||
for conn in connections {
|
|
||||||
assert!(conn.await.unwrap_err().is_cancelled());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,11 +71,21 @@ pub async fn handle_post_object(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(content) = HeaderValue::from_str(&field.text().await?) {
|
if let Ok(content) = HeaderValue::from_str(&field.text().await?) {
|
||||||
if params.insert(&name, content).is_some() {
|
match name.as_str() {
|
||||||
return Err(Error::bad_request(format!(
|
"tag" => (/* tag need to be reencoded, but we don't support them yet anyway */),
|
||||||
"Field '{}' provided more than once",
|
"acl" => {
|
||||||
name
|
if params.insert("x-amz-acl", content).is_some() {
|
||||||
)));
|
return Err(Error::bad_request("Field 'acl' provided more than once"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if params.insert(&name, content).is_some() {
|
||||||
|
return Err(Error::bad_request(format!(
|
||||||
|
"Field '{}' provided more than once",
|
||||||
|
name
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -212,8 +222,6 @@ pub async fn handle_post_object(
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we ever start supporting ACLs, we likely want to map "acl" to x-amz-acl" somewhere
|
|
||||||
// arround here to make sure the rest of the machinery takes our acl into account.
|
|
||||||
let headers = get_headers(¶ms)?;
|
let headers = get_headers(¶ms)?;
|
||||||
|
|
||||||
let expected_checksums = ExpectedChecksums {
|
let expected_checksums = ExpectedChecksums {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "garage_block"
|
name = "garage_block"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "garage_db"
|
name = "garage_db"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|
|
@ -211,12 +211,16 @@ impl Tree {
|
||||||
|
|
||||||
/// Returns the old value if there was one
|
/// Returns the old value if there was one
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn insert<T: AsRef<[u8]>, U: AsRef<[u8]>>(&self, key: T, value: U) -> Result<()> {
|
pub fn insert<T: AsRef<[u8]>, U: AsRef<[u8]>>(
|
||||||
|
&self,
|
||||||
|
key: T,
|
||||||
|
value: U,
|
||||||
|
) -> Result<Option<Value>> {
|
||||||
self.0.insert(self.1, key.as_ref(), value.as_ref())
|
self.0.insert(self.1, key.as_ref(), value.as_ref())
|
||||||
}
|
}
|
||||||
/// Returns the old value if there was one
|
/// Returns the old value if there was one
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn remove<T: AsRef<[u8]>>(&self, key: T) -> Result<()> {
|
pub fn remove<T: AsRef<[u8]>>(&self, key: T) -> Result<Option<Value>> {
|
||||||
self.0.remove(self.1, key.as_ref())
|
self.0.remove(self.1, key.as_ref())
|
||||||
}
|
}
|
||||||
/// Clears all values from the tree
|
/// Clears all values from the tree
|
||||||
|
@ -274,12 +278,12 @@ impl<'a> Transaction<'a> {
|
||||||
tree: &Tree,
|
tree: &Tree,
|
||||||
key: T,
|
key: T,
|
||||||
value: U,
|
value: U,
|
||||||
) -> TxOpResult<()> {
|
) -> TxOpResult<Option<Value>> {
|
||||||
self.tx.insert(tree.1, key.as_ref(), value.as_ref())
|
self.tx.insert(tree.1, key.as_ref(), value.as_ref())
|
||||||
}
|
}
|
||||||
/// Returns the old value if there was one
|
/// Returns the old value if there was one
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn remove<T: AsRef<[u8]>>(&mut self, tree: &Tree, key: T) -> TxOpResult<()> {
|
pub fn remove<T: AsRef<[u8]>>(&mut self, tree: &Tree, key: T) -> TxOpResult<Option<Value>> {
|
||||||
self.tx.remove(tree.1, key.as_ref())
|
self.tx.remove(tree.1, key.as_ref())
|
||||||
}
|
}
|
||||||
/// Clears all values in a tree
|
/// Clears all values in a tree
|
||||||
|
@ -335,8 +339,8 @@ pub(crate) trait IDb: Send + Sync {
|
||||||
fn get(&self, tree: usize, key: &[u8]) -> Result<Option<Value>>;
|
fn get(&self, tree: usize, key: &[u8]) -> Result<Option<Value>>;
|
||||||
fn len(&self, tree: usize) -> Result<usize>;
|
fn len(&self, tree: usize) -> Result<usize>;
|
||||||
|
|
||||||
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()>;
|
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>>;
|
||||||
fn remove(&self, tree: usize, key: &[u8]) -> Result<()>;
|
fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>>;
|
||||||
fn clear(&self, tree: usize) -> Result<()>;
|
fn clear(&self, tree: usize) -> Result<()>;
|
||||||
|
|
||||||
fn iter(&self, tree: usize) -> Result<ValueIter<'_>>;
|
fn iter(&self, tree: usize) -> Result<ValueIter<'_>>;
|
||||||
|
@ -362,8 +366,8 @@ pub(crate) trait ITx {
|
||||||
fn get(&self, tree: usize, key: &[u8]) -> TxOpResult<Option<Value>>;
|
fn get(&self, tree: usize, key: &[u8]) -> TxOpResult<Option<Value>>;
|
||||||
fn len(&self, tree: usize) -> TxOpResult<usize>;
|
fn len(&self, tree: usize) -> TxOpResult<usize>;
|
||||||
|
|
||||||
fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> TxOpResult<()>;
|
fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> TxOpResult<Option<Value>>;
|
||||||
fn remove(&mut self, tree: usize, key: &[u8]) -> TxOpResult<()>;
|
fn remove(&mut self, tree: usize, key: &[u8]) -> TxOpResult<Option<Value>>;
|
||||||
fn clear(&mut self, tree: usize) -> TxOpResult<()>;
|
fn clear(&mut self, tree: usize) -> TxOpResult<()>;
|
||||||
|
|
||||||
fn iter(&self, tree: usize) -> TxOpResult<TxValueIter<'_>>;
|
fn iter(&self, tree: usize) -> TxOpResult<TxValueIter<'_>>;
|
||||||
|
|
|
@ -132,20 +132,22 @@ impl IDb for LmdbDb {
|
||||||
Ok(tree.len(&tx)?.try_into().unwrap())
|
Ok(tree.len(&tx)?.try_into().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> {
|
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>> {
|
||||||
let tree = self.get_tree(tree)?;
|
let tree = self.get_tree(tree)?;
|
||||||
let mut tx = self.db.write_txn()?;
|
let mut tx = self.db.write_txn()?;
|
||||||
|
let old_val = tree.get(&tx, key)?.map(Vec::from);
|
||||||
tree.put(&mut tx, key, value)?;
|
tree.put(&mut tx, key, value)?;
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
Ok(())
|
Ok(old_val)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&self, tree: usize, key: &[u8]) -> Result<()> {
|
fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>> {
|
||||||
let tree = self.get_tree(tree)?;
|
let tree = self.get_tree(tree)?;
|
||||||
let mut tx = self.db.write_txn()?;
|
let mut tx = self.db.write_txn()?;
|
||||||
|
let old_val = tree.get(&tx, key)?.map(Vec::from);
|
||||||
tree.delete(&mut tx, key)?;
|
tree.delete(&mut tx, key)?;
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
Ok(())
|
Ok(old_val)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&self, tree: usize) -> Result<()> {
|
fn clear(&self, tree: usize) -> Result<()> {
|
||||||
|
@ -252,15 +254,17 @@ impl<'a> ITx for LmdbTx<'a> {
|
||||||
Ok(tree.len(&self.tx)? as usize)
|
Ok(tree.len(&self.tx)? as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> TxOpResult<()> {
|
fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> TxOpResult<Option<Value>> {
|
||||||
let tree = *self.get_tree(tree)?;
|
let tree = *self.get_tree(tree)?;
|
||||||
|
let old_val = tree.get(&self.tx, key)?.map(Vec::from);
|
||||||
tree.put(&mut self.tx, key, value)?;
|
tree.put(&mut self.tx, key, value)?;
|
||||||
Ok(())
|
Ok(old_val)
|
||||||
}
|
}
|
||||||
fn remove(&mut self, tree: usize, key: &[u8]) -> TxOpResult<()> {
|
fn remove(&mut self, tree: usize, key: &[u8]) -> TxOpResult<Option<Value>> {
|
||||||
let tree = *self.get_tree(tree)?;
|
let tree = *self.get_tree(tree)?;
|
||||||
|
let old_val = tree.get(&self.tx, key)?.map(Vec::from);
|
||||||
tree.delete(&mut self.tx, key)?;
|
tree.delete(&mut self.tx, key)?;
|
||||||
Ok(())
|
Ok(old_val)
|
||||||
}
|
}
|
||||||
fn clear(&mut self, tree: usize) -> TxOpResult<()> {
|
fn clear(&mut self, tree: usize) -> TxOpResult<()> {
|
||||||
let tree = *self.get_tree(tree)?;
|
let tree = *self.get_tree(tree)?;
|
||||||
|
|
|
@ -169,7 +169,7 @@ impl IDb for SqliteDb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> {
|
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>> {
|
||||||
let tree = self.get_tree(tree)?;
|
let tree = self.get_tree(tree)?;
|
||||||
let db = self.db.get()?;
|
let db = self.db.get()?;
|
||||||
let lock = self.write_lock.lock();
|
let lock = self.write_lock.lock();
|
||||||
|
@ -184,18 +184,23 @@ impl IDb for SqliteDb {
|
||||||
assert_eq!(n, 1);
|
assert_eq!(n, 1);
|
||||||
|
|
||||||
drop(lock);
|
drop(lock);
|
||||||
Ok(())
|
Ok(old_val)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&self, tree: usize, key: &[u8]) -> Result<()> {
|
fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>> {
|
||||||
let tree = self.get_tree(tree)?;
|
let tree = self.get_tree(tree)?;
|
||||||
let db = self.db.get()?;
|
let db = self.db.get()?;
|
||||||
let lock = self.write_lock.lock();
|
let lock = self.write_lock.lock();
|
||||||
|
|
||||||
db.execute(&format!("DELETE FROM {} WHERE k = ?1", tree), params![key])?;
|
let old_val = self.internal_get(&db, &tree, key)?;
|
||||||
|
|
||||||
|
if old_val.is_some() {
|
||||||
|
let n = db.execute(&format!("DELETE FROM {} WHERE k = ?1", tree), params![key])?;
|
||||||
|
assert_eq!(n, 1);
|
||||||
|
}
|
||||||
|
|
||||||
drop(lock);
|
drop(lock);
|
||||||
Ok(())
|
Ok(old_val)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&self, tree: usize) -> Result<()> {
|
fn clear(&self, tree: usize) -> Result<()> {
|
||||||
|
@ -336,17 +341,31 @@ impl<'a> ITx for SqliteTx<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> TxOpResult<()> {
|
fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> TxOpResult<Option<Value>> {
|
||||||
let tree = self.get_tree(tree)?;
|
let tree = self.get_tree(tree)?;
|
||||||
let sql = format!("INSERT OR REPLACE INTO {} (k, v) VALUES (?1, ?2)", tree);
|
let old_val = self.internal_get(tree, key)?;
|
||||||
self.tx.execute(&sql, params![key, value])?;
|
|
||||||
Ok(())
|
let sql = match &old_val {
|
||||||
|
Some(_) => format!("UPDATE {} SET v = ?2 WHERE k = ?1", tree),
|
||||||
|
None => format!("INSERT INTO {} (k, v) VALUES (?1, ?2)", tree),
|
||||||
|
};
|
||||||
|
let n = self.tx.execute(&sql, params![key, value])?;
|
||||||
|
assert_eq!(n, 1);
|
||||||
|
|
||||||
|
Ok(old_val)
|
||||||
}
|
}
|
||||||
fn remove(&mut self, tree: usize, key: &[u8]) -> TxOpResult<()> {
|
fn remove(&mut self, tree: usize, key: &[u8]) -> TxOpResult<Option<Value>> {
|
||||||
let tree = self.get_tree(tree)?;
|
let tree = self.get_tree(tree)?;
|
||||||
self.tx
|
let old_val = self.internal_get(tree, key)?;
|
||||||
.execute(&format!("DELETE FROM {} WHERE k = ?1", tree), params![key])?;
|
|
||||||
Ok(())
|
if old_val.is_some() {
|
||||||
|
let n = self
|
||||||
|
.tx
|
||||||
|
.execute(&format!("DELETE FROM {} WHERE k = ?1", tree), params![key])?;
|
||||||
|
assert_eq!(n, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(old_val)
|
||||||
}
|
}
|
||||||
fn clear(&mut self, tree: usize) -> TxOpResult<()> {
|
fn clear(&mut self, tree: usize) -> TxOpResult<()> {
|
||||||
let tree = self.get_tree(tree)?;
|
let tree = self.get_tree(tree)?;
|
||||||
|
|
|
@ -12,7 +12,7 @@ fn test_suite(db: Db) {
|
||||||
|
|
||||||
// ---- test simple insert/delete ----
|
// ---- test simple insert/delete ----
|
||||||
|
|
||||||
assert!(tree.insert(ka, va).is_ok());
|
assert!(tree.insert(ka, va).unwrap().is_none());
|
||||||
assert_eq!(tree.get(ka).unwrap().unwrap(), va);
|
assert_eq!(tree.get(ka).unwrap().unwrap(), va);
|
||||||
assert_eq!(tree.len().unwrap(), 1);
|
assert_eq!(tree.len().unwrap(), 1);
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ fn test_suite(db: Db) {
|
||||||
let res = db.transaction::<_, (), _>(|tx| {
|
let res = db.transaction::<_, (), _>(|tx| {
|
||||||
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), va);
|
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), va);
|
||||||
|
|
||||||
assert_eq!(tx.insert(&tree, ka, vb).unwrap(), ());
|
assert_eq!(tx.insert(&tree, ka, vb).unwrap().unwrap(), va);
|
||||||
|
|
||||||
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vb);
|
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vb);
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ fn test_suite(db: Db) {
|
||||||
let res = db.transaction::<(), _, _>(|tx| {
|
let res = db.transaction::<(), _, _>(|tx| {
|
||||||
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vb);
|
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vb);
|
||||||
|
|
||||||
assert_eq!(tx.insert(&tree, ka, vc).unwrap(), ());
|
assert_eq!(tx.insert(&tree, ka, vc).unwrap().unwrap(), vb);
|
||||||
|
|
||||||
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vc);
|
assert_eq!(tx.get(&tree, ka).unwrap().unwrap(), vc);
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ fn test_suite(db: Db) {
|
||||||
assert!(iter.next().is_none());
|
assert!(iter.next().is_none());
|
||||||
drop(iter);
|
drop(iter);
|
||||||
|
|
||||||
assert!(tree.insert(kb, vc).is_ok());
|
assert!(tree.insert(kb, vc).unwrap().is_none());
|
||||||
assert_eq!(tree.get(kb).unwrap().unwrap(), vc);
|
assert_eq!(tree.get(kb).unwrap().unwrap(), vc);
|
||||||
|
|
||||||
let mut iter = tree.iter().unwrap();
|
let mut iter = tree.iter().unwrap();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "garage"
|
name = "garage"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|
|
@ -24,7 +24,6 @@ pub struct ConvertDbOpt {
|
||||||
output_engine: Engine,
|
output_engine: Engine,
|
||||||
|
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
#[allow(dead_code)]
|
|
||||||
db_open: OpenDbOpt,
|
db_open: OpenDbOpt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +52,6 @@ pub(crate) fn do_conversion(args: ConvertDbOpt) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let opt = OpenOpt {
|
let opt = OpenOpt {
|
||||||
#[cfg(feature = "lmdb")]
|
|
||||||
lmdb_map_size: args.db_open.lmdb.map_size.map(|x| x.as_u64() as usize),
|
lmdb_map_size: args.db_open.lmdb.map_size.map(|x| x.as_u64() as usize),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
|
@ -358,7 +358,7 @@ pub async fn cmd_layout_history(
|
||||||
|
|
||||||
if layout.versions.len() > 1 {
|
if layout.versions.len() > 1 {
|
||||||
println!("==== UPDATE TRACKERS ====");
|
println!("==== UPDATE TRACKERS ====");
|
||||||
println!("Several layout versions are currently live in the cluster, and data is being migrated.");
|
println!("Several layout versions are currently live in the version, and data is being migrated.");
|
||||||
println!(
|
println!(
|
||||||
"This is the internal data that Garage stores to know which nodes have what data."
|
"This is the internal data that Garage stores to know which nodes have what data."
|
||||||
);
|
);
|
||||||
|
@ -377,27 +377,15 @@ pub async fn cmd_layout_history(
|
||||||
table[1..].sort();
|
table[1..].sort();
|
||||||
format_table(table);
|
format_table(table);
|
||||||
|
|
||||||
let min_ack = layout
|
|
||||||
.update_trackers
|
|
||||||
.ack_map
|
|
||||||
.min_among(&all_nodes, layout.min_stored());
|
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
println!(
|
println!(
|
||||||
"If some nodes are not catching up to the latest layout version in the update trackers,"
|
"If some nodes are not catching up to the latest layout version in the update trackers,"
|
||||||
);
|
);
|
||||||
println!("it might be because they are offline or unable to complete a sync successfully.");
|
println!("it might be because they are offline or unable to complete a sync successfully.");
|
||||||
if min_ack < layout.current().version {
|
println!(
|
||||||
println!(
|
"You may force progress using `garage layout skip-dead-nodes --version {}`",
|
||||||
"You may force progress using `garage layout skip-dead-nodes --version {}`",
|
layout.current().version
|
||||||
layout.current().version
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
println!(
|
|
||||||
"You may force progress using `garage layout skip-dead-nodes --version {} --allow-missing-data`.",
|
|
||||||
layout.current().version
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
println!("Your cluster is currently in a stable state with a single live layout version.");
|
println!("Your cluster is currently in a stable state with a single live layout version.");
|
||||||
println!("No metadata migration is in progress. Note that the migration of data blocks is not tracked,");
|
println!("No metadata migration is in progress. Note that the migration of data blocks is not tracked,");
|
||||||
|
@ -438,15 +426,15 @@ pub async fn cmd_layout_skip_dead_nodes(
|
||||||
let all_nodes = layout.get_all_nodes();
|
let all_nodes = layout.get_all_nodes();
|
||||||
let mut did_something = false;
|
let mut did_something = false;
|
||||||
for node in all_nodes.iter() {
|
for node in all_nodes.iter() {
|
||||||
// Update ACK tracker for dead nodes or for all nodes if --allow-missing-data
|
if status.iter().any(|x| x.id == *node && x.is_up) {
|
||||||
if opt.allow_missing_data || !status.iter().any(|x| x.id == *node && x.is_up) {
|
continue;
|
||||||
if layout.update_trackers.ack_map.set_max(*node, opt.version) {
|
}
|
||||||
println!("Increased the ACK tracker for node {:?}", node);
|
|
||||||
did_something = true;
|
if layout.update_trackers.ack_map.set_max(*node, opt.version) {
|
||||||
}
|
println!("Increased the ACK tracker for node {:?}", node);
|
||||||
|
did_something = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If --allow-missing-data, update SYNC tracker for all nodes.
|
|
||||||
if opt.allow_missing_data {
|
if opt.allow_missing_data {
|
||||||
if layout.update_trackers.sync_map.set_max(*node, opt.version) {
|
if layout.update_trackers.sync_map.set_max(*node, opt.version) {
|
||||||
println!("Increased the SYNC tracker for node {:?}", node);
|
println!("Increased the SYNC tracker for node {:?}", node);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "garage_model"
|
name = "garage_model"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|
|
@ -141,7 +141,7 @@ impl Garage {
|
||||||
)?)
|
)?)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|x| NetworkKey::from_slice(&x))
|
.and_then(|x| NetworkKey::from_slice(&x))
|
||||||
.ok_or_message("Invalid RPC secret key: expected 32 bytes of random hex, please check the documentation for requirements")?;
|
.ok_or_message("Invalid RPC secret key: expected 32 bits of entropy, please check the documentation for requirements")?;
|
||||||
|
|
||||||
let (replication_factor, consistency_mode) = parse_replication_mode(&config)?;
|
let (replication_factor, consistency_mode) = parse_replication_mode(&config)?;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "garage_net"
|
name = "garage_net"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "garage_rpc"
|
name = "garage_rpc"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|
|
@ -227,29 +227,24 @@ impl LayoutHistory {
|
||||||
// ================== updates to layout, public interface ===================
|
// ================== updates to layout, public interface ===================
|
||||||
|
|
||||||
pub fn merge(&mut self, other: &LayoutHistory) -> bool {
|
pub fn merge(&mut self, other: &LayoutHistory) -> bool {
|
||||||
// If our current layout version is completely out-of-date,
|
|
||||||
// forget everything we know and replace it by incoming layout data.
|
|
||||||
if self.current().version < other.min_stored() {
|
|
||||||
*self = other.clone();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
|
|
||||||
// Add any new versions to history
|
// Add any new versions to history
|
||||||
for v2 in other.versions.iter() {
|
for v2 in other.versions.iter() {
|
||||||
if v2.version == self.current().version + 1 {
|
if let Some(v1) = self.versions.iter().find(|v| v.version == v2.version) {
|
||||||
// This is the next version, add it to our version list
|
|
||||||
self.versions.push(v2.clone());
|
|
||||||
changed = true;
|
|
||||||
} else if let Some(v1) = self.versions.iter().find(|v| v.version == v2.version) {
|
|
||||||
// Version is already present, check consistency
|
// Version is already present, check consistency
|
||||||
if v1 != v2 {
|
if v1 != v2 {
|
||||||
error!("Inconsistent layout histories: different layout compositions for version {}. Your cluster will be broken as long as this layout version is not replaced.", v2.version);
|
error!("Inconsistent layout histories: different layout compositions for version {}. Your cluster will be broken as long as this layout version is not replaced.", v2.version);
|
||||||
}
|
}
|
||||||
|
} else if self.versions.iter().all(|v| v.version != v2.version - 1) {
|
||||||
|
error!(
|
||||||
|
"Cannot receive new layout version {}, version {} is missing",
|
||||||
|
v2.version,
|
||||||
|
v2.version - 1
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// This is an older version
|
self.versions.push(v2.clone());
|
||||||
assert!(v2.version < self.min_stored());
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -455,7 +455,7 @@ impl UpdateTracker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn min_among(&self, storage_nodes: &[Uuid], min_version: u64) -> u64 {
|
pub(crate) fn min_among(&self, storage_nodes: &[Uuid], min_version: u64) -> u64 {
|
||||||
storage_nodes
|
storage_nodes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| self.get(x, min_version))
|
.map(|x| self.get(x, min_version))
|
||||||
|
|
|
@ -4,6 +4,8 @@ use opentelemetry::{global, metrics::*};
|
||||||
pub struct RpcMetrics {
|
pub struct RpcMetrics {
|
||||||
pub(crate) rpc_counter: Counter<u64>,
|
pub(crate) rpc_counter: Counter<u64>,
|
||||||
pub(crate) rpc_timeout_counter: Counter<u64>,
|
pub(crate) rpc_timeout_counter: Counter<u64>,
|
||||||
|
pub(crate) rpc_watchdogs_started_counter: Counter<u64>,
|
||||||
|
pub(crate) rpc_watchdogs_preemption_counter: Counter<u64>,
|
||||||
pub(crate) rpc_netapp_error_counter: Counter<u64>,
|
pub(crate) rpc_netapp_error_counter: Counter<u64>,
|
||||||
pub(crate) rpc_garage_error_counter: Counter<u64>,
|
pub(crate) rpc_garage_error_counter: Counter<u64>,
|
||||||
|
|
||||||
|
@ -21,6 +23,14 @@ impl RpcMetrics {
|
||||||
.u64_counter("rpc.timeout_counter")
|
.u64_counter("rpc.timeout_counter")
|
||||||
.with_description("Number of RPC timeouts")
|
.with_description("Number of RPC timeouts")
|
||||||
.init(),
|
.init(),
|
||||||
|
rpc_watchdogs_started_counter: meter
|
||||||
|
.u64_counter("rpc.watchdogs_started_counter")
|
||||||
|
.with_description("Number of RPC requests started with a watchdog")
|
||||||
|
.init(),
|
||||||
|
rpc_watchdogs_preemption_counter: meter
|
||||||
|
.u64_counter("rpc.watchdogs_preemption_counter")
|
||||||
|
.with_description("Number of RPC watchdogs which timed out and caused an extra RPC to be scheduled")
|
||||||
|
.init(),
|
||||||
rpc_netapp_error_counter: meter
|
rpc_netapp_error_counter: meter
|
||||||
.u64_counter("rpc.netapp_error_counter")
|
.u64_counter("rpc.netapp_error_counter")
|
||||||
.with_description("Number of communication errors (errors in the Netapp library)")
|
.with_description("Number of communication errors (errors in the Netapp library)")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//! Contain structs related to making RPCs
|
//! Contain structs related to making RPCs
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
@ -38,6 +38,8 @@ pub struct RequestStrategy<T> {
|
||||||
rs_quorum: Option<usize>,
|
rs_quorum: Option<usize>,
|
||||||
/// Send all requests at once
|
/// Send all requests at once
|
||||||
rs_send_all_at_once: Option<bool>,
|
rs_send_all_at_once: Option<bool>,
|
||||||
|
/// Start with enough RPCs to reach quorum, but send extras when some take too long
|
||||||
|
rs_preemptive_send: Option<bool>,
|
||||||
/// Request priority
|
/// Request priority
|
||||||
rs_priority: RequestPriority,
|
rs_priority: RequestPriority,
|
||||||
/// Custom timeout for this request
|
/// Custom timeout for this request
|
||||||
|
@ -58,6 +60,7 @@ impl Clone for RequestStrategy<()> {
|
||||||
RequestStrategy {
|
RequestStrategy {
|
||||||
rs_quorum: self.rs_quorum,
|
rs_quorum: self.rs_quorum,
|
||||||
rs_send_all_at_once: self.rs_send_all_at_once,
|
rs_send_all_at_once: self.rs_send_all_at_once,
|
||||||
|
rs_preemptive_send: self.rs_preemptive_send,
|
||||||
rs_priority: self.rs_priority,
|
rs_priority: self.rs_priority,
|
||||||
rs_timeout: self.rs_timeout,
|
rs_timeout: self.rs_timeout,
|
||||||
rs_drop_on_complete: (),
|
rs_drop_on_complete: (),
|
||||||
|
@ -71,6 +74,7 @@ impl RequestStrategy<()> {
|
||||||
RequestStrategy {
|
RequestStrategy {
|
||||||
rs_quorum: None,
|
rs_quorum: None,
|
||||||
rs_send_all_at_once: None,
|
rs_send_all_at_once: None,
|
||||||
|
rs_preemptive_send: None,
|
||||||
rs_priority: prio,
|
rs_priority: prio,
|
||||||
rs_timeout: Timeout::Default,
|
rs_timeout: Timeout::Default,
|
||||||
rs_drop_on_complete: (),
|
rs_drop_on_complete: (),
|
||||||
|
@ -81,6 +85,7 @@ impl RequestStrategy<()> {
|
||||||
RequestStrategy {
|
RequestStrategy {
|
||||||
rs_quorum: self.rs_quorum,
|
rs_quorum: self.rs_quorum,
|
||||||
rs_send_all_at_once: self.rs_send_all_at_once,
|
rs_send_all_at_once: self.rs_send_all_at_once,
|
||||||
|
rs_preemptive_send: self.rs_preemptive_send,
|
||||||
rs_priority: self.rs_priority,
|
rs_priority: self.rs_priority,
|
||||||
rs_timeout: self.rs_timeout,
|
rs_timeout: self.rs_timeout,
|
||||||
rs_drop_on_complete: drop_on_complete,
|
rs_drop_on_complete: drop_on_complete,
|
||||||
|
@ -94,11 +99,16 @@ impl<T> RequestStrategy<T> {
|
||||||
self.rs_quorum = Some(quorum);
|
self.rs_quorum = Some(quorum);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
/// Set quorum to be reached for request
|
/// Set flag to send all requests at once
|
||||||
pub fn send_all_at_once(mut self, value: bool) -> Self {
|
pub fn send_all_at_once(mut self, value: bool) -> Self {
|
||||||
self.rs_send_all_at_once = Some(value);
|
self.rs_send_all_at_once = Some(value);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
/// Set flag to preemptively send extra requests after some wait
|
||||||
|
pub fn with_preemptive_send(mut self, value: bool) -> Self {
|
||||||
|
self.rs_preemptive_send = Some(value);
|
||||||
|
self
|
||||||
|
}
|
||||||
/// Deactivate timeout for this request
|
/// Deactivate timeout for this request
|
||||||
pub fn without_timeout(mut self) -> Self {
|
pub fn without_timeout(mut self) -> Self {
|
||||||
self.rs_timeout = Timeout::None;
|
self.rs_timeout = Timeout::None;
|
||||||
|
@ -115,6 +125,7 @@ impl<T> RequestStrategy<T> {
|
||||||
RequestStrategy {
|
RequestStrategy {
|
||||||
rs_quorum: self.rs_quorum,
|
rs_quorum: self.rs_quorum,
|
||||||
rs_send_all_at_once: self.rs_send_all_at_once,
|
rs_send_all_at_once: self.rs_send_all_at_once,
|
||||||
|
rs_preemptive_send: self.rs_preemptive_send,
|
||||||
rs_priority: self.rs_priority,
|
rs_priority: self.rs_priority,
|
||||||
rs_timeout: self.rs_timeout,
|
rs_timeout: self.rs_timeout,
|
||||||
rs_drop_on_complete: (),
|
rs_drop_on_complete: (),
|
||||||
|
@ -335,29 +346,53 @@ impl RpcHelper {
|
||||||
S: Send + 'static,
|
S: Send + 'static,
|
||||||
{
|
{
|
||||||
// Once quorum is reached, other requests don't matter.
|
// Once quorum is reached, other requests don't matter.
|
||||||
// What we do here is only send the required number of requests
|
// The default here is to only send the required number of requests
|
||||||
// to reach a quorum, priorizing nodes with the lowest latency.
|
// to reach a quorum, priorizing nodes with the lowest latency.
|
||||||
// When there are errors, we start new requests to compensate.
|
// When there are errors, we start new requests to compensate.
|
||||||
|
|
||||||
// TODO: this could be made more aggressive, e.g. if after 2x the
|
|
||||||
// average ping of a given request, the response is not yet received,
|
|
||||||
// preemptively send an additional request to any remaining nodes.
|
|
||||||
|
|
||||||
// Reorder requests to priorize closeness / low latency
|
// Reorder requests to priorize closeness / low latency
|
||||||
let request_order =
|
let request_order =
|
||||||
self.request_order(&self.0.layout.read().unwrap().current(), to.iter().copied());
|
self.request_order(&self.0.layout.read().unwrap().current(), to.iter().copied());
|
||||||
|
let layout_nodes_count = request_order.len();
|
||||||
|
|
||||||
|
// The send_all_at_once flag overrides the behaviour described
|
||||||
|
// above and sends an RPC to every node from the get-go. This
|
||||||
|
// is more demanding on the network but also offers the best
|
||||||
|
// chance to reach quorum quickly.
|
||||||
let send_all_at_once = strategy.rs_send_all_at_once.unwrap_or(false);
|
let send_all_at_once = strategy.rs_send_all_at_once.unwrap_or(false);
|
||||||
|
|
||||||
|
// The preemptive_send flag is an attempt at compromise: we
|
||||||
|
// start by sending just enough to reach quorum, but associate
|
||||||
|
// each RPC to a watchog which triggers after 2x the average
|
||||||
|
// ping for that peer. When a watchdog triggers, an extra RPC
|
||||||
|
// is sent as a preemptive "replacement" in case the slow node
|
||||||
|
// is having serious trouble and can't reply. This is
|
||||||
|
// overriden by send_all_at_once.
|
||||||
|
let preemptive_send = strategy.rs_preemptive_send.unwrap_or(false);
|
||||||
|
let mut preemptive_watchdogs = FuturesUnordered::new();
|
||||||
|
let mut completed_node_ids = HashSet::<Uuid>::new();
|
||||||
|
let metric_tags = [
|
||||||
|
KeyValue::new("rpc_endpoint", endpoint.path().to_string()),
|
||||||
|
KeyValue::new("from", format!("{:?}", self.0.our_node_id)),
|
||||||
|
KeyValue::new("to", format!("{:?}", to)),
|
||||||
|
];
|
||||||
|
|
||||||
// Build future for each request
|
// Build future for each request
|
||||||
// They are not started now: they are added below in a FuturesUnordered
|
// They are not started now: they are added below in a FuturesUnordered
|
||||||
// object that will take care of polling them (see below)
|
// object that will take care of polling them (see below)
|
||||||
let msg = msg.into_req().map_err(garage_net::error::Error::from)?;
|
let msg = msg.into_req().map_err(garage_net::error::Error::from)?;
|
||||||
let mut requests = request_order.into_iter().map(|to| {
|
let mut requests = request_order.into_iter().map(|(avg_ping, to)| {
|
||||||
let self2 = self.clone();
|
let self2 = self.clone();
|
||||||
let msg = msg.clone();
|
let msg = msg.clone();
|
||||||
let endpoint2 = endpoint.clone();
|
let endpoint2 = endpoint.clone();
|
||||||
let strategy = strategy.clone();
|
let strategy = strategy.clone();
|
||||||
async move { self2.call(&endpoint2, to, msg, strategy).await }
|
(
|
||||||
|
async move { (to, self2.call(&endpoint2, to, msg, strategy).await) },
|
||||||
|
preemptive_send.then_some(async move {
|
||||||
|
tokio::time::sleep(2 * avg_ping).await;
|
||||||
|
to
|
||||||
|
}),
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Vectors in which success results and errors will be collected
|
// Vectors in which success results and errors will be collected
|
||||||
|
@ -368,13 +403,26 @@ impl RpcHelper {
|
||||||
// (for the moment none, they will be added in the loop below)
|
// (for the moment none, they will be added in the loop below)
|
||||||
let mut resp_stream = FuturesUnordered::new();
|
let mut resp_stream = FuturesUnordered::new();
|
||||||
|
|
||||||
|
// The number of in-flight requests we want at the moment
|
||||||
|
let mut target_outbound_count = if send_all_at_once {
|
||||||
|
layout_nodes_count
|
||||||
|
} else {
|
||||||
|
quorum
|
||||||
|
};
|
||||||
|
|
||||||
// Do some requests and collect results
|
// Do some requests and collect results
|
||||||
while successes.len() < quorum {
|
while successes.len() < quorum {
|
||||||
// If the current set of requests that are running is not enough to possibly
|
// If our current outbound request count is not enough, start new ones
|
||||||
// reach quorum, start some new requests.
|
while successes.len() + resp_stream.len() < target_outbound_count {
|
||||||
while send_all_at_once || successes.len() + resp_stream.len() < quorum {
|
if let Some((fut, watchdog)) = requests.next() {
|
||||||
if let Some(fut) = requests.next() {
|
if let Some(sleep) = watchdog {
|
||||||
resp_stream.push(fut)
|
preemptive_watchdogs.push(sleep);
|
||||||
|
self.0
|
||||||
|
.metrics
|
||||||
|
.rpc_watchdogs_started_counter
|
||||||
|
.add(1, &metric_tags);
|
||||||
|
}
|
||||||
|
resp_stream.push(fut);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -385,14 +433,45 @@ impl RpcHelper {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for one request to terminate
|
let response_or_watchdog = async {
|
||||||
match resp_stream.next().await.unwrap() {
|
if preemptive_watchdogs.is_empty() {
|
||||||
Ok(msg) => {
|
// We don't have any watchdogs to listen to, just wait for a request
|
||||||
successes.push(msg);
|
// This avoids waiting on a empty FuturesUnordered, which creates a busy wait
|
||||||
|
resp_stream
|
||||||
|
.next()
|
||||||
|
.await
|
||||||
|
.map(|(res, to)| WatchedRPCResult::Completed(res, to))
|
||||||
|
} else {
|
||||||
|
select! {
|
||||||
|
opt = resp_stream.next() => opt.map(|(res, to)| WatchedRPCResult::Completed(res, to)),
|
||||||
|
watchdog = preemptive_watchdogs.next() => watchdog.map(WatchedRPCResult::TimedOut),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
};
|
||||||
errors.push(e);
|
|
||||||
|
// Wait for the next completed request, or for a watchdog to trigger
|
||||||
|
match response_or_watchdog.await {
|
||||||
|
Some(WatchedRPCResult::Completed(to, res)) => {
|
||||||
|
completed_node_ids.insert(to);
|
||||||
|
match res {
|
||||||
|
Ok(msg) => successes.push(msg),
|
||||||
|
Err(e) => errors.push(e),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Some(WatchedRPCResult::TimedOut(to)) => {
|
||||||
|
// A watchdog has triggered, meaning one of the active requests is taking too long
|
||||||
|
// Note that we don't cancel watchdogs after requests complete, so we need to ignore those
|
||||||
|
if target_outbound_count < layout_nodes_count
|
||||||
|
&& !completed_node_ids.contains(&to)
|
||||||
|
{
|
||||||
|
target_outbound_count += 1;
|
||||||
|
self.0
|
||||||
|
.metrics
|
||||||
|
.rpc_watchdogs_preemption_counter
|
||||||
|
.add(1, &metric_tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,7 +633,7 @@ impl RpcHelper {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let nodes = ver.nodes_of(position, ver.replication_factor);
|
let nodes = ver.nodes_of(position, ver.replication_factor);
|
||||||
for node in rpc_helper.request_order(layout.current(), nodes) {
|
for (_, node) in rpc_helper.request_order(layout.current(), nodes) {
|
||||||
if !ret.contains(&node) {
|
if !ret.contains(&node) {
|
||||||
ret.push(node);
|
ret.push(node);
|
||||||
}
|
}
|
||||||
|
@ -567,7 +646,7 @@ impl RpcHelper {
|
||||||
&self,
|
&self,
|
||||||
layout: &LayoutVersion,
|
layout: &LayoutVersion,
|
||||||
nodes: impl Iterator<Item = Uuid>,
|
nodes: impl Iterator<Item = Uuid>,
|
||||||
) -> Vec<Uuid> {
|
) -> Vec<(Duration, Uuid)> {
|
||||||
// Retrieve some status variables that we will use to sort requests
|
// Retrieve some status variables that we will use to sort requests
|
||||||
let peer_list = self.0.peering.get_peer_list();
|
let peer_list = self.0.peering.get_peer_list();
|
||||||
let our_zone = layout.get_node_zone(&self.0.our_node_id).unwrap_or("");
|
let our_zone = layout.get_node_zone(&self.0.our_node_id).unwrap_or("");
|
||||||
|
@ -600,7 +679,7 @@ impl RpcHelper {
|
||||||
|
|
||||||
nodes
|
nodes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(_, _, _, to)| to)
|
.map(|(_, _, ping, to)| (ping, to))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -709,3 +788,10 @@ where
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------- utility for tracking RPC results and watchdog triggers --------
|
||||||
|
|
||||||
|
enum WatchedRPCResult<S> {
|
||||||
|
Completed(Uuid, Result<S, Error>),
|
||||||
|
TimedOut(Uuid),
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "garage_table"
|
name = "garage_table"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|
|
@ -317,7 +317,8 @@ impl<F: TableSchema, R: TableReplication> Table<F, R> {
|
||||||
&who,
|
&who,
|
||||||
rpc,
|
rpc,
|
||||||
RequestStrategy::with_priority(PRIO_NORMAL)
|
RequestStrategy::with_priority(PRIO_NORMAL)
|
||||||
.with_quorum(self.data.replication.read_quorum()),
|
.with_quorum(self.data.replication.read_quorum())
|
||||||
|
.with_preemptive_send(true),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -412,7 +413,8 @@ impl<F: TableSchema, R: TableReplication> Table<F, R> {
|
||||||
&who,
|
&who,
|
||||||
rpc,
|
rpc,
|
||||||
RequestStrategy::with_priority(PRIO_NORMAL)
|
RequestStrategy::with_priority(PRIO_NORMAL)
|
||||||
.with_quorum(self.data.replication.read_quorum()),
|
.with_quorum(self.data.replication.read_quorum())
|
||||||
|
.with_preemptive_send(true),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "garage_util"
|
name = "garage_util"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "garage_web"
|
name = "garage_web"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>", "Quentin Dufour <quentin@dufour.io>"]
|
authors = ["Alex Auvolat <alex@adnab.me>", "Quentin Dufour <quentin@dufour.io>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|
Loading…
Reference in a new issue