Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 44ab2d0

Browse files
authored
Experimental/inline cord separate (vesoft-inc#2055)
1 parent 26aac4b commit 44ab2d0

File tree

7 files changed

+637
-283
lines changed

7 files changed

+637
-283
lines changed

src/common/base/ICord.h

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
/* Copyright (c) 2020 vesoft inc. All rights reserved.
2+
*
3+
* This source code is licensed under Apache 2.0 License,
4+
* attached with Common Clause Condition 1.0, found in the LICENSES directory.
5+
*/
6+
7+
#pragma once
8+
9+
#include <base/Base.h>
10+
11+
namespace nebula {
12+
13+
template <std::size_t kBlockContentSize = 1024>
14+
class ICord {
15+
public:
16+
static_assert(kBlockContentSize && !(kBlockContentSize & (kBlockContentSize-1)),
17+
"kBlockContentSize must be power of 2");
18+
ICord() : head_(inlineBlock_), tail_(head_) {}
19+
20+
virtual ~ICord() {
21+
clear();
22+
}
23+
24+
size_t size() const noexcept {
25+
return len_;
26+
}
27+
28+
bool empty() const noexcept {
29+
return len_ == 0;
30+
}
31+
32+
void clear() {
33+
auto alloc = next(head_);
34+
if (alloc) {
35+
DCHECK(tail_);
36+
37+
// Need to release all blocks
38+
char* p = alloc;
39+
while (p != tail_) {
40+
char* n = next(p);
41+
free(p);
42+
p = n;
43+
}
44+
// Free the last block
45+
free(p);
46+
}
47+
48+
len_ = 0;
49+
50+
head_ = nullptr;
51+
tail_ = nullptr;
52+
}
53+
54+
// Apply each block to the visitor until the end or the visitor
55+
// returns false
56+
bool applyTo(std::function<bool(const char*, int32_t)> visitor) const {
57+
if (empty()) {
58+
return true;
59+
}
60+
61+
char* n = head_;
62+
while (n != tail_) {
63+
if (!visitor(n, kBlockContentSize)) {
64+
// stop visiting further
65+
return false;
66+
}
67+
// Get the pointer to the next block
68+
n = next(n);
69+
}
70+
71+
// Last block
72+
return visitor(tail_, lengthMod());
73+
}
74+
75+
// Append the cord content to the given string
76+
size_t appendTo(std::string& str) const {
77+
if (empty()) {
78+
return 0;
79+
}
80+
81+
char* n = head_;
82+
while (n != tail_) {
83+
str.append(n, kBlockContentSize);
84+
// Get the pointer to the next block
85+
n = next(n);
86+
}
87+
88+
// Last block
89+
std::size_t lengthModSize = lengthMod();
90+
str.append(tail_, lengthModSize == 0 ? kBlockContentSize : lengthModSize);
91+
92+
return len_;
93+
}
94+
95+
// Convert the cord content to a new string
96+
std::string str() const {
97+
std::string buf;
98+
buf.reserve(len_);
99+
appendTo(buf);
100+
101+
return buf;
102+
}
103+
104+
ICord<kBlockContentSize>& write(const char* value, size_t len) {
105+
if (len == 0) {
106+
return *this;
107+
}
108+
109+
std::size_t lengthModSize = lengthMod();
110+
size_t bytesToWrite =
111+
std::min(len, static_cast<size_t>(kBlockContentSize - lengthModSize));
112+
if (len_ != 0 && lengthModSize == 0) { // is full filled.
113+
allocateBlock();
114+
bytesToWrite = std::min(len, static_cast<size_t>(kBlockContentSize));
115+
}
116+
memcpy(tail_ + lengthModSize, value, bytesToWrite);
117+
len_ += bytesToWrite;
118+
119+
if (bytesToWrite < len) {
120+
return write(value + bytesToWrite, len - bytesToWrite);
121+
} else {
122+
return *this;
123+
}
124+
}
125+
126+
// stream
127+
ICord<kBlockContentSize>& operator<<(int8_t value) {
128+
return write(reinterpret_cast<char*>(&value), sizeof(int8_t));
129+
}
130+
131+
ICord<kBlockContentSize>& operator<<(uint8_t value) {
132+
return write(reinterpret_cast<char*>(&value), sizeof(uint8_t));
133+
}
134+
135+
ICord<kBlockContentSize>& operator<<(int16_t value) {
136+
return write(reinterpret_cast<char*>(&value), sizeof(int16_t));
137+
}
138+
139+
ICord<kBlockContentSize>& operator<<(uint16_t value) {
140+
return write(reinterpret_cast<char*>(&value), sizeof(uint16_t));
141+
}
142+
143+
ICord<kBlockContentSize>& operator<<(int32_t value) {
144+
return write(reinterpret_cast<char*>(&value), sizeof(int32_t));
145+
}
146+
147+
ICord<kBlockContentSize>& operator<<(uint32_t value) {
148+
return write(reinterpret_cast<char*>(&value), sizeof(uint32_t));
149+
}
150+
151+
ICord<kBlockContentSize>& operator<<(int64_t value) {
152+
return write(reinterpret_cast<char*>(&value), sizeof(int64_t));
153+
}
154+
155+
ICord<kBlockContentSize>& operator<<(uint64_t value) {
156+
return write(reinterpret_cast<char*>(&value), sizeof(uint64_t));
157+
}
158+
159+
ICord<kBlockContentSize>& operator<<(char value) {
160+
return write(&value, sizeof(char));
161+
}
162+
163+
ICord<kBlockContentSize>& operator<<(bool value) {
164+
return write(reinterpret_cast<char*>(&value), sizeof(bool));
165+
}
166+
167+
ICord<kBlockContentSize>& operator<<(float value) {
168+
return write(reinterpret_cast<char*>(&value), sizeof(float));
169+
}
170+
171+
ICord<kBlockContentSize>& operator<<(double value) {
172+
return write(reinterpret_cast<char*>(&value), sizeof(double));
173+
}
174+
175+
ICord<kBlockContentSize>& operator<<(const std::string& value) {
176+
return write(value.data(), value.size());
177+
}
178+
179+
ICord<kBlockContentSize>& operator<<(const char* value) {
180+
return write(value, strlen(value));
181+
}
182+
183+
ICord<kBlockContentSize>& operator<<(const ICord& rhs) {
184+
char* n = rhs.head_;
185+
while (n != rhs.tail_) {
186+
write(n, kBlockContentSize);
187+
// Get the pointer to the next block
188+
n = next(n);
189+
}
190+
191+
// Last block
192+
write(rhs.tail_, rhs.lengthMod());
193+
194+
return *this;
195+
}
196+
197+
private:
198+
// Disable dynamic allocation
199+
void* operator new(std::size_t) = delete;
200+
201+
// Is the capacity full filled
202+
bool isFull() const {
203+
return len_ != 0 && lengthMod() == 0;
204+
}
205+
206+
// Used size in last block
207+
std::size_t lengthMod() const {
208+
return len_ & (kBlockContentSize - 1);
209+
}
210+
211+
// Is there only inline allocation
212+
bool isInline() const {
213+
return len_ < kBlockContentSize;
214+
}
215+
216+
// return next block pointer
217+
char* next(char* p) const {
218+
if (p == tail_) {
219+
return nullptr;
220+
} else {
221+
return *reinterpret_cast<char**>(p + kBlockContentSize);
222+
}
223+
}
224+
225+
void allocateBlock() {
226+
DCHECK(isFull());
227+
char* blk = reinterpret_cast<char*>(malloc(kBlockSize * sizeof(char)));
228+
229+
if (tail_) {
230+
// Link the tail to the new block
231+
memcpy(tail_ + kBlockContentSize, reinterpret_cast<char*>(&blk), sizeof(char*));
232+
}
233+
tail_ = blk;
234+
235+
if (!head_) {
236+
head_ = blk;
237+
}
238+
}
239+
240+
static constexpr std::size_t kBlockSize = kBlockContentSize + sizeof(char*);
241+
242+
size_t len_ = 0;
243+
char* head_;
244+
char* tail_;
245+
char inlineBlock_[kBlockSize];
246+
};
247+
248+
} // namespace nebula

src/common/base/test/CMakeLists.txt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@ nebula_add_test(
55
LIBRARIES gtest
66
)
77

8+
nebula_add_test(
9+
NAME icord_test
10+
SOURCES ICordTest.cpp
11+
OBJECTS $<TARGET_OBJECTS:base_obj>
12+
LIBRARIES gtest
13+
)
14+
815
nebula_add_executable(
9-
NAME cord_bm
10-
SOURCES CordBenchmark.cpp
16+
NAME icord_bm
17+
SOURCES ICordBenchmark.cpp
1118
OBJECTS $<TARGET_OBJECTS:base_obj>
1219
LIBRARIES follybenchmark boost_regex
1320
)

src/common/base/test/CordBenchmark.cpp

Lines changed: 0 additions & 83 deletions
This file was deleted.

0 commit comments

Comments
 (0)