diff options
Diffstat (limited to 'mysys')
-rw-r--r-- | mysys/my_handler.c | 99 | ||||
-rw-r--r-- | mysys/my_lock.c | 2 |
2 files changed, 90 insertions, 11 deletions
diff --git a/mysys/my_handler.c b/mysys/my_handler.c index 7a3b8269190..7c13149cb27 100644 --- a/mysys/my_handler.c +++ b/mysys/my_handler.c @@ -84,13 +84,15 @@ static int compare_bin(const uchar *a, uint a_length, ha_key_cmp() keyseg Array of key segments of key to compare a First key to compare, in format from _mi_pack_key() - This is normally key specified by user - b Second key to compare. This is always from a row - key_length Length of key to compare. This can be shorter than - a to just compare sub keys + This is always from the row + b Second key to compare. This is from the row or the user + key_length Length of key to compare, based on key b. This can be shorter + than b to just compare sub keys next_flag How keys should be compared If bit SEARCH_FIND is not set the keys includes the row position and this should also be compared + If SEARCH_PAGE_KEY_HAS_TRANSID is set then 'a' has transid + If SEARCH_USER_KEY_HAS_TRANSID is set then 'b' has transid diff_pos OUT Number of first keypart where values differ, counting from one. diff_pos[1] OUT (b + diff_pos[1]) points to first value in tuple b @@ -120,7 +122,7 @@ static int compare_bin(const uchar *a, uint a_length, #define FCMP(A,B) ((int) (A) - (int) (B)) int ha_key_cmp(register HA_KEYSEG *keyseg, register const uchar *a, - register const uchar *b, uint key_length, uint nextflag, + register const uchar *b, uint key_length, uint32 nextflag, uint *diff_pos) { int flag; @@ -152,8 +154,13 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register const uchar *a, b++; if (!*a++) /* If key was NULL */ { - if (nextflag == (SEARCH_FIND | SEARCH_UPDATE)) - nextflag=SEARCH_SAME; /* Allow duplicate keys */ + if ((nextflag & (SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT | + SEARCH_NULL_ARE_EQUAL)) == + (SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT)) + { + /* Allow duplicate keys */ + nextflag= (nextflag & ~(SEARCH_FIND | SEARCH_UPDATE)) | SEARCH_SAME; + } else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL) { /* @@ -456,18 +463,90 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register const uchar *a, end: if (!(nextflag & SEARCH_FIND)) { + /* + Compare rowid and possible transid + This happens in the following case: + - INSERT, UPDATE, DELETE when we have not unique keys or + are using versioning + - SEARCH_NEXT, SEARCH_PREVIOUS when we need to restart search + + The logic for comparing transid are as follows: + Keys with have a transid have lowest bit in the rowidt. This means that + if we are comparing a key with a transid with another key that doesn't + have a tranid, we must reset the lowest bit for both keys. + + When we have transid, the keys are compared in transid order. + A key without a transid is regared to be smaller than a key with + a transid. + */ + uint i; + uchar key_mask, tmp_a, tmp_b; + if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */ return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1; - flag=0; - for (i=keyseg->length ; i-- > 0 ; ) + key_mask= (uchar) 255; + + if (!(nextflag & (SEARCH_USER_KEY_HAS_TRANSID | + SEARCH_PAGE_KEY_HAS_TRANSID))) + { + /* + Neither key has a trid. Only compare row id's and don't + try to store rows in trid order + */ + key_length= keyseg->length; + nextflag&= ~SEARCH_INSERT; + } + else + { + /* + Set key_mask so that we reset the last bit in the rowid before + we compare it. This is needed as the lowest bit in the rowid is + used to mark if the key has a transid or not. + */ + key_mask= (uchar) 254; + if (!test_all_bits(nextflag, (SEARCH_USER_KEY_HAS_TRANSID | + SEARCH_PAGE_KEY_HAS_TRANSID))) + { + /* + No transaction id for user key or for key on page + Ignore transid as at least one of the keys are visible for all + */ + key_length= keyseg->length; + } + else + { + /* + Both keys have trids. No need of special handling of incomplete + trids below. + */ + nextflag&= ~SEARCH_INSERT; + } + } + DBUG_ASSERT(key_length > 0); + + for (i= key_length-1 ; (int) i-- > 0 ; ) { if (*a++ != *b++) { flag= FCMP(a[-1],b[-1]); - break; + goto found; } } + tmp_a= *a & key_mask; + tmp_b= *b & key_mask; + flag= FCMP(tmp_a, tmp_b); + + if (flag == 0 && (nextflag & SEARCH_INSERT)) + { + /* + Ensure that on insert we get rows stored in trid order. + If one of the parts doesn't have a trid, this should be regarded + as smaller than the other + */ + return (nextflag & SEARCH_USER_KEY_HAS_TRANSID) ? -1 : 1; + } +found: if (nextflag & SEARCH_SAME) return (flag); /* read same */ if (nextflag & SEARCH_BIGGER) diff --git a/mysys/my_lock.c b/mysys/my_lock.c index 200ee7188c9..8450fcfc30a 100644 --- a/mysys/my_lock.c +++ b/mysys/my_lock.c @@ -87,7 +87,7 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, nxLockFlags = NX_RANGE_LOCK_EXCL; } - if (MyFlags & MY_DONT_WAIT) + if (MyFlags & MY_NO_WAIT) { /* Don't block on the lock. */ nxLockFlags |= NX_RANGE_LOCK_TRYLOCK; |