1 /* Copyright (c) 2003, 2021, Oracle and/or its affiliates.
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, version 2.0,
5   as published by the Free Software Foundation.
6 
7   This program is also distributed with certain software (including
8   but not limited to OpenSSL) that is licensed under separate terms,
9   as designated in a particular file or component or in included license
10   documentation.  The authors of MySQL hereby grant you an additional
11   permission to link the program and your derivative works with the
12   separately licensed software that they have included with MySQL.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License, version 2.0, for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #include <zlib.h>
24 #include "azlib.h"
25 
26 /*
27   Please read ha_archive.cc first. If you are looking for more general
28   answers on how storage engines work, look at ha_example.cc and
29   ha_example.h.
30 */
31 
32 typedef struct st_archive_record_buffer {
33   uchar *buffer;
34   uint32 length;
35 } archive_record_buffer;
36 
37 
38 class Archive_share : public Handler_share
39 {
40 public:
41   mysql_mutex_t mutex;
42   THR_LOCK lock;
43   azio_stream archive_write;     /* Archive file we are working with */
44   ha_rows rows_recorded;    /* Number of rows in tables */
45   char table_name[FN_REFLEN];
46   char data_file_name[FN_REFLEN];
47   bool in_optimize;
48   bool archive_write_open;
49   bool dirty;               /* Flag for if a flush should occur */
50   bool crashed;             /* Meta file is crashed */
51   Archive_share();
~Archive_share()52   ~Archive_share()
53   {
54     DBUG_PRINT("ha_archive", ("~Archive_share: %p",
55                               this));
56     if (archive_write_open)
57     {
58       mysql_mutex_lock(&mutex);
59       (void) close_archive_writer();
60       mysql_mutex_unlock(&mutex);
61     }
62     thr_lock_delete(&lock);
63     mysql_mutex_destroy(&mutex);
64   }
65   int init_archive_writer();
66   void close_archive_writer();
67   int write_v1_metafile();
68   int read_v1_metafile();
69 };
70 
71 /*
72   Version for file format.
73   1 - Initial Version (Never Released)
74   2 - Stream Compression, seperate blobs, no packing
75   3 - One steam (row and blobs), with packing
76 */
77 #define ARCHIVE_VERSION 3
78 
79 class ha_archive: public handler
80 {
81   THR_LOCK_DATA lock;        /* MySQL lock */
82   Archive_share *share;      /* Shared lock info */
83 
84   azio_stream archive;            /* Archive file we are working with */
85   my_off_t current_position;  /* The position of the row we just read */
86   uchar byte_buffer[IO_SIZE]; /* Initial buffer for our string */
87   String buffer;             /* Buffer used for blob storage */
88   ha_rows scan_rows;         /* Number of rows left in scan */
89   bool bulk_insert;          /* If we are performing a bulk insert */
90   const uchar *current_key;
91   uint current_key_len;
92   uint current_k_offset;
93   archive_record_buffer *record_buffer;
94   bool archive_reader_open;
95 
96   archive_record_buffer *create_record_buffer(unsigned int length);
97   void destroy_record_buffer(archive_record_buffer *r);
98   int frm_copy(azio_stream *src, azio_stream *dst);
99   void frm_load(const char *name, azio_stream *dst);
100   unsigned int pack_row_v1(uchar *record);
101 
102 public:
103   ha_archive(handlerton *hton, TABLE_SHARE *table_arg);
~ha_archive()104   ~ha_archive()
105   {
106   }
table_type()107   const char *table_type() const { return "ARCHIVE"; }
index_type(uint inx)108   const char *index_type(uint inx) { return "NONE"; }
109   const char **bas_ext() const;
table_flags()110   ulonglong table_flags() const
111   {
112     return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_CAN_BIT_FIELD |
113             HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
114             HA_STATS_RECORDS_IS_EXACT |
115             HA_HAS_RECORDS | HA_CAN_REPAIR |
116             HA_FILE_BASED | HA_CAN_GEOMETRY);
117   }
index_flags(uint idx,uint part,bool all_parts)118   ulong index_flags(uint idx, uint part, bool all_parts) const
119   {
120     return HA_ONLY_WHOLE_INDEX;
121   }
122   virtual void get_auto_increment(ulonglong offset, ulonglong increment,
123                                   ulonglong nb_desired_values,
124                                   ulonglong *first_value,
125                                   ulonglong *nb_reserved_values);
max_supported_keys()126   uint max_supported_keys()          const { return 1; }
max_supported_key_length()127   uint max_supported_key_length()    const { return sizeof(ulonglong); }
max_supported_key_part_length(HA_CREATE_INFO * create_info MY_ATTRIBUTE ((unused)))128   uint max_supported_key_part_length(HA_CREATE_INFO
129                     *create_info MY_ATTRIBUTE((unused))) const
130   { return sizeof(ulonglong); }
records(ha_rows * num_rows)131   virtual int records(ha_rows *num_rows)
132   {
133     *num_rows= share->rows_recorded;
134     return 0;
135   }
136   int index_init(uint keynr, bool sorted);
137   virtual int index_read(uchar * buf, const uchar * key,
138 			 uint key_len, enum ha_rkey_function find_flag);
139   virtual int index_read_idx(uchar * buf, uint index, const uchar * key,
140 			     uint key_len, enum ha_rkey_function find_flag);
141   int index_next(uchar * buf);
142   int open(const char *name, int mode, uint test_if_locked);
143   int close(void);
144   int write_row(uchar * buf);
145   int real_write_row(uchar *buf, azio_stream *writer);
146   int truncate();
147   int rnd_init(bool scan=1);
148   int rnd_next(uchar *buf);
149   int rnd_pos(uchar * buf, uchar *pos);
150   int get_row(azio_stream *file_to_read, uchar *buf);
151   int get_row_version2(azio_stream *file_to_read, uchar *buf);
152   int get_row_version3(azio_stream *file_to_read, uchar *buf);
153   Archive_share *get_share(const char *table_name, int *rc);
154   int init_archive_reader();
auto_repair()155   bool auto_repair() const { return 1; } // For the moment we just do this
156   int read_data_header(azio_stream *file_to_read);
157   void position(const uchar *record);
158   int info(uint);
159   int extra(enum ha_extra_function operation);
160   void update_create_info(HA_CREATE_INFO *create_info);
161   int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
162   int optimize(THD* thd, HA_CHECK_OPT* check_opt);
163   int repair(THD* thd, HA_CHECK_OPT* check_opt);
164   void start_bulk_insert(ha_rows rows);
165   int end_bulk_insert();
get_row_type()166   enum row_type get_row_type() const
167   {
168     return ROW_TYPE_COMPRESSED;
169   }
170   THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
171                              enum thr_lock_type lock_type);
172   bool is_crashed() const;
173   int check_for_upgrade(HA_CHECK_OPT *check_opt);
174   int check(THD* thd, HA_CHECK_OPT* check_opt);
175   bool check_and_repair(THD *thd);
176   uint32 max_row_length(const uchar *buf);
177   bool fix_rec_buff(unsigned int length);
178   int unpack_row(azio_stream *file_to_read, uchar *record);
179   unsigned int pack_row(uchar *record, azio_stream *writer);
180   bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes);
181 };
182 
183