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:
509
weed/query/engine/broker_client.go
Normal file
509
weed/query/engine/broker_client.go
Normal file
@@ -0,0 +1,509 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/cluster"
|
||||
"github.com/seaweedfs/seaweedfs/weed/filer"
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/pub_balancer"
|
||||
"github.com/seaweedfs/seaweedfs/weed/mq/topic"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/master_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/mq_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
jsonpb "google.golang.org/protobuf/encoding/protojson"
|
||||
)
|
||||
|
||||
// BrokerClient handles communication with SeaweedFS MQ broker
|
||||
// Implements BrokerClientInterface for production use
|
||||
// Assumptions:
|
||||
// 1. Service discovery via master server (discovers filers and brokers)
|
||||
// 2. gRPC connection with default timeout of 30 seconds
|
||||
// 3. Topics and namespaces are managed via SeaweedMessaging service
|
||||
type BrokerClient struct {
|
||||
masterAddress string
|
||||
filerAddress string
|
||||
brokerAddress string
|
||||
grpcDialOption grpc.DialOption
|
||||
}
|
||||
|
||||
// NewBrokerClient creates a new MQ broker client
|
||||
// Uses master HTTP address and converts it to gRPC address for service discovery
|
||||
func NewBrokerClient(masterHTTPAddress string) *BrokerClient {
|
||||
// Convert HTTP address to gRPC address using pb.ServerAddress method
|
||||
httpAddr := pb.ServerAddress(masterHTTPAddress)
|
||||
masterGRPCAddress := httpAddr.ToGrpcAddress()
|
||||
|
||||
return &BrokerClient{
|
||||
masterAddress: masterGRPCAddress,
|
||||
grpcDialOption: grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
}
|
||||
}
|
||||
|
||||
// No need for convertHTTPToGRPC - pb.ServerAddress.ToGrpcAddress() already handles this
|
||||
|
||||
// discoverFiler finds a filer from the master server
|
||||
func (c *BrokerClient) discoverFiler() error {
|
||||
if c.filerAddress != "" {
|
||||
return nil // already discovered
|
||||
}
|
||||
|
||||
conn, err := pb.GrpcDial(context.Background(), c.masterAddress, false, c.grpcDialOption)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to master at %s: %v", c.masterAddress, err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := master_pb.NewSeaweedClient(conn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
resp, err := client.ListClusterNodes(ctx, &master_pb.ListClusterNodesRequest{
|
||||
ClientType: cluster.FilerType,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list filers from master: %v", err)
|
||||
}
|
||||
|
||||
if len(resp.ClusterNodes) == 0 {
|
||||
return fmt.Errorf("no filers found in cluster")
|
||||
}
|
||||
|
||||
// Use the first available filer and convert HTTP address to gRPC
|
||||
filerHTTPAddress := resp.ClusterNodes[0].Address
|
||||
httpAddr := pb.ServerAddress(filerHTTPAddress)
|
||||
c.filerAddress = httpAddr.ToGrpcAddress()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// findBrokerBalancer discovers the broker balancer using filer lock mechanism
|
||||
// First discovers filer from master, then uses filer to find broker balancer
|
||||
func (c *BrokerClient) findBrokerBalancer() error {
|
||||
if c.brokerAddress != "" {
|
||||
return nil // already found
|
||||
}
|
||||
|
||||
// First discover filer from master
|
||||
if err := c.discoverFiler(); err != nil {
|
||||
return fmt.Errorf("failed to discover filer: %v", err)
|
||||
}
|
||||
|
||||
conn, err := pb.GrpcDial(context.Background(), c.filerAddress, false, c.grpcDialOption)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to filer at %s: %v", c.filerAddress, err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := filer_pb.NewSeaweedFilerClient(conn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
resp, err := client.FindLockOwner(ctx, &filer_pb.FindLockOwnerRequest{
|
||||
Name: pub_balancer.LockBrokerBalancer,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find broker balancer: %v", err)
|
||||
}
|
||||
|
||||
c.brokerAddress = resp.Owner
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFilerClient creates a filer client for accessing MQ data files
|
||||
// Discovers filer from master if not already known
|
||||
func (c *BrokerClient) GetFilerClient() (filer_pb.FilerClient, error) {
|
||||
// Ensure filer is discovered
|
||||
if err := c.discoverFiler(); err != nil {
|
||||
return nil, fmt.Errorf("failed to discover filer: %v", err)
|
||||
}
|
||||
|
||||
return &filerClientImpl{
|
||||
filerAddress: c.filerAddress,
|
||||
grpcDialOption: c.grpcDialOption,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// filerClientImpl implements filer_pb.FilerClient interface for MQ data access
|
||||
type filerClientImpl struct {
|
||||
filerAddress string
|
||||
grpcDialOption grpc.DialOption
|
||||
}
|
||||
|
||||
// WithFilerClient executes a function with a connected filer client
|
||||
func (f *filerClientImpl) WithFilerClient(followRedirect bool, fn func(client filer_pb.SeaweedFilerClient) error) error {
|
||||
conn, err := pb.GrpcDial(context.Background(), f.filerAddress, false, f.grpcDialOption)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to filer at %s: %v", f.filerAddress, err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := filer_pb.NewSeaweedFilerClient(conn)
|
||||
return fn(client)
|
||||
}
|
||||
|
||||
// AdjustedUrl implements the FilerClient interface (placeholder implementation)
|
||||
func (f *filerClientImpl) AdjustedUrl(location *filer_pb.Location) string {
|
||||
return location.Url
|
||||
}
|
||||
|
||||
// GetDataCenter implements the FilerClient interface (placeholder implementation)
|
||||
func (f *filerClientImpl) GetDataCenter() string {
|
||||
// Return empty string as we don't have data center information for this simple client
|
||||
return ""
|
||||
}
|
||||
|
||||
// ListNamespaces retrieves all MQ namespaces (databases) from the filer
|
||||
func (c *BrokerClient) ListNamespaces(ctx context.Context) ([]string, error) {
|
||||
// Get filer client to list directories under /topics
|
||||
filerClient, err := c.GetFilerClient()
|
||||
if err != nil {
|
||||
return []string{}, fmt.Errorf("failed to get filer client: %v", err)
|
||||
}
|
||||
|
||||
var namespaces []string
|
||||
err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
|
||||
// List directories under /topics to get namespaces
|
||||
request := &filer_pb.ListEntriesRequest{
|
||||
Directory: "/topics", // filer.TopicsDir constant value
|
||||
}
|
||||
|
||||
stream, streamErr := client.ListEntries(ctx, request)
|
||||
if streamErr != nil {
|
||||
return fmt.Errorf("failed to list topics directory: %v", streamErr)
|
||||
}
|
||||
|
||||
for {
|
||||
resp, recvErr := stream.Recv()
|
||||
if recvErr != nil {
|
||||
if recvErr == io.EOF {
|
||||
break // End of stream
|
||||
}
|
||||
return fmt.Errorf("failed to receive entry: %v", recvErr)
|
||||
}
|
||||
|
||||
// Only include directories (namespaces), skip files and system directories (starting with .)
|
||||
if resp.Entry != nil && resp.Entry.IsDirectory && !strings.HasPrefix(resp.Entry.Name, ".") {
|
||||
namespaces = append(namespaces, resp.Entry.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return []string{}, fmt.Errorf("failed to list namespaces from /topics: %v", err)
|
||||
}
|
||||
|
||||
// Return actual namespaces found (may be empty if no topics exist)
|
||||
return namespaces, nil
|
||||
}
|
||||
|
||||
// ListTopics retrieves all topics in a namespace from the filer
|
||||
func (c *BrokerClient) ListTopics(ctx context.Context, namespace string) ([]string, error) {
|
||||
// Get filer client to list directories under /topics/{namespace}
|
||||
filerClient, err := c.GetFilerClient()
|
||||
if err != nil {
|
||||
// Return empty list if filer unavailable - no fallback sample data
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
var topics []string
|
||||
err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
|
||||
// List directories under /topics/{namespace} to get topics
|
||||
namespaceDir := fmt.Sprintf("/topics/%s", namespace)
|
||||
request := &filer_pb.ListEntriesRequest{
|
||||
Directory: namespaceDir,
|
||||
}
|
||||
|
||||
stream, streamErr := client.ListEntries(ctx, request)
|
||||
if streamErr != nil {
|
||||
return fmt.Errorf("failed to list namespace directory %s: %v", namespaceDir, streamErr)
|
||||
}
|
||||
|
||||
for {
|
||||
resp, recvErr := stream.Recv()
|
||||
if recvErr != nil {
|
||||
if recvErr == io.EOF {
|
||||
break // End of stream
|
||||
}
|
||||
return fmt.Errorf("failed to receive entry: %v", recvErr)
|
||||
}
|
||||
|
||||
// Only include directories (topics), skip files
|
||||
if resp.Entry != nil && resp.Entry.IsDirectory {
|
||||
topics = append(topics, resp.Entry.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// Return empty list if directory listing fails - no fallback sample data
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
// Return actual topics found (may be empty if no topics exist in namespace)
|
||||
return topics, nil
|
||||
}
|
||||
|
||||
// GetTopicSchema retrieves the flat schema and key columns for a topic
|
||||
// Returns (flatSchema, keyColumns, schemaFormat, error)
|
||||
func (c *BrokerClient) GetTopicSchema(ctx context.Context, namespace, topicName string) (*schema_pb.RecordType, []string, string, error) {
|
||||
// Get filer client to read topic configuration
|
||||
filerClient, err := c.GetFilerClient()
|
||||
if err != nil {
|
||||
return nil, nil, "", fmt.Errorf("failed to get filer client: %v", err)
|
||||
}
|
||||
|
||||
var flatSchema *schema_pb.RecordType
|
||||
var keyColumns []string
|
||||
var schemaFormat string
|
||||
err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
|
||||
// Read topic.conf file from /topics/{namespace}/{topic}/topic.conf
|
||||
topicDir := fmt.Sprintf("/topics/%s/%s", namespace, topicName)
|
||||
|
||||
// First check if topic directory exists
|
||||
_, err := client.LookupDirectoryEntry(ctx, &filer_pb.LookupDirectoryEntryRequest{
|
||||
Directory: topicDir,
|
||||
Name: "topic.conf",
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("topic %s.%s not found: %v", namespace, topicName, err)
|
||||
}
|
||||
|
||||
// Read the topic.conf file content
|
||||
data, err := filer.ReadInsideFiler(ctx, client, topicDir, "topic.conf")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read topic.conf for %s.%s: %v", namespace, topicName, err)
|
||||
}
|
||||
|
||||
// Parse the configuration
|
||||
conf := &mq_pb.ConfigureTopicResponse{}
|
||||
if err = jsonpb.Unmarshal(data, conf); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal topic %s.%s configuration: %v", namespace, topicName, err)
|
||||
}
|
||||
|
||||
// Extract flat schema, key columns, and schema format
|
||||
flatSchema = conf.MessageRecordType
|
||||
keyColumns = conf.KeyColumns
|
||||
schemaFormat = conf.SchemaFormat
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
}
|
||||
|
||||
return flatSchema, keyColumns, schemaFormat, nil
|
||||
}
|
||||
|
||||
// ConfigureTopic creates or modifies a topic using flat schema format
|
||||
func (c *BrokerClient) ConfigureTopic(ctx context.Context, namespace, topicName string, partitionCount int32, flatSchema *schema_pb.RecordType, keyColumns []string) error {
|
||||
if err := c.findBrokerBalancer(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn, err := pb.GrpcDial(ctx, c.brokerAddress, false, c.grpcDialOption)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to broker at %s: %v", c.brokerAddress, err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := mq_pb.NewSeaweedMessagingClient(conn)
|
||||
|
||||
// Create topic configuration using flat schema format
|
||||
_, err = client.ConfigureTopic(ctx, &mq_pb.ConfigureTopicRequest{
|
||||
Topic: &schema_pb.Topic{
|
||||
Namespace: namespace,
|
||||
Name: topicName,
|
||||
},
|
||||
PartitionCount: partitionCount,
|
||||
MessageRecordType: flatSchema,
|
||||
KeyColumns: keyColumns,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to configure topic %s.%s: %v", namespace, topicName, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteTopic removes a topic and all its data
|
||||
// Assumption: There's a delete/drop topic method (may need to be implemented in broker)
|
||||
func (c *BrokerClient) DeleteTopic(ctx context.Context, namespace, topicName string) error {
|
||||
if err := c.findBrokerBalancer(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Implement topic deletion
|
||||
// This may require a new gRPC method in the broker service
|
||||
|
||||
return fmt.Errorf("topic deletion not yet implemented in broker - need to add DeleteTopic gRPC method")
|
||||
}
|
||||
|
||||
// ListTopicPartitions discovers the actual partitions for a given topic via MQ broker
|
||||
func (c *BrokerClient) ListTopicPartitions(ctx context.Context, namespace, topicName string) ([]topic.Partition, error) {
|
||||
if err := c.findBrokerBalancer(); err != nil {
|
||||
// Fallback to default partition when broker unavailable
|
||||
return []topic.Partition{{RangeStart: 0, RangeStop: 1000}}, nil
|
||||
}
|
||||
|
||||
// Get topic configuration to determine actual partitions
|
||||
topicObj := topic.Topic{Namespace: namespace, Name: topicName}
|
||||
|
||||
// Use filer client to read topic configuration
|
||||
filerClient, err := c.GetFilerClient()
|
||||
if err != nil {
|
||||
// Fallback to default partition
|
||||
return []topic.Partition{{RangeStart: 0, RangeStop: 1000}}, nil
|
||||
}
|
||||
|
||||
var topicConf *mq_pb.ConfigureTopicResponse
|
||||
err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
|
||||
topicConf, err = topicObj.ReadConfFile(client)
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// Topic doesn't exist or can't read config, use default
|
||||
return []topic.Partition{{RangeStart: 0, RangeStop: 1000}}, nil
|
||||
}
|
||||
|
||||
// Generate partitions based on topic configuration
|
||||
partitionCount := int32(4) // Default partition count for topics
|
||||
if len(topicConf.BrokerPartitionAssignments) > 0 {
|
||||
partitionCount = int32(len(topicConf.BrokerPartitionAssignments))
|
||||
}
|
||||
|
||||
// Create partition ranges - simplified approach
|
||||
// Each partition covers an equal range of the hash space
|
||||
rangeSize := topic.PartitionCount / partitionCount
|
||||
var partitions []topic.Partition
|
||||
|
||||
for i := int32(0); i < partitionCount; i++ {
|
||||
rangeStart := i * rangeSize
|
||||
rangeStop := (i + 1) * rangeSize
|
||||
if i == partitionCount-1 {
|
||||
// Last partition covers remaining range
|
||||
rangeStop = topic.PartitionCount
|
||||
}
|
||||
|
||||
partitions = append(partitions, topic.Partition{
|
||||
RangeStart: rangeStart,
|
||||
RangeStop: rangeStop,
|
||||
RingSize: topic.PartitionCount,
|
||||
UnixTimeNs: time.Now().UnixNano(),
|
||||
})
|
||||
}
|
||||
|
||||
return partitions, nil
|
||||
}
|
||||
|
||||
// GetUnflushedMessages returns only messages that haven't been flushed to disk yet
|
||||
// Uses buffer_start metadata from disk files for precise deduplication
|
||||
// This prevents double-counting when combining with disk-based data
|
||||
func (c *BrokerClient) GetUnflushedMessages(ctx context.Context, namespace, topicName string, partition topic.Partition, startTimeNs int64) ([]*filer_pb.LogEntry, error) {
|
||||
glog.V(2).Infof("GetUnflushedMessages called for %s/%s, partition: RangeStart=%d, RangeStop=%d",
|
||||
namespace, topicName, partition.RangeStart, partition.RangeStop)
|
||||
|
||||
// Step 1: Find the broker that hosts this partition
|
||||
if err := c.findBrokerBalancer(); err != nil {
|
||||
glog.V(2).Infof("Failed to find broker balancer: %v", err)
|
||||
// Return empty slice if we can't find broker - prevents double-counting
|
||||
return []*filer_pb.LogEntry{}, nil
|
||||
}
|
||||
glog.V(2).Infof("Found broker at address: %s", c.brokerAddress)
|
||||
|
||||
// Step 2: Connect to broker
|
||||
conn, err := pb.GrpcDial(ctx, c.brokerAddress, false, c.grpcDialOption)
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Failed to connect to broker %s: %v", c.brokerAddress, err)
|
||||
// Return empty slice if connection fails - prevents double-counting
|
||||
return []*filer_pb.LogEntry{}, nil
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := mq_pb.NewSeaweedMessagingClient(conn)
|
||||
|
||||
// Step 3: For unflushed messages, always start from 0 to get all in-memory data
|
||||
// The buffer_start metadata in log files uses timestamp-based indices for uniqueness,
|
||||
// but the broker's LogBuffer uses sequential indices internally (0, 1, 2, 3...)
|
||||
// For unflushed data queries, we want all messages in the buffer regardless of their
|
||||
// timestamp-based buffer indices, so we always use 0.
|
||||
topicObj := topic.Topic{Namespace: namespace, Name: topicName}
|
||||
partitionPath := topic.PartitionDir(topicObj, partition)
|
||||
glog.V(2).Infof("Getting buffer start from partition path: %s", partitionPath)
|
||||
|
||||
// Always use 0 for unflushed messages to ensure we get all in-memory data
|
||||
earliestBufferOffset := int64(0)
|
||||
glog.V(2).Infof("Using StartBufferOffset=0 for unflushed messages (buffer offsets are sequential internally)")
|
||||
|
||||
// Step 4: Prepare request using buffer offset filtering only
|
||||
request := &mq_pb.GetUnflushedMessagesRequest{
|
||||
Topic: &schema_pb.Topic{
|
||||
Namespace: namespace,
|
||||
Name: topicName,
|
||||
},
|
||||
Partition: &schema_pb.Partition{
|
||||
RingSize: partition.RingSize,
|
||||
RangeStart: partition.RangeStart,
|
||||
RangeStop: partition.RangeStop,
|
||||
UnixTimeNs: partition.UnixTimeNs,
|
||||
},
|
||||
StartBufferOffset: earliestBufferOffset,
|
||||
}
|
||||
|
||||
// Step 5: Call the broker streaming API
|
||||
glog.V(2).Infof("Calling GetUnflushedMessages gRPC with StartBufferOffset=%d", earliestBufferOffset)
|
||||
stream, err := client.GetUnflushedMessages(ctx, request)
|
||||
if err != nil {
|
||||
glog.V(2).Infof("GetUnflushedMessages gRPC call failed: %v", err)
|
||||
// Return empty slice if gRPC call fails - prevents double-counting
|
||||
return []*filer_pb.LogEntry{}, nil
|
||||
}
|
||||
|
||||
// Step 5: Receive streaming responses
|
||||
var logEntries []*filer_pb.LogEntry
|
||||
for {
|
||||
response, err := stream.Recv()
|
||||
if err != nil {
|
||||
// End of stream or error - return what we have to prevent double-counting
|
||||
break
|
||||
}
|
||||
|
||||
// Handle error messages
|
||||
if response.Error != "" {
|
||||
// Log the error but return empty slice - prevents double-counting
|
||||
// (In debug mode, this would be visible)
|
||||
return []*filer_pb.LogEntry{}, nil
|
||||
}
|
||||
|
||||
// Check for end of stream
|
||||
if response.EndOfStream {
|
||||
break
|
||||
}
|
||||
|
||||
// Convert and collect the message
|
||||
if response.Message != nil {
|
||||
logEntries = append(logEntries, &filer_pb.LogEntry{
|
||||
TsNs: response.Message.TsNs,
|
||||
Key: response.Message.Key,
|
||||
Data: response.Message.Data,
|
||||
PartitionKeyHash: int32(response.Message.PartitionKeyHash), // Convert uint32 to int32
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return logEntries, nil
|
||||
}
|
||||
Reference in New Issue
Block a user