Skip to content

Commit b2b1146

Browse files
committed
Refactor lustate handling to be much more efficient
Previously luastates were stored in an array. Worker threads accessed luastates by simply retrieving the "next" state in the array, regardless of whether that state was in use or not. This commit instead uses a pool approach, where worker threads pop the state off the aray while the state is in use, then return the state once it's no longer needed (automatically via destructor). A read-only copy of the entire array is maintained for the console/ control thread which needs to be able to call all luastates.
1 parent acbdfd9 commit b2b1146

File tree

2 files changed

+129
-67
lines changed

2 files changed

+129
-67
lines changed

trackalert/trackalert-luastate.hh

Lines changed: 56 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
*/
2222

2323
#pragma once
24+
2425
#include "ext/luawrapper/include/LuaContext.hpp"
2526
#include "misc.hh"
2627
#include <mutex>
@@ -42,7 +43,9 @@ typedef std::function<void()> background_t;
4243
extern background_t g_background;
4344
typedef std::unordered_map<std::string, background_t> bg_func_map_t;
4445

45-
vector<std::function<void(void)>> setupLua(bool client, bool allow_report, LuaContext& c_lua, report_t& report_func, bg_func_map_t* bg_func_map, CustomFuncMap& custom_func_map, const std::string& config);
46+
vector<std::function<void(void)>>
47+
setupLua(bool client, bool allow_report, LuaContext& c_lua, report_t& report_func, bg_func_map_t* bg_func_map,
48+
CustomFuncMap& custom_func_map, const std::string& config);
4649

4750
struct LuaThreadContext {
4851
LuaContext lua_context;
@@ -54,40 +57,46 @@ struct LuaThreadContext {
5457

5558
#define NUM_LUA_STATES 6
5659

57-
class LuaMultiThread
58-
{
60+
class LuaMultiThread {
5961
public:
60-
LuaMultiThread() : num_states(NUM_LUA_STATES),
61-
state_index(0)
62+
LuaMultiThread() : num_states(NUM_LUA_STATES)
6263
{
6364
LuaMultiThread{num_states};
6465
}
6566

66-
LuaMultiThread(unsigned int nstates) : num_states(nstates),
67-
state_index(0)
67+
LuaMultiThread(unsigned int nstates) : num_states(nstates)
6868
{
69-
for (unsigned int i=0; i<num_states; i++) {
70-
lua_cv.push_back(std::make_shared<LuaThreadContext>());
71-
}
69+
for (unsigned int i = 0; i < num_states; i++) {
70+
lua_pool.push_back(std::make_shared<LuaThreadContext>());
71+
}
72+
lua_read_only = lua_pool; // Make a copy for use by the control thread
7273
}
7374

7475
LuaMultiThread(const LuaMultiThread&) = delete;
76+
7577
LuaMultiThread& operator=(const LuaMultiThread&) = delete;
76-
78+
7779
// these are used to setup the function pointers
78-
std::vector<std::shared_ptr<LuaThreadContext>>::iterator begin() { return lua_cv.begin(); }
79-
std::vector<std::shared_ptr<LuaThreadContext>>::iterator end() { return lua_cv.end(); }
80+
std::vector<std::shared_ptr<LuaThreadContext>>::iterator begin()
81+
{ return lua_read_only.begin(); }
8082

81-
void report(const LoginTuple& lt) {
82-
auto lt_context = getLuaState();
83+
std::vector<std::shared_ptr<LuaThreadContext>>::iterator end()
84+
{ return lua_read_only.end(); }
85+
86+
void report(const LoginTuple& lt)
87+
{
88+
auto pool_member = getPoolMember();
89+
auto lt_context = pool_member.getLuaContext();
8390
// lock the lua state mutex
8491
std::lock_guard<std::mutex> lock(lt_context->lua_mutex);
8592
// call the report function
8693
lt_context->report_func(lt);
8794
}
8895

89-
void background(const std::string& func_name) {
90-
auto lt_context = getLuaState();
96+
void background(const std::string& func_name)
97+
{
98+
auto pool_member = getPoolMember();
99+
auto lt_context = pool_member.getLuaContext();
91100
// lock the lua state mutex
92101
std::lock_guard<std::mutex> lock(lt_context->lua_mutex);
93102
// call the background function
@@ -96,31 +105,49 @@ public:
96105
fn->second();
97106
}
98107

99-
CustomFuncReturn custom_func(const std::string& command, const CustomFuncArgs& cfa) {
100-
auto lt_context = getLuaState();
108+
CustomFuncReturn custom_func(const std::string& command, const CustomFuncArgs& cfa)
109+
{
110+
auto pool_member = getPoolMember();
111+
auto lt_context = pool_member.getLuaContext();
101112
// lock the lua state mutex
102113
std::lock_guard<std::mutex> lock(lt_context->lua_mutex);
103114
// call the custom function
104-
for (const auto& i : lt_context->custom_func_map) {
115+
for (const auto& i: lt_context->custom_func_map) {
105116
if (command.compare(i.first) == 0) {
106-
return i.second.c_func(cfa);
117+
return i.second.c_func(cfa);
107118
}
108119
}
109120
return CustomFuncReturn(false, KeyValVector{});
110121
}
111-
122+
112123
protected:
113-
std::shared_ptr<LuaThreadContext> getLuaState()
114-
{
124+
class SharedPoolMember {
125+
public:
126+
SharedPoolMember(std::shared_ptr<LuaThreadContext> ptr, LuaMultiThread* pool) : d_pool_item(ptr), d_pool(pool) {}
127+
~SharedPoolMember() { if (d_pool != nullptr) { d_pool->returnPoolMember(d_pool_item); } }
128+
SharedPoolMember(const SharedPoolMember&) = delete;
129+
SharedPoolMember& operator=(const SharedPoolMember&) = delete;
130+
std::shared_ptr<LuaThreadContext> getLuaContext() { return d_pool_item; }
131+
private:
132+
std::shared_ptr<LuaThreadContext> d_pool_item;
133+
LuaMultiThread* d_pool;
134+
};
135+
136+
SharedPoolMember getPoolMember() {
115137
std::lock_guard<std::mutex> lock(mutx);
116-
if (state_index >= num_states)
117-
state_index = 0;
118-
return lua_cv[state_index++];
138+
auto member = lua_pool.back();
139+
lua_pool.pop_back();
140+
return SharedPoolMember(member, this);
119141
}
142+
void returnPoolMember(std::shared_ptr<LuaThreadContext> my_ptr) {
143+
std::lock_guard<std::mutex> lock(mutx);
144+
lua_pool.push_back(my_ptr);
145+
}
146+
120147
private:
121-
std::vector<std::shared_ptr<LuaThreadContext>> lua_cv;
148+
std::vector<std::shared_ptr<LuaThreadContext>> lua_pool;
149+
std::vector<std::shared_ptr<LuaThreadContext>> lua_read_only;
122150
unsigned int num_states;
123-
unsigned int state_index;
124151
std::mutex mutx;
125152
};
126153

wforce/luastate.hh

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
*/
2222

2323
#pragma once
24+
2425
#include "ext/luawrapper/include/LuaContext.hpp"
2526
#include "misc.hh"
2627
#include <mutex>
@@ -41,7 +42,7 @@ typedef std::function<std::string(const std::string&)> canonicalize_t;
4142

4243
struct CustomFuncMapObject {
4344
custom_func_t c_func;
44-
bool c_reportSink;
45+
bool c_reportSink;
4546
};
4647

4748
typedef std::map<std::string, CustomFuncMapObject> CustomFuncMap;
@@ -50,7 +51,10 @@ extern CustomFuncMap g_custom_func_map;
5051
typedef std::map<std::string, custom_get_func_t> CustomGetFuncMap;
5152
extern CustomGetFuncMap g_custom_get_func_map;
5253

53-
vector<std::function<void(void)>> setupLua(bool client, bool allow_report, LuaContext& c_lua, allow_t& allow_func, report_t& report_func, reset_t& reset_func, canonicalize_t& canon_func, CustomFuncMap& custom_func_map, CustomGetFuncMap& custom_get_func_map, const std::string& config);
54+
vector<std::function<void(void)>>
55+
setupLua(bool client, bool allow_report, LuaContext& c_lua, allow_t& allow_func, report_t& report_func,
56+
reset_t& reset_func, canonicalize_t& canon_func, CustomFuncMap& custom_func_map,
57+
CustomGetFuncMap& custom_get_func_map, const std::string& config);
5458

5559
struct LuaThreadContext {
5660
LuaContext lua_context;
@@ -65,101 +69,132 @@ struct LuaThreadContext {
6569

6670
#define NUM_LUA_STATES 6
6771

68-
class LuaMultiThread
69-
{
72+
class LuaMultiThread {
7073
public:
71-
LuaMultiThread() : num_states(NUM_LUA_STATES),
72-
state_index(0)
74+
75+
LuaMultiThread() : num_states(NUM_LUA_STATES)
7376
{
7477
LuaMultiThread{num_states};
7578
}
7679

77-
LuaMultiThread(unsigned int nstates) : num_states(nstates),
78-
state_index(0)
80+
LuaMultiThread(unsigned int nstates) : num_states(nstates)
7981
{
80-
for (unsigned int i=0; i<num_states; i++) {
81-
lua_cv.push_back(std::make_shared<LuaThreadContext>());
82-
}
82+
for (unsigned int i = 0; i < num_states; i++) {
83+
lua_pool.push_back(std::make_shared<LuaThreadContext>());
84+
}
85+
lua_read_only = lua_pool; // Make a copy for use by the control thread
8386
}
8487

8588
LuaMultiThread(const LuaMultiThread&) = delete;
89+
8690
LuaMultiThread& operator=(const LuaMultiThread&) = delete;
8791

8892
// these are used to setup the allow and report function pointers
89-
std::vector<std::shared_ptr<LuaThreadContext>>::iterator begin() { return lua_cv.begin(); }
90-
std::vector<std::shared_ptr<LuaThreadContext>>::iterator end() { return lua_cv.end(); }
93+
std::vector<std::shared_ptr<LuaThreadContext>>::iterator begin()
94+
{ return lua_read_only.begin(); }
95+
96+
std::vector<std::shared_ptr<LuaThreadContext>>::iterator end()
97+
{ return lua_read_only.end(); }
9198

92-
bool reset(const std::string& type, const std::string& login_value, const ComboAddress& ca_value) {
93-
auto lt_context = getLuaState();
99+
bool reset(const std::string& type, const std::string& login_value, const ComboAddress& ca_value)
100+
{
101+
auto pool_member = getPoolMember();
102+
auto lt_context = pool_member.getLuaContext();
94103
// lock the lua state mutex
95104
std::lock_guard<std::mutex> lock(lt_context->lua_mutex);
96105
// call the reset function
97106
return lt_context->reset_func(type, login_value, ca_value);
98107
}
99108

100-
AllowReturn allow(const LoginTuple& lt) {
101-
auto lt_context = getLuaState();
109+
AllowReturn allow(const LoginTuple& lt)
110+
{
111+
auto pool_member = getPoolMember();
112+
auto lt_context = pool_member.getLuaContext();
102113
// lock the lua state mutex
103114
std::lock_guard<std::mutex> lock(lt_context->lua_mutex);
104115
// call the allow function
105116
return lt_context->allow_func(lt);
106117
}
107118

108-
void report(const LoginTuple& lt) {
109-
auto lt_context = getLuaState();
119+
void report(const LoginTuple& lt)
120+
{
121+
auto pool_member = getPoolMember();
122+
auto lt_context = pool_member.getLuaContext();
110123
// lock the lua state mutex
111124
std::lock_guard<std::mutex> lock(lt_context->lua_mutex);
112125
// call the report function
113126
lt_context->report_func(lt);
114127
}
115128

116-
std::string canonicalize(const std::string& login) {
117-
auto lt_context = getLuaState();
129+
std::string canonicalize(const std::string& login)
130+
{
131+
auto pool_member = getPoolMember();
132+
auto lt_context = pool_member.getLuaContext();
118133
// lock the lua state mutex
119134
std::lock_guard<std::mutex> lock(lt_context->lua_mutex);
120135
// call the canonicalize function
121136
return lt_context->canon_func(login);
122137
}
123138

124-
CustomFuncReturn custom_func(const std::string& command, const CustomFuncArgs& cfa, bool& reportSinkReturn) {
125-
auto lt_context = getLuaState();
139+
CustomFuncReturn custom_func(const std::string& command, const CustomFuncArgs& cfa, bool& reportSinkReturn)
140+
{
141+
auto pool_member = getPoolMember();
142+
auto lt_context = pool_member.getLuaContext();
126143
// lock the lua state mutex
127144
std::lock_guard<std::mutex> lock(lt_context->lua_mutex);
128145
// call the custom function
129-
for (const auto& i : lt_context->custom_func_map) {
146+
for (const auto& i: lt_context->custom_func_map) {
130147
if (command.compare(i.first) == 0) {
131-
reportSinkReturn = i.second.c_reportSink;
132-
return i.second.c_func(cfa);
148+
reportSinkReturn = i.second.c_reportSink;
149+
return i.second.c_func(cfa);
133150
}
134151
}
135152
return CustomFuncReturn(false, KeyValVector{});
136153
}
137154

138-
std::string custom_get_func(const std::string& command) {
139-
auto lt_context = getLuaState();
155+
std::string custom_get_func(const std::string& command)
156+
{
157+
auto pool_member = getPoolMember();
158+
auto lt_context = pool_member.getLuaContext();
140159
// lock the lua state mutex
141160
std::lock_guard<std::mutex> lock(lt_context->lua_mutex);
142161
// call the custom function
143-
for (const auto& i : lt_context->custom_get_func_map) {
162+
for (const auto& i: lt_context->custom_get_func_map) {
144163
if (command.compare(i.first) == 0) {
145-
return i.second();
164+
return i.second();
146165
}
147166
}
148167
return string();
149168
}
150-
169+
151170
protected:
152-
std::shared_ptr<LuaThreadContext> getLuaState()
153-
{
171+
172+
class SharedPoolMember {
173+
public:
174+
SharedPoolMember(std::shared_ptr<LuaThreadContext> ptr, LuaMultiThread* pool) : d_pool_item(ptr), d_pool(pool) {}
175+
~SharedPoolMember() { if (d_pool != nullptr) { d_pool->returnPoolMember(d_pool_item); } }
176+
SharedPoolMember(const SharedPoolMember&) = delete;
177+
SharedPoolMember& operator=(const SharedPoolMember&) = delete;
178+
std::shared_ptr<LuaThreadContext> getLuaContext() { return d_pool_item; }
179+
private:
180+
std::shared_ptr<LuaThreadContext> d_pool_item;
181+
LuaMultiThread* d_pool;
182+
};
183+
SharedPoolMember getPoolMember() {
184+
std::lock_guard<std::mutex> lock(mutx);
185+
auto member = lua_pool.back();
186+
lua_pool.pop_back();
187+
return SharedPoolMember(member, this);
188+
}
189+
void returnPoolMember(std::shared_ptr<LuaThreadContext> my_ptr) {
154190
std::lock_guard<std::mutex> lock(mutx);
155-
if (state_index >= num_states)
156-
state_index = 0;
157-
return lua_cv[state_index++];
191+
lua_pool.push_back(my_ptr);
158192
}
193+
159194
private:
160-
std::vector<std::shared_ptr<LuaThreadContext>> lua_cv;
195+
std::vector<std::shared_ptr<LuaThreadContext>> lua_pool;
196+
std::vector<std::shared_ptr<LuaThreadContext>> lua_read_only;
161197
unsigned int num_states;
162-
unsigned int state_index;
163198
std::mutex mutx;
164199
};
165200

0 commit comments

Comments
 (0)