From cc634da5bd2b5d3702ac68554c2cad15cced8b5a Mon Sep 17 00:00:00 2001 From: pingqiu Date: Sun, 8 Feb 2026 14:50:29 -0800 Subject: [PATCH] feat(uds): include .dat file path in locate response Add DatPathLen (2 bytes at offset 24) + variable-length DatPath after the 32-byte header. Solves the filename mismatch where sra-volume assumed {vol}.dat but SeaweedFS uses {collection}_{vol}.dat. Backward compatible: old clients that only read 32 bytes still work (DatPathLen is in the formerly-reserved region, and the trailing path bytes are simply ignored by old readers). Co-Authored-By: Claude Opus 4.6 --- weed/server/volume_server_uds.go | 44 +++++++++++++++++++-------- weed/server/volume_server_uds_test.go | 6 ++++ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/weed/server/volume_server_uds.go b/weed/server/volume_server_uds.go index 6442fb32e..e11354051 100644 --- a/weed/server/volume_server_uds.go +++ b/weed/server/volume_server_uds.go @@ -15,8 +15,9 @@ import ( // UDS protocol constants const ( - UdsRequestSize = 24 // fid(16) + version(4) + flags(4) - UdsResponseSize = 32 // status(1) + pad(3) + volume_id(4) + offset(8) + length(8) + reserved(8) + UdsRequestSize = 24 // fid(16) + version(4) + flags(4) + UdsResponseSize = 32 // status(1) + pad(3) + volume_id(4) + offset(8) + length(8) + dat_path_len(2) + reserved(6) + UdsMaxDatPathLen = 256 // max .dat file path length ) // UDS status codes @@ -43,12 +44,14 @@ type LocateRequest struct { // LocateResponse represents a UDS locate response type LocateResponse struct { - Status uint8 - _pad [3]byte - VolumeId uint32 - Offset uint64 - Length uint64 - _ [8]byte // reserved + Status uint8 + _pad [3]byte + VolumeId uint32 + Offset uint64 + Length uint64 + DatPathLen uint16 // length of .dat file path (follows the 32-byte header) + _ [6]byte // reserved + DatPath string // variable-length .dat file path (not in wire header) } // NewUdsServer creates a new UDS server for the volume server @@ -142,7 +145,7 @@ func (u *UdsServer) handleConnection(conn net.Conn) { // Handle request resp := u.handleLocate(&req) - // Serialize response + // Serialize response header (32 bytes) respBuf[0] = resp.Status respBuf[1] = 0 respBuf[2] = 0 @@ -150,13 +153,22 @@ func (u *UdsServer) handleConnection(conn net.Conn) { binary.LittleEndian.PutUint32(respBuf[4:8], resp.VolumeId) binary.LittleEndian.PutUint64(respBuf[8:16], resp.Offset) binary.LittleEndian.PutUint64(respBuf[16:24], resp.Length) - // reserved bytes 24-32 are zero + binary.LittleEndian.PutUint16(respBuf[24:26], resp.DatPathLen) + // reserved bytes 26-32 are zero - // Write response + // Write fixed header if _, err := conn.Write(respBuf); err != nil { glog.V(2).Infof("UDS write error: %v", err) return } + + // Write variable-length .dat path if present + if resp.DatPathLen > 0 { + if _, err := conn.Write([]byte(resp.DatPath)); err != nil { + glog.V(2).Infof("UDS write dat path error: %v", err) + return + } + } } } @@ -228,6 +240,14 @@ func (u *UdsServer) handleLocate(req *LocateRequest) *LocateResponse { resp.Offset = uint64(nv.Offset.ToActualOffset()) resp.Length = uint64(nv.Size) - glog.V(3).Infof("UDS: located %s -> vol=%d offset=%d size=%d", fid, volumeId, resp.Offset, resp.Length) + // Include .dat file path so sidecar knows the exact filename + // (SeaweedFS uses {collection}_{id}.dat when collection is non-empty) + datPath := v.DataFileName() + ".dat" + if len(datPath) <= UdsMaxDatPathLen { + resp.DatPath = datPath + resp.DatPathLen = uint16(len(datPath)) + } + + glog.V(3).Infof("UDS: located %s -> vol=%d offset=%d size=%d dat=%s", fid, volumeId, resp.Offset, resp.Length, datPath) return resp } diff --git a/weed/server/volume_server_uds_test.go b/weed/server/volume_server_uds_test.go index 0a1f6de1e..f860c7b0f 100644 --- a/weed/server/volume_server_uds_test.go +++ b/weed/server/volume_server_uds_test.go @@ -167,6 +167,12 @@ func TestUdsServerProtocol(t *testing.T) { if status != UdsStatusError { t.Errorf("Expected UdsStatusError (%d) for nil VolumeServer, got %d", UdsStatusError, status) } + + // DatPathLen should be 0 for error responses + datPathLen := binary.LittleEndian.Uint16(respBuf[24:26]) + if datPathLen != 0 { + t.Errorf("Expected DatPathLen=0 for error, got %d", datPathLen) + } } // TestUdsSocketCleanup tests that existing socket is removed