├── .gitignore
├── .travis.yml
├── LICENSE
├── README.en.md
├── README.md
├── gen_test_data.sh
├── src
├── Makefile
├── art
│ ├── art.cpp
│ ├── art.hpp
│ ├── node.cpp
│ └── node.hpp
├── blink
│ ├── b_link_tree.cpp
│ ├── b_link_tree.hpp
│ ├── bounded_mapping_queue.hpp
│ ├── db.cpp
│ ├── db.hpp
│ ├── hash_entry.hpp
│ ├── log.hpp
│ ├── page.cpp
│ ├── page.hpp
│ ├── page_pool.cpp
│ ├── page_pool.hpp
│ ├── pool_manager.cpp
│ ├── pool_manager.hpp
│ ├── slice.hpp
│ ├── task.hpp
│ └── thread_pool_mapping.hpp
├── include
│ ├── atomic.hpp
│ ├── bounded_list.hpp
│ ├── bounded_queue.hpp
│ ├── cond.hpp
│ ├── guard.hpp
│ ├── latch.hpp
│ ├── mutex.hpp
│ ├── spin_lock.hpp
│ ├── thread.hpp
│ ├── thread_pool.hpp
│ └── utility.hpp
├── network
│ ├── buffer.cpp
│ ├── buffer.hpp
│ ├── callback.hpp
│ ├── channel.cpp
│ ├── channel.hpp
│ ├── connection.cpp
│ ├── connection.hpp
│ ├── endpoint.cpp
│ ├── endpoint.hpp
│ ├── eventbase.cpp
│ ├── eventbase.hpp
│ ├── poller.cpp
│ ├── poller.hpp
│ ├── server.cpp
│ ├── server.hpp
│ ├── signal.hpp
│ ├── socket.cpp
│ ├── socket.hpp
│ └── time.hpp
├── palm
│ ├── barrier.hpp
│ ├── batch.cpp
│ ├── batch.hpp
│ ├── batcher.cpp
│ ├── batcher.hpp
│ ├── palm_tree.cpp
│ └── palm_tree.hpp
├── raft
│ ├── arg.hpp
│ ├── log.hpp
│ ├── mushroom_log.hpp
│ ├── raft_server.cpp
│ └── raft_server.hpp
├── rpc
│ ├── future.hpp
│ ├── marshaller.hpp
│ ├── rpc.hpp
│ ├── rpc_connection.cpp
│ ├── rpc_connection.hpp
│ ├── rpc_server.cpp
│ └── rpc_server.hpp
└── run
├── test
├── art.cpp
├── barrier.cpp
├── batch.cpp
├── batcher.cpp
├── bloom.cpp
├── distributed_index.cpp
├── mushroom_log_vector.cpp
├── mushroom_multi_thread.cpp
├── mushroom_with_queue.cpp
├── network_client.cpp
├── network_server.cpp
├── page.cpp
├── palm.cpp
├── raft.cpp
├── rpc_call.hpp
├── rpc_client.cpp
├── rpc_server.cpp
└── unit.h
├── test_data.cpp
└── version.md
/.gitignore:
--------------------------------------------------------------------------------
1 | *_test
2 | *.o
3 | .tags*
4 | paxos
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: trusty
2 |
3 | language: cpp
4 |
5 | matrix:
6 | include:
7 | - os: linux
8 |
9 | script:
10 | - g++ -std=c++11 -O3 test_data.cpp -o test_data
11 | - cd src && make -j4 all
12 |
13 | notifications:
14 | email: never
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016-2018 UncP. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above
10 | copyright notice, this list of conditions and the following disclaimer
11 | in the documentation and/or other materials provided with the
12 | distribution.
13 | * Neither the name of Mushroom nor the names of UncP may be used
14 | to endorse or promote products derived from this software
15 | without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/README.en.md:
--------------------------------------------------------------------------------
1 | ### this repo is not updated any more,please go to [aili](https://github.com/UncP/aili)
2 | ***
3 |
4 | ## Mushroom: Distributed In-Memory Index
5 | [中文版 README](./README.md)
6 |
7 | [](./LICENSE)
8 | []()
9 | [](https://travis-ci.org/UncP/Mushroom)
10 | [](./LICENSE)
11 |
12 | #### Mushroom is a Linux light-weight distributed in-memory index written in C++11, consists of concurrent Blink tree, TCP communication library, RPC framework and Raft consensus algorithm.
13 |
14 | ### Behold, the power of Mushroom!
15 |
16 | ### Try Mushroom
17 | `first run gen_test_data.sh to generate test data, then enter src directory`
18 | `./run index 100, test distributed index on single machine,100 represents index number(raft is not well optimized, please limit number to 1-1000)`
19 | `./run blink thread 100, test multi-thread b link tree, number can be 1 to 10 million`
20 | `./run blink queue 100, test multi-thread b link tree, number can be 1 to 10 million`
21 | `./run art 100, test adaptive radix tree, number can be 1 to 10 million`
22 |
23 |
24 | ### Version Information
25 | | Version | Improvements |
26 | |:------:|:--------------------------:|
27 | | 0.1.0 | |
28 | | 0.2.0 | two-phase lock based concurrent index |
29 | | 0.2.1 | latch manager optimization |
30 | | 0.3.0 | implement prefix compaction, reducing Blink tree memory about 9.1 % |
31 | | 0.4.0 | implement **Mapping Queue**, reducing total program memory up to 50 %|
32 | | 0.4.1 | merge latch manager and page manager,reduce 1 lock per operation |
33 | | 0.4.2 | change the way B link tree root split |
34 | | 0.4.3 | new test strategy, threads conduct operations without going through the queue |
35 | | 0.4.4 | latch manager refactoring |
36 | | 0.5.0 | fix **BUG**(atomic operation bug) that exists from 0.4.1 to 0.4.4 |
37 | | 0.6.0 | multi-process supported, fix Blink tree search **bug**|
38 | | 0.6.1 | two-phase hashing page manager, implement lazy page allocation|
39 | | 0.6.2 | reduce dependency on standard library, speed up compile, reduce program size about 42.1%|
40 | | 0.6.4 |using posix spin lock, Optimize MushroomDB and BLinkTree structure|
41 | | 0.7.0 | Log-Structured Merge Tree |
42 | | 0.8.0 | TCP Communication Library & RPC Framework |
43 | | 0.9.0 | Raft |
44 | | 0.9.1 | ACID (batch operation) & modify locking strategy |
45 | | 0.9.2 | optimize Raft state transfer, improve liveness |
46 | | 1.0.0 | distributed in-memory index |
47 | | 1.1.0 | Blink tree node occupies 2/3 of node's space, originally 1/2, reducing memory use about 12% |
48 | | 1.1.1 | optimize raft memory use |
49 | | 1.2.0 | Adaptive Radix Tree |
50 | | 1.2.1 | remove latch manager, each page has its own latch, improve performance by 10% |
51 | | 1.2.2 | introducing bloom filter for write/read optimization |
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### 这个 repo 已弃用,请移步 [aili](https://github.com/UncP/aili) 查看最新进展
2 | ***
3 |
4 | ## Mushroom(蘑菇):分布式内存索引
5 | [English Version of README](./README.en.md)
6 |
7 | [](https://github.com/UncP)
8 | []()
9 | [](https://travis-ci.org/UncP/Mushroom)
10 | [](./LICENSE)
11 |
12 | #### Mushroom是一个C++11编写、不依赖第三方库的轻量级Linux环境分布式内存索引,它由并发Blink树索引,TCP通信库,RPC框架,Raft一致性算法组成。
13 |
14 | ### Behold, the power of Mushroom!
15 |
16 |
17 | ### 尝试
18 | `首先运行脚本gen_test_data.sh生成测试数据,然后进入src目录`
19 | `./run blink queue 100,测试多线程索引(通过队列),数量可以是1到1000万`
20 | `./run blink thread 100,测试多线程索引,数量可以是1到1000万`
21 | `./run art 100,测试Adaptive Radix Tree,数量可以是1到1000万`
22 | `【失效】./run index 100,单机测试分布式索引,100是索引数量(因为Raft没有深入优化过,所以请将数量控制在1-1000)`
23 |
24 |
25 | ### 版本信息
26 | | 版本 | 备注 |
27 | |:------:|:---------------------------:|
28 | | 0.1.0 | |
29 | | 0.2.0 | 读写锁并发索引 |
30 | | 0.2.1 | 锁管理器优化 |
31 | | 0.3.0 | 引入前缀压缩,Blink树占用内存减少约 9.1 %|
32 | | 0.4.0 | 实现映射队列,减少程序使用内存超过 50 %|
33 | | 0.4.1 | 合并锁管理器与页面管理器,使每次操作减少1把锁|
34 | | 0.4.2 | 修改根节点分裂方式 |
35 | | 0.4.3 | 增加测试策略,多线程不经过队列直接进行任务|
36 | | 0.4.4 | 重构锁管理器 |
37 | | 0.5.0 | 修复从版本0.4.1到0.4.4一直存在的**bug**(原子操作bug)|
38 | | 0.6.0 | 共享内存映射支持多进程,修复搜索**bug**,正确实现并发Blink树|
39 | | 0.6.1 | 二次哈希页面管理器,实现页面的懒惰分配|
40 | | 0.6.2 | 减少对标准库的依赖,加快编译速度,减少程序体积约42.1%|
41 | | 0.6.4 | 使用posix自旋锁,优化MushroomDB和BLinkTree结构 |
42 | | 0.7.0 | 日志结构合并树(LSM Tree) |
43 | | 0.8.0 | TCP通信库、RPC框架 |
44 | | 0.9.0 | Raft |
45 | | 0.9.1 | ACID (批操作)、修改加锁策略 |
46 | | 0.9.2 | 优化Raft状态变化,提高Liveness |
47 | | 1.0.0 | 分布式内存索引 |
48 | | 1.1.0 | Blink树结点从1/2满提高到2/3满,降低内存使用率约12% |
49 | | 1.1.1 | 优化Raft内存使用(牺牲可读性) |
50 | | 1.2.0 | Adaptive Radix Tree |
51 | | 1.2.1 | 移除锁管理器,每个页面一把锁,性能提升约10% |
52 | | 1.2.2 | 引入布隆过滤器进行读写优化(然并卵) |
53 |
54 |
55 | ### 其他
56 | + 你可以在这个[知乎专栏](https://zhuanlan.zhihu.com/b-tree)里找到**Mushroom**的介绍
57 | + 分布式索引只是完成了单机功能,我写完就放弃优化了,所以较新的版本里`./run index`这个命令并不支持
58 |
59 | ***
60 |
61 | PS: Mushroom 是一次致力于获得**极致**存储性能的**激进**尝试,在阅读具体代码之前,请注意:
62 | 1. 编程规范、代码可读性、内存使用、接口是否友好等等一切无条件为性能做出让步
63 | 2. 但是核心 B link 树的并发算法实现很简洁
64 | 3. 对于内存的使用很极端,比如**映射队列**,介绍文章[上](https://zhuanlan.zhihu.com/p/26856329)以及[下](https://zhuanlan.zhihu.com/p/26919167)
65 | 4. 有一些指针的 Hack 操作,比如柔性数组
66 | 5. 删除和插入都是写操作,所以只有 Put(写)和 Get(读)操作(即不支持物理删除)
67 |
--------------------------------------------------------------------------------
/gen_test_data.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 |
3 | g++ -std=c++11 -O3 test_data.cpp -o test_data && ./test_data && rm test_data
4 | # mv data/10000000_0 data/10000000
5 |
--------------------------------------------------------------------------------
/src/Makefile:
--------------------------------------------------------------------------------
1 | CPP = $(CXX)
2 | CPPFLAGS = -std=c++11 -Wall -Wextra -O3
3 | LDFLAGS = -pthread
4 |
5 | BlinkFile = $(shell find blink -name '*.cpp')
6 | NetworkFile = $(shell find network -name '*.cpp')
7 | RaftFile = $(shell find raft -name '*.cpp')
8 | RpcFile = $(shell find rpc -name '*.cpp')
9 | ARTFILE = $(shell find art -name '*.cpp')
10 | PalmFile = $(shell find palm -name '*.cpp')
11 |
12 | MOBJ = $(BlinkFile:.cpp=.o)
13 | NOBJ = $(NetworkFile:.cpp=.o)
14 | RaftOBJ = $(RaftFile:.cpp=.o)
15 | RpcOBJ = $(RpcFile:.cpp=.o)
16 | AOBJ = $(ARTFILE:.cpp=.o)
17 | POBJ = $(PalmFile:.cpp=.o)
18 |
19 | default: palm_tree_test
20 |
21 | all: blinktree_with_queue_test blinktree_multi_thread_test palm_tree_test
22 |
23 | palm_tree_test: $(POBJ) ./blink/pool_manager.o ./blink/page_pool.o ./blink/page.o ../test/palm.cpp
24 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
25 |
26 | batcher_test: ../test/batcher.cpp ./palm/batcher.o ./blink/page.o
27 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
28 |
29 | batch_test: ../test/batch.cpp ./palm/batch.o
30 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
31 |
32 | barrier_test: ../test/barrier.cpp
33 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
34 |
35 | art_tree_test: $(AOBJ) ../test/art.cpp
36 | $(CPP) $(CPPFLAGS) -o $@ $^ -msse2
37 |
38 | mushroom_log_vector_test: raft/mushroom_log_vector.cpp ../test/mushroom_log_vector.cpp
39 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
40 |
41 | distributed_index_test: $(MOBJ) $(NOBJ) $(RpcOBJ) $(RaftOBJ) ../test/distributed_index.cpp
42 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
43 |
44 | raft_test: $(NOBJ) $(RpcOBJ) $(RaftOBJ) ../test/raft.cpp
45 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
46 |
47 | rpc_client_test: $(NOBJ) $(RpcOBJ) ../test/rpc_client.cpp
48 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
49 |
50 | rpc_server_test: $(NOBJ) $(RpcOBJ) ../test/rpc_server.cpp
51 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
52 |
53 | client_test: $(NOBJ) ../test/network_client.cpp
54 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
55 |
56 | server_test: $(NOBJ) ../test/network_server.cpp
57 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
58 |
59 | page_test: $(MOBJ) ../test/page.cpp
60 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
61 |
62 | blinktree_with_queue_test: $(MOBJ) ../test/mushroom_with_queue.cpp
63 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
64 |
65 | blinktree_multi_thread_test: $(MOBJ) ../test/mushroom_multi_thread.cpp
66 | $(CPP) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
67 |
68 | .cpp.o:
69 | $(CPP) $(CPPFLAGS) -c $< -o $@ $(DFLAGS) $(LDFLAGS)
70 |
71 | tag:
72 | cd .. && ctags -R -f .tags
73 |
74 | clean:
75 | rm */*.o
76 | rm -rf *_test
77 |
--------------------------------------------------------------------------------
/src/art/art.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-06-21 10:40:44
6 | **/
7 |
8 | #include
9 |
10 | #include "node.hpp"
11 | #include "art.hpp"
12 |
13 | namespace Mushroom {
14 |
15 | ART::ART():root_(0) { }
16 |
17 | static Node** Descend(Node *cur, char byte)
18 | {
19 | union {
20 | Node4 *p4;
21 | Node16 *p16;
22 | Node48 *p48;
23 | Node256 *p256;
24 | }p;
25 | switch(cur->Type()) {
26 | case NODE4 : p.p4 = (Node4 *)cur; return p.p4 ->Descend(byte);
27 | case NODE16 : p.p16 = (Node16 *)cur; return p.p16 ->Descend(byte);
28 | case NODE48 : p.p48 = (Node48 *)cur; return p.p48 ->Descend(byte);
29 | case NODE256 : p.p256 = (Node256 *)cur; return p.p256->Descend(byte);
30 | default : assert(0);
31 | }
32 | }
33 |
34 | static void AddChild(Node *cur, Node **ref, uint8_t byte, void *child)
35 | {
36 | union {
37 | Node4 *p4;
38 | Node16 *p16;
39 | Node48 *p48;
40 | Node256 *p256;
41 | }p;
42 | switch(cur->Type()) {
43 | case NODE4:
44 | p.p4 = (Node4 *)cur;
45 | if (p.p4->Full()) {
46 | Node16 *node16 = new Node16(p.p4);
47 | *ref = node16;
48 | delete cur;
49 | node16->AddChild(byte, child);
50 | } else {
51 | p.p4->AddChild(byte, child);
52 | }
53 | break;
54 | case NODE16:
55 | p.p16 = (Node16 *)cur;
56 | if (p.p16->Full()) {
57 | Node48 *node48 = new Node48(p.p16);
58 | *ref = node48;
59 | delete cur;
60 | node48->AddChild(byte, child);
61 | } else {
62 | p.p16->AddChild(byte, child);
63 | }
64 | break;
65 | case NODE48:
66 | p.p48 = (Node48 *)cur;
67 | if (p.p48->Full()) {
68 | Node256 *node256 = new Node256(p.p48);
69 | *ref = node256;
70 | delete cur;
71 | node256->AddChild(byte, child);
72 | } else {
73 | p.p48->AddChild(byte, child);
74 | }
75 | break;
76 | case NODE256:
77 | p.p256 = (Node256 *)cur;
78 | p.p256->AddChild(byte, child);
79 | break;
80 | default:
81 | assert(0);
82 | }
83 | }
84 |
85 | static bool Insert(Node *cur, Node **ref, const uint8_t *key, uint32_t depth, uint32_t len, uint32_t val)
86 | {
87 | if (!cur) {
88 | *ref = (Node *)SET_LEAF(NewLeaf(key, len, val));
89 | return true;
90 | }
91 |
92 | if (IS_LEAF(cur)) {
93 | Leaf *leaf = LEAF_RAW(cur);
94 | if (leaf->Match(key, len)) return false;
95 |
96 | Leaf *leaf2 = NewLeaf(key, len, val);
97 | uint32_t prefix_len = leaf->CommonPrefix(depth, leaf2);
98 |
99 | Node4 *node4 = new Node4();
100 | *ref = (Node *)node4;
101 |
102 | node4->SetPrefix(key + depth, prefix_len);
103 |
104 | node4->AddChild(leaf->KeyAt(depth + prefix_len), SET_LEAF(leaf));
105 | node4->AddChild(leaf2->KeyAt(depth + prefix_len), SET_LEAF(leaf2));
106 | return true;
107 | }
108 |
109 | if (cur->PrefixLen()) {
110 | uint32_t prefix_diff = cur->MismatchPrefix(key, len, depth);
111 | if (prefix_diff >= cur->PrefixLen()) {
112 | depth += cur->PrefixLen();
113 | goto Recurse_Search;
114 | }
115 |
116 | Node4 *node4 = new Node4();
117 | *ref = (Node *)node4;
118 | node4->SetPrefix(cur->Prefix(), prefix_diff);
119 |
120 | if (node4->PrefixLen() <= Node::MAX_PREFIX_LEN) {
121 | node4->AddChild(cur->Prefix()[prefix_diff], cur);
122 | cur->AdjustPrefix(prefix_diff);
123 | } else {
124 | Leaf *leaf = Node::Minimum(cur);
125 | node4->AddChild(leaf->KeyAt(depth + prefix_diff), cur);
126 | cur->AdjustPrefix(prefix_diff, leaf->Key() + depth);
127 | }
128 |
129 | Leaf *leaf = NewLeaf(key, len, val);
130 | node4->AddChild(key[depth + prefix_diff], SET_LEAF(leaf));
131 | return true;
132 | }
133 |
134 | Recurse_Search:
135 | Node **child = Descend(cur, key[depth]);
136 | if (child)
137 | return Insert(*child, child, key, depth + 1, len, val);
138 |
139 | Leaf *leaf = NewLeaf(key, len, val);
140 | AddChild(cur, ref, key[depth], SET_LEAF(leaf));
141 | return true;
142 | }
143 |
144 | bool ART::Put(const uint8_t *key, uint32_t len, uint32_t val)
145 | {
146 | return Insert(root_, &root_, key, 0, len, val);
147 | }
148 |
149 | bool ART::Get(const uint8_t *key, uint32_t len, uint32_t *val)
150 | {
151 | Node *cur = root_;
152 | uint32_t depth = 0;
153 | while (cur) {
154 | if (IS_LEAF(cur)) {
155 | Leaf *leaf = LEAF_RAW(cur);
156 | if (leaf->Match(key, len)) {
157 | *val = leaf->Value();
158 | return true;
159 | }
160 | return false;
161 | }
162 |
163 | if (cur->PrefixLen()) {
164 | uint32_t prefix_len = cur->CheckPrefix(key, len, depth);
165 | if (prefix_len != std::min(Node::MAX_PREFIX_LEN, cur->PrefixLen()))
166 | return false;
167 | depth += cur->PrefixLen();
168 | }
169 |
170 | Node **child = Descend(cur, key[depth]);
171 | cur = child ? *child : 0;
172 | ++depth;
173 | }
174 | return false;
175 | }
176 |
177 | ART::~ART()
178 | {
179 | Free(root_);
180 | }
181 |
182 | } // namespace Mushroom
183 |
--------------------------------------------------------------------------------
/src/art/art.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-06-20 18:42:03
6 | **/
7 |
8 | #ifndef _ART_HPP_
9 | #define _ART_HPP_
10 |
11 | class Node;
12 |
13 | namespace Mushroom {
14 |
15 | class ART
16 | {
17 | public:
18 | ART();
19 |
20 | bool Put(const uint8_t *key, uint32_t len, uint32_t val);
21 |
22 | bool Get(const uint8_t *key, uint32_t len, uint32_t *val);
23 |
24 | ~ART();
25 |
26 | private:
27 | Node *root_;
28 | };
29 |
30 | } // namespace Mushroom
31 |
32 | #endif /* _ART_HPP_ */
--------------------------------------------------------------------------------
/src/art/node.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-06-30 10:10:10
6 | **/
7 |
8 | #include
9 |
10 | #include "node.hpp"
11 |
12 | namespace Mushroom {
13 |
14 | uint32_t Node::MAX_PREFIX_LEN = 8;
15 |
16 | void Free(Node *node)
17 | {
18 | if (!node) return ;
19 |
20 | if (IS_LEAF(node)) {
21 | DeleteLeaf(LEAF_RAW(node));
22 | return ;
23 | }
24 |
25 | int i;
26 | union {
27 | Node4 *p4;
28 | Node16 *p16;
29 | Node48 *p48;
30 | Node256 *p256;
31 | }p;
32 | switch (node->Type()) {
33 | case NODE4:
34 | p.p4 = (Node4 *)node;
35 | for (i = 0; i < node->Count(); ++i)
36 | Free(p.p4->ChildAt(i));
37 | break;
38 | case NODE16:
39 | p.p16 = (Node16 *)node;
40 | for (i = 0; i < node->Count(); ++i)
41 | Free(p.p16->ChildAt(i));
42 | break;
43 | case NODE48:
44 | p.p48 = (Node48 *)node;
45 | for (i = 0; i < node->Count(); ++i)
46 | Free(p.p48->ChildAt(i));
47 | break;
48 | case NODE256:
49 | p.p256 = (Node256 *)node;
50 | for (i = 0; i < 256; ++i)
51 | if (p.p256->ChildAt(i))
52 | Free(p.p256->ChildAt(i));
53 | break;
54 | default:
55 | assert(0);
56 | }
57 | delete node;
58 | }
59 |
60 | Leaf* Node::Minimum(const Node *node)
61 | {
62 | if (!node) return 0;
63 | if (IS_LEAF(node)) return LEAF_RAW(node);
64 |
65 | int idx;
66 | union {
67 | const Node48 *p48;
68 | const Node256 *p256;
69 | }p;
70 | switch (node->Type()) {
71 | case NODE4:
72 | return Minimum(((const Node4 *)node)->ChildAt(0));
73 | case NODE16:
74 | return Minimum(((const Node16 *)node)->ChildAt(0));
75 | case NODE48:
76 | idx = 0;
77 | p.p48 = (const Node48 *)node;
78 | while (!p.p48->KeyAt(idx)) ++idx;
79 | idx = p.p48->KeyAt(idx) - 1;
80 | return Minimum(p.p48->ChildAt(idx));
81 | case NODE256:
82 | idx = 0;
83 | p.p256 = (const Node256 *)node;
84 | while (!p.p256->ChildAt(idx)) ++idx;
85 | return Minimum(p.p256->ChildAt(idx));
86 | default:
87 | assert(0);
88 | }
89 | }
90 |
91 | } // namespace Mushroom
92 |
--------------------------------------------------------------------------------
/src/art/node.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-06-21 09:42:33
6 | **/
7 |
8 | #ifndef _NODE_HPP_
9 | #define _NODE_HPP_
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | namespace Mushroom {
17 |
18 | enum NodeType { NODE4 = 0x0, NODE16, NODE48, NODE256, LEAF };
19 |
20 | #define IS_LEAF(x) (uintptr_t(x) & 1)
21 | #define SET_LEAF(x) (void *)(uintptr_t(x) | 1)
22 | #define LEAF_RAW(x) (Leaf *)(uintptr_t(x) & ~1)
23 |
24 | class Leaf
25 | {
26 | public:
27 | Leaf(const uint8_t *key, uint32_t len, uint32_t val):val_(val), len_(len) {
28 | memcpy(key_, key, len_);
29 | }
30 |
31 | inline bool Match(const uint8_t *key, uint32_t len) const {
32 | if (len != len_) return false;
33 | return !memcmp(key_, key, len_);
34 | }
35 |
36 | uint32_t CommonPrefix(uint32_t depth, const Leaf *that) const {
37 | int max_cmp = std::min(this->len_, that->len_) - depth;
38 | int idx;
39 | for (idx = 0; idx < max_cmp; ++idx)
40 | if (this->key_[depth + idx] != that->key_[depth + idx])
41 | return idx;
42 | return idx;
43 | }
44 |
45 | inline uint32_t KeyLen() const { return len_; }
46 |
47 | inline uint8_t KeyAt(uint32_t idx) const {
48 | return key_[idx];
49 | }
50 |
51 | inline uint32_t Value() const { return val_; }
52 |
53 | inline const uint8_t* Key() const { return key_; }
54 |
55 | private:
56 | uint32_t val_;
57 | uint32_t len_;
58 | uint8_t key_[0];
59 | };
60 |
61 | inline Leaf* NewLeaf(const uint8_t *key, uint32_t len, uint32_t val) {
62 | return new (new char[sizeof(Leaf) + len]) Leaf(key, len, val);
63 | }
64 |
65 | inline void DeleteLeaf(Leaf *leaf) {
66 | delete [] (char *)leaf;
67 | }
68 |
69 | class Node
70 | {
71 | public:
72 | Node(NodeType type):type_(type), count_(0), len_(0) { }
73 |
74 | Node(NodeType type, uint8_t count, uint32_t len, const uint8_t *prefix)
75 | :type_(type), count_(count), len_(len) {
76 | memcpy(prefix_, prefix, std::min(MAX_PREFIX_LEN, len_));
77 | }
78 |
79 | inline NodeType Type() const { return (NodeType)type_; }
80 |
81 | inline uint8_t Count() const { return count_; }
82 |
83 | inline void SetPrefix(const uint8_t *prefix, uint32_t len) {
84 | len_ = len;
85 | memcpy(prefix_, prefix, std::min(MAX_PREFIX_LEN, len_));
86 | }
87 |
88 | inline uint32_t CheckPrefix(const uint8_t *key, uint32_t len, uint32_t depth) {
89 | int max_cmp = std::min(int(std::min(len_, MAX_PREFIX_LEN)), int(len - depth));
90 | int idx;
91 | for (idx = 0; idx < max_cmp; ++idx)
92 | if (prefix_[idx] != key[depth + idx])
93 | return idx;
94 | return idx;
95 | }
96 |
97 | inline void AdjustPrefix(uint32_t len) {
98 | len_ -= len + 1;
99 | memmove(prefix_, prefix_ + len + 1, std::min(MAX_PREFIX_LEN, len_));
100 | }
101 |
102 | inline void AdjustPrefix(uint32_t len, const uint8_t *key) {
103 | len_ -= len + 1;
104 | memcpy(prefix_, key + len + 1, std::min(MAX_PREFIX_LEN, len_));
105 | }
106 |
107 | inline const uint8_t* Prefix() const { return prefix_; }
108 |
109 | inline uint32_t PrefixLen() const { return len_; }
110 |
111 | uint32_t MismatchPrefix(const uint8_t *key, uint32_t len, uint32_t depth) {
112 | int max_cmp = std::min(int(std::min(MAX_PREFIX_LEN, len_)), int(len - depth));
113 | int idx;
114 | for (idx = 0; idx < max_cmp; ++idx) {
115 | if (prefix_[idx] != key[depth + idx])
116 | return idx;
117 | }
118 |
119 | if (len_ > MAX_PREFIX_LEN) {
120 | Leaf *leaf = Minimum(this);
121 | max_cmp = std::min(leaf->KeyLen(), len) - depth;
122 | for (; idx < max_cmp; ++idx) {
123 | if (leaf->KeyAt(depth + idx) != key[depth + idx])
124 | return idx;
125 | }
126 | }
127 | return idx;
128 | }
129 |
130 | Node(const Node &) = delete;
131 | Node& operator=(const Node &) = delete;
132 |
133 | static uint32_t MAX_PREFIX_LEN;
134 |
135 | static Leaf* Minimum(const Node *node);
136 |
137 | protected:
138 | inline void IncrCount() { ++count_; }
139 |
140 | private:
141 | uint8_t type_;
142 | uint8_t count_;
143 | uint32_t len_;
144 | uint8_t prefix_[8]; // MAX_PREFIX_LEN
145 | };
146 |
147 | class Node4 : public Node
148 | {
149 | public:
150 | Node4():Node(NODE4) { memset(key_, 0, 4); }
151 |
152 | inline bool Full() const { return Count() == 4; }
153 |
154 | inline const uint8_t* Key() const { return key_; }
155 |
156 | inline const Node* Child() const { return (const Node *)child_; }
157 |
158 | inline Node* ChildAt(uint32_t idx) const {
159 | return child_[idx];
160 | }
161 |
162 | Node** Descend(uint8_t byte) {
163 | for (int i = 0; i < Count(); ++i)
164 | if (key_[i] == byte)
165 | return &child_[i];
166 | return 0;
167 | }
168 |
169 | void AddChild(uint8_t byte, void *child) {
170 | int idx;
171 | for (idx = 0; idx < Count(); ++idx)
172 | if (byte < key_[idx])
173 | break;
174 | memmove(key_ + idx + 1, key_ + idx, Count() - idx);
175 | memmove(child_ + idx + 1, child_ + idx, sizeof(Node *) * (Count() - idx));
176 | key_[idx] = byte;
177 | child_[idx] = (Node *)child;
178 | IncrCount();
179 | }
180 |
181 | private:
182 | uint8_t key_[4];
183 | Node *child_[4];
184 | };
185 |
186 | class Node16 : public Node
187 | {
188 | public:
189 | Node16(const Node4 *node4)
190 | :Node(NODE16, node4->Count(), node4->PrefixLen(), node4->Prefix()) {
191 | memset(key_, 0, 16);
192 | memcpy(key_, node4->Key(), node4->Count());
193 | memcpy(child_, node4->Child(), sizeof(Node *) * node4->Count());
194 | }
195 |
196 | inline bool Full() const { return Count() == 16; }
197 |
198 | inline const Node* Child() const { return (const Node *)child_; }
199 |
200 | inline uint8_t KeyAt(uint32_t idx) const {
201 | return key_[idx];
202 | }
203 |
204 | inline Node* ChildAt(uint32_t idx) const {
205 | return child_[idx];
206 | }
207 |
208 | Node** Descend(uint8_t byte) {
209 | __m128i cmp = _mm_cmpeq_epi8(_mm_set1_epi8(byte), _mm_loadu_si128((__m128i *)key_));
210 | int bit = _mm_movemask_epi8(cmp) & ((1 << Count()) - 1);
211 | if (bit) return &child_[__builtin_ctz(bit)];
212 | else return 0;
213 | }
214 |
215 | void AddChild(uint8_t byte, void *child) {
216 | __m128i cmp = _mm_cmplt_epi8(_mm_set1_epi8(byte), _mm_loadu_si128((__m128i *)key_));
217 | int bit = _mm_movemask_epi8(cmp) & ((1 << Count()) - 1);
218 | int idx;
219 | if (bit) {
220 | idx = __builtin_ctz(bit);
221 | memmove(key_ + idx + 1, key_ + idx, Count() - idx);
222 | memmove(child_ + idx + 1, child_ + idx, sizeof(Node *) * (Count() - idx));
223 | } else {
224 | idx = Count();
225 | }
226 | key_[idx] = byte;
227 | child_[idx] = (Node *)child;
228 | IncrCount();
229 | }
230 |
231 | private:
232 | uint8_t key_[16];
233 | Node *child_[16];
234 | };
235 |
236 | class Node48 : public Node
237 | {
238 | public:
239 | Node48(const Node16 *node16)
240 | :Node(NODE48, node16->Count(), node16->PrefixLen(), node16->Prefix()) {
241 | memset(index_, 0, 256); memset(child_, 0, sizeof(Node *) * 48);
242 | memcpy(child_, node16->Child(), sizeof(Node *) * node16->Count());
243 | for (uint8_t i = 0; i < node16->Count(); ++i)
244 | index_[node16->KeyAt(i)] = i + 1;
245 | }
246 |
247 | inline bool Full() const { return Count() == 48; }
248 |
249 | inline uint8_t KeyAt(uint32_t idx) const {
250 | return index_[idx];
251 | }
252 |
253 | inline Node* ChildAt(uint32_t idx) const {
254 | return child_[idx];
255 | }
256 |
257 | Node** Descend(uint8_t byte) {
258 | uint8_t idx = index_[byte];
259 | if (idx)
260 | return &child_[idx - 1];
261 | return 0;
262 | }
263 |
264 | void AddChild(uint8_t byte, void *child) {
265 | int idx = 0;
266 | while (child_[idx]) ++idx;
267 | index_[byte] = idx + 1;
268 | child_[idx] = (Node *)child;
269 | IncrCount();
270 | }
271 |
272 | private:
273 | uint8_t index_[256];
274 | Node *child_[48];
275 | };
276 |
277 | class Node256 : public Node
278 | {
279 | public:
280 | Node256(const Node48 *node48)
281 | :Node(NODE256, node48->Count(), node48->PrefixLen(), node48->Prefix()) {
282 | memset(child_, 0, sizeof(Node *) * 256);
283 | for (uint32_t i = 0; i < 256; ++i)
284 | if (node48->KeyAt(i))
285 | child_[i] = node48->ChildAt(node48->KeyAt(i) - 1);
286 | }
287 |
288 | inline Node* ChildAt(uint32_t idx) const {
289 | return child_[idx];
290 | }
291 |
292 | Node** Descend(uint8_t byte) {
293 | return &child_[byte];
294 | }
295 |
296 | void AddChild(uint8_t byte, void *child) {
297 | child_[byte] = (Node *)child;
298 | IncrCount();
299 | }
300 |
301 | private:
302 | Node *child_[256];
303 | };
304 |
305 | void Free(Node *node);
306 |
307 | } // namespace Mushroom
308 |
309 | #endif /* _NODE_HPP_ */
--------------------------------------------------------------------------------
/src/blink/b_link_tree.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2016-10-07 20:12:13
6 | **/
7 |
8 | #include
9 |
10 | #include "b_link_tree.hpp"
11 | #include "page.hpp"
12 | #include "pool_manager.hpp"
13 |
14 | namespace Mushroom {
15 |
16 | BLinkTree::BLinkTree(uint32_t key_len)
17 | :pool_manager_(new PoolManager()), root_(0), key_len_(key_len)
18 | {
19 | degree_ = Page::CalculateDegree(key_len_);
20 | Set set;
21 | set.page_ = pool_manager_->NewPage(Page::ROOT, key_len_, 0, degree_);
22 | set.page_->InsertInfiniteKey();
23 | }
24 |
25 | BLinkTree::~BLinkTree()
26 | {
27 | delete pool_manager_;
28 | }
29 |
30 | void BLinkTree::Free()
31 | {
32 | pool_manager_->Free();
33 | }
34 |
35 | void BLinkTree::DescendToLeaf(const KeySlice *key, Set &set, LockType type)
36 | {
37 | set.page_no_ = root_.get();
38 | set.page_ = pool_manager_->GetPage(set.page_no_);
39 | uint8_t level = set.page_->level_;
40 | for (; level;) {
41 | set.page_->LockShared();
42 | page_t pre_no = set.page_->page_no_;
43 | set.page_no_ = set.page_->Descend(key);
44 | set.page_->UnlockShared();
45 | set.page_ = pool_manager_->GetPage(set.page_no_);
46 | if (set.page_->level_ != level) {
47 | set.stack_[set.depth_++] = pre_no;
48 | --level;
49 | }
50 | }
51 | if (type == WriteLock)
52 | set.page_->Lock();
53 | else
54 | set.page_->LockShared();
55 | }
56 |
57 | bool BLinkTree::Split(Set &set, KeySlice *key)
58 | {
59 | if (set.page_->type_ != Page::ROOT) {
60 | Page *right = pool_manager_->NewPage(set.page_->type_, set.page_->key_len_,
61 | set.page_->level_, set.page_->degree_);
62 | set.page_->Split(right, key);
63 | set.page_->Unlock();
64 | assert(set.depth_);
65 | set.page_no_ = set.stack_[--set.depth_];
66 | set.page_ = pool_manager_->GetPage(set.page_no_);
67 | set.page_->Lock();
68 | Insert(set, key);
69 | return true;
70 | } else {
71 | uint8_t level = set.page_->level_;
72 | Page *new_root = pool_manager_->NewPage(Page::ROOT, key_len_, level + 1, degree_);
73 | Page *right = pool_manager_->NewPage(level ? Page::BRANCH : Page::LEAF,
74 | set.page_->key_len_, level, degree_);
75 |
76 | new_root->InsertInfiniteKey();
77 | new_root->AssignFirst(set.page_->page_no_);
78 |
79 | set.page_->type_ = level ? Page::BRANCH : Page::LEAF;
80 | set.page_->Split(right, key);
81 |
82 | page_t page_no = 0;
83 | new_root->Insert(key, page_no);
84 | root_ = new_root->page_no_;
85 | return false;
86 | }
87 | }
88 |
89 | void BLinkTree::Insert(Set &set, KeySlice *key)
90 | {
91 | InsertStatus status;
92 | for (; (status = set.page_->Insert(key, set.page_no_));) {
93 | assert(status == MoveRight);
94 | Latch *pre = set.page_->GetLatch();
95 | set.page_ = pool_manager_->GetPage(set.page_no_);
96 | set.page_->Lock();
97 | pre->Unlock();
98 | }
99 | }
100 |
101 | // this is the entrance for putting a key in b link tree
102 | bool BLinkTree::Put(KeySlice *key)
103 | {
104 | Set set;
105 |
106 | DescendToLeaf(key, set, WriteLock);
107 |
108 | Insert(set, key);
109 |
110 | for (; set.page_->NeedSplit() && Split(set, key); )
111 | continue;
112 |
113 | set.page_->Unlock();
114 | return true;
115 | }
116 |
117 | // this is the entrance for getting a key in b link tree
118 | bool BLinkTree::Get(KeySlice *key)
119 | {
120 | Set set;
121 |
122 | DescendToLeaf(key, set, ReadLock);
123 |
124 | for (uint16_t idx = 0; !set.page_->Search(key, &idx);) {
125 | if (idx != set.page_->total_key_) {
126 | set.page_->UnlockShared();
127 | assert(0);
128 | return false;
129 | }
130 | set.page_no_ = set.page_->Next();
131 | Latch *pre = set.page_->GetLatch();
132 | set.page_ = pool_manager_->GetPage(set.page_no_);
133 | set.page_->LockShared();
134 | pre->Unlock();
135 | }
136 |
137 | set.page_->UnlockShared();
138 | return true;
139 | }
140 |
141 | } // namespace Mushroom
142 |
--------------------------------------------------------------------------------
/src/blink/b_link_tree.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2016-10-07 20:10:30
6 | **/
7 |
8 | #ifndef _B_LINK_TREE_HPP_
9 | #define _B_LINK_TREE_HPP_
10 |
11 | #include "../include/utility.hpp"
12 | #include "../include/atomic.hpp"
13 |
14 | namespace Mushroom {
15 |
16 | class KeySlice;
17 | class Page;
18 | class PoolManager;
19 |
20 | enum LockType { WriteLock, ReadLock };
21 |
22 | class BLinkTree : private NoCopy
23 | {
24 | public:
25 | static const uint32_t MAX_KEY_LENGTH = 255;
26 |
27 | BLinkTree(uint32_t key_len);
28 |
29 | ~BLinkTree();
30 |
31 | bool Put(KeySlice *key);
32 |
33 | bool Get(KeySlice *key);
34 |
35 | void Free();
36 |
37 | private:
38 | struct Set {
39 | Set():depth_(0) { }
40 | page_t page_no_;
41 | Page *page_;
42 | page_t stack_[8];
43 | uint32_t depth_;
44 | };
45 |
46 | void DescendToLeaf(const KeySlice *key, Set &set, LockType type);
47 |
48 | bool Split(Set &set, KeySlice *key);
49 |
50 | void Insert(Set &set, KeySlice *key);
51 |
52 | PoolManager *pool_manager_;
53 |
54 | Atomic root_;
55 |
56 | uint8_t key_len_;
57 | uint16_t degree_;
58 | };
59 |
60 | } // namespace Mushroom
61 |
62 | #endif /* _B_LINK_TREE_HPP_ */
--------------------------------------------------------------------------------
/src/blink/bounded_mapping_queue.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-05 22:48:10
6 | **/
7 |
8 | #ifndef _BOUNDED_MAPPING_QUEUE_HPP_
9 | #define _BOUNDED_MAPPING_QUEUE_HPP_
10 |
11 | #include "../include/utility.hpp"
12 | #include "../include/mutex.hpp"
13 | #include "../include/cond.hpp"
14 |
15 | namespace Mushroom {
16 |
17 | template
18 | class BoundedMappingQueue : private NoCopyTemplate
19 | {
20 | public:
21 | BoundedMappingQueue(int capacity, const std::function &constructor);
22 |
23 | ~BoundedMappingQueue();
24 |
25 | inline T* Get();
26 |
27 | inline void Push();
28 |
29 | inline T* Pop(int *pos);
30 |
31 | inline void Put(int pos);
32 |
33 | void Clear();
34 |
35 | private:
36 | bool clear_;
37 | int capacity_;
38 | T* *queue_;
39 | int *avail_;
40 | int *work_;
41 | int front_;
42 | int avail_back_;
43 | int work_back_;
44 | Mutex mutex_;
45 | Cond ready_;
46 | Cond empty_;
47 | };
48 |
49 | template
50 | BoundedMappingQueue::BoundedMappingQueue(int capacity,const std::function &constructor)
51 | :clear_(false), capacity_(capacity), front_(0), avail_back_(0), work_back_(0)
52 | {
53 | if (capacity_ <= 0)
54 | capacity_ = 8;
55 | if (capacity_ > 1024)
56 | capacity_ = 1024;
57 |
58 | queue_ = new T*[capacity_];
59 | for (int i = 0; i != capacity_; ++i)
60 | queue_[i] = constructor();
61 |
62 | avail_ = new int[capacity_];
63 | for (int i = 0; i != capacity_; ++i)
64 | avail_[i] = i;
65 |
66 | work_ = new int[capacity_];
67 | for (int i = 0; i != capacity_; ++i)
68 | work_[i] = -1;
69 | }
70 |
71 | template
72 | BoundedMappingQueue::~BoundedMappingQueue()
73 | {
74 | Clear();
75 |
76 | delete [] avail_;
77 | delete [] work_;
78 |
79 | while (capacity_) delete queue_[--capacity_];
80 |
81 | delete [] queue_;
82 | }
83 |
84 | template
85 | void BoundedMappingQueue::Clear()
86 | {
87 | mutex_.Lock();
88 |
89 | if (clear_) {
90 | mutex_.Unlock();
91 | return ;
92 | }
93 |
94 | while (front_ != avail_back_ || front_ != work_back_)
95 | empty_.Wait(mutex_);
96 |
97 | clear_ = true;
98 |
99 | mutex_.Unlock();
100 | ready_.Broadcast();
101 | }
102 |
103 | template
104 | inline T* BoundedMappingQueue::Get()
105 | {
106 | mutex_.Lock();
107 | while (avail_[front_] < 0)
108 | empty_.Wait(mutex_);
109 | return queue_[avail_[front_]];
110 | }
111 |
112 | template
113 | inline void BoundedMappingQueue::Push()
114 | {
115 | work_[front_] = avail_[front_];
116 |
117 | avail_[front_] = -1;
118 | if (++front_ == capacity_) front_ = 0;
119 |
120 | mutex_.Unlock();
121 | ready_.Signal();
122 | }
123 |
124 | template
125 | inline T* BoundedMappingQueue::Pop(int *pos)
126 | {
127 | mutex_.Lock();
128 | while (work_[work_back_] < 0 && !clear_)
129 | ready_.Wait(mutex_);
130 |
131 | if (clear_) {
132 | mutex_.Unlock();
133 | *pos = -1;
134 | return 0;
135 | }
136 |
137 | *pos = work_[work_back_];
138 | T *ret = queue_[*pos];
139 |
140 | work_[work_back_] = -1;
141 | if (++work_back_ == capacity_) work_back_ = 0;
142 |
143 | mutex_.Unlock();
144 | return ret;
145 | }
146 |
147 | template
148 | inline void BoundedMappingQueue::Put(int pos)
149 | {
150 | mutex_.Lock();
151 |
152 | avail_[avail_back_] = pos;
153 | if (++avail_back_ == capacity_) avail_back_ = 0;
154 |
155 | mutex_.Unlock();
156 | empty_.Signal();
157 | }
158 |
159 | } // namespace Mushroom
160 |
161 | #endif /* _BOUNDED_MAPPING_QUEUE_HPP_ */
--------------------------------------------------------------------------------
/src/blink/db.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2016-10-10 15:34:43
6 | **/
7 |
8 | #include
9 | #include
10 |
11 | #include "db.hpp"
12 | #include "pool_manager.hpp"
13 | #include "b_link_tree.hpp"
14 | #include "pool_manager.hpp"
15 | #include "page.hpp"
16 |
17 | namespace Mushroom {
18 |
19 | MushroomDB::MushroomDB(const char *name, uint32_t key_len, uint32_t page_size,
20 | uint32_t pool_size, uint32_t hash_bits, uint32_t seg_bits)
21 | {
22 | assert(name);
23 |
24 | PoolManager::SetManagerInfo(page_size, pool_size, hash_bits, seg_bits);
25 |
26 | tree_ = new BLinkTree(key_len);
27 | }
28 |
29 | MushroomDB::~MushroomDB()
30 | {
31 | delete tree_;
32 | }
33 |
34 | bool MushroomDB::Put(KeySlice *key)
35 | {
36 | return tree_->Put(key);
37 | }
38 |
39 | bool MushroomDB::Get(KeySlice *key)
40 | {
41 | return tree_->Get(key);
42 | }
43 |
44 | void MushroomDB::Close()
45 | {
46 | tree_->Free();
47 | }
48 |
49 | } // namespace Mushroom
50 |
--------------------------------------------------------------------------------
/src/blink/db.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2016-10-10 15:32:20
6 | **/
7 |
8 | #ifndef _MUSHROOM_DB_HPP_
9 | #define _MUSHROOM_DB_HPP_
10 |
11 | #include "../include/utility.hpp"
12 |
13 | namespace Mushroom {
14 |
15 | class KeySlice;
16 | class BLinkTree;
17 |
18 | class MushroomDB : private NoCopy
19 | {
20 | public:
21 | MushroomDB(const char *name, uint32_t key_len, uint32_t page_size, uint32_t pool_size,
22 | uint32_t hash_bits, uint32_t seg_bits);
23 |
24 | bool Put(KeySlice *key);
25 |
26 | bool Get(KeySlice *key);
27 |
28 | void Close();
29 |
30 | ~MushroomDB();
31 |
32 | private:
33 | BLinkTree *tree_;
34 | };
35 |
36 | } // namespace Mushroom
37 |
38 | #endif /* _MUSHROOM_DB_HPP_ */
--------------------------------------------------------------------------------
/src/blink/hash_entry.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-07-19 16:55:10
6 | **/
7 |
8 | #include "../include/spin_lock.hpp"
9 |
10 | namespace Mushroom {
11 |
12 | class HashEntry {
13 | public:
14 | HashEntry():slot_(0) { }
15 |
16 | inline void Lock() {
17 | lock_.Lock();
18 | }
19 |
20 | inline bool TryLock() {
21 | return lock_.TryLock();
22 | }
23 |
24 | inline void Unlock() {
25 | lock_.Unlock();
26 | }
27 |
28 | inline void SetSlot(uint16_t slot) {
29 | slot_ = slot;
30 | }
31 |
32 | inline uint16_t GetSlot() const {
33 | return slot_;
34 | }
35 |
36 | private:
37 | SpinLock lock_;
38 | uint16_t slot_;
39 | };
40 |
41 | } // namespace Mushroom
42 |
--------------------------------------------------------------------------------
/src/blink/log.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-29 14:22:34
6 | **/
7 |
8 | #ifndef _MUSHROOM_LOG_HPP_
9 | #define _MUSHROOM_LOG_HPP_
10 |
11 | #include "../include/utility.hpp"
12 |
13 | namespace Mushroom {
14 |
15 | class KeySlice;
16 |
17 | class Log : private NoCopy
18 | {
19 | public:
20 | Log(uint8_t op, const KeySlice *key):op_(op), key_(key) { }
21 |
22 | private:
23 | uint8_t op_;
24 | const KeySlice *key_;
25 | };
26 |
27 | } // namespace Mushroom
28 |
29 | #endif /* _MUSHROOM_LOG_HPP_ */
--------------------------------------------------------------------------------
/src/blink/page.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2016-10-22 09:10:01
6 | **/
7 |
8 | #include
9 | #include
10 |
11 | #include "page.hpp"
12 |
13 | namespace Mushroom {
14 |
15 | uint32_t Page::PageSize = 4096;
16 |
17 | void Page::SetPageInfo(uint32_t page_size)
18 | {
19 | PageSize = page_size;
20 | }
21 |
22 | uint16_t Page::CalculateDegree(uint8_t key_len, uint8_t pre_len)
23 | {
24 | Page *page = 0;
25 | uint16_t offset = (char *)page->data_ - (char *)page + pre_len;
26 | return (PageSize - offset) / (KeySlice::ValLen + IndexByte + key_len);
27 | }
28 |
29 | Page::Page(page_t page_no, uint8_t type, uint8_t key_len, uint8_t level, uint16_t degree)
30 | {
31 | memset(this, 0, PageSize);
32 | latch_.Init();
33 | page_no_ = page_no;
34 | degree_ = degree;
35 | type_ = (uint8_t)type;
36 | key_len_ = key_len;
37 | level_ = level;
38 | }
39 |
40 | void Page::InsertInfiniteKey()
41 | {
42 | TempSlice(key);
43 | memset(key->key_, 0xFF, key_len_);
44 | page_t page_no = 0;
45 | assert(Insert(key, page_no) == InsertOk);
46 | }
47 |
48 | void Page::AssignFirst(page_t first)
49 | {
50 | first_ = first;
51 | }
52 |
53 | bool Page::Traverse(const KeySlice *key, uint16_t *idx, KeySlice **slice, int type) const
54 | {
55 | uint16_t low = 0, high = total_key_, mid = 0;
56 | uint16_t *index = Index();
57 | if (pre_len_) {
58 | int res = memcmp(key->key_, data_, pre_len_);
59 | if (res < 0) {
60 | *idx = 0;
61 | return false;
62 | } else if (res > 0) {
63 | *idx = high--;
64 | *slice = Key(index, high);
65 | return false;
66 | }
67 | }
68 | KeySlice *curr = 0;
69 | while (low != high) {
70 | mid = low + ((high - low) >> 1);
71 | curr = Key(index, mid);
72 | int res = memcmp(key->key_ + pre_len_, curr->key_, key_len_);
73 | if (res < 0) {
74 | high = mid;
75 | } else if (res > 0) {
76 | low = mid + 1;
77 | } else {
78 | if (type) {
79 | *idx = mid;
80 | *slice = Key(index, *idx);
81 | return true;
82 | } else {
83 | low = mid + 1;
84 | }
85 | }
86 | }
87 | *idx = high;
88 | if (high) *slice = Key(index, high-1);
89 | return false;
90 | }
91 |
92 | page_t Page::Descend(const KeySlice *key) const
93 | {
94 | uint16_t index;
95 | KeySlice *slice = 0;
96 | Traverse(key, &index, &slice, 0);
97 | return index ? slice->page_no_ : first_;
98 | }
99 |
100 | bool Page::Search(const KeySlice *key, uint16_t *index) const
101 | {
102 | KeySlice *slice = 0;
103 | return Traverse(key, index, &slice);
104 | }
105 |
106 | InsertStatus Page::Insert(const KeySlice *key, page_t &page_no)
107 | {
108 | uint16_t pos;
109 | KeySlice *slice = 0;
110 | bool flag = Traverse(key, &pos, &slice);
111 | if (flag)
112 | return ExistedKey;
113 | if (pos == total_key_ && pos) {
114 | page_no = Next();
115 | assert(page_no);
116 | return MoveRight;
117 | }
118 |
119 | uint16_t end = total_key_ * (KeySlice::ValLen + key_len_) + pre_len_;
120 | memcpy(data_ + end, &key->page_no_, KeySlice::ValLen);
121 | memcpy(data_ + end + KeySlice::ValLen, key->key_ + pre_len_, key_len_);
122 |
123 | uint16_t *index = Index();
124 | --index;
125 | if (pos) memmove(&index[0], &index[1], pos << 1);
126 | index[pos] = end;
127 | ++total_key_;
128 | return InsertOk;
129 | }
130 |
131 | void Page::Split(Page *that, KeySlice *slice)
132 | {
133 | uint16_t left = total_key_ >> 1, right = total_key_ - left, index = left;
134 | uint16_t *l_idx = this->Index();
135 | uint16_t *r_idx = that->Index();
136 | KeySlice *fence = Key(l_idx, left++);
137 |
138 | if (pre_len_) {
139 | memcpy(that->data_, this->data_, pre_len_);
140 | that->pre_len_ = this->pre_len_;
141 | memcpy(slice->key_, data_, pre_len_);
142 | }
143 |
144 | slice->page_no_ = that->page_no_;
145 | memcpy(slice->key_ + pre_len_, fence->key_, key_len_);
146 |
147 | if (level_) {
148 | that->AssignFirst(fence->page_no_);
149 | r_idx -= --right;
150 | ++index;
151 | } else {
152 | r_idx -= right;
153 | }
154 |
155 | uint16_t slot_len = KeySlice::ValLen + key_len_;
156 | for (uint16_t i = index, j = 0; i != total_key_; ++i, ++j) {
157 | r_idx[j] = that->pre_len_ + j * slot_len;
158 | KeySlice *l = this->Key(l_idx, i);
159 | KeySlice *r = that->Key(r_idx, j);
160 | memcpy(r, l, KeySlice::ValLen + key_len_);
161 | }
162 |
163 | fence->page_no_ = that->page_no_;
164 |
165 | uint16_t limit = left * (KeySlice::ValLen + this->key_len_) + this->pre_len_, j = 0;
166 | for (uint16_t i = left; i < total_key_ && j < left; ++i) {
167 | if (l_idx[i] < limit) {
168 | for (; j < left; ++j) {
169 | if (l_idx[j] >= limit) {
170 | KeySlice *o = Key(l_idx, i);
171 | KeySlice *n = Key(l_idx, j);
172 | l_idx[j] = l_idx[i];
173 | memcpy(o, n, KeySlice::ValLen + key_len_);
174 | ++j;
175 | break;
176 | }
177 | }
178 | }
179 | }
180 | uint16_t offset = this->total_key_ - left;
181 | memmove(&l_idx[offset], &l_idx[0], left << 1);
182 |
183 | this->total_key_ = left;
184 | that->total_key_ = right;
185 | }
186 |
187 | bool Page::Full() const
188 | {
189 | return total_key_ == degree_;
190 | }
191 |
192 | bool Page::NeedSplit()
193 | {
194 | if (!Full()) return false;
195 | uint16_t *index = Index();
196 | const char *first = Key(index, 0)->key_;
197 | const char *last = Key(index, total_key_ - 1)->key_;
198 | char prefix[key_len_];
199 | uint8_t pre_len = 0;
200 | for (; first[pre_len] == last[pre_len]; ++pre_len)
201 | prefix[pre_len] = first[pre_len];
202 | if (!pre_len)
203 | return true;
204 | uint16_t degree = CalculateDegree(key_len_ - pre_len, pre_len + pre_len_);
205 | if (degree <= degree_)
206 | return true;
207 | char buf[PageSize];
208 | Page *copy = (Page *)buf;
209 | memcpy(copy, this, PageSize);
210 | memcpy(data_ + pre_len_, prefix, pre_len);
211 | char *curr = data_ + pre_len_ + pre_len;
212 | uint16_t *cindex = copy->Index();
213 | uint16_t suf_len = key_len_ - pre_len;
214 | for (uint16_t i = 0; i != total_key_; ++i, ++index) {
215 | KeySlice *key = copy->Key(cindex, i);
216 | *index = curr - data_;
217 | memcpy(curr, &key->page_no_, KeySlice::ValLen);
218 | curr += KeySlice::ValLen;
219 | memcpy(curr, key->key_ + pre_len, suf_len);
220 | curr += suf_len;
221 | }
222 | pre_len_ += pre_len;
223 | key_len_ -= pre_len;
224 | degree_ = degree;
225 | return false;
226 | }
227 |
228 | std::string Page::ToString(bool f, bool f2) const
229 | {
230 | std::ostringstream os;
231 | os << "type: ";
232 | if (type_ == LEAF) os << "leaf ";
233 | if (type_ == BRANCH) os << "branch ";
234 | if (type_ == ROOT) os << "root ";
235 | os << "no: " << page_no_ << " ";
236 | os << "fir: " << first_ << " ";
237 | os << "tot: " << total_key_ << " ";
238 | os << "lvl: " << (int)level_ << " ";
239 | os << "keylen: " << (int)key_len_ << " ";
240 | os << "deg: " << degree_ << "\n";
241 |
242 | if (pre_len_) {
243 | os << "pre_len: " << (int)pre_len_ << " ";
244 | os << "prefix: " << std::string(data_, pre_len_) << "\n";
245 | }
246 |
247 | uint16_t *index = Index();
248 | if (!f) {
249 | os << Key(index, 0)->ToString(key_len_);
250 | os << Key(index, total_key_ - 1)->ToString(key_len_);
251 | } else {
252 | // for (uint16_t i = 0; i != total_key_; ++i)
253 | // os << index[i] << " ";
254 | // os << "\n";
255 | for (uint16_t i = 0; i != total_key_; ++i) {
256 | KeySlice *key = Key(index, i);
257 | if (f2)
258 | os << key->page_no_ << " ";
259 | os << key->ToString(key_len_);
260 | }
261 | }
262 | os << "\nnext: " << Key(index, total_key_-1)->page_no_ << "\n";
263 | return os.str();
264 | }
265 |
266 | } // namespace Mushroom
267 |
--------------------------------------------------------------------------------
/src/blink/page.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2016-10-22 09:09:54
6 | **/
7 |
8 | #ifndef _BTREE_PAGE_HPP_
9 | #define _BTREE_PAGE_HPP_
10 |
11 | #include
12 | #include
13 |
14 | #include "../include/utility.hpp"
15 | #include "slice.hpp"
16 | #include "../include/latch.hpp"
17 |
18 | namespace Mushroom {
19 |
20 | typedef enum { InsertOk = 0x0, ExistedKey = 0x1, MoveRight = 0x2 } InsertStatus;
21 |
22 | typedef enum { UpdateOk = 0x0, Promote = 0x1, MoveNext = 0x2 } UpdateStatus;
23 |
24 | class KeySlice;
25 | class BLinkTree;
26 |
27 | class Page : private NoCopy
28 | {
29 | friend class BLinkTree;
30 | public:
31 | static uint32_t PageSize;
32 |
33 | static enum { ROOT = 1, BRANCH = 2, LEAF = 4 } Type;
34 |
35 | static const uint32_t IndexByte = 2;
36 |
37 | static void SetPageInfo(uint32_t page_size);
38 |
39 | static uint16_t CalculateDegree(uint8_t key_len, uint8_t pre_len = 0);
40 |
41 | void InsertInfiniteKey();
42 |
43 | Page(page_t id, uint8_t type, uint8_t key_len, uint8_t level, uint16_t degree);
44 |
45 | inline page_t Next() const {
46 | KeySlice *key = (KeySlice *)(data_ + Index()[total_key_-1]);
47 | return key->page_no_;
48 | }
49 |
50 | inline void SetPageNo(page_t page_no) { page_no_ = page_no; }
51 |
52 | inline page_t PageNo() const { return page_no_; }
53 |
54 | inline uint16_t TotalKey() const { return total_key_; }
55 |
56 | inline uint16_t Degree() const { return degree_; }
57 |
58 | void AssignFirst(page_t first);
59 |
60 | page_t Descend(const KeySlice *key) const;
61 |
62 | bool Search(const KeySlice *key, uint16_t *index) const;
63 |
64 | InsertStatus Insert(const KeySlice *key, page_t &page_no);
65 |
66 | void Insert(Page *that, KeySlice *key);
67 |
68 | void Split(Page *that, KeySlice *slice);
69 |
70 | bool Full() const;
71 |
72 | bool NeedSplit();
73 |
74 | inline Latch* GetLatch() { return &latch_; }
75 |
76 | inline void LockShared() { latch_.ReadLock(); }
77 |
78 | inline void Lock() { latch_.WriteLock(); }
79 |
80 | inline void UnlockShared() { latch_.Unlock(); }
81 |
82 | inline void Unlock() { latch_.Unlock(); }
83 |
84 | inline uint16_t* Index() const {
85 | return (uint16_t *)((char *)this + (PageSize - (total_key_ * IndexByte)));
86 | }
87 |
88 | inline KeySlice* Key(const uint16_t *index, uint16_t pos) const {
89 | return (KeySlice *)(data_ + index[pos]);
90 | }
91 |
92 | std::string ToString(bool f, bool f2) const;
93 |
94 | private:
95 | bool Traverse(const KeySlice *key, uint16_t *idx, KeySlice **slice, int type = 1) const;
96 |
97 | Latch latch_;
98 | page_t page_no_;
99 | page_t first_;
100 | uint16_t total_key_;
101 | uint16_t degree_;
102 | uint8_t type_;
103 | uint8_t level_;
104 | uint8_t key_len_;
105 | uint8_t pre_len_;
106 | char data_[0];
107 | };
108 |
109 | } // namespace Mushroom
110 |
111 | #endif /* _BTREE_PAGE_HPP_ */
--------------------------------------------------------------------------------
/src/blink/page_pool.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-03-25 12:58:32
6 | **/
7 |
8 | #include "page_pool.hpp"
9 |
10 | namespace Mushroom {
11 |
12 | uint32_t PagePool::SegBits;
13 | uint32_t PagePool::SegSize;
14 | uint32_t PagePool::SegMask;
15 |
16 | } // namespace Mushroom
17 |
--------------------------------------------------------------------------------
/src/blink/page_pool.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-03-25 12:56:16
6 | **/
7 |
8 | #ifndef _PAGE_POOL_HPP_
9 | #define _PAGE_POOL_HPP_
10 |
11 | #include
12 |
13 | #include "../include/utility.hpp"
14 | #include "page.hpp"
15 |
16 | namespace Mushroom {
17 |
18 | class PoolManager;
19 |
20 | class PagePool : private NoCopy
21 | {
22 | friend class PoolManager;
23 |
24 | public:
25 | static void SetPoolInfo(uint32_t seg_bits) {
26 | SegBits = seg_bits;
27 | SegSize = 1 << seg_bits;
28 | SegMask = SegSize - 1;
29 | }
30 |
31 | PagePool() { }
32 |
33 | inline void Initialize(page_t base) {
34 | base_ = base;
35 | mem_ = new char[Page::PageSize << SegBits];
36 | memset(mem_, 0, Page::PageSize << SegBits);
37 | }
38 |
39 | inline Page* GetPage(page_t page_no) {
40 | return (Page *)(mem_ + Page::PageSize * (page_no & SegMask));
41 | }
42 |
43 | inline void Destroy() {
44 | delete [] mem_;
45 | }
46 |
47 | static uint32_t SegSize;
48 | private:
49 | static uint32_t SegBits;
50 | static uint32_t SegMask;
51 |
52 | page_t base_;
53 | char *mem_;
54 | PagePool *next_;
55 | };
56 |
57 | } // namespace Mushroom
58 |
59 | #endif /* _PAGE_POOL_HPP_ */
--------------------------------------------------------------------------------
/src/blink/pool_manager.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-03-19 13:13:52
6 | **/
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #include "hash_entry.hpp"
14 | #include "page.hpp"
15 | #include "page_pool.hpp"
16 | #include "pool_manager.hpp"
17 |
18 | namespace Mushroom {
19 |
20 | uint32_t PoolManager::HashMask;
21 | uint32_t PoolManager::PoolSize;
22 |
23 | void PoolManager::SetManagerInfo(uint32_t page_size, uint32_t pool_size, uint32_t hash_bits,
24 | uint32_t seg_bits)
25 | {
26 | Page::SetPageInfo(page_size);
27 | PagePool::SetPoolInfo(seg_bits);
28 | PoolSize = pool_size;
29 | HashMask = (1 << hash_bits) - 1;
30 | }
31 |
32 | PoolManager::PoolManager():cur_page_(0), total_pool_(0)
33 | {
34 | entries_ = new HashEntry[HashMask+1];
35 | pool_ = new PagePool[PoolSize];
36 | }
37 |
38 | PoolManager::~PoolManager()
39 | {
40 | delete [] pool_;
41 | delete [] entries_;
42 | }
43 |
44 | void PoolManager::Link(uint16_t hash, uint16_t victim)
45 | {
46 | PagePool *pool = pool_ + victim;
47 |
48 | uint16_t slot = entries_[hash].GetSlot();
49 | if (slot)
50 | pool->next_ = pool_ + slot;
51 |
52 | entries_[hash].SetSlot(victim);
53 | }
54 |
55 | Page* PoolManager::GetPage(page_t page_no)
56 | {
57 | page_t base = page_no & ~PagePool::SegMask;
58 | page_t hash = (page_no >> PagePool::SegBits) & HashMask;
59 | Page *page = 0;
60 |
61 | entries_[hash].Lock();
62 |
63 | uint16_t slot = entries_[hash].GetSlot();
64 | if (slot) {
65 | PagePool *pool = pool_ + slot;
66 | for (; pool; pool = pool->next_)
67 | if (pool->base_ == base)
68 | break;
69 | if (pool) {
70 | page = pool->GetPage(page_no);
71 | entries_[hash].Unlock();
72 | return page;
73 | }
74 | }
75 |
76 | uint16_t victim = ++total_pool_;
77 | assert(victim < PoolSize);
78 |
79 | pool_[victim].Initialize(base);
80 | Link(hash, victim);
81 | page = pool_[victim].GetPage(page_no);
82 | entries_[hash].Unlock();
83 | return page;
84 | }
85 |
86 | Page* PoolManager::NewPage(uint8_t type, uint8_t key_len, uint8_t level, uint16_t degree)
87 | {
88 | page_t page_no = cur_page_++;
89 | Page *page = GetPage(page_no);
90 | return new (page) Page(page_no, type, key_len, level, degree);
91 | }
92 |
93 | void PoolManager::Free()
94 | {
95 | for (uint16_t i = 1, end = total_pool_.get(); i <= end; ++i)
96 | pool_[i].Destroy();
97 | }
98 |
99 | } // namespace Mushroom
100 |
--------------------------------------------------------------------------------
/src/blink/pool_manager.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-03-19 13:09:33
6 | **/
7 |
8 | #ifndef _POOL_MANAGER_HPP_
9 | #define _POOL_MANAGER_HPP_
10 |
11 | #include "../include/utility.hpp"
12 | #include "../include/atomic.hpp"
13 |
14 | namespace Mushroom {
15 |
16 | class Page;
17 | class HashEntry;
18 | class PagePool;
19 |
20 | class PoolManager : private NoCopy
21 | {
22 | public:
23 | static void SetManagerInfo(uint32_t page_size, uint32_t pool_size, uint32_t hash_bits,
24 | uint32_t seg_bits);
25 |
26 | PoolManager();
27 |
28 | ~PoolManager();
29 |
30 | Page* GetPage(page_t page_no);
31 |
32 | Page* NewPage(uint8_t type, uint8_t key_len, uint8_t level, uint16_t degree);
33 |
34 | void Free();
35 |
36 | private:
37 | static uint32_t HashMask;
38 | static uint32_t PoolSize;
39 |
40 | void Link(uint16_t hash, uint16_t victim);
41 |
42 | Atomic cur_page_;
43 | atomic_16_t total_pool_;
44 | HashEntry *entries_;
45 | PagePool *pool_;
46 | };
47 |
48 | } // namespace Mushroom
49 |
50 | #endif /* _POOL_MANAGER_HPP_ */
--------------------------------------------------------------------------------
/src/blink/slice.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2016-10-09 15:37:50
6 | **/
7 |
8 | #ifndef _SLICE_HPP_
9 | #define _SLICE_HPP_
10 |
11 | #include
12 | #include
13 |
14 | #include "../include/utility.hpp"
15 |
16 | namespace Mushroom {
17 |
18 | class KeySlice : private NoCopy
19 | {
20 | public:
21 | static const uint32_t KeyLen = 16;
22 | static const uint32_t ValLen = sizeof(page_t);
23 | static const uint32_t KeySize = KeyLen + ValLen;
24 |
25 | std::string ToString(uint32_t len = KeyLen) const {
26 | return std::string(key_, len) + "\n";
27 | }
28 |
29 | page_t page_no_;
30 | char key_[0];
31 | };
32 |
33 | inline KeySlice* NewKeySlice() {
34 | return (KeySlice *)new char[KeySlice::KeySize];
35 | }
36 |
37 | inline void DeleteKeySlice(KeySlice *key) {
38 | delete [] (char *)key;
39 | }
40 |
41 | #define TempSlice(name) \
42 | char buf_##name[KeySlice::KeySize]; \
43 | memset(buf_##name, 0, KeySlice::KeySize); \
44 | KeySlice *name = (KeySlice *)buf_##name;
45 |
46 | } // namespace Mushroom
47 |
48 | #endif /* _SLICE_HPP_ */
--------------------------------------------------------------------------------
/src/blink/task.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2016-10-18 15:30:39
6 | **/
7 |
8 | #ifndef _MUSHROOM_TASK_HPP_
9 | #define _MUSHROOM_TASK_HPP_
10 |
11 | #include "../include/utility.hpp"
12 | #include "slice.hpp"
13 |
14 | namespace Mushroom {
15 |
16 | class MushroomDB;
17 |
18 | class MushroomTask : private NoCopy
19 | {
20 | public:
21 | MushroomTask():fun_(0), db_(0), key_(NewKeySlice()) { }
22 |
23 | ~MushroomTask() { DeleteKeySlice(key_); }
24 |
25 | inline void Assign(bool (MushroomDB::*(fun))(KeySlice *), MushroomDB *db, KeySlice *key) {
26 | fun_ = fun;
27 | db_ = db;
28 | memcpy(key_, key, KeySlice::KeySize);
29 | }
30 |
31 | bool operator()() { return (db_->*fun_)(key_); }
32 |
33 | private:
34 | bool (MushroomDB::*(fun_))(KeySlice *);
35 | MushroomDB *db_;
36 | KeySlice *key_;
37 | };
38 |
39 | } // namespace Mushroom
40 |
41 | #endif /* _MUSHROOM_TASK_HPP_ */
--------------------------------------------------------------------------------
/src/blink/thread_pool_mapping.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2016-10-16 18:51:28
6 | **/
7 |
8 | #ifndef _THREAD_POOL_MAPPING_HPP_
9 | #define _THREAD_POOL_MAPPING_HPP_
10 |
11 | #include "../include/utility.hpp"
12 | #include "../include/thread.hpp"
13 | #include "bounded_mapping_queue.hpp"
14 |
15 | namespace Mushroom {
16 |
17 | template
18 | class ThreadPoolMapping : private NoCopyTemplate
19 | {
20 | public:
21 | ThreadPoolMapping(BoundedMappingQueue *queue, int thread_num);
22 |
23 | ~ThreadPoolMapping();
24 |
25 | void Run();
26 |
27 | void Clear();
28 |
29 | private:
30 | bool working_;
31 | int thread_num_;
32 | BoundedMappingQueue *queue_;
33 | Thread **threads_;
34 | };
35 |
36 | template
37 | ThreadPoolMapping::ThreadPoolMapping(BoundedMappingQueue *queue, int thread_num)
38 | :working_(false), thread_num_(thread_num), queue_(queue)
39 | {
40 | if (thread_num_ <= 0)
41 | thread_num_ = 1;
42 | if (thread_num_ > 4)
43 | thread_num_ = 4;
44 |
45 | threads_ = new Thread*[thread_num_];
46 |
47 | working_ = true;
48 |
49 | for (int i = 0; i != thread_num_; ++i) {
50 | threads_[i] = new Thread([this] { this->Run(); });
51 | threads_[i]->Start();
52 | }
53 | }
54 |
55 | template
56 | void ThreadPoolMapping::Run()
57 | {
58 | for (;;) {
59 | int pos;
60 | T* task = queue_->Pop(&pos);
61 |
62 | if (!task) break;
63 |
64 | (*task)();
65 |
66 | queue_->Put(pos);
67 | }
68 | }
69 |
70 | template
71 | void ThreadPoolMapping::Clear()
72 | {
73 | if (!working_) return ;
74 |
75 | queue_->Clear();
76 |
77 | working_ = false;
78 |
79 | for (int i = 0; i != thread_num_; ++i)
80 | threads_[i]->Stop();
81 | }
82 |
83 | template
84 | ThreadPoolMapping::~ThreadPoolMapping()
85 | {
86 | Clear();
87 |
88 | for (int i = 0; i != thread_num_; ++i)
89 | delete threads_[i];
90 |
91 | delete [] threads_;
92 | }
93 |
94 | } // namespace Mushroom
95 |
96 | #endif /* _THREAD_POOL_MAPPING_HPP_ */
--------------------------------------------------------------------------------
/src/include/atomic.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-04 12:54:54
6 | **/
7 |
8 | #ifndef _ATOMIC_HPP_
9 | #define _ATOMIC_HPP_
10 |
11 | #include
12 |
13 | namespace Mushroom {
14 |
15 | template
16 | class Atomic
17 | {
18 | public:
19 | Atomic() { }
20 |
21 | Atomic(T val):val_(val) { }
22 |
23 | inline T get() {
24 | return __sync_val_compare_and_swap(&val_, 0, 0);
25 | }
26 |
27 | inline T operator++() {
28 | return __sync_add_and_fetch(&val_, 1);
29 | }
30 |
31 | inline T operator--() {
32 | return __sync_sub_and_fetch(&val_, 1);
33 | }
34 |
35 | inline T operator++(int) {
36 | return __sync_fetch_and_add(&val_, 1);
37 | }
38 |
39 | inline T operator--(int) {
40 | return __sync_fetch_and_sub(&val_, 1);
41 | }
42 |
43 | inline Atomic& operator=(T new_val) {
44 | __sync_val_compare_and_swap(&val_, val_, new_val);
45 | return *this;
46 | }
47 |
48 | private:
49 | volatile T val_;
50 | };
51 |
52 | typedef Atomic atomic_8_t;
53 | typedef Atomic atomic_16_t;
54 | typedef Atomic atomic_32_t;
55 |
56 | } // namespace Mushroom
57 |
58 | #endif /* _ATOMIC_HPP_ */
--------------------------------------------------------------------------------
/src/include/bounded_list.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-14 16:09:39
6 | **/
7 |
8 | #ifndef _BOUNDED_LIST_HPP_
9 | #define _BOUNDED_LIST_HPP_
10 |
11 | #include
12 |
13 | #include "utility.hpp"
14 | #include "mutex.hpp"
15 | #include "cond.hpp"
16 |
17 | namespace Mushroom {
18 |
19 | template
20 | class BoundedList : private NoCopyTemplate
21 | {
22 | public:
23 | BoundedList(int capacity, const std::function &constructor);
24 |
25 | ~BoundedList();
26 |
27 | inline T* Get();
28 |
29 | inline void Push(T *t);
30 |
31 | inline T* Pop();
32 |
33 | inline void Put(T *);
34 |
35 | void Clear();
36 |
37 | private:
38 | bool clear_;
39 | int capacity_;
40 | std::list free_;
41 | std::list busy_;
42 | Mutex free_mutex_;
43 | Mutex busy_mutex_;
44 | Cond free_cond_;
45 | Cond busy_cond_;
46 | };
47 |
48 | template
49 | BoundedList::BoundedList(int capacity, const std::function &constructor)
50 | :clear_(false), capacity_(capacity)
51 | {
52 | if (capacity_ <= 0)
53 | capacity_ = 8;
54 | if (capacity_ > 1024)
55 | capacity_ = 1024;
56 |
57 | for (int i = 0; i < capacity_; ++i)
58 | free_.push_back(constructor());
59 | }
60 |
61 | template
62 | BoundedList::~BoundedList()
63 | {
64 | Clear();
65 |
66 | for (auto e : free_)
67 | delete e;
68 | }
69 |
70 | template
71 | void BoundedList::Clear()
72 | {
73 | free_mutex_.Lock();
74 |
75 | if (clear_) {
76 | free_mutex_.Unlock();
77 | return ;
78 | }
79 |
80 | while (int(free_.size()) != capacity_)
81 | free_cond_.Wait(free_mutex_);
82 |
83 | clear_ = true;
84 |
85 | free_mutex_.Unlock();
86 | busy_cond_.Broadcast();
87 | }
88 |
89 | template
90 | inline T* BoundedList::Get()
91 | {
92 | free_mutex_.Lock();
93 | while (free_.empty())
94 | free_cond_.Wait(free_mutex_);
95 | T* t = free_.front();
96 | free_.pop_front();
97 | free_mutex_.Unlock();
98 | return t;
99 | }
100 |
101 | template
102 | inline void BoundedList::Push(T *t)
103 | {
104 | busy_mutex_.Lock();
105 | busy_.push_back(t);
106 | busy_mutex_.Unlock();
107 | busy_cond_.Signal();
108 | }
109 |
110 | template
111 | inline T* BoundedList::Pop()
112 | {
113 | busy_mutex_.Lock();
114 | while (busy_.empty() && !clear_)
115 | busy_cond_.Wait(busy_mutex_);
116 | if (clear_) {
117 | busy_mutex_.Unlock();
118 | return 0;
119 | }
120 | T* t = busy_.front();
121 | busy_.pop_front();
122 | busy_mutex_.Unlock();
123 | return t;
124 | }
125 |
126 | template
127 | inline void BoundedList::Put(T *t)
128 | {
129 | free_mutex_.Lock();
130 | free_.push_back(t);
131 | free_mutex_.Unlock();
132 | free_cond_.Signal();
133 | }
134 |
135 | } // namespace Mushroom
136 |
137 | #endif /* _BOUNDED_LIST_HPP_ */
--------------------------------------------------------------------------------
/src/include/bounded_queue.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-09 21:14:07
6 | **/
7 |
8 | #ifndef _BOUNDED_QUEUE_HPP_
9 | #define _BOUNDED_QUEUE_HPP_
10 |
11 | #include "utility.hpp"
12 | #include "mutex.hpp"
13 | #include "cond.hpp"
14 |
15 | namespace Mushroom {
16 |
17 | template
18 | class BoundedQueue : private NoCopyTemplate
19 | {
20 | public:
21 | BoundedQueue(int capacity);
22 |
23 | ~BoundedQueue();
24 |
25 | inline void Push(T &&);
26 |
27 | inline T Pop();
28 |
29 | inline void Clear();
30 |
31 | private:
32 | bool clear_;
33 | int beg_;
34 | int end_;
35 | int capacity_;
36 | T *queue_;
37 | Mutex mutex_;
38 | Cond empty_;
39 | Cond full_;
40 | };
41 |
42 | template
43 | BoundedQueue::BoundedQueue(int capacity):clear_(false), beg_(0), end_(0),capacity_(capacity)
44 | {
45 | if (capacity_ <= 0)
46 | capacity_ = 8;
47 | if (capacity_ > 1024)
48 | capacity_ = 1024;
49 |
50 | queue_ = new T[capacity_];
51 | }
52 |
53 | template
54 | BoundedQueue::~BoundedQueue()
55 | {
56 | delete [] queue_;
57 | }
58 |
59 | template
60 | inline void BoundedQueue::Clear()
61 | {
62 | mutex_.Lock();
63 | if (clear_) {
64 | mutex_.Unlock();
65 | return ;
66 | }
67 | clear_ = true;
68 | empty_.Broadcast();
69 | mutex_.Unlock();
70 | }
71 |
72 | template
73 | inline void BoundedQueue::Push(T &&t)
74 | {
75 | mutex_.Lock();
76 | while (((end_+1)%capacity_) == beg_)
77 | full_.Wait(mutex_);
78 | queue_[end_] = t;
79 | if (++end_ == capacity_)
80 | end_ = 0;
81 | mutex_.Unlock();
82 | empty_.Signal();
83 | }
84 |
85 | template
86 | inline T BoundedQueue::Pop()
87 | {
88 | mutex_.Lock();
89 | while (beg_ == end_ && !clear_)
90 | empty_.Wait(mutex_);
91 | if (clear_) {
92 | mutex_.Unlock();
93 | return T();
94 | }
95 | T t = std::move(queue_[beg_]);
96 | if (++beg_ == capacity_)
97 | beg_ = 0;
98 | mutex_.Unlock();
99 | full_.Signal();
100 | return t;
101 | }
102 |
103 | } // namespace Mushroom
104 |
105 | #endif /* _BOUNDED_QUEUE_HPP_ */
--------------------------------------------------------------------------------
/src/include/cond.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-05 22:54:44
6 | **/
7 |
8 | #ifndef _COND_HPP_
9 | #define _COND_HPP_
10 |
11 | #include
12 | #include
13 |
14 | #include "utility.hpp"
15 | #include "mutex.hpp"
16 |
17 | namespace Mushroom {
18 |
19 | class Cond : private NoCopy
20 | {
21 | public:
22 | Cond() {
23 | assert(!pthread_cond_init(cond_, 0));
24 | }
25 |
26 | inline void Wait(Mutex &mutex) {
27 | pthread_cond_wait(cond_, mutex.mutex_);
28 | }
29 |
30 | inline void Signal() {
31 | pthread_cond_signal(cond_);
32 | }
33 |
34 | inline void Broadcast() {
35 | pthread_cond_broadcast(cond_);
36 | }
37 |
38 | inline bool TimedWait(Mutex &mutex, int64_t millisecond) {
39 | struct timeval tv;
40 | gettimeofday(&tv, 0);
41 | timespec abstime;
42 | abstime.tv_sec = tv.tv_sec;
43 | int64_t nsec = int64_t(tv.tv_usec) * 1000 + millisecond * 1000000;
44 | if (nsec >= 1000000000) {
45 | ++abstime.tv_sec;
46 | nsec -= 1000000000;
47 | }
48 | abstime.tv_nsec = nsec;
49 | return pthread_cond_timedwait(cond_, mutex.mutex_, &abstime) == ETIMEDOUT;
50 | }
51 |
52 | ~Cond() {
53 | assert(!pthread_cond_destroy(cond_));
54 | }
55 |
56 | private:
57 | pthread_cond_t cond_[1];
58 | };
59 |
60 | } // namespace Mushroom
61 |
62 | #endif /* _COND_HPP_ */
--------------------------------------------------------------------------------
/src/include/guard.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-19 10:24:14
6 | **/
7 |
8 | #ifndef _GUARD_HPP_
9 | #define _GUARD_HPP_
10 |
11 | #include "utility.hpp"
12 | #include "mutex.hpp"
13 |
14 | namespace Mushroom {
15 |
16 | class Guard : private NoCopy
17 | {
18 | public:
19 | Guard(Mutex &mutex):mutex_(mutex) { mutex_.Lock(); }
20 |
21 | ~Guard() { mutex_.Unlock(); }
22 |
23 | private:
24 | Mutex &mutex_;
25 | };
26 |
27 | } // namespace Mushroom
28 |
29 | #endif /* _GUARD_HPP_ */
--------------------------------------------------------------------------------
/src/include/latch.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-09-05 16:03:53
6 | **/
7 |
8 | #ifndef _LATCH_HPP_
9 | #define _LATCH_HPP_
10 |
11 | #include
12 | #include
13 |
14 | #include "utility.hpp"
15 |
16 | namespace Mushroom {
17 |
18 | class Latch : private NoCopy {
19 | public:
20 | Latch() { }
21 |
22 | inline void Init() {
23 | assert(!pthread_rwlock_init(latch_, 0));
24 | }
25 |
26 | inline void ReadLock() {
27 | pthread_rwlock_rdlock(latch_);
28 | }
29 |
30 | inline void WriteLock() {
31 | pthread_rwlock_wrlock(latch_);
32 | }
33 |
34 | inline void Unlock() {
35 | pthread_rwlock_unlock(latch_);
36 | }
37 |
38 | inline void Destroy() {
39 | assert(!pthread_rwlock_destroy(latch_));
40 | }
41 |
42 | private:
43 | pthread_rwlock_t latch_[1];
44 | };
45 |
46 | } // namespace Mushroom
47 |
48 | #endif /* _LATCH_HPP_ */
--------------------------------------------------------------------------------
/src/include/mutex.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-05 22:53:02
6 | **/
7 |
8 | #ifndef _MUTEX_HPP_
9 | #define _MUTEX_HPP_
10 |
11 | #include
12 | #include
13 |
14 | #include "utility.hpp"
15 |
16 | namespace Mushroom {
17 |
18 | class Cond;
19 |
20 | class Mutex : private NoCopy
21 | {
22 | friend class Cond;
23 | public:
24 | Mutex() {
25 | assert(!pthread_mutex_init(mutex_, 0));
26 | }
27 |
28 | inline void Lock() {
29 | pthread_mutex_lock(mutex_);
30 | }
31 |
32 | inline void Unlock() {
33 | pthread_mutex_unlock(mutex_);
34 | }
35 |
36 | ~Mutex() {
37 | assert(!pthread_mutex_destroy(mutex_));
38 | }
39 |
40 | private:
41 | pthread_mutex_t mutex_[1];
42 | };
43 |
44 | } // namespace Mushroom
45 |
46 | #endif /* _MUTEX_HPP_ */
--------------------------------------------------------------------------------
/src/include/spin_lock.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-05 22:56:41
6 | **/
7 |
8 | #ifndef _SPIN_LOCK_HPP_
9 | #define _SPIN_LOCK_HPP_
10 |
11 | #include
12 | #include
13 |
14 | #include "utility.hpp"
15 |
16 | #ifdef __APPLE__
17 |
18 | #include
19 | #include
20 | #include
21 |
22 | #ifndef PTHREAD_PROCESS_SHARED
23 | #define PTHREAD_PROCESS_SHARED 1
24 | #endif
25 | #ifndef PTHREAD_PROCESS_PRIVATE
26 | #define PTHREAD_PROCESS_PRIVATE 2
27 | #endif
28 |
29 | #ifndef UNUSED
30 | #define UNUSED(expr) (void)(expr)
31 | #endif
32 |
33 | typedef std::atomic_flag pthread_spinlock_t;
34 |
35 | static inline int pthread_spin_destroy(pthread_spinlock_t *lock) {
36 | UNUSED(lock);
37 | return 0;
38 | }
39 |
40 | static inline int pthread_spin_lock(pthread_spinlock_t *lock) {
41 | while (lock->test_and_set(std::memory_order_acquire))
42 | std::this_thread::yield();
43 | return 0;
44 | }
45 |
46 | static inline int pthread_spin_trylock(pthread_spinlock_t *lock) {
47 | if (lock->test_and_set(std::memory_order_acquire))
48 | return 0;
49 | else
50 | return EBUSY;
51 | }
52 |
53 | static inline int pthread_spin_unlock(pthread_spinlock_t *lock) {
54 | lock->clear(std::memory_order_release);
55 | return 0;
56 | }
57 |
58 | static inline int pthread_spin_init(pthread_spinlock_t *lock, int pshared) {
59 | UNUSED(pshared);
60 | pthread_spin_unlock(lock);
61 | return 0;
62 | }
63 |
64 | #endif /* __APPLE__ */
65 |
66 | namespace Mushroom {
67 |
68 | class SpinLock : private NoCopy
69 | {
70 | public:
71 | SpinLock() {
72 | assert(!pthread_spin_init(lock_, 0));
73 | }
74 |
75 | inline void Lock() {
76 | pthread_spin_lock(lock_);
77 | }
78 |
79 | inline bool TryLock() {
80 | return !pthread_spin_trylock(lock_);
81 | }
82 |
83 | inline void Unlock() {
84 | pthread_spin_unlock(lock_);
85 | }
86 |
87 | ~SpinLock() {
88 | assert(!pthread_spin_destroy(lock_));
89 | }
90 |
91 | private:
92 | pthread_spinlock_t lock_[1];
93 | };
94 |
95 | } // namespace Mushroom
96 |
97 | #endif /* _SPIN_LOCK_HPP_ */
--------------------------------------------------------------------------------
/src/include/thread.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-04 09:18:22
6 | **/
7 |
8 | #ifndef _THREAD_HPP_
9 | #define _THREAD_HPP_
10 |
11 | #include
12 |
13 | #include "utility.hpp"
14 |
15 | namespace Mushroom {
16 |
17 | class Thread : private NoCopy
18 | {
19 | public:
20 | Thread(const Func &func):func_(func) { }
21 |
22 | inline void Start() {
23 | std::thread tmp(func_);
24 | thread_.swap(tmp);
25 | }
26 |
27 | inline void Stop() {
28 | thread_.join();
29 | }
30 |
31 | private:
32 | Func func_;
33 | std::thread thread_;
34 | };
35 |
36 | } // namespace Mushroom
37 |
38 | #endif /* _THREAD_HPP_ */
--------------------------------------------------------------------------------
/src/include/thread_pool.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-09 21:16:59
6 | **/
7 |
8 | #ifndef _THREAD_POOL_HPP_
9 | #define _THREAD_POOL_HPP_
10 |
11 | #include "utility.hpp"
12 | #include "bounded_queue.hpp"
13 | #include "thread.hpp"
14 | #include "atomic.hpp"
15 |
16 | namespace Mushroom {
17 |
18 | template
19 | class ThreadPool : private NoCopyTemplate
20 | {
21 | public:
22 | ThreadPool(BoundedQueue *queue, int thread_num);
23 |
24 | ~ThreadPool();
25 |
26 | void Run();
27 |
28 | void Clear();
29 |
30 | private:
31 | atomic_8_t working_;
32 | int thread_num_;
33 | BoundedQueue *queue_;
34 | Thread **threads_;
35 | };
36 |
37 | template
38 | ThreadPool::ThreadPool(BoundedQueue *queue, int thread_num)
39 | :working_(0), thread_num_(thread_num), queue_(queue)
40 | {
41 | if (thread_num_ <= 0)
42 | thread_num_ = 1;
43 | else if (thread_num_ > 8)
44 | thread_num_ = 8;
45 |
46 | threads_ = new Thread*[thread_num_];
47 |
48 | for (int i = 0; i != thread_num_; ++i) {
49 | threads_[i] = new Thread([this] { this->Run(); });
50 | threads_[i]->Start();
51 | }
52 | working_ = 1;
53 | }
54 |
55 | template
56 | void ThreadPool::Run()
57 | {
58 | for (;;) {
59 | T task = queue_->Pop();
60 |
61 | if (!working_.get())
62 | break;
63 |
64 | task();
65 | }
66 | }
67 |
68 | template
69 | void ThreadPool::Clear()
70 | {
71 | if (!working_.get())
72 | return ;
73 |
74 | working_ = 0;
75 |
76 | queue_->Clear();
77 |
78 | for (int i = 0; i != thread_num_; ++i)
79 | threads_[i]->Stop();
80 | }
81 |
82 | template
83 | ThreadPool::~ThreadPool()
84 | {
85 | for (int i = 0; i != thread_num_; ++i)
86 | delete threads_[i];
87 |
88 | delete [] threads_;
89 | }
90 |
91 | } // namespace Mushroom
92 |
93 | #endif /* _THREAD_POOL_HPP_ */
--------------------------------------------------------------------------------
/src/include/utility.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-06 22:38:46
6 | **/
7 |
8 | #ifndef _UTILITY_HPP_
9 | #define _UTILITY_HPP_
10 |
11 | #include
12 |
13 | namespace Mushroom {
14 |
15 | class NoCopy {
16 | public:
17 | NoCopy() = default;
18 | private:
19 | NoCopy(const NoCopy &) = delete;
20 | NoCopy& operator=(const NoCopy &) = delete;
21 | };
22 |
23 | template
24 | class NoCopyTemplate
25 | {
26 | public:
27 | NoCopyTemplate() = default;
28 | private:
29 | NoCopyTemplate(const NoCopyTemplate &) = delete;
30 | NoCopyTemplate& operator=(const NoCopyTemplate &) = delete;
31 | };
32 |
33 | typedef uint32_t valptr;
34 | typedef uint32_t page_t;
35 |
36 | typedef std::function Task;
37 | typedef std::function Func;
38 |
39 | } // namespace Mushroom
40 |
41 | #endif /* _UTILITY_HPP_ */
--------------------------------------------------------------------------------
/src/network/buffer.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-04-27 09:44:47
6 | **/
7 |
8 | #include
9 | #include
10 |
11 | #include "buffer.hpp"
12 |
13 | namespace Mushroom {
14 |
15 | Buffer::Buffer():data_(new char[4096]), cap_(4096)
16 | {
17 | memset(data_, 0, cap_);
18 | Clear();
19 | }
20 |
21 | Buffer::~Buffer()
22 | {
23 | delete [] data_;
24 | }
25 |
26 | uint32_t Buffer::size() const
27 | {
28 | return size_;
29 | }
30 |
31 | bool Buffer::empty() const
32 | {
33 | return !size_;
34 | }
35 |
36 | char* Buffer::data() const
37 | {
38 | data_[end_] = '\0';
39 | return data_ + beg_;
40 | }
41 |
42 | char* Buffer::begin() const
43 | {
44 | return data_ + beg_;
45 | }
46 |
47 | char* Buffer::end() const
48 | {
49 | return data_ + end_;
50 | }
51 |
52 | uint32_t Buffer::space() const
53 | {
54 | return cap_ - end_;
55 | }
56 |
57 | void Buffer::Clear()
58 | {
59 | beg_ = 0;
60 | end_ = 0;
61 | size_ = 0;
62 | }
63 |
64 | void Buffer::Reset()
65 | {
66 | if (empty()) {
67 | assert(beg_ == end_);
68 | beg_ = 0;
69 | end_ = 0;
70 | size_ = 0;
71 | }
72 | }
73 |
74 | void Buffer::Adjust()
75 | {
76 | memmove(data_, begin(), size_);
77 | beg_ = 0;
78 | end_ = size_;
79 | }
80 |
81 | void Buffer::AdvanceHead(uint32_t len)
82 | {
83 | assert(size_ >= len);
84 | beg_ += len;
85 | size_ -= len;
86 | }
87 |
88 | void Buffer::AdvanceTail(uint32_t len)
89 | {
90 | assert(end_ + len <= cap_);
91 | end_ += len;
92 | size_ += len;
93 | }
94 |
95 | void Buffer::Unget(uint32_t len)
96 | {
97 | assert(beg_ >= len);
98 | beg_ -= len;
99 | size_ += len;
100 | }
101 |
102 | void Buffer::Read(const char *data, uint32_t len)
103 | {
104 | if (end_ + len > cap_) {
105 | uint32_t new_cap = cap_;
106 | while (end_ + len > new_cap)
107 | new_cap <<= 1;
108 | char *buf = new char[new_cap];
109 | memcpy(buf, begin(), size_);
110 | delete [] data_;
111 | data_ = buf;
112 | beg_ = 0;
113 | end_ = size_;
114 | cap_ = new_cap;
115 | }
116 | assert(end_ + len <= cap_);
117 | memcpy(end(), data, len);
118 | end_ += len;
119 | size_ += len;
120 | }
121 |
122 | void Buffer::Write(char *data, uint32_t len)
123 | {
124 | assert(size_ >= len);
125 | memcpy(data, begin(), len);
126 | beg_ += len;
127 | size_ -= len;
128 | }
129 |
130 | } // namespace Mushroom
131 |
--------------------------------------------------------------------------------
/src/network/buffer.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-04-27 09:44:37
6 | **/
7 |
8 | #ifndef _BUFFER_HPP_
9 | #define _BUFFER_HPP_
10 |
11 | #include "../include/utility.hpp"
12 |
13 | namespace Mushroom {
14 |
15 | class Buffer : private NoCopy
16 | {
17 | public:
18 | Buffer();
19 |
20 | ~Buffer();
21 |
22 | uint32_t size() const;
23 |
24 | bool empty() const;
25 |
26 | char* data() const;
27 |
28 | char* begin() const;
29 |
30 | char* end() const;
31 |
32 | uint32_t space() const;
33 |
34 | void Read(const char *data, uint32_t len);
35 |
36 | void Write(char *data, uint32_t len);
37 |
38 | void AdvanceHead(uint32_t len);
39 |
40 | void AdvanceTail(uint32_t len);
41 |
42 | void Reset();
43 |
44 | void Clear();
45 |
46 | void Adjust();
47 |
48 | void Unget(uint32_t len);
49 |
50 | private:
51 | char *data_;
52 | uint32_t size_;
53 | uint32_t cap_;
54 | uint32_t beg_;
55 | uint32_t end_;
56 | };
57 |
58 | } // namespace Mushroom
59 |
60 | #endif /* _BUFFER_HPP_ */
--------------------------------------------------------------------------------
/src/network/callback.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-04-30 17:25:03
6 | **/
7 |
8 | #ifndef _CALLBACK_HPP_
9 | #define _CALLBACK_HPP_
10 |
11 | #include
12 |
13 | namespace Mushroom {
14 |
15 | class Connection;
16 |
17 | typedef std::function ReadCallBack;
18 | typedef std::function WriteCallBack;
19 |
20 | typedef std::function ConnectCallBack;
21 |
22 | } // namespace Mushroom
23 |
24 | #endif /* _CALLBACK_HPP_ */
--------------------------------------------------------------------------------
/src/network/channel.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-04-30 17:07:49
6 | **/
7 |
8 | #include "channel.hpp"
9 | #include "poller.hpp"
10 |
11 | namespace Mushroom {
12 |
13 | Channel::Channel(int fd, Poller *poller, const ReadCallBack &readcb,
14 | const WriteCallBack &writecb)
15 | :fd_(fd), poller_(poller), readcb_(readcb), writecb_(writecb)
16 | {
17 | events_ = ReadEvent;
18 | poller_->AddChannel(this);
19 | }
20 |
21 | Channel::~Channel()
22 | {
23 | poller_->RemoveChannel(this);
24 | }
25 |
26 | int Channel::fd() const
27 | {
28 | return fd_;
29 | }
30 |
31 | uint32_t Channel::events() const
32 | {
33 | return events_;
34 | }
35 |
36 | void Channel::OnRead(const ReadCallBack &readcb)
37 | {
38 | readcb_ = readcb;
39 | }
40 |
41 | void Channel::OnWrite(const WriteCallBack &writecb)
42 | {
43 | writecb_ = writecb;
44 | }
45 |
46 | bool Channel::CanRead() const
47 | {
48 | return events_ & ReadEvent;
49 | }
50 |
51 | bool Channel::CanWrite() const
52 | {
53 | return events_ & WriteEvent;
54 | }
55 |
56 | void Channel::EnableRead(bool flag)
57 | {
58 | if (flag)
59 | events_ |= ReadEvent;
60 | else
61 | events_ &= ~ReadEvent;
62 |
63 | poller_->UpdateChannel(this);
64 | }
65 |
66 | void Channel::EnableWrite(bool flag)
67 | {
68 | if (flag)
69 | events_ |= WriteEvent;
70 | else
71 | events_ &= ~WriteEvent;
72 |
73 | poller_->UpdateChannel(this);
74 | }
75 |
76 | void Channel::HandleRead()
77 | {
78 | readcb_();
79 | }
80 |
81 | void Channel::HandleWrite()
82 | {
83 | writecb_();
84 | }
85 |
86 | } // namespace Mushroom
87 |
--------------------------------------------------------------------------------
/src/network/channel.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-04-30 17:07:38
6 | **/
7 |
8 | #ifndef _CHANNEL_HPP_
9 | #define _CHANNEL_HPP_
10 |
11 | #include "../include/utility.hpp"
12 | #include "callback.hpp"
13 |
14 | namespace Mushroom {
15 |
16 | class Poller;
17 |
18 | class Channel : private NoCopy
19 | {
20 | public:
21 | friend class Connection;
22 |
23 | Channel(int fd, Poller *poller, const ReadCallBack &readcb, const WriteCallBack &writecb);
24 |
25 | ~Channel();
26 |
27 | int fd() const;
28 |
29 | uint32_t events() const;
30 |
31 | bool CanRead() const;
32 |
33 | bool CanWrite() const;
34 |
35 | void OnRead(const ReadCallBack &readcb);
36 |
37 | void OnWrite(const WriteCallBack &writecb);
38 |
39 | void EnableRead(bool flag);
40 |
41 | void EnableWrite(bool flag);
42 |
43 | void HandleRead();
44 |
45 | void HandleWrite();
46 |
47 | private:
48 | int fd_;
49 | uint32_t events_;
50 | Poller *poller_;
51 |
52 | ReadCallBack readcb_;
53 | WriteCallBack writecb_;
54 | };
55 |
56 | } // namespace Mushroom
57 |
58 | #endif /* _CHANNEL_HPP_ */
--------------------------------------------------------------------------------
/src/network/connection.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-04-25 22:11:08
6 | **/
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #include "connection.hpp"
14 | #include "channel.hpp"
15 |
16 | namespace Mushroom {
17 |
18 | Connection::Connection(const EndPoint &server, Poller *poller)
19 | :readcb_(0), writecb_(0)
20 | {
21 | assert(socket_.Create());
22 | if (!socket_.Connect(server)) {
23 | printf("socket connect server %s failed, %s :(\n",
24 | server.ToString().c_str(), strerror(errno));
25 | return ;
26 | }
27 | assert(socket_.SetNonBlock());
28 | channel_ = new Channel(socket_.fd(), poller,
29 | [this]() { this->HandleRead(); }, [this]() { this->HandleWrite(); });
30 | connected_ = true;
31 | }
32 |
33 | Connection::Connection(const Socket &socket, Poller *poller)
34 | :socket_(socket), readcb_(0), writecb_(0)
35 | {
36 | assert(socket_.SetNonBlock());
37 | channel_ = new Channel(socket_.fd(), poller,
38 | [this]() { this->HandleRead(); }, [this]() { this->HandleWrite(); });
39 | connected_ = true;
40 | }
41 |
42 | Connection::~Connection()
43 | {
44 | Close();
45 | }
46 |
47 | bool Connection::Close()
48 | {
49 | if (socket_.Valid()) {
50 | connected_ = false;
51 | delete channel_;
52 | return socket_.Close();
53 | }
54 | return true;
55 | }
56 |
57 | bool Connection::Success() const
58 | {
59 | return connected_;
60 | }
61 |
62 | Buffer& Connection::GetInput()
63 | {
64 | return input_;
65 | }
66 |
67 | Buffer& Connection::GetOutput()
68 | {
69 | return output_;
70 | }
71 |
72 | void Connection::OnRead(const ReadCallBack &readcb)
73 | {
74 | readcb_ = readcb;
75 | }
76 |
77 | void Connection::OnWrite(const WriteCallBack &writecb)
78 | {
79 | writecb_ = writecb;
80 | }
81 |
82 | void Connection::HandleRead()
83 | {
84 | if (!connected_) {
85 | printf("connection has closed :(\n");
86 | return ;
87 | }
88 | input_.Reset();
89 | bool blocked = false;
90 | uint32_t read = socket_.Read(input_.end(), input_.space(), &blocked);
91 | if (!read && !blocked) {
92 | Close();
93 | return ;
94 | }
95 | input_.AdvanceTail(read);
96 | if (readcb_ && read)
97 | readcb_();
98 | }
99 |
100 | void Connection::HandleWrite()
101 | {
102 | if (!connected_) {
103 | printf("connection has closed :(\n");
104 | return ;
105 | }
106 | bool blocked = false;
107 | uint32_t write = socket_.Write(output_.begin(), output_.size(), &blocked);
108 | if (!write && !blocked) {
109 | Close();
110 | return ;
111 | }
112 | output_.AdvanceHead(write);
113 | if (output_.empty()) {
114 | if (writecb_)
115 | writecb_();
116 | if (channel_->CanWrite())
117 | channel_->EnableWrite(false);
118 | }
119 | }
120 |
121 | void Connection::Send(const char *str)
122 | {
123 | Send(str, strlen(str));
124 | }
125 |
126 | void Connection::Send(Buffer &buffer)
127 | {
128 | output_.Read(buffer.begin(), buffer.size());
129 | buffer.Clear();
130 | SendOutput();
131 | }
132 |
133 | void Connection::Send(const char *str, uint32_t len)
134 | {
135 | output_.Read(str, len);
136 | SendOutput();
137 | }
138 |
139 | void Connection::SendOutput()
140 | {
141 | if (!connected_) {
142 | // Error("connection has closed :(");
143 | output_.Clear();
144 | return ;
145 | }
146 | bool blocked = false;
147 | uint32_t write = socket_.Write(output_.begin(), output_.size(), &blocked);
148 | if (!write && !blocked) {
149 | Close();
150 | return ;
151 | }
152 | output_.AdvanceHead(write);
153 | if (output_.size()) {
154 | output_.Adjust();
155 | // if (!channel_->CanWrite())
156 | // channel_->EnableWrite(true);
157 | }
158 | }
159 |
160 | } // namespace Mushroom
161 |
--------------------------------------------------------------------------------
/src/network/connection.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-04-25 22:11:01
6 | **/
7 |
8 | #ifndef _CONNECTION_HPP_
9 | #define _CONNECTION_HPP_
10 |
11 | #include "../include/utility.hpp"
12 | #include "callback.hpp"
13 | #include "socket.hpp"
14 | #include "endpoint.hpp"
15 | #include "buffer.hpp"
16 |
17 | namespace Mushroom {
18 |
19 | class Channel;
20 | class Poller;
21 |
22 | class Connection : private NoCopy
23 | {
24 | public:
25 | Connection(const Socket &socket, Poller *poller);
26 |
27 | Connection(const EndPoint &server, Poller *poller);
28 |
29 | virtual ~Connection();
30 |
31 | bool Success() const;
32 |
33 | Buffer& GetInput();
34 |
35 | Buffer& GetOutput();
36 |
37 | void HandleRead();
38 |
39 | void HandleWrite();
40 |
41 | void OnRead(const ReadCallBack &readcb);
42 |
43 | void OnWrite(const WriteCallBack &writecb);
44 |
45 | bool Close();
46 |
47 | void Send(const char *str);
48 |
49 | void Send(Buffer &buffer);
50 |
51 | void Send(const char *str, uint32_t len);
52 |
53 | void SendOutput();
54 |
55 | protected:
56 | Socket socket_;
57 | bool connected_;
58 | Channel *channel_;
59 | Buffer input_;
60 | Buffer output_;
61 |
62 | ReadCallBack readcb_;
63 | WriteCallBack writecb_;
64 | };
65 |
66 | } // namespace Mushroom
67 |
68 | #endif /* _CONNECTION_HPP_ */
--------------------------------------------------------------------------------
/src/network/endpoint.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-04-23 23:25:45
6 | **/
7 |
8 | #include
9 | #include
10 |
11 | #include "endpoint.hpp"
12 |
13 | namespace Mushroom {
14 |
15 | EndPoint::EndPoint(uint16_t port, uint32_t address):port_(port), address_(address) { }
16 |
17 | EndPoint::EndPoint(uint16_t port, const char *str):port_(port)
18 | {
19 | assert(inet_pton(AF_INET, str, &address_) == 1);
20 | }
21 |
22 | EndPoint::~EndPoint() { }
23 |
24 | uint16_t EndPoint::Port() const
25 | {
26 | return port_;
27 | }
28 |
29 | uint32_t EndPoint::Address() const
30 | {
31 | return address_;
32 | }
33 |
34 | std::string EndPoint::ToString() const
35 | {
36 | char buf[MaxLen];
37 | assert(inet_ntop(AF_INET, &address_, buf, MaxLen));
38 | return std::string(buf) + " port " + std::to_string(port_);
39 | }
40 |
41 | } // namespace Mushroom
42 |
--------------------------------------------------------------------------------
/src/network/endpoint.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-04-23 23:25:32
6 | **/
7 |
8 | #ifndef _ENDPOINT_HPP_
9 | #define _ENDPOINT_HPP_
10 |
11 | #include
12 |
13 | namespace Mushroom {
14 |
15 | class EndPoint
16 | {
17 | public:
18 | static const uint32_t MaxLen = 16;
19 |
20 | EndPoint(uint16_t port, uint32_t address);
21 |
22 | EndPoint(uint16_t port, const char *str);
23 |
24 | ~EndPoint();
25 |
26 | uint16_t Port() const;
27 |
28 | uint32_t Address() const;
29 |
30 | std::string ToString() const;
31 |
32 | private:
33 | uint16_t port_;
34 | uint32_t address_;
35 | };
36 |
37 | } // namespace Mushroom
38 |
39 | #endif /* _ENDPOINT_HPP_ */
--------------------------------------------------------------------------------
/src/network/eventbase.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-06 23:47:45
6 | **/
7 |
8 | #include
9 | #include
10 |
11 | #include "../include/bounded_queue.hpp"
12 | #include "../include/thread_pool.hpp"
13 | #include "time.hpp"
14 | #include "eventbase.hpp"
15 | #include "poller.hpp"
16 | #include "channel.hpp"
17 | #include "socket.hpp"
18 |
19 | namespace Mushroom {
20 |
21 | static const int MaxTimeout = 0x7FFFFFFF;
22 |
23 | EventBase::EventBase(int thread_num, int queue_size)
24 | :running_(true), poller_(new Poller()), next_time_out_(MaxTimeout), seq_(0),
25 | queue_(new BoundedQueue(queue_size)), pool_(new ThreadPool(queue_, thread_num))
26 | {
27 | int r = pipe(wake_up_);
28 | assert(!r);
29 | assert(Socket(wake_up_[0]).SetNonBlock());
30 | channel_ = new Channel(wake_up_[0], poller_, 0, 0);
31 | channel_->OnRead([this]() {
32 | char buf;
33 | ssize_t r = read(channel_->fd(), &buf, sizeof(buf));
34 | if (r == sizeof(buf)) {
35 | } else {
36 | assert(0);
37 | }
38 | });
39 | pid_ = pthread_self();
40 | }
41 |
42 | EventBase::~EventBase()
43 | {
44 | close(wake_up_[1]);
45 | delete channel_;
46 | delete poller_;
47 | delete pool_;
48 | delete queue_;
49 | }
50 |
51 | Poller* EventBase::GetPoller()
52 | {
53 | return poller_;
54 | }
55 |
56 | void EventBase::Loop()
57 | {
58 | while (running_) {
59 | poller_->LoopOnce(std::min(5000, next_time_out_));
60 | HandleTimeout();
61 | }
62 | if (next_time_out_ != MaxTimeout) {
63 | poller_->LoopOnce(next_time_out_);
64 | HandleTimeout();
65 | } else {
66 | poller_->LoopOnce(0);
67 | }
68 | repeat_.clear();
69 | pending_.clear();
70 | pool_->Clear();
71 | }
72 |
73 | void EventBase::Exit()
74 | {
75 | mutex_.Lock();
76 | if (!running_) {
77 | mutex_.Unlock();
78 | return ;
79 | }
80 | running_ = false;
81 | WakeUp();
82 | mutex_.Unlock();
83 | }
84 |
85 | void EventBase::WakeUp()
86 | {
87 | char buf;
88 | ssize_t r = write(wake_up_[1], &buf, sizeof(buf));
89 | assert(r > 0);
90 | }
91 |
92 | void EventBase::Refresh()
93 | {
94 | if (pending_.empty()) {
95 | next_time_out_ = MaxTimeout;
96 | } else {
97 | auto &it = pending_.begin()->first;
98 | int64_t tmp = it.first - Time::Now();
99 | next_time_out_ = (tmp <= 0) ? 0 : int(tmp);
100 | }
101 | }
102 |
103 | void EventBase::RunNow(Task &&task)
104 | {
105 | RunAfter(0, std::move(task));
106 | }
107 |
108 | TimerId EventBase::RunAfter(int64_t milli_sec, Task &&task)
109 | {
110 | mutex_.Lock();
111 | if (!running_) {
112 | mutex_.Unlock();
113 | return TimerId();
114 | }
115 | TimerId id { Time::Now() + milli_sec, seq_++};
116 | pending_.insert({id, std::move(task)});
117 | if (pthread_self() != pid_)
118 | WakeUp();
119 | else
120 | Refresh();
121 | mutex_.Unlock();
122 | return id;
123 | }
124 |
125 | TimerId EventBase::RunEvery(int64_t milli_sec, Task &&task)
126 | {
127 | mutex_.Lock();
128 | if (!running_) {
129 | mutex_.Unlock();
130 | return TimerId();
131 | }
132 | uint32_t seq = seq_++;
133 | TimeRep rep {milli_sec, Time::Now()};
134 | TimerId id {rep.second, seq};
135 | repeat_.insert({seq, rep});
136 | pending_.insert({id, std::move(task)});
137 | if (pthread_self() != pid_)
138 | WakeUp();
139 | else
140 | Refresh();
141 | mutex_.Unlock();
142 | return {milli_sec, seq};
143 | }
144 |
145 | void EventBase::RescheduleAfter(TimerId *id, int64_t milli_sec, Task &&task)
146 | {
147 | mutex_.Lock();
148 | if (!running_) {
149 | mutex_.Unlock();
150 | return ;
151 | }
152 | TimerId nid { Time::Now() + milli_sec, seq_++};
153 | auto it = pending_.find(*id);
154 | if (it != pending_.end())
155 | pending_.erase(it);
156 | pending_.insert({nid, std::move(task)});
157 | *id = nid;
158 | if (pthread_self() != pid_)
159 | WakeUp();
160 | else
161 | Refresh();
162 | mutex_.Unlock();
163 | }
164 |
165 | void EventBase::RescheduleAfter(const TimerId &id, int64_t milli_sec)
166 | {
167 | mutex_.Lock();
168 | if (!running_) {
169 | mutex_.Unlock();
170 | return ;
171 | }
172 | TimerId nid { Time::Now() + milli_sec, seq_++};
173 | auto it = pending_.find(id);
174 | if (it == pending_.end()) {
175 | mutex_.Unlock();
176 | return ;
177 | }
178 | Task task = std::move(it->second);
179 | pending_.erase(it);
180 | pending_.insert({nid, std::move(task)});
181 | if (pthread_self() != pid_)
182 | WakeUp();
183 | else
184 | Refresh();
185 | mutex_.Unlock();
186 | }
187 |
188 | void EventBase::Cancel(const TimerId &id)
189 | {
190 | mutex_.Lock();
191 | auto rit = repeat_.find(id.second);
192 | if (rit != repeat_.end()) {
193 | repeat_.erase(rit);
194 | auto it = pending_.find({rit->second.second, id.second});
195 | if (it != pending_.end())
196 | pending_.erase(it);
197 | } else {
198 | auto it = pending_.find(id);
199 | if (it != pending_.end())
200 | pending_.erase(it);
201 | }
202 | mutex_.Unlock();
203 | }
204 |
205 | void EventBase::HandleTimeout()
206 | {
207 | TimerId now { Time::Now(), 0xFFFFFFFF};
208 | std::vector expired;
209 | mutex_.Lock();
210 | for (; running_ && !pending_.empty() && pending_.begin()->first <= now; ) {
211 | expired.push_back(pending_.begin()->second);
212 | const TimerId &id = pending_.begin()->first;
213 | auto it = repeat_.find(id.second);
214 | if (it != repeat_.end()) {
215 | TimerId nid { now.first + it->second.first, id.second };
216 | it->second.second = nid.first;
217 | pending_.insert({nid, std::move(pending_.begin()->second)});
218 | }
219 | pending_.erase(pending_.begin());
220 | }
221 | Refresh();
222 | mutex_.Unlock();
223 | for (uint32_t i = 0; i < expired.size(); ++i)
224 | queue_->Push(std::move(expired[i]));
225 | }
226 |
227 | } // namespace Mushroom
228 |
--------------------------------------------------------------------------------
/src/network/eventbase.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * > Author: UncP
3 | * > Github: www.github.com/UncP/Mushroom
4 | * > License: BSD-3
5 | * > Time: 2017-05-06 23:45:21
6 | **/
7 |
8 | #ifndef _EVENT_BASE_HPP_
9 | #define _EVENT_BASE_HPP_
10 |
11 | #include