예제 #1
0
        public virtual (IReplica Replica, bool IsNew) GetOrRegister(PublicationRef publicationRef, Func <IReplica> replicaFactory)
        {
            var random = publicationRef.PublicationId.HashCode;

            OnOperation(random);
            var spinWait   = new SpinWait();
            var newReplica = (IReplica?)null;  // Just to make sure we store this ref

            while (true)
            {
                // ReSharper disable once HeapView.CanAvoidClosure
                var handle = _handles.GetOrAdd(publicationRef, _ => {
                    newReplica = replicaFactory.Invoke();
                    return(_gcHandlePool.Acquire(newReplica, random));
                });
                var target = (IReplica?)handle.Target;
                if (target != null)
                {
                    if (target == newReplica)
                    {
                        return(target, true);
                    }
                    (newReplica as IReplicaImpl)?.DisposeTemporaryReplica();
                    return(target, false);
                }
                // GCHandle target == null => we have to recycle it
                if (_handles.TryRemove(publicationRef, handle))
                {
                    // The thread that succeeds in removal releases gcHandle as well
                    _gcHandlePool.Release(handle, random);
                }
                // And since we didn't manage to add the replica, let's retry
                spinWait.SpinOnce();
            }
        }
예제 #2
0
        public virtual void Register(IComputed computed)
        {
            // Debug.WriteLine($"{nameof(Register)}: {computed}");
            var key    = computed.Input;
            var random = Randomize(key.HashCode);

            OnOperation(random);

            var      spinWait  = new SpinWait();
            GCHandle?newHandle = null;

            while (computed.ConsistencyState != ConsistencyState.Invalidated)
            {
                if (_storage.TryGetValue(key, out var handle))
                {
                    var target = (IComputed?)handle.Target;
                    if (target == computed)
                    {
                        break;
                    }
                    if (target == null || target.ConsistencyState == ConsistencyState.Invalidated)
                    {
                        if (_storage.TryRemove(key, handle))
                        {
                            _gcHandlePool.Release(handle, random);
                        }
                    }
                    else
                    {
                        // This typically triggers Unregister -
                        // except for ReplicaClientComputed.
                        target.Invalidate();
                    }
                }
                else
                {
                    newHandle ??= _gcHandlePool.Acquire(computed, random);
                    if (_storage.TryAdd(key, newHandle.GetValueOrDefault()))
                    {
                        if (computed.ConsistencyState == ConsistencyState.Invalidated)
                        {
                            if (_storage.TryRemove(key, handle))
                            {
                                _gcHandlePool.Release(handle, random);
                            }
                        }
                        break;
                    }
                }
                spinWait.SpinOnce();
            }
        }