polardbxengine/storage/innobase/include/lizard0iv.h

268 lines
7.2 KiB
C++

/*****************************************************************************
Copyright (c) 2018, 2021, Alibaba and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL/PolarDB-X Engine hereby grant you an
additional permission to link the program and your derivative works with the
separately licensed software that they have included with
MySQL/PolarDB-X Engine.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License, version 2.0, for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/** @file include/lizard0iv.h
Lizard universe tools
Created 2021-11-05 by Jianwei.zhao
*******************************************************/
#ifndef lizard0iv_h
#define lizard0iv_h
#include "univ.i"
#include "hash0hash.h"
namespace lizard {
template <typename Element_type, size_t SIZE>
struct iv_hash_t {
public:
ulint n_cells;
hash_cell_t cells[SIZE];
explicit iv_hash_t() {
n_cells = SIZE;
memset(&cells, 0x0, sizeof(cells));
}
ulint size() { return n_cells; }
hash_cell_t *nth_cell(ulint fold) { return cells + fold; }
};
#define HASH_LINK_MAX_SIZE 4
/**
Insert into hash unqiuely.
@retval false success
@retval true failure
*/
template <typename Element_type, size_t SIZE>
bool iv_hash_insert(iv_hash_t<Element_type, SIZE> *hash, Element_type *elem) {
hash_cell_t *cell3333;
Element_type *struct3333;
ulint i = 0;
/** Insert last. */
elem->hash_node() = nullptr;
cell3333 = hash->nth_cell(ut_hash_ulint(elem->key(), hash->size()));
if (cell3333->node == nullptr) {
cell3333->node = elem;
return false;
} else {
struct3333 = (Element_type *)cell3333->node;
if (struct3333->key() == elem->key()) return true;
while (struct3333->hash_node() != nullptr) {
struct3333 = (Element_type *)struct3333->hash_node();
if (struct3333->key() == elem->key()) return true;
if (i++ > HASH_LINK_MAX_SIZE) return true;
}
struct3333->hash_node() = elem;
return false;
}
}
template <typename Element_type, size_t SIZE>
bool iv_hash_delete(iv_hash_t<Element_type, SIZE> *hash, Element_type *elem) {
hash_cell_t *cell3333;
Element_type *struct3333;
cell3333 = hash->nth_cell(ut_hash_ulint(elem->key(), hash->size()));
if (cell3333->node == elem) {
cell3333->node = elem->hash_node();
return false;
} else {
struct3333 = (Element_type *)cell3333->node;
while (struct3333->hash_node() != elem) {
struct3333 = (Element_type *)struct3333->hash_node();
ut_a(struct3333);
}
struct3333->hash_node() = elem->hash_node();
return false;
}
}
template <typename Element_type, typename Key_type, size_t SIZE>
Element_type *iv_hash_search(iv_hash_t<Element_type, SIZE> *hash,
Key_type key) {
hash_cell_t *cell3333;
cell3333 = hash->nth_cell(ut_hash_ulint(key, hash->size()));
Element_type *elem = (Element_type *)cell3333->node;
while (elem != nullptr) {
if (elem->key() == key) {
return elem;
}
elem = (Element_type *)elem->hash_node();
}
return nullptr;
}
template <typename Element_type, typename Key_type, typename Value_type>
class Cache_interface {
public:
Cache_interface() {}
virtual ~Cache_interface() {}
virtual bool insert(Value_type value) = 0;
virtual Value_type search(Key_type key) = 0;
};
template <typename Element_type, typename Key_type, typename Value_type,
size_t Prealloc>
class Random_array
: public Cache_interface<Element_type, Key_type, Value_type> {
public:
Random_array() {}
virtual ~Random_array() {}
virtual bool do_before_operation(size_t pos) { return false; }
virtual void do_after_operation(bool required, size_t pos) {}
virtual bool insert(Value_type value) {
size_t pos = ut_hash_ulint(value.key(), Prealloc);
bool pre_check = do_before_operation(pos);
if (!pre_check) {
m_elements[pos] = value;
}
do_after_operation(!pre_check, pos);
return pre_check;
}
virtual Value_type search(Key_type key) {
size_t pos = ut_hash_ulint(key, Prealloc);
bool pre_check = do_before_operation(pos);
Value_type value;
if (!pre_check) {
value = m_elements[pos];
}
do_after_operation(!pre_check, pos);
return value;
}
private:
Value_type m_elements[Prealloc];
};
#define ATOMIC_RANDOM_ARRAY_RETRY_MAX_TIMES 10
template <typename Element_type, typename Key_type, typename Value_type,
size_t Prealloc>
class Atomic_random_array
: public Random_array<Element_type, Key_type, Value_type, Prealloc> {
public:
Atomic_random_array() {}
virtual bool do_before_operation(size_t pos) {
uint loop = 0;
bool expected;
uint used_index = (pos%512) * 64;
retry:
if (loop++ > ATOMIC_RANDOM_ARRAY_RETRY_MAX_TIMES) return true;
expected = false;
if (m_used[used_index].compare_exchange_strong(expected, true)) {
return false;
} else {
goto retry;
}
}
virtual void do_after_operation(bool required, size_t pos) {
if (required) {
m_used[(pos%512) * 64].store(false);
}
}
private:
std::atomic<bool> m_used[512 * 64];
};
/**
Lru_list for array of tcn nodes,
also include:
1) Fixed array
2) Free list
3) LRU list
4) Hash
*/
template <typename Element_type, typename Key_type, typename Value_type,
size_t Prealloc>
class Lru_list : public Cache_interface<Element_type, Key_type, Value_type> {
constexpr static ulint HASH_SIZE = Prealloc / 2;
public:
explicit Lru_list();
virtual ~Lru_list();
bool insert(Value_type value);
Value_type search(Key_type key);
Element_type *get_free_item() {
Element_type *elem = nullptr;
retry:
/** Lock free list mutex */
elem = UT_LIST_GET_FIRST(m_free_list);
if (elem != nullptr) {
UT_LIST_REMOVE(m_free_list, elem);
return elem;
} else {
/** Lock lru list mutex */
/** Lock hash mutex */
elem = UT_LIST_GET_FIRST(m_lru_list);
UT_LIST_REMOVE(m_lru_list, elem);
iv_hash_delete(&hash, elem);
put_free_item(elem);
goto retry;
}
return elem;
}
void put_free_item(Element_type *elem) {
/** Lock free list mutex */
UT_LIST_ADD_LAST(m_free_list, elem);
}
private:
Element_type m_elements[Prealloc];
UT_LIST_BASE_NODE_T(Element_type) m_free_list;
UT_LIST_BASE_NODE_T(Element_type) m_lru_list;
iv_hash_t<Element_type, HASH_SIZE> hash;
};
} // namespace lizard
#endif