11 #include "include/common_fwd.h"
12 #include "rgw_perf_counters.h"
16 // push ceph time in string format: "%Y-%m-%d %H:%M:%S"
17 template <typename CephTime
>
18 void pushtime(lua_State
* L
, const CephTime
& tp
)
20 const auto tt
= CephTime::clock::to_time_t(tp
);
21 const auto tm
= *std::localtime(&tt
);
23 std::strftime(buff
, sizeof(buff
), "%Y-%m-%d %H:%M:%S", &tm
);
24 lua_pushstring(L
, buff
);
27 static inline void pushstring(lua_State
* L
, std::string_view str
)
29 lua_pushlstring(L
, str
.data(), str
.size());
32 static inline void unsetglobal(lua_State
* L
, const char* name
)
35 lua_setglobal(L
, name
);
38 // dump the lua stack to stdout
39 void stack_dump(lua_State
* L
);
41 class lua_state_guard
{
44 lua_state_guard(lua_State
* _l
) : l(_l
) {
46 perfcounter
->inc(l_rgw_lua_current_vms
, 1);
52 perfcounter
->dec(l_rgw_lua_current_vms
, 1);
55 void reset(lua_State
* _l
=nullptr) {l
= _l
;}
58 constexpr const int MAX_LUA_VALUE_SIZE
= 1000;
59 constexpr const int MAX_LUA_KEY_ENTRIES
= 100000;
61 constexpr auto ONE_UPVAL
= 1;
62 constexpr auto TWO_UPVALS
= 2;
63 constexpr auto THREE_UPVALS
= 3;
64 constexpr auto FOUR_UPVALS
= 4;
65 constexpr auto FIVE_UPVALS
= 5;
67 constexpr auto FIRST_UPVAL
= 1;
68 constexpr auto SECOND_UPVAL
= 2;
69 constexpr auto THIRD_UPVAL
= 3;
70 constexpr auto FOURTH_UPVAL
= 4;
71 constexpr auto FIFTH_UPVAL
= 5;
73 constexpr auto NO_RETURNVAL
= 0;
74 constexpr auto ONE_RETURNVAL
= 1;
75 constexpr auto TWO_RETURNVALS
= 2;
76 constexpr auto THREE_RETURNVALS
= 3;
77 constexpr auto FOUR_RETURNVALS
= 4;
78 // utility functions to create a metatable
79 // and tie it to an unnamed table
81 // add an __index method to it, to allow reading values
82 // if "readonly" parameter is set to "false", it will also add
83 // a __newindex method to it, to allow writing values
84 // if the "toplevel" parameter is set to "true", it will name the
85 // table as well as the metatable, this would allow direct access from
88 // The MetaTable is expected to be a class with the following members:
89 // Name (static function returning the unique name of the metatable)
90 // TableName (static function returning the unique name of the table - needed only for "toplevel" tables)
91 // Type (typename) - the type of the "upvalue" (the type that the meta table represent)
92 // IndexClosure (static function return "int" and accept "lua_State*")
93 // NewIndexClosure (static function return "int" and accept "lua_State*")
95 // struct MyStructMetaTable {
96 // static std::string TableName() {
100 // using Type = MyStruct;
102 // static int IndexClosure(lua_State* L) {
103 // const auto value = reinterpret_cast<const Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
107 // static int NewIndexClosure(lua_State* L) {
108 // auto value = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
114 template<typename MetaTable
, typename
... Upvalues
>
115 void create_metatable(lua_State
* L
, bool toplevel
, Upvalues
... upvalues
)
117 constexpr auto upvals_size
= sizeof...(upvalues
);
118 const std::array
<void*, upvals_size
> upvalue_arr
= {upvalues
...};
122 // duplicate the table to make sure it remain in the stack
123 lua_pushvalue(L
, -1);
124 // give table a name (in cae of "toplevel")
125 lua_setglobal(L
, MetaTable::TableName().c_str());
128 [[maybe_unused
]] const auto rc
= luaL_newmetatable(L
, MetaTable::Name().c_str());
129 lua_pushliteral(L
, "__index");
130 for (const auto upvalue
: upvalue_arr
) {
131 lua_pushlightuserdata(L
, upvalue
);
133 lua_pushcclosure(L
, MetaTable::IndexClosure
, upvals_size
);
135 lua_pushliteral(L
, "__newindex");
136 for (const auto upvalue
: upvalue_arr
) {
137 lua_pushlightuserdata(L
, upvalue
);
139 lua_pushcclosure(L
, MetaTable::NewIndexClosure
, upvals_size
);
141 lua_pushliteral(L
, "__pairs");
142 for (const auto upvalue
: upvalue_arr
) {
143 lua_pushlightuserdata(L
, upvalue
);
145 lua_pushcclosure(L
, MetaTable::PairsClosure
, upvals_size
);
147 lua_pushliteral(L
, "__len");
148 for (const auto upvalue
: upvalue_arr
) {
149 lua_pushlightuserdata(L
, upvalue
);
151 lua_pushcclosure(L
, MetaTable::LenClosure
, upvals_size
);
153 // tie metatable and table
154 lua_setmetatable(L
, -2);
157 template<typename MetaTable
>
158 void create_metatable(lua_State
* L
, bool toplevel
, std::unique_ptr
<typename
MetaTable::Type
>& ptr
)
161 create_metatable
<MetaTable
>(L
, toplevel
, reinterpret_cast<void*>(ptr
.get()));
167 // following struct may be used as a base class for other MetaTable classes
168 // note, however, this is not mandatory to use it as a base
169 struct EmptyMetaTable
{
170 // by default everythinmg is "readonly"
171 // to change, overload this function in the derived
172 static int NewIndexClosure(lua_State
* L
) {
173 return luaL_error(L
, "trying to write to readonly field");
176 // by default nothing is iterable
177 // to change, overload this function in the derived
178 static int PairsClosure(lua_State
* L
) {
179 return luaL_error(L
, "trying to iterate over non-iterable field");
182 // by default nothing is iterable
183 // to change, overload this function in the derived
184 static int LenClosure(lua_State
* L
) {
185 return luaL_error(L
, "trying to get length of non-iterable field");
188 static int error_unknown_field(lua_State
* L
, const std::string
& index
, const std::string
& table
) {
189 return luaL_error(L
, "unknown field name: %s provided to: %s",
190 index
.c_str(), table
.c_str());
194 // create a debug log action
195 // it expects CephContext to be captured
196 // it expects one string parameter, which is the message to log
197 // could be executed from any context that has CephContext
199 // RGWDebugLog("hello world from lua")
201 void create_debug_action(lua_State
* L
, CephContext
* cct
);
203 // set the packages search path according to:
204 // package.path = "<install_dir>/share/lua/5.3/?.lua" │ LuaRocks.
205 // package.cpath= "<install_dir>/lib/lua/5.3/?.so"
206 void set_package_path(lua_State
* L
, const std::string
& install_dir
);
208 // open standard lua libs and remove the following functions:
214 // and the "debug" library
215 void open_standard_libs(lua_State
* L
);
217 typedef int MetaTableClosure(lua_State
* L
);
219 template<typename MapType
=std::map
<std::string
, std::string
>>
220 int StringMapWriteableNewIndex(lua_State
* L
) {
221 const auto map
= reinterpret_cast<MapType
*>(lua_touserdata(L
, lua_upvalueindex(FIRST_UPVAL
)));
223 const char* index
= luaL_checkstring(L
, 2);
225 if (lua_isnil(L
, 3) == 0) {
226 const char* value
= luaL_checkstring(L
, 3);
227 if (strnlen(value
, MAX_LUA_VALUE_SIZE
) + strnlen(index
, MAX_LUA_VALUE_SIZE
)
228 > MAX_LUA_VALUE_SIZE
) {
229 return luaL_error(L
, "Lua maximum size of entry limit exceeded");
230 } else if (map
->size() > MAX_LUA_KEY_ENTRIES
) {
231 return luaL_error(L
, "Lua max number of entries limit exceeded");
233 map
->insert_or_assign(index
, value
);
236 map
->erase(std::string(index
));
242 template<typename MapType
=std::map
<std::string
, std::string
>,
243 MetaTableClosure NewIndex
=EmptyMetaTable::NewIndexClosure
>
244 struct StringMapMetaTable
: public EmptyMetaTable
{
246 static std::string
TableName() {return "StringMap";}
247 static std::string
Name() {return TableName() + "Meta";}
249 static int IndexClosure(lua_State
* L
) {
250 const auto map
= reinterpret_cast<MapType
*>(lua_touserdata(L
, lua_upvalueindex(FIRST_UPVAL
)));
252 const char* index
= luaL_checkstring(L
, 2);
254 const auto it
= map
->find(std::string(index
));
255 if (it
== map
->end()) {
258 pushstring(L
, it
->second
);
260 return ONE_RETURNVAL
;
263 static int NewIndexClosure(lua_State
* L
) {
267 static int PairsClosure(lua_State
* L
) {
268 auto map
= reinterpret_cast<MapType
*>(lua_touserdata(L
, lua_upvalueindex(FIRST_UPVAL
)));
270 lua_pushlightuserdata(L
, map
);
271 lua_pushcclosure(L
, stateless_iter
, ONE_UPVAL
); // push the stateless iterator function
272 lua_pushnil(L
); // indicate this is the first call
273 // return stateless_iter, nil
275 return TWO_RETURNVALS
;
278 static int stateless_iter(lua_State
* L
) {
279 // based on: http://lua-users.org/wiki/GeneralizedPairsAndIpairs
280 auto map
= reinterpret_cast<MapType
*>(lua_touserdata(L
, lua_upvalueindex(FIRST_UPVAL
)));
281 typename
MapType::const_iterator next_it
;
282 if (lua_isnil(L
, -1)) {
283 next_it
= map
->begin();
285 const char* index
= luaL_checkstring(L
, 2);
286 const auto it
= map
->find(std::string(index
));
287 ceph_assert(it
!= map
->end());
288 next_it
= std::next(it
);
291 if (next_it
== map
->end()) {
292 // index of the last element was provided
297 pushstring(L
, next_it
->first
);
298 pushstring(L
, next_it
->second
);
302 return TWO_RETURNVALS
;
305 static int LenClosure(lua_State
* L
) {
306 const auto map
= reinterpret_cast<MapType
*>(lua_touserdata(L
, lua_upvalueindex(FIRST_UPVAL
)));
308 lua_pushinteger(L
, map
->size());
310 return ONE_RETURNVAL
;
314 } // namespace rgw::lua