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 int CalcStackStize(CachedRequest[] batch) { var bsize = 0; foreach(var request in batch) { var key = request.Key; bsize += _align8(sizeof(DataKey) + (key == null ? 0 : key.Length)); } return bsize; }
private void Encode(CachedRequest request, int opaque) { if (request == null) throw new ArgumentNullException(); var opc = opaque == 0 ? request.Opcode : (int)QuietMap[request.Opcode]; _packet.Reset(opc); if (opaque != 0) _packet.Opaque = (uint)opaque; var key = request.Key; switch ((Opcode)request.Opcode) { case Opcode.Get: case Opcode.GetQ: case Opcode.GetK: case Opcode.GetKq: case Opcode.Delete: case Opcode.DeleteQ: _packet.KeyLength = _packet.TotalBody = (uint)key.Length; _packet.WriteTo(_output); _output.WriteBytes(key, 0, key.Length); break; case Opcode.Set: case Opcode.SetQ: case Opcode.Add: case Opcode.AddQ: case Opcode.Replace: case Opcode.ReplaceQ: _packet.KeyLength = (uint)key.Length; _packet.ExtLength = 8; var data = request.Data; var vsz = data != null ? data.Length : 0; _packet.TotalBody = (uint)(key.Length + vsz + 8); if (request.Cas != 0) _packet.Cas = request.Cas; _packet.WriteTo(_output); _output.WriteB32BE((uint)request.Flags); _output.WriteB32BE(request.Expires); _output.WriteBytes(key, 0, key.Length); if (vsz > 0) _output.WriteBytes(data, 0, vsz); break; case Opcode.Noop: case Opcode.Version: case Opcode.Quit: case Opcode.QuitQ: _packet.WriteTo(_output); break; case Opcode.Flush: case Opcode.FlushQ: var expires = request.HasExpires; if (expires) _packet.ExtLength = _packet.TotalBody = 4; _packet.WriteTo(_output); if (expires) _output.WriteB32BE(request.Expires); break; case Opcode.Inc: case Opcode.IncQ: case Opcode.Dec: case Opcode.DecQ: _packet.ExtLength = 20; _packet.KeyLength = (uint)key.Length; _packet.TotalBody = (uint)(20 + key.Length); if (request.HasCas) _packet.Cas = request.Cas; _packet.WriteTo(_output); _output.WriteB64BE(request.Delta); _output.WriteB64BE(request.Flags); _output.WriteB32BE(request.Expires); _output.WriteBytes(key, 0, key.Length); break; case Opcode.Append: case Opcode.AppendQ: case Opcode.Prepend: case Opcode.PrependQ: _packet.KeyLength = (uint)key.Length; var pdata = request.Data; _packet.TotalBody = (uint)(key.Length + pdata.Length); if (request.Cas != 0) _packet.Cas = request.Cas; _packet.WriteTo(_output); _output.WriteBytes(key, 0, key.Length); _output.WriteBytes(pdata, 0, pdata.Length); break; default: throw new NotSupportedException(); } }
public CachedResponse(CachedRequest request) { Request = request; }
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; } }
private DataKey* SetDataKey(DataKey* dk, CachedRequest rqs) { dk->cas = rqs.Cas; dk->etime = rqs.Expires; dk->flags = Pbs.SwapBytes((uint)rqs.Flags); if (!IncDecOps.Has(dk->opcode)) { var data = rqs.Data; var size = rqs.DataCount; if (size > 0) { dk->ValSize = size; dk->val_addr = AllocValueMem(size); fixed (byte* ds = data) dk->AppendValue(ds + rqs.DataOffset, size, 0); } } else { dk->longval = (long)rqs.Delta; dk->def_val = (long)rqs.Flags; } return dk; }