One of the bottlenecks in mod_include is the setting of
environment variables in add_include_vars(). This patch
defers the evaluation of the more computationally expensive
variables (user name and various timestamps) until/unless
they're actually used. With this change, I'm seeing a ~5%
throughput increase (Linux, 10KB .shtml file, single client)
for documents that don't use those variables.
--Brian
Index: modules/filters/mod_include.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/filters/mod_include.c,v
retrieving revision 1.129
diff -u -r1.129 mod_include.c
--- modules/filters/mod_include.c 2001/08/23 15:45:49 1.129
+++ modules/filters/mod_include.c 2001/08/23 21:32:23
@@ -96,6 +96,29 @@
static apr_hash_t *include_hash;
static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *ssi_pfn_register;
+/*****************************************************************
+ *
+ * XBITHACK. Sigh... NB it's configurable per-directory; the compile-time
+ * option only changes the default.
+ */
+
+module include_module;
+enum xbithack {
+ xbithack_off, xbithack_on, xbithack_full
+};
+
+typedef struct {
+ char *default_error_msg;
+ char *default_time_fmt;
+ enum xbithack *xbithack;
+} include_dir_config;
+
+#ifdef XBITHACK
+#define DEFAULT_XBITHACK xbithack_full
+#else
+#define DEFAULT_XBITHACK xbithack_off
+#endif
+
#define BYTE_COUNT_THRESHOLD AP_MIN_BYTES_TO_WRITE
/* This function is used to split the brigade at the beginning of
@@ -123,6 +146,11 @@
/* ------------------------ Environment function
-------------------------- */
+/* Sentinel value to store in subprocess_env for items that
+ * shouldn't be evaluated until/unless they're actually used
+ */
+static char lazy_eval_sentinel;
+
/* XXX: could use ap_table_overlap here */
static void add_include_vars(request_rec *r, char *timefmt)
{
@@ -131,18 +159,12 @@
char *t;
apr_time_t date = r->request_time;
- apr_table_setn(e, "DATE_LOCAL", ap_ht_time(r->pool, date, timefmt, 0));
- apr_table_setn(e, "DATE_GMT", ap_ht_time(r->pool, date, timefmt, 1));
- apr_table_setn(e, "LAST_MODIFIED",
- ap_ht_time(r->pool, r->finfo.mtime, timefmt, 0));
+ apr_table_setn(e, "DATE_LOCAL", &lazy_eval_sentinel);
+ apr_table_setn(e, "DATE_GMT", &lazy_eval_sentinel);
+ apr_table_setn(e, "LAST_MODIFIED", &lazy_eval_sentinel);
apr_table_setn(e, "DOCUMENT_URI", r->uri);
apr_table_setn(e, "DOCUMENT_PATH_INFO", r->path_info);
- if (apr_get_username(&pwname, r->finfo.user, r->pool) == APR_SUCCESS) {
- apr_table_setn(e, "USER_NAME", pwname);
- }
- else {
- apr_table_setn(e, "USER_NAME", "<unknown>");
- }
+ apr_table_setn(e, "USER_NAME", &lazy_eval_sentinel);
if ((t = strrchr(r->filename, '/'))) {
apr_table_setn(e, "DOCUMENT_NAME", ++t);
}
@@ -158,7 +180,42 @@
}
}
+static const char *add_include_vars_lazy(request_rec *r, const char *var)
+{
+ char *val;
+ if (!strcasecmp(var, "DATE_LOCAL")) {
+ include_dir_config *conf =
+ (include_dir_config *)ap_get_module_config(r->per_dir_config,
+ &include_module);
+ val = ap_ht_time(r->pool, r->request_time, conf->default_time_fmt, 0);
+ }
+ else if (!strcasecmp(var, "DATE_GMT")) {
+ include_dir_config *conf =
+ (include_dir_config *)ap_get_module_config(r->per_dir_config,
+ &include_module);
+ val = ap_ht_time(r->pool, r->request_time, conf->default_time_fmt, 1);
+ }
+ else if (!strcasecmp(var, "LAST_MODIFIED")) {
+ include_dir_config *conf =
+ (include_dir_config *)ap_get_module_config(r->per_dir_config,
+ &include_module);
+ val = ap_ht_time(r->pool, r->finfo.mtime, conf->default_time_fmt, 0);
+ }
+ else if (!strcasecmp(var, "USER_NAME")) {
+ if (apr_get_username(&val, r->finfo.user, r->pool) != APR_SUCCESS) {
+ val = "<unknown>";
+ }
+ }
+ else {
+ val = NULL;
+ }
+ if (val) {
+ apr_table_setn(r->subprocess_env, var, val);
+ }
+ return val;
+}
+
/* --------------------------- Parser functions
--------------------------- */
@@ -701,6 +758,9 @@
tmp_store = *end_of_var_name;
*end_of_var_name = '\0';
val = apr_table_get(r->subprocess_env,
start_of_var_name);
+ if (val == &lazy_eval_sentinel) {
+ val = add_include_vars_lazy(r, start_of_var_name);
+ }
*end_of_var_name = tmp_store;
if (val) {
@@ -944,13 +1004,15 @@
}
if (!strcmp(tag, "var")) {
const char *val = apr_table_get(r->subprocess_env,
tag_val);
-
+ if (val == &lazy_eval_sentinel) {
+ val = add_include_vars_lazy(r, tag_val);
+ }
if (val) {
switch(encode) {
case E_NONE: echo_text =
val; break;
case E_URL: echo_text = ap_escape_uri(r->pool,
val); break;
case E_ENTITY: echo_text = ap_escape_html(r->pool,
val); break;
- }
+ }
e_len = strlen(echo_text);
tmp_buck = apr_bucket_heap_create(echo_text, e_len,
1, &e_wrt);
@@ -2320,13 +2382,18 @@
apr_array_header_t *arr = apr_table_elts(r->subprocess_env);
apr_table_entry_t *elts = (apr_table_entry_t *)arr->elts;
int i;
- char *key_text, *val_text;
+ const char *key_text, *val_text;
apr_size_t k_len, v_len, t_wrt;
*inserted_head = NULL;
for (i = 0; i < arr->nelts; ++i) {
key_text = ap_escape_html(r->pool, elts[i].key);
- val_text = ap_escape_html(r->pool, elts[i].val);
+ if (elts[i].key == &lazy_eval_sentinel) {
+ val_text = add_include_vars_lazy(r, elts[i].key);
+ }
+ else {
+ val_text = ap_escape_html(r->pool, elts[i].val);
+ }
k_len = strlen(key_text);
v_len = strlen(val_text);
@@ -2657,29 +2724,6 @@
}
return APR_SUCCESS;
}
-
-/*****************************************************************
- *
- * XBITHACK. Sigh... NB it's configurable per-directory; the compile-time
- * option only changes the default.
- */
-
-module include_module;
-enum xbithack {
- xbithack_off, xbithack_on, xbithack_full
-};
-
-typedef struct {
- char *default_error_msg;
- char *default_time_fmt;
- enum xbithack *xbithack;
-} include_dir_config;
-
-#ifdef XBITHACK
-#define DEFAULT_XBITHACK xbithack_full
-#else
-#define DEFAULT_XBITHACK xbithack_off
-#endif
static void *create_includes_dir_config(apr_pool_t *p, char *dummy)
{
Index: modules/filters/mod_include.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/filters/mod_include.c,v
retrieving revision 1.129
diff -u -r1.129 mod_include.c
--- modules/filters/mod_include.c 2001/08/23 15:45:49 1.129
+++ modules/filters/mod_include.c 2001/08/23 21:32:23
@@ -96,6 +96,29 @@
static apr_hash_t *include_hash;
static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *ssi_pfn_register;
+/*****************************************************************
+ *
+ * XBITHACK. Sigh... NB it's configurable per-directory; the compile-time
+ * option only changes the default.
+ */
+
+module include_module;
+enum xbithack {
+ xbithack_off, xbithack_on, xbithack_full
+};
+
+typedef struct {
+ char *default_error_msg;
+ char *default_time_fmt;
+ enum xbithack *xbithack;
+} include_dir_config;
+
+#ifdef XBITHACK
+#define DEFAULT_XBITHACK xbithack_full
+#else
+#define DEFAULT_XBITHACK xbithack_off
+#endif
+
#define BYTE_COUNT_THRESHOLD AP_MIN_BYTES_TO_WRITE
/* This function is used to split the brigade at the beginning of
@@ -123,6 +146,11 @@
/* ------------------------ Environment function -------------------------- */
+/* Sentinel value to store in subprocess_env for items that
+ * shouldn't be evaluated until/unless they're actually used
+ */
+static char lazy_eval_sentinel;
+
/* XXX: could use ap_table_overlap here */
static void add_include_vars(request_rec *r, char *timefmt)
{
@@ -131,18 +159,12 @@
char *t;
apr_time_t date = r->request_time;
- apr_table_setn(e, "DATE_LOCAL", ap_ht_time(r->pool, date, timefmt, 0));
- apr_table_setn(e, "DATE_GMT", ap_ht_time(r->pool, date, timefmt, 1));
- apr_table_setn(e, "LAST_MODIFIED",
- ap_ht_time(r->pool, r->finfo.mtime, timefmt, 0));
+ apr_table_setn(e, "DATE_LOCAL", &lazy_eval_sentinel);
+ apr_table_setn(e, "DATE_GMT", &lazy_eval_sentinel);
+ apr_table_setn(e, "LAST_MODIFIED", &lazy_eval_sentinel);
apr_table_setn(e, "DOCUMENT_URI", r->uri);
apr_table_setn(e, "DOCUMENT_PATH_INFO", r->path_info);
- if (apr_get_username(&pwname, r->finfo.user, r->pool) == APR_SUCCESS) {
- apr_table_setn(e, "USER_NAME", pwname);
- }
- else {
- apr_table_setn(e, "USER_NAME", "<unknown>");
- }
+ apr_table_setn(e, "USER_NAME", &lazy_eval_sentinel);
if ((t = strrchr(r->filename, '/'))) {
apr_table_setn(e, "DOCUMENT_NAME", ++t);
}
@@ -158,7 +180,42 @@
}
}
+static const char *add_include_vars_lazy(request_rec *r, const char *var)
+{
+ char *val;
+ if (!strcasecmp(var, "DATE_LOCAL")) {
+ include_dir_config *conf =
+ (include_dir_config *)ap_get_module_config(r->per_dir_config,
+ &include_module);
+ val = ap_ht_time(r->pool, r->request_time, conf->default_time_fmt, 0);
+ }
+ else if (!strcasecmp(var, "DATE_GMT")) {
+ include_dir_config *conf =
+ (include_dir_config *)ap_get_module_config(r->per_dir_config,
+ &include_module);
+ val = ap_ht_time(r->pool, r->request_time, conf->default_time_fmt, 1);
+ }
+ else if (!strcasecmp(var, "LAST_MODIFIED")) {
+ include_dir_config *conf =
+ (include_dir_config *)ap_get_module_config(r->per_dir_config,
+ &include_module);
+ val = ap_ht_time(r->pool, r->finfo.mtime, conf->default_time_fmt, 0);
+ }
+ else if (!strcasecmp(var, "USER_NAME")) {
+ if (apr_get_username(&val, r->finfo.user, r->pool) != APR_SUCCESS) {
+ val = "<unknown>";
+ }
+ }
+ else {
+ val = NULL;
+ }
+ if (val) {
+ apr_table_setn(r->subprocess_env, var, val);
+ }
+ return val;
+}
+
/* --------------------------- Parser functions --------------------------- */
@@ -701,6 +758,9 @@
tmp_store = *end_of_var_name;
*end_of_var_name = '\0';
val = apr_table_get(r->subprocess_env, start_of_var_name);
+ if (val == &lazy_eval_sentinel) {
+ val = add_include_vars_lazy(r, start_of_var_name);
+ }
*end_of_var_name = tmp_store;
if (val) {
@@ -944,13 +1004,15 @@
}
if (!strcmp(tag, "var")) {
const char *val = apr_table_get(r->subprocess_env, tag_val);
-
+ if (val == &lazy_eval_sentinel) {
+ val = add_include_vars_lazy(r, tag_val);
+ }
if (val) {
switch(encode) {
case E_NONE: echo_text = val; break;
case E_URL: echo_text = ap_escape_uri(r->pool, val); break;
case E_ENTITY: echo_text = ap_escape_html(r->pool, val); break;
- }
+ }
e_len = strlen(echo_text);
tmp_buck = apr_bucket_heap_create(echo_text, e_len, 1, &e_wrt);
@@ -2320,13 +2382,18 @@
apr_array_header_t *arr = apr_table_elts(r->subprocess_env);
apr_table_entry_t *elts = (apr_table_entry_t *)arr->elts;
int i;
- char *key_text, *val_text;
+ const char *key_text, *val_text;
apr_size_t k_len, v_len, t_wrt;
*inserted_head = NULL;
for (i = 0; i < arr->nelts; ++i) {
key_text = ap_escape_html(r->pool, elts[i].key);
- val_text = ap_escape_html(r->pool, elts[i].val);
+ if (elts[i].key == &lazy_eval_sentinel) {
+ val_text = add_include_vars_lazy(r, elts[i].key);
+ }
+ else {
+ val_text = ap_escape_html(r->pool, elts[i].val);
+ }
k_len = strlen(key_text);
v_len = strlen(val_text);
@@ -2657,29 +2724,6 @@
}
return APR_SUCCESS;
}
-
-/*****************************************************************
- *
- * XBITHACK. Sigh... NB it's configurable per-directory; the compile-time
- * option only changes the default.
- */
-
-module include_module;
-enum xbithack {
- xbithack_off, xbithack_on, xbithack_full
-};
-
-typedef struct {
- char *default_error_msg;
- char *default_time_fmt;
- enum xbithack *xbithack;
-} include_dir_config;
-
-#ifdef XBITHACK
-#define DEFAULT_XBITHACK xbithack_full
-#else
-#define DEFAULT_XBITHACK xbithack_off
-#endif
static void *create_includes_dir_config(apr_pool_t *p, char *dummy)
{