Skip to content

Commit 851643a

Browse files
committed
Optimization of encoding string to nginx temp buffer chain
1 parent 7e4bd36 commit 851643a

20 files changed

+658
-201
lines changed

HISTORY.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ Downloads & Release History
44
1. [Binaries of Releases](http://sourceforge.net/projects/nginx-clojure/files/)
55
1. [Sources of Releases](https://github.com/nginx-clojure/nginx-clojure/releases)
66

7+
## 0.2.7 (2014-11-11)
8+
9+
1. New Feature: Compiling option for disabling all functions silently when JVM_PATH not configured. (issue #47)
10+
1. New Feature: Access request BODY in rewrite handler (issue #49)
11+
1. Enhancement : Optimization of encoding String to Nginx temp buffer chain to reduce Java heap memory usage and improve the performance.
12+
13+
714
## 0.2.6 (2014-10-10)
815

916
1. Fix Bug: rewrite handler does not handle write event correctly with thread pool mode or coroutine mode (issue #43)

project.clj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
(defproject nginx-clojure "0.2.6"
1+
(defproject nginx-clojure "0.2.7"
22
:description "Nginx module for clojure & java programming"
33
:url "https://github.com/nginx-clojure/nginx-clojure"
44
:license {:name "BSD 3-Clause license"
@@ -39,9 +39,9 @@
3939
[org.codehaus.groovy/groovy "2.3.4"]
4040
]}
4141
:unittest {
42-
:jvm-opts ["-javaagent:target/nginx-clojure-0.2.6.jar=mb"
42+
:jvm-opts ["-javaagent:target/nginx-clojure-0.2.7.jar=mb"
4343
"-Dnginx.clojure.wave.udfs=pure-clj.txt,compojure.txt,compojure-http-clj.txt"
44-
"-Xbootclasspath/a:target/nginx-clojure-0.2.6.jar"]
44+
"-Xbootclasspath/a:target/nginx-clojure-0.2.7.jar"]
4545
:junit-options {:fork "on"}
4646
:java-source-paths ["test/java" "test/clojure"]
4747
:test-paths ["src/test/clojure"]

src/c/ngx_http_clojure_mem.c

Lines changed: 280 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,83 @@ static jlong JNICALL jni_ngx_create_temp_buf (JNIEnv *env, jclass cls, jlong r,
133133
return (uintptr_t)ngx_create_temp_buf(req->pool, (size_t)size);
134134
}
135135

136+
static jlong JNICALL jni_ngx_create_temp_buf_by_jstring (JNIEnv *env, jclass cls, jlong req, jstring jstr, jint last_buf) {
137+
ngx_http_request_t *r = (ngx_http_request_t *)(uintptr_t) req;
138+
139+
jsize ch_size = (*env)->GetStringLength(env, jstr);
140+
jsize utf8_size = (*env)->GetStringUTFLength(env, jstr);
141+
ngx_buf_t *b = ngx_create_temp_buf(r->pool, (size_t)utf8_size);
142+
143+
if (b == NULL) {
144+
return 0;
145+
}
146+
147+
(*env)->GetStringUTFRegion(env, jstr, 0, ch_size, (char *)b->pos);
148+
b->last = b->pos + utf8_size;
149+
150+
if (last_buf & NGX_BUF_LAST_OF_RESPONSE) {
151+
b->last_buf = b->last_in_chain = 1;
152+
}else {
153+
b->last_in_chain = last_buf & NGX_BUF_LAST_OF_CHAIN;
154+
}
155+
156+
if (r->headers_out.content_length_n < 0 ) {
157+
r->headers_out.content_length_n = utf8_size;
158+
}else {
159+
r->headers_out.content_length_n += utf8_size;
160+
}
161+
162+
/*
163+
* If File and String are in the same ISeq of one response body,
164+
* we should clear the last_modified_time.
165+
*/
166+
r->headers_out.last_modified_time = -2;
167+
r->headers_out.last_modified = NULL;
168+
169+
return (uintptr_t)b;
170+
}
171+
172+
173+
static jlong JNICALL jni_ngx_create_temp_buf_by_obj(JNIEnv *env, jclass cls, jlong req, jobject obj, jlong off, jlong len, jint last_buf) {
174+
ngx_http_request_t *r = (ngx_http_request_t *)(uintptr_t) req;
175+
ngx_buf_t *b;
176+
177+
if (len == 0) {
178+
return 0;
179+
}
180+
181+
b = ngx_calloc_buf(r->pool);
182+
if (b == NULL) {
183+
return 0;
184+
}
185+
186+
b->start = (u_char *)ngx_http_clojure_abs_off_addr(obj, off);
187+
b->pos = b->start;
188+
b->last = b->start + len;
189+
b->end = b->last;
190+
b->memory = 1;
191+
192+
if (last_buf & NGX_BUF_LAST_OF_RESPONSE) {
193+
b->last_buf = b->last_in_chain = 1;
194+
}else {
195+
b->last_in_chain = last_buf & NGX_BUF_LAST_OF_CHAIN;
196+
}
197+
198+
if (r->headers_out.content_length_n < 0 ) {
199+
r->headers_out.content_length_n = len;
200+
}else {
201+
r->headers_out.content_length_n += len;
202+
}
203+
204+
/*
205+
* If File and String are in the same ISeq of one response body,
206+
* we should clear the last_modified_time.
207+
*/
208+
r->headers_out.last_modified_time = -2;
209+
r->headers_out.last_modified = NULL;
210+
211+
return (uintptr_t)b;
212+
}
136213

137214
static jlong JNICALL jni_ngx_create_file_buf (JNIEnv *env, jclass cls, jlong r, jlong file, jlong name_len, jint last_buf) {
138215
ngx_http_request_t *req = (ngx_http_request_t *) (uintptr_t)r;
@@ -1353,6 +1430,204 @@ static jlong JNICALL jni_ngx_http_clojure_mem_init_ngx_buf(JNIEnv *env, jclass c
13531430
return (uintptr_t)b;
13541431
}
13551432

1433+
static jlong JNICALL jni_ngx_http_clojure_mem_build_temp_chain(JNIEnv *env, jclass cls, jlong req , jlong prevChain, jobject obj, jlong offset, jlong len) {
1434+
ngx_chain_t *pre = (ngx_chain_t*)(uintptr_t)prevChain;
1435+
ngx_http_request_t *r = (ngx_http_request_t *)(uintptr_t)req;
1436+
ngx_buf_t *b;
1437+
ngx_chain_t *cl;
1438+
1439+
if (pre != NULL) {
1440+
while (pre->next != NULL) {
1441+
pre = pre->next;
1442+
}
1443+
}
1444+
1445+
if (r->headers_out.content_length_n < 0 ) {
1446+
r->headers_out.content_length_n = len;
1447+
}else {
1448+
r->headers_out.content_length_n += len;
1449+
}
1450+
1451+
/*
1452+
* If File and String are in the same ISeq of one response body,
1453+
* we should clear the last_modified_time.
1454+
*/
1455+
r->headers_out.last_modified_time = -2;
1456+
r->headers_out.last_modified = NULL;
1457+
1458+
b = ngx_create_temp_buf(r->pool, (size_t)len);
1459+
if (b == NULL){
1460+
return 0;
1461+
}
1462+
1463+
cl = ngx_palloc(r->pool, sizeof(ngx_chain_t));
1464+
if (cl == NULL) {
1465+
return 0;
1466+
}
1467+
1468+
cl->buf = b;
1469+
1470+
if (len > 0) {
1471+
ngx_memcpy(b->pos, ngx_http_clojure_abs_off_addr(obj, offset), len);
1472+
b->last = b->pos + len;
1473+
}
1474+
1475+
if (pre != NULL) {
1476+
cl->next = pre->next;
1477+
pre->next = cl;
1478+
b->last_in_chain = pre->buf->last_in_chain;
1479+
b->last_buf = pre->buf->last_buf;
1480+
pre->buf->last_in_chain = 0;
1481+
pre->buf->last_buf = 0;
1482+
}else {
1483+
cl->next = NULL;
1484+
b->last_in_chain = 1;
1485+
b->last_buf = 1;
1486+
}
1487+
1488+
return (uintptr_t)cl;
1489+
}
1490+
1491+
1492+
static jlong JNICALL jni_ngx_http_clojure_mem_build_file_chain(JNIEnv *env, jclass cls, jlong req , jlong prevChain, jobject file, jlong offset, jlong len) {
1493+
ngx_chain_t *pre = (ngx_chain_t*)(uintptr_t)prevChain;
1494+
ngx_http_request_t *r = (ngx_http_request_t *)(uintptr_t)req;
1495+
ngx_buf_t *b;
1496+
ngx_chain_t *cl;
1497+
ngx_str_t path; // = {(ngx_int_t)name_len, (u_char *)file};
1498+
ngx_open_file_info_t of;
1499+
ngx_http_core_loc_conf_t *clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1500+
ngx_uint_t level;
1501+
ngx_log_t *log = r->connection->log;
1502+
1503+
if (pre != NULL) {
1504+
while (pre->next != NULL) {
1505+
pre = pre->next;
1506+
}
1507+
}
1508+
1509+
/*make VS 2010 happy*/
1510+
path.data = (u_char *)ngx_http_clojure_abs_off_addr(file, offset);
1511+
path.len = (ngx_int_t)len;
1512+
1513+
/*just like http_static module */
1514+
1515+
ngx_memzero(&of, sizeof(ngx_open_file_info_t));
1516+
1517+
of.read_ahead = clcf->read_ahead;
1518+
of.directio = clcf->directio;
1519+
of.valid = clcf->open_file_cache_valid;
1520+
of.min_uses = clcf->open_file_cache_min_uses;
1521+
of.errors = clcf->open_file_cache_errors;
1522+
of.events = clcf->open_file_cache_events;
1523+
1524+
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) {
1525+
ngx_int_t rc = 0;
1526+
1527+
switch (of.err) {
1528+
1529+
case 0:
1530+
return -NGX_HTTP_INTERNAL_SERVER_ERROR;
1531+
1532+
case NGX_ENOENT:
1533+
case NGX_ENOTDIR:
1534+
case NGX_ENAMETOOLONG:
1535+
1536+
level = NGX_LOG_ERR;
1537+
rc = NGX_HTTP_NOT_FOUND;
1538+
break;
1539+
1540+
case NGX_EACCES:
1541+
1542+
level = NGX_LOG_ERR;
1543+
rc = NGX_HTTP_FORBIDDEN;
1544+
break;
1545+
1546+
default:
1547+
1548+
level = NGX_LOG_CRIT;
1549+
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
1550+
break;
1551+
}
1552+
1553+
if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
1554+
ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed,
1555+
path.data);
1556+
}
1557+
1558+
return -rc;
1559+
}
1560+
1561+
if (of.is_dir) {
1562+
return -NGX_HTTP_NOT_FOUND;
1563+
}
1564+
1565+
#if !(NGX_WIN32) /* the not regular files are probably Unix specific */
1566+
1567+
if (!of.is_file) {
1568+
ngx_log_error(NGX_LOG_CRIT, log, 0,
1569+
"\"%s\" is not a regular file", path.data);
1570+
1571+
return -NGX_HTTP_NOT_FOUND;
1572+
}
1573+
1574+
#endif
1575+
1576+
r->allow_ranges = 1;
1577+
1578+
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
1579+
if (b == NULL) {
1580+
return -NGX_HTTP_INTERNAL_SERVER_ERROR;
1581+
}
1582+
1583+
b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
1584+
if (b->file == NULL) {
1585+
return -NGX_HTTP_INTERNAL_SERVER_ERROR;
1586+
}
1587+
1588+
b->file_pos = 0;
1589+
b->file_last = of.size;
1590+
1591+
b->in_file = b->file_last ? 1: 0;
1592+
1593+
b->file->fd = of.fd;
1594+
b->file->name = path;
1595+
b->file->log = log;
1596+
b->file->directio = of.is_directio;
1597+
1598+
if (r->headers_out.content_length_n < 0) {
1599+
r->headers_out.content_length_n = of.size;
1600+
} else {
1601+
r->headers_out.content_length_n += of.size;
1602+
}
1603+
1604+
if (r->headers_out.last_modified_time != -2 && r->headers_out.last_modified_time < of.mtime) {
1605+
r->headers_out.last_modified_time = of.mtime;
1606+
}
1607+
1608+
cl = ngx_palloc(r->pool, sizeof(ngx_chain_t));
1609+
if (cl == NULL) {
1610+
return 0;
1611+
}
1612+
1613+
cl->buf = b;
1614+
1615+
if (pre != NULL) {
1616+
cl->next = pre->next;
1617+
pre->next = cl;
1618+
b->last_in_chain = pre->buf->last_in_chain;
1619+
b->last_buf = pre->buf->last_buf;
1620+
pre->buf->last_in_chain = 0;
1621+
pre->buf->last_buf = 0;
1622+
}else {
1623+
cl->next = NULL;
1624+
b->last_in_chain = 1;
1625+
b->last_buf = 1;
1626+
}
1627+
1628+
return (uintptr_t)cl;
1629+
}
1630+
13561631
static jlong JNICALL jni_ngx_http_clojure_mem_get_obj_addr(JNIEnv *env, jclass cls, jobject obj){
13571632
return obj ? (*(uintptr_t*)obj) : 0;
13581633
}
@@ -1473,7 +1748,7 @@ static void JNICALL jni_ngx_http_clojure_mem_continue_current_phase(JNIEnv *env,
14731748
ngx_http_request_t *req = (ngx_http_request_t *)(uintptr_t) r;
14741749
ngx_http_clojure_module_ctx_t *ctx = ngx_http_get_module_ctx(req, ngx_http_clojure_module);
14751750
ctx->phrase = ~ctx->phrase;
1476-
req->write_event_handler(req);
1751+
ngx_http_core_run_phases(req);
14771752
}
14781753

14791754
static jlong JNICALL jni_ngx_http_clojure_mem_get_module_ctx_phase(JNIEnv *env, jclass cls, jlong r) {
@@ -1889,12 +2164,16 @@ int ngx_http_clojure_init_memory_util(ngx_int_t jvm_workers, ngx_log_t *log) {
18892164
{"ngx_list_init", "(JJJJ)J", jni_ngx_list_init},
18902165
{"ngx_list_push", "(J)J", jni_ngx_list_push},
18912166
{"ngx_create_temp_buf", "(JJ)J", jni_ngx_create_temp_buf},
2167+
{"ngx_create_temp_buf_by_jstring", "(JLjava/lang/String;I)J" , jni_ngx_create_temp_buf_by_jstring},
2168+
{"ngx_create_temp_buf_by_obj", "(JLjava/lang/Object;JJI)J", jni_ngx_create_temp_buf_by_obj}, //JNIEnv *env, jclass cls, jlong req, jobject obj, jlong offset, jlong len, jint last_buf
18922169
{"ngx_create_file_buf", "(JJJI)J", jni_ngx_create_file_buf},
18932170
{"ngx_http_set_content_type", "(J)J", jni_ngx_http_set_content_type},
18942171
{"ngx_http_send_header", "(J)J", jni_ngx_http_send_header},
18952172
{"ngx_http_output_filter", "(JJ)J", jni_ngx_http_output_filter},
18962173
{"ngx_http_finalize_request", "(JJ)V", jni_ngx_http_finalize_request},
18972174
{"ngx_http_clojure_mem_init_ngx_buf", "(JLjava/lang/Object;JJI)J", jni_ngx_http_clojure_mem_init_ngx_buf}, //jlong buf, jlong obj, jlong offset, jlong len, jint last_buf
2175+
{"ngx_http_clojure_mem_build_temp_chain", "(JJLjava/lang/Object;JJ)J", jni_ngx_http_clojure_mem_build_temp_chain},
2176+
{"ngx_http_clojure_mem_build_file_chain", "(JJLjava/lang/Object;JJ)J", jni_ngx_http_clojure_mem_build_file_chain} ,
18982177
{"ngx_http_clojure_mem_get_obj_addr", "(Ljava/lang/Object;)J", jni_ngx_http_clojure_mem_get_obj_addr},
18992178
{"ngx_http_clojure_mem_get_list_size", "(J)J", jni_ngx_http_clojure_mem_get_list_size},
19002179
{"ngx_http_clojure_mem_get_list_item", "(JJ)J", jni_ngx_http_clojure_mem_get_list_item},

src/c/ngx_http_clojure_mem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
#define nginx_clojure_ver 2007 /*0.2.7*/
2929

3030
/*the least jar version required*/
31-
#define nginx_clojure_required_rt_lver 2006
31+
#define nginx_clojure_required_rt_lver 2007
3232

3333
#define NGINX_CLOJURE_VER "nginx clojure/0.2.7"
3434

0 commit comments

Comments
 (0)