~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/archive/ha_archive.cc

  • Committer: Brian Aker
  • Date: 2009-08-21 18:46:31 UTC
  • mto: This revision was merged to the branch mainline in revision 1123.
  • Revision ID: brian@gaz-20090821184631-e11gja79070fvhk4
Cleanup around page checksum removal

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
  along with this program; if not, write to the Free Software
14
14
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
 
#ifdef USE_PRAGMA_IMPLEMENTATION
17
 
#pragma implementation        // gcc: Class implementation
18
 
#endif
19
16
 
20
 
#include <drizzled/common_includes.h>
21
 
#include <storage/myisam/myisam.h>
 
17
#include "drizzled/server_includes.h"
 
18
#include "drizzled/field.h"
 
19
#include "drizzled/field/blob.h"
 
20
#include "drizzled/field/timestamp.h"
 
21
#include "plugin/myisam/myisam.h"
 
22
#include "drizzled/table.h"
 
23
#include "drizzled/session.h"
 
24
#include <mysys/my_dir.h>
22
25
 
23
26
#include "ha_archive.h"
24
27
 
 
28
#include <stdio.h>
 
29
#include <string>
 
30
#include <map>
 
31
 
 
32
using namespace std;
 
33
 
 
34
static const string engine_name("ARCHIVE");
 
35
 
25
36
/*
26
 
  First, if you want to understand storage engines you should look at 
27
 
  ha_example.cc and ha_example.h. 
 
37
  First, if you want to understand storage engines you should look at
 
38
  ha_example.cc and ha_example.h.
28
39
 
29
40
  This example was written as a test case for a customer who needed
30
41
  a storage engine without indexes that could compress data very well.
31
42
  So, welcome to a completely compressed storage engine. This storage
32
 
  engine only does inserts. No replace, deletes, or updates. All reads are 
 
43
  engine only does inserts. No replace, deletes, or updates. All reads are
33
44
  complete table scans. Compression is done through a combination of packing
34
45
  and making use of the zlib library
35
 
  
 
46
 
36
47
  We keep a file pointer open for each instance of ha_archive for each read
37
48
  but for writes we keep one open file handle just for that. We flush it
38
49
  only if we have a read occur. azip handles compressing lots of records
42
53
  the same time since we would want to flush).
43
54
 
44
55
  A "meta" file is kept alongside the data file. This file serves two purpose.
45
 
  The first purpose is to track the number of rows in the table. The second 
46
 
  purpose is to determine if the table was closed properly or not. When the 
47
 
  meta file is first opened it is marked as dirty. It is opened when the table 
48
 
  itself is opened for writing. When the table is closed the new count for rows 
49
 
  is written to the meta file and the file is marked as clean. If the meta file 
50
 
  is opened and it is marked as dirty, it is assumed that a crash occured. At 
 
56
  The first purpose is to track the number of rows in the table. The second
 
57
  purpose is to determine if the table was closed properly or not. When the
 
58
  meta file is first opened it is marked as dirty. It is opened when the table
 
59
  itself is opened for writing. When the table is closed the new count for rows
 
60
  is written to the meta file and the file is marked as clean. If the meta file
 
61
  is opened and it is marked as dirty, it is assumed that a crash occured. At
51
62
  this point an error occurs and the user is told to rebuild the file.
52
63
  A rebuild scans the rows and rewrites the meta file. If corruption is found
53
64
  in the data file then the meta file is not repaired.
54
65
 
55
66
  At some point a recovery method for such a drastic case needs to be divised.
56
67
 
57
 
  Locks are row level, and you will get a consistant read. 
 
68
  Locks are row level, and you will get a consistant read.
58
69
 
59
70
  For performance as far as table scans go it is quite fast. I don't have
60
71
  good numbers but locally it has out performed both Innodb and MyISAM. For
61
72
  Innodb the question will be if the table can be fit into the buffer
62
73
  pool. For MyISAM its a question of how much the file system caches the
63
74
  MyISAM file. With enough free memory MyISAM is faster. Its only when the OS
64
 
  doesn't have enough memory to cache entire table that archive turns out 
65
 
  to be any faster. 
 
75
  doesn't have enough memory to cache entire table that archive turns out
 
76
  to be any faster.
66
77
 
67
78
  Examples between MyISAM (packed) and Archive.
68
79
 
91
102
*/
92
103
 
93
104
/* Variables for archive share methods */
94
 
pthread_mutex_t archive_mutex;
95
 
static HASH archive_open_tables;
 
105
pthread_mutex_t archive_mutex= PTHREAD_MUTEX_INITIALIZER;
 
106
 
 
107
std::map<const char *, ArchiveShare *> archive_open_tables;
 
108
 
96
109
static unsigned int global_version;
97
110
 
98
111
/* The file extension */
99
112
#define ARZ ".ARZ"               // The data file
100
113
#define ARN ".ARN"               // Files used during an optimize call
101
 
#define ARM ".ARM"               // Meta file (deprecated)
102
 
 
103
 
/*
104
 
  unsigned char + unsigned char
105
 
*/
106
 
#define DATA_BUFFER_SIZE 2       // Size of the data used in the data file
107
 
#define ARCHIVE_CHECK_HEADER 254 // The number we use to determine corruption
108
 
 
109
 
/* Static declarations for handerton */
110
 
static handler *archive_create_handler(handlerton *hton, 
111
 
                                       TABLE_SHARE *table, 
112
 
                                       MEM_ROOT *mem_root);
113
 
int archive_discover(handlerton *hton, THD* thd, const char *db, 
114
 
                     const char *name,
115
 
                     unsigned char **frmblob, 
116
 
                     size_t *frmlen);
 
114
 
 
115
 
117
116
 
118
117
static bool archive_use_aio= false;
119
118
 
127
126
*/
128
127
#define ARCHIVE_ROW_HEADER_SIZE 4
129
128
 
130
 
static handler *archive_create_handler(handlerton *hton,
131
 
                                       TABLE_SHARE *table, 
132
 
                                       MEM_ROOT *mem_root)
133
 
{
134
 
  return new (mem_root) ha_archive(hton, table);
135
 
}
136
 
 
137
129
/*
138
 
  Used for hash table that tracks open tables.
 
130
  We just implement one additional file extension.
139
131
*/
140
 
static unsigned char* archive_get_key(ARCHIVE_SHARE *share, size_t *length,
141
 
                             bool not_used __attribute__((unused)))
142
 
{
143
 
  *length=share->table_name_length;
144
 
  return (unsigned char*) share->table_name;
145
 
}
146
 
 
 
132
static const char *ha_archive_exts[] = {
 
133
  ARZ,
 
134
  NULL
 
135
};
 
136
 
 
137
class ArchiveTableNameIterator: public TableNameIteratorImplementation
 
138
{
 
139
private:
 
140
  MY_DIR *dirp;
 
141
  uint32_t current_entry;
 
142
 
 
143
public:
 
144
  ArchiveTableNameIterator(const std::string &database)
 
145
    : TableNameIteratorImplementation(database), dirp(NULL), current_entry(-1)
 
146
    {};
 
147
 
 
148
  ~ArchiveTableNameIterator();
 
149
 
 
150
  int next(std::string *name);
 
151
 
 
152
};
 
153
 
 
154
ArchiveTableNameIterator::~ArchiveTableNameIterator()
 
155
{
 
156
  if (dirp)
 
157
    my_dirend(dirp);
 
158
}
 
159
 
 
160
int ArchiveTableNameIterator::next(string *name)
 
161
{
 
162
  char uname[NAME_LEN + 1];
 
163
  FILEINFO *file;
 
164
  char *ext;
 
165
  uint32_t file_name_len;
 
166
  const char *wild= NULL;
 
167
 
 
168
  if (dirp == NULL)
 
169
  {
 
170
    bool dir= false;
 
171
    char path[FN_REFLEN];
 
172
 
 
173
    build_table_filename(path, sizeof(path), db.c_str(), "", false);
 
174
    dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0));
 
175
    if (dirp == NULL)
 
176
    {
 
177
      if (my_errno == ENOENT)
 
178
        my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db.c_str());
 
179
      else
 
180
        my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
 
181
      return(ENOENT);
 
182
    }
 
183
    current_entry= -1;
 
184
  }
 
185
 
 
186
  while(true)
 
187
  {
 
188
    current_entry++;
 
189
 
 
190
    if (current_entry == dirp->number_off_files)
 
191
    {
 
192
      my_dirend(dirp);
 
193
      dirp= NULL;
 
194
      return -1;
 
195
    }
 
196
 
 
197
    file= dirp->dir_entry + current_entry;
 
198
 
 
199
    if (my_strcasecmp(system_charset_info, ext=strchr(file->name,'.'), ARZ) ||
 
200
        is_prefix(file->name, TMP_FILE_PREFIX))
 
201
      continue;
 
202
    *ext=0;
 
203
 
 
204
    file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
 
205
 
 
206
    uname[file_name_len]= '\0';
 
207
 
 
208
    if (wild && wild_compare(uname, wild, 0))
 
209
      continue;
 
210
    if (name)
 
211
      name->assign(uname);
 
212
 
 
213
    return 0;
 
214
  }
 
215
}
 
216
 
 
217
class ArchiveEngine : public StorageEngine
 
218
{
 
219
public:
 
220
  ArchiveEngine(const string &name_arg) : StorageEngine(name_arg,
 
221
                                      HTON_FILE_BASED
 
222
                                    | HTON_HAS_DATA_DICTIONARY
 
223
                                    | HTON_DATA_DIR) {}
 
224
 
 
225
  virtual handler *create(TableShare *table,
 
226
                          MEM_ROOT *mem_root)
 
227
  {
 
228
    return new (mem_root) ha_archive(this, table);
 
229
  }
 
230
 
 
231
  const char **bas_ext() const {
 
232
    return ha_archive_exts;
 
233
  }
 
234
 
 
235
  int createTableImplementation(Session *session, const char *table_name,
 
236
                                Table *table_arg, HA_CREATE_INFO *create_info,
 
237
                                drizzled::message::Table* proto);
 
238
 
 
239
  int getTableProtoImplementation(const char* path,
 
240
                                  drizzled::message::Table *table_proto);
 
241
 
 
242
  TableNameIteratorImplementation* tableNameIterator(const std::string &database)
 
243
  {
 
244
    return new ArchiveTableNameIterator(database);
 
245
  }
 
246
};
 
247
 
 
248
int ArchiveEngine::getTableProtoImplementation(const char* path,
 
249
                                         drizzled::message::Table *table_proto)
 
250
{
 
251
  struct stat stat_info;
 
252
  int error= 0;
 
253
  string proto_path;
 
254
 
 
255
  proto_path.reserve(FN_REFLEN);
 
256
  proto_path.assign(path);
 
257
 
 
258
  proto_path.append(ARZ);
 
259
 
 
260
  if (stat(proto_path.c_str(),&stat_info))
 
261
    return errno;
 
262
 
 
263
  if (table_proto)
 
264
  {
 
265
    azio_stream proto_stream;
 
266
    char* proto_string;
 
267
    if(azopen(&proto_stream, proto_path.c_str(), O_RDONLY, AZ_METHOD_BLOCK) == 0)
 
268
      return HA_ERR_CRASHED_ON_USAGE;
 
269
 
 
270
    proto_string= (char*)malloc(sizeof(char) * proto_stream.frm_length);
 
271
    if (proto_string == NULL)
 
272
    {
 
273
      azclose(&proto_stream);
 
274
      return ENOMEM;
 
275
    }
 
276
 
 
277
    azread_frm(&proto_stream, proto_string);
 
278
 
 
279
    if(table_proto->ParseFromArray(proto_string, proto_stream.frm_length) == false)
 
280
      error= HA_ERR_CRASHED_ON_USAGE;
 
281
 
 
282
    azclose(&proto_stream);
 
283
    free(proto_string);
 
284
  }
 
285
 
 
286
  return EEXIST;
 
287
}
 
288
 
 
289
static ArchiveEngine *archive_engine= NULL;
147
290
 
148
291
/*
149
292
  Initialize the archive handler.
157
300
    true        Error
158
301
*/
159
302
 
160
 
int archive_db_init(void *p)
 
303
static int archive_db_init(drizzled::plugin::Registry &registry)
161
304
{
162
 
  handlerton *archive_hton;
163
305
 
164
 
  archive_hton= (handlerton *)p;
165
 
  archive_hton->state= SHOW_OPTION_YES;
166
 
  archive_hton->create= archive_create_handler;
167
 
  archive_hton->flags= HTON_NO_FLAGS;
168
 
  archive_hton->discover= archive_discover;
 
306
  pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST);
 
307
  archive_engine= new ArchiveEngine(engine_name);
 
308
  registry.add(archive_engine);
169
309
 
170
310
  /* When the engine starts up set the first version */
171
311
  global_version= 1;
172
312
 
173
 
  if (pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST))
174
 
    goto error;
175
 
  if (hash_init(&archive_open_tables, system_charset_info, 32, 0, 0,
176
 
                (hash_get_key) archive_get_key, 0, 0))
177
 
  {
178
 
    pthread_mutex_destroy(&archive_mutex);
179
 
  }
180
 
  else
181
 
  {
182
 
    return(false);
183
 
  }
184
 
error:
185
 
  return(true);
 
313
  return false;
186
314
}
187
315
 
188
316
/*
196
324
    false       OK
197
325
*/
198
326
 
199
 
int archive_db_done(void *p __attribute__((unused)))
 
327
static int archive_db_done(drizzled::plugin::Registry &registry)
200
328
{
201
 
  hash_free(&archive_open_tables);
 
329
  registry.remove(archive_engine);
 
330
  delete archive_engine;
 
331
 
202
332
  pthread_mutex_destroy(&archive_mutex);
203
333
 
204
334
  return 0;
205
335
}
206
336
 
207
337
 
208
 
ha_archive::ha_archive(handlerton *hton, TABLE_SHARE *table_arg)
209
 
  :handler(hton, table_arg), delayed_insert(0), bulk_insert(0)
 
338
ha_archive::ha_archive(StorageEngine *engine_arg, TableShare *table_arg)
 
339
  :handler(engine_arg, table_arg), delayed_insert(0), bulk_insert(0)
210
340
{
211
341
  /* Set our original buffer from pre-allocated memory */
212
342
  buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info);
216
346
  archive_reader_open= false;
217
347
}
218
348
 
219
 
int archive_discover(handlerton *hton __attribute__((unused)),
220
 
                     THD* thd __attribute__((unused)),
221
 
                     const char *db,
222
 
                     const char *name,
223
 
                     unsigned char **frmblob,
224
 
                     size_t *frmlen)
225
 
{
226
 
  azio_stream frm_stream;
227
 
  char az_file[FN_REFLEN];
228
 
  char *frm_ptr;
229
 
  struct stat file_stat; 
230
 
 
231
 
  fn_format(az_file, name, db, ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
232
 
 
233
 
  if (stat(az_file, &file_stat))
234
 
    goto err;
235
 
 
236
 
  if (!(azopen(&frm_stream, az_file, O_RDONLY|O_BINARY, AZ_METHOD_BLOCK)))
237
 
  {
238
 
    if (errno == EROFS || errno == EACCES)
239
 
      return(my_errno= errno);
240
 
    return(HA_ERR_CRASHED_ON_USAGE);
241
 
  }
242
 
 
243
 
  if (frm_stream.frm_length == 0)
244
 
    goto err;
245
 
 
246
 
  frm_ptr= (char *)my_malloc(sizeof(char) * frm_stream.frm_length, MYF(0));
247
 
  azread_frm(&frm_stream, frm_ptr);
248
 
  azclose(&frm_stream);
249
 
 
250
 
  *frmlen= frm_stream.frm_length;
251
 
  *frmblob= (unsigned char*) frm_ptr;
252
 
 
253
 
  return(0);
254
 
err:
255
 
  my_errno= 0;
256
 
  return(1);
257
 
}
258
 
 
259
349
/*
260
350
  This method reads the header of a datafile and returns whether or not it was successful.
261
351
*/
270
360
  return(1);
271
361
}
272
362
 
 
363
ArchiveShare::ArchiveShare():
 
364
  use_count(0), archive_write_open(false), dirty(false), crashed(false),
 
365
  mean_rec_length(0), version(0), rows_recorded(0), version_rows(0)
 
366
{
 
367
  assert(1);
 
368
}
 
369
 
 
370
ArchiveShare::ArchiveShare(const char *name):
 
371
  use_count(0), archive_write_open(false), dirty(false), crashed(false),
 
372
  mean_rec_length(0), version(0), rows_recorded(0), version_rows(0)
 
373
{
 
374
  memset(&archive_write, 0, sizeof(azio_stream));     /* Archive file we are working with */
 
375
  table_name.append(name);
 
376
  fn_format(data_file_name, table_name.c_str(), "",
 
377
            ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
378
  /*
 
379
    We will use this lock for rows.
 
380
  */
 
381
  pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST);
 
382
}
 
383
 
 
384
ArchiveShare::~ArchiveShare()
 
385
{
 
386
  thr_lock_delete(&lock);
 
387
  pthread_mutex_destroy(&mutex);
 
388
  /*
 
389
    We need to make sure we don't reset the crashed state.
 
390
    If we open a crashed file, wee need to close it as crashed unless
 
391
    it has been repaired.
 
392
    Since we will close the data down after this, we go on and count
 
393
    the flush on close;
 
394
  */
 
395
  if (archive_write_open == true)
 
396
    (void)azclose(&archive_write);
 
397
}
 
398
 
 
399
bool ArchiveShare::prime(uint64_t *auto_increment)
 
400
{
 
401
  azio_stream archive_tmp;
 
402
 
 
403
  /*
 
404
    We read the meta file, but do not mark it dirty. Since we are not
 
405
    doing a write we won't mark it dirty (and we won't open it for
 
406
    anything but reading... open it for write and we will generate null
 
407
    compression writes).
 
408
  */
 
409
  if (!(azopen(&archive_tmp, data_file_name, O_RDONLY,
 
410
               AZ_METHOD_BLOCK)))
 
411
    return false;
 
412
 
 
413
  *auto_increment= archive_tmp.auto_increment + 1;
 
414
  rows_recorded= (ha_rows)archive_tmp.rows;
 
415
  crashed= archive_tmp.dirty;
 
416
  if (version < global_version)
 
417
  {
 
418
    version_rows= rows_recorded;
 
419
    version= global_version;
 
420
  }
 
421
  azclose(&archive_tmp);
 
422
 
 
423
  return true;
 
424
}
 
425
 
273
426
 
274
427
/*
275
 
  We create the shared memory space that we will use for the open table. 
 
428
  We create the shared memory space that we will use for the open table.
276
429
  No matter what we try to get or create a share. This is so that a repair
277
 
  table operation can occur. 
 
430
  table operation can occur.
278
431
 
279
432
  See ha_example.cc for a longer description.
280
433
*/
281
 
ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, int *rc)
 
434
ArchiveShare *ha_archive::get_share(const char *table_name, int *rc)
282
435
{
283
436
  uint32_t length;
 
437
  map<const char *, ArchiveShare *> ::iterator find_iter;
284
438
 
285
439
  pthread_mutex_lock(&archive_mutex);
286
440
  length=(uint) strlen(table_name);
287
441
 
288
 
  if (!(share=(ARCHIVE_SHARE*) hash_search(&archive_open_tables,
289
 
                                           (unsigned char*) table_name,
290
 
                                           length)))
 
442
  find_iter= archive_open_tables.find(table_name);
 
443
 
 
444
  if (find_iter != archive_open_tables.end())
 
445
    share= (*find_iter).second;
 
446
  else
 
447
    share= NULL;
 
448
 
 
449
  if (!share)
291
450
  {
292
 
    char *tmp_name;
293
 
    azio_stream archive_tmp;
 
451
    share= new ArchiveShare(table_name);
294
452
 
295
 
    if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
296
 
                          &share, sizeof(*share),
297
 
                          &tmp_name, length+1,
298
 
                          NULL)) 
 
453
    if (share == NULL)
299
454
    {
300
455
      pthread_mutex_unlock(&archive_mutex);
301
456
      *rc= HA_ERR_OUT_OF_MEM;
302
457
      return(NULL);
303
458
    }
304
459
 
305
 
    share->use_count= 0;
306
 
    share->table_name_length= length;
307
 
    share->table_name= tmp_name;
308
 
    share->crashed= false;
309
 
    share->archive_write_open= false;
310
 
    fn_format(share->data_file_name, table_name, "",
311
 
              ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
312
 
    my_stpcpy(share->table_name, table_name);
313
 
    /*
314
 
      We will use this lock for rows.
315
 
    */
316
 
    pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
317
 
    
318
 
    /*
319
 
      We read the meta file, but do not mark it dirty. Since we are not
320
 
      doing a write we won't mark it dirty (and we won't open it for
321
 
      anything but reading... open it for write and we will generate null
322
 
      compression writes).
323
 
    */
324
 
    if (!(azopen(&archive_tmp, share->data_file_name, O_RDONLY|O_BINARY,
325
 
                 AZ_METHOD_BLOCK)))
 
460
    if (share->prime(&stats.auto_increment_value) == false)
326
461
    {
327
 
      pthread_mutex_destroy(&share->mutex);
328
 
      free(share);
329
462
      pthread_mutex_unlock(&archive_mutex);
330
463
      *rc= HA_ERR_CRASHED_ON_REPAIR;
331
 
      return(NULL);
332
 
    }
333
 
    stats.auto_increment_value= archive_tmp.auto_increment + 1;
334
 
    share->rows_recorded= (ha_rows)archive_tmp.rows;
335
 
    share->crashed= archive_tmp.dirty;
336
 
    if (share->version < global_version)
337
 
    {
338
 
      share->version_rows= share->rows_recorded;
339
 
      share->version= global_version;
340
 
    }
341
 
    azclose(&archive_tmp);
342
 
 
343
 
    my_hash_insert(&archive_open_tables, (unsigned char*) share);
 
464
      delete share;
 
465
 
 
466
      return NULL;
 
467
    }
 
468
 
 
469
    archive_open_tables[share->table_name.c_str()]= share; 
344
470
    thr_lock_init(&share->lock);
345
471
  }
346
472
  share->use_count++;
352
478
}
353
479
 
354
480
 
355
 
/* 
 
481
/*
356
482
  Free the share.
357
483
  See ha_example.cc for a description.
358
484
*/
359
485
int ha_archive::free_share()
360
486
{
361
 
  int rc= 0;
362
 
 
363
487
  pthread_mutex_lock(&archive_mutex);
364
488
  if (!--share->use_count)
365
489
  {
366
 
    hash_delete(&archive_open_tables, (unsigned char*) share);
367
 
    thr_lock_delete(&share->lock);
368
 
    pthread_mutex_destroy(&share->mutex);
369
 
    /* 
370
 
      We need to make sure we don't reset the crashed state.
371
 
      If we open a crashed file, wee need to close it as crashed unless
372
 
      it has been repaired.
373
 
      Since we will close the data down after this, we go on and count
374
 
      the flush on close;
375
 
    */
376
 
    if (share->archive_write_open == true)
377
 
    {
378
 
      if (azclose(&(share->archive_write)))
379
 
        rc= 1;
380
 
    }
381
 
    free((unsigned char*) share);
 
490
    archive_open_tables.erase(share->table_name.c_str());
 
491
    delete share;
382
492
  }
383
493
  pthread_mutex_unlock(&archive_mutex);
384
494
 
385
 
  return(rc);
 
495
  return 0;
386
496
}
387
497
 
388
498
int ha_archive::init_archive_writer()
389
499
{
390
 
  /* 
 
500
  /*
391
501
    It is expensive to open and close the data files and since you can't have
392
502
    a gzip file that can be both read and written we keep a writer open
393
503
    that is shared amoung all open tables.
394
504
  */
395
 
  if (!(azopen(&(share->archive_write), share->data_file_name, 
396
 
               O_RDWR|O_BINARY, AZ_METHOD_BLOCK)))
 
505
  if (!(azopen(&(share->archive_write), share->data_file_name,
 
506
               O_RDWR, AZ_METHOD_BLOCK)))
397
507
  {
398
508
    share->crashed= true;
399
509
    return(1);
404
514
}
405
515
 
406
516
 
407
 
/* 
 
517
/*
408
518
  No locks are required because it is associated with just one handler instance
409
519
*/
410
520
int ha_archive::init_archive_reader()
411
521
{
412
 
  /* 
 
522
  /*
413
523
    It is expensive to open and close the data files and since you can't have
414
524
    a gzip file that can be both read and written we keep a writer open
415
525
    that is shared amoung all open tables.
429
539
    default:
430
540
      method= AZ_METHOD_BLOCK;
431
541
    }
432
 
    if (!(azopen(&archive, share->data_file_name, O_RDONLY|O_BINARY, 
 
542
    if (!(azopen(&archive, share->data_file_name, O_RDONLY,
433
543
                 method)))
434
544
    {
435
545
      share->crashed= true;
441
551
  return(0);
442
552
}
443
553
 
444
 
 
445
554
/*
446
 
  We just implement one additional file extension.
447
 
*/
448
 
static const char *ha_archive_exts[] = {
449
 
  ARZ,
450
 
  NULL
451
 
};
452
 
 
453
 
const char **ha_archive::bas_ext() const
454
 
{
455
 
  return ha_archive_exts;
456
 
}
457
 
 
458
 
 
459
 
/* 
460
555
  When opening a file we:
461
556
  Create/get our shared structure.
462
557
  Init out lock.
463
558
  We open the file we will read from.
464
559
*/
465
 
int ha_archive::open(const char *name,
466
 
                     int mode __attribute__((unused)),
467
 
                     uint32_t open_options)
 
560
int ha_archive::open(const char *name, int, uint32_t open_options)
468
561
{
469
562
  int rc= 0;
470
563
  share= get_share(name, &rc);
474
567
    /* purecov: begin inspected */
475
568
    free_share();
476
569
    return(rc);
477
 
    /* purecov: end */    
 
570
    /* purecov: end */
478
571
  }
479
572
  else if (rc == HA_ERR_OUT_OF_MEM)
480
573
  {
483
576
 
484
577
  assert(share);
485
578
 
486
 
  record_buffer= create_record_buffer(table->s->reclength + 
 
579
  record_buffer= create_record_buffer(table->s->reclength +
487
580
                                      ARCHIVE_ROW_HEADER_SIZE);
488
581
 
489
582
  if (!record_buffer)
508
601
 
509
602
  SYNOPSIS
510
603
    close();
511
 
  
 
604
 
512
605
  IMPLEMENTATION:
513
606
 
514
607
  We first close this storage engines file handle to the archive and
540
633
 
541
634
 
542
635
/*
543
 
  We create our data file here. The format is pretty simple. 
 
636
  We create our data file here. The format is pretty simple.
544
637
  You can read about the format of the data file above.
545
 
  Unlike other storage engines we do not "pack" our data. Since we 
546
 
  are about to do a general compression, packing would just be a waste of 
547
 
  CPU time. If the table has blobs they are written after the row in the order 
 
638
  Unlike other storage engines we do not "pack" our data. Since we
 
639
  are about to do a general compression, packing would just be a waste of
 
640
  CPU time. If the table has blobs they are written after the row in the order
548
641
  of creation.
549
642
*/
550
643
 
551
 
int ha_archive::create(const char *name, Table *table_arg,
552
 
                       HA_CREATE_INFO *create_info)
 
644
int ArchiveEngine::createTableImplementation(Session *session,
 
645
                                             const char *table_name,
 
646
                                             Table *table_arg,
 
647
                                             HA_CREATE_INFO *create_info,
 
648
                                             drizzled::message::Table *proto)
553
649
{
554
650
  char name_buff[FN_REFLEN];
555
651
  char linkname[FN_REFLEN];
556
 
  int error;
 
652
  int error= 0;
557
653
  azio_stream create_stream;            /* Archive file we are working with */
558
 
  File frm_file;                   /* File handler for readers */
559
 
  struct stat file_stat;
560
 
  unsigned char *frm_ptr;
 
654
  uint64_t auto_increment_value;
 
655
  string serialized_proto;
561
656
 
562
 
  stats.auto_increment_value= create_info->auto_increment_value;
 
657
  auto_increment_value= create_info->auto_increment_value;
563
658
 
564
659
  for (uint32_t key= 0; key < table_arg->sizeKeys(); key++)
565
660
  {
579
674
    }
580
675
  }
581
676
 
582
 
  /* 
 
677
  /*
583
678
    We reuse name_buff since it is available.
584
679
  */
585
680
  if (create_info->data_file_name && create_info->data_file_name[0] != '#')
586
681
  {
587
682
    fn_format(name_buff, create_info->data_file_name, "", ARZ,
588
683
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
589
 
    fn_format(linkname, name, "", ARZ,
 
684
    fn_format(linkname, table_name, "", ARZ,
590
685
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
591
686
  }
592
687
  else
593
688
  {
594
 
    fn_format(name_buff, name, "", ARZ,
 
689
    fn_format(name_buff, table_name, "", ARZ,
595
690
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
596
691
    linkname[0]= 0;
597
692
  }
598
693
 
 
694
  my_errno= 0;
 
695
  if (azopen(&create_stream, name_buff, O_CREAT|O_RDWR,
 
696
             AZ_METHOD_BLOCK) == 0)
 
697
  {
 
698
    error= errno;
 
699
    goto error2;
 
700
  }
 
701
 
 
702
  if (linkname[0])
 
703
    if(symlink(name_buff, linkname) != 0)
 
704
      goto error2;
 
705
 
 
706
  proto->SerializeToString(&serialized_proto);
 
707
 
 
708
  if (azwrite_frm(&create_stream, serialized_proto.c_str(),
 
709
                  serialized_proto.length()))
 
710
    goto error2;
 
711
 
 
712
  if (proto->options().has_comment())
 
713
  {
 
714
    int write_length;
 
715
 
 
716
    write_length= azwrite_comment(&create_stream,
 
717
                                  proto->options().comment().c_str(),
 
718
                                  proto->options().comment().length());
 
719
 
 
720
    if (write_length < 0)
 
721
    {
 
722
      error= errno;
 
723
      goto error2;
 
724
    }
 
725
  }
 
726
 
599
727
  /*
600
 
    There is a chance that the file was "discovered". In this case
601
 
    just use whatever file is there.
 
728
    Yes you need to do this, because the starting value
 
729
    for the autoincrement may not be zero.
602
730
  */
603
 
  if (!stat(name_buff, &file_stat))
 
731
  create_stream.auto_increment= auto_increment_value ?
 
732
    auto_increment_value - 1 : 0;
 
733
 
 
734
  if (azclose(&create_stream))
604
735
  {
605
 
    my_errno= 0;
606
 
    if (!(azopen(&create_stream, name_buff, O_CREAT|O_RDWR|O_BINARY,
607
 
                 AZ_METHOD_BLOCK)))
608
 
    {
609
 
      error= errno;
610
 
      goto error2;
611
 
    }
612
 
 
613
 
    if (linkname[0])
614
 
      my_symlink(name_buff, linkname, MYF(0));
615
 
    fn_format(name_buff, name, "", ".frm",
616
 
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
617
 
 
618
 
    /*
619
 
      Here is where we open up the frm and pass it to archive to store 
620
 
    */
621
 
    if ((frm_file= my_open(name_buff, O_RDONLY, MYF(0))) > 0)
622
 
    {
623
 
      if (fstat(frm_file, &file_stat))
624
 
      {
625
 
        frm_ptr= (unsigned char *)my_malloc(sizeof(unsigned char) * file_stat.st_size, MYF(0));
626
 
        if (frm_ptr)
627
 
        {
628
 
          my_read(frm_file, frm_ptr, file_stat.st_size, MYF(0));
629
 
          azwrite_frm(&create_stream, (char *)frm_ptr, file_stat.st_size);
630
 
          free((unsigned char*)frm_ptr);
631
 
        }
632
 
      }
633
 
      my_close(frm_file, MYF(0));
634
 
    }
635
 
 
636
 
    if (create_info->comment.str)
637
 
      azwrite_comment(&create_stream, create_info->comment.str, 
638
 
                      (unsigned int)create_info->comment.length);
639
 
 
640
 
    /* 
641
 
      Yes you need to do this, because the starting value 
642
 
      for the autoincrement may not be zero.
643
 
    */
644
 
    create_stream.auto_increment= stats.auto_increment_value ?
645
 
                                    stats.auto_increment_value - 1 : 0;
646
 
    if (azclose(&create_stream))
647
 
    {
648
 
      error= errno;
649
 
      goto error2;
650
 
    }
 
736
    error= errno;
 
737
    goto error2;
651
738
  }
652
 
  else
653
 
    my_errno= 0;
654
739
 
655
740
  return(0);
656
741
 
657
742
error2:
658
 
  delete_table(name);
 
743
  deleteTable(session, table_name);
659
744
error:
660
745
  /* Return error number, if we got one */
661
746
  return(error ? error : -1);
666
751
*/
667
752
int ha_archive::real_write_row(unsigned char *buf, azio_stream *writer)
668
753
{
669
 
  my_off_t written;
 
754
  off_t written;
670
755
  unsigned int r_pack_length;
671
756
 
672
757
  /* We pack the row for writing */
685
770
}
686
771
 
687
772
 
688
 
/* 
 
773
/*
689
774
  Calculate max length needed for row. This includes
690
775
  the bytes required for the length in the header.
691
776
*/
692
777
 
693
 
uint32_t ha_archive::max_row_length(const unsigned char *buf __attribute__((unused)))
 
778
uint32_t ha_archive::max_row_length(const unsigned char *)
694
779
{
695
780
  uint32_t length= (uint32_t)(table->getRecordLength() + table->sizeFields()*2);
696
781
  length+= ARCHIVE_ROW_HEADER_SIZE;
728
813
}
729
814
 
730
815
 
731
 
/* 
 
816
/*
732
817
  Look at ha_archive::open() for an explanation of the row format.
733
818
  Here we just write out the row.
734
819
 
735
820
  Wondering about start_bulk_insert()? We don't implement it for
736
821
  archive since it optimizes for lots of writes. The only save
737
 
  for implementing start_bulk_insert() is that we could skip 
 
822
  for implementing start_bulk_insert() is that we could skip
738
823
  setting dirty to true each time.
739
824
*/
740
825
int ha_archive::write_row(unsigned char *buf)
748
833
    return(HA_ERR_CRASHED_ON_USAGE);
749
834
 
750
835
  ha_statistic_increment(&SSV::ha_write_count);
751
 
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
752
 
    table->timestamp_field->set_time();
753
836
  pthread_mutex_lock(&share->mutex);
754
837
 
755
838
  if (share->archive_write_open == false)
767
850
      We don't support decremening auto_increment. They make the performance
768
851
      just cry.
769
852
    */
770
 
    if (temp_auto <= share->archive_write.auto_increment && 
 
853
    if (temp_auto <= share->archive_write.auto_increment &&
771
854
        mkey->flags & HA_NOSAME)
772
855
    {
773
856
      rc= HA_ERR_FOUND_DUPP_KEY;
774
857
      goto error;
775
858
    }
776
 
#ifdef DEAD_CODE
777
 
    /*
778
 
      Bad news, this will cause a search for the unique value which is very 
779
 
      expensive since we will have to do a table scan which will lock up 
780
 
      all other writers during this period. This could perhaps be optimized 
781
 
      in the future.
782
 
    */
783
 
    {
784
 
      /* 
785
 
        First we create a buffer that we can use for reading rows, and can pass
786
 
        to get_row().
787
 
      */
788
 
      if (!(read_buf= (unsigned char*) my_malloc(table->s->reclength, MYF(MY_WME))))
789
 
      {
790
 
        rc= HA_ERR_OUT_OF_MEM;
791
 
        goto error;
792
 
      }
793
 
       /* 
794
 
         All of the buffer must be written out or we won't see all of the
795
 
         data 
796
 
       */
797
 
      azflush(&(share->archive_write), Z_SYNC_FLUSH);
798
 
      /*
799
 
        Set the position of the local read thread to the beginning postion.
800
 
      */
801
 
      if (read_data_header(&archive))
802
 
      {
803
 
        rc= HA_ERR_CRASHED_ON_USAGE;
804
 
        goto error;
805
 
      }
806
 
 
807
 
      Field *mfield= table->next_number_field;
808
 
 
809
 
      while (!(get_row(&archive, read_buf)))
810
 
      {
811
 
        if (!memcmp(read_buf + mfield->offset(record),
812
 
                    table->next_number_field->ptr,
813
 
                    mfield->max_display_length()))
814
 
        {
815
 
          rc= HA_ERR_FOUND_DUPP_KEY;
816
 
          goto error;
817
 
        }
818
 
      }
819
 
    }
820
 
#endif
821
859
    else
822
860
    {
823
861
      if (temp_auto > share->archive_write.auto_increment)
841
879
}
842
880
 
843
881
 
844
 
void ha_archive::get_auto_increment(uint64_t offset __attribute__((unused)),
845
 
                                    uint64_t increment __attribute__((unused)),
846
 
                                    uint64_t nb_desired_values __attribute__((unused)),
847
 
                                    uint64_t *first_value __attribute__((unused)),
848
 
                                    uint64_t *nb_reserved_values __attribute__((unused)))
 
882
void ha_archive::get_auto_increment(uint64_t, uint64_t, uint64_t,
 
883
                                    uint64_t *first_value, uint64_t *nb_reserved_values)
849
884
{
850
885
  *nb_reserved_values= UINT64_MAX;
851
886
  *first_value= share->archive_write.auto_increment + 1;
852
887
}
853
888
 
854
889
/* Initialized at each key walk (called multiple times unlike rnd_init()) */
855
 
int ha_archive::index_init(uint32_t keynr, bool sorted __attribute__((unused)))
 
890
int ha_archive::index_init(uint32_t keynr, bool)
856
891
{
857
892
  active_index= keynr;
858
893
  return(0);
873
908
 
874
909
 
875
910
int ha_archive::index_read_idx(unsigned char *buf, uint32_t index, const unsigned char *key,
876
 
                               uint32_t key_len,
877
 
                               enum ha_rkey_function find_flag __attribute__((unused)))
 
911
                               uint32_t key_len, enum ha_rkey_function)
878
912
{
879
913
  int rc;
880
914
  bool found= 0;
905
939
}
906
940
 
907
941
 
908
 
int ha_archive::index_next(unsigned char * buf) 
909
 
 
942
int ha_archive::index_next(unsigned char * buf)
 
943
{
910
944
  bool found= 0;
911
945
 
912
946
  while (!(get_row(&archive, buf)))
918
952
    }
919
953
  }
920
954
 
921
 
  return(found ? 0 : HA_ERR_END_OF_FILE); 
 
955
  return(found ? 0 : HA_ERR_END_OF_FILE);
922
956
}
923
957
 
924
958
/*
946
980
 
947
981
 
948
982
/*
949
 
  This is the method that is used to read a row. It assumes that the row is 
 
983
  This is the method that is used to read a row. It assumes that the row is
950
984
  positioned where you want it.
951
985
*/
952
986
int ha_archive::get_row(azio_stream *file_to_read, unsigned char *buf)
969
1003
  if (length > record_buffer->length)
970
1004
  {
971
1005
    unsigned char *newptr;
972
 
    if (!(newptr=(unsigned char*) my_realloc((unsigned char*) record_buffer->buffer, 
973
 
                                    length,
974
 
                                    MYF(MY_ALLOW_ZERO_PTR))))
 
1006
    if (!(newptr= (unsigned char *)realloc(record_buffer->buffer, length)))
975
1007
      return(1);
976
1008
    record_buffer->buffer= newptr;
977
1009
    record_buffer->length= length;
1018
1050
}
1019
1051
 
1020
1052
 
1021
 
/* 
 
1053
/*
1022
1054
  Called during ORDER BY. Its position is either from being called sequentially
1023
1055
  or by having had ha_archive::rnd_pos() called before it is called.
1024
1056
*/
1050
1082
  needed.
1051
1083
*/
1052
1084
 
1053
 
void ha_archive::position(const unsigned char *record __attribute__((unused)))
 
1085
void ha_archive::position(const unsigned char *)
1054
1086
{
1055
1087
  my_store_ptr(ref, ref_length, current_position);
1056
1088
  return;
1074
1106
}
1075
1107
 
1076
1108
/*
1077
 
  This method repairs the meta file. It does this by walking the datafile and 
 
1109
  This method repairs the meta file. It does this by walking the datafile and
1078
1110
  rewriting the meta file. Currently it does this by calling optimize with
1079
1111
  the extended flag.
1080
1112
*/
1081
 
int ha_archive::repair(THD* thd, HA_CHECK_OPT* check_opt)
 
1113
int ha_archive::repair(Session* session, HA_CHECK_OPT* check_opt)
1082
1114
{
1083
1115
  check_opt->flags= T_EXTEND;
1084
 
  int rc= optimize(thd, check_opt);
 
1116
  int rc= optimize(session, check_opt);
1085
1117
 
1086
1118
  if (rc)
1087
1119
    return(HA_ERR_CRASHED_ON_REPAIR);
1092
1124
 
1093
1125
/*
1094
1126
  The table can become fragmented if data was inserted, read, and then
1095
 
  inserted again. What we do is open up the file and recompress it completely. 
 
1127
  inserted again. What we do is open up the file and recompress it completely.
1096
1128
*/
1097
 
int ha_archive::optimize(THD* thd __attribute__((unused)),
1098
 
                         HA_CHECK_OPT* check_opt __attribute__((unused)))
 
1129
int ha_archive::optimize(Session *, HA_CHECK_OPT *)
1099
1130
{
1100
1131
  int rc= 0;
1101
1132
  azio_stream writer;
1110
1141
    share->archive_write_open= false;
1111
1142
  }
1112
1143
 
 
1144
  char* proto_string;
 
1145
  proto_string= (char*)malloc(sizeof(char) * archive.frm_length);
 
1146
  if (proto_string == NULL)
 
1147
  {
 
1148
    return ENOMEM;
 
1149
  }
 
1150
  azread_frm(&archive, proto_string);
 
1151
 
1113
1152
  /* Lets create a file to contain the new data */
1114
 
  fn_format(writer_filename, share->table_name, "", ARN, 
 
1153
  fn_format(writer_filename, share->table_name.c_str(), "", ARN,
1115
1154
            MY_REPLACE_EXT | MY_UNPACK_FILENAME);
1116
1155
 
1117
 
  if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR|O_BINARY, AZ_METHOD_BLOCK)))
1118
 
    return(HA_ERR_CRASHED_ON_USAGE); 
1119
 
 
1120
 
  /* 
1121
 
    An extended rebuild is a lot more effort. We open up each row and re-record it. 
1122
 
    Any dead rows are removed (aka rows that may have been partially recorded). 
 
1156
  if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR, AZ_METHOD_BLOCK)))
 
1157
  {
 
1158
    free(proto_string);
 
1159
    return(HA_ERR_CRASHED_ON_USAGE);
 
1160
  }
 
1161
 
 
1162
  azwrite_frm(&writer, proto_string, archive.frm_length);
 
1163
 
 
1164
  /*
 
1165
    An extended rebuild is a lot more effort. We open up each row and re-record it.
 
1166
    Any dead rows are removed (aka rows that may have been partially recorded).
1123
1167
 
1124
1168
    As of Archive format 3, this is the only type that is performed, before this
1125
1169
    version it was just done on T_EXTEND
1127
1171
  if (1)
1128
1172
  {
1129
1173
    /*
1130
 
      Now we will rewind the archive file so that we are positioned at the 
 
1174
      Now we will rewind the archive file so that we are positioned at the
1131
1175
      start of the file.
1132
1176
    */
1133
1177
    azflush(&archive, Z_SYNC_FLUSH);
1134
1178
    rc= read_data_header(&archive);
1135
1179
 
1136
 
    /* 
 
1180
    /*
1137
1181
      On success of writing out the new header, we now fetch each row and
1138
 
      insert it into the new archive file. 
 
1182
      insert it into the new archive file.
1139
1183
    */
1140
1184
    if (!rc)
1141
1185
    {
1162
1206
        if (table->found_next_number_field)
1163
1207
        {
1164
1208
          Field *field= table->found_next_number_field;
 
1209
 
 
1210
          /* Since we will need to use field to translate, we need to flip its read bit */
 
1211
          field->setReadSet();
 
1212
 
1165
1213
          uint64_t auto_value=
1166
1214
            (uint64_t) field->val_int(table->record[0] +
1167
1215
                                       field->offset(table->record[0]));
1177
1225
    {
1178
1226
      goto error;
1179
1227
    }
1180
 
  } 
 
1228
  }
1181
1229
 
1182
1230
  azclose(&writer);
1183
1231
  share->dirty= false;
1184
 
  
 
1232
 
1185
1233
  azclose(&archive);
1186
1234
 
1187
1235
  // make the file we just wrote be our data file
1188
1236
  rc = my_rename(writer_filename,share->data_file_name,MYF(0));
1189
1237
 
1190
 
 
 
1238
  free(proto_string);
1191
1239
  return(rc);
1192
1240
error:
 
1241
  free(proto_string);
1193
1242
  azclose(&writer);
1194
1243
 
1195
 
  return(rc); 
 
1244
  return(rc);
1196
1245
}
1197
1246
 
1198
 
/* 
 
1247
/*
1199
1248
  Below is an example of how to setup row level locking.
1200
1249
*/
1201
 
THR_LOCK_DATA **ha_archive::store_lock(THD *thd,
 
1250
THR_LOCK_DATA **ha_archive::store_lock(Session *session,
1202
1251
                                       THR_LOCK_DATA **to,
1203
1252
                                       enum thr_lock_type lock_type)
1204
1253
{
1205
 
  if (lock_type == TL_WRITE_DELAYED)
1206
 
    delayed_insert= true;
1207
 
  else
1208
 
    delayed_insert= false;
 
1254
  delayed_insert= false;
1209
1255
 
1210
 
  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) 
 
1256
  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
1211
1257
  {
1212
 
    /* 
 
1258
    /*
1213
1259
      Here is where we get into the guts of a row level lock.
1214
 
      If TL_UNLOCK is set 
 
1260
      If TL_UNLOCK is set
1215
1261
      If we are not doing a LOCK Table or DISCARD/IMPORT
1216
 
      TABLESPACE, then allow multiple writers 
 
1262
      TABLESPACE, then allow multiple writers
1217
1263
    */
1218
1264
 
1219
1265
    if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
1220
 
         lock_type <= TL_WRITE) && !thd_in_lock_tables(thd)
1221
 
        && !thd_tablespace_op(thd))
 
1266
         lock_type <= TL_WRITE)
 
1267
        && !session_tablespace_op(session))
1222
1268
      lock_type = TL_WRITE_ALLOW_WRITE;
1223
1269
 
1224
 
    /* 
 
1270
    /*
1225
1271
      In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
1226
1272
      MySQL would use the lock TL_READ_NO_INSERT on t2, and that
1227
1273
      would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
1228
1274
      to t2. Convert the lock to a normal read lock to allow
1229
 
      concurrent inserts to t2. 
 
1275
      concurrent inserts to t2.
1230
1276
    */
1231
1277
 
1232
 
    if (lock_type == TL_READ_NO_INSERT && !thd_in_lock_tables(thd)) 
 
1278
    if (lock_type == TL_READ_NO_INSERT)
1233
1279
      lock_type = TL_READ;
1234
1280
 
1235
1281
    lock.type=lock_type;
1240
1286
  return to;
1241
1287
}
1242
1288
 
1243
 
void ha_archive::update_create_info(HA_CREATE_INFO *create_info)
1244
 
{
1245
 
  ha_archive::info(HA_STATUS_AUTO);
1246
 
  if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
1247
 
  {
1248
 
    create_info->auto_increment_value= stats.auto_increment_value;
1249
 
  }
1250
 
 
1251
 
  if (!(my_readlink(share->real_path, share->data_file_name, MYF(0))))
1252
 
    create_info->data_file_name= share->real_path;
1253
 
 
1254
 
  return;
1255
 
}
1256
 
 
1257
 
 
1258
1289
/*
1259
1290
  Hints for optimizer, see ha_tina for more information
1260
1291
*/
1261
1292
int ha_archive::info(uint32_t flag)
1262
1293
{
1263
 
  /* 
 
1294
  /*
1264
1295
    If dirty, we lock, and then reset/flush the data.
1265
1296
    I found that just calling azflush() doesn't always work.
1266
1297
  */
1278
1309
 
1279
1310
  }
1280
1311
 
1281
 
  /* 
 
1312
  /*
1282
1313
    This should be an accurate number now, though bulk and delayed inserts can
1283
1314
    cause the number to be inaccurate.
1284
1315
  */
1331
1362
}
1332
1363
 
1333
1364
 
1334
 
/* 
 
1365
/*
1335
1366
  Other side of start_bulk_insert, is end_bulk_insert. Here we turn off the bulk insert
1336
1367
  flag, and set the share dirty so that the next select will call sync for us.
1337
1368
*/
1344
1375
 
1345
1376
/*
1346
1377
  We cancel a truncate command. The only way to delete an archive table is to drop it.
1347
 
  This is done for security reasons. In a later version we will enable this by 
 
1378
  This is done for security reasons. In a later version we will enable this by
1348
1379
  allowing the user to select a different row format.
1349
1380
*/
1350
1381
int ha_archive::delete_all_rows()
1355
1386
/*
1356
1387
  We just return state if asked.
1357
1388
*/
1358
 
bool ha_archive::is_crashed() const 
 
1389
bool ha_archive::is_crashed() const
1359
1390
{
1360
 
  return(share->crashed); 
 
1391
  return(share->crashed);
1361
1392
}
1362
1393
 
1363
1394
/*
1364
1395
  Simple scan of the tables to make sure everything is ok.
1365
1396
*/
1366
1397
 
1367
 
int ha_archive::check(THD* thd,
1368
 
                      HA_CHECK_OPT* check_opt __attribute__((unused)))
 
1398
int ha_archive::check(Session* session, HA_CHECK_OPT *)
1369
1399
{
1370
1400
  int rc= 0;
1371
1401
  const char *old_proc_info;
1372
1402
  uint64_t x;
1373
1403
 
1374
 
  old_proc_info= thd_proc_info(thd, "Checking table");
 
1404
  old_proc_info= get_session_proc_info(session);
 
1405
  set_session_proc_info(session, "Checking table");
1375
1406
  /* Flush any waiting data */
1376
1407
  pthread_mutex_lock(&share->mutex);
1377
1408
  azflush(&(share->archive_write), Z_SYNC_FLUSH);
1378
1409
  pthread_mutex_unlock(&share->mutex);
1379
1410
 
1380
1411
  /*
1381
 
    Now we will rewind the archive file so that we are positioned at the 
 
1412
    Now we will rewind the archive file so that we are positioned at the
1382
1413
    start of the file.
1383
1414
  */
1384
1415
  init_archive_reader();
1392
1423
      break;
1393
1424
  }
1394
1425
 
1395
 
  thd_proc_info(thd, old_proc_info);
 
1426
  set_session_proc_info(session, old_proc_info);
1396
1427
 
1397
 
  if ((rc && rc != HA_ERR_END_OF_FILE))  
 
1428
  if ((rc && rc != HA_ERR_END_OF_FILE))
1398
1429
  {
1399
1430
    share->crashed= false;
1400
1431
    return(HA_ADMIN_CORRUPT);
1405
1436
  }
1406
1437
}
1407
1438
 
1408
 
/*
1409
 
  Check and repair the table if needed.
1410
 
*/
1411
 
bool ha_archive::check_and_repair(THD *thd) 
1412
 
{
1413
 
  HA_CHECK_OPT check_opt;
1414
 
 
1415
 
  check_opt.init();
1416
 
 
1417
 
  return(repair(thd, &check_opt));
1418
 
}
1419
 
 
1420
 
archive_record_buffer *ha_archive::create_record_buffer(unsigned int length) 
 
1439
archive_record_buffer *ha_archive::create_record_buffer(unsigned int length)
1421
1440
{
1422
1441
  archive_record_buffer *r;
1423
 
  if (!(r= 
1424
 
        (archive_record_buffer*) my_malloc(sizeof(archive_record_buffer),
1425
 
                                           MYF(MY_WME))))
 
1442
  if (!(r= (archive_record_buffer*) malloc(sizeof(archive_record_buffer))))
1426
1443
  {
1427
1444
    return(NULL); /* purecov: inspected */
1428
1445
  }
1429
1446
  r->length= (int)length;
1430
1447
 
1431
 
  if (!(r->buffer= (unsigned char*) my_malloc(r->length,
1432
 
                                    MYF(MY_WME))))
 
1448
  if (!(r->buffer= (unsigned char*) malloc(r->length)))
1433
1449
  {
1434
1450
    free((char*) r);
1435
1451
    return(NULL); /* purecov: inspected */
1438
1454
  return(r);
1439
1455
}
1440
1456
 
1441
 
void ha_archive::destroy_record_buffer(archive_record_buffer *r) 
 
1457
void ha_archive::destroy_record_buffer(archive_record_buffer *r)
1442
1458
{
1443
1459
  free((char*) r->buffer);
1444
1460
  free((char*) r);
1455
1471
  NULL
1456
1472
};
1457
1473
 
1458
 
mysql_declare_plugin(archive)
 
1474
drizzle_declare_plugin(archive)
1459
1475
{
1460
 
  DRIZZLE_STORAGE_ENGINE_PLUGIN,
1461
1476
  "ARCHIVE",
1462
1477
  "3.5",
1463
1478
  "Brian Aker, MySQL AB",
1469
1484
  archive_system_variables,   /* system variables                */
1470
1485
  NULL                        /* config options                  */
1471
1486
}
1472
 
mysql_declare_plugin_end;
 
1487
drizzle_declare_plugin_end;
1473
1488