private DataKey* LookupKey(DataKey* rqs, bool deleteKey = false) { var level = 0; var he = _htable + (rqs->hash & _hashMask); do { if (he->IsList) { DataKey* cp = he->List, nx; for (DataKey* wx = null; cp != null; wx = cp, cp = nx) { nx = cp->next; // check eviction opportunities. if (IsExpired(cp)) { var expired = DataKey.Equal(cp, rqs); he->Pop(wx); DeleteKey(cp); if (expired) break; cp = wx; continue; } // check if we have a clean match. if (DataKey.Equal(cp, rqs)) { if (!deleteKey) return LruUpdate(cp); he->Pop(wx); DeleteKey(cp); return null; } } } else { var htp = _hashBits + iHSubBits * level++; htp = (int)(rqs->hash >> htp) & iHSubMask; he = he->Htab + htp; continue; } // if command can append to cache, request entry will be consumed. if (!ReqsAdds.Has(rqs->opcode) || deleteKey) return null; Stats.CurrentItems++; // create new data key for the request. var nk = GetDk(rqs->KeySize); _copy_with_key(nk, rqs); // add new key to the head of LRU list. var head = _lruHead; nk->lrup = null; if (head != null) { nk->lrux = head; head->lrup = nk; } else _lruTail = nk; var hmax = he->Push(_lruHead = nk); if (hmax > 8 && hmax > 8 + level * 2 && level < 3) he->Split(GetBucket(), _hashBits + level * iHSubBits, iHSubMask); return nk; } while (true); }
private DataKey* LruUpdate(DataKey* cp) { if (_lruHead != cp) { DataKey* prev = cp->lrup, lx = cp->lrux; prev->lrux = lx; if (lx != null) lx->lrup = prev; else _lruTail = prev; cp->lrup = null; cp->lrux = _lruHead; _lruHead->lrup = cp; _lruHead = cp; } return cp; }
private byte* ParsePacket(byte* cp, byte* ep) { var left = (int)(ep - cp); if (left < SizeofPacket) return SaveIntoSplit(cp, left); var cr = (Packet*)cp; if (cr->magic != 0x80) throw new SerializationException("magic byte"); if (_ce == null) { // create new datakey and add it to the list. _ce = GetDk(cr); if (_clist == null) _clist = _ce; else _clast->next = _ce; _clast = _ce; } int xsz = cr->extlen, xks = xsz + _ce->KeySize; // buffer may split on extras or key part. if (xks > left - SizeofPacket) return SaveIntoSplit(cp, left); // copy key and extras bytes into place. cp += sizeof(Packet); _set_key(_ce, cp + xsz); if (xsz > 0) _ce->SetExtras(cp, xsz); return cp + xks; }
private void DeleteKey(DataKey* dk) { // remove entry from LRU list. DataKey* prev = dk->lrup, next = dk->lrux; if (next == null) if ((_lruTail = prev) != null) prev->lrux = null; else _lruHead = null; else { next->lrup = prev; if (prev != null) prev->lrux = next; else _lruHead = next; } // free key-mem and release val-mem. FreeDk(dk); }
public override int ParseExecuteRequest() { if (_stackSize > 512 * 1024) throw new InvalidOperationException("request-too-big"); // allocate space on stack for request headers and keys. _clist = _clast = _ce = null; byte* sp = stackalloc byte[_stackSize + iDataKeyLimit]; _split = _ep = sp + _stackSize; _cp = sp; // parse storage data into request entries. var bytesIn = _data.ContentSize; ParseRequests(_data); if (_ce != null) throw new SerializationException("corrupt memcached byte stream"); // run requests through cache instance, copy results into storage and release values. try { _cache.ExecuteBatch(_clist, bytesIn); OutputResponse(_data.Reset()); } finally { _cache.ReleaseValues(_clist, (uint)_data.ContentSize); _stackSize = 0; } return 0; }