Mercurial > urweb
comparison src/c/urweb.c @ 2211:ef766ef6e242
Merge.
author | Ziv Scully <ziv@mit.edu> |
---|---|
date | Sat, 13 Sep 2014 19:16:07 -0400 |
parents | 0ca11d57c175 a9159911c3ba |
children | 98b87d905601 |
comparison
equal
deleted
inserted
replaced
2210:69c0f36255cb | 2211:ef766ef6e242 |
---|---|
439 | 439 |
440 cleanup *cleanup, *cleanup_front, *cleanup_back; | 440 cleanup *cleanup, *cleanup_front, *cleanup_back; |
441 | 441 |
442 const char *script_header; | 442 const char *script_header; |
443 | 443 |
444 int needs_push, needs_sig, could_write_db; | 444 int needs_push, needs_sig, could_write_db, at_most_one_query; |
445 | 445 |
446 size_t n_deltas, used_deltas; | 446 size_t n_deltas, used_deltas; |
447 delta *deltas; | 447 delta *deltas; |
448 | 448 |
449 client *client; | 449 client *client; |
521 | 521 |
522 ctx->script_header = ""; | 522 ctx->script_header = ""; |
523 ctx->needs_push = 0; | 523 ctx->needs_push = 0; |
524 ctx->needs_sig = 0; | 524 ctx->needs_sig = 0; |
525 ctx->could_write_db = 1; | 525 ctx->could_write_db = 1; |
526 ctx->at_most_one_query = 0; | |
526 | 527 |
527 ctx->source_count = 0; | 528 ctx->source_count = 0; |
528 | 529 |
529 ctx->n_deltas = ctx->used_deltas = 0; | 530 ctx->n_deltas = ctx->used_deltas = 0; |
530 ctx->deltas = malloc(0); | 531 ctx->deltas = malloc(0); |
789 | 790 |
790 return r; | 791 return r; |
791 } | 792 } |
792 | 793 |
793 void uw_ensure_transaction(uw_context ctx) { | 794 void uw_ensure_transaction(uw_context ctx) { |
794 if (!ctx->transaction_started) { | 795 if (!ctx->transaction_started && !ctx->at_most_one_query) { |
795 if (ctx->app->db_begin(ctx, ctx->could_write_db)) | 796 if (ctx->app->db_begin(ctx, ctx->could_write_db)) |
796 uw_error(ctx, BOUNDED_RETRY, "Error running SQL BEGIN"); | 797 uw_error(ctx, BOUNDED_RETRY, "Error running SQL BEGIN"); |
797 ctx->transaction_started = 1; | 798 ctx->transaction_started = 1; |
798 } | 799 } |
799 } | 800 } |
1046 | 1047 |
1047 int uw_set_file_input(uw_context ctx, const char *name, uw_Basis_file f) { | 1048 int uw_set_file_input(uw_context ctx, const char *name, uw_Basis_file f) { |
1048 int n = ctx->app->input_num(name); | 1049 int n = ctx->app->input_num(name); |
1049 | 1050 |
1050 if (n < 0) { | 1051 if (n < 0) { |
1051 uw_set_error(ctx, "Bad file input name %s", uw_Basis_htmlifyString(ctx, name)); | 1052 uw_set_error(ctx, "Bad file input name"); |
1052 return -1; | 1053 return -1; |
1053 } | 1054 } |
1054 | 1055 |
1055 if (n >= ctx->app->inputs_len) { | 1056 if (n >= ctx->app->inputs_len) { |
1056 uw_set_error(ctx, "For file input name %s, index %d is out of range", uw_Basis_htmlifyString(ctx, name), n); | 1057 uw_set_error(ctx, "For file input name, index %d is out of range", n); |
1057 return -1; | 1058 return -1; |
1058 } | 1059 } |
1059 | 1060 |
1060 ctx->inputs[n].kind = FIL; | 1061 ctx->inputs[n].kind = FIL; |
1061 ctx->inputs[n].data.file = f; | 1062 ctx->inputs[n].data.file = f; |
1206 ctx->needs_sig = n; | 1207 ctx->needs_sig = n; |
1207 } | 1208 } |
1208 | 1209 |
1209 void uw_set_could_write_db(uw_context ctx, int n) { | 1210 void uw_set_could_write_db(uw_context ctx, int n) { |
1210 ctx->could_write_db = n; | 1211 ctx->could_write_db = n; |
1212 } | |
1213 | |
1214 void uw_set_at_most_one_query(uw_context ctx, int n) { | |
1215 ctx->at_most_one_query = n; | |
1211 } | 1216 } |
1212 | 1217 |
1213 | 1218 |
1214 static void uw_buffer_check_ctx(uw_context ctx, const char *kind, uw_buffer *b, size_t extra, const char *desc) { | 1219 static void uw_buffer_check_ctx(uw_context ctx, const char *kind, uw_buffer *b, size_t extra, const char *desc) { |
1215 if (b->back - b->front < extra) { | 1220 if (b->back - b->front < extra) { |
3315 return NULL; | 3320 return NULL; |
3316 | 3321 |
3317 return s; | 3322 return s; |
3318 } | 3323 } |
3319 | 3324 |
3325 static pthread_mutex_t message_send_mutex = PTHREAD_MUTEX_INITIALIZER; | |
3326 | |
3320 int uw_commit(uw_context ctx) { | 3327 int uw_commit(uw_context ctx) { |
3321 int i; | 3328 int i; |
3322 char *sig; | 3329 char *sig; |
3323 | 3330 |
3324 if (uw_has_error(ctx)) { | 3331 if (uw_has_error(ctx)) { |
3334 uw_rollback(ctx, 0); | 3341 uw_rollback(ctx, 0); |
3335 return 0; | 3342 return 0; |
3336 } | 3343 } |
3337 } | 3344 } |
3338 | 3345 |
3346 // Here's an important lock to provide the abstraction that all messages from one transaction are sent as an atomic unit. | |
3347 if (ctx->used_deltas > 0) | |
3348 pthread_mutex_lock(&message_send_mutex); | |
3349 | |
3339 if (ctx->transaction_started) { | 3350 if (ctx->transaction_started) { |
3340 int code = ctx->app->db_commit(ctx); | 3351 int code = ctx->app->db_commit(ctx); |
3341 | 3352 |
3342 if (code) { | 3353 if (code) { |
3354 if (ctx->used_deltas > 0) | |
3355 pthread_mutex_unlock(&message_send_mutex); | |
3356 | |
3343 if (ctx->client) | 3357 if (ctx->client) |
3344 release_client(ctx->client); | 3358 release_client(ctx->client); |
3345 | 3359 |
3346 if (code == -1) { | 3360 if (code == -1) { |
3347 // This case is for a serialization failure, which is not really an "error." | 3361 // This case is for a serialization failure, which is not really an "error." |
3354 | 3368 |
3355 for (i = ctx->used_transactionals-1; i >= 0; --i) | 3369 for (i = ctx->used_transactionals-1; i >= 0; --i) |
3356 if (ctx->transactionals[i].free) | 3370 if (ctx->transactionals[i].free) |
3357 ctx->transactionals[i].free(ctx->transactionals[i].data, 1); | 3371 ctx->transactionals[i].free(ctx->transactionals[i].data, 1); |
3358 | 3372 |
3359 return 1; | 3373 return 1; |
3360 } | 3374 } |
3361 | 3375 |
3362 for (i = ctx->used_transactionals-1; i >= 0; --i) | 3376 for (i = ctx->used_transactionals-1; i >= 0; --i) |
3363 if (ctx->transactionals[i].free) | 3377 if (ctx->transactionals[i].free) |
3364 ctx->transactionals[i].free(ctx->transactionals[i].data, 0); | 3378 ctx->transactionals[i].free(ctx->transactionals[i].data, 0); |
3371 for (i = ctx->used_transactionals-1; i >= 0; --i) | 3385 for (i = ctx->used_transactionals-1; i >= 0; --i) |
3372 if (ctx->transactionals[i].rollback == NULL) | 3386 if (ctx->transactionals[i].rollback == NULL) |
3373 if (ctx->transactionals[i].commit) { | 3387 if (ctx->transactionals[i].commit) { |
3374 ctx->transactionals[i].commit(ctx->transactionals[i].data); | 3388 ctx->transactionals[i].commit(ctx->transactionals[i].data); |
3375 if (uw_has_error(ctx)) { | 3389 if (uw_has_error(ctx)) { |
3376 if (ctx->client) | 3390 if (ctx->used_deltas > 0) |
3377 release_client(ctx->client); | 3391 pthread_mutex_unlock(&message_send_mutex); |
3378 | 3392 |
3379 for (i = ctx->used_transactionals-1; i >= 0; --i) | 3393 if (ctx->client) |
3380 if (ctx->transactionals[i].rollback != NULL) | 3394 release_client(ctx->client); |
3381 ctx->transactionals[i].rollback(ctx->transactionals[i].data); | 3395 |
3382 | 3396 for (i = ctx->used_transactionals-1; i >= 0; --i) |
3383 for (i = ctx->used_transactionals-1; i >= 0; --i) | 3397 if (ctx->transactionals[i].rollback != NULL) |
3384 if (ctx->transactionals[i].free) | 3398 ctx->transactionals[i].rollback(ctx->transactionals[i].data); |
3385 ctx->transactionals[i].free(ctx->transactionals[i].data, 0); | 3399 |
3400 for (i = ctx->used_transactionals-1; i >= 0; --i) | |
3401 if (ctx->transactionals[i].free) | |
3402 ctx->transactionals[i].free(ctx->transactionals[i].data, 0); | |
3386 | 3403 |
3387 return 0; | 3404 return 0; |
3388 } | 3405 } |
3389 } | 3406 } |
3390 | 3407 |
3395 assert (c != NULL); | 3412 assert (c != NULL); |
3396 assert(c->mode == USED); | 3413 assert(c->mode == USED); |
3397 | 3414 |
3398 client_send(c, &d->msgs, ctx->script.start, uw_buffer_used(&ctx->script)); | 3415 client_send(c, &d->msgs, ctx->script.start, uw_buffer_used(&ctx->script)); |
3399 } | 3416 } |
3417 | |
3418 if (ctx->used_deltas > 0) | |
3419 pthread_mutex_unlock(&message_send_mutex); | |
3400 | 3420 |
3401 if (ctx->client) | 3421 if (ctx->client) |
3402 release_client(ctx->client); | 3422 release_client(ctx->client); |
3403 | 3423 |
3404 for (i = ctx->used_transactionals-1; i >= 0; --i) | 3424 for (i = ctx->used_transactionals-1; i >= 0; --i) |
3615 return NULL; | 3635 return NULL; |
3616 } | 3636 } |
3617 | 3637 |
3618 static int mime_format(const char *s) { | 3638 static int mime_format(const char *s) { |
3619 for (; *s; ++s) | 3639 for (; *s; ++s) |
3620 if (!isalnum((int)*s) && *s != '/' && *s != '-' && *s != '.') | 3640 if (!isalnum((int)*s) && *s != '/' && *s != '-' && *s != '.' && *s != '+') |
3621 return 0; | 3641 return 0; |
3622 | 3642 |
3623 return 1; | 3643 return 1; |
3624 } | 3644 } |
3625 | 3645 |
3855 cl->func(cl->arg); | 3875 cl->func(cl->arg); |
3856 | 3876 |
3857 ctx->cleanup_front = ctx->cleanup; | 3877 ctx->cleanup_front = ctx->cleanup; |
3858 | 3878 |
3859 longjmp(ctx->jmp_buf, RETURN_INDIRECTLY); | 3879 longjmp(ctx->jmp_buf, RETURN_INDIRECTLY); |
3880 } | |
3881 | |
3882 void uw_replace_page(uw_context ctx, const char *data, size_t size) { | |
3883 uw_buffer_reset(&ctx->page); | |
3884 ctx_uw_buffer_append(ctx, "page", &ctx->page, data, size); | |
3860 } | 3885 } |
3861 | 3886 |
3862 __attribute__((noreturn)) void uw_return_blob_from_page(uw_context ctx, uw_Basis_string mimeType) { | 3887 __attribute__((noreturn)) void uw_return_blob_from_page(uw_context ctx, uw_Basis_string mimeType) { |
3863 cleanup *cl; | 3888 cleanup *cl; |
3864 int len; | 3889 int len; |
4267 uw_Basis_bool uw_Basis_eq_time(uw_context ctx, uw_Basis_time t1, uw_Basis_time t2) { | 4292 uw_Basis_bool uw_Basis_eq_time(uw_context ctx, uw_Basis_time t1, uw_Basis_time t2) { |
4268 return !!(t1.seconds == t2.seconds && t1.microseconds == t2.microseconds); | 4293 return !!(t1.seconds == t2.seconds && t1.microseconds == t2.microseconds); |
4269 } | 4294 } |
4270 | 4295 |
4271 uw_Basis_bool uw_Basis_lt_time(uw_context ctx, uw_Basis_time t1, uw_Basis_time t2) { | 4296 uw_Basis_bool uw_Basis_lt_time(uw_context ctx, uw_Basis_time t1, uw_Basis_time t2) { |
4272 return !!(t1.seconds < t2.seconds || t1.microseconds < t2.microseconds); | 4297 return !!(t1.seconds < t2.seconds || (t1.seconds == t2.seconds && t1.microseconds < t2.microseconds)); |
4273 } | 4298 } |
4274 | 4299 |
4275 uw_Basis_bool uw_Basis_le_time(uw_context ctx, uw_Basis_time t1, uw_Basis_time t2) { | 4300 uw_Basis_bool uw_Basis_le_time(uw_context ctx, uw_Basis_time t1, uw_Basis_time t2) { |
4276 return !!(uw_Basis_eq_time(ctx, t1, t2) || uw_Basis_lt_time(ctx, t1, t2)); | 4301 return !!(uw_Basis_eq_time(ctx, t1, t2) || uw_Basis_lt_time(ctx, t1, t2)); |
4277 } | 4302 } |