2 #include "common/dout.h"
3 #include "rgw_common.h"
5 #include <unordered_map>
7 #include "rgw_lua_utils.h"
8 #include "rgw_realm_reloader.h"
12 //Interval between each execution of the script is set to 5 seconds
13 constexpr const int INIT_EXECUTE_INTERVAL
= 5;
15 //Writeable meta table named RGW with mutex protection
16 using BackgroundMapValue
= std::variant
<std::string
, long long int, double, bool>;
17 using BackgroundMap
= std::unordered_map
<std::string
, BackgroundMapValue
>;
19 inline void pushvalue(lua_State
* L
, const std::string
& value
) {
23 inline void pushvalue(lua_State
* L
, long long value
) {
24 lua_pushinteger(L
, value
);
27 inline void pushvalue(lua_State
* L
, double value
) {
28 lua_pushnumber(L
, value
);
31 inline void pushvalue(lua_State
* L
, bool value
) {
32 lua_pushboolean(L
, value
);
36 struct RGWTable
: EmptyMetaTable
{
38 static const char* INCREMENT
;
39 static const char* DECREMENT
;
41 static std::string
TableName() {return "RGW";}
42 static std::string
Name() {return TableName() + "Meta";}
44 static int increment_by(lua_State
* L
);
46 static int IndexClosure(lua_State
* L
) {
47 const auto map
= reinterpret_cast<BackgroundMap
*>(lua_touserdata(L
, lua_upvalueindex(FIRST_UPVAL
)));
48 auto& mtx
= *reinterpret_cast<std::mutex
*>(lua_touserdata(L
, lua_upvalueindex(SECOND_UPVAL
)));
49 const char* index
= luaL_checkstring(L
, 2);
51 if (strcasecmp(index
, INCREMENT
) == 0) {
52 lua_pushlightuserdata(L
, map
);
53 lua_pushlightuserdata(L
, &mtx
);
54 lua_pushboolean(L
, false /*increment*/);
55 lua_pushcclosure(L
, increment_by
, THREE_UPVALS
);
58 if (strcasecmp(index
, DECREMENT
) == 0) {
59 lua_pushlightuserdata(L
, map
);
60 lua_pushlightuserdata(L
, &mtx
);
61 lua_pushboolean(L
, true /*decrement*/);
62 lua_pushcclosure(L
, increment_by
, THREE_UPVALS
);
66 std::lock_guard
l(mtx
);
68 const auto it
= map
->find(std::string(index
));
69 if (it
== map
->end()) {
72 std::visit([L
](auto&& value
) { pushvalue(L
, value
); }, it
->second
);
77 static int LenClosure(lua_State
* L
) {
78 const auto map
= reinterpret_cast<BackgroundMap
*>(lua_touserdata(L
, lua_upvalueindex(FIRST_UPVAL
)));
79 auto& mtx
= *reinterpret_cast<std::mutex
*>(lua_touserdata(L
, lua_upvalueindex(SECOND_UPVAL
)));
81 std::lock_guard
l(mtx
);
83 lua_pushinteger(L
, map
->size());
88 static int NewIndexClosure(lua_State
* L
) {
89 const auto map
= reinterpret_cast<BackgroundMap
*>(lua_touserdata(L
, lua_upvalueindex(FIRST_UPVAL
)));
90 auto& mtx
= *reinterpret_cast<std::mutex
*>(lua_touserdata(L
, lua_upvalueindex(SECOND_UPVAL
)));
91 const auto index
= luaL_checkstring(L
, 2);
93 if (strcasecmp(index
, INCREMENT
) == 0 || strcasecmp(index
, DECREMENT
) == 0) {
94 return luaL_error(L
, "increment/decrement are reserved function names for RGW");
97 std::unique_lock
l(mtx
);
100 BackgroundMapValue value
;
101 const int value_type
= lua_type(L
, 3);
103 switch (value_type
) {
105 map
->erase(std::string(index
));
108 value
= static_cast<bool>(lua_toboolean(L
, 3));
112 if (lua_isinteger(L
, 3)) {
113 value
= lua_tointeger(L
, 3);
114 len
= sizeof(long long int);
116 value
= lua_tonumber(L
, 3);
117 len
= sizeof(double);
122 const auto str
= lua_tolstring(L
, 3, &len
);
123 value
= std::string
{str
, len
};
128 return luaL_error(L
, "unsupported value type for RGW table");
131 if (len
+ strnlen(index
, MAX_LUA_VALUE_SIZE
)
132 > MAX_LUA_VALUE_SIZE
) {
133 return luaL_error(L
, "Lua maximum size of entry limit exceeded");
134 } else if (map
->size() > MAX_LUA_KEY_ENTRIES
) {
136 return luaL_error(L
, "Lua max number of entries limit exceeded");
138 map
->insert_or_assign(index
, value
);
144 static int PairsClosure(lua_State
* L
) {
145 auto map
= reinterpret_cast<BackgroundMap
*>(lua_touserdata(L
, lua_upvalueindex(FIRST_UPVAL
)));
147 lua_pushlightuserdata(L
, map
);
148 lua_pushcclosure(L
, stateless_iter
, ONE_UPVAL
); // push the stateless iterator function
149 lua_pushnil(L
); // indicate this is the first call
150 // return stateless_iter, nil
152 return TWO_RETURNVALS
;
155 static int stateless_iter(lua_State
* L
) {
156 // based on: http://lua-users.org/wiki/GeneralizedPairsAndIpairs
157 auto map
= reinterpret_cast<BackgroundMap
*>(lua_touserdata(L
, lua_upvalueindex(FIRST_UPVAL
)));
158 typename
BackgroundMap::const_iterator next_it
;
159 if (lua_isnil(L
, -1)) {
160 next_it
= map
->begin();
162 const char* index
= luaL_checkstring(L
, 2);
163 const auto it
= map
->find(std::string(index
));
164 ceph_assert(it
!= map
->end());
165 next_it
= std::next(it
);
168 if (next_it
== map
->end()) {
169 // index of the last element was provided
174 pushstring(L
, next_it
->first
);
175 std::visit([L
](auto&& value
) { pushvalue(L
, value
); }, next_it
->second
);
179 return TWO_RETURNVALS
;
183 class Background
: public RGWRealmReloader::Pauser
{
186 BackgroundMap rgw_map
;
187 bool stopped
= false;
188 bool started
= false;
190 int execute_interval
;
192 std::unique_ptr
<rgw::sal::LuaManager
> lua_manager
;
193 CephContext
* const cct
;
194 const std::string luarocks_path
;
196 mutable std::mutex table_mutex
;
197 std::mutex cond_mutex
;
198 std::mutex pause_mutex
;
199 std::condition_variable cond
;
200 static const BackgroundMapValue empty_table_value
;
205 std::string rgw_script
;
206 virtual int read_script();
209 Background(rgw::sal::Driver
* driver
,
211 const std::string
& luarocks_path
,
212 int execute_interval
= INIT_EXECUTE_INTERVAL
);
214 virtual ~Background() = default;
217 void create_background_metatable(lua_State
* L
);
218 const BackgroundMapValue
& get_table_value(const std::string
& key
) const;
220 void put_table_value(const std::string
& key
, T value
) {
221 std::unique_lock
cond_lock(table_mutex
);
222 rgw_map
[key
] = value
;
225 void pause() override
;
226 void resume(rgw::sal::Driver
* _driver
) override
;
229 } //namepsace rgw::lua