diff --git a/include/data_structures/concurrent/skiplist.hpp b/include/data_structures/concurrent/skiplist.hpp index 2722cc343..bb7834a60 100644 --- a/include/data_structures/concurrent/skiplist.hpp +++ b/include/data_structures/concurrent/skiplist.hpp @@ -352,11 +352,13 @@ public: return succs[0]->value(); } - bool has_next() - { - assert(succs[0] != nullptr); - return succs[0].forward(0) != nullptr; - } + // WRONG THIS CAN POSSIBLY NOT BE TRUE IF SOMEONE JUST AFTER THIS REMOVE + // ELEMENT AFTER THIS ONE. + // bool has_next() + // { + // assert(succs[0] != nullptr); + // return succs[0].forward(0) != nullptr; + // } bool has_value() { return succs[0] != nullptr; } diff --git a/tests/concurrent/common.h b/tests/concurrent/common.h index 934c29a87..82910cdd4 100644 --- a/tests/concurrent/common.h +++ b/tests/concurrent/common.h @@ -7,6 +7,7 @@ #include #include +#include "data_structures/bitset/dynamic_bitset.hpp" #include "data_structures/concurrent/concurrent_map.hpp" #include "data_structures/concurrent/concurrent_multimap.hpp" #include "data_structures/concurrent/concurrent_multiset.hpp" @@ -106,6 +107,14 @@ void check_zero(size_t key_range, long array[], const char *str) } } +void check_set(DynamicBitset<> &db, std::vector &set) +{ + for (int i = 0; i < set.size(); i++) { + permanent_assert(!(set[i] ^ db.at(i)), + "Set constraints aren't fullfilled."); + } +} + // Checks multiIterator and iterator guarantees void check_multi_iterator(multimap_t::Accessor &accessor, size_t key_range, long set[]) @@ -164,6 +173,25 @@ run(size_t threads_no, S &skiplist, return futures; } +// Runs given function in threads_no threads and returns vector of futures for +// there +// results. +template +std::vector>> run(size_t threads_no, + std::function f) +{ + std::vector>> futures; + + for (size_t thread_i = 0; thread_i < threads_no; ++thread_i) { + std::packaged_task()> task([f, thread_i]() { + return std::pair(thread_i, f(thread_i)); + }); // wrap the function + futures.push_back(task.get_future()); // get a future + std::thread(std::move(task)).detach(); + } + return futures; +} + // Collects all data from futures. template auto collect(std::vector> &collect) @@ -175,6 +203,19 @@ auto collect(std::vector> &collect) return collection; } +std::vector collect_set( + std::vector>>> &&futures) +{ + std::vector set; + for (auto &data : collect(futures)) { + set.resize(data.second.size()); + for (int i = 0; i < data.second.size(); i++) { + set[i] = set[i] | data.second[i]; + } + } + return set; +} + // Returns object which tracs in owned which (key,data) where added and // downcounts. template diff --git a/tests/concurrent/dynamic_bitset.cpp b/tests/concurrent/dynamic_bitset.cpp new file mode 100644 index 000000000..252874650 --- /dev/null +++ b/tests/concurrent/dynamic_bitset.cpp @@ -0,0 +1,39 @@ +#include "common.h" + +#define THREADS_NO 8 +constexpr size_t op_per_thread = 1e5; +constexpr size_t bit_part_len = 2; +constexpr size_t no_slots = 1e4; +constexpr size_t key_range = no_slots * THREADS_NO * bit_part_len; +constexpr size_t no_sets_per_clear = 2; + +int main() +{ + DynamicBitset<> db; + auto seted = + collect_set(run>(THREADS_NO, [&](auto index) { + auto rand = rand_gen(no_slots); + auto clear_op = rand_gen_bool(no_sets_per_clear); + std::vector set(key_range); + + for (size_t i = 0; i < op_per_thread; i++) { + size_t num = + rand() * THREADS_NO * bit_part_len + index * bit_part_len; + + if (clear_op()) { + db.clear(num, bit_part_len); + for (int j = 0; j < bit_part_len; j++) { + set[num + j] = false; + } + } else { + db.set(num, bit_part_len); + for (int j = 0; j < bit_part_len; j++) + set[num + j] = true; + } + } + + return set; + })); + + check_set(db, seted); +} diff --git a/tests/concurrent/dynamic_bitset_clear_n.cpp b/tests/concurrent/dynamic_bitset_clear_n.cpp new file mode 100644 index 000000000..61b5384aa --- /dev/null +++ b/tests/concurrent/dynamic_bitset_clear_n.cpp @@ -0,0 +1,52 @@ +#include "common.h" + +#define THREADS_NO 4 +constexpr size_t op_per_thread = 1e5; +constexpr size_t up_border_bit_set_pow2 = 3; +constexpr size_t key_range = + op_per_thread * THREADS_NO * (1 << up_border_bit_set_pow2) * 2; + +int main() +{ + DynamicBitset<> db; + auto seted = + collect_set(run>(THREADS_NO, [&](auto index) { + auto rand = rand_gen(key_range); + auto rand_len = rand_gen(up_border_bit_set_pow2); + std::vector set(key_range + (1 << up_border_bit_set_pow2)); + + for (size_t i = 0; i < op_per_thread; i++) { + auto len = 1 << rand_len(); + size_t num = (rand() / len) * len; + db.set(num, len); + for (int j = 0; j < len; j++) + set[num + j] = true; + } + + return set; + })); + + auto cleared = + collect_set(run>(THREADS_NO, [&](auto index) { + auto rand = rand_gen(key_range); + auto rand_len = rand_gen(up_border_bit_set_pow2); + std::vector set(key_range + (1 << up_border_bit_set_pow2)); + + for (size_t i = 0; i < op_per_thread; i++) { + auto len = 1 << rand_len(); + size_t num = (rand() / len) * len; + for (int j = 0; j < len; j++) { + set[num + j] = set[num + j] | db.at(num + j); + } + db.clear(num, len); + } + + return set; + })); + + for (size_t i = 0; i < seted.size(); i++) { + seted[i] = seted[i] & (!cleared[i]); + } + + check_set(db, seted); +} diff --git a/tests/concurrent/dynamic_bitset_set.cpp b/tests/concurrent/dynamic_bitset_set.cpp new file mode 100644 index 000000000..f219a6a97 --- /dev/null +++ b/tests/concurrent/dynamic_bitset_set.cpp @@ -0,0 +1,24 @@ +#include "common.h" + +#define THREADS_NO 8 +constexpr size_t op_per_thread = 1e5; +constexpr size_t key_range = op_per_thread * THREADS_NO * 3; + +int main() +{ + DynamicBitset<> db; + auto set = collect_set(run>(THREADS_NO, [&](auto index) { + auto rand = rand_gen(key_range); + std::vector set(key_range); + + for (size_t i = 0; i < op_per_thread; i++) { + size_t num = rand(); + db.set(num); + set[num] = true; + } + + return set; + })); + + check_set(db, set); +} diff --git a/tests/concurrent/dynamic_bitset_set_n.cpp b/tests/concurrent/dynamic_bitset_set_n.cpp new file mode 100644 index 000000000..c05118feb --- /dev/null +++ b/tests/concurrent/dynamic_bitset_set_n.cpp @@ -0,0 +1,29 @@ +#include "common.h" + +#define THREADS_NO 4 +constexpr size_t op_per_thread = 1e5; +constexpr size_t up_border_bit_set_pow2 = 3; +constexpr size_t key_range = + op_per_thread * THREADS_NO * (1 << up_border_bit_set_pow2) * 2; + +int main() +{ + DynamicBitset<> db; + auto set = collect_set(run>(THREADS_NO, [&](auto index) { + auto rand = rand_gen(key_range); + auto rand_len = rand_gen(up_border_bit_set_pow2); + std::vector set(key_range + (1 << up_border_bit_set_pow2)); + + for (size_t i = 0; i < op_per_thread; i++) { + auto len = 1 << rand_len(); + size_t num = (rand() / len) * len; + db.set(num, len); + for (int j = 0; j < len; j++) + set[num + j] = true; + } + + return set; + })); + + check_set(db, set); +} diff --git a/tests/unit/chunked_decoder.cpp b/tests/unit/chunked_decoder.cpp index 4890affdb..b19b08fa5 100644 --- a/tests/unit/chunked_decoder.cpp +++ b/tests/unit/chunked_decoder.cpp @@ -1,23 +1,20 @@ -#include -#include +#include #include #include -#include +#include +#include #include #include "communication/bolt/v1/transport/chunked_decoder.hpp" using byte = unsigned char; -void print_hex(byte x) -{ - printf("%02X ", static_cast(x)); -} +void print_hex(byte x) { printf("%02X ", static_cast(x)); } class DummyStream { public: - void write(const byte* values, size_t n) + void write(const byte *values, size_t n) { data.insert(data.end(), values, values + n); } @@ -28,11 +25,11 @@ public: using Decoder = bolt::ChunkedDecoder; std::vector chunks[] = { - {0x00,0x08,'A',' ','q','u','i','c','k',' ',0x00,0x06,'b','r','o','w','n',' '}, - {0x00,0x0A,'f','o','x',' ','j','u','m','p','s',' '}, - {0x00,0x07,'o','v','e','r',' ','a',' '}, - {0x00,0x08,'l','a','z','y',' ','d','o','g',0x00,0x00} -}; + {0x00, 0x08, 'A', ' ', 'q', 'u', 'i', 'c', 'k', ' ', 0x00, 0x06, 'b', 'r', + 'o', 'w', 'n', ' '}, + {0x00, 0x0A, 'f', 'o', 'x', ' ', 'j', 'u', 'm', 'p', 's', ' '}, + {0x00, 0x07, 'o', 'v', 'e', 'r', ' ', 'a', ' '}, + {0x00, 0x08, 'l', 'a', 'z', 'y', ' ', 'd', 'o', 'g', 0x00, 0x00}}; static constexpr size_t N = std::extent::value; diff --git a/tests/unit/skiplistset.cpp b/tests/unit/skiplistset.cpp new file mode 100644 index 000000000..b4ec81600 --- /dev/null +++ b/tests/unit/skiplistset.cpp @@ -0,0 +1,53 @@ +#include + +#include "data_structures/concurrent/concurrent_set.hpp" + +using std::cout; +using std::endl; + +void print_skiplist(const ConcurrentSet::Accessor &skiplist) +{ + cout << "---- skiplist set now has: "; + + for (auto &item : skiplist) + cout << item << ", "; + + cout << "----" << endl; +} + +int main(void) +{ + ConcurrentSet set; + auto accessor = set.access(); + + cout << std::boolalpha; + + cout << "added non-existing 1? (true) " << accessor.insert(1).second + << endl; + + cout << "added already existing 1? (false) " << accessor.insert(1).second + << endl; + + accessor.insert(2); + print_skiplist(accessor); + + cout << "item 3 doesn't exist? (true) " + << (accessor.find(3) == accessor.end()) << endl; + + cout << "item 3 exists? (false) " << accessor.contains(3) << endl; + + cout << "item 2 exists? (true) " << (accessor.find(2) != accessor.end()) + << endl; + + cout << "at item 2 is? 2 " << *accessor.find(2) << endl; + + cout << "removed existing 1? (true) " << accessor.remove(1) << endl; + cout << "removed non-existing 3? (false) " << accessor.remove(3) << endl; + + accessor.insert(1); + accessor.insert(4); + + print_skiplist(accessor); + + return 0; +}