Files
seaweedfs/weed/mount/weedfs_write.go
T
bdcc3154ed refactor: centralize genUploadUrl in UploadOption (#10164)
* refactor: centralize genUploadUrl in UploadOption

Replace inline genFileUrlFn closures with operation.GenUploadUrl field:

- Add GenUploadUrl func(host, fileId) string to UploadOption struct
- Add GenUploadUrlProxy(filerAddress string) utility function
- Remove genFileUrlFn parameter from UploadWithRetry signature
- Update all callers: mount, gateway, mq, filer_copy, filer_sync

This matches the weed mount -filerProxy pattern exactly,
factorizing the URL generation logic across all consumers.

Co-Authored-By: Athena 🏛️ <hermes-agent@local> (custom / Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf)

* docker release: run all platform jobs in one wave, cache rocksdb compile

Drop max-parallel so the 13 per-platform builds run together instead of two
waves of 8 (rocksdb was queuing behind the cap and starting ~8 min late).

Keep cache-to mode=max for rocksdb: its RocksDB static_lib compile is
sha-independent, so it caches across releases and stops being the ~16-min
long-pole that gates the merge fan-in. go-build variants stay mode=min.

Co-Authored-By: Athena 🏛️ <hermes-agent@local> (custom / Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf)

* refactor: centralize genUploadUrl in UploadOption

Replace inline genFileUrlFn closures with operation.GenUploadUrl field:

- Add GenUploadUrl func(host, fileId) string to UploadOption struct
- Add GenUploadUrlProxy(filerAddress string) utility function
- Remove genFileUrlFn parameter from UploadWithRetry signature
- Update all callers: mount, gateway, mq, filer_copy, filer_sync

This matches the weed mount -filerProxy pattern exactly,
factorizing the URL generation logic across all consumers.

Co-Authored-By: Athena 🏛️ <hermes-agent@local> (custom / Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf)

* Remove accidental ROCmFPX submodule reference

* gofmt chunk upload option block

* Preserve broker cipher and re-read proxy filer per upload attempt

Chunk uploads must keep the configured Cipher, and both the mount and broker current filer can change on failover, so build the proxy upload URL inside the closure instead of capturing the address once.

---------

Co-authored-by: Chris Lu <chris.lu@gmail.com>
2026-06-30 20:45:43 -07:00

96 lines
3.5 KiB
Go

package mount
import (
"fmt"
"io"
"github.com/seaweedfs/seaweedfs/weed/filer"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/operation"
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
"github.com/seaweedfs/seaweedfs/weed/util"
)
func (wfs *WFS) saveDataAsChunk(fullPath util.FullPath) filer.SaveDataAsChunkFunctionType {
// Backstop: FUSE entry points sanitize names before they reach
// inodeToPath, but async flush paths (e.g. writebackCache, handles whose
// RememberPath was set from an older code path) may still carry bytes
// that predate sanitization. Proto3 string fields require valid UTF-8,
// so scrub the full path once here before every AssignVolume call.
assignPath := fullPath.Sanitized()
return func(reader io.Reader, filename string, offset int64, tsNs int64, _ uint64) (chunk *filer_pb.FileChunk, err error) {
uploader, err := operation.NewUploader()
if err != nil {
return
}
// WantMd5 gives mount writes a real filer.ETag (server echoes Content-MD5 back).
uploadOption := &operation.UploadOption{
Filename: filename,
Cipher: wfs.option.Cipher,
IsInputCompressed: false,
MimeType: "",
PairMap: nil,
WantMd5: true,
}
if wfs.option.VolumeServerAccess == "filerProxy" {
// getCurrentFiler() can change on failover, so read it per attempt.
uploadOption.GenUploadUrl = func(host, fileId string) string {
return fmt.Sprintf("http://%s/?proxyChunkId=%s", wfs.getCurrentFiler(), fileId)
}
}
fileId, uploadResult, err, data := uploader.UploadWithRetry(
wfs,
&filer_pb.AssignVolumeRequest{
Count: 1,
Replication: wfs.option.Replication,
Collection: wfs.option.Collection,
TtlSec: wfs.option.TtlSec,
DiskType: string(wfs.option.DiskType),
DataCenter: wfs.option.DataCenter,
Path: assignPath,
},
uploadOption, reader,
)
if err != nil {
glog.V(0).Infof("upload data %v: %v", filename, err)
return nil, fmt.Errorf("upload data: %w", err)
}
if uploadResult.Error != "" {
glog.V(0).Infof("upload failure %v: %v", filename, err)
return nil, fmt.Errorf("upload result: %v", uploadResult.Error)
}
// When peer sharing is enabled we need EVERY chunk in the
// local cache so we can actually serve it back to peers on
// FetchChunk — otherwise the directory would advertise us as
// a holder and the fetcher would get NOT_FOUND from our
// chunk cache. When peer sharing is off we preserve the
// original behavior of caching only the first chunk (small
// files) to avoid blowing the cache on large uploads. Both
// paths gate on chunkCache != nil: -cacheCapacityMB=0 disables
// the cache entirely, in which case SetChunk would panic.
shouldCache := wfs.chunkCache != nil && (offset == 0 || wfs.peerAnnouncer != nil)
if shouldCache {
wfs.chunkCache.SetChunk(fileId, data)
}
// Announce every uploaded chunk so the tier-2 directory fills
// in as the file is written. Without this, the per-fetch
// announce path only bootstraps after someone else has already
// pulled a chunk via peer — which can't happen if nobody has
// told the directory who holds the chunk. Skip the announce
// when we couldn't cache (no point advertising bytes we can't
// actually serve back).
if wfs.peerAnnouncer != nil && shouldCache {
wfs.peerAnnouncer.EnqueueAnnounce(fileId)
}
chunk = uploadResult.ToPbFileChunk(fileId, offset, tsNs)
return chunk, nil
}
}