Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 132 additions & 5 deletions src/storage/SimpleLRU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,147 @@
namespace Afina {
namespace Backend {

void SimpleLRU::update_keynode(SimpleLRU::lru_node & cur_node, const std::string &value)
{
while (_nonblank_size - cur_node.value.size() + value.size() > _max_size) {
SimpleLRU::Delete(_lru_tail->key);
}
_nonblank_size += - cur_node.value.size() + value.size();
cur_node.value = value;
go_to_head(cur_node);
return;
}

void SimpleLRU::add_new_pair(const std::string &key, const std::string &value)
{
while (_nonblank_size + key.size() + value.size() > _max_size) {
SimpleLRU::Delete(_lru_tail->key);
}
SimpleLRU::lru_node * new_node = new SimpleLRU::lru_node{key, value, nullptr, nullptr};
if (_lru_head != nullptr)
{
_lru_head->prev = new_node;
}
if (_lru_tail == nullptr)
{
_lru_tail = new_node;
}
_nonblank_size += key.size() + value.size();
new_node->next = std::move(_lru_head);
_lru_head = std::unique_ptr<SimpleLRU::lru_node>(new_node);
_lru_index.emplace(std::make_pair(std::reference_wrapper<const std::string>(new_node->key), std::reference_wrapper<SimpleLRU::lru_node>(*new_node)));
go_to_head(*new_node);
return;
}

void SimpleLRU::del_node(SimpleLRU::lru_node & cur_node)
{
if (cur_node.prev != nullptr){
if(cur_node.next != nullptr){
cur_node.next->prev = cur_node.prev;
cur_node.prev->next = std::move(cur_node.next);
} else {
_lru_tail = cur_node.prev;
cur_node.prev->next = std::move(cur_node.next);
}
} else {
if (cur_node.next != nullptr){
cur_node.next->prev = cur_node.prev;
_lru_head = std::move(cur_node.next);
} else {
_lru_tail = cur_node.prev;
_lru_head = std::move(cur_node.next);
}
}
return;
}

void SimpleLRU::go_to_head(SimpleLRU::lru_node & cur_node)
{
if (_lru_head.get() != & cur_node)
{
auto one_more_ptr = std::move(cur_node.prev->next);
one_more_ptr->prev->next = std::move(one_more_ptr->next);
one_more_ptr->prev = nullptr;
if (one_more_ptr->next == nullptr) {
_lru_tail = one_more_ptr->prev;
} else {
one_more_ptr->next->prev = one_more_ptr->prev;
}
one_more_ptr->next = std::move(_lru_head);
one_more_ptr->next->prev = one_more_ptr.get();
_lru_head = std::move(one_more_ptr);
}
return;
}


// See MapBasedGlobalLockImpl.h
bool SimpleLRU::Put(const std::string &key, const std::string &value) { return false; }
bool SimpleLRU::Put(const std::string &key, const std::string &value) {
if (key.size() + value.size() > _max_size) {
return false;
}
auto find_key = _lru_index.find(std::reference_wrapper<const std::string>(key));
if (find_key != _lru_index.end()) {
update_keynode(find_key->second, value);
} else {
add_new_pair(key, value);
}
return true;
}

// See MapBasedGlobalLockImpl.h
bool SimpleLRU::PutIfAbsent(const std::string &key, const std::string &value) { return false; }
bool SimpleLRU::PutIfAbsent(const std::string &key, const std::string &value) {
if (key.size() + value.size() > _max_size) {
return false;
}
if (_lru_index.find(std::reference_wrapper<const std::string>(key)) != _lru_index.end()) {
return false;
}
add_new_pair(key, value);
return true;
}

// See MapBasedGlobalLockImpl.h
bool SimpleLRU::Set(const std::string &key, const std::string &value) { return false; }
bool SimpleLRU::Set(const std::string &key, const std::string &value) {
if (key.size() + value.size() > _max_size) {
return false;
}
auto find_key = _lru_index.find(std::reference_wrapper<const std::string>(key));
if (find_key == _lru_index.end()) {
return false;
}
update_keynode(find_key->second, value);
return true;
}

// See MapBasedGlobalLockImpl.h
bool SimpleLRU::Delete(const std::string &key) { return false; }
bool SimpleLRU::Delete(const std::string &key) {
if (_lru_head == nullptr) {
return false;
}
auto find_key = _lru_index.find(std::reference_wrapper<const std::string>(key));
if (find_key == _lru_index.end()) {
return false;
}
std::size_t del_size = find_key->second.get().key.size() + find_key->second.get().value.size();
auto cur_del_node = find_key->second;
_lru_index.erase(find_key);
_nonblank_size -= del_size;
SimpleLRU::del_node(cur_del_node);
return true;
}

// See MapBasedGlobalLockImpl.h
bool SimpleLRU::Get(const std::string &key, std::string &value) { return false; }
bool SimpleLRU::Get(const std::string &key, std::string &value) {
auto find_key = _lru_index.find(std::reference_wrapper<const std::string>(key));
if (find_key == _lru_index.end()) {
return false;
}
value = find_key->second.get().value;
go_to_head(find_key->second);
return true;
}

} // namespace Backend
} // namespace Afina
25 changes: 19 additions & 6 deletions src/storage/SimpleLRU.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ namespace Backend {
*/
class SimpleLRU : public Afina::Storage {
public:
SimpleLRU(size_t max_size = 1024) : _max_size(max_size) {}
SimpleLRU(size_t max_size = 1024) : _max_size(max_size), _nonblank_size(0),
_lru_tail(nullptr), _lru_head(nullptr) {}

~SimpleLRU() {
_lru_index.clear();
_lru_head.reset(); // TODO: Here is stack overflow
while (_lru_head != nullptr) {
auto next = std::move(_lru_head->next);
_lru_head.reset(nullptr);
_lru_head = std::move(next);
}
}

// Implements Afina::Storage interface
Expand All @@ -42,24 +47,32 @@ class SimpleLRU : public Afina::Storage {
private:
// LRU cache node
using lru_node = struct lru_node {
std::string key;
const std::string key;
std::string value;
std::unique_ptr<lru_node> prev;
lru_node *prev;
std::unique_ptr<lru_node> next;

};

// Maximum number of bytes could be stored in this cache.
// i.e all (keys+values) must be not greater than the _max_size
// i.e all (keys+values) must be less the _max_size
std::size_t _max_size;
std::size_t _nonblank_size;

// Main storage of lru_nodes, elements in this list ordered descending by "freshness": in the head
// element that wasn't used for longest time.
//
// List owns all nodes
std::unique_ptr<lru_node> _lru_head;
lru_node *_lru_tail;

// Index of nodes from list above, allows fast random access to elements by lru_node#key
std::map<std::reference_wrapper<std::string>, std::reference_wrapper<lru_node>, std::less<std::string>> _lru_index;
std::map<std::reference_wrapper<const std::string>, std::reference_wrapper<lru_node>, std::less<std::string>> _lru_index;

void update_keynode(lru_node & cur_node, const std::string &value);
void add_new_pair(const std::string &key, const std::string &value);
void del_node(lru_node & cur_node);
void go_to_head(lru_node & cur_node);
};

} // namespace Backend
Expand Down