Scope and guarantees of currentSyncAnchor (NSFileProviderReplicatedExtension)

Should currentSyncAnchor(completionHandler:) return a global version number of the backend, or one scoped to the enumerator's container identifier? What should we return if the backend has no per-container version?

Also, how does the system use this anchor? It appears to be followed by enumerateItems(for:startingAt:), but nothing seems to guarantee the anchor hasn't changed in between. Is there an atomicity expectation here?

Answered by Engineer in 891095022

The anchor is associated with the enumerator, and enumerators are created per container (enumeratorForContainerItemIdentifier: in NSFileProviderEnumerating.h). Conceptually it bounds "what this container knew at this point in time."

The system treats the anchor as opaque user-defined data. A global backend version is fine to return as long as your enumerateChanges(for:from:) can answer "what changed in this container between that anchor and now."

There is no atomicity guarantee and the framework doesn't provide one. The header lays out the sequence: request anchor A, enumerate items, then later enumerate changes from A.

The safety invariant is one-directional: the anchor you return must be at or before the state delivered in the subsequent page enumeration. Then any change that landed after A will be picked up by the change enumeration that uses A as its starting point — even if that change also affected the page enumeration (you'll just re-deliver it, which is harmless).

You should not return an anchor newer than your page snapshot or you would silently skip changes that happened in between.

Accepted Answer

The anchor is associated with the enumerator, and enumerators are created per container (enumeratorForContainerItemIdentifier: in NSFileProviderEnumerating.h). Conceptually it bounds "what this container knew at this point in time."

The system treats the anchor as opaque user-defined data. A global backend version is fine to return as long as your enumerateChanges(for:from:) can answer "what changed in this container between that anchor and now."

There is no atomicity guarantee and the framework doesn't provide one. The header lays out the sequence: request anchor A, enumerate items, then later enumerate changes from A.

The safety invariant is one-directional: the anchor you return must be at or before the state delivered in the subsequent page enumeration. Then any change that landed after A will be picked up by the change enumeration that uses A as its starting point — even if that change also affected the page enumeration (you'll just re-deliver it, which is harmless).

You should not return an anchor newer than your page snapshot or you would silently skip changes that happened in between.

That's very clear, thanks! I now see how currentSyncAnchor, enumerateItems, and enumerateChanges work together for the working set.

One more thing I'd like to clarify: what is the role of currentSyncAnchor for containers other than the working set?

From the earlier answers I understand that:

Yet currentSyncAnchor is also called on per-folder enumerators. If the system never asks a folder "what changed since this anchor?", I don't see what that anchor is used for.

Practically: can I return the same anchor for every folder that I currently return for the working set, i.e. one global backend version shared by the working set and all folders? Or is there a reason to scope or optimize it per container?

This is only useful for the working set because the folder enumerators don't use this value.

Scope and guarantees of currentSyncAnchor (NSFileProviderReplicatedExtension)
 
 
Q