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
36int 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
149err:
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
171void _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