mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-16 03:20:50 +02:00
* mount: apply cached remote entry without blocking the read Reading an uncached remote-mounted file hung forever. The read holds the file-handle shared lock across the on-demand download, then synchronously waits on the metadata apply loop to apply the cached entry. The filer's update event for that same object reaches the apply loop first and runs invalidateFunc, which wants the file-handle exclusive lock — held in shared mode by the still-running read. The loop blocks on the read; the read blocks on the loop. Enqueue the apply without waiting so the read never blocks on the apply loop while holding the lock. The handle is already updated via SetEntry, and the filer subscription delivers the same event regardless. * mount: regression test for uncached remote read deadlock Drives the real Read path through downloadRemoteEntry with a stub filer that broadcasts the matching invalidate event before returning, reproducing the lock-ordering deadlock. Fails (times out) without the fix.
71 lines
2.1 KiB
Go
71 lines
2.1 KiB
Go
package mount
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/mount/meta_cache"
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
func (wfs *WFS) applyLocalMetadataEvent(ctx context.Context, event *filer_pb.SubscribeMetadataResponse) error {
|
|
if ctx == nil {
|
|
ctx = context.Background()
|
|
}
|
|
return wfs.metaCache.ApplyMetadataResponseOwned(ctx, event, meta_cache.LocalMetadataResponseApplyOptions)
|
|
}
|
|
|
|
func (wfs *WFS) applyLocalMetadataEventAsync(event *filer_pb.SubscribeMetadataResponse) {
|
|
wfs.metaCache.ApplyMetadataResponseOwnedAsync(event, meta_cache.LocalMetadataResponseApplyOptions)
|
|
}
|
|
|
|
func metadataDeleteEvent(directory, name string, isDirectory bool) *filer_pb.SubscribeMetadataResponse {
|
|
if name == "" {
|
|
return nil
|
|
}
|
|
return &filer_pb.SubscribeMetadataResponse{
|
|
Directory: directory,
|
|
EventNotification: &filer_pb.EventNotification{
|
|
OldEntry: &filer_pb.Entry{Name: name, IsDirectory: isDirectory},
|
|
},
|
|
}
|
|
}
|
|
|
|
func metadataCreateEvent(directory string, entry *filer_pb.Entry) *filer_pb.SubscribeMetadataResponse {
|
|
if entry == nil {
|
|
return nil
|
|
}
|
|
return &filer_pb.SubscribeMetadataResponse{
|
|
Directory: directory,
|
|
EventNotification: &filer_pb.EventNotification{
|
|
NewEntry: proto.Clone(entry).(*filer_pb.Entry),
|
|
NewParentPath: directory,
|
|
},
|
|
}
|
|
}
|
|
|
|
func metadataUpdateEvent(directory string, entry *filer_pb.Entry) *filer_pb.SubscribeMetadataResponse {
|
|
if entry == nil {
|
|
return nil
|
|
}
|
|
return &filer_pb.SubscribeMetadataResponse{
|
|
Directory: directory,
|
|
EventNotification: &filer_pb.EventNotification{
|
|
OldEntry: &filer_pb.Entry{Name: entry.Name},
|
|
NewEntry: proto.Clone(entry).(*filer_pb.Entry),
|
|
NewParentPath: directory,
|
|
},
|
|
}
|
|
}
|
|
|
|
func metadataEventFromRenameResponse(resp *filer_pb.StreamRenameEntryResponse) *filer_pb.SubscribeMetadataResponse {
|
|
if resp == nil || resp.EventNotification == nil {
|
|
return nil
|
|
}
|
|
return &filer_pb.SubscribeMetadataResponse{
|
|
Directory: resp.Directory,
|
|
EventNotification: proto.Clone(resp.EventNotification).(*filer_pb.EventNotification),
|
|
TsNs: resp.TsNs,
|
|
}
|
|
}
|