Commit 18d8f06f authored by Eugene Kosov's avatar Eugene Kosov Committed by Eugene Kosov

intrusive::list fixes

namespace intrusive: removed

split class into two: ilist<T> and sized_ilist<T> which has a size field.

ilist<T> no more NULLify pointers to bring a slignly better performance.
As a consequence, fil_space_t::is_in_unflushed_spaces and
fil_space_t::is_in_rotation_list boolean members are needed now.
parent 403dacf6
/*
Copyright (c) 2019, MariaDB
Copyright (c) 2019, 2020, MariaDB
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
......@@ -21,26 +21,28 @@
#include <cstddef>
#include <iterator>
namespace intrusive
{
// Derive your class from this struct to insert to a linked list.
template <class Tag= void> struct list_node
template <class Tag= void> struct ilist_node
{
list_node(list_node *next= NULL, list_node *prev= NULL)
: next(next), prev(prev)
ilist_node()
:
#ifndef DBUG_OFF
next(NULL), prev(NULL)
#endif
{
}
list_node *next;
list_node *prev;
ilist_node(ilist_node *next, ilist_node *prev) : next(next), prev(prev) {}
ilist_node *next;
ilist_node *prev;
};
// Modelled after std::list<T>
template <class T, class Tag= void> class list
template <class T, class Tag= void> class ilist
{
public:
typedef list_node<Tag> ListNode;
typedef ilist_node<Tag> ListNode;
class Iterator;
// All containers in C++ should define these types to implement generic
......@@ -103,10 +105,10 @@ template <class T, class Tag= void> class list
private:
ListNode *node_;
friend class list;
friend class ilist;
};
list() : sentinel_(&sentinel_, &sentinel_), size_(0) {}
ilist() : sentinel_(&sentinel_, &sentinel_) {}
reference front() { return *begin(); }
reference back() { return *--end(); }
......@@ -127,14 +129,18 @@ template <class T, class Tag= void> class list
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const { return reverse_iterator(begin()); }
bool empty() const { return size_ == 0; }
size_type size() const { return size_; }
bool empty() const { return sentinel_.next == &sentinel_; }
// Not implemented because it's O(N)
// size_type size() const
// {
// return static_cast<size_type>(std::distance(begin(), end()));
// }
void clear()
{
sentinel_.next= &sentinel_;
sentinel_.prev= &sentinel_;
size_= 0;
}
iterator insert(iterator pos, reference value)
......@@ -148,7 +154,6 @@ template <class T, class Tag= void> class list
static_cast<ListNode &>(value).prev= prev;
static_cast<ListNode &>(value).next= curr;
++size_;
return iterator(&value);
}
......@@ -160,13 +165,12 @@ template <class T, class Tag= void> class list
prev->next= next;
next->prev= prev;
// This is not required for list functioning. But maybe it'll prevent bugs
// and ease debugging.
#ifndef DBUG_OFF
ListNode *curr= pos.node_;
curr->prev= NULL;
curr->next= NULL;
#endif
--size_;
return next;
}
......@@ -177,12 +181,63 @@ template <class T, class Tag= void> class list
void pop_front() { erase(begin()); }
// STL version is O(n) but this is O(1) because an element can't be inserted
// several times in the same intrusive list.
// several times in the same ilist.
void remove(reference value) { erase(iterator(&value)); }
private:
ListNode sentinel_;
size_type size_;
};
} // namespace intrusive
// Similar to ilist but also has O(1) size() method.
template <class T, class Tag= void> class sized_ilist : public ilist<T, Tag>
{
typedef ilist<T, Tag> BASE;
public:
// All containers in C++ should define these types to implement generic
// container interface.
using typename BASE::const_iterator;
using typename BASE::const_pointer;
using typename BASE::const_reference;
using typename BASE::const_reverse_iterator;
using typename BASE::difference_type;
using typename BASE::iterator;
using typename BASE::pointer;
using typename BASE::reference;
using typename BASE::reverse_iterator;
using typename BASE::size_type;
using typename BASE::value_type;
sized_ilist() : size_(0) {}
size_type size() const { return size_; }
void clear()
{
BASE::clear();
size_= 0;
}
iterator insert(iterator pos, reference value)
{
++size_;
return BASE::insert(pos, value);
}
iterator erase(iterator pos)
{
--size_;
return BASE::erase(pos);
}
void push_back(reference value) { insert(BASE::end(), value); }
void pop_back() { erase(BASE::end()); }
void push_front(reference value) { insert(BASE::begin(), value); }
void pop_front() { erase(BASE::begin()); }
void remove(reference value) { erase(iterator(&value)); }
private:
size_t size_;
};
......@@ -2261,7 +2261,7 @@ static void fil_crypt_rotation_list_fill()
space != NULL;
space = UT_LIST_GET_NEXT(space_list, space)) {
if (space->purpose != FIL_TYPE_TABLESPACE
|| space->is_in_rotation_list()
|| space->is_in_rotation_list
|| space->is_stopping()
|| UT_LIST_GET_LEN(space->chain) == 0) {
continue;
......@@ -2306,6 +2306,7 @@ static void fil_crypt_rotation_list_fill()
}
fil_system->rotation_list.push_back(*space);
space->is_in_rotation_list = true;
}
}
......
/*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2014, 2019, MariaDB Corporation.
Copyright (c) 2014, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
......@@ -832,7 +832,7 @@ static void fil_flush_low(fil_space_t* space, bool metadata = false)
/* No need to flush. User has explicitly disabled
buffering. */
ut_ad(!space->is_in_unflushed_spaces());
ut_ad(!space->is_in_unflushed_spaces);
ut_ad(fil_space_is_flushed(space));
ut_ad(space->n_pending_flushes == 0);
......@@ -895,10 +895,11 @@ static void fil_flush_low(fil_space_t* space, bool metadata = false)
skip_flush:
#endif /* _WIN32 */
if (!node->needs_flush) {
if (space->is_in_unflushed_spaces()
if (space->is_in_unflushed_spaces
&& fil_space_is_flushed(space)) {
fil_system->unflushed_spaces.remove(*space);
space->is_in_unflushed_spaces = false;
}
}
......@@ -1193,13 +1194,14 @@ fil_node_close_to_free(
if (fil_buffering_disabled(space)) {
ut_ad(!space->is_in_unflushed_spaces());
ut_ad(!space->is_in_unflushed_spaces);
ut_ad(fil_space_is_flushed(space));
} else if (space->is_in_unflushed_spaces()
} else if (space->is_in_unflushed_spaces
&& fil_space_is_flushed(space)) {
fil_system->unflushed_spaces.remove(*space);
space->is_in_unflushed_spaces = false;
}
fil_node_close_file(node);
......@@ -1226,16 +1228,18 @@ fil_space_detach(
HASH_DELETE(fil_space_t, name_hash, fil_system->name_hash,
ut_fold_string(space->name), space);
if (space->is_in_unflushed_spaces()) {
if (space->is_in_unflushed_spaces) {
ut_ad(!fil_buffering_disabled(space));
fil_system->unflushed_spaces.remove(*space);
space->is_in_unflushed_spaces = false;
}
if (space->is_in_rotation_list()) {
if (space->is_in_rotation_list) {
fil_system->rotation_list.remove(*space);
space->is_in_rotation_list = false;
}
UT_LIST_REMOVE(fil_system->space_list, space);
......@@ -1462,6 +1466,7 @@ fil_space_create(
/* Key rotation is not enabled, need to inform background
encryption threads. */
fil_system->rotation_list.push_back(*space);
space->is_in_rotation_list = true;
mutex_exit(&fil_system->mutex);
mutex_enter(&fil_crypt_threads_mutex);
os_event_set(fil_crypt_threads_event);
......@@ -4751,16 +4756,17 @@ fil_node_complete_io(fil_node_t* node, const IORequest& type)
/* We don't need to keep track of unflushed
changes as user has explicitly disabled
buffering. */
ut_ad(!node->space->is_in_unflushed_spaces());
ut_ad(!node->space->is_in_unflushed_spaces);
ut_ad(node->needs_flush == false);
} else {
node->needs_flush = true;
if (!node->space->is_in_unflushed_spaces()) {
if (!node->space->is_in_unflushed_spaces) {
fil_system->unflushed_spaces.push_front(
*node->space);
node->space->is_in_unflushed_spaces = true;
}
}
}
......@@ -5247,7 +5253,7 @@ fil_flush_file_spaces(
n_space_ids = 0;
for (intrusive::list<fil_space_t, unflushed_spaces_tag_t>::iterator it
for (sized_ilist<fil_space_t, unflushed_spaces_tag_t>::iterator it
= fil_system->unflushed_spaces.begin(),
end = fil_system->unflushed_spaces.end();
it != end; ++it) {
......@@ -5974,9 +5980,10 @@ fil_space_remove_from_keyrotation(fil_space_t* space)
ut_ad(mutex_own(&fil_system->mutex));
ut_ad(space);
if (space->n_pending_ops == 0 && space->is_in_rotation_list()) {
if (space->n_pending_ops == 0 && space->is_in_rotation_list) {
ut_a(!fil_system->rotation_list.empty());
fil_system->rotation_list.remove(*space);
space->is_in_rotation_list = false;
}
}
......@@ -6005,7 +6012,7 @@ fil_space_t *fil_system_t::keyrotate_next(fil_space_t *prev_space,
don't remove the last processed tablespace from the rotation list. */
const bool remove= (!recheck || prev_space->crypt_data) &&
!key_version == !srv_encrypt_tables;
intrusive::list<fil_space_t, rotation_list_tag_t>::iterator it=
sized_ilist<fil_space_t, rotation_list_tag_t>::iterator it=
prev_space == NULL ? fil_system->rotation_list.end() : prev_space;
if (it == fil_system->rotation_list.end())
......@@ -6117,24 +6124,3 @@ fil_space_set_punch_hole(
{
node->space->punch_hole = val;
}
/** Checks that this tablespace in a list of unflushed tablespaces.
@return true if in a list */
bool fil_space_t::is_in_unflushed_spaces() const
{
ut_ad(mutex_own(&fil_system->mutex));
return static_cast<const intrusive::list_node<unflushed_spaces_tag_t> *>(
this)
->next;
}
/** Checks that this tablespace needs key rotation.
@return true if in a rotation list */
bool fil_space_t::is_in_rotation_list() const
{
ut_ad(mutex_own(&fil_system->mutex));
return static_cast<const intrusive::list_node<rotation_list_tag_t> *>(this)
->next;
}
......@@ -29,7 +29,7 @@ Created 2013-03-16 Sunny Bains
#include "mem0mem.h"
#include "dyn0types.h"
#include "intrusive_list.h"
#include "ilist.h"
/** Class that manages dynamic buffers. It uses a UT_LIST of
......@@ -43,7 +43,7 @@ template <size_t SIZE = DYN_ARRAY_DATA_SIZE>
class dyn_buf_t {
public:
class block_t : public intrusive::list_node<> {
class block_t : public ilist_node<> {
public:
block_t()
......@@ -153,7 +153,7 @@ class dyn_buf_t {
/** SIZE - sizeof(m_node) + sizeof(m_used) */
enum {
MAX_DATA_SIZE = SIZE
- sizeof(intrusive::list_node<>)
- sizeof(ilist_node<>)
+ sizeof(ib_uint32_t)
};
......@@ -167,7 +167,7 @@ class dyn_buf_t {
friend class dyn_buf_t;
};
typedef intrusive::list<block_t> list_t;
typedef sized_ilist<block_t> list_t;
enum { MAX_DATA_SIZE = block_t::MAX_DATA_SIZE};
......
......@@ -33,7 +33,7 @@ Created 10/25/1995 Heikki Tuuri
#include "dict0types.h"
#include "page0size.h"
#include "ibuf0types.h"
#include "intrusive_list.h"
#include "ilist.h"
#include <list>
......@@ -82,8 +82,8 @@ fil_type_is_data(
struct fil_node_t;
/** Tablespace or log data space */
struct fil_space_t : intrusive::list_node<unflushed_spaces_tag_t>,
intrusive::list_node<rotation_list_tag_t>
struct fil_space_t : ilist_node<unflushed_spaces_tag_t>,
ilist_node<rotation_list_tag_t>
{
ulint id; /*!< space id */
hash_node_t hash; /*!< hash chain node */
......@@ -165,18 +165,18 @@ struct fil_space_t : intrusive::list_node<unflushed_spaces_tag_t>,
UT_LIST_NODE_T(fil_space_t) named_spaces;
/*!< list of spaces for which MLOG_FILE_NAME
records have been issued */
/** Checks that this tablespace in a list of unflushed tablespaces.
@return true if in a list */
bool is_in_unflushed_spaces() const;
UT_LIST_NODE_T(fil_space_t) space_list;
/*!< list of all spaces */
/** Checks that this tablespace needs key rotation.
@return true if in a rotation list */
bool is_in_rotation_list() const;
/** MariaDB encryption data */
fil_space_crypt_t* crypt_data;
/** Checks that this tablespace in a list of unflushed tablespaces. */
bool is_in_unflushed_spaces;
/** Checks that this tablespace needs key rotation. */
bool is_in_rotation_list;
/** True if the device this filespace is on supports atomic writes */
bool atomic_write_supported;
......@@ -507,7 +507,7 @@ struct fil_system_t {
not put to this list: they are opened
after the startup, and kept open until
shutdown */
intrusive::list<fil_space_t, unflushed_spaces_tag_t> unflushed_spaces;
sized_ilist<fil_space_t, unflushed_spaces_tag_t> unflushed_spaces;
/*!< list of those
tablespaces whose files contain
unflushed writes; those spaces have
......@@ -530,7 +530,7 @@ struct fil_system_t {
record has been written since
the latest redo log checkpoint.
Protected only by log_sys->mutex. */
intrusive::list<fil_space_t, rotation_list_tag_t> rotation_list;
ilist<fil_space_t, rotation_list_tag_t> rotation_list;
/*!< list of all file spaces needing
key rotation.*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment