~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/archive/ha_archive.cc

  • Committer: Brian Aker
  • Date: 2009-06-03 19:30:45 UTC
  • mfrom: (1046.1.6 merge)
  • Revision ID: brian@gaz-20090603193045-4xgeczyfixh07beg
MergeĀ forĀ Brian

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
class ArchiveEngine : public StorageEngine
 
129
{
 
130
public:
 
131
  ArchiveEngine(const string &name_arg) : StorageEngine(name_arg) {}
 
132
  virtual handler *create(TableShare *table,
 
133
                          MEM_ROOT *mem_root)
 
134
  {
 
135
    return new (mem_root) ha_archive(this, table);
 
136
  }
 
137
};
 
138
 
 
139
static ArchiveEngine *archive_engine= NULL;
 
140
 
 
141
/*
 
142
  Initialize the archive handler.
 
143
 
 
144
  SYNOPSIS
 
145
    archive_db_init()
 
146
    void *
 
147
 
 
148
  RETURN
 
149
    false       OK
 
150
    true        Error
 
151
*/
 
152
 
 
153
int archive_db_init(PluginRegistry &registry)
 
154
{
 
155
 
 
156
  pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST);
 
157
  archive_engine= new ArchiveEngine(engine_name);
 
158
  registry.add(archive_engine);
 
159
 
 
160
  /* When the engine starts up set the first version */
 
161
  global_version= 1;
 
162
 
 
163
  return false;
 
164
}
 
165
 
 
166
/*
 
167
  Release the archive handler.
 
168
 
 
169
  SYNOPSIS
 
170
    archive_db_done()
 
171
    void
 
172
 
 
173
  RETURN
 
174
    false       OK
 
175
*/
 
176
 
 
177
int archive_db_done(PluginRegistry &registry)
 
178
{
 
179
  registry.remove(archive_engine);
 
180
  delete archive_engine;
 
181
 
 
182
  pthread_mutex_destroy(&archive_mutex);
 
183
 
 
184
  return 0;
 
185
}
 
186
 
 
187
 
 
188
ha_archive::ha_archive(StorageEngine *engine_arg, TableShare *table_arg)
 
189
  :handler(engine_arg, table_arg), delayed_insert(0), bulk_insert(0)
203
190
{
204
191
  /* Set our original buffer from pre-allocated memory */
205
192
  buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info);
206
193
 
207
194
  /* The size of the offset value we will use for position() */
208
 
  ref_length= sizeof(internal::my_off_t);
 
195
  ref_length= sizeof(my_off_t);
209
196
  archive_reader_open= false;
210
197
}
211
198
 
236
223
{
237
224
  memset(&archive_write, 0, sizeof(azio_stream));     /* Archive file we are working with */
238
225
  table_name.append(name);
239
 
  data_file_name.assign(table_name);
240
 
  data_file_name.append(ARZ);
 
226
  fn_format(data_file_name, table_name.c_str(), "",
 
227
            ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
241
228
  /*
242
229
    We will use this lock for rows.
243
230
  */
244
 
  pthread_mutex_init(&_mutex,MY_MUTEX_INIT_FAST);
 
231
  pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST);
245
232
}
246
233
 
247
234
ArchiveShare::~ArchiveShare()
248
235
{
249
 
  _lock.deinit();
250
 
  pthread_mutex_destroy(&_mutex);
 
236
  thr_lock_delete(&lock);
 
237
  pthread_mutex_destroy(&mutex);
251
238
  /*
252
239
    We need to make sure we don't reset the crashed state.
253
240
    If we open a crashed file, wee need to close it as crashed unless
261
248
 
262
249
bool ArchiveShare::prime(uint64_t *auto_increment)
263
250
{
264
 
  boost::scoped_ptr<azio_stream> archive_tmp(new azio_stream);
 
251
  azio_stream archive_tmp;
265
252
 
266
253
  /*
267
254
    We read the meta file, but do not mark it dirty. Since we are not
269
256
    anything but reading... open it for write and we will generate null
270
257
    compression writes).
271
258
  */
272
 
  if (!(azopen(archive_tmp.get(), data_file_name.c_str(), O_RDONLY,
 
259
  if (!(azopen(&archive_tmp, data_file_name, O_RDONLY,
273
260
               AZ_METHOD_BLOCK)))
274
261
    return false;
275
262
 
276
 
  *auto_increment= archive_tmp->auto_increment + 1;
277
 
  rows_recorded= (ha_rows)archive_tmp->rows;
278
 
  crashed= archive_tmp->dirty;
 
263
  *auto_increment= archive_tmp.auto_increment + 1;
 
264
  rows_recorded= (ha_rows)archive_tmp.rows;
 
265
  crashed= archive_tmp.dirty;
279
266
  if (version < global_version)
280
267
  {
281
268
    version_rows= rows_recorded;
282
269
    version= global_version;
283
270
  }
284
 
  azclose(archive_tmp.get());
 
271
  azclose(&archive_tmp);
285
272
 
286
273
  return true;
287
274
}
296
283
*/
297
284
ArchiveShare *ha_archive::get_share(const char *table_name, int *rc)
298
285
{
299
 
  ArchiveEngine *a_engine= static_cast<ArchiveEngine *>(getEngine());
300
 
 
301
 
  pthread_mutex_lock(&a_engine->mutex());
302
 
 
303
 
  share= a_engine->findOpenTable(table_name);
 
286
  uint32_t length;
 
287
  map<const char *, ArchiveShare *> ::iterator find_iter;
 
288
 
 
289
  pthread_mutex_lock(&archive_mutex);
 
290
  length=(uint) strlen(table_name);
 
291
 
 
292
  find_iter= archive_open_tables.find(table_name);
 
293
 
 
294
  if (find_iter != archive_open_tables.end())
 
295
    share= (*find_iter).second;
 
296
  else
 
297
    share= NULL;
304
298
 
305
299
  if (!share)
306
300
  {
308
302
 
309
303
    if (share == NULL)
310
304
    {
311
 
      pthread_mutex_unlock(&a_engine->mutex());
 
305
      pthread_mutex_unlock(&archive_mutex);
312
306
      *rc= HA_ERR_OUT_OF_MEM;
313
307
      return(NULL);
314
308
    }
315
309
 
316
310
    if (share->prime(&stats.auto_increment_value) == false)
317
311
    {
318
 
      pthread_mutex_unlock(&a_engine->mutex());
 
312
      pthread_mutex_unlock(&archive_mutex);
319
313
      *rc= HA_ERR_CRASHED_ON_REPAIR;
320
314
      delete share;
321
315
 
322
316
      return NULL;
323
317
    }
324
318
 
325
 
    a_engine->addOpenTable(share->table_name, share);
326
 
    thr_lock_init(&share->_lock);
 
319
    archive_open_tables[share->table_name.c_str()]= share; 
 
320
    thr_lock_init(&share->lock);
327
321
  }
328
322
  share->use_count++;
329
 
 
330
323
  if (share->crashed)
331
324
    *rc= HA_ERR_CRASHED_ON_USAGE;
332
 
  pthread_mutex_unlock(&a_engine->mutex());
 
325
  pthread_mutex_unlock(&archive_mutex);
333
326
 
334
327
  return(share);
335
328
}
341
334
*/
342
335
int ha_archive::free_share()
343
336
{
344
 
  ArchiveEngine *a_engine= static_cast<ArchiveEngine *>(getEngine());
345
 
 
346
 
  pthread_mutex_lock(&a_engine->mutex());
 
337
  pthread_mutex_lock(&archive_mutex);
347
338
  if (!--share->use_count)
348
339
  {
349
 
    a_engine->deleteOpenTable(share->table_name);
 
340
    archive_open_tables.erase(share->table_name.c_str());
350
341
    delete share;
351
342
  }
352
 
  pthread_mutex_unlock(&a_engine->mutex());
 
343
  pthread_mutex_unlock(&archive_mutex);
353
344
 
354
345
  return 0;
355
346
}
361
352
    a gzip file that can be both read and written we keep a writer open
362
353
    that is shared amoung all open tables.
363
354
  */
364
 
  if (!(azopen(&(share->archive_write), share->data_file_name.c_str(),
 
355
  if (!(azopen(&(share->archive_write), share->data_file_name,
365
356
               O_RDWR, AZ_METHOD_BLOCK)))
366
357
  {
367
358
    share->crashed= true;
374
365
 
375
366
 
376
367
/*
377
 
  No locks are required because it is associated with just one Cursor instance
 
368
  No locks are required because it is associated with just one handler instance
378
369
*/
379
370
int ha_archive::init_archive_reader()
380
371
{
387
378
  {
388
379
    az_method method;
389
380
 
390
 
    if (archive_aio_state())
 
381
    switch (archive_use_aio)
391
382
    {
 
383
    case false:
 
384
      method= AZ_METHOD_BLOCK;
 
385
      break;
 
386
    case true:
392
387
      method= AZ_METHOD_AIO;
393
 
    }
394
 
    else
395
 
    {
 
388
      break;
 
389
    default:
396
390
      method= AZ_METHOD_BLOCK;
397
391
    }
398
 
    if (!(azopen(&archive, share->data_file_name.c_str(), O_RDONLY,
 
392
    if (!(azopen(&archive, share->data_file_name, O_RDONLY,
399
393
                 method)))
400
394
    {
401
395
      share->crashed= true;
407
401
  return(0);
408
402
}
409
403
 
 
404
 
 
405
/*
 
406
  We just implement one additional file extension.
 
407
*/
 
408
static const char *ha_archive_exts[] = {
 
409
  ARZ,
 
410
  NULL
 
411
};
 
412
 
 
413
const char **ha_archive::bas_ext() const
 
414
{
 
415
  return ha_archive_exts;
 
416
}
 
417
 
 
418
 
410
419
/*
411
420
  When opening a file we:
412
421
  Create/get our shared structure.
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 ha_archive::create(const char *name, Table *table_arg,
 
510
                       HA_CREATE_INFO *create_info)
504
511
{
 
512
  char name_buff[FN_REFLEN];
 
513
  char linkname[FN_REFLEN];
505
514
  int error= 0;
506
 
  boost::scoped_ptr<azio_stream> create_stream(new azio_stream);
507
 
  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++)
 
515
  azio_stream create_stream;            /* Archive file we are working with */
 
516
  FILE *frm_file;                   /* File handler for readers */
 
517
  struct stat file_stat;
 
518
  unsigned char *frm_ptr;
 
519
  int r;
 
520
 
 
521
  stats.auto_increment_value= create_info->auto_increment_value;
 
522
 
 
523
  for (uint32_t key= 0; key < table_arg->sizeKeys(); key++)
513
524
  {
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;
 
525
    KEY *pos= table_arg->key_info+key;
 
526
    KEY_PART_INFO *key_part=     pos->key_part;
 
527
    KEY_PART_INFO *key_part_end= key_part + pos->key_parts;
517
528
 
518
529
    for (; key_part != key_part_end; key_part++)
519
530
    {
521
532
 
522
533
      if (!(field->flags & AUTO_INCREMENT_FLAG))
523
534
      {
524
 
        return -1;
 
535
        error= -1;
 
536
        goto error;
525
537
      }
526
538
    }
527
539
  }
528
540
 
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)
 
541
  /*
 
542
    We reuse name_buff since it is available.
 
543
  */
 
544
  if (create_info->data_file_name && create_info->data_file_name[0] != '#')
 
545
  {
 
546
    fn_format(name_buff, create_info->data_file_name, "", ARZ,
 
547
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
548
    fn_format(linkname, name, "", ARZ,
 
549
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
550
  }
 
551
  else
 
552
  {
 
553
    fn_format(name_buff, name, "", ARZ,
 
554
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
555
    linkname[0]= 0;
 
556
  }
 
557
 
 
558
  /*
 
559
    There is a chance that the file was "discovered". In this case
 
560
    just use whatever file is there.
 
561
  */
 
562
  r= stat(name_buff, &file_stat);
 
563
  if (r == -1 && errno!=ENOENT)
 
564
  {
 
565
    return errno;
 
566
  }
 
567
  if (!r)
 
568
    return HA_ERR_TABLE_EXIST;
 
569
 
 
570
  my_errno= 0;
 
571
  if (!(azopen(&create_stream, name_buff, O_CREAT|O_RDWR,
 
572
               AZ_METHOD_BLOCK)))
535
573
  {
536
574
    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)
 
575
    goto error2;
 
576
  }
 
577
 
 
578
  if (linkname[0])
 
579
    my_symlink(name_buff, linkname, MYF(0));
 
580
  fn_format(name_buff, name, "", ".frm",
 
581
            MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
582
 
 
583
  /*
 
584
    Here is where we open up the frm and pass it to archive to store
 
585
  */
 
586
  if ((frm_file= fopen(name_buff, "r")) > 0)
 
587
  {
 
588
    if (fstat(fileno(frm_file), &file_stat))
569
589
    {
570
 
      error= errno;
571
 
      unlink(named_file.c_str());
572
 
 
573
 
      return(error ? error : -1);
 
590
      if ((uint64_t)file_stat.st_size > SIZE_MAX)
 
591
      {
 
592
        error= ENOMEM;
 
593
        goto error2;
 
594
      }
 
595
      frm_ptr= (unsigned char *)malloc((size_t)file_stat.st_size);
 
596
      if (frm_ptr)
 
597
      {
 
598
        size_t length_io;
 
599
        length_io= read(fileno(frm_file), frm_ptr, (size_t)file_stat.st_size);
 
600
 
 
601
        if (length_io != (size_t)file_stat.st_size)
 
602
        {
 
603
          free(frm_ptr);
 
604
          goto error2;
 
605
        }
 
606
 
 
607
        length_io= azwrite_frm(&create_stream, (char *)frm_ptr, (size_t)file_stat.st_size);
 
608
 
 
609
        if (length_io != (size_t)file_stat.st_size)
 
610
        {
 
611
          free(frm_ptr);
 
612
          goto error2;
 
613
        }
 
614
 
 
615
        free(frm_ptr);
 
616
      }
574
617
    }
 
618
    fclose(frm_file);
 
619
  }
 
620
 
 
621
  if (create_info->comment.str)
 
622
  {
 
623
    size_t write_length;
 
624
 
 
625
    write_length= azwrite_comment(&create_stream, create_info->comment.str,
 
626
                                  (unsigned int)create_info->comment.length);
 
627
 
 
628
    if (write_length == (size_t)create_info->comment.length)
 
629
      goto error2;
575
630
  }
576
631
 
577
632
  /*
578
633
    Yes you need to do this, because the starting value
579
634
    for the autoincrement may not be zero.
580
635
  */
581
 
  create_stream->auto_increment= auto_increment_value ?
582
 
    auto_increment_value - 1 : 0;
583
 
 
584
 
  if (azclose(create_stream.get()))
 
636
  create_stream.auto_increment= stats.auto_increment_value ?
 
637
    stats.auto_increment_value - 1 : 0;
 
638
  if (azclose(&create_stream))
585
639
  {
586
640
    error= errno;
587
 
    unlink(named_file.c_str());
588
 
 
589
 
    return(error ? error : -1);
 
641
    goto error2;
590
642
  }
591
643
 
592
644
  return(0);
 
645
 
 
646
error2:
 
647
  delete_table(name);
 
648
error:
 
649
  /* Return error number, if we got one */
 
650
  return(error ? error : -1);
593
651
}
594
652
 
595
653
/*
603
661
  /* We pack the row for writing */
604
662
  r_pack_length= pack_row(buf);
605
663
 
606
 
  written= azwrite_row(writer, &record_buffer[0], r_pack_length);
 
664
  written= azwrite_row(writer, record_buffer->buffer, r_pack_length);
607
665
  if (written != r_pack_length)
608
666
  {
609
667
    return(-1);
623
681
 
624
682
uint32_t ha_archive::max_row_length(const unsigned char *)
625
683
{
626
 
  uint32_t length= (uint32_t)(getTable()->getRecordLength() + getTable()->sizeFields()*2);
 
684
  uint32_t length= (uint32_t)(table->getRecordLength() + table->sizeFields()*2);
627
685
  length+= ARCHIVE_ROW_HEADER_SIZE;
628
686
 
629
687
  uint32_t *ptr, *end;
630
 
  for (ptr= getTable()->getBlobField(), end=ptr + getTable()->sizeBlobFields();
 
688
  for (ptr= table->getBlobField(), end=ptr + table->sizeBlobFields();
631
689
       ptr != end ;
632
690
       ptr++)
633
691
  {
634
 
      length += 2 + ((Field_blob*)getTable()->getField(*ptr))->get_length();
 
692
      length += 2 + ((Field_blob*)table->field[*ptr])->get_length();
635
693
  }
636
694
 
637
695
  return length;
643
701
  unsigned char *ptr;
644
702
 
645
703
  if (fix_rec_buff(max_row_length(record)))
646
 
    return(HA_ERR_OUT_OF_MEM);
 
704
    return(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
647
705
 
648
706
  /* Copy null bits */
649
 
  memcpy(&record_buffer[0], record, getTable()->getShare()->null_bytes);
650
 
  ptr= &record_buffer[0] + getTable()->getShare()->null_bytes;
 
707
  memcpy(record_buffer->buffer, record, table->s->null_bytes);
 
708
  ptr= record_buffer->buffer + table->s->null_bytes;
651
709
 
652
 
  for (Field **field=getTable()->getFields() ; *field ; field++)
 
710
  for (Field **field=table->field ; *field ; field++)
653
711
  {
654
712
    if (!((*field)->is_null()))
655
713
      ptr= (*field)->pack(ptr, record + (*field)->offset(record));
656
714
  }
657
715
 
658
 
  return((unsigned int) (ptr - &record_buffer[0]));
 
716
  return((unsigned int) (ptr - record_buffer->buffer));
659
717
}
660
718
 
661
719
 
668
726
  for implementing start_bulk_insert() is that we could skip
669
727
  setting dirty to true each time.
670
728
*/
671
 
int ha_archive::doInsertRecord(unsigned char *buf)
 
729
int ha_archive::write_row(unsigned char *buf)
672
730
{
673
731
  int rc;
674
732
  unsigned char *read_buf= NULL;
675
733
  uint64_t temp_auto;
676
 
  unsigned char *record=  getTable()->getInsertRecord();
 
734
  unsigned char *record=  table->record[0];
677
735
 
678
736
  if (share->crashed)
679
737
    return(HA_ERR_CRASHED_ON_USAGE);
680
738
 
681
 
  pthread_mutex_lock(&share->mutex());
 
739
  ha_statistic_increment(&SSV::ha_write_count);
 
740
  pthread_mutex_lock(&share->mutex);
682
741
 
683
742
  if (share->archive_write_open == false)
684
743
    if (init_archive_writer())
685
744
      return(HA_ERR_CRASHED_ON_USAGE);
686
745
 
687
746
 
688
 
  if (getTable()->next_number_field && record == getTable()->getInsertRecord())
 
747
  if (table->next_number_field && record == table->record[0])
689
748
  {
 
749
    KEY *mkey= &table->s->key_info[0]; // We only support one key right now
690
750
    update_auto_increment();
691
 
    temp_auto= getTable()->next_number_field->val_int();
 
751
    temp_auto= table->next_number_field->val_int();
692
752
 
693
753
    /*
694
754
      We don't support decremening auto_increment. They make the performance
695
755
      just cry.
696
756
    */
697
757
    if (temp_auto <= share->archive_write.auto_increment &&
698
 
        getTable()->getShare()->getKeyInfo(0).flags & HA_NOSAME)
 
758
        mkey->flags & HA_NOSAME)
699
759
    {
700
760
      rc= HA_ERR_FOUND_DUPP_KEY;
701
761
      goto error;
715
775
  share->rows_recorded++;
716
776
  rc= real_write_row(buf,  &(share->archive_write));
717
777
error:
718
 
  pthread_mutex_unlock(&share->mutex());
 
778
  pthread_mutex_unlock(&share->mutex);
719
779
  if (read_buf)
720
780
    free((unsigned char*) read_buf);
721
781
 
730
790
  *first_value= share->archive_write.auto_increment + 1;
731
791
}
732
792
 
733
 
/* Initialized at each key walk (called multiple times unlike doStartTableScan()) */
734
 
int ha_archive::doStartIndexScan(uint32_t keynr, bool)
 
793
/* Initialized at each key walk (called multiple times unlike rnd_init()) */
 
794
int ha_archive::index_init(uint32_t keynr, bool)
735
795
{
736
796
  active_index= keynr;
737
797
  return(0);
743
803
  the optimizer that we have unique indexes, we scan
744
804
*/
745
805
int ha_archive::index_read(unsigned char *buf, const unsigned char *key,
746
 
                             uint32_t key_len, enum ha_rkey_function)
 
806
                             uint32_t key_len, enum ha_rkey_function find_flag)
 
807
{
 
808
  int rc;
 
809
  rc= index_read_idx(buf, active_index, key, key_len, find_flag);
 
810
  return(rc);
 
811
}
 
812
 
 
813
 
 
814
int ha_archive::index_read_idx(unsigned char *buf, uint32_t index, const unsigned char *key,
 
815
                               uint32_t key_len, enum ha_rkey_function)
747
816
{
748
817
  int rc;
749
818
  bool found= 0;
750
 
  current_k_offset= getTable()->getShare()->getKeyInfo(0).key_part->offset;
 
819
  KEY *mkey= &table->s->key_info[index];
 
820
  current_k_offset= mkey->key_part->offset;
751
821
  current_key= key;
752
822
  current_key_len= key_len;
753
823
 
754
 
  rc= doStartTableScan(true);
 
824
  rc= rnd_init(true);
755
825
 
756
826
  if (rc)
757
827
    goto error;
795
865
  we assume the position will be set.
796
866
*/
797
867
 
798
 
int ha_archive::doStartTableScan(bool scan)
 
868
int ha_archive::rnd_init(bool scan)
799
869
{
800
870
  if (share->crashed)
801
871
      return(HA_ERR_CRASHED_ON_USAGE);
832
902
/* Reallocate buffer if needed */
833
903
bool ha_archive::fix_rec_buff(unsigned int length)
834
904
{
835
 
  record_buffer.resize(length);
836
 
 
837
 
  return false;
 
905
  assert(record_buffer->buffer);
 
906
 
 
907
  if (length > record_buffer->length)
 
908
  {
 
909
    unsigned char *newptr;
 
910
    if (!(newptr= (unsigned char *)realloc(record_buffer->buffer, length)))
 
911
      return(1);
 
912
    record_buffer->buffer= newptr;
 
913
    record_buffer->length= length;
 
914
  }
 
915
 
 
916
  assert(length <= record_buffer->length);
 
917
 
 
918
  return(0);
838
919
}
839
920
 
840
921
int ha_archive::unpack_row(azio_stream *file_to_read, unsigned char *record)
852
933
  }
853
934
 
854
935
  /* Copy null bits */
855
 
  memcpy(record, ptr, getTable()->getNullBytes());
856
 
  ptr+= getTable()->getNullBytes();
857
 
  for (Field **field= getTable()->getFields() ; *field ; field++)
 
936
  memcpy(record, ptr, table->getNullBytes());
 
937
  ptr+= table->getNullBytes();
 
938
  for (Field **field=table->field ; *field ; field++)
858
939
  {
859
940
    if (!((*field)->is_null()))
860
941
    {
861
 
      ptr= (*field)->unpack(record + (*field)->offset(getTable()->getInsertRecord()), ptr);
 
942
      ptr= (*field)->unpack(record + (*field)->offset(table->record[0]), ptr);
862
943
    }
863
944
  }
864
945
  return(0);
889
970
    return(HA_ERR_END_OF_FILE);
890
971
  scan_rows--;
891
972
 
892
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
 
973
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
893
974
  current_position= aztell(&archive);
894
975
  rc= get_row(&archive, buf);
895
976
 
896
 
  getTable()->status=rc ? STATUS_NOT_FOUND: 0;
 
977
  table->status=rc ? STATUS_NOT_FOUND: 0;
897
978
 
898
979
  return(rc);
899
980
}
900
981
 
901
982
 
902
983
/*
903
 
  Thanks to the table bool is_ordered this will be called after
 
984
  Thanks to the table flag HA_REC_NOT_IN_SEQ this will be called after
904
985
  each call to ha_archive::rnd_next() if an ordering of the rows is
905
986
  needed.
906
987
*/
907
988
 
908
989
void ha_archive::position(const unsigned char *)
909
990
{
910
 
  internal::my_store_ptr(ref, ref_length, current_position);
 
991
  my_store_ptr(ref, ref_length, current_position);
911
992
  return;
912
993
}
913
994
 
921
1002
 
922
1003
int ha_archive::rnd_pos(unsigned char * buf, unsigned char *pos)
923
1004
{
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);
 
1005
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
 
1006
  current_position= (my_off_t)my_get_ptr(pos, ref_length);
926
1007
  if (azseek(&archive, (size_t)current_position, SEEK_SET) == (size_t)(-1L))
927
1008
    return(HA_ERR_CRASHED_ON_USAGE);
928
1009
  return(get_row(&archive, buf));
933
1014
  rewriting the meta file. Currently it does this by calling optimize with
934
1015
  the extended flag.
935
1016
*/
936
 
int ha_archive::repair()
 
1017
int ha_archive::repair(Session* session, HA_CHECK_OPT* check_opt)
937
1018
{
938
 
  int rc= optimize();
 
1019
  check_opt->flags= T_EXTEND;
 
1020
  int rc= optimize(session, check_opt);
939
1021
 
940
1022
  if (rc)
941
1023
    return(HA_ERR_CRASHED_ON_REPAIR);
948
1030
  The table can become fragmented if data was inserted, read, and then
949
1031
  inserted again. What we do is open up the file and recompress it completely.
950
1032
*/
951
 
int ha_archive::optimize()
 
1033
int ha_archive::optimize(Session *, HA_CHECK_OPT *)
952
1034
{
953
1035
  int rc= 0;
954
 
  boost::scoped_ptr<azio_stream> writer(new azio_stream);
 
1036
  azio_stream writer;
 
1037
  char writer_filename[FN_REFLEN];
955
1038
 
956
1039
  init_archive_reader();
957
1040
 
962
1045
    share->archive_write_open= false;
963
1046
  }
964
1047
 
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
1048
  /* Lets create a file to contain the new data */
974
 
  std::string writer_filename= share->table_name;
975
 
  writer_filename.append(ARN);
 
1049
  fn_format(writer_filename, share->table_name.c_str(), "", ARN,
 
1050
            MY_REPLACE_EXT | MY_UNPACK_FILENAME);
976
1051
 
977
 
  if (!(azopen(writer.get(), writer_filename.c_str(), O_CREAT|O_RDWR, AZ_METHOD_BLOCK)))
978
 
  {
979
 
    free(proto_string);
 
1052
  if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR, AZ_METHOD_BLOCK)))
980
1053
    return(HA_ERR_CRASHED_ON_USAGE);
981
 
  }
982
 
 
983
 
  azwrite_frm(writer.get(), proto_string, archive.frm_length);
984
1054
 
985
1055
  /*
986
1056
    An extended rebuild is a lot more effort. We open up each row and re-record it.
1004
1074
    */
1005
1075
    if (!rc)
1006
1076
    {
 
1077
      uint64_t x;
1007
1078
      uint64_t rows_restored;
1008
1079
      share->rows_recorded= 0;
1009
1080
      stats.auto_increment_value= 1;
1011
1082
 
1012
1083
      rows_restored= archive.rows;
1013
1084
 
1014
 
      for (uint64_t x= 0; x < rows_restored ; x++)
 
1085
      for (x= 0; x < rows_restored ; x++)
1015
1086
      {
1016
 
        rc= get_row(&archive, getTable()->getInsertRecord());
 
1087
        rc= get_row(&archive, table->record[0]);
1017
1088
 
1018
1089
        if (rc != 0)
1019
1090
          break;
1020
1091
 
1021
 
        real_write_row(getTable()->getInsertRecord(), writer.get());
 
1092
        real_write_row(table->record[0], &writer);
1022
1093
        /*
1023
1094
          Long term it should be possible to optimize this so that
1024
1095
          it is not called on each row.
1025
1096
        */
1026
 
        if (getTable()->found_next_number_field)
 
1097
        if (table->found_next_number_field)
1027
1098
        {
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
 
 
 
1099
          Field *field= table->found_next_number_field;
1033
1100
          uint64_t auto_value=
1034
 
            (uint64_t) field->val_int_internal(getTable()->getInsertRecord() +
1035
 
                                               field->offset(getTable()->getInsertRecord()));
 
1101
            (uint64_t) field->val_int(table->record[0] +
 
1102
                                       field->offset(table->record[0]));
1036
1103
          if (share->archive_write.auto_increment < auto_value)
1037
1104
            stats.auto_increment_value=
1038
1105
              (share->archive_write.auto_increment= auto_value) + 1;
1039
1106
        }
1040
1107
      }
1041
 
      share->rows_recorded= (ha_rows)writer->rows;
 
1108
      share->rows_recorded= (ha_rows)writer.rows;
1042
1109
    }
1043
1110
 
1044
1111
    if (rc && rc != HA_ERR_END_OF_FILE)
1047
1114
    }
1048
1115
  }
1049
1116
 
1050
 
  azclose(writer.get());
 
1117
  azclose(&writer);
1051
1118
  share->dirty= false;
1052
1119
 
1053
1120
  azclose(&archive);
1054
1121
 
1055
1122
  // 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);
 
1123
  rc = my_rename(writer_filename,share->data_file_name,MYF(0));
 
1124
 
 
1125
 
1059
1126
  return(rc);
1060
1127
error:
1061
 
  free(proto_string);
1062
 
  azclose(writer.get());
 
1128
  azclose(&writer);
1063
1129
 
1064
1130
  return(rc);
1065
1131
}
1083
1149
    */
1084
1150
 
1085
1151
    if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
1086
 
         lock_type <= TL_WRITE)
 
1152
         lock_type <= TL_WRITE) && !session_in_lock_tables(session)
1087
1153
        && !session_tablespace_op(session))
1088
1154
      lock_type = TL_WRITE_ALLOW_WRITE;
1089
1155
 
1095
1161
      concurrent inserts to t2.
1096
1162
    */
1097
1163
 
1098
 
    if (lock_type == TL_READ_NO_INSERT)
 
1164
    if (lock_type == TL_READ_NO_INSERT && !session_in_lock_tables(session))
1099
1165
      lock_type = TL_READ;
1100
1166
 
1101
1167
    lock.type=lock_type;
1106
1172
  return to;
1107
1173
}
1108
1174
 
 
1175
void ha_archive::update_create_info(HA_CREATE_INFO *create_info)
 
1176
{
 
1177
  ha_archive::info(HA_STATUS_AUTO);
 
1178
  if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
 
1179
  {
 
1180
    create_info->auto_increment_value= stats.auto_increment_value;
 
1181
  }
 
1182
 
 
1183
  if (!(my_readlink(share->real_path, share->data_file_name, MYF(0))))
 
1184
    create_info->data_file_name= share->real_path;
 
1185
 
 
1186
  return;
 
1187
}
 
1188
 
 
1189
 
1109
1190
/*
1110
1191
  Hints for optimizer, see ha_tina for more information
1111
1192
*/
1115
1196
    If dirty, we lock, and then reset/flush the data.
1116
1197
    I found that just calling azflush() doesn't always work.
1117
1198
  */
1118
 
  pthread_mutex_lock(&share->mutex());
 
1199
  pthread_mutex_lock(&share->mutex);
1119
1200
  if (share->dirty == true)
1120
1201
  {
1121
1202
    azflush(&(share->archive_write), Z_SYNC_FLUSH);
1134
1215
    cause the number to be inaccurate.
1135
1216
  */
1136
1217
  stats.records= share->rows_recorded;
1137
 
  pthread_mutex_unlock(&share->mutex());
 
1218
  pthread_mutex_unlock(&share->mutex);
1138
1219
 
1139
1220
  scan_rows= stats.records;
1140
1221
  stats.deleted= 0;
1144
1225
  {
1145
1226
    struct stat file_stat;  // Stat information for the data file
1146
1227
 
1147
 
    stat(share->data_file_name.c_str(), &file_stat);
 
1228
    stat(share->data_file_name, &file_stat);
1148
1229
 
1149
 
    stats.mean_rec_length= getTable()->getRecordLength()+ buffer.alloced_length();
 
1230
    stats.mean_rec_length= table->getRecordLength()+ buffer.alloced_length();
1150
1231
    stats.data_file_length= file_stat.st_size;
1151
1232
    stats.create_time= file_stat.st_ctime;
1152
1233
    stats.update_time= file_stat.st_mtime;
1158
1239
  if (flag & HA_STATUS_AUTO)
1159
1240
  {
1160
1241
    init_archive_reader();
1161
 
    pthread_mutex_lock(&share->mutex());
 
1242
    pthread_mutex_lock(&share->mutex);
1162
1243
    azflush(&archive, Z_SYNC_FLUSH);
1163
 
    pthread_mutex_unlock(&share->mutex());
 
1244
    pthread_mutex_unlock(&share->mutex);
1164
1245
    stats.auto_increment_value= archive.auto_increment + 1;
1165
1246
  }
1166
1247
 
1170
1251
 
1171
1252
/*
1172
1253
  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
 
1254
  a flag which will keep write_row from saying that its data is dirty. This in
1174
1255
  turn will keep selects from causing a sync to occur.
1175
1256
  Basically, yet another optimizations to keep compression working well.
1176
1257
*/
1204
1285
}
1205
1286
 
1206
1287
/*
 
1288
  We just return state if asked.
 
1289
*/
 
1290
bool ha_archive::is_crashed() const
 
1291
{
 
1292
  return(share->crashed);
 
1293
}
 
1294
 
 
1295
/*
1207
1296
  Simple scan of the tables to make sure everything is ok.
1208
1297
*/
1209
1298
 
1210
 
int ha_archive::check(Session* session)
 
1299
int ha_archive::check(Session* session, HA_CHECK_OPT *)
1211
1300
{
1212
1301
  int rc= 0;
1213
1302
  const char *old_proc_info;
 
1303
  uint64_t x;
1214
1304
 
1215
1305
  old_proc_info= get_session_proc_info(session);
1216
1306
  set_session_proc_info(session, "Checking table");
1217
1307
  /* Flush any waiting data */
1218
 
  pthread_mutex_lock(&share->mutex());
 
1308
  pthread_mutex_lock(&share->mutex);
1219
1309
  azflush(&(share->archive_write), Z_SYNC_FLUSH);
1220
 
  pthread_mutex_unlock(&share->mutex());
 
1310
  pthread_mutex_unlock(&share->mutex);
1221
1311
 
1222
1312
  /*
1223
1313
    Now we will rewind the archive file so that we are positioned at the
1226
1316
  init_archive_reader();
1227
1317
  azflush(&archive, Z_SYNC_FLUSH);
1228
1318
  read_data_header(&archive);
1229
 
  for (uint64_t x= 0; x < share->archive_write.rows; x++)
 
1319
  for (x= 0; x < share->archive_write.rows; x++)
1230
1320
  {
1231
 
    rc= get_row(&archive, getTable()->getInsertRecord());
 
1321
    rc= get_row(&archive, table->record[0]);
1232
1322
 
1233
1323
    if (rc != 0)
1234
1324
      break;
1247
1337
  }
1248
1338
}
1249
1339
 
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
 
}
 
1340
/*
 
1341
  Check and repair the table if needed.
 
1342
*/
 
1343
bool ha_archive::check_and_repair(Session *session)
 
1344
{
 
1345
  HA_CHECK_OPT check_opt;
 
1346
 
 
1347
  check_opt.init();
 
1348
 
 
1349
  return(repair(session, &check_opt));
 
1350
}
 
1351
 
 
1352
archive_record_buffer *ha_archive::create_record_buffer(unsigned int length)
 
1353
{
 
1354
  archive_record_buffer *r;
 
1355
  if (!(r= (archive_record_buffer*) malloc(sizeof(archive_record_buffer))))
 
1356
  {
 
1357
    return(NULL); /* purecov: inspected */
 
1358
  }
 
1359
  r->length= (int)length;
 
1360
 
 
1361
  if (!(r->buffer= (unsigned char*) malloc(r->length)))
 
1362
  {
 
1363
    free((char*) r);
 
1364
    return(NULL); /* purecov: inspected */
 
1365
  }
 
1366
 
 
1367
  return(r);
 
1368
}
 
1369
 
 
1370
void ha_archive::destroy_record_buffer(archive_record_buffer *r)
 
1371
{
 
1372
  free((char*) r->buffer);
 
1373
  free((char*) r);
 
1374
  return;
 
1375
}
 
1376
 
 
1377
static DRIZZLE_SYSVAR_BOOL(aio, archive_use_aio,
 
1378
  PLUGIN_VAR_NOCMDOPT,
 
1379
  "Whether or not to use asynchronous IO.",
 
1380
  NULL, NULL, true);
 
1381
 
 
1382
static struct st_mysql_sys_var* archive_system_variables[]= {
 
1383
  DRIZZLE_SYSVAR(aio),
 
1384
  NULL
 
1385
};
 
1386
 
 
1387
drizzle_declare_plugin(archive)
 
1388
{
 
1389
  "ARCHIVE",
 
1390
  "3.5",
 
1391
  "Brian Aker, MySQL AB",
 
1392
  "Archive storage engine",
 
1393
  PLUGIN_LICENSE_GPL,
 
1394
  archive_db_init, /* Plugin Init */
 
1395
  archive_db_done, /* Plugin Deinit */
 
1396
  NULL,                       /* status variables                */
 
1397
  archive_system_variables,   /* system variables                */
 
1398
  NULL                        /* config options                  */
 
1399
}
 
1400
drizzle_declare_plugin_end;
 
1401