|
@@ -206,7 +206,77 @@ sol::object module::redis::command(const std::string& cmd, sol::this_state ts)
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+sol::object module::redis::command_ex(const sol::table& args, sol::this_state ts)
|
|
|
|
|
+{
|
|
|
|
|
+ if (!args.valid()) {
|
|
|
|
|
+ throw ylib::exception("redis.command_ex: invalid arguments table");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ size_t table_size = args.size();
|
|
|
|
|
+ if (table_size == 0) {
|
|
|
|
|
+ throw ylib::exception("redis.command_ex: empty arguments table");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 使用智能指针自动管理内存
|
|
|
|
|
+ std::vector<std::unique_ptr<char[]>> buffers;
|
|
|
|
|
+ std::vector<const char*> argv;
|
|
|
|
|
+ std::vector<size_t> argvlen;
|
|
|
|
|
+
|
|
|
|
|
+ buffers.reserve(table_size);
|
|
|
|
|
+ argv.reserve(table_size);
|
|
|
|
|
+ argvlen.reserve(table_size);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建参数数组
|
|
|
|
|
+ for (size_t i = 1; i <= table_size; ++i) {
|
|
|
|
|
+ sol::object arg = args[i];
|
|
|
|
|
+ if (!arg.is<std::string>()) {
|
|
|
|
|
+ throw ylib::exception("redis.command_ex: argument at index "+std::to_string(i)+" is not a string");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ std::string str = arg.as<std::string>();
|
|
|
|
|
+ auto buffer = std::make_unique<char[]>(str.length() + 1);
|
|
|
|
|
+ std::strcpy(buffer.get(), str.c_str());
|
|
|
|
|
+
|
|
|
|
|
+ argv.push_back(buffer.get());
|
|
|
|
|
+ argvlen.push_back(str.length());
|
|
|
|
|
+ buffers.push_back(std::move(buffer)); // 转移所有权
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 执行命令
|
|
|
|
|
+ redisReply* reply = (redisReply*)redisCommandArgv(
|
|
|
|
|
+ m_context,
|
|
|
|
|
+ table_size,
|
|
|
|
|
+ argv.data(),
|
|
|
|
|
+ argvlen.data()
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // 处理错误
|
|
|
|
|
+ if (reply == NULL) {
|
|
|
|
|
+ if (m_context->err) {
|
|
|
|
|
+ m_context = m_pool->reget(m_context);
|
|
|
|
|
+ if (m_context == NULL || m_context->err) {
|
|
|
|
|
+ throw ylib::exception("Failed to reacquire Redis connection");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 重新执行(buffers仍然持有内存,可以重用)
|
|
|
|
|
+ reply = (redisReply*)redisCommandArgv(
|
|
|
|
|
+ m_context,
|
|
|
|
|
+ table_size,
|
|
|
|
|
+ argv.data(),
|
|
|
|
|
+ argvlen.data()
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if (reply == NULL) {
|
|
|
|
|
+ throw ylib::exception(std::string("Redis command failed after retry: ") + m_context->errstr);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ throw ylib::exception("Unknown error: reply is NULL but context has no error");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return m_pool->reply(&ts, m_context, reply);
|
|
|
|
|
+}
|
|
|
void module::redis_regist(sol::state* lua)
|
|
void module::redis_regist(sol::state* lua)
|
|
|
{
|
|
{
|
|
|
lua->new_usertype<module::redis_pool>("fw_redis_pool",
|
|
lua->new_usertype<module::redis_pool>("fw_redis_pool",
|
|
@@ -217,6 +287,7 @@ void module::redis_regist(sol::state* lua)
|
|
|
"self", &module::redis_pool::self
|
|
"self", &module::redis_pool::self
|
|
|
);
|
|
);
|
|
|
lua->new_usertype<module::redis>("fw_redis_conn",
|
|
lua->new_usertype<module::redis>("fw_redis_conn",
|
|
|
- "command", &module::redis::command
|
|
|
|
|
|
|
+ "command", &module::redis::command,
|
|
|
|
|
+ "command_ex", &module::redis::command_ex
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|