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

This commit is contained in:
upstream-mirror
2026-09-16 03:23:42 +05:00
commit 89f5be005d
3997 changed files with 961970 additions and 0 deletions

View File

@@ -0,0 +1,233 @@
package winfsp
import (
"strings"
"sync"
"time"
"github.com/seaweedfs/go-fuse/v2/fuse"
)
// pathCache stands in for the dentry and attribute caches the kernel provides
// on the unix mounts. WinFsp addresses every operation by path, so without it
// each operation walks the whole path through Lookup again, and in a directory
// the filer has not listed yet every one of those lookups is a filer round
// trip.
//
// The cache owns one lookup reference per entry, the way the kernel holds one
// until it sends FORGET. An evicted reference sits out one sweep in the
// graveyard before it is returned, so an operation that resolved just before
// the eviction is not left holding a reclaimed inode.
type pathCache struct {
ttl time.Duration
forget func(inode uint64)
mu sync.Mutex
entries map[string]*pathCacheEntry
// Two graveyard generations: an appended reference always survives the
// sweep of the call that appended it, so a caller still using the inode -
// a walk mid-resolution, an operation that looked it up just before - is
// never holding a reference the same call just returned.
graveyard []uint64
prevGraveyard []uint64
lastSweep time.Time
// gen counts purges. A resolve holds no lock across its Lookup RPC, so a
// purge can run between the RPC and the insert; the insert then carries
// exactly the name the purge removed and has to be discarded. The recent
// purges are kept by key so only a purge that covers the inserted name
// discards it: unrelated churn must not starve resolveAndSteal into EIO.
gen uint64
recentPurges []purgeRecord
}
type purgeRecord struct {
key string
prefix bool
}
// maxRecentPurges bounds the purges remembered for the covers check. A resolve
// older than the window is discarded without one, which only costs a retry.
const maxRecentPurges = 128
func (r purgeRecord) covers(key string) bool {
if r.key == key {
return true
}
if !r.prefix {
return false
}
// An empty key with prefix is the whole cache: purge clears every entry
// for it, so it has to cover every in-flight insert too.
return r.key == "" || strings.HasPrefix(key, r.key+"/")
}
// purgedSince reports whether any purge after gen covers key.
func (c *pathCache) purgedSince(gen uint64, key string) bool {
dropped := c.gen - gen
if dropped == 0 {
return false
}
if dropped > uint64(len(c.recentPurges)) {
return true
}
for _, r := range c.recentPurges[uint64(len(c.recentPurges))-dropped:] {
if r.covers(key) {
return true
}
}
return false
}
type pathCacheEntry struct {
inode uint64
attr fuse.Attr
expires time.Time
}
// maxCachedPaths bounds the references parked here. Overflow clears the whole
// cache rather than tracking recency: entries expire within ttl anyway, so
// exact eviction order buys nothing.
const maxCachedPaths = 64 << 10
func newPathCache(ttl time.Duration, forget func(inode uint64)) *pathCache {
return &pathCache{
ttl: ttl,
forget: forget,
entries: map[string]*pathCacheEntry{},
lastSweep: time.Now(),
}
}
// cacheKey canonicalises a WinFsp path. The root maps to "", which is never
// cached: its inode is fixed and holds no reference.
func cacheKey(path string) string {
return strings.Join(splitPath(path), "/")
}
// lookup reports the cached inode and attributes for key. The entry stays in
// the cache; the inode remains valid at least one sweep past its expiry.
func (c *pathCache) lookup(key string) (inode uint64, attr fuse.Attr, ok bool) {
if key == "" {
return 0, fuse.Attr{}, false
}
c.mu.Lock()
defer c.mu.Unlock()
entry, found := c.entries[key]
if !found || time.Now().After(entry.expires) {
return 0, fuse.Attr{}, false
}
return entry.inode, entry.attr, true
}
// snapshot returns the purge generation. A caller about to resolve outside
// the lock passes it back to insert, which discards the entry if any purge ran
// in between.
func (c *pathCache) snapshot() uint64 {
c.mu.Lock()
defer c.mu.Unlock()
return c.gen
}
// insert takes ownership of one lookup reference on inode, in every outcome:
// an entry a covering purge outdated goes to the graveyard instead of the map,
// so the caller may keep using the inode for at least one sweep either way.
func (c *pathCache) insert(key string, inode uint64, attr fuse.Attr, gen uint64) {
if key == "" {
c.forget(inode)
return
}
var pending []uint64
c.mu.Lock()
if c.purgedSince(gen, key) {
c.graveyard = append(c.graveyard, inode)
pending = c.sweepLocked()
c.mu.Unlock()
c.forgetAll(pending)
return
}
if existing, found := c.entries[key]; found {
c.graveyard = append(c.graveyard, existing.inode)
} else if len(c.entries) >= maxCachedPaths {
for _, entry := range c.entries {
c.graveyard = append(c.graveyard, entry.inode)
}
c.entries = map[string]*pathCacheEntry{}
}
c.entries[key] = &pathCacheEntry{inode: inode, attr: attr, expires: time.Now().Add(c.ttl)}
pending = c.sweepLocked()
c.mu.Unlock()
c.forgetAll(pending)
}
// steal removes key and hands its reference to the caller.
func (c *pathCache) steal(key string) (inode uint64, ok bool) {
c.mu.Lock()
defer c.mu.Unlock()
entry, found := c.entries[key]
if !found {
return 0, false
}
delete(c.entries, key)
return entry.inode, true
}
// purge drops key, and everything under it when prefix is set, which a rename
// or removal of a directory needs: the children's cached paths name entries
// that are no longer there.
func (c *pathCache) purge(key string, prefix bool) {
var pending []uint64
c.mu.Lock()
// Recorded even when the map holds nothing: the point is as much the
// in-flight resolve about to insert this very name.
c.gen++
c.recentPurges = append(c.recentPurges, purgeRecord{key: key, prefix: prefix})
if len(c.recentPurges) > maxRecentPurges {
c.recentPurges = append(c.recentPurges[:0], c.recentPurges[len(c.recentPurges)-maxRecentPurges:]...)
}
if entry, found := c.entries[key]; found {
c.graveyard = append(c.graveyard, entry.inode)
delete(c.entries, key)
}
if prefix {
under := key + "/"
for k, entry := range c.entries {
if key == "" || strings.HasPrefix(k, under) {
c.graveyard = append(c.graveyard, entry.inode)
delete(c.entries, k)
}
}
}
pending = c.sweepLocked()
c.mu.Unlock()
c.forgetAll(pending)
}
// sweepLocked returns the generation before last for the caller to forget
// outside the lock, and retires the current one. Sweeps run at most once per
// ttl and an appended reference sits out the sweep of its own call, so every
// reference rests for at least one full ttl after its last possible use.
func (c *pathCache) sweepLocked() []uint64 {
now := time.Now()
if now.Sub(c.lastSweep) < c.ttl {
return nil
}
c.lastSweep = now
pending := c.prevGraveyard
c.prevGraveyard = c.graveyard
c.graveyard = nil
for key, entry := range c.entries {
if now.After(entry.expires) {
// Returned by the next sweep, a full ttl away: served from the map
// until a moment ago, so someone may still be holding it.
c.prevGraveyard = append(c.prevGraveyard, entry.inode)
delete(c.entries, key)
}
}
return pending
}
func (c *pathCache) forgetAll(inodes []uint64) {
for _, inode := range inodes {
c.forget(inode)
}
}