diff --git a/README.md b/README.md index 46c6ed1..f5c5080 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ In this repository, we present AnyBlob. AnyBlob is a universal download manager that allows to retrieve and upload objects to different cloud object stores. Our download manager uses less CPU resources than cloud-vendor provided libraries while retaining maximum throughput performance. AnyBlob leverages IO\_uring for superior performance per core. -For experimental results, please visit our research paper at []. +For experimental results, please visit our research paper at [PVLDB 16](https://www.vldb.org/pvldb/vol16/p2734-durner.pdf). ## Building AnyBlob @@ -42,9 +42,10 @@ For coverage testing you can simply `make coverage` and open the coverage report ## Cite this work -If you are using AnyBlob in our scientific work, please cite: +If you are using AnyBlob in your scientific work, please cite: ``` Exploiting Cloud Object Storage for High-Performance Analytics Dominik Durner, Viktor Leis, and Thomas Neumann +PVLDB 16, 11 (2023), 49th International Conference on Very Large Data Bases ``` diff --git a/test/unit/utils/ring_buffer_test.cpp b/test/unit/utils/ring_buffer_test.cpp index 1ade0d9..d199b22 100644 --- a/test/unit/utils/ring_buffer_test.cpp +++ b/test/unit/utils/ring_buffer_test.cpp @@ -1,5 +1,6 @@ #include "utils/ring_buffer.hpp" #include "catch2/single_include/catch2/catch.hpp" +#include //--------------------------------------------------------------------------- // AnyBlob - Universal Cloud Object Storage Library // Dominik Durner, 2022 @@ -27,6 +28,72 @@ TEST_CASE("ring_buffer") { REQUIRE(rb.empty()); } //--------------------------------------------------------------------------- +TEST_CASE("single_threaded_insert_multi_threaded_consume") { + RingBuffer rb(1000); + for (int i = 0; i < 1000; i++) { + REQUIRE(rb.insert(i) != ~0ull); + } + std::vector threads; + for (int i = 0; i < 10; i++) { + threads.push_back(std::thread([&] { + for (int j = 0; j < 100; j++) { + REQUIRE(rb.consume().value() < 1000ul); + } + })); + } + for (auto& th : threads) { + th.join(); + } + REQUIRE(!rb.consume().has_value()); +} +//--------------------------------------------------------------------------- +TEST_CASE("multi_threaded_ring_buffer") { + RingBuffer rb(1000); + std::vector threads; + for (int i = 0; i < 10; i++) { + threads.push_back(std::thread([&] { + for (int j = 0; j < 100; j++) { + REQUIRE(rb.insert(j) != ~0ull); + } + })); + } + for (auto& th : threads) { + th.join(); + } + for (int i = 0; i < 1000; i++) { + REQUIRE(rb.consume().value() < 100ul); + } + REQUIRE(!rb.consume().has_value()); +} +//--------------------------------------------------------------------------- +TEST_CASE("multi_threaded_ring_buffer_multi_threaded_consume") { + RingBuffer rb(1000); + std::vector threads; + for (int i = 0; i < 10; i++) { + threads.push_back(std::thread([&] { + for (int j = 0; j < 100; j++) { + REQUIRE(rb.insert(j) != ~0ull); + } + })); + } + for (auto& th : threads) { + th.join(); + } + // Consume multi-threaded + threads.clear(); + for (int i = 0; i < 10; i++) { + threads.push_back(std::thread([&] { + for (int j = 0; j < 100; j++) { + REQUIRE(rb.consume().value() < 100ul); + } + })); + } + for (auto& th : threads) { + th.join(); + } + REQUIRE(!rb.consume().has_value()); +} +//--------------------------------------------------------------------------- } // namespace test } // namespace utils } // namespace anyblob diff --git a/test/unit/utils/unordered_map_test.cpp b/test/unit/utils/unordered_map_test.cpp index ca06dd3..6e753c5 100644 --- a/test/unit/utils/unordered_map_test.cpp +++ b/test/unit/utils/unordered_map_test.cpp @@ -1,5 +1,6 @@ #include "utils/unordered_map.hpp" #include "catch2/single_include/catch2/catch.hpp" +#include //--------------------------------------------------------------------------- // AnyBlob - Universal Cloud Object Storage Library // Dominik Durner, 2022 @@ -28,6 +29,60 @@ TEST_CASE("unordered_map") { REQUIRE(ht.size() == 1); } //--------------------------------------------------------------------------- +TEST_CASE("unordered_map_multi_threaded") { + // Insert 1000 elements in 10 threads + UnorderedMap ht(128); + std::thread t[10]; + for (int i = 0; i < 10; i++) { + t[i] = std::thread([&ht, i]() { + for (int j = 0; j < 10; j++) { + std::ignore = ht.insert(i * 10 + j, i * 10 + j); + } + }); + } + for (int i = 0; i < 10; i++) { + t[i].join(); + } + // Find the elements multu-threaded + for (int i = 0; i < 10; i++) { + t[i] = std::thread([&ht, i]() { + for (int j = 0; j < 10; j++) { + REQUIRE(ht.find(i * 10 + j) != ht.end()); + } + }); + } + for (int i = 0; i < 10; i++) { + t[i].join(); + } +} +//--------------------------------------------------------------------------- +TEST_CASE("unordered_map_multi_threaded_delete") { + UnorderedMap ht(128); + // Insert 1000 elements in 10 threads + std::thread t[10]; + for (int i = 0; i < 10; i++) { + t[i] = std::thread([&ht, i]() { + for (int j = 0; j < 10; j++) { + std::ignore = ht.insert(i * 10 + j, i * 10 + j); + } + }); + } + for (int i = 0; i < 10; i++) { + t[i].join(); + } + // Delete the elements multi-threaded + for (int i = 0; i < 10; i++) { + t[i] = std::thread([&ht, i]() { + for (int j = 0; j < 10; j++) { + REQUIRE(ht.erase(i * 10 + j)); + } + }); + } + for (int i = 0; i < 10; i++) { + t[i].join(); + } +} +//--------------------------------------------------------------------------- } // namespace test } // namespace utils } // namespace anyblob