]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_lua_background.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rgw / rgw_lua_background.h
1 #pragma once
2 #include "common/dout.h"
3 #include "rgw_common.h"
4 #include <string>
5 #include <unordered_map>
6 #include <variant>
7 #include "rgw_lua_utils.h"
8 #include "rgw_realm_reloader.h"
9
10 namespace rgw::lua {
11
12 //Interval between each execution of the script is set to 5 seconds
13 constexpr const int INIT_EXECUTE_INTERVAL = 5;
14
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>;
18
19 inline void pushvalue(lua_State* L, const std::string& value) {
20 pushstring(L, value);
21 }
22
23 inline void pushvalue(lua_State* L, long long value) {
24 lua_pushinteger(L, value);
25 }
26
27 inline void pushvalue(lua_State* L, double value) {
28 lua_pushnumber(L, value);
29 }
30
31 inline void pushvalue(lua_State* L, bool value) {
32 lua_pushboolean(L, value);
33 }
34
35
36 struct RGWTable : EmptyMetaTable {
37
38 static const char* INCREMENT;
39 static const char* DECREMENT;
40
41 static std::string TableName() {return "RGW";}
42 static std::string Name() {return TableName() + "Meta";}
43
44 static int increment_by(lua_State* L);
45
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);
50
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);
56 return ONE_RETURNVAL;
57 }
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);
63 return ONE_RETURNVAL;
64 }
65
66 std::lock_guard l(mtx);
67
68 const auto it = map->find(std::string(index));
69 if (it == map->end()) {
70 lua_pushnil(L);
71 } else {
72 std::visit([L](auto&& value) { pushvalue(L, value); }, it->second);
73 }
74 return ONE_RETURNVAL;
75 }
76
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)));
80
81 std::lock_guard l(mtx);
82
83 lua_pushinteger(L, map->size());
84
85 return ONE_RETURNVAL;
86 }
87
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);
92
93 if (strcasecmp(index, INCREMENT) == 0 || strcasecmp(index, DECREMENT) == 0) {
94 return luaL_error(L, "increment/decrement are reserved function names for RGW");
95 }
96
97 std::unique_lock l(mtx);
98
99 size_t len;
100 BackgroundMapValue value;
101 const int value_type = lua_type(L, 3);
102
103 switch (value_type) {
104 case LUA_TNIL:
105 map->erase(std::string(index));
106 return NO_RETURNVAL;
107 case LUA_TBOOLEAN:
108 value = static_cast<bool>(lua_toboolean(L, 3));
109 len = sizeof(bool);
110 break;
111 case LUA_TNUMBER:
112 if (lua_isinteger(L, 3)) {
113 value = lua_tointeger(L, 3);
114 len = sizeof(long long int);
115 } else {
116 value = lua_tonumber(L, 3);
117 len = sizeof(double);
118 }
119 break;
120 case LUA_TSTRING:
121 {
122 const auto str = lua_tolstring(L, 3, &len);
123 value = std::string{str, len};
124 break;
125 }
126 default:
127 l.unlock();
128 return luaL_error(L, "unsupported value type for RGW table");
129 }
130
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) {
135 l.unlock();
136 return luaL_error(L, "Lua max number of entries limit exceeded");
137 } else {
138 map->insert_or_assign(index, value);
139 }
140
141 return NO_RETURNVAL;
142 }
143
144 static int PairsClosure(lua_State* L) {
145 auto map = reinterpret_cast<BackgroundMap*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
146 ceph_assert(map);
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
151
152 return TWO_RETURNVALS;
153 }
154
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();
161 } else {
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);
166 }
167
168 if (next_it == map->end()) {
169 // index of the last element was provided
170 lua_pushnil(L);
171 lua_pushnil(L);
172 // return nil, nil
173 } else {
174 pushstring(L, next_it->first);
175 std::visit([L](auto&& value) { pushvalue(L, value); }, next_it->second);
176 // return key, value
177 }
178
179 return TWO_RETURNVALS;
180 }
181 };
182
183 class Background : public RGWRealmReloader::Pauser {
184
185 private:
186 BackgroundMap rgw_map;
187 bool stopped = false;
188 bool started = false;
189 bool paused = false;
190 int execute_interval;
191 const DoutPrefix dp;
192 std::unique_ptr<rgw::sal::LuaManager> lua_manager;
193 CephContext* const cct;
194 const std::string luarocks_path;
195 std::thread runner;
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;
201
202 void run();
203
204 protected:
205 std::string rgw_script;
206 virtual int read_script();
207
208 public:
209 Background(rgw::sal::Driver* driver,
210 CephContext* cct,
211 const std::string& luarocks_path,
212 int execute_interval = INIT_EXECUTE_INTERVAL);
213
214 virtual ~Background() = default;
215 void start();
216 void shutdown();
217 void create_background_metatable(lua_State* L);
218 const BackgroundMapValue& get_table_value(const std::string& key) const;
219 template<typename T>
220 void put_table_value(const std::string& key, T value) {
221 std::unique_lock cond_lock(table_mutex);
222 rgw_map[key] = value;
223 }
224
225 void pause() override;
226 void resume(rgw::sal::Driver* _driver) override;
227 };
228
229 } //namepsace rgw::lua
230