iobuf_unittest.cpp 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709
  1. // Licensed to the Apache Software Foundation (ASF) under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The ASF licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. #include <gtest/gtest.h>
  18. #include <sys/types.h>
  19. #include <sys/socket.h> // socketpair
  20. #include <errno.h> // errno
  21. #include <fcntl.h> // O_RDONLY
  22. #include <butil/files/temp_file.h> // TempFile
  23. #include <butil/containers/flat_map.h>
  24. #include <butil/macros.h>
  25. #include <butil/time.h> // Timer
  26. #include <butil/fd_utility.h> // make_non_blocking
  27. #include <butil/iobuf.h>
  28. #include <butil/logging.h>
  29. #include <butil/fd_guard.h>
  30. #include <butil/errno.h>
  31. #include <butil/fast_rand.h>
  32. #if BAZEL_TEST
  33. #include "test/iobuf.pb.h"
  34. #else
  35. #include "iobuf.pb.h"
  36. #endif // BAZEL_TEST
  37. namespace butil {
  38. namespace iobuf {
  39. extern void* (*blockmem_allocate)(size_t);
  40. extern void (*blockmem_deallocate)(void*);
  41. extern void reset_blockmem_allocate_and_deallocate();
  42. extern int32_t block_shared_count(butil::IOBuf::Block const* b);
  43. extern uint32_t block_cap(butil::IOBuf::Block const* b);
  44. extern IOBuf::Block* get_tls_block_head();
  45. extern int get_tls_block_count();
  46. extern void remove_tls_block_chain();
  47. extern IOBuf::Block* acquire_tls_block();
  48. extern IOBuf::Block* share_tls_block();
  49. extern void release_tls_block_chain(IOBuf::Block* b);
  50. extern uint32_t block_cap(IOBuf::Block const* b);
  51. extern uint32_t block_size(IOBuf::Block const* b);
  52. extern IOBuf::Block* get_portal_next(IOBuf::Block const* b);
  53. }
  54. }
  55. namespace {
  56. const size_t BLOCK_OVERHEAD = 32; //impl dependent
  57. const size_t DEFAULT_PAYLOAD = butil::IOBuf::DEFAULT_BLOCK_SIZE - BLOCK_OVERHEAD;
  58. void check_tls_block() {
  59. ASSERT_EQ((butil::IOBuf::Block*)NULL, butil::iobuf::get_tls_block_head());
  60. printf("tls_block of butil::IOBuf was deleted\n");
  61. }
  62. const int ALLOW_UNUSED check_dummy = butil::thread_atexit(check_tls_block);
  63. static butil::FlatSet<void*> s_set;
  64. void* debug_block_allocate(size_t block_size) {
  65. void* b = operator new (block_size, std::nothrow);
  66. s_set.insert(b);
  67. return b;
  68. }
  69. void debug_block_deallocate(void* b) {
  70. if (1ul != s_set.erase(b)) {
  71. ASSERT_TRUE(false) << "Bad block=" << b;
  72. } else {
  73. operator delete(b);
  74. }
  75. }
  76. inline bool is_debug_allocator_enabled() {
  77. return (butil::iobuf::blockmem_allocate == debug_block_allocate);
  78. }
  79. void install_debug_allocator() {
  80. if (!is_debug_allocator_enabled()) {
  81. butil::iobuf::remove_tls_block_chain();
  82. s_set.init(1024);
  83. butil::iobuf::blockmem_allocate = debug_block_allocate;
  84. butil::iobuf::blockmem_deallocate = debug_block_deallocate;
  85. LOG(INFO) << "<Installed debug create/destroy>";
  86. }
  87. }
  88. void show_prof_and_rm(const char* bin_name, const char* filename, size_t topn) {
  89. char cmd[1024];
  90. if (topn != 0) {
  91. snprintf(cmd, sizeof(cmd), "if [ -e %s ] ; then CPUPROFILE_FREQUENCY=1000 ./pprof --text %s %s | head -%lu; rm -f %s; fi", filename, bin_name, filename, topn+1, filename);
  92. } else {
  93. snprintf(cmd, sizeof(cmd), "if [ -e %s ] ; then CPUPROFILE_FREQUENCY=1000 ./pprof --text %s %s; rm -f %s; fi", filename, bin_name, filename, filename);
  94. }
  95. ASSERT_EQ(0, system(cmd));
  96. }
  97. static void check_memory_leak() {
  98. if (is_debug_allocator_enabled()) {
  99. butil::IOBuf::Block* p = butil::iobuf::get_tls_block_head();
  100. size_t n = 0;
  101. while (p) {
  102. ASSERT_TRUE(s_set.seek(p)) << "Memory leak: " << p;
  103. p = butil::iobuf::get_portal_next(p);
  104. ++n;
  105. }
  106. ASSERT_EQ(n, s_set.size());
  107. ASSERT_EQ(n, (size_t)butil::iobuf::get_tls_block_count());
  108. }
  109. }
  110. class IOBufTest : public ::testing::Test{
  111. protected:
  112. IOBufTest(){};
  113. virtual ~IOBufTest(){};
  114. virtual void SetUp() {
  115. };
  116. virtual void TearDown() {
  117. check_memory_leak();
  118. };
  119. };
  120. std::string to_str(const butil::IOBuf& p) {
  121. return p.to_string();
  122. }
  123. TEST_F(IOBufTest, append_zero) {
  124. int fds[2];
  125. ASSERT_EQ(0, pipe(fds));
  126. butil::IOPortal p;
  127. ASSERT_EQ(0, p.append_from_file_descriptor(fds[0], 0));
  128. ASSERT_EQ(0, close(fds[0]));
  129. ASSERT_EQ(0, close(fds[1]));
  130. }
  131. TEST_F(IOBufTest, pop_front) {
  132. install_debug_allocator();
  133. butil::IOBuf buf;
  134. ASSERT_EQ(0UL, buf.pop_front(1)); // nothing happened
  135. std::string s = "hello";
  136. buf.append(s);
  137. ASSERT_EQ(s, to_str(buf));
  138. ASSERT_EQ(0UL, buf.pop_front(0)); // nothing happened
  139. ASSERT_EQ(s, to_str(buf));
  140. ASSERT_EQ(1UL, buf.pop_front(1));
  141. s.erase(0, 1);
  142. ASSERT_EQ(s, to_str(buf));
  143. ASSERT_EQ(s.length(), buf.length());
  144. ASSERT_FALSE(buf.empty());
  145. ASSERT_EQ(s.length(), buf.pop_front(INT_MAX));
  146. s.clear();
  147. ASSERT_EQ(s, to_str(buf));
  148. ASSERT_EQ(0UL, buf.length());
  149. ASSERT_TRUE(buf.empty());
  150. for (size_t i = 0; i < DEFAULT_PAYLOAD * 3/2; ++i) {
  151. s.push_back(i);
  152. }
  153. buf.append(s);
  154. ASSERT_EQ(1UL, buf.pop_front(1));
  155. s.erase(0, 1);
  156. ASSERT_EQ(s, to_str(buf));
  157. ASSERT_EQ(s.length(), buf.length());
  158. ASSERT_FALSE(buf.empty());
  159. ASSERT_EQ(s.length(), buf.pop_front(INT_MAX));
  160. s.clear();
  161. ASSERT_EQ(s, to_str(buf));
  162. ASSERT_EQ(0UL, buf.length());
  163. ASSERT_TRUE(buf.empty());
  164. }
  165. TEST_F(IOBufTest, pop_back) {
  166. install_debug_allocator();
  167. butil::IOBuf buf;
  168. ASSERT_EQ(0UL, buf.pop_back(1)); // nothing happened
  169. std::string s = "hello";
  170. buf.append(s);
  171. ASSERT_EQ(s, to_str(buf));
  172. ASSERT_EQ(0UL, buf.pop_back(0)); // nothing happened
  173. ASSERT_EQ(s, to_str(buf));
  174. ASSERT_EQ(1UL, buf.pop_back(1));
  175. s.resize(s.size() - 1);
  176. ASSERT_EQ(s, to_str(buf));
  177. ASSERT_EQ(s.length(), buf.length());
  178. ASSERT_FALSE(buf.empty());
  179. ASSERT_EQ(s.length(), buf.pop_back(INT_MAX));
  180. s.clear();
  181. ASSERT_EQ(s, to_str(buf));
  182. ASSERT_EQ(0UL, buf.length());
  183. ASSERT_TRUE(buf.empty());
  184. for (size_t i = 0; i < DEFAULT_PAYLOAD * 3/2; ++i) {
  185. s.push_back(i);
  186. }
  187. buf.append(s);
  188. ASSERT_EQ(1UL, buf.pop_back(1));
  189. s.resize(s.size() - 1);
  190. ASSERT_EQ(s, to_str(buf));
  191. ASSERT_EQ(s.length(), buf.length());
  192. ASSERT_FALSE(buf.empty());
  193. ASSERT_EQ(s.length(), buf.pop_back(INT_MAX));
  194. s.clear();
  195. ASSERT_EQ(s, to_str(buf));
  196. ASSERT_EQ(0UL, buf.length());
  197. ASSERT_TRUE(buf.empty());
  198. }
  199. TEST_F(IOBufTest, append) {
  200. install_debug_allocator();
  201. butil::IOBuf b;
  202. ASSERT_EQ(0UL, b.length());
  203. ASSERT_TRUE(b.empty());
  204. ASSERT_EQ(-1, b.append(NULL));
  205. ASSERT_EQ(0, b.append(""));
  206. ASSERT_EQ(0, b.append(std::string()));
  207. ASSERT_EQ(-1, b.append(NULL, 1));
  208. ASSERT_EQ(0, b.append("dummy", 0));
  209. ASSERT_EQ(0UL, b.length());
  210. ASSERT_TRUE(b.empty());
  211. ASSERT_EQ(0, b.append("1"));
  212. ASSERT_EQ(1UL, b.length());
  213. ASSERT_FALSE(b.empty());
  214. ASSERT_EQ("1", to_str(b));
  215. const std::string s = "22";
  216. ASSERT_EQ(0, b.append(s));
  217. ASSERT_EQ(3UL, b.length());
  218. ASSERT_FALSE(b.empty());
  219. ASSERT_EQ("122", to_str(b));
  220. }
  221. TEST_F(IOBufTest, appendv) {
  222. install_debug_allocator();
  223. butil::IOBuf b;
  224. const_iovec vec[] = { {"hello1", 6}, {" world1", 7},
  225. {"hello2", 6}, {" world2", 7},
  226. {"hello3", 6}, {" world3", 7},
  227. {"hello4", 6}, {" world4", 7},
  228. {"hello5", 6}, {" world5", 7} };
  229. ASSERT_EQ(0, b.appendv(vec, arraysize(vec)));
  230. ASSERT_EQ("hello1 world1hello2 world2hello3 world3hello4 world4hello5 world5",
  231. b.to_string());
  232. // Make some iov_len shorter to test if iov_len works.
  233. vec[2].iov_len = 4; // "hello2"
  234. vec[5].iov_len = 3; // " world3"
  235. b.clear();
  236. ASSERT_EQ(0, b.appendv(vec, arraysize(vec)));
  237. ASSERT_EQ("hello1 world1hell world2hello3 wohello4 world4hello5 world5",
  238. b.to_string());
  239. // Append some long stuff.
  240. const size_t full_len = DEFAULT_PAYLOAD * 9;
  241. char* str = (char*)malloc(full_len);
  242. ASSERT_TRUE(str);
  243. const size_t len1 = full_len / 6;
  244. const size_t len2 = full_len / 3;
  245. const size_t len3 = full_len - len1 - len2;
  246. ASSERT_GT(len1, (size_t)DEFAULT_PAYLOAD);
  247. ASSERT_GT(len2, (size_t)DEFAULT_PAYLOAD);
  248. ASSERT_GT(len3, (size_t)DEFAULT_PAYLOAD);
  249. ASSERT_EQ(full_len, len1 + len2 + len3);
  250. for (size_t i = 0; i < full_len; ++i) {
  251. str[i] = i * 7;
  252. }
  253. const_iovec vec2[] = {{str, len1},
  254. {str + len1, len2},
  255. {str + len1 + len2, len3}};
  256. b.clear();
  257. ASSERT_EQ(0, b.appendv(vec2, arraysize(vec2)));
  258. ASSERT_EQ(full_len, b.size());
  259. ASSERT_EQ(0, memcmp(str, b.to_string().data(), full_len));
  260. }
  261. TEST_F(IOBufTest, reserve) {
  262. butil::IOBuf b;
  263. ASSERT_EQ(butil::IOBuf::INVALID_AREA, b.reserve(0));
  264. const size_t NRESERVED1 = 5;
  265. const butil::IOBuf::Area a1 = b.reserve(NRESERVED1);
  266. ASSERT_TRUE(a1 != butil::IOBuf::INVALID_AREA);
  267. ASSERT_EQ(NRESERVED1, b.size());
  268. b.append("hello world");
  269. ASSERT_EQ(0, b.unsafe_assign(a1, "prefix")); // `x' will not be copied
  270. ASSERT_EQ("prefihello world", b.to_string());
  271. ASSERT_EQ((size_t)16, b.size());
  272. // pop/append sth. from back-side and assign again.
  273. ASSERT_EQ((size_t)5, b.pop_back(5));
  274. ASSERT_EQ("prefihello ", b.to_string());
  275. b.append("blahblahfoobar");
  276. ASSERT_EQ(0, b.unsafe_assign(a1, "goodorbad")); // `x' will not be copied
  277. ASSERT_EQ("goodohello blahblahfoobar", b.to_string());
  278. // append a long string and assign again.
  279. std::string s1(DEFAULT_PAYLOAD * 3, '\0');
  280. for (size_t i = 0; i < s1.size(); ++i) {
  281. s1[i] = i * 7;
  282. }
  283. ASSERT_EQ(DEFAULT_PAYLOAD * 3, s1.size());
  284. // remove everything after reserved area
  285. ASSERT_GE(b.size(), NRESERVED1);
  286. b.pop_back(b.size() - NRESERVED1);
  287. ASSERT_EQ(NRESERVED1, b.size());
  288. b.append(s1);
  289. ASSERT_EQ(0, b.unsafe_assign(a1, "appleblahblah"));
  290. ASSERT_EQ("apple" + s1, b.to_string());
  291. // Reserve long
  292. b.pop_back(b.size() - NRESERVED1);
  293. ASSERT_EQ(NRESERVED1, b.size());
  294. const size_t NRESERVED2 = DEFAULT_PAYLOAD * 3;
  295. const butil::IOBuf::Area a2 = b.reserve(NRESERVED2);
  296. ASSERT_EQ(NRESERVED1 + NRESERVED2, b.size());
  297. b.append(s1);
  298. ASSERT_EQ(NRESERVED1 + NRESERVED2 + s1.size(), b.size());
  299. std::string s2(NRESERVED2, 0);
  300. for (size_t i = 0; i < s2.size(); ++i) {
  301. s2[i] = i * 13;
  302. }
  303. ASSERT_EQ(NRESERVED2, s2.size());
  304. ASSERT_EQ(0, b.unsafe_assign(a2, s2.data()));
  305. ASSERT_EQ("apple" + s2 + s1, b.to_string());
  306. ASSERT_EQ(0, b.unsafe_assign(a1, "orangeblahblah"));
  307. ASSERT_EQ("orang" + s2 + s1, b.to_string());
  308. }
  309. struct FakeBlock {
  310. int nshared;
  311. FakeBlock() : nshared(1) {}
  312. };
  313. TEST_F(IOBufTest, iobuf_as_queue) {
  314. install_debug_allocator();
  315. // If INITIAL_CAP gets bigger, creating butil::IOBuf::Block are very
  316. // small. Since We don't access butil::IOBuf::Block::data in this case.
  317. // We replace butil::IOBuf::Block with FakeBlock with only nshared (in
  318. // the same offset)
  319. FakeBlock* blocks[butil::IOBuf::INITIAL_CAP+16];
  320. const size_t NBLOCKS = ARRAY_SIZE(blocks);
  321. butil::IOBuf::BlockRef r[NBLOCKS];
  322. const size_t LENGTH = 7UL;
  323. for (size_t i = 0; i < NBLOCKS; ++i) {
  324. ASSERT_TRUE((blocks[i] = new FakeBlock));
  325. r[i].offset = 1;
  326. r[i].length = LENGTH;
  327. r[i].block = (butil::IOBuf::Block*)blocks[i];
  328. }
  329. butil::IOBuf p;
  330. // Empty
  331. ASSERT_EQ(0UL, p._ref_num());
  332. ASSERT_EQ(-1, p._pop_front_ref());
  333. ASSERT_EQ(0UL, p.length());
  334. // Add one ref
  335. p._push_back_ref(r[0]);
  336. ASSERT_EQ(1UL, p._ref_num());
  337. ASSERT_EQ(LENGTH, p.length());
  338. ASSERT_EQ(r[0], p._front_ref());
  339. ASSERT_EQ(r[0], p._back_ref());
  340. ASSERT_EQ(r[0], p._ref_at(0));
  341. ASSERT_EQ(2, butil::iobuf::block_shared_count(r[0].block));
  342. // Add second ref
  343. p._push_back_ref(r[1]);
  344. ASSERT_EQ(2UL, p._ref_num());
  345. ASSERT_EQ(LENGTH*2, p.length());
  346. ASSERT_EQ(r[0], p._front_ref());
  347. ASSERT_EQ(r[1], p._back_ref());
  348. ASSERT_EQ(r[0], p._ref_at(0));
  349. ASSERT_EQ(r[1], p._ref_at(1));
  350. ASSERT_EQ(2, butil::iobuf::block_shared_count(r[1].block));
  351. // Pop a ref
  352. ASSERT_EQ(0, p._pop_front_ref());
  353. ASSERT_EQ(1UL, p._ref_num());
  354. ASSERT_EQ(LENGTH, p.length());
  355. ASSERT_EQ(r[1], p._front_ref());
  356. ASSERT_EQ(r[1], p._back_ref());
  357. ASSERT_EQ(r[1], p._ref_at(0));
  358. //ASSERT_EQ(1, butil::iobuf::block_shared_count(r[0].block));
  359. // Pop second
  360. ASSERT_EQ(0, p._pop_front_ref());
  361. ASSERT_EQ(0UL, p._ref_num());
  362. ASSERT_EQ(0UL, p.length());
  363. //ASSERT_EQ(1, r[1].block->nshared);
  364. // Add INITIAL_CAP+2 refs, r[0] and r[1] are used, don't use again
  365. for (size_t i = 0; i < butil::IOBuf::INITIAL_CAP+2; ++i) {
  366. p._push_back_ref(r[i+2]);
  367. ASSERT_EQ(i+1, p._ref_num());
  368. ASSERT_EQ(p._ref_num()*LENGTH, p.length());
  369. ASSERT_EQ(r[2], p._front_ref()) << i;
  370. ASSERT_EQ(r[i+2], p._back_ref());
  371. for (size_t j = 0; j <= i; j+=std::max(1UL, i/20) /*not check all*/) {
  372. ASSERT_EQ(r[j+2], p._ref_at(j));
  373. }
  374. ASSERT_EQ(2, butil::iobuf::block_shared_count(r[i+2].block));
  375. }
  376. // Pop them all
  377. const size_t saved_ref_num = p._ref_num();
  378. while (p._ref_num() >= 2UL) {
  379. const size_t last_ref_num = p._ref_num();
  380. ASSERT_EQ(0, p._pop_front_ref());
  381. ASSERT_EQ(last_ref_num, p._ref_num()+1);
  382. ASSERT_EQ(p._ref_num()*LENGTH, p.length());
  383. const size_t f = saved_ref_num - p._ref_num() + 2;
  384. ASSERT_EQ(r[f], p._front_ref());
  385. ASSERT_EQ(r[saved_ref_num+1], p._back_ref());
  386. for (size_t j = 0; j < p._ref_num(); j += std::max(1UL, p._ref_num()/20)) {
  387. ASSERT_EQ(r[j+f], p._ref_at(j));
  388. }
  389. //ASSERT_EQ(1, r[f-1].block->nshared);
  390. }
  391. ASSERT_EQ(1ul, p._ref_num());
  392. // Pop last one
  393. ASSERT_EQ(0, p._pop_front_ref());
  394. ASSERT_EQ(0UL, p._ref_num());
  395. ASSERT_EQ(0UL, p.length());
  396. //ASSERT_EQ(1, r[saved_ref_num+1].block->nshared);
  397. // Delete blocks
  398. for (size_t i = 0; i < NBLOCKS; ++i) {
  399. delete blocks[i];
  400. }
  401. }
  402. TEST_F(IOBufTest, iobuf_sanity) {
  403. install_debug_allocator();
  404. LOG(INFO) << "sizeof(butil::IOBuf)=" << sizeof(butil::IOBuf)
  405. << " sizeof(IOPortal)=" << sizeof(butil::IOPortal);
  406. butil::IOBuf b1;
  407. std::string s1 = "hello world";
  408. const char c1 = 'A';
  409. const std::string s2 = "too simple";
  410. std::string s1c = s1;
  411. s1c.erase(0, 1);
  412. // Append a c-std::string
  413. ASSERT_EQ(0, b1.append(s1.c_str()));
  414. ASSERT_EQ(s1.length(), b1.length());
  415. ASSERT_EQ(s1, to_str(b1));
  416. ASSERT_EQ(1UL, b1._ref_num());
  417. // Append a char
  418. ASSERT_EQ(0, b1.push_back(c1));
  419. ASSERT_EQ(s1.length() + 1, b1.length());
  420. ASSERT_EQ(s1+c1, to_str(b1));
  421. ASSERT_EQ(1UL, b1._ref_num());
  422. // Append a std::string
  423. ASSERT_EQ(0, b1.append(s2));
  424. ASSERT_EQ(s1.length() + 1 + s2.length(), b1.length());
  425. ASSERT_EQ(s1+c1+s2, to_str(b1));
  426. ASSERT_EQ(1UL, b1._ref_num());
  427. // Pop first char
  428. ASSERT_EQ(1UL, b1.pop_front(1));
  429. ASSERT_EQ(1UL, b1._ref_num());
  430. ASSERT_EQ(s1.length() + s2.length(), b1.length());
  431. ASSERT_EQ(s1c+c1+s2, to_str(b1));
  432. // Pop all
  433. ASSERT_EQ(0UL, b1.pop_front(0));
  434. ASSERT_EQ(s1.length() + s2.length(), b1.pop_front(b1.length()+1));
  435. ASSERT_TRUE(b1.empty());
  436. ASSERT_EQ(0UL, b1.length());
  437. ASSERT_EQ(0UL, b1._ref_num());
  438. ASSERT_EQ("", to_str(b1));
  439. // Restore
  440. ASSERT_EQ(0, b1.append(s1.c_str()));
  441. ASSERT_EQ(0, b1.push_back(c1));
  442. ASSERT_EQ(0, b1.append(s2));
  443. // Cut first char
  444. butil::IOBuf p;
  445. b1.cutn(&p, 0);
  446. b1.cutn(&p, 1);
  447. ASSERT_EQ(s1.substr(0, 1), to_str(p));
  448. ASSERT_EQ(s1c+c1+s2, to_str(b1));
  449. // Cut another two and append to p
  450. b1.cutn(&p, 2);
  451. ASSERT_EQ(s1.substr(0, 3), to_str(p));
  452. std::string s1d = s1;
  453. s1d.erase(0, 3);
  454. ASSERT_EQ(s1d+c1+s2, to_str(b1));
  455. // Clear
  456. b1.clear();
  457. ASSERT_TRUE(b1.empty());
  458. ASSERT_EQ(0UL, b1.length());
  459. ASSERT_EQ(0UL, b1._ref_num());
  460. ASSERT_EQ("", to_str(b1));
  461. ASSERT_EQ(s1.substr(0, 3), to_str(p));
  462. }
  463. TEST_F(IOBufTest, copy_and_assign) {
  464. install_debug_allocator();
  465. const size_t TARGET_SIZE = butil::IOBuf::DEFAULT_BLOCK_SIZE * 2;
  466. butil::IOBuf buf0;
  467. buf0.append("hello");
  468. ASSERT_EQ(1u, buf0._ref_num());
  469. // Copy-construct from SmallView
  470. butil::IOBuf buf1 = buf0;
  471. ASSERT_EQ(1u, buf1._ref_num());
  472. ASSERT_EQ(buf0, buf1);
  473. buf1.resize(TARGET_SIZE, 'z');
  474. ASSERT_LT(2u, buf1._ref_num());
  475. ASSERT_EQ(TARGET_SIZE, buf1.size());
  476. // Copy-construct from BigView
  477. butil::IOBuf buf2 = buf1;
  478. ASSERT_EQ(buf1, buf2);
  479. // assign BigView to SmallView
  480. butil::IOBuf buf3;
  481. buf3 = buf1;
  482. ASSERT_EQ(buf1, buf3);
  483. // assign BigView to BigView
  484. butil::IOBuf buf4;
  485. buf4.resize(TARGET_SIZE, 'w');
  486. ASSERT_NE(buf1, buf4);
  487. buf4 = buf1;
  488. ASSERT_EQ(buf1, buf4);
  489. }
  490. TEST_F(IOBufTest, compare) {
  491. install_debug_allocator();
  492. const char* SEED = "abcdefghijklmnqopqrstuvwxyz";
  493. butil::IOBuf seedbuf;
  494. seedbuf.append(SEED);
  495. const int REP = 100;
  496. butil::IOBuf b1;
  497. for (int i = 0; i < REP; ++i) {
  498. b1.append(seedbuf);
  499. b1.append(SEED);
  500. }
  501. butil::IOBuf b2;
  502. for (int i = 0; i < REP * 2; ++i) {
  503. b2.append(SEED);
  504. }
  505. ASSERT_EQ(b1, b2);
  506. butil::IOBuf b3 = b2;
  507. b2.push_back('0');
  508. ASSERT_NE(b1, b2);
  509. ASSERT_EQ(b1, b3);
  510. b1.clear();
  511. b2.clear();
  512. ASSERT_EQ(b1, b2);
  513. }
  514. TEST_F(IOBufTest, append_and_cut_it_all) {
  515. butil::IOBuf b;
  516. const size_t N = 32768UL;
  517. for (size_t i = 0; i < N; ++i) {
  518. ASSERT_EQ(0, b.push_back(i));
  519. }
  520. ASSERT_EQ(N, b.length());
  521. butil::IOBuf p;
  522. b.cutn(&p, N);
  523. ASSERT_TRUE(b.empty());
  524. ASSERT_EQ(N, p.length());
  525. }
  526. TEST_F(IOBufTest, copy_to) {
  527. butil::IOBuf b;
  528. const std::string seed = "abcdefghijklmnopqrstuvwxyz";
  529. std::string src;
  530. for (size_t i = 0; i < 1000; ++i) {
  531. src.append(seed);
  532. }
  533. b.append(src);
  534. ASSERT_GT(b.size(), DEFAULT_PAYLOAD);
  535. std::string s1;
  536. ASSERT_EQ(src.size(), b.copy_to(&s1));
  537. ASSERT_EQ(src, s1);
  538. std::string s2;
  539. ASSERT_EQ(32u, b.copy_to(&s2, 32));
  540. ASSERT_EQ(src.substr(0, 32), s2);
  541. std::string s3;
  542. const std::string expected = src.substr(DEFAULT_PAYLOAD - 1, 33);
  543. ASSERT_EQ(33u, b.copy_to(&s3, 33, DEFAULT_PAYLOAD - 1));
  544. ASSERT_EQ(expected, s3);
  545. ASSERT_EQ(33u, b.append_to(&s3, 33, DEFAULT_PAYLOAD - 1));
  546. ASSERT_EQ(expected + expected, s3);
  547. butil::IOBuf b1;
  548. ASSERT_EQ(src.size(), b.append_to(&b1));
  549. ASSERT_EQ(src, b1.to_string());
  550. butil::IOBuf b2;
  551. ASSERT_EQ(32u, b.append_to(&b2, 32));
  552. ASSERT_EQ(src.substr(0, 32), b2.to_string());
  553. butil::IOBuf b3;
  554. ASSERT_EQ(33u, b.append_to(&b3, 33, DEFAULT_PAYLOAD - 1));
  555. ASSERT_EQ(expected, b3.to_string());
  556. ASSERT_EQ(33u, b.append_to(&b3, 33, DEFAULT_PAYLOAD - 1));
  557. ASSERT_EQ(expected + expected, b3.to_string());
  558. }
  559. TEST_F(IOBufTest, cut_by_single_text_delim) {
  560. install_debug_allocator();
  561. butil::IOBuf b;
  562. butil::IOBuf p;
  563. std::vector<butil::IOBuf> ps;
  564. std::string s1 = "1234567\n12\n\n2567";
  565. ASSERT_EQ(0, b.append(s1));
  566. ASSERT_EQ(s1.length(), b.length());
  567. for (; b.cut_until(&p, "\n") == 0; ) {
  568. ps.push_back(p);
  569. p.clear();
  570. }
  571. ASSERT_EQ(3UL, ps.size());
  572. ASSERT_EQ("1234567", to_str(ps[0]));
  573. ASSERT_EQ("12", to_str(ps[1]));
  574. ASSERT_EQ("", to_str(ps[2]));
  575. ASSERT_EQ("2567", to_str(b));
  576. b.append("\n");
  577. ASSERT_EQ(0, b.cut_until(&p, "\n"));
  578. ASSERT_EQ("2567", to_str(p));
  579. ASSERT_EQ("", to_str(b));
  580. }
  581. TEST_F(IOBufTest, cut_by_multiple_text_delim) {
  582. install_debug_allocator();
  583. butil::IOBuf b;
  584. butil::IOBuf p;
  585. std::vector<butil::IOBuf> ps;
  586. std::string s1 = "\r\n1234567\r\n12\r\n\n\r2567";
  587. ASSERT_EQ(0, b.append(s1));
  588. ASSERT_EQ(s1.length(), b.length());
  589. for (; b.cut_until(&p, "\r\n") == 0; ) {
  590. ps.push_back(p);
  591. p.clear();
  592. }
  593. ASSERT_EQ(3UL, ps.size());
  594. ASSERT_EQ("", to_str(ps[0]));
  595. ASSERT_EQ("1234567", to_str(ps[1]));
  596. ASSERT_EQ("12", to_str(ps[2]));
  597. ASSERT_EQ("\n\r2567", to_str(b));
  598. b.append("\r\n");
  599. ASSERT_EQ(0, b.cut_until(&p, "\r\n"));
  600. ASSERT_EQ("\n\r2567", to_str(p));
  601. ASSERT_EQ("", to_str(b));
  602. }
  603. TEST_F(IOBufTest, append_a_lot_and_cut_them_all) {
  604. install_debug_allocator();
  605. butil::IOBuf b;
  606. butil::IOBuf p;
  607. std::string s1 = "12345678901234567";
  608. const size_t N = 10000;
  609. for (size_t i= 0; i < N; ++i) {
  610. b.append(s1);
  611. }
  612. ASSERT_EQ(N*s1.length(), b.length());
  613. while (b.length() >= 7) {
  614. b.cutn(&p, 7);
  615. }
  616. size_t remain = s1.length()*N % 7;
  617. ASSERT_EQ(remain, b.length());
  618. ASSERT_EQ(s1.substr(s1.length() - remain, remain), to_str(b));
  619. ASSERT_EQ(s1.length()*N/7*7, p.length());
  620. }
  621. TEST_F(IOBufTest, cut_into_fd_tiny) {
  622. install_debug_allocator();
  623. butil::IOPortal b1, b2;
  624. std::string ref;
  625. int fds[2];
  626. for (int j = 10; j > 0; --j) {
  627. ref.push_back(j);
  628. }
  629. b1.append(ref);
  630. ASSERT_EQ(1UL, b1.pop_front(1));
  631. ref.erase(0, 1);
  632. ASSERT_EQ(ref, to_str(b1));
  633. LOG(INFO) << "ref.size=" << ref.size();
  634. //ASSERT_EQ(0, pipe(fds));
  635. ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
  636. butil::make_non_blocking(fds[0]);
  637. butil::make_non_blocking(fds[1]);
  638. while (!b1.empty() || b2.length() != ref.length()) {
  639. size_t b1len = b1.length(), b2len = b2.length();
  640. errno = 0;
  641. printf("b1.length=%lu - %ld (%m), ",
  642. b1len, b1.cut_into_file_descriptor(fds[1]));
  643. printf("b2.length=%lu + %ld (%m)\n",
  644. b2len, b2.append_from_file_descriptor(fds[0], LONG_MAX));
  645. }
  646. printf("b1.length=%lu, b2.length=%lu\n", b1.length(), b2.length());
  647. ASSERT_EQ(ref, to_str(b2));
  648. close(fds[0]);
  649. close(fds[1]);
  650. }
  651. TEST_F(IOBufTest, cut_multiple_into_fd_tiny) {
  652. install_debug_allocator();
  653. butil::IOBuf* b1[10];
  654. butil::IOPortal b2;
  655. std::string ref;
  656. int fds[2];
  657. for (size_t j = 0; j < ARRAY_SIZE(b1); ++j) {
  658. std::string s;
  659. for (int i = 10; i > 0; --i) {
  660. s.push_back(j * 10 + i);
  661. }
  662. ref.append(s);
  663. butil::IOPortal* b = new butil::IOPortal();
  664. b->append(s);
  665. b1[j] = b;
  666. }
  667. ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
  668. butil::make_non_blocking(fds[0]);
  669. butil::make_non_blocking(fds[1]);
  670. ASSERT_EQ((ssize_t)ref.length(),
  671. butil::IOBuf::cut_multiple_into_file_descriptor(
  672. fds[1], b1, ARRAY_SIZE(b1)));
  673. for (size_t j = 0; j < ARRAY_SIZE(b1); ++j) {
  674. ASSERT_TRUE(b1[j]->empty());
  675. delete (butil::IOPortal*)b1[j];
  676. b1[j] = NULL;
  677. }
  678. ASSERT_EQ((ssize_t)ref.length(),
  679. b2.append_from_file_descriptor(fds[0], LONG_MAX));
  680. ASSERT_EQ(ref, to_str(b2));
  681. close(fds[0]);
  682. close(fds[1]);
  683. }
  684. TEST_F(IOBufTest, cut_into_fd_a_lot_of_data) {
  685. install_debug_allocator();
  686. butil::IOPortal b0, b1, b2;
  687. std::string s, ref;
  688. int fds[2];
  689. for (int j = rand()%7777+300000; j > 0; --j) {
  690. ref.push_back(j);
  691. s.push_back(j);
  692. if (s.length() == 1024UL || j == 1) {
  693. b0.append(s);
  694. ref.append("tailing");
  695. b0.cutn(&b1, b0.length());
  696. ASSERT_EQ(0, b1.append("tailing"));
  697. s.clear();
  698. }
  699. }
  700. ASSERT_EQ(ref.length(), b1.length());
  701. ASSERT_EQ(ref, to_str(b1));
  702. ASSERT_TRUE(b0.empty());
  703. LOG(INFO) << "ref.size=" << ref.size();
  704. //ASSERT_EQ(0, pipe(fds));
  705. ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
  706. butil::make_non_blocking(fds[0]);
  707. butil::make_non_blocking(fds[1]);
  708. const int sockbufsize = 16 * 1024 - 17;
  709. ASSERT_EQ(0, setsockopt(fds[1], SOL_SOCKET, SO_SNDBUF,
  710. (const char*)&sockbufsize, sizeof(int)));
  711. ASSERT_EQ(0, setsockopt(fds[0], SOL_SOCKET, SO_RCVBUF,
  712. (const char*)&sockbufsize, sizeof(int)));
  713. while (!b1.empty() || b2.length() != ref.length()) {
  714. size_t b1len = b1.length(), b2len = b2.length();
  715. errno = 0;
  716. printf("b1.length=%lu - %ld (%m), ", b1len, b1.cut_into_file_descriptor(fds[1]));
  717. printf("b2.length=%lu + %ld (%m)\n", b2len, b2.append_from_file_descriptor(fds[0], LONG_MAX));
  718. }
  719. printf("b1.length=%lu, b2.length=%lu\n", b1.length(), b2.length());
  720. ASSERT_EQ(ref, to_str(b2));
  721. close(fds[0]);
  722. close(fds[1]);
  723. }
  724. TEST_F(IOBufTest, cut_by_delim_perf) {
  725. butil::iobuf::reset_blockmem_allocate_and_deallocate();
  726. butil::IOBuf b;
  727. butil::IOBuf p;
  728. std::vector<butil::IOBuf> ps;
  729. std::string s1 = "123456789012345678901234567890\n";
  730. const size_t N = 100000;
  731. for (size_t i = 0; i < N; ++i) {
  732. ASSERT_EQ(0, b.append(s1));
  733. }
  734. ASSERT_EQ(N * s1.length(), b.length());
  735. butil::Timer t;
  736. //ProfilerStart("cutd.prof");
  737. t.start();
  738. for (; b.cut_until(&p, "\n") == 0; ) { }
  739. t.stop();
  740. //ProfilerStop();
  741. LOG(INFO) << "IOPortal::cut_by_delim takes "
  742. << t.n_elapsed()/N << "ns, tp="
  743. << s1.length() * N * 1000.0 / t.n_elapsed () << "MB/s";
  744. show_prof_and_rm("test_iobuf", "cutd.prof", 10);
  745. }
  746. TEST_F(IOBufTest, cut_perf) {
  747. butil::iobuf::reset_blockmem_allocate_and_deallocate();
  748. butil::IOBuf b;
  749. butil::IOBuf p;
  750. const size_t length = 60000000UL;
  751. const size_t REP = 10;
  752. butil::Timer t;
  753. std::string s = "1234567890";
  754. const bool push_char = false;
  755. if (!push_char) {
  756. //ProfilerStart("iobuf_append.prof");
  757. t.start();
  758. for (size_t j = 0; j < REP; ++j) {
  759. b.clear();
  760. for (size_t i = 0; i < length/s.length(); ++i) {
  761. b.append(s);
  762. }
  763. }
  764. t.stop();
  765. //ProfilerStop();
  766. LOG(INFO) << "IOPortal::append(std::string_" << s.length() << ") takes "
  767. << t.n_elapsed() * s.length() / length / REP << "ns, tp="
  768. << REP * length * 1000.0 / t.n_elapsed () << "MB/s";
  769. } else {
  770. //ProfilerStart("iobuf_pushback.prof");
  771. t.start();
  772. for (size_t i = 0; i < length; ++i) {
  773. b.push_back(i);
  774. }
  775. t.stop();
  776. //ProfilerStop();
  777. LOG(INFO) << "IOPortal::push_back(char) takes "
  778. << t.n_elapsed() / length << "ns, tp="
  779. << length * 1000.0 / t.n_elapsed () << "MB/s";
  780. }
  781. ASSERT_EQ(length, b.length());
  782. size_t w[3] = { 16, 128, 1024 };
  783. //char name[32];
  784. for (size_t i = 0; i < ARRAY_SIZE(w); ++i) {
  785. // snprintf(name, sizeof(name), "iobuf_cut%lu.prof", w[i]);
  786. // ProfilerStart(name);
  787. t.start ();
  788. while (b.length() >= w[i]+12) {
  789. b.cutn(&p, 12);
  790. b.cutn(&p, w[i]);
  791. }
  792. t.stop ();
  793. //ProfilerStop();
  794. LOG(INFO) << "IOPortal::cutn(12+" << w[i] << ") takes "
  795. << t.n_elapsed()*(w[i]+12)/length << "ns, tp="
  796. << length * 1000.0 / t.n_elapsed () << "MB/s";
  797. ASSERT_LT(b.length(), w[i]+12);
  798. t.start();
  799. b.append(p);
  800. t.stop();
  801. LOG(INFO) << "IOPortal::append(butil::IOBuf) takes "
  802. << t.n_elapsed ()/p._ref_num() << "ns, tp="
  803. << length * 1000.0 / t.n_elapsed () << "MB/s";
  804. p.clear();
  805. ASSERT_EQ(length, b.length());
  806. }
  807. show_prof_and_rm("test_iobuf", "./iobuf_append.prof", 10);
  808. show_prof_and_rm("test_iobuf", "./iobuf_pushback.prof", 10);
  809. }
  810. TEST_F(IOBufTest, append_store_append_cut) {
  811. butil::iobuf::reset_blockmem_allocate_and_deallocate();
  812. std::string ref;
  813. ref.resize(rand()%376813+19777777);
  814. for (size_t j = 0; j < ref.size(); ++j) {
  815. ref[j] = j;
  816. }
  817. butil::IOPortal b1, b2;
  818. std::vector<butil::IOBuf> ps;
  819. ssize_t nr;
  820. size_t HINT = 16*1024UL;
  821. butil::Timer t;
  822. size_t w[3] = { 16, 128, 1024 };
  823. char name[64];
  824. char profname[64];
  825. char cmd[512];
  826. bool write_to_dev_null = true;
  827. size_t nappend, ncut;
  828. butil::TempFile f;
  829. ASSERT_EQ(0, f.save_bin(ref.data(), ref.length()));
  830. for (size_t i = 0; i < ARRAY_SIZE(w); ++i) {
  831. ps.reserve(ref.size()/(w[i]+12) + 1);
  832. // LOG(INFO) << "ps.cap=" << ps.capacity();
  833. const int ifd = open(f.fname(), O_RDONLY);
  834. ASSERT_TRUE(ifd > 0);
  835. if (write_to_dev_null) {
  836. snprintf(name, sizeof(name), "/dev/null");
  837. } else {
  838. snprintf(name, sizeof(name), "iobuf_asac%lu.output", w[i]);
  839. snprintf(cmd, sizeof(cmd), "cmp %s %s", f.fname(), name);
  840. }
  841. const int ofd = open(name, O_CREAT | O_WRONLY, 0666);
  842. ASSERT_TRUE(ofd > 0) << strerror(errno);
  843. snprintf(profname, sizeof(profname), "iobuf_asac%lu.prof", w[i]);
  844. //ProfilerStart(profname);
  845. t.start();
  846. nappend = ncut = 0;
  847. while ((nr = b1.append_from_file_descriptor(ifd, HINT)) > 0) {
  848. ++nappend;
  849. while (b1.length() >= w[i] + 12) {
  850. butil::IOBuf p;
  851. b1.cutn(&p, 12);
  852. b1.cutn(&p, w[i]);
  853. ps.push_back(p);
  854. }
  855. }
  856. for (size_t j = 0; j < ps.size(); ++j) {
  857. b2.append(ps[j]);
  858. if (b2.length() >= HINT) {
  859. b2.cut_into_file_descriptor(ofd);
  860. }
  861. }
  862. b2.cut_into_file_descriptor(ofd);
  863. b1.cut_into_file_descriptor(ofd);
  864. close(ifd);
  865. close(ofd);
  866. t.stop();
  867. //ProfilerStop();
  868. ASSERT_TRUE(b1.empty());
  869. ASSERT_TRUE(b2.empty());
  870. //LOG(INFO) << "ps.size=" << ps.size();
  871. ps.clear();
  872. LOG(INFO) << "Bandwidth of append(" << f.fname() << ")->cut(12+" << w[i]
  873. << ")->store->append->cut(" << name << ") is "
  874. << ref.length() * 1000.0 / t.n_elapsed () << "MB/s";
  875. if (!write_to_dev_null) {
  876. ASSERT_EQ(0, system(cmd));
  877. }
  878. remove(name);
  879. }
  880. for (size_t i = 0; i < ARRAY_SIZE(w); ++i) {
  881. snprintf(name, sizeof(name), "iobuf_asac%lu.prof", w[i]);
  882. show_prof_and_rm("test_iobuf", name, 10);
  883. }
  884. }
  885. TEST_F(IOBufTest, conversion_with_protobuf) {
  886. const int REP = 1000;
  887. proto::Misc m1;
  888. m1.set_required_enum(proto::CompressTypeGzip);
  889. m1.set_required_uint64(0xdeadbeef);
  890. m1.set_optional_uint64(10000);
  891. m1.set_required_string("hello iobuf");
  892. m1.set_optional_string("hello iobuf again");
  893. for (int i = 0; i < REP; ++i) {
  894. char buf[16];
  895. snprintf(buf, sizeof(buf), "value%d", i);
  896. m1.add_repeated_string(buf);
  897. }
  898. m1.set_required_bool(true);
  899. m1.set_required_int32(0xbeefdead);
  900. butil::IOBuf buf;
  901. const std::string header("just-make-sure-wrapper-does-not-clear-IOBuf");
  902. ASSERT_EQ(0, buf.append(header));
  903. butil::IOBufAsZeroCopyOutputStream out_wrapper(&buf);
  904. ASSERT_EQ(0, out_wrapper.ByteCount());
  905. ASSERT_TRUE(m1.SerializeToZeroCopyStream(&out_wrapper));
  906. ASSERT_EQ((size_t)m1.ByteSize() + header.size(), buf.length());
  907. ASSERT_EQ(m1.ByteSize(), out_wrapper.ByteCount());
  908. ASSERT_EQ(header.size(), buf.pop_front(header.size()));
  909. butil::IOBufAsZeroCopyInputStream in_wrapper(buf);
  910. ASSERT_EQ(0, in_wrapper.ByteCount());
  911. {
  912. const void* dummy_blk = NULL;
  913. int dummy_size = 0;
  914. ASSERT_TRUE(in_wrapper.Next(&dummy_blk, &dummy_size));
  915. ASSERT_EQ(dummy_size, in_wrapper.ByteCount());
  916. in_wrapper.BackUp(1);
  917. ASSERT_EQ(dummy_size - 1, in_wrapper.ByteCount());
  918. const void* dummy_blk2 = NULL;
  919. int dummy_size2 = 0;
  920. ASSERT_TRUE(in_wrapper.Next(&dummy_blk2, &dummy_size2));
  921. ASSERT_EQ(1, dummy_size2);
  922. ASSERT_EQ((char*)dummy_blk + dummy_size - 1, (char*)dummy_blk2);
  923. ASSERT_EQ(dummy_size, in_wrapper.ByteCount());
  924. in_wrapper.BackUp(dummy_size);
  925. ASSERT_EQ(0, in_wrapper.ByteCount());
  926. }
  927. proto::Misc m2;
  928. ASSERT_TRUE(m2.ParseFromZeroCopyStream(&in_wrapper));
  929. ASSERT_EQ(m1.ByteSize(), in_wrapper.ByteCount());
  930. ASSERT_EQ(m2.ByteSize(), in_wrapper.ByteCount());
  931. ASSERT_EQ(m1.required_enum(), m2.required_enum());
  932. ASSERT_FALSE(m2.has_optional_enum());
  933. ASSERT_EQ(m1.required_uint64(), m2.required_uint64());
  934. ASSERT_TRUE(m2.has_optional_uint64());
  935. ASSERT_EQ(m1.optional_uint64(), m2.optional_uint64());
  936. ASSERT_EQ(m1.required_string(), m2.required_string());
  937. ASSERT_TRUE(m2.has_optional_string());
  938. ASSERT_EQ(m1.optional_string(), m2.optional_string());
  939. ASSERT_EQ(REP, m2.repeated_string_size());
  940. for (int i = 0; i < REP; ++i) {
  941. ASSERT_EQ(m1.repeated_string(i), m2.repeated_string(i));
  942. }
  943. ASSERT_EQ(m1.required_bool(), m2.required_bool());
  944. ASSERT_FALSE(m2.has_optional_bool());
  945. ASSERT_EQ(m1.required_int32(), m2.required_int32());
  946. ASSERT_FALSE(m2.has_optional_int32());
  947. }
  948. TEST_F(IOBufTest, extended_backup) {
  949. for (int i = 0; i < 2; ++i) {
  950. std::cout << "i=" << i << std::endl;
  951. // Consume the left TLS block so that cases are easier to check.
  952. butil::iobuf::remove_tls_block_chain();
  953. butil::IOBuf src;
  954. const int BLKSIZE = (i == 0 ? 1024 : butil::IOBuf::DEFAULT_BLOCK_SIZE);
  955. const int PLDSIZE = BLKSIZE - BLOCK_OVERHEAD;
  956. butil::IOBufAsZeroCopyOutputStream out_stream1(&src, BLKSIZE);
  957. butil::IOBufAsZeroCopyOutputStream out_stream2(&src);
  958. butil::IOBufAsZeroCopyOutputStream & out_stream =
  959. (i == 0 ? out_stream1 : out_stream2);
  960. void* blk1 = NULL;
  961. int size1 = 0;
  962. ASSERT_TRUE(out_stream.Next(&blk1, &size1));
  963. ASSERT_EQ(PLDSIZE, size1);
  964. ASSERT_EQ(size1, out_stream.ByteCount());
  965. void* blk2 = NULL;
  966. int size2 = 0;
  967. ASSERT_TRUE(out_stream.Next(&blk2, &size2));
  968. ASSERT_EQ(PLDSIZE, size2);
  969. ASSERT_EQ(size1 + size2, out_stream.ByteCount());
  970. // BackUp a size that's valid for all ZeroCopyOutputStream
  971. out_stream.BackUp(PLDSIZE / 2);
  972. ASSERT_EQ(size1 + size2 - PLDSIZE / 2, out_stream.ByteCount());
  973. void* blk3 = NULL;
  974. int size3 = 0;
  975. ASSERT_TRUE(out_stream.Next(&blk3, &size3));
  976. ASSERT_EQ((char*)blk2 + PLDSIZE / 2, blk3);
  977. ASSERT_EQ(PLDSIZE / 2, size3);
  978. ASSERT_EQ(size1 + size2, out_stream.ByteCount());
  979. // BackUp a size that's undefined in regular ZeroCopyOutputStream
  980. out_stream.BackUp(PLDSIZE * 2);
  981. ASSERT_EQ(0, out_stream.ByteCount());
  982. void* blk4 = NULL;
  983. int size4 = 0;
  984. ASSERT_TRUE(out_stream.Next(&blk4, &size4));
  985. ASSERT_EQ(PLDSIZE, size4);
  986. ASSERT_EQ(size4, out_stream.ByteCount());
  987. if (i == 1) {
  988. ASSERT_EQ(blk1, blk4);
  989. }
  990. void* blk5 = NULL;
  991. int size5 = 0;
  992. ASSERT_TRUE(out_stream.Next(&blk5, &size5));
  993. ASSERT_EQ(PLDSIZE, size5);
  994. ASSERT_EQ(size4 + size5, out_stream.ByteCount());
  995. if (i == 1) {
  996. ASSERT_EQ(blk2, blk5);
  997. }
  998. }
  999. }
  1000. TEST_F(IOBufTest, backup_iobuf_never_called_next) {
  1001. {
  1002. // Consume the left TLS block so that later cases are easier
  1003. // to check.
  1004. butil::IOBuf dummy;
  1005. butil::IOBufAsZeroCopyOutputStream dummy_stream(&dummy);
  1006. void* dummy_data = NULL;
  1007. int dummy_size = 0;
  1008. ASSERT_TRUE(dummy_stream.Next(&dummy_data, &dummy_size));
  1009. }
  1010. butil::IOBuf src;
  1011. const size_t N = DEFAULT_PAYLOAD * 2;
  1012. src.resize(N);
  1013. ASSERT_EQ(2u, src.backing_block_num());
  1014. ASSERT_EQ(N, src.size());
  1015. butil::IOBufAsZeroCopyOutputStream out_stream(&src);
  1016. out_stream.BackUp(1); // also succeed.
  1017. ASSERT_EQ(-1, out_stream.ByteCount());
  1018. ASSERT_EQ(DEFAULT_PAYLOAD * 2 - 1, src.size());
  1019. ASSERT_EQ(2u, src.backing_block_num());
  1020. void* data0 = NULL;
  1021. int size0 = 0;
  1022. ASSERT_TRUE(out_stream.Next(&data0, &size0));
  1023. ASSERT_EQ(1, size0);
  1024. ASSERT_EQ(0, out_stream.ByteCount());
  1025. ASSERT_EQ(2u, src.backing_block_num());
  1026. void* data1 = NULL;
  1027. int size1 = 0;
  1028. ASSERT_TRUE(out_stream.Next(&data1, &size1));
  1029. ASSERT_EQ(size1, out_stream.ByteCount());
  1030. ASSERT_EQ(3u, src.backing_block_num());
  1031. ASSERT_EQ(N + size1, src.size());
  1032. void* data2 = NULL;
  1033. int size2 = 0;
  1034. ASSERT_TRUE(out_stream.Next(&data2, &size2));
  1035. ASSERT_EQ(size1 + size2, out_stream.ByteCount());
  1036. ASSERT_EQ(4u, src.backing_block_num());
  1037. ASSERT_EQ(N + size1 + size2, src.size());
  1038. LOG(INFO) << "Backup1";
  1039. out_stream.BackUp(size1); // intended size1, not size2 to make this BackUp
  1040. // to cross boundary of blocks.
  1041. ASSERT_EQ(size2, out_stream.ByteCount());
  1042. ASSERT_EQ(N + size2, src.size());
  1043. LOG(INFO) << "Backup2";
  1044. out_stream.BackUp(size2);
  1045. ASSERT_EQ(0, out_stream.ByteCount());
  1046. ASSERT_EQ(N, src.size());
  1047. }
  1048. void *backup_thread(void *arg) {
  1049. butil::IOBufAsZeroCopyOutputStream *wrapper =
  1050. (butil::IOBufAsZeroCopyOutputStream *)arg;
  1051. wrapper->BackUp(1024);
  1052. return NULL;
  1053. }
  1054. TEST_F(IOBufTest, backup_in_another_thread) {
  1055. butil::IOBuf buf;
  1056. butil::IOBufAsZeroCopyOutputStream wrapper(&buf);
  1057. size_t alloc_size = 0;
  1058. for (int i = 0; i < 10; ++i) {
  1059. void *data;
  1060. int len;
  1061. ASSERT_TRUE(wrapper.Next(&data, &len));
  1062. alloc_size += len;
  1063. }
  1064. ASSERT_EQ(alloc_size, buf.length());
  1065. for (int i = 0; i < 10; ++i) {
  1066. void *data;
  1067. int len;
  1068. ASSERT_TRUE(wrapper.Next(&data, &len));
  1069. alloc_size += len;
  1070. pthread_t tid;
  1071. pthread_create(&tid, NULL, backup_thread, &wrapper);
  1072. pthread_join(tid, NULL);
  1073. }
  1074. ASSERT_EQ(alloc_size - 1024 * 10, buf.length());
  1075. }
  1076. TEST_F(IOBufTest, own_block) {
  1077. butil::IOBuf buf;
  1078. const ssize_t BLOCK_SIZE = 1024;
  1079. butil::IOBuf::Block *saved_tls_block = butil::iobuf::get_tls_block_head();
  1080. butil::IOBufAsZeroCopyOutputStream wrapper(&buf, BLOCK_SIZE);
  1081. int alloc_size = 0;
  1082. for (int i = 0; i < 100; ++i) {
  1083. void *data;
  1084. int size;
  1085. ASSERT_TRUE(wrapper.Next(&data, &size));
  1086. alloc_size += size;
  1087. if (size > 1) {
  1088. wrapper.BackUp(1);
  1089. alloc_size -= 1;
  1090. }
  1091. }
  1092. ASSERT_EQ(static_cast<size_t>(alloc_size), buf.length());
  1093. ASSERT_EQ(saved_tls_block, butil::iobuf::get_tls_block_head());
  1094. ASSERT_EQ(butil::iobuf::block_cap(buf._front_ref().block), BLOCK_SIZE - BLOCK_OVERHEAD);
  1095. }
  1096. struct Foo1 {
  1097. explicit Foo1(int x2) : x(x2) {}
  1098. int x;
  1099. };
  1100. struct Foo2 {
  1101. std::vector<Foo1> foo1;
  1102. };
  1103. std::ostream& operator<<(std::ostream& os, const Foo1& foo1) {
  1104. return os << "foo1.x=" << foo1.x;
  1105. }
  1106. std::ostream& operator<<(std::ostream& os, const Foo2& foo2) {
  1107. for (size_t i = 0; i < foo2.foo1.size(); ++i) {
  1108. os << "foo2[" << i << "]=" << foo2.foo1[i];
  1109. }
  1110. return os;
  1111. }
  1112. TEST_F(IOBufTest, as_ostream) {
  1113. butil::iobuf::reset_blockmem_allocate_and_deallocate();
  1114. butil::IOBufBuilder builder;
  1115. LOG(INFO) << "sizeof(IOBufBuilder)=" << sizeof(builder) << std::endl
  1116. << "sizeof(IOBuf)=" << sizeof(butil::IOBuf) << std::endl
  1117. << "sizeof(IOBufAsZeroCopyOutputStream)="
  1118. << sizeof(butil::IOBufAsZeroCopyOutputStream) << std::endl
  1119. << "sizeof(ZeroCopyStreamAsStreamBuf)="
  1120. << sizeof(butil::ZeroCopyStreamAsStreamBuf) << std::endl
  1121. << "sizeof(ostream)=" << sizeof(std::ostream);
  1122. int x = -1;
  1123. builder << 2 << " " << x << " " << 1.1 << " hello ";
  1124. ASSERT_EQ("2 -1 1.1 hello ", builder.buf().to_string());
  1125. builder << "world!";
  1126. ASSERT_EQ("2 -1 1.1 hello world!", builder.buf().to_string());
  1127. builder.buf().clear();
  1128. builder << "world!";
  1129. ASSERT_EQ("world!", builder.buf().to_string());
  1130. Foo2 foo2;
  1131. for (int i = 0; i < 10000; ++i) {
  1132. foo2.foo1.push_back(Foo1(i));
  1133. }
  1134. builder.buf().clear();
  1135. builder << "<before>" << foo2 << "<after>";
  1136. std::ostringstream oss;
  1137. oss << "<before>" << foo2 << "<after>";
  1138. ASSERT_EQ(oss.str(), builder.buf().to_string());
  1139. butil::IOBuf target;
  1140. builder.move_to(target);
  1141. ASSERT_TRUE(builder.buf().empty());
  1142. ASSERT_EQ(oss.str(), target.to_string());
  1143. std::ostringstream oss2;
  1144. oss2 << target;
  1145. ASSERT_EQ(oss.str(), oss2.str());
  1146. }
  1147. TEST_F(IOBufTest, append_from_fd_with_offset) {
  1148. butil::TempFile file;
  1149. file.save("dummy");
  1150. butil::fd_guard fd(open(file.fname(), O_RDWR | O_TRUNC));
  1151. ASSERT_TRUE(fd >= 0) << file.fname() << ' ' << berror();
  1152. butil::IOPortal buf;
  1153. char dummy[10 * 1024];
  1154. buf.append(dummy, sizeof(dummy));
  1155. ASSERT_EQ((ssize_t)sizeof(dummy), buf.cut_into_file_descriptor(fd));
  1156. for (size_t i = 0; i < sizeof(dummy); ++i) {
  1157. butil::IOPortal b0;
  1158. ASSERT_EQ(sizeof(dummy) - i, (size_t)b0.pappend_from_file_descriptor(fd, i, sizeof(dummy))) << berror();
  1159. char tmp[sizeof(dummy)];
  1160. ASSERT_EQ(0, memcmp(dummy + i, b0.fetch(tmp, b0.length()), b0.length()));
  1161. }
  1162. }
  1163. static butil::atomic<int> s_nthread(0);
  1164. static long number_per_thread = 1024;
  1165. void* cut_into_fd(void* arg) {
  1166. int fd = (int)(long)arg;
  1167. const long start_num = number_per_thread *
  1168. s_nthread.fetch_add(1, butil::memory_order_relaxed);
  1169. off_t offset = start_num * sizeof(int);
  1170. for (int i = 0; i < number_per_thread; ++i) {
  1171. int to_write = start_num + i;
  1172. butil::IOBuf out;
  1173. out.append(&to_write, sizeof(int));
  1174. CHECK_EQ(out.pcut_into_file_descriptor(fd, offset + sizeof(int) * i),
  1175. (ssize_t)sizeof(int));
  1176. }
  1177. return NULL;
  1178. }
  1179. TEST_F(IOBufTest, cut_into_fd_with_offset_multithreaded) {
  1180. s_nthread.store(0);
  1181. number_per_thread = 10240;
  1182. pthread_t threads[8];
  1183. long fd = open(".out.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
  1184. ASSERT_TRUE(fd >= 0) << berror();
  1185. for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
  1186. ASSERT_EQ(0, pthread_create(&threads[i], NULL, cut_into_fd, (void*)fd));
  1187. }
  1188. for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
  1189. pthread_join(threads[i], NULL);
  1190. }
  1191. for (int i = 0; i < number_per_thread * (int)ARRAY_SIZE(threads); ++i) {
  1192. off_t offset = i * sizeof(int);
  1193. butil::IOPortal in;
  1194. ASSERT_EQ((ssize_t)sizeof(int), in.pappend_from_file_descriptor(fd, offset, sizeof(int)));
  1195. int j;
  1196. ASSERT_EQ(sizeof(j), in.cutn(&j, sizeof(j)));
  1197. ASSERT_EQ(i, j);
  1198. }
  1199. }
  1200. TEST_F(IOBufTest, slice) {
  1201. size_t N = 100000;
  1202. std::string expected;
  1203. expected.reserve(N);
  1204. butil::IOBuf buf;
  1205. for (size_t i = 0; i < N; ++i) {
  1206. expected.push_back(i % 26 + 'a');
  1207. buf.push_back(i % 26 + 'a');
  1208. }
  1209. const size_t block_count = buf.backing_block_num();
  1210. std::string actual;
  1211. actual.reserve(expected.size());
  1212. for (size_t i = 0; i < block_count; ++i) {
  1213. butil::StringPiece p = buf.backing_block(i);
  1214. ASSERT_FALSE(p.empty());
  1215. actual.append(p.data(), p.size());
  1216. }
  1217. ASSERT_TRUE(expected == actual);
  1218. }
  1219. TEST_F(IOBufTest, swap) {
  1220. butil::IOBuf a;
  1221. a.append("I'am a");
  1222. butil::IOBuf b;
  1223. b.append("I'am b");
  1224. std::swap(a, b);
  1225. ASSERT_TRUE(a.equals("I'am b"));
  1226. ASSERT_TRUE(b.equals("I'am a"));
  1227. }
  1228. TEST_F(IOBufTest, resize) {
  1229. butil::IOBuf a;
  1230. a.resize(100);
  1231. std::string as;
  1232. as.resize(100);
  1233. butil::IOBuf b;
  1234. b.resize(100, 'b');
  1235. std::string bs;
  1236. bs.resize(100, 'b');
  1237. ASSERT_EQ(100u, a.length());
  1238. ASSERT_EQ(100u, b.length());
  1239. ASSERT_TRUE(a.equals(as));
  1240. ASSERT_TRUE(b.equals(bs));
  1241. }
  1242. TEST_F(IOBufTest, iterate_bytes) {
  1243. butil::IOBuf a;
  1244. a.append("hello world");
  1245. std::string saved_a = a.to_string();
  1246. size_t n = 0;
  1247. butil::IOBufBytesIterator it(a);
  1248. for (; it != NULL; ++it, ++n) {
  1249. ASSERT_EQ(saved_a[n], *it);
  1250. }
  1251. ASSERT_EQ(saved_a.size(), n);
  1252. ASSERT_TRUE(saved_a == a);
  1253. // append more to the iobuf, iterator should still be ended.
  1254. a.append(", this is iobuf");
  1255. ASSERT_TRUE(it == NULL);
  1256. // append more-than-one-block data to the iobuf
  1257. for (int i = 0; i < 1024; ++i) {
  1258. a.append("ab33jm4hgaklkv;2[25lj4lkj312kl4j321kl4j3k");
  1259. }
  1260. saved_a = a.to_string();
  1261. n = 0;
  1262. for (butil::IOBufBytesIterator it2(a); it2 != NULL; it2++/*intended post++*/, ++n) {
  1263. ASSERT_EQ(saved_a[n], *it2);
  1264. }
  1265. ASSERT_EQ(saved_a.size(), n);
  1266. ASSERT_TRUE(saved_a == a);
  1267. }
  1268. TEST_F(IOBufTest, appender) {
  1269. butil::IOBufAppender appender;
  1270. ASSERT_EQ(0, appender.append("hello", 5));
  1271. ASSERT_EQ("hello", appender.buf());
  1272. ASSERT_EQ(0, appender.push_back(' '));
  1273. ASSERT_EQ(0, appender.append("world", 5));
  1274. ASSERT_EQ("hello world", appender.buf());
  1275. butil::IOBuf buf2;
  1276. appender.move_to(buf2);
  1277. ASSERT_EQ("", appender.buf());
  1278. ASSERT_EQ("hello world", buf2);
  1279. std::string str;
  1280. for (int i = 0; i < 10000; ++i) {
  1281. char buf[128];
  1282. int len = snprintf(buf, sizeof(buf), "1%d2%d3%d4%d5%d", i, i, i, i, i);
  1283. appender.append(buf, len);
  1284. str.append(buf, len);
  1285. }
  1286. ASSERT_EQ(str, appender.buf());
  1287. butil::IOBuf buf3;
  1288. appender.move_to(buf3);
  1289. ASSERT_EQ("", appender.buf());
  1290. ASSERT_EQ(str, buf3);
  1291. }
  1292. TEST_F(IOBufTest, appender_perf) {
  1293. const size_t N1 = 100000;
  1294. butil::Timer tm1;
  1295. tm1.start();
  1296. butil::IOBuf buf1;
  1297. for (size_t i = 0; i < N1; ++i) {
  1298. buf1.push_back(i);
  1299. }
  1300. tm1.stop();
  1301. butil::Timer tm2;
  1302. tm2.start();
  1303. butil::IOBufAppender appender1;
  1304. for (size_t i = 0; i < N1; ++i) {
  1305. appender1.push_back(i);
  1306. }
  1307. tm2.stop();
  1308. LOG(INFO) << "IOBuf.push_back=" << tm1.n_elapsed() / N1
  1309. << "ns IOBufAppender.push_back=" << tm2.n_elapsed() / N1
  1310. << "ns";
  1311. const size_t N2 = 50000;
  1312. const std::string s = "a repeatly appended string";
  1313. std::string str2;
  1314. butil::IOBuf buf2;
  1315. tm1.start();
  1316. for (size_t i = 0; i < N2; ++i) {
  1317. buf2.append(s);
  1318. }
  1319. tm1.stop();
  1320. tm2.start();
  1321. butil::IOBufAppender appender2;
  1322. for (size_t i = 0; i < N2; ++i) {
  1323. appender2.append(s);
  1324. }
  1325. tm2.stop();
  1326. butil::Timer tm3;
  1327. tm3.start();
  1328. for (size_t i = 0; i < N2; ++i) {
  1329. str2.append(s);
  1330. }
  1331. tm3.stop();
  1332. LOG(INFO) << "IOBuf.append=" << tm1.n_elapsed() / N2
  1333. << "ns IOBufAppender.append=" << tm2.n_elapsed() / N2
  1334. << "ns string.append=" << tm3.n_elapsed() / N2
  1335. << "ns (string-length=" << s.size() << ')';
  1336. }
  1337. TEST_F(IOBufTest, printed_as_binary) {
  1338. butil::IOBuf buf;
  1339. std::string str;
  1340. for (int i = 0; i < 256; ++i) {
  1341. buf.push_back((char)i);
  1342. str.push_back((char)i);
  1343. }
  1344. const char* const OUTPUT =
  1345. "\\00\\01\\02\\03\\04\\05\\06\\07\\b\\t\\n\\0B\\0C\\r\\0E\\0F"
  1346. "\\10\\11\\12\\13\\14\\15\\16\\17\\18\\19\\1A\\1B\\1C\\1D\\1E"
  1347. "\\1F !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUV"
  1348. "WXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\7F\\80\\81\\82"
  1349. "\\83\\84\\85\\86\\87\\88\\89\\8A\\8B\\8C\\8D\\8E\\8F\\90\\91"
  1350. "\\92\\93\\94\\95\\96\\97\\98\\99\\9A\\9B\\9C\\9D\\9E\\9F\\A0"
  1351. "\\A1\\A2\\A3\\A4\\A5\\A6\\A7\\A8\\A9\\AA\\AB\\AC\\AD\\AE\\AF"
  1352. "\\B0\\B1\\B2\\B3\\B4\\B5\\B6\\B7\\B8\\B9\\BA\\BB\\BC\\BD\\BE"
  1353. "\\BF\\C0\\C1\\C2\\C3\\C4\\C5\\C6\\C7\\C8\\C9\\CA\\CB\\CC\\CD"
  1354. "\\CE\\CF\\D0\\D1\\D2\\D3\\D4\\D5\\D6\\D7\\D8\\D9\\DA\\DB\\DC"
  1355. "\\DD\\DE\\DF\\E0\\E1\\E2\\E3\\E4\\E5\\E6\\E7\\E8\\E9\\EA\\EB"
  1356. "\\EC\\ED\\EE\\EF\\F0\\F1\\F2\\F3\\F4\\F5\\F6\\F7\\F8\\F9\\FA"
  1357. "\\FB\\FC\\FD\\FE\\FF";
  1358. std::ostringstream os;
  1359. os << butil::ToPrintable(buf, 256);
  1360. ASSERT_STREQ(OUTPUT, os.str().c_str());
  1361. os.str("");
  1362. os << butil::ToPrintable(str, 256);
  1363. ASSERT_STREQ(OUTPUT, os.str().c_str());
  1364. }
  1365. TEST_F(IOBufTest, copy_to_string_from_iterator) {
  1366. butil::IOBuf b0;
  1367. for (size_t i = 0; i < 1 * 1024 * 1024lu; ++i) {
  1368. b0.push_back(butil::fast_rand_in('a', 'z'));
  1369. }
  1370. butil::IOBuf b1(b0);
  1371. butil::IOBufBytesIterator iter(b0);
  1372. size_t nc = 0;
  1373. while (nc < b0.length()) {
  1374. size_t to_copy = butil::fast_rand_in(1024lu, 64 * 1024lu);
  1375. butil::IOBuf b;
  1376. b1.cutn(&b, to_copy);
  1377. std::string s;
  1378. const size_t copied = iter.copy_and_forward(&s, to_copy);
  1379. ASSERT_GT(copied, 0u);
  1380. ASSERT_TRUE(b.equals(s));
  1381. nc += copied;
  1382. }
  1383. ASSERT_EQ(nc, b0.length());
  1384. }
  1385. static void* my_free_params = NULL;
  1386. static void my_free(void* m) {
  1387. free(m);
  1388. my_free_params = m;
  1389. }
  1390. TEST_F(IOBufTest, append_user_data_and_consume) {
  1391. butil::IOBuf b0;
  1392. const int REP = 16;
  1393. const size_t len = REP * 256;
  1394. char* data = (char*)malloc(len);
  1395. for (int i = 0; i < 256; ++i) {
  1396. for (int j = 0; j < REP; ++j) {
  1397. data[i * REP + j] = (char)i;
  1398. }
  1399. }
  1400. my_free_params = NULL;
  1401. ASSERT_EQ(0, b0.append_user_data(data, len, my_free));
  1402. ASSERT_EQ(1UL, b0._ref_num());
  1403. butil::IOBuf::BlockRef r = b0._front_ref();
  1404. ASSERT_EQ(1, butil::iobuf::block_shared_count(r.block));
  1405. ASSERT_EQ(len, b0.size());
  1406. std::string out;
  1407. ASSERT_EQ(len, b0.cutn(&out, len));
  1408. ASSERT_TRUE(b0.empty());
  1409. ASSERT_EQ(data, my_free_params);
  1410. ASSERT_EQ(len, out.size());
  1411. // note: cannot memcmp with data which is already free-ed
  1412. for (int i = 0; i < 256; ++i) {
  1413. for (int j = 0; j < REP; ++j) {
  1414. ASSERT_EQ((char)i, out[i * REP + j]);
  1415. }
  1416. }
  1417. }
  1418. TEST_F(IOBufTest, append_user_data_and_share) {
  1419. butil::IOBuf b0;
  1420. const int REP = 16;
  1421. const size_t len = REP * 256;
  1422. char* data = (char*)malloc(len);
  1423. for (int i = 0; i < 256; ++i) {
  1424. for (int j = 0; j < REP; ++j) {
  1425. data[i * REP + j] = (char)i;
  1426. }
  1427. }
  1428. my_free_params = NULL;
  1429. ASSERT_EQ(0, b0.append_user_data(data, len, my_free));
  1430. ASSERT_EQ(1UL, b0._ref_num());
  1431. butil::IOBuf::BlockRef r = b0._front_ref();
  1432. ASSERT_EQ(1, butil::iobuf::block_shared_count(r.block));
  1433. ASSERT_EQ(len, b0.size());
  1434. {
  1435. butil::IOBuf bufs[256];
  1436. for (int i = 0; i < 256; ++i) {
  1437. ASSERT_EQ((size_t)REP, b0.cutn(&bufs[i], REP));
  1438. ASSERT_EQ(len - (i+1) * REP, b0.size());
  1439. if (i != 255) {
  1440. ASSERT_EQ(1UL, b0._ref_num());
  1441. butil::IOBuf::BlockRef r = b0._front_ref();
  1442. ASSERT_EQ(i + 2, butil::iobuf::block_shared_count(r.block));
  1443. } else {
  1444. ASSERT_EQ(0UL, b0._ref_num());
  1445. ASSERT_TRUE(b0.empty());
  1446. }
  1447. }
  1448. ASSERT_EQ(NULL, my_free_params);
  1449. for (int i = 0; i < 256; ++i) {
  1450. std::string out = bufs[i].to_string();
  1451. ASSERT_EQ((size_t)REP, out.size());
  1452. for (int j = 0; j < REP; ++j) {
  1453. ASSERT_EQ((char)i, out[j]);
  1454. }
  1455. }
  1456. }
  1457. ASSERT_EQ(data, my_free_params);
  1458. }
  1459. TEST_F(IOBufTest, share_tls_block) {
  1460. butil::iobuf::remove_tls_block_chain();
  1461. butil::IOBuf::Block* b = butil::iobuf::acquire_tls_block();
  1462. ASSERT_EQ(0u, butil::iobuf::block_size(b));
  1463. butil::IOBuf::Block* b2 = butil::iobuf::share_tls_block();
  1464. butil::IOBuf buf;
  1465. for (size_t i = 0; i < butil::iobuf::block_cap(b2); i++) {
  1466. buf.push_back('x');
  1467. }
  1468. // after pushing to b2, b2 is full but it is still head of tls block.
  1469. ASSERT_NE(b, b2);
  1470. butil::iobuf::release_tls_block_chain(b);
  1471. ASSERT_EQ(b, butil::iobuf::share_tls_block());
  1472. // After releasing b, now tls block is b(not full) -> b2(full) -> NULL
  1473. for (size_t i = 0; i < butil::iobuf::block_cap(b); i++) {
  1474. buf.push_back('x');
  1475. }
  1476. // now tls block is b(full) -> b2(full) -> NULL
  1477. butil::IOBuf::Block* head_block = butil::iobuf::share_tls_block();
  1478. ASSERT_EQ(0u, butil::iobuf::block_size(head_block));
  1479. ASSERT_NE(b, head_block);
  1480. ASSERT_NE(b2, head_block);
  1481. }
  1482. TEST_F(IOBufTest, acquire_tls_block) {
  1483. butil::iobuf::remove_tls_block_chain();
  1484. butil::IOBuf::Block* b = butil::iobuf::acquire_tls_block();
  1485. const size_t block_cap = butil::iobuf::block_cap(b);
  1486. butil::IOBuf buf;
  1487. for (size_t i = 0; i < block_cap; i++) {
  1488. buf.append("x");
  1489. }
  1490. ASSERT_EQ(1, butil::iobuf::get_tls_block_count());
  1491. butil::IOBuf::Block* head = butil::iobuf::get_tls_block_head();
  1492. ASSERT_EQ(butil::iobuf::block_cap(head), butil::iobuf::block_size(head));
  1493. butil::iobuf::release_tls_block_chain(b);
  1494. ASSERT_EQ(2, butil::iobuf::get_tls_block_count());
  1495. for (size_t i = 0; i < block_cap; i++) {
  1496. buf.append("x");
  1497. }
  1498. ASSERT_EQ(2, butil::iobuf::get_tls_block_count());
  1499. head = butil::iobuf::get_tls_block_head();
  1500. ASSERT_EQ(butil::iobuf::block_cap(head), butil::iobuf::block_size(head));
  1501. b = butil::iobuf::acquire_tls_block();
  1502. ASSERT_EQ(0, butil::iobuf::get_tls_block_count());
  1503. ASSERT_NE(butil::iobuf::block_cap(b), butil::iobuf::block_size(b));
  1504. }
  1505. } // namespace