summaryrefslogtreecommitdiff
path: root/storage/heap
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2013-02-28 19:00:58 +0100
committerSergei Golubchik <sergii@pisem.net>2013-02-28 19:00:58 +0100
commit5dec570d7c1e2a39b67503a90d2d7905ac4dbb44 (patch)
treed206f4c8848a50899d8d0656e8c8212189365ace /storage/heap
parent5138bf4238d4a8850ee364a3adf10dc2687af67c (diff)
parent027e34e13b8d0baed51e26be8d4ffd86d9b3b041 (diff)
downloadmariadb-git-5dec570d7c1e2a39b67503a90d2d7905ac4dbb44.tar.gz
5.1 -> 5.2 merge
Diffstat (limited to 'storage/heap')
-rw-r--r--storage/heap/hp_delete.c54
1 files changed, 41 insertions, 13 deletions
diff --git a/storage/heap/hp_delete.c b/storage/heap/hp_delete.c
index ceba0fcf12e..7612b896ccc 100644
--- a/storage/heap/hp_delete.c
+++ b/storage/heap/hp_delete.c
@@ -47,7 +47,6 @@ int heap_delete(HP_INFO *info, const uchar *record)
share->del_link=pos;
pos[share->reclength]=0; /* Record deleted */
share->deleted++;
- info->current_hash_ptr=0;
#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
DBUG_EXECUTE("check_heap",heap_check_heap(info, 0););
#endif
@@ -104,7 +103,7 @@ int hp_rb_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
const uchar *record, uchar *recpos, int flag)
{
- ulong blength,pos2,pos_hashnr,lastpos_hashnr;
+ ulong blength, pos2, pos_hashnr, lastpos_hashnr, key_pos;
HASH_INFO *lastpos,*gpos,*pos,*pos3,*empty,*last_ptr;
HP_SHARE *share=info->s;
DBUG_ENTER("hp_delete_key");
@@ -116,9 +115,9 @@ int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
last_ptr=0;
/* Search after record with key */
- pos= hp_find_hash(&keyinfo->block,
- hp_mask(hp_rec_hashnr(keyinfo, record), blength,
- share->records + 1));
+ key_pos= hp_mask(hp_rec_hashnr(keyinfo, record), blength, share->records + 1);
+ pos= hp_find_hash(&keyinfo->block, key_pos);
+
gpos = pos3 = 0;
while (pos->ptr_to_rec != recpos)
@@ -180,21 +179,50 @@ int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo,
}
pos2= hp_mask(lastpos_hashnr, blength, share->records + 1);
if (pos2 == hp_mask(pos_hashnr, blength, share->records + 1))
- { /* Identical key-positions */
+ {
+ /* lastpos and the row in the main bucket entry (pos) has the same hash */
if (pos2 != share->records)
{
- empty[0]=lastpos[0];
+ /*
+ The bucket entry was not deleted. Copy lastpos over the
+ deleted entry and update previous link to point to it.
+ */
+ empty[0]= lastpos[0];
hp_movelink(lastpos, pos, empty);
+ if (last_ptr == lastpos)
+ {
+ /*
+ We moved the row that info->current_hash_ptr points to.
+ Update info->current_hash_ptr to point to the new position.
+ */
+ info->current_hash_ptr= empty;
+ }
DBUG_RETURN(0);
}
- pos3= pos; /* Link pos->next after lastpos */
- }
- else
- {
- pos3= 0; /* Different positions merge */
- keyinfo->hash_buckets--;
+ /*
+ Shrinking the hash table deleted the main bucket entry for this hash.
+ In this case the last entry was the first key in the key chain.
+ We move things around so that we keep the original key order to ensure
+ that heap_rnext() works.
+
+ - Move the row at the main bucket entry to the empty spot.
+ - Move the last entry first in the new chain.
+ - Link in the first element of the hash.
+ */
+ empty[0]= pos[0];
+ pos[0]= lastpos[0];
+ hp_movelink(pos, pos, empty);
+
+ /* Update current_hash_ptr if the entry moved */
+ if (last_ptr == lastpos)
+ info->current_hash_ptr= pos;
+ else if (last_ptr == pos)
+ info->current_hash_ptr= empty;
+ DBUG_RETURN(0);
}
+ pos3= 0; /* Different positions merge */
+ keyinfo->hash_buckets--;
empty[0]=lastpos[0];
hp_movelink(pos3, empty, pos->next_key);
pos->next_key=empty;