1585346868 преди 1 месец
родител
ревизия
8487a299bb
променени са 1 файла, в които са добавени 34 реда и са изтрити 13 реда
  1. 34 13
      src/redis.cpp

+ 34 - 13
src/redis.cpp

@@ -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)
 {