s3vectors: name weed-vector processes servers (#12627)

* s3vectors: call the registered weed-vector processes servers

The gateway's discovery named them workers, the name of the admin
plugin workers. Also drops two comments left without a function.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011UpvafvK8JpagF94MHWqwK

* test/s3vectors: build the Enterprise engine as weed-vector

In an Enterprise checkout, make ./weed-vector builds the distributed
engine, which also serves VectorService, instead of a separate
weed-vector-worker. An open-source checkout builds weed-vector-server
as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011UpvafvK8JpagF94MHWqwK

* test/s3vectors: distributed mode starts two more weed-vector engines

It started weed-vector-worker, which no target builds now, and waited
for a gateway log line that no longer exists. The Enterprise
weed-vector's engines all join the placement controller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011UpvafvK8JpagF94MHWqwK

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chris LuandClaude Opus 5.5 authored and GitHub committed 2026-11-13 20:17:15 -08:00
1 parent a8436a621a
commit 63c99183d1
7 files changed
+66 -79

No files matched your search

+25 -25
View File
@@ -15,7 +15,7 @@ import (
func NewVectorDiscovery(masters func() []pb.ServerAddress, dialOption grpc.DialOption, filerGroup string) *vectorDiscovery {
return &vectorDiscovery{masters: masters, grpcDialOption: dialOption, discover: func(m []pb.ServerAddress, opt grpc.DialOption) []string {
return discoverVectorWorkers(m, opt, filerGroup)
return discoverVectorServers(m, opt, filerGroup)
}}
}
@@ -25,7 +25,7 @@ type vectorDiscovery struct {
discover func([]pb.ServerAddress, grpc.DialOption) []string
mu sync.Mutex
closed bool
worker string
server string
failed string
active map[vector_pb.VectorServiceClient]int
retired map[vector_pb.VectorServiceClient]*grpc.ClientConn
@@ -40,7 +40,7 @@ func (d *vectorDiscovery) Close() error {
defer d.mu.Unlock()
d.closed = true
d.retire()
d.worker, d.conn, d.client = "", nil, nil
d.server, d.conn, d.client = "", nil, nil
return nil
}
@@ -50,9 +50,9 @@ func (d *vectorDiscovery) reset(c vector_pb.VectorServiceClient) {
if c != d.client {
return
}
d.failed = d.worker
d.failed = d.server
d.retire()
d.worker, d.conn, d.client = "", nil, nil
d.server, d.conn, d.client = "", nil, nil
d.nextResolve = time.Time{}
}
@@ -92,7 +92,7 @@ func (d *vectorDiscovery) resolve() {
if d.masters != nil {
masters = d.masters()
}
workers := d.discover(masters, d.grpcDialOption)
servers := d.discover(masters, d.grpcDialOption)
d.mu.Lock()
defer d.mu.Unlock()
// Measured from lookup end so a slow lookup cannot leave the next one already due.
@@ -105,30 +105,30 @@ func (d *vectorDiscovery) resolve() {
close(d.resolving)
d.resolving = nil
}()
if d.closed || len(workers) == 0 {
if d.closed || len(servers) == 0 {
return
}
worker := workers[0]
for _, w := range workers {
server := servers[0]
for _, w := range servers {
if w != d.failed {
worker = w
server = w
break
}
}
for _, w := range workers {
if w == d.worker && w != d.failed {
worker = w
for _, w := range servers {
if w == d.server && w != d.failed {
server = w
break
}
}
if worker != d.worker {
conn, err := pb.GrpcDial(context.Background(), worker, false, d.grpcDialOption)
if server != d.server {
conn, err := pb.GrpcDial(context.Background(), server, false, d.grpcDialOption)
if err != nil {
glog.Warningf("S3 Vectors: dial weed-vector %s: %v", worker, err)
glog.Warningf("S3 Vectors: dial weed-vector %s: %v", server, err)
return
}
d.retire()
d.worker, d.conn = worker, conn
d.server, d.conn = server, conn
d.client = vector_pb.NewVectorServiceClient(conn)
}
}
@@ -138,7 +138,7 @@ const (
vectorRecheckInterval = 500 * time.Millisecond
)
var errNoVectorWorker = status.Error(codes.Unavailable, "no weed-vector registered on master")
var errNoVectorServer = status.Error(codes.Unavailable, "no weed-vector registered on master")
func (d *vectorDiscovery) cli(ctx context.Context) (vector_pb.VectorServiceClient, error) {
if err := ctx.Err(); err != nil {
@@ -168,7 +168,7 @@ func (d *vectorDiscovery) cli(ctx context.Context) (vector_pb.VectorServiceClien
return nil, status.Error(codes.Canceled, "vector discovery closed")
}
if d.client == nil {
return nil, errNoVectorWorker
return nil, errNoVectorServer
}
if d.active == nil {
d.active = make(map[vector_pb.VectorServiceClient]int)
@@ -326,7 +326,7 @@ func (d *vectorDiscovery) QueryVectors(ctx context.Context, in *vector_pb.QueryV
return nil, err
}
func discoverVectorWorkers(masters []pb.ServerAddress, grpcDialOption grpc.DialOption, filerGroup string) []string {
func discoverVectorServers(masters []pb.ServerAddress, grpcDialOption grpc.DialOption, filerGroup string) []string {
for _, master := range masters {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
conn, err := pb.GrpcDial(ctx, master.ToGrpcAddress(), false, grpcDialOption)
@@ -343,15 +343,15 @@ func discoverVectorWorkers(masters []pb.ServerAddress, grpcDialOption grpc.DialO
if err != nil {
continue
}
workers := make([]string, 0, len(resp.ClusterNodes))
servers := make([]string, 0, len(resp.ClusterNodes))
for _, node := range resp.ClusterNodes {
glog.V(0).Infof("S3 Vectors: discovered weed-vector at %s via master %s", node.Address, master)
workers = append(workers, node.Address)
servers = append(servers, node.Address)
}
// A follower can answer with an empty list — workers register with
// A follower can answer with an empty list — servers register with
// the leader, so keep looking rather than accept "none."
if len(workers) > 0 {
return workers
if len(servers) > 0 {
return servers
}
}
return nil
+16 -16
View File
@@ -15,7 +15,7 @@ import (
"google.golang.org/grpc/status"
)
// A worker that registers a moment after a failed lookup must surface inside
// A server that registers a moment after a failed lookup must surface inside
// a caller's retry budget: the no-client recheck window is much shorter than
// the live-client membership refresh.
func TestVectorDiscoveryRechecksRegistration(t *testing.T) {
@@ -28,10 +28,10 @@ func TestVectorDiscoveryRechecksRegistration(t *testing.T) {
}
if _, err := d.cli(t.Context()); status.Code(err) != codes.Unavailable {
t.Fatalf("no registered worker: expected Unavailable, got %v", err)
t.Fatalf("no registered server: expected Unavailable, got %v", err)
}
if _, err := d.cli(t.Context()); status.Code(err) != codes.Unavailable {
t.Fatalf("no registered worker: expected Unavailable, got %v", err)
t.Fatalf("no registered server: expected Unavailable, got %v", err)
}
if got := atomic.LoadInt32(&calls); got != 1 {
t.Fatalf("lookup inside the recheck window hit master again: %d lookups", got)
@@ -48,7 +48,7 @@ func TestVectorDiscoveryRechecksRegistration(t *testing.T) {
d.grpcDialOption = grpc.WithTransportCredentials(insecure.NewCredentials())
if _, err := d.cli(t.Context()); err != nil {
t.Fatalf("worker registered: expected a client, got %v", err)
t.Fatalf("server registered: expected a client, got %v", err)
}
if got := atomic.LoadInt32(&calls); got != 2 {
t.Fatalf("expired recheck window did not rediscover: %d lookups", got)
@@ -79,10 +79,10 @@ func TestVectorDiscoveryThrottlesFromLookupEnd(t *testing.T) {
}
if _, err := d.cli(t.Context()); status.Code(err) != codes.Unavailable {
t.Fatalf("no registered worker: expected Unavailable, got %v", err)
t.Fatalf("no registered server: expected Unavailable, got %v", err)
}
if _, err := d.cli(t.Context()); status.Code(err) != codes.Unavailable {
t.Fatalf("no registered worker: expected Unavailable, got %v", err)
t.Fatalf("no registered server: expected Unavailable, got %v", err)
}
if got := atomic.LoadInt32(&calls); got != 1 {
t.Fatalf("slow lookup was repeated right away: %d lookups", got)
@@ -97,7 +97,7 @@ func TestVectorDiscoveryThrottlesFromLookupEnd(t *testing.T) {
d.nextResolve = time.Time{}
d.mu.Unlock()
if _, err := d.cli(t.Context()); err != nil {
t.Fatalf("worker registered: expected a client, got %v", err)
t.Fatalf("server registered: expected a client, got %v", err)
}
waitResolved(d)
}
@@ -105,7 +105,7 @@ func TestVectorDiscoveryThrottlesFromLookupEnd(t *testing.T) {
left := time.Until(d.nextResolve)
d.mu.Unlock()
if left < vectorResolveInterval-lookup/2 {
t.Fatalf("refresh of a live worker is due in %v, want ~%v", left, vectorResolveInterval)
t.Fatalf("refresh of a live server is due in %v, want ~%v", left, vectorResolveInterval)
}
}
@@ -119,7 +119,7 @@ func waitResolved(d *vectorDiscovery) {
}
// A lookup stuck on an unreachable master must not hold up requests that
// already have a live worker, and concurrent callers start only one lookup.
// already have a live server, and concurrent callers start only one lookup.
func TestVectorDiscoveryLookupDoesNotBlockCachedClient(t *testing.T) {
d := &vectorDiscovery{
grpcDialOption: grpc.WithTransportCredentials(insecure.NewCredentials()),
@@ -129,7 +129,7 @@ func TestVectorDiscoveryLookupDoesNotBlockCachedClient(t *testing.T) {
}
cached, err := d.cli(t.Context())
if err != nil {
t.Fatalf("worker registered: expected a client, got %v", err)
t.Fatalf("server registered: expected a client, got %v", err)
}
var calls int32
@@ -179,7 +179,7 @@ func TestVectorDiscoveryLookupDoesNotBlockCachedClient(t *testing.T) {
}
}
// Callers with no worker wait for the in-flight lookup and share its result
// Callers with no server wait for the in-flight lookup and share its result
// rather than failing while it runs.
func TestVectorDiscoveryUncachedCallersShareLookup(t *testing.T) {
var calls int32
@@ -212,7 +212,7 @@ func TestVectorDiscoveryUncachedCallersShareLookup(t *testing.T) {
}
}
// A failed dial to a new worker must leave the cached connection open.
// A failed dial to a new server must leave the cached connection open.
func TestVectorDiscoveryKeepsConnOnDialError(t *testing.T) {
d := &vectorDiscovery{
grpcDialOption: grpc.WithTransportCredentials(insecure.NewCredentials()),
@@ -222,7 +222,7 @@ func TestVectorDiscoveryKeepsConnOnDialError(t *testing.T) {
}
cached, err := d.cli(t.Context())
if err != nil {
t.Fatalf("worker registered: expected a client, got %v", err)
t.Fatalf("server registered: expected a client, got %v", err)
}
// Without transport credentials the dial fails synchronously.
@@ -287,7 +287,7 @@ func TestVectorDiscoveryWaitingRespectsCancellation(t *testing.T) {
waitResolved(d)
}
func TestVectorDiscoveryRetriesAnotherWorker(t *testing.T) {
func TestVectorDiscoveryRetriesAnotherServer(t *testing.T) {
d := &vectorDiscovery{grpcDialOption: grpc.WithTransportCredentials(insecure.NewCredentials()), discover: func([]pb.ServerAddress, grpc.DialOption) []string {
return []string{"127.0.0.1:9301", "127.0.0.1:9302"}
}}
@@ -302,8 +302,8 @@ func TestVectorDiscoveryRetriesAnotherWorker(t *testing.T) {
t.Fatal(err)
}
defer d.release(second)
if d.worker != "127.0.0.1:9302" {
t.Fatalf("retry selected failed worker: %s", d.worker)
if d.server != "127.0.0.1:9302" {
t.Fatalf("retry selected failed server: %s", d.server)
}
}
+1 -1
View File
@@ -1255,7 +1255,7 @@ func (s *Server) handleCreateIndex(w http.ResponseWriter, r *http.Request) {
vectorErr(w, r, arns, err)
return
}
if !errors.Is(err, errNoVectorWorker) {
if !errors.Is(err, errNoVectorServer) {
switch status.Code(err) {
case codes.InvalidArgument, codes.PermissionDenied, codes.Unauthenticated, codes.FailedPrecondition, codes.AlreadyExists, codes.NotFound, codes.OutOfRange, codes.Unimplemented:
default: