lpereira / lwan

Experimental, scalable, high performance HTTP server
https://lwan.ws
GNU General Public License v2.0
5.92k stars 549 forks source link

Disable cache but still make use of coroutine #72

Closed whatvn closed 9 years ago

whatvn commented 9 years ago

Hello,

I write a simple handler with lwan, this handler do a simple thing: when client make a request which ask server to delay x miliseconds then response, server sleeps x miliseconds then response ok to client. The reason I do this is we are trying to demonstrate real time bidding issue, when server have to response within 120ms for a bidding request, and client must close request after 120ms even if it does not receive response.

Write a handler which does not use coroutine is easy, but it causes blocking when many concurrent delay client make requests to lwan, it just can reply only some first requests, then cannot response at all.

Using coroutine is better, but I dont know how to use it without passing it through cache. Source code below:

/*

lwan_t l;

struct delay_info_t { struct cache_entry_t base; char key; const char callback; };

static struct cache_t *cache = NULL;

static struct cache_entry_t create_delay_info(const char input, void context attribute((unused))) { unsigned int i; uintmax_t delay = 0; bool valid = true; for (i = 0; i < strlen(input); i++) { if (!isdigit(input[i])) { valid = false; break; } } if (valid) { delay = strtoumax(input, NULL, 10); } if (!valid || (delay == UINTMAX_MAX && errno == ERANGE)) { return NULL; } time_t rawtime; struct tm * timeinfo; time ( &rawtime ); timeinfo = localtime ( &rawtime ); usleep((__useconds_t)delay * 1000); struct delay_info_t delay_info; delay_info = calloc(1, sizeof (struct delay_info_t)); delay_info->key = asctime(timeinfo); return (struct cache_entry_t *) delay_info; }

static void destroy_delayinfo(struct cache_entry_t entry, void context attribute((unused))) { struct delay_info_t delay_info = (struct delay_info_t ) entry; if (!delay_info) return; free(delay_info); }

lwan_http_status_t delay_handler(lwan_request_t _request, lwan_response_t response, void data attribute((unused))) { const char name = lwan_request_get_query_param(request, "delay"); struct cache_entry_t dl; dl = calloc(1, sizeof (struct cache_entry_t)); cache = cache_create(create_delay_info, destroy_delayinfo, NULL, 0); dl = cache_coro_get_and_ref_entry(cache, request->conn->coro, name); if (dl) { response->mime_type = "text/html"; strbuf_setstatic(response->buffer, (char) "ok", sizeof ("ok") - 1); cache_entry_unref(cache, dl); return HTTP_OK; } return HTTP_BAD_REQUEST; }

int main(void) { lwan_init(&l); // init cache cache = cache_create(create_fileinfo, destroy_fileinfo, NULL, 10); printf("Config root path: %s\n", l.config.root); lwan_main_loop(&l); lwan_shutdown(&l); return 0; }

As you can see, I try to make uniq cache key by current request time in order to disable caching, but lwan still cache request. If I make 2 request to server: http://localhost/d?delay=1000, 1 request will receive response in 1012 ms, the second one receive response in 10 ms (did not sleep)

So, the issue is: how to disable the cache in this case? I also try to remove assert(cache->time_to_live > 0) in lwan_cache.c to create cache with time_to_live = 0, but request is still cached.

Thanks

lpereira commented 9 years ago

Closing duplicate of #74.