~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/archive/ha_archive.cc

  • Committer: Stewart Smith
  • Date: 2009-06-16 03:43:00 UTC
  • mto: This revision was merged to the branch mainline in revision 1094.
  • Revision ID: stewart@flamingspork.com-20090616034300-bamg5dsfaknwi05b
fix join_outer for MyISAM as temp only: 1x open table twice, 1x CREATE TEMP

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* Copyright (C) 2003 MySQL AB
2
 
   Copyright (C) 2010 Brian Aker
3
2
 
4
3
  This program is free software; you can redistribute it and/or modify
5
4
  it under the terms of the GNU General Public License as published by
12
11
 
13
12
  You should have received a copy of the GNU General Public License
14
13
  along with this program; if not, write to the Free Software
15
 
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
16
 
 
17
 
 
18
 
#include "config.h"
19
 
 
20
 
#include "plugin/archive/archive_engine.h"
21
 
#include <memory>
22
 
#include <boost/scoped_ptr.hpp>
 
14
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
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
 
 
25
#include "ha_archive.h"
 
26
 
 
27
#include <stdio.h>
 
28
#include <string>
 
29
#include <map>
23
30
 
24
31
using namespace std;
25
 
using namespace drizzled;
26
32
 
 
33
static const string engine_name("ARCHIVE");
27
34
 
28
35
/*
29
36
  First, if you want to understand storage engines you should look at
93
100
    -Brian
94
101
*/
95
102
 
96
 
/* When the engine starts up set the first version */
97
 
static uint64_t global_version= 1;
98
 
 
99
 
// We use this to find out the state of the archive aio option.
100
 
extern bool archive_aio_state(void);
 
103
/* Variables for archive share methods */
 
104
pthread_mutex_t archive_mutex= PTHREAD_MUTEX_INITIALIZER;
 
105
 
 
106
std::map<const char *, ArchiveShare *> archive_open_tables;
 
107
 
 
108
static unsigned int global_version;
 
109
 
 
110
/* The file extension */
 
111
#define ARZ ".ARZ"               // The data file
 
112
#define ARN ".ARN"               // Files used during an optimize call
 
113
 
 
114
 
 
115
 
 
116
static bool archive_use_aio= false;
101
117
 
102
118
/*
103
119
  Number of rows that will force a bulk insert.
109
125
*/
110
126
#define ARCHIVE_ROW_HEADER_SIZE 4
111
127
 
112
 
ArchiveShare *ArchiveEngine::findOpenTable(const string table_name)
113
 
{
114
 
  ArchiveMap::iterator find_iter=
115
 
    archive_open_tables.find(table_name);
116
 
 
117
 
  if (find_iter != archive_open_tables.end())
118
 
    return (*find_iter).second;
119
 
  else
120
 
    return NULL;
121
 
}
122
 
 
123
 
void ArchiveEngine::addOpenTable(const string &table_name, ArchiveShare *share)
124
 
{
125
 
  archive_open_tables[table_name]= share;
126
 
}
127
 
 
128
 
void ArchiveEngine::deleteOpenTable(const string &table_name)
129
 
{
130
 
  archive_open_tables.erase(table_name);
131
 
}
132
 
 
133
 
 
134
 
int ArchiveEngine::doDropTable(Session&, const TableIdentifier &identifier)
135
 
{
136
 
  string new_path(identifier.getPath());
137
 
 
138
 
  new_path+= ARZ;
139
 
 
140
 
  int error= unlink(new_path.c_str());
141
 
 
142
 
  if (error != 0)
143
 
  {
144
 
    error= errno= errno;
145
 
  }
146
 
 
147
 
  return error;
148
 
}
149
 
 
150
 
int ArchiveEngine::doGetTableDefinition(Session&,
151
 
                                        const TableIdentifier &identifier,
152
 
                                        drizzled::message::Table &table_proto)
153
 
{
154
 
  struct stat stat_info;
155
 
  int error= ENOENT;
156
 
  string proto_path;
157
 
 
158
 
  proto_path.reserve(FN_REFLEN);
159
 
  proto_path.assign(identifier.getPath());
160
 
 
161
 
  proto_path.append(ARZ);
162
 
 
163
 
  if (stat(proto_path.c_str(),&stat_info))
164
 
    return errno;
165
 
  else
166
 
    error= EEXIST;
167
 
 
168
 
  {
169
 
    boost::scoped_ptr<azio_stream> proto_stream(new azio_stream);
170
 
    char* proto_string;
171
 
    if (azopen(proto_stream.get(), proto_path.c_str(), O_RDONLY, AZ_METHOD_BLOCK) == 0)
172
 
      return HA_ERR_CRASHED_ON_USAGE;
173
 
 
174
 
    proto_string= (char*)malloc(sizeof(char) * proto_stream->frm_length);
175
 
    if (proto_string == NULL)
176
 
    {
177
 
      azclose(proto_stream.get());
178
 
      return ENOMEM;
179
 
    }
180
 
 
181
 
    azread_frm(proto_stream.get(), proto_string);
182
 
 
183
 
    if (table_proto.ParseFromArray(proto_string, proto_stream->frm_length) == false)
184
 
      error= HA_ERR_CRASHED_ON_USAGE;
185
 
 
186
 
    azclose(proto_stream.get());
187
 
    free(proto_string);
188
 
  }
189
 
 
190
 
  /* We set the name from what we've asked for as in RENAME TABLE for ARCHIVE
191
 
     we do not rewrite the table proto (as it's wedged in the file header)
192
 
  */
193
 
  table_proto.set_schema(identifier.getSchemaName());
194
 
  table_proto.set_name(identifier.getTableName());
195
 
 
196
 
  return error;
197
 
}
198
 
 
199
 
 
200
 
ha_archive::ha_archive(drizzled::plugin::StorageEngine &engine_arg,
201
 
                       Table &table_arg)
202
 
  :Cursor(engine_arg, table_arg), delayed_insert(0), bulk_insert(0)
 
128
/*
 
129
  We just implement one additional file extension.
 
130
*/
 
131
static const char *ha_archive_exts[] = {
 
132
  ARZ,
 
133
  NULL
 
134
};
 
135
 
 
136
class ArchiveEngine : public StorageEngine
 
137
{
 
138
public:
 
139
  ArchiveEngine(const string &name_arg) : StorageEngine(name_arg) {}
 
140
  virtual handler *create(TableShare *table,
 
141
                          MEM_ROOT *mem_root)
 
142
  {
 
143
    return new (mem_root) ha_archive(this, table);
 
144
  }
 
145
 
 
146
  const char **bas_ext() const {
 
147
    return ha_archive_exts;
 
148
  }
 
149
 
 
150
  int createTableImpl(Session *session, const char *table_name,
 
151
                      Table *table_arg, HA_CREATE_INFO *create_info);
 
152
};
 
153
 
 
154
static ArchiveEngine *archive_engine= NULL;
 
155
 
 
156
/*
 
157
  Initialize the archive handler.
 
158
 
 
159
  SYNOPSIS
 
160
    archive_db_init()
 
161
    void *
 
162
 
 
163
  RETURN
 
164
    false       OK
 
165
    true        Error
 
166
*/
 
167
 
 
168
int archive_db_init(PluginRegistry &registry)
 
169
{
 
170
 
 
171
  pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST);
 
172
  archive_engine= new ArchiveEngine(engine_name);
 
173
  registry.add(archive_engine);
 
174
 
 
175
  /* When the engine starts up set the first version */
 
176
  global_version= 1;
 
177
 
 
178
  return false;
 
179
}
 
180
 
 
181
/*
 
182
  Release the archive handler.
 
183
 
 
184
  SYNOPSIS
 
185
    archive_db_done()
 
186
    void
 
187
 
 
188
  RETURN
 
189
    false       OK
 
190
*/
 
191
 
 
192
int archive_db_done(PluginRegistry &registry)
 
193
{
 
194
  registry.remove(archive_engine);
 
195
  delete archive_engine;
 
196
 
 
197
  pthread_mutex_destroy(&archive_mutex);
 
198
 
 
199
  return 0;
 
200
}
 
201
 
 
202
 
 
203
ha_archive::ha_archive(StorageEngine *engine_arg, TableShare *table_arg)
 
204
  :handler(engine_arg, table_arg), delayed_insert(0), bulk_insert(0)
203
205
{
204
206
  /* Set our original buffer from pre-allocated memory */
205
207
  buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info);
206
208
 
207
209
  /* The size of the offset value we will use for position() */
208
 
  ref_length= sizeof(internal::my_off_t);
 
210
  ref_length= sizeof(my_off_t);
209
211
  archive_reader_open= false;
210
212
}
211
213
 
236
238
{
237
239
  memset(&archive_write, 0, sizeof(azio_stream));     /* Archive file we are working with */
238
240
  table_name.append(name);
239
 
  data_file_name.assign(table_name);
240
 
  data_file_name.append(ARZ);
 
241
  fn_format(data_file_name, table_name.c_str(), "",
 
242
            ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
241
243
  /*
242
244
    We will use this lock for rows.
243
245
  */
244
 
  pthread_mutex_init(&_mutex,MY_MUTEX_INIT_FAST);
 
246
  pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST);
245
247
}
246
248
 
247
249
ArchiveShare::~ArchiveShare()
248
250
{
249
 
  _lock.deinit();
250
 
  pthread_mutex_destroy(&_mutex);
 
251
  thr_lock_delete(&lock);
 
252
  pthread_mutex_destroy(&mutex);
251
253
  /*
252
254
    We need to make sure we don't reset the crashed state.
253
255
    If we open a crashed file, wee need to close it as crashed unless
261
263
 
262
264
bool ArchiveShare::prime(uint64_t *auto_increment)
263
265
{
264
 
  boost::scoped_ptr<azio_stream> archive_tmp(new azio_stream);
 
266
  azio_stream archive_tmp;
265
267
 
266
268
  /*
267
269
    We read the meta file, but do not mark it dirty. Since we are not
269
271
    anything but reading... open it for write and we will generate null
270
272
    compression writes).
271
273
  */
272
 
  if (!(azopen(archive_tmp.get(), data_file_name.c_str(), O_RDONLY,
 
274
  if (!(azopen(&archive_tmp, data_file_name, O_RDONLY,
273
275
               AZ_METHOD_BLOCK)))
274
276
    return false;
275
277
 
276
 
  *auto_increment= archive_tmp->auto_increment + 1;
277
 
  rows_recorded= (ha_rows)archive_tmp->rows;
278
 
  crashed= archive_tmp->dirty;
 
278
  *auto_increment= archive_tmp.auto_increment + 1;
 
279
  rows_recorded= (ha_rows)archive_tmp.rows;
 
280
  crashed= archive_tmp.dirty;
279
281
  if (version < global_version)
280
282
  {
281
283
    version_rows= rows_recorded;
282
284
    version= global_version;
283
285
  }
284
 
  azclose(archive_tmp.get());
 
286
  azclose(&archive_tmp);
285
287
 
286
288
  return true;
287
289
}
296
298
*/
297
299
ArchiveShare *ha_archive::get_share(const char *table_name, int *rc)
298
300
{
299
 
  ArchiveEngine *a_engine= static_cast<ArchiveEngine *>(getEngine());
300
 
 
301
 
  pthread_mutex_lock(&a_engine->mutex());
302
 
 
303
 
  share= a_engine->findOpenTable(table_name);
 
301
  uint32_t length;
 
302
  map<const char *, ArchiveShare *> ::iterator find_iter;
 
303
 
 
304
  pthread_mutex_lock(&archive_mutex);
 
305
  length=(uint) strlen(table_name);
 
306
 
 
307
  find_iter= archive_open_tables.find(table_name);
 
308
 
 
309
  if (find_iter != archive_open_tables.end())
 
310
    share= (*find_iter).second;
 
311
  else
 
312
    share= NULL;
304
313
 
305
314
  if (!share)
306
315
  {
308
317
 
309
318
    if (share == NULL)
310
319
    {
311
 
      pthread_mutex_unlock(&a_engine->mutex());
 
320
      pthread_mutex_unlock(&archive_mutex);
312
321
      *rc= HA_ERR_OUT_OF_MEM;
313
322
      return(NULL);
314
323
    }
315
324
 
316
325
    if (share->prime(&stats.auto_increment_value) == false)
317
326
    {
318
 
      pthread_mutex_unlock(&a_engine->mutex());
 
327
      pthread_mutex_unlock(&archive_mutex);
319
328
      *rc= HA_ERR_CRASHED_ON_REPAIR;
320
329
      delete share;
321
330
 
322
331
      return NULL;
323
332
    }
324
333
 
325
 
    a_engine->addOpenTable(share->table_name, share);
326
 
    thr_lock_init(&share->_lock);
 
334
    archive_open_tables[share->table_name.c_str()]= share; 
 
335
    thr_lock_init(&share->lock);
327
336
  }
328
337
  share->use_count++;
329
 
 
330
338
  if (share->crashed)
331
339
    *rc= HA_ERR_CRASHED_ON_USAGE;
332
 
  pthread_mutex_unlock(&a_engine->mutex());
 
340
  pthread_mutex_unlock(&archive_mutex);
333
341
 
334
342
  return(share);
335
343
}
341
349
*/
342
350
int ha_archive::free_share()
343
351
{
344
 
  ArchiveEngine *a_engine= static_cast<ArchiveEngine *>(getEngine());
345
 
 
346
 
  pthread_mutex_lock(&a_engine->mutex());
 
352
  pthread_mutex_lock(&archive_mutex);
347
353
  if (!--share->use_count)
348
354
  {
349
 
    a_engine->deleteOpenTable(share->table_name);
 
355
    archive_open_tables.erase(share->table_name.c_str());
350
356
    delete share;
351
357
  }
352
 
  pthread_mutex_unlock(&a_engine->mutex());
 
358
  pthread_mutex_unlock(&archive_mutex);
353
359
 
354
360
  return 0;
355
361
}
361
367
    a gzip file that can be both read and written we keep a writer open
362
368
    that is shared amoung all open tables.
363
369
  */
364
 
  if (!(azopen(&(share->archive_write), share->data_file_name.c_str(),
 
370
  if (!(azopen(&(share->archive_write), share->data_file_name,
365
371
               O_RDWR, AZ_METHOD_BLOCK)))
366
372
  {
367
373
    share->crashed= true;
374
380
 
375
381
 
376
382
/*
377
 
  No locks are required because it is associated with just one Cursor instance
 
383
  No locks are required because it is associated with just one handler instance
378
384
*/
379
385
int ha_archive::init_archive_reader()
380
386
{
387
393
  {
388
394
    az_method method;
389
395
 
390
 
    if (archive_aio_state())
 
396
    switch (archive_use_aio)
391
397
    {
 
398
    case false:
 
399
      method= AZ_METHOD_BLOCK;
 
400
      break;
 
401
    case true:
392
402
      method= AZ_METHOD_AIO;
393
 
    }
394
 
    else
395
 
    {
 
403
      break;
 
404
    default:
396
405
      method= AZ_METHOD_BLOCK;
397
406
    }
398
 
    if (!(azopen(&archive, share->data_file_name.c_str(), O_RDONLY,
 
407
    if (!(azopen(&archive, share->data_file_name, O_RDONLY,
399
408
                 method)))
400
409
    {
401
410
      share->crashed= true;
413
422
  Init out lock.
414
423
  We open the file we will read from.
415
424
*/
416
 
int ha_archive::doOpen(const TableIdentifier &identifier, int , uint32_t )
 
425
int ha_archive::open(const char *name, int, uint32_t open_options)
417
426
{
418
427
  int rc= 0;
419
 
  share= get_share(identifier.getPath().c_str(), &rc);
420
 
 
421
 
  /** 
422
 
    We either fix it ourselves, or we just take it offline 
423
 
 
424
 
    @todo Create some documentation in the recovery tools shipped with the engine.
425
 
  */
426
 
  if (rc == HA_ERR_CRASHED_ON_USAGE)
 
428
  share= get_share(name, &rc);
 
429
 
 
430
  if (rc == HA_ERR_CRASHED_ON_USAGE && !(open_options & HA_OPEN_FOR_REPAIR))
427
431
  {
 
432
    /* purecov: begin inspected */
428
433
    free_share();
429
 
    rc= repair();
430
 
 
431
 
    return 0;
 
434
    return(rc);
 
435
    /* purecov: end */
432
436
  }
433
437
  else if (rc == HA_ERR_OUT_OF_MEM)
434
438
  {
437
441
 
438
442
  assert(share);
439
443
 
440
 
  record_buffer.resize(getTable()->getShare()->getRecordLength() + ARCHIVE_ROW_HEADER_SIZE);
441
 
 
442
 
  lock.init(&share->_lock);
443
 
 
444
 
  return(rc);
445
 
}
446
 
 
447
 
// Should never be called
448
 
int ha_archive::open(const char *, int, uint32_t)
449
 
{
450
 
  assert(0);
451
 
  return -1;
 
444
  record_buffer= create_record_buffer(table->s->reclength +
 
445
                                      ARCHIVE_ROW_HEADER_SIZE);
 
446
 
 
447
  if (!record_buffer)
 
448
  {
 
449
    free_share();
 
450
    return(HA_ERR_OUT_OF_MEM);
 
451
  }
 
452
 
 
453
  thr_lock_data_init(&share->lock, &lock, NULL);
 
454
 
 
455
  if (rc == HA_ERR_CRASHED_ON_USAGE && open_options & HA_OPEN_FOR_REPAIR)
 
456
  {
 
457
    return(0);
 
458
  }
 
459
  else
 
460
    return(rc);
452
461
}
453
462
 
454
463
 
473
482
{
474
483
  int rc= 0;
475
484
 
476
 
  record_buffer.clear();
 
485
  destroy_record_buffer(record_buffer);
477
486
 
478
487
  /* First close stream */
479
488
  if (archive_reader_open == true)
497
506
  of creation.
498
507
*/
499
508
 
500
 
int ArchiveEngine::doCreateTable(Session &,
501
 
                                 Table& table_arg,
502
 
                                 const drizzled::TableIdentifier &identifier,
503
 
                                 drizzled::message::Table& proto)
 
509
int ArchiveEngine::createTableImpl(Session *session, const char *table_name,
 
510
                                   Table *table_arg,
 
511
                                   HA_CREATE_INFO *create_info)
504
512
{
 
513
  char name_buff[FN_REFLEN];
 
514
  char linkname[FN_REFLEN];
505
515
  int error= 0;
506
 
  boost::scoped_ptr<azio_stream> create_stream(new azio_stream);
 
516
  azio_stream create_stream;            /* Archive file we are working with */
 
517
  FILE *frm_file;                   /* File handler for readers */
 
518
  struct stat file_stat;
 
519
  unsigned char *frm_ptr;
 
520
  int r;
507
521
  uint64_t auto_increment_value;
508
 
  string serialized_proto;
509
 
 
510
 
  auto_increment_value= proto.options().auto_increment_value();
511
 
 
512
 
  for (uint32_t key= 0; key < table_arg.sizeKeys(); key++)
 
522
 
 
523
  auto_increment_value= create_info->auto_increment_value;
 
524
 
 
525
  for (uint32_t key= 0; key < table_arg->sizeKeys(); key++)
513
526
  {
514
 
    KeyInfo *pos= &table_arg.key_info[key];
515
 
    KeyPartInfo *key_part=     pos->key_part;
516
 
    KeyPartInfo *key_part_end= key_part + pos->key_parts;
 
527
    KEY *pos= table_arg->key_info+key;
 
528
    KEY_PART_INFO *key_part=     pos->key_part;
 
529
    KEY_PART_INFO *key_part_end= key_part + pos->key_parts;
517
530
 
518
531
    for (; key_part != key_part_end; key_part++)
519
532
    {
521
534
 
522
535
      if (!(field->flags & AUTO_INCREMENT_FLAG))
523
536
      {
524
 
        return -1;
 
537
        error= -1;
 
538
        goto error;
525
539
      }
526
540
    }
527
541
  }
528
542
 
529
 
  std::string named_file= identifier.getPath();
530
 
  named_file.append(ARZ);
531
 
 
532
 
  errno= 0;
533
 
  if (azopen(create_stream.get(), named_file.c_str(), O_CREAT|O_RDWR,
534
 
             AZ_METHOD_BLOCK) == 0)
 
543
  /*
 
544
    We reuse name_buff since it is available.
 
545
  */
 
546
  if (create_info->data_file_name && create_info->data_file_name[0] != '#')
 
547
  {
 
548
    fn_format(name_buff, create_info->data_file_name, "", ARZ,
 
549
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
550
    fn_format(linkname, table_name, "", ARZ,
 
551
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
552
  }
 
553
  else
 
554
  {
 
555
    fn_format(name_buff, table_name, "", ARZ,
 
556
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
557
    linkname[0]= 0;
 
558
  }
 
559
 
 
560
  /*
 
561
    There is a chance that the file was "discovered". In this case
 
562
    just use whatever file is there.
 
563
  */
 
564
  r= stat(name_buff, &file_stat);
 
565
  if (r == -1 && errno!=ENOENT)
 
566
  {
 
567
    return errno;
 
568
  }
 
569
  if (!r)
 
570
    return HA_ERR_TABLE_EXIST;
 
571
 
 
572
  my_errno= 0;
 
573
  if (!(azopen(&create_stream, name_buff, O_CREAT|O_RDWR,
 
574
               AZ_METHOD_BLOCK)))
535
575
  {
536
576
    error= errno;
537
 
    unlink(named_file.c_str());
538
 
 
539
 
    return(error ? error : -1);
540
 
  }
541
 
 
542
 
  try {
543
 
    proto.SerializeToString(&serialized_proto);
544
 
  }
545
 
  catch (...)
546
 
  {
547
 
    unlink(named_file.c_str());
548
 
 
549
 
    return(error ? error : -1);
550
 
  }
551
 
 
552
 
  if (azwrite_frm(create_stream.get(), serialized_proto.c_str(),
553
 
                  serialized_proto.length()))
554
 
  {
555
 
    unlink(named_file.c_str());
556
 
 
557
 
    return(error ? error : -1);
558
 
  }
559
 
 
560
 
  if (proto.options().has_comment())
561
 
  {
562
 
    int write_length;
563
 
 
564
 
    write_length= azwrite_comment(create_stream.get(),
565
 
                                  proto.options().comment().c_str(),
566
 
                                  proto.options().comment().length());
567
 
 
568
 
    if (write_length < 0)
 
577
    goto error2;
 
578
  }
 
579
 
 
580
  if (linkname[0])
 
581
    my_symlink(name_buff, linkname, MYF(0));
 
582
  fn_format(name_buff, table_name, "", ".frm",
 
583
            MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
584
 
 
585
  /*
 
586
    Here is where we open up the frm and pass it to archive to store
 
587
  */
 
588
  if ((frm_file= fopen(name_buff, "r")) > 0)
 
589
  {
 
590
    if (fstat(fileno(frm_file), &file_stat))
569
591
    {
570
 
      error= errno;
571
 
      unlink(named_file.c_str());
572
 
 
573
 
      return(error ? error : -1);
 
592
      if ((uint64_t)file_stat.st_size > SIZE_MAX)
 
593
      {
 
594
        error= ENOMEM;
 
595
        goto error2;
 
596
      }
 
597
      frm_ptr= (unsigned char *)malloc((size_t)file_stat.st_size);
 
598
      if (frm_ptr)
 
599
      {
 
600
        size_t length_io;
 
601
        length_io= read(fileno(frm_file), frm_ptr, (size_t)file_stat.st_size);
 
602
 
 
603
        if (length_io != (size_t)file_stat.st_size)
 
604
        {
 
605
          free(frm_ptr);
 
606
          goto error2;
 
607
        }
 
608
 
 
609
        length_io= azwrite_frm(&create_stream, (char *)frm_ptr, (size_t)file_stat.st_size);
 
610
 
 
611
        if (length_io != (size_t)file_stat.st_size)
 
612
        {
 
613
          free(frm_ptr);
 
614
          goto error2;
 
615
        }
 
616
 
 
617
        free(frm_ptr);
 
618
      }
574
619
    }
 
620
    fclose(frm_file);
 
621
  }
 
622
 
 
623
  if (create_info->comment.str)
 
624
  {
 
625
    size_t write_length;
 
626
 
 
627
    write_length= azwrite_comment(&create_stream, create_info->comment.str,
 
628
                                  (unsigned int)create_info->comment.length);
 
629
 
 
630
    if (write_length == (size_t)create_info->comment.length)
 
631
      goto error2;
575
632
  }
576
633
 
577
634
  /*
578
635
    Yes you need to do this, because the starting value
579
636
    for the autoincrement may not be zero.
580
637
  */
581
 
  create_stream->auto_increment= auto_increment_value ?
 
638
  create_stream.auto_increment= auto_increment_value ?
582
639
    auto_increment_value - 1 : 0;
583
640
 
584
 
  if (azclose(create_stream.get()))
 
641
  if (azclose(&create_stream))
585
642
  {
586
643
    error= errno;
587
 
    unlink(named_file.c_str());
588
 
 
589
 
    return(error ? error : -1);
 
644
    goto error2;
590
645
  }
591
646
 
592
647
  return(0);
 
648
 
 
649
error2:
 
650
  deleteTable(session, table_name);
 
651
error:
 
652
  /* Return error number, if we got one */
 
653
  return(error ? error : -1);
593
654
}
594
655
 
595
656
/*
603
664
  /* We pack the row for writing */
604
665
  r_pack_length= pack_row(buf);
605
666
 
606
 
  written= azwrite_row(writer, &record_buffer[0], r_pack_length);
 
667
  written= azwrite_row(writer, record_buffer->buffer, r_pack_length);
607
668
  if (written != r_pack_length)
608
669
  {
609
670
    return(-1);
623
684
 
624
685
uint32_t ha_archive::max_row_length(const unsigned char *)
625
686
{
626
 
  uint32_t length= (uint32_t)(getTable()->getRecordLength() + getTable()->sizeFields()*2);
 
687
  uint32_t length= (uint32_t)(table->getRecordLength() + table->sizeFields()*2);
627
688
  length+= ARCHIVE_ROW_HEADER_SIZE;
628
689
 
629
690
  uint32_t *ptr, *end;
630
 
  for (ptr= getTable()->getBlobField(), end=ptr + getTable()->sizeBlobFields();
 
691
  for (ptr= table->getBlobField(), end=ptr + table->sizeBlobFields();
631
692
       ptr != end ;
632
693
       ptr++)
633
694
  {
634
 
      length += 2 + ((Field_blob*)getTable()->getField(*ptr))->get_length();
 
695
      length += 2 + ((Field_blob*)table->field[*ptr])->get_length();
635
696
  }
636
697
 
637
698
  return length;
643
704
  unsigned char *ptr;
644
705
 
645
706
  if (fix_rec_buff(max_row_length(record)))
646
 
    return(HA_ERR_OUT_OF_MEM);
 
707
    return(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
647
708
 
648
709
  /* Copy null bits */
649
 
  memcpy(&record_buffer[0], record, getTable()->getShare()->null_bytes);
650
 
  ptr= &record_buffer[0] + getTable()->getShare()->null_bytes;
 
710
  memcpy(record_buffer->buffer, record, table->s->null_bytes);
 
711
  ptr= record_buffer->buffer + table->s->null_bytes;
651
712
 
652
 
  for (Field **field=getTable()->getFields() ; *field ; field++)
 
713
  for (Field **field=table->field ; *field ; field++)
653
714
  {
654
715
    if (!((*field)->is_null()))
655
716
      ptr= (*field)->pack(ptr, record + (*field)->offset(record));
656
717
  }
657
718
 
658
 
  return((unsigned int) (ptr - &record_buffer[0]));
 
719
  return((unsigned int) (ptr - record_buffer->buffer));
659
720
}
660
721
 
661
722
 
668
729
  for implementing start_bulk_insert() is that we could skip
669
730
  setting dirty to true each time.
670
731
*/
671
 
int ha_archive::doInsertRecord(unsigned char *buf)
 
732
int ha_archive::write_row(unsigned char *buf)
672
733
{
673
734
  int rc;
674
735
  unsigned char *read_buf= NULL;
675
736
  uint64_t temp_auto;
676
 
  unsigned char *record=  getTable()->getInsertRecord();
 
737
  unsigned char *record=  table->record[0];
677
738
 
678
739
  if (share->crashed)
679
740
    return(HA_ERR_CRASHED_ON_USAGE);
680
741
 
681
 
  pthread_mutex_lock(&share->mutex());
 
742
  ha_statistic_increment(&SSV::ha_write_count);
 
743
  pthread_mutex_lock(&share->mutex);
682
744
 
683
745
  if (share->archive_write_open == false)
684
746
    if (init_archive_writer())
685
747
      return(HA_ERR_CRASHED_ON_USAGE);
686
748
 
687
749
 
688
 
  if (getTable()->next_number_field && record == getTable()->getInsertRecord())
 
750
  if (table->next_number_field && record == table->record[0])
689
751
  {
 
752
    KEY *mkey= &table->s->key_info[0]; // We only support one key right now
690
753
    update_auto_increment();
691
 
    temp_auto= getTable()->next_number_field->val_int();
 
754
    temp_auto= table->next_number_field->val_int();
692
755
 
693
756
    /*
694
757
      We don't support decremening auto_increment. They make the performance
695
758
      just cry.
696
759
    */
697
760
    if (temp_auto <= share->archive_write.auto_increment &&
698
 
        getTable()->getShare()->getKeyInfo(0).flags & HA_NOSAME)
 
761
        mkey->flags & HA_NOSAME)
699
762
    {
700
763
      rc= HA_ERR_FOUND_DUPP_KEY;
701
764
      goto error;
715
778
  share->rows_recorded++;
716
779
  rc= real_write_row(buf,  &(share->archive_write));
717
780
error:
718
 
  pthread_mutex_unlock(&share->mutex());
 
781
  pthread_mutex_unlock(&share->mutex);
719
782
  if (read_buf)
720
783
    free((unsigned char*) read_buf);
721
784
 
730
793
  *first_value= share->archive_write.auto_increment + 1;
731
794
}
732
795
 
733
 
/* Initialized at each key walk (called multiple times unlike doStartTableScan()) */
734
 
int ha_archive::doStartIndexScan(uint32_t keynr, bool)
 
796
/* Initialized at each key walk (called multiple times unlike rnd_init()) */
 
797
int ha_archive::index_init(uint32_t keynr, bool)
735
798
{
736
799
  active_index= keynr;
737
800
  return(0);
743
806
  the optimizer that we have unique indexes, we scan
744
807
*/
745
808
int ha_archive::index_read(unsigned char *buf, const unsigned char *key,
746
 
                             uint32_t key_len, enum ha_rkey_function)
 
809
                             uint32_t key_len, enum ha_rkey_function find_flag)
 
810
{
 
811
  int rc;
 
812
  rc= index_read_idx(buf, active_index, key, key_len, find_flag);
 
813
  return(rc);
 
814
}
 
815
 
 
816
 
 
817
int ha_archive::index_read_idx(unsigned char *buf, uint32_t index, const unsigned char *key,
 
818
                               uint32_t key_len, enum ha_rkey_function)
747
819
{
748
820
  int rc;
749
821
  bool found= 0;
750
 
  current_k_offset= getTable()->getShare()->getKeyInfo(0).key_part->offset;
 
822
  KEY *mkey= &table->s->key_info[index];
 
823
  current_k_offset= mkey->key_part->offset;
751
824
  current_key= key;
752
825
  current_key_len= key_len;
753
826
 
754
 
  rc= doStartTableScan(true);
 
827
  rc= rnd_init(true);
755
828
 
756
829
  if (rc)
757
830
    goto error;
795
868
  we assume the position will be set.
796
869
*/
797
870
 
798
 
int ha_archive::doStartTableScan(bool scan)
 
871
int ha_archive::rnd_init(bool scan)
799
872
{
800
873
  if (share->crashed)
801
874
      return(HA_ERR_CRASHED_ON_USAGE);
832
905
/* Reallocate buffer if needed */
833
906
bool ha_archive::fix_rec_buff(unsigned int length)
834
907
{
835
 
  record_buffer.resize(length);
836
 
 
837
 
  return false;
 
908
  assert(record_buffer->buffer);
 
909
 
 
910
  if (length > record_buffer->length)
 
911
  {
 
912
    unsigned char *newptr;
 
913
    if (!(newptr= (unsigned char *)realloc(record_buffer->buffer, length)))
 
914
      return(1);
 
915
    record_buffer->buffer= newptr;
 
916
    record_buffer->length= length;
 
917
  }
 
918
 
 
919
  assert(length <= record_buffer->length);
 
920
 
 
921
  return(0);
838
922
}
839
923
 
840
924
int ha_archive::unpack_row(azio_stream *file_to_read, unsigned char *record)
852
936
  }
853
937
 
854
938
  /* Copy null bits */
855
 
  memcpy(record, ptr, getTable()->getNullBytes());
856
 
  ptr+= getTable()->getNullBytes();
857
 
  for (Field **field= getTable()->getFields() ; *field ; field++)
 
939
  memcpy(record, ptr, table->getNullBytes());
 
940
  ptr+= table->getNullBytes();
 
941
  for (Field **field=table->field ; *field ; field++)
858
942
  {
859
943
    if (!((*field)->is_null()))
860
944
    {
861
 
      ptr= (*field)->unpack(record + (*field)->offset(getTable()->getInsertRecord()), ptr);
 
945
      ptr= (*field)->unpack(record + (*field)->offset(table->record[0]), ptr);
862
946
    }
863
947
  }
864
948
  return(0);
889
973
    return(HA_ERR_END_OF_FILE);
890
974
  scan_rows--;
891
975
 
892
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
 
976
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
893
977
  current_position= aztell(&archive);
894
978
  rc= get_row(&archive, buf);
895
979
 
896
 
  getTable()->status=rc ? STATUS_NOT_FOUND: 0;
 
980
  table->status=rc ? STATUS_NOT_FOUND: 0;
897
981
 
898
982
  return(rc);
899
983
}
900
984
 
901
985
 
902
986
/*
903
 
  Thanks to the table bool is_ordered this will be called after
 
987
  Thanks to the table flag HA_REC_NOT_IN_SEQ this will be called after
904
988
  each call to ha_archive::rnd_next() if an ordering of the rows is
905
989
  needed.
906
990
*/
907
991
 
908
992
void ha_archive::position(const unsigned char *)
909
993
{
910
 
  internal::my_store_ptr(ref, ref_length, current_position);
 
994
  my_store_ptr(ref, ref_length, current_position);
911
995
  return;
912
996
}
913
997
 
921
1005
 
922
1006
int ha_archive::rnd_pos(unsigned char * buf, unsigned char *pos)
923
1007
{
924
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
925
 
  current_position= (internal::my_off_t)internal::my_get_ptr(pos, ref_length);
 
1008
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
 
1009
  current_position= (my_off_t)my_get_ptr(pos, ref_length);
926
1010
  if (azseek(&archive, (size_t)current_position, SEEK_SET) == (size_t)(-1L))
927
1011
    return(HA_ERR_CRASHED_ON_USAGE);
928
1012
  return(get_row(&archive, buf));
933
1017
  rewriting the meta file. Currently it does this by calling optimize with
934
1018
  the extended flag.
935
1019
*/
936
 
int ha_archive::repair()
 
1020
int ha_archive::repair(Session* session, HA_CHECK_OPT* check_opt)
937
1021
{
938
 
  int rc= optimize();
 
1022
  check_opt->flags= T_EXTEND;
 
1023
  int rc= optimize(session, check_opt);
939
1024
 
940
1025
  if (rc)
941
1026
    return(HA_ERR_CRASHED_ON_REPAIR);
948
1033
  The table can become fragmented if data was inserted, read, and then
949
1034
  inserted again. What we do is open up the file and recompress it completely.
950
1035
*/
951
 
int ha_archive::optimize()
 
1036
int ha_archive::optimize(Session *, HA_CHECK_OPT *)
952
1037
{
953
1038
  int rc= 0;
954
 
  boost::scoped_ptr<azio_stream> writer(new azio_stream);
 
1039
  azio_stream writer;
 
1040
  char writer_filename[FN_REFLEN];
955
1041
 
956
1042
  init_archive_reader();
957
1043
 
962
1048
    share->archive_write_open= false;
963
1049
  }
964
1050
 
965
 
  char* proto_string;
966
 
  proto_string= (char*)malloc(sizeof(char) * archive.frm_length);
967
 
  if (proto_string == NULL)
968
 
  {
969
 
    return ENOMEM;
970
 
  }
971
 
  azread_frm(&archive, proto_string);
972
 
 
973
1051
  /* Lets create a file to contain the new data */
974
 
  std::string writer_filename= share->table_name;
975
 
  writer_filename.append(ARN);
 
1052
  fn_format(writer_filename, share->table_name.c_str(), "", ARN,
 
1053
            MY_REPLACE_EXT | MY_UNPACK_FILENAME);
976
1054
 
977
 
  if (!(azopen(writer.get(), writer_filename.c_str(), O_CREAT|O_RDWR, AZ_METHOD_BLOCK)))
978
 
  {
979
 
    free(proto_string);
 
1055
  if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR, AZ_METHOD_BLOCK)))
980
1056
    return(HA_ERR_CRASHED_ON_USAGE);
981
 
  }
982
 
 
983
 
  azwrite_frm(writer.get(), proto_string, archive.frm_length);
984
1057
 
985
1058
  /*
986
1059
    An extended rebuild is a lot more effort. We open up each row and re-record it.
1004
1077
    */
1005
1078
    if (!rc)
1006
1079
    {
 
1080
      uint64_t x;
1007
1081
      uint64_t rows_restored;
1008
1082
      share->rows_recorded= 0;
1009
1083
      stats.auto_increment_value= 1;
1011
1085
 
1012
1086
      rows_restored= archive.rows;
1013
1087
 
1014
 
      for (uint64_t x= 0; x < rows_restored ; x++)
 
1088
      for (x= 0; x < rows_restored ; x++)
1015
1089
      {
1016
 
        rc= get_row(&archive, getTable()->getInsertRecord());
 
1090
        rc= get_row(&archive, table->record[0]);
1017
1091
 
1018
1092
        if (rc != 0)
1019
1093
          break;
1020
1094
 
1021
 
        real_write_row(getTable()->getInsertRecord(), writer.get());
 
1095
        real_write_row(table->record[0], &writer);
1022
1096
        /*
1023
1097
          Long term it should be possible to optimize this so that
1024
1098
          it is not called on each row.
1025
1099
        */
1026
 
        if (getTable()->found_next_number_field)
 
1100
        if (table->found_next_number_field)
1027
1101
        {
1028
 
          Field *field= getTable()->found_next_number_field;
1029
 
 
1030
 
          /* Since we will need to use field to translate, we need to flip its read bit */
1031
 
          field->setReadSet();
1032
 
 
 
1102
          Field *field= table->found_next_number_field;
1033
1103
          uint64_t auto_value=
1034
 
            (uint64_t) field->val_int_internal(getTable()->getInsertRecord() +
1035
 
                                               field->offset(getTable()->getInsertRecord()));
 
1104
            (uint64_t) field->val_int(table->record[0] +
 
1105
                                       field->offset(table->record[0]));
1036
1106
          if (share->archive_write.auto_increment < auto_value)
1037
1107
            stats.auto_increment_value=
1038
1108
              (share->archive_write.auto_increment= auto_value) + 1;
1039
1109
        }
1040
1110
      }
1041
 
      share->rows_recorded= (ha_rows)writer->rows;
 
1111
      share->rows_recorded= (ha_rows)writer.rows;
1042
1112
    }
1043
1113
 
1044
1114
    if (rc && rc != HA_ERR_END_OF_FILE)
1047
1117
    }
1048
1118
  }
1049
1119
 
1050
 
  azclose(writer.get());
 
1120
  azclose(&writer);
1051
1121
  share->dirty= false;
1052
1122
 
1053
1123
  azclose(&archive);
1054
1124
 
1055
1125
  // make the file we just wrote be our data file
1056
 
  rc = internal::my_rename(writer_filename.c_str(), share->data_file_name.c_str(), MYF(0));
1057
 
 
1058
 
  free(proto_string);
 
1126
  rc = my_rename(writer_filename,share->data_file_name,MYF(0));
 
1127
 
 
1128
 
1059
1129
  return(rc);
1060
1130
error:
1061
 
  free(proto_string);
1062
 
  azclose(writer.get());
 
1131
  azclose(&writer);
1063
1132
 
1064
1133
  return(rc);
1065
1134
}
1106
1175
  return to;
1107
1176
}
1108
1177
 
 
1178
void ha_archive::update_create_info(HA_CREATE_INFO *create_info)
 
1179
{
 
1180
  ha_archive::info(HA_STATUS_AUTO);
 
1181
  if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
 
1182
  {
 
1183
    create_info->auto_increment_value= stats.auto_increment_value;
 
1184
  }
 
1185
 
 
1186
  if (!(my_readlink(share->real_path, share->data_file_name, MYF(0))))
 
1187
    create_info->data_file_name= share->real_path;
 
1188
 
 
1189
  return;
 
1190
}
 
1191
 
 
1192
 
1109
1193
/*
1110
1194
  Hints for optimizer, see ha_tina for more information
1111
1195
*/
1115
1199
    If dirty, we lock, and then reset/flush the data.
1116
1200
    I found that just calling azflush() doesn't always work.
1117
1201
  */
1118
 
  pthread_mutex_lock(&share->mutex());
 
1202
  pthread_mutex_lock(&share->mutex);
1119
1203
  if (share->dirty == true)
1120
1204
  {
1121
1205
    azflush(&(share->archive_write), Z_SYNC_FLUSH);
1134
1218
    cause the number to be inaccurate.
1135
1219
  */
1136
1220
  stats.records= share->rows_recorded;
1137
 
  pthread_mutex_unlock(&share->mutex());
 
1221
  pthread_mutex_unlock(&share->mutex);
1138
1222
 
1139
1223
  scan_rows= stats.records;
1140
1224
  stats.deleted= 0;
1144
1228
  {
1145
1229
    struct stat file_stat;  // Stat information for the data file
1146
1230
 
1147
 
    stat(share->data_file_name.c_str(), &file_stat);
 
1231
    stat(share->data_file_name, &file_stat);
1148
1232
 
1149
 
    stats.mean_rec_length= getTable()->getRecordLength()+ buffer.alloced_length();
 
1233
    stats.mean_rec_length= table->getRecordLength()+ buffer.alloced_length();
1150
1234
    stats.data_file_length= file_stat.st_size;
1151
1235
    stats.create_time= file_stat.st_ctime;
1152
1236
    stats.update_time= file_stat.st_mtime;
1158
1242
  if (flag & HA_STATUS_AUTO)
1159
1243
  {
1160
1244
    init_archive_reader();
1161
 
    pthread_mutex_lock(&share->mutex());
 
1245
    pthread_mutex_lock(&share->mutex);
1162
1246
    azflush(&archive, Z_SYNC_FLUSH);
1163
 
    pthread_mutex_unlock(&share->mutex());
 
1247
    pthread_mutex_unlock(&share->mutex);
1164
1248
    stats.auto_increment_value= archive.auto_increment + 1;
1165
1249
  }
1166
1250
 
1170
1254
 
1171
1255
/*
1172
1256
  This method tells us that a bulk insert operation is about to occur. We set
1173
 
  a flag which will keep doInsertRecord from saying that its data is dirty. This in
 
1257
  a flag which will keep write_row from saying that its data is dirty. This in
1174
1258
  turn will keep selects from causing a sync to occur.
1175
1259
  Basically, yet another optimizations to keep compression working well.
1176
1260
*/
1204
1288
}
1205
1289
 
1206
1290
/*
 
1291
  We just return state if asked.
 
1292
*/
 
1293
bool ha_archive::is_crashed() const
 
1294
{
 
1295
  return(share->crashed);
 
1296
}
 
1297
 
 
1298
/*
1207
1299
  Simple scan of the tables to make sure everything is ok.
1208
1300
*/
1209
1301
 
1210
 
int ha_archive::check(Session* session)
 
1302
int ha_archive::check(Session* session, HA_CHECK_OPT *)
1211
1303
{
1212
1304
  int rc= 0;
1213
1305
  const char *old_proc_info;
 
1306
  uint64_t x;
1214
1307
 
1215
1308
  old_proc_info= get_session_proc_info(session);
1216
1309
  set_session_proc_info(session, "Checking table");
1217
1310
  /* Flush any waiting data */
1218
 
  pthread_mutex_lock(&share->mutex());
 
1311
  pthread_mutex_lock(&share->mutex);
1219
1312
  azflush(&(share->archive_write), Z_SYNC_FLUSH);
1220
 
  pthread_mutex_unlock(&share->mutex());
 
1313
  pthread_mutex_unlock(&share->mutex);
1221
1314
 
1222
1315
  /*
1223
1316
    Now we will rewind the archive file so that we are positioned at the
1226
1319
  init_archive_reader();
1227
1320
  azflush(&archive, Z_SYNC_FLUSH);
1228
1321
  read_data_header(&archive);
1229
 
  for (uint64_t x= 0; x < share->archive_write.rows; x++)
 
1322
  for (x= 0; x < share->archive_write.rows; x++)
1230
1323
  {
1231
 
    rc= get_row(&archive, getTable()->getInsertRecord());
 
1324
    rc= get_row(&archive, table->record[0]);
1232
1325
 
1233
1326
    if (rc != 0)
1234
1327
      break;
1247
1340
  }
1248
1341
}
1249
1342
 
1250
 
int ArchiveEngine::doRenameTable(Session&, const TableIdentifier &from, const TableIdentifier &to)
1251
 
{
1252
 
  int error= 0;
1253
 
 
1254
 
  for (const char **ext= bas_ext(); *ext ; ext++)
1255
 
  {
1256
 
    if (rename_file_ext(from.getPath().c_str(), to.getPath().c_str(), *ext))
1257
 
    {
1258
 
      if ((error=errno) != ENOENT)
1259
 
        break;
1260
 
      error= 0;
1261
 
    }
1262
 
  }
1263
 
 
1264
 
  return error;
1265
 
}
1266
 
 
1267
 
bool ArchiveEngine::doDoesTableExist(Session&,
1268
 
                                     const TableIdentifier &identifier)
1269
 
{
1270
 
  string proto_path(identifier.getPath());
1271
 
  proto_path.append(ARZ);
1272
 
 
1273
 
  if (access(proto_path.c_str(), F_OK))
1274
 
  {
1275
 
    return false;
1276
 
  }
1277
 
 
1278
 
  return true;
1279
 
}
1280
 
 
1281
 
void ArchiveEngine::doGetTableIdentifiers(drizzled::CachedDirectory &directory,
1282
 
                                          const drizzled::SchemaIdentifier &schema_identifier,
1283
 
                                          drizzled::TableIdentifier::vector &set_of_identifiers)
1284
 
{
1285
 
  drizzled::CachedDirectory::Entries entries= directory.getEntries();
1286
 
 
1287
 
  for (drizzled::CachedDirectory::Entries::iterator entry_iter= entries.begin(); 
1288
 
       entry_iter != entries.end(); ++entry_iter)
1289
 
  {
1290
 
    drizzled::CachedDirectory::Entry *entry= *entry_iter;
1291
 
    const string *filename= &entry->filename;
1292
 
 
1293
 
    assert(filename->size());
1294
 
 
1295
 
    const char *ext= strchr(filename->c_str(), '.');
1296
 
 
1297
 
    if (ext == NULL || my_strcasecmp(system_charset_info, ext, ARZ) ||
1298
 
        (filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
1299
 
    {  }
1300
 
    else
1301
 
    {
1302
 
      char uname[NAME_LEN + 1];
1303
 
      uint32_t file_name_len;
1304
 
 
1305
 
      file_name_len= TableIdentifier::filename_to_tablename(filename->c_str(), uname, sizeof(uname));
1306
 
      // TODO: Remove need for memory copy here
1307
 
      uname[file_name_len - sizeof(ARZ) + 1]= '\0'; // Subtract ending, place NULL 
1308
 
 
1309
 
      set_of_identifiers.push_back(TableIdentifier(schema_identifier, uname));
1310
 
    }
1311
 
  }
1312
 
}
 
1343
/*
 
1344
  Check and repair the table if needed.
 
1345
*/
 
1346
bool ha_archive::check_and_repair(Session *session)
 
1347
{
 
1348
  HA_CHECK_OPT check_opt;
 
1349
 
 
1350
  check_opt.init();
 
1351
 
 
1352
  return(repair(session, &check_opt));
 
1353
}
 
1354
 
 
1355
archive_record_buffer *ha_archive::create_record_buffer(unsigned int length)
 
1356
{
 
1357
  archive_record_buffer *r;
 
1358
  if (!(r= (archive_record_buffer*) malloc(sizeof(archive_record_buffer))))
 
1359
  {
 
1360
    return(NULL); /* purecov: inspected */
 
1361
  }
 
1362
  r->length= (int)length;
 
1363
 
 
1364
  if (!(r->buffer= (unsigned char*) malloc(r->length)))
 
1365
  {
 
1366
    free((char*) r);
 
1367
    return(NULL); /* purecov: inspected */
 
1368
  }
 
1369
 
 
1370
  return(r);
 
1371
}
 
1372
 
 
1373
void ha_archive::destroy_record_buffer(archive_record_buffer *r)
 
1374
{
 
1375
  free((char*) r->buffer);
 
1376
  free((char*) r);
 
1377
  return;
 
1378
}
 
1379
 
 
1380
static DRIZZLE_SYSVAR_BOOL(aio, archive_use_aio,
 
1381
  PLUGIN_VAR_NOCMDOPT,
 
1382
  "Whether or not to use asynchronous IO.",
 
1383
  NULL, NULL, true);
 
1384
 
 
1385
static struct st_mysql_sys_var* archive_system_variables[]= {
 
1386
  DRIZZLE_SYSVAR(aio),
 
1387
  NULL
 
1388
};
 
1389
 
 
1390
drizzle_declare_plugin(archive)
 
1391
{
 
1392
  "ARCHIVE",
 
1393
  "3.5",
 
1394
  "Brian Aker, MySQL AB",
 
1395
  "Archive storage engine",
 
1396
  PLUGIN_LICENSE_GPL,
 
1397
  archive_db_init, /* Plugin Init */
 
1398
  archive_db_done, /* Plugin Deinit */
 
1399
  NULL,                       /* status variables                */
 
1400
  archive_system_variables,   /* system variables                */
 
1401
  NULL                        /* config options                  */
 
1402
}
 
1403
drizzle_declare_plugin_end;
 
1404