| 1 | /* |
| 2 | Copyright (c) 2000, 2010, Oracle and/or its affiliates |
| 3 | |
| 4 | This program is free software; you can redistribute it and/or modify |
| 5 | it under the terms of the GNU General Public License as published by |
| 6 | the Free Software Foundation; version 2 of the License. |
| 7 | |
| 8 | This program is distributed in the hope that it will be useful, |
| 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | GNU General Public License for more details. |
| 12 | |
| 13 | You should have received a copy of the GNU General Public License |
| 14 | along with this program; if not, write to the Free Software |
| 15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
| 16 | |
| 17 | /* Read and write key blocks */ |
| 18 | |
| 19 | #include "myisamdef.h" |
| 20 | |
| 21 | /* Fetch a key-page in memory */ |
| 22 | |
| 23 | uchar *_mi_fetch_keypage(register MI_INFO *info, MI_KEYDEF *keyinfo, |
| 24 | my_off_t page, int level, |
| 25 | uchar *buff, int return_buffer) |
| 26 | { |
| 27 | uchar *tmp; |
| 28 | uint page_size; |
| 29 | DBUG_ENTER("_mi_fetch_keypage" ); |
| 30 | DBUG_PRINT("enter" ,("page: %ld" , (long) page)); |
| 31 | |
| 32 | tmp=(uchar*) key_cache_read(info->s->key_cache, |
| 33 | info->s->kfile, page, level, (uchar*) buff, |
| 34 | (uint) keyinfo->block_length, |
| 35 | (uint) keyinfo->block_length, |
| 36 | return_buffer); |
| 37 | if (tmp == info->buff) |
| 38 | info->buff_used=1; |
| 39 | else if (!tmp) |
| 40 | { |
| 41 | DBUG_PRINT("error" ,("Got errno: %d from key_cache_read" ,my_errno)); |
| 42 | info->last_keypage=HA_OFFSET_ERROR; |
| 43 | mi_print_error(info->s, HA_ERR_CRASHED); |
| 44 | my_errno=HA_ERR_CRASHED; |
| 45 | DBUG_RETURN(0); |
| 46 | } |
| 47 | info->last_keypage=page; |
| 48 | page_size=mi_getint(tmp); |
| 49 | if (page_size < 4 || page_size > keyinfo->block_length) |
| 50 | { |
| 51 | DBUG_PRINT("error" ,("page %lu had wrong page length: %u" , |
| 52 | (ulong) page, page_size)); |
| 53 | DBUG_DUMP("page" , tmp, keyinfo->block_length); |
| 54 | info->last_keypage = HA_OFFSET_ERROR; |
| 55 | mi_print_error(info->s, HA_ERR_CRASHED); |
| 56 | my_errno = HA_ERR_CRASHED; |
| 57 | tmp = 0; |
| 58 | } |
| 59 | DBUG_RETURN(tmp); |
| 60 | } /* _mi_fetch_keypage */ |
| 61 | |
| 62 | |
| 63 | /* Write a key-page on disk */ |
| 64 | |
| 65 | int _mi_write_keypage(register MI_INFO *info, register MI_KEYDEF *keyinfo, |
| 66 | my_off_t page, int level, uchar *buff) |
| 67 | { |
| 68 | reg3 uint length; |
| 69 | DBUG_ENTER("_mi_write_keypage" ); |
| 70 | |
| 71 | #ifndef FAST /* Safety check */ |
| 72 | if (page < info->s->base.keystart || |
| 73 | page+keyinfo->block_length > info->state->key_file_length || |
| 74 | (page & (MI_MIN_KEY_BLOCK_LENGTH-1))) |
| 75 | { |
| 76 | DBUG_PRINT("error" ,("Trying to write inside key status region: key_start: %lu length: %lu page: %lu" , |
| 77 | (long) info->s->base.keystart, |
| 78 | (long) info->state->key_file_length, |
| 79 | (long) page)); |
| 80 | my_errno=EINVAL; |
| 81 | DBUG_RETURN((-1)); |
| 82 | } |
| 83 | DBUG_PRINT("page" ,("write page at: %lu" ,(long) page)); |
| 84 | DBUG_DUMP("buff" ,(uchar*) buff,mi_getint(buff)); |
| 85 | #endif |
| 86 | |
| 87 | if ((length=keyinfo->block_length) > IO_SIZE*2 && |
| 88 | info->state->key_file_length != page+length) |
| 89 | length= ((mi_getint(buff)+IO_SIZE-1) & (uint) ~(IO_SIZE-1)); |
| 90 | DBUG_RETURN((key_cache_write(info->s->key_cache, |
| 91 | info->s->kfile, &info->s->dirty_part_map, |
| 92 | page, level, (uchar*) buff, length, |
| 93 | (uint) keyinfo->block_length, |
| 94 | (int) ((info->lock_type != F_UNLCK) || |
| 95 | info->s->delay_key_write)))); |
| 96 | } /* mi_write_keypage */ |
| 97 | |
| 98 | |
| 99 | /* Remove page from disk */ |
| 100 | |
| 101 | int _mi_dispose(register MI_INFO *info, MI_KEYDEF *keyinfo, my_off_t pos, |
| 102 | int level) |
| 103 | { |
| 104 | my_off_t old_link; |
| 105 | uchar buff[8]; |
| 106 | DBUG_ENTER("_mi_dispose" ); |
| 107 | DBUG_PRINT("enter" ,("pos: %ld" , (long) pos)); |
| 108 | |
| 109 | old_link= info->s->state.key_del[keyinfo->block_size_index]; |
| 110 | info->s->state.key_del[keyinfo->block_size_index]= pos; |
| 111 | mi_sizestore(buff,old_link); |
| 112 | info->s->state.changed|= STATE_NOT_SORTED_PAGES; |
| 113 | DBUG_RETURN(key_cache_write(info->s->key_cache, |
| 114 | info->s->kfile, &info->s->dirty_part_map, |
| 115 | pos , level, buff, |
| 116 | sizeof(buff), |
| 117 | (uint) keyinfo->block_length, |
| 118 | (int) (info->lock_type != F_UNLCK))); |
| 119 | } /* _mi_dispose */ |
| 120 | |
| 121 | |
| 122 | /* Make new page on disk */ |
| 123 | |
| 124 | my_off_t _mi_new(register MI_INFO *info, MI_KEYDEF *keyinfo, int level) |
| 125 | { |
| 126 | my_off_t pos; |
| 127 | uchar buff[8]; |
| 128 | DBUG_ENTER("_mi_new" ); |
| 129 | |
| 130 | if ((pos= info->s->state.key_del[keyinfo->block_size_index]) == |
| 131 | HA_OFFSET_ERROR) |
| 132 | { |
| 133 | if (info->state->key_file_length >= |
| 134 | info->s->base.max_key_file_length - keyinfo->block_length) |
| 135 | { |
| 136 | my_errno=HA_ERR_INDEX_FILE_FULL; |
| 137 | DBUG_RETURN(HA_OFFSET_ERROR); |
| 138 | } |
| 139 | pos=info->state->key_file_length; |
| 140 | info->state->key_file_length+= keyinfo->block_length; |
| 141 | } |
| 142 | else |
| 143 | { |
| 144 | if (!key_cache_read(info->s->key_cache, |
| 145 | info->s->kfile, pos, level, |
| 146 | buff, |
| 147 | (uint) sizeof(buff), |
| 148 | (uint) keyinfo->block_length,0)) |
| 149 | pos= HA_OFFSET_ERROR; |
| 150 | else |
| 151 | info->s->state.key_del[keyinfo->block_size_index]= mi_sizekorr(buff); |
| 152 | } |
| 153 | info->s->state.changed|= STATE_NOT_SORTED_PAGES; |
| 154 | DBUG_PRINT("exit" ,("Pos: %ld" ,(long) pos)); |
| 155 | DBUG_RETURN(pos); |
| 156 | } /* _mi_new */ |
| 157 | |