Пример #1
0
        /// <summary>
        /// Notifies of a 'members view' event.
        /// </summary>
        /// <param name="version">The version.</param>
        /// <param name="members">The members.</param>
        public async ValueTask <MembersUpdatedEventArgs> NotifyMembersView(int version, ICollection <MemberInfo> members)
        {
            // FIXME could we process two of these at a time?

            // get a new table
            var table = new MemberTable(version, members);

            // compute changes
            // count 1 for old members, 2 for new members, and then the result is
            // that 1=removed, 2=added, 3=unchanged
            // MemberInfo overrides GetHashCode and can be used as a key here
            var diff = new Dictionary <MemberInfo, int>();

            if (_memberTable == null)
            {
                foreach (var m in table.Members.Values)
                {
                    diff[m] = 2;
                }
            }
            else
            {
                foreach (var m in _memberTable.Members.Values)
                {
                    diff[m] = 1;
                }
                foreach (var m in table.Members.Values)
                {
                    if (diff.ContainsKey(m))
                    {
                        diff[m] += 2;
                    }
                    else
                    {
                        diff[m] = 2;
                    }
                }
            }

            // replace the table
            _memberTable = table;

            // notify the load balancer of the new list of members
            _loadBalancer.NotifyMembers(members.Select(x => x.Id));

            // signal once
            if (Interlocked.CompareExchange(ref _firstMembersViewed, 1, 0) == 0)
            {
                _firstMembersView.Release();
            }

            // process changes, gather events
            var added   = new List <MemberInfo>();
            var removed = new List <MemberInfo>();

            foreach (var(member, status) in diff)
            {
                switch (status)
                {
                case 1:     // old but not new = removed
                    HConsole.WriteLine(this, $"Removed member {member.Id}");
                    removed.Add(member);
                    if (_connections.TryGetValue(member.Id, out var client))
                    {
                        await client.TerminateAsync().CfAwait();     // TODO: consider dying in the background?
                    }
                    break;

                case 2:     // new but not old = added
                    HConsole.WriteLine(this, $"Added member {member.Id}");
                    added.Add(member);
                    break;

                case 3:     // old and new = no change
                    break;

                default:
                    throw new NotSupportedException();
                }
            }

            return(new MembersUpdatedEventArgs(added, removed, table.Members.Values));
        }