testing: pools
[awesomized/libmemcached] / test / tests / memcached / regression / lp_000-962-815.cpp
1 #include "test/lib/common.hpp"
2 #include "test/lib/MemcachedCluster.hpp"
3
4 #include "libmemcachedutil-1.0/pool.h"
5
6 #include <atomic>
7 #include <sstream>
8
9 static atomic<bool> running = false;
10
11 static inline void set_running(bool is) {
12 running.store(is, memory_order_release);
13 }
14 static inline bool is_running() {
15 return running.load(memory_order_consume);
16 }
17
18 struct worker_ctx {
19 memcached_pool_st *pool;
20 vector<stringstream> errors;
21
22 explicit worker_ctx(memcached_st *memc)
23 : pool{memcached_pool_create(memc, 5, 10)}
24 , errors{}
25 {
26 }
27
28 ~worker_ctx() {
29 memcached_pool_destroy(pool);
30 for (const auto &err : errors) {
31 cerr << err.str() << endl;
32 }
33 }
34
35 stringstream &err() {
36 return errors[errors.size()];
37 }
38 };
39
40 static void *worker(void *arg) {
41 auto *ctx = static_cast<worker_ctx *>(arg);
42
43 while (is_running()) {
44 memcached_return_t rc;
45 timespec block{5, 0};
46 auto *mc = memcached_pool_fetch(ctx->pool, &block, &rc);
47
48 if (!mc || memcached_failed(rc)) {
49 ctx->err() << "failed to fetch connection from pool: "
50 << memcached_strerror(nullptr, rc);
51 this_thread::sleep_for(100ms);
52 }
53
54 auto rs = random_ascii_string(12);
55 rc = memcached_set(mc, rs.c_str(), rs.length(), rs.c_str(), rs.length(), 0, 0);
56 if (memcached_failed(rc)) {
57 ctx->err() << "failed to memcached_set() "
58 << memcached_last_error_message(mc);
59 }
60 rc = memcached_pool_release(ctx->pool, mc);
61 if (memcached_failed(rc)) {
62 ctx->err() << "failed to release connection to pool: "
63 << memcached_strerror(nullptr, rc);
64 }
65 }
66
67 return ctx;
68 }
69
70 TEST_CASE("memcached_regression_lp962815") {
71 auto test = MemcachedCluster::mixed();
72 auto memc = &test.memc;
73
74 constexpr auto NUM_THREADS = 20;
75 array<pthread_t, NUM_THREADS> tid;
76 worker_ctx ctx{memc};
77
78 set_running(true);
79
80 for (auto &t : tid) {
81 REQUIRE(0 == pthread_create(&t, nullptr, worker, &ctx));
82 }
83
84 this_thread::sleep_for(5s);
85 set_running(false);
86
87 for (auto t : tid) {
88 void *ret = nullptr;
89 REQUIRE(0 == pthread_join(t, &ret));
90 REQUIRE(ret == &ctx);
91 }
92 }