snapshot of https://github.com/seaweedfs/seaweedfs.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
This commit is contained in:
607
weed/worker/tasks/iceberg/delete_rewrite.go
Normal file
607
weed/worker/tasks/iceberg/delete_rewrite.go
Normal file
@@ -0,0 +1,607 @@
|
||||
package iceberg
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"path"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/apache/iceberg-go"
|
||||
"github.com/apache/iceberg-go/table"
|
||||
"github.com/parquet-go/parquet-go"
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3tables"
|
||||
)
|
||||
|
||||
type deleteRewriteInput struct {
|
||||
Entry iceberg.ManifestEntry
|
||||
ReferencedPath string
|
||||
Positions []int64
|
||||
}
|
||||
|
||||
type deleteRewriteGroup struct {
|
||||
SpecID int32
|
||||
Partition map[int]any
|
||||
PartitionKey string
|
||||
ReferencedPath string
|
||||
Inputs []deleteRewriteInput
|
||||
TotalSize int64
|
||||
}
|
||||
|
||||
type positionDeleteRow struct {
|
||||
FilePath string `parquet:"file_path"`
|
||||
Pos int64 `parquet:"pos"`
|
||||
}
|
||||
|
||||
func hasEligibleDeleteRewrite(
|
||||
ctx context.Context,
|
||||
filerClient filer_pb.SeaweedFilerClient,
|
||||
bucketName, dataPath string,
|
||||
manifests []iceberg.ManifestFile,
|
||||
config Config,
|
||||
meta table.Metadata,
|
||||
predicate *partitionPredicate,
|
||||
) (bool, error) {
|
||||
groups, _, err := collectDeleteRewriteGroups(ctx, filerClient, bucketName, dataPath, manifests, specByID(meta), meta.CurrentSchema())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, group := range groups {
|
||||
if predicate != nil {
|
||||
spec, ok := specByID(meta)[int(group.SpecID)]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
match, err := predicate.Matches(spec, group.Partition)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !match {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if groupEligibleForRewrite(group, config) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func collectDeleteRewriteGroups(
|
||||
ctx context.Context,
|
||||
filerClient filer_pb.SeaweedFilerClient,
|
||||
bucketName, dataPath string,
|
||||
manifests []iceberg.ManifestFile,
|
||||
specs map[int]iceberg.PartitionSpec,
|
||||
schema *iceberg.Schema,
|
||||
) (map[string]*deleteRewriteGroup, []iceberg.ManifestEntry, error) {
|
||||
groups := make(map[string]*deleteRewriteGroup)
|
||||
var allPositionEntries []iceberg.ManifestEntry
|
||||
|
||||
for _, mf := range manifests {
|
||||
if mf.ManifestContent() != iceberg.ManifestContentDeletes {
|
||||
continue
|
||||
}
|
||||
|
||||
manifestData, err := loadFileByIcebergPath(ctx, filerClient, bucketName, dataPath, mf.FilePath())
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("read delete manifest %s: %w", mf.FilePath(), err)
|
||||
}
|
||||
entries, err := s3tables.ReadManifest(mf, manifestData, true, specs, schema)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("parse delete manifest %s: %w", mf.FilePath(), err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if entry.DataFile().ContentType() != iceberg.EntryContentPosDeletes {
|
||||
continue
|
||||
}
|
||||
|
||||
allPositionEntries = append(allPositionEntries, entry)
|
||||
|
||||
fileDeletes, err := readPositionDeleteFile(ctx, filerClient, bucketName, dataPath, entry.DataFile().FilePath())
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("read position delete file %s: %w", entry.DataFile().FilePath(), err)
|
||||
}
|
||||
if len(fileDeletes) != 1 {
|
||||
// Phase 1 only rewrites files that target a single data file.
|
||||
continue
|
||||
}
|
||||
|
||||
var referencedPath string
|
||||
var positions []int64
|
||||
for fp, pos := range fileDeletes {
|
||||
normalized, err := normalizeIcebergPath(fp, bucketName, dataPath)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("resolve deleted file %s: %w", fp, err)
|
||||
}
|
||||
// The rewritten delete file has to name the data file the way the
|
||||
// table does, so keep the absolute form readers compare against.
|
||||
referencedPath = absoluteIcebergPath(bucketName, normalized)
|
||||
positions = append(positions, pos...)
|
||||
}
|
||||
sort.Slice(positions, func(i, j int) bool { return positions[i] < positions[j] })
|
||||
|
||||
partKey := partitionKey(entry.DataFile().Partition())
|
||||
groupKey := fmt.Sprintf("spec%d\x00%s\x00%s", entry.DataFile().SpecID(), partKey, referencedPath)
|
||||
group, ok := groups[groupKey]
|
||||
if !ok {
|
||||
group = &deleteRewriteGroup{
|
||||
SpecID: entry.DataFile().SpecID(),
|
||||
Partition: entry.DataFile().Partition(),
|
||||
PartitionKey: partKey,
|
||||
ReferencedPath: referencedPath,
|
||||
}
|
||||
groups[groupKey] = group
|
||||
}
|
||||
group.Inputs = append(group.Inputs, deleteRewriteInput{
|
||||
Entry: entry,
|
||||
ReferencedPath: referencedPath,
|
||||
Positions: positions,
|
||||
})
|
||||
group.TotalSize += entry.DataFile().FileSizeBytes()
|
||||
}
|
||||
}
|
||||
|
||||
return groups, allPositionEntries, nil
|
||||
}
|
||||
|
||||
func groupEligibleForRewrite(group *deleteRewriteGroup, config Config) bool {
|
||||
if group == nil {
|
||||
return false
|
||||
}
|
||||
if len(group.Inputs) < 2 {
|
||||
return false
|
||||
}
|
||||
if group.TotalSize > config.DeleteMaxFileGroupSizeBytes {
|
||||
return false
|
||||
}
|
||||
target := config.DeleteTargetFileSizeBytes
|
||||
if target <= 0 {
|
||||
target = defaultDeleteTargetFileSizeMB * 1024 * 1024
|
||||
}
|
||||
outputFiles := int64(estimatedDeleteOutputFiles(group.TotalSize, target))
|
||||
if config.DeleteMaxOutputFiles > 0 && outputFiles > config.DeleteMaxOutputFiles {
|
||||
return false
|
||||
}
|
||||
return int64(len(group.Inputs)) >= config.DeleteMinInputFiles
|
||||
}
|
||||
|
||||
func estimatedDeleteOutputFiles(totalSize, targetSize int64) int {
|
||||
if totalSize <= 0 || targetSize <= 0 {
|
||||
return 1
|
||||
}
|
||||
count := int(math.Ceil(float64(totalSize) / float64(targetSize)))
|
||||
if count < 1 {
|
||||
return 1
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func manifestEntrySeqNum(entry iceberg.ManifestEntry) *int64 {
|
||||
seqNum := entry.SequenceNum()
|
||||
if seqNum < 0 {
|
||||
return nil
|
||||
}
|
||||
return &seqNum
|
||||
}
|
||||
|
||||
func manifestEntryFileSeqNum(entry iceberg.ManifestEntry) *int64 {
|
||||
if fileSeqNum := entry.FileSequenceNum(); fileSeqNum != nil {
|
||||
value := *fileSeqNum
|
||||
return &value
|
||||
}
|
||||
return manifestEntrySeqNum(entry)
|
||||
}
|
||||
|
||||
func writeManifestWithContent(
|
||||
filename string,
|
||||
version int,
|
||||
spec iceberg.PartitionSpec,
|
||||
schema *iceberg.Schema,
|
||||
snapshotID int64,
|
||||
entries []iceberg.ManifestEntry,
|
||||
content iceberg.ManifestContent,
|
||||
) (iceberg.ManifestFile, []byte, error) {
|
||||
var manifestBuf bytes.Buffer
|
||||
mf, err := iceberg.WriteManifest(filename, &manifestBuf, version, spec, schema, snapshotID, entries)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
manifestBytes := manifestBuf.Bytes()
|
||||
if content == iceberg.ManifestContentDeletes {
|
||||
manifestBytes, err = patchManifestContentBytesToDeletes(manifestBytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
rebuilt := iceberg.NewManifestFile(version, filename, int64(len(manifestBytes)), int32(spec.ID()), snapshotID).
|
||||
Content(content).
|
||||
AddedFiles(mf.AddedDataFiles()).
|
||||
ExistingFiles(mf.ExistingDataFiles()).
|
||||
DeletedFiles(mf.DeletedDataFiles()).
|
||||
AddedRows(mf.AddedRows()).
|
||||
ExistingRows(mf.ExistingRows()).
|
||||
DeletedRows(mf.DeletedRows()).
|
||||
Partitions(mf.Partitions()).
|
||||
Build()
|
||||
return rebuilt, manifestBytes, nil
|
||||
}
|
||||
|
||||
func patchManifestContentBytesToDeletes(manifestBytes []byte) ([]byte, error) {
|
||||
old := append([]byte{0x0e}, []byte("content")...)
|
||||
old = append(old, 0x08)
|
||||
old = append(old, []byte("data")...)
|
||||
|
||||
new := append([]byte{0x0e}, []byte("content")...)
|
||||
new = append(new, 0x0e)
|
||||
new = append(new, []byte("deletes")...)
|
||||
|
||||
result := bytes.Replace(manifestBytes, old, new, 1)
|
||||
if bytes.Equal(result, manifestBytes) {
|
||||
return nil, fmt.Errorf("delete manifest content patch failed")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func writePositionDeleteFile(rows []positionDeleteRow) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
writer := parquet.NewWriter(&buf, parquet.SchemaOf(new(positionDeleteRow)))
|
||||
for _, row := range rows {
|
||||
if err := writer.Write(&row); err != nil {
|
||||
return nil, fmt.Errorf("write position delete row: %w", err)
|
||||
}
|
||||
}
|
||||
if err := writer.Close(); err != nil {
|
||||
return nil, fmt.Errorf("close position delete file: %w", err)
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (h *Handler) rewritePositionDeleteFiles(
|
||||
ctx context.Context,
|
||||
filerClient filer_pb.SeaweedFilerClient,
|
||||
bucketName, tablePath string,
|
||||
config Config,
|
||||
) (string, map[string]int64, error) {
|
||||
start := time.Now()
|
||||
state, err := loadCurrentMetadata(ctx, filerClient, bucketName, tablePath)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("load metadata: %w", err)
|
||||
}
|
||||
meta, dataPath := state.Metadata, state.DataPath
|
||||
|
||||
currentSnap := meta.CurrentSnapshot()
|
||||
if currentSnap == nil || currentSnap.ManifestList == "" {
|
||||
return "no current snapshot", nil, nil
|
||||
}
|
||||
|
||||
manifestListData, err := loadFileByIcebergPath(ctx, filerClient, bucketName, dataPath, currentSnap.ManifestList)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("read manifest list: %w", err)
|
||||
}
|
||||
manifests, err := s3tables.ReadManifestList(manifestListData)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("parse manifest list: %w", err)
|
||||
}
|
||||
|
||||
specs := specByID(meta)
|
||||
schema := meta.CurrentSchema()
|
||||
|
||||
var dataManifests []iceberg.ManifestFile
|
||||
var allEqualityEntries []iceberg.ManifestEntry
|
||||
for _, mf := range manifests {
|
||||
switch mf.ManifestContent() {
|
||||
case iceberg.ManifestContentData:
|
||||
dataManifests = append(dataManifests, mf)
|
||||
case iceberg.ManifestContentDeletes:
|
||||
manifestData, readErr := loadFileByIcebergPath(ctx, filerClient, bucketName, dataPath, mf.FilePath())
|
||||
if readErr != nil {
|
||||
return "", nil, fmt.Errorf("read delete manifest %s: %w", mf.FilePath(), readErr)
|
||||
}
|
||||
entries, parseErr := s3tables.ReadManifest(mf, manifestData, true, specs, schema)
|
||||
if parseErr != nil {
|
||||
return "", nil, fmt.Errorf("parse delete manifest %s: %w", mf.FilePath(), parseErr)
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if entry.DataFile().ContentType() == iceberg.EntryContentEqDeletes {
|
||||
allEqualityEntries = append(allEqualityEntries, entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
groupMap, allPositionEntries, err := collectDeleteRewriteGroups(ctx, filerClient, bucketName, dataPath, manifests, specs, schema)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if len(groupMap) == 0 {
|
||||
return "no position delete files eligible for rewrite", nil, nil
|
||||
}
|
||||
|
||||
type artifact struct {
|
||||
dir, fileName string
|
||||
}
|
||||
var writtenArtifacts []artifact
|
||||
committed := false
|
||||
defer func() {
|
||||
if committed || len(writtenArtifacts) == 0 {
|
||||
return
|
||||
}
|
||||
cleanupCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
for _, a := range writtenArtifacts {
|
||||
if err := deleteFilerFile(cleanupCtx, filerClient, a.dir, a.fileName); err != nil {
|
||||
glog.Warningf("iceberg delete rewrite: failed to clean up artifact %s/%s: %v", a.dir, a.fileName, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
specByID := specByID(meta)
|
||||
predicate, err := parsePartitionPredicate(config.Where, meta)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
type specEntries struct {
|
||||
specID int32
|
||||
entries []iceberg.ManifestEntry
|
||||
}
|
||||
specEntriesMap := make(map[int32]*specEntries)
|
||||
addToSpec := func(specID int32, entry iceberg.ManifestEntry) {
|
||||
se, ok := specEntriesMap[specID]
|
||||
if !ok {
|
||||
se = &specEntries{specID: specID}
|
||||
specEntriesMap[specID] = se
|
||||
}
|
||||
se.entries = append(se.entries, entry)
|
||||
}
|
||||
|
||||
newSnapID := time.Now().UnixMilli()
|
||||
version := meta.Version()
|
||||
snapshotID := currentSnap.SnapshotID
|
||||
seqNum := currentSnap.SequenceNumber + 1
|
||||
metaDir := path.Join(s3tables.TablesPath, bucketName, dataPath, "metadata")
|
||||
dataDir := path.Join(s3tables.TablesPath, bucketName, dataPath, "data")
|
||||
artifactSuffix := compactRandomSuffix()
|
||||
|
||||
replacedPaths := make(map[string]struct{})
|
||||
var summary snapshotSummary
|
||||
var rewrittenGroups int64
|
||||
var skippedGroups int64
|
||||
var deleteFilesRewritten int64
|
||||
var deleteFilesWritten int64
|
||||
var deleteBytesRewritten int64
|
||||
|
||||
sortedKeys := make([]string, 0, len(groupMap))
|
||||
for key := range groupMap {
|
||||
sortedKeys = append(sortedKeys, key)
|
||||
}
|
||||
sort.Strings(sortedKeys)
|
||||
|
||||
for _, key := range sortedKeys {
|
||||
group := groupMap[key]
|
||||
if predicate != nil {
|
||||
spec, ok := specByID[int(group.SpecID)]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
match, err := predicate.Matches(spec, group.Partition)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if !match {
|
||||
skippedGroups++
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !groupEligibleForRewrite(group, config) {
|
||||
skippedGroups++
|
||||
continue
|
||||
}
|
||||
rows := make([]positionDeleteRow, 0)
|
||||
for _, input := range group.Inputs {
|
||||
for _, pos := range input.Positions {
|
||||
rows = append(rows, positionDeleteRow{FilePath: input.ReferencedPath, Pos: pos})
|
||||
}
|
||||
replacedPaths[input.Entry.DataFile().FilePath()] = struct{}{}
|
||||
deleteFilesRewritten++
|
||||
deleteBytesRewritten += input.Entry.DataFile().FileSizeBytes()
|
||||
}
|
||||
sort.Slice(rows, func(i, j int) bool {
|
||||
if rows[i].FilePath != rows[j].FilePath {
|
||||
return rows[i].FilePath < rows[j].FilePath
|
||||
}
|
||||
return rows[i].Pos < rows[j].Pos
|
||||
})
|
||||
|
||||
outputFiles := estimatedDeleteOutputFiles(group.TotalSize, config.DeleteTargetFileSizeBytes)
|
||||
rowsPerFile := (len(rows) + outputFiles - 1) / outputFiles
|
||||
if rowsPerFile < 1 {
|
||||
rowsPerFile = len(rows)
|
||||
}
|
||||
|
||||
for startIdx, fileIdx := 0, 0; startIdx < len(rows); startIdx, fileIdx = startIdx+rowsPerFile, fileIdx+1 {
|
||||
endIdx := startIdx + rowsPerFile
|
||||
if endIdx > len(rows) {
|
||||
endIdx = len(rows)
|
||||
}
|
||||
outputRows := rows[startIdx:endIdx]
|
||||
deleteBytes, err := writePositionDeleteFile(outputRows)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
fileName := fmt.Sprintf("rewrite-delete-%d-%s-%d.parquet", newSnapID, artifactSuffix, deleteFilesWritten)
|
||||
if err := ensureFilerDir(ctx, filerClient, dataDir); err != nil {
|
||||
return "", nil, fmt.Errorf("ensure data dir: %w", err)
|
||||
}
|
||||
if err := saveFilerFile(ctx, filerClient, dataDir, fileName, deleteBytes); err != nil {
|
||||
return "", nil, fmt.Errorf("save rewritten delete file: %w", err)
|
||||
}
|
||||
writtenArtifacts = append(writtenArtifacts, artifact{dir: dataDir, fileName: fileName})
|
||||
|
||||
spec, ok := specByID[int(group.SpecID)]
|
||||
if !ok {
|
||||
return "", nil, fmt.Errorf("partition spec %d not found", group.SpecID)
|
||||
}
|
||||
dfBuilder, err := iceberg.NewDataFileBuilder(
|
||||
spec,
|
||||
iceberg.EntryContentPosDeletes,
|
||||
absoluteIcebergPath(bucketName, dataPath, "data", fileName),
|
||||
iceberg.ParquetFile,
|
||||
group.Partition,
|
||||
nil, nil,
|
||||
int64(len(outputRows)),
|
||||
int64(len(deleteBytes)),
|
||||
)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("build rewritten delete file: %w", err)
|
||||
}
|
||||
rewrittenDeleteFile := dfBuilder.Build()
|
||||
summary.addFile(rewrittenDeleteFile)
|
||||
addToSpec(group.SpecID, iceberg.NewManifestEntry(iceberg.EntryStatusADDED, &newSnapID, nil, nil, rewrittenDeleteFile))
|
||||
deleteFilesWritten++
|
||||
}
|
||||
|
||||
for _, input := range group.Inputs {
|
||||
summary.removeFile(input.Entry.DataFile())
|
||||
delEntry := iceberg.NewManifestEntry(
|
||||
iceberg.EntryStatusDELETED,
|
||||
&newSnapID,
|
||||
manifestEntrySeqNum(input.Entry),
|
||||
manifestEntryFileSeqNum(input.Entry),
|
||||
input.Entry.DataFile(),
|
||||
)
|
||||
addToSpec(group.SpecID, delEntry)
|
||||
}
|
||||
rewrittenGroups++
|
||||
}
|
||||
|
||||
if rewrittenGroups == 0 {
|
||||
return "no position delete files eligible for rewrite", nil, nil
|
||||
}
|
||||
|
||||
for _, entry := range allEqualityEntries {
|
||||
existingEntry := iceberg.NewManifestEntry(
|
||||
iceberg.EntryStatusEXISTING,
|
||||
func() *int64 { id := entry.SnapshotID(); return &id }(),
|
||||
manifestEntrySeqNum(entry),
|
||||
manifestEntryFileSeqNum(entry),
|
||||
entry.DataFile(),
|
||||
)
|
||||
addToSpec(entry.DataFile().SpecID(), existingEntry)
|
||||
}
|
||||
|
||||
for _, entry := range allPositionEntries {
|
||||
if _, replaced := replacedPaths[entry.DataFile().FilePath()]; replaced {
|
||||
continue
|
||||
}
|
||||
existingEntry := iceberg.NewManifestEntry(
|
||||
iceberg.EntryStatusEXISTING,
|
||||
func() *int64 { id := entry.SnapshotID(); return &id }(),
|
||||
manifestEntrySeqNum(entry),
|
||||
manifestEntryFileSeqNum(entry),
|
||||
entry.DataFile(),
|
||||
)
|
||||
addToSpec(entry.DataFile().SpecID(), existingEntry)
|
||||
}
|
||||
|
||||
sortedSpecIDs := make([]int32, 0, len(specEntriesMap))
|
||||
for specID := range specEntriesMap {
|
||||
sortedSpecIDs = append(sortedSpecIDs, specID)
|
||||
}
|
||||
sort.Slice(sortedSpecIDs, func(i, j int) bool { return sortedSpecIDs[i] < sortedSpecIDs[j] })
|
||||
|
||||
allManifests := make([]iceberg.ManifestFile, 0, len(dataManifests)+len(sortedSpecIDs))
|
||||
allManifests = append(allManifests, dataManifests...)
|
||||
|
||||
for _, specID := range sortedSpecIDs {
|
||||
spec, ok := specByID[int(specID)]
|
||||
if !ok {
|
||||
return "", nil, fmt.Errorf("partition spec %d not found", specID)
|
||||
}
|
||||
manifestName := fmt.Sprintf("rewrite-delete-%d-%s-spec%d.avro", newSnapID, artifactSuffix, specID)
|
||||
manifestPath := absoluteIcebergPath(bucketName, dataPath, "metadata", manifestName)
|
||||
mf, manifestBytes, err := writeManifestWithContent(
|
||||
manifestPath,
|
||||
version,
|
||||
spec,
|
||||
meta.CurrentSchema(),
|
||||
newSnapID,
|
||||
specEntriesMap[specID].entries,
|
||||
iceberg.ManifestContentDeletes,
|
||||
)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("write delete manifest for spec %d: %w", specID, err)
|
||||
}
|
||||
if err := saveFilerFile(ctx, filerClient, metaDir, manifestName, manifestBytes); err != nil {
|
||||
return "", nil, fmt.Errorf("save delete manifest for spec %d: %w", specID, err)
|
||||
}
|
||||
writtenArtifacts = append(writtenArtifacts, artifact{dir: metaDir, fileName: manifestName})
|
||||
allManifests = append(allManifests, mf)
|
||||
}
|
||||
|
||||
var manifestListBuf bytes.Buffer
|
||||
if err := iceberg.WriteManifestList(version, &manifestListBuf, newSnapID, &snapshotID, &seqNum, 0, allManifests); err != nil {
|
||||
return "", nil, fmt.Errorf("write delete manifest list: %w", err)
|
||||
}
|
||||
manifestListName := fmt.Sprintf("snap-%d-%s.avro", newSnapID, artifactSuffix)
|
||||
if err := saveFilerFile(ctx, filerClient, metaDir, manifestListName, manifestListBuf.Bytes()); err != nil {
|
||||
return "", nil, fmt.Errorf("save delete manifest list: %w", err)
|
||||
}
|
||||
writtenArtifacts = append(writtenArtifacts, artifact{dir: metaDir, fileName: manifestListName})
|
||||
|
||||
manifestListLocation := absoluteIcebergPath(bucketName, dataPath, "metadata", manifestListName)
|
||||
err = h.commitWithRetry(ctx, filerClient, bucketName, tablePath, state.MetadataFileName, config, func(currentMeta table.Metadata, builder *table.MetadataBuilder) error {
|
||||
cs := currentMeta.CurrentSnapshot()
|
||||
if cs == nil || cs.SnapshotID != snapshotID {
|
||||
return errStalePlan
|
||||
}
|
||||
newSnapshot := &table.Snapshot{
|
||||
SnapshotID: newSnapID,
|
||||
ParentSnapshotID: &snapshotID,
|
||||
SequenceNumber: seqNum,
|
||||
TimestampMs: newSnapID,
|
||||
ManifestList: manifestListLocation,
|
||||
Summary: summary.build(table.OpReplace, cs, map[string]string{
|
||||
"maintenance": "rewrite_position_delete_files",
|
||||
"delete-files-rewritten": fmt.Sprintf("%d", deleteFilesRewritten),
|
||||
"delete-files-written": fmt.Sprintf("%d", deleteFilesWritten),
|
||||
"delete-groups": fmt.Sprintf("%d", rewrittenGroups),
|
||||
}),
|
||||
SchemaID: func() *int {
|
||||
id := meta.CurrentSchema().ID
|
||||
return &id
|
||||
}(),
|
||||
}
|
||||
if err := builder.AddSnapshot(newSnapshot); err != nil {
|
||||
return err
|
||||
}
|
||||
return builder.SetSnapshotRef(table.MainBranch, newSnapID, table.BranchRef)
|
||||
})
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("commit delete rewrite: %w", err)
|
||||
}
|
||||
|
||||
committed = true
|
||||
metrics := map[string]int64{
|
||||
MetricDeleteFilesRewritten: deleteFilesRewritten,
|
||||
MetricDeleteFilesWritten: deleteFilesWritten,
|
||||
MetricDeleteBytesRewritten: deleteBytesRewritten,
|
||||
MetricDeleteGroupsPlanned: rewrittenGroups,
|
||||
MetricDeleteGroupsSkipped: skippedGroups,
|
||||
MetricDurationMs: time.Since(start).Milliseconds(),
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"rewrote %d position delete files into %d across %d group(s)",
|
||||
deleteFilesRewritten,
|
||||
deleteFilesWritten,
|
||||
rewrittenGroups,
|
||||
), metrics, nil
|
||||
}
|
||||
Reference in New Issue
Block a user