mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-14 02:20:41 +02:00
* fix(wdclient,volume): compare master leader with ServerAddress.Equals Raft leader is advertised as host:httpPort.grpcPort, but clients dial host:httpPort. Raw string comparison against VolumeLocation.Leader / HeartbeatResponse.Leader therefore never matches, causing the masterclient and the volume server heartbeat loop to continuously "redirect" to the already-connected master, tearing down the stream and reconnecting. Use ServerAddress.Equals, which normalizes the grpc-port suffix. * fix(filer,mq): compare ServerAddress via Equals in two more sites filer bootstrap skip (MaybeBootstrapFromOnePeer) and the broker's local partition assignment check both compared a wire-supplied address string against the local self ServerAddress with raw string equality. Both are vulnerable to the same plain-vs-host:port.grpcPort mismatch as the masterclient/volume heartbeat sites: filer would bootstrap from itself, and the broker would fail to claim a partition it was actually assigned. Route both through ServerAddress.Equals. * fix(master,shell): more ServerAddress comparisons via Equals - raft_server_handlers.go HealthzHandler: s.serverAddr == leader would skip the child-lock check on the real leader when the two carry different plain/grpc-suffix forms, returning 200 OK instead of 423. - master_server.go SetRaftServer leader-change callback: the Leader() == Name() guard for ensureTopologyId could disagree with topology.IsLeader() (which already uses Equals), so leader-only initialization could be skipped after an election. - command_volume_merge.go isReplicaServer: the -target guard compared user-supplied host:port against NewServerAddressFromDataNode(...) with ==, letting an existing replica slip through when topology carries the embedded gRPC port. All routed through pb.ServerAddress.Equals. * fix(mq,cluster): more ServerAddress comparisons via Equals - broker_grpc_lookup.go GetTopicPublishers/GetTopicSubscribers: the partition ownership check gated listing on raw LeaderBroker == BrokerAddress().String(), so listings silently omitted partitions hosted locally when the assignment carried the other host:port / host:port.grpcPort form. - lock_client.go: LockHostMovedTo comparison and the seedFiler fallback guard both used raw string equality against configured filer addresses (which may be plain host:port while LockHostMovedTo comes back suffixed), causing spurious host-change churn and blocking the seed-filer fallback. * fix(mq): more ServerAddress comparisons via Equals - pub_balancer/allocate.go EnsureAssignmentsToActiveBrokers: direct activeBrokers.Get() lookup missed brokers when a persisted assignment carried a different address encoding than the registered broker key, triggering a bogus reassignment on every read/write cycle. Added a findActiveBroker helper that falls back to an Equals-based scan and canonicalizes the assignment in place so later writes are stable. - broker_grpc_lookup.go isLockOwner: used raw string equality between LockOwner() and BrokerAddress().String(), so a lock owner could fail to recognize itself and proxy local lookup/config/admin RPCs away. - pub_client/scheduler.go onEachAssignments: reused publisher jobs only on exact LeaderBroker match, so an encoding flip in lookup results tore down and recreated a stream to the same broker.
63 lines
1.7 KiB
Go
63 lines
1.7 KiB
Go
package weed_server
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/cenkalti/backoff/v4"
|
|
"github.com/seaweedfs/seaweedfs/weed/glog"
|
|
"github.com/seaweedfs/seaweedfs/weed/pb"
|
|
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
|
|
)
|
|
|
|
type ClusterStatusResult struct {
|
|
IsLeader bool `json:"IsLeader,omitempty"`
|
|
Leader pb.ServerAddress `json:"Leader,omitempty"`
|
|
Peers []string `json:"Peers,omitempty"`
|
|
MaxVolumeId needle.VolumeId `json:"MaxVolumeId,omitempty"`
|
|
}
|
|
|
|
func (s *RaftServer) StatusHandler(w http.ResponseWriter, r *http.Request) {
|
|
ret := ClusterStatusResult{
|
|
IsLeader: s.topo.IsLeader(),
|
|
Peers: s.Peers(),
|
|
MaxVolumeId: s.topo.GetMaxVolumeId(),
|
|
}
|
|
|
|
if leader, e := s.topo.Leader(); e == nil {
|
|
ret.Leader = leader
|
|
}
|
|
writeJsonQuiet(w, r, http.StatusOK, ret)
|
|
}
|
|
|
|
func (s *RaftServer) HealthzHandler(w http.ResponseWriter, r *http.Request) {
|
|
leader, err := s.topo.Leader()
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
return
|
|
}
|
|
if s.serverAddr.Equals(leader) {
|
|
expBackoff := backoff.NewExponentialBackOff()
|
|
expBackoff.InitialInterval = 20 * time.Millisecond
|
|
expBackoff.MaxInterval = 1 * time.Second
|
|
expBackoff.MaxElapsedTime = 5 * time.Second
|
|
isLocked, err := backoff.RetryWithData(s.topo.IsChildLocked, expBackoff)
|
|
if err != nil {
|
|
glog.Errorf("HealthzHandler: %+v", err)
|
|
}
|
|
if isLocked {
|
|
w.WriteHeader(http.StatusLocked)
|
|
return
|
|
}
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
|
|
func (s *RaftServer) StatsRaftHandler(w http.ResponseWriter, r *http.Request) {
|
|
if s.RaftHashicorp == nil {
|
|
writeJsonQuiet(w, r, http.StatusNotFound, nil)
|
|
return
|
|
}
|
|
writeJsonQuiet(w, r, http.StatusOK, s.RaftHashicorp.Stats())
|
|
}
|