| 1 | /* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. |
| 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ |
| 15 | |
| 16 | #ifdef USE_PRAGMA_INTERFACE |
| 17 | #pragma interface /* gcc class implementation */ |
| 18 | #endif |
| 19 | |
| 20 | #include <zlib.h> |
| 21 | #include "azlib.h" |
| 22 | |
| 23 | /* |
| 24 | Please read ha_archive.cc first. If you are looking for more general |
| 25 | answers on how storage engines work, look at ha_example.cc and |
| 26 | ha_example.h. |
| 27 | */ |
| 28 | |
| 29 | typedef struct st_archive_record_buffer { |
| 30 | uchar *buffer; |
| 31 | uint32 length; |
| 32 | } archive_record_buffer; |
| 33 | |
| 34 | |
| 35 | class Archive_share : public Handler_share |
| 36 | { |
| 37 | public: |
| 38 | mysql_mutex_t mutex; |
| 39 | THR_LOCK lock; |
| 40 | azio_stream archive_write; /* Archive file we are working with */ |
| 41 | ha_rows rows_recorded; /* Number of rows in tables */ |
| 42 | char table_name[FN_REFLEN]; |
| 43 | char data_file_name[FN_REFLEN]; |
| 44 | bool in_optimize; |
| 45 | bool archive_write_open; |
| 46 | bool dirty; /* Flag for if a flush should occur */ |
| 47 | bool crashed; /* Meta file is crashed */ |
| 48 | Archive_share(); |
| 49 | ~Archive_share() |
| 50 | { |
| 51 | DBUG_PRINT("ha_archive" , ("~Archive_share: %p" , |
| 52 | this)); |
| 53 | if (archive_write_open) |
| 54 | { |
| 55 | mysql_mutex_lock(&mutex); |
| 56 | (void) close_archive_writer(); |
| 57 | mysql_mutex_unlock(&mutex); |
| 58 | } |
| 59 | thr_lock_delete(&lock); |
| 60 | mysql_mutex_destroy(&mutex); |
| 61 | } |
| 62 | int init_archive_writer(); |
| 63 | void close_archive_writer(); |
| 64 | int write_v1_metafile(); |
| 65 | int read_v1_metafile(); |
| 66 | }; |
| 67 | |
| 68 | /* |
| 69 | Version for file format. |
| 70 | 1 - Initial Version (Never Released) |
| 71 | 2 - Stream Compression, seperate blobs, no packing |
| 72 | 3 - One stream (row and blobs), with packing |
| 73 | */ |
| 74 | #define ARCHIVE_VERSION 3 |
| 75 | |
| 76 | class ha_archive: public handler |
| 77 | { |
| 78 | THR_LOCK_DATA lock; /* MySQL lock */ |
| 79 | Archive_share *share; /* Shared lock info */ |
| 80 | |
| 81 | azio_stream archive; /* Archive file we are working with */ |
| 82 | my_off_t current_position; /* The position of the row we just read */ |
| 83 | uchar byte_buffer[IO_SIZE]; /* Initial buffer for our string */ |
| 84 | String buffer; /* Buffer used for blob storage */ |
| 85 | ha_rows scan_rows; /* Number of rows left in scan */ |
| 86 | bool delayed_insert; /* If the insert is delayed */ |
| 87 | bool bulk_insert; /* If we are performing a bulk insert */ |
| 88 | const uchar *current_key; |
| 89 | uint current_key_len; |
| 90 | uint current_k_offset; |
| 91 | archive_record_buffer *record_buffer; |
| 92 | bool archive_reader_open; |
| 93 | |
| 94 | archive_record_buffer *create_record_buffer(unsigned int length); |
| 95 | void destroy_record_buffer(archive_record_buffer *r); |
| 96 | int frm_copy(azio_stream *src, azio_stream *dst); |
| 97 | int frm_compare(azio_stream *src); |
| 98 | unsigned int pack_row_v1(uchar *record); |
| 99 | |
| 100 | public: |
| 101 | ha_archive(handlerton *hton, TABLE_SHARE *table_arg); |
| 102 | ~ha_archive() |
| 103 | { |
| 104 | } |
| 105 | const char *index_type(uint inx) { return "NONE" ; } |
| 106 | ulonglong table_flags() const |
| 107 | { |
| 108 | return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_CAN_BIT_FIELD | |
| 109 | HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | |
| 110 | HA_STATS_RECORDS_IS_EXACT | HA_CAN_EXPORT | |
| 111 | HA_HAS_RECORDS | HA_CAN_REPAIR | |
| 112 | HA_FILE_BASED | HA_CAN_INSERT_DELAYED | HA_CAN_GEOMETRY); |
| 113 | } |
| 114 | ulong index_flags(uint idx, uint part, bool all_parts) const |
| 115 | { |
| 116 | return HA_ONLY_WHOLE_INDEX; |
| 117 | } |
| 118 | virtual void get_auto_increment(ulonglong offset, ulonglong increment, |
| 119 | ulonglong nb_desired_values, |
| 120 | ulonglong *first_value, |
| 121 | ulonglong *nb_reserved_values); |
| 122 | uint max_supported_keys() const { return 1; } |
| 123 | uint max_supported_key_length() const { return sizeof(ulonglong); } |
| 124 | uint max_supported_key_part_length() const { return sizeof(ulonglong); } |
| 125 | ha_rows records() { return share->rows_recorded; } |
| 126 | int index_init(uint keynr, bool sorted); |
| 127 | virtual int index_read(uchar * buf, const uchar * key, |
| 128 | uint key_len, enum ha_rkey_function find_flag); |
| 129 | virtual int index_read_idx(uchar * buf, uint index, const uchar * key, |
| 130 | uint key_len, enum ha_rkey_function find_flag); |
| 131 | int index_next(uchar * buf); |
| 132 | int open(const char *name, int mode, uint test_if_locked); |
| 133 | int close(void); |
| 134 | int write_row(uchar * buf); |
| 135 | int real_write_row(uchar *buf, azio_stream *writer); |
| 136 | int truncate(); |
| 137 | int rnd_init(bool scan=1); |
| 138 | int rnd_next(uchar *buf); |
| 139 | int rnd_pos(uchar * buf, uchar *pos); |
| 140 | int get_row(azio_stream *file_to_read, uchar *buf); |
| 141 | int get_row_version2(azio_stream *file_to_read, uchar *buf); |
| 142 | int get_row_version3(azio_stream *file_to_read, uchar *buf); |
| 143 | Archive_share *get_share(const char *table_name, int *rc); |
| 144 | int init_archive_reader(); |
| 145 | // Always try auto_repair in case of HA_ERR_CRASHED_ON_USAGE |
| 146 | bool auto_repair(int error) const |
| 147 | { return error == HA_ERR_CRASHED_ON_USAGE; } |
| 148 | int (azio_stream *file_to_read); |
| 149 | void position(const uchar *record); |
| 150 | int info(uint); |
| 151 | void update_create_info(HA_CREATE_INFO *create_info); |
| 152 | int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); |
| 153 | int optimize(THD* thd, HA_CHECK_OPT* check_opt); |
| 154 | int repair(THD* thd, HA_CHECK_OPT* check_opt); |
| 155 | int check_for_upgrade(HA_CHECK_OPT *check_opt); |
| 156 | void start_bulk_insert(ha_rows rows, uint flags); |
| 157 | int end_bulk_insert(); |
| 158 | enum row_type get_row_type() const |
| 159 | { |
| 160 | return ROW_TYPE_COMPRESSED; |
| 161 | } |
| 162 | THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, |
| 163 | enum thr_lock_type lock_type); |
| 164 | bool is_crashed() const; |
| 165 | int check(THD* thd, HA_CHECK_OPT* check_opt); |
| 166 | bool check_and_repair(THD *thd); |
| 167 | uint32 max_row_length(const uchar *buf); |
| 168 | bool fix_rec_buff(unsigned int length); |
| 169 | int unpack_row(azio_stream *file_to_read, uchar *record); |
| 170 | unsigned int pack_row(uchar *record, azio_stream *writer); |
| 171 | bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes); |
| 172 | }; |
| 173 | |
| 174 | |