Skip to content
This repository has been archived by the owner on Jun 14, 2024. It is now read-only.

Add deterministic asset id generation process for asset caches. #264

Merged
merged 5 commits into from
Nov 7, 2019

Conversation

chrisfromwork
Copy link
Contributor

@chrisfromwork chrisfromwork commented Oct 31, 2019

This review addresses: #47. It contains the following changes:

  1. A new AssetId class has been created to use as a key for AssetCacheEntries. This type contains a GUID and long is based on Asset file GUIDs and file identifiers
  2. Asset caches are updated to use this new AssetId key

Breaking Change Details:

Notes:

StringGuid keys for asset caches have been updated to AssetIds so that they can be deterministically created on different computers. This will break old AssetCaches.

Migration Instructions:

  1. Delete asset caches in your Generated.StateSynchronization.AssetCaches\Resources folder (these will be the .asset files).
  2. Call Spectator View -> Update All Asset Caches in your project to regenerate asset caches.
  3. Recompile all player flavors (UWP, iOS, Android) of your application.

@chrisfromwork chrisfromwork added the breaking change Pull request contains a breaking change and requires additional information. label Oct 31, 2019
@@ -59,6 +59,8 @@ protected override TextMeshProBroadcasterChangeType CalculateDeltaChanges()

protected override void SendCompleteChanges(IEnumerable<SocketEndpoint> endpoints)
{
previousText = this.textMesh.text;
previousProperties = new TextMeshProperties(textMesh);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was some weird behavior here where font details were sent prior to populating on this first call to SendCompleteChanges

@chrisfromwork chrisfromwork changed the title Add deterministic asset id generation process for asset caches. Add deterministic asset id generation process for asset caches and defer loading assets. Nov 5, 2019
@chrisfromwork chrisfromwork changed the title Add deterministic asset id generation process for asset caches and defer loading assets. Add deterministic asset id generation process for asset caches. Nov 6, 2019
m_storage: 74fae14d-39c0-497e-ae6d-72f1f2084231
Asset: {fileID: 21300000, guid: d651fc00b471cfe44834a222e9433461, type: 3}
guid:
m_storage: 00000000-0000-0000-f000-000000000000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

00000000-0000-0000-f000-000000000000 [](start = 19, length = 36)

This GUID seems to be strannnnnnnnnnngely full of zeros - is it just the case that some portion of our deterministic guids are going to look like this?

It's just interesting seeing a bunch of other GUIDs that look like regular GUIDs, and then seeing this guid (and the c000 one) which looks like a bunch of zeroes that then got smashed by a cosmic ray.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have seen guids like this for Unity's default assets. Things like cube and cone meshes have similar guids.

}
}

CleanUpUnused(oldAssets, unvisitedAssets);
assets = oldAssets.Values.ToArray();
assets = oldAssets.Values.OrderBy(x => x.AssetId.FileIdentifier).ThenBy(x => x.AssetId.Guid).ToArray();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OrderBy(x => x.AssetId.FileIdentifier).ThenBy(x => x.AssetId.Guid) [](start = 38, length = 66)

If we're changing the mechanics of how our assets are enumerated (i.e. the EnumerateAllAssets). it might be worth documenting in the surfaces where this is exposed (i.e. EnumerateAllAssets will enumerate assets on File Identifier and then Guid)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't we want to orderby Guid first, then file Id? As Guid represents the file, and fileId is the id within that file

[SerializeField]
private StringGuid guid;

public long FileIdentifier => fileIdentifier;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FileIdentifier [](start = 20, length = 14)

Can you add a comment about what "FileIdentifier" is?

It's possible that this location isn't the right place for the comment (i.e. it's somewhat abstract at this location) but I'm trying to get a little more clarity for a reader who sees an abstract number (i.e. file ID), then look at this code, and ideally there should be some explanation/direction that this point that guides them to what's up

@wiwei
Copy link
Contributor

wiwei commented Nov 7, 2019

        return new StringGuid { m_storage = rhs.ToString("D") };

Now that I'm seeing this in two places, what's the significance of "D"? Is it just a sentinel string (i.e. "private static string INVALID_GUID = "D"?)


Refers to: src/SpectatorView.Unity/Assets/SpectatorView/Scripts/StateSynchronization/StringGuid.cs:17 in 07dadf2. [](commit_id = 07dadf2, deletion_comment = False)

Copy link
Contributor

@wiwei wiwei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@chrisfromwork chrisfromwork merged commit 049aa75 into microsoft:master Nov 7, 2019

public override int GetHashCode()
{
return FileIdentifier.GetHashCode() ^ Guid.ToString().GetHashCode();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will do an allocation everytime you add to the dictionary, because GetHashCode is called, which will create a string from Guid.

Instead, just do Guid.GetHashCode().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I'll pick these changes up in stabilization/1.1.0 with the expectation to merge back into master

}

public static bool operator ==(AssetId lhs, AssetId rhs)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would simplify this to: Equals(lhs, rhs); which would propogate to your Equals override above.

I would update that method to not use this one, as you already did a null check, and "this" can't be null. So just compare Guid and FileIndentierifer.

Also, don't do Guid.ToString() for comparison, just compare Guids. Guid.Tostring() is an allocation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, what aspect of Guid.ToString() is an allocation? StringGuid has a custom ToString definition that just returns the internally stored string value for the Guid. I'm not 100% if historically this type was made for serializtion, but we aren't currently using the default Guid type.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

        public override string ToString()
        {
            return (m_storage == null) ? System.Guid.Empty.ToString("D") : m_storage;
        }

Now looking at:
https://github.com/microsoft/referencesource/blob/master/mscorlib/system/guid.cs

            if (formatCh == 'D' || formatCh == 'd') {
                guidString = string.FastAllocateString(36);
            }

Looks like there is no special-casing for an empty guid, unless I missed it.

@@ -7,7 +7,7 @@
namespace Microsoft.MixedReality.SpectatorView
{
[Serializable]
internal class StringGuid
internal class StringGuid : IComparable
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StringGuid [](start = 19, length = 10)

Out of curiosity, what's wrong with the ordinary GUID? It's already comparable, and should be way faster to work with.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure historically why the GUID wasn't used. is a GUID serializable?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs say that it has SerializableAttribute, so it should be.

I'm genuinely curious why the string representation was chosen instead. Maybe there was some issue with the Unity integration?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
breaking change Pull request contains a breaking change and requires additional information.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants