Compare commits

..

1 Commits

Author SHA1 Message Date
Quentin Dufour a259f820a4 wip apple+windows 2023-04-10 16:36:38 +02:00
50 changed files with 1061 additions and 1514 deletions
Generated
+199 -333
View File
File diff suppressed because it is too large Load Diff
+640 -837
View File
File diff suppressed because it is too large Load Diff
-12
View File
@@ -11,22 +11,10 @@ members = [
"src/web", "src/web",
"src/garage", "src/garage",
"src/k2v-client", "src/k2v-client",
"src/format-table",
] ]
default-members = ["src/garage"] default-members = ["src/garage"]
[workspace.dependencies]
format_table = { version = "0.1.0", path = "src/format-table" }
garage_api = { version = "0.8.2", path = "src/api" }
garage_block = { version = "0.8.2", path = "src/block" }
garage_db = { version = "0.8.2", path = "src/db", default-features = false }
garage_model = { version = "0.8.2", path = "src/model", default-features = false }
garage_rpc = { version = "0.8.2", path = "src/rpc" }
garage_table = { version = "0.8.2", path = "src/table" }
garage_util = { version = "0.8.2", path = "src/util" }
garage_web = { version = "0.8.2", path = "src/web" }
[profile.dev] [profile.dev]
lto = "off" lto = "off"
+7
View File
@@ -32,6 +32,13 @@ in {
i386 = build_debug_and_release "i686-unknown-linux-musl"; i386 = build_debug_and_release "i686-unknown-linux-musl";
arm64 = build_debug_and_release "aarch64-unknown-linux-musl"; arm64 = build_debug_and_release "aarch64-unknown-linux-musl";
arm = build_debug_and_release "armv6l-unknown-linux-musleabihf"; arm = build_debug_and_release "armv6l-unknown-linux-musleabihf";
win = {
amd64 = build_debug_and_release "x86_64-w64-mingw32";
};
apple = {
arm64 = build_debug_and_release "aarch64-apple-darwin";
amd64 = build_debug_and_release "x86_64-apple-darwin";
};
}; };
test = { test = {
amd64 = test (compile { amd64 = test (compile {
+49 -4
View File
@@ -202,11 +202,56 @@ See its usage output for other commands available.
## Cyberduck & duck {#cyberduck} ## Cyberduck & duck {#cyberduck}
Both Cyberduck (the GUI) and duck (the CLI) have a concept of "Connection Profiles" that contain some presets for a specific provider. Both Cyberduck (the GUI) and duck (the CLI) have a concept of "Connection Profiles" that contain some presets for a specific provider.
We wrote the following connection profile for Garage:
Within Cyberduck, a ```xml
[Garage connection profile](https://docs.cyberduck.io/protocols/s3/garage/) is <?xml version="1.0" encoding="UTF-8"?>
available within the `Preferences -> Profiles` section. This can enabled and <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
then connections to Garage may be configured. <plist version="1.0">
<dict>
<key>Protocol</key>
<string>s3</string>
<key>Vendor</key>
<string>garage</string>
<key>Scheme</key>
<string>https</string>
<key>Description</key>
<string>GarageS3</string>
<key>Default Hostname</key>
<string>127.0.0.1</string>
<key>Default Port</key>
<string>4443</string>
<key>Hostname Configurable</key>
<false/>
<key>Port Configurable</key>
<false/>
<key>Username Configurable</key>
<true/>
<key>Username Placeholder</key>
<string>Access Key ID (GK...)</string>
<key>Password Placeholder</key>
<string>Secret Key</string>
<key>Properties</key>
<array>
<string>s3service.disable-dns-buckets=true</string>
</array>
<key>Region</key>
<string>garage</string>
<key>Regions</key>
<array>
<string>garage</string>
</array>
</dict>
</plist>
```
*Note: If your garage instance is configured with vhost access style, you can remove `s3service.disable-dns-buckets=true`.*
### Instructions for the GUI
Copy the connection profile, and save it anywhere as `garage.cyberduckprofile`.
Then find this file with your file explorer and double click on it: Cyberduck will open a connection wizard for this profile.
Simply follow the wizard and you should be done!
### Instuctions for the CLI ### Instuctions for the CLI
+1 -1
View File
@@ -349,5 +349,5 @@ and is covered in the [quick start guide](@/documentation/quick-start/_index.md)
Remember also that the CLI is self-documented thanks to the `--help` flag and Remember also that the CLI is self-documented thanks to the `--help` flag and
the `help` subcommand (e.g. `garage help`, `garage key --help`). the `help` subcommand (e.g. `garage help`, `garage key --help`).
Configuring S3-compatible applications to interact with Garage Configuring S3-compatible applicatiosn to interact with Garage
is covered in the [Integrations](@/documentation/connect/_index.md) section. is covered in the [Integrations](@/documentation/connect/_index.md) section.
+3 -3
View File
@@ -290,13 +290,13 @@ sourcing the right file.*
aws s3 ls aws s3 ls
# list objects of a bucket # list objects of a bucket
aws s3 ls s3://nextcloud-bucket aws s3 ls s3://my_files
# copy from your filesystem to garage # copy from your filesystem to garage
aws s3 cp /proc/cpuinfo s3://nextcloud-bucket/cpuinfo.txt aws s3 cp /proc/cpuinfo s3://my_files/cpuinfo.txt
# copy from garage to your filesystem # copy from garage to your filesystem
aws s3 cp s3://nextcloud-bucket/cpuinfo.txt /tmp/cpuinfo.txt aws s3 cp s3/my_files/cpuinfo.txt /tmp/cpuinfo.txt
``` ```
Note that you can use `awscli` for more advanced operations like Note that you can use `awscli` for more advanced operations like
Generated
+23 -76
View File
@@ -41,15 +41,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" "type": "github"
}, },
"original": { "original": {
@@ -59,15 +56,12 @@
} }
}, },
"flake-utils_2": { "flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": { "locked": {
"lastModified": 1681202837, "lastModified": 1667395993,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401", "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -78,61 +72,44 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1682109806, "lastModified": 1665657542,
"narHash": "sha256-d9g7RKNShMLboTWwukM+RObDWWpHKaqTYXB48clBWXI=", "narHash": "sha256-mojxNyzbvmp8NtVtxqiHGhRfjCALLfk9i/Uup68Y5q8=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "2362848adf8def2866fabbffc50462e929d7fffb", "rev": "a3073c49bc0163fea6a121c276f526837672b555",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1682423271,
"narHash": "sha256-WHhl1GiOij1ob4cTLL+yhqr+vFOUH8E5wAX8Ir8fvjE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "94517a501434a627c5d9e72ac6e7f26174b978d3",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "94517a501434a627c5d9e72ac6e7f26174b978d3", "rev": "a3073c49bc0163fea6a121c276f526837672b555",
"type": "github" "type": "github"
} }
}, },
"root": { "root": {
"inputs": { "inputs": {
"cargo2nix": "cargo2nix", "cargo2nix": "cargo2nix",
"flake-compat": [ "flake-utils": "flake-utils_2",
"cargo2nix", "nixpkgs": "nixpkgs"
"flake-compat"
],
"flake-utils": [
"cargo2nix",
"flake-utils"
],
"nixpkgs": "nixpkgs_2"
} }
}, },
"rust-overlay": { "rust-overlay": {
"inputs": { "inputs": {
"flake-utils": "flake-utils_2", "flake-utils": [
"nixpkgs": "nixpkgs" "cargo2nix",
"flake-utils"
],
"nixpkgs": [
"cargo2nix",
"nixpkgs"
]
}, },
"locked": { "locked": {
"lastModified": 1682389182, "lastModified": 1664247556,
"narHash": "sha256-8t2nmFnH+8V48+IJsf8AK51ebXNlVbOSVYOpiqJKvJE=", "narHash": "sha256-J4vazHU3609ekn7dr+3wfqPo5WGlZVAgV7jfux352L0=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "74f1a64dd28faeeb85ef081f32cad2989850322c", "rev": "524db9c9ea7bc7743bb74cdd45b6d46ea3fcc2ab",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -140,36 +117,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",
+3 -17
View File
@@ -2,30 +2,16 @@
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 unstable as of 2023-04-25, has rustc v1.68
inputs.nixpkgs.url = inputs.nixpkgs.url =
"github:NixOS/nixpkgs/94517a501434a627c5d9e72ac6e7f26174b978d3"; "github:NixOS/nixpkgs/a3073c49bc0163fea6a121c276f526837672b555";
inputs.cargo2nix = { inputs.cargo2nix = {
# As of 2022-10-18: two small patches over unstable branch, one for clippy and one to fix feature detection # As of 2022-10-18: two small patches over unstable branch, one for clippy and one to fix feature detection
url = "github:Alexis211/cargo2nix/a7a61179b66054904ef6a195d8da736eaaa06c36"; url = "github:Alexis211/cargo2nix/a7a61179b66054904ef6a195d8da736eaaa06c36";
# As of 2023-04-25:
# - my two patches were merged into unstable (one for clippy and one to "fix" feature detection)
# - rustc v1.66
# url = "github:cargo2nix/cargo2nix/8fb57a670f7993bfc24099c33eb9c5abb51f29a2";
# Rust overlay as of 2023-04-25
inputs.rust-overlay.url =
"github:oxalica/rust-overlay/74f1a64dd28faeeb85ef081f32cad2989850322c";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
inputs.flake-utils.url = "github:numtide/flake-utils";
inputs.flake-utils.follows = "cargo2nix/flake-utils"; outputs = { self, nixpkgs, cargo2nix, flake-utils }:
inputs.flake-compat.follows = "cargo2nix/flake-compat";
outputs = { self, nixpkgs, cargo2nix, flake-utils, ... }:
let let
git_version = self.lastModifiedDate; git_version = self.lastModifiedDate;
compile = import ./nix/compile.nix; compile = import ./nix/compile.nix;
+15 -10
View File
@@ -1,14 +1,19 @@
let rec {
lock = builtins.fromJSON (builtins.readFile ../flake.lock); # * Fixed dependencies
flakeCompatRev = lock.nodes.flake-compat.locked.rev; pkgsSrc = fetchTarball {
flakeCompat = fetchTarball { # As of 2022-10-13
url = url =
"https://github.com/edolstra/flake-compat/archive/${flakeCompatRev}.tar.gz"; "https://github.com/NixOS/nixpkgs/archive/a3073c49bc0163fea6a121c276f526837672b555.zip";
sha256 = lock.nodes.flake-compat.locked.narHash; sha256 = "1bz632psfbpmicyzjb8b4265y50shylccvfm6ry6mgnv5hvz324s";
}; };
flake = ((import flakeCompat) { src = ../.; }).defaultNix; cargo2nixSrc = fetchGit {
in rec { # As of 2022-10-18: two small patches over unstable branch, one for clippy and one to fix feature detection
pkgsSrc = flake.inputs.nixpkgs; url = "https://github.com/Alexis211/cargo2nix";
cargo2nix = flake.inputs.cargo2nix; ref = "custom_unstable";
rev = "a7a61179b66054904ef6a195d8da736eaaa06c36";
};
# * Shared objects
cargo2nix = import cargo2nixSrc;
cargo2nixOverlay = cargo2nix.overlays.default; cargo2nixOverlay = cargo2nix.overlays.default;
} }
+1 -1
View File
@@ -32,7 +32,7 @@ let
*/ */
toolchainOptions = if target == null || target == "x86_64-unknown-linux-musl" toolchainOptions = if target == null || target == "x86_64-unknown-linux-musl"
|| target == "aarch64-unknown-linux-musl" then { || target == "aarch64-unknown-linux-musl" then {
rustVersion = "1.68.0"; rustVersion = "1.63.0";
extraRustComponents = [ "clippy" ]; extraRustComponents = [ "clippy" ];
} else { } else {
rustToolchain = pkgs.symlinkJoin { rustToolchain = pkgs.symlinkJoin {
+2 -2
View File
@@ -1,13 +1,13 @@
pkgs: pkgs:
pkgs.buildGoModule rec { pkgs.buildGoModule rec {
pname = "kaniko"; pname = "kaniko";
version = "1.9.2"; version = "1.6.0";
src = pkgs.fetchFromGitHub { src = pkgs.fetchFromGitHub {
owner = "GoogleContainerTools"; owner = "GoogleContainerTools";
repo = "kaniko"; repo = "kaniko";
rev = "v${version}"; rev = "v${version}";
sha256 = "dXQ0/o1qISv+sjNVIpfF85bkbM9sGOGwqVbWZpMWfMY="; sha256 = "1fnclr556avxay6pvgw5ya3xbxfnf2gv4njq2hr4fd6fcjyslq5h";
}; };
vendorSha256 = null; vendorSha256 = null;
+2 -2
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.4.1 version: 0.3.0
# This is the version number of the application being deployed. This version number should be # This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to # incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using. # follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes. # It is recommended to use it with quotes.
appVersion: "v0.8.2" appVersion: "v0.7.2.1"
+3 -33
View File
@@ -4,28 +4,9 @@
# Garage configuration. These values go to garage.toml # Garage configuration. These values go to garage.toml
garage: garage:
# Can be changed for better performance on certain systems
# https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#db-engine-since-v0-8-0
dbEngine: "sled"
# Defaults is 1MB
# An increase can result in better performance in certain scenarios
# https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#block-size
blockSize: "1048576"
# Tuning parameters for the sled DB engine
# https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#sled-cache-capacity
sledCacheCapacity: "134217728"
sledFlushEveryMs: "2000"
# Default to 3 replicas, see the replication_mode section at # Default to 3 replicas, see the replication_mode section at
# https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#replication-mode # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/
replicationMode: "3" replicationMode: "3"
# zstd compression level of stored blocks
# https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#compression-level
compressionLevel: "1"
rpcBindAddr: "[::]:3901" rpcBindAddr: "[::]:3901"
# If not given, a random secret will be generated and stored in a Secret object # If not given, a random secret will be generated and stored in a Secret object
rpcSecret: "" rpcSecret: ""
@@ -46,19 +27,8 @@ garage:
metadata_dir = "/mnt/meta" metadata_dir = "/mnt/meta"
data_dir = "/mnt/data" data_dir = "/mnt/data"
db_engine = "{{ .Values.garage.dbEngine }}"
block_size = {{ .Values.garage.blockSize }}
{{- if eq .Values.garage.dbEngine "sled"}}
sled_cache_capacity = {{ .Values.garage.sledCacheCapacity }}
sled_flush_every_ms = {{ .Values.garage.sledFlushEveryMs }}
{{- end }}
replication_mode = "{{ .Values.garage.replicationMode }}" replication_mode = "{{ .Values.garage.replicationMode }}"
compression_level = {{ .Values.garage.compressionLevel }}
rpc_bind_addr = "{{ .Values.garage.rpcBindAddr }}" rpc_bind_addr = "{{ .Values.garage.rpcBindAddr }}"
# rpc_secret will be populated by the init container from a k8s secret object # rpc_secret will be populated by the init container from a k8s secret object
rpc_secret = "__RPC_SECRET_REPLACE__" rpc_secret = "__RPC_SECRET_REPLACE__"
@@ -79,7 +49,7 @@ garage:
bind_addr = "[::]:3902" bind_addr = "[::]:3902"
root_domain = "{{ .Values.garage.s3.web.rootDomain }}" root_domain = "{{ .Values.garage.s3.web.rootDomain }}"
index = "{{ .Values.garage.s3.web.index }}" index = "{{ .Values.garage.s3.web.index }}"
[admin] [admin]
api_bind_addr = "[::]:3903" api_bind_addr = "[::]:3903"
{{- if .Values.monitoring.tracing.sink }} {{- if .Values.monitoring.tracing.sink }}
@@ -241,4 +211,4 @@ monitoring:
scrapeTimeout: 10s scrapeTimeout: 10s
relabelings: [] relabelings: []
tracing: tracing:
sink: "" sink: ""
+6 -6
View File
@@ -14,11 +14,11 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
garage_model.workspace = true garage_model = { version = "0.8.2", path = "../model" }
garage_table.workspace = true garage_table = { version = "0.8.2", path = "../table" }
garage_block.workspace = true garage_block = { version = "0.8.2", path = "../block" }
garage_util.workspace = true garage_util = { version = "0.8.2", path = "../util" }
garage_rpc.workspace = true garage_rpc = { version = "0.8.2", path = "../rpc" }
async-trait = "0.1.7" async-trait = "0.1.7"
base64 = "0.21" base64 = "0.21"
@@ -51,7 +51,7 @@ roxmltree = "0.14"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_bytes = "0.11" serde_bytes = "0.11"
serde_json = "1.0" serde_json = "1.0"
quick-xml = { version = "0.26", features = [ "serialize" ] } quick-xml = { version = "0.21", features = [ "serialize" ] }
url = "2.3" url = "2.3"
opentelemetry = "0.17" opentelemetry = "0.17"
+1 -1
View File
@@ -105,7 +105,7 @@ impl AdminApiServer {
let bucket_id = self let bucket_id = self
.garage .garage
.bucket_helper() .bucket_helper()
.resolve_global_bucket_name(domain) .resolve_global_bucket_name(&domain)
.await? .await?
.ok_or(HelperError::NoSuchBucket(domain.to_string()))?; .ok_or(HelperError::NoSuchBucket(domain.to_string()))?;
+2 -2
View File
@@ -183,8 +183,8 @@ async fn bucket_info_results(
} }
}), }),
keys: relevant_keys keys: relevant_keys
.into_values() .into_iter()
.map(|key| { .map(|(_, key)| {
let p = key.state.as_option().unwrap(); let p = key.state.as_option().unwrap();
GetBucketInfoKey { GetBucketInfoKey {
access_key_id: key.key_id, access_key_id: key.key_id,
+2 -2
View File
@@ -183,8 +183,8 @@ async fn key_info_results(garage: &Arc<Garage>, key: Key) -> Result<Response<Bod
create_bucket: *key_state.allow_create_bucket.get(), create_bucket: *key_state.allow_create_bucket.get(),
}, },
buckets: relevant_buckets buckets: relevant_buckets
.into_values() .into_iter()
.map(|bucket| { .map(|(_, bucket)| {
let state = bucket.state.as_option().unwrap(); let state = bucket.state.as_option().unwrap();
KeyInfoBucketResult { KeyInfoBucketResult {
id: hex::encode(bucket.id), id: hex::encode(bucket.id),
+1 -1
View File
@@ -128,7 +128,7 @@ impl<A: ApiHandler> ApiServer<A> {
let uri = req.uri().clone(); let uri = req.uri().clone();
if let Ok(forwarded_for_ip_addr) = if let Ok(forwarded_for_ip_addr) =
forwarded_headers::handle_forwarded_for_headers(req.headers()) forwarded_headers::handle_forwarded_for_headers(&req.headers())
{ {
info!( info!(
"{} (via {}) {} {}", "{} (via {}) {} {}",
+2 -2
View File
@@ -282,8 +282,8 @@ pub(crate) async fn handle_poll_range(
if let Some((items, seen_marker)) = resp { if let Some((items, seen_marker)) = resp {
let resp = PollRangeResponse { let resp = PollRangeResponse {
items: items items: items
.into_values() .into_iter()
.map(ReadBatchResponseItem::from) .map(|(_k, i)| ReadBatchResponseItem::from(i))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
seen_marker, seen_marker,
}; };
+2 -2
View File
@@ -443,7 +443,7 @@ fn body_from_blocks_range(
// block.part_number, which is not the same in the case of a multipart upload) // block.part_number, which is not the same in the case of a multipart upload)
let mut blocks: Vec<(VersionBlock, u64)> = Vec::with_capacity(std::cmp::min( let mut blocks: Vec<(VersionBlock, u64)> = Vec::with_capacity(std::cmp::min(
all_blocks.len(), all_blocks.len(),
4 + ((end - begin) / std::cmp::max(all_blocks[0].1.size, 1024)) as usize, 4 + ((end - begin) / std::cmp::max(all_blocks[0].1.size as u64, 1024)) as usize,
)); ));
let mut block_offset: u64 = 0; let mut block_offset: u64 = 0;
for (_, b) in all_blocks.iter() { for (_, b) in all_blocks.iter() {
@@ -454,7 +454,7 @@ fn body_from_blocks_range(
if block_offset < end && block_offset + b.size > begin { if block_offset < end && block_offset + b.size > begin {
blocks.push((*b, block_offset)); blocks.push((*b, block_offset));
} }
block_offset += b.size; block_offset += b.size as u64;
} }
let order_stream = OrderTag::stream(); let order_stream = OrderTag::stream();
+5 -5
View File
@@ -14,10 +14,10 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
garage_db.workspace = true garage_db = { version = "0.8.2", path = "../db" }
garage_rpc.workspace = true garage_rpc = { version = "0.8.2", path = "../rpc" }
garage_util.workspace = true garage_util = { version = "0.8.2", path = "../util" }
garage_table.workspace = true garage_table = { version = "0.8.2", path = "../table" }
opentelemetry = "0.17" opentelemetry = "0.17"
@@ -37,7 +37,7 @@ serde_bytes = "0.11"
futures = "0.3" futures = "0.3"
futures-util = "0.3" futures-util = "0.3"
tokio = { version = "1.0", default-features = false, features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros", "sync", "signal", "fs"] } tokio = { version = "1.0", default-features = false, features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros", "sync", "signal", "fs"] }
tokio-util = { version = "0.7", features = ["io"] } tokio-util = { version = "0.6", features = ["io"] }
[features] [features]
system-libs = [ "zstd/pkg-config" ] system-libs = [ "zstd/pkg-config" ]
+5 -25
View File
@@ -600,32 +600,12 @@ impl BlockManager {
/// Utility: check if block is stored compressed. Error if block is not stored /// Utility: check if block is stored compressed. Error if block is not stored
async fn is_block_compressed(&self, hash: &Hash) -> Result<bool, Error> { async fn is_block_compressed(&self, hash: &Hash) -> Result<bool, Error> {
let mut path = self.block_path(hash); let mut path = self.block_path(hash);
path.set_extension("zst");
// If compression is disabled on node - check for the raw block if fs::metadata(&path).await.is_ok() {
// first and then a compressed one (as compression may have been return Ok(true);
// previously enabled).
match self.compression_level {
None => {
if fs::metadata(&path).await.is_ok() {
return Ok(false);
}
path.set_extension("zst");
fs::metadata(&path).await.map(|_| true).map_err(Into::into)
}
_ => {
path.set_extension("zst");
if fs::metadata(&path).await.is_ok() {
return Ok(true);
}
path.set_extension("");
fs::metadata(&path).await.map(|_| false).map_err(Into::into)
}
} }
path.set_extension("");
fs::metadata(&path).await.map(|_| false).map_err(Into::into)
} }
async fn lock_mutate(&self, hash: &Hash) -> MutexGuard<'_, BlockManagerLocked> { async fn lock_mutate(&self, hash: &Hash) -> MutexGuard<'_, BlockManagerLocked> {
+12 -16
View File
@@ -220,12 +220,14 @@ fn randomize_next_scrub_run_time(timestamp: u64) -> u64 {
// Take SCRUB_INTERVAL and mix in a random interval of 10 days to attempt to // Take SCRUB_INTERVAL and mix in a random interval of 10 days to attempt to
// balance scrub load across different cluster nodes. // balance scrub load across different cluster nodes.
timestamp let next_run_timestamp = timestamp
+ SCRUB_INTERVAL + SCRUB_INTERVAL
.saturating_add(Duration::from_secs( .saturating_add(Duration::from_secs(
rand::thread_rng().gen_range(0..3600 * 24 * 10), rand::thread_rng().gen_range(0..3600 * 24 * 10),
)) ))
.as_millis() as u64 .as_millis() as u64;
next_run_timestamp
} }
impl Default for ScrubWorkerPersisted { impl Default for ScrubWorkerPersisted {
@@ -239,14 +241,18 @@ impl Default for ScrubWorkerPersisted {
} }
} }
#[derive(Default)]
enum ScrubWorkerState { enum ScrubWorkerState {
Running(BlockStoreIterator), Running(BlockStoreIterator),
Paused(BlockStoreIterator, u64), // u64 = time when to resume scrub Paused(BlockStoreIterator, u64), // u64 = time when to resume scrub
#[default]
Finished, Finished,
} }
impl Default for ScrubWorkerState {
fn default() -> Self {
ScrubWorkerState::Finished
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum ScrubWorkerCommand { pub enum ScrubWorkerCommand {
Start, Start,
@@ -275,7 +281,6 @@ impl ScrubWorker {
ScrubWorkerCommand::Start => { ScrubWorkerCommand::Start => {
self.work = match std::mem::take(&mut self.work) { self.work = match std::mem::take(&mut self.work) {
ScrubWorkerState::Finished => { ScrubWorkerState::Finished => {
info!("Scrub worker initializing, now performing datastore scrub");
let iterator = BlockStoreIterator::new(&self.manager); let iterator = BlockStoreIterator::new(&self.manager);
ScrubWorkerState::Running(iterator) ScrubWorkerState::Running(iterator)
} }
@@ -389,21 +394,12 @@ impl Worker for ScrubWorker {
.tranquilizer .tranquilizer
.tranquilize_worker(self.persister.get_with(|p| p.tranquility))) .tranquilize_worker(self.persister.get_with(|p| p.tranquility)))
} else { } else {
let now = now_msec();
let next_scrub_timestamp = randomize_next_scrub_run_time(now);
self.persister.set_with(|p| { self.persister.set_with(|p| {
p.time_last_complete_scrub = now; p.time_last_complete_scrub = now_msec();
p.time_next_run_scrub = next_scrub_timestamp; p.time_next_run_scrub = randomize_next_scrub_run_time(now_msec());
})?; })?;
self.work = ScrubWorkerState::Finished; self.work = ScrubWorkerState::Finished;
self.tranquilizer.clear(); self.tranquilizer.clear();
info!(
"Datastore scrub completed, next scrub scheduled for {}",
msec_to_rfc3339(next_scrub_timestamp)
);
Ok(WorkerState::Idle) Ok(WorkerState::Idle)
} }
} }
+1 -1
View File
@@ -349,6 +349,6 @@ pub fn recommended_map_size() -> usize {
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
pub fn recommended_map_size() -> usize { pub fn recommended_map_size() -> usize {
tracing::warn!("LMDB is not recommended on 32-bit systems, database size will be limited"); warn!("LMDB is not recommended on 32-bit systems, database size will be limited");
1usize << 30 1usize << 30
} }
-12
View File
@@ -1,12 +0,0 @@
[package]
name = "format_table"
version = "0.1.0"
authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018"
license = "AGPL-3.0"
description = "Format tables with a stupid API"
repository = "https://git.deuxfleurs.fr/Deuxfleurs/garage"
readme = "README.md"
[lib]
path = "lib.rs"
-13
View File
@@ -1,13 +0,0 @@
# `format_table`
Format tables with a stupid API. [Documentation](https://docs.rs/format_table).
Example:
```rust
let mut table = vec!["product\tquantity\tprice".to_string()];
for (p, q, r) in [("tomato", 12, 15), ("potato", 10, 20), ("rice", 5, 12)] {
table.push(format!("{}\t{}\t{}", p, q, r));
}
format_table::format_table(table);
```
+9 -11
View File
@@ -21,20 +21,19 @@ path = "tests/lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
format_table.workspace = true garage_db = { version = "0.8.2", path = "../db" }
garage_db.workspace = true garage_api = { version = "0.8.2", path = "../api" }
garage_api.workspace = true garage_block = { version = "0.8.2", path = "../block" }
garage_block.workspace = true garage_model = { version = "0.8.2", path = "../model" }
garage_model.workspace = true garage_rpc = { version = "0.8.2", path = "../rpc" }
garage_rpc.workspace = true garage_table = { version = "0.8.2", path = "../table" }
garage_table.workspace = true garage_util = { version = "0.8.2", path = "../util" }
garage_util.workspace = true garage_web = { version = "0.8.2", path = "../web" }
garage_web.workspace = true
backtrace = "0.3" backtrace = "0.3"
bytes = "1.0" bytes = "1.0"
bytesize = "1.1" bytesize = "1.1"
timeago = { version = "0.4", default-features = false } timeago = "0.4"
parse_duration = "2.1" parse_duration = "2.1"
hex = "0.4" hex = "0.4"
tracing = { version = "0.1" } tracing = { version = "0.1" }
@@ -42,7 +41,6 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
rand = "0.8" rand = "0.8"
async-trait = "0.1.7" async-trait = "0.1.7"
sodiumoxide = { version = "0.2.5-0", package = "kuska-sodiumoxide" } sodiumoxide = { version = "0.2.5-0", package = "kuska-sodiumoxide" }
git-version = "0.3.4"
serde = { version = "1.0", default-features = false, features = ["derive", "rc"] } serde = { version = "1.0", default-features = false, features = ["derive", "rc"] }
serde_bytes = "0.11" serde_bytes = "0.11"
+1 -1
View File
@@ -5,11 +5,11 @@ use std::sync::Arc;
use async_trait::async_trait; use async_trait::async_trait;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use format_table::format_table_to_string;
use garage_util::background::BackgroundRunner; use garage_util::background::BackgroundRunner;
use garage_util::crdt::*; use garage_util::crdt::*;
use garage_util::data::*; use garage_util::data::*;
use garage_util::error::Error as GarageError; use garage_util::error::Error as GarageError;
use garage_util::formater::format_table_to_string;
use garage_util::time::*; use garage_util::time::*;
use garage_table::replication::*; use garage_table::replication::*;
+1 -1
View File
@@ -1,8 +1,8 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::time::Duration; use std::time::Duration;
use format_table::format_table;
use garage_util::error::*; use garage_util::error::*;
use garage_util::formater::format_table;
use garage_rpc::layout::*; use garage_rpc::layout::*;
use garage_rpc::system::*; use garage_rpc::system::*;
+1 -1
View File
@@ -1,6 +1,6 @@
use format_table::format_table;
use garage_util::crdt::Crdt; use garage_util::crdt::Crdt;
use garage_util::error::*; use garage_util::error::*;
use garage_util::formater::format_table;
use garage_rpc::layout::*; use garage_rpc::layout::*;
use garage_rpc::system::*; use garage_rpc::system::*;
+1 -1
View File
@@ -1,11 +1,11 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::time::Duration; use std::time::Duration;
use format_table::format_table;
use garage_util::background::*; use garage_util::background::*;
use garage_util::crdt::*; use garage_util::crdt::*;
use garage_util::data::*; use garage_util::data::*;
use garage_util::error::*; use garage_util::error::*;
use garage_util::formater::format_table;
use garage_util::time::*; use garage_util::time::*;
use garage_block::manager::BlockResyncErrorInfo; use garage_block::manager::BlockResyncErrorInfo;
-6
View File
@@ -108,12 +108,6 @@ async fn main() {
][..]; ][..];
if let Some(git_version) = option_env!("GIT_VERSION") { if let Some(git_version) = option_env!("GIT_VERSION") {
garage_util::version::init_version(git_version); garage_util::version::init_version(git_version);
} else {
garage_util::version::init_version(git_version::git_version!(
prefix = "git:",
cargo_prefix = "cargo:",
fallback = "unknown"
));
} }
garage_util::version::init_features(features); garage_util::version::init_features(features);
+4 -4
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "k2v-client" name = "k2v-client"
version = "0.0.2" version = "0.1.1"
authors = ["Trinity Pointard <trinity.pointard@gmail.com>", "Alex Auvolat <alex@adnab.me>"] authors = ["Trinity Pointard <trinity.pointard@gmail.com>", "Alex Auvolat <alex@adnab.me>"]
edition = "2018" edition = "2018"
license = "AGPL-3.0" license = "AGPL-3.0"
@@ -19,15 +19,15 @@ hyper-rustls = { version = "0.23", default-features = false, features = [ "http1
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
thiserror = "1.0" thiserror = "1.0"
tokio = { version = "1.0", default-features = false, features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros", "sync", "signal", "fs"] } tokio = "1.24"
# cli deps # cli deps
clap = { version = "4.1", optional = true, features = ["derive", "env"] } clap = { version = "4.1", optional = true, features = ["derive", "env"] }
format_table = { workspace = true, optional = true } garage_util = { version = "0.8.2", path = "../util", optional = true }
[features] [features]
cli = ["clap", "tokio/fs", "tokio/io-std", "format_table"] cli = ["clap", "tokio/fs", "tokio/io-std", "garage_util"]
[lib] [lib]
path = "lib.rs" path = "lib.rs"
+8 -12
View File
@@ -2,11 +2,9 @@ use std::collections::BTreeMap;
use std::process::exit; use std::process::exit;
use std::time::Duration; use std::time::Duration;
use base64::prelude::*;
use k2v_client::*; use k2v_client::*;
use format_table::format_table; use garage_util::formater::format_table;
use rusoto_core::credential::AwsCredentials; use rusoto_core::credential::AwsCredentials;
use rusoto_core::Region; use rusoto_core::Region;
@@ -157,9 +155,7 @@ impl Value {
if let Some(ref text) = self.text { if let Some(ref text) = self.text {
Ok(text.as_bytes().to_vec()) Ok(text.as_bytes().to_vec())
} else if let Some(ref b64) = self.b64 { } else if let Some(ref b64) = self.b64 {
BASE64_STANDARD base64::decode(b64).map_err(|_| Error::Message("invalid base64 input".into()))
.decode(b64)
.map_err(|_| Error::Message("invalid base64 input".into()))
} else if let Some(ref path) = self.file { } else if let Some(ref path) = self.file {
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
if path == "-" { if path == "-" {
@@ -234,7 +230,7 @@ impl ReadOutputKind {
for val in val.value { for val in val.value {
match val { match val {
K2vValue::Value(v) => { K2vValue::Value(v) => {
println!("{}", BASE64_STANDARD.encode(&v)) println!("{}", base64::encode(&v))
} }
K2vValue::Tombstone => { K2vValue::Tombstone => {
println!(); println!();
@@ -253,7 +249,7 @@ impl ReadOutputKind {
if let Ok(string) = std::str::from_utf8(&v) { if let Ok(string) = std::str::from_utf8(&v) {
println!(" utf-8: {}", string); println!(" utf-8: {}", string);
} else { } else {
println!(" base64: {}", BASE64_STANDARD.encode(&v)); println!(" base64: {}", base64::encode(&v));
} }
} }
K2vValue::Tombstone => { K2vValue::Tombstone => {
@@ -279,7 +275,7 @@ struct BatchOutputKind {
impl BatchOutputKind { impl BatchOutputKind {
fn display_human_output(&self, values: BTreeMap<String, CausalValue>) -> ! { fn display_human_output(&self, values: BTreeMap<String, CausalValue>) -> ! {
for (key, values) in values { for (key, values) in values {
println!("sort_key: {}", key); println!("key: {}", key);
let causality: String = values.causality.into(); let causality: String = values.causality.into();
println!("causality: {}", causality); println!("causality: {}", causality);
for value in values.value { for value in values.value {
@@ -288,7 +284,7 @@ impl BatchOutputKind {
if let Ok(string) = std::str::from_utf8(&v) { if let Ok(string) = std::str::from_utf8(&v) {
println!(" value(utf-8): {}", string); println!(" value(utf-8): {}", string);
} else { } else {
println!(" value(base64): {}", BASE64_STANDARD.encode(&v)); println!(" value(base64): {}", base64::encode(&v));
} }
} }
K2vValue::Tombstone => { K2vValue::Tombstone => {
@@ -524,7 +520,7 @@ async fn main() -> Result<(), Error> {
value value
.as_object_mut() .as_object_mut()
.unwrap() .unwrap()
.insert("partition_key".to_owned(), k.into()); .insert("sort_key".to_owned(), k.into());
value value
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@@ -541,7 +537,7 @@ async fn main() -> Result<(), Error> {
} }
let mut to_print = Vec::new(); let mut to_print = Vec::new();
to_print.push(format!("partition_key\tentries\tconflicts\tvalues\tbytes")); to_print.push(format!("key:\tentries\tconflicts\tvalues\tbytes"));
for (k, v) in res.items { for (k, v) in res.items {
to_print.push(format!( to_print.push(format!(
"{}\t{}\t{}\t{}\t{}", "{}\t{}\t{}\t{}\t{}",
+6 -9
View File
@@ -1,7 +1,6 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::time::Duration; use std::time::Duration;
use base64::prelude::*;
use http::header::{ACCEPT, CONTENT_LENGTH, CONTENT_TYPE}; use http::header::{ACCEPT, CONTENT_LENGTH, CONTENT_TYPE};
use http::status::StatusCode; use http::status::StatusCode;
use http::HeaderMap; use http::HeaderMap;
@@ -376,7 +375,7 @@ impl K2vClient {
.unwrap_or_default(); .unwrap_or_default();
let err_body_str = std::str::from_utf8(&err_body) let err_body_str = std::str::from_utf8(&err_body)
.map(String::from) .map(String::from)
.unwrap_or_else(|_| BASE64_STANDARD.encode(&err_body)); .unwrap_or_else(|_| base64::encode(&err_body));
if s.is_client_error() || s.is_server_error() { if s.is_client_error() || s.is_server_error() {
error!("Error response {}: {}", res.status, err_body_str); error!("Error response {}: {}", res.status, err_body_str);
@@ -409,7 +408,7 @@ impl K2vClient {
"Response body: {}", "Response body: {}",
std::str::from_utf8(&body) std::str::from_utf8(&body)
.map(String::from) .map(String::from)
.unwrap_or_else(|_| BASE64_STANDARD.encode(&body)) .unwrap_or_else(|_| base64::encode(&body))
); );
Ok(Response { Ok(Response {
@@ -483,11 +482,9 @@ impl<'de> Deserialize<'de> for K2vValue {
{ {
let val: Option<&str> = Option::deserialize(d)?; let val: Option<&str> = Option::deserialize(d)?;
Ok(match val { Ok(match val {
Some(s) => K2vValue::Value( Some(s) => {
BASE64_STANDARD K2vValue::Value(base64::decode(s).map_err(|_| DeError::custom("invalid base64"))?)
.decode(s) }
.map_err(|_| DeError::custom("invalid base64"))?,
),
None => K2vValue::Tombstone, None => K2vValue::Tombstone,
}) })
} }
@@ -501,7 +498,7 @@ impl Serialize for K2vValue {
match self { match self {
K2vValue::Tombstone => serializer.serialize_none(), K2vValue::Tombstone => serializer.serialize_none(),
K2vValue::Value(v) => { K2vValue::Value(v) => {
let b64 = BASE64_STANDARD.encode(v); let b64 = base64::encode(v);
serializer.serialize_str(&b64) serializer.serialize_str(&b64)
} }
} }
+5 -5
View File
@@ -14,11 +14,11 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
garage_db.workspace = true garage_db = { version = "0.8.2", default-features = false, path = "../db" }
garage_rpc.workspace = true garage_rpc = { version = "0.8.2", path = "../rpc" }
garage_table.workspace = true garage_table = { version = "0.8.2", path = "../table" }
garage_block.workspace = true garage_block = { version = "0.8.2", path = "../block" }
garage_util.workspace = true garage_util = { version = "0.8.2", path = "../util" }
async-trait = "0.1.7" async-trait = "0.1.7"
arc-swap = "1.0" arc-swap = "1.0"
+1 -1
View File
@@ -79,7 +79,7 @@ impl RangeSeenMarker {
let bytes = nonversioned_encode(&self)?; let bytes = nonversioned_encode(&self)?;
let bytes = zstd::stream::encode_all(&mut &bytes[..], zstd::DEFAULT_COMPRESSION_LEVEL)?; let bytes = zstd::stream::encode_all(&mut &bytes[..], zstd::DEFAULT_COMPRESSION_LEVEL)?;
Ok(BASE64_STANDARD.encode(bytes)) Ok(BASE64_STANDARD.encode(&bytes))
} }
/// Decode from msgpack+zstd+b64 representation, returns None on error. /// Decode from msgpack+zstd+b64 representation, returns None on error.
+1 -1
View File
@@ -14,7 +14,7 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
garage_util.workspace = true garage_util = { version = "0.8.2", path = "../util" }
arc-swap = "1.0" arc-swap = "1.0"
bytes = "1.0" bytes = "1.0"
+3 -3
View File
@@ -14,9 +14,9 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
garage_db.workspace = true garage_db = { version = "0.8.2", path = "../db" }
garage_rpc.workspace = true garage_rpc = { version = "0.8.2", path = "../rpc" }
garage_util.workspace = true garage_util = { version = "0.8.2", path = "../util" }
opentelemetry = "0.17" opentelemetry = "0.17"
+8 -8
View File
@@ -44,22 +44,22 @@ pub struct TableData<F: TableSchema, R: TableReplication> {
impl<F: TableSchema, R: TableReplication> TableData<F, R> { impl<F: TableSchema, R: TableReplication> TableData<F, R> {
pub fn new(system: Arc<System>, instance: F, replication: R, db: &db::Db) -> Arc<Self> { pub fn new(system: Arc<System>, instance: F, replication: R, db: &db::Db) -> Arc<Self> {
let store = db let store = db
.open_tree(format!("{}:table", F::TABLE_NAME)) .open_tree(&format!("{}:table", F::TABLE_NAME))
.expect("Unable to open DB tree"); .expect("Unable to open DB tree");
let merkle_tree = db let merkle_tree = db
.open_tree(format!("{}:merkle_tree", F::TABLE_NAME)) .open_tree(&format!("{}:merkle_tree", F::TABLE_NAME))
.expect("Unable to open DB Merkle tree tree"); .expect("Unable to open DB Merkle tree tree");
let merkle_todo = db let merkle_todo = db
.open_tree(format!("{}:merkle_todo", F::TABLE_NAME)) .open_tree(&format!("{}:merkle_todo", F::TABLE_NAME))
.expect("Unable to open DB Merkle TODO tree"); .expect("Unable to open DB Merkle TODO tree");
let insert_queue = db let insert_queue = db
.open_tree(format!("{}:insert_queue", F::TABLE_NAME)) .open_tree(&format!("{}:insert_queue", F::TABLE_NAME))
.expect("Unable to open insert queue DB tree"); .expect("Unable to open insert queue DB tree");
let gc_todo = db let gc_todo = db
.open_tree(format!("{}:gc_todo_v2", F::TABLE_NAME)) .open_tree(&format!("{}:gc_todo_v2", F::TABLE_NAME))
.expect("Unable to open GC DB tree"); .expect("Unable to open GC DB tree");
let gc_todo = CountedTree::new(gc_todo).expect("Cannot count gc_todo_v2"); let gc_todo = CountedTree::new(gc_todo).expect("Cannot count gc_todo_v2");
@@ -90,7 +90,7 @@ impl<F: TableSchema, R: TableReplication> TableData<F, R> {
pub fn read_entry(&self, p: &F::P, s: &F::S) -> Result<Option<ByteBuf>, Error> { pub fn read_entry(&self, p: &F::P, s: &F::S) -> Result<Option<ByteBuf>, Error> {
let tree_key = self.tree_key(p, s); let tree_key = self.tree_key(p, s);
if let Some(bytes) = self.store.get(tree_key)? { if let Some(bytes) = self.store.get(&tree_key)? {
Ok(Some(ByteBuf::from(bytes.to_vec()))) Ok(Some(ByteBuf::from(bytes.to_vec())))
} else { } else {
Ok(None) Ok(None)
@@ -132,10 +132,10 @@ impl<F: TableSchema, R: TableReplication> TableData<F, R> {
} }
} }
fn read_range_aux( fn read_range_aux<'a>(
&self, &self,
partition_hash: Hash, partition_hash: Hash,
range: db::ValueIter, range: db::ValueIter<'a>,
filter: &Option<F::Filter>, filter: &Option<F::Filter>,
limit: usize, limit: usize,
) -> Result<Vec<Arc<ByteBuf>>, Error> { ) -> Result<Vec<Arc<ByteBuf>>, Error> {
+7 -2
View File
@@ -34,9 +34,8 @@ impl DeletedFilter {
} }
} }
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum EnumerationOrder { pub enum EnumerationOrder {
#[default]
Forward, Forward,
Reverse, Reverse,
} }
@@ -50,3 +49,9 @@ impl EnumerationOrder {
} }
} }
} }
impl Default for EnumerationOrder {
fn default() -> Self {
EnumerationOrder::Forward
}
}
+2 -1
View File
@@ -14,7 +14,7 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
garage_db.workspace = true garage_db = { version = "0.8.2", path = "../db" }
arc-swap = "1.0" arc-swap = "1.0"
async-trait = "0.1" async-trait = "0.1"
@@ -22,6 +22,7 @@ blake2 = "0.10"
bytes = "1.0" bytes = "1.0"
digest = "0.10" digest = "0.10"
err-derive = "0.3" err-derive = "0.3"
git-version = "0.3.4"
hexdump = "0.1" hexdump = "0.1"
xxhash-rust = { version = "0.8", default-features = false, features = ["xxh3"] } xxhash-rust = { version = "0.8", default-features = false, features = ["xxh3"] }
hex = "0.4" hex = "0.4"
+1 -1
View File
@@ -223,7 +223,7 @@ fn secret_from_file(
#[cfg(unix)] #[cfg(unix)]
if std::env::var("GARAGE_ALLOW_WORLD_READABLE_SECRETS").as_deref() != Ok("true") { if std::env::var("GARAGE_ALLOW_WORLD_READABLE_SECRETS").as_deref() != Ok("true") {
use std::os::unix::fs::MetadataExt; use std::os::unix::fs::MetadataExt;
let metadata = std::fs::metadata(file_path)?; let metadata = std::fs::metadata(&file_path)?;
if metadata.mode() & 0o077 != 0 { if metadata.mode() & 0o077 != 0 {
return Err(format!("File {} is world-readable! (mode: 0{:o}, expected 0600)\nRefusing to start until this is fixed, or environment variable GARAGE_ALLOW_WORLD_READABLE_SECRETS is set to true.", file_path, metadata.mode()).into()); return Err(format!("File {} is world-readable! (mode: 0{:o}, expected 0600)\nRefusing to start until this is fixed, or environment variable GARAGE_ALLOW_WORLD_READABLE_SECRETS is set to true.", file_path, metadata.mode()).into());
} }
@@ -1,19 +1,3 @@
//! Format tables with a stupid API.
//!
//! Example:
//!
//! ```rust
//! let mut table = vec!["product\tquantity\tprice".to_string()];
//! for (p, q, r) in [("tomato", 12, 15), ("potato", 10, 20), ("rice", 5, 12)] {
//! table.push(format!("{}\t{}\t{}", p, q, r));
//! }
//! format_table::format_table(table);
//! ```
//!
//! A table to be formatted is a `Vec<String>`, containing one string per line.
//! Table columns in each line are separated by a `\t` character.
/// Format a table and return the result as a string.
pub fn format_table_to_string(data: Vec<String>) -> String { pub fn format_table_to_string(data: Vec<String>) -> String {
let data = data let data = data
.iter() .iter()
@@ -43,7 +27,6 @@ pub fn format_table_to_string(data: Vec<String>) -> String {
out out
} }
/// Format a table and print the result to stdout.
pub fn format_table(data: Vec<String>) { pub fn format_table(data: Vec<String>) {
print!("{}", format_table_to_string(data)); print!("{}", format_table_to_string(data));
} }
+1 -1
View File
@@ -13,7 +13,7 @@ pub fn handle_forwarded_for_headers(headers: &HeaderMap<HeaderValue>) -> Result<
.to_str() .to_str()
.ok_or_message("Error parsing X-Forwarded-For header")?; .ok_or_message("Error parsing X-Forwarded-For header")?;
let client_ip = IpAddr::from_str(forwarded_for_ip_str) let client_ip = IpAddr::from_str(&forwarded_for_ip_str)
.ok_or_message("Valid IP address not found in X-Forwarded-For header")?; .ok_or_message("Valid IP address not found in X-Forwarded-For header")?;
Ok(client_ip.to_string()) Ok(client_ip.to_string())
+1
View File
@@ -10,6 +10,7 @@ pub mod crdt;
pub mod data; pub mod data;
pub mod encode; pub mod encode;
pub mod error; pub mod error;
pub mod formater;
pub mod forwarded_headers; pub mod forwarded_headers;
pub mod metrics; pub mod metrics;
pub mod migrate; pub mod migrate;
+8 -4
View File
@@ -1,14 +1,18 @@
use std::sync::Arc; use std::sync::Arc;
use arc_swap::ArcSwapOption; use arc_swap::{ArcSwap, ArcSwapOption};
lazy_static::lazy_static! { lazy_static::lazy_static! {
static ref VERSION: ArcSwapOption<&'static str> = ArcSwapOption::new(None); static ref VERSION: ArcSwap<&'static str> = ArcSwap::new(Arc::new(git_version::git_version!(
prefix = "git:",
cargo_prefix = "cargo:",
fallback = "unknown"
)));
static ref FEATURES: ArcSwapOption<&'static [&'static str]> = ArcSwapOption::new(None); static ref FEATURES: ArcSwapOption<&'static [&'static str]> = ArcSwapOption::new(None);
} }
pub fn garage_version() -> &'static str { pub fn garage_version() -> &'static str {
VERSION.load().as_ref().unwrap() &VERSION.load()
} }
pub fn garage_features() -> Option<&'static [&'static str]> { pub fn garage_features() -> Option<&'static [&'static str]> {
@@ -16,7 +20,7 @@ pub fn garage_features() -> Option<&'static [&'static str]> {
} }
pub fn init_version(version: &'static str) { pub fn init_version(version: &'static str) {
VERSION.store(Some(Arc::new(version))); VERSION.store(Arc::new(version));
} }
pub fn init_features(features: &'static [&'static str]) { pub fn init_features(features: &'static [&'static str]) {
+4 -4
View File
@@ -14,10 +14,10 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
garage_api.workspace = true garage_api = { version = "0.8.2", path = "../api" }
garage_model.workspace = true garage_model = { version = "0.8.2", path = "../model" }
garage_util.workspace = true garage_util = { version = "0.8.2", path = "../util" }
garage_table.workspace = true garage_table = { version = "0.8.2", path = "../table" }
err-derive = "0.3" err-derive = "0.3"
tracing = "0.1" tracing = "0.1"
+1 -1
View File
@@ -106,7 +106,7 @@ impl WebServer {
addr: SocketAddr, addr: SocketAddr,
) -> Result<Response<Body>, Infallible> { ) -> Result<Response<Body>, Infallible> {
if let Ok(forwarded_for_ip_addr) = if let Ok(forwarded_for_ip_addr) =
forwarded_headers::handle_forwarded_for_headers(req.headers()) forwarded_headers::handle_forwarded_for_headers(&req.headers())
{ {
info!( info!(
"{} (via {}) {} {}", "{} (via {}) {} {}",