| 1 | /* Copyright (c) 2003-2008 MySQL AB, 2009 Sun Microsystems, Inc. |
| 2 | Use is subject to license terms. |
| 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 | /* |
| 18 | Key cache assignments |
| 19 | */ |
| 20 | |
| 21 | #include "myisamdef.h" |
| 22 | |
| 23 | /* |
| 24 | Assign pages of the index file for a table to a key cache |
| 25 | |
| 26 | SYNOPSIS |
| 27 | mi_assign_to_key_cache() |
| 28 | info open table |
| 29 | key_map map of indexes to assign to the key cache |
| 30 | key_cache_ptr pointer to the key cache handle |
| 31 | assign_lock Mutex to lock during assignment |
| 32 | |
| 33 | PREREQUESTS |
| 34 | One must have a READ lock or a WRITE lock on the table when calling |
| 35 | the function to ensure that there is no other writers to it. |
| 36 | |
| 37 | The caller must also ensure that one doesn't call this function from |
| 38 | two different threads with the same table. |
| 39 | |
| 40 | NOTES |
| 41 | At present pages for all indexes must be assigned to the same key cache. |
| 42 | In future only pages for indexes specified in the key_map parameter |
| 43 | of the table will be assigned to the specified key cache. |
| 44 | |
| 45 | RETURN VALUE |
| 46 | 0 If a success |
| 47 | # Error code |
| 48 | */ |
| 49 | |
| 50 | int mi_assign_to_key_cache(MI_INFO *info, |
| 51 | ulonglong key_map __attribute__((unused)), |
| 52 | KEY_CACHE *new_key_cache) |
| 53 | { |
| 54 | int error= 0; |
| 55 | MYISAM_SHARE* share= info->s; |
| 56 | KEY_CACHE *old_key_cache= share->key_cache; |
| 57 | DBUG_ENTER("mi_assign_to_key_cache" ); |
| 58 | DBUG_PRINT("enter" ,("old_key_cache_handle: %p new_key_cache_handle: %p" , |
| 59 | old_key_cache, new_key_cache)); |
| 60 | |
| 61 | /* |
| 62 | Skip operation if we didn't change key cache. This can happen if we |
| 63 | call this for all open instances of the same table |
| 64 | */ |
| 65 | if (old_key_cache == new_key_cache) |
| 66 | DBUG_RETURN(0); |
| 67 | |
| 68 | /* |
| 69 | First flush all blocks for the table in the old key cache. |
| 70 | This is to ensure that the disk is consistent with the data pages |
| 71 | in memory (which may not be the case if the table uses delayed_key_write) |
| 72 | |
| 73 | Note that some other read thread may still fill in the key cache with |
| 74 | new blocks during this call and after, but this doesn't matter as |
| 75 | all threads will start using the new key cache for their next call to |
| 76 | myisam library and we know that there will not be any changed blocks |
| 77 | in the old key cache. |
| 78 | */ |
| 79 | |
| 80 | pthread_mutex_lock(&old_key_cache->op_lock); |
| 81 | DEBUG_SYNC_C("assign_key_cache_op_lock" ); |
| 82 | if (flush_key_blocks(old_key_cache, share->kfile, &share->dirty_part_map, |
| 83 | FLUSH_RELEASE)) |
| 84 | { |
| 85 | error= my_errno; |
| 86 | mi_print_error(info->s, HA_ERR_CRASHED); |
| 87 | mi_mark_crashed(info); /* Mark that table must be checked */ |
| 88 | } |
| 89 | pthread_mutex_unlock(&old_key_cache->op_lock); |
| 90 | DEBUG_SYNC_C("assign_key_cache_op_unlock" ); |
| 91 | |
| 92 | /* |
| 93 | Flush the new key cache for this file. This is needed to ensure |
| 94 | that there is no old blocks (with outdated data) left in the new key |
| 95 | cache from an earlier assign_to_keycache operation |
| 96 | |
| 97 | (This can never fail as there is never any not written data in the |
| 98 | new key cache) |
| 99 | */ |
| 100 | (void) flush_key_blocks(new_key_cache, share->kfile, &share->dirty_part_map, |
| 101 | FLUSH_RELEASE); |
| 102 | |
| 103 | /* |
| 104 | ensure that setting the key cache and changing the multi_key_cache |
| 105 | is done atomicly |
| 106 | */ |
| 107 | mysql_mutex_lock(&share->intern_lock); |
| 108 | /* |
| 109 | Tell all threads to use the new key cache |
| 110 | This should be seen at the lastes for the next call to an myisam function. |
| 111 | */ |
| 112 | share->key_cache= new_key_cache; |
| 113 | share->dirty_part_map= 0; |
| 114 | |
| 115 | /* store the key cache in the global hash structure for future opens */ |
| 116 | if (multi_key_cache_set((uchar*) share->unique_file_name, |
| 117 | share->unique_name_length, |
| 118 | new_key_cache)) |
| 119 | error= my_errno; |
| 120 | mysql_mutex_unlock(&share->intern_lock); |
| 121 | DBUG_RETURN(error); |
| 122 | } |
| 123 | |
| 124 | |
| 125 | /* |
| 126 | Change all MyISAM entries that uses one key cache to another key cache |
| 127 | |
| 128 | SYNOPSIS |
| 129 | mi_change_key_cache() |
| 130 | old_key_cache Old key cache |
| 131 | new_key_cache New key cache |
| 132 | |
| 133 | NOTES |
| 134 | This is used when we delete one key cache. |
| 135 | |
| 136 | To handle the case where some other threads tries to open an MyISAM |
| 137 | table associated with the to-be-deleted key cache while this operation |
| 138 | is running, we have to call 'multi_key_cache_change()' from this |
| 139 | function while we have a lock on the MyISAM table list structure. |
| 140 | |
| 141 | This is safe as long as it's only MyISAM that is using this specific |
| 142 | key cache. |
| 143 | */ |
| 144 | |
| 145 | |
| 146 | void mi_change_key_cache(KEY_CACHE *old_key_cache, |
| 147 | KEY_CACHE *new_key_cache) |
| 148 | { |
| 149 | LIST *pos; |
| 150 | DBUG_ENTER("mi_change_key_cache" ); |
| 151 | |
| 152 | /* |
| 153 | Lock list to ensure that no one can close the table while we manipulate it |
| 154 | */ |
| 155 | mysql_mutex_lock(&THR_LOCK_myisam); |
| 156 | for (pos=myisam_open_list ; pos ; pos=pos->next) |
| 157 | { |
| 158 | MI_INFO *info= (MI_INFO*) pos->data; |
| 159 | MYISAM_SHARE *share= info->s; |
| 160 | if (share->key_cache == old_key_cache) |
| 161 | mi_assign_to_key_cache(info, (ulonglong) ~0, new_key_cache); |
| 162 | } |
| 163 | |
| 164 | /* |
| 165 | We have to do the following call while we have the lock on the |
| 166 | MyISAM list structure to ensure that another thread is not trying to |
| 167 | open a new table that will be associted with the old key cache |
| 168 | */ |
| 169 | multi_key_cache_change(old_key_cache, new_key_cache); |
| 170 | mysql_mutex_unlock(&THR_LOCK_myisam); |
| 171 | DBUG_VOID_RETURN; |
| 172 | } |
| 173 | |