static int add_member(rlite *db, rl_btree *scores, long scores_page, rl_skiplist *skiplist, long skiplist_page, double score, unsigned char *member, long memberlen) { int retval; unsigned char *digest = NULL; void *value_ptr; RL_MALLOC(value_ptr, sizeof(double)); digest = rl_malloc(sizeof(unsigned char) * 20); if (!digest) { rl_free(value_ptr); retval = RL_OUT_OF_MEMORY; goto cleanup; } *(double *)value_ptr = score; retval = sha1(member, memberlen, digest); if (retval != RL_OK) { rl_free(value_ptr); rl_free(digest); goto cleanup; } RL_CALL(rl_btree_add_element, RL_OK, db, scores, scores_page, digest, value_ptr); retval = rl_skiplist_add(db, skiplist, skiplist_page, score, member, memberlen); if (retval != RL_OK) { // This failure is critical. The btree already has the element, but // the skiplist failed to add it. If left as is, it would be in an // inconsistent state. Dropping all the transaction in progress. rl_discard(db); goto cleanup; } cleanup: return retval; }
int rl_close(rlite *db) { if (!db) { return RL_OK; } if (db->driver_type == RL_FILE_DRIVER) { rl_unsubscribe_all(db); } // discard before removing the driver, since we need to release locks rl_discard(db); if (db->driver_type == RL_FILE_DRIVER) { rl_file_driver *driver = db->driver; rl_free(driver->filename); } else if (db->driver_type == RL_MEMORY_DRIVER) { rl_memory_driver* driver = db->driver; rl_free(driver->data); } if (db->subscriber_lock_filename) { remove(db->subscriber_lock_filename); rl_free(db->subscriber_lock_filename); } rl_free(db->driver); rl_free(db->subscriber_id); rl_free(db->read_pages); rl_free(db->write_pages); rl_free(db->databases); rl_free(db->initial_databases); rl_free(db); return RL_OK; }
int rl_commit(struct rlite *db) { int retval; RL_CALL(rl_write_apply_wal, RL_OK, db); db->initial_next_empty_page = db->next_empty_page; db->initial_number_of_pages = db->number_of_pages; db->initial_number_of_databases = db->number_of_databases; rl_free(db->initial_databases); RL_MALLOC(db->initial_databases, sizeof(long) * (db->number_of_databases + RLITE_INTERNAL_DB_COUNT)); memcpy(db->initial_databases, db->databases, sizeof(long) * (db->number_of_databases + RLITE_INTERNAL_DB_COUNT)); rl_discard(db); cleanup: return retval; }
TEST btree_insert_oom() { long btree_node_size = 2; rl_btree *btree = NULL; int retval; rlite *db = NULL; RL_CALL_VERBOSE(setup_db, RL_OK, &db, 0, 1); long *key; long *val; long j, i; int finished = 0; for (j = 1; !finished; j++) { for (i = 0; i < 7; i++) { test_mode = 0; RL_CALL_VERBOSE(rl_btree_create_size, RL_OK, db, &btree, &rl_btree_type_hash_long_long, btree_node_size); long btree_page = db->next_empty_page; RL_CALL_VERBOSE(rl_write, RL_OK, db, btree->type->btree_type, btree_page, btree); test_mode = 1; test_mode_caller = "rl_btree_add_element"; test_mode_counter = j; key = malloc(sizeof(long)); val = malloc(sizeof(long)); *key = i + 1; *val = i * 10; CHECK_RETVAL(rl_btree_add_element(db, btree, btree_page, key, val)); if (i == 6 && retval == RL_OK) { if (j == 1) { fprintf(stderr, "No OOM triggered\n"); test_mode = 0; FAIL(); } finished = 1; break; } } test_mode = 0; rl_discard(db); } test_mode = 0; rl_close(db); PASS(); }
int rl_write(struct rlite *db, rl_data_type *type, long page_number, void *obj) { // fprintf(stderr, "w %ld %s\n", page_number, type->name); rl_page *page = NULL; long pos; int retval; if (page_number == db->next_empty_page) { RL_CALL(rl_alloc_page_number, RL_OK, db, NULL); retval = rl_write(db, &rl_data_type_header, 0, NULL); if (retval != RL_OK) { goto cleanup; } } retval = rl_search_cache(db, type, page_number, NULL, &pos, NULL, db->write_pages, db->write_pages_len); if (retval == RL_FOUND) { if (obj != db->write_pages[pos]->obj) { if (db->write_pages[pos]->obj) { db->write_pages[pos]->type->destroy(db, db->write_pages[pos]->obj); } db->write_pages[pos]->obj = obj; db->write_pages[pos]->type = type; } retval = RL_OK; } else if (retval == RL_NOT_FOUND) { if (db->driver_type == RL_FILE_DRIVER) { RL_CALL(file_driver_fp, RL_OK, db); } rl_ensure_pages(db); RL_MALLOC(page, sizeof(*page)); #ifdef RL_DEBUG page->serialized_data = NULL; #endif page->page_number = page_number; page->type = type; page->obj = obj; if (pos < db->write_pages_len) { memmove(&db->write_pages[pos + 1], &db->write_pages[pos], sizeof(rl_page *) * (db->write_pages_len - pos)); } db->write_pages[pos] = page; db->write_pages_len++; retval = rl_search_cache(db, type, page_number, NULL, &pos, NULL, db->read_pages, db->read_pages_len); if (retval == RL_FOUND) { #ifdef RL_DEBUG rl_free(db->read_pages[pos]->serialized_data); #endif if (db->read_pages[pos]->obj != obj) { db->read_pages[pos]->type->destroy(db, db->read_pages[pos]->obj); } rl_free(db->read_pages[pos]); memmove(&db->read_pages[pos], &db->read_pages[pos + 1], sizeof(rl_page *) * (db->read_pages_len - pos)); db->read_pages_len--; retval = RL_OK; } else if (retval != RL_NOT_FOUND) { goto cleanup; } retval = RL_OK; } cleanup: if (retval != RL_OK) { if (obj) { type->destroy(db, obj); rl_purge_cache(db, page_number); } if (page_number != 0) { rl_discard(db); } } return retval; }