]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: Lua scripting global map feature
authorMatan Breizman <Matan.Brz@gmail.com>
Sat, 14 Aug 2021 21:01:49 +0000 (21:01 +0000)
committerYuval Lifshitz <ylifshit@redhat.com>
Sun, 8 May 2022 11:10:32 +0000 (14:10 +0300)
Adding a lua background class. This class aims to allow to run a background
Lua script and bind a shared Lua table with a cpp map.

Signed-off-by: Matan Breizman <Matan.Brz@gmail.com>
16 files changed:
doc/radosgw/lua-scripting.rst
src/rgw/CMakeLists.txt
src/rgw/rgw_admin.cc
src/rgw/rgw_asio_frontend.cc
src/rgw/rgw_loadgen_process.cc
src/rgw/rgw_lua.cc
src/rgw/rgw_lua.h
src/rgw/rgw_lua_background.cc [new file with mode: 0644]
src/rgw/rgw_lua_background.h [new file with mode: 0644]
src/rgw/rgw_lua_request.cc
src/rgw/rgw_lua_request.h
src/rgw/rgw_lua_utils.h
src/rgw/rgw_main.cc
src/rgw/rgw_process.cc
src/rgw/rgw_process.h
src/test/cli/radosgw-admin/help.t

index 31306dec98acea3c2d8e46faabf56b2b5dfcf2ac..0732ee67fee0b926f734391226d336cf3008425f 100644 (file)
@@ -6,9 +6,10 @@ Lua Scripting
 
 .. contents::
 
-This feature allows users to upload Lua scripts to different context in the radosgw. The two supported context are "preRequest" that will execute a script before the
-operation was taken, and "postRequest" that will execute after each operation is taken. Script may be uploaded to address requests for users of a specific tenant.
-The script can access fields in the request and modify some fields. All Lua language features can be used in the script.
+This feature allows users to upload Lua scripts to different context in the radosgw. The three supported contexts are "preRequest" that will execute a script before the
+operation was taken, "postRequest" that will execute after each operation is taken and "background" that will execute a script in a given time interval.
+Request context script may be uploaded to address requests for users of a specific tenant.
+The request context script can also access fields in the request and modify some fields. All Lua language features can be used in the script.
 
 By default, all lua standard libraries are available in the script, however, in order to allow for other lua modules to be used in the script, we support adding packages to an allowlist:
 
@@ -28,23 +29,27 @@ Script Management via CLI
 
 To upload a script:
    
+
 ::
    
-   # radosgw-admin script put --infile={lua-file} --context={preRequest|postRequest} [--tenant={tenant-name}]
+   # radosgw-admin script put --infile={lua-file} --context={preRequest|postRequest|background} [--tenant={tenant-name}]
+
+
+* When uploading a script in background context, tenant name could not be specified.
 
 
 To print the content of the script to standard output:
 
 ::
    
-   # radosgw-admin script get --context={preRequest|postRequest} [--tenant={tenant-name}]
+   # radosgw-admin script get --context={preRequest|postRequest|background} [--tenant={tenant-name}]
 
 
 To remove the script:
 
 ::
    
-   # radosgw-admin script rm --context={preRequest|postRequest} [--tenant={tenant-name}]
+   # radosgw-admin script rm --context={preRequest|postRequest|background} [--tenant={tenant-name}]
 
 
 Package Management via CLI
@@ -297,6 +302,23 @@ Operations Log
 ~~~~~~~~~~~~~~
 The ``Request.Log()`` function prints the requests into the operations log. This function has no parameters. It returns 0 for success and an error code if it fails.
 
+Background Context
+--------------------
+The background context may be used for various need such as analytics, monitoring and
+caching data from other context executions.
+
+The ``RGW`` Lua table which is accesible from any context saves the data written into it
+while execution and this data could be read and used later in any other execution.
+
+- Background script execution default interval is 5 seconds.
+
+- Each RGW instance has its own ``RGW`` Lua table, while the Background Context script
+  will run on every instance.
+
+- The maximum number of entries in the table is 100,000. Each entry has a key and string value
+  of no more than 1KB (together). Lua script will abort with an error if the
+  number of entries or entry size exceeds their limits.
+
 Lua Code Samples
 ----------------
 - Print information on source and destination objects in case of copy:
index 3f569deb20bbe4912edd407376720e35b687c44b..2297d575b21771912758b94c8995072341156aa1 100644 (file)
@@ -162,7 +162,8 @@ set(librgw_common_srcs
   rgw_lua_utils.cc
   rgw_lua.cc
   rgw_bucket_encryption.cc
-  rgw_tracer.cc)
+  rgw_tracer.cc
+  rgw_lua_background.cc)
 
 if(WITH_RADOSGW_AMQP_ENDPOINT)
   list(APPEND librgw_common_srcs rgw_amqp.cc)
@@ -357,7 +358,10 @@ add_library(radosgw SHARED
 target_compile_definitions(radosgw PUBLIC "-DCLS_CLIENT_HIDE_IOCTX")
 target_include_directories(radosgw
   PUBLIC "${CMAKE_SOURCE_DIR}/src/dmclock/support/src"
-  PRIVATE "${CMAKE_SOURCE_DIR}/src/libkmip")
+  PRIVATE "${CMAKE_SOURCE_DIR}/src/libkmip"
+  PUBLIC "${CMAKE_SOURCE_DIR}/src/rgw"
+  PRIVATE "${LUA_INCLUDE_DIR}")
+
 target_include_directories(radosgw SYSTEM PUBLIC "../rapidjson/include")
 
 target_link_libraries(radosgw
index 5a7b113e84f21f6b3f2100c408c7408d3ade5488..36fbd06e5d7aab18945da868e9c09321aabb7170 100644 (file)
@@ -454,7 +454,7 @@ void usage()
   cout << "   --subscription            pubsub subscription name\n";
   cout << "   --event-id                event id in a pubsub subscription\n";
   cout << "\nScript options:\n";
-  cout << "   --context                 context in which the script runs. one of: preRequest, postRequest\n";
+  cout << "   --context                 context in which the script runs. one of: preRequest, postRequest, background\n";
   cout << "   --package                 name of the lua package that should be added/removed to/from the allowlist\n";
   cout << "   --allow-compilation       package is allowed to compile C code as part of its installation\n";
   cout << "\nradoslist options:\n";
@@ -10037,7 +10037,11 @@ next:
     }
     const rgw::lua::context script_ctx = rgw::lua::to_context(*str_script_ctx);
     if (script_ctx == rgw::lua::context::none) {
-      cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest" <<  std::endl;
+      cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest, background" << std::endl;
+      return EINVAL;
+    }
+    if (script_ctx == rgw::lua::context::background && !tenant.empty()) {
+      cerr << "ERROR: cannot specify tenant in background context" << std::endl;
       return EINVAL;
     }
     rc = rgw::lua::write_script(dpp(), store, tenant, null_yield, script_ctx, script);
@@ -10054,7 +10058,7 @@ next:
     }
     const rgw::lua::context script_ctx = rgw::lua::to_context(*str_script_ctx);
     if (script_ctx == rgw::lua::context::none) {
-      cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest" <<  std::endl;
+      cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest, background" << std::endl;
       return EINVAL;
     }
     std::string script;
@@ -10077,7 +10081,7 @@ next:
     }
     const rgw::lua::context script_ctx = rgw::lua::to_context(*str_script_ctx);
     if (script_ctx == rgw::lua::context::none) {
-      cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest" <<  std::endl;
+      cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest, background" << std::endl;
       return EINVAL;
     }
     const auto rc = rgw::lua::delete_script(dpp(), store, tenant, null_yield, script_ctx);
index c368b719ef6310ad48fe16cc14dafcc2d2bd693a..2d6e3a3259eed9973972621839c4221f34542b1e 100644 (file)
@@ -269,7 +269,7 @@ void handle_connection(boost::asio::io_context& context,
                       *env.auth_registry, &client, env.olog, y,
                       scheduler, &user, &latency,
                       env.ratelimiting->get_active(),
-                      &http_ret);
+                      &http_ret, env.lua_background);
 
       if (cct->_conf->subsys.should_gather(dout_subsys, 1)) {
         // access log line elements begin per Apache Combined Log Format with additions following
index 27078f04c4e89d1ff5f22ac44e7ec1a1596950f6..38b7510974360f166a8b552ed848814e0e8ec1ee 100644 (file)
@@ -137,7 +137,7 @@ void RGWLoadGenProcess::handle_request(const DoutPrefixProvider *dpp, RGWRequest
   int ret = process_request(store, rest, req, uri_prefix,
                             *auth_registry, &client_io, olog,
                             null_yield, nullptr, nullptr, nullptr,
-                            ratelimit.get_active());
+                            ratelimit.get_active(), nullptr);
   if (ret < 0) {
     /* we don't really care about return code */
     dout(20) << "process_request() returned " << ret << dendl;
index 83c834877efad355970095f27e1a08cbd04c3c50..323cc5ed0f62deecad445f4844198f2941f1f8f6 100644 (file)
@@ -23,6 +23,9 @@ context to_context(const std::string& s)
   if (strcasecmp(s.c_str(), "postrequest") == 0) {
     return context::postRequest;
   }
+  if (strcasecmp(s.c_str(), "background") == 0) {
+    return context::background;
+  }
   return context::none;
 }
 
@@ -33,6 +36,8 @@ std::string to_string(context ctx)
       return "prerequest";
     case context::postRequest:
       return "postrequest";
+    case context::background:
+      return "background";
     case context::none:
       break;
   }
index 3bb0603d9569420474e4c00ccac0f9816d72a1dd..2fd920a36e79b339660e816fcbbde758b5d066f8 100644 (file)
@@ -15,6 +15,7 @@ namespace rgw::lua {
 enum class context {
   preRequest,
   postRequest,
+  background,
   none
 };
 
diff --git a/src/rgw/rgw_lua_background.cc b/src/rgw/rgw_lua_background.cc
new file mode 100644 (file)
index 0000000..2c85cab
--- /dev/null
@@ -0,0 +1,56 @@
+#include "rgw_lua_background.h"
+#include "rgw_lua.h"
+#include "rgw_lua_utils.h"
+#include "include/ceph_assert.h"
+#include <lua.hpp>
+
+namespace rgw::lua {
+
+void Background::shutdown(){
+  this->stop();
+  runner.join();
+}
+void Background::stop(){
+  stopped = true;
+}
+
+//(1) Loads the script from the object
+//(2) Executes the script
+//(3) Sleep (configurable)
+void Background::run() {
+  lua_State* const L = luaL_newstate();
+  rgw::lua::lua_state_guard lguard(L);
+  open_standard_libs(L);
+  set_package_path(L, luarocks_path);
+  create_debug_action(L, cct->get());
+  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);
+    if (rc == -ENOENT) {
+      // no script, nothing to do
+    } else if (rc < 0) {
+      ldpp_dout(dpp, 1) << "WARNING: failed to read background script. error " << rc << dendl;
+    } else {
+      try {
+        //execute the background lua script
+        if (luaL_dostring(L, rgw_script.c_str()) != LUA_OK) {
+          const std::string err(lua_tostring(L, -1));
+          ldpp_dout(dpp, 1) << "Lua ERROR: " << err << dendl;
+        }
+      } catch (const std::exception& e) {
+         ldpp_dout(dpp, 1) << "Lua ERROR: " << e.what() << dendl;
+      }
+    }
+    std::this_thread::sleep_for(std::chrono::seconds(execute_interval));
+  }
+}
+
+void Background::create_background_metatable(lua_State* L) {
+  create_metatable<rgw::lua::RGWTable>(L, true, &rgw_map, &m_mutex);
+}
+
+} //namespace lua
+
diff --git a/src/rgw/rgw_lua_background.h b/src/rgw/rgw_lua_background.h
new file mode 100644 (file)
index 0000000..8c33171
--- /dev/null
@@ -0,0 +1,73 @@
+#pragma once
+#include "common/dout.h"
+#include "rgw_common.h"
+#include <string>
+#include "rgw_lua_utils.h"
+
+namespace rgw::lua {
+
+//Interval between each execution of the script is set to 5 seconds
+constexpr const int INIT_EXECUTE_INTERVAL = 5;
+
+//Writeable meta table named RGW with mutex protection
+using BackgroundMap = std::unordered_map<std::string, std::string>;
+struct RGWTable : StringMapMetaTable<BackgroundMap,
+  StringMapWriteableNewIndex<BackgroundMap>> {
+    static std::string TableName() {return "RGW";}
+    static std::string Name() {return TableName() + "Meta";}
+    static int IndexClosure(lua_State* L) {
+      auto& mtx = *reinterpret_cast<std::mutex*>(lua_touserdata(L, lua_upvalueindex(2)));
+      std::lock_guard l(mtx);
+      return StringMapMetaTable::IndexClosure(L);
+    }
+    static int LenClosure(lua_State* L) {
+      auto& mtx = *reinterpret_cast<std::mutex*>(lua_touserdata(L, lua_upvalueindex(2)));
+      std::lock_guard l(mtx);
+      return StringMapMetaTable::LenClosure(L);
+    }
+    static int NewIndexClosure(lua_State* L) {
+      auto& mtx = *reinterpret_cast<std::mutex*>(lua_touserdata(L, lua_upvalueindex(2)));
+      std::lock_guard l(mtx);
+      return StringMapMetaTable::NewIndexClosure(L);
+    }
+};
+
+class Background {
+
+private:
+  BackgroundMap rgw_map;
+  std::string rgw_script;
+  bool stopped = false;
+  int execute_interval = INIT_EXECUTE_INTERVAL;
+  const DoutPrefixProvider* const dpp;
+  rgw::sal::Store* const store;
+  CephContext* const cct;
+  std::string luarocks_path;
+  std::thread runner;
+  std::mutex m_mutex;
+
+  void run();
+
+public:
+  Background(const DoutPrefixProvider* dpp,
+      rgw::sal::Store* store,
+      CephContext* cct,
+      const std::string& luarocks_path) :
+    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);
+    }
+
+    ~Background() = default;
+    void stop();
+    void shutdown();
+    void create_background_metatable(lua_State* L);
+};
+
+} //namepsace lua
+
index d6021b2a91d9799304e0bea11c121fa9b5155191..1904337128cdb836af4628cb8dfcf791690fa984 100644 (file)
@@ -11,6 +11,7 @@
 #include "rgw_zone.h"
 #include "rgw_acl.h"
 #include "rgw_sal_rados.h"
+#include "rgw_lua_background.h"
 
 #define dout_subsys ceph_subsys_rgw
 
@@ -241,90 +242,6 @@ struct ObjectMetaTable : public EmptyMetaTable {
   }
 };
 
-typedef int MetaTableClosure(lua_State* L);
-
-template<typename MapType>
-int StringMapWriteableNewIndex(lua_State* L) {
-  const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
-
-  const char* index = luaL_checkstring(L, 2);
-  const char* value = luaL_checkstring(L, 3);
-  map->insert_or_assign(index, value);
-  return NO_RETURNVAL;
-}
-
-template<typename MapType=std::map<std::string, std::string>,
-  MetaTableClosure NewIndex=EmptyMetaTable::NewIndexClosure>
-struct StringMapMetaTable : public EmptyMetaTable {
-
-  static std::string TableName() {return "StringMap";}
-  static std::string Name() {return TableName() + "Meta";}
-
-  static int IndexClosure(lua_State* L) {
-    const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
-
-    const char* index = luaL_checkstring(L, 2);
-
-    const auto it = map->find(std::string(index));
-    if (it == map->end()) {
-      lua_pushnil(L);
-    } else {
-      pushstring(L, it->second);
-    }
-    return ONE_RETURNVAL;
-  }
-
-  static int NewIndexClosure(lua_State* L) {
-    return NewIndex(L);
-  }
-
-  static int PairsClosure(lua_State* L) {
-    auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
-    ceph_assert(map);
-    lua_pushlightuserdata(L, map);
-    lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
-    lua_pushnil(L);                                 // indicate this is the first call
-    // return stateless_iter, nil
-
-    return TWO_RETURNVALS;
-  }
-  
-  static int stateless_iter(lua_State* L) {
-    // based on: http://lua-users.org/wiki/GeneralizedPairsAndIpairs
-    auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
-    typename MapType::const_iterator next_it;
-    if (lua_isnil(L, -1)) {
-      next_it = map->begin();
-    } else {
-      const char* index = luaL_checkstring(L, 2);
-      const auto it = map->find(std::string(index));
-      ceph_assert(it != map->end());
-      next_it = std::next(it);
-    }
-
-    if (next_it == map->end()) {
-      // index of the last element was provided
-      lua_pushnil(L);
-      lua_pushnil(L);
-      // return nil, nil
-    } else {
-      pushstring(L, next_it->first);
-      pushstring(L, next_it->second);
-      // return key, value
-    }
-
-    return TWO_RETURNVALS;
-  }
-
-  static int LenClosure(lua_State* L) {
-    const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
-
-    lua_pushinteger(L, map->size());
-
-    return ONE_RETURNVAL;
-  }
-};
-
 struct GrantMetaTable : public EmptyMetaTable {
   static std::string TableName() {return "Grant";}
   static std::string Name() {return TableName() + "Meta";}
@@ -799,7 +716,8 @@ int execute(
     OpsLogSink* olog,
     req_state* s, 
     const char* op_name,
-    const std::string& script)
+    const std::string& script,
+    rgw::lua::Background* background)
 
 {
   auto L = luaL_newstate();
@@ -811,12 +729,13 @@ int execute(
       "");
 
   create_debug_action(L, s->cct);  
-
-  create_metatable<RequestMetaTable>(L, true, s, const_cast<char*>(op_name));
   
-  // add the ops log action
+  create_metatable<RequestMetaTable>(L, true, s, const_cast<char*>(op_name));
+
   lua_getglobal(L, RequestMetaTable::TableName().c_str());
   ceph_assert(lua_istable(L, -1));
+
+  // add the ops log action
   pushstring(L, RequestLogAction);
   lua_pushlightuserdata(L, rest);
   lua_pushlightuserdata(L, olog);
@@ -824,6 +743,12 @@ int execute(
   lua_pushlightuserdata(L, const_cast<char*>(op_name));
   lua_pushcclosure(L, RequestLog, FOUR_UPVALS);
   lua_rawset(L, -3);
+  
+  if (background) {
+    background->create_background_metatable(L);
+    lua_getglobal(L, rgw::lua::RGWTable::TableName().c_str());
+    ceph_assert(lua_istable(L, -1));
+  }
 
   try {
     // execute the lua script
index fcf0673f3ba7b5bb71c9cca394c9cd5f1bf3b642..d1410b584ff0ac73650346581e336bef483fa0e1 100644 (file)
@@ -9,6 +9,9 @@ class OpsLogSink;
 namespace rgw::sal {
   class Store;
 }
+namespace rgw::lua {
+  class Background;
+}
 
 namespace rgw::lua::request {
 
@@ -19,7 +22,8 @@ int execute(
     OpsLogSink* olog,
     req_state *s, 
     const char* op_name,
-    const std::string& script);
+    const std::string& script,
+    rgw::lua::Background* background = nullptr);
 
 }
 
index ac4ec4799e4070b5e14d2239b7121d816b8d54af..fb3cb5dcc62982c7a0416cca7c0f4e04277d1fc0 100644 (file)
@@ -43,6 +43,9 @@ public:
   void reset(lua_State* _l=nullptr) {l = _l;}
 };
 
+constexpr const int MAX_LUA_VALUE_SIZE = 1000;
+constexpr const int MAX_LUA_KEY_ENTRIES = 100000;
+
 constexpr auto ONE_UPVAL    = 1;
 constexpr auto TWO_UPVALS   = 2;
 constexpr auto THREE_UPVALS = 3;
@@ -193,5 +196,101 @@ void set_package_path(lua_State* L, const std::string& install_dir);
 // and the "debug" library
 void open_standard_libs(lua_State* L);
 
+typedef int MetaTableClosure(lua_State* L);
+
+template<typename MapType>
+int StringMapWriteableNewIndex(lua_State* L) {
+  const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
+
+  const char* index = luaL_checkstring(L, 2);
+
+  if (lua_isnil(L, 3) == 0) {
+    const char* value = luaL_checkstring(L, 3);
+    if (strnlen(value, MAX_LUA_VALUE_SIZE) + strnlen(index, MAX_LUA_VALUE_SIZE)
+        > MAX_LUA_VALUE_SIZE) {
+      return luaL_error(L, "Lua maximum size of entry limit exceeded");
+    } else if (map->size() > MAX_LUA_KEY_ENTRIES) {
+      return luaL_error(L, "Lua max number of entries limit exceeded");
+    } else {
+      map->insert_or_assign(index, value);
+    }
+  } else {
+    map->erase(std::string(index));
+  }
+
+  return NO_RETURNVAL;
+}
+
+template<typename MapType=std::map<std::string, std::string>,
+  MetaTableClosure NewIndex=EmptyMetaTable::NewIndexClosure>
+struct StringMapMetaTable : public EmptyMetaTable {
+
+  static std::string TableName() {return "StringMap";}
+  static std::string Name() {return TableName() + "Meta";}
+
+  static int IndexClosure(lua_State* L) {
+    const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
+
+    const char* index = luaL_checkstring(L, 2);
+
+    const auto it = map->find(std::string(index));
+    if (it == map->end()) {
+      lua_pushnil(L);
+    } else {
+        pushstring(L, it->second);
+    }
+    return ONE_RETURNVAL;
+  }
+
+  static int NewIndexClosure(lua_State* L) {
+    return NewIndex(L);
+  }
+
+  static int PairsClosure(lua_State* L) {
+    auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
+    ceph_assert(map);
+    lua_pushlightuserdata(L, map);
+    lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
+    lua_pushnil(L);                                 // indicate this is the first call
+    // return stateless_iter, nil
+
+    return TWO_RETURNVALS;
+  }
+  
+  static int stateless_iter(lua_State* L) {
+    // based on: http://lua-users.org/wiki/GeneralizedPairsAndIpairs
+    auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
+    typename MapType::const_iterator next_it;
+    if (lua_isnil(L, -1)) {
+      next_it = map->begin();
+    } else {
+      const char* index = luaL_checkstring(L, 2);
+      const auto it = map->find(std::string(index));
+      ceph_assert(it != map->end());
+      next_it = std::next(it);
+    }
+
+    if (next_it == map->end()) {
+      // index of the last element was provided
+      lua_pushnil(L);
+      lua_pushnil(L);
+      // return nil, nil
+    } else {
+      pushstring(L, next_it->first);
+      pushstring(L, next_it->second);
+      // return key, value
+    }
+
+    return TWO_RETURNVALS;
+  }
+
+  static int LenClosure(lua_State* L) {
+    const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
+
+    lua_pushinteger(L, map->size());
+
+    return ONE_RETURNVAL;
+  }
+};
 }
 
index f2fc502a70fb9ed6cbe7545d2ef8a41758785858..dd537c0d023d0de2894eb7389b33ebcf91197db8 100644 (file)
@@ -58,6 +58,7 @@
 #ifdef WITH_RADOSGW_DBSTORE
 #include "rgw_sal_dbstore.h"
 #endif
+#include "rgw_lua_background.h"
 
 #include "services/svc_zone.h"
 
@@ -605,6 +606,8 @@ int radosgw_Main(int argc, const char **argv)
 
   int fe_count = 0;
 
+  rgw::lua::Background lua_background(&dp, store, cct.get(), store->get_luarocks_path());
+
   for (multimap<string, RGWFrontendConfig *>::iterator fiter = fe_map.begin();
        fiter != fe_map.end(); ++fiter, ++fe_count) {
     RGWFrontendConfig *config = fiter->second;
@@ -623,7 +626,8 @@ int radosgw_Main(int argc, const char **argv)
       std::string uri_prefix;
       config->get_val("prefix", "", &uri_prefix);
 
-      RGWProcessEnv env = { store, &rest, olog, port, uri_prefix, auth_registry, &ratelimiting };
+      RGWProcessEnv env = { store, &rest, olog, port, uri_prefix, 
+                            auth_registry, &ratelimiting, &lua_background};
 
       fe = new RGWLoadGenFrontend(env, config);
     }
@@ -632,7 +636,8 @@ int radosgw_Main(int argc, const char **argv)
       config->get_val("port", 80, &port);
       std::string uri_prefix;
       config->get_val("prefix", "", &uri_prefix);
-      RGWProcessEnv env{ store, &rest, olog, port, uri_prefix, auth_registry, &ratelimiting };
+      RGWProcessEnv env{ store, &rest, olog, port, uri_prefix, 
+                         auth_registry, &ratelimiting, &lua_background};
       fe = new RGWAsioFrontend(env, config, sched_ctx);
     }
 
@@ -740,6 +745,8 @@ int radosgw_Main(int argc, const char **argv)
   rgw::kafka::shutdown();
 #endif
 
+  lua_background.shutdown();
+
   rgw_perf_stop(g_ceph_context);
 
   dout(1) << "final shutdown" << dendl;
index 77ef102d30c1d3f0afe01256d35737ca2a8a3ee8..9b76046ce456d7fda206e813ea849561c134312e 100644 (file)
@@ -273,10 +273,10 @@ int process_request(rgw::sal::Store* const store,
                     string* user,
                     ceph::coarse_real_clock::duration* latency,
                     std::shared_ptr<RateLimiter> ratelimit,
-                    int* http_ret)
+                    int* http_ret,
+                    rgw::lua::Background* lua_background)
 {
   int ret = client_io->init(g_ceph_context);
-
   dout(1) << "====== starting new request req=" << hex << req << dec
          << " =====" << dendl;
   perfcounter->inc(l_rgw_req);
@@ -335,7 +335,7 @@ int process_request(rgw::sal::Store* const store,
     } else if (rc < 0) {
       ldpp_dout(op, 5) << "WARNING: failed to read pre request script. error: " << rc << dendl;
     } else {
-      rc = rgw::lua::request::execute(store, rest, olog, s, op->name(), script);
+      rc = rgw::lua::request::execute(store, rest, olog, s, op->name(), script, lua_background);
       if (rc < 0) {
         ldpp_dout(op, 5) << "WARNING: failed to execute pre request script. error: " << rc << dendl;
       }
@@ -417,7 +417,7 @@ done:
     } else if (rc < 0) {
       ldpp_dout(op, 5) << "WARNING: failed to read post request script. error: " << rc << dendl;
     } else {
-      rc = rgw::lua::request::execute(store, rest, olog, s, op->name(), script);
+      rc = rgw::lua::request::execute(store, rest, olog, s, op->name(), script, lua_background);
       if (rc < 0) {
         ldpp_dout(op, 5) << "WARNING: failed to execute post request script. error: " << rc << dendl;
       }
index edf76a443e30f4f66d50d8998aff61ec670c5074..c40a9beaf3beea64e781fb5ad9775db2d8082549 100644 (file)
@@ -30,6 +30,9 @@ extern void signal_shutdown();
 namespace rgw::dmclock {
   class Scheduler;
 }
+namespace rgw::lua {
+  class Background;
+}
 
 struct RGWProcessEnv {
   rgw::sal::Store* store;
@@ -40,6 +43,7 @@ struct RGWProcessEnv {
   std::shared_ptr<rgw::auth::StrategyRegistry> auth_registry;
   //maybe there is a better place to store the rate limit data structure
   ActiveRateLimiter* ratelimiting;
+  rgw::lua::Background* lua_background;
 };
 
 class RGWFrontendConfig;
@@ -58,6 +62,7 @@ protected:
   RGWFrontendConfig* conf;
   int sock_fd;
   std::string uri_prefix;
+  rgw::lua::Background* lua_background;
 
   struct RGWWQ : public DoutPrefixProvider, public ThreadPool::WorkQueue<RGWRequest> {
     RGWProcess* process;
@@ -109,6 +114,7 @@ public:
       conf(conf),
       sock_fd(-1),
       uri_prefix(pe->uri_prefix),
+      lua_background(pe->lua_background),
       req_wq(this,
             ceph::make_timespan(g_conf()->rgw_op_thread_timeout),
             ceph::make_timespan(g_conf()->rgw_op_thread_suicide_timeout),
@@ -177,7 +183,8 @@ extern int process_request(rgw::sal::Store* store,
                            std::string* user,
                            ceph::coarse_real_clock::duration* latency,
                            std::shared_ptr<RateLimiter> ratelimit,
-                           int* http_ret = nullptr);
+                           int* http_ret = nullptr,
+                           rgw::lua::Background* lua_background = nullptr);
 
 extern int rgw_process_authenticated(RGWHandler_REST* handler,
                                      RGWOp*& op,
index 6784b966ca4451939bc1f2f3dacf2182cda8218e..7029266ea0f55480b22a302f6122c9eaae860970 100644 (file)
      --event-id                event id in a pubsub subscription
   
   Script options:
-     --context                 context in which the script runs. one of: preRequest, postRequest
+     --context                 context in which the script runs. one of: preRequest, postRequest, background
      --package                 name of the lua package that should be added/removed to/from the allowlist
      --allow-compilation       package is allowed to compile C code as part of its installation