|
24 | 24 | #endif |
25 | 25 | #include "netbuf/netbuf.h" |
26 | 26 |
|
| 27 | +#include "sllist.h" |
| 28 | +#include "sllist-inl.h" |
| 29 | + |
| 30 | +#include <array> |
| 31 | + |
27 | 32 | #define BIG_BUF_SIZE 5000 |
28 | 33 | #define SMALL_BUF_SIZE 50 |
29 | 34 |
|
@@ -456,3 +461,134 @@ TEST_F(NetbufTest, testOutOfOrder) |
456 | 461 |
|
457 | 462 | clean_check(&mgr); |
458 | 463 | } |
| 464 | + |
| 465 | +struct my_PACKET { |
| 466 | + sllist_node slnode{nullptr}; |
| 467 | + nb_SPAN key_{}; |
| 468 | + nb_SPAN value_{}; |
| 469 | + bool is_flushed_{false}; |
| 470 | + |
| 471 | + my_PACKET(nb_MGR *mgr, std::string key, std::string value) |
| 472 | + { |
| 473 | + key_.size = key.size(); |
| 474 | + netbuf_mblock_reserve(mgr, &key_); |
| 475 | + |
| 476 | + value_.size = value.size(); |
| 477 | + netbuf_mblock_reserve(mgr, &value_); |
| 478 | + } |
| 479 | + |
| 480 | + void remove_pdu_from(nb_MGR *mgr) |
| 481 | + { |
| 482 | + sllist_iterator iter; |
| 483 | + SLLIST_ITERFOR(&mgr->sendq.pdus, &iter) |
| 484 | + { |
| 485 | + my_PACKET *el = SLLIST_ITEM(iter.cur, my_PACKET, slnode); |
| 486 | + if (el == this) { |
| 487 | + sllist_iter_remove(&mgr->sendq.pdus, &iter); |
| 488 | + } |
| 489 | + } |
| 490 | + } |
| 491 | + |
| 492 | + [[nodiscard]] auto key() -> nb_SPAN * |
| 493 | + { |
| 494 | + return &key_; |
| 495 | + } |
| 496 | + |
| 497 | + [[nodiscard]] auto value() -> nb_SPAN * |
| 498 | + { |
| 499 | + return &value_; |
| 500 | + } |
| 501 | + |
| 502 | + [[nodiscard]] auto is_flushed() const -> bool |
| 503 | + { |
| 504 | + return is_flushed_; |
| 505 | + } |
| 506 | + |
| 507 | + void mark_as_flushed() |
| 508 | + { |
| 509 | + is_flushed_ = true; |
| 510 | + } |
| 511 | + |
| 512 | + [[nodiscard]] auto size() const -> std::size_t |
| 513 | + { |
| 514 | + return key_.size + value_.size; |
| 515 | + } |
| 516 | +}; |
| 517 | + |
| 518 | +static nb_SIZE packet_flush_callback(void *pdu, nb_SIZE hint, void * /* arg */) |
| 519 | +{ |
| 520 | + my_PACKET *packet = (my_PACKET *)pdu; |
| 521 | + if (hint >= packet->size()) { |
| 522 | + packet->mark_as_flushed(); |
| 523 | + } |
| 524 | + return packet->size(); |
| 525 | +} |
| 526 | + |
| 527 | +TEST_F(NetbufTest, testPacketCleanup) |
| 528 | +{ |
| 529 | + nb_MGR mgr; |
| 530 | + nb_SETTINGS settings; |
| 531 | + netbuf_default_settings(&settings); |
| 532 | + settings.data_basealloc = 1; |
| 533 | + netbuf_init(&mgr, &settings); |
| 534 | + |
| 535 | + std::array<my_PACKET, 3> packets{ |
| 536 | + my_PACKET{&mgr, "key_1", "value_1"}, |
| 537 | + my_PACKET{&mgr, "key_2", "value_2"}, |
| 538 | + my_PACKET{&mgr, "key_3", "value_3"}, |
| 539 | + }; |
| 540 | + |
| 541 | + /* enqueue first two packets */ |
| 542 | + for (std::size_t i = 0; i < 2; ++i) { |
| 543 | + netbuf_enqueue_span(&mgr, packets[i].key(), &packets[i]); |
| 544 | + netbuf_enqueue_span(&mgr, packets[i].value(), &packets[i]); |
| 545 | + netbuf_pdu_enqueue(&mgr, &packets[i], offsetof(my_PACKET, slnode)); |
| 546 | + } |
| 547 | + |
| 548 | + nb_IOV iov[10]; |
| 549 | + nb_SIZE to_flush; |
| 550 | + |
| 551 | + /* start flushing first two packets */ |
| 552 | + to_flush = netbuf_start_flush(&mgr, iov, 4, NULL); |
| 553 | + ASSERT_EQ(packets[0].size() + packets[1].size(), to_flush); |
| 554 | + |
| 555 | + /* discard second packet |
| 556 | + * |
| 557 | + * this simulates network failure and relocation of the packet |
| 558 | + * to some other pipeline while the IO still being processed by |
| 559 | + * the OS kernel |
| 560 | + */ |
| 561 | + packets[1].remove_pdu_from(&mgr); |
| 562 | + netbuf_cleanup_packet(&mgr, &packets[1]); |
| 563 | + |
| 564 | + /* |
| 565 | + * OS kernel returned and completed flushing |
| 566 | + */ |
| 567 | + netbuf_end_flush2(&mgr, to_flush, packet_flush_callback, offsetof(my_PACKET, slnode), NULL); |
| 568 | + ASSERT_TRUE(packets[0].is_flushed()); |
| 569 | + ASSERT_FALSE(packets[1].is_flushed()); |
| 570 | + ASSERT_FALSE(packets[2].is_flushed()); |
| 571 | + |
| 572 | + /* |
| 573 | + * enqueue last packet |
| 574 | + */ |
| 575 | + netbuf_enqueue_span(&mgr, packets[2].key(), &packets[2]); |
| 576 | + netbuf_enqueue_span(&mgr, packets[2].value(), &packets[2]); |
| 577 | + netbuf_pdu_enqueue(&mgr, &packets[2], offsetof(my_PACKET, slnode)); |
| 578 | + |
| 579 | + /* start flushing last packet */ |
| 580 | + to_flush = netbuf_start_flush(&mgr, iov, 10, NULL); |
| 581 | + ASSERT_EQ(packets[2].size(), to_flush); |
| 582 | + |
| 583 | + netbuf_end_flush2(&mgr, to_flush, packet_flush_callback, 0, NULL); |
| 584 | + ASSERT_TRUE(packets[0].is_flushed()); |
| 585 | + ASSERT_FALSE(packets[1].is_flushed()); |
| 586 | + ASSERT_TRUE(packets[2].is_flushed()); |
| 587 | + |
| 588 | + for (auto &packet : packets) { |
| 589 | + netbuf_mblock_release(&mgr, packet.key()); |
| 590 | + netbuf_mblock_release(&mgr, packet.value()); |
| 591 | + } |
| 592 | + |
| 593 | + clean_check(&mgr); |
| 594 | +} |
0 commit comments