/// <summary>
        /// Removes the provided actor and all cataloged state from this registry.
        /// This method expects an external transaction to be provided for managing atomicity
        /// </summary>
        /// <param name="tx">The <see cref="ITransaction"/> this Remove operation is part of.</param>
        /// <param name="reference"><see cref="ActorReference"/></param>
        /// <param name="cancellationToken"><see cref="CancellationToken"/></param>
        /// <returns><see cref="Task"/></returns>
        protected async Task RemoveActorAsync(ITransaction tx, ActorReference reference, CancellationToken cancellationToken)
        {
            var referenceMap = await GetReferenceMapAsync();

            var indexableRef = new IndexableActorReference(reference);

            var index = await referenceMap.TryRemoveAsync(tx, indexableRef, ReliableCollectionDefaults.WriteTimeout, cancellationToken);

            if (!index.HasValue)
            {
                return;
            }

            var indexMap = await GetIndexMapAsync();

            var state = await indexMap.TryRemoveAsync(tx, index.Value, ReliableCollectionDefaults.WriteTimeout, cancellationToken);

            if (state.HasValue)
            {
                var identityMap = await GetIdentityMapAsync();

                await identityMap.TryRemoveAsync(tx, state.Value.Identity, ReliableCollectionDefaults.WriteTimeout, cancellationToken);

                await OnRemoveActorAsync(tx, state.Value, cancellationToken);
            }
        }
        /// <summary>
        /// Catalogs the provided actor and its identity into this registry.
        /// This method expects an external transaction to be provided for managing atomicity
        /// </summary>
        /// <param name="tx">The <see cref="ITransaction"/> this Add operation is part of.</param>
        /// <param name="reference"><see cref="ActorReference"/> to store into internal state</param>
        /// <param name="identity">The underlying identity of the provided actor. This is not the actor id</param>
        /// <param name="cancellationToken"><see cref="CancellationToken"/></param>
        /// <returns><see cref="Task"/></returns>
        protected async Task AddActorAsync(ITransaction tx, ActorReference reference, Identity identity, CancellationToken cancellationToken)
        {
            var referenceMap = await GetReferenceMapAsync();

            var indexMap = await GetIndexMapAsync();

            var indexableRef = new IndexableActorReference(reference);
            var indexLookup  = await referenceMap.TryGetValueAsync(tx, indexableRef, ReliableCollectionDefaults.ReadTimeout, cancellationToken);

            long       index;
            IndexState state;

            if (indexLookup.HasValue)
            {
                index = indexLookup.Value;
                var stateLookup = await indexMap.TryGetValueAsync(tx, index, ReliableCollectionDefaults.ReadTimeout, cancellationToken);

                if (!stateLookup.HasValue)
                {
                    throw new InvalidOperationException($"{indexableRef.StringRepresentation} is missing its internal IndexState");
                }
                state = stateLookup.Value;
                IndexState newState;
                if (Equals(state.Identity, identity))
                {
                    newState = state;
                }
                else
                {
                    newState = new IndexState
                    {
                        Reference = reference,
                        Identity  = identity,
                        Index     = index
                    };
                    // replace old state
                    await indexMap.SetAsync(tx, index, newState, ReliableCollectionDefaults.WriteTimeout, cancellationToken);
                }

                await OnUpdateActorAsync(tx, state, newState, cancellationToken);
            }
            else
            {
                var identityMap = await GetIdentityMapAsync();

                var existingIndex = await identityMap.TryGetValueAsync(tx, identity, ReliableCollectionDefaults.ReadTimeout, cancellationToken);

                if (existingIndex.HasValue)
                {
                    var existingState = await indexMap.TryGetValueAsync(tx, existingIndex.Value);

                    throw new InvalidOperationException($"{identity} is already registered to Actor {new IndexableActorReference(existingState.Value.Reference).StringRepresentation}");
                }

                var propertiesMap = await GetPropertiesMapAsync();

                index = (long)await propertiesMap.AddOrUpdateAsync(tx, "currentIndex", 1L, (key, value) => (long)value + 1, ReliableCollectionDefaults.WriteTimeout, cancellationToken);

                state = new IndexState
                {
                    Reference = reference,
                    Identity  = identity,
                    Index     = index
                };

                await referenceMap.AddAsync(tx, indexableRef, index, ReliableCollectionDefaults.WriteTimeout, cancellationToken);

                await indexMap.AddAsync(tx, index, state, ReliableCollectionDefaults.WriteTimeout, cancellationToken);

                await identityMap.AddAsync(tx, identity, index, ReliableCollectionDefaults.WriteTimeout, cancellationToken);

                await OnAddActorAsync(tx, state, cancellationToken);
            }
        }