1 | /* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB |
2 | |
3 | This program is free software; you can redistribute it and/or modify |
4 | it under the terms of the GNU General Public License as published by |
5 | the Free Software Foundation; version 2 of the License. |
6 | |
7 | This program is distributed in the hope that it will be useful, |
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | GNU General Public License for more details. |
11 | |
12 | You should have received a copy of the GNU General Public License |
13 | along with this program; if not, write to the Free Software |
14 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ |
15 | |
16 | /* Remove all rows from a MARIA table */ |
17 | /* This clears the status information and truncates files */ |
18 | |
19 | #include "maria_def.h" |
20 | #include "trnman.h" |
21 | |
22 | /** |
23 | @brief deletes all rows from a table |
24 | |
25 | @param info Maria handler |
26 | |
27 | @note It is important that this function does not rely on the state |
28 | information, as it may be called by ma_apply_undo_bulk_insert() on an |
29 | inconsistent table left by a crash. |
30 | |
31 | @return Operation status |
32 | @retval 0 ok |
33 | @retval 1 error |
34 | */ |
35 | |
36 | int maria_delete_all_rows(MARIA_HA *info) |
37 | { |
38 | MARIA_SHARE *share= info->s; |
39 | my_bool log_record; |
40 | LSN lsn; |
41 | DBUG_ENTER("maria_delete_all_rows" ); |
42 | |
43 | if (share->options & HA_OPTION_READ_ONLY_DATA) |
44 | { |
45 | DBUG_RETURN(my_errno=EACCES); |
46 | } |
47 | /** |
48 | @todo LOCK take X-lock on table here. |
49 | When we have versioning, if some other thread is looking at this table, |
50 | we cannot shrink the file like this. |
51 | */ |
52 | if (_ma_readinfo(info,F_WRLCK,1)) |
53 | DBUG_RETURN(my_errno); |
54 | log_record= share->now_transactional && !share->temporary; |
55 | |
56 | if (log_record) |
57 | { |
58 | /* |
59 | This record will be used by Recovery to finish the deletion if it |
60 | crashed. We force it to have a complete history in the log. |
61 | */ |
62 | LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1]; |
63 | uchar log_data[FILEID_STORE_SIZE]; |
64 | log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data; |
65 | log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data); |
66 | if (unlikely(translog_write_record(&lsn, LOGREC_REDO_DELETE_ALL, |
67 | info->trn, info, 0, |
68 | sizeof(log_array)/sizeof(log_array[0]), |
69 | log_array, log_data, NULL) || |
70 | translog_flush(lsn))) |
71 | goto err; |
72 | /* |
73 | If we fail in this function after this point, log and table will be |
74 | inconsistent. |
75 | */ |
76 | if (_ma_mark_file_changed(share)) |
77 | goto err; |
78 | } |
79 | else |
80 | { |
81 | if (_ma_mark_file_changed(share)) |
82 | goto err; |
83 | /* Other branch called function below when writing log record, in hook */ |
84 | _ma_reset_status(info); |
85 | } |
86 | /* Remove old history as the table is now empty for everyone */ |
87 | _ma_reset_state(info); |
88 | share->state.changed= 0; |
89 | |
90 | /* |
91 | If we are using delayed keys or if the user has done changes to the tables |
92 | since it was locked then there may be key blocks in the page cache. Or |
93 | there may be data blocks there. We need to throw them away or they may |
94 | re-enter the emptied table or another table later. |
95 | */ |
96 | |
97 | #ifdef HAVE_MMAP |
98 | if (share->file_map) |
99 | _ma_unmap_file(info); |
100 | #endif |
101 | |
102 | if (_ma_flush_table_files(info, MARIA_FLUSH_DATA|MARIA_FLUSH_INDEX, |
103 | FLUSH_IGNORE_CHANGED, FLUSH_IGNORE_CHANGED) || |
104 | mysql_file_chsize(info->dfile.file, 0, 0, MYF(MY_WME)) || |
105 | mysql_file_chsize(share->kfile.file, share->base.keystart, 0, MYF(MY_WME))) |
106 | goto err; |
107 | |
108 | if (_ma_initialize_data_file(share, info->dfile.file)) |
109 | goto err; |
110 | |
111 | if (log_record) |
112 | { |
113 | /* |
114 | Because LOGREC_REDO_DELETE_ALL does not operate on pages, it has the |
115 | following problem: |
116 | delete_all; inserts (redo_insert); all pages get flushed; checkpoint: |
117 | the dirty pages list will be empty. In recovery, delete_all is executed, |
118 | but redo_insert are skipped (dirty pages list is empty). |
119 | To avoid this, we need to set skip_redo_lsn now, and thus need to sync |
120 | files. |
121 | Also fixes the problem of: |
122 | bulk insert; insert; delete_all; crash: |
123 | "bulk insert" is skipped (no REDOs), so if "insert" would not be skipped |
124 | (if we didn't update skip_redo_lsn below) then "insert" would be tried |
125 | and fail, saying that it sees that the first page has to be created |
126 | though the inserted row has rownr>0. |
127 | */ |
128 | my_bool error= _ma_state_info_write(share, |
129 | MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET | |
130 | MA_STATE_INFO_WRITE_LOCK) || |
131 | _ma_update_state_lsns(share, lsn, trnman_get_min_trid(), FALSE, FALSE) || |
132 | _ma_sync_table_files(info); |
133 | info->trn->rec_lsn= LSN_IMPOSSIBLE; |
134 | if (error) |
135 | goto err; |
136 | } |
137 | |
138 | if (info->opt_flag & WRITE_CACHE_USED) |
139 | reinit_io_cache(&info->rec_cache, WRITE_CACHE, 0, 1, 1); |
140 | |
141 | _ma_writeinfo(info, WRITEINFO_UPDATE_KEYFILE); |
142 | #ifdef HAVE_MMAP |
143 | /* Map again */ |
144 | if (share->file_map) |
145 | _ma_dynmap_file(info, (my_off_t) 0); |
146 | #endif |
147 | DBUG_RETURN(0); |
148 | |
149 | err: |
150 | { |
151 | int save_errno=my_errno; |
152 | _ma_writeinfo(info, WRITEINFO_UPDATE_KEYFILE); |
153 | info->update|=HA_STATE_WRITTEN; /* Buffer changed */ |
154 | DBUG_RETURN(my_errno=save_errno); |
155 | } |
156 | } /* maria_delete_all_rows */ |
157 | |
158 | |
159 | /* |
160 | Reset status information |
161 | |
162 | SYNOPSIS |
163 | _ma_reset_status() |
164 | maria Maria handler |
165 | |
166 | DESCRIPTION |
167 | Resets data and index file information as if the file would be empty |
168 | Files are not touched. |
169 | */ |
170 | |
171 | void _ma_reset_status(MARIA_HA *info) |
172 | { |
173 | MARIA_SHARE *share= info->s; |
174 | MARIA_STATE_INFO *state= &share->state; |
175 | uint i; |
176 | DBUG_ENTER("_ma_reset_status" ); |
177 | |
178 | state->split= 0; |
179 | state->state.records= state->state.del= 0; |
180 | state->changed= 0; /* File is optimized */ |
181 | state->dellink= HA_OFFSET_ERROR; |
182 | state->sortkey= (ushort) ~0; |
183 | state->state.key_file_length= share->base.keystart; |
184 | state->state.data_file_length= 0; |
185 | state->state.empty= state->state.key_empty= 0; |
186 | state->state.checksum= 0; |
187 | share->state.open_count= 0; |
188 | share->global_changed= 0; |
189 | |
190 | share->changed= 1; /* We must write state */ |
191 | |
192 | *info->state= state->state; |
193 | |
194 | /* Drop the delete key chain. */ |
195 | state->key_del= HA_OFFSET_ERROR; |
196 | /* Clear all keys */ |
197 | for (i=0 ; i < share->base.keys ; i++) |
198 | state->key_root[i]= HA_OFFSET_ERROR; |
199 | DBUG_VOID_RETURN; |
200 | } |
201 | |