CachedResponse ICachedClient.Execute(CachedRequest request)
 {
     var batch = new CachedRequest[1] { request };
     var result = new CachedResponse[1] { new CachedResponse(request) };
     ExecuteBatch(batch, result);
     return result[0];
 }
 CachedResponse[] ExecuteBatch(CachedRequest[] batch)
 {
     var response = new CachedResponse[batch.Length];
     for (int i = 0; i < batch.Length; i++)
         response[i] = new CachedResponse(batch[i]);
     ExecuteBatch(batch, response);
     return response;
 }
 private void Decode(CachedResponse rsp)
 {
     var cas = _packet.Cas;
     if (cas != 0) rsp.Cas = cas;
     switch ((Opcode)_packet.Command)
     {
         case Opcode.Get:
         case Opcode.GetQ:
         case Opcode.GetK:
         case Opcode.GetKq:
             rsp.Flags = _source.GetB32BE();
             var szk = _packet.KeyLength;
             // skip key bytes, returned when GetK was issued.
             if (szk != 0) _source.Skip((int)szk);
             szk = _packet.TotalBody - szk - 4;
             rsp.Data = ExtractBytes((int)szk);
             break;
         case Opcode.Set:
         case Opcode.SetQ:
         case Opcode.Add:
         case Opcode.AddQ:
         case Opcode.Replace:
         case Opcode.ReplaceQ:
             break;
         case Opcode.Inc:
         case Opcode.IncQ:
         case Opcode.Dec:
         case Opcode.DecQ:
             rsp.Counter = _source.GetB64BE();
             break;
         case Opcode.Noop:
         case Opcode.Delete:
         case Opcode.DeleteQ:
         case Opcode.Flush:
             break;
         case Opcode.Version:
         case Opcode.Stat:
             rsp.Data = ExtractBytes((int)_packet.TotalBody);
             break;
         case Opcode.Append:
         case Opcode.AppendQ:
         case Opcode.Prepend:
         case Opcode.PrependQ:
             break;
         default:
             throw new NotImplementedException();
     }
 }
 void IChannelSync.Dispatch(Message request, Message response)
 {
     var batch = new CachedRequest[1] { request as CachedRequest };
     var result = new CachedResponse[1] { response as CachedResponse };
     ExecuteBatch(batch, result);
 }
        public void ExecuteBatch(CachedRequest[] batch, CachedResponse[] result)
        {
            if (batch == null || batch.Length == 0) 
                return;

            // calculate transient memory space requirements.
            var bsize = CalcStackStize(batch);
            uint opaque = 1;
            DataKey* dataKey = null, last = null;
            var db = stackalloc byte[bsize];
            var cp = db;

            // copy requests data into memcached protocol format.
            foreach(var request in batch)
            {
                var dk = (DataKey*)cp;
                _init_dk(dk, request.Opcode);
                var key = request.Key;
                if (key != null)
                {
                    _set_key(dk, key, key.Length);
                    cp += _align8(sizeof(DataKey) + key.Length);
                }
                else cp += sizeof(DataKey);
                dk->opaque = opaque++;
                dk = SetDataKey(dk, request);
                // append new request to dataKey list
                if (last == null) dataKey = dk;
                else last->next = dk;
                last = dk;
            }

            // execute built-up request chain against cache.
            ExecuteBatch(dataKey, 0);
            
            // move cached results into responses fields.
            foreach(var response in result)
            {
                // copy response data from datakey into message.
                var status = dataKey->status;
                response.Status = 0;
                switch (status)
                {
                    case 0:
                        response.Cas = dataKey->cas;
                        response.Flags = Pbs.SwapBytes(dataKey->flags);
                        var dtsize = dataKey->ValSize;
                        if (dtsize > 0)
                        {
                            response.Data = new byte[dtsize];
                            _memcopy(response.Data, dataKey->val_addr, dtsize);
                        }
                        break;
                    case iSpecialCommand:
                        if (IncDecOps.Has(dataKey->opcode))
                        {
                            response.Cas = dataKey->cas;
                            response.Counter = (ulong)dataKey->longval;
                        }
                        else
                        {
                            //todo: support for more stats.
                            if (dataKey->opcode == (byte)Opcode.Version)
                                response.Data = sLocalVersion;
                        }
                        break;
                    default:
                        response.Status = status;
                        break;
                }
                // advance datakey in sync with responses list.
                dataKey = dataKey->next;
            }
        }