Exemple #1
0
void
btr_pcur_move_to_next_page(
/*=======================*/
	btr_pcur_t*	cursor,	/* in: persistent cursor; must be on the
				last record of the current page */
	mtr_t*		mtr)	/* in: mtr */
{
	ulint	next_page_no;
	ulint	space;
	page_t*	page;
	page_t*	next_page;

	ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);	
	ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
	ut_ad(btr_pcur_is_after_last_on_page(cursor, mtr));	

	cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
	
	page = btr_pcur_get_page(cursor);

	next_page_no = btr_page_get_next(page, mtr);
	space = buf_frame_get_space_id(page);

	ut_ad(next_page_no != FIL_NULL);	

	next_page = btr_page_get(space, next_page_no, cursor->latch_mode, mtr);
	ut_a(page_is_comp(next_page) == page_is_comp(page));
	buf_block_align(next_page)->check_index_page_at_flush = TRUE;

	btr_leaf_page_release(page, cursor->latch_mode, mtr);
	
	page_cur_set_before_first(next_page, btr_pcur_get_page_cur(cursor));

	page_check_dir(next_page);
}
Exemple #2
0
/*********************************************************//**
Moves the persistent cursor to the first record on the next page. Releases the
latch on the current page, and bufferunfixes it. Note that there must not be
modifications on the current page, as then the x-latch can be released only in
mtr_commit. */
UNIV_INTERN
void
btr_pcur_move_to_next_page(
/*=======================*/
	btr_pcur_t*	cursor,	/*!< in: persistent cursor; must be on the
				last record of the current page */
	mtr_t*		mtr)	/*!< in: mtr */
{
	ulint		next_page_no;
	ulint		space;
	ulint		zip_size;
	page_t*		page;
	buf_block_t*	next_block;
	page_t*		next_page;

	ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
	ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
	ut_ad(btr_pcur_is_after_last_on_page(cursor));

	cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;

	page = btr_pcur_get_page(cursor);
	next_page_no = btr_page_get_next(page, mtr);
	space = buf_block_get_space(btr_pcur_get_block(cursor));
	zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor));

	ut_ad(next_page_no != FIL_NULL);

	next_block = btr_block_get(space, zip_size, next_page_no,
				   cursor->latch_mode,
				   btr_pcur_get_btr_cur(cursor)->index, mtr);
	next_page = buf_block_get_frame(next_block);

	if (srv_pass_corrupt_table && !next_page) {
		btr_leaf_page_release(btr_pcur_get_block(cursor),
				      cursor->latch_mode, mtr);
		btr_pcur_get_page_cur(cursor)->block = 0;
		btr_pcur_get_page_cur(cursor)->rec = 0;
		return;
	}
	ut_a(next_page);
#ifdef UNIV_BTR_DEBUG
	ut_a(page_is_comp(next_page) == page_is_comp(page));
	ut_a(btr_page_get_prev(next_page, mtr)
	     == buf_block_get_page_no(btr_pcur_get_block(cursor)));
#endif /* UNIV_BTR_DEBUG */
	next_block->check_index_page_at_flush = TRUE;

	btr_leaf_page_release(btr_pcur_get_block(cursor),
			      cursor->latch_mode, mtr);

	page_cur_set_before_first(next_block, btr_pcur_get_page_cur(cursor));

	page_check_dir(next_page);
}
inline bool check_page_format(page_t *page) {
	if (process_redundant && page_is_comp(page)) {
		if (debug) printf("Page is in COMPACT format while we're looking for REDUNDANT - skipping\n");
		return FALSE;
	}

	if (process_compact && !page_is_comp(page)) {
		if (debug) printf("Page is in REDUNDANT format while we're looking for COMPACT - skipping\n");
		return FALSE;
	}
	
    return TRUE;
}
int check_page(page_t *page, unsigned int *n_records){
    int comp = page_is_comp(page);
    int16_t i, s, p, b, p_prev;
    int recs = 0;
    int max_recs = UNIV_PAGE_SIZE / 5;
    *n_records = 0;
    i = (comp) ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM;
    s = (comp) ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM;

	if(deleted_records_only == 1){
		if (debug) printf("We look for deleted records only. Consider all pages are not valid\n");
		return 0;
		}
    if (debug) printf("Checking a page\nInfimum offset: 0x%X\nSupremum offset: 0x%X\n", i, s);
    p_prev = 0;
    p = i;
    while(p != s){
        if(recs > max_recs){
            *n_records = 0;
            if (debug) printf("Page is bad\n");
            return 0;
            }
        // If a pointer to the next record is negative - the page is bad
        if(p < 2){
            *n_records = 0;
            if (debug) printf("Page is bad\n");
            return 0;
            }
	// If the pointer is bigger than UNIV_PAGE_SIZE, the page is corrupted
        if(p > UNIV_PAGE_SIZE){
            *n_records = 0;
            if (debug) printf("Page is bad\n");
            return 0;
            }
	//  If we've already was here, the page is bad
        if(p == p_prev){
            *n_records = 0;
            if (debug) printf("Page is bad\n");
            return 0;
            }
	p_prev = p;
        // Get next pointer
        if(comp){
            b = mach_read_from_2(page + p - 2);
            p = p + b;
            }
        else{
            p =  mach_read_from_2(page + p - 2);
            }
        if (debug) printf("Next record at offset: 0x%X (%d) \n", 0x0000FFFF & p, p);
        recs++;
        }
    *n_records = recs -1; // - infinum record
    if (debug) printf("Page is good\n");
    return 1;
    }
inline ibool check_for_a_record(page_t *page, rec_t *rec, table_def_t *table, ulint *offsets) {
	ulint offset, data_size;

	// Check if given origin is valid
	offset = rec - page;
	if (offset < record_extra_bytes + table->min_rec_header_len) return FALSE;
	if (debug) printf("ORIGIN=OK ");

	// Skip non-deleted records
	if (deleted_records_only && !rec_get_deleted_flag(rec, page_is_comp(page))) return FALSE;
	if (debug) printf("DELETED=OK ");
	// Skip non-deleted records
	if (undeleted_records_only && rec_get_deleted_flag(rec, page_is_comp(page))) return FALSE;
	if (debug) printf("UNDELETED=OK ");

	// Get field offsets for current table
	if (process_compact && !ibrec_init_offsets_new(page, rec, table, offsets)) return FALSE;
	if (process_redundant && !ibrec_init_offsets_old(page, rec, table, offsets)) return FALSE;
	if (debug) printf("OFFSETS=OK ");

	// Check the record's data size
	data_size = rec_offs_data_size(offsets);
	if (data_size > table->data_max_size) {
        if (debug) printf("DATA_SIZE=FAIL(%lu > %lu) ", (long int)data_size, (long int)table->data_max_size);
        return FALSE;
	}
	if (data_size < table->data_min_size) {
        if (debug) printf("DATA_SIZE=FAIL(%lu < %lu) ", (long int)data_size, (long int)table->data_min_size);
        return FALSE;
	}
	if (debug) printf("DATA_SIZE=OK ");

	// Check fields sizes
	if (!check_fields_sizes(rec, table, offsets)) return FALSE;
	if (debug) printf("FIELD_SIZES=OK ");
	
	// This record could be valid and useful for us
	return TRUE;
}
Exemple #6
0
ulint
dict_truncate_index_tree(
/*=====================*/
				/* out: new root page number, or
				FIL_NULL on failure */
	dict_table_t*	table,	/* in: the table the index belongs to */
	btr_pcur_t*	pcur,	/* in/out: persistent cursor pointing to
				record in the clustered index of
				SYS_INDEXES table. The cursor may be
				repositioned in this call. */
	mtr_t*		mtr)	/* in: mtr having the latch
				on the record page. The mtr may be
				committed and restarted in this call. */
{
	ulint		root_page_no;
	ulint		space;
	ulint		type;
	dulint		index_id;
	rec_t*		rec;
	byte*		ptr;
	ulint		len;
	ulint		comp;
	dict_index_t*	index;

	ut_ad(mutex_own(&(dict_sys->mutex)));
	ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
	rec = btr_pcur_get_rec(pcur);
	ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);

	ut_ad(len == 4);

	root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);

	if (root_page_no == FIL_NULL) {
		/* The tree has been freed. */

		ut_print_timestamp(stderr);
		fprintf(stderr, "  InnoDB: Trying to TRUNCATE"
			" a missing index of table %s!\n", table->name);
		return(FIL_NULL);
	}

	ptr = rec_get_nth_field_old(rec,
				    DICT_SYS_INDEXES_SPACE_NO_FIELD, &len);

	ut_ad(len == 4);

	space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);

	if (!fil_tablespace_exists_in_mem(space)) {
		/* It is a single table tablespace and the .ibd file is
		missing: do nothing */

		ut_print_timestamp(stderr);
		fprintf(stderr, "  InnoDB: Trying to TRUNCATE"
			" a missing .ibd file of table %s!\n", table->name);
		return(FIL_NULL);
	}

	ptr = rec_get_nth_field_old(rec,
				    DICT_SYS_INDEXES_TYPE_FIELD, &len);
	ut_ad(len == 4);
	type = mach_read_from_4(ptr);

	ptr = rec_get_nth_field_old(rec, 1, &len);
	ut_ad(len == 8);
	index_id = mach_read_from_8(ptr);

	/* We free all the pages but the root page first; this operation
	may span several mini-transactions */

	btr_free_but_not_root(space, root_page_no);

	/* Then we free the root page in the same mini-transaction where
	we create the b-tree and write its new root page number to the
	appropriate field in the SYS_INDEXES record: this mini-transaction
	marks the B-tree totally truncated */

	comp = page_is_comp(btr_page_get(space, root_page_no, RW_X_LATCH,
					 mtr));

	btr_free_root(space, root_page_no, mtr);
	/* We will temporarily write FIL_NULL to the PAGE_NO field
	in SYS_INDEXES, so that the database will not get into an
	inconsistent state in case it crashes between the mtr_commit()
	below and the following mtr_commit() call. */
	page_rec_write_index_page_no(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
				     FIL_NULL, mtr);

	/* We will need to commit the mini-transaction in order to avoid
	deadlocks in the btr_create() call, because otherwise we would
	be freeing and allocating pages in the same mini-transaction. */
	btr_pcur_store_position(pcur, mtr);
	mtr_commit(mtr);

	mtr_start(mtr);
	btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);

	/* Find the index corresponding to this SYS_INDEXES record. */
	for (index = UT_LIST_GET_FIRST(table->indexes);
	     index;
	     index = UT_LIST_GET_NEXT(indexes, index)) {
		if (!ut_dulint_cmp(index->id, index_id)) {
			break;
		}
	}

	root_page_no = btr_create(type, space, index_id, comp, mtr);
	if (index) {
		index->page = (unsigned int) root_page_no;
	} else {
		ut_print_timestamp(stderr);
		fprintf(stderr,
			"  InnoDB: Index %lu %lu of table %s is missing\n"
			"InnoDB: from the data dictionary during TRUNCATE!\n",
			ut_dulint_get_high(index_id),
			ut_dulint_get_low(index_id),
			table->name);
	}

	return(root_page_no);
}
void process_ibpage(page_t *page) {
    ulint page_id;
	rec_t *origin;
	ulint offsets[MAX_TABLE_FIELDS + 2];
	ulint offset, i;
    int is_page_valid = 0;
    int comp;
    unsigned int expected_records = 0;
    unsigned int actual_records = 0;
    int16_t b, infimum, supremum;
	
	// Skip tables if filter used
    if (use_filter_id) {
        dulint index_id = mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID);
        if (index_id.low != filter_id.low || index_id.high != filter_id.high) {
            if (debug) {
            	page_id = mach_read_from_4(page + FIL_PAGE_OFFSET);
                printf("Skipped using index id filter: %lu!\n", page_id);
            }
            return;
        }
    }

	// Read page id
	page_id = mach_read_from_4(page + FIL_PAGE_OFFSET);
	if (debug) printf("Page id: %lu\n", page_id);
	fprintf(f_result, "-- Page id: %lu", page_id);
	// Check requested and actual formats
    if (!check_page_format(page)) return;
	if(table_definitions_cnt == 0){
		fprintf(stderr, "There are no table definitions. Please check  include/table_defs.h\n");
		exit(EXIT_FAILURE);
		}
    is_page_valid = check_page(page, &expected_records);
    
    // comp == 1 if page in COMPACT format and 0 if REDUNDANT
    comp = page_is_comp(page);
    fprintf(f_result, ", Format: %s", (comp ) ? "COMPACT": "REDUNDANT");
    infimum = (comp) ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM;
    supremum = (comp) ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM;
	// Find possible data area start point (at least 5 bytes of utility data)
	if(is_page_valid){
        b = mach_read_from_2(page + infimum - 2);
        offset = (comp) ? infimum + b : b;
        }
    else{
        offset = 100 + record_extra_bytes;
        }
    	fprintf(f_result, ", Records list: %s", is_page_valid? "Valid": "Invalid");
    	fprintf(f_result, ", Expected records: (%u %lu)", expected_records, mach_read_from_2(page + PAGE_HEADER + PAGE_N_RECS));
    	fprintf(f_result, "\n");
	if (debug) printf("Starting offset: %lu (%lX). Checking %d table definitions.\n", offset, offset, table_definitions_cnt);
	
	// Walk through all possible positions to the end of page 
	// (start of directory - extra bytes of the last rec)
    //is_page_valid = 0;
	while (offset < UNIV_PAGE_SIZE - record_extra_bytes && ( (offset != supremum ) || !is_page_valid) ) {
		// Get record pointer
		origin = page + offset;
		if (debug) printf("\nChecking offset: 0x%lX: ", offset);
		
		// Check all tables
		for (i = 0; i < table_definitions_cnt; i++) {
			// Get table info
			table_def_t *table = &(table_definitions[i]);
			if (debug) printf(" (%s) ", table->name);

			// Check if origin points to a valid record
			if (check_for_a_record(page, origin, table, offsets) && check_constraints(origin, table, offsets)) {
				actual_records++;
				if (debug) printf("\n---------------------------------------------------\n"
			       			  "PAGE%lu: Found a table %s record: %p (offset = %lu)\n", \
						  page_id, table->name, origin, offset);
                		if(is_page_valid){
					process_ibrec(page, origin, table, offsets);
                    			b = mach_read_from_2(page + offset - 2);
					offset = (comp) ? offset + b : b;
                    			}
				else{
					offset += process_ibrec(page, origin, table, offsets);
                    			}
                		if (debug) printf("Next offset: 0x%lX", offset);
			   		break;
		        	}
            		else{
                		if(is_page_valid){
					b = mach_read_from_2(page + offset - 2);
					offset = (comp) ? offset + b : b;
                    			}
				else{
					offset++;
					}
                		if (debug) printf("\nNext offset: %lX", offset);
               			}
			}
		}
	fprintf(f_result, "-- Page id: %lu", page_id);
	fprintf(f_result, ", Found records: %u", actual_records);
	fprintf(f_result, ", Lost records: %s", (actual_records != expected_records) ? "YES": "NO");
    	fprintf(f_result, ", Leaf page: %s", (mach_read_from_2(page + PAGE_HEADER + PAGE_LEVEL) == 0)? "YES": "NO");
	fprintf(f_result, "\n");
}