protected static void RemoveSocketFromPool(Hashtable pool, string host, SockIO socket) { if (string.IsNullOrEmpty(host) || pool == null) { return; } if (pool.ContainsKey(host)) { var sockets = (Hashtable)pool[host]; if (sockets != null) { sockets.Remove(socket); } } }
/// <summary> /// Increments/decrements the value at the specified key by inc. /// /// Note that the server uses a 32-bit unsigned integer, and checks for /// underflow. In the event of underflow, the result will be zero. Because /// Java lacks unsigned types, the value is returned as a 64-bit integer. /// The server will only decrement a value if it already exists; /// if a value is not found, -1 will be returned. /// /// TODO: C# has unsigned types. We can fix this. /// </summary> /// <param name="cmdname">increment/decrement</param> /// <param name="key">cache key</param> /// <param name="inc">amount to incr or decr</param> /// <param name="hashCode">if not null, then the int hashcode to use</param> /// <returns>new value or -1 if not exist</returns> private long IncrementOrDecrement(string cmdname, string key, long inc, object hashCode) { key = Prefix + key; // get SockIO obj for given cache key SockIO sock = SockIOPool.GetInstance(_poolName).GetSock(key, hashCode); if (sock == null) { return(-1); } try { string cmd = cmdname + " " + key + " " + inc + "\r\n"; sock.Write(Encoding.UTF8.GetBytes(cmd)); sock.Flush(); // get result back string line = sock.ReadLine(); if (new Regex("\\d+").Match(line).Success) { // return sock to pool and return result sock.Close(); return(long.Parse(line, new NumberFormatInfo())); } } catch (IOException e) { try { sock.TrueClose(); } finally { sock = null; } } if (sock != null) { sock.Close(); } return(-1); }
public void CheckIn(SockIO socket, bool addToAvail) { if (socket == null) { return; } string host = socket.Host; RemoveSocketFromPool(_busyPool, host, socket); // add to avail pool if (addToAvail && socket.IsConnected) { AddSocketToPool(_availPool, host, socket); } }
/// <summary> /// Retrieve a key from the server, using a specific hash. /// /// If the data was compressed or serialized when compressed, it will automatically /// be decompressed or serialized, as appropriate. (Inclusive or) /// /// Non-serialized data will be returned as a string, so explicit conversion to /// numeric types will be necessary, if desired /// </summary> /// <param name="key">key where data is stored</param> /// <param name="hashCode">if not null, then the int hashcode to use</param> /// <param name="asString">if true, then return string val</param> /// <returns>the object that was previously stored, or null if it was not previously stored</returns> public object Get(string key, object hashCode, bool asString) { if (string.IsNullOrEmpty(key)) { return(null); } key = Prefix + key; // get SockIO obj using cache key SockIO sock = SockIOPool.GetInstance(_poolName).GetSock(key, hashCode); if (sock == null) { return(null); } try { string cmd = "get " + key + "\r\n"; sock.Write(Encoding.UTF8.GetBytes(cmd)); sock.Flush(); // build empty map // and fill it from server Hashtable hm = new Hashtable(); LoadItems(sock, hm, asString); // return the value for this key if we found it // else return null sock.Close(); return(hm[key]); } catch { try { sock.TrueClose(); } finally { sock = null; } } return(null); }
/// <summary> /// Adds a socket to a given pool for the given host. /// /// Internal utility method. /// </summary> /// <param name="pool">pool to add to</param> /// <param name="host">host this socket is connected to</param> /// <param name="socket">socket to add</param> //[MethodImpl(MethodImplOptions.Synchronized)] protected static void AddSocketToPool(Hashtable pool, string host, SockIO socket) { if (pool == null || string.IsNullOrEmpty(host)) { return; } Hashtable sockets; if (!string.IsNullOrEmpty(host) && pool.ContainsKey(host)) { sockets = (Hashtable)pool[host]; if (sockets != null) { sockets[socket] = DateTime.Now; //MaxM 1.16.05: Use current DateTime to indicate socker creation time rather than milliseconds since 1970 return; } } sockets = new Hashtable(); sockets[socket] = DateTime.Now; //MaxM 1.16.05: Use current DateTime to indicate socker creation time rather than milliseconds since 1970 pool[host] = sockets; }
/// <summary> /// Creates a new SockIO obj for the given server. /// ///If server fails to connect, then return null and do not try ///again until a duration has passed. This duration will grow ///by doubling after each failed attempt to connect. /// </summary> /// <param name="host">host:port to connect to</param> /// <returns>SockIO obj or null if failed to create</returns> protected SockIO CreateSocket(string host) { SockIO socket = null; // if host is dead, then we don't need to try again // until the dead status has expired // we do not try to put back in if failover is off if(_failover && _hostDead.ContainsKey(host) && _hostDeadDuration.ContainsKey(host)) { DateTime store = (DateTime)_hostDead[host]; long expire = ((long)_hostDeadDuration[host]); if((store.AddMilliseconds(expire)) > DateTime.Now) return null; } try { socket = new SockIO(this, host, _socketTimeout, _socketConnectTimeout, _nagle); if (!socket.IsConnected) { try { socket.TrueClose(); } catch (SocketException) { socket = null; } } } catch { socket = null; } // if we failed to get socket, then mark // host dead for a duration which falls off if(socket == null) { DateTime now = DateTime.Now; _hostDead[host] = now; long expire = (_hostDeadDuration.ContainsKey(host)) ? (((long)_hostDeadDuration[host]) * 2) : 100; _hostDeadDuration[host] = expire; // also clear all entries for this host from availPool ClearHostFromPool(_availPool, host); } else { _hostDead.Remove(host); _hostDeadDuration.Remove(host); if(_buckets.BinarySearch(host) < 0) _buckets.Add(host); } return socket; }
/// <summary> /// Returns appropriate SockIO object given /// string cache key and optional hashcode. /// /// Trys to get SockIO from pool. Fails over /// to additional pools in event of server failure. /// </summary> /// <param name="key">hashcode for cache key</param> /// <param name="hashCode">if not null, then the int hashcode to use</param> /// <returns>SockIO obj connected to server</returns> public SockIO GetSock(string key, object hashCode) { //string hashCodeString = "<null>"; //if(hashCode != null) // hashCodeString = hashCode.ToString(); if (string.IsNullOrEmpty(key) || !_initialized || _buckets.Count == 0) { return(null); } // if only one server, return it if (_buckets.Count == 1) { return(GetConnection((string)_buckets[0])); } int tries = 0; int hv; if (hashCode != null) { hv = (int)hashCode; } else { // NATIVE_HASH = 0 // OLD_COMPAT_HASH = 1 // NEW_COMPAT_HASH = 2 switch (_hashingAlgorithm) { case HashingAlgorithm.Native: hv = key.GetHashCode(); break; case HashingAlgorithm.OldCompatibleHash: hv = OriginalHashingAlgorithm(key); break; case HashingAlgorithm.NewCompatibleHash: hv = NewHashingAlgorithm(key); break; default: // use the native hash as a default hv = key.GetHashCode(); _hashingAlgorithm = HashingAlgorithm.Native; break; } } // keep trying different servers until we find one while (tries++ <= _buckets.Count) { // get bucket using hashcode // get one from factory int bucket = hv % _buckets.Count; if (bucket < 0) { bucket += _buckets.Count; } SockIO sock = GetConnection((string)_buckets[bucket]); if (sock != null) { return(sock); } // if we do not want to failover, then bail here if (!_failover) { return(null); } // if we failed to get a socket from this server // then we try again by adding an incrementer to the // current key and then rehashing switch (_hashingAlgorithm) { case HashingAlgorithm.Native: hv += ((string)("" + tries + key)).GetHashCode(); break; case HashingAlgorithm.OldCompatibleHash: hv += OriginalHashingAlgorithm("" + tries + key); break; case HashingAlgorithm.NewCompatibleHash: hv += NewHashingAlgorithm("" + tries + key); break; default: // use the native hash as a default hv += ((string)("" + tries + key)).GetHashCode(); _hashingAlgorithm = HashingAlgorithm.Native; break; } } return(null); }
public SockIO GetConnection(string host) { if (!_initialized) { return(null); } if (host == null) { return(null); } // if we have items in the pool // then we can return it if (_availPool != null && _availPool.Count != 0) { // take first connected socket Hashtable aSockets = (Hashtable)_availPool[host]; if (aSockets != null && aSockets.Count != 0) { foreach (SockIO socket in new IteratorIsolateCollection(aSockets.Keys)) { if (socket.IsConnected) { // remove from avail pool aSockets.Remove(socket); // add to busy pool AddSocketToPool(_busyPool, host, socket); // return socket return(socket); } // remove from avail pool aSockets.Remove(socket); } } } // if here, then we found no sockets in the pool // try to create on a sliding scale up to maxCreate object cShift = _createShift[host]; int shift = (cShift != null) ? (int)cShift : 0; int create = 1 << shift; if (create >= _maxCreate) { create = _maxCreate; } else { shift++; } // store the shift value for this host _createShift[host] = shift; for (int i = create; i > 0; i--) { SockIO socket = CreateSocket(host); if (socket == null) { break; } if (i == 1) { // last iteration, add to busy pool and return sockio AddSocketToPool(_busyPool, host, socket); return(socket); } // add to avail pool AddSocketToPool(_availPool, host, socket); } // should never get here return(null); }
public void Initialize() { // check to see if already initialized if (_initialized && _buckets != null && _availPool != null && _busyPool != null) { return; } // initialize empty maps _buckets = new ArrayList(); _availPool = new Hashtable(_servers.Count * _initConns); _busyPool = new Hashtable(_servers.Count * _initConns); _hostDeadDuration = new Hashtable(); _hostDead = new Hashtable(); _createShift = new Hashtable(); _maxCreate = (_poolMultiplier > _minConns) ? _minConns : _minConns / _poolMultiplier; // only create up to maxCreate connections at once // if servers is not set, or it empty, then // throw a runtime exception if (_servers == null || _servers.Count <= 0) { throw new ArgumentException(); } for (int i = 0; i < _servers.Count; i++) { // add to bucket // with weights if we have them if (_weights != null && _weights.Count > i) { for (int k = 0; k < ((int)_weights[i]); k++) { _buckets.Add(_servers[i]); } } else { _buckets.Add(_servers[i]); } for (int j = 0; j < _initConns; j++) { SockIO socket = CreateSocket((string)_servers[i]); if (socket == null) { break; } AddSocketToPool(_availPool, (string)_servers[i], socket); } } // mark pool as initialized _initialized = true; // start maint thread TODO: re-enable if (_maintThreadSleep > 0) { this.StartMaintenanceThread(); } }
/// <summary> /// Creates a new SockIO obj for the given server. /// ///If server fails to connect, then return null and do not try ///again until a duration has passed. This duration will grow ///by doubling after each failed attempt to connect. /// </summary> /// <param name="host">host:port to connect to</param> /// <returns>SockIO obj or null if failed to create</returns> protected SockIO CreateSocket(string host) { SockIO socket = null; // if host is dead, then we don't need to try again // until the dead status has expired // we do not try to put back in if failover is off if (_failover && _hostDead.ContainsKey(host) && _hostDeadDuration.ContainsKey(host)) { DateTime store = (DateTime)_hostDead[host]; long expire = ((long)_hostDeadDuration[host]); if ((store.AddMilliseconds(expire)) > DateTime.Now) { return(null); } } try { socket = new SockIO(this, host, _socketTimeout, _socketConnectTimeout, _nagle); if (!socket.IsConnected) { try { socket.TrueClose(); } catch (SocketException) { socket = null; } } } catch { socket = null; } // if we failed to get socket, then mark // host dead for a duration which falls off if (socket == null) { DateTime now = DateTime.Now; _hostDead[host] = now; long expire = (_hostDeadDuration.ContainsKey(host)) ? (((long)_hostDeadDuration[host]) * 2) : 100; _hostDeadDuration[host] = expire; // also clear all entries for this host from availPool ClearHostFromPool(_availPool, host); } else { _hostDead.Remove(host); _hostDeadDuration.Remove(host); if (_buckets.BinarySearch(host) < 0) { _buckets.Add(host); } } return(socket); }
public void CheckIn(SockIO socket, bool addToAvail) { if (socket == null) return; string host = socket.Host; RemoveSocketFromPool(_busyPool, host, socket); // add to avail pool if(addToAvail && socket.IsConnected) { AddSocketToPool(_availPool, host, socket); } }
public void CheckIn(SockIO socket) { CheckIn(socket, true); }
/// <summary> /// Invalidates the entire cache. /// /// Will return true only if succeeds in clearing all servers. /// If pass in null, then will try to flush all servers. /// </summary> /// <param name="servers">optional array of host(s) to flush (host:port)</param> /// <returns>success true/false</returns> public bool FlushAll(ArrayList servers) { // get SockIOPool instance SockIOPool pool = SockIOPool.GetInstance(_poolName); // return false if unable to get SockIO obj if (pool == null) { return(false); } // get all servers and iterate over them if (servers == null) { servers = pool.Servers; } // if no servers, then return early if (servers == null || servers.Count <= 0) { return(false); } bool success = true; for (int i = 0; i < servers.Count; i++) { SockIO sock = pool.GetConnection((string)servers[i]); if (sock == null) { success = false; continue; } // build command string command = "flush_all\r\n"; try { sock.Write(Encoding.UTF8.GetBytes(command)); sock.Flush(); // if we get appropriate response back, then we return true string line = sock.ReadLine(); success = (OK == line) ? success && true : false; } catch (IOException e) { try { sock.TrueClose(); } catch {} success = false; sock = null; } if (sock != null) { sock.Close(); } } return(success); }
/// <summary> /// Retrieves stats for passed in servers (or all servers). /// /// Returns a map keyed on the servername. /// The value is another map which contains stats /// with stat name as key and value as value. /// </summary> /// <param name="servers">string array of servers to retrieve stats from, or all if this is null</param> /// <returns>Stats map</returns> public Hashtable Stats(ArrayList servers) { // get SockIOPool instance SockIOPool pool = SockIOPool.GetInstance(_poolName); // return false if unable to get SockIO obj if (pool == null) { return(null); } // get all servers and iterate over them if (servers == null) { servers = pool.Servers; } // if no servers, then return early if (servers == null || servers.Count <= 0) { return(null); } // array of stats Hashtables Hashtable statsMaps = new Hashtable(); for (int i = 0; i < servers.Count; i++) { SockIO sock = pool.GetConnection((string)servers[i]); if (sock == null) { continue; } // build command string command = "stats\r\n"; try { sock.Write(UTF8Encoding.UTF8.GetBytes(command)); sock.Flush(); // map to hold key value pairs Hashtable stats = new Hashtable(); // loop over results while (true) { string line = sock.ReadLine(); if (line.StartsWith(STATS)) { string[] info = line.Split(' '); string key = info[1]; string val = info[2]; stats[key] = val; } else if (END == line) { break; } statsMaps[servers[i]] = stats; } } catch (IOException e) { try { sock.TrueClose(); } catch (IOException) { } sock = null; } if (sock != null) { sock.Close(); } } return(statsMaps); }
/// <summary> /// This method loads the data from cache into a Hashtable. /// /// Pass a SockIO object which is ready to receive data and a Hashtable /// to store the results. /// </summary> /// <param name="sock">socket waiting to pass back data</param> /// <param name="hm">hashmap to store data into</param> /// <param name="asString">if true, and if we are using NativehHandler, return string val</param> private void LoadItems(SockIO sock, Hashtable hm, bool asString) { while(true) { string line = sock.ReadLine(); if(line.StartsWith(VALUE)) { string[] info = line.Split(' '); string key = info[1]; int flag = int.Parse(info[2], new NumberFormatInfo()); int length = int.Parse(info[3], new NumberFormatInfo()); // read obj into buffer byte[] buf = new byte[length]; sock.Read(buf); sock.ClearEndOfLine(); // ready object object o=null; // check for compression if((flag & F_COMPRESSED) != 0) { MemoryStream mem = null; GZipStream gzi = null; try { // read the input stream, and write to a byte array output stream since // we have to read into a byte array, but we don't know how large it // will need to be, and we don't want to resize it a bunch mem = new MemoryStream(buf.Length); gzi = new GZipStream(new MemoryStream(buf), CompressionMode.Compress); int count; var tmp = new byte[2048]; while ((count = gzi.Read(tmp, 0, tmp.Length)) > 0) { mem.Write(tmp, 0, count); } // store uncompressed back to buffer buf = mem.ToArray(); } finally { if(mem!=null) { mem.Close(); mem.Dispose(); } if(gzi != null) { gzi.Close(); gzi.Dispose(); } } } // we can only take out serialized objects if((flag & F_SERIALIZED) == 0) { if(_primitiveAsString || asString) { o = Encoding.GetEncoding(_defaultEncoding).GetString(buf); } else { // decoding object try { o = NativeHandler.Decode(buf); } catch(Exception e) { return; } } } else { // deserialize if the data is serialized MemoryStream memStream = null; try { memStream = new MemoryStream(buf); o = new BinaryFormatter().Deserialize(memStream); } catch(SerializationException e) { } finally { if(memStream != null) { memStream.Close(); memStream.Dispose(); } } } // store the object into the cache hm[ key ] = o ; } else if(END == line) { break; } } }
/// <summary> /// Retrieve multiple objects from the memcache. /// /// This is recommended over repeated calls to <see cref="get">get(string)</see>, since it /// is more efficient. /// </summary> /// <param name="keys">string array of keys to retrieve</param> /// <param name="hashCodes">hashCodes if not null, then the int array of hashCodes</param> /// <param name="asString">if true then retrieve using string val</param> /// <returns> /// a hashmap with entries for each key is found by the server, /// keys that are not found are not entered into the hashmap, but attempting to /// retrieve them from the hashmap gives you null. /// </returns> public Hashtable GetMultiple(string[] keys, int[] hashCodes, bool asString) { if (keys == null) { return(new Hashtable()); } Hashtable sockKeys = new Hashtable(); for (int i = 0; i < keys.Length; ++i) { object hash = null; if (hashCodes != null && hashCodes.Length > i) { hash = hashCodes[i]; } // get SockIO obj from cache key SockIO sock = SockIOPool.GetInstance(_poolName).GetSock(Prefix + keys[i], hash); if (sock == null) { continue; } // store in map and list if not already if (!sockKeys.ContainsKey(sock.Host)) { sockKeys[sock.Host] = new StringBuilder(); } ((StringBuilder)sockKeys[sock.Host]).Append(" " + Prefix + keys[i]); // return to pool sock.Close(); } // now query memcache Hashtable ret = new Hashtable(); ArrayList toRemove = new ArrayList(); foreach (string host in sockKeys.Keys) { // get SockIO obj from hostname SockIO sock = SockIOPool.GetInstance(_poolName).GetConnection(host); try { string cmd = "get" + (StringBuilder)sockKeys[host] + "\r\n"; sock.Write(Encoding.UTF8.GetBytes(cmd)); sock.Flush(); LoadItems(sock, ret, asString); } catch { // clear this sockIO obj from the list // and from the map containing keys toRemove.Add(host); try { sock.TrueClose(); } finally { sock = null; } } // Return socket to pool if (sock != null) { sock.Close(); } } foreach (string host in toRemove) { sockKeys.Remove(host); } return(ret); }
/// <summary> /// Deletes an object from cache given cache key, a delete time, and an optional hashcode. /// /// The item is immediately made non retrievable.<br/> /// Keep in mind: /// <see cref="add">add(string, object)</see> and <see cref="replace">replace(string, object)</see> /// will fail when used with the same key will fail, until the server reaches the /// specified time. However, <see cref="set">set(string, object)</see> will succeed /// and the new value will not be deleted. /// </summary> /// <param name="key">the key to be removed</param> /// <param name="hashCode">if not null, then the int hashcode to use</param> /// <param name="expiry">when to expire the record.</param> /// <returns><c>true</c>, if the data was deleted successfully</returns> public bool Delete(string key, object hashCode, DateTime expiry) { if (key == null) { return(false); } key = Prefix + key; // get SockIO obj from hash or from key SockIO sock = SockIOPool.GetInstance(_poolName).GetSock(key, hashCode); // return false if unable to get SockIO obj if (sock == null) { return(false); } // build command StringBuilder command = new StringBuilder("delete ").Append(key); if (expiry != DateTime.MaxValue) { command.Append(" " + GetExpirationTime(expiry) / 1000); } command.Append("\r\n"); try { sock.Write(Encoding.UTF8.GetBytes(command.ToString())); sock.Flush(); // if we get appropriate response back, then we return true string line = sock.ReadLine(); if (DELETED == line) { // return sock to pool and bail here sock.Close(); sock = null; return(true); } } catch { try { if (sock != null) { sock.TrueClose(); } } finally { sock = null; } } if (sock != null) { sock.Close(); } return(false); }
/// <summary> /// Stores data to cache. /// /// If data does not already exist for this key on the server, or if the key is being /// deleted, the specified value will not be stored. /// The server will automatically delete the value when the expiration time has been reached. /// /// If compression is enabled, and the data is longer than the compression threshold /// the data will be stored in compressed form. /// /// As of the current release, all objects stored will use .NET serialization. /// </summary> /// <param name="cmdname">action to take (set, add, replace)</param> /// <param name="key">key to store cache under</param> /// <param name="obj">object to cache</param> /// <param name="expiry">expiration</param> /// <param name="hashCode">if not null, then the int hashcode to use</param> /// <param name="asString">store this object as a string?</param> /// <returns>true/false indicating success</returns> private bool Set(string cmdname, string key, object obj, DateTime expiry, object hashCode, bool asString) { if (expiry < DateTime.Now) { return(true); } if (cmdname == null || cmdname.Trim().Length == 0 || string.IsNullOrEmpty(key)) { return(false); } key = Prefix + key; // get SockIO obj SockIO sock = SockIOPool.GetInstance(_poolName).GetSock(key, hashCode); if (sock == null) { return(false); } if (expiry == DateTime.MaxValue) { expiry = new DateTime(0); } // store flags int flags = 0; // byte array to hold data byte[] val; int length = 0; // useful for sharing data between .NET and non-.NET // and also for storing ints for the increment method if (NativeHandler.IsHandled(obj)) { if (asString) { if (obj != null) { try { val = Encoding.UTF8.GetBytes(obj.ToString()); length = val.Length; } catch { sock.Close(); sock = null; return(false); } } else { val = new byte[0]; length = 0; } } else { try { val = NativeHandler.Encode(obj); length = val.Length; } catch { sock.Close(); sock = null; return(false); } } } else { if (obj != null) { // always serialize for non-primitive types try { var memStream = new MemoryStream(); new BinaryFormatter().Serialize(memStream, obj); val = memStream.GetBuffer(); length = (int)memStream.Length; flags |= F_SERIALIZED; } catch { // return socket to pool and bail sock.Close(); sock = null; return(false); } } else { val = new byte[0]; length = 0; } } // now try to compress if we want to // and if the length is over the threshold if (_compressEnable && length > _compressThreshold) { MemoryStream memoryStream = null; GZipStream gos = null; try { memoryStream = new MemoryStream(); gos = new GZipStream(memoryStream, CompressionMode.Compress); gos.Write(val, 0, length); gos.Flush(); // store it and set compression flag val = memoryStream.GetBuffer(); length = (int)memoryStream.Length; flags |= F_COMPRESSED; } finally { if (memoryStream != null) { memoryStream.Close(); memoryStream.Dispose(); } if (gos != null) { gos.Close(); gos.Dispose(); } } } // now write the data to the cache server try { string cmd = cmdname + " " + key + " " + flags + " " + GetExpirationTime(expiry) + " " + length + "\r\n"; sock.Write(Encoding.UTF8.GetBytes(cmd)); sock.Write(val, 0, length); sock.Write(Encoding.UTF8.GetBytes("\r\n")); sock.Flush(); // get result code string line = sock.ReadLine(); if (STORED == line) { sock.Close(); sock = null; return(true); } } catch { try { if (sock != null) { sock.TrueClose(); } } finally { sock = null; } } if (sock != null) { sock.Close(); } return(false); }
/// <summary> /// Adds a socket to a given pool for the given host. /// /// Internal utility method. /// </summary> /// <param name="pool">pool to add to</param> /// <param name="host">host this socket is connected to</param> /// <param name="socket">socket to add</param> //[MethodImpl(MethodImplOptions.Synchronized)] protected static void AddSocketToPool(Hashtable pool, string host, SockIO socket) { if (pool == null || string.IsNullOrEmpty(host)) return; Hashtable sockets; if (!string.IsNullOrEmpty(host) && pool.ContainsKey(host)) { sockets = (Hashtable)pool[host]; if (sockets != null) { sockets[socket] = DateTime.Now; //MaxM 1.16.05: Use current DateTime to indicate socker creation time rather than milliseconds since 1970 return; } } sockets = new Hashtable(); sockets[socket] = DateTime.Now; //MaxM 1.16.05: Use current DateTime to indicate socker creation time rather than milliseconds since 1970 pool[host] = sockets; }
protected static void RemoveSocketFromPool(Hashtable pool, string host, SockIO socket) { if (string.IsNullOrEmpty(host) || pool == null) return; if(pool.ContainsKey(host)) { var sockets = (Hashtable)pool[host]; if(sockets != null) { sockets.Remove(socket); } } }
protected void SelfMaintain() { // go through avail sockets and create/destroy sockets // as needed to maintain pool settings foreach (string host in new IteratorIsolateCollection(_availPool.Keys)) { Hashtable sockets = (Hashtable)_availPool[host]; // if pool is too small (n < minSpare) if (sockets.Count < _minConns) { // need to create new sockets int need = _minConns - sockets.Count; for (int j = 0; j < need; j++) { SockIO socket = CreateSocket(host); if (socket == null) { break; } AddSocketToPool(_availPool, host, socket); } } else if (sockets.Count > _maxConns) { // need to close down some sockets int diff = sockets.Count - _maxConns; int needToClose = (diff <= _poolMultiplier) ? diff : (diff) / _poolMultiplier; foreach (SockIO socket in new IteratorIsolateCollection(sockets.Keys)) { if (needToClose <= 0) { break; } // remove stale entries DateTime expire = (DateTime)sockets[socket]; // if past idle time // then close socket // and remove from pool if ((expire.AddMilliseconds(_maxIdle)) < DateTime.Now) { try { socket.TrueClose(); } finally { sockets.Remove(socket); needToClose--; } } } } // reset the shift value for creating new SockIO objects _createShift[host] = 0; } // go through busy sockets and destroy sockets // as needed to maintain pool settings foreach (string host in _busyPool.Keys) { Hashtable sockets = (Hashtable)_busyPool[host]; // loop through all connections and check to see if we have any hung connections foreach (SockIO socket in new IteratorIsolateCollection(sockets.Keys)) { // remove stale entries DateTime hungTime = (DateTime)sockets[socket]; // if past max busy time // then close socket // and remove from pool if ((hungTime.AddMilliseconds(_maxBusyTime)) < DateTime.Now) { try { socket.TrueClose(); } finally { sockets.Remove(socket); } } } } }
/// <summary> /// This method loads the data from cache into a Hashtable. /// /// Pass a SockIO object which is ready to receive data and a Hashtable /// to store the results. /// </summary> /// <param name="sock">socket waiting to pass back data</param> /// <param name="hm">hashmap to store data into</param> /// <param name="asString">if true, and if we are using NativehHandler, return string val</param> private void LoadItems(SockIO sock, Hashtable hm, bool asString) { while (true) { string line = sock.ReadLine(); if (line.StartsWith(VALUE)) { string[] info = line.Split(' '); string key = info[1]; int flag = int.Parse(info[2], new NumberFormatInfo()); int length = int.Parse(info[3], new NumberFormatInfo()); // read obj into buffer byte[] buf = new byte[length]; sock.Read(buf); sock.ClearEndOfLine(); // ready object object o = null; // check for compression if ((flag & F_COMPRESSED) != 0) { MemoryStream mem = null; GZipStream gzi = null; try { // read the input stream, and write to a byte array output stream since // we have to read into a byte array, but we don't know how large it // will need to be, and we don't want to resize it a bunch mem = new MemoryStream(buf.Length); gzi = new GZipStream(new MemoryStream(buf), CompressionMode.Compress); int count; var tmp = new byte[2048]; while ((count = gzi.Read(tmp, 0, tmp.Length)) > 0) { mem.Write(tmp, 0, count); } // store uncompressed back to buffer buf = mem.ToArray(); } finally { if (mem != null) { mem.Close(); mem.Dispose(); } if (gzi != null) { gzi.Close(); gzi.Dispose(); } } } // we can only take out serialized objects if ((flag & F_SERIALIZED) == 0) { if (_primitiveAsString || asString) { o = Encoding.GetEncoding(_defaultEncoding).GetString(buf); } else { // decoding object try { o = NativeHandler.Decode(buf); } catch (Exception e) { return; } } } else { // deserialize if the data is serialized MemoryStream memStream = null; try { memStream = new MemoryStream(buf); o = new BinaryFormatter().Deserialize(memStream); } catch (SerializationException e) { } finally { if (memStream != null) { memStream.Close(); memStream.Dispose(); } } } // store the object into the cache hm[key] = o; } else if (END == line) { break; } } }