~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/archive/ha_archive.cc

  • Committer: Brian Aker
  • Date: 2008-10-06 06:47:29 UTC
  • Revision ID: brian@tangent.org-20081006064729-2i9mhjkzyvow9xsm
RemoveĀ uint.

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
16
19
 
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>
 
20
#include <drizzled/common_includes.h>
 
21
#include <storage/myisam/myisam.h>
25
22
 
26
23
#include "ha_archive.h"
27
24
 
28
 
#include <stdio.h>
29
 
#include <string>
30
 
#include <map>
31
 
 
32
 
using namespace std;
33
 
 
34
 
static const string engine_name("ARCHIVE");
35
 
 
36
25
/*
37
 
  First, if you want to understand storage engines you should look at
38
 
  ha_example.cc and ha_example.h.
 
26
  First, if you want to understand storage engines you should look at 
 
27
  ha_example.cc and ha_example.h. 
39
28
 
40
29
  This example was written as a test case for a customer who needed
41
30
  a storage engine without indexes that could compress data very well.
42
31
  So, welcome to a completely compressed storage engine. This storage
43
 
  engine only does inserts. No replace, deletes, or updates. All reads are
 
32
  engine only does inserts. No replace, deletes, or updates. All reads are 
44
33
  complete table scans. Compression is done through a combination of packing
45
34
  and making use of the zlib library
46
 
 
 
35
  
47
36
  We keep a file pointer open for each instance of ha_archive for each read
48
37
  but for writes we keep one open file handle just for that. We flush it
49
38
  only if we have a read occur. azip handles compressing lots of records
53
42
  the same time since we would want to flush).
54
43
 
55
44
  A "meta" file is kept alongside the data file. This file serves two purpose.
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
 
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 
62
51
  this point an error occurs and the user is told to rebuild the file.
63
52
  A rebuild scans the rows and rewrites the meta file. If corruption is found
64
53
  in the data file then the meta file is not repaired.
65
54
 
66
55
  At some point a recovery method for such a drastic case needs to be divised.
67
56
 
68
 
  Locks are row level, and you will get a consistant read.
 
57
  Locks are row level, and you will get a consistant read. 
69
58
 
70
59
  For performance as far as table scans go it is quite fast. I don't have
71
60
  good numbers but locally it has out performed both Innodb and MyISAM. For
72
61
  Innodb the question will be if the table can be fit into the buffer
73
62
  pool. For MyISAM its a question of how much the file system caches the
74
63
  MyISAM file. With enough free memory MyISAM is faster. Its only when the OS
75
 
  doesn't have enough memory to cache entire table that archive turns out
76
 
  to be any faster.
 
64
  doesn't have enough memory to cache entire table that archive turns out 
 
65
  to be any faster. 
77
66
 
78
67
  Examples between MyISAM (packed) and Archive.
79
68
 
102
91
*/
103
92
 
104
93
/* Variables for archive share methods */
105
 
pthread_mutex_t archive_mutex= PTHREAD_MUTEX_INITIALIZER;
106
 
 
107
 
std::map<const char *, ArchiveShare *> archive_open_tables;
108
 
 
 
94
pthread_mutex_t archive_mutex;
 
95
static HASH archive_open_tables;
109
96
static unsigned int global_version;
110
97
 
111
98
/* The file extension */
112
99
#define ARZ ".ARZ"               // The data file
113
100
#define ARN ".ARN"               // Files used during an optimize call
114
 
 
115
 
 
 
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);
116
117
 
117
118
static bool archive_use_aio= false;
118
119
 
126
127
*/
127
128
#define ARCHIVE_ROW_HEADER_SIZE 4
128
129
 
 
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
 
129
137
/*
130
 
  We just implement one additional file extension.
 
138
  Used for hash table that tracks open tables.
131
139
*/
132
 
static const char *ha_archive_exts[] = {
133
 
  ARZ,
134
 
  NULL
135
 
};
136
 
 
137
 
class ArchiveTableNameIterator: public drizzled::plugin::TableNameIteratorImplementation
138
 
{
139
 
private:
140
 
  MY_DIR *dirp;
141
 
  uint32_t current_entry;
142
 
 
143
 
public:
144
 
  ArchiveTableNameIterator(const std::string &database)
145
 
    : drizzled::plugin::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 drizzled::plugin::StorageEngine
218
 
{
219
 
public:
220
 
  ArchiveEngine(const string &name_arg)
221
 
   : drizzled::plugin::StorageEngine(name_arg,
222
 
                                     HTON_FILE_BASED
223
 
                                      | HTON_HAS_DATA_DICTIONARY) {}
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
 
  drizzled::plugin::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;
 
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
 
290
147
 
291
148
/*
292
149
  Initialize the archive handler.
300
157
    true        Error
301
158
*/
302
159
 
303
 
static int archive_db_init(drizzled::plugin::Registry &registry)
 
160
int archive_db_init(void *p)
304
161
{
 
162
  handlerton *archive_hton;
305
163
 
306
 
  pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST);
307
 
  archive_engine= new ArchiveEngine(engine_name);
308
 
  registry.add(archive_engine);
 
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;
309
169
 
310
170
  /* When the engine starts up set the first version */
311
171
  global_version= 1;
312
172
 
313
 
  return false;
 
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);
314
186
}
315
187
 
316
188
/*
324
196
    false       OK
325
197
*/
326
198
 
327
 
static int archive_db_done(drizzled::plugin::Registry &registry)
 
199
int archive_db_done(void *p __attribute__((unused)))
328
200
{
329
 
  registry.remove(archive_engine);
330
 
  delete archive_engine;
331
 
 
 
201
  hash_free(&archive_open_tables);
332
202
  pthread_mutex_destroy(&archive_mutex);
333
203
 
334
204
  return 0;
335
205
}
336
206
 
337
207
 
338
 
ha_archive::ha_archive(drizzled::plugin::StorageEngine *engine_arg,
339
 
                       TableShare *table_arg)
340
 
  :handler(engine_arg, table_arg), delayed_insert(0), bulk_insert(0)
 
208
ha_archive::ha_archive(handlerton *hton, TABLE_SHARE *table_arg)
 
209
  :handler(hton, table_arg), delayed_insert(0), bulk_insert(0)
341
210
{
342
211
  /* Set our original buffer from pre-allocated memory */
343
212
  buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info);
347
216
  archive_reader_open= false;
348
217
}
349
218
 
 
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
 
350
259
/*
351
260
  This method reads the header of a datafile and returns whether or not it was successful.
352
261
*/
361
270
  return(1);
362
271
}
363
272
 
364
 
ArchiveShare::ArchiveShare():
365
 
  use_count(0), archive_write_open(false), dirty(false), crashed(false),
366
 
  mean_rec_length(0), version(0), rows_recorded(0), version_rows(0)
367
 
{
368
 
  assert(1);
369
 
}
370
 
 
371
 
ArchiveShare::ArchiveShare(const char *name):
372
 
  use_count(0), archive_write_open(false), dirty(false), crashed(false),
373
 
  mean_rec_length(0), version(0), rows_recorded(0), version_rows(0)
374
 
{
375
 
  memset(&archive_write, 0, sizeof(azio_stream));     /* Archive file we are working with */
376
 
  table_name.append(name);
377
 
  fn_format(data_file_name, table_name.c_str(), "",
378
 
            ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
379
 
  /*
380
 
    We will use this lock for rows.
381
 
  */
382
 
  pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST);
383
 
}
384
 
 
385
 
ArchiveShare::~ArchiveShare()
386
 
{
387
 
  thr_lock_delete(&lock);
388
 
  pthread_mutex_destroy(&mutex);
389
 
  /*
390
 
    We need to make sure we don't reset the crashed state.
391
 
    If we open a crashed file, wee need to close it as crashed unless
392
 
    it has been repaired.
393
 
    Since we will close the data down after this, we go on and count
394
 
    the flush on close;
395
 
  */
396
 
  if (archive_write_open == true)
397
 
    (void)azclose(&archive_write);
398
 
}
399
 
 
400
 
bool ArchiveShare::prime(uint64_t *auto_increment)
401
 
{
402
 
  azio_stream archive_tmp;
403
 
 
404
 
  /*
405
 
    We read the meta file, but do not mark it dirty. Since we are not
406
 
    doing a write we won't mark it dirty (and we won't open it for
407
 
    anything but reading... open it for write and we will generate null
408
 
    compression writes).
409
 
  */
410
 
  if (!(azopen(&archive_tmp, data_file_name, O_RDONLY,
411
 
               AZ_METHOD_BLOCK)))
412
 
    return false;
413
 
 
414
 
  *auto_increment= archive_tmp.auto_increment + 1;
415
 
  rows_recorded= (ha_rows)archive_tmp.rows;
416
 
  crashed= archive_tmp.dirty;
417
 
  if (version < global_version)
418
 
  {
419
 
    version_rows= rows_recorded;
420
 
    version= global_version;
421
 
  }
422
 
  azclose(&archive_tmp);
423
 
 
424
 
  return true;
425
 
}
426
 
 
427
273
 
428
274
/*
429
 
  We create the shared memory space that we will use for the open table.
 
275
  We create the shared memory space that we will use for the open table. 
430
276
  No matter what we try to get or create a share. This is so that a repair
431
 
  table operation can occur.
 
277
  table operation can occur. 
432
278
 
433
279
  See ha_example.cc for a longer description.
434
280
*/
435
 
ArchiveShare *ha_archive::get_share(const char *table_name, int *rc)
 
281
ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, int *rc)
436
282
{
437
283
  uint32_t length;
438
 
  map<const char *, ArchiveShare *> ::iterator find_iter;
439
284
 
440
285
  pthread_mutex_lock(&archive_mutex);
441
286
  length=(uint) strlen(table_name);
442
287
 
443
 
  find_iter= archive_open_tables.find(table_name);
444
 
 
445
 
  if (find_iter != archive_open_tables.end())
446
 
    share= (*find_iter).second;
447
 
  else
448
 
    share= NULL;
449
 
 
450
 
  if (!share)
 
288
  if (!(share=(ARCHIVE_SHARE*) hash_search(&archive_open_tables,
 
289
                                           (unsigned char*) table_name,
 
290
                                           length)))
451
291
  {
452
 
    share= new ArchiveShare(table_name);
 
292
    char *tmp_name;
 
293
    azio_stream archive_tmp;
453
294
 
454
 
    if (share == NULL)
 
295
    if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
 
296
                          &share, sizeof(*share),
 
297
                          &tmp_name, length+1,
 
298
                          NULL)) 
455
299
    {
456
300
      pthread_mutex_unlock(&archive_mutex);
457
301
      *rc= HA_ERR_OUT_OF_MEM;
458
302
      return(NULL);
459
303
    }
460
304
 
461
 
    if (share->prime(&stats.auto_increment_value) == false)
 
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)))
462
326
    {
 
327
      pthread_mutex_destroy(&share->mutex);
 
328
      free(share);
463
329
      pthread_mutex_unlock(&archive_mutex);
464
330
      *rc= HA_ERR_CRASHED_ON_REPAIR;
465
 
      delete share;
466
 
 
467
 
      return NULL;
468
 
    }
469
 
 
470
 
    archive_open_tables[share->table_name.c_str()]= share; 
 
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);
471
344
    thr_lock_init(&share->lock);
472
345
  }
473
346
  share->use_count++;
479
352
}
480
353
 
481
354
 
482
 
/*
 
355
/* 
483
356
  Free the share.
484
357
  See ha_example.cc for a description.
485
358
*/
486
359
int ha_archive::free_share()
487
360
{
 
361
  int rc= 0;
 
362
 
488
363
  pthread_mutex_lock(&archive_mutex);
489
364
  if (!--share->use_count)
490
365
  {
491
 
    archive_open_tables.erase(share->table_name.c_str());
492
 
    delete share;
 
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);
493
382
  }
494
383
  pthread_mutex_unlock(&archive_mutex);
495
384
 
496
 
  return 0;
 
385
  return(rc);
497
386
}
498
387
 
499
388
int ha_archive::init_archive_writer()
500
389
{
501
 
  /*
 
390
  /* 
502
391
    It is expensive to open and close the data files and since you can't have
503
392
    a gzip file that can be both read and written we keep a writer open
504
393
    that is shared amoung all open tables.
505
394
  */
506
 
  if (!(azopen(&(share->archive_write), share->data_file_name,
507
 
               O_RDWR, AZ_METHOD_BLOCK)))
 
395
  if (!(azopen(&(share->archive_write), share->data_file_name, 
 
396
               O_RDWR|O_BINARY, AZ_METHOD_BLOCK)))
508
397
  {
509
398
    share->crashed= true;
510
399
    return(1);
515
404
}
516
405
 
517
406
 
518
 
/*
 
407
/* 
519
408
  No locks are required because it is associated with just one handler instance
520
409
*/
521
410
int ha_archive::init_archive_reader()
522
411
{
523
 
  /*
 
412
  /* 
524
413
    It is expensive to open and close the data files and since you can't have
525
414
    a gzip file that can be both read and written we keep a writer open
526
415
    that is shared amoung all open tables.
540
429
    default:
541
430
      method= AZ_METHOD_BLOCK;
542
431
    }
543
 
    if (!(azopen(&archive, share->data_file_name, O_RDONLY,
 
432
    if (!(azopen(&archive, share->data_file_name, O_RDONLY|O_BINARY, 
544
433
                 method)))
545
434
    {
546
435
      share->crashed= true;
552
441
  return(0);
553
442
}
554
443
 
 
444
 
555
445
/*
 
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
/* 
556
460
  When opening a file we:
557
461
  Create/get our shared structure.
558
462
  Init out lock.
559
463
  We open the file we will read from.
560
464
*/
561
 
int ha_archive::open(const char *name, int, uint32_t open_options)
 
465
int ha_archive::open(const char *name,
 
466
                     int mode __attribute__((unused)),
 
467
                     uint32_t open_options)
562
468
{
563
469
  int rc= 0;
564
470
  share= get_share(name, &rc);
565
471
 
566
472
  if (rc == HA_ERR_CRASHED_ON_USAGE && !(open_options & HA_OPEN_FOR_REPAIR))
567
473
  {
 
474
    /* purecov: begin inspected */
568
475
    free_share();
569
476
    return(rc);
 
477
    /* purecov: end */    
570
478
  }
571
479
  else if (rc == HA_ERR_OUT_OF_MEM)
572
480
  {
575
483
 
576
484
  assert(share);
577
485
 
578
 
  record_buffer= create_record_buffer(table->s->reclength +
 
486
  record_buffer= create_record_buffer(table->s->reclength + 
579
487
                                      ARCHIVE_ROW_HEADER_SIZE);
580
488
 
581
489
  if (!record_buffer)
600
508
 
601
509
  SYNOPSIS
602
510
    close();
603
 
 
 
511
  
604
512
  IMPLEMENTATION:
605
513
 
606
514
  We first close this storage engines file handle to the archive and
632
540
 
633
541
 
634
542
/*
635
 
  We create our data file here. The format is pretty simple.
 
543
  We create our data file here. The format is pretty simple. 
636
544
  You can read about the format of the data file above.
637
 
  Unlike other storage engines we do not "pack" our data. Since we
638
 
  are about to do a general compression, packing would just be a waste of
639
 
  CPU time. If the table has blobs they are written after the row in the order
 
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 
640
548
  of creation.
641
549
*/
642
550
 
643
 
int ArchiveEngine::createTableImplementation(Session *session,
644
 
                                             const char *table_name,
645
 
                                             Table *table_arg,
646
 
                                             HA_CREATE_INFO *create_info,
647
 
                                             drizzled::message::Table *proto)
 
551
int ha_archive::create(const char *name, Table *table_arg,
 
552
                       HA_CREATE_INFO *create_info)
648
553
{
649
554
  char name_buff[FN_REFLEN];
650
 
  int error= 0;
 
555
  char linkname[FN_REFLEN];
 
556
  int error;
651
557
  azio_stream create_stream;            /* Archive file we are working with */
652
 
  uint64_t auto_increment_value;
653
 
  string serialized_proto;
 
558
  File frm_file;                   /* File handler for readers */
 
559
  struct stat file_stat;
 
560
  unsigned char *frm_ptr;
654
561
 
655
 
  auto_increment_value= create_info->auto_increment_value;
 
562
  stats.auto_increment_value= create_info->auto_increment_value;
656
563
 
657
564
  for (uint32_t key= 0; key < table_arg->sizeKeys(); key++)
658
565
  {
672
579
    }
673
580
  }
674
581
 
675
 
  /*
 
582
  /* 
676
583
    We reuse name_buff since it is available.
677
584
  */
678
 
  fn_format(name_buff, table_name, "", ARZ,
679
 
            MY_REPLACE_EXT | MY_UNPACK_FILENAME);
680
 
 
681
 
  my_errno= 0;
682
 
  if (azopen(&create_stream, name_buff, O_CREAT|O_RDWR,
683
 
             AZ_METHOD_BLOCK) == 0)
 
585
  if (create_info->data_file_name && create_info->data_file_name[0] != '#')
684
586
  {
685
 
    error= errno;
686
 
    goto error2;
 
587
    fn_format(name_buff, create_info->data_file_name, "", ARZ,
 
588
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
589
    fn_format(linkname, name, "", ARZ,
 
590
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
687
591
  }
688
 
 
689
 
  proto->SerializeToString(&serialized_proto);
690
 
 
691
 
  if (azwrite_frm(&create_stream, serialized_proto.c_str(),
692
 
                  serialized_proto.length()))
693
 
    goto error2;
694
 
 
695
 
  if (proto->options().has_comment())
 
592
  else
696
593
  {
697
 
    int write_length;
698
 
 
699
 
    write_length= azwrite_comment(&create_stream,
700
 
                                  proto->options().comment().c_str(),
701
 
                                  proto->options().comment().length());
702
 
 
703
 
    if (write_length < 0)
704
 
    {
705
 
      error= errno;
706
 
      goto error2;
707
 
    }
 
594
    fn_format(name_buff, name, "", ARZ,
 
595
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
 
596
    linkname[0]= 0;
708
597
  }
709
598
 
710
599
  /*
711
 
    Yes you need to do this, because the starting value
712
 
    for the autoincrement may not be zero.
 
600
    There is a chance that the file was "discovered". In this case
 
601
    just use whatever file is there.
713
602
  */
714
 
  create_stream.auto_increment= auto_increment_value ?
715
 
    auto_increment_value - 1 : 0;
716
 
 
717
 
  if (azclose(&create_stream))
 
603
  if (!stat(name_buff, &file_stat))
718
604
  {
719
 
    error= errno;
720
 
    goto error2;
 
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
    }
721
651
  }
 
652
  else
 
653
    my_errno= 0;
722
654
 
723
655
  return(0);
724
656
 
725
657
error2:
726
 
  deleteTable(session, table_name);
 
658
  delete_table(name);
727
659
error:
728
660
  /* Return error number, if we got one */
729
661
  return(error ? error : -1);
734
666
*/
735
667
int ha_archive::real_write_row(unsigned char *buf, azio_stream *writer)
736
668
{
737
 
  off_t written;
 
669
  my_off_t written;
738
670
  unsigned int r_pack_length;
739
671
 
740
672
  /* We pack the row for writing */
753
685
}
754
686
 
755
687
 
756
 
/*
 
688
/* 
757
689
  Calculate max length needed for row. This includes
758
690
  the bytes required for the length in the header.
759
691
*/
760
692
 
761
 
uint32_t ha_archive::max_row_length(const unsigned char *)
 
693
uint32_t ha_archive::max_row_length(const unsigned char *buf __attribute__((unused)))
762
694
{
763
695
  uint32_t length= (uint32_t)(table->getRecordLength() + table->sizeFields()*2);
764
696
  length+= ARCHIVE_ROW_HEADER_SIZE;
780
712
  unsigned char *ptr;
781
713
 
782
714
  if (fix_rec_buff(max_row_length(record)))
783
 
    return(HA_ERR_OUT_OF_MEM);
 
715
    return(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
784
716
 
785
717
  /* Copy null bits */
786
718
  memcpy(record_buffer->buffer, record, table->s->null_bytes);
796
728
}
797
729
 
798
730
 
799
 
/*
 
731
/* 
800
732
  Look at ha_archive::open() for an explanation of the row format.
801
733
  Here we just write out the row.
802
734
 
803
735
  Wondering about start_bulk_insert()? We don't implement it for
804
736
  archive since it optimizes for lots of writes. The only save
805
 
  for implementing start_bulk_insert() is that we could skip
 
737
  for implementing start_bulk_insert() is that we could skip 
806
738
  setting dirty to true each time.
807
739
*/
808
740
int ha_archive::write_row(unsigned char *buf)
816
748
    return(HA_ERR_CRASHED_ON_USAGE);
817
749
 
818
750
  ha_statistic_increment(&SSV::ha_write_count);
 
751
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
 
752
    table->timestamp_field->set_time();
819
753
  pthread_mutex_lock(&share->mutex);
820
754
 
821
755
  if (share->archive_write_open == false)
833
767
      We don't support decremening auto_increment. They make the performance
834
768
      just cry.
835
769
    */
836
 
    if (temp_auto <= share->archive_write.auto_increment &&
 
770
    if (temp_auto <= share->archive_write.auto_increment && 
837
771
        mkey->flags & HA_NOSAME)
838
772
    {
839
773
      rc= HA_ERR_FOUND_DUPP_KEY;
840
774
      goto error;
841
775
    }
 
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
842
821
    else
843
822
    {
844
823
      if (temp_auto > share->archive_write.auto_increment)
862
841
}
863
842
 
864
843
 
865
 
void ha_archive::get_auto_increment(uint64_t, uint64_t, uint64_t,
866
 
                                    uint64_t *first_value, uint64_t *nb_reserved_values)
 
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)))
867
849
{
868
850
  *nb_reserved_values= UINT64_MAX;
869
851
  *first_value= share->archive_write.auto_increment + 1;
870
852
}
871
853
 
872
854
/* Initialized at each key walk (called multiple times unlike rnd_init()) */
873
 
int ha_archive::index_init(uint32_t keynr, bool)
 
855
int ha_archive::index_init(uint32_t keynr, bool sorted __attribute__((unused)))
874
856
{
875
857
  active_index= keynr;
876
858
  return(0);
891
873
 
892
874
 
893
875
int ha_archive::index_read_idx(unsigned char *buf, uint32_t index, const unsigned char *key,
894
 
                               uint32_t key_len, enum ha_rkey_function)
 
876
                               uint32_t key_len,
 
877
                               enum ha_rkey_function find_flag __attribute__((unused)))
895
878
{
896
879
  int rc;
897
880
  bool found= 0;
922
905
}
923
906
 
924
907
 
925
 
int ha_archive::index_next(unsigned char * buf)
926
 
{
 
908
int ha_archive::index_next(unsigned char * buf) 
 
909
927
910
  bool found= 0;
928
911
 
929
912
  while (!(get_row(&archive, buf)))
935
918
    }
936
919
  }
937
920
 
938
 
  return(found ? 0 : HA_ERR_END_OF_FILE);
 
921
  return(found ? 0 : HA_ERR_END_OF_FILE); 
939
922
}
940
923
 
941
924
/*
963
946
 
964
947
 
965
948
/*
966
 
  This is the method that is used to read a row. It assumes that the row is
 
949
  This is the method that is used to read a row. It assumes that the row is 
967
950
  positioned where you want it.
968
951
*/
969
952
int ha_archive::get_row(azio_stream *file_to_read, unsigned char *buf)
986
969
  if (length > record_buffer->length)
987
970
  {
988
971
    unsigned char *newptr;
989
 
    if (!(newptr= (unsigned char *)realloc(record_buffer->buffer, length)))
 
972
    if (!(newptr=(unsigned char*) my_realloc((unsigned char*) record_buffer->buffer, 
 
973
                                    length,
 
974
                                    MYF(MY_ALLOW_ZERO_PTR))))
990
975
      return(1);
991
976
    record_buffer->buffer= newptr;
992
977
    record_buffer->length= length;
1033
1018
}
1034
1019
 
1035
1020
 
1036
 
/*
 
1021
/* 
1037
1022
  Called during ORDER BY. Its position is either from being called sequentially
1038
1023
  or by having had ha_archive::rnd_pos() called before it is called.
1039
1024
*/
1065
1050
  needed.
1066
1051
*/
1067
1052
 
1068
 
void ha_archive::position(const unsigned char *)
 
1053
void ha_archive::position(const unsigned char *record __attribute__((unused)))
1069
1054
{
1070
1055
  my_store_ptr(ref, ref_length, current_position);
1071
1056
  return;
1089
1074
}
1090
1075
 
1091
1076
/*
1092
 
  This method repairs the meta file. It does this by walking the datafile and
 
1077
  This method repairs the meta file. It does this by walking the datafile and 
1093
1078
  rewriting the meta file. Currently it does this by calling optimize with
1094
1079
  the extended flag.
1095
1080
*/
1096
 
int ha_archive::repair(Session* session, HA_CHECK_OPT* check_opt)
 
1081
int ha_archive::repair(THD* thd, HA_CHECK_OPT* check_opt)
1097
1082
{
1098
1083
  check_opt->flags= T_EXTEND;
1099
 
  int rc= optimize(session, check_opt);
 
1084
  int rc= optimize(thd, check_opt);
1100
1085
 
1101
1086
  if (rc)
1102
1087
    return(HA_ERR_CRASHED_ON_REPAIR);
1107
1092
 
1108
1093
/*
1109
1094
  The table can become fragmented if data was inserted, read, and then
1110
 
  inserted again. What we do is open up the file and recompress it completely.
 
1095
  inserted again. What we do is open up the file and recompress it completely. 
1111
1096
*/
1112
 
int ha_archive::optimize(Session *, HA_CHECK_OPT *)
 
1097
int ha_archive::optimize(THD* thd __attribute__((unused)),
 
1098
                         HA_CHECK_OPT* check_opt __attribute__((unused)))
1113
1099
{
1114
1100
  int rc= 0;
1115
1101
  azio_stream writer;
1124
1110
    share->archive_write_open= false;
1125
1111
  }
1126
1112
 
1127
 
  char* proto_string;
1128
 
  proto_string= (char*)malloc(sizeof(char) * archive.frm_length);
1129
 
  if (proto_string == NULL)
1130
 
  {
1131
 
    return ENOMEM;
1132
 
  }
1133
 
  azread_frm(&archive, proto_string);
1134
 
 
1135
1113
  /* Lets create a file to contain the new data */
1136
 
  fn_format(writer_filename, share->table_name.c_str(), "", ARN,
 
1114
  fn_format(writer_filename, share->table_name, "", ARN, 
1137
1115
            MY_REPLACE_EXT | MY_UNPACK_FILENAME);
1138
1116
 
1139
 
  if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR, AZ_METHOD_BLOCK)))
1140
 
  {
1141
 
    free(proto_string);
1142
 
    return(HA_ERR_CRASHED_ON_USAGE);
1143
 
  }
1144
 
 
1145
 
  azwrite_frm(&writer, proto_string, archive.frm_length);
1146
 
 
1147
 
  /*
1148
 
    An extended rebuild is a lot more effort. We open up each row and re-record it.
1149
 
    Any dead rows are removed (aka rows that may have been partially recorded).
 
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). 
1150
1123
 
1151
1124
    As of Archive format 3, this is the only type that is performed, before this
1152
1125
    version it was just done on T_EXTEND
1154
1127
  if (1)
1155
1128
  {
1156
1129
    /*
1157
 
      Now we will rewind the archive file so that we are positioned at the
 
1130
      Now we will rewind the archive file so that we are positioned at the 
1158
1131
      start of the file.
1159
1132
    */
1160
1133
    azflush(&archive, Z_SYNC_FLUSH);
1161
1134
    rc= read_data_header(&archive);
1162
1135
 
1163
 
    /*
 
1136
    /* 
1164
1137
      On success of writing out the new header, we now fetch each row and
1165
 
      insert it into the new archive file.
 
1138
      insert it into the new archive file. 
1166
1139
    */
1167
1140
    if (!rc)
1168
1141
    {
1189
1162
        if (table->found_next_number_field)
1190
1163
        {
1191
1164
          Field *field= table->found_next_number_field;
1192
 
 
1193
 
          /* Since we will need to use field to translate, we need to flip its read bit */
1194
 
          field->setReadSet();
1195
 
 
1196
1165
          uint64_t auto_value=
1197
1166
            (uint64_t) field->val_int(table->record[0] +
1198
1167
                                       field->offset(table->record[0]));
1208
1177
    {
1209
1178
      goto error;
1210
1179
    }
1211
 
  }
 
1180
  } 
1212
1181
 
1213
1182
  azclose(&writer);
1214
1183
  share->dirty= false;
1215
 
 
 
1184
  
1216
1185
  azclose(&archive);
1217
1186
 
1218
1187
  // make the file we just wrote be our data file
1219
1188
  rc = my_rename(writer_filename,share->data_file_name,MYF(0));
1220
1189
 
1221
 
  free(proto_string);
 
1190
 
1222
1191
  return(rc);
1223
1192
error:
1224
 
  free(proto_string);
1225
1193
  azclose(&writer);
1226
1194
 
1227
 
  return(rc);
 
1195
  return(rc); 
1228
1196
}
1229
1197
 
1230
 
/*
 
1198
/* 
1231
1199
  Below is an example of how to setup row level locking.
1232
1200
*/
1233
 
THR_LOCK_DATA **ha_archive::store_lock(Session *session,
 
1201
THR_LOCK_DATA **ha_archive::store_lock(THD *thd,
1234
1202
                                       THR_LOCK_DATA **to,
1235
1203
                                       enum thr_lock_type lock_type)
1236
1204
{
1237
 
  delayed_insert= false;
 
1205
  if (lock_type == TL_WRITE_DELAYED)
 
1206
    delayed_insert= true;
 
1207
  else
 
1208
    delayed_insert= false;
1238
1209
 
1239
 
  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
 
1210
  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) 
1240
1211
  {
1241
 
    /*
 
1212
    /* 
1242
1213
      Here is where we get into the guts of a row level lock.
1243
 
      If TL_UNLOCK is set
 
1214
      If TL_UNLOCK is set 
1244
1215
      If we are not doing a LOCK Table or DISCARD/IMPORT
1245
 
      TABLESPACE, then allow multiple writers
 
1216
      TABLESPACE, then allow multiple writers 
1246
1217
    */
1247
1218
 
1248
1219
    if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
1249
 
         lock_type <= TL_WRITE)
1250
 
        && !session_tablespace_op(session))
 
1220
         lock_type <= TL_WRITE) && !thd_in_lock_tables(thd)
 
1221
        && !thd_tablespace_op(thd))
1251
1222
      lock_type = TL_WRITE_ALLOW_WRITE;
1252
1223
 
1253
 
    /*
 
1224
    /* 
1254
1225
      In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
1255
1226
      MySQL would use the lock TL_READ_NO_INSERT on t2, and that
1256
1227
      would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
1257
1228
      to t2. Convert the lock to a normal read lock to allow
1258
 
      concurrent inserts to t2.
 
1229
      concurrent inserts to t2. 
1259
1230
    */
1260
1231
 
1261
 
    if (lock_type == TL_READ_NO_INSERT)
 
1232
    if (lock_type == TL_READ_NO_INSERT && !thd_in_lock_tables(thd)) 
1262
1233
      lock_type = TL_READ;
1263
1234
 
1264
1235
    lock.type=lock_type;
1269
1240
  return to;
1270
1241
}
1271
1242
 
 
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
 
1272
1258
/*
1273
1259
  Hints for optimizer, see ha_tina for more information
1274
1260
*/
1275
1261
int ha_archive::info(uint32_t flag)
1276
1262
{
1277
 
  /*
 
1263
  /* 
1278
1264
    If dirty, we lock, and then reset/flush the data.
1279
1265
    I found that just calling azflush() doesn't always work.
1280
1266
  */
1292
1278
 
1293
1279
  }
1294
1280
 
1295
 
  /*
 
1281
  /* 
1296
1282
    This should be an accurate number now, though bulk and delayed inserts can
1297
1283
    cause the number to be inaccurate.
1298
1284
  */
1345
1331
}
1346
1332
 
1347
1333
 
1348
 
/*
 
1334
/* 
1349
1335
  Other side of start_bulk_insert, is end_bulk_insert. Here we turn off the bulk insert
1350
1336
  flag, and set the share dirty so that the next select will call sync for us.
1351
1337
*/
1358
1344
 
1359
1345
/*
1360
1346
  We cancel a truncate command. The only way to delete an archive table is to drop it.
1361
 
  This is done for security reasons. In a later version we will enable this by
 
1347
  This is done for security reasons. In a later version we will enable this by 
1362
1348
  allowing the user to select a different row format.
1363
1349
*/
1364
1350
int ha_archive::delete_all_rows()
1369
1355
/*
1370
1356
  We just return state if asked.
1371
1357
*/
1372
 
bool ha_archive::is_crashed() const
 
1358
bool ha_archive::is_crashed() const 
1373
1359
{
1374
 
  return(share->crashed);
 
1360
  return(share->crashed); 
1375
1361
}
1376
1362
 
1377
1363
/*
1378
1364
  Simple scan of the tables to make sure everything is ok.
1379
1365
*/
1380
1366
 
1381
 
int ha_archive::check(Session* session, HA_CHECK_OPT *)
 
1367
int ha_archive::check(THD* thd,
 
1368
                      HA_CHECK_OPT* check_opt __attribute__((unused)))
1382
1369
{
1383
1370
  int rc= 0;
1384
1371
  const char *old_proc_info;
1385
1372
  uint64_t x;
1386
1373
 
1387
 
  old_proc_info= get_session_proc_info(session);
1388
 
  set_session_proc_info(session, "Checking table");
 
1374
  old_proc_info= thd_proc_info(thd, "Checking table");
1389
1375
  /* Flush any waiting data */
1390
1376
  pthread_mutex_lock(&share->mutex);
1391
1377
  azflush(&(share->archive_write), Z_SYNC_FLUSH);
1392
1378
  pthread_mutex_unlock(&share->mutex);
1393
1379
 
1394
1380
  /*
1395
 
    Now we will rewind the archive file so that we are positioned at the
 
1381
    Now we will rewind the archive file so that we are positioned at the 
1396
1382
    start of the file.
1397
1383
  */
1398
1384
  init_archive_reader();
1406
1392
      break;
1407
1393
  }
1408
1394
 
1409
 
  set_session_proc_info(session, old_proc_info);
 
1395
  thd_proc_info(thd, old_proc_info);
1410
1396
 
1411
 
  if ((rc && rc != HA_ERR_END_OF_FILE))
 
1397
  if ((rc && rc != HA_ERR_END_OF_FILE))  
1412
1398
  {
1413
1399
    share->crashed= false;
1414
1400
    return(HA_ADMIN_CORRUPT);
1419
1405
  }
1420
1406
}
1421
1407
 
1422
 
archive_record_buffer *ha_archive::create_record_buffer(unsigned int length)
 
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) 
1423
1421
{
1424
1422
  archive_record_buffer *r;
1425
 
  if (!(r= (archive_record_buffer*) malloc(sizeof(archive_record_buffer))))
 
1423
  if (!(r= 
 
1424
        (archive_record_buffer*) my_malloc(sizeof(archive_record_buffer),
 
1425
                                           MYF(MY_WME))))
1426
1426
  {
1427
 
    return(NULL);
 
1427
    return(NULL); /* purecov: inspected */
1428
1428
  }
1429
1429
  r->length= (int)length;
1430
1430
 
1431
 
  if (!(r->buffer= (unsigned char*) malloc(r->length)))
 
1431
  if (!(r->buffer= (unsigned char*) my_malloc(r->length,
 
1432
                                    MYF(MY_WME))))
1432
1433
  {
1433
1434
    free((char*) r);
1434
 
    return(NULL);
 
1435
    return(NULL); /* purecov: inspected */
1435
1436
  }
1436
1437
 
1437
1438
  return(r);
1438
1439
}
1439
1440
 
1440
 
void ha_archive::destroy_record_buffer(archive_record_buffer *r)
 
1441
void ha_archive::destroy_record_buffer(archive_record_buffer *r) 
1441
1442
{
1442
1443
  free((char*) r->buffer);
1443
1444
  free((char*) r);
1454
1455
  NULL
1455
1456
};
1456
1457
 
1457
 
drizzle_declare_plugin(archive)
 
1458
mysql_declare_plugin(archive)
1458
1459
{
 
1460
  DRIZZLE_STORAGE_ENGINE_PLUGIN,
1459
1461
  "ARCHIVE",
1460
1462
  "3.5",
1461
1463
  "Brian Aker, MySQL AB",
1467
1469
  archive_system_variables,   /* system variables                */
1468
1470
  NULL                        /* config options                  */
1469
1471
}
1470
 
drizzle_declare_plugin_end;
 
1472
mysql_declare_plugin_end;
1471
1473