public SetCommand(string command, SetCommandType type, string value) => (Command, this.type, this.value) = (command, type, value);
/// <summary> /// Stores data to cache. /// /// If data does not already exist for this key on the server, or if the key is being<br/> /// deleted, the specified value will not be stored.<br/> /// The server will automatically delete the value when the expiration time has been reached.<br/> /// <br/> /// If compression is enabled, and the data is longer than the compression threshold<br/> /// the data will be stored in compressed form.<br/> /// <br/> /// As of the current release, all objects stored will use serialization. /// </summary> /// /// <param name="cmdType">action to take (set, add, replace)</param> /// <param name="key">key to store cache under</param> /// <param name="value">object to cache</param> /// <param name="expiry">expiration, if any</param> /// <param name="sock">SockIO to use</param> /// /// <returns><code>true</code> if successful, <code>fale</code> or exception otherwise</returns> private bool SetItem(SetCommandType cmdType, string key, object value, DateTime expiry, SockIOPool.SockIO sock) { // store flags int flags = 0; // byte array to hold data byte[] val; if(expiry.Equals(DateTime.MinValue)) expiry = new DateTime(0); // serialize the object // unless client request data to be not serialized // in which case, we will go with string representation // but only for a select few classes if (!(value is string || value is Int32 || value is Double || value is Single || value is Int64 || value is SByte || value is Int16 || value is Char || value is StringBuilder)) { // we can ONLY not serialize the above classes // this is generally a bad idea as we should always // just use serialization. // but, it is useful for sharing data between non-.NET // and also for storing ints for the increment method if(log.IsInfoEnabled) log.Info("storing data as a string for key: " + key + " for class: " + value.GetType().FullName); val = UTF8Encoding.UTF8.GetBytes(value.ToString()); } else { if(log.IsInfoEnabled) log.Info("serializing for key: " + key + " for class: " + value.GetType().FullName); try { MemoryStream bos = new MemoryStream(); new BinaryFormatter().Serialize((new BinaryWriter(bos)).BaseStream, value); val = bos.ToArray(); flags |= F_SERIALIZED; } catch(SerializationException se) { if(log.IsErrorEnabled) log.Error("failed to serialize obj: " + value.ToString(), se); // return socket to pool and bail sock.Close(); #if EXCEPTIONS throw new MemcachedException(se); #else return false; #endif } } // now try to compress if we want to // and if the length is over the threshold if (compressEnable && val.Length > compressThreshold) { if(log.IsInfoEnabled) log.Info("trying to compress data, size prior to compression: " + val.Length); try { MemoryStream bos = new MemoryStream(val.Length); GZipOutputStream gos = new GZipOutputStream(bos); gos.Write(val, 0, val.Length); gos.Close(); // store it and set compression flag val = bos.ToArray(); flags |= F_COMPRESSED; if(log.IsInfoEnabled) log.Info("compression succeeded, size after: " + val.Length); } // TODO Not sure which specific exception(s) is/are thrown catch(Exception e) { if(log.IsErrorEnabled) log.Error("Exception while compressing stream", e); } } // now write the data to the cache server StringBuilder cmd = new StringBuilder(); switch(cmdType) { case SetCommandType.Add: cmd.Append("add"); break; case SetCommandType.Replace: cmd.Append("replace"); break; case SetCommandType.Set: cmd.Append("set"); break; default: // As if this can actually happen throw new ArgumentException("cmdType"); } cmd.Append(" "); cmd.Append(key); cmd.Append(" "); cmd.Append(flags.ToString()); cmd.Append(" "); cmd.Append(expiry.Ticks / 1000); cmd.Append(" "); cmd.Append(val.Length.ToString()); cmd.Append("\n"); try { sock.Write(UTF8Encoding.UTF8.GetBytes(cmd.ToString())); sock.Write(val); sock.Write(UTF8Encoding.UTF8.GetBytes("\n")); sock.Flush(); // get result code string line = sock.ReadLine(); if(log.IsInfoEnabled) log.Info("memcache cmd (result code): " + cmd + " (" + line + ")"); switch(line) { case STORED: if(log.IsInfoEnabled) log.Info("data successfully stored for key: " + key); return true; case NOTSTORED: if(log.IsInfoEnabled) log.Info("data not stored in cache for key: " + key); #if EXCEPTIONS throw new NotStoredException(key); #else return false; #endif default: if(log.IsErrorEnabled) log.Error("error storing data in cache for key: " + key + " -- length: " + val.Length); #if EXCEPTIONS throw new MemcachedException(line); #else return false; #endif } } catch(IOException ioe) { if(log.IsErrorEnabled) log.Error("exception thrown while writing bytes to server on set", ioe); try { sock.TrueClose(); } catch(IOException ioee) { if(log.IsErrorEnabled) log.Error("failed to close socket : " + sock.ToString(), ioee); } sock = null; #if EXCEPTIONS throw new SocketException(e); #else return false; #endif } finally { if(sock != null) sock.Close(); } }