Example #1
0
 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();
            }
        }