Skip to content

Commit

Permalink
library: btree_blue - a simple btree with rapid linear traversal
Browse files Browse the repository at this point in the history
Subject: library: btree_blue - a simple btree with rapid linear traversal V7.2

This is a bug-fixed version. Thanks Uladzislau Rezki very much for testing.

btree_blue is a simple btree whose algorithm implementation comes from Joern
Engel's lib/btree. btree_blue extended lib/btree with several features and
optimizations:

	Added Two-way links between leaf-nodes to offer a very fast linear traversal.

	Besides rapid linear traversal, insert, search, delete are also relatively
	fast comparing with btree, rbtee, even though with a big node size (4K)
	btree_blue is still some fast.

	The 0 value of key itself is allowed.

	Node size can be choosed in 256, 512, 1024, 2K, 4K. Or 192, 384 ...

	Key length has sizes of one long, two longs (32-bit OS).

Joern Engel's lib/btree represents an elegance in logical and is fast and
effective (100% slots usage). When I decided to add new features on it, which
are required for me and in many practices, I found it is a challenge to keep
speed and effective with lib/btree, so I have to do several optimizings to keep
or (hopefully) get more performance.

Basically, traversal in btree_blue is 8x (800%) faster than btree, 14x (1400%)
faster than rbtree. Random insert/search/delete is 30% ~ 50% faster than btree
and is 2x (200%) ~ 3x (300%) faster than rbtree, 2x (200%) ~ 4x (400%) faster
than maple tree.

Note, those comparisons may not much fair for the three trees: maple tree is
RCU-safe and can deal with many complex cases, rbtree support duplicated keys,
lib/btree's grace logical has virtue itself ...

Signed-off-by: Liu Weifeng 4019c26b5c0d5f6b <liuwf@mailbox.org>
  • Loading branch information
Liu Weifeng 4019c26b5c0d5f6b authored and intel-lab-lkp committed May 9, 2023
1 parent fbe1871 commit fba954c
Show file tree
Hide file tree
Showing 5 changed files with 1,715 additions and 0 deletions.
85 changes: 85 additions & 0 deletions include/linux/btree_blue.h
@@ -0,0 +1,85 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef BTREE_BLUE_H
#define BTREE_BLUE_H

#include <linux/kernel.h>
#include <linux/mempool.h>

#define MAX_TREE_HEIGHT 8
#define MIN_SLOTS_NUMBER 16
#define MIN_NODE_SIZE (MIN_SLOTS_NUMBER * 2 * sizeof(unsigned long))

#define GET_PREV 0
#define GET_NEXT 1

struct btree_blue_head;
struct btree_blue_node_cb;

struct btree_blue_head {
unsigned long *node;

u16 node_size;
u16 leaf_size;
u16 stub_base;
u8 keylen;
u8 slot_width;
u8 height;
u8 reserved[1];

u16 slot_vols[MAX_TREE_HEIGHT + 1];
};

void *btree_blue_alloc(gfp_t gfp_mask, void *pool_data);

void btree_blue_free(void *element, void *pool_data);

int __must_check btree_blue_init(struct btree_blue_head *head,
int node_size_in_byte, int key_len_in_byte,
int flags);

void btree_blue_destroy(struct btree_blue_head *head);

void *btree_blue_lookup(struct btree_blue_head *head, unsigned long *key);

int __must_check btree_blue_insert(struct btree_blue_head *head,
unsigned long *key, void *val, gfp_t gfp);

int btree_blue_update(struct btree_blue_head *head, unsigned long *key,
void *val);

void *btree_blue_remove(struct btree_blue_head *head, unsigned long *key);

void *btree_blue_first(struct btree_blue_head *head, unsigned long *__key);
void *btree_blue_last(struct btree_blue_head *head, unsigned long *__key);

void *btree_blue_get_prev(struct btree_blue_head *head, unsigned long *__key);
void *btree_blue_get_next(struct btree_blue_head *head, unsigned long *__key);

typedef bool (*btree_blue_traverse_FN_T)(const unsigned long *key,
const void *val);

/*
* Visit each key-value pair started from the @key and continue toward
* @prev_or_next until the last or fisrt.
*
* IF @key is given NULL, visit starts with the last(the biggest) key and walk
* toward the smallest.
*
* @prev_or_next, bool value to specify the visit direction.
*
* @callback. Your function that is called in the visit loop with each key-value
* visited.
* If a function like : bool myfunc(const unsigned long *key, const void *val)
* is given to the param @callback, you will see every *key and *val from the
* start @key(included, and it's value). Your function's return value of 0
* indicates to continue visit and 1 to exit the loop.
*
* @return value. The API return the number of key-value pairs visited.
*
* */
size_t btree_blue_traverse_from_key(struct btree_blue_head *head,
unsigned long *key,
btree_blue_traverse_FN_T callback,
bool prev_or_next);

#endif
8 changes: 8 additions & 0 deletions lib/Kconfig
Expand Up @@ -466,6 +466,14 @@ config TEXTSEARCH_FSM
config BTREE
bool

config BTREE_BLUE
tristate
default m

config BTREE_BLUE_TEST
tristate
default m

config INTERVAL_TREE
bool
help
Expand Down
2 changes: 2 additions & 0 deletions lib/Makefile
Expand Up @@ -152,6 +152,8 @@ obj-$(CONFIG_TRACE_MMIO_ACCESS) += trace_readwrite.o
obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o

obj-$(CONFIG_BTREE) += btree.o
obj-$(CONFIG_BTREE_BLUE) += btree_blue.o
obj-$(CONFIG_BTREE_BLUE_TEST) += btree_blue_test.o
obj-$(CONFIG_INTERVAL_TREE) += interval_tree.o
obj-$(CONFIG_ASSOCIATIVE_ARRAY) += assoc_array.o
obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
Expand Down

0 comments on commit fba954c

Please sign in to comment.