You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by hu...@apache.org on 2012/08/05 21:57:45 UTC

svn commit: r1369656 - in /httpd/httpd/trunk/modules/lua: lua_vmprep.c lua_vmprep.h mod_lua.c mod_lua.h

Author: humbedooh
Date: Sun Aug  5 19:57:44 2012
New Revision: 1369656

URL: http://svn.apache.org/viewvc?rev=1369656&view=rev
Log:
Add a server scope for Lua states (in LuaScope), which creates a pool of  states with manageable minimum and maximum size.

Modified:
    httpd/httpd/trunk/modules/lua/lua_vmprep.c
    httpd/httpd/trunk/modules/lua/lua_vmprep.h
    httpd/httpd/trunk/modules/lua/mod_lua.c
    httpd/httpd/trunk/modules/lua/mod_lua.h

Modified: httpd/httpd/trunk/modules/lua/lua_vmprep.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/lua/lua_vmprep.c?rev=1369656&r1=1369655&r2=1369656&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/lua/lua_vmprep.c (original)
+++ httpd/httpd/trunk/modules/lua/lua_vmprep.c Sun Aug  5 19:57:44 2012
@@ -23,6 +23,15 @@
 
 APLOG_USE_MODULE(lua);
 
+#if APR_HAS_THREADS
+    apr_thread_mutex_t *ap_lua_mutex;
+    
+void ap_lua_init_mutex(apr_pool_t *pool, server_rec *s) 
+{
+    apr_thread_mutex_create(&ap_lua_mutex, APR_THREAD_MUTEX_DEFAULT, pool);
+}
+#endif
+
 /* forward dec'l from this file */
 
 #if 0
@@ -127,7 +136,7 @@ AP_LUA_DECLARE(void) ap_lua_load_apache2
     makeintegerfield(L, AUTHZ_NEUTRAL);
     makeintegerfield(L, AUTHZ_GENERAL_ERROR);
     makeintegerfield(L, AUTHZ_DENIED_NO_USER);
-
+    
     /*
        makeintegerfield(L, HTTP_CONTINUE);
        makeintegerfield(L, HTTP_SWITCHING_PROTOCOLS);
@@ -201,6 +210,16 @@ static apr_status_t cleanup_lua(void *l)
     return APR_SUCCESS;
 }
 
+static apr_status_t server_cleanup_lua(void *resource)
+{
+    ap_lua_server_spec* spec = (ap_lua_server_spec*) resource;
+    AP_DEBUG_ASSERT(spec != NULL);
+    if (spec->L != NULL) {
+        lua_close((lua_State *) spec->L);
+    }
+    return APR_SUCCESS;
+}
+
 /*
         munge_path(L, 
                    "path", 
@@ -333,6 +352,39 @@ static apr_status_t vm_construct(lua_Sta
     return APR_SUCCESS;
 }
 
+ap_lua_vm_spec* copy_vm_spec(apr_pool_t* pool, ap_lua_vm_spec* spec) 
+{
+    ap_lua_vm_spec* copied_spec = apr_pcalloc(pool, sizeof(ap_lua_vm_spec));
+    copied_spec->bytecode_len = spec->bytecode_len;
+    copied_spec->bytecode = spec->bytecode ? apr_pstrdup(pool, spec->bytecode) : 0;
+    copied_spec->cb = spec->cb;
+    copied_spec->cb_arg = NULL;
+    copied_spec->file = spec->file ? apr_pstrdup(pool, spec->file) : 0;
+    copied_spec->package_cpaths = apr_array_copy(pool, spec->package_cpaths);
+    copied_spec->package_paths = apr_array_copy(pool, spec->package_paths);
+    copied_spec->pool = pool;
+    copied_spec->scope = AP_LUA_SCOPE_SERVER;
+    copied_spec->codecache = spec->codecache;
+    return copied_spec;
+}
+
+static apr_status_t server_vm_construct(lua_State **resource, void *params, apr_pool_t *pool)
+{
+    lua_State* L;
+    ap_lua_server_spec* spec = apr_pcalloc(pool, sizeof(ap_lua_server_spec));
+    if (vm_construct(&L, params, pool) == APR_SUCCESS) {
+        spec->finfo = apr_pcalloc(pool, sizeof(ap_lua_finfo));
+        if (L != NULL) {
+            spec->L = L;
+            *resource = (void*) spec;
+            lua_pushlightuserdata(L, spec);
+            lua_setfield(L, LUA_REGISTRYINDEX, "Apache2.Lua.server_spec");
+            return APR_SUCCESS;
+        }
+    }
+    return APR_EGENERAL;
+}
+
 /**
  * Function used to create a lua_State instance bound into the web
  * server in the appropriate scope.
@@ -341,57 +393,96 @@ AP_LUA_DECLARE(lua_State*)ap_lua_get_lua
                                                ap_lua_vm_spec *spec, request_rec* r)
 {
     lua_State *L = NULL;
+    ap_lua_finfo *cache_info;
     int tryCache = 0;
-    if (apr_pool_userdata_get((void **)&L, spec->file,
-                              lifecycle_pool) == APR_SUCCESS) {
-        
-      if(L==NULL) {
+    
+    if (spec->scope == AP_LUA_SCOPE_SERVER) {
+        char *hash;
+        apr_reslist_t* reslist = NULL;
+        ap_lua_server_spec* sspec = NULL;
+        hash = apr_psprintf(r->pool, "reslist:%s", spec->file);
+#if APR_HAS_THREADS
+        apr_thread_mutex_lock(ap_lua_mutex);
+#endif
+        if (apr_pool_userdata_get((void **)&reslist, hash,
+                                  r->server->process->pool) == APR_SUCCESS) {
+            if (reslist != NULL) {
+                if (apr_reslist_acquire(reslist, (void**) &sspec) == APR_SUCCESS) {
+                    L = sspec->L;
+                    cache_info = sspec->finfo;
+                }
+            }
+        }
+        if (L == NULL) {
+            ap_lua_vm_spec* server_spec = copy_vm_spec(r->server->process->pool, spec);
+            apr_reslist_create(&reslist, spec->vm_min, spec->vm_max, spec->vm_max, 0, 
+                                (apr_reslist_constructor) server_vm_construct, 
+                                (apr_reslist_destructor) server_cleanup_lua, 
+                                server_spec, r->server->process->pool);
+            apr_pool_userdata_set(reslist, hash, NULL,
+                                        r->server->process->pool);
+            if (apr_reslist_acquire(reslist, (void**) &sspec) == APR_SUCCESS) {
+                L = sspec->L;
+                cache_info = sspec->finfo;
+            }
+        }
+#if APR_HAS_THREADS
+        apr_thread_mutex_unlock(ap_lua_mutex);
+#endif
+    }
+    else {
+        if (apr_pool_userdata_get((void **)&L, spec->file,
+                              lifecycle_pool) != APR_SUCCESS) {
+            L = NULL;
+        }
+    }
+    if(L==NULL) {
         ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, lifecycle_pool, APLOGNO(01483)
-                      "creating lua_State with file %s", spec->file);
+                        "creating lua_State with file %s", spec->file);
         /* not available, so create */
-        
+
         if(!vm_construct(&L, spec, lifecycle_pool)) {
-          AP_DEBUG_ASSERT(L != NULL);
-          apr_pool_userdata_set(L, 
+            AP_DEBUG_ASSERT(L != NULL);
+            apr_pool_userdata_set(L, 
                                 spec->file, 
                                 cleanup_lua,
                                 lifecycle_pool);
         }
-      }
     }
-        /*}*/
+
     if (spec->codecache == AP_LUA_CACHE_FOREVER || (spec->bytecode && spec->bytecode_len > 0)) {
         tryCache = 1;
     }
     else {
-        ap_lua_finfo *cache_info;
-        char* mkey = apr_psprintf(r->pool, "ap_lua_modified:%s", spec->file);
-        if (apr_pool_userdata_get((void **)&cache_info, mkey,
-                              lifecycle_pool) == APR_SUCCESS) {
+        char* mkey;
+        if (spec->scope != AP_LUA_SCOPE_SERVER) {
+            mkey = apr_psprintf(r->pool, "ap_lua_modified:%s", spec->file);
+            apr_pool_userdata_get((void **)&cache_info, mkey, lifecycle_pool);
             if (cache_info == NULL) {
                 cache_info = apr_pcalloc(lifecycle_pool, sizeof(ap_lua_finfo));
             }
-            if (spec->codecache == AP_LUA_CACHE_STAT) {
-                apr_finfo_t lua_finfo;
-                apr_stat(&lua_finfo, spec->file, APR_FINFO_MTIME|APR_FINFO_SIZE, lifecycle_pool);
-            
-                /* On first visit, modified will be zero, but that's fine - The file is 
-                loaded in the vm_construct function.
-                */
-                if ((cache_info->modified == lua_finfo.mtime && cache_info->size == lua_finfo.size) \
-                        || cache_info->modified == 0) tryCache = 1;
-                cache_info->modified = lua_finfo.mtime;
-                cache_info->size = lua_finfo.size;
-            }
-            else if (spec->codecache == AP_LUA_CACHE_NEVER) {
-                if (cache_info->runs == 0) tryCache = 1;
+        }
+        if (spec->codecache == AP_LUA_CACHE_STAT) {
+            apr_finfo_t lua_finfo;
+            apr_stat(&lua_finfo, spec->file, APR_FINFO_MTIME|APR_FINFO_SIZE, lifecycle_pool);
+
+            /* On first visit, modified will be zero, but that's fine - The file is 
+            loaded in the vm_construct function.
+            */
+            if ((cache_info->modified == lua_finfo.mtime && cache_info->size == lua_finfo.size) \
+                    || cache_info->modified == 0) {
+                tryCache = 1;
             }
-            cache_info->runs++;
+            cache_info->modified = lua_finfo.mtime;
+            cache_info->size = lua_finfo.size;
+        }
+        else if (spec->codecache == AP_LUA_CACHE_NEVER) {
+            if (cache_info->runs == 0) tryCache = 1;
         }
-        else {
-            tryCache = 1;
+        cache_info->runs++;
+        if (spec->scope != AP_LUA_SCOPE_SERVER) {
+            apr_pool_userdata_set((void*) cache_info, mkey, NULL, lifecycle_pool);
         }
-        apr_pool_userdata_set((void*) cache_info, mkey, NULL, lifecycle_pool);
     }
     if (tryCache == 0 && spec->scope != AP_LUA_SCOPE_ONCE) {
         int rc;

Modified: httpd/httpd/trunk/modules/lua/lua_vmprep.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/lua/lua_vmprep.h?rev=1369656&r1=1369655&r2=1369656&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/lua/lua_vmprep.h (original)
+++ httpd/httpd/trunk/modules/lua/lua_vmprep.h Sun Aug  5 19:57:44 2012
@@ -29,6 +29,7 @@
 #include "apr_file_info.h"
 #include "apr_time.h"
 #include "apr_pools.h"
+#include "apr_reslist.h"
 
 
 #ifndef VMPREP_H
@@ -39,16 +40,15 @@
 #define AP_LUA_SCOPE_REQUEST       2
 #define AP_LUA_SCOPE_CONN          3
 #define AP_LUA_SCOPE_THREAD        4
+#define AP_LUA_SCOPE_SERVER        5
 
 #define AP_LUA_CACHE_UNSET         0
 #define AP_LUA_CACHE_NEVER         1
 #define AP_LUA_CACHE_STAT          2
 #define AP_LUA_CACHE_FOREVER       3
 
-
 typedef void (*ap_lua_state_open_callback) (lua_State *L, apr_pool_t *p,
                                              void *ctx);
-
 /**
  * Specification for a lua virtual machine
  */
@@ -61,8 +61,10 @@ typedef struct
     /* name of base file to load in the vm */
     const char *file;
 
-    /* APL_SCOPE_ONCE | APL_SCOPE_REQUEST | APL_SCOPE_CONN | APL_SCOPE_THREAD */
+    /* APL_SCOPE_ONCE | APL_SCOPE_REQUEST | APL_SCOPE_CONN | APL_SCOPE_THREAD | APL_SCOPE_SERVER */
     int scope;
+    unsigned int vm_min;
+    unsigned int vm_max;
 
     ap_lua_state_open_callback cb;
     void* cb_arg;
@@ -97,6 +99,11 @@ typedef struct {
     apr_size_t size;
 } ap_lua_finfo;
 
+typedef struct {
+    lua_State* L;
+    ap_lua_finfo* finfo;
+} ap_lua_server_spec;
+
 /* remove and make static once out of mod_wombat.c */
 AP_LUA_DECLARE(void) ap_lua_openlibs(lua_State *L);
 

Modified: httpd/httpd/trunk/modules/lua/mod_lua.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/lua/mod_lua.c?rev=1369656&r1=1369655&r2=1369656&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/lua/mod_lua.c (original)
+++ httpd/httpd/trunk/modules/lua/mod_lua.c Sun Aug  5 19:57:44 2012
@@ -65,7 +65,6 @@ static void report_lua_error(lua_State *
     const char *lua_response;
     r->status = HTTP_INTERNAL_SERVER_ERROR;
     r->content_type = "text/html";
-
     ap_rputs("<b>Error!</b>\n", r);
     ap_rputs("<p>", r);
     lua_response = lua_tostring(L, -1);
@@ -109,6 +108,29 @@ static const char *scope_to_string(unsig
     }
 }
 
+static void ap_lua_release_state(lua_State* L, ap_lua_vm_spec* spec, request_rec* r) {
+    char *hash;
+    apr_reslist_t* reslist = NULL;
+    if (spec->scope == AP_LUA_SCOPE_SERVER) {
+        ap_lua_server_spec* sspec = NULL;
+        lua_settop(L, 0);
+        lua_getfield(L, LUA_REGISTRYINDEX, "Apache2.Lua.server_spec");
+        sspec = (ap_lua_server_spec*) lua_touserdata(L, 1);
+        hash = apr_psprintf(r->pool, "reslist:%s", spec->file);
+        if (apr_pool_userdata_get((void **)&reslist, hash,
+                                r->server->process->pool) == APR_SUCCESS) {
+            AP_DEBUG_ASSERT(sspec != NULL);
+            if (reslist != NULL) {
+                apr_reslist_release(reslist, sspec);
+            }
+        }
+    }
+}
+
+#if APR_HAS_THREADS
+extern void ap_lua_init_mutex(apr_pool_t *pool, server_rec *s);
+#endif
+
 static ap_lua_vm_spec *create_vm_spec(apr_pool_t **lifecycle_pool,
                                       request_rec *r,
                                       const ap_lua_dir_cfg *cfg,
@@ -131,7 +153,9 @@ static ap_lua_vm_spec *create_vm_spec(ap
     spec->bytecode = bytecode;
     spec->bytecode_len = bytecode_len;
     spec->codecache = (cfg->codecache == AP_LUA_CACHE_UNSET) ? AP_LUA_CACHE_STAT : cfg->codecache;
-
+    spec->vm_min = cfg->vm_min ? cfg->vm_min : 1;
+    spec->vm_max = cfg->vm_max ? cfg->vm_max : 1;
+    
     if (filename) {
         char *file;
         apr_filepath_merge(&file, server_cfg->root_path,
@@ -161,6 +185,9 @@ static ap_lua_vm_spec *create_vm_spec(ap
     case AP_LUA_SCOPE_THREAD:
         pool = apr_thread_pool_get(r->connection->current_thread);
         break;
+    case AP_LUA_SCOPE_SERVER:
+        pool = r->server->process->pool;
+        break;
 #endif
     default:
         ap_assert(0);
@@ -230,6 +257,7 @@ static int lua_handler(request_rec *r)
             /* TODO annotate spec with failure reason */
             r->status = HTTP_INTERNAL_SERVER_ERROR;
             ap_rputs("Unable to compile VM, see logs", r);
+            ap_lua_release_state(L, spec, r);
             return HTTP_INTERNAL_SERVER_ERROR;
         }
         ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, APLOGNO(01474) "got a vm!");
@@ -239,12 +267,14 @@ static int lua_handler(request_rec *r)
                           "lua: Unable to find function %s in %s",
                           "handle",
                           spec->file);
+            ap_lua_release_state(L, spec, r);
             return HTTP_INTERNAL_SERVER_ERROR;
         }
         ap_lua_run_lua_request(L, r);
         if (lua_pcall(L, 1, 0, 0)) {
             report_lua_error(L, r);
         }
+        ap_lua_release_state(L, spec, r);
     }
     return OK;
 }
@@ -300,6 +330,7 @@ static int lua_request_rec_hook_harness(
                                   "lua: Unable to find function %s in %s",
                                   hook_spec->function_name,
                                   hook_spec->file_name);
+                    ap_lua_release_state(L, spec, r);
                     return HTTP_INTERNAL_SERVER_ERROR;
                 }
 
@@ -316,6 +347,7 @@ static int lua_request_rec_hook_harness(
 
             if (lua_pcall(L, 1, 1, 0)) {
                 report_lua_error(L, r);
+                ap_lua_release_state(L, spec, r);
                 return HTTP_INTERNAL_SERVER_ERROR;
             }
             rc = DECLINED;
@@ -323,6 +355,7 @@ static int lua_request_rec_hook_harness(
                 rc = lua_tointeger(L, -1);
             }
             if (rc != DECLINED) {
+                ap_lua_release_state(L, spec, r);
                 return rc;
             }
         }
@@ -373,6 +406,7 @@ static int lua_map_handler(request_rec *
                 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01477)
                                 "lua: Failed to obtain lua interpreter for %s %s",
                                 function_name, filename);
+                ap_lua_release_state(L, spec, r);
                 return HTTP_INTERNAL_SERVER_ERROR;
             }
 
@@ -383,6 +417,7 @@ static int lua_map_handler(request_rec *
                                     "lua: Unable to find function %s in %s",
                                     function_name,
                                     filename);
+                    ap_lua_release_state(L, spec, r);
                     return HTTP_INTERNAL_SERVER_ERROR;
                 }
 
@@ -399,6 +434,7 @@ static int lua_map_handler(request_rec *
 
             if (lua_pcall(L, 1, 1, 0)) {
                 report_lua_error(L, r);
+                ap_lua_release_state(L, spec, r);
                 return HTTP_INTERNAL_SERVER_ERROR;
             }
             rc = DECLINED;
@@ -406,6 +442,7 @@ static int lua_map_handler(request_rec *
                 rc = lua_tointeger(L, -1);
             }
             if (rc != DECLINED) {
+                ap_lua_release_state(L, spec, r);
                 return rc;
             }
         }
@@ -1110,12 +1147,33 @@ static const char *register_lua_scope(cm
 #endif
         cfg->vm_scope = AP_LUA_SCOPE_THREAD;
     }
+    else if (strcmp("server", scope) == 0) {
+        unsigned int vmin, vmax;
+#if !APR_HAS_THREADS
+        return apr_psprintf(cmd->pool,
+                            "Scope type of '%s' cannot be used because this "
+                            "server does not have threading support "
+                            "(APR_HAS_THREADS)" 
+                            scope);
+#endif
+        cfg->vm_scope = AP_LUA_SCOPE_SERVER;
+        vmin = min ? atoi(min) : 1;
+        vmax = max ? atoi(max) : 1;
+        if (vmin == 0) {
+            vmin = 1;
+        }
+        if (vmax < vmin) {
+            vmax = vmin;
+        }
+        cfg->vm_min = vmin;
+        cfg->vm_max = vmax;
+    }
     else {
         return apr_psprintf(cmd->pool,
                             "Invalid value for LuaScope, '%s', acceptable "
-                            "values are: 'once', 'request', 'conn', 'server'"
+                            "values are: 'once', 'request', 'conn'"
 #if APR_HAS_THREADS
-                            ", 'thread'"
+                            ", 'thread', 'server'"
 #endif
                             ,scope);
     }
@@ -1203,6 +1261,7 @@ static authz_status lua_authz_check(requ
         ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02319)
                       "Unable to find function %s in %s",
                       prov_spec->function_name, prov_spec->file_name);
+        ap_lua_release_state(L, spec, r);
         return AUTHZ_GENERAL_ERROR;
     }
     ap_lua_run_lua_request(L, r);
@@ -1211,6 +1270,7 @@ static authz_status lua_authz_check(requ
         if (!lua_checkstack(L, prov_spec->args->nelts)) {
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02315)
                           "Error: authz provider %s: too many arguments", prov_spec->name);
+            ap_lua_release_state(L, spec, r);
             return AUTHZ_GENERAL_ERROR;
         }
         for (i = 0; i < prov_spec->args->nelts; i++) {
@@ -1223,14 +1283,17 @@ static authz_status lua_authz_check(requ
         const char *err = lua_tostring(L, -1);
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02316)
                       "Error executing authz provider %s: %s", prov_spec->name, err);
+        ap_lua_release_state(L, spec, r);
         return AUTHZ_GENERAL_ERROR;
     }
     if (!lua_isnumber(L, -1)) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02317)
                       "Error: authz provider %s did not return integer", prov_spec->name);
+        ap_lua_release_state(L, spec, r);
         return AUTHZ_GENERAL_ERROR;
     }
     result = lua_tointeger(L, -1);
+    ap_lua_release_state(L, spec, r);
     switch (result) {
         case AUTHZ_DENIED:
         case AUTHZ_GRANTED:
@@ -1389,6 +1452,8 @@ static void *create_dir_config(apr_pool_
     cfg->dir = apr_pstrdup(p, dir);
     cfg->vm_scope = AP_LUA_SCOPE_UNSET;
     cfg->codecache = AP_LUA_CACHE_UNSET;
+    cfg->vm_min = 0;
+    cfg->vm_max = 0;
 
     return cfg;
 }
@@ -1452,6 +1517,9 @@ static void *merge_dir_config(apr_pool_t
     a->vm_scope = (overrides->vm_scope == AP_LUA_SCOPE_UNSET) ? base->vm_scope: overrides->vm_scope;
     a->inherit = (overrides->inherit== AP_LUA_INHERIT_UNSET) ? base->inherit : overrides->inherit;
     a->codecache = (overrides->codecache== AP_LUA_CACHE_UNSET) ? base->codecache : overrides->codecache;
+    
+    a->vm_min = (overrides->vm_min== 0) ? base->vm_min : overrides->vm_min;
+    a->vm_max = (overrides->vm_max== 0) ? base->vm_max : overrides->vm_max;
 
     if (a->inherit == AP_LUA_INHERIT_UNSET || a->inherit == AP_LUA_INHERIT_PARENT_FIRST) { 
         a->package_paths = apr_array_append(p, base->package_paths, overrides->package_paths);
@@ -1529,6 +1597,9 @@ static void lua_register_hooks(apr_pool_
     APR_OPTIONAL_HOOK(ap_lua, lua_request, lua_request_hook, NULL, NULL,
                       APR_HOOK_REALLY_FIRST);
     ap_hook_handler(lua_map_handler, NULL, NULL, AP_LUA_HOOK_FIRST);
+#if APR_HAS_THREADS
+    ap_hook_child_init(ap_lua_init_mutex, NULL, NULL, APR_HOOK_MIDDLE);
+#endif
     /* providers */
     lua_authz_providers = apr_hash_make(p);
 }

Modified: httpd/httpd/trunk/modules/lua/mod_lua.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/lua/mod_lua.h?rev=1369656&r1=1369655&r2=1369656&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/lua/mod_lua.h (original)
+++ httpd/httpd/trunk/modules/lua/mod_lua.h Sun Aug  5 19:57:44 2012
@@ -39,6 +39,7 @@
 #include "apr_file_info.h"
 #include "apr_time.h"
 #include "apr_hooks.h"
+#include "apr_reslist.h"
 
 /* Allow for Lua 5.2 backwards compatibility */
 #define LUA_COMPAT_ALL
@@ -111,6 +112,8 @@ typedef struct
      * AP_LUA_SCOPE_ONCE | AP_LUA_SCOPE_REQUEST | AP_LUA_SCOPE_CONN | AP_LUA_SCOPE_SERVER
      */
     unsigned int vm_scope;
+    unsigned int vm_min;
+    unsigned int vm_max;
 
     /* info for the hook harnesses */
     apr_hash_t *hooks;          /* <wombat_hook_info> */