/*******************************************************************//** Rolls back a transaction back to a named savepoint. Modifications after the savepoint are undone but InnoDB does NOT release the corresponding locks which are stored in memory. If a lock is 'implicit', that is, a new inserted row holds a lock where the lock information is carried by the trx id stored in the row, these locks are naturally released in the rollback. Savepoints which were set after this savepoint are deleted. @return if no savepoint of the name found then DB_NO_SAVEPOINT, otherwise DB_SUCCESS */ UNIV_INTERN ulint trx_rollback_to_savepoint_for_mysql( /*================================*/ trx_t* trx, /*!< in: transaction handle */ const char* savepoint_name, /*!< in: savepoint name */ ib_int64_t* mysql_binlog_cache_pos) /*!< out: the MySQL binlog cache position corresponding to this savepoint; MySQL needs this information to remove the binlog entries of the queries executed after the savepoint */ { trx_named_savept_t* savep; ulint err; savep = UT_LIST_GET_FIRST(trx->trx_savepoints); while (savep != NULL) { if (0 == ut_strcmp(savep->name, savepoint_name)) { /* Found */ break; } savep = UT_LIST_GET_NEXT(trx_savepoints, savep); } if (savep == NULL) { return(DB_NO_SAVEPOINT); } if (trx->conc_state == TRX_NOT_STARTED) { ut_print_timestamp(stderr); fputs(" InnoDB: Error: transaction has a savepoint ", stderr); ut_print_name(stderr, trx, FALSE, savep->name); fputs(" though it is not started\n", stderr); return(DB_ERROR); } /* We can now free all savepoints strictly later than this one */ trx_roll_savepoints_free(trx, savep); *mysql_binlog_cache_pos = savep->mysql_binlog_cache_pos; trx->op_info = "rollback to a savepoint"; err = trx_general_rollback_for_mysql(trx, &savep->savept); /* Store the current undo_no of the transaction so that we know where to roll back if we have to roll back the next SQL statement: */ trx_mark_sql_stat_end(trx); trx->op_info = ""; return(err); }
/*******************************************************************//** Creates a named savepoint. If the transaction is not yet started, starts it. If there is already a savepoint of the same name, this call erases that old savepoint and replaces it with a new. Savepoints are deleted in a transaction commit or rollback. @return always DB_SUCCESS */ UNIV_INTERN ulint trx_savepoint_for_mysql( /*====================*/ trx_t* trx, /*!< in: transaction handle */ const char* savepoint_name, /*!< in: savepoint name */ ib_int64_t binlog_cache_pos) /*!< in: MySQL binlog cache position corresponding to this connection at the time of the savepoint */ { trx_named_savept_t* savep; ut_a(trx); ut_a(savepoint_name); trx_start_if_not_started(trx); savep = UT_LIST_GET_FIRST(trx->trx_savepoints); while (savep != NULL) { if (0 == ut_strcmp(savep->name, savepoint_name)) { /* Found */ break; } savep = UT_LIST_GET_NEXT(trx_savepoints, savep); } if (savep) { /* There is a savepoint with the same name: free that */ UT_LIST_REMOVE(trx_savepoints, trx->trx_savepoints, savep); mem_free(savep->name); mem_free(savep); } /* Create a new savepoint and add it as the last in the list */ savep = mem_alloc(sizeof(trx_named_savept_t)); savep->name = mem_strdup(savepoint_name); savep->savept = trx_savept_take(trx); savep->mysql_binlog_cache_pos = binlog_cache_pos; UT_LIST_ADD_LAST(trx_savepoints, trx->trx_savepoints, savep); return(DB_SUCCESS); }
/*******************************************************************//** Releases only the named savepoint. Savepoints which were set after this savepoint are left as is. @return if no savepoint of the name found then DB_NO_SAVEPOINT, otherwise DB_SUCCESS */ UNIV_INTERN ulint trx_release_savepoint_for_mysql( /*============================*/ trx_t* trx, /*!< in: transaction handle */ const char* savepoint_name) /*!< in: savepoint name */ { trx_named_savept_t* savep; savep = UT_LIST_GET_FIRST(trx->trx_savepoints); /* Search for the savepoint by name and free if found. */ while (savep != NULL) { if (0 == ut_strcmp(savep->name, savepoint_name)) { trx_roll_savepoint_free(trx, savep); return(DB_SUCCESS); } savep = UT_LIST_GET_NEXT(trx_savepoints, savep); } return(DB_NO_SAVEPOINT); }
/* * Show free area list (used inside shift_scroll-lock stuff) * We also calculate the percentage fragmentation. We do this by counting the * memory on each free list with the exception of the first item on the list. */ int Jcmd_mem(char *arg1, char *arg2) { unsigned long order, flags; unsigned long total = 0; spin_lock_irqsave(&free_area_lock, flags); for (order = 0; order < NR_MEM_LISTS; order++) { struct page * tmp; unsigned long nr = 0; for (tmp = free_mem_area[order].next; tmp != memory_head(free_mem_area+order); tmp = tmp->next) { nr++; } total += nr << order; ut_printf("%d(%d): count:%d static count:%d total:%d (%dM)\n", order,1<<order, nr, free_mem_area[order].stat_count, (nr << order), ((nr << order)*PAGE_SIZE)/(1024*1024)); } spin_unlock_irqrestore(&free_area_lock, flags); ut_printf("total Free pages = %d (%dM) Actual pages: %d (%dM) pagecachesize: %dM , freepages:%d\n", total, (total * 4) / 1024,g_stat_mem_size/PAGE_SIZE,g_stat_mem_size/(1024*1024),g_pagecache_size/(1024*1024),g_nr_free_pages); int slab=0; int referenced=0; int reserved=0; int dma=0; unsigned long va_end=(unsigned long)__va(g_phy_mem_size); page_struct_t *p; p = g_mem_map + MAP_NR(va_end); do { --p; if (PageReserved(p)) reserved++; if (PageDMA(p)) dma++; if (PageReferenced(p))referenced++; if (PageSlab(p)) slab++; } while (p > g_mem_map); ut_printf(" reserved :%d(%dM) referenced:%d dma:%d slab:%d stat_allocs:%d stat_frees: %d\n\n",reserved,(reserved*PAGE_SIZE)/(1024*1024),referenced,dma,slab,stat_allocs,stat_frees); if ((arg1 != 0) && (ut_strcmp(arg1,"all")==0)) Jcmd_jslab(0,0); return 1; }
/*******************************************************************//** Set the value of the config variable "flush_method". ib_cfg_var_set_flush_method@{ @return DB_SUCCESS if set successfully */ static ib_err_t ib_cfg_var_set_flush_method( /*========================*/ struct ib_cfg_var* cfg_var,/*!< in/out: configuration variable to manipulate, must be "log_group_home_dir" */ const void* value) /*!< in: value to set, must point to char* variable */ { const char* value_str; ib_err_t err = DB_SUCCESS; ut_a(strcasecmp(cfg_var->name, "flush_method") == 0); ut_a(cfg_var->type == IB_CFG_TEXT); value_str = *(const char**) value; os_aio_use_native_aio = FALSE; #ifndef __WIN__ if (0 == ut_strcmp(value_str, "fsync")) { srv_unix_file_flush_method = SRV_UNIX_FSYNC; } else if (0 == ut_strcmp(value_str, "O_DSYNC")) { srv_unix_file_flush_method = SRV_UNIX_O_DSYNC; } else if (0 == ut_strcmp(value_str, "O_DIRECT")) { srv_unix_file_flush_method = SRV_UNIX_O_DIRECT; } else if (0 == ut_strcmp(value_str, "littlesync")) { srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC; } else if (0 == ut_strcmp(value_str, "nosync")) { srv_unix_file_flush_method = SRV_UNIX_NOSYNC; } else { err = DB_INVALID_INPUT; } #else if (0 == ut_strcmp(value_str, "normal")) { srv_win_file_flush_method = SRV_WIN_IO_NORMAL; } else if (0 == ut_strcmp(value_str, "unbuffered")) { srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED; } else if (0 == ut_strcmp(value_str, "async_unbuffered")) { srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED; } else { err = DB_INVALID_INPUT; } if (err == DB_SUCCESS) { switch (os_get_os_version()) { case OS_WIN95: case OS_WIN31: case OS_WINNT: /* On Win 95, 98, ME, Win32 subsystem for Windows 3.1, and NT use simulated aio. In NT Windows provides async i/o, but when run in conjunction with InnoDB Hot Backup, it seemed to corrupt the data files. */ os_aio_use_native_aio = FALSE; break; default: /* On Win 2000 and XP use async i/o */ os_aio_use_native_aio = TRUE; break; } } #endif if (err == DB_SUCCESS) { *(const char**) cfg_var->tank = value_str; } else { *(const char**) cfg_var->tank = NULL; } return(err); }
/************************************************************************ Loads definitions for index fields. */ static void dict_load_fields( /*=============*/ dict_table_t* table, /* in: table */ dict_index_t* index, /* in: index whose fields to load */ mem_heap_t* heap) /* in: memory heap for temporary storage */ { dict_table_t* sys_fields; dict_index_t* sys_index; btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; char* col_name; rec_t* rec; byte* field; ulint len; byte* buf; ulint i; mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); UT_NOT_USED(table); mtr_start(&mtr); sys_fields = dict_table_get_low("SYS_FIELDS"); sys_index = UT_LIST_GET_FIRST(sys_fields->indexes); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); buf = mem_heap_alloc(heap, 8); mach_write_to_8(buf, index->id); dfield_set_data(dfield, buf, 8); dict_index_copy_types(tuple, sys_index, 1); btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); for (i = 0; i < index->n_fields; i++) { rec = btr_pcur_get_rec(&pcur); ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr)); ut_a(!rec_get_deleted_flag(rec)); field = rec_get_nth_field(rec, 0, &len); ut_ad(len == 8); ut_a(ut_memcmp(buf, field, len) == 0); field = rec_get_nth_field(rec, 1, &len); ut_ad(len == 4); ut_a(i == mach_read_from_4(field)); ut_a(0 == ut_strcmp("COL_NAME", dict_field_get_col( dict_index_get_nth_field( dict_table_get_first_index(sys_fields), 4))->name)); field = rec_get_nth_field(rec, 4, &len); col_name = mem_heap_alloc(heap, len + 1); ut_memcpy(col_name, field, len); col_name[len] = '\0'; dict_mem_index_add_field(index, col_name, 0); btr_pcur_move_to_next_user_rec(&pcur, &mtr); } btr_pcur_close(&pcur); mtr_commit(&mtr); }
/************************************************************************ Loads definitions for table indexes. Adds them to the data dictionary cache. */ static void dict_load_indexes( /*==============*/ dict_table_t* table, /* in: table */ mem_heap_t* heap) /* in: memory heap for temporary storage */ { dict_table_t* sys_indexes; dict_index_t* sys_index; dict_index_t* index; btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; rec_t* rec; byte* field; ulint len; ulint name_len; char* name_buf; ulint type; ulint space; ulint page_no; ulint n_fields; byte* buf; ibool is_sys_table; dulint id; mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); if ((ut_dulint_get_high(table->id) == 0) && (ut_dulint_get_low(table->id) < DICT_HDR_FIRST_ID)) { is_sys_table = TRUE; } else { is_sys_table = FALSE; } mtr_start(&mtr); sys_indexes = dict_table_get_low("SYS_INDEXES"); sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); buf = mem_heap_alloc(heap, 8); mach_write_to_8(buf, table->id); dfield_set_data(dfield, buf, 8); dict_index_copy_types(tuple, sys_index, 1); btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); for (;;) { if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { break; } rec = btr_pcur_get_rec(&pcur); field = rec_get_nth_field(rec, 0, &len); ut_ad(len == 8); if (ut_memcmp(buf, field, len) != 0) { break; } ut_a(!rec_get_deleted_flag(rec)); field = rec_get_nth_field(rec, 1, &len); ut_ad(len == 8); id = mach_read_from_8(field); ut_a(0 == ut_strcmp("NAME", dict_field_get_col( dict_index_get_nth_field( dict_table_get_first_index(sys_indexes), 4))->name)); field = rec_get_nth_field(rec, 4, &name_len); name_buf = mem_heap_alloc(heap, name_len + 1); ut_memcpy(name_buf, field, name_len); name_buf[name_len] = '\0'; field = rec_get_nth_field(rec, 5, &len); n_fields = mach_read_from_4(field); field = rec_get_nth_field(rec, 6, &len); type = mach_read_from_4(field); field = rec_get_nth_field(rec, 7, &len); space = mach_read_from_4(field); ut_a(0 == ut_strcmp("PAGE_NO", dict_field_get_col( dict_index_get_nth_field( dict_table_get_first_index(sys_indexes), 8))->name)); field = rec_get_nth_field(rec, 8, &len); page_no = mach_read_from_4(field); if (is_sys_table && ((type & DICT_CLUSTERED) || ((table == dict_sys->sys_tables) && (name_len == ut_strlen("ID_IND")) && (0 == ut_memcmp(name_buf, "ID_IND", name_len))))) { /* The index was created in memory already in booting */ } else { index = dict_mem_index_create(table->name, name_buf, space, type, n_fields); index->page_no = page_no; index->id = id; dict_load_fields(table, index, heap); dict_index_add_to_cache(table, index); } btr_pcur_move_to_next_user_rec(&pcur, &mtr); } btr_pcur_close(&pcur); mtr_commit(&mtr); }
/************************************************************************ Loads definitions for table columns. */ static void dict_load_columns( /*==============*/ dict_table_t* table, /* in: table */ mem_heap_t* heap) /* in: memory heap for temporary storage */ { dict_table_t* sys_columns; dict_index_t* sys_index; btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; rec_t* rec; byte* field; ulint len; byte* buf; char* name_buf; char* name; ulint mtype; ulint prtype; ulint col_len; ulint prec; ulint i; mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); mtr_start(&mtr); sys_columns = dict_table_get_low("SYS_COLUMNS"); sys_index = UT_LIST_GET_FIRST(sys_columns->indexes); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); buf = mem_heap_alloc(heap, 8); mach_write_to_8(buf, table->id); dfield_set_data(dfield, buf, 8); dict_index_copy_types(tuple, sys_index, 1); btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); for (i = 0; i < table->n_cols - DATA_N_SYS_COLS; i++) { rec = btr_pcur_get_rec(&pcur); ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr)); ut_a(!rec_get_deleted_flag(rec)); field = rec_get_nth_field(rec, 0, &len); ut_ad(len == 8); ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0); field = rec_get_nth_field(rec, 1, &len); ut_ad(len == 4); ut_a(i == mach_read_from_4(field)); ut_a(0 == ut_strcmp("NAME", dict_field_get_col( dict_index_get_nth_field( dict_table_get_first_index(sys_columns), 4))->name)); field = rec_get_nth_field(rec, 4, &len); name_buf = mem_heap_alloc(heap, len + 1); ut_memcpy(name_buf, field, len); name_buf[len] = '\0'; name = name_buf; field = rec_get_nth_field(rec, 5, &len); mtype = mach_read_from_4(field); field = rec_get_nth_field(rec, 6, &len); prtype = mach_read_from_4(field); field = rec_get_nth_field(rec, 7, &len); col_len = mach_read_from_4(field); ut_a(0 == ut_strcmp("PREC", dict_field_get_col( dict_index_get_nth_field( dict_table_get_first_index(sys_columns), 8))->name)); field = rec_get_nth_field(rec, 8, &len); prec = mach_read_from_4(field); dict_mem_table_add_col(table, name, mtype, prtype, col_len, prec); btr_pcur_move_to_next_user_rec(&pcur, &mtr); } btr_pcur_close(&pcur); mtr_commit(&mtr); }
dict_table_t* dict_load_table( /*============*/ /* out: table, NULL if does not exist */ char* name) /* in: table name */ { dict_table_t* table; dict_table_t* sys_tables; btr_pcur_t pcur; dict_index_t* sys_index; dtuple_t* tuple; mem_heap_t* heap; dfield_t* dfield; rec_t* rec; byte* field; ulint len; char* buf; ulint space; ulint n_cols; mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); heap = mem_heap_create(1000); mtr_start(&mtr); sys_tables = dict_table_get_low("SYS_TABLES"); sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); dfield_set_data(dfield, name, ut_strlen(name)); dict_index_copy_types(tuple, sys_index, 1); btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); rec = btr_pcur_get_rec(&pcur); if (!btr_pcur_is_on_user_rec(&pcur, &mtr) || rec_get_deleted_flag(rec)) { /* Not found */ btr_pcur_close(&pcur); mtr_commit(&mtr); mem_heap_free(heap); return(NULL); } field = rec_get_nth_field(rec, 0, &len); /* Check if the table name in record is the searched one */ if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) { btr_pcur_close(&pcur); mtr_commit(&mtr); mem_heap_free(heap); return(NULL); } ut_a(0 == ut_strcmp("SPACE", dict_field_get_col( dict_index_get_nth_field( dict_table_get_first_index(sys_tables), 9))->name)); field = rec_get_nth_field(rec, 9, &len); space = mach_read_from_4(field); ut_a(0 == ut_strcmp("N_COLS", dict_field_get_col( dict_index_get_nth_field( dict_table_get_first_index(sys_tables), 4))->name)); field = rec_get_nth_field(rec, 4, &len); n_cols = mach_read_from_4(field); table = dict_mem_table_create(name, space, n_cols); ut_a(0 == ut_strcmp("ID", dict_field_get_col( dict_index_get_nth_field( dict_table_get_first_index(sys_tables), 3))->name)); field = rec_get_nth_field(rec, 3, &len); table->id = mach_read_from_8(field); field = rec_get_nth_field(rec, 5, &len); table->type = mach_read_from_4(field); if (table->type == DICT_TABLE_CLUSTER_MEMBER) { ut_a(0); field = rec_get_nth_field(rec, 6, &len); table->mix_id = mach_read_from_8(field); field = rec_get_nth_field(rec, 8, &len); buf = mem_heap_alloc(heap, len); ut_memcpy(buf, field, len); table->cluster_name = buf; } if ((table->type == DICT_TABLE_CLUSTER) || (table->type == DICT_TABLE_CLUSTER_MEMBER)) { field = rec_get_nth_field(rec, 7, &len); table->mix_len = mach_read_from_4(field); } btr_pcur_close(&pcur); mtr_commit(&mtr); if (table->type == DICT_TABLE_CLUSTER_MEMBER) { /* Load the cluster table definition if not yet in memory cache */ dict_table_get_low(table->cluster_name); } dict_load_columns(table, heap); dict_table_add_to_cache(table); dict_load_indexes(table, heap); ut_a(DB_SUCCESS == dict_load_foreigns(table->name)); mem_heap_free(heap); return(table); }