From c8f5b098adee4b01e653a3a67a9c3533d948bb9b Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Mon, 22 Nov 2021 15:03:08 +0800 Subject: [PATCH 01/36] add space map into pagestorage v3 --- CMakeLists.txt | 3 + dbms/CMakeLists.txt | 4 + dbms/src/Storages/CMakeLists.txt | 4 + dbms/src/Storages/Page/V3/CMakeLists.txt | 16 + dbms/src/Storages/Page/V3/spacemap/bits.cpp | 88 +++ dbms/src/Storages/Page/V3/spacemap/bits.h | 19 + .../src/Storages/Page/V3/spacemap/rb_tree.cpp | 509 +++++++++++++ dbms/src/Storages/Page/V3/spacemap/rb_tree.h | 71 ++ .../Storages/Page/V3/spacemap/space_map.cpp | 174 +++++ .../src/Storages/Page/V3/spacemap/space_map.h | 119 ++++ .../Page/V3/spacemap/space_map_rbtree.cpp | 666 ++++++++++++++++++ .../src/Storages/Page/V3/tests/CMakeLists.txt | 15 + .../Storages/Page/V3/tests/gtest_free_map.cpp | 122 ++++ 13 files changed, 1810 insertions(+) create mode 100644 dbms/src/Storages/Page/V3/CMakeLists.txt create mode 100644 dbms/src/Storages/Page/V3/spacemap/bits.cpp create mode 100644 dbms/src/Storages/Page/V3/spacemap/bits.h create mode 100644 dbms/src/Storages/Page/V3/spacemap/rb_tree.cpp create mode 100644 dbms/src/Storages/Page/V3/spacemap/rb_tree.h create mode 100644 dbms/src/Storages/Page/V3/spacemap/space_map.cpp create mode 100644 dbms/src/Storages/Page/V3/spacemap/space_map.h create mode 100644 dbms/src/Storages/Page/V3/spacemap/space_map_rbtree.cpp create mode 100644 dbms/src/Storages/Page/V3/tests/CMakeLists.txt create mode 100644 dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8efc87575ff..4198428894d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -364,6 +364,9 @@ else (ENABLE_FAILPOINTS) message (STATUS "Failpoints are disabled") endif (ENABLE_FAILPOINTS) +# Enable PageStorage V3 test. +option (ENABLE_V3_PAGESTORAGE "Enables V3 PageStorage" ON) + # Flags for test coverage option (TEST_COVERAGE "Enables flags for test coverage" OFF) option (TEST_COVERAGE_XML "Output XML report for test coverage" OFF) diff --git a/dbms/CMakeLists.txt b/dbms/CMakeLists.txt index de778848b03..9668972ac44 100644 --- a/dbms/CMakeLists.txt +++ b/dbms/CMakeLists.txt @@ -80,6 +80,10 @@ add_headers_and_sources(dbms src/Storages/Page/V2/mvcc) add_headers_and_sources(dbms src/Storages/Page/V2/VersionSet) add_headers_and_sources(dbms src/Storages/Page/V2/gc) add_headers_and_sources(dbms src/Storages/Page/) +if (ENABLE_V3_PAGESTORAGE) + add_headers_and_sources(dbms src/Storages/Page/V3) + add_headers_and_sources(dbms src/Storages/Page/V3/freemap) +endif() add_headers_and_sources(dbms src/TiDB) add_headers_and_sources(dbms src/Client) add_headers_only(dbms src/Flash/Coprocessor) diff --git a/dbms/src/Storages/CMakeLists.txt b/dbms/src/Storages/CMakeLists.txt index 29ab6a82368..6d64bb7671e 100644 --- a/dbms/src/Storages/CMakeLists.txt +++ b/dbms/src/Storages/CMakeLists.txt @@ -7,5 +7,9 @@ if (ENABLE_TESTS) add_subdirectory (Transaction/tests EXCLUDE_FROM_ALL) add_subdirectory (Page/V2/tests EXCLUDE_FROM_ALL) add_subdirectory (DeltaMerge/tests EXCLUDE_FROM_ALL) + if (ENABLE_V3_PAGESTORAGE) + add_subdirectory (Page/V3 EXCLUDE_FROM_ALL) + add_subdirectory (Page/V3/tests EXCLUDE_FROM_ALL) + endif () endif () diff --git a/dbms/src/Storages/Page/V3/CMakeLists.txt b/dbms/src/Storages/Page/V3/CMakeLists.txt new file mode 100644 index 00000000000..64f39cbdfc1 --- /dev/null +++ b/dbms/src/Storages/Page/V3/CMakeLists.txt @@ -0,0 +1,16 @@ +add_headers_and_sources(page_storage_v3 ./) +add_headers_and_sources(page_storage_v3 ./spacemap) + + +list(APPEND page_storage_v3_sources + ${ClickHouse_SOURCE_DIR}/dbms/src/Server/StorageConfigParser.cpp + ${ClickHouse_SOURCE_DIR}/dbms/src/Storages/Page/PageUtil.cpp + ${ClickHouse_SOURCE_DIR}/dbms/src/Encryption/RateLimiter.cpp +) + +add_library(page_storage_v3 EXCLUDE_FROM_ALL + ${page_storage_v3_headers} ${page_storage_v3_sources} + ${io_base_headers} ${io_base_sources} +) +target_include_directories(page_storage_v3 PUBLIC ${ClickHouse_SOURCE_DIR}/contrib/tiflash-proxy/raftstore-proxy/ffi/src) +target_link_libraries(page_storage_v3 clickhouse_common_io cpptoml kv_client tipb) \ No newline at end of file diff --git a/dbms/src/Storages/Page/V3/spacemap/bits.cpp b/dbms/src/Storages/Page/V3/spacemap/bits.cpp new file mode 100644 index 00000000000..2f3e1ebf26b --- /dev/null +++ b/dbms/src/Storages/Page/V3/spacemap/bits.cpp @@ -0,0 +1,88 @@ +#include "bits.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int set_bit(unsigned int nr, void * addr) +{ + int mask, retval; + unsigned char * ADDR = (unsigned char *)addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + retval = mask & *ADDR; + *ADDR |= mask; + return retval; +} + +int clear_bit(unsigned int nr, void * addr) +{ + int mask, retval; + unsigned char * ADDR = (unsigned char *)addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + retval = mask & *ADDR; + *ADDR &= ~mask; + return retval; +} + +int test_bit(unsigned int nr, const void * addr) +{ + int mask; + const unsigned char * ADDR = (const unsigned char *)addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + return (mask & *ADDR); +} + +/* + * C-only 64 bit ops. + */ +int set_bit64(UInt64 nr, void * addr) +{ + int mask, retval; + unsigned char * ADDR = (unsigned char *)addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + retval = mask & *ADDR; + *ADDR |= mask; + return retval; +} + +int clear_bit64(UInt64 nr, void * addr) +{ + int mask, retval; + unsigned char * ADDR = (unsigned char *)addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + retval = mask & *ADDR; + *ADDR &= ~mask; + return retval; +} + +int test_bit64(UInt64 nr, const void * addr) +{ + int mask; + const unsigned char * ADDR = (const unsigned char *)addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + return (mask & *ADDR); +} + +unsigned int div_ceil(UInt64 a, UInt64 b) +{ + if (!a) + return 0; + return ((a - 1) / b) + 1; +} + + +#ifdef __cplusplus +} +#endif diff --git a/dbms/src/Storages/Page/V3/spacemap/bits.h b/dbms/src/Storages/Page/V3/spacemap/bits.h new file mode 100644 index 00000000000..ba5d2884155 --- /dev/null +++ b/dbms/src/Storages/Page/V3/spacemap/bits.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int set_bit(unsigned int nr, void * addr); +int clear_bit(unsigned int nr, void * addr); +int test_bit(unsigned int nr, const void * addr); +int set_bit64(UInt64 nr, void * addr); +int clear_bit64(UInt64 nr, void * addr); +int test_bit64(UInt64 nr, const void * addr); +unsigned int div_ceil(UInt64 a, UInt64 b); + +#ifdef __cplusplus +} // extern "C" +#endif \ No newline at end of file diff --git a/dbms/src/Storages/Page/V3/spacemap/rb_tree.cpp b/dbms/src/Storages/Page/V3/spacemap/rb_tree.cpp new file mode 100644 index 00000000000..0bb8e090758 --- /dev/null +++ b/dbms/src/Storages/Page/V3/spacemap/rb_tree.cpp @@ -0,0 +1,509 @@ +#include "rb_tree.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define COLOR_BLACK 1 +#define COLOR_MASK 3 + +static inline struct rb_node * node_parent(struct rb_node * node) +{ + return (struct rb_node *)(node->parent & ~COLOR_MASK); +} + +static inline uintptr_t node_color(struct rb_node * node) +{ + return node->parent & COLOR_BLACK; +} + +static inline void node_set_red(struct rb_node * node) +{ + node->parent &= ~COLOR_BLACK; +} + +static inline void node_set_black(struct rb_node * node) +{ + node->parent |= COLOR_BLACK; +} + +static inline void node_set_parent(struct rb_node * node, struct rb_node * p) +{ + node->parent = (node->parent & COLOR_MASK) | (uintptr_t)p; +} + +static inline void node_set_color(struct rb_node * node, int color) +{ + node->parent = (node->parent & ~COLOR_BLACK) | color; +} + +static inline void node_clear(struct rb_node * node) +{ + node_set_parent(node, node); +} + +static void node_rotate_left(struct rb_node * node, struct rb_root * root) +{ + struct rb_node * right = node->node_right; + struct rb_node * parent = node_parent(node); + + if ((node->node_right = right->node_left)) + { + node_set_parent(right->node_left, node); + } + + right->node_left = node; + + node_set_parent(right, parent); + + if (parent) + { + if (node == parent->node_left) + { + parent->node_left = right; + } + else + { + parent->node_right = right; + } + } + else + { + root->rb_node = right; + } + + node_set_parent(node, right); +} + +static void node_rotate_right(struct rb_node * node, struct rb_root * root) +{ + struct rb_node * left = node->node_left; + struct rb_node * parent = node_parent(node); + + if ((node->node_left = left->node_right)) + node_set_parent(left->node_right, node); + left->node_right = node; + + node_set_parent(left, parent); + + if (parent) + { + if (node == parent->node_right) + { + parent->node_right = left; + } + + else + { + parent->node_left = left; + } + } + else + { + root->rb_node = left; + } + node_set_parent(node, left); +} + +static void node_clear_color(struct rb_node * node, struct rb_node * parent, struct rb_root * root) +{ + struct rb_node * other; + + while ((!node || node_color(node)) && node != root->rb_node) + { + if (parent->node_left == node) + { + other = parent->node_right; + if (!node_color(other)) + { + node_set_black(other); + node_set_red(parent); + node_rotate_left(parent, root); + other = parent->node_right; + } + if ((!other->node_left || node_color(other->node_left)) && (!other->node_right || node_color(other->node_right))) + { + node_set_red(other); + node = parent; + parent = node_parent(node); + } + else + { + if (!other->node_right || node_color(other->node_right)) + { + node_set_black(other->node_left); + node_set_red(other); + node_rotate_right(other, root); + other = parent->node_right; + } + node_set_color(other, node_color(parent)); + node_set_black(parent); + node_set_black(other->node_right); + node_rotate_left(parent, root); + node = root->rb_node; + break; + } + } + else + { + other = parent->node_left; + if (!node_color(other)) + { + node_set_black(other); + node_set_red(parent); + node_rotate_right(parent, root); + other = parent->node_left; + } + if ((!other->node_left || node_color(other->node_left)) && (!other->node_right || node_color(other->node_right))) + { + node_set_red(other); + node = parent; + parent = node_parent(node); + } + else + { + if (!other->node_left || node_color(other->node_left)) + { + node_set_black(other->node_right); + node_set_red(other); + node_rotate_left(other, root); + other = parent->node_left; + } + node_set_color(other, node_color(parent)); + node_set_black(parent); + node_set_black(other->node_left); + node_rotate_right(parent, root); + node = root->rb_node; + break; + } + } + } + if (node) + { + node_set_black(node); + } +} + + +void rb_node_insert(struct rb_node * node, struct rb_root * root) +{ + struct rb_node *parent, *gparent; + + while ((parent = node_parent(node)) && !node_color(parent)) + { + gparent = node_parent(parent); + if (parent == gparent->node_left) + { + { + // register + struct rb_node * uncle = gparent->node_right; + if (uncle && !node_color(uncle)) + { + node_set_black(uncle); + node_set_black(parent); + node_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->node_right == node) + { + // register + struct rb_node * tmp; + node_rotate_left(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + node_set_black(parent); + node_set_red(gparent); + node_rotate_right(gparent, root); + } + else + { + { + // register + struct rb_node * uncle = gparent->node_left; + if (uncle && !node_color(uncle)) + { + node_set_black(uncle); + node_set_black(parent); + node_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->node_left == node) + { + // register + struct rb_node * tmp; + node_rotate_right(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + node_set_black(parent); + node_set_red(gparent); + node_rotate_left(gparent, root); + } + } + + node_set_black(root->rb_node); +} + +void rb_node_remove(struct rb_node * node, struct rb_root * root) +{ + struct rb_node *child, *parent; + int color; + + if (!node->node_left) + { + child = node->node_right; + } + else if (!node->node_right) + { + child = node->node_left; + } + else + { + struct rb_node *old = node, *left; + + node = node->node_right; + while ((left = node->node_left) != NULL) + { + node = left; + } + + if (node_parent(old)) + { + if (node_parent(old)->node_left == old) + { + node_parent(old)->node_left = node; + } + else + { + node_parent(old)->node_right = node; + } + } + else + { + root->rb_node = node; + } + + child = node->node_right; + parent = node_parent(node); + color = node_color(node); + + if (parent == old) + { + parent = node; + } + else + { + if (child) + { + node_set_parent(child, parent); + } + + parent->node_left = child; + node->node_right = old->node_right; + node_set_parent(old->node_right, node); + } + + node->parent = old->parent; + node->node_left = old->node_left; + node_set_parent(old->node_left, node); + + goto check_color; + } + + parent = node_parent(node); + color = node_color(node); + + if (child) + { + node_set_parent(child, parent); + } + + if (parent) + { + if (parent->node_left == node) + { + parent->node_left = child; + } + else + { + parent->node_right = child; + } + } + else + { + root->rb_node = child; + } + +check_color: + if (color == COLOR_BLACK) + { + node_clear_color(child, parent, root); + } +} + +struct rb_node * rb_tree_first(const struct rb_root * root) +{ + struct rb_node * n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->node_left) + n = n->node_left; + return n; +} + +struct rb_node * rb_tree_last(const struct rb_root * root) +{ + struct rb_node * n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->node_right) + n = n->node_right; + return n; +} + +struct rb_node * rb_tree_next(struct rb_node * current) +{ + struct rb_node * parent; + + // No more `next` node. + if (node_parent(current) == current) + { + return NULL; + } + + // If tree looks like: + // A + // / \ + // B C + // / \ / + // D E F ... + // / \ + // G H + // Then the node is `B` , it should return `G` + // Because `G` will bigger than `B` but small than `E` + if (current->node_right) + { + current = current->node_right; + while (current->node_left) + { + current = current->node_left; + } + + return current; + } + + // In this situation, there are left-node exist. + // And all of left node is smaller than `current` node + // So the `next` node must in parent node,Then we need go up into the parent node. + // If `current` node is the right-node child of its parent, Then it still need go up for upper layer. + while ((parent = node_parent(current)) && current == parent->node_right) + { + current = parent; + } + + return parent; +} + +struct rb_node * rb_tree_prev(struct rb_node * current) +{ + struct rb_node * parent; + + // No more `prev` node. + if (node_parent(current) == current) + { + return NULL; + } + + // Same as `rb_tree_next` + // If tree looks like: + // A + // / \ + // B C + // \ / \ + // ... D E F + // / \ + // G H + // Then the node is `C` , it should return `H` + // Because `H` smaller than `C` but small than `E` + if (current->node_left) + { + current = current->node_left; + while (current->node_right) + { + current = current->node_right; + } + return current; + } + + // Same as `rb_tree_next` + // In this situation, there are left-node exist. + // And all of left node is bigger than `current` node + // So the `prev` node must in parent node,Then we need go up into the parent node. + // If `current` node is the left-node child of its parent, Then it still need go up for upper layer. + while ((parent = node_parent(current)) && current == parent->node_left) + current = parent; + + return parent; +} + +void rb_tree_update_node(struct rb_node * old_node, struct rb_node * new_node, struct rb_root * root) +{ + struct rb_node * parent = node_parent(old_node); + + assert(parent != NULL); + + if (parent) + { + // Update the parent ptr to child + if (old_node == parent->node_left) + { + parent->node_left = new_node; + } + else if (old_node == parent->node_right) + { + parent->node_right = new_node; + } + else + { + assert(false); + } + } + else + { + // No find parent, tree is empty + // Just update the root + root->rb_node = new_node; + } + + // Let the `child` node point to the `new` node + if (old_node->node_left) + { + node_set_parent(old_node->node_left, new_node); + } + + if (old_node->node_right) + { + node_set_parent(old_node->node_right, new_node); + } + + *new_node = *old_node; +} + +#ifdef __cplusplus +} // extern "C" +#endif \ No newline at end of file diff --git a/dbms/src/Storages/Page/V3/spacemap/rb_tree.h b/dbms/src/Storages/Page/V3/spacemap/rb_tree.h new file mode 100644 index 00000000000..4d40e7dad8b --- /dev/null +++ b/dbms/src/Storages/Page/V3/spacemap/rb_tree.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rb_node +{ + /** + * using uintptr_t + * - contain node color + * - contain parent ptr + */ + uintptr_t parent; + struct rb_node * node_right; + struct rb_node * node_left; +} __attribute__((aligned(sizeof(long)))); + +struct rb_root +{ + struct rb_node * rb_node; +}; + +/** + * Insert node into red-black tree + */ +void rb_node_insert(struct rb_node *, struct rb_root *); + +/** + * remove node from red-black tree + */ +void rb_node_remove(struct rb_node *, struct rb_root *); + +/** + * Return the first node of the tree. + * It is a O(n) method + * call the `rb_next` as a iterator + */ +struct rb_node * rb_tree_first(const struct rb_root *); + +/** + * Return the last node of the tree. + * It is a O(n) method + * call the `rb_prev` as a iterator + */ +struct rb_node * rb_tree_last(const struct rb_root *); + +/** + * Return the next node of the tree. + */ +struct rb_node * rb_tree_next(struct rb_node *); + +/** + * Return the prev node of the tree. + */ +struct rb_node * rb_tree_prev(struct rb_node *); + +/** + * Update node into a new node + * - Just replace the position, tree won't rotate + * - Note its own pointer + */ +void rb_tree_update_node(struct rb_node * old_node, struct rb_node * new_node, struct rb_root * root); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/dbms/src/Storages/Page/V3/spacemap/space_map.cpp b/dbms/src/Storages/Page/V3/spacemap/space_map.cpp new file mode 100644 index 00000000000..5284a678aa2 --- /dev/null +++ b/dbms/src/Storages/Page/V3/spacemap/space_map.cpp @@ -0,0 +1,174 @@ +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include "space_map.h" + +void printf_smap(struct spacemap * smap) +{ + if (unlikely(!smap)) + { + return; + } + smap->spacemap_ops->print_stats(smap); +} + +int unmark_smap(struct spacemap * smap, UInt64 arg) +{ + if (unlikely(!smap)) + { + return -1; + } + + arg >>= smap->cluster_bits; + + if ((arg < smap->start) || (arg > smap->end)) + { + return -1; + } + + return smap->spacemap_ops->unmark_smap_bit(smap, arg); +} + +int mark_smap(struct spacemap * smap, UInt64 arg) +{ + if (unlikely(!smap)) + { + return -1; + } + + arg >>= smap->cluster_bits; + + if ((arg < smap->start) || (arg > smap->end)) + { + return -1; + } + + return smap->spacemap_ops->mark_smap_bit(smap, arg); +} + +int unmark_smap_range(struct spacemap * smap, UInt64 block, unsigned int num) +{ + UInt64 end = block + num; + + if (unlikely(!smap)) + { + return -1; + } + + /* convert to clusters if necessary */ + block >>= smap->cluster_bits; + end += (1 << smap->cluster_bits) - 1; + end >>= smap->cluster_bits; + num = end - block; + + if ((block < smap->start) || (block > smap->end) || (block + num - 1 > smap->end)) + { + return -1; + } + + return smap->spacemap_ops->unmark_smap_range(smap, block, num); +} + +int mark_smap_range(struct spacemap * smap, UInt64 block, unsigned int num) +{ + UInt64 end = block + num; + + if (unlikely(!smap)) + { + return -1; + } + /* convert to clusters if necessary */ + block >>= smap->cluster_bits; + end += (1 << smap->cluster_bits) - 1; + end >>= smap->cluster_bits; + num = end - block; + + if ((block < smap->start) || (block > smap->end) || (block + num - 1 > smap->end)) + { + return -1; + } + + return smap->spacemap_ops->mark_smap_range(smap, block, num); +} + +int test_smap(struct spacemap * smap, UInt64 arg) +{ + if (unlikely(!smap)) + return 0; + + arg >>= smap->cluster_bits; + + if ((arg < smap->start) || (arg > smap->end)) + { + return -1; + } + + return smap->spacemap_ops->test_smap_bit(smap, arg); +} + +int test_smap_range(struct spacemap * smap, UInt64 block, unsigned int num) +{ + UInt64 end = block + num; + + if (unlikely(num == 1)) + return !test_smap(smap, block); + + block >>= smap->cluster_bits; + end += (1 << smap->cluster_bits) - 1; + end >>= smap->cluster_bits; + num = end - block; + + if ((block < smap->start) || (block > smap->end) || (block + num - 1 > smap->end)) + { + return -1; + } + + return smap->spacemap_ops->test_smap_range(smap, block, num); +} + +int init_space_map(struct spacemap * smap, int type, UInt64 start, UInt64 end, UInt64 real_end) +{ + int rc = 0; + assert(smap != NULL); + + switch (type) + { + case SMAP64_RBTREE: + break; + case SMAP64_BITARRAY: + case SMAP64_AUTODIR: // not support yet + return -1; + } + + smap->spacemap_ops = &smap_rbtree; + smap->start = start; + smap->end = end; + smap->real_end = real_end; + smap->cluster_bits = 0; + + rc = smap->spacemap_ops->new_smap(smap); + if (rc != 0) + { + smap->spacemap_ops->free_smap(smap); + } + + return rc; +} + +void destory_space_map(struct spacemap * smap) +{ + if (smap != NULL) + smap->spacemap_ops->free_smap(smap); +} + + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/dbms/src/Storages/Page/V3/spacemap/space_map.h b/dbms/src/Storages/Page/V3/spacemap/space_map.h new file mode 100644 index 00000000000..53b04c21a0b --- /dev/null +++ b/dbms/src/Storages/Page/V3/spacemap/space_map.h @@ -0,0 +1,119 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SMAP64_RBTREE 1 +#define SMAP64_BITARRAY 2 +#define SMAP64_AUTODIR 3 + +#define container_of(ptr, type, member) ({ \ + const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) ); }) + +struct spacemap_ops +{ + int type; + // void (*set_space_callback)(struct spacemap * smap); + + /* Generic space map operators */ + int (*new_smap)(struct spacemap * smap); + /* The difference between clear and free is that after you clear, you can still use this spacemap. */ + void (*clear_smap)(struct spacemap * smap); + void (*free_smap)(struct spacemap * smap); + int (*copy_smap)(struct spacemap * src, struct spacemap * dest); + int (*resize_smap)(struct spacemap * smap, UInt64 new_end, UInt64 new_real_end); + + /* print space maps status */ + void (*print_stats)(struct spacemap * smap); + + /* space map bit/bits test operators */ + int (*test_smap_bit)(struct spacemap * smap, UInt64 block); + int (*test_smap_range)(struct spacemap * smap, UInt64 block, unsigned int num); + + /* search range , return the free bits */ + void (*search_smap_range)(struct spacemap * smap, UInt64 start, UInt64 end, size_t num, UInt64 * ret); + + /* Find the first zero/set bit between start and end, inclusive. + * May be NULL, in which case a generic function is used. */ + int (*find_smap_first_zero)(struct spacemap * smap, UInt64 start, UInt64 end, UInt64 * out); + int (*find_smap_first_set)(struct spacemap * smap, UInt64 start, UInt64 end, UInt64 * out); + + /* space map bit set/unset operators */ + int (*mark_smap_bit)(struct spacemap * smap, UInt64 block); + int (*unmark_smap_bit)(struct spacemap * smap, UInt64 block); + + /* space map range set/unset operators */ + int (*mark_smap_range)(struct spacemap * smap, UInt64 block, unsigned int num); + int (*unmark_smap_range)(struct spacemap * smap, UInt64 block, unsigned int num); +}; + +struct spacemap +{ + struct spacemap_ops * spacemap_ops; + int flags; + /* [left - right] range */ + UInt64 start, end; + /* limit range */ + UInt64 real_end; + /* shift */ + int cluster_bits; + char * description; + void * _private; +}; + +extern struct spacemap_ops smap_rbtree; + +void printf_smap(struct spacemap * smap); + +/** + * ret value : + * -1: Invalid args + * 0: Unmark the marked node + * 1: Unmark the unmarked node + */ +int unmark_smap(struct spacemap * smap, UInt64 arg); + +/** + * ret value : + * -1: Invalid args + * 1: Mark success + */ +int mark_smap(struct spacemap * smap, UInt64 arg); + +/** + * The return value same as `unmark_smap` + */ +int unmark_smap_range(struct spacemap * smap, UInt64 block, unsigned int num); + +/** + * The return value same as `mark_smap` + */ +int mark_smap_range(struct spacemap * smap, UInt64 block, unsigned int num); + +/** + * ret value : + * -1: Invalid args + * 0: This bit is marked + * 1: This bit is not marked + */ +int test_smap(struct spacemap * smap, UInt64 arg); + +/** + * The return value same as `mark_smap` + */ +int test_smap_range(struct spacemap * smap, UInt64 block, unsigned int num); + +/** + * ret value : + * -1: Invalid args + * 0: init success + */ +int init_space_map(struct spacemap * smap, int type, UInt64 start, UInt64 end, UInt64 real_end); +void destory_space_map(struct spacemap * smap); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/dbms/src/Storages/Page/V3/spacemap/space_map_rbtree.cpp b/dbms/src/Storages/Page/V3/spacemap/space_map_rbtree.cpp new file mode 100644 index 00000000000..d07a581d511 --- /dev/null +++ b/dbms/src/Storages/Page/V3/spacemap/space_map_rbtree.cpp @@ -0,0 +1,666 @@ +#include "bits.h" +#include "rb_tree.h" +#include "space_map.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct smap_rb_entry +{ + struct rb_node node; + UInt64 start; + UInt64 count; +}; + +struct rb_private +{ + struct rb_root root; + // Cache the index for write + struct smap_rb_entry * write_index; + // Cache the index for read + struct smap_rb_entry * read_index; + struct smap_rb_entry * read_index_next; +}; + +// convert rb_node to smap_rb_entry +inline static struct smap_rb_entry * node_to_entry(struct rb_node * node) +{ + struct smap_rb_entry * rb_ex; + rb_ex = container_of(node, struct smap_rb_entry, node); + return rb_ex; +} + +static int rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data); +static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data); + +static inline void rb_link_node(struct rb_node * node, + struct rb_node * parent, + struct rb_node ** rb_link) +{ + node->parent = (uintptr_t)parent; + node->node_left = NULL; + node->node_right = NULL; + + *rb_link = node; +} + +#define ENABLE_DEBUG_IN_RB_TREE 0 + +#if !defined(NDEBUG) && !defined(DBMS_PUBLIC_GTEST) && ENABLE_DEBUG_IN_RB_TREE +static void rb_tree_debug(struct rb_root * root, const char * method_call) +{ + struct rb_node * node = NULL; + struct smap_rb_entry * entry; + + node = rb_tree_first(root); + printf("call in %s", method_call); + for (node = rb_tree_first(root); node != NULL; node = rb_tree_next(node)) + { + entry = node_to_entry(node); + printf(" range - (%llu -> %llu)\n", entry->start, entry->start + entry->count); + } +} + +#else +#define rb_tree_debug(root, function) \ + do \ + { \ + } while (0) +#endif + + +static void rb_get_new_entry(struct smap_rb_entry ** entry, UInt64 start, UInt64 count) +{ + struct smap_rb_entry * new_entry; + + new_entry = (struct smap_rb_entry *)calloc(1, sizeof(struct smap_rb_entry)); + if (new_entry == NULL) + { + return; + } + + new_entry->start = start; + new_entry->count = count; + *entry = new_entry; +} + +inline static void rb_free_entry(struct rb_private * private_data, struct smap_rb_entry * entry) +{ + /** + * reset all index + */ + if (private_data->write_index == entry) + { + private_data->write_index = NULL; + } + + if (private_data->read_index == entry) + { + private_data->read_index = NULL; + } + + if (private_data->read_index_next == entry) + { + private_data->read_index_next = NULL; + } + + free(entry); +} + +static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data) +{ + struct rb_root * root = &private_data->root; + struct rb_node *parent = NULL, **n = &root->rb_node; + struct rb_node * node; + struct smap_rb_entry * entry; + UInt64 new_start, new_count; + int retval = 0; + + // Root node have not been init + if (private_data->root.rb_node == NULL) + { + return 0; + } + + while (*n) + { + parent = *n; + entry = node_to_entry(parent); + if (start < entry->start) + { + n = &(*n)->node_left; + continue; + } + else if (start >= (entry->start + entry->count)) + { + n = &(*n)->node_right; + continue; + } + + if ((start > entry->start) && (start + count) < (entry->start + entry->count)) + { + // Split entry + new_start = start + count; + new_count = (entry->start + entry->count) - new_start; + + entry->count = start - entry->start; + + rb_insert_entry(new_start, new_count, private_data); + return 1; + } + + if ((start + count) >= (entry->start + entry->count)) + { + entry->count = start - entry->start; + retval = 1; + } + + if (0 == entry->count) + { + parent = rb_tree_next(&entry->node); + rb_node_remove(&entry->node, root); + rb_free_entry(private_data, entry); + break; + } + + if (start == entry->start) + { + entry->start += count; + entry->count -= count; + return 1; + } + } + + // Check the right node + for (; parent != NULL; parent = node) + { + node = rb_tree_next(parent); + entry = node_to_entry(parent); + if ((entry->start + entry->count) <= start) + continue; + + if ((start + count) < entry->start) + break; + + // Merge the nearby node + // TBD : If there are a small range inside two range, Then it should be ignored + if ((start + count) >= (entry->start + entry->count)) + { + rb_node_remove(parent, root); + rb_free_entry(private_data, entry); + retval = 1; + continue; + } + else + { + entry->count -= ((start + count) - entry->start); + entry->start = start + count; + retval = 1; + break; + } + } + + return retval; +} + +static int rb_alloc_private_data(struct spacemap * smap) +{ + struct rb_private * private_data; + + // alloc root node + private_data = (struct rb_private *)calloc(1, sizeof(struct rb_private)); + if (private_data == NULL) + { + return -1; + } + + private_data->root = {NULL}; + private_data->read_index = NULL; + private_data->read_index_next = NULL; + private_data->write_index = NULL; + + smap->_private = (void *)private_data; + return 0; +} + +static int rb_new_smap(struct spacemap * smap) +{ + int ret; + struct rb_private * private_data; + + ret = rb_alloc_private_data(smap); + if (ret) + { + return ret; + } + + private_data = (struct rb_private *)smap->_private; + + ret = rb_insert_entry(smap->start, smap->end, private_data); + if (ret != 0) + { + printf("Erorr happend, when mark all range to free.\n"); + free(private_data); + return -1; + } + + return 0; +} + +static void rb_free_tree(struct rb_root * root) +{ + struct smap_rb_entry * entry; + struct rb_node *node, *next; + + for (node = rb_tree_first(root); node; node = next) + { + next = rb_tree_next(node); + entry = node_to_entry(node); + rb_node_remove(node, root); + free(entry); + } +} + +static void rb_free_smap(struct spacemap * smap) +{ + struct rb_private * private_data; + + private_data = (struct rb_private *)smap->_private; + + rb_free_tree(&private_data->root); + free(private_data); +} + +static void rb_clear_smap(struct spacemap * smap) +{ + struct rb_private * private_data; + + private_data = (struct rb_private *)smap->_private; + + rb_free_tree(&private_data->root); + private_data->read_index = NULL; + private_data->read_index_next = NULL; + private_data->write_index = NULL; + rb_tree_debug(&private_data->root, __func__); +} + +static void rb_print_stats(struct spacemap * smap) +{ + struct rb_private * private_data; + struct rb_node * node = NULL; + struct smap_rb_entry * entry; + UInt64 count = 0; + UInt64 max_size = 0; + UInt64 min_size = ULONG_MAX; + + private_data = (struct rb_private *)smap->_private; + printf("entry status :\n"); + for (node = rb_tree_first(&private_data->root); node != NULL; node = rb_tree_next(node)) + { + entry = node_to_entry(node); + printf("range %lld : start=%lld , count=%lld \n", count, entry->start, entry->count); + count++; + if (entry->count > max_size) + max_size = entry->count; + if (entry->count < min_size) + min_size = entry->count; + } +} + + +inline static int rb_test_bit(struct rb_private * private_data, UInt64 bit) +{ + struct smap_rb_entry *read_index, *next_entry = NULL; + struct rb_node *parent = NULL, *next_node; + struct rb_node ** n = &private_data->root.rb_node; + struct smap_rb_entry * entry; + + read_index = private_data->read_index; + + // derect search tree + if (!read_index) + { + goto search_tree; + } + + + if (bit >= read_index->start && bit < read_index->start + read_index->count) + { + return 1; + } + + next_entry = private_data->read_index_next; + if (!next_entry) + { + next_node = rb_tree_next(&read_index->node); + if (next_node) + { + next_entry = node_to_entry(next_node); + } + private_data->read_index_next = next_entry; + } + if (next_entry) + { + if ((bit >= read_index->start + read_index->count) && (bit < next_entry->start)) + { + return 0; + } + } + private_data->read_index = NULL; + private_data->read_index_next = NULL; + + read_index = private_data->write_index; + if (!read_index) + { + goto search_tree; + } + + if (bit >= read_index->start && bit < read_index->start + read_index->count) + { + return 1; + } + +search_tree: + + while (*n) + { + parent = *n; + entry = node_to_entry(parent); + if (bit < entry->start) + { + n = &(*n)->node_left; + } + else if (bit >= (entry->start + entry->count)) + { + n = &(*n)->node_right; + } + else + { + private_data->read_index = entry; + private_data->read_index_next = NULL; + return 1; + } + } + return 0; +} + +inline static int rb_test_smap_bit(struct spacemap * smap, UInt64 arg) +{ + struct rb_private * private_data; + + private_data = (struct rb_private *)smap->_private; + arg -= smap->start; + + return rb_test_bit(private_data, arg); +} + + +static int rb_test_smap_range(struct spacemap * smap, + UInt64 start, + unsigned int len) +{ + struct rb_node *parent = NULL, **n; + struct rb_node *node, *next; + struct rb_private * private_data; + struct smap_rb_entry * entry; + int retval = 0; + + private_data = (struct rb_private *)smap->_private; + n = &private_data->root.rb_node; + start -= smap->start; + + if (len == 0 || private_data->root.rb_node == NULL) + { + return -1; + } + + + while (*n) + { + parent = *n; + entry = node_to_entry(parent); + if (start < entry->start) + { + n = &(*n)->node_left; + } + else if (start >= (entry->start + entry->count)) + { + n = &(*n)->node_right; + } + else + { + // the tree -> entry is not clear + // so just return + return 1; + } + } + + node = parent; + while (node) + { + next = rb_tree_next(node); + entry = node_to_entry(node); + node = next; + + if ((entry->start + entry->count) <= start) + continue; + + /* No more merging */ + if ((start + len) <= entry->start) + break; + + retval = 1; + break; + } + return retval; +} + +static int rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data) +{ + struct rb_root * root = &private_data->root; + struct rb_node *parent = NULL, **n = &root->rb_node; + struct rb_node *new_node, *node, *next; + struct smap_rb_entry * new_entry; + struct smap_rb_entry * entry; + int retval = 0; + + if (count == 0) + { + return retval; + } + + + private_data->read_index_next = NULL; + entry = private_data->write_index; + if (entry) + { + if (start >= entry->start && start <= (entry->start + entry->count)) + { + goto got_entry; + } + } + + while (*n) + { + parent = *n; + entry = node_to_entry(parent); + + if (start < entry->start) + { + n = &(*n)->node_left; + } + else if (start > (entry->start + entry->count)) + { + n = &(*n)->node_right; + } + else + { + got_entry: + if ((start + count) <= (entry->start + entry->count)) + { + retval = 1; + return retval; + } + + if ((entry->start + entry->count) == start) + { + retval = 0; + } + else + { + retval = 1; + } + + count += (start - entry->start); + start = entry->start; + new_entry = entry; + new_node = &entry->node; + + goto no_need_insert; + } + } + + rb_get_new_entry(&new_entry, start, count); + + new_node = &new_entry->node; + rb_link_node(new_node, parent, n); + rb_node_insert(new_node, root); + private_data->write_index = new_entry; + + node = rb_tree_prev(new_node); + if (node) + { + entry = node_to_entry(node); + if ((entry->start + entry->count) == start) + { + start = entry->start; + count += entry->count; + rb_node_remove(node, root); + rb_free_entry(private_data, entry); + } + } + +no_need_insert: + // merge entry to the right + for (node = rb_tree_next(new_node); node != NULL; node = next) + { + next = rb_tree_next(node); + entry = node_to_entry(node); + + if ((entry->start + entry->count) <= start) + { + continue; + } + + + // not match + // TBD : same as comment in remove + if ((start + count) < entry->start) + break; + + if ((start + count) >= (entry->start + entry->count)) + { + rb_node_remove(node, root); + rb_free_entry(private_data, entry); + continue; + } + else + { + // merge entry + // TBD : same as comment in remove + count += ((entry->start + entry->count) - (start + count)); + rb_node_remove(node, root); + rb_free_entry(private_data, entry); + break; + } + } + + new_entry->start = start; + new_entry->count = count; + + return retval; +} + +static int rb_mark_smap(struct spacemap * smap, UInt64 arg) +{ + struct rb_private * private_data; + int retval; + + private_data = (struct rb_private *)smap->_private; + arg -= smap->start; + + retval = rb_remove_entry(arg, 1, private_data); + rb_tree_debug(&private_data->root, __func__); + return retval; +} + +static int rb_unmark_smap(struct spacemap * smap, UInt64 arg) +{ + struct rb_private * private_data; + int retval; + + private_data = (struct rb_private *)smap->_private; + arg -= smap->start; + + retval = rb_insert_entry(arg, 1, private_data); + rb_tree_debug(&private_data->root, __func__); + + return retval; +} + +static int rb_mark_smap_entry(struct spacemap * smap, UInt64 arg, unsigned int num) +{ + struct rb_private * private_data; + int retval; + + private_data = (struct rb_private *)smap->_private; + arg -= smap->start; + + retval = rb_remove_entry(arg, num, private_data); + rb_tree_debug(&private_data->root, __func__); + return retval; +} + +static int rb_unmark_smap_entry(struct spacemap * smap, UInt64 arg, unsigned int num) +{ + struct rb_private * private_data; + int retval; + + private_data = (struct rb_private *)smap->_private; + arg -= smap->start; + + retval = rb_insert_entry(arg, num, private_data); + rb_tree_debug(&private_data->root, __func__); + return retval; +} + +struct spacemap_ops smap_rbtree = { + .type = SMAP64_RBTREE, + + .new_smap = rb_new_smap, + .clear_smap = rb_clear_smap, + .free_smap = rb_free_smap, + .copy_smap = NULL, + .resize_smap = NULL, + .print_stats = rb_print_stats, + + .test_smap_bit = rb_test_smap_bit, + .test_smap_range = rb_test_smap_range, + + // TBD : may need remove search_smap_range + .search_smap_range = NULL, + + .find_smap_first_zero = NULL, + .find_smap_first_set = NULL, + + .mark_smap_bit = rb_mark_smap, + .unmark_smap_bit = rb_unmark_smap, + + .mark_smap_range = rb_mark_smap_entry, + .unmark_smap_range = rb_unmark_smap_entry, +}; + +#ifdef __cplusplus +} // extern "C" +#endif \ No newline at end of file diff --git a/dbms/src/Storages/Page/V3/tests/CMakeLists.txt b/dbms/src/Storages/Page/V3/tests/CMakeLists.txt new file mode 100644 index 00000000000..fc4e7747c8c --- /dev/null +++ b/dbms/src/Storages/Page/V3/tests/CMakeLists.txt @@ -0,0 +1,15 @@ + +# glob all unit tests of PageStorage into gtests_page_storage +macro(grep_gtest_sources BASE_DIR DST_VAR) + # Cold match files that are not in tests/ directories + file(GLOB_RECURSE "${DST_VAR}" RELATIVE "${BASE_DIR}" "gtest*.cpp") +endmacro() + +# attach all dm gtest sources +grep_gtest_sources(${ClickHouse_SOURCE_DIR}/dbms/src/Storages/Page/V3/tests ps_v3_gtest_sources) + +add_executable(gtests_page_storage_v3 ${ps_v3_gtest_sources} ${ClickHouse_SOURCE_DIR}/dbms/src/TestUtils/gtests_dbms_main.cpp) +target_link_libraries(gtests_page_storage_v3 page_storage_v3 gtest_main) +target_compile_options(gtests_page_storage_v3 PRIVATE -Wno-unknown-pragmas) +target_compile_definitions(gtests_page_storage_v3 PRIVATE DBMS_PUBLIC_GTEST) +add_check(gtests_page_storage_v3) \ No newline at end of file diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp new file mode 100644 index 00000000000..9a15003f05e --- /dev/null +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -0,0 +1,122 @@ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#include +#ifdef __cplusplus +} // extern "C" +#endif + +namespace DB::PS::V3::tests +{ +struct range +{ + size_t start; + size_t end; +}; + +bool check_nodes(struct rb_root * root, range * ranges, size_t size) +{ + struct rb_node * node = NULL; + struct smap_rb_entry * ext; + + assert(size != 0); + + size_t i = 0; + for (node = rb_tree_first(root); node != NULL; node = rb_tree_next(node)) + { + ext = node_to_entry(node); + if (i >= size && ranges[i].start != ext->start && ranges[i].end != ext->start + ext->count) + { + return false; + } + i++; + } + + return true; +} + +TEST(space_map_test, InitAndDestory) +{ + struct spacemap * smap; + + smap = (struct spacemap *)calloc(1, sizeof(struct spacemap)); + ASSERT_TRUE(smap); + ASSERT_EQ(init_space_map(smap, SMAP64_RBTREE, 0, 100, 101), 0); + printf_smap(smap); + destory_space_map(smap); +} + +TEST(space_map_test, MarkUnmarkBit) +{ + struct spacemap * smap; + + smap = (struct spacemap *)calloc(1, sizeof(struct spacemap)); + ASSERT_TRUE(smap); + ASSERT_EQ(init_space_map(smap, SMAP64_RBTREE, 0, 100, 101), 0); + + struct rb_private * bp = (struct rb_private *)smap->_private; + + range ranges[] = {{.start = 0, + .end = 100}}; + check_nodes(&bp->root, ranges, 1); + + ASSERT_TRUE(mark_smap(smap, 50)); + ASSERT_EQ(test_smap(smap, 50), 0); + ASSERT_EQ(test_smap(smap, 51), 1); + + range ranges1[] = {{.start = 0, + .end = 49}, + {.start = 50, + .end = 100}}; + check_nodes(&bp->root, ranges1, 2); + + unmark_smap(smap, 50); + check_nodes(&bp->root, ranges, 1); + ASSERT_EQ(test_smap(smap, 50), 1); + + destory_space_map(smap); +} + +TEST(space_map_test, MarkUnmarkRange) +{ + struct spacemap * smap; + + smap = (struct spacemap *)calloc(1, sizeof(struct spacemap)); + ASSERT_TRUE(smap); + ASSERT_EQ(init_space_map(smap, SMAP64_RBTREE, 0, 100, 101), 0); + + struct rb_private * bp = (struct rb_private *)smap->_private; + + range ranges[] = {{.start = 0, + .end = 100}}; + check_nodes(&bp->root, ranges, 1); + ASSERT_EQ(test_smap_range(smap, 1, 99), 1); + ASSERT_EQ(test_smap_range(smap, 0, 1000), -1); + + ASSERT_TRUE(mark_smap_range(smap, 50, 10)); + + range ranges1[] = {{.start = 0, + .end = 49}, + {.start = 60, + .end = 100}}; + check_nodes(&bp->root, ranges1, 2); + ASSERT_EQ(test_smap_range(smap, 51, 5), 0); + + unmark_smap_range(smap, 50, 5); + range ranges2[] = {{.start = 0, + .end = 55}, + {.start = 60, + .end = 100}}; + check_nodes(&bp->root, ranges2, 2); + unmark_smap_range(smap, 55, 5); + check_nodes(&bp->root, ranges, 2); + + destory_space_map(smap); +} + +} // namespace DB::PS::V3::tests \ No newline at end of file From 48ac64c084ff967d447d37740f29ff15540678ef Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Mon, 29 Nov 2021 17:36:01 +0800 Subject: [PATCH 02/36] [WIP]just for read --- dbms/CMakeLists.txt | 2 +- .../V3/spacemap/{rb_tree.cpp => RBTree.cpp} | 21 ++- .../Page/V3/spacemap/{rb_tree.h => RBTree.h} | 0 .../Storages/Page/V3/spacemap/SpaceMap.cpp | 131 +++++++++++++ dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 131 +++++++++++++ ...pace_map_rbtree.cpp => SpaceMapRBTree.cpp} | 91 ++------- .../Page/V3/spacemap/SpaceMapRBTree.h | 110 +++++++++++ .../Page/V3/spacemap/SpaceMapSTDMap.h | 135 ++++++++++++++ dbms/src/Storages/Page/V3/spacemap/bits.cpp | 88 --------- dbms/src/Storages/Page/V3/spacemap/bits.h | 19 -- .../Storages/Page/V3/spacemap/space_map.cpp | 174 ------------------ .../src/Storages/Page/V3/spacemap/space_map.h | 119 ------------ .../Storages/Page/V3/tests/gtest_free_map.cpp | 32 ++-- 13 files changed, 556 insertions(+), 497 deletions(-) rename dbms/src/Storages/Page/V3/spacemap/{rb_tree.cpp => RBTree.cpp} (99%) rename dbms/src/Storages/Page/V3/spacemap/{rb_tree.h => RBTree.h} (100%) create mode 100644 dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp create mode 100644 dbms/src/Storages/Page/V3/spacemap/SpaceMap.h rename dbms/src/Storages/Page/V3/spacemap/{space_map_rbtree.cpp => SpaceMapRBTree.cpp} (87%) create mode 100644 dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h create mode 100644 dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h delete mode 100644 dbms/src/Storages/Page/V3/spacemap/bits.cpp delete mode 100644 dbms/src/Storages/Page/V3/spacemap/bits.h delete mode 100644 dbms/src/Storages/Page/V3/spacemap/space_map.cpp delete mode 100644 dbms/src/Storages/Page/V3/spacemap/space_map.h diff --git a/dbms/CMakeLists.txt b/dbms/CMakeLists.txt index 6c50468720d..92bc624849f 100644 --- a/dbms/CMakeLists.txt +++ b/dbms/CMakeLists.txt @@ -82,7 +82,7 @@ add_headers_and_sources(dbms src/Storages/Page/V2/gc) add_headers_and_sources(dbms src/Storages/Page/) if (ENABLE_V3_PAGESTORAGE) add_headers_and_sources(dbms src/Storages/Page/V3) - add_headers_and_sources(dbms src/Storages/Page/V3/freemap) + add_headers_and_sources(dbms src/Storages/Page/V3/spacemap) endif() add_headers_and_sources(dbms src/TiDB) add_headers_and_sources(dbms src/Client) diff --git a/dbms/src/Storages/Page/V3/spacemap/rb_tree.cpp b/dbms/src/Storages/Page/V3/spacemap/RBTree.cpp similarity index 99% rename from dbms/src/Storages/Page/V3/spacemap/rb_tree.cpp rename to dbms/src/Storages/Page/V3/spacemap/RBTree.cpp index 0bb8e090758..acbe1e77253 100644 --- a/dbms/src/Storages/Page/V3/spacemap/rb_tree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/RBTree.cpp @@ -1,4 +1,4 @@ -#include "rb_tree.h" +#include "RBTree.h" #ifdef __cplusplus extern "C" { @@ -37,11 +37,6 @@ static inline void node_set_color(struct rb_node * node, int color) node->parent = (node->parent & ~COLOR_BLACK) | color; } -static inline void node_clear(struct rb_node * node) -{ - node_set_parent(node, node); -} - static void node_rotate_left(struct rb_node * node, struct rb_root * root) { struct rb_node * right = node->node_right; @@ -358,9 +353,15 @@ struct rb_node * rb_tree_first(const struct rb_root * root) n = root->rb_node; if (!n) + { return NULL; + } + while (n->node_left) + { n = n->node_left; + } + return n; } @@ -370,9 +371,15 @@ struct rb_node * rb_tree_last(const struct rb_root * root) n = root->rb_node; if (!n) + { return NULL; + } + while (n->node_right) + { n = n->node_right; + } + return n; } @@ -456,7 +463,9 @@ struct rb_node * rb_tree_prev(struct rb_node * current) // So the `prev` node must in parent node,Then we need go up into the parent node. // If `current` node is the left-node child of its parent, Then it still need go up for upper layer. while ((parent = node_parent(current)) && current == parent->node_left) + { current = parent; + } return parent; } diff --git a/dbms/src/Storages/Page/V3/spacemap/rb_tree.h b/dbms/src/Storages/Page/V3/spacemap/RBTree.h similarity index 100% rename from dbms/src/Storages/Page/V3/spacemap/rb_tree.h rename to dbms/src/Storages/Page/V3/spacemap/RBTree.h diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp new file mode 100644 index 00000000000..74165edfdab --- /dev/null +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -0,0 +1,131 @@ +#include +#include + +#include +#include +#include + +#include "SpaceMap.h" +#include "SpaceMapRBTree.h" + +namespace DB::PS::V3 +{ + +void SpaceMap::printf() +{ + spacemap_ops->smapStats(this); +} + +int SpaceMap::unmark(UInt64 arg) +{ + arg >>= cluster_bits; + + if ((arg < start) || (arg > end)) + { + return -1; + } + + return spacemap_ops->unmarkSmapBit(this, arg); +} + +int SpaceMap::mark(UInt64 arg) +{ + arg >>= cluster_bits; + + if ((arg < start) || (arg > end)) + { + return -1; + } + + return spacemap_ops->markSmapBit(this, arg); +} + +int SpaceMap::unmarkRange(UInt64 block, unsigned int num) +{ + UInt64 end = block + num; + + + /* convert to clusters if necessary */ + block >>= cluster_bits; + end += (1 << cluster_bits) - 1; + end >>= cluster_bits; + num = end - block; + + if ((block < start) || (block > end) || (block + num - 1 > end)) + { + return -1; + } + + return spacemap_ops->unmarkSmapRange(this, block, num); +} + +int SpaceMap::markRange(UInt64 block, unsigned int num) +{ + UInt64 end = block + num; + + /* convert to clusters if necessary */ + block >>= cluster_bits; + end += (1 << cluster_bits) - 1; + end >>= cluster_bits; + num = end - block; + + if ((block < start) || (block > end) || (block + num - 1 > end)) + { + return -1; + } + + return spacemap_ops->markSmapRange(this, block, num); +} + +int SpaceMap::test(UInt64 arg) +{ + arg >>= cluster_bits; + + if ((arg < start) || (arg > end)) + { + return -1; + } + + return spacemap_ops->testSmapBit(this, arg); +} + +int SpaceMap::testRange(UInt64 block, unsigned int num) +{ + UInt64 end = block + num; + + if (unlikely(num == 1)) + return !test(block); + + block >>= cluster_bits; + end += (1 << cluster_bits) - 1; + end >>= cluster_bits; + num = end - block; + + if ((block < start) || (block > end) || (block + num - 1 > end)) + { + return -1; + } + + return spacemap_ops->testSmapRange(this, block, num); +} + +SpaceMap::SpaceMap(SpaceMapOpsPtr ops, UInt64 start_, UInt64 end_, UInt64 real_end_) + : spacemap_ops(ops), + start(start_), + end(end_), + real_end(real_end_), + cluster_bits(0) +{ + int rc = spacemap_ops->newSmap(this); + if (rc != 0) + { + spacemap_ops->freeSmap(this); + } +} + +SpaceMap::~SpaceMap() +{ + spacemap_ops->freeSmap(this); +} + +} diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h new file mode 100644 index 00000000000..36dbe3228f6 --- /dev/null +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -0,0 +1,131 @@ +#pragma once +#include + +namespace DB::PS::V3 +{ + +#define SMAP64_INVALID 0 +#define SMAP64_RBTREE 1 +#define SMAP64_STD_MAP 2 + +struct SpaceMap; + +class SpaceMapOps +{ +public: + virtual ~SpaceMapOps() = default; + + /* Generic space map operators */ + virtual int newSmap(SpaceMap * smap) = 0; + + /* The difference between clear and free is that after you clear, you can still use this spacemap. */ + virtual void clearSmap(SpaceMap * smap) = 0; + + virtual void freeSmap(SpaceMap * smap) = 0; + + virtual int copySmap(SpaceMap * src, SpaceMap * dest) = 0; + + virtual int resizeSmap(SpaceMap * smap, UInt64 new_end, UInt64 new_real_end) = 0; + + /* Print space maps status */ + virtual void smapStats(struct SpaceMap * smap) = 0; + + /* Space map bit/bits test operators */ + virtual int testSmapBit(struct SpaceMap * smap, UInt64 block) = 0; + + virtual int testSmapRange(struct SpaceMap * smap, UInt64 block, unsigned int num) = 0; + + /* Search range , return the free bits */ + virtual void searchSmapRange(struct SpaceMap * smap, UInt64 start, UInt64 end, size_t num, UInt64 * ret) = 0; + + /* Find the first zero/set bit between start and end, inclusive. + * May be NULL, in which case a generic function is used. */ + virtual int findSmapFirstZero(struct SpaceMap * smap, UInt64 start, UInt64 end, UInt64 * out) = 0; + + virtual int findSmapFirstSet(struct SpaceMap * smap, UInt64 start, UInt64 end, UInt64 * out) = 0; + + /* Space map bit set/unset operators */ + virtual int markSmapBit(struct SpaceMap * smap, UInt64 block) = 0; + + virtual int unmarkSmapBit(struct SpaceMap * smap, UInt64 block) = 0; + + /* Space map range set/unset operators */ + virtual int markSmapRange(struct SpaceMap * smap, UInt64 block, unsigned int num) = 0; + + virtual int unmarkSmapRange(struct SpaceMap * smap, UInt64 block, unsigned int num) = 0; + + /* Get Space map type */ + int getSmapType() + { + return type; + } + +protected: + int type = SMAP64_INVALID; +}; + +using SpaceMapOpsPtr = std::shared_ptr; + +struct SpaceMap +{ +public: + SpaceMapOpsPtr spacemap_ops; + + int flags; + /* [left - right] range */ + UInt64 start, end; + /* limit range */ + UInt64 real_end; + /* shift */ + int cluster_bits; + + char * description; + void * _private; + + SpaceMap(SpaceMapOpsPtr ops, UInt64 start, UInt64 end, UInt64 real_end); + + ~SpaceMap(); + + void printf(); + + /** + * ret value : + * -1: Invalid args + * 0: Unmark the marked node + * 1: Unmark the unmarked node + */ + int unmark(UInt64 arg); + + /** + * ret value : + * -1: Invalid args + * 1: Mark success + */ + int mark(UInt64 arg); + + /** + * The return value same as `unmark` + */ + int unmarkRange(UInt64 block, unsigned int num); + + /** + * The return value same as `mark` + */ + int markRange(UInt64 block, unsigned int num); + + /** + * ret value : + * -1: Invalid args + * 0: This bit is marked + * 1: This bit is not marked + */ + int test(UInt64 arg); + + /** + * The return value same as `test` + */ + int testRange(UInt64 block, unsigned int num); + +}; + +} diff --git a/dbms/src/Storages/Page/V3/spacemap/space_map_rbtree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp similarity index 87% rename from dbms/src/Storages/Page/V3/spacemap/space_map_rbtree.cpp rename to dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index d07a581d511..5dce42ad853 100644 --- a/dbms/src/Storages/Page/V3/spacemap/space_map_rbtree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -1,35 +1,7 @@ -#include "bits.h" -#include "rb_tree.h" -#include "space_map.h" +#include "SpaceMapRBTree.h" -#ifdef __cplusplus -extern "C" { -#endif - -struct smap_rb_entry +namespace DB::PS::V3 { - struct rb_node node; - UInt64 start; - UInt64 count; -}; - -struct rb_private -{ - struct rb_root root; - // Cache the index for write - struct smap_rb_entry * write_index; - // Cache the index for read - struct smap_rb_entry * read_index; - struct smap_rb_entry * read_index_next; -}; - -// convert rb_node to smap_rb_entry -inline static struct smap_rb_entry * node_to_entry(struct rb_node * node) -{ - struct smap_rb_entry * rb_ex; - rb_ex = container_of(node, struct smap_rb_entry, node); - return rb_ex; -} static int rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data); static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data); @@ -111,7 +83,7 @@ inline static void rb_free_entry(struct rb_private * private_data, struct smap_r static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data) { struct rb_root * root = &private_data->root; - struct rb_node *parent = NULL, **n = &root->rb_node; + struct rb_node * parent = NULL, **n = &root->rb_node; struct rb_node * node; struct smap_rb_entry * entry; UInt64 new_start, new_count; @@ -204,7 +176,7 @@ static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * priva return retval; } -static int rb_alloc_private_data(struct spacemap * smap) +static int rb_alloc_private_data(SpaceMap * smap) { struct rb_private * private_data; @@ -224,7 +196,7 @@ static int rb_alloc_private_data(struct spacemap * smap) return 0; } -static int rb_new_smap(struct spacemap * smap) +int RBTreeSpaceMapOps::newSmap(SpaceMap * smap) { int ret; struct rb_private * private_data; @@ -262,7 +234,7 @@ static void rb_free_tree(struct rb_root * root) } } -static void rb_free_smap(struct spacemap * smap) +void RBTreeSpaceMapOps::freeSmap(SpaceMap * smap) { struct rb_private * private_data; @@ -272,7 +244,7 @@ static void rb_free_smap(struct spacemap * smap) free(private_data); } -static void rb_clear_smap(struct spacemap * smap) +void RBTreeSpaceMapOps::clearSmap(SpaceMap * smap) { struct rb_private * private_data; @@ -285,7 +257,7 @@ static void rb_clear_smap(struct spacemap * smap) rb_tree_debug(&private_data->root, __func__); } -static void rb_print_stats(struct spacemap * smap) +void RBTreeSpaceMapOps::smapStats(SpaceMap * smap) { struct rb_private * private_data; struct rb_node * node = NULL; @@ -302,9 +274,14 @@ static void rb_print_stats(struct spacemap * smap) printf("range %lld : start=%lld , count=%lld \n", count, entry->start, entry->count); count++; if (entry->count > max_size) + { max_size = entry->count; + } + if (entry->count < min_size) + { min_size = entry->count; + } } } @@ -385,7 +362,7 @@ inline static int rb_test_bit(struct rb_private * private_data, UInt64 bit) return 0; } -inline static int rb_test_smap_bit(struct spacemap * smap, UInt64 arg) +int RBTreeSpaceMapOps::testSmapBit(SpaceMap * smap, UInt64 arg) { struct rb_private * private_data; @@ -396,7 +373,7 @@ inline static int rb_test_smap_bit(struct spacemap * smap, UInt64 arg) } -static int rb_test_smap_range(struct spacemap * smap, +int RBTreeSpaceMapOps::testSmapRange(SpaceMap * smap, UInt64 start, unsigned int len) { @@ -582,7 +559,7 @@ static int rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * priva return retval; } -static int rb_mark_smap(struct spacemap * smap, UInt64 arg) +int RBTreeSpaceMapOps::markSmapBit(SpaceMap * smap, UInt64 arg) { struct rb_private * private_data; int retval; @@ -595,7 +572,7 @@ static int rb_mark_smap(struct spacemap * smap, UInt64 arg) return retval; } -static int rb_unmark_smap(struct spacemap * smap, UInt64 arg) +int RBTreeSpaceMapOps::unmarkSmapBit(SpaceMap * smap, UInt64 arg) { struct rb_private * private_data; int retval; @@ -609,7 +586,7 @@ static int rb_unmark_smap(struct spacemap * smap, UInt64 arg) return retval; } -static int rb_mark_smap_entry(struct spacemap * smap, UInt64 arg, unsigned int num) +int RBTreeSpaceMapOps::markSmapRange(SpaceMap * smap, UInt64 arg, unsigned int num) { struct rb_private * private_data; int retval; @@ -622,7 +599,7 @@ static int rb_mark_smap_entry(struct spacemap * smap, UInt64 arg, unsigned int n return retval; } -static int rb_unmark_smap_entry(struct spacemap * smap, UInt64 arg, unsigned int num) +int RBTreeSpaceMapOps::unmarkSmapRange(SpaceMap * smap, UInt64 arg, unsigned int num) { struct rb_private * private_data; int retval; @@ -635,32 +612,4 @@ static int rb_unmark_smap_entry(struct spacemap * smap, UInt64 arg, unsigned int return retval; } -struct spacemap_ops smap_rbtree = { - .type = SMAP64_RBTREE, - - .new_smap = rb_new_smap, - .clear_smap = rb_clear_smap, - .free_smap = rb_free_smap, - .copy_smap = NULL, - .resize_smap = NULL, - .print_stats = rb_print_stats, - - .test_smap_bit = rb_test_smap_bit, - .test_smap_range = rb_test_smap_range, - - // TBD : may need remove search_smap_range - .search_smap_range = NULL, - - .find_smap_first_zero = NULL, - .find_smap_first_set = NULL, - - .mark_smap_bit = rb_mark_smap, - .unmark_smap_bit = rb_unmark_smap, - - .mark_smap_range = rb_mark_smap_entry, - .unmark_smap_range = rb_unmark_smap_entry, -}; - -#ifdef __cplusplus -} // extern "C" -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h new file mode 100644 index 00000000000..bc1cd3e1227 --- /dev/null +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h @@ -0,0 +1,110 @@ +#pragma once +#include "RBTree.h" +#include "SpaceMap.h" + + +namespace DB::PS::V3 +{ + +struct smap_rb_entry +{ + struct rb_node node; + UInt64 start; + UInt64 count; +}; + +struct rb_private +{ + struct rb_root root; + // Cache the index for write + struct smap_rb_entry * write_index; + // Cache the index for read + struct smap_rb_entry * read_index; + struct smap_rb_entry * read_index_next; +}; + +// convert rb_node to smap_rb_entry +inline static struct smap_rb_entry * node_to_entry(struct rb_node * node) +{ + struct smap_rb_entry * rb_ex; + #define container_of(ptr, type, member) ({ \ + const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) ); }) + + rb_ex = container_of(node, struct smap_rb_entry, node); + + #undef container_of + return rb_ex; +} + +class RBTreeSpaceMapOps : public SpaceMapOps +{ +public: + + RBTreeSpaceMapOps() + { + type = SMAP64_RBTREE; + }; + + ~RBTreeSpaceMapOps() override {}; + + /* Generic space map operators */ + int newSmap(SpaceMap * smap) override; + + /* The difference between clear and free is that after you clear, you can still use this spacemap. */ + void clearSmap(SpaceMap * smap) override; + + void freeSmap(SpaceMap * smap) override; + + int copySmap([[maybe_unused]] SpaceMap * src, [[maybe_unused]] SpaceMap * dest) override + { + // TBD : no implement + return -1; + } + + int resizeSmap([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 new_end, [[maybe_unused]] UInt64 new_real_end) override + { + // TBD : no implement + return -1; + } + + /* Print space maps status */ + void smapStats(SpaceMap * smap) override; + + /* Space map bit/bits test operators */ + int testSmapBit(SpaceMap * smap, UInt64 block) override; + + int testSmapRange(SpaceMap * smap, UInt64 block, unsigned int num) override; + + /* Search range , return the free bits */ + void searchSmapRange([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] size_t num, + [[maybe_unused]] UInt64 * ret) override + { + // TBD + } + + /* Find the first zero/set bit between start and end, inclusive. + * May be NULL, in which case a generic function is used. */ + int findSmapFirstZero([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override + { + return -1; + } + + int findSmapFirstSet([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override + { + return -1; + } + + /* Space map bit set/unset operators */ + int markSmapBit(SpaceMap * smap, UInt64 block) override; + + int unmarkSmapBit(SpaceMap * smap, UInt64 block) override; + + /* Space map range set/unset operators */ + int markSmapRange(SpaceMap * smap, UInt64 block, unsigned int num) override; + + int unmarkSmapRange(SpaceMap * smap, UInt64 block, unsigned int num) override; +}; + + +} \ No newline at end of file diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h new file mode 100644 index 00000000000..6b5c599081c --- /dev/null +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -0,0 +1,135 @@ +#pragma once +#include +#include "SpaceMap.h" + + +namespace DB::PS::V3 { + +class STDMapSpaceMapOps : public SpaceMapOps +{ +public: + STDMapSpaceMapOps() + { + type = SMAP64_STD_MAP; + }; + + ~STDMapSpaceMapOps() override {}; + + /* Generic space map operators */ + int newSmap(SpaceMap * smap) override + { + std::map * private_data; + + private_data = new std::map(); + if (private_data == nullptr) + { + return -1; + } + + smap->_private = (void *)private_data; + + return 0; + } + + void clearSmap(SpaceMap * smap) override + { + std::map * map; + + map = (std::map *)smap->_private; + map->clear(); + } + + void freeSmap(SpaceMap * smap) override + { + std::map * map; + + map = (std::map *)smap->_private; + map->clear(); + + delete map; + smap->_private = nullptr; + } + + int copySmap([[maybe_unused]] SpaceMap * src, [[maybe_unused]] SpaceMap * dest) override + { + // TBD : no implement + return -1; + } + + int resizeSmap([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 new_end, [[maybe_unused]] UInt64 new_real_end) override + { + // TBD : no implement + return -1; + } + + void smapStats(SpaceMap * smap) override + { + std::map * map; + + map = (std::map *)smap->_private; + UInt64 count = 0; + + printf("entry status :\n"); + for (auto it = map->begin(); it != map->end(); it++) + { + printf("range %lld : start=%lld , count=%lld \n", count, it->first, it->second); + count++; + } + } + + int testSmapBit(SpaceMap * smap, UInt64 block) override + { + std::map * map; + + map = (std::map *)smap->_private; + auto it = map->find(block); + return it == map->end(); + } + + int testSmapRange(SpaceMap * smap, UInt64 block, unsigned int num) override + { + std::map * map; + map = (std::map *)smap->_private; + + for (auto it = map->begin(); it != map->end(); it++) + { + // If the range contain the search + if (it->first < block && (it->first + it->second) > (block + num)) + { + return 0; + } + + // TBD + + } + + return 1; + } + + void searchSmapRange([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] size_t num, + [[maybe_unused]] UInt64 * ret) override + { + // TBD + } + + int findSmapFirstZero([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override + { + return -1; + } + + int findSmapFirstSet([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override + { + return -1; + } + + + int markSmapBit(SpaceMap * smap, UInt64 block) override; + + int unmarkSmapBit(SpaceMap * smap, UInt64 block) override; + + int markSmapRange(SpaceMap * smap, UInt64 block, unsigned int num) override; + + int unmarkSmapRange(SpaceMap * smap, UInt64 block, unsigned int num) override; +}; + +} \ No newline at end of file diff --git a/dbms/src/Storages/Page/V3/spacemap/bits.cpp b/dbms/src/Storages/Page/V3/spacemap/bits.cpp deleted file mode 100644 index 2f3e1ebf26b..00000000000 --- a/dbms/src/Storages/Page/V3/spacemap/bits.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "bits.h" - -#ifdef __cplusplus -extern "C" { -#endif - -int set_bit(unsigned int nr, void * addr) -{ - int mask, retval; - unsigned char * ADDR = (unsigned char *)addr; - - ADDR += nr >> 3; - mask = 1 << (nr & 0x07); - retval = mask & *ADDR; - *ADDR |= mask; - return retval; -} - -int clear_bit(unsigned int nr, void * addr) -{ - int mask, retval; - unsigned char * ADDR = (unsigned char *)addr; - - ADDR += nr >> 3; - mask = 1 << (nr & 0x07); - retval = mask & *ADDR; - *ADDR &= ~mask; - return retval; -} - -int test_bit(unsigned int nr, const void * addr) -{ - int mask; - const unsigned char * ADDR = (const unsigned char *)addr; - - ADDR += nr >> 3; - mask = 1 << (nr & 0x07); - return (mask & *ADDR); -} - -/* - * C-only 64 bit ops. - */ -int set_bit64(UInt64 nr, void * addr) -{ - int mask, retval; - unsigned char * ADDR = (unsigned char *)addr; - - ADDR += nr >> 3; - mask = 1 << (nr & 0x07); - retval = mask & *ADDR; - *ADDR |= mask; - return retval; -} - -int clear_bit64(UInt64 nr, void * addr) -{ - int mask, retval; - unsigned char * ADDR = (unsigned char *)addr; - - ADDR += nr >> 3; - mask = 1 << (nr & 0x07); - retval = mask & *ADDR; - *ADDR &= ~mask; - return retval; -} - -int test_bit64(UInt64 nr, const void * addr) -{ - int mask; - const unsigned char * ADDR = (const unsigned char *)addr; - - ADDR += nr >> 3; - mask = 1 << (nr & 0x07); - return (mask & *ADDR); -} - -unsigned int div_ceil(UInt64 a, UInt64 b) -{ - if (!a) - return 0; - return ((a - 1) / b) + 1; -} - - -#ifdef __cplusplus -} -#endif diff --git a/dbms/src/Storages/Page/V3/spacemap/bits.h b/dbms/src/Storages/Page/V3/spacemap/bits.h deleted file mode 100644 index ba5d2884155..00000000000 --- a/dbms/src/Storages/Page/V3/spacemap/bits.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -int set_bit(unsigned int nr, void * addr); -int clear_bit(unsigned int nr, void * addr); -int test_bit(unsigned int nr, const void * addr); -int set_bit64(UInt64 nr, void * addr); -int clear_bit64(UInt64 nr, void * addr); -int test_bit64(UInt64 nr, const void * addr); -unsigned int div_ceil(UInt64 a, UInt64 b); - -#ifdef __cplusplus -} // extern "C" -#endif \ No newline at end of file diff --git a/dbms/src/Storages/Page/V3/spacemap/space_map.cpp b/dbms/src/Storages/Page/V3/spacemap/space_map.cpp deleted file mode 100644 index 5284a678aa2..00000000000 --- a/dbms/src/Storages/Page/V3/spacemap/space_map.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include -#include -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -#include "space_map.h" - -void printf_smap(struct spacemap * smap) -{ - if (unlikely(!smap)) - { - return; - } - smap->spacemap_ops->print_stats(smap); -} - -int unmark_smap(struct spacemap * smap, UInt64 arg) -{ - if (unlikely(!smap)) - { - return -1; - } - - arg >>= smap->cluster_bits; - - if ((arg < smap->start) || (arg > smap->end)) - { - return -1; - } - - return smap->spacemap_ops->unmark_smap_bit(smap, arg); -} - -int mark_smap(struct spacemap * smap, UInt64 arg) -{ - if (unlikely(!smap)) - { - return -1; - } - - arg >>= smap->cluster_bits; - - if ((arg < smap->start) || (arg > smap->end)) - { - return -1; - } - - return smap->spacemap_ops->mark_smap_bit(smap, arg); -} - -int unmark_smap_range(struct spacemap * smap, UInt64 block, unsigned int num) -{ - UInt64 end = block + num; - - if (unlikely(!smap)) - { - return -1; - } - - /* convert to clusters if necessary */ - block >>= smap->cluster_bits; - end += (1 << smap->cluster_bits) - 1; - end >>= smap->cluster_bits; - num = end - block; - - if ((block < smap->start) || (block > smap->end) || (block + num - 1 > smap->end)) - { - return -1; - } - - return smap->spacemap_ops->unmark_smap_range(smap, block, num); -} - -int mark_smap_range(struct spacemap * smap, UInt64 block, unsigned int num) -{ - UInt64 end = block + num; - - if (unlikely(!smap)) - { - return -1; - } - /* convert to clusters if necessary */ - block >>= smap->cluster_bits; - end += (1 << smap->cluster_bits) - 1; - end >>= smap->cluster_bits; - num = end - block; - - if ((block < smap->start) || (block > smap->end) || (block + num - 1 > smap->end)) - { - return -1; - } - - return smap->spacemap_ops->mark_smap_range(smap, block, num); -} - -int test_smap(struct spacemap * smap, UInt64 arg) -{ - if (unlikely(!smap)) - return 0; - - arg >>= smap->cluster_bits; - - if ((arg < smap->start) || (arg > smap->end)) - { - return -1; - } - - return smap->spacemap_ops->test_smap_bit(smap, arg); -} - -int test_smap_range(struct spacemap * smap, UInt64 block, unsigned int num) -{ - UInt64 end = block + num; - - if (unlikely(num == 1)) - return !test_smap(smap, block); - - block >>= smap->cluster_bits; - end += (1 << smap->cluster_bits) - 1; - end >>= smap->cluster_bits; - num = end - block; - - if ((block < smap->start) || (block > smap->end) || (block + num - 1 > smap->end)) - { - return -1; - } - - return smap->spacemap_ops->test_smap_range(smap, block, num); -} - -int init_space_map(struct spacemap * smap, int type, UInt64 start, UInt64 end, UInt64 real_end) -{ - int rc = 0; - assert(smap != NULL); - - switch (type) - { - case SMAP64_RBTREE: - break; - case SMAP64_BITARRAY: - case SMAP64_AUTODIR: // not support yet - return -1; - } - - smap->spacemap_ops = &smap_rbtree; - smap->start = start; - smap->end = end; - smap->real_end = real_end; - smap->cluster_bits = 0; - - rc = smap->spacemap_ops->new_smap(smap); - if (rc != 0) - { - smap->spacemap_ops->free_smap(smap); - } - - return rc; -} - -void destory_space_map(struct spacemap * smap) -{ - if (smap != NULL) - smap->spacemap_ops->free_smap(smap); -} - - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/dbms/src/Storages/Page/V3/spacemap/space_map.h b/dbms/src/Storages/Page/V3/spacemap/space_map.h deleted file mode 100644 index 53b04c21a0b..00000000000 --- a/dbms/src/Storages/Page/V3/spacemap/space_map.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define SMAP64_RBTREE 1 -#define SMAP64_BITARRAY 2 -#define SMAP64_AUTODIR 3 - -#define container_of(ptr, type, member) ({ \ - const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) ); }) - -struct spacemap_ops -{ - int type; - // void (*set_space_callback)(struct spacemap * smap); - - /* Generic space map operators */ - int (*new_smap)(struct spacemap * smap); - /* The difference between clear and free is that after you clear, you can still use this spacemap. */ - void (*clear_smap)(struct spacemap * smap); - void (*free_smap)(struct spacemap * smap); - int (*copy_smap)(struct spacemap * src, struct spacemap * dest); - int (*resize_smap)(struct spacemap * smap, UInt64 new_end, UInt64 new_real_end); - - /* print space maps status */ - void (*print_stats)(struct spacemap * smap); - - /* space map bit/bits test operators */ - int (*test_smap_bit)(struct spacemap * smap, UInt64 block); - int (*test_smap_range)(struct spacemap * smap, UInt64 block, unsigned int num); - - /* search range , return the free bits */ - void (*search_smap_range)(struct spacemap * smap, UInt64 start, UInt64 end, size_t num, UInt64 * ret); - - /* Find the first zero/set bit between start and end, inclusive. - * May be NULL, in which case a generic function is used. */ - int (*find_smap_first_zero)(struct spacemap * smap, UInt64 start, UInt64 end, UInt64 * out); - int (*find_smap_first_set)(struct spacemap * smap, UInt64 start, UInt64 end, UInt64 * out); - - /* space map bit set/unset operators */ - int (*mark_smap_bit)(struct spacemap * smap, UInt64 block); - int (*unmark_smap_bit)(struct spacemap * smap, UInt64 block); - - /* space map range set/unset operators */ - int (*mark_smap_range)(struct spacemap * smap, UInt64 block, unsigned int num); - int (*unmark_smap_range)(struct spacemap * smap, UInt64 block, unsigned int num); -}; - -struct spacemap -{ - struct spacemap_ops * spacemap_ops; - int flags; - /* [left - right] range */ - UInt64 start, end; - /* limit range */ - UInt64 real_end; - /* shift */ - int cluster_bits; - char * description; - void * _private; -}; - -extern struct spacemap_ops smap_rbtree; - -void printf_smap(struct spacemap * smap); - -/** - * ret value : - * -1: Invalid args - * 0: Unmark the marked node - * 1: Unmark the unmarked node - */ -int unmark_smap(struct spacemap * smap, UInt64 arg); - -/** - * ret value : - * -1: Invalid args - * 1: Mark success - */ -int mark_smap(struct spacemap * smap, UInt64 arg); - -/** - * The return value same as `unmark_smap` - */ -int unmark_smap_range(struct spacemap * smap, UInt64 block, unsigned int num); - -/** - * The return value same as `mark_smap` - */ -int mark_smap_range(struct spacemap * smap, UInt64 block, unsigned int num); - -/** - * ret value : - * -1: Invalid args - * 0: This bit is marked - * 1: This bit is not marked - */ -int test_smap(struct spacemap * smap, UInt64 arg); - -/** - * The return value same as `mark_smap` - */ -int test_smap_range(struct spacemap * smap, UInt64 block, unsigned int num); - -/** - * ret value : - * -1: Invalid args - * 0: init success - */ -int init_space_map(struct spacemap * smap, int type, UInt64 start, UInt64 end, UInt64 real_end); -void destory_space_map(struct spacemap * smap); - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index 9a15003f05e..49c2fa6e21d 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -1,18 +1,14 @@ #include #include -#ifdef __cplusplus -extern "C" { -#endif -#include -#include -#include -#ifdef __cplusplus -} // extern "C" -#endif +#include +#include +#include + namespace DB::PS::V3::tests { + struct range { size_t start; @@ -42,20 +38,17 @@ bool check_nodes(struct rb_root * root, range * ranges, size_t size) TEST(space_map_test, InitAndDestory) { - struct spacemap * smap; + SpaceMap smap(std::make_shared(), 0, 100, 101); - smap = (struct spacemap *)calloc(1, sizeof(struct spacemap)); - ASSERT_TRUE(smap); - ASSERT_EQ(init_space_map(smap, SMAP64_RBTREE, 0, 100, 101), 0); - printf_smap(smap); - destory_space_map(smap); + smap.printf(); } +/* TEST(space_map_test, MarkUnmarkBit) { - struct spacemap * smap; + struct SpaceMap * smap; - smap = (struct spacemap *)calloc(1, sizeof(struct spacemap)); + smap = (struct SpaceMap *)calloc(1, sizeof(struct SpaceMap)); ASSERT_TRUE(smap); ASSERT_EQ(init_space_map(smap, SMAP64_RBTREE, 0, 100, 101), 0); @@ -84,9 +77,9 @@ TEST(space_map_test, MarkUnmarkBit) TEST(space_map_test, MarkUnmarkRange) { - struct spacemap * smap; + struct SpaceMap * smap; - smap = (struct spacemap *)calloc(1, sizeof(struct spacemap)); + smap = (struct SpaceMap *)calloc(1, sizeof(struct SpaceMap)); ASSERT_TRUE(smap); ASSERT_EQ(init_space_map(smap, SMAP64_RBTREE, 0, 100, 101), 0); @@ -118,5 +111,6 @@ TEST(space_map_test, MarkUnmarkRange) destory_space_map(smap); } +*/ } // namespace DB::PS::V3::tests \ No newline at end of file From 9d3031d01cc62e4f20a08081e149ca0d97ad4cf0 Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Mon, 29 Nov 2021 18:22:09 +0800 Subject: [PATCH 03/36] Try refactor interface Signed-off-by: JaySon-Huang --- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 133 ++++++------------ .../Page/V3/spacemap/SpaceMapRBTree.h | 54 ++++--- .../Page/V3/spacemap/SpaceMapSTDMap.h | 88 ++++-------- 3 files changed, 97 insertions(+), 178 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index 36dbe3228f6..03942702ad8 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -8,69 +8,9 @@ namespace DB::PS::V3 #define SMAP64_RBTREE 1 #define SMAP64_STD_MAP 2 -struct SpaceMap; - -class SpaceMapOps -{ -public: - virtual ~SpaceMapOps() = default; - - /* Generic space map operators */ - virtual int newSmap(SpaceMap * smap) = 0; - - /* The difference between clear and free is that after you clear, you can still use this spacemap. */ - virtual void clearSmap(SpaceMap * smap) = 0; - - virtual void freeSmap(SpaceMap * smap) = 0; - - virtual int copySmap(SpaceMap * src, SpaceMap * dest) = 0; - - virtual int resizeSmap(SpaceMap * smap, UInt64 new_end, UInt64 new_real_end) = 0; - - /* Print space maps status */ - virtual void smapStats(struct SpaceMap * smap) = 0; - - /* Space map bit/bits test operators */ - virtual int testSmapBit(struct SpaceMap * smap, UInt64 block) = 0; - - virtual int testSmapRange(struct SpaceMap * smap, UInt64 block, unsigned int num) = 0; - - /* Search range , return the free bits */ - virtual void searchSmapRange(struct SpaceMap * smap, UInt64 start, UInt64 end, size_t num, UInt64 * ret) = 0; - - /* Find the first zero/set bit between start and end, inclusive. - * May be NULL, in which case a generic function is used. */ - virtual int findSmapFirstZero(struct SpaceMap * smap, UInt64 start, UInt64 end, UInt64 * out) = 0; - - virtual int findSmapFirstSet(struct SpaceMap * smap, UInt64 start, UInt64 end, UInt64 * out) = 0; - - /* Space map bit set/unset operators */ - virtual int markSmapBit(struct SpaceMap * smap, UInt64 block) = 0; - - virtual int unmarkSmapBit(struct SpaceMap * smap, UInt64 block) = 0; - - /* Space map range set/unset operators */ - virtual int markSmapRange(struct SpaceMap * smap, UInt64 block, unsigned int num) = 0; - - virtual int unmarkSmapRange(struct SpaceMap * smap, UInt64 block, unsigned int num) = 0; - - /* Get Space map type */ - int getSmapType() - { - return type; - } - -protected: - int type = SMAP64_INVALID; -}; - -using SpaceMapOpsPtr = std::shared_ptr; - -struct SpaceMap +class SpaceMap { -public: - SpaceMapOpsPtr spacemap_ops; - +private: int flags; /* [left - right] range */ UInt64 start, end; @@ -80,51 +20,62 @@ struct SpaceMap int cluster_bits; char * description; - void * _private; - SpaceMap(SpaceMapOpsPtr ops, UInt64 start, UInt64 end, UInt64 real_end); +public: + SpaceMap(UInt64 start, UInt64 end, UInt64 real_end); - ~SpaceMap(); + virtual ~SpaceMap(); void printf(); - /** - * ret value : - * -1: Invalid args - * 0: Unmark the marked node - * 1: Unmark the unmarked node - */ - int unmark(UInt64 arg); - - /** - * ret value : - * -1: Invalid args - * 1: Mark success - */ - int mark(UInt64 arg); - /** * The return value same as `unmark` */ - int unmarkRange(UInt64 block, unsigned int num); + int unmarkRange(UInt64 offset, size_t length); /** * The return value same as `mark` */ - int markRange(UInt64 block, unsigned int num); - - /** - * ret value : - * -1: Invalid args - * 0: This bit is marked - * 1: This bit is not marked - */ - int test(UInt64 arg); + int markRange(UInt64 offset, size_t length); /** * The return value same as `test` */ - int testRange(UInt64 block, unsigned int num); + int testRange(UInt64 offset, size_t length); + +protected: + + /* Generic space map operators */ + virtual int newSmap() = 0; + + /* The difference between clear and free is that after you clear, you can still use this spacemap. */ + virtual void clearSmap() = 0; + + virtual void freeSmap() = 0; + + virtual int copySmap(SpaceMap * dest) = 0; + + virtual int resizeSmap(UInt64 new_end, UInt64 new_real_end) = 0; + + /* Print space maps status */ + virtual void smapStats() = 0; + + /* Space map bit/bits test operators */ + virtual int testSmapRange(UInt64 block, unsigned int num) = 0; + + /* Search range, return the free bits */ + virtual void searchSmapRange(UInt64 start, UInt64 end, size_t num, UInt64 * ret) = 0; + + /* Find the first zero/set bit between start and end, inclusive. + * May be NULL, in which case a generic function is used. */ + virtual int findSmapFirstZero(UInt64 start, UInt64 end, UInt64 * out) = 0; + + virtual int findSmapFirstSet(UInt64 start, UInt64 end, UInt64 * out) = 0; + + /* Space map range set/unset operators */ + virtual int markSmapRange(UInt64 block, unsigned int num) = 0; + + virtual int unmarkSmapRange(UInt64 block, unsigned int num) = 0; }; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h index bc1cd3e1227..b0fbcb4d418 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h @@ -3,9 +3,8 @@ #include "SpaceMap.h" -namespace DB::PS::V3 +namespace DB::PS::V3 { - struct smap_rb_entry { struct rb_node node; @@ -27,84 +26,79 @@ struct rb_private inline static struct smap_rb_entry * node_to_entry(struct rb_node * node) { struct smap_rb_entry * rb_ex; - #define container_of(ptr, type, member) ({ \ +#define container_of(ptr, type, member) ({ \ const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) ); }) rb_ex = container_of(node, struct smap_rb_entry, node); - #undef container_of +#undef container_of return rb_ex; } -class RBTreeSpaceMapOps : public SpaceMapOps +class RBTreeSpaceMap : public SpaceMap { -public: - - RBTreeSpaceMapOps() + public: + RBTreeSpaceMap() { type = SMAP64_RBTREE; }; - ~RBTreeSpaceMapOps() override {}; + ~RBTreeSpaceMap() override = default; +protected: /* Generic space map operators */ - int newSmap(SpaceMap * smap) override; + int newSmap() override; /* The difference between clear and free is that after you clear, you can still use this spacemap. */ - void clearSmap(SpaceMap * smap) override; + void clearSmap() override; - void freeSmap(SpaceMap * smap) override; + void freeSmap() override; - int copySmap([[maybe_unused]] SpaceMap * src, [[maybe_unused]] SpaceMap * dest) override + int copySmap([[maybe_unused]] SpaceMap * dest) override { // TBD : no implement return -1; } - int resizeSmap([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 new_end, [[maybe_unused]] UInt64 new_real_end) override + int resizeSmap([[maybe_unused]] UInt64 new_end, [[maybe_unused]] UInt64 new_real_end) override { // TBD : no implement return -1; } /* Print space maps status */ - void smapStats(SpaceMap * smap) override; + void smapStats() override; /* Space map bit/bits test operators */ - int testSmapBit(SpaceMap * smap, UInt64 block) override; - - int testSmapRange(SpaceMap * smap, UInt64 block, unsigned int num) override; + int testSmapRange(UInt64 block, unsigned int num) override; /* Search range , return the free bits */ - void searchSmapRange([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] size_t num, - [[maybe_unused]] UInt64 * ret) override + void searchSmapRange([[maybe_unused]], [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] size_t num, [[maybe_unused]] UInt64 * ret) override { // TBD } /* Find the first zero/set bit between start and end, inclusive. * May be NULL, in which case a generic function is used. */ - int findSmapFirstZero([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override + int findSmapFirstZero([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override { return -1; } - int findSmapFirstSet([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override + int findSmapFirstSet([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override { return -1; } - /* Space map bit set/unset operators */ - int markSmapBit(SpaceMap * smap, UInt64 block) override; - - int unmarkSmapBit(SpaceMap * smap, UInt64 block) override; - /* Space map range set/unset operators */ - int markSmapRange(SpaceMap * smap, UInt64 block, unsigned int num) override; + int markSmapRange(UInt64 block, unsigned int num) override; + + int unmarkSmapRange(UInt64 block, unsigned int num) override; - int unmarkSmapRange(SpaceMap * smap, UInt64 block, unsigned int num) override; +private: + struct rb_private * rb_tree; }; -} \ No newline at end of file +} // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 6b5c599081c..c550d8e9d20 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -1,135 +1,109 @@ #pragma once #include -#include "SpaceMap.h" +#include "SpaceMap.h" -namespace DB::PS::V3 { -class STDMapSpaceMapOps : public SpaceMapOps +namespace DB::PS::V3 +{ +class STDMapSpaceMap : public SpaceMap { public: - STDMapSpaceMapOps() + STDMapSpaceMap() { type = SMAP64_STD_MAP; }; - ~STDMapSpaceMapOps() override {}; + virtual ~STDMapSpaceMap() override = default; /* Generic space map operators */ - int newSmap(SpaceMap * smap) override + int newSmap() override { - std::map * private_data; + /* + std::map * private_data; - private_data = new std::map(); + private_data = new std::map(); if (private_data == nullptr) { return -1; } smap->_private = (void *)private_data; - +*/ return 0; } - void clearSmap(SpaceMap * smap) override + void clearSmap() override { - std::map * map; - - map = (std::map *)smap->_private; - map->clear(); + map.clear(); } - void freeSmap(SpaceMap * smap) override + void freeSmap() override { - std::map * map; - - map = (std::map *)smap->_private; - map->clear(); - - delete map; - smap->_private = nullptr; + map.clear(); } - int copySmap([[maybe_unused]] SpaceMap * src, [[maybe_unused]] SpaceMap * dest) override + int copySmap([[maybe_unused]] SpaceMap * dest) override { // TBD : no implement return -1; } - int resizeSmap([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 new_end, [[maybe_unused]] UInt64 new_real_end) override + int resizeSmap([[maybe_unused]] UInt64 new_end, [[maybe_unused]] UInt64 new_real_end) override { // TBD : no implement return -1; } - void smapStats(SpaceMap * smap) override + void smapStats() override { - std::map * map; - - map = (std::map *)smap->_private; UInt64 count = 0; printf("entry status :\n"); - for (auto it = map->begin(); it != map->end(); it++) + for (auto it = map.begin(); it != map.end(); it++) { printf("range %lld : start=%lld , count=%lld \n", count, it->first, it->second); count++; } } - int testSmapBit(SpaceMap * smap, UInt64 block) override + int testSmapRange(UInt64 block, unsigned int num) override { - std::map * map; - - map = (std::map *)smap->_private; - auto it = map->find(block); - return it == map->end(); - } - - int testSmapRange(SpaceMap * smap, UInt64 block, unsigned int num) override - { - std::map * map; - map = (std::map *)smap->_private; - - for (auto it = map->begin(); it != map->end(); it++) + for (auto it = map.begin(); it != map.end(); it++) { // If the range contain the search - if (it->first < block && (it->first + it->second) > (block + num)) + if (it->first < block && (it->first + it->second) > (block + num)) { return 0; } - // TBD - + // TBD } return 1; } - void searchSmapRange([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] size_t num, - [[maybe_unused]] UInt64 * ret) override + void searchSmapRange([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] size_t num, [[maybe_unused]] UInt64 * ret) override { // TBD } - int findSmapFirstZero([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override + int findSmapFirstZero([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override { return -1; } - int findSmapFirstSet([[maybe_unused]] SpaceMap * smap, [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override + int findSmapFirstSet([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override { return -1; } + int markSmapRange(UInt64 block, unsigned int num) override; - int markSmapBit(SpaceMap * smap, UInt64 block) override; - - int unmarkSmapBit(SpaceMap * smap, UInt64 block) override; - - int markSmapRange(SpaceMap * smap, UInt64 block, unsigned int num) override; + int unmarkSmapRange(UInt64 block, unsigned int num) override; - int unmarkSmapRange(SpaceMap * smap, UInt64 block, unsigned int num) override; +private: + std::map map; }; -} \ No newline at end of file +} // namespace DB::PS::V3 From 98ec4cee36f047172480a42c4e648e76bc6d8662 Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Mon, 29 Nov 2021 18:30:34 +0800 Subject: [PATCH 04/36] Add spacemap.cpp Signed-off-by: JaySon-Huang --- .../Storages/Page/V3/spacemap/SpaceMap.cpp | 46 ++----------------- 1 file changed, 5 insertions(+), 41 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index 74165edfdab..2445cbf2a27 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -13,31 +13,7 @@ namespace DB::PS::V3 void SpaceMap::printf() { - spacemap_ops->smapStats(this); -} - -int SpaceMap::unmark(UInt64 arg) -{ - arg >>= cluster_bits; - - if ((arg < start) || (arg > end)) - { - return -1; - } - - return spacemap_ops->unmarkSmapBit(this, arg); -} - -int SpaceMap::mark(UInt64 arg) -{ - arg >>= cluster_bits; - - if ((arg < start) || (arg > end)) - { - return -1; - } - - return spacemap_ops->markSmapBit(this, arg); + smapStats(); } int SpaceMap::unmarkRange(UInt64 block, unsigned int num) @@ -56,7 +32,7 @@ int SpaceMap::unmarkRange(UInt64 block, unsigned int num) return -1; } - return spacemap_ops->unmarkSmapRange(this, block, num); + return unmarkSmapRange(block, num); } int SpaceMap::markRange(UInt64 block, unsigned int num) @@ -74,19 +50,7 @@ int SpaceMap::markRange(UInt64 block, unsigned int num) return -1; } - return spacemap_ops->markSmapRange(this, block, num); -} - -int SpaceMap::test(UInt64 arg) -{ - arg >>= cluster_bits; - - if ((arg < start) || (arg > end)) - { - return -1; - } - - return spacemap_ops->testSmapBit(this, arg); + return markSmapRange(block, num); } int SpaceMap::testRange(UInt64 block, unsigned int num) @@ -106,10 +70,10 @@ int SpaceMap::testRange(UInt64 block, unsigned int num) return -1; } - return spacemap_ops->testSmapRange(this, block, num); + return testSmapRange(block, num); } -SpaceMap::SpaceMap(SpaceMapOpsPtr ops, UInt64 start_, UInt64 end_, UInt64 real_end_) +SpaceMap::SpaceMap(UInt64 start_, UInt64 end_, UInt64 real_end_) : spacemap_ops(ops), start(start_), end(end_), From 04776e1fadaa043aa60e73f83b9e8c58404fac15 Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Tue, 30 Nov 2021 16:06:04 +0800 Subject: [PATCH 05/36] finished std map implement --- .../Storages/Page/V3/spacemap/SpaceMap.cpp | 116 ++++---- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 113 +++++--- .../Page/V3/spacemap/SpaceMapRBTree.cpp | 263 +++++------------- .../Page/V3/spacemap/SpaceMapRBTree.h | 56 ++-- .../Page/V3/spacemap/SpaceMapSTDMap.h | 164 ++++++++--- .../Storages/Page/V3/tests/gtest_free_map.cpp | 150 +++++++--- 6 files changed, 468 insertions(+), 394 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index 2445cbf2a27..2b9fed9b262 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -1,95 +1,109 @@ +#include "SpaceMap.h" + #include #include - #include #include #include -#include "SpaceMap.h" #include "SpaceMapRBTree.h" +#include "SpaceMapSTDMap.h" -namespace DB::PS::V3 +namespace DB::PS::V3 { - -void SpaceMap::printf() +SpaceMapPtr SpaceMap::createSpaceMap(SpaceMapType type, UInt64 start, UInt64 end, int cluster_bits) { - smapStats(); + SpaceMapPtr smap; + switch (type) + { + case SMAP64_RBTREE: + smap = std::make_shared(start, end, cluster_bits); + break; + case SMAP64_STD_MAP: + smap = std::make_shared(start, end, cluster_bits); + break; + default: + return nullptr; + } + + int rc = smap->newSmap(); + if (rc != 0) + { + smap->freeSmap(); + return nullptr; + } + + return smap; } -int SpaceMap::unmarkRange(UInt64 block, unsigned int num) +std::pair SpaceMap::shiftBlock(UInt64 block, size_t size) { - UInt64 end = block + num; - + UInt64 block_end = block + size; - /* convert to clusters if necessary */ block >>= cluster_bits; - end += (1 << cluster_bits) - 1; - end >>= cluster_bits; - num = end - block; + block_end += (1 << cluster_bits) - 1; + block_end >>= cluster_bits; + size = block_end - block; + return std::make_pair(block, size); +} - if ((block < start) || (block > end) || (block + num - 1 > end)) - { - return -1; - } - return unmarkSmapRange(block, num); +bool SpaceMap::checkRange(UInt64 block, size_t size) +{ + return (block < start) || (block > end) || (block + size - 1 > end); } -int SpaceMap::markRange(UInt64 block, unsigned int num) +void SpaceMap::logStats() { - UInt64 end = block + num; + smapStats(); +} - /* convert to clusters if necessary */ - block >>= cluster_bits; - end += (1 << cluster_bits) - 1; - end >>= cluster_bits; - num = end - block; - if ((block < start) || (block > end) || (block + num - 1 > end)) +int SpaceMap::unmarkRange(UInt64 block, size_t size) +{ + std::tie(block, size) = shiftBlock(block, size); + + if (checkRange(block, size)) { + LOG_ERROR(log, "unMark range out of the limit range.[type=" << type << "] [block=" << block << "], [size = " << size << "]"); return -1; } - return markSmapRange(block, num); + return unmarkSmapRange(block, size); } -int SpaceMap::testRange(UInt64 block, unsigned int num) +int SpaceMap::markRange(UInt64 block, size_t size) { - UInt64 end = block + num; + std::tie(block, size) = shiftBlock(block, size); - if (unlikely(num == 1)) - return !test(block); - - block >>= cluster_bits; - end += (1 << cluster_bits) - 1; - end >>= cluster_bits; - num = end - block; - - if ((block < start) || (block > end) || (block + num - 1 > end)) + if (checkRange(block, size)) { + LOG_ERROR(log, "Mark range out of the limit range.[type=" << type << "] [block=" << block << "], [size = " << size << "]"); return -1; } - return testSmapRange(block, num); + return markSmapRange(block, size); } -SpaceMap::SpaceMap(UInt64 start_, UInt64 end_, UInt64 real_end_) - : spacemap_ops(ops), - start(start_), - end(end_), - real_end(real_end_), - cluster_bits(0) +int SpaceMap::testRange(UInt64 block, size_t size) { - int rc = spacemap_ops->newSmap(this); - if (rc != 0) + std::tie(block, size) = shiftBlock(block, size); + + if (checkRange(block, size)) { - spacemap_ops->freeSmap(this); + LOG_ERROR(log, "Test range out of the limit range.[type=" << type << "] [block=" << block << "], [size = " << size << "]"); + return -1; } + + return testSmapRange(block, size); } -SpaceMap::~SpaceMap() +SpaceMap::SpaceMap(UInt64 start_, UInt64 end_, int cluster_bits) + : start(start_) + , end(end_) + , log(&Poco::Logger::get("RBTreeSpaceMap")) + , cluster_bits(cluster_bits) { - spacemap_ops->freeSmap(this); } -} +} // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index 03942702ad8..ff5b59b1d11 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -1,49 +1,73 @@ #pragma once #include +#include -namespace DB::PS::V3 +namespace DB::PS::V3 { - -#define SMAP64_INVALID 0 -#define SMAP64_RBTREE 1 -#define SMAP64_STD_MAP 2 - +class SpaceMap; +using SpaceMapPtr = std::shared_ptr; class SpaceMap { -private: - int flags; - /* [left - right] range */ - UInt64 start, end; - /* limit range */ - UInt64 real_end; - /* shift */ - int cluster_bits; - - char * description; - public: - SpaceMap(UInt64 start, UInt64 end, UInt64 real_end); - - virtual ~SpaceMap(); + enum SpaceMapType + { + SMAP64_INVALID = 0, + SMAP64_RBTREE = 1, + SMAP64_STD_MAP = 2 + }; - void printf(); + static SpaceMapPtr createSpaceMap(SpaceMapType type, UInt64 start, UInt64 end, int cluster_bits = 0); /** - * The return value same as `unmark` + * ret value : + * -1: Invalid args + * 0: Unmark the marked node + * 1: Unmark the unmarked node */ int unmarkRange(UInt64 offset, size_t length); /** - * The return value same as `mark` + * ret value : + * -1: Invalid args + * 1: Mark success */ int markRange(UInt64 offset, size_t length); /** - * The return value same as `test` + * ret value : + * -1: Invalid args + * 0: This bit is marked + * 1: This bit is not marked */ int testRange(UInt64 offset, size_t length); + /** + * Search range, return the free bits + */ + void searchRange(UInt64 start, UInt64 end, size_t size, UInt64 * ret); + + /** + * Clear all ranges + */ + void clear(); + + /** + * Log the status of space map + */ + void logStats(); + + SpaceMapType getType() + { + return type; + } + +#ifndef DBMS_PUBLIC_GTEST protected: +#endif + + SpaceMap(UInt64 start, UInt64 end, int cluster_bits = 0); + + virtual ~SpaceMap(){}; /* Generic space map operators */ virtual int newSmap() = 0; @@ -61,22 +85,43 @@ class SpaceMap virtual void smapStats() = 0; /* Space map bit/bits test operators */ - virtual int testSmapRange(UInt64 block, unsigned int num) = 0; + virtual int testSmapRange(UInt64 offset, size_t size) = 0; /* Search range, return the free bits */ - virtual void searchSmapRange(UInt64 start, UInt64 end, size_t num, UInt64 * ret) = 0; + virtual void searchSmapRange(UInt64 start, UInt64 end, size_t size, UInt64 * ret) = 0; - /* Find the first zero/set bit between start and end, inclusive. - * May be NULL, in which case a generic function is used. */ - virtual int findSmapFirstZero(UInt64 start, UInt64 end, UInt64 * out) = 0; + /* Space map range set/unset operators */ + virtual int markSmapRange(UInt64 offset, size_t size) = 0; - virtual int findSmapFirstSet(UInt64 start, UInt64 end, UInt64 * out) = 0; + virtual int unmarkSmapRange(UInt64 offset, size_t size) = 0; - /* Space map range set/unset operators */ - virtual int markSmapRange(UInt64 block, unsigned int num) = 0; +private: + /* shift block to the right range */ + std::pair shiftBlock(UInt64 offset, size_t num); - virtual int unmarkSmapRange(UInt64 block, unsigned int num) = 0; + /* Check the range */ + bool checkRange(UInt64 offset, size_t num); + /* Check Space Map have been inited or not*/ + bool checkInited(); +#ifndef DBMS_PUBLIC_GTEST +protected: +#else +public: +#endif + SpaceMapType type = SpaceMapType::SMAP64_INVALID; + + /* [left - right] range */ + UInt64 start, end; + + Poco::Logger * log; + +private: + /* shift */ + int cluster_bits; + + char * description; }; -} + +} // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index 5dce42ad853..6ca472f82bd 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -1,8 +1,8 @@ #include "SpaceMapRBTree.h" -namespace DB::PS::V3 -{ +namespace DB::PS::V3 +{ static int rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data); static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data); @@ -20,6 +20,7 @@ static inline void rb_link_node(struct rb_node * node, #define ENABLE_DEBUG_IN_RB_TREE 0 #if !defined(NDEBUG) && !defined(DBMS_PUBLIC_GTEST) && ENABLE_DEBUG_IN_RB_TREE +// Its local debug info, So don't us LOG static void rb_tree_debug(struct rb_root * root, const char * method_call) { struct rb_node * node = NULL; @@ -83,7 +84,7 @@ inline static void rb_free_entry(struct rb_private * private_data, struct smap_r static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data) { struct rb_root * root = &private_data->root; - struct rb_node * parent = NULL, **n = &root->rb_node; + struct rb_node *parent = NULL, **n = &root->rb_node; struct rb_node * node; struct smap_rb_entry * entry; UInt64 new_start, new_count; @@ -176,44 +177,25 @@ static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * priva return retval; } -static int rb_alloc_private_data(SpaceMap * smap) +int RBTreeSpaceMap::newSmap() { - struct rb_private * private_data; - - // alloc root node - private_data = (struct rb_private *)calloc(1, sizeof(struct rb_private)); - if (private_data == NULL) + rb_tree = (struct rb_private *)calloc(1, sizeof(struct rb_private)); + if (rb_tree == NULL) { return -1; } - private_data->root = {NULL}; - private_data->read_index = NULL; - private_data->read_index_next = NULL; - private_data->write_index = NULL; - - smap->_private = (void *)private_data; - return 0; -} - -int RBTreeSpaceMapOps::newSmap(SpaceMap * smap) -{ - int ret; - struct rb_private * private_data; - - ret = rb_alloc_private_data(smap); - if (ret) - { - return ret; - } - - private_data = (struct rb_private *)smap->_private; + rb_tree->root = { + NULL, + }; + rb_tree->read_index = NULL; + rb_tree->read_index_next = NULL; + rb_tree->write_index = NULL; - ret = rb_insert_entry(smap->start, smap->end, private_data); - if (ret != 0) + if (rb_insert_entry(start, end, rb_tree) != 0) { - printf("Erorr happend, when mark all range to free.\n"); - free(private_data); + LOG_ERROR(log, "Erorr happend, when mark all range to free. [start=" << start << "] , [end = " << end << "]"); + free(rb_tree); return -1; } @@ -234,50 +216,52 @@ static void rb_free_tree(struct rb_root * root) } } -void RBTreeSpaceMapOps::freeSmap(SpaceMap * smap) +void RBTreeSpaceMap::freeSmap() { - struct rb_private * private_data; - - private_data = (struct rb_private *)smap->_private; - - rb_free_tree(&private_data->root); - free(private_data); + rb_free_tree(&rb_tree->root); + free(rb_tree); } -void RBTreeSpaceMapOps::clearSmap(SpaceMap * smap) +void RBTreeSpaceMap::clearSmap() { - struct rb_private * private_data; - - private_data = (struct rb_private *)smap->_private; + if (rb_tree == nullptr) + { + LOG_ERROR(log, "SpaceMap have not been inited."); + return; + } - rb_free_tree(&private_data->root); - private_data->read_index = NULL; - private_data->read_index_next = NULL; - private_data->write_index = NULL; - rb_tree_debug(&private_data->root, __func__); + rb_free_tree(&rb_tree->root); + rb_tree->read_index = NULL; + rb_tree->read_index_next = NULL; + rb_tree->write_index = NULL; + rb_tree_debug(&rb_tree->root, __func__); } -void RBTreeSpaceMapOps::smapStats(SpaceMap * smap) +void RBTreeSpaceMap::smapStats() { - struct rb_private * private_data; struct rb_node * node = NULL; struct smap_rb_entry * entry; UInt64 count = 0; UInt64 max_size = 0; UInt64 min_size = ULONG_MAX; - private_data = (struct rb_private *)smap->_private; - printf("entry status :\n"); - for (node = rb_tree_first(&private_data->root); node != NULL; node = rb_tree_next(node)) + if (rb_tree->root.rb_node == nullptr) + { + LOG_ERROR(log, "Tree have not been inited."); + return; + } + + LOG_DEBUG(log, "entry status :"); + for (node = rb_tree_first(&rb_tree->root); node != NULL; node = rb_tree_next(node)) { entry = node_to_entry(node); - printf("range %lld : start=%lld , count=%lld \n", count, entry->start, entry->count); + LOG_DEBUG(log, " range : " << count << " start:" << entry->start << " size : " << entry->count); count++; if (entry->count > max_size) { max_size = entry->count; } - + if (entry->count < min_size) { min_size = entry->count; @@ -285,109 +269,18 @@ void RBTreeSpaceMapOps::smapStats(SpaceMap * smap) } } - -inline static int rb_test_bit(struct rb_private * private_data, UInt64 bit) -{ - struct smap_rb_entry *read_index, *next_entry = NULL; - struct rb_node *parent = NULL, *next_node; - struct rb_node ** n = &private_data->root.rb_node; - struct smap_rb_entry * entry; - - read_index = private_data->read_index; - - // derect search tree - if (!read_index) - { - goto search_tree; - } - - - if (bit >= read_index->start && bit < read_index->start + read_index->count) - { - return 1; - } - - next_entry = private_data->read_index_next; - if (!next_entry) - { - next_node = rb_tree_next(&read_index->node); - if (next_node) - { - next_entry = node_to_entry(next_node); - } - private_data->read_index_next = next_entry; - } - if (next_entry) - { - if ((bit >= read_index->start + read_index->count) && (bit < next_entry->start)) - { - return 0; - } - } - private_data->read_index = NULL; - private_data->read_index_next = NULL; - - read_index = private_data->write_index; - if (!read_index) - { - goto search_tree; - } - - if (bit >= read_index->start && bit < read_index->start + read_index->count) - { - return 1; - } - -search_tree: - - while (*n) - { - parent = *n; - entry = node_to_entry(parent); - if (bit < entry->start) - { - n = &(*n)->node_left; - } - else if (bit >= (entry->start + entry->count)) - { - n = &(*n)->node_right; - } - else - { - private_data->read_index = entry; - private_data->read_index_next = NULL; - return 1; - } - } - return 0; -} - -int RBTreeSpaceMapOps::testSmapBit(SpaceMap * smap, UInt64 arg) -{ - struct rb_private * private_data; - - private_data = (struct rb_private *)smap->_private; - arg -= smap->start; - - return rb_test_bit(private_data, arg); -} - - -int RBTreeSpaceMapOps::testSmapRange(SpaceMap * smap, - UInt64 start, - unsigned int len) +int RBTreeSpaceMap::testSmapRange(UInt64 _start, + size_t len) { struct rb_node *parent = NULL, **n; struct rb_node *node, *next; - struct rb_private * private_data; struct smap_rb_entry * entry; int retval = 0; - private_data = (struct rb_private *)smap->_private; - n = &private_data->root.rb_node; - start -= smap->start; + n = &rb_tree->root.rb_node; + _start -= start; - if (len == 0 || private_data->root.rb_node == NULL) + if (len == 0 || rb_tree->root.rb_node == NULL) { return -1; } @@ -397,11 +290,11 @@ int RBTreeSpaceMapOps::testSmapRange(SpaceMap * smap, { parent = *n; entry = node_to_entry(parent); - if (start < entry->start) + if (_start < entry->start) { n = &(*n)->node_left; } - else if (start >= (entry->start + entry->count)) + else if (_start >= (entry->start + entry->count)) { n = &(*n)->node_right; } @@ -420,11 +313,11 @@ int RBTreeSpaceMapOps::testSmapRange(SpaceMap * smap, entry = node_to_entry(node); node = next; - if ((entry->start + entry->count) <= start) + if ((entry->start + entry->count) <= _start) continue; /* No more merging */ - if ((start + len) <= entry->start) + if ((_start + len) <= entry->start) break; retval = 1; @@ -559,57 +452,27 @@ static int rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * priva return retval; } -int RBTreeSpaceMapOps::markSmapBit(SpaceMap * smap, UInt64 arg) -{ - struct rb_private * private_data; - int retval; - - private_data = (struct rb_private *)smap->_private; - arg -= smap->start; - - retval = rb_remove_entry(arg, 1, private_data); - rb_tree_debug(&private_data->root, __func__); - return retval; -} - -int RBTreeSpaceMapOps::unmarkSmapBit(SpaceMap * smap, UInt64 arg) +int RBTreeSpaceMap::markSmapRange(UInt64 block, size_t size) { - struct rb_private * private_data; - int retval; - - private_data = (struct rb_private *)smap->_private; - arg -= smap->start; + int rc; - retval = rb_insert_entry(arg, 1, private_data); - rb_tree_debug(&private_data->root, __func__); + block -= start; - return retval; + rc = rb_remove_entry(block, size, rb_tree); + rb_tree_debug(&rb_tree->root, __func__); + return rc; } -int RBTreeSpaceMapOps::markSmapRange(SpaceMap * smap, UInt64 arg, unsigned int num) +int RBTreeSpaceMap::unmarkSmapRange(UInt64 block, size_t size) { - struct rb_private * private_data; - int retval; + int rc; - private_data = (struct rb_private *)smap->_private; - arg -= smap->start; + block -= start; - retval = rb_remove_entry(arg, num, private_data); - rb_tree_debug(&private_data->root, __func__); - return retval; + rc = rb_insert_entry(block, size, rb_tree); + rb_tree_debug(&rb_tree->root, __func__); + return rc; } -int RBTreeSpaceMapOps::unmarkSmapRange(SpaceMap * smap, UInt64 arg, unsigned int num) -{ - struct rb_private * private_data; - int retval; - - private_data = (struct rb_private *)smap->_private; - arg -= smap->start; - - retval = rb_insert_entry(arg, num, private_data); - rb_tree_debug(&private_data->root, __func__); - return retval; -} -} \ No newline at end of file +} // namespace DB::PS::V3 \ No newline at end of file diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h index b0fbcb4d418..9d79a02227f 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h @@ -1,9 +1,17 @@ #pragma once +#include + #include "RBTree.h" #include "SpaceMap.h" +namespace DB +{ +namespace ErrorCodes +{ +extern const int NOT_IMPLEMENTED; +} // namespace ErrorCodes -namespace DB::PS::V3 +namespace PS::V3 { struct smap_rb_entry { @@ -38,15 +46,20 @@ inline static struct smap_rb_entry * node_to_entry(struct rb_node * node) class RBTreeSpaceMap : public SpaceMap { - public: - RBTreeSpaceMap() +public: + RBTreeSpaceMap(UInt64 start, UInt64 end, int cluster_bits = 0) + : SpaceMap(start, end, cluster_bits) { type = SMAP64_RBTREE; }; - ~RBTreeSpaceMap() override = default; - + ~RBTreeSpaceMap() override + { + freeSmap(); + }; +#ifndef DBMS_PUBLIC_GTEST protected: +#endif /* Generic space map operators */ int newSmap() override; @@ -57,48 +70,37 @@ class RBTreeSpaceMap : public SpaceMap int copySmap([[maybe_unused]] SpaceMap * dest) override { - // TBD : no implement - return -1; + throw Exception("Unimplement here. After need use, then implement it.", ErrorCodes::NOT_IMPLEMENTED); } int resizeSmap([[maybe_unused]] UInt64 new_end, [[maybe_unused]] UInt64 new_real_end) override { - // TBD : no implement - return -1; + throw Exception("NOT_IMPLEMENTED. After need use, then implement it.", ErrorCodes::NOT_IMPLEMENTED); } /* Print space maps status */ void smapStats() override; /* Space map bit/bits test operators */ - int testSmapRange(UInt64 block, unsigned int num) override; + int testSmapRange(UInt64 block, size_t num) override; /* Search range , return the free bits */ - void searchSmapRange([[maybe_unused]], [[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] size_t num, [[maybe_unused]] UInt64 * ret) override + void searchSmapRange([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] size_t num, [[maybe_unused]] UInt64 * ret) override { // TBD } - /* Find the first zero/set bit between start and end, inclusive. - * May be NULL, in which case a generic function is used. */ - int findSmapFirstZero([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override - { - return -1; - } - - int findSmapFirstSet([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override - { - return -1; - } - - /* Space map range set/unset operators */ - int markSmapRange(UInt64 block, unsigned int num) override; + int markSmapRange(UInt64 block, size_t num) override; - int unmarkSmapRange(UInt64 block, unsigned int num) override; + int unmarkSmapRange(UInt64 block, size_t num) override; +#ifndef DBMS_PUBLIC_GTEST private: +#endif struct rb_private * rb_tree; }; +using RBTreeSpaceMapPtr = std::shared_ptr; -} // namespace DB::PS::V3 +} // namespace PS::V3 +} // namespace DB \ No newline at end of file diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index c550d8e9d20..9ea987b7aad 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -1,86 +1,91 @@ #pragma once +#include + #include #include "SpaceMap.h" +namespace DB +{ +namespace ErrorCodes +{ +extern const int NOT_IMPLEMENTED; +} // namespace ErrorCodes -namespace DB::PS::V3 +namespace PS::V3 { class STDMapSpaceMap : public SpaceMap { public: - STDMapSpaceMap() + STDMapSpaceMap(UInt64 start, UInt64 end, int cluster_bits = 0) + : SpaceMap(start, end, cluster_bits) { type = SMAP64_STD_MAP; }; - virtual ~STDMapSpaceMap() override = default; + ~STDMapSpaceMap() override{ - /* Generic space map operators */ + }; +#ifndef DBMS_PUBLIC_GTEST +protected: +#endif int newSmap() override { - /* - std::map * private_data; - - private_data = new std::map(); - if (private_data == nullptr) - { - return -1; - } - - smap->_private = (void *)private_data; -*/ + map.insert({start, end}); return 0; } void clearSmap() override { map.clear(); + map.insert({start, end}); } void freeSmap() override { - map.clear(); + clearSmap(); } int copySmap([[maybe_unused]] SpaceMap * dest) override { - // TBD : no implement - return -1; + throw Exception("Unimplement here. After need use, then implement it.", ErrorCodes::NOT_IMPLEMENTED); } int resizeSmap([[maybe_unused]] UInt64 new_end, [[maybe_unused]] UInt64 new_real_end) override { - // TBD : no implement - return -1; + throw Exception("Unimplement here. After need use, then implement it.", ErrorCodes::NOT_IMPLEMENTED); } void smapStats() override { UInt64 count = 0; - printf("entry status :\n"); + LOG_DEBUG(log, "entry status :"); for (auto it = map.begin(); it != map.end(); it++) { - printf("range %lld : start=%lld , count=%lld \n", count, it->first, it->second); + LOG_DEBUG(log, " range : " << count << " start:" << it->first << " size : " << it->second); count++; } } - int testSmapRange(UInt64 block, unsigned int num) override + int testSmapRange(UInt64 block, size_t num) override { for (auto it = map.begin(); it != map.end(); it++) { - // If the range contain the search - if (it->first < block && (it->first + it->second) > (block + num)) + // block in the range + if (it->first <= block && (it->first + it->second) > block) { - return 0; + // end of block still in the range + return (it->first + it->second) >= (num + block); } - // TBD + if (it->first >= block) + { + break; + } } - return 1; + return 0; } void searchSmapRange([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] size_t num, [[maybe_unused]] UInt64 * ret) override @@ -88,22 +93,109 @@ class STDMapSpaceMap : public SpaceMap // TBD } - int findSmapFirstZero([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override + int markSmapRange(UInt64 block, size_t num) override { - return -1; + auto it = map.find(block); + if (it == map.end()) + { + // can't found , check the near one. + for (it = map.begin(); it != map.end(); it++) + { + // In the range, jump to range. + if (it->first <= block && (it->first + it->second) > block) + { + goto found_range; + } + + // Counld not found, break. + if (it->first > block) + { + break; + } + } + } + else + { + found_range: + // match + if (it->first == block) + { + map.erase(it); + + // in the range + } + else + { + // In the mid, and not match the left or right. + // Split to two range + if (((it->first + it->second) - block) > num) + { + map.insert({block + num, it->first + it->second - block - num}); + map[it->first] = block - it->first; + } + else + { // < num + map[it->first] = it->first + it->second - block; + } + } + } + return 1; } - int findSmapFirstSet([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] UInt64 * out) override + int unmarkSmapRange(UInt64 block, size_t num) override { - return -1; - } + auto it = map.find(block); + + // already unmarked + if (it != map.end()) + { + return 0; + } + + bool meanless = false; + std::tie(it, meanless) = map.insert({block, num}); + + auto it_prev = it; + it_prev--; + + if (it == map.begin()) + { + goto only_do_right; + } - int markSmapRange(UInt64 block, unsigned int num) override; + // Prev range can merge + if (it_prev->first + it_prev->second >= it->first) + { + map[it_prev->first] = it->first + it->second - it_prev->first; + map.erase(it); + it = it_prev; + } + + only_do_right: + if (it == map.end()) + { + return 0; + } - int unmarkSmapRange(UInt64 block, unsigned int num) override; + auto it_next = it; + it_next++; + // next range can merge + if (it->first + it->second >= it_next->first) + { + map[it->first] = it_next->first + it_next->second - it->first; + map.erase(it_next); + } + + return 0; + } +#ifndef DBMS_PUBLIC_GTEST private: +#endif std::map map; }; -} // namespace DB::PS::V3 +using STDMapSpaceMapPtr = std::shared_ptr; + +} // namespace PS::V3 +} // namespace DB diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index 49c2fa6e21d..dae0488755c 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -1,14 +1,14 @@ -#include -#include - #include #include #include +#include +#include +#include +#include namespace DB::PS::V3::tests { - struct range { size_t start; @@ -26,7 +26,7 @@ bool check_nodes(struct rb_root * root, range * ranges, size_t size) for (node = rb_tree_first(root); node != NULL; node = rb_tree_next(node)) { ext = node_to_entry(node); - if (i >= size && ranges[i].start != ext->start && ranges[i].end != ext->start + ext->count) + if (i >= size || ranges[i].start != ext->start || ranges[i].end != ext->start + ext->count) { return false; } @@ -36,81 +36,139 @@ bool check_nodes(struct rb_root * root, range * ranges, size_t size) return true; } -TEST(space_map_test, InitAndDestory) +bool check_nodes(std::map & map, range * ranges, size_t size) { - SpaceMap smap(std::make_shared(), 0, 100, 101); + assert(size != 0); - smap.printf(); + size_t i = 0; + for (auto it = map.begin(); it != map.end(); it++) + { + if (i >= size || ranges[i].start != it->first || ranges[i].end != it->first + it->second) + { + return false; + } + i++; + } + + return true; } -/* -TEST(space_map_test, MarkUnmarkBit) + +TEST(space_map_test, InitAndDestory) { - struct SpaceMap * smap; + SpaceMapPtr smap = SpaceMap::createSpaceMap(SpaceMap::SpaceMapType::SMAP64_RBTREE, 0, 100); - smap = (struct SpaceMap *)calloc(1, sizeof(struct SpaceMap)); - ASSERT_TRUE(smap); - ASSERT_EQ(init_space_map(smap, SMAP64_RBTREE, 0, 100, 101), 0); + smap->logStats(); +} + + +TEST(space_map_test, MarkUnmarkBitRBTree) +{ + RBTreeSpaceMapPtr smap = std::make_shared(0, 100); + ASSERT_EQ(smap->newSmap(), 0); - struct rb_private * bp = (struct rb_private *)smap->_private; + struct rb_private * bp = (struct rb_private *)smap->rb_tree; range ranges[] = {{.start = 0, .end = 100}}; - check_nodes(&bp->root, ranges, 1); + ASSERT_TRUE(check_nodes(&bp->root, ranges, 1)); - ASSERT_TRUE(mark_smap(smap, 50)); - ASSERT_EQ(test_smap(smap, 50), 0); - ASSERT_EQ(test_smap(smap, 51), 1); + ASSERT_TRUE(smap->markRange(50, 1)); + ASSERT_EQ(smap->testRange(50, 1), 0); + ASSERT_EQ(smap->testRange(51, 1), 1); range ranges1[] = {{.start = 0, - .end = 49}, - {.start = 50, + .end = 50}, + {.start = 51, .end = 100}}; - check_nodes(&bp->root, ranges1, 2); - unmark_smap(smap, 50); - check_nodes(&bp->root, ranges, 1); - ASSERT_EQ(test_smap(smap, 50), 1); + ASSERT_TRUE(check_nodes(&bp->root, ranges1, 2)); - destory_space_map(smap); + smap->unmarkRange(50, 1); + ASSERT_TRUE(check_nodes(&bp->root, ranges, 1)); + ASSERT_EQ(smap->testRange(50, 1), 1); } -TEST(space_map_test, MarkUnmarkRange) +TEST(space_map_test, MarkUnmarkRangeRBTree) { - struct SpaceMap * smap; - - smap = (struct SpaceMap *)calloc(1, sizeof(struct SpaceMap)); - ASSERT_TRUE(smap); - ASSERT_EQ(init_space_map(smap, SMAP64_RBTREE, 0, 100, 101), 0); + RBTreeSpaceMapPtr smap = std::make_shared(0, 100); + ASSERT_EQ(smap->newSmap(), 0); - struct rb_private * bp = (struct rb_private *)smap->_private; + struct rb_private * bp = (struct rb_private *)smap->rb_tree; range ranges[] = {{.start = 0, .end = 100}}; - check_nodes(&bp->root, ranges, 1); - ASSERT_EQ(test_smap_range(smap, 1, 99), 1); - ASSERT_EQ(test_smap_range(smap, 0, 1000), -1); + ASSERT_TRUE(check_nodes(&bp->root, ranges, 1)); + ASSERT_EQ(smap->testRange(1, 99), 1); + ASSERT_EQ(smap->testRange(0, 1000), -1); - ASSERT_TRUE(mark_smap_range(smap, 50, 10)); + ASSERT_TRUE(smap->markRange(50, 10)); range ranges1[] = {{.start = 0, - .end = 49}, + .end = 50}, {.start = 60, .end = 100}}; - check_nodes(&bp->root, ranges1, 2); - ASSERT_EQ(test_smap_range(smap, 51, 5), 0); + ASSERT_TRUE(check_nodes(&bp->root, ranges1, 2)); + ASSERT_EQ(smap->testRange(51, 5), 0); - unmark_smap_range(smap, 50, 5); + smap->unmarkRange(50, 5); range ranges2[] = {{.start = 0, .end = 55}, {.start = 60, .end = 100}}; - check_nodes(&bp->root, ranges2, 2); - unmark_smap_range(smap, 55, 5); - check_nodes(&bp->root, ranges, 2); + ASSERT_TRUE(check_nodes(&bp->root, ranges2, 2)); + smap->unmarkRange(55, 5); + ASSERT_TRUE(check_nodes(&bp->root, ranges, 2)); +} + +TEST(space_map_test, MarkUnmarkRangeSTDMap) +{ + STDMapSpaceMapPtr smap = std::make_shared(0, 100); + ASSERT_EQ(smap->newSmap(), 0); + + range ranges[] = {{.start = 0, + .end = 100}}; + + ASSERT_TRUE(check_nodes(smap->map, ranges, 1)); + ASSERT_EQ(smap->testRange(1, 99), 1); + ASSERT_EQ(smap->testRange(0, 1000), -1); + + ASSERT_TRUE(smap->markRange(50, 20)); + + range ranges1[] = {{.start = 0, + .end = 50}, + {.start = 70, + .end = 100}}; + ASSERT_TRUE(check_nodes(smap->map, ranges1, 2)); + ASSERT_EQ(smap->testRange(51, 5), 0); + + smap->unmarkRange(50, 5); + range ranges2[] = {{.start = 0, + .end = 55}, + {.start = 70, + .end = 100}}; + ASSERT_TRUE(check_nodes(smap->map, ranges2, 2)); + + smap->unmarkRange(60, 5); + range ranges3[] = {{.start = 0, + .end = 55}, + {.start = 60, + .end = 65}, + {.start = 70, + .end = 100}}; + + ASSERT_TRUE(check_nodes(smap->map, ranges3, 3)); + + smap->unmarkRange(65, 5); + range ranges4[] = {{.start = 0, + .end = 55}, + {.start = 60, + .end = 100}}; + ASSERT_TRUE(check_nodes(smap->map, ranges4, 2)); + - destory_space_map(smap); + smap->unmarkRange(55, 5); + ASSERT_TRUE(check_nodes(smap->map, ranges, 2)); } -*/ } // namespace DB::PS::V3::tests \ No newline at end of file From 93ee120c187fe2da0e25879e1d906e2543dbb601 Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Mon, 6 Dec 2021 11:42:39 +0800 Subject: [PATCH 06/36] update --- dbms/src/Storages/Page/V3/spacemap/RBTree.cpp | 76 +++++++++++-------- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 4 +- .../Page/V3/spacemap/SpaceMapRBTree.cpp | 15 ---- .../Page/V3/spacemap/SpaceMapRBTree.h | 4 - .../Page/V3/spacemap/SpaceMapSTDMap.h | 35 ++++----- .../Storages/Page/V3/tests/gtest_free_map.cpp | 52 ++++++++++++- 6 files changed, 109 insertions(+), 77 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/RBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/RBTree.cpp index acbe1e77253..d0a0029cfeb 100644 --- a/dbms/src/Storages/Page/V3/spacemap/RBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/RBTree.cpp @@ -393,16 +393,19 @@ struct rb_node * rb_tree_next(struct rb_node * current) return NULL; } - // If tree looks like: - // A - // / \ - // B C - // / \ / - // D E F ... - // / \ - // G H - // Then the node is `B` , it should return `G` - // Because `G` will bigger than `B` but small than `E` + /** + * If tree looks like: + * A + * / \ + * B C + * / \ / + * D E F ... + * / \ + * G H + * + * Then the node is `B` , it should return `G` + * Because `G` will bigger than `B` but small than `E` + */ if (current->node_right) { current = current->node_right; @@ -414,10 +417,13 @@ struct rb_node * rb_tree_next(struct rb_node * current) return current; } - // In this situation, there are left-node exist. - // And all of left node is smaller than `current` node - // So the `next` node must in parent node,Then we need go up into the parent node. - // If `current` node is the right-node child of its parent, Then it still need go up for upper layer. + /** + * In this situation, there are left-node exist. + * And all of left node is smaller than `current` node + * So the `next` node must in parent node,Then we need go up into the parent node. + * If `current` node is the right-node child of its parent, Then it still need go up for upper layer. + * + */ while ((parent = node_parent(current)) && current == parent->node_right) { current = parent; @@ -436,17 +442,19 @@ struct rb_node * rb_tree_prev(struct rb_node * current) return NULL; } - // Same as `rb_tree_next` - // If tree looks like: - // A - // / \ - // B C - // \ / \ - // ... D E F - // / \ - // G H - // Then the node is `C` , it should return `H` - // Because `H` smaller than `C` but small than `E` + /** + * Same as `rb_tree_next` + * If tree looks like: + * A + * / \ + * B C + * \ / \ + * ... D E F + * / \ + * G H + * Then the node is `C` , it should return `H` + * Because `H` smaller than `C` but small than `E` + */ if (current->node_left) { current = current->node_left; @@ -457,11 +465,13 @@ struct rb_node * rb_tree_prev(struct rb_node * current) return current; } - // Same as `rb_tree_next` - // In this situation, there are left-node exist. - // And all of left node is bigger than `current` node - // So the `prev` node must in parent node,Then we need go up into the parent node. - // If `current` node is the left-node child of its parent, Then it still need go up for upper layer. + /** + * Same as `rb_tree_next` + * In this situation, there are left-node exist. + * And all of left node is bigger than `current` node + * So the `prev` node must in parent node,Then we need go up into the parent node. + * If `current` node is the left-node child of its parent, Then it still need go up for upper layer. + */ while ((parent = node_parent(current)) && current == parent->node_left) { current = parent; @@ -494,8 +504,10 @@ void rb_tree_update_node(struct rb_node * old_node, struct rb_node * new_node, s } else { - // No find parent, tree is empty - // Just update the root + /** + * No find parent, tree is empty + * Just update the root + */ root->rb_node = new_node; } diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index ff5b59b1d11..833e51749e4 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -72,9 +72,7 @@ class SpaceMap /* Generic space map operators */ virtual int newSmap() = 0; - /* The difference between clear and free is that after you clear, you can still use this spacemap. */ - virtual void clearSmap() = 0; - + /* Free the space map if necessary */ virtual void freeSmap() = 0; virtual int copySmap(SpaceMap * dest) = 0; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index 6ca472f82bd..07497a460c2 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -222,21 +222,6 @@ void RBTreeSpaceMap::freeSmap() free(rb_tree); } -void RBTreeSpaceMap::clearSmap() -{ - if (rb_tree == nullptr) - { - LOG_ERROR(log, "SpaceMap have not been inited."); - return; - } - - rb_free_tree(&rb_tree->root); - rb_tree->read_index = NULL; - rb_tree->read_index_next = NULL; - rb_tree->write_index = NULL; - rb_tree_debug(&rb_tree->root, __func__); -} - void RBTreeSpaceMap::smapStats() { struct rb_node * node = NULL; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h index 9d79a02227f..e6ea5b9d259 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h @@ -60,12 +60,8 @@ class RBTreeSpaceMap : public SpaceMap #ifndef DBMS_PUBLIC_GTEST protected: #endif - /* Generic space map operators */ int newSmap() override; - /* The difference between clear and free is that after you clear, you can still use this spacemap. */ - void clearSmap() override; - void freeSmap() override; int copySmap([[maybe_unused]] SpaceMap * dest) override diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 9ea987b7aad..3de81442f3f 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -35,15 +35,9 @@ class STDMapSpaceMap : public SpaceMap return 0; } - void clearSmap() override - { - map.clear(); - map.insert({start, end}); - } - void freeSmap() override { - clearSmap(); + // no need clear } int copySmap([[maybe_unused]] SpaceMap * dest) override @@ -146,7 +140,11 @@ class STDMapSpaceMap : public SpaceMap { auto it = map.find(block); - // already unmarked + /** + * already unmarked. + * The `block` won't be mid of free range. + * Because we alloc space from left to right. + */ if (it != map.end()) { return 0; @@ -156,22 +154,21 @@ class STDMapSpaceMap : public SpaceMap std::tie(it, meanless) = map.insert({block, num}); auto it_prev = it; - it_prev--; - if (it == map.begin()) + if (it != map.begin()) { - goto only_do_right; - } + it_prev--; - // Prev range can merge - if (it_prev->first + it_prev->second >= it->first) - { - map[it_prev->first] = it->first + it->second - it_prev->first; - map.erase(it); - it = it_prev; + // Prev range can merge + if (it_prev->first + it_prev->second >= it->first) + { + map[it_prev->first] = it->first + it->second - it_prev->first; + map.erase(it); + it = it_prev; + } } - only_do_right: + // Check right if (it == map.end()) { return 0; diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index dae0488755c..1aeae758bf2 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -54,7 +54,7 @@ bool check_nodes(std::map & map, range * ranges, size_t size) } -TEST(space_map_test, InitAndDestory) +TEST(SpaceMapTest, InitAndDestory) { SpaceMapPtr smap = SpaceMap::createSpaceMap(SpaceMap::SpaceMapType::SMAP64_RBTREE, 0, 100); @@ -62,7 +62,7 @@ TEST(space_map_test, InitAndDestory) } -TEST(space_map_test, MarkUnmarkBitRBTree) +TEST(SpaceMapTest, MarkUnmarkBitRBTree) { RBTreeSpaceMapPtr smap = std::make_shared(0, 100); ASSERT_EQ(smap->newSmap(), 0); @@ -89,7 +89,7 @@ TEST(space_map_test, MarkUnmarkBitRBTree) ASSERT_EQ(smap->testRange(50, 1), 1); } -TEST(space_map_test, MarkUnmarkRangeRBTree) +TEST(SpaceMapTest, MarkUnmarkRangeRBTree) { RBTreeSpaceMapPtr smap = std::make_shared(0, 100); ASSERT_EQ(smap->newSmap(), 0); @@ -121,7 +121,7 @@ TEST(space_map_test, MarkUnmarkRangeRBTree) ASSERT_TRUE(check_nodes(&bp->root, ranges, 2)); } -TEST(space_map_test, MarkUnmarkRangeSTDMap) +TEST(SpaceMapTest, MarkUnmarkRangeSTDMap) { STDMapSpaceMapPtr smap = std::make_shared(0, 100); ASSERT_EQ(smap->newSmap(), 0); @@ -171,4 +171,48 @@ TEST(space_map_test, MarkUnmarkRangeSTDMap) ASSERT_TRUE(check_nodes(smap->map, ranges, 2)); } +TEST(SpaceMapTest, TestMarginsRBTree) +{ + RBTreeSpaceMapPtr smap = std::make_shared(0, 100); + ASSERT_EQ(smap->newSmap(), 0); + + struct rb_private * bp = (struct rb_private *)smap->rb_tree; + + range ranges[] = {{.start = 0, + .end = 100}}; + ASSERT_TRUE(check_nodes(&bp->root, ranges, 1)); + ASSERT_TRUE(smap->markRange(50, 10)); + + range ranges1[] = {{.start = 0, + .end = 50}, + {.start = 60, + .end = 100}}; + ASSERT_TRUE(check_nodes(&bp->root, ranges1, 2)); + + ASSERT_EQ(smap->testRange(50, 5), 0); + ASSERT_EQ(smap->testRange(60, 1), 1); +} + + +TEST(SpaceMapTest, TestMarginsSTDMap) +{ + STDMapSpaceMapPtr smap = std::make_shared(0, 100); + ASSERT_EQ(smap->newSmap(), 0); + + range ranges[] = {{.start = 0, + .end = 100}}; + ASSERT_TRUE(check_nodes(smap->map, ranges, 1)); + ASSERT_TRUE(smap->markRange(50, 10)); + + range ranges1[] = {{.start = 0, + .end = 50}, + {.start = 60, + .end = 100}}; + ASSERT_TRUE(check_nodes(smap->map, ranges1, 2)); + + ASSERT_EQ(smap->testRange(50, 1), 0); + ASSERT_EQ(smap->testRange(60, 1), 1); +} + + } // namespace DB::PS::V3::tests \ No newline at end of file From 465b45f3625d0c7fb5eac4ee0b5b7d890763c0ae Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Mon, 6 Dec 2021 15:31:10 +0800 Subject: [PATCH 07/36] update --- .../Storages/Page/V3/spacemap/SpaceMap.cpp | 12 ++++ dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 58 ++++++++++++++----- .../Page/V3/spacemap/SpaceMapRBTree.h | 14 +---- .../Page/V3/spacemap/SpaceMapSTDMap.h | 4 +- .../Storages/Page/V3/tests/gtest_free_map.cpp | 23 ++++++++ 5 files changed, 84 insertions(+), 27 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index 2b9fed9b262..7b1c903092a 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -98,6 +98,18 @@ int SpaceMap::testRange(UInt64 block, size_t size) return testSmapRange(block, size); } +void SpaceMap::searchRange(size_t size, UInt64 * ret, UInt64 * max_cap) +{ + UInt64 meanless; + UInt64 shift_cap; + std::tie(meanless, size) = shiftBlock(0, size); + + searchSmapRange(size, ret, max_cap); + + std::tie(meanless, shift_cap) = shiftBlock(0, *max_cap); + *max_cap = shift_cap; +} + SpaceMap::SpaceMap(UInt64 start_, UInt64 end_, int cluster_bits) : start(start_) , end(end_) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index 833e51749e4..9a3b624e1be 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -16,9 +16,29 @@ class SpaceMap SMAP64_STD_MAP = 2 }; + /** + * Create a SpaceMapPtr. + * - type : + * - SMAP64_RBTREE : red-black tree Implementation + * - SMAP64_STD_MAP: std::map Implementation + * - start : begin of the range + * - end : end if the range + * - cluster_bits : the shift mask. + * final range will Divide 2^cluster_bits in all public api + * ex. request [offset=100,size=500] + * cluster_bits=0: [offset=100,size=500] + * cluster_bits=1: [offset=100,size=500] + * + */ static SpaceMapPtr createSpaceMap(SpaceMapType type, UInt64 start, UInt64 end, int cluster_bits = 0); /** + * Unmark a range [offset,offset + length) of the space map. + * It means this range will be marked as freed. + * After unmark this range. + * When user use `searchRange` to get a range. + * Then this range may be selected(If request size fit range size). + * * ret value : * -1: Invalid args * 0: Unmark the marked node @@ -27,6 +47,12 @@ class SpaceMap int unmarkRange(UInt64 offset, size_t length); /** + * Mark a range [offset,offset + length) of the space map. + * It means this range will be marked as used. + * After this range been marked. + * When user use `searchRange` to get a range. + * This range won't be selected. + * * ret value : * -1: Invalid args * 1: Mark success @@ -34,22 +60,26 @@ class SpaceMap int markRange(UInt64 offset, size_t length); /** + * Test a range [offset,offset + length) have been used or not. + * * ret value : * -1: Invalid args - * 0: This bit is marked - * 1: This bit is not marked + * 0: This range have been marked, or some sub range have been marked + * 1: This range have not been marked, all of range is free for use. */ int testRange(UInt64 offset, size_t length); /** - * Search range, return the free bits + * Search an range that can fit in `size` + * SpaceMap will loop the range from start. + * After it found a range which can fit this `size`. + * It will decide if there needs to keep traverse for find `max_cap`. + * + * return val: + * ret : offset of the range + * max_cap : Current SpaceMap can hold the largest size */ - void searchRange(UInt64 start, UInt64 end, size_t size, UInt64 * ret); - - /** - * Clear all ranges - */ - void clear(); + void searchRange(size_t size, UInt64 * ret, UInt64 * max_cap); /** * Log the status of space map @@ -85,14 +115,13 @@ class SpaceMap /* Space map bit/bits test operators */ virtual int testSmapRange(UInt64 offset, size_t size) = 0; - /* Search range, return the free bits */ - virtual void searchSmapRange(UInt64 start, UInt64 end, size_t size, UInt64 * ret) = 0; - /* Space map range set/unset operators */ virtual int markSmapRange(UInt64 offset, size_t size) = 0; virtual int unmarkSmapRange(UInt64 offset, size_t size) = 0; + virtual void searchSmapRange(size_t size, UInt64 * ret, UInt64 * max_cap) = 0; + private: /* shift block to the right range */ std::pair shiftBlock(UInt64 offset, size_t num); @@ -109,8 +138,9 @@ class SpaceMap #endif SpaceMapType type = SpaceMapType::SMAP64_INVALID; - /* [left - right] range */ - UInt64 start, end; + /* The offset range managed by this SpaceMap. The range is [left, right). */ + UInt64 start; + UInt64 end; Poco::Logger * log; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h index e6ea5b9d259..3482dffc1dc 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h @@ -33,15 +33,7 @@ struct rb_private // convert rb_node to smap_rb_entry inline static struct smap_rb_entry * node_to_entry(struct rb_node * node) { - struct smap_rb_entry * rb_ex; -#define container_of(ptr, type, member) ({ \ - const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) ); }) - - rb_ex = container_of(node, struct smap_rb_entry, node); - -#undef container_of - return rb_ex; + return reinterpret_cast(node); } class RBTreeSpaceMap : public SpaceMap @@ -81,9 +73,9 @@ class RBTreeSpaceMap : public SpaceMap int testSmapRange(UInt64 block, size_t num) override; /* Search range , return the free bits */ - void searchSmapRange([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] size_t num, [[maybe_unused]] UInt64 * ret) override + void searchSmapRange([[maybe_unused]] size_t size, [[maybe_unused]] UInt64 * ret, [[maybe_unused]] UInt64 * max_cap) override { - // TBD + // Will implement in BlobStore } int markSmapRange(UInt64 block, size_t num) override; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 3de81442f3f..4c324610b02 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -82,9 +82,9 @@ class STDMapSpaceMap : public SpaceMap return 0; } - void searchSmapRange([[maybe_unused]] UInt64 start, [[maybe_unused]] UInt64 end, [[maybe_unused]] size_t num, [[maybe_unused]] UInt64 * ret) override + void searchSmapRange([[maybe_unused]] size_t size, [[maybe_unused]] UInt64 * ret, [[maybe_unused]] UInt64 * max_cap) override { - // TBD + // Will implement in BlobStore } int markSmapRange(UInt64 block, size_t num) override diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index 1aeae758bf2..06e9d2a27bd 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -215,4 +215,27 @@ TEST(SpaceMapTest, TestMarginsSTDMap) } +std::pair shiftBlock(UInt64 block, size_t size) +{ + UInt64 cluster_bits = 1; + UInt64 block_end = block + size; + + block >>= cluster_bits; + block_end += (1 << cluster_bits) - 1; + block_end >>= cluster_bits; + size = block_end - block; + return std::make_pair(block, size); +} + + +TEST(SpaceMapTest, null) +{ + UInt64 b = 0; + size_t s = 0; + + std::tie(b, s) = shiftBlock(100, 500); + + std::cout << "b : " << b << " , s : " << s << std::endl; +} + } // namespace DB::PS::V3::tests \ No newline at end of file From 188643547fb532d81f87d9fca88315612f09bf6f Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Mon, 6 Dec 2021 15:34:58 +0800 Subject: [PATCH 08/36] update --- .../Storages/Page/V3/tests/gtest_free_map.cpp | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index 06e9d2a27bd..ddb042dffab 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -214,28 +214,4 @@ TEST(SpaceMapTest, TestMarginsSTDMap) ASSERT_EQ(smap->testRange(60, 1), 1); } - -std::pair shiftBlock(UInt64 block, size_t size) -{ - UInt64 cluster_bits = 1; - UInt64 block_end = block + size; - - block >>= cluster_bits; - block_end += (1 << cluster_bits) - 1; - block_end >>= cluster_bits; - size = block_end - block; - return std::make_pair(block, size); -} - - -TEST(SpaceMapTest, null) -{ - UInt64 b = 0; - size_t s = 0; - - std::tie(b, s) = shiftBlock(100, 500); - - std::cout << "b : " << b << " , s : " << s << std::endl; -} - } // namespace DB::PS::V3::tests \ No newline at end of file From fe044444c64cd24ed5aef480155769577f28e076 Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Mon, 6 Dec 2021 15:37:10 +0800 Subject: [PATCH 09/36] update search cluster --- dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index 7b1c903092a..1e83fcaa2c0 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -105,9 +105,7 @@ void SpaceMap::searchRange(size_t size, UInt64 * ret, UInt64 * max_cap) std::tie(meanless, size) = shiftBlock(0, size); searchSmapRange(size, ret, max_cap); - - std::tie(meanless, shift_cap) = shiftBlock(0, *max_cap); - *max_cap = shift_cap; + *max_cap = *max_cap * (2 ^ cluster_bits); } SpaceMap::SpaceMap(UInt64 start_, UInt64 end_, int cluster_bits) From 353130caafabefad01ec495110b833d60ccf92f8 Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Mon, 6 Dec 2021 15:43:32 +0800 Subject: [PATCH 10/36] usless --- dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index 1e83fcaa2c0..2a04ffbe1b2 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -101,7 +101,6 @@ int SpaceMap::testRange(UInt64 block, size_t size) void SpaceMap::searchRange(size_t size, UInt64 * ret, UInt64 * max_cap) { UInt64 meanless; - UInt64 shift_cap; std::tie(meanless, size) = shiftBlock(0, size); searchSmapRange(size, ret, max_cap); From 9ac75e292abbb08dca921d5f7cdcd2559343d74b Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Mon, 6 Dec 2021 20:09:05 +0800 Subject: [PATCH 11/36] update --- .../Storages/Page/V3/spacemap/SpaceMap.cpp | 87 +++---- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 122 +++++----- .../Page/V3/spacemap/SpaceMapRBTree.cpp | 182 +++++++++++---- .../Page/V3/spacemap/SpaceMapRBTree.h | 34 +-- .../Page/V3/spacemap/SpaceMapSTDMap.h | 214 ++++++++++++------ .../Storages/Page/V3/tests/gtest_free_map.cpp | 142 +++++++----- 6 files changed, 475 insertions(+), 306 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index 2a04ffbe1b2..33702a292ea 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -1,6 +1,7 @@ #include "SpaceMap.h" #include +#include #include #include #include @@ -9,25 +10,31 @@ #include "SpaceMapRBTree.h" #include "SpaceMapSTDMap.h" -namespace DB::PS::V3 +namespace DB { -SpaceMapPtr SpaceMap::createSpaceMap(SpaceMapType type, UInt64 start, UInt64 end, int cluster_bits) +namespace ErrorCodes +{ +extern const int LOGICAL_ERROR; +} // namespace ErrorCodes + +namespace PS::V3 +{ +SpaceMapPtr SpaceMap::createSpaceMap(SpaceMapType type, UInt64 start, UInt64 end) { SpaceMapPtr smap; switch (type) { case SMAP64_RBTREE: - smap = std::make_shared(start, end, cluster_bits); + smap = std::make_shared(start, end); break; case SMAP64_STD_MAP: - smap = std::make_shared(start, end, cluster_bits); + smap = std::make_shared(start, end); break; default: return nullptr; } - int rc = smap->newSmap(); - if (rc != 0) + if (!smap->newSmap()) { smap->freeSmap(); return nullptr; @@ -36,19 +43,7 @@ SpaceMapPtr SpaceMap::createSpaceMap(SpaceMapType type, UInt64 start, UInt64 end return smap; } -std::pair SpaceMap::shiftBlock(UInt64 block, size_t size) -{ - UInt64 block_end = block + size; - - block >>= cluster_bits; - block_end += (1 << cluster_bits) - 1; - block_end >>= cluster_bits; - size = block_end - block; - return std::make_pair(block, size); -} - - -bool SpaceMap::checkRange(UInt64 block, size_t size) +bool SpaceMap::checkSpace(UInt64 block, size_t size) { return (block < start) || (block > end) || (block + size - 1 > end); } @@ -58,61 +53,53 @@ void SpaceMap::logStats() smapStats(); } - -int SpaceMap::unmarkRange(UInt64 block, size_t size) +bool SpaceMap::markFree(UInt64 offset, size_t length) { - std::tie(block, size) = shiftBlock(block, size); - - if (checkRange(block, size)) + if (checkSpace(offset, length)) { - LOG_ERROR(log, "unMark range out of the limit range.[type=" << type << "] [block=" << block << "], [size = " << size << "]"); - return -1; + throw Exception("Unmark space out of the limit space.[type=" + typeToString(getType()) + + "] [block=" + DB::toString(offset) + "], [size = " + DB::toString(length) + "]", + ErrorCodes::LOGICAL_ERROR); } - return unmarkSmapRange(block, size); + return markSmapFree(offset, length); } -int SpaceMap::markRange(UInt64 block, size_t size) +bool SpaceMap::markUsed(UInt64 offset, size_t length) { - std::tie(block, size) = shiftBlock(block, size); - - if (checkRange(block, size)) + if (checkSpace(offset, length)) { - LOG_ERROR(log, "Mark range out of the limit range.[type=" << type << "] [block=" << block << "], [size = " << size << "]"); - return -1; + throw Exception("Mark space out of the limit space.[type=" + typeToString(getType()) + + "] [block=" + DB::toString(offset) + "], [size = " + DB::toString(length) + "]", + ErrorCodes::LOGICAL_ERROR); } - return markSmapRange(block, size); + return markSmapUsed(offset, length); } -int SpaceMap::testRange(UInt64 block, size_t size) +bool SpaceMap::isMarkUsed(UInt64 offset, size_t length) { - std::tie(block, size) = shiftBlock(block, size); - - if (checkRange(block, size)) + if (checkSpace(offset, length)) { - LOG_ERROR(log, "Test range out of the limit range.[type=" << type << "] [block=" << block << "], [size = " << size << "]"); - return -1; + throw Exception("Test space out of the limit space.[type=" + typeToString(getType()) + + "] [block=" + DB::toString(offset) + "], [size = " + DB::toString(length) + "]", + ErrorCodes::LOGICAL_ERROR); } - return testSmapRange(block, size); + return isSmapMarkUsed(offset, length); } -void SpaceMap::searchRange(size_t size, UInt64 * ret, UInt64 * max_cap) +std::pair SpaceMap::searchInsertOffset(size_t size) { - UInt64 meanless; - std::tie(meanless, size) = shiftBlock(0, size); - - searchSmapRange(size, ret, max_cap); - *max_cap = *max_cap * (2 ^ cluster_bits); + return searchSmapInsertOffset(size); } -SpaceMap::SpaceMap(UInt64 start_, UInt64 end_, int cluster_bits) +SpaceMap::SpaceMap(UInt64 start_, UInt64 end_) : start(start_) , end(end_) , log(&Poco::Logger::get("RBTreeSpaceMap")) - , cluster_bits(cluster_bits) { } -} // namespace DB::PS::V3 +} // namespace PS::V3 +} // namespace DB diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index 9a3b624e1be..3d5afadd4f0 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -17,69 +17,59 @@ class SpaceMap }; /** - * Create a SpaceMapPtr. + * Create a SpaceMap that manages space address [start, end). * - type : - * - SMAP64_RBTREE : red-black tree Implementation - * - SMAP64_STD_MAP: std::map Implementation - * - start : begin of the range - * - end : end if the range - * - cluster_bits : the shift mask. - * final range will Divide 2^cluster_bits in all public api - * ex. request [offset=100,size=500] - * cluster_bits=0: [offset=100,size=500] - * cluster_bits=1: [offset=100,size=500] - * + * - SMAP64_RBTREE : red-black tree implementation + * - SMAP64_STD_MAP: std::map implementation + * - start : begin of the space + * - end : end if the space */ - static SpaceMapPtr createSpaceMap(SpaceMapType type, UInt64 start, UInt64 end, int cluster_bits = 0); + static SpaceMapPtr createSpaceMap(SpaceMapType type, UInt64 start, UInt64 end); /** - * Unmark a range [offset,offset + length) of the space map. - * It means this range will be marked as freed. - * After unmark this range. - * When user use `searchRange` to get a range. - * Then this range may be selected(If request size fit range size). + * Mark a space [offset,offset + length) free of the space map. + * After mark this space freed. + * When user use `searchInsertOffset` to get a space. + * Then this space may been selected(If request size fit space size + * and it is the first freed space). * - * ret value : - * -1: Invalid args - * 0: Unmark the marked node - * 1: Unmark the unmarked node + * ret value: + * true: mark the space which is used. + * false: mark the space which is freed. */ - int unmarkRange(UInt64 offset, size_t length); + bool markFree(UInt64 offset, size_t length); /** - * Mark a range [offset,offset + length) of the space map. - * It means this range will be marked as used. - * After this range been marked. - * When user use `searchRange` to get a range. - * This range won't be selected. - * - * ret value : - * -1: Invalid args - * 1: Mark success + * Mark a space [offset,offset + length) of the space map. + * After this space been marked. + * When user use `searchInsertOffset` to get a space. + * This space won't be selected. + * ret value: + * false: This space is freed, marked all space used. + * true: This space is used, or some sub space is used. */ - int markRange(UInt64 offset, size_t length); + bool markUsed(UInt64 offset, size_t length); /** - * Test a range [offset,offset + length) have been used or not. + * Test a space [offset,offset + length) have been used or not. * - * ret value : - * -1: Invalid args - * 0: This range have been marked, or some sub range have been marked - * 1: This range have not been marked, all of range is free for use. + * ret value: + * true: This space is used, or some sub space is used + * false: This space is freed, all of space is freed for use. */ - int testRange(UInt64 offset, size_t length); + bool isMarkUsed(UInt64 offset, size_t length); /** - * Search an range that can fit in `size` + * Search a space that can fit in `size` * SpaceMap will loop the range from start. * After it found a range which can fit this `size`. - * It will decide if there needs to keep traverse for find `max_cap`. + * It will decide if there needs to keep traverse to update `max_cap`. * - * return val: - * ret : offset of the range - * max_cap : Current SpaceMap can hold the largest size + * Return value is : + * insert_offset : start offset for the inserted space + * max_cap : The largest available space this SpaceMap can hold. */ - void searchRange(size_t size, UInt64 * ret, UInt64 * max_cap); + std::pair searchInsertOffset(size_t size); /** * Log the status of space map @@ -91,46 +81,50 @@ class SpaceMap return type; } + String typeToString(SpaceMapType type) + { + switch (type) + { + case SMAP64_RBTREE: + return "RB-Tree"; + case SMAP64_STD_MAP: + return "STD Map"; + default: + return "Invalid"; + } + } + #ifndef DBMS_PUBLIC_GTEST protected: #endif - SpaceMap(UInt64 start, UInt64 end, int cluster_bits = 0); + SpaceMap(UInt64 start, UInt64 end); virtual ~SpaceMap(){}; /* Generic space map operators */ - virtual int newSmap() = 0; + virtual bool newSmap() = 0; /* Free the space map if necessary */ virtual void freeSmap() = 0; - virtual int copySmap(SpaceMap * dest) = 0; - - virtual int resizeSmap(UInt64 new_end, UInt64 new_real_end) = 0; - /* Print space maps status */ virtual void smapStats() = 0; /* Space map bit/bits test operators */ - virtual int testSmapRange(UInt64 offset, size_t size) = 0; + virtual bool isSmapMarkUsed(UInt64 offset, size_t size) = 0; - /* Space map range set/unset operators */ - virtual int markSmapRange(UInt64 offset, size_t size) = 0; + /* Space map mark used/free operators */ + virtual bool markSmapUsed(UInt64 offset, size_t size) = 0; - virtual int unmarkSmapRange(UInt64 offset, size_t size) = 0; + virtual bool markSmapFree(UInt64 offset, size_t size) = 0; - virtual void searchSmapRange(size_t size, UInt64 * ret, UInt64 * max_cap) = 0; + virtual std::pair searchSmapInsertOffset(size_t size) = 0; private: - /* shift block to the right range */ - std::pair shiftBlock(UInt64 offset, size_t num); - /* Check the range */ - bool checkRange(UInt64 offset, size_t num); + bool checkSpace(UInt64 offset, size_t num); - /* Check Space Map have been inited or not*/ - bool checkInited(); #ifndef DBMS_PUBLIC_GTEST protected: #else @@ -143,12 +137,6 @@ class SpaceMap UInt64 end; Poco::Logger * log; - -private: - /* shift */ - int cluster_bits; - - char * description; }; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index 07497a460c2..e78b9339112 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -3,8 +3,8 @@ namespace DB::PS::V3 { -static int rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data); -static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data); +static bool rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data); +static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data); static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, @@ -31,7 +31,7 @@ static void rb_tree_debug(struct rb_root * root, const char * method_call) for (node = rb_tree_first(root); node != NULL; node = rb_tree_next(node)) { entry = node_to_entry(node); - printf(" range - (%llu -> %llu)\n", entry->start, entry->start + entry->count); + printf(" Space - (%llu -> %llu)\n", entry->start, entry->start + entry->count); } } @@ -81,19 +81,19 @@ inline static void rb_free_entry(struct rb_private * private_data, struct smap_r free(entry); } -static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data) +static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data) { struct rb_root * root = &private_data->root; struct rb_node *parent = NULL, **n = &root->rb_node; struct rb_node * node; struct smap_rb_entry * entry; UInt64 new_start, new_count; - int retval = 0; + bool marked = false; // Root node have not been init if (private_data->root.rb_node == NULL) { - return 0; + assert(false); } while (*n) @@ -120,13 +120,13 @@ static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * priva entry->count = start - entry->start; rb_insert_entry(new_start, new_count, private_data); - return 1; + return true; } if ((start + count) >= (entry->start + entry->count)) { entry->count = start - entry->start; - retval = 1; + marked = true; } if (0 == entry->count) @@ -141,11 +141,11 @@ static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * priva { entry->start += count; entry->count -= count; - return 1; + return true; } } - // Check the right node + // Checking the right node for (; parent != NULL; parent = node) { node = rb_tree_next(parent); @@ -157,32 +157,36 @@ static int rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * priva break; // Merge the nearby node - // TBD : If there are a small range inside two range, Then it should be ignored if ((start + count) >= (entry->start + entry->count)) { rb_node_remove(parent, root); rb_free_entry(private_data, entry); - retval = 1; + marked = true; continue; } else { + if (((start + count) - entry->start) == 0 + && (start + count == entry->start)) + { + break; + } entry->count -= ((start + count) - entry->start); entry->start = start + count; - retval = 1; + marked = true; break; } } - return retval; + return marked; } -int RBTreeSpaceMap::newSmap() +bool RBTreeSpaceMap::newSmap() { rb_tree = (struct rb_private *)calloc(1, sizeof(struct rb_private)); if (rb_tree == NULL) { - return -1; + return false; } rb_tree->root = { @@ -194,12 +198,12 @@ int RBTreeSpaceMap::newSmap() if (rb_insert_entry(start, end, rb_tree) != 0) { - LOG_ERROR(log, "Erorr happend, when mark all range to free. [start=" << start << "] , [end = " << end << "]"); + LOG_ERROR(log, "Erorr happend, when mark all space free. [start=" << start << "] , [end = " << end << "]"); free(rb_tree); - return -1; + return false; } - return 0; + return true; } static void rb_free_tree(struct rb_root * root) @@ -218,8 +222,11 @@ static void rb_free_tree(struct rb_root * root) void RBTreeSpaceMap::freeSmap() { - rb_free_tree(&rb_tree->root); - free(rb_tree); + if (rb_tree) + { + rb_free_tree(&rb_tree->root); + free(rb_tree); + } } void RBTreeSpaceMap::smapStats() @@ -240,7 +247,7 @@ void RBTreeSpaceMap::smapStats() for (node = rb_tree_first(&rb_tree->root); node != NULL; node = rb_tree_next(node)) { entry = node_to_entry(node); - LOG_DEBUG(log, " range : " << count << " start:" << entry->start << " size : " << entry->count); + LOG_DEBUG(log, " Space : " << count << " start:" << entry->start << " size : " << entry->count); count++; if (entry->count > max_size) { @@ -254,23 +261,22 @@ void RBTreeSpaceMap::smapStats() } } -int RBTreeSpaceMap::testSmapRange(UInt64 _start, - size_t len) +bool RBTreeSpaceMap::isSmapMarkUsed(UInt64 _start, + size_t len) { struct rb_node *parent = NULL, **n; struct rb_node *node, *next; struct smap_rb_entry * entry; - int retval = 0; + bool retval = false; n = &rb_tree->root.rb_node; _start -= start; if (len == 0 || rb_tree->root.rb_node == NULL) { - return -1; + assert(0); } - while (*n) { parent = *n; @@ -287,7 +293,7 @@ int RBTreeSpaceMap::testSmapRange(UInt64 _start, { // the tree -> entry is not clear // so just return - return 1; + return true; } } @@ -305,20 +311,20 @@ int RBTreeSpaceMap::testSmapRange(UInt64 _start, if ((_start + len) <= entry->start) break; - retval = 1; + retval = true; break; } return retval; } -static int rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data) +static bool rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data) { struct rb_root * root = &private_data->root; struct rb_node *parent = NULL, **n = &root->rb_node; struct rb_node *new_node, *node, *next; struct smap_rb_entry * new_entry; struct smap_rb_entry * entry; - int retval = 0; + bool retval = false; if (count == 0) { @@ -354,17 +360,17 @@ static int rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * priva got_entry: if ((start + count) <= (entry->start + entry->count)) { - retval = 1; + retval = true; return retval; } if ((entry->start + entry->count) == start) { - retval = 0; + retval = false; } else { - retval = 1; + retval = true; } count += (start - entry->start); @@ -408,9 +414,7 @@ static int rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * priva continue; } - // not match - // TBD : same as comment in remove if ((start + count) < entry->start) break; @@ -423,7 +427,6 @@ static int rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * priva else { // merge entry - // TBD : same as comment in remove count += ((entry->start + entry->count) - (start + count)); rb_node_remove(node, root); rb_free_entry(private_data, entry); @@ -437,9 +440,106 @@ static int rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * priva return retval; } -int RBTreeSpaceMap::markSmapRange(UInt64 block, size_t size) +std::pair RBTreeSpaceMap::searchSmapInsertOffset(size_t size) +{ + UInt64 offset = UINT64_MAX; + UInt64 max_cap = 0; + struct rb_node * node = NULL; + struct smap_rb_entry * entry; + + UInt64 _biggest_cap = 0; + UInt64 _biggest_range = 0; + for (node = rb_tree_first(&rb_tree->root); node != NULL; node = rb_tree_next(node)) + { + entry = node_to_entry(node); + if (entry->count >= size) + { + break; + } + else + { + if (entry->count > _biggest_cap) + { + _biggest_cap = entry->count; + _biggest_range = entry->start; + } + } + } + + // not place found. + if (!node) + { + LOG_ERROR(log, "Not sure why can't found any place to insert. [old biggest_range= " << biggest_range << "] [old biggest_cap=" << biggest_cap << "] [new biggest_range=" << _biggest_range << "] [new biggest_cap=" << _biggest_cap << "]"); + biggest_range = _biggest_range; + biggest_cap = _biggest_cap; + + return std::make_pair(offset, max_cap); + } + + // Update return start + offset = entry->start; + + if (entry->count == size) + { + // It is champion, need update + if (entry->start == biggest_range) + { + struct rb_node * old_node = node; + node = rb_tree_next(node); + rb_node_remove(old_node, &rb_tree->root); + rb_free_entry(rb_tree, entry); + // still need update max_cap + } + else // It not champion, just return + { + rb_node_remove(node, &rb_tree->root); + rb_free_entry(rb_tree, entry); + max_cap = biggest_cap; + return std::make_pair(offset, max_cap); + } + } + else // must be entry->count > size + { + // Resize this node, no need update + entry->start += size; + entry->count -= size; + + // It is champion, need update + if (entry->start - size == biggest_range) + { + if (entry->count > _biggest_cap) + { + _biggest_cap = entry->count; + _biggest_range = entry->start; + } + node = rb_tree_next(node); + // still need update max_cap + } + else // It not champion, just return + { + max_cap = biggest_cap; + return std::make_pair(offset, max_cap); + } + } + + for (; node != NULL; node = rb_tree_next(node)) + { + entry = node_to_entry(node); + if (entry->count > _biggest_cap) + { + _biggest_cap = entry->count; + _biggest_range = entry->start; + } + } + biggest_range = _biggest_range; + biggest_cap = _biggest_cap; + max_cap = biggest_cap; + return std::make_pair(offset, max_cap); +} + +bool RBTreeSpaceMap::markSmapUsed(UInt64 block, size_t size) { - int rc; + bool rc; block -= start; @@ -448,9 +548,9 @@ int RBTreeSpaceMap::markSmapRange(UInt64 block, size_t size) return rc; } -int RBTreeSpaceMap::unmarkSmapRange(UInt64 block, size_t size) +bool RBTreeSpaceMap::markSmapFree(UInt64 block, size_t size) { - int rc; + bool rc; block -= start; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h index 3482dffc1dc..f0404c59baf 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h @@ -39,8 +39,8 @@ inline static struct smap_rb_entry * node_to_entry(struct rb_node * node) class RBTreeSpaceMap : public SpaceMap { public: - RBTreeSpaceMap(UInt64 start, UInt64 end, int cluster_bits = 0) - : SpaceMap(start, end, cluster_bits) + RBTreeSpaceMap(UInt64 start, UInt64 end) + : SpaceMap(start, end) { type = SMAP64_RBTREE; }; @@ -49,43 +49,31 @@ class RBTreeSpaceMap : public SpaceMap { freeSmap(); }; + #ifndef DBMS_PUBLIC_GTEST protected: #endif - int newSmap() override; - - void freeSmap() override; - int copySmap([[maybe_unused]] SpaceMap * dest) override - { - throw Exception("Unimplement here. After need use, then implement it.", ErrorCodes::NOT_IMPLEMENTED); - } + bool newSmap() override; - int resizeSmap([[maybe_unused]] UInt64 new_end, [[maybe_unused]] UInt64 new_real_end) override - { - throw Exception("NOT_IMPLEMENTED. After need use, then implement it.", ErrorCodes::NOT_IMPLEMENTED); - } + void freeSmap() override; - /* Print space maps status */ void smapStats() override; - /* Space map bit/bits test operators */ - int testSmapRange(UInt64 block, size_t num) override; + bool isSmapMarkUsed(UInt64 block, size_t num) override; - /* Search range , return the free bits */ - void searchSmapRange([[maybe_unused]] size_t size, [[maybe_unused]] UInt64 * ret, [[maybe_unused]] UInt64 * max_cap) override - { - // Will implement in BlobStore - } + bool markSmapUsed(UInt64 block, size_t num) override; - int markSmapRange(UInt64 block, size_t num) override; + bool markSmapFree(UInt64 block, size_t num) override; - int unmarkSmapRange(UInt64 block, size_t num) override; + std::pair searchSmapInsertOffset(size_t size) override; #ifndef DBMS_PUBLIC_GTEST private: #endif struct rb_private * rb_tree; + UInt64 biggest_range = 0; + UInt64 biggest_cap = 0; }; using RBTreeSpaceMapPtr = std::shared_ptr; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 4c324610b02..38348b34a61 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -17,8 +17,8 @@ namespace PS::V3 class STDMapSpaceMap : public SpaceMap { public: - STDMapSpaceMap(UInt64 start, UInt64 end, int cluster_bits = 0) - : SpaceMap(start, end, cluster_bits) + STDMapSpaceMap(UInt64 start, UInt64 end) + : SpaceMap(start, end) { type = SMAP64_STD_MAP; }; @@ -26,13 +26,14 @@ class STDMapSpaceMap : public SpaceMap ~STDMapSpaceMap() override{ }; + #ifndef DBMS_PUBLIC_GTEST protected: #endif - int newSmap() override + bool newSmap() override { - map.insert({start, end}); - return 0; + free_map.insert({start, end}); + return true; } void freeSmap() override @@ -40,36 +41,26 @@ class STDMapSpaceMap : public SpaceMap // no need clear } - int copySmap([[maybe_unused]] SpaceMap * dest) override - { - throw Exception("Unimplement here. After need use, then implement it.", ErrorCodes::NOT_IMPLEMENTED); - } - - int resizeSmap([[maybe_unused]] UInt64 new_end, [[maybe_unused]] UInt64 new_real_end) override - { - throw Exception("Unimplement here. After need use, then implement it.", ErrorCodes::NOT_IMPLEMENTED); - } - void smapStats() override { UInt64 count = 0; LOG_DEBUG(log, "entry status :"); - for (auto it = map.begin(); it != map.end(); it++) + for (auto it = free_map.begin(); it != free_map.end(); it++) { - LOG_DEBUG(log, " range : " << count << " start:" << it->first << " size : " << it->second); + LOG_DEBUG(log, " Space : " << count << " start:" << it->first << " size : " << it->second); count++; } } - int testSmapRange(UInt64 block, size_t num) override + bool isSmapMarkUsed(UInt64 block, size_t num) override { - for (auto it = map.begin(); it != map.end(); it++) + for (auto it = free_map.begin(); it != free_map.end(); it++) { - // block in the range + // block in the space if (it->first <= block && (it->first + it->second) > block) { - // end of block still in the range + // end of block still in the space return (it->first + it->second) >= (num + block); } @@ -79,117 +70,208 @@ class STDMapSpaceMap : public SpaceMap } } - return 0; + return false; } - void searchSmapRange([[maybe_unused]] size_t size, [[maybe_unused]] UInt64 * ret, [[maybe_unused]] UInt64 * max_cap) override + bool markSmapUsed(UInt64 block, size_t num) override { - // Will implement in BlobStore - } - - int markSmapRange(UInt64 block, size_t num) override - { - auto it = map.find(block); - if (it == map.end()) + auto it = free_map.find(block); + if (it == free_map.end()) { // can't found , check the near one. - for (it = map.begin(); it != map.end(); it++) + for (it = free_map.begin(); it != free_map.end(); it++) { - // In the range, jump to range. + // In the space, jump to space. if (it->first <= block && (it->first + it->second) > block) { - goto found_range; + break; } - // Counld not found, break. + // Could not found if (it->first > block) { - break; + return false; } } } + + // match + if (it->first == block) + { + free_map.erase(it); + + // in the space + } else { - found_range: - // match - if (it->first == block) + // In the mid, and not match the left or right. + // Split to two space + if (((it->first + it->second) - block) > num) { - map.erase(it); + free_map.insert({block + num, it->first + it->second - block - num}); + free_map[it->first] = block - it->first; + } + else + { // < num + free_map[it->first] = it->first + it->second - block; + } + } + + return true; + } + + std::pair searchSmapInsertOffset(size_t size) override + { + UInt64 offset = UINT64_MAX; + UInt64 max_cap = 0; + UInt64 _biggest_cap = 0; + UInt64 _biggest_range = 0; - // in the range + auto it = free_map.begin(); + for (; it != free_map.end(); it++) + { + if (it->second >= size) + { + break; } else { - // In the mid, and not match the left or right. - // Split to two range - if (((it->first + it->second) - block) > num) + if (it->second > _biggest_cap) { - map.insert({block + num, it->first + it->second - block - num}); - map[it->first] = block - it->first; + _biggest_cap = it->second; + _biggest_range = it->first; } - else - { // < num - map[it->first] = it->first + it->second - block; + } + } + + // not place found. + if (it == free_map.end()) + { + LOG_ERROR(log, "Not sure why can't found any place to insert.[old biggest_range= " << biggest_range << "] [old biggest_cap=" << biggest_cap << "] [new biggest_range=" << _biggest_range << "] [new biggest_cap=" << _biggest_cap << "]"); + biggest_range = _biggest_range; + biggest_cap = _biggest_cap; + + return std::make_pair(offset, max_cap); + } + + // Update return start + offset = it->first; + + if (it->second == size) + { + // It is champion, need update + if (it->first == biggest_range) + { + auto it_cur = it++; + free_map.erase(it_cur); + // still need search for max_cap + } + else // It not champion, just return + { + free_map.erase(it); + max_cap = biggest_cap; + return std::make_pair(offset, max_cap); + } + } + else + { + auto k = it->first + size; + auto v = it->second - size; + + free_map.erase(it); + free_map.insert({k, v}); + + // It is champion, need update + if (k - size == biggest_range) + { + if (v > _biggest_cap) + { + _biggest_cap = v; + _biggest_range = k; } + it = free_map.find(k); + // still need search for max_cap + } + else // It not champion, just return + { + max_cap = biggest_cap; + return std::make_pair(offset, max_cap); } } - return 1; + + for (; it != free_map.end(); it++) + { + if (it->second > _biggest_cap) + { + _biggest_cap = it->second; + _biggest_range = it->first; + } + } + biggest_range = _biggest_range; + biggest_cap = _biggest_cap; + max_cap = biggest_cap; + + return std::make_pair(offset, max_cap); } - int unmarkSmapRange(UInt64 block, size_t num) override + bool markSmapFree(UInt64 block, size_t num) override { - auto it = map.find(block); + auto it = free_map.find(block); /** * already unmarked. - * The `block` won't be mid of free range. + * The `block` won't be mid of free space. * Because we alloc space from left to right. */ - if (it != map.end()) + if (it != free_map.end()) { - return 0; + return true; } bool meanless = false; - std::tie(it, meanless) = map.insert({block, num}); + std::tie(it, meanless) = free_map.insert({block, num}); auto it_prev = it; - if (it != map.begin()) + if (it != free_map.begin()) { it_prev--; - // Prev range can merge + // Prev space can merge if (it_prev->first + it_prev->second >= it->first) { - map[it_prev->first] = it->first + it->second - it_prev->first; - map.erase(it); + free_map[it_prev->first] = it->first + it->second - it_prev->first; + free_map.erase(it); it = it_prev; } } // Check right - if (it == map.end()) + if (it == free_map.end()) { - return 0; + return false; } auto it_next = it; it_next++; - // next range can merge + // next space can merge if (it->first + it->second >= it_next->first) { - map[it->first] = it_next->first + it_next->second - it->first; - map.erase(it_next); + free_map[it->first] = it_next->first + it_next->second - it->first; + free_map.erase(it_next); } - return 0; + return false; } #ifndef DBMS_PUBLIC_GTEST private: #endif - std::map map; + + // Save the of free blocks + std::map free_map; + UInt64 biggest_range = 0; + UInt64 biggest_cap = 0; }; using STDMapSpaceMapPtr = std::shared_ptr; diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index ddb042dffab..ed835d2f8c5 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -9,13 +9,13 @@ namespace DB::PS::V3::tests { -struct range +struct Range { size_t start; size_t end; }; -bool check_nodes(struct rb_root * root, range * ranges, size_t size) +bool check_nodes(struct rb_root * root, Range * ranges, size_t size) { struct rb_node * node = NULL; struct smap_rb_entry * ext; @@ -36,7 +36,7 @@ bool check_nodes(struct rb_root * root, range * ranges, size_t size) return true; } -bool check_nodes(std::map & map, range * ranges, size_t size) +bool check_nodes(std::map & map, Range * ranges, size_t size) { assert(size != 0); @@ -65,153 +65,177 @@ TEST(SpaceMapTest, InitAndDestory) TEST(SpaceMapTest, MarkUnmarkBitRBTree) { RBTreeSpaceMapPtr smap = std::make_shared(0, 100); - ASSERT_EQ(smap->newSmap(), 0); + ASSERT_TRUE(smap->newSmap()); struct rb_private * bp = (struct rb_private *)smap->rb_tree; - range ranges[] = {{.start = 0, + Range ranges[] = {{.start = 0, .end = 100}}; ASSERT_TRUE(check_nodes(&bp->root, ranges, 1)); - ASSERT_TRUE(smap->markRange(50, 1)); - ASSERT_EQ(smap->testRange(50, 1), 0); - ASSERT_EQ(smap->testRange(51, 1), 1); + ASSERT_TRUE(smap->markUsed(50, 1)); + ASSERT_FALSE(smap->markUsed(50, 1)); - range ranges1[] = {{.start = 0, + ASSERT_FALSE(smap->isMarkUsed(50, 1)); + ASSERT_TRUE(smap->isMarkUsed(51, 1)); + + Range ranges1[] = {{.start = 0, .end = 50}, {.start = 51, .end = 100}}; ASSERT_TRUE(check_nodes(&bp->root, ranges1, 2)); - smap->unmarkRange(50, 1); + smap->markFree(50, 1); ASSERT_TRUE(check_nodes(&bp->root, ranges, 1)); - ASSERT_EQ(smap->testRange(50, 1), 1); + ASSERT_TRUE(smap->isMarkUsed(50, 1)); } -TEST(SpaceMapTest, MarkUnmarkRangeRBTree) +TEST(SpaceMapTest, MarkmarkFreeRBTree) { RBTreeSpaceMapPtr smap = std::make_shared(0, 100); - ASSERT_EQ(smap->newSmap(), 0); + ASSERT_TRUE(smap->newSmap()); struct rb_private * bp = (struct rb_private *)smap->rb_tree; - range ranges[] = {{.start = 0, + Range ranges[] = {{.start = 0, .end = 100}}; ASSERT_TRUE(check_nodes(&bp->root, ranges, 1)); - ASSERT_EQ(smap->testRange(1, 99), 1); - ASSERT_EQ(smap->testRange(0, 1000), -1); - - ASSERT_TRUE(smap->markRange(50, 10)); + ASSERT_TRUE(smap->isMarkUsed(1, 99)); + bool will_throw_exception = false; + try + { + smap->isMarkUsed(0, 1000); + } + catch (DB::Exception e) + { + will_throw_exception = true; + } + ASSERT_TRUE(will_throw_exception); - range ranges1[] = {{.start = 0, + ASSERT_TRUE(smap->markUsed(50, 10)); + ASSERT_FALSE(smap->markUsed(50, 10)); + ASSERT_FALSE(smap->markUsed(50, 9)); + ASSERT_FALSE(smap->markUsed(55, 5)); + Range ranges1[] = {{.start = 0, .end = 50}, {.start = 60, .end = 100}}; ASSERT_TRUE(check_nodes(&bp->root, ranges1, 2)); - ASSERT_EQ(smap->testRange(51, 5), 0); + ASSERT_FALSE(smap->isMarkUsed(51, 5)); - smap->unmarkRange(50, 5); - range ranges2[] = {{.start = 0, + smap->markFree(50, 5); + Range ranges2[] = {{.start = 0, .end = 55}, {.start = 60, .end = 100}}; ASSERT_TRUE(check_nodes(&bp->root, ranges2, 2)); - smap->unmarkRange(55, 5); + smap->markFree(55, 5); ASSERT_TRUE(check_nodes(&bp->root, ranges, 2)); } -TEST(SpaceMapTest, MarkUnmarkRangeSTDMap) +TEST(SpaceMapTest, MarkmarkFreeSTDMap) { STDMapSpaceMapPtr smap = std::make_shared(0, 100); - ASSERT_EQ(smap->newSmap(), 0); + ASSERT_TRUE(smap->newSmap()); - range ranges[] = {{.start = 0, + Range ranges[] = {{.start = 0, .end = 100}}; - ASSERT_TRUE(check_nodes(smap->map, ranges, 1)); - ASSERT_EQ(smap->testRange(1, 99), 1); - ASSERT_EQ(smap->testRange(0, 1000), -1); - - ASSERT_TRUE(smap->markRange(50, 20)); + ASSERT_TRUE(check_nodes(smap->free_map, ranges, 1)); + ASSERT_TRUE(smap->isMarkUsed(1, 99)); + bool will_throw_exception = false; + try + { + smap->isMarkUsed(0, 1000); + } + catch (DB::Exception e) + { + will_throw_exception = true; + } + ASSERT_TRUE(will_throw_exception); - range ranges1[] = {{.start = 0, + ASSERT_TRUE(smap->markUsed(50, 20)); + ASSERT_FALSE(smap->markUsed(50, 1)); + ASSERT_FALSE(smap->markUsed(50, 20)); + ASSERT_FALSE(smap->markUsed(55, 15)); + Range ranges1[] = {{.start = 0, .end = 50}, {.start = 70, .end = 100}}; - ASSERT_TRUE(check_nodes(smap->map, ranges1, 2)); - ASSERT_EQ(smap->testRange(51, 5), 0); + ASSERT_TRUE(check_nodes(smap->free_map, ranges1, 2)); + ASSERT_FALSE(smap->isMarkUsed(51, 5)); - smap->unmarkRange(50, 5); - range ranges2[] = {{.start = 0, + smap->markFree(50, 5); + Range ranges2[] = {{.start = 0, .end = 55}, {.start = 70, .end = 100}}; - ASSERT_TRUE(check_nodes(smap->map, ranges2, 2)); + ASSERT_TRUE(check_nodes(smap->free_map, ranges2, 2)); - smap->unmarkRange(60, 5); - range ranges3[] = {{.start = 0, + smap->markFree(60, 5); + Range ranges3[] = {{.start = 0, .end = 55}, {.start = 60, .end = 65}, {.start = 70, .end = 100}}; - ASSERT_TRUE(check_nodes(smap->map, ranges3, 3)); + ASSERT_TRUE(check_nodes(smap->free_map, ranges3, 3)); - smap->unmarkRange(65, 5); - range ranges4[] = {{.start = 0, + smap->markFree(65, 5); + Range ranges4[] = {{.start = 0, .end = 55}, {.start = 60, .end = 100}}; - ASSERT_TRUE(check_nodes(smap->map, ranges4, 2)); + ASSERT_TRUE(check_nodes(smap->free_map, ranges4, 2)); - smap->unmarkRange(55, 5); - ASSERT_TRUE(check_nodes(smap->map, ranges, 2)); + smap->markFree(55, 5); + ASSERT_TRUE(check_nodes(smap->free_map, ranges, 2)); } TEST(SpaceMapTest, TestMarginsRBTree) { RBTreeSpaceMapPtr smap = std::make_shared(0, 100); - ASSERT_EQ(smap->newSmap(), 0); + ASSERT_TRUE(smap->newSmap()); struct rb_private * bp = (struct rb_private *)smap->rb_tree; - range ranges[] = {{.start = 0, + Range ranges[] = {{.start = 0, .end = 100}}; ASSERT_TRUE(check_nodes(&bp->root, ranges, 1)); - ASSERT_TRUE(smap->markRange(50, 10)); + ASSERT_TRUE(smap->markUsed(50, 10)); - range ranges1[] = {{.start = 0, + Range ranges1[] = {{.start = 0, .end = 50}, {.start = 60, .end = 100}}; ASSERT_TRUE(check_nodes(&bp->root, ranges1, 2)); - ASSERT_EQ(smap->testRange(50, 5), 0); - ASSERT_EQ(smap->testRange(60, 1), 1); + ASSERT_FALSE(smap->isMarkUsed(50, 5)); + ASSERT_TRUE(smap->isMarkUsed(60, 1)); } TEST(SpaceMapTest, TestMarginsSTDMap) { STDMapSpaceMapPtr smap = std::make_shared(0, 100); - ASSERT_EQ(smap->newSmap(), 0); + ASSERT_TRUE(smap->newSmap()); - range ranges[] = {{.start = 0, + Range ranges[] = {{.start = 0, .end = 100}}; - ASSERT_TRUE(check_nodes(smap->map, ranges, 1)); - ASSERT_TRUE(smap->markRange(50, 10)); + ASSERT_TRUE(check_nodes(smap->free_map, ranges, 1)); + ASSERT_TRUE(smap->markUsed(50, 10)); - range ranges1[] = {{.start = 0, + Range ranges1[] = {{.start = 0, .end = 50}, {.start = 60, .end = 100}}; - ASSERT_TRUE(check_nodes(smap->map, ranges1, 2)); + ASSERT_TRUE(check_nodes(smap->free_map, ranges1, 2)); - ASSERT_EQ(smap->testRange(50, 1), 0); - ASSERT_EQ(smap->testRange(60, 1), 1); + ASSERT_FALSE(smap->isMarkUsed(50, 1)); + ASSERT_TRUE(smap->isMarkUsed(60, 1)); } } // namespace DB::PS::V3::tests \ No newline at end of file From 9c12952dae7f39cba534d5ec438f47daba847afe Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Tue, 7 Dec 2021 10:11:05 +0800 Subject: [PATCH 12/36] update --- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index 3d5afadd4f0..042b06b134b 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -6,6 +6,17 @@ namespace DB::PS::V3 { class SpaceMap; using SpaceMapPtr = std::shared_ptr; +/** + * SpaceMap design doc: + * https://docs.google.com/document/d/1l1GoIV6Rp0GEwuYtToJMKYACmZv6jf4kp1n8JdQidS8/edit#heading=h.pff0nn7vsa6w + * + * SpaceMap have red-black tree/ map implemention. + * Each node on the tree records the information of free data blocks, + * + * The node is composed of `offset` : `size`. Each node sorted according to offset. + * - offset: Record the starting address of the free data segment in the file. + * - size: The length of the space data segment is recorded. + */ class SpaceMap { public: From a6c87056b6b8a46ad300c21d305be5cf6c61755b Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Tue, 7 Dec 2021 14:13:32 +0800 Subject: [PATCH 13/36] Make constructor protected Signed-off-by: JaySon-Huang --- .../Storages/Page/V3/spacemap/SpaceMap.cpp | 9 +++--- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 20 ++++++++---- .../Page/V3/spacemap/SpaceMapRBTree.cpp | 20 +++++++++++- .../Page/V3/spacemap/SpaceMapRBTree.h | 26 +++++++-------- .../Page/V3/spacemap/SpaceMapSTDMap.h | 32 ++++++++++++------- 5 files changed, 70 insertions(+), 37 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index 33702a292ea..e837f993786 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -25,10 +25,10 @@ SpaceMapPtr SpaceMap::createSpaceMap(SpaceMapType type, UInt64 start, UInt64 end switch (type) { case SMAP64_RBTREE: - smap = std::make_shared(start, end); + smap = RBTreeSpaceMap::create(start, end); break; case SMAP64_STD_MAP: - smap = std::make_shared(start, end); + smap = STDMapSpaceMap::create(start, end); break; default: return nullptr; @@ -94,8 +94,9 @@ std::pair SpaceMap::searchInsertOffset(size_t size) return searchSmapInsertOffset(size); } -SpaceMap::SpaceMap(UInt64 start_, UInt64 end_) - : start(start_) +SpaceMap::SpaceMap(UInt64 start_, UInt64 end_, SpaceMapType type_) + : type(type_) + , start(start_) , end(end_) , log(&Poco::Logger::get("RBTreeSpaceMap")) { diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index 042b06b134b..5ff218d7c2e 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -82,17 +82,26 @@ class SpaceMap */ std::pair searchInsertOffset(size_t size); + /** + * Sanity check for correctness + */ + using CheckerFunc = std::function; + virtual bool check(CheckerFunc /*checker*/) + { + return true; + } + /** * Log the status of space map */ void logStats(); - SpaceMapType getType() + SpaceMapType getType() const { return type; } - String typeToString(SpaceMapType type) + static String typeToString(SpaceMapType type) { switch (type) { @@ -105,13 +114,10 @@ class SpaceMap } } -#ifndef DBMS_PUBLIC_GTEST protected: -#endif - - SpaceMap(UInt64 start, UInt64 end); + SpaceMap(UInt64 start_, UInt64 end_, SpaceMapType type_); - virtual ~SpaceMap(){}; + virtual ~SpaceMap() = default; /* Generic space map operators */ virtual bool newSmap() = 0; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index e78b9339112..aac382ac473 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -559,5 +559,23 @@ bool RBTreeSpaceMap::markSmapFree(UInt64 block, size_t size) return rc; } +bool RBTreeSpaceMap::check(std::function checker) +{ + struct smap_rb_entry * ext; + + size_t i = 0; + for (struct rb_node * node = rb_tree_first(&rb_tree->root); node != nullptr; node = rb_tree_next(node)) + { + ext = node_to_entry(node); + if (!checker(i, ext->start, ext->start + ext->count)) + { + return false; + } + i++; + } + + return true; +} + -} // namespace DB::PS::V3 \ No newline at end of file +} // namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h index f0404c59baf..a5269dad0d3 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h @@ -1,6 +1,8 @@ #pragma once #include +#include + #include "RBTree.h" #include "SpaceMap.h" @@ -36,23 +38,23 @@ inline static struct smap_rb_entry * node_to_entry(struct rb_node * node) return reinterpret_cast(node); } -class RBTreeSpaceMap : public SpaceMap +class RBTreeSpaceMap + : public SpaceMap + , public ext::SharedPtrHelper { public: - RBTreeSpaceMap(UInt64 start, UInt64 end) - : SpaceMap(start, end) - { - type = SMAP64_RBTREE; - }; - ~RBTreeSpaceMap() override { freeSmap(); - }; + } + + bool check(std::function checker) override; -#ifndef DBMS_PUBLIC_GTEST protected: -#endif + RBTreeSpaceMap(UInt64 start, UInt64 end) + : SpaceMap(start, end, SMAP64_RBTREE) + { + } bool newSmap() override; @@ -68,9 +70,7 @@ class RBTreeSpaceMap : public SpaceMap std::pair searchSmapInsertOffset(size_t size) override; -#ifndef DBMS_PUBLIC_GTEST private: -#endif struct rb_private * rb_tree; UInt64 biggest_range = 0; UInt64 biggest_cap = 0; @@ -79,4 +79,4 @@ class RBTreeSpaceMap : public SpaceMap using RBTreeSpaceMapPtr = std::shared_ptr; } // namespace PS::V3 -} // namespace DB \ No newline at end of file +} // namespace DB diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 38348b34a61..4246539389a 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include "SpaceMap.h" @@ -14,22 +15,31 @@ extern const int NOT_IMPLEMENTED; namespace PS::V3 { -class STDMapSpaceMap : public SpaceMap +class STDMapSpaceMap + : public SpaceMap + , public ext::SharedPtrHelper { public: - STDMapSpaceMap(UInt64 start, UInt64 end) - : SpaceMap(start, end) + ~STDMapSpaceMap() override = default; + + bool check(std::function checker) override { - type = SMAP64_STD_MAP; - }; + size_t idx = 0; + for (const auto [offset, length] : free_map) + { + if (!checker(idx, offset, offset + length)) + return false; + } + return true; + } - ~STDMapSpaceMap() override{ +protected: - }; + STDMapSpaceMap(UInt64 start, UInt64 end) + : SpaceMap(start, end, SMAP64_STD_MAP) + { + } -#ifndef DBMS_PUBLIC_GTEST -protected: -#endif bool newSmap() override { free_map.insert({start, end}); @@ -264,9 +274,7 @@ class STDMapSpaceMap : public SpaceMap return false; } -#ifndef DBMS_PUBLIC_GTEST private: -#endif // Save the of free blocks std::map free_map; From 02081aedd4c0f86270b987d8ca88b6bb5825cec6 Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Tue, 7 Dec 2021 14:31:31 +0800 Subject: [PATCH 14/36] Refactor ut Signed-off-by: JaySon-Huang --- .../Storages/Page/V3/tests/gtest_free_map.cpp | 171 ++++++------------ 1 file changed, 53 insertions(+), 118 deletions(-) diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index ed835d2f8c5..3b360701d28 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -15,63 +16,40 @@ struct Range size_t end; }; -bool check_nodes(struct rb_root * root, Range * ranges, size_t size) +class SpaceMapTest + : public testing::TestWithParam { - struct rb_node * node = NULL; - struct smap_rb_entry * ext; - - assert(size != 0); - - size_t i = 0; - for (node = rb_tree_first(root); node != NULL; node = rb_tree_next(node)) +public: + SpaceMapTest() + : test_type(GetParam()) + {} + SpaceMap::SpaceMapType test_type; + +protected: + static SpaceMap::CheckerFunc + genChecker(const Range * ranges, size_t range_size) { - ext = node_to_entry(node); - if (i >= size || ranges[i].start != ext->start || ranges[i].end != ext->start + ext->count) - { - return false; - } - i++; - } - - return true; -} - -bool check_nodes(std::map & map, Range * ranges, size_t size) -{ - assert(size != 0); - - size_t i = 0; - for (auto it = map.begin(); it != map.end(); it++) - { - if (i >= size || ranges[i].start != it->first || ranges[i].end != it->first + it->second) - { - return false; - } - i++; - } - - return true; -} - + return [&](size_t idx, UInt64 start, UInt64 end) -> bool { + return idx < range_size && ranges[idx].start != start && ranges[idx].end != end; + }; + }; +}; -TEST(SpaceMapTest, InitAndDestory) +TEST_P(SpaceMapTest, InitAndDestory) { - SpaceMapPtr smap = SpaceMap::createSpaceMap(SpaceMap::SpaceMapType::SMAP64_RBTREE, 0, 100); + SpaceMapPtr smap = SpaceMap::createSpaceMap(test_type, 0, 100); smap->logStats(); } -TEST(SpaceMapTest, MarkUnmarkBitRBTree) +TEST_P(SpaceMapTest, MarkUnmark) { - RBTreeSpaceMapPtr smap = std::make_shared(0, 100); - ASSERT_TRUE(smap->newSmap()); - - struct rb_private * bp = (struct rb_private *)smap->rb_tree; + auto smap = SpaceMap::createSpaceMap(test_type, 0, 100); Range ranges[] = {{.start = 0, .end = 100}}; - ASSERT_TRUE(check_nodes(&bp->root, ranges, 1)); + ASSERT_TRUE(smap->check(genChecker(ranges, 1))); ASSERT_TRUE(smap->markUsed(50, 1)); ASSERT_FALSE(smap->markUsed(50, 1)); @@ -84,34 +62,24 @@ TEST(SpaceMapTest, MarkUnmarkBitRBTree) {.start = 51, .end = 100}}; - ASSERT_TRUE(check_nodes(&bp->root, ranges1, 2)); + ASSERT_TRUE(smap->check(genChecker(ranges1, 2))); smap->markFree(50, 1); - ASSERT_TRUE(check_nodes(&bp->root, ranges, 1)); + ASSERT_TRUE(smap->check(genChecker(ranges, 1))); ASSERT_TRUE(smap->isMarkUsed(50, 1)); } -TEST(SpaceMapTest, MarkmarkFreeRBTree) +TEST_P(SpaceMapTest, MarkmarkFree) { - RBTreeSpaceMapPtr smap = std::make_shared(0, 100); - ASSERT_TRUE(smap->newSmap()); - - struct rb_private * bp = (struct rb_private *)smap->rb_tree; + auto smap = SpaceMap::createSpaceMap(test_type, 0, 100); Range ranges[] = {{.start = 0, .end = 100}}; - ASSERT_TRUE(check_nodes(&bp->root, ranges, 1)); + ASSERT_TRUE(smap->check(genChecker(ranges, 1))); ASSERT_TRUE(smap->isMarkUsed(1, 99)); - bool will_throw_exception = false; - try - { - smap->isMarkUsed(0, 1000); - } - catch (DB::Exception e) - { - will_throw_exception = true; - } - ASSERT_TRUE(will_throw_exception); + + // call `isMarkUsed` with invalid length + ASSERT_THROW({ smap->isMarkUsed(0, 1000); }, DB::Exception); ASSERT_TRUE(smap->markUsed(50, 10)); ASSERT_FALSE(smap->markUsed(50, 10)); @@ -121,7 +89,7 @@ TEST(SpaceMapTest, MarkmarkFreeRBTree) .end = 50}, {.start = 60, .end = 100}}; - ASSERT_TRUE(check_nodes(&bp->root, ranges1, 2)); + ASSERT_TRUE(smap->check(genChecker(ranges1, 2))); ASSERT_FALSE(smap->isMarkUsed(51, 5)); smap->markFree(50, 5); @@ -129,31 +97,14 @@ TEST(SpaceMapTest, MarkmarkFreeRBTree) .end = 55}, {.start = 60, .end = 100}}; - ASSERT_TRUE(check_nodes(&bp->root, ranges2, 2)); + ASSERT_TRUE(smap->check(genChecker(ranges2, 2))); smap->markFree(55, 5); - ASSERT_TRUE(check_nodes(&bp->root, ranges, 2)); + ASSERT_TRUE(smap->check(genChecker(ranges, 1))); } -TEST(SpaceMapTest, MarkmarkFreeSTDMap) +TEST_P(SpaceMapTest, MarkmarkFree2) { - STDMapSpaceMapPtr smap = std::make_shared(0, 100); - ASSERT_TRUE(smap->newSmap()); - - Range ranges[] = {{.start = 0, - .end = 100}}; - - ASSERT_TRUE(check_nodes(smap->free_map, ranges, 1)); - ASSERT_TRUE(smap->isMarkUsed(1, 99)); - bool will_throw_exception = false; - try - { - smap->isMarkUsed(0, 1000); - } - catch (DB::Exception e) - { - will_throw_exception = true; - } - ASSERT_TRUE(will_throw_exception); + auto smap = SpaceMap::createSpaceMap(test_type, 0, 100); ASSERT_TRUE(smap->markUsed(50, 20)); ASSERT_FALSE(smap->markUsed(50, 1)); @@ -163,7 +114,7 @@ TEST(SpaceMapTest, MarkmarkFreeSTDMap) .end = 50}, {.start = 70, .end = 100}}; - ASSERT_TRUE(check_nodes(smap->free_map, ranges1, 2)); + ASSERT_TRUE(smap->check(genChecker(ranges1, 2))); ASSERT_FALSE(smap->isMarkUsed(51, 5)); smap->markFree(50, 5); @@ -171,7 +122,7 @@ TEST(SpaceMapTest, MarkmarkFreeSTDMap) .end = 55}, {.start = 70, .end = 100}}; - ASSERT_TRUE(check_nodes(smap->free_map, ranges2, 2)); + ASSERT_TRUE(smap->check(genChecker(ranges2, 2))); smap->markFree(60, 5); Range ranges3[] = {{.start = 0, @@ -181,61 +132,45 @@ TEST(SpaceMapTest, MarkmarkFreeSTDMap) {.start = 70, .end = 100}}; - ASSERT_TRUE(check_nodes(smap->free_map, ranges3, 3)); + ASSERT_TRUE(smap->check(genChecker(ranges3, 3))); smap->markFree(65, 5); Range ranges4[] = {{.start = 0, .end = 55}, {.start = 60, .end = 100}}; - ASSERT_TRUE(check_nodes(smap->free_map, ranges4, 2)); - + ASSERT_TRUE(smap->check(genChecker(ranges4, 2))); + Range ranges[] = {{.start = 0, + .end = 100}}; smap->markFree(55, 5); - ASSERT_TRUE(check_nodes(smap->free_map, ranges, 2)); + ASSERT_TRUE(smap->check(genChecker(ranges, 1))); } -TEST(SpaceMapTest, TestMarginsRBTree) +TEST_P(SpaceMapTest, TestMarginsRBTree) { - RBTreeSpaceMapPtr smap = std::make_shared(0, 100); - ASSERT_TRUE(smap->newSmap()); - - struct rb_private * bp = (struct rb_private *)smap->rb_tree; + auto smap = SpaceMap::createSpaceMap(test_type, 0, 100); Range ranges[] = {{.start = 0, .end = 100}}; - ASSERT_TRUE(check_nodes(&bp->root, ranges, 1)); + ASSERT_TRUE(smap->check(genChecker(ranges, 1))); ASSERT_TRUE(smap->markUsed(50, 10)); Range ranges1[] = {{.start = 0, .end = 50}, {.start = 60, .end = 100}}; - ASSERT_TRUE(check_nodes(&bp->root, ranges1, 2)); + ASSERT_TRUE(smap->check(genChecker(ranges1, 2))); ASSERT_FALSE(smap->isMarkUsed(50, 5)); ASSERT_TRUE(smap->isMarkUsed(60, 1)); } +INSTANTIATE_TEST_CASE_P( + Type, + SpaceMapTest, + testing::Values( + SpaceMap::SMAP64_RBTREE, + SpaceMap::SMAP64_STD_MAP)); -TEST(SpaceMapTest, TestMarginsSTDMap) -{ - STDMapSpaceMapPtr smap = std::make_shared(0, 100); - ASSERT_TRUE(smap->newSmap()); - - Range ranges[] = {{.start = 0, - .end = 100}}; - ASSERT_TRUE(check_nodes(smap->free_map, ranges, 1)); - ASSERT_TRUE(smap->markUsed(50, 10)); - - Range ranges1[] = {{.start = 0, - .end = 50}, - {.start = 60, - .end = 100}}; - ASSERT_TRUE(check_nodes(smap->free_map, ranges1, 2)); - - ASSERT_FALSE(smap->isMarkUsed(50, 1)); - ASSERT_TRUE(smap->isMarkUsed(60, 1)); -} - -} // namespace DB::PS::V3::tests \ No newline at end of file +} // namespace DB::PS::V3::tests From 6f9d4ac3ff23cb9feff306998b7dd138b3488fd5 Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Tue, 7 Dec 2021 15:10:10 +0800 Subject: [PATCH 15/36] fix some bugs --- dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp | 4 ++-- dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h | 4 ++-- dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index e837f993786..cd797c0f6e7 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -31,13 +31,13 @@ SpaceMapPtr SpaceMap::createSpaceMap(SpaceMapType type, UInt64 start, UInt64 end smap = STDMapSpaceMap::create(start, end); break; default: - return nullptr; + throw Exception("Invalid type to create spaceMap", ErrorCodes::LOGICAL_ERROR); } if (!smap->newSmap()) { smap->freeSmap(); - return nullptr; + throw Exception("Failed create SpaceMap [type=" + typeToString(type) + "]", ErrorCodes::LOGICAL_ERROR); } return smap; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 4246539389a..2a35a7374f9 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -29,12 +29,12 @@ class STDMapSpaceMap { if (!checker(idx, offset, offset + length)) return false; + idx++; } return true; } protected: - STDMapSpaceMap(UInt64 start, UInt64 end) : SpaceMap(start, end, SMAP64_STD_MAP) { @@ -274,8 +274,8 @@ class STDMapSpaceMap return false; } -private: +private: // Save the of free blocks std::map free_map; UInt64 biggest_range = 0; diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index 3b360701d28..f38210da5d3 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -29,8 +29,8 @@ class SpaceMapTest static SpaceMap::CheckerFunc genChecker(const Range * ranges, size_t range_size) { - return [&](size_t idx, UInt64 start, UInt64 end) -> bool { - return idx < range_size && ranges[idx].start != start && ranges[idx].end != end; + return [ranges, range_size](size_t idx, UInt64 start, UInt64 end) -> bool { + return idx < range_size && ranges[idx].start == start && ranges[idx].end == end; }; }; }; From f244f1e98ced7e40834d23304d7a59e6adaa0d69 Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Tue, 7 Dec 2021 19:19:42 +0800 Subject: [PATCH 16/36] update --- .../Storages/Page/V3/spacemap/SpaceMap.cpp | 4 +- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 2 +- .../Page/V3/spacemap/SpaceMapRBTree.cpp | 347 +++++++++++------- .../Page/V3/spacemap/SpaceMapRBTree.h | 2 +- .../Page/V3/spacemap/SpaceMapSTDMap.h | 140 ++++--- .../Storages/Page/V3/tests/gtest_free_map.cpp | 158 ++++++-- 6 files changed, 436 insertions(+), 217 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index cd797c0f6e7..d071ccff2b3 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -86,7 +86,7 @@ bool SpaceMap::isMarkUsed(UInt64 offset, size_t length) ErrorCodes::LOGICAL_ERROR); } - return isSmapMarkUsed(offset, length); + return !isSmapMarkUsed(offset, length); } std::pair SpaceMap::searchInsertOffset(size_t size) @@ -98,7 +98,7 @@ SpaceMap::SpaceMap(UInt64 start_, UInt64 end_, SpaceMapType type_) : type(type_) , start(start_) , end(end_) - , log(&Poco::Logger::get("RBTreeSpaceMap")) + , log(&Poco::Logger::get("SpaceMap")) { } diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index 5ff218d7c2e..d45188d8b1a 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -86,7 +86,7 @@ class SpaceMap * Sanity check for correctness */ using CheckerFunc = std::function; - virtual bool check(CheckerFunc /*checker*/) + virtual bool check(CheckerFunc /*checker*/, size_t /*size*/) { return true; } diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index aac382ac473..dbc088792bd 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -3,8 +3,8 @@ namespace DB::PS::V3 { -static bool rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data); -static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data); +static bool rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data, Poco::Logger * log); +static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data, Poco::Logger * log); static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, @@ -81,7 +81,178 @@ inline static void rb_free_entry(struct rb_private * private_data, struct smap_r free(entry); } -static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data) + +static bool rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data, Poco::Logger * log) +{ + struct rb_root * root = &private_data->root; + struct rb_node *parent = NULL, **n = &root->rb_node; + struct rb_node *new_node, *node, *next; + struct smap_rb_entry * new_entry; + struct smap_rb_entry * entry; + bool retval = true; + + (void)log; + + if (count == 0) + { + return false; + } + + private_data->read_index_next = NULL; + entry = private_data->write_index; + if (entry) + { + if (start >= entry->start && start <= (entry->start + entry->count)) + { + goto got_entry; + } + } + + while (*n) + { + parent = *n; + entry = node_to_entry(parent); + + if (start < entry->start) + { + n = &(*n)->node_left; + } + else if (start > (entry->start + entry->count)) + { + n = &(*n)->node_right; + } + else + { + got_entry: + if ((start + count) <= (entry->start + entry->count)) + { + return false; + } + + if ((entry->start + entry->count) == start) + { + retval = true; + if (parent) + { + auto * _node = rb_tree_next(parent); + if (_node) + { + auto * _entry = node_to_entry(_node); + if (start + count > _entry->start) + { + LOG_WARNING(log, "Marked space free failed. [offset = " << start << ", size= " << count << "], next node is [offset=" << _entry->start << ",size=" << _entry->count << "]"); + return false; + } + } + } + } + else + { + return false; + } + + count += (start - entry->start); + start = entry->start; + new_entry = entry; + new_node = &entry->node; + + goto no_need_insert; + } + } + + rb_get_new_entry(&new_entry, start, count); + + new_node = &new_entry->node; + rb_link_node(new_node, parent, n); + rb_node_insert(new_node, root); + private_data->write_index = new_entry; + + /** + * We need check current node is legal before we merge it. + * If prev/next node exist. Check if they have overlap with the current node. + * Also, We can’t check while doing the merge. + * Because it will cause the original state not to be restored + */ + node = rb_tree_prev(new_node); + if (node) + { + entry = node_to_entry(node); + if (entry->start + entry->count > new_entry->start) + { + LOG_WARNING(log, "Marked space free failed. [offset = " << new_entry->start << ", size= " << new_entry->count << "], prev node is [offset=" << entry->start << ",size=" << entry->count << "]"); + rb_node_remove(new_node, root); + rb_free_entry(private_data, new_entry); + return false; + } + } + + node = rb_tree_next(new_node); + if (node) + { + entry = node_to_entry(node); + if (new_entry->start + new_entry->count > entry->start) + { + LOG_WARNING(log, "Marked space free failed. [offset = " << new_entry->start << ", size= " << new_entry->count << "], next node is [offset=" << entry->start << ",size=" << entry->count << "]"); + rb_node_remove(new_node, root); + rb_free_entry(private_data, new_entry); + return false; + } + } + + + node = rb_tree_prev(new_node); + if (node) + { + entry = node_to_entry(node); + if ((entry->start + entry->count) == start) + { + start = entry->start; + count += entry->count; + rb_node_remove(node, root); + rb_free_entry(private_data, entry); + } + } + +no_need_insert: + // merge entry to the right + for (node = rb_tree_next(new_node); node != NULL; node = next) + { + next = rb_tree_next(node); + entry = node_to_entry(node); + + if ((entry->start + entry->count) <= start) + { + continue; + } + + // not match + if ((start + count) < entry->start) + break; + + if ((start + count) >= (entry->start + entry->count)) + { + rb_node_remove(node, root); + rb_free_entry(private_data, entry); + continue; + } + else + { + // merge entry + count += ((entry->start + entry->count) - (start + count)); + rb_node_remove(node, root); + rb_free_entry(private_data, entry); + break; + } + } + + new_entry->start = start; + new_entry->count = count; + + return retval; +} + + +static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data, Poco::Logger * log) { struct rb_root * root = &private_data->root; struct rb_node *parent = NULL, **n = &root->rb_node; @@ -111,6 +282,24 @@ static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * priv continue; } + /** + * We got node. + * entry->start < start < (entry->start + entry->count) + */ + + if ((start + count) > (entry->start + entry->count)) + { + LOG_WARNING(log, "Marked space used failed. [offset = " << start << ", size= " << count << "] is bigger than space [offset=" << entry->start << ",size=" << entry->count << "]"); + return false; + } + + if (start < entry->start) + { + LOG_WARNING(log, "Marked space used failed. [offset = " << start << ", size= " << count << "] is less than space [offset=" << entry->start << ",size=" << entry->count << "]"); + return false; + } + + // In the Mid if ((start > entry->start) && (start + count) < (entry->start + entry->count)) { // Split entry @@ -119,16 +308,18 @@ static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * priv entry->count = start - entry->start; - rb_insert_entry(new_start, new_count, private_data); + rb_insert_entry(new_start, new_count, private_data, log); return true; } - if ((start + count) >= (entry->start + entry->count)) + // Match right + if ((start + count) == (entry->start + entry->count)) { entry->count = start - entry->start; marked = true; } + // Left have no count remian. if (0 == entry->count) { parent = rb_tree_next(&entry->node); @@ -156,6 +347,9 @@ static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * priv if ((start + count) < entry->start) break; + if ((start + count) > entry->start) + return false; + // Merge the nearby node if ((start + count) >= (entry->start + entry->count)) { @@ -196,7 +390,7 @@ bool RBTreeSpaceMap::newSmap() rb_tree->read_index_next = NULL; rb_tree->write_index = NULL; - if (rb_insert_entry(start, end, rb_tree) != 0) + if (!rb_insert_entry(start, end, rb_tree, log)) { LOG_ERROR(log, "Erorr happend, when mark all space free. [start=" << start << "] , [end = " << end << "]"); free(rb_tree); @@ -243,11 +437,11 @@ void RBTreeSpaceMap::smapStats() return; } - LOG_DEBUG(log, "entry status :"); + LOG_DEBUG(log, "RB-Tree entries status: "); for (node = rb_tree_first(&rb_tree->root); node != NULL; node = rb_tree_next(node)) { entry = node_to_entry(node); - LOG_DEBUG(log, " Space : " << count << " start:" << entry->start << " size : " << entry->count); + LOG_DEBUG(log, " Space: " << count << " start:" << entry->start << " size : " << entry->count); count++; if (entry->count > max_size) { @@ -317,129 +511,6 @@ bool RBTreeSpaceMap::isSmapMarkUsed(UInt64 _start, return retval; } -static bool rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data) -{ - struct rb_root * root = &private_data->root; - struct rb_node *parent = NULL, **n = &root->rb_node; - struct rb_node *new_node, *node, *next; - struct smap_rb_entry * new_entry; - struct smap_rb_entry * entry; - bool retval = false; - - if (count == 0) - { - return retval; - } - - - private_data->read_index_next = NULL; - entry = private_data->write_index; - if (entry) - { - if (start >= entry->start && start <= (entry->start + entry->count)) - { - goto got_entry; - } - } - - while (*n) - { - parent = *n; - entry = node_to_entry(parent); - - if (start < entry->start) - { - n = &(*n)->node_left; - } - else if (start > (entry->start + entry->count)) - { - n = &(*n)->node_right; - } - else - { - got_entry: - if ((start + count) <= (entry->start + entry->count)) - { - retval = true; - return retval; - } - - if ((entry->start + entry->count) == start) - { - retval = false; - } - else - { - retval = true; - } - - count += (start - entry->start); - start = entry->start; - new_entry = entry; - new_node = &entry->node; - - goto no_need_insert; - } - } - - rb_get_new_entry(&new_entry, start, count); - - new_node = &new_entry->node; - rb_link_node(new_node, parent, n); - rb_node_insert(new_node, root); - private_data->write_index = new_entry; - - node = rb_tree_prev(new_node); - if (node) - { - entry = node_to_entry(node); - if ((entry->start + entry->count) == start) - { - start = entry->start; - count += entry->count; - rb_node_remove(node, root); - rb_free_entry(private_data, entry); - } - } - -no_need_insert: - // merge entry to the right - for (node = rb_tree_next(new_node); node != NULL; node = next) - { - next = rb_tree_next(node); - entry = node_to_entry(node); - - if ((entry->start + entry->count) <= start) - { - continue; - } - - // not match - if ((start + count) < entry->start) - break; - - if ((start + count) >= (entry->start + entry->count)) - { - rb_node_remove(node, root); - rb_free_entry(private_data, entry); - continue; - } - else - { - // merge entry - count += ((entry->start + entry->count) - (start + count)); - rb_node_remove(node, root); - rb_free_entry(private_data, entry); - break; - } - } - - new_entry->start = start; - new_entry->count = count; - - return retval; -} - std::pair RBTreeSpaceMap::searchSmapInsertOffset(size_t size) { UInt64 offset = UINT64_MAX; @@ -543,7 +614,7 @@ bool RBTreeSpaceMap::markSmapUsed(UInt64 block, size_t size) block -= start; - rc = rb_remove_entry(block, size, rb_tree); + rc = rb_remove_entry(block, size, rb_tree, log); rb_tree_debug(&rb_tree->root, __func__); return rc; } @@ -554,27 +625,27 @@ bool RBTreeSpaceMap::markSmapFree(UInt64 block, size_t size) block -= start; - rc = rb_insert_entry(block, size, rb_tree); + rc = rb_insert_entry(block, size, rb_tree, log); rb_tree_debug(&rb_tree->root, __func__); return rc; } -bool RBTreeSpaceMap::check(std::function checker) +bool RBTreeSpaceMap::check(std::function checker, size_t size) { struct smap_rb_entry * ext; - size_t i = 0; + size_t idx = 0; for (struct rb_node * node = rb_tree_first(&rb_tree->root); node != nullptr; node = rb_tree_next(node)) { ext = node_to_entry(node); - if (!checker(i, ext->start, ext->start + ext->count)) + if (!checker(idx, ext->start, ext->start + ext->count)) { return false; } - i++; + idx++; } - return true; + return idx == size; } diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h index a5269dad0d3..254128c39cc 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h @@ -48,7 +48,7 @@ class RBTreeSpaceMap freeSmap(); } - bool check(std::function checker) override; + bool check(std::function checker, size_t size) override; protected: RBTreeSpaceMap(UInt64 start, UInt64 end) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 2a35a7374f9..9b33f96ed2a 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -22,7 +22,7 @@ class STDMapSpaceMap public: ~STDMapSpaceMap() override = default; - bool check(std::function checker) override + bool check(std::function checker, size_t size) override { size_t idx = 0; for (const auto [offset, length] : free_map) @@ -31,7 +31,8 @@ class STDMapSpaceMap return false; idx++; } - return true; + + return idx == size; } protected: @@ -55,10 +56,10 @@ class STDMapSpaceMap { UInt64 count = 0; - LOG_DEBUG(log, "entry status :"); + LOG_DEBUG(log, "STD-Map entries status: "); for (auto it = free_map.begin(); it != free_map.end(); it++) { - LOG_DEBUG(log, " Space : " << count << " start:" << it->first << " size : " << it->second); + LOG_DEBUG(log, " Space: " << count << " start:" << it->first << " size : " << it->second); count++; } } @@ -83,47 +84,59 @@ class STDMapSpaceMap return false; } - bool markSmapUsed(UInt64 block, size_t num) override + bool markSmapUsed(UInt64 offset, size_t length) override { - auto it = free_map.find(block); - if (it == free_map.end()) + auto it = free_map.upper_bound(offset); + if (it == free_map.begin()) { - // can't found , check the near one. - for (it = free_map.begin(); it != free_map.end(); it++) - { - // In the space, jump to space. - if (it->first <= block && (it->first + it->second) > block) - { - break; - } + return false; + } - // Could not found - if (it->first > block) - { - return false; - } - } + --it; + + // already been marked used + if (it->first + it->second < offset) + { + return false; } - // match - if (it->first == block) + if (length > it->second || it->first + it->second < offset + length) { - free_map.erase(it); + LOG_WARNING(log, "Marked space used failed. [offset = " << offset << ", size= " << length << "] is bigger than space [offset=" << it->first << ",size=" << it->second << "]"); + return false; + } - // in the space + // match + if (it->first == offset) + { + if (length == it->second) + { + free_map.erase(it); + } + else + { + auto _offset = it->first + length; + auto _size = it->second - length; + free_map.erase(it); + free_map[_offset] = _size; + } + } + else if (it->first + it->second == offset + length) + { + free_map[it->first] = it->second - length; } else { // In the mid, and not match the left or right. // Split to two space - if (((it->first + it->second) - block) > num) + if (((it->first + it->second) - offset) > length) { - free_map.insert({block + num, it->first + it->second - block - num}); - free_map[it->first] = block - it->first; + free_map.insert({offset + length, it->first + it->second - offset - length}); + free_map[it->first] = offset - it->first; } else - { // < num - free_map[it->first] = it->first + it->second - block; + { // < length + free_map[it->first] = it->first + it->second - offset; } } @@ -224,13 +237,13 @@ class STDMapSpaceMap return std::make_pair(offset, max_cap); } - bool markSmapFree(UInt64 block, size_t num) override + bool markSmapFree(UInt64 offset, size_t length) override { - auto it = free_map.find(block); + auto it = free_map.find(offset); /** * already unmarked. - * The `block` won't be mid of free space. + * The `offset` won't be mid of free space. * Because we alloc space from left to right. */ if (it != free_map.end()) @@ -239,40 +252,77 @@ class STDMapSpaceMap } bool meanless = false; - std::tie(it, meanless) = free_map.insert({block, num}); + std::tie(it, meanless) = free_map.insert({offset, length}); auto it_prev = it; + auto it_next = it; + /** + * We need check current node is legal before we merge it. + * If prev/next node exist. Check if they have overlap with the current node. + * Also, We can’t check while doing the merge. + * Because it will cause the original state not to be restored + */ if (it != free_map.begin()) { it_prev--; + if (it_prev->first + it_prev->second > it->first) + { + LOG_WARNING(log, "Marked space free failed. [offset = " << it->first << ", size= " << it->second << "], prev node is [offset=" << it_prev->first << ",size=" << it_prev->second << "]"); + free_map.erase(it); + return false; + } + } + + it_next++; + if (it_next != free_map.end()) + { + if (it->first + it->second > it_next->first) + { + LOG_WARNING(log, "Marked space free failed. [offset = " << it->first << ", size= " << it->second << "], next node is [offset=" << it_next->first << ",size=" << it_next->second << "]"); + free_map.erase(it); + return false; + } + } + /** + * Now, we can do merge. + * Restore the prev and next to the origin one. + * Also, we need check begin/end again. + * Because there not cache result. + */ + it_prev = it; + + // Check prev + if (it != free_map.begin()) + { + it_prev--; // Prev space can merge - if (it_prev->first + it_prev->second >= it->first) + if (it_prev->first + it_prev->second == it->first) { free_map[it_prev->first] = it->first + it->second - it_prev->first; free_map.erase(it); it = it_prev; } - } - // Check right - if (it == free_map.end()) - { - return false; + // prev can't merge } - auto it_next = it; + // Check next + it_next = it; it_next++; + if (it_next == free_map.end()) + { + return true; + } - // next space can merge - if (it->first + it->second >= it_next->first) + if (it->first + it->second == it_next->first) { free_map[it->first] = it_next->first + it_next->second - it->first; free_map.erase(it_next); } - - return false; + // next can't merge + return true; } private: diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index f38210da5d3..f57729b4238 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -49,24 +49,24 @@ TEST_P(SpaceMapTest, MarkUnmark) Range ranges[] = {{.start = 0, .end = 100}}; - ASSERT_TRUE(smap->check(genChecker(ranges, 1))); + ASSERT_TRUE(smap->check(genChecker(ranges, 1), 1)); ASSERT_TRUE(smap->markUsed(50, 1)); ASSERT_FALSE(smap->markUsed(50, 1)); - ASSERT_FALSE(smap->isMarkUsed(50, 1)); - ASSERT_TRUE(smap->isMarkUsed(51, 1)); + ASSERT_TRUE(smap->isMarkUsed(50, 1)); + ASSERT_FALSE(smap->isMarkUsed(51, 1)); Range ranges1[] = {{.start = 0, .end = 50}, {.start = 51, .end = 100}}; - ASSERT_TRUE(smap->check(genChecker(ranges1, 2))); + ASSERT_TRUE(smap->check(genChecker(ranges1, 2), 2)); - smap->markFree(50, 1); - ASSERT_TRUE(smap->check(genChecker(ranges, 1))); - ASSERT_TRUE(smap->isMarkUsed(50, 1)); + ASSERT_TRUE(smap->markFree(50, 1)); + ASSERT_TRUE(smap->check(genChecker(ranges, 1), 1)); + ASSERT_FALSE(smap->isMarkUsed(50, 1)); } TEST_P(SpaceMapTest, MarkmarkFree) @@ -75,8 +75,8 @@ TEST_P(SpaceMapTest, MarkmarkFree) Range ranges[] = {{.start = 0, .end = 100}}; - ASSERT_TRUE(smap->check(genChecker(ranges, 1))); - ASSERT_TRUE(smap->isMarkUsed(1, 99)); + ASSERT_TRUE(smap->check(genChecker(ranges, 1), 1)); + ASSERT_FALSE(smap->isMarkUsed(1, 99)); // call `isMarkUsed` with invalid length ASSERT_THROW({ smap->isMarkUsed(0, 1000); }, DB::Exception); @@ -89,17 +89,17 @@ TEST_P(SpaceMapTest, MarkmarkFree) .end = 50}, {.start = 60, .end = 100}}; - ASSERT_TRUE(smap->check(genChecker(ranges1, 2))); - ASSERT_FALSE(smap->isMarkUsed(51, 5)); + ASSERT_TRUE(smap->check(genChecker(ranges1, 2), 2)); + ASSERT_TRUE(smap->isMarkUsed(51, 5)); - smap->markFree(50, 5); + ASSERT_TRUE(smap->markFree(50, 5)); Range ranges2[] = {{.start = 0, .end = 55}, {.start = 60, .end = 100}}; - ASSERT_TRUE(smap->check(genChecker(ranges2, 2))); - smap->markFree(55, 5); - ASSERT_TRUE(smap->check(genChecker(ranges, 1))); + ASSERT_TRUE(smap->check(genChecker(ranges2, 2), 2)); + ASSERT_TRUE(smap->markFree(55, 5)); + ASSERT_TRUE(smap->check(genChecker(ranges, 1), 1)); } TEST_P(SpaceMapTest, MarkmarkFree2) @@ -114,17 +114,17 @@ TEST_P(SpaceMapTest, MarkmarkFree2) .end = 50}, {.start = 70, .end = 100}}; - ASSERT_TRUE(smap->check(genChecker(ranges1, 2))); - ASSERT_FALSE(smap->isMarkUsed(51, 5)); + ASSERT_TRUE(smap->check(genChecker(ranges1, 2), 2)); + ASSERT_TRUE(smap->isMarkUsed(51, 5)); - smap->markFree(50, 5); + ASSERT_TRUE(smap->markFree(50, 5)); Range ranges2[] = {{.start = 0, .end = 55}, {.start = 70, .end = 100}}; - ASSERT_TRUE(smap->check(genChecker(ranges2, 2))); + ASSERT_TRUE(smap->check(genChecker(ranges2, 2), 2)); - smap->markFree(60, 5); + ASSERT_TRUE(smap->markFree(60, 5)); Range ranges3[] = {{.start = 0, .end = 55}, {.start = 60, @@ -132,40 +132,138 @@ TEST_P(SpaceMapTest, MarkmarkFree2) {.start = 70, .end = 100}}; - ASSERT_TRUE(smap->check(genChecker(ranges3, 3))); + ASSERT_TRUE(smap->check(genChecker(ranges3, 3), 3)); - smap->markFree(65, 5); + ASSERT_TRUE(smap->markFree(65, 5)); Range ranges4[] = {{.start = 0, .end = 55}, {.start = 60, .end = 100}}; - ASSERT_TRUE(smap->check(genChecker(ranges4, 2))); + ASSERT_TRUE(smap->check(genChecker(ranges4, 2), 2)); Range ranges[] = {{.start = 0, .end = 100}}; - smap->markFree(55, 5); - ASSERT_TRUE(smap->check(genChecker(ranges, 1))); + ASSERT_TRUE(smap->markFree(55, 5)); + ASSERT_TRUE(smap->check(genChecker(ranges, 1), 1)); } -TEST_P(SpaceMapTest, TestMarginsRBTree) +TEST_P(SpaceMapTest, TestMargins) { auto smap = SpaceMap::createSpaceMap(test_type, 0, 100); Range ranges[] = {{.start = 0, .end = 100}}; - ASSERT_TRUE(smap->check(genChecker(ranges, 1))); + ASSERT_TRUE(smap->check(genChecker(ranges, 1), 1)); ASSERT_TRUE(smap->markUsed(50, 10)); Range ranges1[] = {{.start = 0, .end = 50}, {.start = 60, .end = 100}}; - ASSERT_TRUE(smap->check(genChecker(ranges1, 2))); + ASSERT_TRUE(smap->check(genChecker(ranges1, 2), 2)); - ASSERT_FALSE(smap->isMarkUsed(50, 5)); - ASSERT_TRUE(smap->isMarkUsed(60, 1)); + ASSERT_TRUE(smap->isMarkUsed(50, 5)); + ASSERT_FALSE(smap->isMarkUsed(60, 1)); + + // Test for two near markUsed + ASSERT_TRUE(smap->markUsed(60, 10)); + Range ranges2[] = {{.start = 0, + .end = 50}, + {.start = 70, + .end = 100}}; + ASSERT_TRUE(smap->check(genChecker(ranges2, 2), 2)); + + ASSERT_TRUE(smap->markUsed(49, 1)); + Range ranges3[] = {{.start = 0, + .end = 49}, + {.start = 70, + .end = 100}}; + ASSERT_TRUE(smap->check(genChecker(ranges3, 2), 2)); + + ASSERT_TRUE(smap->markFree(49, 1)); + ASSERT_TRUE(smap->check(genChecker(ranges2, 2), 2)); } +TEST_P(SpaceMapTest, TestMargins2) +{ + auto smap = SpaceMap::createSpaceMap(test_type, 0, 100); + Range ranges[] = {{.start = 0, + .end = 100}}; + ASSERT_TRUE(smap->check(genChecker(ranges, 1), 1)); + ASSERT_TRUE(smap->markUsed(50, 10)); + + // total in marked used range + ASSERT_FALSE(smap->markUsed(50, 1)); + ASSERT_FALSE(smap->markUsed(59, 1)); + ASSERT_FALSE(smap->markUsed(55, 1)); + ASSERT_FALSE(smap->markUsed(55, 5)); + ASSERT_FALSE(smap->markUsed(50, 5)); + + // Right margin in marked used space + // Left margin contain freed space + ASSERT_FALSE(smap->markUsed(45, 10)); + + // Left margin in marked used space + // Right margin contain freed space + ASSERT_FALSE(smap->markUsed(55, 15)); + + // Left margin align with marked used space left margin + // But right margin contain freed space + ASSERT_FALSE(smap->markUsed(50, 20)); + + // Right margin align with marked used space right margin + // But left margin contain freed space + ASSERT_FALSE(smap->markUsed(40, 20)); + + // Left margin in freed space + // Right margin in freed space + // But used space in the middle + ASSERT_FALSE(smap->markUsed(40, 30)); + + + Range ranges1[] = {{.start = 0, + .end = 50}, + {.start = 60, + .end = 100}}; + ASSERT_TRUE(smap->check(genChecker(ranges1, 2), 2)); + + ASSERT_TRUE(smap->markFree(50, 1)); + + // Mark a space which contain a sub freed space. + ASSERT_FALSE(smap->markFree(50, 2)); + ASSERT_FALSE(smap->markFree(50, 5)); + ASSERT_TRUE(smap->markFree(59, 1)); + + // Left margin in marked used space + // Right margin contain freed space + ASSERT_FALSE(smap->markFree(58, 10)); + + // Right margin in marked used space + // Left margin contain freed space + ASSERT_FALSE(smap->markFree(49, 10)); + smap->logStats(); + // Left margin align with marked used space left margin + // But right margin contain freed space + ASSERT_FALSE(smap->markFree(51, 20)); + smap->logStats(); + // Right margin align with marked used space right margin + // But left margin contain freed space + ASSERT_FALSE(smap->markUsed(40, 19)); + + // Left margin in freed space + // Right margin in freed space + // But used space in the middle + ASSERT_FALSE(smap->markUsed(40, 30)); + + + Range ranges2[] = {{.start = 0, + .end = 51}, + {.start = 59, + .end = 100}}; + ASSERT_TRUE(smap->check(genChecker(ranges2, 2), 2)); +} + + INSTANTIATE_TEST_CASE_P( Type, SpaceMapTest, From 3ceb78a9bdbc157f3e3064935aae8fb86e58c22b Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Tue, 7 Dec 2021 20:21:19 +0800 Subject: [PATCH 17/36] update --- .../Page/V3/spacemap/SpaceMapRBTree.cpp | 58 +++++++++---------- .../Page/V3/spacemap/SpaceMapSTDMap.h | 57 ++++++++---------- .../Storages/Page/V3/tests/gtest_free_map.cpp | 7 +++ 3 files changed, 60 insertions(+), 62 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index dbc088792bd..2576dce128a 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -11,8 +11,8 @@ static inline void rb_link_node(struct rb_node * node, struct rb_node ** rb_link) { node->parent = (uintptr_t)parent; - node->node_left = NULL; - node->node_right = NULL; + node->node_left = nullptr; + node->node_right = nullptr; *rb_link = node; } @@ -23,12 +23,12 @@ static inline void rb_link_node(struct rb_node * node, // Its local debug info, So don't us LOG static void rb_tree_debug(struct rb_root * root, const char * method_call) { - struct rb_node * node = NULL; + struct rb_node * node = nullptr; struct smap_rb_entry * entry; node = rb_tree_first(root); printf("call in %s", method_call); - for (node = rb_tree_first(root); node != NULL; node = rb_tree_next(node)) + for (node = rb_tree_first(root); node != nullptr; node = rb_tree_next(node)) { entry = node_to_entry(node); printf(" Space - (%llu -> %llu)\n", entry->start, entry->start + entry->count); @@ -48,7 +48,7 @@ static void rb_get_new_entry(struct smap_rb_entry ** entry, UInt64 start, UInt64 struct smap_rb_entry * new_entry; new_entry = (struct smap_rb_entry *)calloc(1, sizeof(struct smap_rb_entry)); - if (new_entry == NULL) + if (new_entry == nullptr) { return; } @@ -65,17 +65,17 @@ inline static void rb_free_entry(struct rb_private * private_data, struct smap_r */ if (private_data->write_index == entry) { - private_data->write_index = NULL; + private_data->write_index = nullptr; } if (private_data->read_index == entry) { - private_data->read_index = NULL; + private_data->read_index = nullptr; } if (private_data->read_index_next == entry) { - private_data->read_index_next = NULL; + private_data->read_index_next = nullptr; } free(entry); @@ -85,20 +85,18 @@ inline static void rb_free_entry(struct rb_private * private_data, struct smap_r static bool rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * private_data, Poco::Logger * log) { struct rb_root * root = &private_data->root; - struct rb_node *parent = NULL, **n = &root->rb_node; + struct rb_node *parent = nullptr, **n = &root->rb_node; struct rb_node *new_node, *node, *next; struct smap_rb_entry * new_entry; struct smap_rb_entry * entry; bool retval = true; - (void)log; - if (count == 0) { return false; } - private_data->read_index_next = NULL; + private_data->read_index_next = nullptr; entry = private_data->write_index; if (entry) { @@ -215,7 +213,7 @@ static bool rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * priv no_need_insert: // merge entry to the right - for (node = rb_tree_next(new_node); node != NULL; node = next) + for (node = rb_tree_next(new_node); node != nullptr; node = next) { next = rb_tree_next(node); entry = node_to_entry(node); @@ -255,14 +253,14 @@ static bool rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * priv static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * private_data, Poco::Logger * log) { struct rb_root * root = &private_data->root; - struct rb_node *parent = NULL, **n = &root->rb_node; + struct rb_node *parent = nullptr, **n = &root->rb_node; struct rb_node * node; struct smap_rb_entry * entry; UInt64 new_start, new_count; bool marked = false; // Root node have not been init - if (private_data->root.rb_node == NULL) + if (private_data->root.rb_node == nullptr) { assert(false); } @@ -337,7 +335,7 @@ static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * priv } // Checking the right node - for (; parent != NULL; parent = node) + for (; parent != nullptr; parent = node) { node = rb_tree_next(parent); entry = node_to_entry(parent); @@ -378,17 +376,17 @@ static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * priv bool RBTreeSpaceMap::newSmap() { rb_tree = (struct rb_private *)calloc(1, sizeof(struct rb_private)); - if (rb_tree == NULL) + if (rb_tree == nullptr) { return false; } rb_tree->root = { - NULL, + nullptr, }; - rb_tree->read_index = NULL; - rb_tree->read_index_next = NULL; - rb_tree->write_index = NULL; + rb_tree->read_index = nullptr; + rb_tree->read_index_next = nullptr; + rb_tree->write_index = nullptr; if (!rb_insert_entry(start, end, rb_tree, log)) { @@ -425,7 +423,7 @@ void RBTreeSpaceMap::freeSmap() void RBTreeSpaceMap::smapStats() { - struct rb_node * node = NULL; + struct rb_node * node = nullptr; struct smap_rb_entry * entry; UInt64 count = 0; UInt64 max_size = 0; @@ -438,7 +436,7 @@ void RBTreeSpaceMap::smapStats() } LOG_DEBUG(log, "RB-Tree entries status: "); - for (node = rb_tree_first(&rb_tree->root); node != NULL; node = rb_tree_next(node)) + for (node = rb_tree_first(&rb_tree->root); node != nullptr; node = rb_tree_next(node)) { entry = node_to_entry(node); LOG_DEBUG(log, " Space: " << count << " start:" << entry->start << " size : " << entry->count); @@ -458,7 +456,7 @@ void RBTreeSpaceMap::smapStats() bool RBTreeSpaceMap::isSmapMarkUsed(UInt64 _start, size_t len) { - struct rb_node *parent = NULL, **n; + struct rb_node *parent = nullptr, **n; struct rb_node *node, *next; struct smap_rb_entry * entry; bool retval = false; @@ -466,7 +464,7 @@ bool RBTreeSpaceMap::isSmapMarkUsed(UInt64 _start, n = &rb_tree->root.rb_node; _start -= start; - if (len == 0 || rb_tree->root.rb_node == NULL) + if (len == 0 || rb_tree->root.rb_node == nullptr) { assert(0); } @@ -515,12 +513,12 @@ std::pair RBTreeSpaceMap::searchSmapInsertOffset(size_t size) { UInt64 offset = UINT64_MAX; UInt64 max_cap = 0; - struct rb_node * node = NULL; + struct rb_node * node = nullptr; struct smap_rb_entry * entry; UInt64 _biggest_cap = 0; UInt64 _biggest_range = 0; - for (node = rb_tree_first(&rb_tree->root); node != NULL; node = rb_tree_next(node)) + for (node = rb_tree_first(&rb_tree->root); node != nullptr; node = rb_tree_next(node)) { entry = node_to_entry(node); if (entry->count >= size) @@ -537,10 +535,10 @@ std::pair RBTreeSpaceMap::searchSmapInsertOffset(size_t size) } } - // not place found. + // No enough space for insert if (!node) { - LOG_ERROR(log, "Not sure why can't found any place to insert. [old biggest_range= " << biggest_range << "] [old biggest_cap=" << biggest_cap << "] [new biggest_range=" << _biggest_range << "] [new biggest_cap=" << _biggest_cap << "]"); + LOG_ERROR(log, "Not sure why can't found any place to insert.[size=" << size << "] [old biggest_range= " << biggest_range << "] [old biggest_cap=" << biggest_cap << "] [new biggest_range=" << _biggest_range << "] [new biggest_cap=" << _biggest_cap << "]"); biggest_range = _biggest_range; biggest_cap = _biggest_cap; @@ -593,7 +591,7 @@ std::pair RBTreeSpaceMap::searchSmapInsertOffset(size_t size) } } - for (; node != NULL; node = rb_tree_next(node)) + for (; node != nullptr; node = rb_tree_next(node)) { entry = node_to_entry(node); if (entry->count > _biggest_cap) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 9b33f96ed2a..5dbf06e969e 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -66,22 +66,18 @@ class STDMapSpaceMap bool isSmapMarkUsed(UInt64 block, size_t num) override { - for (auto it = free_map.begin(); it != free_map.end(); it++) - { - // block in the space - if (it->first <= block && (it->first + it->second) > block) - { - // end of block still in the space - return (it->first + it->second) >= (num + block); - } + auto it = free_map.lower_bound(block); - if (it->first >= block) - { - break; - } + if (it == free_map.end()) + { + it--; + } + else if (it->first > block && it != free_map.begin()) + { + it--; } - return false; + return (it->first <= block && (it->first + it->second >= block + num)); } bool markSmapUsed(UInt64 offset, size_t length) override @@ -170,7 +166,7 @@ class STDMapSpaceMap // not place found. if (it == free_map.end()) { - LOG_ERROR(log, "Not sure why can't found any place to insert.[old biggest_range= " << biggest_range << "] [old biggest_cap=" << biggest_cap << "] [new biggest_range=" << _biggest_range << "] [new biggest_cap=" << _biggest_cap << "]"); + LOG_ERROR(log, "Not sure why can't found any place to insert. [size=" << size << "] [old biggest_range= " << biggest_range << "] [old biggest_cap=" << biggest_cap << "] [new biggest_range=" << _biggest_range << "] [new biggest_cap=" << _biggest_cap << "]"); biggest_range = _biggest_range; biggest_cap = _biggest_cap; @@ -185,8 +181,7 @@ class STDMapSpaceMap // It is champion, need update if (it->first == biggest_range) { - auto it_cur = it++; - free_map.erase(it_cur); + it = free_map.erase(it); // still need search for max_cap } else // It not champion, just return @@ -198,28 +193,27 @@ class STDMapSpaceMap } else { + // Shrink the free block by `size` auto k = it->first + size; auto v = it->second - size; - free_map.erase(it); - free_map.insert({k, v}); + it = free_map.erase(it); + it = free_map.insert(/*hint=*/it, {k, v}); // Use the `it` after erased as a hint, should be good for performance - // It is champion, need update - if (k - size == biggest_range) - { - if (v > _biggest_cap) - { - _biggest_cap = v; - _biggest_range = k; - } - it = free_map.find(k); - // still need search for max_cap - } - else // It not champion, just return + // It not champion, just return + if (k - size != biggest_range) { max_cap = biggest_cap; return std::make_pair(offset, max_cap); } + + // It is champion, need to update `_biggest_cap`, `_biggest_range` + // and scan other free blocks to update `biggest_range` and `biggest_cap` + if (v > _biggest_cap) + { + _biggest_cap = v; + _biggest_range = k; + } } for (; it != free_map.end(); it++) @@ -232,9 +226,8 @@ class STDMapSpaceMap } biggest_range = _biggest_range; biggest_cap = _biggest_cap; - max_cap = biggest_cap; - return std::make_pair(offset, max_cap); + return std::make_pair(offset, biggest_cap); } bool markSmapFree(UInt64 offset, size_t length) override diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index f57729b4238..9ce100fbcf3 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -263,6 +263,13 @@ TEST_P(SpaceMapTest, TestMargins2) ASSERT_TRUE(smap->check(genChecker(ranges2, 2), 2)); } +TEST(AAA, nulld) +{ + std::map map; + map.insert({0, 100}); + auto it = map.lower_bound(1); + std::cout << "rc:" << (int)(it == map.end()) << std::endl; +} INSTANTIATE_TEST_CASE_P( Type, From 986ffc2961c643e8f13f94528279cd6fb1ed42bb Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Tue, 7 Dec 2021 20:26:10 +0800 Subject: [PATCH 18/36] update --- dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp | 2 +- dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h | 6 +++--- dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp | 8 -------- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index 2576dce128a..1ccfad0bb94 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -439,7 +439,7 @@ void RBTreeSpaceMap::smapStats() for (node = rb_tree_first(&rb_tree->root); node != nullptr; node = rb_tree_next(node)) { entry = node_to_entry(node); - LOG_DEBUG(log, " Space: " << count << " start:" << entry->start << " size : " << entry->count); + LOG_DEBUG(log, " Space: " << count << " start:" << entry->start << " size: " << entry->count); count++; if (entry->count > max_size) { diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 5dbf06e969e..4567a16c85a 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -182,9 +182,9 @@ class STDMapSpaceMap if (it->first == biggest_range) { it = free_map.erase(it); - // still need search for max_cap + // Still need search for max_cap } - else // It not champion, just return + else // It is not champion, just return { free_map.erase(it); max_cap = biggest_cap; @@ -200,7 +200,7 @@ class STDMapSpaceMap it = free_map.erase(it); it = free_map.insert(/*hint=*/it, {k, v}); // Use the `it` after erased as a hint, should be good for performance - // It not champion, just return + // It is not champion, just return if (k - size != biggest_range) { max_cap = biggest_cap; diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index 9ce100fbcf3..0a7f404928e 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -263,14 +263,6 @@ TEST_P(SpaceMapTest, TestMargins2) ASSERT_TRUE(smap->check(genChecker(ranges2, 2), 2)); } -TEST(AAA, nulld) -{ - std::map map; - map.insert({0, 100}); - auto it = map.lower_bound(1); - std::cout << "rc:" << (int)(it == map.end()) << std::endl; -} - INSTANTIATE_TEST_CASE_P( Type, SpaceMapTest, From efe48bf46b6f3b96782e4b083d59ca1d98068931 Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Wed, 8 Dec 2021 11:52:52 +0800 Subject: [PATCH 19/36] Fix var naming Signed-off-by: JaySon-Huang --- .../Page/V3/spacemap/SpaceMapSTDMap.h | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 4567a16c85a..ea99ba5f25e 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include @@ -64,20 +65,20 @@ class STDMapSpaceMap } } - bool isSmapMarkUsed(UInt64 block, size_t num) override + bool isSmapMarkUsed(UInt64 offset, size_t length) override { - auto it = free_map.lower_bound(block); + auto it = free_map.lower_bound(offset); if (it == free_map.end()) { it--; } - else if (it->first > block && it != free_map.begin()) + else if (it->first > offset && it != free_map.begin()) { it--; } - return (it->first <= block && (it->first + it->second >= block + num)); + return (it->first <= offset && (it->first + it->second >= offset + length)); } bool markSmapUsed(UInt64 offset, size_t length) override @@ -111,10 +112,11 @@ class STDMapSpaceMap } else { - auto _offset = it->first + length; - auto _size = it->second - length; + // Shrink the free block + auto shrink_offset = it->first + length; + auto shrink_size = it->second - length; free_map.erase(it); - free_map[_offset] = _size; + free_map[shrink_offset] = shrink_size; } } else if (it->first + it->second == offset + length) @@ -143,8 +145,9 @@ class STDMapSpaceMap { UInt64 offset = UINT64_MAX; UInt64 max_cap = 0; - UInt64 _biggest_cap = 0; - UInt64 _biggest_range = 0; + // The biggest free block capacity and its start offset + UInt64 scan_biggest_cap = 0; + UInt64 scan_biggest_offset = 0; auto it = free_map.begin(); for (; it != free_map.end(); it++) @@ -153,22 +156,20 @@ class STDMapSpaceMap { break; } - else + // Keep track of the biggest free block we scanned before `it` + if (it->second > scan_biggest_cap) { - if (it->second > _biggest_cap) - { - _biggest_cap = it->second; - _biggest_range = it->first; - } + scan_biggest_cap = it->second; + scan_biggest_offset = it->first; } } - // not place found. + // No enough space for insert if (it == free_map.end()) { - LOG_ERROR(log, "Not sure why can't found any place to insert. [size=" << size << "] [old biggest_range= " << biggest_range << "] [old biggest_cap=" << biggest_cap << "] [new biggest_range=" << _biggest_range << "] [new biggest_cap=" << _biggest_cap << "]"); - biggest_range = _biggest_range; - biggest_cap = _biggest_cap; + LOG_ERROR(log, "Not sure why can't found any place to insert. [size=" << size << "] [old biggest_offset=" << biggest_offset << "] [old biggest_cap=" << biggest_cap << "] [new biggest_offset=" << scan_biggest_offset << "] [new biggest_cap=" << scan_biggest_cap << "]"); + biggest_offset= scan_biggest_offset; + biggest_cap = scan_biggest_cap; return std::make_pair(offset, max_cap); } @@ -179,7 +180,7 @@ class STDMapSpaceMap if (it->second == size) { // It is champion, need update - if (it->first == biggest_range) + if (it->first == biggest_offset) { it = free_map.erase(it); // Still need search for max_cap @@ -201,31 +202,31 @@ class STDMapSpaceMap it = free_map.insert(/*hint=*/it, {k, v}); // Use the `it` after erased as a hint, should be good for performance // It is not champion, just return - if (k - size != biggest_range) + if (k - size != biggest_offset) { max_cap = biggest_cap; return std::make_pair(offset, max_cap); } - // It is champion, need to update `_biggest_cap`, `_biggest_range` - // and scan other free blocks to update `biggest_range` and `biggest_cap` - if (v > _biggest_cap) + // It is champion, need to update `scan_biggest_cap`, `scan_biggest_offset` + // and scan other free blocks to update `biggest_offset` and `biggest_cap` + if (v > scan_biggest_cap) { - _biggest_cap = v; - _biggest_range = k; + scan_biggest_cap = v; + scan_biggest_offset = k; } } for (; it != free_map.end(); it++) { - if (it->second > _biggest_cap) + if (it->second > scan_biggest_cap) { - _biggest_cap = it->second; - _biggest_range = it->first; + scan_biggest_cap = it->second; + scan_biggest_offset = it->first; } } - biggest_range = _biggest_range; - biggest_cap = _biggest_cap; + biggest_offset = scan_biggest_offset; + biggest_cap = scan_biggest_cap; return std::make_pair(offset, biggest_cap); } @@ -321,7 +322,8 @@ class STDMapSpaceMap private: // Save the of free blocks std::map free_map; - UInt64 biggest_range = 0; + // Keep track of the biggest free block. Save its biggest capacity and start offset. + UInt64 biggest_offset = 0; UInt64 biggest_cap = 0; }; From 59ac245f530fbc3f683c592684fd7bfd10eb1277 Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Wed, 8 Dec 2021 12:03:02 +0800 Subject: [PATCH 20/36] Format files Signed-off-by: JaySon-Huang --- dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index ea99ba5f25e..3e0cf39d8af 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -168,7 +168,7 @@ class STDMapSpaceMap if (it == free_map.end()) { LOG_ERROR(log, "Not sure why can't found any place to insert. [size=" << size << "] [old biggest_offset=" << biggest_offset << "] [old biggest_cap=" << biggest_cap << "] [new biggest_offset=" << scan_biggest_offset << "] [new biggest_cap=" << scan_biggest_cap << "]"); - biggest_offset= scan_biggest_offset; + biggest_offset = scan_biggest_offset; biggest_cap = scan_biggest_cap; return std::make_pair(offset, max_cap); From 5b991d172ccafee833d17dc7e34d8f64d7647f61 Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Wed, 8 Dec 2021 12:07:37 +0800 Subject: [PATCH 21/36] Fix misleading naming Signed-off-by: JaySon-Huang --- dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp | 2 +- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 4 ++-- dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp | 4 ++-- dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h | 2 +- dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index d071ccff2b3..ed812dcdf9e 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -86,7 +86,7 @@ bool SpaceMap::isMarkUsed(UInt64 offset, size_t length) ErrorCodes::LOGICAL_ERROR); } - return !isSmapMarkUsed(offset, length); + return !isMarkUnused(offset, length); } std::pair SpaceMap::searchInsertOffset(size_t size) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index d45188d8b1a..8116edeecec 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -128,8 +128,8 @@ class SpaceMap /* Print space maps status */ virtual void smapStats() = 0; - /* Space map bit/bits test operators */ - virtual bool isSmapMarkUsed(UInt64 offset, size_t size) = 0; + // Return true if space [offset, offset+size) are all free + virtual bool isMarkUnused(UInt64 offset, size_t size) = 0; /* Space map mark used/free operators */ virtual bool markSmapUsed(UInt64 offset, size_t size) = 0; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index 1ccfad0bb94..80118939f32 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -453,8 +453,8 @@ void RBTreeSpaceMap::smapStats() } } -bool RBTreeSpaceMap::isSmapMarkUsed(UInt64 _start, - size_t len) +bool RBTreeSpaceMap::isMarkUnused(UInt64 _start, + size_t len) { struct rb_node *parent = nullptr, **n; struct rb_node *node, *next; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h index 254128c39cc..88411e831f7 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h @@ -62,7 +62,7 @@ class RBTreeSpaceMap void smapStats() override; - bool isSmapMarkUsed(UInt64 block, size_t num) override; + bool isMarkUnused(UInt64 block, size_t num) override; bool markSmapUsed(UInt64 block, size_t num) override; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 3e0cf39d8af..97049040c9d 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -65,7 +65,7 @@ class STDMapSpaceMap } } - bool isSmapMarkUsed(UInt64 offset, size_t length) override + bool isMarkUnused(UInt64 offset, size_t length) override { auto it = free_map.lower_bound(offset); From 1329ae651bdeba42ad6eca7189ada981834f1021 Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Wed, 8 Dec 2021 15:34:16 +0800 Subject: [PATCH 22/36] fix build --- dbms/src/Storages/CMakeLists.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dbms/src/Storages/CMakeLists.txt b/dbms/src/Storages/CMakeLists.txt index bab6aa04fef..0d6dcd5c19d 100644 --- a/dbms/src/Storages/CMakeLists.txt +++ b/dbms/src/Storages/CMakeLists.txt @@ -6,13 +6,10 @@ if (ENABLE_TESTS) add_subdirectory (tests EXCLUDE_FROM_ALL) add_subdirectory (Transaction/tests EXCLUDE_FROM_ALL) add_subdirectory (Page/V2/tests EXCLUDE_FROM_ALL) - if (ENABLE_V3_PAGESTORAGE) - add_subdirectory (Page/V3/tests EXCLUDE_FROM_ALL) - endif () - add_subdirectory (DeltaMerge/tests EXCLUDE_FROM_ALL) if (ENABLE_V3_PAGESTORAGE) add_subdirectory (Page/V3 EXCLUDE_FROM_ALL) add_subdirectory (Page/V3/tests EXCLUDE_FROM_ALL) endif () + add_subdirectory (DeltaMerge/tests EXCLUDE_FROM_ALL) endif () From a3524971b0683e4937d5ca355b642d8dd56eff37 Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Wed, 8 Dec 2021 18:12:08 +0800 Subject: [PATCH 23/36] Abstract out finding less or equal from std::map Signed-off-by: JaySon-Huang --- .../Page/V3/spacemap/SpaceMapSTDMap.h | 41 +++++++++++++------ .../Storages/Page/V3/tests/gtest_free_map.cpp | 40 ++++++++++++++++++ 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 97049040c9d..197d344a754 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include @@ -16,6 +17,23 @@ extern const int NOT_IMPLEMENTED; namespace PS::V3 { +namespace details +{ +// Return an iterator to the last element whose key is less than or equal to `key`. +// If no such element is found, the past-the-end iterator is returned. +template +typename C::const_iterator +findLessEQ(const C & c, const typename C::key_type & key) +{ + auto iter = c.upper_bound(key); // first element > `key` + // Nothing greater than key + if (iter == c.cbegin()) + return c.cend(); + // its prev must be less than or equal to `key` + return --iter; +} + +} // namespace details class STDMapSpaceMap : public SpaceMap , public ext::SharedPtrHelper @@ -67,15 +85,11 @@ class STDMapSpaceMap bool isMarkUnused(UInt64 offset, size_t length) override { - auto it = free_map.lower_bound(offset); - + auto it = details::findLessEQ(free_map, offset); // first free block <= `offset` if (it == free_map.end()) { - it--; - } - else if (it->first > offset && it != free_map.begin()) - { - it--; + // No free blocks <= `offset` + return false; } return (it->first <= offset && (it->first + it->second >= offset + length)); @@ -83,14 +97,12 @@ class STDMapSpaceMap bool markSmapUsed(UInt64 offset, size_t length) override { - auto it = free_map.upper_bound(offset); - if (it == free_map.begin()) + auto it = details::findLessEQ(free_map, offset); // first free block <= `offset` + if (it == free_map.end()) { return false; } - --it; - // already been marked used if (it->first + it->second < offset) { @@ -112,7 +124,7 @@ class STDMapSpaceMap } else { - // Shrink the free block + // Shrink the free block from left auto shrink_offset = it->first + length; auto shrink_size = it->second - length; free_map.erase(it); @@ -121,6 +133,8 @@ class STDMapSpaceMap } else if (it->first + it->second == offset + length) { + // Shrink the free block from right + assert(it->second != length); // should not run into here free_map[it->first] = it->second - length; } else @@ -179,7 +193,8 @@ class STDMapSpaceMap if (it->second == size) { - // It is champion, need update + // It is champion, need to update `scan_biggest_cap`, `scan_biggest_offset` + // and scan other free blocks to update `biggest_offset` and `biggest_cap` if (it->first == biggest_offset) { it = free_map.erase(it); diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index 0a7f404928e..f5fe18917da 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -8,8 +8,48 @@ #include +#include "gtest/gtest.h" +#include "gtest/internal/gtest-internal.h" + namespace DB::PS::V3::tests { +::testing::AssertionResult MapIterCompare( + const char * lhs_expr, + const char * rhs_expr, + const std::map::const_iterator lhs, + const std::pair rhs) +{ + if (lhs->first == rhs.first && lhs->second == rhs.second) + return ::testing::AssertionSuccess(); + return ::testing::internal::EqFailure( + lhs_expr, + rhs_expr, + fmt::format("{{{},{}}}", lhs->first, lhs->second), + fmt::format("{{{}, {}}}", rhs.first, rhs.second), + false); +} + +#define ASSERT_ITER_EQ(iter, val) ASSERT_PRED_FORMAT2(MapIterCompare, iter, val) + +TEST(STDMapUtil, FindLessEqual) +{ + std::map m0{}; + ASSERT_EQ(details::findLessEQ(m0, 1), m0.end()); + + std::map m1{{1, 1}, {2, 2}, {3, 3}, {6, 6}}; + ASSERT_EQ(details::findLessEQ(m1, 0), m1.end()); + ASSERT_ITER_EQ(details::findLessEQ(m1, 1), std::make_pair(1, 1)); + ASSERT_ITER_EQ(details::findLessEQ(m1, 2), std::make_pair(2, 2)); + ASSERT_ITER_EQ(details::findLessEQ(m1, 3), std::make_pair(3, 3)); + for (int x = 4; x < 20; ++x) + { + if (x < 6) + ASSERT_ITER_EQ(details::findLessEQ(m1, x), std::make_pair(3, 3)); + else + ASSERT_ITER_EQ(details::findLessEQ(m1, x), std::make_pair(6, 6)); + } +} + struct Range { size_t start; From 70c7c63601db76031683b63de9ba09748408f7a4 Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Wed, 8 Dec 2021 19:46:57 +0800 Subject: [PATCH 24/36] Cleanup redunt space in loggings Signed-off-by: JaySon-Huang --- .../Storages/Page/V3/spacemap/SpaceMap.cpp | 6 +++--- .../Page/V3/spacemap/SpaceMapRBTree.cpp | 14 ++++++------- .../Page/V3/spacemap/SpaceMapSTDMap.h | 20 +++++++++---------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index ed812dcdf9e..af2cb8477af 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -58,7 +58,7 @@ bool SpaceMap::markFree(UInt64 offset, size_t length) if (checkSpace(offset, length)) { throw Exception("Unmark space out of the limit space.[type=" + typeToString(getType()) - + "] [block=" + DB::toString(offset) + "], [size = " + DB::toString(length) + "]", + + "] [block=" + DB::toString(offset) + "], [size=" + DB::toString(length) + "]", ErrorCodes::LOGICAL_ERROR); } @@ -70,7 +70,7 @@ bool SpaceMap::markUsed(UInt64 offset, size_t length) if (checkSpace(offset, length)) { throw Exception("Mark space out of the limit space.[type=" + typeToString(getType()) - + "] [block=" + DB::toString(offset) + "], [size = " + DB::toString(length) + "]", + + "] [block=" + DB::toString(offset) + "], [size=" + DB::toString(length) + "]", ErrorCodes::LOGICAL_ERROR); } @@ -82,7 +82,7 @@ bool SpaceMap::isMarkUsed(UInt64 offset, size_t length) if (checkSpace(offset, length)) { throw Exception("Test space out of the limit space.[type=" + typeToString(getType()) - + "] [block=" + DB::toString(offset) + "], [size = " + DB::toString(length) + "]", + + "] [block=" + DB::toString(offset) + "], [size=" + DB::toString(length) + "]", ErrorCodes::LOGICAL_ERROR); } diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index 80118939f32..1f351908fa5 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -138,7 +138,7 @@ static bool rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * priv auto * _entry = node_to_entry(_node); if (start + count > _entry->start) { - LOG_WARNING(log, "Marked space free failed. [offset = " << start << ", size= " << count << "], next node is [offset=" << _entry->start << ",size=" << _entry->count << "]"); + LOG_WARNING(log, "Marked space free failed. [offset=" << start << ", size=" << count << "], next node is [offset=" << _entry->start << ",size=" << _entry->count << "]"); return false; } } @@ -177,7 +177,7 @@ static bool rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * priv entry = node_to_entry(node); if (entry->start + entry->count > new_entry->start) { - LOG_WARNING(log, "Marked space free failed. [offset = " << new_entry->start << ", size= " << new_entry->count << "], prev node is [offset=" << entry->start << ",size=" << entry->count << "]"); + LOG_WARNING(log, "Marked space free failed. [offset=" << new_entry->start << ", size=" << new_entry->count << "], prev node is [offset=" << entry->start << ",size=" << entry->count << "]"); rb_node_remove(new_node, root); rb_free_entry(private_data, new_entry); return false; @@ -190,7 +190,7 @@ static bool rb_insert_entry(UInt64 start, UInt64 count, struct rb_private * priv entry = node_to_entry(node); if (new_entry->start + new_entry->count > entry->start) { - LOG_WARNING(log, "Marked space free failed. [offset = " << new_entry->start << ", size= " << new_entry->count << "], next node is [offset=" << entry->start << ",size=" << entry->count << "]"); + LOG_WARNING(log, "Marked space free failed. [offset=" << new_entry->start << ", size=" << new_entry->count << "], next node is [offset=" << entry->start << ",size=" << entry->count << "]"); rb_node_remove(new_node, root); rb_free_entry(private_data, new_entry); return false; @@ -287,13 +287,13 @@ static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * priv if ((start + count) > (entry->start + entry->count)) { - LOG_WARNING(log, "Marked space used failed. [offset = " << start << ", size= " << count << "] is bigger than space [offset=" << entry->start << ",size=" << entry->count << "]"); + LOG_WARNING(log, "Marked space used failed. [offset=" << start << ", size=" << count << "] is bigger than space [offset=" << entry->start << ",size=" << entry->count << "]"); return false; } if (start < entry->start) { - LOG_WARNING(log, "Marked space used failed. [offset = " << start << ", size= " << count << "] is less than space [offset=" << entry->start << ",size=" << entry->count << "]"); + LOG_WARNING(log, "Marked space used failed. [offset=" << start << ", size=" << count << "] is less than space [offset=" << entry->start << ",size=" << entry->count << "]"); return false; } @@ -390,7 +390,7 @@ bool RBTreeSpaceMap::newSmap() if (!rb_insert_entry(start, end, rb_tree, log)) { - LOG_ERROR(log, "Erorr happend, when mark all space free. [start=" << start << "] , [end = " << end << "]"); + LOG_ERROR(log, "Erorr happend, when mark all space free. [start=" << start << "] , [end=" << end << "]"); free(rb_tree); return false; } @@ -538,7 +538,7 @@ std::pair RBTreeSpaceMap::searchSmapInsertOffset(size_t size) // No enough space for insert if (!node) { - LOG_ERROR(log, "Not sure why can't found any place to insert.[size=" << size << "] [old biggest_range= " << biggest_range << "] [old biggest_cap=" << biggest_cap << "] [new biggest_range=" << _biggest_range << "] [new biggest_cap=" << _biggest_cap << "]"); + LOG_ERROR(log, "Not sure why can't found any place to insert.[size=" << size << "] [old biggest_range=" << biggest_range << "] [old biggest_cap=" << biggest_cap << "] [new biggest_range=" << _biggest_range << "] [new biggest_cap=" << _biggest_cap << "]"); biggest_range = _biggest_range; biggest_cap = _biggest_cap; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 197d344a754..2a4dbf3e422 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -111,7 +111,7 @@ class STDMapSpaceMap if (length > it->second || it->first + it->second < offset + length) { - LOG_WARNING(log, "Marked space used failed. [offset = " << offset << ", size= " << length << "] is bigger than space [offset=" << it->first << ",size=" << it->second << "]"); + LOG_WARNING(log, "Marked space used failed. [offset=" << offset << ", size=" << length << "] is bigger than space [offset=" << it->first << ",size=" << it->second << "]"); return false; } @@ -193,19 +193,17 @@ class STDMapSpaceMap if (it->second == size) { - // It is champion, need to update `scan_biggest_cap`, `scan_biggest_offset` - // and scan other free blocks to update `biggest_offset` and `biggest_cap` - if (it->first == biggest_offset) - { - it = free_map.erase(it); - // Still need search for max_cap - } - else // It is not champion, just return + // It is not champion, just return + if (it->first != biggest_offset) { free_map.erase(it); max_cap = biggest_cap; return std::make_pair(offset, max_cap); } + + // It is champion, need to update `scan_biggest_cap`, `scan_biggest_offset` + // and scan other free blocks to update `biggest_offset` and `biggest_cap` + it = free_map.erase(it); } else { @@ -277,7 +275,7 @@ class STDMapSpaceMap it_prev--; if (it_prev->first + it_prev->second > it->first) { - LOG_WARNING(log, "Marked space free failed. [offset = " << it->first << ", size= " << it->second << "], prev node is [offset=" << it_prev->first << ",size=" << it_prev->second << "]"); + LOG_WARNING(log, "Marked space free failed. [offset=" << it->first << ", size=" << it->second << "], prev node is [offset=" << it_prev->first << ",size=" << it_prev->second << "]"); free_map.erase(it); return false; } @@ -288,7 +286,7 @@ class STDMapSpaceMap { if (it->first + it->second > it_next->first) { - LOG_WARNING(log, "Marked space free failed. [offset = " << it->first << ", size= " << it->second << "], next node is [offset=" << it_next->first << ",size=" << it_next->second << "]"); + LOG_WARNING(log, "Marked space free failed. [offset=" << it->first << ", size=" << it->second << "], next node is [offset=" << it_next->first << ",size=" << it_next->second << "]"); free_map.erase(it); return false; } From f51117caaf9300e7984fb3712070034d4c5aef91 Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Wed, 8 Dec 2021 20:02:30 +0800 Subject: [PATCH 25/36] Remove useless new/free virtual functions Signed-off-by: JaySon-Huang --- .../Storages/Page/V3/spacemap/SpaceMap.cpp | 3 +- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 6 ---- .../Page/V3/spacemap/SpaceMapRBTree.cpp | 29 ++++++++++--------- .../Page/V3/spacemap/SpaceMapRBTree.h | 8 ++--- .../Page/V3/spacemap/SpaceMapSTDMap.h | 10 ------- 5 files changed, 20 insertions(+), 36 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index af2cb8477af..4d5190ac99c 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -34,9 +34,8 @@ SpaceMapPtr SpaceMap::createSpaceMap(SpaceMapType type, UInt64 start, UInt64 end throw Exception("Invalid type to create spaceMap", ErrorCodes::LOGICAL_ERROR); } - if (!smap->newSmap()) + if (!smap) { - smap->freeSmap(); throw Exception("Failed create SpaceMap [type=" + typeToString(type) + "]", ErrorCodes::LOGICAL_ERROR); } diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index 8116edeecec..e2dda202d83 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -119,12 +119,6 @@ class SpaceMap virtual ~SpaceMap() = default; - /* Generic space map operators */ - virtual bool newSmap() = 0; - - /* Free the space map if necessary */ - virtual void freeSmap() = 0; - /* Print space maps status */ virtual void smapStats() = 0; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index 1f351908fa5..6a5b23b290e 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -373,29 +373,30 @@ static bool rb_remove_entry(UInt64 start, UInt64 count, struct rb_private * priv return marked; } -bool RBTreeSpaceMap::newSmap() +std::shared_ptr RBTreeSpaceMap::create(UInt64 start, UInt64 end) { - rb_tree = (struct rb_private *)calloc(1, sizeof(struct rb_private)); - if (rb_tree == nullptr) + auto ptr = std::shared_ptr(new RBTreeSpaceMap(start, end)); + + ptr->rb_tree = static_cast(calloc(1, sizeof(struct rb_private))); + if (ptr->rb_tree == nullptr) { - return false; + return nullptr; } - rb_tree->root = { + ptr->rb_tree->root = { nullptr, }; - rb_tree->read_index = nullptr; - rb_tree->read_index_next = nullptr; - rb_tree->write_index = nullptr; + ptr->rb_tree->read_index = nullptr; + ptr->rb_tree->read_index_next = nullptr; + ptr->rb_tree->write_index = nullptr; - if (!rb_insert_entry(start, end, rb_tree, log)) + if (!rb_insert_entry(start, end, ptr->rb_tree, ptr->log)) { - LOG_ERROR(log, "Erorr happend, when mark all space free. [start=" << start << "] , [end=" << end << "]"); - free(rb_tree); - return false; + LOG_ERROR(ptr->log, "Erorr happend, when mark all space free. [start=" << start << "] , [end=" << end << "]"); + free(ptr->rb_tree); + return nullptr; } - - return true; + return ptr; } static void rb_free_tree(struct rb_root * root) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h index 88411e831f7..83c12e51be0 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h @@ -40,7 +40,6 @@ inline static struct smap_rb_entry * node_to_entry(struct rb_node * node) class RBTreeSpaceMap : public SpaceMap - , public ext::SharedPtrHelper { public: ~RBTreeSpaceMap() override @@ -50,15 +49,16 @@ class RBTreeSpaceMap bool check(std::function checker, size_t size) override; + static + std::shared_ptr create(UInt64, UInt64 end); + protected: RBTreeSpaceMap(UInt64 start, UInt64 end) : SpaceMap(start, end, SMAP64_RBTREE) { } - bool newSmap() override; - - void freeSmap() override; + void freeSmap(); void smapStats() override; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 2a4dbf3e422..d83d84db32a 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -57,18 +57,8 @@ class STDMapSpaceMap protected: STDMapSpaceMap(UInt64 start, UInt64 end) : SpaceMap(start, end, SMAP64_STD_MAP) - { - } - - bool newSmap() override { free_map.insert({start, end}); - return true; - } - - void freeSmap() override - { - // no need clear } void smapStats() override From 7bbb503af0810613e4368583d607d6fdb7d4be6b Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Wed, 8 Dec 2021 20:05:32 +0800 Subject: [PATCH 26/36] Keep include header path style Signed-off-by: JaySon-Huang --- dbms/src/Storages/Page/V3/spacemap/RBTree.cpp | 4 ++-- dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp | 8 +++----- dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp | 2 +- dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h | 8 +++----- dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h | 3 +-- dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp | 2 -- 6 files changed, 10 insertions(+), 17 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/RBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/RBTree.cpp index d0a0029cfeb..8efcb911555 100644 --- a/dbms/src/Storages/Page/V3/spacemap/RBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/RBTree.cpp @@ -1,4 +1,4 @@ -#include "RBTree.h" +#include #ifdef __cplusplus extern "C" { @@ -527,4 +527,4 @@ void rb_tree_update_node(struct rb_node * old_node, struct rb_node * new_node, s #ifdef __cplusplus } // extern "C" -#endif \ No newline at end of file +#endif diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index 4d5190ac99c..af1136c0e20 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -1,15 +1,13 @@ -#include "SpaceMap.h" - #include #include +#include +#include +#include #include #include #include #include -#include "SpaceMapRBTree.h" -#include "SpaceMapSTDMap.h" - namespace DB { namespace ErrorCodes diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index 6a5b23b290e..6da703a99ef 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -1,4 +1,4 @@ -#include "SpaceMapRBTree.h" +#include namespace DB::PS::V3 diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h index 83c12e51be0..f85d03cd9d4 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h @@ -1,11 +1,10 @@ #pragma once #include +#include +#include #include -#include "RBTree.h" -#include "SpaceMap.h" - namespace DB { namespace ErrorCodes @@ -49,8 +48,7 @@ class RBTreeSpaceMap bool check(std::function checker, size_t size) override; - static - std::shared_ptr create(UInt64, UInt64 end); + static std::shared_ptr create(UInt64, UInt64 end); protected: RBTreeSpaceMap(UInt64 start, UInt64 end) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index d83d84db32a..28704ad4996 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -3,11 +3,10 @@ #include #include +#include #include #include -#include "SpaceMap.h" - namespace DB { namespace ErrorCodes diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index f5fe18917da..8f666dc6bbe 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -8,8 +8,6 @@ #include -#include "gtest/gtest.h" -#include "gtest/internal/gtest-internal.h" namespace DB::PS::V3::tests { From 5911eacaa73c10444a0d0c96f0ab9085d2b17d6d Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Wed, 8 Dec 2021 20:18:12 +0800 Subject: [PATCH 27/36] Cleanup interface Signed-off-by: JaySon-Huang --- dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp | 9 ++------- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 8 +++----- dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp | 6 +++--- dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h | 8 ++++---- dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h | 6 +++--- 5 files changed, 15 insertions(+), 22 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp index af1136c0e20..ab3d0482298 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.cpp @@ -59,7 +59,7 @@ bool SpaceMap::markFree(UInt64 offset, size_t length) ErrorCodes::LOGICAL_ERROR); } - return markSmapFree(offset, length); + return markFreeImpl(offset, length); } bool SpaceMap::markUsed(UInt64 offset, size_t length) @@ -71,7 +71,7 @@ bool SpaceMap::markUsed(UInt64 offset, size_t length) ErrorCodes::LOGICAL_ERROR); } - return markSmapUsed(offset, length); + return markUsedImpl(offset, length); } bool SpaceMap::isMarkUsed(UInt64 offset, size_t length) @@ -86,11 +86,6 @@ bool SpaceMap::isMarkUsed(UInt64 offset, size_t length) return !isMarkUnused(offset, length); } -std::pair SpaceMap::searchInsertOffset(size_t size) -{ - return searchSmapInsertOffset(size); -} - SpaceMap::SpaceMap(UInt64 start_, UInt64 end_, SpaceMapType type_) : type(type_) , start(start_) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index e2dda202d83..2b593e0c913 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -80,7 +80,7 @@ class SpaceMap * insert_offset : start offset for the inserted space * max_cap : The largest available space this SpaceMap can hold. */ - std::pair searchInsertOffset(size_t size); + virtual std::pair searchInsertOffset(size_t size) = 0; /** * Sanity check for correctness @@ -126,11 +126,9 @@ class SpaceMap virtual bool isMarkUnused(UInt64 offset, size_t size) = 0; /* Space map mark used/free operators */ - virtual bool markSmapUsed(UInt64 offset, size_t size) = 0; + virtual bool markUsedImpl(UInt64 offset, size_t size) = 0; - virtual bool markSmapFree(UInt64 offset, size_t size) = 0; - - virtual std::pair searchSmapInsertOffset(size_t size) = 0; + virtual bool markFreeImpl(UInt64 offset, size_t size) = 0; private: /* Check the range */ diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index 6da703a99ef..e9be7491f9d 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -510,7 +510,7 @@ bool RBTreeSpaceMap::isMarkUnused(UInt64 _start, return retval; } -std::pair RBTreeSpaceMap::searchSmapInsertOffset(size_t size) +std::pair RBTreeSpaceMap::searchInsertOffset(size_t size) { UInt64 offset = UINT64_MAX; UInt64 max_cap = 0; @@ -607,7 +607,7 @@ std::pair RBTreeSpaceMap::searchSmapInsertOffset(size_t size) return std::make_pair(offset, max_cap); } -bool RBTreeSpaceMap::markSmapUsed(UInt64 block, size_t size) +bool RBTreeSpaceMap::markUsedImpl(UInt64 block, size_t size) { bool rc; @@ -618,7 +618,7 @@ bool RBTreeSpaceMap::markSmapUsed(UInt64 block, size_t size) return rc; } -bool RBTreeSpaceMap::markSmapFree(UInt64 block, size_t size) +bool RBTreeSpaceMap::markFreeImpl(UInt64 block, size_t size) { bool rc; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h index f85d03cd9d4..146a3208db5 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.h @@ -50,6 +50,8 @@ class RBTreeSpaceMap static std::shared_ptr create(UInt64, UInt64 end); + std::pair searchInsertOffset(size_t size) override; + protected: RBTreeSpaceMap(UInt64 start, UInt64 end) : SpaceMap(start, end, SMAP64_RBTREE) @@ -62,11 +64,9 @@ class RBTreeSpaceMap bool isMarkUnused(UInt64 block, size_t num) override; - bool markSmapUsed(UInt64 block, size_t num) override; - - bool markSmapFree(UInt64 block, size_t num) override; + bool markUsedImpl(UInt64 block, size_t num) override; - std::pair searchSmapInsertOffset(size_t size) override; + bool markFreeImpl(UInt64 block, size_t num) override; private: struct rb_private * rb_tree; diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 28704ad4996..050708dba8d 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -84,7 +84,7 @@ class STDMapSpaceMap return (it->first <= offset && (it->first + it->second >= offset + length)); } - bool markSmapUsed(UInt64 offset, size_t length) override + bool markUsedImpl(UInt64 offset, size_t length) override { auto it = details::findLessEQ(free_map, offset); // first free block <= `offset` if (it == free_map.end()) @@ -144,7 +144,7 @@ class STDMapSpaceMap return true; } - std::pair searchSmapInsertOffset(size_t size) override + std::pair searchInsertOffset(size_t size) override { UInt64 offset = UINT64_MAX; UInt64 max_cap = 0; @@ -233,7 +233,7 @@ class STDMapSpaceMap return std::make_pair(offset, biggest_cap); } - bool markSmapFree(UInt64 offset, size_t length) override + bool markFreeImpl(UInt64 offset, size_t length) override { auto it = free_map.find(offset); From a3ed7df4914737114d471ad5b219f3a1bf63553b Mon Sep 17 00:00:00 2001 From: JaySon-Huang Date: Wed, 8 Dec 2021 20:20:05 +0800 Subject: [PATCH 28/36] Format files Signed-off-by: JaySon-Huang --- dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h | 1 - 1 file changed, 1 deletion(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 050708dba8d..fbfeb9526d0 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -3,7 +3,6 @@ #include #include -#include #include #include From d04e793999d60bf38064939755e0de3e28f4748a Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Wed, 8 Dec 2021 22:25:52 +0800 Subject: [PATCH 29/36] Update dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h Co-authored-by: JaySon --- dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index fbfeb9526d0..0b0278a2f0d 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -323,9 +323,10 @@ class STDMapSpaceMap private: // Save the of free blocks std::map free_map; - // Keep track of the biggest free block. Save its biggest capacity and start offset. - UInt64 biggest_offset = 0; - UInt64 biggest_cap = 0; + // Keep a hint track of the biggest free block. Save its biggest capacity and start offset. + // The hint could be invalid after `markSmapUsed` while restoring or `markSmapFree`. + UInt64 hint_biggest_offset = 0; + UInt64 hint_biggest_cap = 0; }; using STDMapSpaceMapPtr = std::shared_ptr; From a5e0ac89347cfc79b7f91ca409d898f5f2b49ffa Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Wed, 8 Dec 2021 22:34:37 +0800 Subject: [PATCH 30/36] update --- dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 0b0278a2f0d..bc16e71b2af 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -129,15 +129,8 @@ class STDMapSpaceMap { // In the mid, and not match the left or right. // Split to two space - if (((it->first + it->second) - offset) > length) - { - free_map.insert({offset + length, it->first + it->second - offset - length}); - free_map[it->first] = offset - it->first; - } - else - { // < length - free_map[it->first] = it->first + it->second - offset; - } + free_map.insert({offset + length, it->first + it->second - offset - length}); + free_map[it->first] = offset - it->first; } return true; From 9b5684ec3b14a154b38210cbcb8c6a6a280998ec Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Wed, 8 Dec 2021 22:40:14 +0800 Subject: [PATCH 31/36] fix some error --- .../Page/V3/spacemap/SpaceMapSTDMap.h | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index bc16e71b2af..7c67b2e6a2b 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -162,9 +162,9 @@ class STDMapSpaceMap // No enough space for insert if (it == free_map.end()) { - LOG_ERROR(log, "Not sure why can't found any place to insert. [size=" << size << "] [old biggest_offset=" << biggest_offset << "] [old biggest_cap=" << biggest_cap << "] [new biggest_offset=" << scan_biggest_offset << "] [new biggest_cap=" << scan_biggest_cap << "]"); - biggest_offset = scan_biggest_offset; - biggest_cap = scan_biggest_cap; + LOG_ERROR(log, "Not sure why can't found any place to insert. [size=" << size << "] [old biggest_offset=" << hint_biggest_offset << "] [old biggest_cap=" << hint_biggest_cap << "] [new biggest_offset=" << scan_biggest_offset << "] [new biggest_cap=" << scan_biggest_cap << "]"); + hint_biggest_offset = scan_biggest_offset; + hint_biggest_cap = scan_biggest_cap; return std::make_pair(offset, max_cap); } @@ -175,10 +175,10 @@ class STDMapSpaceMap if (it->second == size) { // It is not champion, just return - if (it->first != biggest_offset) + if (it->first != hint_biggest_offset) { free_map.erase(it); - max_cap = biggest_cap; + max_cap = hint_biggest_cap; return std::make_pair(offset, max_cap); } @@ -196,9 +196,9 @@ class STDMapSpaceMap it = free_map.insert(/*hint=*/it, {k, v}); // Use the `it` after erased as a hint, should be good for performance // It is not champion, just return - if (k - size != biggest_offset) + if (k - size != hint_biggest_offset) { - max_cap = biggest_cap; + max_cap = hint_biggest_cap; return std::make_pair(offset, max_cap); } @@ -219,10 +219,10 @@ class STDMapSpaceMap scan_biggest_offset = it->first; } } - biggest_offset = scan_biggest_offset; - biggest_cap = scan_biggest_cap; + hint_biggest_offset = scan_biggest_offset; + hint_biggest_cap = scan_biggest_cap; - return std::make_pair(offset, biggest_cap); + return std::make_pair(offset, hint_biggest_cap); } bool markFreeImpl(UInt64 offset, size_t length) override From 0ab02caf14c150ff97727e50e02ec9c6dce33c37 Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Thu, 9 Dec 2021 10:22:46 +0800 Subject: [PATCH 32/36] add tests --- .../Page/V3/spacemap/SpaceMapRBTree.cpp | 2 +- .../Page/V3/spacemap/SpaceMapSTDMap.h | 2 +- .../Storages/Page/V3/tests/gtest_free_map.cpp | 62 +++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp index e9be7491f9d..f86a2f1f245 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapRBTree.cpp @@ -543,7 +543,7 @@ std::pair RBTreeSpaceMap::searchInsertOffset(size_t size) biggest_range = _biggest_range; biggest_cap = _biggest_cap; - return std::make_pair(offset, max_cap); + return std::make_pair(offset, biggest_cap); } // Update return start diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h index 7c67b2e6a2b..d74b61c1ec8 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMapSTDMap.h @@ -166,7 +166,7 @@ class STDMapSpaceMap hint_biggest_offset = scan_biggest_offset; hint_biggest_cap = scan_biggest_cap; - return std::make_pair(offset, max_cap); + return std::make_pair(offset, hint_biggest_cap); } // Update return start diff --git a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp index 8f666dc6bbe..8123722fda4 100644 --- a/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp +++ b/dbms/src/Storages/Page/V3/tests/gtest_free_map.cpp @@ -301,6 +301,68 @@ TEST_P(SpaceMapTest, TestMargins2) ASSERT_TRUE(smap->check(genChecker(ranges2, 2), 2)); } +TEST_P(SpaceMapTest, TestSearch) +{ + auto smap = SpaceMap::createSpaceMap(test_type, 0, 100); + UInt64 offset; + UInt64 max_cap; + Range ranges[] = {{.start = 0, + .end = 100}}; + ASSERT_TRUE(smap->check(genChecker(ranges, 1), 1)); + ASSERT_TRUE(smap->markUsed(50, 10)); + + std::tie(offset, max_cap) = smap->searchInsertOffset(20); + ASSERT_EQ(offset, 0); + ASSERT_EQ(max_cap, 40); + + Range ranges1[] = {{.start = 20, + .end = 50}, + {.start = 60, + .end = 100}}; + ASSERT_TRUE(smap->check(genChecker(ranges1, 2), 2)); + + // We can't use `markFree` to restore the map status + // It won't update `max_cap`/`max_offset` which inside space map + // So just recreate a space map + smap = SpaceMap::createSpaceMap(test_type, 0, 100); + ASSERT_TRUE(smap->markUsed(50, 10)); + + std::tie(offset, max_cap) = smap->searchInsertOffset(5); + ASSERT_EQ(offset, 0); + ASSERT_EQ(max_cap, 45); + + Range ranges2[] = {{.start = 5, + .end = 50}, + {.start = 60, + .end = 100}}; + ASSERT_TRUE(smap->check(genChecker(ranges2, 2), 2)); + + // Test margin + smap = SpaceMap::createSpaceMap(test_type, 0, 100); + ASSERT_TRUE(smap->markUsed(50, 10)); + std::tie(offset, max_cap) = smap->searchInsertOffset(50); + ASSERT_EQ(offset, 0); + ASSERT_EQ(max_cap, 40); + + Range ranges3[] = {{.start = 60, + .end = 100}}; + ASSERT_TRUE(smap->check(genChecker(ranges3, 1), 1)); + + // Test invalid Size + smap = SpaceMap::createSpaceMap(test_type, 0, 100); + ASSERT_TRUE(smap->markUsed(50, 10)); + std::tie(offset, max_cap) = smap->searchInsertOffset(100); + ASSERT_EQ(offset, UINT64_MAX); + ASSERT_EQ(max_cap, 50); + + // No changed + Range ranges4[] = {{.start = 0, + .end = 50}, + {.start = 60, + .end = 100}}; + ASSERT_TRUE(smap->check(genChecker(ranges4, 2), 2)); +} + INSTANTIATE_TEST_CASE_P( Type, SpaceMapTest, From a639b66c9ca3704ec54e39547fdf7d80775660e9 Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Thu, 9 Dec 2021 11:22:26 +0800 Subject: [PATCH 33/36] Update dbms/src/Storages/Page/V3/spacemap/SpaceMap.h Co-authored-by: JaySon --- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index 2b593e0c913..eeeab427201 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -71,14 +71,13 @@ class SpaceMap bool isMarkUsed(UInt64 offset, size_t length); /** - * Search a space that can fit in `size` - * SpaceMap will loop the range from start. - * After it found a range which can fit this `size`. - * It will decide if there needs to keep traverse to update `max_cap`. + * Search a span that can fit in `size`. + * If such span is found, it will also return a hint of the max capacity available + * in this SpaceMap. * - * Return value is : + * return value is : * insert_offset : start offset for the inserted space - * max_cap : The largest available space this SpaceMap can hold. + * max_cap : A hint of the largest available space this SpaceMap can hold. */ virtual std::pair searchInsertOffset(size_t size) = 0; From 39ce4d8ae71894b53358c5bcaa3d94e7485b8ae7 Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Thu, 9 Dec 2021 11:22:34 +0800 Subject: [PATCH 34/36] Update dbms/src/Storages/Page/V3/spacemap/SpaceMap.h Co-authored-by: JaySon --- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index eeeab427201..daaf9c37228 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -62,11 +62,11 @@ class SpaceMap bool markUsed(UInt64 offset, size_t length); /** - * Test a space [offset,offset + length) have been used or not. + * Check a span [offset, offset + length) has been used or not. * * ret value: - * true: This space is used, or some sub space is used - * false: This space is freed, all of space is freed for use. + * true: This span is used, or some sub span is used + * false: All of this span is freed. */ bool isMarkUsed(UInt64 offset, size_t length); From 466f5b1331548dbe2bf539a1b2687cc9761425de Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Thu, 9 Dec 2021 11:22:40 +0800 Subject: [PATCH 35/36] Update dbms/src/Storages/Page/V3/spacemap/SpaceMap.h Co-authored-by: JaySon --- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index daaf9c37228..d67e6e39837 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -51,13 +51,12 @@ class SpaceMap bool markFree(UInt64 offset, size_t length); /** - * Mark a space [offset,offset + length) of the space map. - * After this space been marked. - * When user use `searchInsertOffset` to get a space. - * This space won't be selected. + * Mark a span [offset,offset + length) to being used. + * After this span is marked used, this span can not be selected by `searchInsertOffset`. + * * ret value: - * false: This space is freed, marked all space used. - * true: This space is used, or some sub space is used. + * false: This span is marked as used successfully. + * true: This span can not be marked as used. It or some sub spans have been marked as used before. */ bool markUsed(UInt64 offset, size_t length); From 00bf672fbb956afd91a9b2debd5c19252262611e Mon Sep 17 00:00:00 2001 From: jiaqizho Date: Thu, 9 Dec 2021 11:22:47 +0800 Subject: [PATCH 36/36] Update dbms/src/Storages/Page/V3/spacemap/SpaceMap.h Co-authored-by: JaySon --- dbms/src/Storages/Page/V3/spacemap/SpaceMap.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h index d67e6e39837..b4bea9effc8 100644 --- a/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h +++ b/dbms/src/Storages/Page/V3/spacemap/SpaceMap.h @@ -38,15 +38,12 @@ class SpaceMap static SpaceMapPtr createSpaceMap(SpaceMapType type, UInt64 start, UInt64 end); /** - * Mark a space [offset,offset + length) free of the space map. - * After mark this space freed. - * When user use `searchInsertOffset` to get a space. - * Then this space may been selected(If request size fit space size - * and it is the first freed space). + * Mark a span [offset,offset + length) to be free. + * After this span is marked free, this span may be selected by `searchInsertOffset`. * * ret value: - * true: mark the space which is used. - * false: mark the space which is freed. + * true: the span is marked as free + * false: the span can not mark as free */ bool markFree(UInt64 offset, size_t length);