/// <summary> /// Returns a MessageStreamListener instance based on this instance's configuration (timeout, bucket name etc.) /// /// When multiple listeners are requested with the exact same parameters (usually when multiple clients are instantiated from the same configuration), /// the same listener will be returned each time. /// </summary> /// <returns></returns> private MessageStreamListener GetPooledListener() { // create a unique key based on the parameters // to find out if we already have a listener attached to this pool var hcc = new HashCodeCombiner(); hcc.Add(this.Timeout); hcc.Add(this.DeadTimeout); hcc.Add(this.RetryCount); hcc.Add(this.RetryTimeout.GetHashCode()); hcc.Add(this.bucketName.GetHashCode()); if (credential != null) { hcc.Add((this.credential.UserName ?? String.Empty).GetHashCode()); hcc.Add((this.credential.Password ?? String.Empty).GetHashCode()); hcc.Add((this.credential.Domain ?? String.Empty).GetHashCode()); } for (var i = 0; i < this.poolUrls.Length; i++) { hcc.Add(this.poolUrls[i].GetHashCode()); } var hash = hcc.CurrentHash; MessageStreamListener retval; lock (ListenerSync) if (listeners.TryGetValue(hash, out retval)) { listenerRefs[retval].RefCount++; retval.Subscribe(this.HandleMessage); } else { var name = this.bucketName; // create a new listener for the pool urls retval = new MessageStreamListener(poolUrls, heartbeatUri, heartbeatInterval, isHeartbeatEnabled, (client, root) => ResolveBucketUri(client, root, name)); retval.ConnectionTimeout = this.Timeout; retval.DeadTimeout = this.DeadTimeout; retval.Credentials = this.credential; retval.RetryCount = this.RetryCount; retval.RetryTimeout = this.RetryTimeout; retval.Subscribe(this.HandleMessage); listeners[hash] = retval; listenerRefs[retval] = new ListenerInfo { RefCount = 1, HashKey = hash }; retval.Start(); } return(retval); }
private void HandleMessage(string message, MessageStreamListener listener) { // everything failed if (String.IsNullOrEmpty(message)) { this.lastHash = null; this.RaiseConfigChanged(null); return; } // deserialize the buckets var jss = new JavaScriptSerializer(); jss.RegisterConverters(KnownConverters); var config = jss.Deserialize <ClusterConfig>(message); // check if the config is the same as the previous // we cannot compare the messages because they have more information than we deserialize from them var configHash = config.GetHashCode(); if (lastHash != configHash) { lastHash = configHash; this.RaiseConfigChanged(config); listener.UpdateNodes(config); } else if (log.IsDebugEnabled) { log.Debug("Last message was the same as current, ignoring."); } }
/// <summary> /// Starts listening for configuration data. This method blocks until the initial configuration is received. (Or until all pool urls fail.) /// </summary> public void Start() { var reset = this.mre = new ManualResetEvent(false); // subscribe to the config url this.listener = this.GetPooledListener(); // this will be signaled by the config changed event handler reset.WaitOne(); // set to null, then dispose, so RaiseConfigChanged will not // fail at Set when the config changes while we're cleaning up here this.mre = null; ((IDisposable)reset).Dispose(); }
/// <summary> /// Unsubscribes from a pooled listener, and destroys it if no additional subscribers are present. /// </summary> /// <param name="listener"></param> private void ReleaseListener(MessageStreamListener listener) { lock (ListenerSync) { listener.Unsubscribe(this.HandleMessage); var info = listenerRefs[listener]; if (info.RefCount == 1) { listenerRefs.Remove(listener); listeners.Remove(info.HashKey); try { using (listener) listener.Stop(); } catch (Exception e) { log.Error(e); } } else { info.RefCount--; } } }
/// <summary> /// Unsubscibes from a pooled listener, and destrpys it if no additionals subscribers are present. /// </summary> /// <param name="listener"></param> private void ReleaseListener(MessageStreamListener listener) { lock (ListenerSync) { listener.Unsubscribe(this.HandleMessage); var info = listenerRefs[listener]; if (info.RefCount == 1) { listenerRefs.Remove(listener); listeners.Remove(info.HashKey); try { using (listener) listener.Stop(); } catch { } } else { info.RefCount--; } } }
/// <summary> /// Returns a MessageStreamListener instance based on this instance's configuratino (timeout, bucket name etc.) /// /// When multiple listeners are requested with the exact same parameters (usually when multiple clients are instantiated from the same configuration), /// the same listener will be returned each time. /// </summary> /// <returns></returns> private MessageStreamListener GetPooledListener() { // create a unique key based on the parameters // to find out if we already have a listener attached to this pool var hcc = new HashCodeCombiner(); hcc.Add(this.Timeout); hcc.Add(this.DeadTimeout); hcc.Add(this.RetryCount); hcc.Add(this.RetryTimeout.GetHashCode()); hcc.Add(this.bucketName.GetHashCode()); if (credential != null) { hcc.Add((this.credential.UserName ?? String.Empty).GetHashCode()); hcc.Add((this.credential.Password ?? String.Empty).GetHashCode()); hcc.Add((this.credential.Domain ?? String.Empty).GetHashCode()); } for (var i = 0; i < this.poolUrls.Length; i++) hcc.Add(this.poolUrls[i].GetHashCode()); var hash = hcc.CurrentHash; MessageStreamListener retval; lock (ListenerSync) if (listeners.TryGetValue(hash, out retval)) { listenerRefs[retval].RefCount++; retval.Subscribe(this.HandleMessage); } else { var name = this.bucketName; // create a new listener for the pool urls retval = new MessageStreamListener(poolUrls, heartbeatUri, heartbeatInterval, isHeartbeatEnabled, (client, root) => ResolveBucketUri(client, root, name)); retval.ConnectionTimeout = this.Timeout; retval.DeadTimeout = this.DeadTimeout; retval.Credentials = this.credential; retval.RetryCount = this.RetryCount; retval.RetryTimeout = this.RetryTimeout; retval.Subscribe(this.HandleMessage); listeners[hash] = retval; listenerRefs[retval] = new ListenerInfo { RefCount = 1, HashKey = hash }; retval.Start(); } return retval; }
public void Stop() { this.ReleaseListener(this.listener); this.listener = null; }
private void HandleMessage(string message, MessageStreamListener listener) { // everything failed if (String.IsNullOrEmpty(message)) { this.lastHash = null; this.RaiseConfigChanged(null); return; } // deserialize the buckets var jss = new JavaScriptSerializer(); jss.RegisterConverters(KnownConverters); var config = jss.Deserialize<ClusterConfig>(message); // check if the config is the same as the previous // we cannot compare the messages because they have more information than we deserialize from them var configHash = config.GetHashCode(); if (lastHash != configHash) { lastHash = configHash; this.RaiseConfigChanged(config); listener.UpdateNodes(config); } else if (log.IsDebugEnabled) log.Debug("Last message was the same as current, ignoring."); }