Nginx is a powerful http server written by a Russian programmer Igor Sysoev. I suspect that
Rambler (one of the most popular Russian search engines) is powered by Nginx.
We are currently rewriting the ad server module of
Ad Server Beans in C using Nginx as the platform for serving our banner files, ad codes and registering actions and clicks.
The first version of Ad Server Beans will be all-Java though. In fact we are not going to abandon the Java branch of the ad server module some time in the future. Java is very powerful and flexible in terms of distributed deployment and development.
The reason why I want to use C and Nginx for the ad server module is mostly memory. It gets quite nasty in Java when you start caching data in memory using TreeMaps, HashMaps and Sets. It grows exponentially and takes up processor time to garbage collect.
C is different in that respect. You always know the size of your structs, pointers and you can easily calculate the memory consumption.
I'm not saying Java is bad, C is good. I guess I should say now I am a bad Java programmer and can't keep my memory accurate. Full stop.
Let's have a look at what I have written so far.
First I wrote a function that returns a pointer to ngx_str_t based on the the ngx_http_request_t.. This is the entry point for our module designed to serve ad codes.
ngx_str_t*
asb_http_ngx_handler(ngx_http_request_t *r)
{
asb_http_request_t *http_params;
http_params = asb_get_http_params(r);
return asb_fill_template(http_params);
}
In fact there is some boilerplate code necessary to create an nginx module. I copied it from the empty_gif module. To avoid browser caching you just shouldn't set r->headers_out.last_modified_time (where r is ngx_http_request_t *). In my case I commented out all lines that were setting it.
Next I created a struct that reflects the request parameters converted to convenient types for ASB. The following function does that:
struct asb_http_request_s {
u_char *target_url;
u_char *target_window;
ngx_int_t image_id;
u_char *image_src;
ngx_int_t width;
ngx_int_t height;
u_char *alt_text;
u_char *window_status;
ngx_int_t banner_id;
ngx_int_t event_id;
};
typedef struct asb_http_request_s asb_http_request_t;
asb_http_request_t*
asb_get_http_params(ngx_http_request_t *r)
{
asb_http_request_t *res;
ngx_str_t banner_id;
ngx_str_t event_id;
res = (asb_http_request_t*)malloc(sizeof(asb_http_request_t));
if (ngx_http_arg(r, (u_char *) "bannerId", 8, &banner_id) == NGX_OK) {
ngx_int_t b_id = ngx_atoi(banner_id.data, banner_id.len);
res->banner_id = b_id;
}else{
res->banner_id = 0;
}
if (ngx_http_arg(r, (u_char *) "eventId", 7, &event_id) == NGX_OK) {
ngx_int_t e_id = ngx_atoi(event_id.data, event_id.len);
res->event_id = e_id;
}else{
res->event_id = 0;
}
res->target_url = (u_char*)"http://www.adserverbeans.com/asb?eventId=4";
res->target_window = (u_char*)"_blank";
res->image_id = 1;
res->image_src = (u_char*)"http://www.adserverbeans.com";
res->width = 468;
res->height = 60;
res->alt_text = (u_char*)"Alt text!";
res->window_status = (u_char*)"window status!";
return res;
}
The strategy is similar to that of the Java implementation. Create an object that first collects converted request parameters then after banner selection occurs it is filled with values related to the selected banner. Finally we are using this object to fill our ad code template with them.
I haven't implemented the banner-selection algorithm in C yet but the template filling function looks like this:
ngx_str_t* asb_fill_template(asb_http_request_t* http_params)
{
ngx_str_t *res;
u_char *re;
re = (u_char*)calloc(asb_adcode_image_js_len+100,sizeof(u_char));
ngx_sprintf(re,ASB_ADCODE_IMAGE_JS,
http_params->target_url,
http_params->target_window,
http_params->image_id,
http_params->image_src,
http_params->width,
http_params->height,
http_params->alt_text,
http_params->window_status);
res = (ngx_str_t*)malloc(sizeof(ngx_str_t));
res->data = re;
res->len = ngx_strlen(re);
return res;
}
I don't like the idea of using malloc/calloc since nginx has its own overhead for these functions. But I still need to figure out the benefit of using nginx's memory management functions.
Next stop is banner selection. I am playing around with examples for
mysql connector/c as I will need to retrieve data from our database and store it in memory.