20 #include "probes_mysql.h"
21 #include "sql_class.h"
22 #include "sql_table.h"
25 #include "ha_archive.h"
28 #include <mysql/plugin.h>
104 #define ARZ ".ARZ" // The data file
105 #define ARN ".ARN" // Files used during an optimize call
106 #define ARM ".ARM" // Meta file (deprecated)
109 #define META_V1_OFFSET_CHECK_HEADER 0
110 #define META_V1_OFFSET_VERSION 1
111 #define META_V1_OFFSET_ROWS_RECORDED 2
112 #define META_V1_OFFSET_CHECK_POINT 10
113 #define META_V1_OFFSET_CRASHED 18
114 #define META_V1_LENGTH 19
119 #define DATA_BUFFER_SIZE 2 // Size of the data used in the data file
120 #define ARCHIVE_CHECK_HEADER 254 // The number we use to determine corruption
122 #ifdef HAVE_PSI_INTERFACE
123 extern "C" PSI_file_key arch_key_file_data;
130 int archive_discover(
handlerton *hton, THD* thd,
const char *db,
138 #define ARCHIVE_MIN_ROWS_TO_USE_BULK_INSERT 2
143 #define ARCHIVE_ROW_HEADER_SIZE 4
149 return new (mem_root)
ha_archive(hton, table);
153 #ifdef HAVE_PSI_INTERFACE
154 PSI_mutex_key az_key_mutex_Archive_share_mutex;
156 static PSI_mutex_info all_archive_mutexes[]=
158 { &az_key_mutex_Archive_share_mutex,
"Archive_share::mutex", 0}
161 PSI_file_key arch_key_file_metadata, arch_key_file_data, arch_key_file_frm;
162 static PSI_file_info all_archive_files[]=
164 { &arch_key_file_metadata,
"metadata", 0},
165 { &arch_key_file_data,
"data", 0},
166 { &arch_key_file_frm,
"FRM", 0}
169 static void init_archive_psi_keys(
void)
171 const char* category=
"archive";
174 count= array_elements(all_archive_mutexes);
177 count= array_elements(all_archive_files);
196 int archive_db_init(
void *p)
198 DBUG_ENTER(
"archive_db_init");
201 #ifdef HAVE_PSI_INTERFACE
202 init_archive_psi_keys();
206 archive_hton->state= SHOW_OPTION_YES;
207 archive_hton->db_type= DB_TYPE_ARCHIVE_DB;
208 archive_hton->create= archive_create_handler;
209 archive_hton->flags= HTON_NO_FLAGS;
210 archive_hton->discover= archive_discover;
216 Archive_share::Archive_share()
220 archive_write_open=
false;
222 DBUG_PRINT(
"ha_archive", (
"Archive_share: %p",
224 thr_lock_init(&lock);
229 &mutex, MY_MUTEX_INIT_FAST);
234 :
handler(hton, table_arg), share(NULL), delayed_insert(0), bulk_insert(0)
237 buffer.set((
char *)byte_buffer, IO_SIZE, system_charset_info);
240 ref_length=
sizeof(my_off_t);
241 archive_reader_open= FALSE;
244 int archive_discover(
handlerton *hton, THD* thd,
const char *db,
249 DBUG_ENTER(
"archive_discover");
250 DBUG_PRINT(
"archive_discover", (
"db: %s, name: %s", db, name));
252 char az_file[FN_REFLEN];
256 build_table_filename(az_file,
sizeof(az_file) - 1, db, name, ARZ, 0);
258 if (!(
mysql_file_stat(arch_key_file_data, az_file, &file_stat, MYF(0))))
261 if (!(azopen(&frm_stream, az_file, O_RDONLY|O_BINARY)))
263 if (errno == EROFS || errno == EACCES)
264 DBUG_RETURN(my_errno= errno);
265 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
268 if (frm_stream.frm_length == 0)
271 frm_ptr= (
char *)my_malloc(
sizeof(
char) * frm_stream.frm_length, MYF(0));
272 azread_frm(&frm_stream, frm_ptr);
273 azclose(&frm_stream);
275 *frmlen= frm_stream.frm_length;
276 *frmblob= (uchar*) frm_ptr;
284 static void save_auto_increment(
TABLE *table, ulonglong *value)
286 Field *field= table->found_next_number_field;
287 ulonglong auto_value=
288 (ulonglong) field->val_int(table->record[0] +
289 field->offset(table->record[0]));
290 if (*value <= auto_value)
291 *value= auto_value + 1;
304 char file_name[FN_REFLEN];
305 uchar
buf[META_V1_LENGTH];
307 DBUG_ENTER(
"Archive_share::read_v1_metafile");
309 fn_format(file_name, data_file_name,
"", ARM, MY_REPLACE_EXT);
310 if ((fd=
mysql_file_open(arch_key_file_metadata, file_name, O_RDONLY, MYF(0))) == -1)
319 rows_recorded= uint8korr(buf + META_V1_OFFSET_ROWS_RECORDED);
320 crashed= buf[META_V1_OFFSET_CRASHED];
336 char file_name[FN_REFLEN];
337 uchar
buf[META_V1_LENGTH];
339 DBUG_ENTER(
"Archive_share::write_v1_metafile");
341 buf[META_V1_OFFSET_CHECK_HEADER]= ARCHIVE_CHECK_HEADER;
342 buf[META_V1_OFFSET_VERSION]= 1;
343 int8store(buf + META_V1_OFFSET_ROWS_RECORDED, rows_recorded);
344 int8store(buf + META_V1_OFFSET_CHECK_POINT, (ulonglong) 0);
345 buf[META_V1_OFFSET_CRASHED]= crashed;
347 fn_format(file_name, data_file_name,
"", ARM, MY_REPLACE_EXT);
348 if ((fd=
mysql_file_open(arch_key_file_metadata, file_name, O_WRONLY, MYF(0))) == -1)
370 unsigned int ha_archive::pack_row_v1(uchar *
record)
374 DBUG_ENTER(
"pack_row_v1");
375 memcpy(record_buffer->buffer, record, table->s->reclength);
376 pos= record_buffer->buffer + table->s->reclength;
377 for (blob= table->s->blob_field, end= blob + table->s->blob_fields;
380 uint32 length= ((
Field_blob *) table->field[*blob])->get_length();
384 ((
Field_blob *) table->field[*blob])->get_ptr(&data_ptr);
385 memcpy(pos, data_ptr, length);
389 DBUG_RETURN(pos - record_buffer->buffer);
396 int ha_archive::read_data_header(
azio_stream *file_to_read)
400 uchar data_buffer[DATA_BUFFER_SIZE];
401 DBUG_ENTER(
"ha_archive::read_data_header");
403 if (azrewind(file_to_read) == -1)
404 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
406 if (file_to_read->version >= 3)
410 DBUG_PRINT(
"ha_archive", (
"Reading legacy data header"));
412 ret= azread(file_to_read, data_buffer, DATA_BUFFER_SIZE, &error);
414 if (ret != DATA_BUFFER_SIZE)
416 DBUG_PRINT(
"ha_archive", (
"Reading, expected %d got %lu",
417 DATA_BUFFER_SIZE, ret));
423 DBUG_PRINT(
"ha_archive", (
"Compression error (%d)", error));
427 DBUG_PRINT(
"ha_archive", (
"Check %u", data_buffer[0]));
428 DBUG_PRINT(
"ha_archive", (
"Version %u", data_buffer[1]));
430 if ((data_buffer[0] != (uchar)ARCHIVE_CHECK_HEADER) &&
431 (data_buffer[1] != (uchar)ARCHIVE_VERSION))
432 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
449 DBUG_ENTER(
"ha_archive::get_share");
460 *rc= HA_ERR_OUT_OF_MEM;
463 DBUG_PRINT(
"ha_archive", (
"new Archive_share: %p",
466 fn_format(tmp_share->data_file_name, table_name,
"",
467 ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
468 strmov(tmp_share->table_name, table_name);
469 DBUG_PRINT(
"ha_archive", (
"Data File %s",
470 tmp_share->data_file_name));
478 if (!(azopen(&archive_tmp, tmp_share->data_file_name, O_RDONLY|O_BINARY)))
481 *rc= my_errno ? my_errno : HA_ERR_CRASHED;
485 stats.auto_increment_value= archive_tmp.auto_increment + 1;
486 tmp_share->rows_recorded= (ha_rows)archive_tmp.rows;
487 tmp_share->crashed= archive_tmp.dirty;
489 if (archive_tmp.version == 1)
491 azclose(&archive_tmp);
495 if (tmp_share->crashed)
496 *rc= HA_ERR_CRASHED_ON_USAGE;
500 DBUG_ASSERT(tmp_share || *rc);
502 DBUG_RETURN(tmp_share);
506 int Archive_share::init_archive_writer()
508 DBUG_ENTER(
"Archive_share::init_archive_writer");
514 if (!(azopen(&archive_write, data_file_name,
517 DBUG_PRINT(
"ha_archive", (
"Could not open archive write file"));
521 archive_write_open=
true;
527 void Archive_share::close_archive_writer()
530 if (archive_write_open)
532 if (archive_write.version == 1)
534 azclose(&archive_write);
535 archive_write_open=
false;
544 int ha_archive::init_archive_reader()
546 DBUG_ENTER(
"ha_archive::init_archive_reader");
553 if (!archive_reader_open)
555 if (!(azopen(&archive, share->data_file_name, O_RDONLY|O_BINARY)))
557 DBUG_PRINT(
"ha_archive", (
"Could not open archive read file"));
558 share->crashed= TRUE;
561 archive_reader_open= TRUE;
571 static const char *ha_archive_exts[] = {
578 return ha_archive_exts;
588 int ha_archive::open(
const char *name,
int mode, uint open_options)
591 DBUG_ENTER(
"ha_archive::open");
593 DBUG_PRINT(
"ha_archive", (
"archive table was opened for crash: %s",
594 (open_options & HA_OPEN_FOR_REPAIR) ?
"yes" :
"no"));
595 share= get_share(name, &rc);
604 case HA_ERR_CRASHED_ON_USAGE:
605 if (open_options & HA_OPEN_FOR_REPAIR)
612 record_buffer= create_record_buffer(table->s->reclength +
613 ARCHIVE_ROW_HEADER_SIZE);
616 DBUG_RETURN(HA_ERR_OUT_OF_MEM);
618 thr_lock_data_init(&share->lock, &lock, NULL);
620 DBUG_PRINT(
"ha_archive", (
"archive table was crashed %s",
621 rc == HA_ERR_CRASHED_ON_USAGE ?
"yes" :
"no"));
622 if (rc == HA_ERR_CRASHED_ON_USAGE && open_options & HA_OPEN_FOR_REPAIR)
648 int ha_archive::close(
void)
651 DBUG_ENTER(
"ha_archive::close");
653 destroy_record_buffer(record_buffer);
655 if (archive_reader_open)
657 if (azclose(&archive))
665 void ha_archive::frm_load(
const char *name,
azio_stream *dst)
667 char name_buff[FN_REFLEN];
671 DBUG_ENTER(
"ha_archive::frm_load");
672 fn_format(name_buff, name,
"",
".frm", MY_REPLACE_EXT | MY_UNPACK_FILENAME);
675 if ((frm_file=
mysql_file_open(arch_key_file_frm, name_buff, O_RDONLY, MYF(0))) >= 0)
679 frm_ptr= (uchar *) my_malloc(
sizeof(uchar) * (size_t) file_stat.st_size, MYF(0));
682 if (
mysql_file_read(frm_file, frm_ptr, (
size_t) file_stat.st_size, MYF(0)) ==
683 (
size_t) file_stat.st_size)
684 azwrite_frm(dst, (
char *) frm_ptr, (size_t) file_stat.st_size);
709 if (!src->frm_length)
711 frm_load(table->s->normalized_path.str, dst);
715 if (!(frm_ptr= (
char *) my_malloc(src->frm_length, MYF(0))))
716 return HA_ERR_OUT_OF_MEM;
719 if (azread_frm(src, frm_ptr) ||
720 azwrite_frm(dst, frm_ptr, src->frm_length))
721 rc= my_errno ? my_errno : HA_ERR_INTERNAL_ERROR;
738 int ha_archive::create(
const char *name,
TABLE *table_arg,
741 char name_buff[FN_REFLEN];
742 char linkname[FN_REFLEN];
747 DBUG_ENTER(
"ha_archive::create");
749 stats.auto_increment_value= create_info->auto_increment_value;
751 for (uint key= 0; key < table_arg->s->keys; key++)
753 KEY *pos= table_arg->key_info+key;
757 for (; key_part != key_part_end; key_part++)
759 Field *field= key_part->field;
761 if (!(field->flags & AUTO_INCREMENT_FLAG))
764 DBUG_PRINT(
"ha_archive", (
"Index error in creating archive table"));
775 create_info->data_file_name &&
776 create_info->data_file_name[0] !=
'#')
778 DBUG_PRINT(
"ha_archive", (
"archive will create stream file %s",
779 create_info->data_file_name));
781 fn_format(name_buff, create_info->data_file_name,
"", ARZ,
782 MY_REPLACE_EXT | MY_UNPACK_FILENAME);
783 fn_format(linkname, name,
"", ARZ,
784 MY_REPLACE_EXT | MY_UNPACK_FILENAME);
789 if (create_info->data_file_name)
791 push_warning_printf(table_arg->in_use, Sql_condition::WARN_LEVEL_WARN,
793 ER_DEFAULT(WARN_OPTION_IGNORED),
796 fn_format(name_buff, name,
"", ARZ,
797 MY_REPLACE_EXT | MY_UNPACK_FILENAME);
802 if (create_info->index_file_name)
804 push_warning_printf(table_arg->in_use, Sql_condition::WARN_LEVEL_WARN,
806 ER_DEFAULT(WARN_OPTION_IGNORED),
814 if (!(
mysql_file_stat(arch_key_file_data, name_buff, &file_stat, MYF(0))))
817 if (!(azopen(&create_stream, name_buff, O_CREAT|O_RDWR|O_BINARY)))
824 my_symlink(name_buff, linkname, MYF(0));
826 frm_load(name, &create_stream);
828 if (create_info->comment.str)
829 azwrite_comment(&create_stream, create_info->comment.str,
830 create_info->comment.length);
836 create_stream.auto_increment=
stats.auto_increment_value ?
837 stats.auto_increment_value - 1 : 0;
838 if (azclose(&create_stream))
847 DBUG_PRINT(
"ha_archive", (
"Creating File %s", name_buff));
848 DBUG_PRINT(
"ha_archive", (
"Creating Link %s", linkname));
857 DBUG_RETURN(error ? error : -1);
866 unsigned int r_pack_length;
867 DBUG_ENTER(
"ha_archive::real_write_row");
870 r_pack_length= pack_row(buf, writer);
872 written= azwrite(writer, record_buffer->buffer, r_pack_length);
873 if (written != r_pack_length)
875 DBUG_PRINT(
"ha_archive", (
"Wrote %d bytes expected %d",
877 (uint32)r_pack_length));
881 if (!delayed_insert || !bulk_insert)
893 uint32 ha_archive::max_row_length(
const uchar *buf)
895 uint32 length= (uint32)(table->s->reclength + table->s->fields*2);
896 length+= ARCHIVE_ROW_HEADER_SIZE;
899 for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
903 if (!table->field[*ptr]->is_null())
904 length += 2 + ((
Field_blob*)table->field[*ptr])->get_length();
911 unsigned int ha_archive::pack_row(uchar *record,
azio_stream *writer)
915 DBUG_ENTER(
"ha_archive::pack_row");
918 if (fix_rec_buff(max_row_length(record)))
919 DBUG_RETURN(HA_ERR_OUT_OF_MEM);
921 if (writer->version == 1)
922 DBUG_RETURN(pack_row_v1(record));
925 memcpy(record_buffer->buffer+ARCHIVE_ROW_HEADER_SIZE,
926 record, table->s->null_bytes);
927 ptr= record_buffer->buffer + table->s->null_bytes + ARCHIVE_ROW_HEADER_SIZE;
929 for (
Field **field=table->field ; *field ; field++)
931 if (!((*field)->is_null()))
932 ptr= (*field)->pack(ptr, record + (*field)->offset(record));
935 int4store(record_buffer->buffer, (
int)(ptr - record_buffer->buffer -
936 ARCHIVE_ROW_HEADER_SIZE));
937 DBUG_PRINT(
"ha_archive",(
"Pack row length %u", (
unsigned int)
938 (ptr - record_buffer->buffer -
939 ARCHIVE_ROW_HEADER_SIZE)));
941 DBUG_RETURN((
unsigned int) (ptr - record_buffer->buffer));
954 int ha_archive::write_row(uchar *buf)
957 uchar *read_buf= NULL;
959 uchar *record= table->record[0];
960 DBUG_ENTER(
"ha_archive::write_row");
963 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
965 ha_statistic_increment(&SSV::ha_write_count);
968 if (!share->archive_write_open && share->init_archive_writer())
970 rc= HA_ERR_CRASHED_ON_USAGE;
974 if (table->next_number_field && record == table->record[0])
976 KEY *mkey= &table->s->key_info[0];
977 update_auto_increment();
978 temp_auto= (((
Field_num*) table->next_number_field)->unsigned_flag ||
979 table->next_number_field->val_int() > 0 ?
980 table->next_number_field->val_int() : 0);
986 if (temp_auto <= share->archive_write.auto_increment &&
987 mkey->
flags & HA_NOSAME)
989 rc= HA_ERR_FOUND_DUPP_KEY;
1004 if (!(read_buf= (uchar*) my_malloc(table->s->reclength, MYF(MY_WME))))
1006 rc= HA_ERR_OUT_OF_MEM;
1013 azflush(&(share->archive_write), Z_SYNC_FLUSH);
1017 if (read_data_header(&archive))
1019 rc= HA_ERR_CRASHED_ON_USAGE;
1023 Field *mfield= table->next_number_field;
1025 while (!(get_row(&archive, read_buf)))
1027 if (!memcmp(read_buf + mfield->offset(record),
1028 table->next_number_field->ptr,
1029 mfield->max_display_length()))
1031 rc= HA_ERR_FOUND_DUPP_KEY;
1039 if (temp_auto > share->archive_write.auto_increment)
1040 stats.auto_increment_value=
1041 (share->archive_write.auto_increment= temp_auto) + 1;
1049 share->rows_recorded++;
1050 rc= real_write_row(buf, &(share->archive_write));
1060 ulonglong nb_desired_values,
1061 ulonglong *first_value,
1062 ulonglong *nb_reserved_values)
1064 *nb_reserved_values= ULONGLONG_MAX;
1065 *first_value= share->archive_write.auto_increment + 1;
1069 int ha_archive::index_init(uint keynr,
bool sorted)
1071 DBUG_ENTER(
"ha_archive::index_init");
1072 active_index= keynr;
1081 int ha_archive::index_read(uchar *buf,
const uchar *key,
1082 uint key_len,
enum ha_rkey_function find_flag)
1085 DBUG_ENTER(
"ha_archive::index_read");
1086 MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
1087 rc= index_read_idx(buf, active_index, key, key_len, find_flag);
1088 MYSQL_INDEX_READ_ROW_DONE(rc);
1093 int ha_archive::index_read_idx(uchar *buf, uint
index,
const uchar *key,
1094 uint key_len,
enum ha_rkey_function find_flag)
1098 KEY *mkey= &table->s->key_info[
index];
1099 current_k_offset= mkey->key_part->offset;
1101 current_key_len= key_len;
1104 DBUG_ENTER(
"ha_archive::index_read_idx");
1111 while (!(get_row(&archive, buf)))
1113 if (!memcmp(current_key, buf + current_k_offset, current_key_len))
1128 DBUG_RETURN(rc ? rc : HA_ERR_END_OF_FILE);
1137 DBUG_ENTER(
"ha_archive::index_next");
1138 MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
1140 while (!(get_row(&archive, buf)))
1142 if (!memcmp(current_key, buf+current_k_offset, current_key_len))
1149 rc= found ? 0 : HA_ERR_END_OF_FILE;
1150 MYSQL_INDEX_READ_ROW_DONE(rc);
1162 DBUG_ENTER(
"ha_archive::rnd_init");
1165 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
1167 init_archive_reader();
1172 scan_rows=
stats.records;
1173 DBUG_PRINT(
"info", (
"archive will retrieve %llu rows",
1174 (
unsigned long long) scan_rows));
1176 if (read_data_header(&archive))
1177 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
1188 int ha_archive::get_row(
azio_stream *file_to_read, uchar *buf)
1191 DBUG_ENTER(
"ha_archive::get_row");
1192 DBUG_PRINT(
"ha_archive", (
"Picking version for get_row() %d -> %d",
1193 (uchar)file_to_read->version,
1195 if (file_to_read->version == ARCHIVE_VERSION)
1196 rc= get_row_version3(file_to_read, buf);
1198 rc= get_row_version2(file_to_read, buf);
1200 DBUG_PRINT(
"ha_archive", (
"Return %d\n", rc));
1206 bool ha_archive::fix_rec_buff(
unsigned int length)
1208 DBUG_ENTER(
"ha_archive::fix_rec_buff");
1209 DBUG_PRINT(
"ha_archive", (
"Fixing %u for %u",
1210 length, record_buffer->length));
1211 DBUG_ASSERT(record_buffer->buffer);
1213 if (length > record_buffer->length)
1216 if (!(newptr=(uchar*) my_realloc((uchar*) record_buffer->buffer,
1218 MYF(MY_ALLOW_ZERO_PTR))))
1220 record_buffer->buffer= newptr;
1221 record_buffer->length= length;
1224 DBUG_ASSERT(length <= record_buffer->length);
1229 int ha_archive::unpack_row(
azio_stream *file_to_read, uchar *record)
1231 DBUG_ENTER(
"ha_archive::unpack_row");
1235 uchar size_buffer[ARCHIVE_ROW_HEADER_SIZE], *size_buffer_p= size_buffer;
1236 unsigned int row_len;
1239 read= azread(file_to_read, size_buffer, ARCHIVE_ROW_HEADER_SIZE, &error);
1241 if (error == Z_STREAM_ERROR || (read && read < ARCHIVE_ROW_HEADER_SIZE))
1242 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
1245 if (read == 0 || read != ARCHIVE_ROW_HEADER_SIZE)
1246 DBUG_RETURN(HA_ERR_END_OF_FILE);
1248 row_len= uint4korr(size_buffer_p);
1249 DBUG_PRINT(
"ha_archive",(
"Unpack row length %u -> %u", row_len,
1250 (
unsigned int)table->s->reclength));
1252 if (fix_rec_buff(row_len))
1254 DBUG_RETURN(HA_ERR_OUT_OF_MEM);
1256 DBUG_ASSERT(row_len <= record_buffer->length);
1258 read= azread(file_to_read, record_buffer->buffer, row_len, &error);
1260 if (read != row_len || error)
1262 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
1266 const uchar *ptr= record_buffer->buffer;
1277 memset(record, 0, table->s->reclength);
1278 memcpy(record, ptr, table->s->null_bytes);
1279 ptr+= table->s->null_bytes;
1280 for (
Field **field=table->field ; *field ; field++)
1282 if (!((*field)->is_null_in_record(record)))
1284 ptr= (*field)->unpack(record + (*field)->offset(table->record[0]), ptr);
1291 int ha_archive::get_row_version3(
azio_stream *file_to_read, uchar *buf)
1293 DBUG_ENTER(
"ha_archive::get_row_version3");
1295 int returnable= unpack_row(file_to_read, buf);
1297 DBUG_RETURN(returnable);
1301 int ha_archive::get_row_version2(
azio_stream *file_to_read, uchar *buf)
1307 size_t total_blob_length= 0;
1309 DBUG_ENTER(
"ha_archive::get_row_version2");
1311 read= azread(file_to_read, (voidp)buf, table->s->reclength, &error);
1315 DBUG_RETURN(HA_ERR_END_OF_FILE);
1317 if (read != table->s->reclength)
1319 DBUG_PRINT(
"ha_archive::get_row_version2", (
"Read %u bytes expected %u",
1321 (
unsigned int)table->s->reclength));
1322 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
1325 if (error == Z_STREAM_ERROR || error == Z_DATA_ERROR )
1326 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
1332 if ((ulong) read != table->s->reclength)
1333 DBUG_RETURN(HA_ERR_END_OF_FILE);
1336 for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
1340 if (bitmap_is_set(read_set,
1341 (((
Field_blob*) table->field[*ptr])->field_index)))
1342 total_blob_length += ((
Field_blob*) table->field[*ptr])->get_length();
1346 buffer.alloc(total_blob_length);
1347 last= (
char *)buffer.ptr();
1350 for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
1357 if (bitmap_is_set(read_set,
1358 ((
Field_blob*) table->field[*ptr])->field_index))
1360 read= azread(file_to_read, last, size, &error);
1363 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
1365 if ((
size_t) read != size)
1366 DBUG_RETURN(HA_ERR_END_OF_FILE);
1367 ((
Field_blob*) table->field[*ptr])->set_ptr(size, (uchar*) last);
1372 (void)azseek(file_to_read, size, SEEK_CUR);
1388 DBUG_ENTER(
"ha_archive::rnd_next");
1389 MYSQL_READ_ROW_START(table_share->db.str,
1390 table_share->table_name.str, TRUE);
1393 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
1397 rc= HA_ERR_END_OF_FILE;
1402 ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1403 current_position= aztell(&archive);
1404 rc= get_row(&archive, buf);
1406 table->status=rc ? STATUS_NOT_FOUND: 0;
1409 MYSQL_READ_ROW_DONE(rc);
1420 void ha_archive::position(
const uchar *record)
1422 DBUG_ENTER(
"ha_archive::position");
1423 my_store_ptr(ref,
ref_length, current_position);
1438 DBUG_ENTER(
"ha_archive::rnd_pos");
1439 MYSQL_READ_ROW_START(table_share->db.str,
1440 table_share->table_name.str, FALSE);
1441 ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1442 current_position= (my_off_t)my_get_ptr(pos,
ref_length);
1443 if (azseek(&archive, current_position, SEEK_SET) == (my_off_t)(-1L))
1445 rc= HA_ERR_CRASHED_ON_USAGE;
1448 rc= get_row(&archive, buf);
1450 MYSQL_READ_ROW_DONE(rc);
1461 DBUG_ENTER(
"ha_archive::repair");
1462 int rc= optimize(thd, check_opt);
1465 DBUG_RETURN(HA_ADMIN_CORRUPT);
1467 share->crashed= FALSE;
1475 int ha_archive::optimize(THD* thd,
HA_CHECK_OPT* check_opt)
1480 my_bitmap_map *org_bitmap;
1481 char writer_filename[FN_REFLEN];
1482 DBUG_ENTER(
"ha_archive::optimize");
1485 if (share->in_optimize)
1488 DBUG_RETURN(HA_ADMIN_FAILED);
1490 share->in_optimize=
true;
1492 count= share->rows_recorded;
1493 if (share->archive_write_open)
1494 azflush(&share->archive_write, Z_SYNC_FLUSH);
1497 init_archive_reader();
1500 fn_format(writer_filename, share->table_name,
"", ARN,
1501 MY_REPLACE_EXT | MY_UNPACK_FILENAME);
1503 if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR|O_BINARY)))
1505 share->in_optimize=
false;
1506 DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
1513 if ((rc= frm_copy(&archive, &writer)))
1515 share->in_optimize=
false;
1526 DBUG_PRINT(
"ha_archive", (
"archive extended rebuild"));
1532 if ((rc= read_data_header(&archive)))
1534 share->in_optimize=
false;
1538 stats.auto_increment_value= 1;
1539 org_bitmap= tmp_use_all_columns(table, table->read_set);
1541 for (ha_rows cur_count= count; cur_count; cur_count--)
1543 if ((rc= get_row(&archive, table->record[0])))
1545 real_write_row(table->record[0], &writer);
1546 if (table->found_next_number_field)
1547 save_auto_increment(table, &
stats.auto_increment_value);
1552 share->close_archive_writer();
1556 for (count= share->rows_recorded - count; count; count--)
1558 if ((rc= get_row(&archive, table->record[0])))
1560 real_write_row(table->record[0], &writer);
1561 if (table->found_next_number_field)
1562 save_auto_increment(table, &
stats.auto_increment_value);
1566 tmp_restore_column_map(table->read_set, org_bitmap);
1567 share->rows_recorded= (ha_rows) writer.rows;
1568 share->archive_write.auto_increment=
stats.auto_increment_value - 1;
1569 DBUG_PRINT(
"info", (
"recovered %llu archive rows",
1570 (
unsigned long long)share->rows_recorded));
1572 DBUG_PRINT(
"ha_archive", (
"recovered %llu archive rows",
1573 (
unsigned long long)share->rows_recorded));
1582 if (rc && rc != HA_ERR_END_OF_FILE && !(check_opt->flags & T_EXTEND))
1584 share->in_optimize=
false;
1590 share->dirty= FALSE;
1592 archive_reader_open= FALSE;
1595 rc= my_rename(writer_filename, share->data_file_name, MYF(0));
1596 share->in_optimize=
false;
1601 DBUG_PRINT(
"ha_archive", (
"Failed to recover, error was %d", rc));
1612 enum thr_lock_type lock_type)
1614 if (lock_type == TL_WRITE_DELAYED)
1615 delayed_insert= TRUE;
1617 delayed_insert= FALSE;
1619 if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
1628 if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
1629 lock_type <= TL_WRITE) && !thd_in_lock_tables(thd)
1630 && !thd_tablespace_op(thd))
1631 lock_type = TL_WRITE_ALLOW_WRITE;
1641 if (lock_type == TL_READ_NO_INSERT && !thd_in_lock_tables(thd))
1642 lock_type = TL_READ;
1644 lock.type=lock_type;
1654 char tmp_real_path[FN_REFLEN];
1655 DBUG_ENTER(
"ha_archive::update_create_info");
1657 ha_archive::info(HA_STATUS_AUTO);
1658 if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
1660 create_info->auto_increment_value=
stats.auto_increment_value;
1663 if (!(my_readlink(tmp_real_path, share->data_file_name, MYF(0))))
1664 create_info->data_file_name= sql_strdup(tmp_real_path);
1673 int ha_archive::info(uint flag)
1675 DBUG_ENTER(
"ha_archive::info");
1680 DBUG_PRINT(
"ha_archive", (
"archive flushing out rows for scan"));
1681 DBUG_ASSERT(share->archive_write_open);
1682 azflush(&(share->archive_write), Z_SYNC_FLUSH);
1683 share->dirty= FALSE;
1690 stats.records= share->rows_recorded;
1695 DBUG_PRINT(
"ha_archive", (
"Stats rows is %d\n", (
int)
stats.records));
1697 if (flag & (HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE))
1701 (void)
mysql_file_stat(arch_key_file_data, share->data_file_name, &file_stat, MYF(MY_WME));
1703 if (flag & HA_STATUS_TIME)
1704 stats.update_time= (ulong) file_stat.st_mtime;
1705 if (flag & HA_STATUS_CONST)
1707 stats.max_data_file_length= share->rows_recorded *
stats.mean_rec_length;
1708 stats.max_data_file_length= MAX_FILE_SIZE;
1709 stats.create_time= (ulong) file_stat.st_ctime;
1711 if (flag & HA_STATUS_VARIABLE)
1713 stats.delete_length= 0;
1714 stats.data_file_length= file_stat.st_size;
1715 stats.index_file_length=0;
1717 ulong(
stats.data_file_length /
stats.records) : table->s->reclength;
1721 if (flag & HA_STATUS_AUTO)
1724 init_archive_reader();
1726 azflush(&archive, Z_SYNC_FLUSH);
1728 stats.auto_increment_value= archive.auto_increment + 1;
1748 DBUG_ENTER(
"ha_archive::extra");
1753 case HA_EXTRA_PREPARE_FOR_RENAME:
1754 case HA_EXTRA_FORCE_REOPEN:
1756 if (archive_reader_open)
1758 ret= azclose(&archive);
1759 archive_reader_open=
false;
1762 share->close_archive_writer();
1780 void ha_archive::start_bulk_insert(ha_rows rows)
1782 DBUG_ENTER(
"ha_archive::start_bulk_insert");
1783 if (!rows || rows >= ARCHIVE_MIN_ROWS_TO_USE_BULK_INSERT)
1793 int ha_archive::end_bulk_insert()
1795 DBUG_ENTER(
"ha_archive::end_bulk_insert");
1798 if (share->archive_write_open)
1811 DBUG_ENTER(
"ha_archive::truncate");
1812 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
1818 bool ha_archive::is_crashed()
const
1820 DBUG_ENTER(
"ha_archive::is_crashed");
1821 DBUG_RETURN(share->crashed);
1838 DBUG_ENTER(
"ha_archive::check_for_upgrade");
1839 if (init_archive_reader())
1840 DBUG_RETURN(HA_ADMIN_CORRUPT);
1841 if (archive.version < ARCHIVE_VERSION)
1842 DBUG_RETURN(HA_ADMIN_NEEDS_UPGRADE);
1843 DBUG_RETURN(HA_ADMIN_OK);
1851 int ha_archive::check(THD* thd,
HA_CHECK_OPT* check_opt)
1854 const char *old_proc_info;
1856 DBUG_ENTER(
"ha_archive::check");
1858 old_proc_info= thd_proc_info(thd,
"Checking table");
1860 count= share->rows_recorded;
1862 if (share->archive_write_open)
1863 azflush(&(share->archive_write), Z_SYNC_FLUSH);
1866 if (init_archive_reader())
1867 DBUG_RETURN(HA_ADMIN_CORRUPT);
1872 read_data_header(&archive);
1873 for (ha_rows cur_count= count; cur_count; cur_count--)
1875 if ((rc= get_row(&archive, table->record[0])))
1884 count= share->rows_recorded - count;
1885 if (share->archive_write_open)
1886 azflush(&(share->archive_write), Z_SYNC_FLUSH);
1887 while (!(rc= get_row(&archive, table->record[0])))
1891 if ((rc && rc != HA_ERR_END_OF_FILE) || count)
1894 thd_proc_info(thd, old_proc_info);
1895 DBUG_RETURN(HA_ADMIN_OK);
1898 thd_proc_info(thd, old_proc_info);
1899 share->crashed= FALSE;
1900 DBUG_RETURN(HA_ADMIN_CORRUPT);
1906 bool ha_archive::check_and_repair(THD *thd)
1909 DBUG_ENTER(
"ha_archive::check_and_repair");
1913 DBUG_RETURN(
repair(thd, &check_opt));
1918 DBUG_ENTER(
"ha_archive::create_record_buffer");
1926 r->length= (int)length;
1928 if (!(r->buffer= (uchar*) my_malloc(r->length,
1940 DBUG_ENTER(
"ha_archive::destroy_record_buffer");
1949 if (info->auto_increment_value !=
stats.auto_increment_value ||
1950 (info->used_fields & HA_CREATE_USED_DATADIR) ||
1951 info->data_file_name ||
1952 (info->used_fields & HA_CREATE_USED_COMMENT) ||
1953 table_changes != IS_EQUAL_YES)
1954 return COMPATIBLE_DATA_NO;
1956 return COMPATIBLE_DATA_YES;
1961 { MYSQL_HANDLERTON_INTERFACE_VERSION };
1963 mysql_declare_plugin(archive)
1965 MYSQL_STORAGE_ENGINE_PLUGIN,
1966 &archive_storage_engine,
1968 "Brian Aker, MySQL AB",
1969 "Archive storage engine",
1979 mysql_declare_plugin_end;