blob: 3cf62e7081e96eee04926494ceea2a2164ffd15f [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include "tscore/ink_defs.h"
#include <openssl/sha.h>
#ifndef HAVE_SHA1
#include <openssl/evp.h>
#endif
#include <cstring>
#include <unordered_map>
#include <list>
#include <tuple>
#include "policy.h"
#define MINIMUM_BUCKET_SIZE 10
//////////////////////////////////////////////////////////////////////////////////////////////
// The LRU based policy keeps track of <bucket> number of URLs, with a counter for each slot.
// Objects are not promoted unless the counter reaches <hits> before it gets evicted. An
// optional <chance> parameter can be used to sample hits, this can reduce contention and
// churning in the LRU as well.
//
class LRUHash
{
friend struct LRUHashHasher;
public:
LRUHash() { TSDebug(PLUGIN_NAME, "LRUHash() CTOR"); }
~LRUHash() { TSDebug(PLUGIN_NAME, "~LRUHash() DTOR"); }
LRUHash(const LRUHash &h)
{
TSDebug(PLUGIN_NAME, "Copy CTOR an LRUHash object");
memcpy(_hash, h._hash, sizeof(_hash));
}
LRUHash &
operator=(const LRUHash &h)
{
TSDebug(PLUGIN_NAME, "copying an LRUHash object");
if (this != &h) {
memcpy(_hash, h._hash, sizeof(_hash));
}
return *this;
}
// Initialize the hash key from the TXN's URL
bool initFromUrl(TSHttpTxn txnp);
private:
u_char _hash[SHA_DIGEST_LENGTH];
};
struct LRUHashHasher {
bool
operator()(const LRUHash *s1, const LRUHash *s2) const
{
return 0 == memcmp(s1->_hash, s2->_hash, sizeof(s2->_hash));
}
size_t
operator()(const LRUHash *s) const
{
return *(reinterpret_cast<const size_t *>(s->_hash)) ^ *(reinterpret_cast<const size_t *>(s->_hash + 9));
}
};
using LRUEntry = std::tuple<LRUHash, unsigned, int64_t>;
using LRUList = std::list<LRUEntry>;
using LRUMap = std::unordered_map<const LRUHash *, LRUList::iterator, LRUHashHasher, LRUHashHasher>;
class LRUPolicy : public PromotionPolicy
{
public:
LRUPolicy() : PromotionPolicy(), _lock(TSMutexCreate()) {}
~LRUPolicy() override;
bool parseOption(int opt, char *optarg) override;
bool doPromote(TSHttpTxn txnp) override;
bool stats_add(const char *remap_id) override;
void addBytes(TSHttpTxn txnp) override;
bool
countBytes() const override
{
return _bytes > 0;
}
void
usage() const override
{
TSError("[%s] Usage: @plugin=%s.so @pparam=--policy=lru @pparam=--buckets=<m> --hits=<n> --bytes=<o> --sample=<p>", PLUGIN_NAME,
PLUGIN_NAME);
}
const char *
policyName() const override
{
return "LRU";
}
const std::string
id() const override
{
return _label + ";LRU=b:" + std::to_string(_buckets) + ",h:" + std::to_string(_hits) + ",B:" + std::to_string(_bytes);
}
void
cleanup(TSHttpTxn txnp) override
{
LRUHash *hash = static_cast<LRUHash *>(TSUserArgGet(txnp, TXN_ARG_IDX));
// Delete the hash, and remove the pointer from the TXN user arg slot (to be safe)
if (hash) {
delete hash;
TSUserArgSet(txnp, TXN_ARG_IDX, nullptr);
}
}
private:
unsigned _buckets = 1000;
unsigned _hits = 10;
int64_t _bytes = 0;
std::string _label = "";
// For the LRU. Note that we keep track of the List sizes, because some versions fo STL have broken
// implementations of size(), making them obsessively slow on calling ::size().
TSMutex _lock;
LRUMap _map;
LRUList _list, _freelist;
size_t _list_size = 0, _freelist_size = 0;
// internal stats ids
int _freelist_size_id = -1;
int _lru_size_id = -1;
int _lru_hit_id = -1;
int _lru_miss_id = -1;
int _lru_vacated_id = -1;
int _promoted_id = -1;
};