[mod_dirlisting] read dir in pieces; less blocking
read dir in pieces, allowing server to do other work between reads
(avoid potentially blocking other requests for long periods of time
while reading a large directory)
#include "base.h"
#include "log.h"
#include "buffer.h"
+#include "connections.h"/* joblist_append() */
#include "fdevent.h"
#include "http_chunk.h"
#include "http_header.h"
@@ -102,6 +103,8 @@ typedef struct {
plugin_config conf;
} handler_ctx;
+#define DIRLIST_BATCH 32
+
static handler_ctx * mod_dirlisting_handler_ctx_init (plugin_data * const p) {
handler_ctx *hctx = calloc(1, sizeof(*hctx));
@@ -916,7 +919,8 @@ static int http_read_directory(handler_ctx * const p) {
const int hide_dotfiles = p->conf.hide_dot_files;
const uint32_t name_max = p->name_max;
struct stat st;
- while ((dent = readdir(p->dp)) != NULL) {
+ int count = -1;
+ while (++count < DIRLIST_BATCH && (dent = readdir(p->dp)) != NULL) {
const char * const d_name = dent->d_name;
const uint32_t dsz = (uint32_t) _D_EXACT_NAMLEN(dent);
if (d_name[0] == '.') {
@@ -978,6 +982,8 @@ static int http_read_directory(handler_ctx * const p) {
tmp->namelen = dsz;
memcpy(DIRLIST_ENT_NAME(tmp), d_name, dsz + 1);
}
+ if (count == DIRLIST_BATCH)
+ return HANDLER_WAIT_FOR_EVENT;
closedir(p->dp);
p->dp = NULL;
@@ -994,10 +1000,6 @@ static void http_list_directory(request_st * const r, handler_ctx * const hctx)
char sizebuf[sizeof("999.9K")];
struct tm tm;
- /* Note: a very large directory may cause lighttpd to pause handling other
- * requests while lighttpd processes directory, especially if directory is
- * on a remote filesystem */
-
/* generate large directory listings into tempfiles
* (estimate approx 200-256 bytes of HTML per item; could be up to ~512) */
chunkqueue * const cq = &r->write_queue;
@@ -1174,6 +1176,9 @@ SUBREQUEST_FUNC(mod_dirlisting_subrequest) {
mod_dirlisting_response(r, hctx);
mod_dirlisting_reset(r, p); /*(release resources, including hctx)*/
break;
+ case HANDLER_WAIT_FOR_EVENT: /*(used here to mean 'yield')*/
+ joblist_append(r->con);
+ break;
default:
break;
}
