void Background::shutdown(){
this->stop();
- runner.join();
+ if (runner.joinable()) {
+ runner.join();
+ }
}
void Background::stop(){
stopped = true;
}
+void Background::start() {
+ if (started) {
+ // start the thread only once
+ return;
+ }
+ started = true;
+ runner = std::thread(&Background::run, this);
+ const auto rc = ceph_pthread_setname(runner.native_handle(),
+ "lua_background");
+ ceph_assert(rc == 0);
+}
+
+int Background::read_script() {
+ std::string tenant;
+ return rgw::lua::read_script(dpp, store, tenant, null_yield, rgw::lua::context::background, rgw_script);
+}
+
//(1) Loads the script from the object
//(2) Executes the script
//(3) Sleep (configurable)
rgw::lua::lua_state_guard lguard(L);
open_standard_libs(L);
set_package_path(L, luarocks_path);
- create_debug_action(L, cct->get());
+ create_debug_action(L, cct);
create_background_metatable(L);
while (!stopped) {
-
- std::string tenant;
- auto rc = rgw::lua::read_script(dpp, store, tenant, null_yield, rgw::lua::context::background, rgw_script);
+ const auto rc = read_script();
if (rc == -ENOENT) {
// no script, nothing to do
} else if (rc < 0) {
private:
BackgroundMap rgw_map;
- std::string rgw_script;
bool stopped = false;
+ bool started = false;
int execute_interval = INIT_EXECUTE_INTERVAL;
const DoutPrefixProvider* const dpp;
rgw::sal::Store* const store;
CephContext* const cct;
- std::string luarocks_path;
+ const std::string luarocks_path;
std::thread runner;
std::mutex m_mutex;
void run();
+protected:
+ std::string rgw_script;
+ virtual int read_script();
+
public:
Background(const DoutPrefixProvider* dpp,
rgw::sal::Store* store,
dpp(dpp),
store(store),
cct(cct),
- luarocks_path(luarocks_path),
- runner(std::thread(&Background::run, this)) {
- const auto rc = ceph_pthread_setname(runner.native_handle(),
- "lua_background");
- ceph_assert(rc == 0);
- }
+ luarocks_path(luarocks_path) {}
- ~Background() = default;
+ virtual ~Background() = default;
+ void start();
void stop();
void shutdown();
void create_background_metatable(lua_State* L);
#include "rgw/rgw_process.h"
#include "rgw/rgw_sal_rados.h"
#include "rgw/rgw_lua_request.h"
+#include "rgw/rgw_lua_background.h"
using namespace std;
using namespace rgw;
EXPECT_TRUE(olog.logged);
}
+class TestBackground : public rgw::lua::Background {
+protected:
+ int read_script() override {
+ // don't read the object from the store
+ return 0;
+ }
+
+public:
+ TestBackground(const std::string& script) :
+ rgw::lua::Background(nullptr, nullptr, nullptr, "") {
+ // the script is passed in the constructor
+ rgw_script = script;
+ }
+
+ ~TestBackground() override {
+ shutdown();
+ }
+};
+
+TEST(TestRGWLua, Background)
+{
+ {
+ // ctr and dtor without running
+ TestBackground lua_background("");
+ }
+ {
+ // ctr and dtor with running
+ TestBackground lua_background("");
+ lua_background.start();
+ // let the background context run for 5 seconds
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+ }
+}
+
+TEST(TestRGWLua, BackgroundScript)
+{
+ const std::string script = R"(
+ local key = "hello"
+ local value = "world"
+ RGW[key] = value
+ print(RGW[key] == value)
+ )";
+
+ TestBackground lua_background(script);
+ lua_background.start();
+ // let the background context run for 5 seconds
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+}
+
+TEST(TestRGWLua, BackgroundRequestScript)
+{
+ const std::string background_script = R"(
+ local key = "hello"
+ local value = "from background"
+ -- set the value only if not set
+ if RGW[key] == nil then
+ RGW[key] = value
+ end
+ print("from background:", RGW[key])
+ )";
+
+ TestBackground lua_background(background_script);
+ lua_background.start();
+ // let the background context run for 5 seconds
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+
+ const std::string request_script = R"(
+ local key = "hello"
+ local value = "from request"
+ print("from request (before setting):", RGW[key])
+ RGW[key] = value
+ print("from request (after setting):", RGW[key])
+ )";
+
+ DEFINE_REQ_STATE;
+
+ const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "", request_script, &lua_background);
+ ASSERT_EQ(rc, 0);
+ // let the background context run for 5 seconds
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+}
+