Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / ConnectAlgorithms.cs / 1 / ConnectAlgorithms.cs
//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------- namespace System.ServiceModel.Channels { using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.ServiceModel; using System.ServiceModel.Diagnostics; using System.Threading; // Graph maintainence algorithms. sealed class ConnectAlgorithms : IConnectAlgorithms { static Random random = new Random(); int wantedConnectionCount = 0; EventWaitHandle addNeighbor = new EventWaitHandle(true, EventResetMode.ManualReset); EventWaitHandle maintainerClosed = new EventWaitHandle(false, EventResetMode.ManualReset); EventWaitHandle welcomeReceived = new EventWaitHandle(false, EventResetMode.ManualReset); DictionarynodeAddresses = new Dictionary (); PeerNodeConfig config; Dictionary pendingConnectedNeighbor = new Dictionary (); object thisLock = new object(); IPeerMaintainer maintainer = null; bool disposed = false; public void Initialize(IPeerMaintainer maintainer, PeerNodeConfig config, int wantedConnectionCount, Dictionary referralCache) { this.maintainer = maintainer; this.config = config; this.wantedConnectionCount = wantedConnectionCount; UpdateEndpointsCollection(referralCache.Values); // Add to the endpoints connection anything in the referralsCache // Hook up the event handlers maintainer.NeighborClosed += OnNeighborClosed; maintainer.NeighborConnected += OnNeighborConnected; maintainer.MaintainerClosed += OnMaintainerClosed; maintainer.ReferralsAdded += OnReferralsAdded; } // instance lock object ThisLock { get { return thisLock; } } public void Connect(TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); addNeighbor.Set(); // We are trying to add a neighbor List results = new List (); List handles = new List (); // While we have more to endpoints try and we have connections pending and we are not connected upto ideal yet, and the maintainer is still open while (results.Count != 0 || (((nodeAddresses.Count != 0 || pendingConnectedNeighbor.Count != 0) && maintainer.IsOpen) && maintainer.ConnectedNeighborCount < wantedConnectionCount)) { try { handles.Clear(); foreach (IAsyncResult iar in results) { handles.Add(iar.AsyncWaitHandle); } handles.Add(welcomeReceived); // One of our connect requests resulted in a welcome or neighborManager was shutting down handles.Add(maintainerClosed); // One of our connect requests resulted in a welcome or neighborManager was shutting down handles.Add(addNeighbor); // Make the last waithandle the add a neighbor signal int index = WaitHandle.WaitAny(handles.ToArray(), config.ConnectTimeout, false); if (index == results.Count) // welcomeReceived was signalled { welcomeReceived.Reset(); } else if (index == results.Count + 1) // maintainerClosed was signalled { maintainerClosed.Reset(); lock (ThisLock) { nodeAddresses.Clear(); } } else if (index == results.Count + 2) // addNeighbor was signalled { // We need to open a new neighbor if (nodeAddresses.Count > 0) { if (pendingConnectedNeighbor.Count + maintainer.ConnectedNeighborCount < wantedConnectionCount) { PeerNodeAddress epr = null; lock (ThisLock) { if (nodeAddresses.Count == 0 || !maintainer.IsOpen) // nodeAddresses or maintainer is closed got updated better cycle { addNeighbor.Reset(); continue; } int index2 = random.Next() % nodeAddresses.Count; ICollection keys = nodeAddresses.Keys; int i = 0; Uri key = null; foreach (Uri uri in keys) { if (i++ == index2) { key = uri; break; } } DiagnosticUtility.DebugAssert(key != null, "key cannot be null here"); epr = nodeAddresses[key]; DiagnosticUtility.DebugAssert(epr != null, "epr cannot be null here"); nodeAddresses.Remove(key); } if (maintainer.FindDuplicateNeighbor(epr) == null && pendingConnectedNeighbor.ContainsKey(GetEndpointUri(epr)) == false) { lock (ThisLock) { pendingConnectedNeighbor.Add(GetEndpointUri(epr), epr); } // If the neighborManager is not open this call is going to throw. // It throws ObjectDisposed exception. // This check merely eliminates the perf hit, this check is not strictly necessary // but cuts down the window for the race that will result in a throw to a miniscule level // We consume the throw because we are closing down try { if (maintainer.IsOpen) { if (DiagnosticUtility.ShouldTraceInformation) { PeerMaintainerTraceRecord record = new PeerMaintainerTraceRecord(SR.GetString(SR.PeerMaintainerConnect,epr, this.config.MeshId)); TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PeerMaintainerActivity, record, this, null); } IAsyncResult iar = maintainer.BeginOpenNeighbor(epr, timeoutHelper.RemainingTime(), null, epr); results.Add(iar); } } catch (Exception e) { if(DiagnosticUtility.IsFatal(e)) throw; if (DiagnosticUtility.ShouldTraceInformation) { PeerMaintainerTraceRecord record = new PeerMaintainerTraceRecord(SR.GetString(SR.PeerMaintainerConnectFailure,epr, this.config.MeshId, e.Message)); TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PeerMaintainerActivity, record, this, null); } // I need to remove the epr just began because the BeginOpen threw. // However Object Disposed can arise as a result of a race between PeerNode.Close() // and Connect trying to reconnect nodes. pendingConnectedNeighbor.Remove(GetEndpointUri(epr)); if (!(e is ObjectDisposedException)) throw; DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } } } } if (nodeAddresses.Count == 0 || pendingConnectedNeighbor.Count + maintainer.ConnectedNeighborCount == wantedConnectionCount) { addNeighbor.Reset(); } } else if (index != WaitHandle.WaitTimeout) { // We have completed this thing remove it from results IAsyncResult iar = results[index]; results.RemoveAt(index); IPeerNeighbor neighbor = null; try { // Get opened neighbor and fire NeighborOpened notification neighbor = maintainer.EndOpenNeighbor(iar); } catch(Exception e) { if(DiagnosticUtility.IsFatal(e)) throw; pendingConnectedNeighbor.Remove(GetEndpointUri((PeerNodeAddress)iar.AsyncState)); throw; } } else { //A timeout occured no connections progressed, try some more connections //This may result in more than wantedConnectionCount connections if the timeout connections were // merely being slow pendingConnectedNeighbor.Clear(); results.Clear(); addNeighbor.Set(); } } catch (CommunicationException e) { // mostly likely the endpoint could not be reached, but any channel exception means we should try another node DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); addNeighbor.Set(); } catch (TimeoutException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); addNeighbor.Set(); } } } void IDisposable.Dispose() { if (!disposed) { lock (ThisLock) { if (!disposed) { disposed = true; maintainer.ReferralsAdded -= OnReferralsAdded; maintainer.MaintainerClosed -= OnMaintainerClosed; maintainer.NeighborClosed -= OnNeighborClosed; maintainer.NeighborConnected -= OnNeighborConnected; addNeighbor.Close(); maintainerClosed.Close(); welcomeReceived.Close(); } } } } // This method exists to minimize code churn if PeerNodeAddress is refactored later to derive from EndpointAddress static Uri GetEndpointUri(PeerNodeAddress address) { return address.EndpointAddress.Uri; } // Algorithm to prune connections // This implementation will reduce the number of connections to config.IdealNeighbors // by examining LinkUtility and selecting the neighbor with the lowest and then disconnecting it public void PruneConnections() { while(maintainer.NonClosingNeighborCount > config.IdealNeighbors && maintainer.IsOpen) { IPeerNeighbor leastUseful = maintainer.GetLeastUsefulNeighbor(); if(leastUseful == null) break; maintainer.CloseNeighbor(leastUseful, PeerCloseReason.NotUsefulNeighbor); } } // Helper method for updating the end points list public void UpdateEndpointsCollection(ICollection src) { if( src != null) { lock (ThisLock) { foreach (PeerNodeAddress address in src) { UpdateEndpointsCollection(address); } } } } public void UpdateEndpointsCollection(ICollection src) { if( src != null) { lock (ThisLock) { foreach (Referral referral in src) { UpdateEndpointsCollection(referral.Address); } } } } void UpdateEndpointsCollection(PeerNodeAddress address) { // Don't accept invalid addresses if (PeerValidateHelper.ValidNodeAddress(address)) { Uri key = GetEndpointUri(address); if (!nodeAddresses.ContainsKey(key) && key != GetEndpointUri(maintainer.GetListenAddress())) { nodeAddresses[key] = address; } } } // When a connection occurs remove it from the list to look at void OnNeighborClosed(IPeerNeighbor neighbor) { if (neighbor.ListenAddress != null) { Uri address = GetEndpointUri(neighbor.ListenAddress); if (!disposed) { lock (ThisLock) { if (!disposed) { if (address != null && pendingConnectedNeighbor.ContainsKey(address)) { pendingConnectedNeighbor.Remove(address); addNeighbor.Set(); } } } } } } // When a connection occurs remove it from the list to look at void OnNeighborConnected(IPeerNeighbor neighbor) { Uri address = GetEndpointUri(neighbor.ListenAddress); if (!disposed) { lock (ThisLock) { if (!disposed) { if (address != null && pendingConnectedNeighbor.ContainsKey(address)) { pendingConnectedNeighbor.Remove(address); } welcomeReceived.Set(); } } } } void OnMaintainerClosed() { if (!disposed) { lock (ThisLock) { if (!disposed) { maintainerClosed.Set(); } } } } // When a connection occurs add those to the group I look at void OnReferralsAdded(IList referrals, IPeerNeighbor neighbor) { bool added = false; // Do some stuff here foreach (Referral referral in referrals) { if (!disposed) { lock (ThisLock) { if (!disposed) { if (!maintainer.IsOpen) return; Uri key = GetEndpointUri(referral.Address); if (key != GetEndpointUri(maintainer.GetListenAddress())) // make sure the referral is not mine { if (!nodeAddresses.ContainsKey(key) && !pendingConnectedNeighbor.ContainsKey(key) && maintainer.FindDuplicateNeighbor(referral.Address) == null) { nodeAddresses[key] = referral.Address; added = true; } } } } } } if(added) { if(maintainer.ConnectedNeighborCount < wantedConnectionCount) { addNeighbor.Set(); } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- QueryContinueDragEvent.cs
- AssemblyGen.cs
- EventWaitHandleSecurity.cs
- XPathNode.cs
- WindowsIPAddress.cs
- UriScheme.cs
- SerializableTypeCodeDomSerializer.cs
- MimeXmlImporter.cs
- WebPartConnectionCollection.cs
- FontWeights.cs
- GrammarBuilderWildcard.cs
- DataContractSerializerElement.cs
- ListView.cs
- ThrowHelper.cs
- SmiConnection.cs
- DbConnectionHelper.cs
- AttributeEmitter.cs
- OleDbConnectionInternal.cs
- CanExecuteRoutedEventArgs.cs
- NegotiateStream.cs
- RegexTree.cs
- RetrieveVirtualItemEventArgs.cs
- DataChangedEventManager.cs
- RequestCachingSection.cs
- _ProxyChain.cs
- RIPEMD160.cs
- PersistChildrenAttribute.cs
- LinkDescriptor.cs
- ValueTypeFixupInfo.cs
- PropertyPushdownHelper.cs
- XPathScanner.cs
- PhysicalAddress.cs
- ContentFilePart.cs
- StringTraceRecord.cs
- GenericTypeParameterConverter.cs
- DiffuseMaterial.cs
- UserPreference.cs
- WinEventHandler.cs
- TcpHostedTransportConfiguration.cs
- MessageSmuggler.cs
- AppDomainAttributes.cs
- UIAgentInitializationException.cs
- DynamicQueryStringParameter.cs
- ThrowHelper.cs
- UserControlCodeDomTreeGenerator.cs
- FlowPanelDesigner.cs
- PersonalizationStateInfoCollection.cs
- MeshGeometry3D.cs
- SpotLight.cs
- ConfigurationSectionCollection.cs
- FormViewDeletedEventArgs.cs
- ScrollPatternIdentifiers.cs
- KerberosRequestorSecurityToken.cs
- TwoPhaseCommitProxy.cs
- InternalConfigHost.cs
- MaskedTextBox.cs
- SqlConnectionString.cs
- XmlSchemaGroupRef.cs
- RepeatButton.cs
- XmlSchemaAnyAttribute.cs
- UriSection.cs
- ReflectPropertyDescriptor.cs
- XmlException.cs
- Image.cs
- LineVisual.cs
- LOSFormatter.cs
- DetailsViewPageEventArgs.cs
- TdsParserHelperClasses.cs
- TableLayoutRowStyleCollection.cs
- UrlUtility.cs
- CodeObject.cs
- SortQueryOperator.cs
- XmlWriterTraceListener.cs
- basecomparevalidator.cs
- complextypematerializer.cs
- DbMetaDataColumnNames.cs
- ProjectionPruner.cs
- SoapAttributeOverrides.cs
- RemotingServices.cs
- ObjectFactoryCodeDomTreeGenerator.cs
- DecoderNLS.cs
- X509Utils.cs
- MDIWindowDialog.cs
- CssTextWriter.cs
- ScriptMethodAttribute.cs
- FamilyTypefaceCollection.cs
- StringArrayEditor.cs
- ContextBase.cs
- NameNode.cs
- Visitor.cs
- DisableDpiAwarenessAttribute.cs
- ServerTooBusyException.cs
- SqlNodeAnnotation.cs
- DurableErrorHandler.cs
- XmlSchemaAttributeGroup.cs
- XsltConvert.cs
- StringCollection.cs
- DataBinding.cs
- RewritingPass.cs
- CheckBoxList.cs