Compare commits

..

33 commits

Author SHA1 Message Date
78de7b5bde Merge pull request 'fix bit/byte inversion in rpc secret error message' (#898) from trinity-1686a/garage:rpc-comment into main
All checks were successful
ci/woodpecker/cron/release/3 Pipeline was successful
ci/woodpecker/cron/release/4 Pipeline was successful
ci/woodpecker/cron/release/2 Pipeline was successful
ci/woodpecker/cron/debug Pipeline was successful
ci/woodpecker/cron/release/1 Pipeline was successful
ci/woodpecker/cron/publish Pipeline was successful
Reviewed-on: #898
2024-11-07 11:11:12 +00:00
9bd9e392ba fix bit/byte inversion in rpc secret error message 2024-11-07 00:29:26 +01:00
a18b3f0d1f Merge pull request 'Garage v1.0.1' (#881) from rel-v1.0.1 into main
Some checks failed
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/cron/release/1 Pipeline was successful
ci/woodpecker/cron/debug Pipeline was successful
ci/woodpecker/cron/release/2 Pipeline failed
ci/woodpecker/cron/release/3 Pipeline failed
ci/woodpecker/cron/release/4 Pipeline was successful
ci/woodpecker/cron/publish unknown status
Reviewed-on: #881
2024-09-22 13:02:02 +00:00
7a143f46fc
Bump to version 1.0.1
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/pr/debug Pipeline was successful
ci/woodpecker/tag/debug Pipeline was successful
ci/woodpecker/deployment/debug Pipeline was successful
ci/woodpecker/deployment/release/3 Pipeline was successful
ci/woodpecker/deployment/release/2 Pipeline was successful
ci/woodpecker/deployment/release/1 Pipeline was successful
ci/woodpecker/deployment/release/4 Pipeline was successful
ci/woodpecker/deployment/publish Pipeline was successful
2024-09-22 14:25:32 +02:00
c731f0291a Merge pull request 'fix logic in garage layout skip-dead-nodes + fix typo (fix #879)' (#880) from fix-skip-dead-nodes into main
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/deployment/debug Pipeline was successful
ci/woodpecker/deployment/release/3 Pipeline was successful
ci/woodpecker/deployment/release/2 Pipeline was successful
ci/woodpecker/deployment/release/1 Pipeline was successful
ci/woodpecker/deployment/release/4 Pipeline was successful
ci/woodpecker/deployment/publish Pipeline was successful
Reviewed-on: #880
2024-09-22 12:01:49 +00:00
34453bc9c2
fix logic in garage layout skip-dead-nodes + fix typo (fix #879)
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/pr/debug Pipeline was successful
2024-09-22 13:47:27 +02:00
6da1353541 Merge pull request 'Don't fetch old values in cross-partition transactional inserts' (#877) from withings/garage:perf/kv/insert-no-return-cross-partition into main
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/deployment/debug Pipeline was successful
ci/woodpecker/deployment/release/3 Pipeline was successful
ci/woodpecker/deployment/release/2 Pipeline was successful
ci/woodpecker/deployment/release/1 Pipeline was successful
ci/woodpecker/deployment/release/4 Pipeline was successful
ci/woodpecker/deployment/publish Pipeline was successful
ci/woodpecker/cron/release/3 Pipeline was successful
ci/woodpecker/cron/release/2 Pipeline was successful
ci/woodpecker/cron/release/4 Pipeline was successful
ci/woodpecker/cron/debug Pipeline was successful
ci/woodpecker/cron/release/1 Pipeline was successful
ci/woodpecker/cron/publish Pipeline was successful
Reviewed-on: #877
2024-09-14 15:57:27 +00:00
bd71728874
Tests: don't expect old value after transactional insert
All checks were successful
ci/woodpecker/pr/debug Pipeline was successful
2024-09-12 10:50:53 +02:00
51ced60366
Don't fetch old values in cross-partition transactional inserts
Some checks failed
ci/woodpecker/pr/debug Pipeline failed
2024-09-12 10:26:28 +02:00
586957b4b7 Merge pull request 'KV: don't retrieve values for write ops' (#873) from marvinj97/garage:perf/kv/insert-no-return into main
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/cron/release/3 Pipeline was successful
ci/woodpecker/cron/release/2 Pipeline was successful
ci/woodpecker/cron/debug Pipeline was successful
ci/woodpecker/cron/release/4 Pipeline was successful
ci/woodpecker/cron/release/1 Pipeline was successful
ci/woodpecker/cron/publish Pipeline was successful
Reviewed-on: #873
Reviewed-by: Alex <alex@adnab.me>
2024-09-10 09:06:29 +00:00
8d2bb4afeb Merge pull request 'Typo' (#875) from faust/garage:doc2 into main
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
Reviewed-on: #875
2024-09-10 09:03:31 +00:00
c26f32b769
Typo
All checks were successful
ci/woodpecker/pr/debug Pipeline was successful
And remove trailing white space.
2024-09-10 09:34:59 +02:00
8062ec7b4b test: fix db tests
All checks were successful
ci/woodpecker/pr/debug Pipeline was successful
2024-09-04 19:24:36 +02:00
eb416a02fb dont assert deletion count in sqlite KV adapter
Some checks failed
ci/woodpecker/pr/debug Pipeline failed
2024-09-04 18:51:51 +02:00
74363c9060 perf(kv): dont retrieve values for write ops
Some checks failed
ci/woodpecker/pr/debug Pipeline failed
see #851
2024-09-04 18:45:17 +02:00
615698df7d Merge pull request 'update compiler to Rust 1.77' (#866) from rust-1.77 into main
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/cron/release/3 Pipeline was successful
ci/woodpecker/cron/debug Pipeline was successful
ci/woodpecker/cron/release/2 Pipeline was successful
ci/woodpecker/cron/release/4 Pipeline was successful
ci/woodpecker/cron/release/1 Pipeline was successful
ci/woodpecker/cron/publish Pipeline was successful
Reviewed-on: #866
2024-08-26 19:08:00 +00:00
7061fa5a56
use rust 1.77 in nix/compile.nix
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/pr/debug Pipeline was successful
ci/woodpecker/deployment/debug Pipeline was successful
ci/woodpecker/deployment/release/1 Pipeline was successful
ci/woodpecker/deployment/release/4 Pipeline was successful
ci/woodpecker/deployment/release/3 Pipeline was successful
ci/woodpecker/deployment/release/2 Pipeline was successful
ci/woodpecker/deployment/publish Pipeline was successful
2024-08-26 19:19:16 +02:00
8881930cdd
update nixpkgs and rust-overlay sources in flake.nix 2024-08-26 19:19:16 +02:00
52f6c0760b Merge pull request 'update crate time (fix #849)' (#865) from update-time into main
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
Reviewed-on: #865
2024-08-26 16:20:04 +00:00
5b0602c7e9
update crate time (fix #849)
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/pr/debug Pipeline was successful
2024-08-26 18:11:21 +02:00
182b2af7e5 Merge pull request 'api servers: kill opened connections after SIGINT after 10s deadline (fix #806)' (#864) from exit-deadline into main
Some checks failed
ci/woodpecker/push/debug Pipeline failed
ci/woodpecker/cron/release/3 Pipeline was successful
ci/woodpecker/cron/debug Pipeline was successful
ci/woodpecker/cron/release/2 Pipeline was successful
ci/woodpecker/cron/release/4 Pipeline was successful
ci/woodpecker/cron/release/1 Pipeline was successful
ci/woodpecker/cron/publish Pipeline was successful
Reviewed-on: #864
2024-08-25 18:34:55 +00:00
baf32c9575
api servers: kill opened connections after SIGINT after 10s deadline (fix #806)
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/pr/debug Pipeline was successful
2024-08-25 20:04:56 +02:00
3dda1ee4f6 Merge pull request 'fix build when lmdb feature is disabled (fix #800)' (#863) from fix-800 into main
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
Reviewed-on: #863
2024-08-25 10:00:40 +00:00
aa7ce9e97c
fix build when lmdb feature is disabled (fix #800)
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/pr/debug Pipeline was successful
2024-08-25 11:42:37 +02:00
8d62616ec0 Merge pull request 'layout: discard old info when it is completely out-of-date (fix #841)' (#861) from fix-841 into main
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/cron/debug Pipeline was successful
ci/woodpecker/cron/release/1 Pipeline was successful
ci/woodpecker/cron/release/2 Pipeline was successful
ci/woodpecker/cron/release/3 Pipeline was successful
ci/woodpecker/cron/release/4 Pipeline was successful
ci/woodpecker/cron/publish Pipeline was successful
Reviewed-on: #861
2024-08-24 11:12:39 +00:00
bd6fe72c06 Merge pull request 'Quick start: mention Docker (replace #803)' (#862) from dougreeder into main
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
Reviewed-on: #862
2024-08-24 11:07:46 +00:00
4c9e8ef625
doc: clarify quick start on using docker
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/pr/debug Pipeline was successful
2024-08-24 13:07:02 +02:00
3e711bc110 Merge pull request 'don't modify postobject request before validating policy' (#850) from trinity-1686a/garage:fix-acl-postobject into main
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
Reviewed-on: #850
2024-08-24 10:49:14 +00:00
7fb66b4944
layout: discard old info when it is completely out-of-date (fix #841)
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/pr/debug Pipeline was successful
2024-08-24 12:38:56 +02:00
679ae8bcbb Merge pull request 'Set "no read ahead" on LMDB to improve performances when "LMDB size" > "RAM size"' (#855) from fix-lmdb-no-read-ahead into main
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/cron/debug Pipeline was successful
ci/woodpecker/cron/release/1 Pipeline was successful
ci/woodpecker/cron/release/2 Pipeline was successful
ci/woodpecker/cron/release/3 Pipeline was successful
ci/woodpecker/cron/release/4 Pipeline was successful
ci/woodpecker/cron/publish Pipeline was successful
Reviewed-on: #855
Reviewed-by: Alex <alex@adnab.me>
2024-08-18 12:25:35 +00:00
2a93ad0c84
force flag "no read ahead" on LMDB
All checks were successful
ci/woodpecker/push/debug Pipeline was successful
ci/woodpecker/pr/debug Pipeline was successful
2024-08-17 21:17:15 +02:00
f190032589 don't modify postobject request before validating policy
All checks were successful
ci/woodpecker/pr/debug Pipeline was successful
2024-08-10 20:10:47 +02:00
0c3b198b22 Improves Quick Start for users not using Linux
All checks were successful
ci/woodpecker/pr/debug Pipeline was successful
2024-04-10 16:42:10 -04:00
35 changed files with 294 additions and 575 deletions

29
Cargo.lock generated
View file

@ -1304,7 +1304,7 @@ dependencies = [
[[package]] [[package]]
name = "garage" name = "garage"
version = "1.0.0" version = "1.0.1"
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.0" version = "1.0.1"
dependencies = [ dependencies = [
"aes-gcm", "aes-gcm",
"argon2", "argon2",
@ -1415,7 +1415,7 @@ dependencies = [
[[package]] [[package]]
name = "garage_block" name = "garage_block"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"async-compression", "async-compression",
@ -1442,13 +1442,12 @@ dependencies = [
[[package]] [[package]]
name = "garage_db" name = "garage_db"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"err-derive", "err-derive",
"heed", "heed",
"hexdump", "hexdump",
"mktemp", "mktemp",
"opentelemetry",
"r2d2", "r2d2",
"r2d2_sqlite", "r2d2_sqlite",
"rusqlite", "rusqlite",
@ -1457,7 +1456,7 @@ dependencies = [
[[package]] [[package]]
name = "garage_model" name = "garage_model"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"async-trait", "async-trait",
@ -1487,7 +1486,7 @@ dependencies = [
[[package]] [[package]]
name = "garage_net" name = "garage_net"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"async-trait", "async-trait",
@ -1513,7 +1512,7 @@ dependencies = [
[[package]] [[package]]
name = "garage_rpc" name = "garage_rpc"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"async-trait", "async-trait",
@ -1549,7 +1548,7 @@ dependencies = [
[[package]] [[package]]
name = "garage_table" name = "garage_table"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"async-trait", "async-trait",
@ -1571,7 +1570,7 @@ dependencies = [
[[package]] [[package]]
name = "garage_util" name = "garage_util"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"async-trait", "async-trait",
@ -1605,7 +1604,7 @@ dependencies = [
[[package]] [[package]]
name = "garage_web" name = "garage_web"
version = "1.0.0" version = "1.0.1"
dependencies = [ dependencies = [
"err-derive", "err-derive",
"futures", "futures",
@ -4083,9 +4082,9 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.34" version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [ dependencies = [
"deranged", "deranged",
"num-conv", "num-conv",
@ -4103,9 +4102,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]] [[package]]
name = "time-macros" name = "time-macros"
version = "0.2.17" version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [ dependencies = [
"num-conv", "num-conv",
"time-core", "time-core",

159
Cargo.nix
View file

@ -34,7 +34,7 @@ args@{
ignoreLockHash, ignoreLockHash,
}: }:
let let
nixifiedLockHash = "5826893fb6082581d96992c846c892c623f3b1b17cefba3b6b8ca10c9f45c589"; nixifiedLockHash = "466643eea782cd68c6f205858bb9e053aecdb18e2e58427b0527022aad596130";
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.0"; garage_db = rustPackages.unknown.garage_db."1.0.1";
garage_util = rustPackages.unknown.garage_util."1.0.0"; garage_util = rustPackages.unknown.garage_util."1.0.1";
garage_net = rustPackages.unknown.garage_net."1.0.0"; garage_net = rustPackages.unknown.garage_net."1.0.1";
garage_rpc = rustPackages.unknown.garage_rpc."1.0.0"; garage_rpc = rustPackages.unknown.garage_rpc."1.0.1";
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.0"; garage_table = rustPackages.unknown.garage_table."1.0.1";
garage_block = rustPackages.unknown.garage_block."1.0.0"; garage_block = rustPackages.unknown.garage_block."1.0.1";
garage_model = rustPackages.unknown.garage_model."1.0.0"; garage_model = rustPackages.unknown.garage_model."1.0.1";
garage_api = rustPackages.unknown.garage_api."1.0.0"; garage_api = rustPackages.unknown.garage_api."1.0.1";
garage_web = rustPackages.unknown.garage_web."1.0.0"; garage_web = rustPackages.unknown.garage_web."1.0.1";
garage = rustPackages.unknown.garage."1.0.0"; garage = rustPackages.unknown.garage."1.0.1";
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.34" { inherit profileName; }).out; time = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" { 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.34" { inherit profileName; }).out; time = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" { 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.34" { inherit profileName; }).out; time = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" { 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.0" = overridableMkRustCrate (profileName: rec { "unknown".garage."1.0.1" = overridableMkRustCrate (profileName: rec {
name = "garage"; name = "garage";
version = "1.0.0"; version = "1.0.1";
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.0" { inherit profileName; }).out; garage_api = (rustPackages."unknown".garage_api."1.0.1" { inherit profileName; }).out;
garage_block = (rustPackages."unknown".garage_block."1.0.0" { inherit profileName; }).out; garage_block = (rustPackages."unknown".garage_block."1.0.1" { inherit profileName; }).out;
garage_db = (rustPackages."unknown".garage_db."1.0.0" { inherit profileName; }).out; garage_db = (rustPackages."unknown".garage_db."1.0.1" { inherit profileName; }).out;
garage_model = (rustPackages."unknown".garage_model."1.0.0" { inherit profileName; }).out; garage_model = (rustPackages."unknown".garage_model."1.0.1" { inherit profileName; }).out;
garage_net = (rustPackages."unknown".garage_net."1.0.0" { inherit profileName; }).out; garage_net = (rustPackages."unknown".garage_net."1.0.1" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.0" { inherit profileName; }).out; garage_rpc = (rustPackages."unknown".garage_rpc."1.0.1" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."1.0.0" { inherit profileName; }).out; garage_table = (rustPackages."unknown".garage_table."1.0.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out; garage_util = (rustPackages."unknown".garage_util."1.0.1" { inherit profileName; }).out;
garage_web = (rustPackages."unknown".garage_web."1.0.0" { inherit profileName; }).out; garage_web = (rustPackages."unknown".garage_web."1.0.1" { 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.0" = overridableMkRustCrate (profileName: rec { "unknown".garage_api."1.0.1" = overridableMkRustCrate (profileName: rec {
name = "garage_api"; name = "garage_api";
version = "1.0.0"; version = "1.0.1";
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.0" { inherit profileName; }).out; garage_block = (rustPackages."unknown".garage_block."1.0.1" { inherit profileName; }).out;
garage_model = (rustPackages."unknown".garage_model."1.0.0" { inherit profileName; }).out; garage_model = (rustPackages."unknown".garage_model."1.0.1" { inherit profileName; }).out;
garage_net = (rustPackages."unknown".garage_net."1.0.0" { inherit profileName; }).out; garage_net = (rustPackages."unknown".garage_net."1.0.1" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.0" { inherit profileName; }).out; garage_rpc = (rustPackages."unknown".garage_rpc."1.0.1" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."1.0.0" { inherit profileName; }).out; garage_table = (rustPackages."unknown".garage_table."1.0.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out; garage_util = (rustPackages."unknown".garage_util."1.0.1" { 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.0" = overridableMkRustCrate (profileName: rec { "unknown".garage_block."1.0.1" = overridableMkRustCrate (profileName: rec {
name = "garage_block"; name = "garage_block";
version = "1.0.0"; version = "1.0.1";
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.0" { inherit profileName; }).out; garage_db = (rustPackages."unknown".garage_db."1.0.1" { inherit profileName; }).out;
garage_net = (rustPackages."unknown".garage_net."1.0.0" { inherit profileName; }).out; garage_net = (rustPackages."unknown".garage_net."1.0.1" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.0" { inherit profileName; }).out; garage_rpc = (rustPackages."unknown".garage_rpc."1.0.1" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."1.0.0" { inherit profileName; }).out; garage_table = (rustPackages."unknown".garage_table."1.0.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out; garage_util = (rustPackages."unknown".garage_util."1.0.1" { 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.0" = overridableMkRustCrate (profileName: rec { "unknown".garage_db."1.0.1" = overridableMkRustCrate (profileName: rec {
name = "garage_db"; name = "garage_db";
version = "1.0.0"; version = "1.0.1";
registry = "unknown"; registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/db"); src = fetchCrateLocal (workspaceSrc + "/src/db");
features = builtins.concatLists [ features = builtins.concatLists [
@ -2104,7 +2104,6 @@ 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;
${ if rootFeatures' ? "garage/default" || rootFeatures' ? "garage/lmdb" || rootFeatures' ? "garage_db/default" || rootFeatures' ? "garage_db/heed" || rootFeatures' ? "garage_db/lmdb" || rootFeatures' ? "garage_model/default" || rootFeatures' ? "garage_model/lmdb" then "heed" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".heed."0.11.0" { inherit profileName; }).out; ${ if rootFeatures' ? "garage/default" || rootFeatures' ? "garage/lmdb" || rootFeatures' ? "garage_db/default" || rootFeatures' ? "garage_db/heed" || rootFeatures' ? "garage_db/lmdb" || rootFeatures' ? "garage_model/default" || rootFeatures' ? "garage_model/lmdb" then "heed" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".heed."0.11.0" { 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;
${ if rootFeatures' ? "garage/default" || rootFeatures' ? "garage/sqlite" || rootFeatures' ? "garage_db/default" || rootFeatures' ? "garage_db/r2d2" || rootFeatures' ? "garage_db/sqlite" || rootFeatures' ? "garage_model/default" || rootFeatures' ? "garage_model/sqlite" then "r2d2" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".r2d2."0.8.10" { inherit profileName; }).out; ${ if rootFeatures' ? "garage/default" || rootFeatures' ? "garage/sqlite" || rootFeatures' ? "garage_db/default" || rootFeatures' ? "garage_db/r2d2" || rootFeatures' ? "garage_db/sqlite" || rootFeatures' ? "garage_model/default" || rootFeatures' ? "garage_model/sqlite" then "r2d2" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".r2d2."0.8.10" { inherit profileName; }).out;
${ if rootFeatures' ? "garage/default" || rootFeatures' ? "garage/sqlite" || rootFeatures' ? "garage_db/default" || rootFeatures' ? "garage_db/r2d2_sqlite" || rootFeatures' ? "garage_db/sqlite" || rootFeatures' ? "garage_model/default" || rootFeatures' ? "garage_model/sqlite" then "r2d2_sqlite" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".r2d2_sqlite."0.24.0" { inherit profileName; }).out; ${ if rootFeatures' ? "garage/default" || rootFeatures' ? "garage/sqlite" || rootFeatures' ? "garage_db/default" || rootFeatures' ? "garage_db/r2d2_sqlite" || rootFeatures' ? "garage_db/sqlite" || rootFeatures' ? "garage_model/default" || rootFeatures' ? "garage_model/sqlite" then "r2d2_sqlite" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".r2d2_sqlite."0.24.0" { inherit profileName; }).out;
${ if rootFeatures' ? "garage/bundled-libs" || rootFeatures' ? "garage/default" || rootFeatures' ? "garage/sqlite" || rootFeatures' ? "garage_db/bundled-libs" || rootFeatures' ? "garage_db/default" || rootFeatures' ? "garage_db/rusqlite" || rootFeatures' ? "garage_db/sqlite" || rootFeatures' ? "garage_model/default" || rootFeatures' ? "garage_model/sqlite" then "rusqlite" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rusqlite."0.31.0" { inherit profileName; }).out; ${ if rootFeatures' ? "garage/bundled-libs" || rootFeatures' ? "garage/default" || rootFeatures' ? "garage/sqlite" || rootFeatures' ? "garage_db/bundled-libs" || rootFeatures' ? "garage_db/default" || rootFeatures' ? "garage_db/rusqlite" || rootFeatures' ? "garage_db/sqlite" || rootFeatures' ? "garage_model/default" || rootFeatures' ? "garage_model/sqlite" then "rusqlite" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rusqlite."0.31.0" { inherit profileName; }).out;
@ -2115,9 +2114,9 @@ in
}; };
}); });
"unknown".garage_model."1.0.0" = overridableMkRustCrate (profileName: rec { "unknown".garage_model."1.0.1" = overridableMkRustCrate (profileName: rec {
name = "garage_model"; name = "garage_model";
version = "1.0.0"; version = "1.0.1";
registry = "unknown"; registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/model"); src = fetchCrateLocal (workspaceSrc + "/src/model");
features = builtins.concatLists [ features = builtins.concatLists [
@ -2135,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.0" { inherit profileName; }).out; garage_block = (rustPackages."unknown".garage_block."1.0.1" { inherit profileName; }).out;
garage_db = (rustPackages."unknown".garage_db."1.0.0" { inherit profileName; }).out; garage_db = (rustPackages."unknown".garage_db."1.0.1" { inherit profileName; }).out;
garage_net = (rustPackages."unknown".garage_net."1.0.0" { inherit profileName; }).out; garage_net = (rustPackages."unknown".garage_net."1.0.1" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.0" { inherit profileName; }).out; garage_rpc = (rustPackages."unknown".garage_rpc."1.0.1" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."1.0.0" { inherit profileName; }).out; garage_table = (rustPackages."unknown".garage_table."1.0.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out; garage_util = (rustPackages."unknown".garage_util."1.0.1" { 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;
@ -2154,9 +2153,9 @@ in
}; };
}); });
"unknown".garage_net."1.0.0" = overridableMkRustCrate (profileName: rec { "unknown".garage_net."1.0.1" = overridableMkRustCrate (profileName: rec {
name = "garage_net"; name = "garage_net";
version = "1.0.0"; version = "1.0.1";
registry = "unknown"; registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/net"); src = fetchCrateLocal (workspaceSrc + "/src/net");
features = builtins.concatLists [ features = builtins.concatLists [
@ -2191,9 +2190,9 @@ in
}; };
}); });
"unknown".garage_rpc."1.0.0" = overridableMkRustCrate (profileName: rec { "unknown".garage_rpc."1.0.1" = overridableMkRustCrate (profileName: rec {
name = "garage_rpc"; name = "garage_rpc";
version = "1.0.0"; version = "1.0.1";
registry = "unknown"; registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/rpc"); src = fetchCrateLocal (workspaceSrc + "/src/rpc");
features = builtins.concatLists [ features = builtins.concatLists [
@ -2215,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.0" { inherit profileName; }).out; garage_db = (rustPackages."unknown".garage_db."1.0.1" { inherit profileName; }).out;
garage_net = (rustPackages."unknown".garage_net."1.0.0" { inherit profileName; }).out; garage_net = (rustPackages."unknown".garage_net."1.0.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out; garage_util = (rustPackages."unknown".garage_util."1.0.1" { 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;
@ -2240,9 +2239,9 @@ in
}; };
}); });
"unknown".garage_table."1.0.0" = overridableMkRustCrate (profileName: rec { "unknown".garage_table."1.0.1" = overridableMkRustCrate (profileName: rec {
name = "garage_table"; name = "garage_table";
version = "1.0.0"; version = "1.0.1";
registry = "unknown"; registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/table"); src = fetchCrateLocal (workspaceSrc + "/src/table");
dependencies = { dependencies = {
@ -2251,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.0" { inherit profileName; }).out; garage_db = (rustPackages."unknown".garage_db."1.0.1" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."1.0.0" { inherit profileName; }).out; garage_rpc = (rustPackages."unknown".garage_rpc."1.0.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out; garage_util = (rustPackages."unknown".garage_util."1.0.1" { 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;
@ -2265,9 +2264,9 @@ in
}; };
}); });
"unknown".garage_util."1.0.0" = overridableMkRustCrate (profileName: rec { "unknown".garage_util."1.0.1" = overridableMkRustCrate (profileName: rec {
name = "garage_util"; name = "garage_util";
version = "1.0.0"; version = "1.0.1";
registry = "unknown"; registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/util"); src = fetchCrateLocal (workspaceSrc + "/src/util");
features = builtins.concatLists [ features = builtins.concatLists [
@ -2283,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.0" { inherit profileName; }).out; garage_db = (rustPackages."unknown".garage_db."1.0.1" { inherit profileName; }).out;
garage_net = (rustPackages."unknown".garage_net."1.0.0" { inherit profileName; }).out; garage_net = (rustPackages."unknown".garage_net."1.0.1" { 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;
@ -2309,18 +2308,18 @@ in
}; };
}); });
"unknown".garage_web."1.0.0" = overridableMkRustCrate (profileName: rec { "unknown".garage_web."1.0.1" = overridableMkRustCrate (profileName: rec {
name = "garage_web"; name = "garage_web";
version = "1.0.0"; version = "1.0.1";
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.0" { inherit profileName; }).out; garage_api = (rustPackages."unknown".garage_api."1.0.1" { inherit profileName; }).out;
garage_model = (rustPackages."unknown".garage_model."1.0.0" { inherit profileName; }).out; garage_model = (rustPackages."unknown".garage_model."1.0.1" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."1.0.0" { inherit profileName; }).out; garage_table = (rustPackages."unknown".garage_table."1.0.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."1.0.0" { inherit profileName; }).out; garage_util = (rustPackages."unknown".garage_util."1.0.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;
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;
@ -5782,11 +5781,11 @@ in
}; };
}); });
"registry+https://github.com/rust-lang/crates.io-index".time."0.3.34" = overridableMkRustCrate (profileName: rec { "registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" = overridableMkRustCrate (profileName: rec {
name = "time"; name = "time";
version = "0.3.34"; version = "0.3.36";
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 = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"; }; src = fetchCratesIo { inherit name version; sha256 = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"; };
features = builtins.concatLists [ features = builtins.concatLists [
[ "alloc" ] [ "alloc" ]
[ "default" ] [ "default" ]
@ -5799,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.17" { profileName = "__noProfile"; }).out; time_macros = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".time-macros."0.2.18" { profileName = "__noProfile"; }).out;
}; };
}); });
@ -5810,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.17" = overridableMkRustCrate (profileName: rec { "registry+https://github.com/rust-lang/crates.io-index".time-macros."0.2.18" = overridableMkRustCrate (profileName: rec {
name = "time-macros"; name = "time-macros";
version = "0.2.17"; version = "0.2.18";
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 = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"; }; src = fetchCratesIo { inherit name version; sha256 = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"; };
features = builtins.concatLists [ features = builtins.concatLists [
[ "parsing" ] [ "parsing" ]
]; ];

View file

@ -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.0", path = "src/api" } garage_api = { version = "1.0.1", path = "src/api" }
garage_block = { version = "1.0.0", path = "src/block" } garage_block = { version = "1.0.1", path = "src/block" }
garage_db = { version = "1.0.0", path = "src/db", default-features = false } garage_db = { version = "1.0.1", path = "src/db", default-features = false }
garage_model = { version = "1.0.0", path = "src/model", default-features = false } garage_model = { version = "1.0.1", path = "src/model", default-features = false }
garage_net = { version = "1.0.0", path = "src/net" } garage_net = { version = "1.0.1", path = "src/net" }
garage_rpc = { version = "1.0.0", path = "src/rpc" } garage_rpc = { version = "1.0.1", path = "src/rpc" }
garage_table = { version = "1.0.0", path = "src/table" } garage_table = { version = "1.0.1", path = "src/table" }
garage_util = { version = "1.0.0", path = "src/util" } garage_util = { version = "1.0.1", path = "src/util" }
garage_web = { version = "1.0.0", path = "src/web" } garage_web = { version = "1.0.1", 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

View file

@ -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.0`) and not the `latest` tag. We encourage you to use a fixed tag (eg. `v1.0.1`) 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.0` 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.1` 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.0 sudo docker pull dxflrs/garage:v1.0.1
``` ```
## 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.0 dxflrs/garage:v1.0.1
``` ```
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.0 image: dxflrs/garage:v1.0.1
network_mode: "host" network_mode: "host"
restart: unless-stopped restart: unless-stopped
volumes: volumes:

View file

@ -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! For Garage is fully equipped to handle drive failures, in most common cases. Fear not! Garage is fully equipped to handle drive failures, in most common cases.
## A note on availability of Garage ## A note on availability of Garage
@ -61,7 +61,7 @@ garage repair -a --yes blocks
This will re-synchronize blocks of data that are missing to the new HDD, reading them from copies located on other nodes. This will re-synchronize blocks of data that are missing to the new HDD, reading them from copies located on other nodes.
You can check on the advancement of this process by doing the following command: You can check on the advancement of this process by doing the following command:
```bash ```bash
garage stats -a garage stats -a

View file

@ -42,6 +42,13 @@ 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
@ -85,6 +92,9 @@ 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`
@ -111,6 +121,26 @@ 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`.
@ -131,6 +161,9 @@ 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:

View file

@ -70,7 +70,7 @@ Example response body:
```json ```json
{ {
"node": "b10c110e4e854e5aa3f4637681befac755154b20059ec163254ddbfae86b09df", "node": "b10c110e4e854e5aa3f4637681befac755154b20059ec163254ddbfae86b09df",
"garageVersion": "v1.0.0", "garageVersion": "v1.0.1",
"garageFeatures": [ "garageFeatures": [
"k2v", "k2v",
"lmdb", "lmdb",

View file

@ -28,11 +28,11 @@
}, },
"flake-compat": { "flake-compat": {
"locked": { "locked": {
"lastModified": 1688025799, "lastModified": 1717312683,
"narHash": "sha256-ktpB4dRtnksm9F5WawoIkEneh1nrEvuxb5lJFt1iOyw=", "narHash": "sha256-FrlieJH50AuvagamEvWMIE6D2OAnERuDboFDYAED/dE=",
"owner": "nix-community", "owner": "nix-community",
"repo": "flake-compat", "repo": "flake-compat",
"rev": "8bf105319d44f6b9f0d764efa4fdef9f1cc9ba1c", "rev": "38fd3954cf65ce6faf3d0d45cd26059e059f07ea",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -42,33 +42,12 @@
} }
}, },
"flake-utils": { "flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": { "locked": {
"lastModified": 1681202837, "lastModified": 1659877975,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401", "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"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": {
@ -79,11 +58,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1682109806, "lastModified": 1724395761,
"narHash": "sha256-d9g7RKNShMLboTWwukM+RObDWWpHKaqTYXB48clBWXI=", "narHash": "sha256-zRkDV/nbrnp3Y8oCADf5ETl1sDrdmAW6/bBVJ8EbIdQ=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "2362848adf8def2866fabbffc50462e929d7fffb", "rev": "ae815cee91b417be55d43781eb4b73ae1ecc396c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -95,17 +74,17 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1707091808, "lastModified": 1724681257,
"narHash": "sha256-LahKBAfGbY836gtpVNnWwBTIzN7yf/uYM/S0g393r0Y=", "narHash": "sha256-EJRuc5Qp7yfXko5ZNeEMYAs4DzAvkCyALuJ/tGllhN4=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9f2ee8c91ac42da3ae6c6a1d21555f283458247e", "rev": "0239aeb2f82ea27ccd6b61582b8f7fb8750eeada",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9f2ee8c91ac42da3ae6c6a1d21555f283458247e", "rev": "0239aeb2f82ea27ccd6b61582b8f7fb8750eeada",
"type": "github" "type": "github"
} }
}, },
@ -122,15 +101,14 @@
}, },
"rust-overlay": { "rust-overlay": {
"inputs": { "inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1707271822, "lastModified": 1724638882,
"narHash": "sha256-/DZsoPH5GBzOpVEGz5PgJ7vh8Q6TcrJq5u8FcBjqAfI=", "narHash": "sha256-ap2jIQi/FuUHR6HCht6ASWhoz8EiB99XmI8Esot38VE=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "7a94fe7690d2bdfe1aab475382a505e14dc114a6", "rev": "19b70f147b9c67a759e35824b241f1ed92e46694",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -138,36 +116,6 @@
"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",

View file

@ -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 23.11 as of 2024-02-07, has rustc v1.73 # Nixpkgs 24.05 as of 2024-08-26 has rustc v1.77
inputs.nixpkgs.url = inputs.nixpkgs.url =
"github:NixOS/nixpkgs/9f2ee8c91ac42da3ae6c6a1d21555f283458247e"; "github:NixOS/nixpkgs/0239aeb2f82ea27ccd6b61582b8f7fb8750eeada";
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-02-07 # Rust overlay as of 2024-08-26
inputs.rust-overlay.url = inputs.rust-overlay.url =
"github:oxalica/rust-overlay/7a94fe7690d2bdfe1aab475382a505e14dc114a6"; "github:oxalica/rust-overlay/19b70f147b9c67a759e35824b241f1ed92e46694";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-compat.follows = "flake-compat"; inputs.flake-compat.follows = "flake-compat";

View file

@ -20,7 +20,7 @@ let
}; };
toolchainOptions = { toolchainOptions = {
rustVersion = "1.73.0"; rustVersion = "1.77.0";
extraRustComponents = [ "clippy" ]; extraRustComponents = [ "clippy" ];
}; };

View file

@ -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.0 version: 0.5.1
# 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.0" appVersion: "v1.0.1"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "garage_api" name = "garage_api"
version = "1.0.0" version = "1.0.1"
authors = ["Alex Auvolat <alex@adnab.me>"] authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018" edition = "2018"
license = "AGPL-3.0" license = "AGPL-3.0"

View file

@ -2,6 +2,7 @@ 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;
@ -19,6 +20,7 @@ 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,
@ -291,7 +293,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::new(); let mut connections = FuturesUnordered::<tokio::task::JoinHandle<()>>::new();
loop { loop {
let collect_next = async { let collect_next = async {
if connections.is_empty() { if connections.is_empty() {
@ -312,23 +314,34 @@ where
} }
} }
} }
if !connections.is_empty() { let deadline = Instant::now() + Duration::from_secs(10);
while !connections.is_empty() {
info!( info!(
"{} server: {} connections still open", "{} server: {} connections still open, deadline in {:.2}s",
server_name, server_name,
connections.len() connections.len(),
(deadline - Instant::now()).as_secs_f32(),
); );
while let Some(conn_res) = connections.next().await { tokio::select! {
trace!( conn_res = connections.next() => {
"{} server: HTTP connection finished: {:?}", trace!(
server_name, "{} server: HTTP connection finished: {:?}",
conn_res server_name,
); conn_res.unwrap(),
info!( );
"{} server: {} connections still open", }
server_name, _ = sleep_until(deadline) => {
connections.len() warn!("{} server: exit deadline reached with {} connections still open, killing them now",
); server_name,
connections.len());
for conn in connections.iter() {
conn.abort();
}
for conn in connections {
assert!(conn.await.unwrap_err().is_cancelled());
}
break;
}
} }
} }
} }

View file

@ -71,21 +71,11 @@ 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?) {
match name.as_str() { if params.insert(&name, content).is_some() {
"tag" => (/* tag need to be reencoded, but we don't support them yet anyway */), return Err(Error::bad_request(format!(
"acl" => { "Field '{}' provided more than once",
if params.insert("x-amz-acl", content).is_some() { name
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
)));
}
}
} }
} }
}; };
@ -222,6 +212,8 @@ 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(&params)?; let headers = get_headers(&params)?;
let expected_checksums = ExpectedChecksums { let expected_checksums = ExpectedChecksums {

View file

@ -1,6 +1,6 @@
[package] [package]
name = "garage_block" name = "garage_block"
version = "1.0.0" version = "1.0.1"
authors = ["Alex Auvolat <alex@adnab.me>"] authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018" edition = "2018"
license = "AGPL-3.0" license = "AGPL-3.0"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "garage_db" name = "garage_db"
version = "1.0.0" version = "1.0.1"
authors = ["Alex Auvolat <alex@adnab.me>"] authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018" edition = "2018"
license = "AGPL-3.0" license = "AGPL-3.0"
@ -15,7 +15,6 @@ path = "lib.rs"
err-derive.workspace = true err-derive.workspace = true
hexdump.workspace = true hexdump.workspace = true
tracing.workspace = true tracing.workspace = true
opentelemetry.workspace = true
heed = { workspace = true, optional = true } heed = { workspace = true, optional = true }
rusqlite = { workspace = true, optional = true, features = ["backup"] } rusqlite = { workspace = true, optional = true, features = ["backup"] }

View file

@ -3,9 +3,6 @@ extern crate tracing;
#[cfg(feature = "lmdb")] #[cfg(feature = "lmdb")]
pub mod lmdb_adapter; pub mod lmdb_adapter;
#[cfg(feature = "lmdb")]
pub mod metric_proxy;
#[cfg(feature = "sqlite")] #[cfg(feature = "sqlite")]
pub mod sqlite_adapter; pub mod sqlite_adapter;
@ -214,16 +211,12 @@ 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]>>( pub fn insert<T: AsRef<[u8]>, U: AsRef<[u8]>>(&self, key: T, value: U) -> Result<()> {
&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<Option<Value>> { pub fn remove<T: AsRef<[u8]>>(&self, key: T) -> Result<()> {
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
@ -281,12 +274,12 @@ impl<'a> Transaction<'a> {
tree: &Tree, tree: &Tree,
key: T, key: T,
value: U, value: U,
) -> TxOpResult<Option<Value>> { ) -> TxOpResult<()> {
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<Option<Value>> { pub fn remove<T: AsRef<[u8]>>(&mut self, tree: &Tree, key: T) -> TxOpResult<()> {
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
@ -342,8 +335,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<Option<Value>>; fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()>;
fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>>; fn remove(&self, tree: usize, key: &[u8]) -> Result<()>;
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<'_>>;
@ -369,8 +362,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<Option<Value>>; fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> TxOpResult<()>;
fn remove(&mut self, tree: usize, key: &[u8]) -> TxOpResult<Option<Value>>; fn remove(&mut self, tree: usize, key: &[u8]) -> TxOpResult<()>;
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<'_>>;

View file

@ -39,15 +39,12 @@ pub struct LmdbDb {
} }
impl LmdbDb { impl LmdbDb {
pub fn to_wrap(db: Env) -> Self { pub fn init(db: Env) -> Db {
Self { let s = Self {
db, db,
trees: RwLock::new((Vec::new(), HashMap::new())), trees: RwLock::new((Vec::new(), HashMap::new())),
} };
} Db(Arc::new(s))
pub fn init(db: Env) -> Db {
Db(Arc::new(Self::to_wrap(db)))
} }
fn get_tree(&self, i: usize) -> Result<Database> { fn get_tree(&self, i: usize) -> Result<Database> {
@ -135,22 +132,20 @@ 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<Option<Value>> { fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> {
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(old_val) Ok(())
} }
fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>> { fn remove(&self, tree: usize, key: &[u8]) -> Result<()> {
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(old_val) Ok(())
} }
fn clear(&self, tree: usize) -> Result<()> { fn clear(&self, tree: usize) -> Result<()> {
@ -229,7 +224,7 @@ impl IDb for LmdbDb {
// ---- // ----
pub(crate) struct LmdbTx<'a> { struct LmdbTx<'a> {
trees: &'a [Database], trees: &'a [Database],
tx: RwTxn<'a, 'a>, tx: RwTxn<'a, 'a>,
} }
@ -257,17 +252,15 @@ 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<Option<Value>> { fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> TxOpResult<()> {
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(old_val) Ok(())
} }
fn remove(&mut self, tree: usize, key: &[u8]) -> TxOpResult<Option<Value>> { fn remove(&mut self, tree: usize, key: &[u8]) -> TxOpResult<()> {
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(old_val) Ok(())
} }
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)?;

View file

@ -1,217 +0,0 @@
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Instant;
use crate::lmdb_adapter::LmdbDb;
use crate::{
Bound, Db, IDb, ITx, ITxFn, OnCommit, Result, TxFnResult, TxOpResult, TxResult, TxValueIter,
Value, ValueIter,
};
use opentelemetry::{
global,
metrics::{Unit, ValueRecorder},
KeyValue,
};
pub struct MetricDbProxy {
//@FIXME Replace with a template
db: LmdbDb,
op: ValueRecorder<f64>,
}
impl MetricDbProxy {
pub fn init(db: LmdbDb) -> Db {
let meter = global::meter("garage/db");
let s = Self {
db,
op: meter
.f64_value_recorder("db.op")
.with_description("Duration and amount of operations on the local metadata engine")
.with_unit(Unit::new("ms"))
.init(),
};
Db(Arc::new(s))
}
fn instrument<T>(
&self,
fx: impl FnOnce() -> T,
op: &'static str,
cat: &'static str,
tx: &'static str,
) -> T {
let metric_tags = [
KeyValue::new("op", op),
KeyValue::new("cat", cat),
KeyValue::new("tx", tx),
];
let request_start = Instant::now();
let res = fx();
let delay_nanos = Instant::now()
.saturating_duration_since(request_start)
.as_nanos();
let delay_millis: f64 = delay_nanos as f64 / 1_000_000f64;
self.op.record(delay_millis, &metric_tags);
res
}
}
impl IDb for MetricDbProxy {
fn engine(&self) -> String {
format!("Metric Proxy on {}", self.db.engine())
}
fn open_tree(&self, name: &str) -> Result<usize> {
self.instrument(|| self.db.open_tree(name), "open_tree", "control", "no")
}
fn list_trees(&self) -> Result<Vec<String>> {
self.instrument(|| self.db.list_trees(), "list_trees", "control", "no")
}
fn snapshot(&self, to: &PathBuf) -> Result<()> {
self.instrument(|| self.db.snapshot(to), "snapshot", "control", "no")
}
// ---
fn get(&self, tree: usize, key: &[u8]) -> Result<Option<Value>> {
self.instrument(|| self.db.get(tree, key), "get", "data", "no")
}
fn len(&self, tree: usize) -> Result<usize> {
self.instrument(|| self.db.len(tree), "len", "data", "no")
}
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>> {
self.instrument(|| self.db.insert(tree, key, value), "insert", "data", "no")
}
fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>> {
self.instrument(|| self.db.remove(tree, key), "remove", "data", "no")
}
fn clear(&self, tree: usize) -> Result<()> {
self.instrument(|| self.db.clear(tree), "clear", "data", "no")
}
fn iter(&self, tree: usize) -> Result<ValueIter<'_>> {
self.instrument(|| self.db.iter(tree), "iter", "data", "no")
}
fn iter_rev(&self, tree: usize) -> Result<ValueIter<'_>> {
self.instrument(|| self.db.iter_rev(tree), "iter_rev", "data", "no")
}
fn range<'r>(
&self,
tree: usize,
low: Bound<&'r [u8]>,
high: Bound<&'r [u8]>,
) -> Result<ValueIter<'_>> {
self.instrument(|| self.db.range(tree, low, high), "range", "data", "no")
}
fn range_rev<'r>(
&self,
tree: usize,
low: Bound<&'r [u8]>,
high: Bound<&'r [u8]>,
) -> Result<ValueIter<'_>> {
self.instrument(
|| self.db.range_rev(tree, low, high),
"range_rev",
"data",
"no",
)
}
// ----
fn transaction(&self, f: &dyn ITxFn) -> TxResult<OnCommit, ()> {
self.instrument(
|| self.db.transaction(&MetricITxFnProxy { f, metrics: self }),
"transaction",
"control",
"yes",
)
}
}
struct MetricITxFnProxy<'a> {
f: &'a dyn ITxFn,
metrics: &'a MetricDbProxy,
}
impl<'a> ITxFn for MetricITxFnProxy<'a> {
fn try_on(&self, tx: &mut dyn ITx) -> TxFnResult {
self.f.try_on(&mut MetricTxProxy {
tx,
metrics: self.metrics,
})
}
}
struct MetricTxProxy<'a> {
tx: &'a mut dyn ITx,
metrics: &'a MetricDbProxy,
}
impl<'a> ITx for MetricTxProxy<'a> {
fn get(&self, tree: usize, key: &[u8]) -> TxOpResult<Option<Value>> {
self.metrics
.instrument(|| self.tx.get(tree, key), "get", "data", "yes")
}
fn len(&self, tree: usize) -> TxOpResult<usize> {
self.metrics
.instrument(|| self.tx.len(tree), "len", "data", "yes")
}
fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> TxOpResult<Option<Value>> {
self.metrics
.instrument(|| self.tx.insert(tree, key, value), "insert", "data", "yes")
}
fn remove(&mut self, tree: usize, key: &[u8]) -> TxOpResult<Option<Value>> {
self.metrics
.instrument(|| self.tx.remove(tree, key), "remove", "data", "yes")
}
fn clear(&mut self, tree: usize) -> TxOpResult<()> {
self.metrics
.instrument(|| self.tx.clear(tree), "clear", "data", "yes")
}
fn iter(&self, tree: usize) -> TxOpResult<TxValueIter<'_>> {
self.metrics
.instrument(|| self.tx.iter(tree), "iter", "data", "yes")
}
fn iter_rev(&self, tree: usize) -> TxOpResult<TxValueIter<'_>> {
self.metrics
.instrument(|| self.tx.iter_rev(tree), "iter_rev", "data", "yes")
}
fn range<'r>(
&self,
tree: usize,
low: Bound<&'r [u8]>,
high: Bound<&'r [u8]>,
) -> TxOpResult<TxValueIter<'_>> {
self.metrics
.instrument(|| self.tx.range(tree, low, high), "range", "data", "yes")
}
fn range_rev<'r>(
&self,
tree: usize,
low: Bound<&'r [u8]>,
high: Bound<&'r [u8]>,
) -> TxOpResult<TxValueIter<'_>> {
self.metrics.instrument(
|| self.tx.range_rev(tree, low, high),
"range_rev",
"data",
"yes",
)
}
}

View file

@ -10,7 +10,6 @@ use crate::{Db, Error, Result};
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Engine { pub enum Engine {
Lmdb, Lmdb,
LmdbWithMetrics,
Sqlite, Sqlite,
} }
@ -19,7 +18,6 @@ impl Engine {
pub fn as_str(&self) -> &'static str { pub fn as_str(&self) -> &'static str {
match self { match self {
Self::Lmdb => "lmdb", Self::Lmdb => "lmdb",
Self::LmdbWithMetrics => "lmdb-with-metrics",
Self::Sqlite => "sqlite", Self::Sqlite => "sqlite",
} }
} }
@ -37,7 +35,6 @@ impl std::str::FromStr for Engine {
fn from_str(text: &str) -> Result<Engine> { fn from_str(text: &str) -> Result<Engine> {
match text { match text {
"lmdb" | "heed" => Ok(Self::Lmdb), "lmdb" | "heed" => Ok(Self::Lmdb),
"lmdb-with-metrics" | "heed-with-metrics" => Ok(Self::LmdbWithMetrics),
"sqlite" | "sqlite3" | "rusqlite" => Ok(Self::Sqlite), "sqlite" | "sqlite3" | "rusqlite" => Ok(Self::Sqlite),
"sled" => Err(Error("Sled is no longer supported as a database engine. Converting your old metadata db can be done using an older Garage binary (e.g. v0.9.4).".into())), "sled" => Err(Error("Sled is no longer supported as a database engine. Converting your old metadata db can be done using an older Garage binary (e.g. v0.9.4).".into())),
kind => Err(Error( kind => Err(Error(
@ -77,7 +74,7 @@ pub fn open_db(path: &PathBuf, engine: Engine, opt: &OpenOpt) -> Result<Db> {
// ---- LMDB DB ---- // ---- LMDB DB ----
#[cfg(feature = "lmdb")] #[cfg(feature = "lmdb")]
Engine::Lmdb | Engine::LmdbWithMetrics => { Engine::Lmdb => {
info!("Opening LMDB database at: {}", path.display()); info!("Opening LMDB database at: {}", path.display());
if let Err(e) = std::fs::create_dir_all(&path) { if let Err(e) = std::fs::create_dir_all(&path) {
return Err(Error( return Err(Error(
@ -113,13 +110,7 @@ pub fn open_db(path: &PathBuf, engine: Engine, opt: &OpenOpt) -> Result<Db> {
)) ))
} }
Err(e) => Err(Error(format!("Cannot open LMDB database: {}", e).into())), Err(e) => Err(Error(format!("Cannot open LMDB database: {}", e).into())),
Ok(db) => match engine { Ok(db) => Ok(crate::lmdb_adapter::LmdbDb::init(db)),
Engine::LmdbWithMetrics => {
let to_wrap = crate::lmdb_adapter::LmdbDb::to_wrap(db);
Ok(crate::metric_proxy::MetricDbProxy::init(to_wrap))
}
_ => Ok(crate::lmdb_adapter::LmdbDb::init(db)),
},
} }
} }

View file

@ -169,7 +169,7 @@ impl IDb for SqliteDb {
} }
} }
fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<Option<Value>> { fn insert(&self, tree: usize, key: &[u8], value: &[u8]) -> Result<()> {
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,23 +184,18 @@ impl IDb for SqliteDb {
assert_eq!(n, 1); assert_eq!(n, 1);
drop(lock); drop(lock);
Ok(old_val) Ok(())
} }
fn remove(&self, tree: usize, key: &[u8]) -> Result<Option<Value>> { fn remove(&self, tree: usize, key: &[u8]) -> Result<()> {
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();
let old_val = self.internal_get(&db, &tree, key)?; db.execute(&format!("DELETE FROM {} WHERE k = ?1", tree), params![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(old_val) Ok(())
} }
fn clear(&self, tree: usize) -> Result<()> { fn clear(&self, tree: usize) -> Result<()> {
@ -341,31 +336,17 @@ impl<'a> ITx for SqliteTx<'a> {
} }
} }
fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> TxOpResult<Option<Value>> { fn insert(&mut self, tree: usize, key: &[u8], value: &[u8]) -> TxOpResult<()> {
let tree = self.get_tree(tree)?; let tree = self.get_tree(tree)?;
let old_val = self.internal_get(tree, key)?; let sql = format!("INSERT OR REPLACE INTO {} (k, v) VALUES (?1, ?2)", tree);
self.tx.execute(&sql, params![key, value])?;
let sql = match &old_val { Ok(())
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<Option<Value>> { fn remove(&mut self, tree: usize, key: &[u8]) -> TxOpResult<()> {
let tree = self.get_tree(tree)?; let tree = self.get_tree(tree)?;
let old_val = self.internal_get(tree, key)?; self.tx
.execute(&format!("DELETE FROM {} WHERE k = ?1", tree), params![key])?;
if old_val.is_some() { Ok(())
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)?;

View file

@ -12,7 +12,7 @@ fn test_suite(db: Db) {
// ---- test simple insert/delete ---- // ---- test simple insert/delete ----
assert!(tree.insert(ka, va).unwrap().is_none()); assert!(tree.insert(ka, va).is_ok());
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().unwrap(), va); assert_eq!(tx.insert(&tree, ka, vb).unwrap(), ());
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().unwrap(), vb); assert_eq!(tx.insert(&tree, ka, vc).unwrap(), ());
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).unwrap().is_none()); assert!(tree.insert(kb, vc).is_ok());
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();

View file

@ -1,6 +1,6 @@
[package] [package]
name = "garage" name = "garage"
version = "1.0.0" version = "1.0.1"
authors = ["Alex Auvolat <alex@adnab.me>"] authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018" edition = "2018"
license = "AGPL-3.0" license = "AGPL-3.0"

View file

@ -24,6 +24,7 @@ pub struct ConvertDbOpt {
output_engine: Engine, output_engine: Engine,
#[structopt(flatten)] #[structopt(flatten)]
#[allow(dead_code)]
db_open: OpenDbOpt, db_open: OpenDbOpt,
} }
@ -52,6 +53,7 @@ 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()
}; };

View file

@ -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 version, and data is being migrated."); println!("Several layout versions are currently live in the cluster, 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,15 +377,27 @@ 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.");
println!( if min_ack < layout.current().version {
"You may force progress using `garage layout skip-dead-nodes --version {}`", println!(
layout.current().version "You may force progress using `garage layout skip-dead-nodes --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,");
@ -426,15 +438,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() {
if status.iter().any(|x| x.id == *node && x.is_up) { // Update ACK tracker for dead nodes or for all nodes if --allow-missing-data
continue; if opt.allow_missing_data || !status.iter().any(|x| x.id == *node && x.is_up) {
} if layout.update_trackers.ack_map.set_max(*node, opt.version) {
println!("Increased the ACK tracker for node {:?}", node);
if layout.update_trackers.ack_map.set_max(*node, opt.version) { did_something = true;
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);

View file

@ -1,6 +1,6 @@
[package] [package]
name = "garage_model" name = "garage_model"
version = "1.0.0" version = "1.0.1"
authors = ["Alex Auvolat <alex@adnab.me>"] authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018" edition = "2018"
license = "AGPL-3.0" license = "AGPL-3.0"

View file

@ -121,7 +121,7 @@ impl Garage {
db::Engine::Sqlite => { db::Engine::Sqlite => {
db_path.push("db.sqlite"); db_path.push("db.sqlite");
} }
db::Engine::Lmdb | db::Engine::LmdbWithMetrics => { db::Engine::Lmdb => {
db_path.push("db.lmdb"); db_path.push("db.lmdb");
} }
} }
@ -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 bits of entropy, please check the documentation for requirements")?; .ok_or_message("Invalid RPC secret key: expected 32 bytes of random hex, please check the documentation for requirements")?;
let (replication_factor, consistency_mode) = parse_replication_mode(&config)?; let (replication_factor, consistency_mode) = parse_replication_mode(&config)?;

View file

@ -1,6 +1,6 @@
[package] [package]
name = "garage_net" name = "garage_net"
version = "1.0.0" version = "1.0.1"
authors = ["Alex Auvolat <alex@adnab.me>"] authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018" edition = "2018"
license = "AGPL-3.0" license = "AGPL-3.0"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "garage_rpc" name = "garage_rpc"
version = "1.0.0" version = "1.0.1"
authors = ["Alex Auvolat <alex@adnab.me>"] authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018" edition = "2018"
license = "AGPL-3.0" license = "AGPL-3.0"

View file

@ -227,24 +227,29 @@ 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 let Some(v1) = self.versions.iter().find(|v| v.version == v2.version) { if v2.version == self.current().version + 1 {
// 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 {
self.versions.push(v2.clone()); // This is an older version
changed = true; assert!(v2.version < self.min_stored());
} }
} }

View file

@ -455,7 +455,7 @@ impl UpdateTracker {
} }
} }
pub(crate) fn min_among(&self, storage_nodes: &[Uuid], min_version: u64) -> u64 { pub 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))

View file

@ -1,6 +1,6 @@
[package] [package]
name = "garage_table" name = "garage_table"
version = "1.0.0" version = "1.0.1"
authors = ["Alex Auvolat <alex@adnab.me>"] authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018" edition = "2018"
license = "AGPL-3.0" license = "AGPL-3.0"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "garage_util" name = "garage_util"
version = "1.0.0" version = "1.0.1"
authors = ["Alex Auvolat <alex@adnab.me>"] authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018" edition = "2018"
license = "AGPL-3.0" license = "AGPL-3.0"

View file

@ -1,13 +1,11 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use std::time::Instant;
use async_trait::async_trait; use async_trait::async_trait;
use futures::future::*; use futures::future::*;
use futures::stream::FuturesUnordered; use futures::stream::FuturesUnordered;
use futures::StreamExt; use futures::StreamExt;
use opentelemetry::{global, metrics::ValueRecorder, KeyValue};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::select; use tokio::select;
use tokio::sync::{mpsc, watch}; use tokio::sync::{mpsc, watch};
@ -64,7 +62,6 @@ pub(crate) struct WorkerProcessor {
stop_signal: watch::Receiver<bool>, stop_signal: watch::Receiver<bool>,
worker_chan: mpsc::UnboundedReceiver<Box<dyn Worker>>, worker_chan: mpsc::UnboundedReceiver<Box<dyn Worker>>,
worker_info: Arc<std::sync::Mutex<HashMap<usize, WorkerInfo>>>, worker_info: Arc<std::sync::Mutex<HashMap<usize, WorkerInfo>>>,
metrics: ValueRecorder<f64>,
} }
impl WorkerProcessor { impl WorkerProcessor {
@ -73,15 +70,10 @@ impl WorkerProcessor {
stop_signal: watch::Receiver<bool>, stop_signal: watch::Receiver<bool>,
worker_info: Arc<std::sync::Mutex<HashMap<usize, WorkerInfo>>>, worker_info: Arc<std::sync::Mutex<HashMap<usize, WorkerInfo>>>,
) -> Self { ) -> Self {
let meter = global::meter("garage/util");
Self { Self {
stop_signal, stop_signal,
worker_chan, worker_chan,
worker_info, worker_info,
metrics: meter
.f64_value_recorder("util.worker_step")
.with_description("Duration and amount of worker steps executed")
.init(),
} }
} }
@ -111,7 +103,6 @@ impl WorkerProcessor {
errors: 0, errors: 0,
consecutive_errors: 0, consecutive_errors: 0,
last_error: None, last_error: None,
metrics: self.metrics.clone(),
}; };
workers.push(async move { workers.push(async move {
worker.step().await; worker.step().await;
@ -192,13 +183,10 @@ struct WorkerHandler {
errors: usize, errors: usize,
consecutive_errors: usize, consecutive_errors: usize,
last_error: Option<(String, u64)>, last_error: Option<(String, u64)>,
metrics: ValueRecorder<f64>,
} }
impl WorkerHandler { impl WorkerHandler {
async fn step(&mut self) { async fn step(&mut self) {
let request_start = Instant::now();
//@FIXME we also want to track errors in metrics but I don't know how yet.
match self.state { match self.state {
WorkerState::Busy => match self.worker.work(&mut self.stop_signal).await { WorkerState::Busy => match self.worker.work(&mut self.stop_signal).await {
Ok(s) => { Ok(s) => {
@ -241,17 +229,5 @@ impl WorkerHandler {
} }
WorkerState::Done => unreachable!(), WorkerState::Done => unreachable!(),
} }
// metrics
let metric_tags = [
KeyValue::new("state", self.state.to_string()),
KeyValue::new("name", self.worker.name()),
KeyValue::new("id", format!("{}", self.task_id)),
];
let delay_secs = Instant::now()
.saturating_duration_since(request_start)
.as_secs_f64();
self.metrics.record(delay_secs, &metric_tags);
} }
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "garage_web" name = "garage_web"
version = "1.0.0" version = "1.0.1"
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"