/** Check if the ticket has already been issued * @return 0 if not unique; otherwise 1 */ static int __check_if_ticket_exists(const unsigned int ticket) { MDB_txn *txn; int e = mdb_txn_begin(sv->db_env, NULL, MDB_RDONLY, &txn); if (0 != e) mdb_fatal(e); MDB_val k = { .mv_size = sizeof(ticket), .mv_data = (void*)&ticket }; MDB_val v; e = mdb_get(txn, sv->tickets, &k, &v); switch (e) { case 0: break; case MDB_NOTFOUND: e = mdb_txn_commit(txn); if (0 != e) mdb_fatal(e); return 0; default: mdb_fatal(e); } e = mdb_txn_commit(txn); if (0 != e) mdb_fatal(e); return 1; } static unsigned int __generate_ticket() { unsigned int ticket; do { // TODO need better random number generator ticket = rand(); } while (__check_if_ticket_exists(ticket)); return ticket; }
static int __batcher_commit(batch_monitor_t* m, batch_queue_t* bq) { if (0 == heap_count(bq->queue)) return 0; MDB_txn *txn; int e = mdb_txn_begin(sv->db_env, NULL, 0, &txn); if (0 != e) mdb_fatal(e); while (0 < heap_count(bq->queue)) { batch_item_t* item = heap_poll(bq->queue); e = mdb_put(txn, sv->docs, &item->key, &item->val, item->flags); switch (e) { case 0: break; case MDB_MAP_FULL: { mdb_txn_abort(txn); while ((item = heap_poll(bq->queue))) ; snprintf(batcher_error, BATCHER_ERROR_LEN, "NOT ENOUGH SPACE"); return -1; } case MDB_KEYEXIST: item->flags = WOULD_OVERWRITE; break; default: mdb_fatal(e); } } e = mdb_txn_commit(txn); if (0 != e) mdb_fatal(e); return 0; }
/** Get a list of document keys where the key prefix matches the provided key */ static int __get_keys(h2o_req_t *req, kstr_t* key) { get_keys_generator_t *gen = h2o_mem_alloc_pool(&req->pool, sizeof(*gen)); gen->super.proceed = __get_keys_proceed; gen->super.stop = __get_keys_close; gen->req = req; gen->key = key; req->res.status = 200; req->res.reason = "OK"; h2o_start_response(req, &gen->super); int e; e = mdb_txn_begin(sv->db_env, NULL, MDB_RDONLY, &gen->txn); if (0 != e) mdb_fatal(e); e = mdb_cursor_open(gen->txn, sv->docs, &gen->curs); if (0 != e) mdb_fatal(e); MDB_val k = { .mv_size = key->len, .mv_data = key->s }, v;
/** Put a document into the database at this key * If the "Prefers: ETag" header is set, we perform a CAS operation */ static int __put(h2o_req_t *req, kstr_t* key) { char* sv_etag = __remove_stored_etag(key); h2o_iovec_t cli_etag = __get_if_match_header_value(req, key); if (0 < cli_etag.len && !__should_etag_conditional_put_succeed(req, key, sv_etag, &cli_etag)) { if (sv_etag) free(sv_etag); return h2oh_respond_with_error(req, 412, "BAD ETAG"); } if (sv_etag) free(sv_etag); batch_item_t item = { .flags = 0, .key.mv_data = key->s, .key.mv_size = key->len, .val.mv_data = req->entity.base, .val.mv_size = req->entity.len, }; int e = bmon_offer(&sv->batch, &item); if (0 != e) return h2oh_respond_with_error(req, 400, batcher_error); return h2oh_respond_with_success(req, 200); } typedef struct { h2o_generator_t super; h2o_req_t *req; MDB_txn *txn; MDB_cursor* curs; kstr_t* key; } get_keys_generator_t; static void __get_keys_close(h2o_generator_t *_self, h2o_req_t *req) { get_keys_generator_t *gen = (void*)_self; mdb_cursor_close(gen->curs); int e = mdb_txn_commit(gen->txn); if (0 != e) mdb_fatal(e); }