Role of _CreateIdentifier in ArResolver implementations

Asset Resolvers are challenging :slight_smile:

I have an asset resolver that is very simple. It is a URL schema resolver that replaces “tmp://” with the value of $TMP. This replacement is done in the _Resolve method, and everything works fine. Then I extended this resolver so that you can set a resolver context from a string to override the value of $TMP. Seems simple enough, and still works fine.

But then I tried to have two stages open at the same time. Both sublayer “tmp://sphere.usda”. But one stage has a resolver context that overrides TMP with /dirA, and the other stage has a resolver context that overrides TMP with /dirB. When I look at these two stages, they are both sublayering in /dirA/sphere.usda (as if they are both using the resolver context of the first stage that gets created).

After a long time I figured out that the problem was I wasn’t using the resolver context in _CreateIdentifier. It is the return value of _CreateIdentifier, I believe, that is used to look up Sdf Layers in the global layer cache. So “tmp://sphere.usda” being returned verbatim from _CreateIdentifier unsurprisingly results in both stages loading the same layer contents regardless of the resolver context value.

To fix this, I changed _CreateIdentifier to call _Resolve, and return the resolved path based on the current resolver context. Then loading “tmp://sphere.usda” in two different stages with two different resolver contexts creates two different entries in the layer cache, and everything works great.

My concern is that this does not seem to be what _CreateIdentifier is supposed to be doing. Because it means that _Resolve is basically never called except from within _CreateIdentifier (because it’s the layer identifier that gets passed to _Resolve, and we’ve already “resolved away” the “tmp://” URL schema in the call to _CreateIdentifier).

Am I doing something wrong here? Am I misunderstanding something? Is there a bug in the asset resolver library or the Sdf layer cache?

When I look at the implementation of ArDefaultResolver::_CreateIdentifier, I can imagine that even this core asset resolver could hit the same problem I was seeing where two stages with two different “search paths” in their resolver contexts could interfere with each other and erroneously load the same layer on disk. This would be in spite of their differing results from calling _Resolve on the same path, because the result of _CreateIdentifier doesn’t rely on the resolver context. So at a minimum there seems to be a bug in the default search path resolver.

Anyway, thanks for any clarifications!
Mark

Hey Mark,

Does your asset resolver implementation already override ArResolver::IsContextDependentPath to return true? If not, give that a try and see if that helps.

I think the issue is that your paths are context-dependent (i.e. they potentially resolve to different locations based on the bound context) but aren’t being reported by your resolver as such. The Sdf layer registry has different behavior for these paths:

  • If a layer uses a context-dependent path as an identifier, the layer registry will use its resolved path (i.e. the result of calling Resolve) as the lookup key for that layer.

  • If a layer uses a non-context-dependent path as an identifier, the layer registry has an optimization where it will try that identifier as the lookup key first, since in this case the identifier will always resolve to the same location regardless of context. This lets us avoid potentially expensive calls to Resolve during layer lookup.

In the default filesystem resolver, search paths are marked as context-dependent paths to avoid exactly the issue you describe.

Let me know if that helps!

  • Sunya
2 Likes

Yes! That’s the secret sauce I was missing. And I’m very glad that it was this simple.

One other key bit here for anyone else facing this issue, you must put:

"implementsContexts" : true

in your plugInfo.json for your resolver or this method won’t be called.

Thanks again Sunya!
Mark

3 Likes