List:Commits« Previous MessageNext Message »
From:marko.makela Date:May 30 2012 8:23am
Subject:bzr push into mysql-trunk-wl6255 branch (marko.makela:3901 to 3903) WL#6255
View as plain text  
 3903 Marko Mäkelä	2012-05-30
      WL#6255 refactoring.
      
      row_ins_duplicate_error_in_clust(): In online table rebuild,
      if the PRIMARY KEY,DB_TRX_ID,DB_ROLL_PTR match with the record,
      return the special status code DB_SUCCESS_LOCKED_REC.
      
      row_log_table_apply_insert_low(): If the record already existed
      in the clustered index, return DB_SUCCESS.

    modified:
      storage/innobase/row/row0ins.cc
      storage/innobase/row/row0log.cc
 3902 Marko Mäkelä	2012-05-30
      WL#6255 refactoring of record comparison.
      
      cmp_dtuple_rec_with_match_low(): Renamed from cmp_dtuple_rec_with_match().
      Add the parameter n_cmp, to override dtuple->n_fields_cmp.
      
      cmp_dtuple_rec_with_match(): A macro wrapper for the above.
      
      cmp_debug_dtuple_rec_with_match(): Add the parameter n_cmp.

    modified:
      storage/innobase/include/rem0cmp.h
      storage/innobase/rem/rem0cmp.cc
 3901 Marko Mäkelä	2012-05-30
      WL#6255 bug fix.
      
      row_tab_op: Use more distinguishable values for the operation codes,
      so that it is easier to inspect the buffered data.
      
      row_log_table_apply_op(): Fix a bug in ROW_T_UPDATE parsing when
      the definition of the PRIMARY KEY is changed.

    modified:
      storage/innobase/row/row0log.cc
=== modified file 'storage/innobase/include/rem0cmp.h'
--- a/storage/innobase/include/rem0cmp.h	revid:marko.makela@strippedqv1f9
+++ b/storage/innobase/include/rem0cmp.h	revid:marko.makela@stripped
@@ -156,21 +156,28 @@ respectively, when only the common first
 the first externally stored field in rec */
 UNIV_INTERN
 int
-cmp_dtuple_rec_with_match(
-/*======================*/
+cmp_dtuple_rec_with_match_low(
+/*==========================*/
 	const dtuple_t*	dtuple,	/*!< in: data tuple */
 	const rec_t*	rec,	/*!< in: physical record which differs from
 				dtuple in some of the common fields, or which
 				has an equal number or more fields than
 				dtuple */
 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
-	ulint*		matched_fields, /*!< in/out: number of already completely
+	ulint		n_cmp,	/*!< in: number of fields to compare */
+	ulint*		matched_fields,
+				/*!< in/out: number of already completely
 				matched fields; when function returns,
 				contains the value for current comparison */
-	ulint*		matched_bytes); /*!< in/out: number of already matched
+	ulint*		matched_bytes)
+				/*!< in/out: number of already matched
 				bytes within the first field not completely
 				matched; when function returns, contains the
 				value for current comparison */
+	__attribute__((nonnull));
+#define cmp_dtuple_rec_with_match(tuple,rec,offsets,fields,bytes)	\
+	cmp_dtuple_rec_with_match_low(					\
+		tuple,rec,offsets,dtuple_get_n_fields_cmp(tuple),fields,bytes)
 /**************************************************************//**
 Compares a data tuple to a physical record.
 @see cmp_dtuple_rec_with_match

=== modified file 'storage/innobase/rem/rem0cmp.cc'
--- a/storage/innobase/rem/rem0cmp.cc	revid:marko.makela@stripped9
+++ b/storage/innobase/rem/rem0cmp.cc	revid:marko.makela@stripped
@@ -70,10 +70,12 @@ cmp_debug_dtuple_rec_with_match(
 				has an equal number or more fields than
 				dtuple */
 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
-	ulint*		matched_fields);/*!< in/out: number of already
+	ulint		n_cmp,	/*!< in: number of fields to compare */
+	ulint*		matched_fields)/*!< in/out: number of already
 				completely  matched fields; when function
 				returns, contains the value for current
 				comparison */
+	__attribute__((nonnull, warn_unused_result));
 #endif /* UNIV_DEBUG */
 /*************************************************************//**
 This function is used to compare two data fields for which the data type
@@ -622,14 +624,15 @@ respectively, when only the common first
 the first externally stored field in rec */
 UNIV_INTERN
 int
-cmp_dtuple_rec_with_match(
-/*======================*/
+cmp_dtuple_rec_with_match_low(
+/*==========================*/
 	const dtuple_t*	dtuple,	/*!< in: data tuple */
 	const rec_t*	rec,	/*!< in: physical record which differs from
 				dtuple in some of the common fields, or which
 				has an equal number or more fields than
 				dtuple */
 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
+	ulint		n_cmp,	/*!< in: number of fields to compare */
 	ulint*		matched_fields, /*!< in/out: number of already completely
 				matched fields; when function returns,
 				contains the value for current comparison */
@@ -653,7 +656,7 @@ cmp_dtuple_rec_with_match(
 	ulint		cur_field;	/* current field number */
 	ulint		cur_bytes;	/* number of already matched bytes
 					in current field */
-	int		ret = 3333;	/* return value */
+	int		ret;		/* return value */
 
 	ut_ad(dtuple && rec && matched_fields && matched_bytes);
 	ut_ad(dtuple_check_typed(dtuple));
@@ -662,7 +665,9 @@ cmp_dtuple_rec_with_match(
 	cur_field = *matched_fields;
 	cur_bytes = *matched_bytes;
 
-	ut_ad(cur_field <= dtuple_get_n_fields_cmp(dtuple));
+	ut_ad(n_cmp > 0);
+	ut_ad(n_cmp <= dtuple_get_n_fields(dtuple));
+	ut_ad(cur_field <= n_cmp);
 	ut_ad(cur_field <= rec_offs_n_fields(offsets));
 
 	if (cur_bytes == 0 && cur_field == 0) {
@@ -682,7 +687,7 @@ cmp_dtuple_rec_with_match(
 	/* Match fields in a loop; stop if we run out of fields in dtuple
 	or find an externally stored field */
 
-	while (cur_field < dtuple_get_n_fields_cmp(dtuple)) {
+	while (cur_field < n_cmp) {
 
 		ulint	mtype;
 		ulint	prtype;
@@ -839,7 +844,7 @@ next_field:
 order_resolved:
 	ut_ad((ret >= - 1) && (ret <= 1));
 	ut_ad(ret == cmp_debug_dtuple_rec_with_match(dtuple, rec, offsets,
-						     matched_fields));
+						     n_cmp, matched_fields));
 	ut_ad(*matched_fields == cur_field); /* In the debug version, the
 					     above cmp_debug_... sets
 					     *matched_fields to a value */
@@ -1352,6 +1357,7 @@ cmp_debug_dtuple_rec_with_match(
 				has an equal number or more fields than
 				dtuple */
 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
+	ulint		n_cmp,	/*!< in: number of fields to compare */
 	ulint*		matched_fields) /*!< in/out: number of already
 				completely matched fields; when function
 				returns, contains the value for current
@@ -1364,14 +1370,16 @@ cmp_debug_dtuple_rec_with_match(
 					field data */
 	ulint		rec_f_len;	/* length of current field in rec */
 	const byte*	rec_f_data;	/* pointer to the current rec field */
-	int		ret = 3333;	/* return value */
+	int		ret;		/* return value */
 	ulint		cur_field;	/* current field number */
 
 	ut_ad(dtuple && rec && matched_fields);
 	ut_ad(dtuple_check_typed(dtuple));
 	ut_ad(rec_offs_validate(rec, NULL, offsets));
 
-	ut_ad(*matched_fields <= dtuple_get_n_fields_cmp(dtuple));
+	ut_ad(n_cmp > 0);
+	ut_ad(n_cmp <= dtuple_get_n_fields(dtuple));
+	ut_ad(*matched_fields <= n_cmp);
 	ut_ad(*matched_fields <= rec_offs_n_fields(offsets));
 
 	cur_field = *matched_fields;
@@ -1397,7 +1405,7 @@ cmp_debug_dtuple_rec_with_match(
 
 	/* Match fields in a loop; stop if we run out of fields in dtuple */
 
-	while (cur_field < dtuple_get_n_fields_cmp(dtuple)) {
+	while (cur_field < n_cmp) {
 
 		ulint	mtype;
 		ulint	prtype;

=== modified file 'storage/innobase/row/row0ins.cc'
--- a/storage/innobase/row/row0ins.cc	revid:marko.makela@oracle.com-20120530065248-5e3vm24c9d5qv1f9
+++ b/storage/innobase/row/row0ins.cc	revid:marko.makela@stripped120530082121-5klorcbaz3z1zuin
@@ -1951,9 +1951,12 @@ end_scan:
 Checks if a unique key violation error would occur at an index entry
 insert. Sets shared locks on possible duplicate records. Works only
 for a clustered index!
-@return DB_SUCCESS if no error, DB_DUPLICATE_KEY if error,
-DB_LOCK_WAIT if we have to wait for a lock on a possible duplicate
-record */
+@retval DB_SUCCESS if no error
+@retval DB_DUPLICATE_KEY if error,
+@retval DB_LOCK_WAIT if we have to wait for a lock on a possible duplicate
+record
+@retval DB_SUCCESS_LOCKED_REC if an exact match of the record was found
+in online table rebuild (flags & (BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG)) */
 static __attribute__((nonnull, warn_unused_result))
 dberr_t
 row_ins_duplicate_error_in_clust(
@@ -2037,8 +2040,43 @@ row_ins_duplicate_error_in_clust(
 				goto func_exit;
 			}
 
-			if (row_ins_dupl_error_with_rec(
-				    rec, entry, cursor->index, offsets)) {
+			if (flags
+			    & (BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG)) {
+				/* We are inserting into the rebuilt table.
+				See if this is a real duplicate, or an
+				exact match of a previous insert. */
+				ulint	fields	= 0;
+				ulint	bytes	= 0;
+
+				/* During rebuild, there should not be any
+				delete-marked rows in the new table. */
+				ut_ad(!rec_get_deleted_flag(
+					      rec, rec_offs_comp(offsets)));
+				ut_ad(dtuple_get_n_fields_cmp(entry)
+				      == n_unique);
+
+				/* Compare the PRIMARY KEY fields and the
+				DB_TRX_ID, DB_ROLL_PTR. */
+				cmp_dtuple_rec_with_match_low(
+					entry, rec, offsets,
+					n_unique + 2, &fields, &bytes);
+
+				if (fields >= n_unique) {
+					if (fields == n_unique + 2) {
+						/* This is an exact match. */
+						ut_ad(bytes == 0);
+						/* Special return code to
+						indicate that the row was
+						already inserted. */
+						err = DB_SUCCESS_LOCKED_REC;
+						goto func_exit;
+					}
+
+					goto duplicate;
+				}
+			} else if (row_ins_dupl_error_with_rec(
+					   rec, entry, cursor->index, offsets)) {
+duplicate:
 				trx->error_info = cursor->index;
 				err = DB_DUPLICATE_KEY;
 				goto func_exit;
@@ -2087,9 +2125,7 @@ row_ins_duplicate_error_in_clust(
 
 			if (row_ins_dupl_error_with_rec(
 				    rec, entry, cursor->index, offsets)) {
-				trx->error_info = cursor->index;
-				err = DB_DUPLICATE_KEY;
-				goto func_exit;
+				goto duplicate;
 			}
 		}
 

=== modified file 'storage/innobase/row/row0log.cc'
--- a/storage/innobase/row/row0log.cc	revid:marko.makela@strippedm-20120530065248-5e3vm24c9d5qv1f9
+++ b/storage/innobase/row/row0log.cc	revid:marko.makela@stripped21-5klorcbaz3z1zuin
@@ -1000,13 +1000,21 @@ row_log_table_apply_insert_low(
 	error = row_ins_clust_index_entry_low(
 		flags, BTR_MODIFY_TREE, index, entry, 0, thr);
 
-	if (error == DB_DUPLICATE_KEY) {
+	switch (error) {
+	case DB_SUCCESS:
+		break;
+	case DB_SUCCESS_LOCKED_REC:
+		/* The row had already been copied to the table. */
+		return(DB_SUCCESS);
+	case DB_DUPLICATE_KEY:
 		/* TODO: report the duplicate key unless the record is
 		a full match of what we tried to insert */
+		/* fall through */
+	default:
 		return(error);
 	}
 
-	while (error == DB_SUCCESS) {
+	do {
 		if (!(index = dict_table_get_next_index(index))) {
 			break;
 		}
@@ -1015,10 +1023,10 @@ row_log_table_apply_insert_low(
 		error = row_ins_sec_index_entry_low(
 			flags, BTR_MODIFY_TREE,
 			index, offsets_heap, heap, entry, thr);
-	}
+	} while (error == DB_SUCCESS);
 
 	if (error == DB_DUPLICATE_KEY) {
-		/* TODO: report dup */
+		/* TODO: report a duplicate */
 	}
 
 	return(error);

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk-wl6255 branch (marko.makela:3901 to 3903) WL#6255marko.makela30 May