mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-06 20:17:38 +01:00
mount: advance the handle watermark for every acknowledged local mutation
Flush was the only path stamping the watermark, so a truncate or setattr through saveEntry, a server-side CopyFileRange, or a remote cache download whose response carried no metadata event could still be rolled back by an older queued subscription event in a read-through directory. saveEntry now stamps any open handle for the saved path, and every site tolerates a response without an event: the metadata cache tracks the newest filer log timestamp seen in any applied event, and that position, captured before the RPC, is a safe lower bound for the state the filer served — anything it returns is at least as new as every event already delivered.
This commit is contained in:
1 parent
ed015b0d6b
commit
36b25fca76
9 files changed
+214
-3
No files matched your search
@@ -6,6 +6,7 @@ import (
|
||||
"math"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sync/singleflight"
|
||||
@@ -42,6 +43,7 @@ type MetaCache struct {
|
||||
buildingDirs map[util.FullPath]*directoryBuildState
|
||||
dedupRing dedupRingBuffer
|
||||
includeSystemEntries bool
|
||||
latestEventTsNs atomic.Int64 // newest filer log timestamp seen in any applied event
|
||||
|
||||
// Entry invalidations run on a worker, not inline on the apply loop:
|
||||
// invalidateFunc takes the fh lock, which a flush can hold while waiting on
|
||||
@@ -574,6 +576,7 @@ type metadataResponseSideEffects struct {
|
||||
}
|
||||
|
||||
func (mc *MetaCache) applyMetadataResponseNow(ctx context.Context, resp *filer_pb.SubscribeMetadataResponse, options MetadataResponseApplyOptions) error {
|
||||
mc.advanceLatestEventTs(resp.TsNs)
|
||||
if mc.shouldSkipDuplicateEvent(resp) {
|
||||
return nil
|
||||
}
|
||||
@@ -651,6 +654,26 @@ func (mc *MetaCache) WaitForEntryInvalidations() {
|
||||
mc.invalidateWorker.Drain()
|
||||
}
|
||||
|
||||
func (mc *MetaCache) advanceLatestEventTs(tsNs int64) {
|
||||
if tsNs == 0 {
|
||||
return
|
||||
}
|
||||
for {
|
||||
current := mc.latestEventTsNs.Load()
|
||||
if tsNs <= current || mc.latestEventTsNs.CompareAndSwap(current, tsNs) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LatestEventTsNs returns the newest filer log timestamp seen in any applied
|
||||
// event. A filer RPC issued after reading this serves state at least this
|
||||
// new, so it is a safe watermark baseline when the RPC response carries no
|
||||
// metadata event of its own.
|
||||
func (mc *MetaCache) LatestEventTsNs() int64 {
|
||||
return mc.latestEventTsNs.Load()
|
||||
}
|
||||
|
||||
func (mc *MetaCache) applyMetadataResponseLocked(ctx context.Context, resp *filer_pb.SubscribeMetadataResponse, _ MetadataResponseApplyOptions, allowUncachedInsert bool) (metadataResponseSideEffects, error) {
|
||||
message := resp.GetEventNotification()
|
||||
if message == nil {
|
||||
|
||||
Reference in new issue
Block a user