|
|
@@ -45,22 +45,34 @@ void module::redis_pool::close()
|
|
|
|
|
|
std::shared_ptr<module::redis> module::redis_pool::get()
|
|
|
{
|
|
|
- if (m_closed)
|
|
|
- {
|
|
|
- throw ylib::exception("connection pool is closed");
|
|
|
- }
|
|
|
redisContext* ctx = nullptr;
|
|
|
- if (m_queue.pop(ctx))
|
|
|
{
|
|
|
+ std::unique_lock<std::mutex> uni(m_mutex);
|
|
|
+ if (m_closed)
|
|
|
+ {
|
|
|
+ throw ylib::exception("connection pool is closed");
|
|
|
+ }
|
|
|
+ if (m_queue.pop(ctx))
|
|
|
+ {
|
|
|
+ m_pop_size++;
|
|
|
+ return std::make_shared<module::redis>(ctx, this);
|
|
|
+ }
|
|
|
+ if (m_pop_size >= m_max_size)
|
|
|
+ throw ylib::exception("connection pool releases more connections than the maximum number");
|
|
|
+ // Reserve a slot before unlocking for the blocking connect.
|
|
|
m_pop_size++;
|
|
|
- return std::make_shared<module::redis>(ctx, this);
|
|
|
}
|
|
|
- if (m_pop_size >= m_max_size)
|
|
|
- throw ylib::exception("connection pool releases more connections than the maximum number");
|
|
|
|
|
|
- ctx = reget(nullptr);
|
|
|
-
|
|
|
- m_pop_size++;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ ctx = reget(nullptr);
|
|
|
+ }
|
|
|
+ catch (...)
|
|
|
+ {
|
|
|
+ std::unique_lock<std::mutex> uni(m_mutex);
|
|
|
+ m_pop_size--;
|
|
|
+ throw;
|
|
|
+ }
|
|
|
return std::make_shared<module::redis>(ctx, this);
|
|
|
}
|
|
|
|
|
|
@@ -170,13 +182,15 @@ void module::redis_pool::recover(redisContext* ctx)
|
|
|
{
|
|
|
if (ctx == nullptr)
|
|
|
return;
|
|
|
+ std::unique_lock<std::mutex> uni(m_mutex);
|
|
|
if (m_closed)
|
|
|
{
|
|
|
redisFree(ctx);
|
|
|
return;
|
|
|
}
|
|
|
m_queue.push(ctx);
|
|
|
- m_pop_size--;
|
|
|
+ if (m_pop_size > 0)
|
|
|
+ m_pop_size--;
|
|
|
}
|
|
|
|
|
|
module::redis::redis(redisContext* context, redis_pool* pool):m_context(context),m_pool(pool)
|
|
|
@@ -190,7 +204,14 @@ module::redis::~redis()
|
|
|
}
|
|
|
void module::redis::close()
|
|
|
{
|
|
|
- m_pool->recover(m_context);
|
|
|
+ // Guard against double-return: Lua close() + shared_ptr destructor
|
|
|
+ // previously pushed the same redisContext* into the pool twice, which
|
|
|
+ // leads to concurrent redisCommand use and "double free or corruption".
|
|
|
+ if (m_context == nullptr || m_pool == nullptr)
|
|
|
+ return;
|
|
|
+ redisContext* ctx = m_context;
|
|
|
+ m_context = nullptr;
|
|
|
+ m_pool->recover(ctx);
|
|
|
}
|
|
|
sol::object module::redis::command(const std::string& cmd, sol::this_state ts)
|
|
|
{
|