~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2003 MySQL AB
2
3
  This program is free software; you can redistribute it and/or modify
4
  it under the terms of the GNU General Public License as published by
5
  the Free Software Foundation; version 2 of the License.
6
7
  This program is distributed in the hope that it will be useful,
8
  but WITHOUT ANY WARRANTY; without even the implied warranty of
9
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
  GNU General Public License for more details.
11
12
  You should have received a copy of the GNU General Public License
13
  along with this program; if not, write to the Free Software
14
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
243.1.14 by Jay Pipes
* Ensured all drizzled/field/x.cc files to include mysql_priv.h
17
#include <drizzled/common_includes.h>
212.4.2 by Monty Taylor
Fixed the includes in places to make the myisam header file move work.
18
#include <storage/myisam/myisam.h>
1 by brian
clean slate
19
20
#include "ha_archive.h"
21
22
/*
23
  First, if you want to understand storage engines you should look at 
24
  ha_example.cc and ha_example.h. 
25
26
  This example was written as a test case for a customer who needed
27
  a storage engine without indexes that could compress data very well.
28
  So, welcome to a completely compressed storage engine. This storage
29
  engine only does inserts. No replace, deletes, or updates. All reads are 
30
  complete table scans. Compression is done through a combination of packing
31
  and making use of the zlib library
32
  
33
  We keep a file pointer open for each instance of ha_archive for each read
34
  but for writes we keep one open file handle just for that. We flush it
35
  only if we have a read occur. azip handles compressing lots of records
36
  at once much better then doing lots of little records between writes.
37
  It is possible to not lock on writes but this would then mean we couldn't
38
  handle bulk inserts as well (that is if someone was trying to read at
39
  the same time since we would want to flush).
40
41
  A "meta" file is kept alongside the data file. This file serves two purpose.
42
  The first purpose is to track the number of rows in the table. The second 
43
  purpose is to determine if the table was closed properly or not. When the 
44
  meta file is first opened it is marked as dirty. It is opened when the table 
45
  itself is opened for writing. When the table is closed the new count for rows 
46
  is written to the meta file and the file is marked as clean. If the meta file 
47
  is opened and it is marked as dirty, it is assumed that a crash occured. At 
48
  this point an error occurs and the user is told to rebuild the file.
49
  A rebuild scans the rows and rewrites the meta file. If corruption is found
50
  in the data file then the meta file is not repaired.
51
52
  At some point a recovery method for such a drastic case needs to be divised.
53
54
  Locks are row level, and you will get a consistant read. 
55
56
  For performance as far as table scans go it is quite fast. I don't have
57
  good numbers but locally it has out performed both Innodb and MyISAM. For
58
  Innodb the question will be if the table can be fit into the buffer
59
  pool. For MyISAM its a question of how much the file system caches the
60
  MyISAM file. With enough free memory MyISAM is faster. Its only when the OS
61
  doesn't have enough memory to cache entire table that archive turns out 
62
  to be any faster. 
63
64
  Examples between MyISAM (packed) and Archive.
65
66
  Table with 76695844 identical rows:
67
  29680807 a_archive.ARZ
68
  920350317 a.MYD
69
70
71
  Table with 8991478 rows (all of Slashdot's comments):
72
  1922964506 comment_archive.ARZ
73
  2944970297 comment_text.MYD
74
75
76
  TODO:
77
   Allow users to set compression level.
78
   Allow adjustable block size.
79
   Implement versioning, should be easy.
80
   Allow for errors, find a way to mark bad rows.
81
   Add optional feature so that rows can be flushed at interval (which will cause less
82
     compression but may speed up ordered searches).
83
   Checkpoint the meta file to allow for faster rebuilds.
84
   Option to allow for dirty reads, this would lower the sync calls, which would make
85
     inserts a lot faster, but would mean highly arbitrary reads.
86
87
    -Brian
88
*/
89
90
/* Variables for archive share methods */
91
pthread_mutex_t archive_mutex;
92
static HASH archive_open_tables;
93
static unsigned int global_version;
94
95
/* The file extension */
96
#define ARZ ".ARZ"               // The data file
97
#define ARN ".ARN"               // Files used during an optimize call
98
99
100
/* Static declarations for handerton */
101
static handler *archive_create_handler(handlerton *hton, 
102
                                       TABLE_SHARE *table, 
103
                                       MEM_ROOT *mem_root);
520.1.22 by Brian Aker
Second pass of thd cleanup
104
int archive_discover(handlerton *hton, Session* session, const char *db, 
1 by brian
clean slate
105
                     const char *name,
481 by Brian Aker
Remove all of uchar.
106
                     unsigned char **frmblob, 
1 by brian
clean slate
107
                     size_t *frmlen);
108
278 by Brian Aker
Fixed my_bool issue in options.
109
static bool archive_use_aio= false;
1 by brian
clean slate
110
111
/*
112
  Number of rows that will force a bulk insert.
113
*/
114
#define ARCHIVE_MIN_ROWS_TO_USE_BULK_INSERT 2
115
116
/*
117
  Size of header used for row
118
*/
119
#define ARCHIVE_ROW_HEADER_SIZE 4
120
121
static handler *archive_create_handler(handlerton *hton,
122
                                       TABLE_SHARE *table, 
123
                                       MEM_ROOT *mem_root)
124
{
125
  return new (mem_root) ha_archive(hton, table);
126
}
127
128
/*
129
  Used for hash table that tracks open tables.
130
*/
481 by Brian Aker
Remove all of uchar.
131
static unsigned char* archive_get_key(ARCHIVE_SHARE *share, size_t *length,
282 by Brian Aker
Modified blackhole and archive to remove my_bool.
132
                             bool not_used __attribute__((unused)))
1 by brian
clean slate
133
{
134
  *length=share->table_name_length;
481 by Brian Aker
Remove all of uchar.
135
  return (unsigned char*) share->table_name;
1 by brian
clean slate
136
}
137
138
139
/*
140
  Initialize the archive handler.
141
142
  SYNOPSIS
143
    archive_db_init()
144
    void *
145
146
  RETURN
163 by Brian Aker
Merge Monty's code.
147
    false       OK
148
    true        Error
1 by brian
clean slate
149
*/
150
151
int archive_db_init(void *p)
152
{
153
  handlerton *archive_hton;
154
155
  archive_hton= (handlerton *)p;
156
  archive_hton->state= SHOW_OPTION_YES;
157
  archive_hton->create= archive_create_handler;
158
  archive_hton->flags= HTON_NO_FLAGS;
159
  archive_hton->discover= archive_discover;
160
161
  /* When the engine starts up set the first version */
162
  global_version= 1;
163
164
  if (pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST))
165
    goto error;
166
  if (hash_init(&archive_open_tables, system_charset_info, 32, 0, 0,
167
                (hash_get_key) archive_get_key, 0, 0))
168
  {
398.1.10 by Monty Taylor
Actually removed VOID() this time.
169
    pthread_mutex_destroy(&archive_mutex);
1 by brian
clean slate
170
  }
171
  else
172
  {
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
173
    return(false);
1 by brian
clean slate
174
  }
175
error:
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
176
  return(true);
1 by brian
clean slate
177
}
178
179
/*
180
  Release the archive handler.
181
182
  SYNOPSIS
183
    archive_db_done()
184
    void
185
186
  RETURN
163 by Brian Aker
Merge Monty's code.
187
    false       OK
1 by brian
clean slate
188
*/
189
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
190
int archive_db_done(void *p __attribute__((unused)))
1 by brian
clean slate
191
{
192
  hash_free(&archive_open_tables);
398.1.10 by Monty Taylor
Actually removed VOID() this time.
193
  pthread_mutex_destroy(&archive_mutex);
1 by brian
clean slate
194
195
  return 0;
196
}
197
198
199
ha_archive::ha_archive(handlerton *hton, TABLE_SHARE *table_arg)
200
  :handler(hton, table_arg), delayed_insert(0), bulk_insert(0)
201
{
202
  /* Set our original buffer from pre-allocated memory */
203
  buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info);
204
205
  /* The size of the offset value we will use for position() */
206
  ref_length= sizeof(my_off_t);
163 by Brian Aker
Merge Monty's code.
207
  archive_reader_open= false;
1 by brian
clean slate
208
}
209
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
210
int archive_discover(handlerton *hton __attribute__((unused)),
520.1.22 by Brian Aker
Second pass of thd cleanup
211
                     Session* session __attribute__((unused)),
53.2.32 by Monty Taylor
First large swath at getting handler stuff clean.
212
                     const char *db,
1 by brian
clean slate
213
                     const char *name,
481 by Brian Aker
Remove all of uchar.
214
                     unsigned char **frmblob,
1 by brian
clean slate
215
                     size_t *frmlen)
216
{
217
  azio_stream frm_stream;
218
  char az_file[FN_REFLEN];
219
  char *frm_ptr;
15 by brian
Fix for stat, NETWARE removal
220
  struct stat file_stat; 
1 by brian
clean slate
221
222
  fn_format(az_file, name, db, ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
223
15 by brian
Fix for stat, NETWARE removal
224
  if (stat(az_file, &file_stat))
1 by brian
clean slate
225
    goto err;
226
492.1.14 by Monty Taylor
Removed O_BINARY and FILE_BINARY.
227
  if (!(azopen(&frm_stream, az_file, O_RDONLY, AZ_METHOD_BLOCK)))
1 by brian
clean slate
228
  {
229
    if (errno == EROFS || errno == EACCES)
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
230
      return(my_errno= errno);
231
    return(HA_ERR_CRASHED_ON_USAGE);
1 by brian
clean slate
232
  }
233
234
  if (frm_stream.frm_length == 0)
235
    goto err;
236
237
  frm_ptr= (char *)my_malloc(sizeof(char) * frm_stream.frm_length, MYF(0));
238
  azread_frm(&frm_stream, frm_ptr);
239
  azclose(&frm_stream);
240
241
  *frmlen= frm_stream.frm_length;
481 by Brian Aker
Remove all of uchar.
242
  *frmblob= (unsigned char*) frm_ptr;
1 by brian
clean slate
243
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
244
  return(0);
1 by brian
clean slate
245
err:
246
  my_errno= 0;
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
247
  return(1);
1 by brian
clean slate
248
}
249
250
/*
251
  This method reads the header of a datafile and returns whether or not it was successful.
252
*/
253
int ha_archive::read_data_header(azio_stream *file_to_read)
254
{
255
  if (azread_init(file_to_read) == -1)
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
256
    return(HA_ERR_CRASHED_ON_USAGE);
1 by brian
clean slate
257
258
  if (file_to_read->version >= 3)
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
259
    return(0);
1 by brian
clean slate
260
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
261
  return(1);
1 by brian
clean slate
262
}
263
264
265
/*
266
  We create the shared memory space that we will use for the open table. 
267
  No matter what we try to get or create a share. This is so that a repair
268
  table operation can occur. 
269
270
  See ha_example.cc for a longer description.
271
*/
272
ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, int *rc)
273
{
482 by Brian Aker
Remove uint.
274
  uint32_t length;
1 by brian
clean slate
275
276
  pthread_mutex_lock(&archive_mutex);
277
  length=(uint) strlen(table_name);
278
279
  if (!(share=(ARCHIVE_SHARE*) hash_search(&archive_open_tables,
481 by Brian Aker
Remove all of uchar.
280
                                           (unsigned char*) table_name,
1 by brian
clean slate
281
                                           length)))
282
  {
283
    char *tmp_name;
284
    azio_stream archive_tmp;
285
286
    if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
287
                          &share, sizeof(*share),
288
                          &tmp_name, length+1,
461 by Monty Taylor
Removed NullS. bu-bye.
289
                          NULL)) 
1 by brian
clean slate
290
    {
291
      pthread_mutex_unlock(&archive_mutex);
292
      *rc= HA_ERR_OUT_OF_MEM;
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
293
      return(NULL);
1 by brian
clean slate
294
    }
295
296
    share->use_count= 0;
297
    share->table_name_length= length;
298
    share->table_name= tmp_name;
163 by Brian Aker
Merge Monty's code.
299
    share->crashed= false;
300
    share->archive_write_open= false;
1 by brian
clean slate
301
    fn_format(share->data_file_name, table_name, "",
302
              ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
411.1.1 by Brian Aker
Work on removing GNU specific calls.
303
    my_stpcpy(share->table_name, table_name);
1 by brian
clean slate
304
    /*
305
      We will use this lock for rows.
306
    */
398.1.10 by Monty Taylor
Actually removed VOID() this time.
307
    pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
1 by brian
clean slate
308
    
309
    /*
310
      We read the meta file, but do not mark it dirty. Since we are not
311
      doing a write we won't mark it dirty (and we won't open it for
312
      anything but reading... open it for write and we will generate null
313
      compression writes).
314
    */
492.1.14 by Monty Taylor
Removed O_BINARY and FILE_BINARY.
315
    if (!(azopen(&archive_tmp, share->data_file_name, O_RDONLY,
1 by brian
clean slate
316
                 AZ_METHOD_BLOCK)))
317
    {
398.1.10 by Monty Taylor
Actually removed VOID() this time.
318
      pthread_mutex_destroy(&share->mutex);
1 by brian
clean slate
319
      free(share);
320
      pthread_mutex_unlock(&archive_mutex);
321
      *rc= HA_ERR_CRASHED_ON_REPAIR;
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
322
      return(NULL);
1 by brian
clean slate
323
    }
324
    stats.auto_increment_value= archive_tmp.auto_increment + 1;
325
    share->rows_recorded= (ha_rows)archive_tmp.rows;
326
    share->crashed= archive_tmp.dirty;
327
    if (share->version < global_version)
328
    {
329
      share->version_rows= share->rows_recorded;
330
      share->version= global_version;
331
    }
332
    azclose(&archive_tmp);
333
481 by Brian Aker
Remove all of uchar.
334
    my_hash_insert(&archive_open_tables, (unsigned char*) share);
1 by brian
clean slate
335
    thr_lock_init(&share->lock);
336
  }
337
  share->use_count++;
338
  if (share->crashed)
339
    *rc= HA_ERR_CRASHED_ON_USAGE;
340
  pthread_mutex_unlock(&archive_mutex);
341
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
342
  return(share);
1 by brian
clean slate
343
}
344
345
346
/* 
347
  Free the share.
348
  See ha_example.cc for a description.
349
*/
350
int ha_archive::free_share()
351
{
352
  int rc= 0;
353
354
  pthread_mutex_lock(&archive_mutex);
355
  if (!--share->use_count)
356
  {
481 by Brian Aker
Remove all of uchar.
357
    hash_delete(&archive_open_tables, (unsigned char*) share);
1 by brian
clean slate
358
    thr_lock_delete(&share->lock);
398.1.10 by Monty Taylor
Actually removed VOID() this time.
359
    pthread_mutex_destroy(&share->mutex);
1 by brian
clean slate
360
    /* 
361
      We need to make sure we don't reset the crashed state.
362
      If we open a crashed file, wee need to close it as crashed unless
363
      it has been repaired.
364
      Since we will close the data down after this, we go on and count
365
      the flush on close;
366
    */
163 by Brian Aker
Merge Monty's code.
367
    if (share->archive_write_open == true)
1 by brian
clean slate
368
    {
369
      if (azclose(&(share->archive_write)))
370
        rc= 1;
371
    }
481 by Brian Aker
Remove all of uchar.
372
    free((unsigned char*) share);
1 by brian
clean slate
373
  }
374
  pthread_mutex_unlock(&archive_mutex);
375
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
376
  return(rc);
1 by brian
clean slate
377
}
378
379
int ha_archive::init_archive_writer()
380
{
381
  /* 
382
    It is expensive to open and close the data files and since you can't have
383
    a gzip file that can be both read and written we keep a writer open
384
    that is shared amoung all open tables.
385
  */
386
  if (!(azopen(&(share->archive_write), share->data_file_name, 
492.1.14 by Monty Taylor
Removed O_BINARY and FILE_BINARY.
387
               O_RDWR, AZ_METHOD_BLOCK)))
1 by brian
clean slate
388
  {
163 by Brian Aker
Merge Monty's code.
389
    share->crashed= true;
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
390
    return(1);
1 by brian
clean slate
391
  }
163 by Brian Aker
Merge Monty's code.
392
  share->archive_write_open= true;
1 by brian
clean slate
393
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
394
  return(0);
1 by brian
clean slate
395
}
396
397
398
/* 
399
  No locks are required because it is associated with just one handler instance
400
*/
401
int ha_archive::init_archive_reader()
402
{
403
  /* 
404
    It is expensive to open and close the data files and since you can't have
405
    a gzip file that can be both read and written we keep a writer open
406
    that is shared amoung all open tables.
407
  */
163 by Brian Aker
Merge Monty's code.
408
  if (archive_reader_open == false)
1 by brian
clean slate
409
  {
410
    az_method method;
411
412
    switch (archive_use_aio)
413
    {
163 by Brian Aker
Merge Monty's code.
414
    case false:
1 by brian
clean slate
415
      method= AZ_METHOD_BLOCK;
416
      break;
163 by Brian Aker
Merge Monty's code.
417
    case true:
1 by brian
clean slate
418
      method= AZ_METHOD_AIO;
419
      break;
420
    default:
421
      method= AZ_METHOD_BLOCK;
422
    }
492.1.14 by Monty Taylor
Removed O_BINARY and FILE_BINARY.
423
    if (!(azopen(&archive, share->data_file_name, O_RDONLY, 
1 by brian
clean slate
424
                 method)))
425
    {
163 by Brian Aker
Merge Monty's code.
426
      share->crashed= true;
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
427
      return(1);
1 by brian
clean slate
428
    }
163 by Brian Aker
Merge Monty's code.
429
    archive_reader_open= true;
1 by brian
clean slate
430
  }
431
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
432
  return(0);
1 by brian
clean slate
433
}
434
435
436
/*
437
  We just implement one additional file extension.
438
*/
439
static const char *ha_archive_exts[] = {
440
  ARZ,
461 by Monty Taylor
Removed NullS. bu-bye.
441
  NULL
1 by brian
clean slate
442
};
443
444
const char **ha_archive::bas_ext() const
445
{
446
  return ha_archive_exts;
447
}
448
449
450
/* 
451
  When opening a file we:
452
  Create/get our shared structure.
453
  Init out lock.
454
  We open the file we will read from.
455
*/
53.2.32 by Monty Taylor
First large swath at getting handler stuff clean.
456
int ha_archive::open(const char *name,
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
457
                     int mode __attribute__((unused)),
482 by Brian Aker
Remove uint.
458
                     uint32_t open_options)
1 by brian
clean slate
459
{
460
  int rc= 0;
461
  share= get_share(name, &rc);
462
463
  if (rc == HA_ERR_CRASHED_ON_USAGE && !(open_options & HA_OPEN_FOR_REPAIR))
464
  {
465
    /* purecov: begin inspected */
466
    free_share();
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
467
    return(rc);
1 by brian
clean slate
468
    /* purecov: end */    
469
  }
470
  else if (rc == HA_ERR_OUT_OF_MEM)
471
  {
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
472
    return(rc);
1 by brian
clean slate
473
  }
474
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
475
  assert(share);
1 by brian
clean slate
476
477
  record_buffer= create_record_buffer(table->s->reclength + 
478
                                      ARCHIVE_ROW_HEADER_SIZE);
479
480
  if (!record_buffer)
481
  {
482
    free_share();
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
483
    return(HA_ERR_OUT_OF_MEM);
1 by brian
clean slate
484
  }
485
486
  thr_lock_data_init(&share->lock, &lock, NULL);
487
488
  if (rc == HA_ERR_CRASHED_ON_USAGE && open_options & HA_OPEN_FOR_REPAIR)
489
  {
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
490
    return(0);
1 by brian
clean slate
491
  }
492
  else
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
493
    return(rc);
1 by brian
clean slate
494
}
495
496
497
/*
498
  Closes the file.
499
500
  SYNOPSIS
501
    close();
502
  
503
  IMPLEMENTATION:
504
505
  We first close this storage engines file handle to the archive and
506
  then remove our reference count to the table (and possibly free it
507
  as well).
508
509
  RETURN
510
    0  ok
511
    1  Error
512
*/
513
514
int ha_archive::close(void)
515
{
516
  int rc= 0;
517
518
  destroy_record_buffer(record_buffer);
519
520
  /* First close stream */
163 by Brian Aker
Merge Monty's code.
521
  if (archive_reader_open == true)
1 by brian
clean slate
522
  {
523
    if (azclose(&archive))
524
      rc= 1;
525
  }
526
  /* then also close share */
527
  rc|= free_share();
528
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
529
  return(rc);
1 by brian
clean slate
530
}
531
532
533
/*
534
  We create our data file here. The format is pretty simple. 
535
  You can read about the format of the data file above.
536
  Unlike other storage engines we do not "pack" our data. Since we 
537
  are about to do a general compression, packing would just be a waste of 
538
  CPU time. If the table has blobs they are written after the row in the order 
539
  of creation.
540
*/
541
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
542
int ha_archive::create(const char *name, Table *table_arg,
1 by brian
clean slate
543
                       HA_CREATE_INFO *create_info)
544
{
545
  char name_buff[FN_REFLEN];
546
  char linkname[FN_REFLEN];
547
  int error;
548
  azio_stream create_stream;            /* Archive file we are working with */
549
  File frm_file;                   /* File handler for readers */
15 by brian
Fix for stat, NETWARE removal
550
  struct stat file_stat;
481 by Brian Aker
Remove all of uchar.
551
  unsigned char *frm_ptr;
1 by brian
clean slate
552
553
  stats.auto_increment_value= create_info->auto_increment_value;
554
482 by Brian Aker
Remove uint.
555
  for (uint32_t key= 0; key < table_arg->sizeKeys(); key++)
1 by brian
clean slate
556
  {
557
    KEY *pos= table_arg->key_info+key;
558
    KEY_PART_INFO *key_part=     pos->key_part;
559
    KEY_PART_INFO *key_part_end= key_part + pos->key_parts;
560
561
    for (; key_part != key_part_end; key_part++)
562
    {
563
      Field *field= key_part->field;
564
565
      if (!(field->flags & AUTO_INCREMENT_FLAG))
566
      {
567
        error= -1;
568
        goto error;
569
      }
570
    }
571
  }
572
573
  /* 
574
    We reuse name_buff since it is available.
575
  */
576
  if (create_info->data_file_name && create_info->data_file_name[0] != '#')
577
  {
578
    fn_format(name_buff, create_info->data_file_name, "", ARZ,
579
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
580
    fn_format(linkname, name, "", ARZ,
581
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
582
  }
583
  else
584
  {
585
    fn_format(name_buff, name, "", ARZ,
586
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
587
    linkname[0]= 0;
588
  }
589
590
  /*
591
    There is a chance that the file was "discovered". In this case
592
    just use whatever file is there.
593
  */
15 by brian
Fix for stat, NETWARE removal
594
  if (!stat(name_buff, &file_stat))
1 by brian
clean slate
595
  {
596
    my_errno= 0;
492.1.14 by Monty Taylor
Removed O_BINARY and FILE_BINARY.
597
    if (!(azopen(&create_stream, name_buff, O_CREAT|O_RDWR,
1 by brian
clean slate
598
                 AZ_METHOD_BLOCK)))
599
    {
600
      error= errno;
601
      goto error2;
602
    }
603
604
    if (linkname[0])
605
      my_symlink(name_buff, linkname, MYF(0));
606
    fn_format(name_buff, name, "", ".frm",
607
              MY_REPLACE_EXT | MY_UNPACK_FILENAME);
608
609
    /*
610
      Here is where we open up the frm and pass it to archive to store 
611
    */
612
    if ((frm_file= my_open(name_buff, O_RDONLY, MYF(0))) > 0)
613
    {
15 by brian
Fix for stat, NETWARE removal
614
      if (fstat(frm_file, &file_stat))
1 by brian
clean slate
615
      {
481 by Brian Aker
Remove all of uchar.
616
        frm_ptr= (unsigned char *)my_malloc(sizeof(unsigned char) * file_stat.st_size, MYF(0));
1 by brian
clean slate
617
        if (frm_ptr)
618
        {
619
          my_read(frm_file, frm_ptr, file_stat.st_size, MYF(0));
620
          azwrite_frm(&create_stream, (char *)frm_ptr, file_stat.st_size);
481 by Brian Aker
Remove all of uchar.
621
          free((unsigned char*)frm_ptr);
1 by brian
clean slate
622
        }
623
      }
624
      my_close(frm_file, MYF(0));
625
    }
626
627
    if (create_info->comment.str)
628
      azwrite_comment(&create_stream, create_info->comment.str, 
629
                      (unsigned int)create_info->comment.length);
630
631
    /* 
632
      Yes you need to do this, because the starting value 
633
      for the autoincrement may not be zero.
634
    */
635
    create_stream.auto_increment= stats.auto_increment_value ?
636
                                    stats.auto_increment_value - 1 : 0;
637
    if (azclose(&create_stream))
638
    {
639
      error= errno;
640
      goto error2;
641
    }
642
  }
643
  else
644
    my_errno= 0;
645
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
646
  return(0);
1 by brian
clean slate
647
648
error2:
649
  delete_table(name);
650
error:
651
  /* Return error number, if we got one */
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
652
  return(error ? error : -1);
1 by brian
clean slate
653
}
654
655
/*
656
  This is where the actual row is written out.
657
*/
481 by Brian Aker
Remove all of uchar.
658
int ha_archive::real_write_row(unsigned char *buf, azio_stream *writer)
1 by brian
clean slate
659
{
660
  my_off_t written;
661
  unsigned int r_pack_length;
662
663
  /* We pack the row for writing */
664
  r_pack_length= pack_row(buf);
665
666
  written= azwrite_row(writer, record_buffer->buffer, r_pack_length);
667
  if (written != r_pack_length)
668
  {
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
669
    return(-1);
1 by brian
clean slate
670
  }
671
672
  if (!delayed_insert || !bulk_insert)
163 by Brian Aker
Merge Monty's code.
673
    share->dirty= true;
1 by brian
clean slate
674
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
675
  return(0);
1 by brian
clean slate
676
}
677
678
679
/* 
680
  Calculate max length needed for row. This includes
681
  the bytes required for the length in the header.
682
*/
683
481 by Brian Aker
Remove all of uchar.
684
uint32_t ha_archive::max_row_length(const unsigned char *buf __attribute__((unused)))
1 by brian
clean slate
685
{
327.1.1 by Brian Aker
First pass in encapsulating table (it is now an object, no longer a structure).
686
  uint32_t length= (uint32_t)(table->getRecordLength() + table->sizeFields()*2);
1 by brian
clean slate
687
  length+= ARCHIVE_ROW_HEADER_SIZE;
688
482 by Brian Aker
Remove uint.
689
  uint32_t *ptr, *end;
327.1.1 by Brian Aker
First pass in encapsulating table (it is now an object, no longer a structure).
690
  for (ptr= table->getBlobField(), end=ptr + table->sizeBlobFields();
1 by brian
clean slate
691
       ptr != end ;
692
       ptr++)
693
  {
694
      length += 2 + ((Field_blob*)table->field[*ptr])->get_length();
695
  }
696
697
  return length;
698
}
699
700
481 by Brian Aker
Remove all of uchar.
701
unsigned int ha_archive::pack_row(unsigned char *record)
1 by brian
clean slate
702
{
481 by Brian Aker
Remove all of uchar.
703
  unsigned char *ptr;
1 by brian
clean slate
704
705
  if (fix_rec_buff(max_row_length(record)))
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
706
    return(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
1 by brian
clean slate
707
708
  /* Copy null bits */
709
  memcpy(record_buffer->buffer, record, table->s->null_bytes);
710
  ptr= record_buffer->buffer + table->s->null_bytes;
711
712
  for (Field **field=table->field ; *field ; field++)
713
  {
714
    if (!((*field)->is_null()))
715
      ptr= (*field)->pack(ptr, record + (*field)->offset(record));
716
  }
717
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
718
  return((unsigned int) (ptr - record_buffer->buffer));
1 by brian
clean slate
719
}
720
721
722
/* 
723
  Look at ha_archive::open() for an explanation of the row format.
724
  Here we just write out the row.
725
726
  Wondering about start_bulk_insert()? We don't implement it for
727
  archive since it optimizes for lots of writes. The only save
728
  for implementing start_bulk_insert() is that we could skip 
729
  setting dirty to true each time.
730
*/
481 by Brian Aker
Remove all of uchar.
731
int ha_archive::write_row(unsigned char *buf)
1 by brian
clean slate
732
{
733
  int rc;
481 by Brian Aker
Remove all of uchar.
734
  unsigned char *read_buf= NULL;
1 by brian
clean slate
735
  uint64_t temp_auto;
481 by Brian Aker
Remove all of uchar.
736
  unsigned char *record=  table->record[0];
1 by brian
clean slate
737
738
  if (share->crashed)
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
739
    return(HA_ERR_CRASHED_ON_USAGE);
1 by brian
clean slate
740
741
  ha_statistic_increment(&SSV::ha_write_count);
742
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
743
    table->timestamp_field->set_time();
744
  pthread_mutex_lock(&share->mutex);
745
163 by Brian Aker
Merge Monty's code.
746
  if (share->archive_write_open == false)
1 by brian
clean slate
747
    if (init_archive_writer())
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
748
      return(HA_ERR_CRASHED_ON_USAGE);
1 by brian
clean slate
749
750
751
  if (table->next_number_field && record == table->record[0])
752
  {
753
    KEY *mkey= &table->s->key_info[0]; // We only support one key right now
754
    update_auto_increment();
755
    temp_auto= table->next_number_field->val_int();
756
757
    /*
758
      We don't support decremening auto_increment. They make the performance
759
      just cry.
760
    */
761
    if (temp_auto <= share->archive_write.auto_increment && 
762
        mkey->flags & HA_NOSAME)
763
    {
764
      rc= HA_ERR_FOUND_DUPP_KEY;
765
      goto error;
766
    }
767
#ifdef DEAD_CODE
768
    /*
769
      Bad news, this will cause a search for the unique value which is very 
770
      expensive since we will have to do a table scan which will lock up 
771
      all other writers during this period. This could perhaps be optimized 
772
      in the future.
773
    */
774
    {
775
      /* 
776
        First we create a buffer that we can use for reading rows, and can pass
777
        to get_row().
778
      */
481 by Brian Aker
Remove all of uchar.
779
      if (!(read_buf= (unsigned char*) my_malloc(table->s->reclength, MYF(MY_WME))))
1 by brian
clean slate
780
      {
781
        rc= HA_ERR_OUT_OF_MEM;
782
        goto error;
783
      }
784
       /* 
785
         All of the buffer must be written out or we won't see all of the
786
         data 
787
       */
788
      azflush(&(share->archive_write), Z_SYNC_FLUSH);
789
      /*
790
        Set the position of the local read thread to the beginning postion.
791
      */
792
      if (read_data_header(&archive))
793
      {
794
        rc= HA_ERR_CRASHED_ON_USAGE;
795
        goto error;
796
      }
797
798
      Field *mfield= table->next_number_field;
799
800
      while (!(get_row(&archive, read_buf)))
801
      {
802
        if (!memcmp(read_buf + mfield->offset(record),
803
                    table->next_number_field->ptr,
804
                    mfield->max_display_length()))
805
        {
806
          rc= HA_ERR_FOUND_DUPP_KEY;
807
          goto error;
808
        }
809
      }
810
    }
811
#endif
812
    else
813
    {
814
      if (temp_auto > share->archive_write.auto_increment)
815
        stats.auto_increment_value=
816
          (share->archive_write.auto_increment= temp_auto) + 1;
817
    }
818
  }
819
820
  /*
821
    Notice that the global auto_increment has been increased.
822
    In case of a failed row write, we will never try to reuse the value.
823
  */
824
  share->rows_recorded++;
825
  rc= real_write_row(buf,  &(share->archive_write));
826
error:
827
  pthread_mutex_unlock(&share->mutex);
828
  if (read_buf)
481 by Brian Aker
Remove all of uchar.
829
    free((unsigned char*) read_buf);
1 by brian
clean slate
830
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
831
  return(rc);
1 by brian
clean slate
832
}
833
834
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
835
void ha_archive::get_auto_increment(uint64_t offset __attribute__((unused)),
836
                                    uint64_t increment __attribute__((unused)),
837
                                    uint64_t nb_desired_values __attribute__((unused)),
838
                                    uint64_t *first_value __attribute__((unused)),
839
                                    uint64_t *nb_reserved_values __attribute__((unused)))
1 by brian
clean slate
840
{
163 by Brian Aker
Merge Monty's code.
841
  *nb_reserved_values= UINT64_MAX;
1 by brian
clean slate
842
  *first_value= share->archive_write.auto_increment + 1;
843
}
844
845
/* Initialized at each key walk (called multiple times unlike rnd_init()) */
482 by Brian Aker
Remove uint.
846
int ha_archive::index_init(uint32_t keynr, bool sorted __attribute__((unused)))
1 by brian
clean slate
847
{
848
  active_index= keynr;
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
849
  return(0);
1 by brian
clean slate
850
}
851
852
853
/*
854
  No indexes, so if we get a request for an index search since we tell
855
  the optimizer that we have unique indexes, we scan
856
*/
481 by Brian Aker
Remove all of uchar.
857
int ha_archive::index_read(unsigned char *buf, const unsigned char *key,
482 by Brian Aker
Remove uint.
858
                             uint32_t key_len, enum ha_rkey_function find_flag)
1 by brian
clean slate
859
{
860
  int rc;
861
  rc= index_read_idx(buf, active_index, key, key_len, find_flag);
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
862
  return(rc);
1 by brian
clean slate
863
}
864
865
482 by Brian Aker
Remove uint.
866
int ha_archive::index_read_idx(unsigned char *buf, uint32_t index, const unsigned char *key,
867
                               uint32_t key_len,
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
868
                               enum ha_rkey_function find_flag __attribute__((unused)))
1 by brian
clean slate
869
{
870
  int rc;
871
  bool found= 0;
872
  KEY *mkey= &table->s->key_info[index];
873
  current_k_offset= mkey->key_part->offset;
874
  current_key= key;
875
  current_key_len= key_len;
876
163 by Brian Aker
Merge Monty's code.
877
  rc= rnd_init(true);
1 by brian
clean slate
878
879
  if (rc)
880
    goto error;
881
882
  while (!(get_row(&archive, buf)))
883
  {
884
    if (!memcmp(current_key, buf + current_k_offset, current_key_len))
885
    {
886
      found= 1;
887
      break;
888
    }
889
  }
890
891
  if (found)
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
892
    return(0);
1 by brian
clean slate
893
894
error:
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
895
  return(rc ? rc : HA_ERR_END_OF_FILE);
1 by brian
clean slate
896
}
897
898
481 by Brian Aker
Remove all of uchar.
899
int ha_archive::index_next(unsigned char * buf) 
1 by brian
clean slate
900
{ 
901
  bool found= 0;
902
903
  while (!(get_row(&archive, buf)))
904
  {
905
    if (!memcmp(current_key, buf+current_k_offset, current_key_len))
906
    {
907
      found= 1;
908
      break;
909
    }
910
  }
911
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
912
  return(found ? 0 : HA_ERR_END_OF_FILE); 
1 by brian
clean slate
913
}
914
915
/*
916
  All calls that need to scan the table start with this method. If we are told
917
  that it is a table scan we rewind the file to the beginning, otherwise
918
  we assume the position will be set.
919
*/
920
921
int ha_archive::rnd_init(bool scan)
922
{
923
  if (share->crashed)
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
924
      return(HA_ERR_CRASHED_ON_USAGE);
1 by brian
clean slate
925
926
  init_archive_reader();
927
928
  /* We rewind the file so that we can read from the beginning if scan */
929
  if (scan)
930
  {
931
    if (read_data_header(&archive))
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
932
      return(HA_ERR_CRASHED_ON_USAGE);
1 by brian
clean slate
933
  }
934
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
935
  return(0);
1 by brian
clean slate
936
}
937
938
939
/*
940
  This is the method that is used to read a row. It assumes that the row is 
941
  positioned where you want it.
942
*/
481 by Brian Aker
Remove all of uchar.
943
int ha_archive::get_row(azio_stream *file_to_read, unsigned char *buf)
1 by brian
clean slate
944
{
945
  int rc;
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
946
1 by brian
clean slate
947
  if (file_to_read->version == ARCHIVE_VERSION)
948
    rc= get_row_version3(file_to_read, buf);
949
  else
950
    rc= -1;
951
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
952
  return(rc);
1 by brian
clean slate
953
}
954
955
/* Reallocate buffer if needed */
956
bool ha_archive::fix_rec_buff(unsigned int length)
957
{
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
958
  assert(record_buffer->buffer);
1 by brian
clean slate
959
960
  if (length > record_buffer->length)
961
  {
481 by Brian Aker
Remove all of uchar.
962
    unsigned char *newptr;
963
    if (!(newptr=(unsigned char*) my_realloc((unsigned char*) record_buffer->buffer, 
1 by brian
clean slate
964
                                    length,
965
				    MYF(MY_ALLOW_ZERO_PTR))))
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
966
      return(1);
1 by brian
clean slate
967
    record_buffer->buffer= newptr;
968
    record_buffer->length= length;
969
  }
970
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
971
  assert(length <= record_buffer->length);
1 by brian
clean slate
972
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
973
  return(0);
1 by brian
clean slate
974
}
975
481 by Brian Aker
Remove all of uchar.
976
int ha_archive::unpack_row(azio_stream *file_to_read, unsigned char *record)
1 by brian
clean slate
977
{
978
  unsigned int read;
979
  int error;
481 by Brian Aker
Remove all of uchar.
980
  const unsigned char *ptr;
1 by brian
clean slate
981
982
  read= azread_row(file_to_read, &error);
481 by Brian Aker
Remove all of uchar.
983
  ptr= (const unsigned char *)file_to_read->row_ptr;
1 by brian
clean slate
984
985
  if (error || read == 0)
986
  {
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
987
    return(-1);
1 by brian
clean slate
988
  }
989
990
  /* Copy null bits */
327.1.1 by Brian Aker
First pass in encapsulating table (it is now an object, no longer a structure).
991
  memcpy(record, ptr, table->getNullBytes());
992
  ptr+= table->getNullBytes();
1 by brian
clean slate
993
  for (Field **field=table->field ; *field ; field++)
994
  {
995
    if (!((*field)->is_null()))
996
    {
997
      ptr= (*field)->unpack(record + (*field)->offset(table->record[0]), ptr);
998
    }
999
  }
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1000
  return(0);
1 by brian
clean slate
1001
}
1002
1003
481 by Brian Aker
Remove all of uchar.
1004
int ha_archive::get_row_version3(azio_stream *file_to_read, unsigned char *buf)
1 by brian
clean slate
1005
{
1006
  int returnable= unpack_row(file_to_read, buf);
1007
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1008
  return(returnable);
1 by brian
clean slate
1009
}
1010
1011
1012
/* 
1013
  Called during ORDER BY. Its position is either from being called sequentially
1014
  or by having had ha_archive::rnd_pos() called before it is called.
1015
*/
1016
481 by Brian Aker
Remove all of uchar.
1017
int ha_archive::rnd_next(unsigned char *buf)
1 by brian
clean slate
1018
{
1019
  int rc;
1020
1021
  if (share->crashed)
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1022
      return(HA_ERR_CRASHED_ON_USAGE);
1 by brian
clean slate
1023
1024
  if (!scan_rows)
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1025
    return(HA_ERR_END_OF_FILE);
1 by brian
clean slate
1026
  scan_rows--;
1027
1028
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1029
  current_position= aztell(&archive);
1030
  rc= get_row(&archive, buf);
1031
1032
  table->status=rc ? STATUS_NOT_FOUND: 0;
1033
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1034
  return(rc);
1 by brian
clean slate
1035
}
1036
1037
1038
/*
1039
  Thanks to the table flag HA_REC_NOT_IN_SEQ this will be called after
1040
  each call to ha_archive::rnd_next() if an ordering of the rows is
1041
  needed.
1042
*/
1043
481 by Brian Aker
Remove all of uchar.
1044
void ha_archive::position(const unsigned char *record __attribute__((unused)))
1 by brian
clean slate
1045
{
1046
  my_store_ptr(ref, ref_length, current_position);
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1047
  return;
1 by brian
clean slate
1048
}
1049
1050
1051
/*
1052
  This is called after a table scan for each row if the results of the
1053
  scan need to be ordered. It will take *pos and use it to move the
1054
  cursor in the file so that the next row that is called is the
1055
  correctly ordered row.
1056
*/
1057
481 by Brian Aker
Remove all of uchar.
1058
int ha_archive::rnd_pos(unsigned char * buf, unsigned char *pos)
1 by brian
clean slate
1059
{
1060
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1061
  current_position= (my_off_t)my_get_ptr(pos, ref_length);
1062
  if (azseek(&archive, (size_t)current_position, SEEK_SET) == (size_t)(-1L))
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1063
    return(HA_ERR_CRASHED_ON_USAGE);
1064
  return(get_row(&archive, buf));
1 by brian
clean slate
1065
}
1066
1067
/*
1068
  This method repairs the meta file. It does this by walking the datafile and 
1069
  rewriting the meta file. Currently it does this by calling optimize with
1070
  the extended flag.
1071
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
1072
int ha_archive::repair(Session* session, HA_CHECK_OPT* check_opt)
1 by brian
clean slate
1073
{
1074
  check_opt->flags= T_EXTEND;
520.1.22 by Brian Aker
Second pass of thd cleanup
1075
  int rc= optimize(session, check_opt);
1 by brian
clean slate
1076
1077
  if (rc)
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1078
    return(HA_ERR_CRASHED_ON_REPAIR);
1 by brian
clean slate
1079
163 by Brian Aker
Merge Monty's code.
1080
  share->crashed= false;
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1081
  return(0);
1 by brian
clean slate
1082
}
1083
1084
/*
1085
  The table can become fragmented if data was inserted, read, and then
1086
  inserted again. What we do is open up the file and recompress it completely. 
1087
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
1088
int ha_archive::optimize(Session* session __attribute__((unused)),
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
1089
                         HA_CHECK_OPT* check_opt __attribute__((unused)))
1 by brian
clean slate
1090
{
1091
  int rc= 0;
1092
  azio_stream writer;
1093
  char writer_filename[FN_REFLEN];
1094
1095
  init_archive_reader();
1096
1097
  // now we close both our writer and our reader for the rename
1098
  if (share->archive_write_open)
1099
  {
1100
    azclose(&(share->archive_write));
163 by Brian Aker
Merge Monty's code.
1101
    share->archive_write_open= false;
1 by brian
clean slate
1102
  }
1103
1104
  /* Lets create a file to contain the new data */
1105
  fn_format(writer_filename, share->table_name, "", ARN, 
1106
            MY_REPLACE_EXT | MY_UNPACK_FILENAME);
1107
492.1.14 by Monty Taylor
Removed O_BINARY and FILE_BINARY.
1108
  if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR, AZ_METHOD_BLOCK)))
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1109
    return(HA_ERR_CRASHED_ON_USAGE); 
1 by brian
clean slate
1110
1111
  /* 
1112
    An extended rebuild is a lot more effort. We open up each row and re-record it. 
1113
    Any dead rows are removed (aka rows that may have been partially recorded). 
1114
1115
    As of Archive format 3, this is the only type that is performed, before this
1116
    version it was just done on T_EXTEND
1117
  */
1118
  if (1)
1119
  {
1120
    /*
1121
      Now we will rewind the archive file so that we are positioned at the 
1122
      start of the file.
1123
    */
1124
    azflush(&archive, Z_SYNC_FLUSH);
1125
    rc= read_data_header(&archive);
1126
1127
    /* 
1128
      On success of writing out the new header, we now fetch each row and
1129
      insert it into the new archive file. 
1130
    */
1131
    if (!rc)
1132
    {
53.2.2 by Monty Taylor
Updated everything that needs updating to compile with -std=gnu99 -pedantic
1133
      uint64_t x;
1134
      uint64_t rows_restored;
1 by brian
clean slate
1135
      share->rows_recorded= 0;
1136
      stats.auto_increment_value= 1;
1137
      share->archive_write.auto_increment= 0;
1138
1139
      rows_restored= archive.rows;
1140
1141
      for (x= 0; x < rows_restored ; x++)
1142
      {
1143
        rc= get_row(&archive, table->record[0]);
1144
1145
        if (rc != 0)
1146
          break;
1147
1148
        real_write_row(table->record[0], &writer);
1149
        /*
1150
          Long term it should be possible to optimize this so that
1151
          it is not called on each row.
1152
        */
1153
        if (table->found_next_number_field)
1154
        {
1155
          Field *field= table->found_next_number_field;
1156
          uint64_t auto_value=
1157
            (uint64_t) field->val_int(table->record[0] +
1158
                                       field->offset(table->record[0]));
1159
          if (share->archive_write.auto_increment < auto_value)
1160
            stats.auto_increment_value=
1161
              (share->archive_write.auto_increment= auto_value) + 1;
1162
        }
1163
      }
1164
      share->rows_recorded= (ha_rows)writer.rows;
1165
    }
1166
1167
    if (rc && rc != HA_ERR_END_OF_FILE)
1168
    {
1169
      goto error;
1170
    }
1171
  } 
1172
1173
  azclose(&writer);
163 by Brian Aker
Merge Monty's code.
1174
  share->dirty= false;
1 by brian
clean slate
1175
  
1176
  azclose(&archive);
1177
1178
  // make the file we just wrote be our data file
1179
  rc = my_rename(writer_filename,share->data_file_name,MYF(0));
1180
1181
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1182
  return(rc);
1 by brian
clean slate
1183
error:
1184
  azclose(&writer);
1185
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1186
  return(rc); 
1 by brian
clean slate
1187
}
1188
1189
/* 
1190
  Below is an example of how to setup row level locking.
1191
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
1192
THR_LOCK_DATA **ha_archive::store_lock(Session *session,
1 by brian
clean slate
1193
                                       THR_LOCK_DATA **to,
1194
                                       enum thr_lock_type lock_type)
1195
{
1196
  if (lock_type == TL_WRITE_DELAYED)
163 by Brian Aker
Merge Monty's code.
1197
    delayed_insert= true;
1 by brian
clean slate
1198
  else
163 by Brian Aker
Merge Monty's code.
1199
    delayed_insert= false;
1 by brian
clean slate
1200
1201
  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) 
1202
  {
1203
    /* 
1204
      Here is where we get into the guts of a row level lock.
1205
      If TL_UNLOCK is set 
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
1206
      If we are not doing a LOCK Table or DISCARD/IMPORT
1 by brian
clean slate
1207
      TABLESPACE, then allow multiple writers 
1208
    */
1209
1210
    if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
520.1.22 by Brian Aker
Second pass of thd cleanup
1211
         lock_type <= TL_WRITE) && !session_in_lock_tables(session)
1212
        && !session_tablespace_op(session))
1 by brian
clean slate
1213
      lock_type = TL_WRITE_ALLOW_WRITE;
1214
1215
    /* 
1216
      In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
1217
      MySQL would use the lock TL_READ_NO_INSERT on t2, and that
1218
      would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
1219
      to t2. Convert the lock to a normal read lock to allow
1220
      concurrent inserts to t2. 
1221
    */
1222
520.1.22 by Brian Aker
Second pass of thd cleanup
1223
    if (lock_type == TL_READ_NO_INSERT && !session_in_lock_tables(session)) 
1 by brian
clean slate
1224
      lock_type = TL_READ;
1225
1226
    lock.type=lock_type;
1227
  }
1228
1229
  *to++= &lock;
1230
1231
  return to;
1232
}
1233
1234
void ha_archive::update_create_info(HA_CREATE_INFO *create_info)
1235
{
1236
  ha_archive::info(HA_STATUS_AUTO);
1237
  if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
1238
  {
1239
    create_info->auto_increment_value= stats.auto_increment_value;
1240
  }
1241
1242
  if (!(my_readlink(share->real_path, share->data_file_name, MYF(0))))
1243
    create_info->data_file_name= share->real_path;
1244
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1245
  return;
1 by brian
clean slate
1246
}
1247
1248
1249
/*
1250
  Hints for optimizer, see ha_tina for more information
1251
*/
482 by Brian Aker
Remove uint.
1252
int ha_archive::info(uint32_t flag)
1 by brian
clean slate
1253
{
1254
  /* 
1255
    If dirty, we lock, and then reset/flush the data.
1256
    I found that just calling azflush() doesn't always work.
1257
  */
1258
  pthread_mutex_lock(&share->mutex);
163 by Brian Aker
Merge Monty's code.
1259
  if (share->dirty == true)
1 by brian
clean slate
1260
  {
1261
    azflush(&(share->archive_write), Z_SYNC_FLUSH);
1262
    share->rows_recorded= share->archive_write.rows;
163 by Brian Aker
Merge Monty's code.
1263
    share->dirty= false;
1 by brian
clean slate
1264
    if (share->version < global_version)
1265
    {
1266
      share->version_rows= share->rows_recorded;
1267
      share->version= global_version;
1268
    }
1269
1270
  }
1271
1272
  /* 
1273
    This should be an accurate number now, though bulk and delayed inserts can
1274
    cause the number to be inaccurate.
1275
  */
1276
  stats.records= share->rows_recorded;
1277
  pthread_mutex_unlock(&share->mutex);
1278
1279
  scan_rows= stats.records;
1280
  stats.deleted= 0;
1281
1282
  /* Costs quite a bit more to get all information */
1283
  if (flag & HA_STATUS_TIME)
1284
  {
15 by brian
Fix for stat, NETWARE removal
1285
    struct stat file_stat;  // Stat information for the data file
1 by brian
clean slate
1286
398.1.10 by Monty Taylor
Actually removed VOID() this time.
1287
    stat(share->data_file_name, &file_stat);
1 by brian
clean slate
1288
327.1.1 by Brian Aker
First pass in encapsulating table (it is now an object, no longer a structure).
1289
    stats.mean_rec_length= table->getRecordLength()+ buffer.alloced_length();
1 by brian
clean slate
1290
    stats.data_file_length= file_stat.st_size;
1291
    stats.create_time= file_stat.st_ctime;
1292
    stats.update_time= file_stat.st_mtime;
1293
    stats.max_data_file_length= share->rows_recorded * stats.mean_rec_length;
1294
  }
1295
  stats.delete_length= 0;
1296
  stats.index_file_length=0;
1297
1298
  if (flag & HA_STATUS_AUTO)
1299
  {
1300
    init_archive_reader();
1301
    pthread_mutex_lock(&share->mutex);
1302
    azflush(&archive, Z_SYNC_FLUSH);
1303
    pthread_mutex_unlock(&share->mutex);
1304
    stats.auto_increment_value= archive.auto_increment + 1;
1305
  }
1306
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1307
  return(0);
1 by brian
clean slate
1308
}
1309
1310
1311
/*
1312
  This method tells us that a bulk insert operation is about to occur. We set
1313
  a flag which will keep write_row from saying that its data is dirty. This in
1314
  turn will keep selects from causing a sync to occur.
1315
  Basically, yet another optimizations to keep compression working well.
1316
*/
1317
void ha_archive::start_bulk_insert(ha_rows rows)
1318
{
1319
  if (!rows || rows >= ARCHIVE_MIN_ROWS_TO_USE_BULK_INSERT)
163 by Brian Aker
Merge Monty's code.
1320
    bulk_insert= true;
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1321
  return;
1 by brian
clean slate
1322
}
1323
1324
1325
/* 
1326
  Other side of start_bulk_insert, is end_bulk_insert. Here we turn off the bulk insert
1327
  flag, and set the share dirty so that the next select will call sync for us.
1328
*/
1329
int ha_archive::end_bulk_insert()
1330
{
163 by Brian Aker
Merge Monty's code.
1331
  bulk_insert= false;
1332
  share->dirty= true;
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1333
  return(0);
1 by brian
clean slate
1334
}
1335
1336
/*
1337
  We cancel a truncate command. The only way to delete an archive table is to drop it.
1338
  This is done for security reasons. In a later version we will enable this by 
1339
  allowing the user to select a different row format.
1340
*/
1341
int ha_archive::delete_all_rows()
1342
{
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1343
  return(HA_ERR_WRONG_COMMAND);
1 by brian
clean slate
1344
}
1345
1346
/*
1347
  We just return state if asked.
1348
*/
1349
bool ha_archive::is_crashed() const 
1350
{
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1351
  return(share->crashed); 
1 by brian
clean slate
1352
}
1353
1354
/*
1355
  Simple scan of the tables to make sure everything is ok.
1356
*/
1357
520.1.22 by Brian Aker
Second pass of thd cleanup
1358
int ha_archive::check(Session* session,
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
1359
                      HA_CHECK_OPT* check_opt __attribute__((unused)))
1 by brian
clean slate
1360
{
1361
  int rc= 0;
1362
  const char *old_proc_info;
53.2.2 by Monty Taylor
Updated everything that needs updating to compile with -std=gnu99 -pedantic
1363
  uint64_t x;
1 by brian
clean slate
1364
520.1.22 by Brian Aker
Second pass of thd cleanup
1365
  old_proc_info= get_session_proc_info(session);
1366
  set_session_proc_info(session, "Checking table");
1 by brian
clean slate
1367
  /* Flush any waiting data */
1368
  pthread_mutex_lock(&share->mutex);
1369
  azflush(&(share->archive_write), Z_SYNC_FLUSH);
1370
  pthread_mutex_unlock(&share->mutex);
1371
1372
  /*
1373
    Now we will rewind the archive file so that we are positioned at the 
1374
    start of the file.
1375
  */
1376
  init_archive_reader();
1377
  azflush(&archive, Z_SYNC_FLUSH);
1378
  read_data_header(&archive);
1379
  for (x= 0; x < share->archive_write.rows; x++)
1380
  {
1381
    rc= get_row(&archive, table->record[0]);
1382
1383
    if (rc != 0)
1384
      break;
1385
  }
1386
520.1.22 by Brian Aker
Second pass of thd cleanup
1387
  set_session_proc_info(session, old_proc_info);
1 by brian
clean slate
1388
1389
  if ((rc && rc != HA_ERR_END_OF_FILE))  
1390
  {
163 by Brian Aker
Merge Monty's code.
1391
    share->crashed= false;
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1392
    return(HA_ADMIN_CORRUPT);
1 by brian
clean slate
1393
  }
1394
  else
1395
  {
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1396
    return(HA_ADMIN_OK);
1 by brian
clean slate
1397
  }
1398
}
1399
1400
/*
1401
  Check and repair the table if needed.
1402
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
1403
bool ha_archive::check_and_repair(Session *session) 
1 by brian
clean slate
1404
{
1405
  HA_CHECK_OPT check_opt;
1406
1407
  check_opt.init();
1408
520.1.22 by Brian Aker
Second pass of thd cleanup
1409
  return(repair(session, &check_opt));
1 by brian
clean slate
1410
}
1411
1412
archive_record_buffer *ha_archive::create_record_buffer(unsigned int length) 
1413
{
1414
  archive_record_buffer *r;
1415
  if (!(r= 
1416
        (archive_record_buffer*) my_malloc(sizeof(archive_record_buffer),
1417
                                           MYF(MY_WME))))
1418
  {
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1419
    return(NULL); /* purecov: inspected */
1 by brian
clean slate
1420
  }
1421
  r->length= (int)length;
1422
481 by Brian Aker
Remove all of uchar.
1423
  if (!(r->buffer= (unsigned char*) my_malloc(r->length,
1 by brian
clean slate
1424
                                    MYF(MY_WME))))
1425
  {
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
1426
    free((char*) r);
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1427
    return(NULL); /* purecov: inspected */
1 by brian
clean slate
1428
  }
1429
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1430
  return(r);
1 by brian
clean slate
1431
}
1432
1433
void ha_archive::destroy_record_buffer(archive_record_buffer *r) 
1434
{
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
1435
  free((char*) r->buffer);
1436
  free((char*) r);
51.3.8 by Jay Pipes
Removed DBUG from CSV and Blackhole storage engines
1437
  return;
1 by brian
clean slate
1438
}
1439
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
1440
static DRIZZLE_SYSVAR_BOOL(aio, archive_use_aio,
1 by brian
clean slate
1441
  PLUGIN_VAR_NOCMDOPT,
1442
  "Whether or not to use asynchronous IO.",
163 by Brian Aker
Merge Monty's code.
1443
  NULL, NULL, true);
1 by brian
clean slate
1444
1445
static struct st_mysql_sys_var* archive_system_variables[]= {
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
1446
  DRIZZLE_SYSVAR(aio),
1 by brian
clean slate
1447
  NULL
1448
};
1449
1450
mysql_declare_plugin(archive)
1451
{
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
1452
  DRIZZLE_STORAGE_ENGINE_PLUGIN,
1 by brian
clean slate
1453
  "ARCHIVE",
177.4.3 by mark
ripped out more plugin ABI and API version checking, and plugin versions are now strings
1454
  "3.5",
1 by brian
clean slate
1455
  "Brian Aker, MySQL AB",
1456
  "Archive storage engine",
1457
  PLUGIN_LICENSE_GPL,
1458
  archive_db_init, /* Plugin Init */
1459
  archive_db_done, /* Plugin Deinit */
1460
  NULL,                       /* status variables                */
1461
  archive_system_variables,   /* system variables                */
1462
  NULL                        /* config options                  */
1463
}
1464
mysql_declare_plugin_end;
1465