Skip to content

Commit 5ece6d7

Browse files
committed
iobuf support reserve_aligned
1 parent 0625945 commit 5ece6d7

3 files changed

Lines changed: 124 additions & 0 deletions

File tree

src/butil/iobuf.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,50 @@ IOBuf::Area IOBuf::reserve(size_t count) {
13711371
return result;
13721372
}
13731373

1374+
IOBuf::Area IOBuf::reserve_aligned(size_t n, size_t alignment) {
1375+
bool is_power_two = alignment > 0 && (alignment & (alignment - 1));
1376+
if (is_power_two != 0) {
1377+
LOG(ERROR) << "Invalid alignment, must power of two";
1378+
return INVALID_AREA;
1379+
}
1380+
size_t count = (n + alignment - 1) & ~(alignment - 1);
1381+
IOBuf::Area result = INVALID_AREA;
1382+
size_t total_nc = 0;
1383+
while (total_nc < count) { // excluded count == 0
1384+
IOBuf::Block* b = iobuf::share_tls_block();
1385+
if (BAIDU_UNLIKELY(!b)) {
1386+
return INVALID_AREA;
1387+
}
1388+
const size_t remainder =
1389+
reinterpret_cast<uintptr_t>(b->data + b->size) % alignment;
1390+
const size_t align_add = (remainder != 0) ? alignment - remainder : 0;
1391+
const size_t align_left =
1392+
(b->left_space() > align_add) ? b->left_space() - align_add : 0;
1393+
if (b->size == 0 && align_left < alignment) {
1394+
LOG(ERROR) << "iobuf block size " << b->cap
1395+
<< " is not suitable for alignment " << alignment;
1396+
return INVALID_AREA;
1397+
}
1398+
if (align_left < alignment) {
1399+
b->size = b->cap;
1400+
continue;
1401+
}
1402+
b->size += align_add;
1403+
const size_t nc =
1404+
std::min(count - total_nc, b->left_space()) & ~(alignment - 1);
1405+
const IOBuf::BlockRef r = {(uint32_t)b->size, (uint32_t)nc, b};
1406+
_push_back_ref(r);
1407+
if (total_nc == 0) {
1408+
// Encode the area at first time. Notice that the pushed ref may
1409+
// be merged with existing ones.
1410+
result = make_area(_ref_num() - 1, _back_ref().length - nc, count);
1411+
}
1412+
total_nc += nc;
1413+
b->size += nc;
1414+
}
1415+
return result;
1416+
}
1417+
13741418
int IOBuf::unsafe_assign(Area area, const void* data) {
13751419
if (area == INVALID_AREA || data == NULL) {
13761420
LOG(ERROR) << "Invalid parameters";

src/butil/iobuf.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,11 @@ friend class IOBufCutter;
273273
// NOTE: reserve(0) returns INVALID_AREA.
274274
Area reserve(size_t n);
275275

276+
// Reserve `n' aligned uninitialized bytes at back-side.
277+
// Returns an object representing the reserved area, INVALID_AREA on failure.
278+
// NOTE: reserve(0) returns INVALID_AREA, alignment must be a power of 2.
279+
Area reserve_aligned(size_t n, size_t alignment);
280+
276281
// [EXTREMELY UNSAFE]
277282
// Copy `data' to the reserved `area'. `data' must be as long as the
278283
// reserved size.

test/iobuf_unittest.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,4 +1785,79 @@ TEST_F(IOBufTest, acquire_tls_block) {
17851785
ASSERT_NE(butil::iobuf::block_cap(b), butil::iobuf::block_size(b));
17861786
}
17871787

1788+
TEST_F(IOBufTest, reserve_aligned) {
1789+
{
1790+
butil::IOBuf buf;
1791+
auto area = buf.reserve_aligned(1024, 16);
1792+
ASSERT_NE(area, butil::IOBuf::INVALID_AREA);
1793+
butil::IOBufAsZeroCopyInputStream wrapper(buf);
1794+
const void* data;
1795+
int size;
1796+
int total_size = 0;
1797+
while (wrapper.Next(&data, &size)) {
1798+
ASSERT_EQ(reinterpret_cast<uintptr_t>(data) % 16, 0);
1799+
ASSERT_EQ(size % 16, 0);
1800+
total_size += size;
1801+
}
1802+
ASSERT_EQ(total_size, 1024);
1803+
}
1804+
{
1805+
butil::IOBuf buf;
1806+
auto area = buf.reserve_aligned(1024, 4096);
1807+
ASSERT_NE(area, butil::IOBuf::INVALID_AREA);
1808+
butil::IOBufAsZeroCopyInputStream wrapper(buf);
1809+
const void* data;
1810+
int size;
1811+
int total_size = 0;
1812+
while (wrapper.Next(&data, &size)) {
1813+
ASSERT_EQ(reinterpret_cast<uintptr_t>(data) % 4096, 0);
1814+
ASSERT_EQ(size % 4096, 0);
1815+
total_size += size;
1816+
}
1817+
ASSERT_EQ(total_size, 4096);
1818+
}
1819+
{
1820+
butil::IOBuf buf;
1821+
auto area = buf.reserve_aligned(8191, 4096);
1822+
ASSERT_NE(area, butil::IOBuf::INVALID_AREA);
1823+
butil::IOBufAsZeroCopyInputStream wrapper(buf);
1824+
const void* data;
1825+
int size;
1826+
int total_size = 0;
1827+
while (wrapper.Next(&data, &size)) {
1828+
ASSERT_EQ(reinterpret_cast<uintptr_t>(data) % 4096, 0);
1829+
ASSERT_EQ(size % 4096, 0);
1830+
total_size += size;
1831+
}
1832+
ASSERT_EQ(total_size, 8192);
1833+
}
1834+
{
1835+
butil::IOBuf buf;
1836+
auto area = buf.reserve_aligned(4096 * 10 - 1, 4096);
1837+
ASSERT_NE(area, butil::IOBuf::INVALID_AREA);
1838+
butil::IOBufAsZeroCopyInputStream wrapper(buf);
1839+
const void* data;
1840+
int size;
1841+
int total_size = 0;
1842+
while (wrapper.Next(&data, &size)) {
1843+
ASSERT_EQ(reinterpret_cast<uintptr_t>(data) % 4096, 0);
1844+
ASSERT_EQ(size % 4096, 0);
1845+
total_size += size;
1846+
}
1847+
ASSERT_EQ(total_size, 4096 * 10);
1848+
}
1849+
{
1850+
LOG(INFO) << "0000";
1851+
butil::IOBuf buf;
1852+
auto area = buf.reserve_aligned(4096, 4095);
1853+
ASSERT_EQ(area, butil::IOBuf::INVALID_AREA);
1854+
}
1855+
{
1856+
LOG(INFO) << "1111";
1857+
butil::IOBuf buf;
1858+
auto area = buf.reserve_aligned(4096 * 10, 8192);
1859+
ASSERT_EQ(area, butil::IOBuf::INVALID_AREA);
1860+
}
1861+
}
1862+
17881863
} // namespace

0 commit comments

Comments
 (0)