Skip to content

Commit

Permalink
Increase performance by taking less global locks
Browse files Browse the repository at this point in the history
Store progress data in request local pool, update shared memory twice per second

Signed-off-by: Michał Pokrywka <michal.pokrywka@gmail.com>
  • Loading branch information
mpokrywka committed Mar 2, 2011
1 parent 3193a18 commit d8246af
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 38 deletions.
7 changes: 7 additions & 0 deletions ap_backports.h
Expand Up @@ -6,6 +6,13 @@
# define ap_is_HTTP_VALID_RESPONSE(x) (((x) >= 100)&&((x) < 600))
#endif

/*
* apr_time_from_msec is defined in APR 1.4.0 or later
*/
#if (APR_MAJOR_VERSION < 1) || ((APR_MAJOR_VERSION == 1) && (APR_MINOR_VERSION < 4))
#define apr_time_from_msec(x) (x * 1000)
#endif

/*
* The following is a patch ported from mod_fcgid for Apache 2.0 releases
* which don't provide a version of apr_shm_remove.
Expand Down
96 changes: 58 additions & 38 deletions mod_upload_progress.c
Expand Up @@ -104,6 +104,11 @@ typedef struct upload_progress_node_s{
char key[ARG_MAXLEN_PROGRESSID];
} upload_progress_node_t;

typedef struct {
apr_time_t cache_updated_at;
upload_progress_node_t node;
} upload_progress_req_t;

typedef struct {
int count;
int active;
Expand Down Expand Up @@ -142,6 +147,12 @@ static inline DirConfig *get_dir_config(request_rec *r)
return (DirConfig *)ap_get_module_config(r->per_dir_config, &upload_progress_module);
}

static inline upload_progress_req_t *get_request_config(request_rec *r)
{
return (upload_progress_req_t *)ap_get_module_config(r->request_config, &upload_progress_module);
}


static int upload_progress_handle_request(request_rec *r)
{
server_rec *server = r->server;
Expand Down Expand Up @@ -184,6 +195,13 @@ static int upload_progress_handle_request(request_rec *r)
}

if (node) {
upload_progress_req_t *reqinfo = (upload_progress_req_t *)apr_pcalloc(r->pool,
sizeof(upload_progress_req_t));
if (reqinfo) {
reqinfo->cache_updated_at = apr_time_now();
memcpy(&(reqinfo->node), node, sizeof(upload_progress_node_t));
}
ap_set_module_config(r->request_config, &upload_progress_module, reqinfo);
apr_pool_cleanup_register(r->pool, r, upload_progress_cleanup, apr_pool_cleanup_null);
ap_add_input_filter("UPLOAD_PROGRESS", NULL, r, r->connection);
}
Expand Down Expand Up @@ -298,40 +316,44 @@ static int track_upload_progress(ap_filter_t *f, apr_bucket_brigade *bb,
{
server_rec *server = f->r->server;
/**/up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "track_upload_progress()");
apr_status_t rv;
upload_progress_node_t *node;
ServerConfig* config = get_server_config(server);

rv = ap_get_brigade(f->next, bb, mode, block, readbytes);

int param_error;
const char* id = get_progress_id(f->r, &param_error);
apr_status_t rv = ap_get_brigade(f->next, bb, mode, block, readbytes);

if (id == NULL) {
up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "Progress id not found, param_error %i", param_error);
upload_progress_req_t *reqinfo = get_request_config(f->r);
if (!reqinfo) {
up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "Request config not available");
return rv;
}
upload_progress_node_t *node = &(reqinfo->node);

CACHE_LOCK();
node = find_node(server, id);
if (node) {
time_t t = time(NULL);
node->updated_at = t;
if (rv == APR_SUCCESS) {
apr_off_t length;
apr_brigade_length(bb, 1, &length);
node->received += length;
if (node->received > node->length) /* handle chunked tranfer */
node->length = node->received;
int upload_time = t - node->started_at;
if (upload_time > 0) {
node->speed = node->received / upload_time;
}
} else {
node->err_status = read_request_status(f->r);
time_t t = time(NULL);
node->updated_at = t;
if (rv == APR_SUCCESS) {
apr_off_t length;
apr_brigade_length(bb, 1, &length);
node->received += length;
if (node->received > node->length) /* handle chunked tranfer */
node->length = node->received;
int upload_time = t - node->started_at;
if (upload_time > 0) {
node->speed = node->received / upload_time;
}
} else {
node->err_status = read_request_status(f->r);
reqinfo->cache_updated_at = 0; /* force cache update */
}

apr_time_t now = apr_time_now();
if ((now - reqinfo->cache_updated_at) > apr_time_from_msec(500)) {
reqinfo->cache_updated_at = now;
CACHE_LOCK();
upload_progress_node_t *cache_node = find_node(server, node->key);
if (cache_node) {
memcpy(cache_node, node, sizeof(upload_progress_node_t);
}
CACHE_UNLOCK();
}
CACHE_UNLOCK();

return rv;
}
Expand Down Expand Up @@ -469,22 +491,20 @@ static apr_status_t upload_progress_cleanup(void *data)
/**/up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "upload_progress_cleanup()");
ServerConfig *config = get_server_config(server);

int param_error;
const char* id = get_progress_id(r, &param_error);

if (id == NULL) {
up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "Progress id not found, param_error %i", param_error);
upload_progress_req_t *reqinfo = get_request_config(r);
if (!reqinfo) {
up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "Request config not available");
return APR_SUCCESS;
}
upload_progress_node_t *node = &(reqinfo->node);
node->err_status = read_request_status(r);
node->updated_at = time(NULL);
node->done = 1;

CACHE_LOCK();
upload_progress_node_t *node = find_node(server, id);
if (node) {
node->err_status = read_request_status(r);
node->updated_at = time(NULL);
node->done = 1;
} else {
up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "Node not found for id %s", id);
upload_progress_node_t *cache_node = find_node(server, node->key);
if (cache_node) {
memcpy(cache_node, node, sizeof(upload_progress_node_t));
}
CACHE_UNLOCK();

Expand Down

0 comments on commit d8246af

Please sign in to comment.