~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/csv/ha_tina.cc

  • Committer: Brian Aker
  • Date: 2010-07-09 17:59:07 UTC
  • Revision ID: brian@gaz-20100709175907-h014kkb6cztsr21d
Fix const_cast, disable the unittest for generators.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
  You should have received a copy of the GNU General Public License
13
13
  along with this program; if not, write to the Free Software
14
 
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
14
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/*
17
17
  Make sure to look at ha_tina.h for more details.
40
40
 
41
41
 -Brian
42
42
*/
43
 
#include <config.h>
 
43
#include "config.h"
44
44
#include <drizzled/field.h>
45
45
#include <drizzled/field/blob.h>
 
46
#include <drizzled/field/timestamp.h>
46
47
#include <drizzled/error.h>
47
48
#include <drizzled/table.h>
48
49
#include <drizzled/session.h>
49
 
#include <drizzled/internal/my_sys.h>
 
50
#include "drizzled/internal/my_sys.h"
50
51
 
51
52
#include "ha_tina.h"
52
53
 
63
64
/*
64
65
  unsigned char + unsigned char + uint64_t + uint64_t + uint64_t + uint64_t + unsigned char
65
66
*/
66
 
static const int META_BUFFER_SIZE = sizeof(unsigned char) + sizeof(unsigned char) + sizeof(uint64_t)
67
 
  + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(unsigned char);
68
 
static const int TINA_CHECK_HEADER = 254; // The number we use to determine corruption
69
 
static const int BLOB_MEMROOT_ALLOC_SIZE = 8192;
 
67
#define META_BUFFER_SIZE sizeof(unsigned char) + sizeof(unsigned char) + sizeof(uint64_t) \
 
68
  + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(unsigned char)
 
69
#define TINA_CHECK_HEADER 254 // The number we use to determine corruption
 
70
#define BLOB_MEMROOT_ALLOC_SIZE 8192
70
71
 
71
72
/* The file extension */
72
 
static const char* CSV_EXT = ".CSV"               // The data file
73
 
static const char* CSN_EXT = ".CSN"               // Files used during repair and update
74
 
static const char* CSM_EXT = ".CSM"               // Meta file
 
73
#define CSV_EXT ".CSV"               // The data file
 
74
#define CSN_EXT ".CSN"               // Files used during repair and update
 
75
#define CSM_EXT ".CSM"               // Meta file
75
76
 
76
77
 
77
78
static int read_meta_file(int meta_file, ha_rows *rows);
78
79
static int write_meta_file(int meta_file, ha_rows rows, bool dirty);
79
80
 
 
81
void tina_get_status(void* param, int concurrent_insert);
 
82
void tina_update_status(void* param);
 
83
bool tina_check_status(void* param);
 
84
 
80
85
/* Stuff for shares */
81
86
pthread_mutex_t tina_mutex;
82
87
 
111
116
    pthread_mutex_destroy(&tina_mutex);
112
117
  }
113
118
 
114
 
  virtual Cursor *create(Table &table)
 
119
  virtual Cursor *create(TableShare &table,
 
120
                         drizzled::memory::Root *mem_root)
115
121
  {
116
 
    return new ha_tina(*this, table);
 
122
    return new (mem_root) ha_tina(*this, table);
117
123
  }
118
124
 
119
125
  const char **bas_ext() const {
122
128
 
123
129
  int doCreateTable(Session &,
124
130
                    Table &table_arg,
125
 
                    const drizzled::identifier::Table &identifier,
 
131
                    const drizzled::TableIdentifier &identifier,
126
132
                    drizzled::message::Table&);
127
133
 
128
134
  int doGetTableDefinition(Session& session,
129
 
                           const drizzled::identifier::Table &identifier,
 
135
                           const drizzled::TableIdentifier &identifier,
130
136
                           drizzled::message::Table &table_message);
131
137
 
132
 
  int doDropTable(Session&, const drizzled::identifier::Table &identifier);
 
138
  /* Temp only engine, so do not return values. */
 
139
  void doGetTableNames(drizzled::CachedDirectory &, const SchemaIdentifier&, set<string>&) { };
 
140
 
 
141
  int doDropTable(Session&, const drizzled::TableIdentifier &identifier);
133
142
  TinaShare *findOpenTable(const string table_name);
134
143
  void addOpenTable(const string &table_name, TinaShare *);
135
144
  void deleteOpenTable(const string &table_name);
138
147
  uint32_t max_keys()          const { return 0; }
139
148
  uint32_t max_key_parts()     const { return 0; }
140
149
  uint32_t max_key_length()    const { return 0; }
141
 
  bool doDoesTableExist(Session& session, const drizzled::identifier::Table &identifier);
142
 
  int doRenameTable(Session&, const drizzled::identifier::Table &from, const drizzled::identifier::Table &to);
 
150
  bool doDoesTableExist(Session& session, const drizzled::TableIdentifier &identifier);
 
151
  int doRenameTable(Session&, const drizzled::TableIdentifier &from, const drizzled::TableIdentifier &to);
143
152
 
144
153
  void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
145
 
                             const drizzled::identifier::Schema &schema_identifier,
146
 
                             drizzled::identifier::Table::vector &set_of_identifiers);
 
154
                             const drizzled::SchemaIdentifier &schema_identifier,
 
155
                             drizzled::TableIdentifiers &set_of_identifiers);
147
156
};
148
157
 
149
158
void Tina::doGetTableIdentifiers(drizzled::CachedDirectory&,
150
 
                                 const drizzled::identifier::Schema&,
151
 
                                 drizzled::identifier::Table::vector&)
 
159
                                 const drizzled::SchemaIdentifier&,
 
160
                                 drizzled::TableIdentifiers&)
152
161
{
153
162
}
154
163
 
155
164
int Tina::doRenameTable(Session &session,
156
 
                        const drizzled::identifier::Table &from, const drizzled::identifier::Table &to)
 
165
                        const drizzled::TableIdentifier &from, const drizzled::TableIdentifier &to)
157
166
{
158
167
  int error= 0;
159
168
  for (const char **ext= bas_ext(); *ext ; ext++)
166
175
    }
167
176
  }
168
177
 
169
 
  session.getMessageCache().renameTableMessage(from, to);
 
178
  session.renameTableMessage(from, to);
170
179
 
171
180
  return error;
172
181
}
173
182
 
174
 
bool Tina::doDoesTableExist(Session &session, const drizzled::identifier::Table &identifier)
 
183
bool Tina::doDoesTableExist(Session &session, const drizzled::TableIdentifier &identifier)
175
184
{
176
 
  return session.getMessageCache().doesTableMessageExist(identifier);
 
185
  return session.doesTableMessageExist(identifier);
177
186
}
178
187
 
179
188
 
180
189
int Tina::doDropTable(Session &session,
181
 
                      const drizzled::identifier::Table &identifier)
 
190
                      const drizzled::TableIdentifier &identifier)
182
191
{
183
192
  int error= 0;
184
193
  int enoent_or_zero= ENOENT;                   // Error if no file was deleted
 
194
  char buff[FN_REFLEN];
185
195
 
186
196
  for (const char **ext= bas_ext(); *ext ; ext++)
187
197
  {
188
 
    std::string full_name= identifier.getPath();
189
 
    full_name.append(*ext);
190
 
 
191
 
    if (internal::my_delete_with_symlink(full_name.c_str(), MYF(0)))
 
198
    internal::fn_format(buff, identifier.getPath().c_str(), "", *ext,
 
199
                        MY_UNPACK_FILENAME|MY_APPEND_EXT);
 
200
    if (internal::my_delete_with_symlink(buff, MYF(0)))
192
201
    {
193
202
      if ((error= errno) != ENOENT)
194
203
        break;
195
204
    }
196
205
    else
197
 
    {
198
206
      enoent_or_zero= 0;                        // No error for ENOENT
199
 
    }
200
207
    error= enoent_or_zero;
201
208
  }
202
209
 
203
 
  session.getMessageCache().removeTableMessage(identifier);
 
210
  session.removeTableMessage(identifier);
204
211
 
205
212
  return error;
206
213
}
228
235
 
229
236
 
230
237
int Tina::doGetTableDefinition(Session &session,
231
 
                               const drizzled::identifier::Table &identifier,
 
238
                               const drizzled::TableIdentifier &identifier,
232
239
                               drizzled::message::Table &table_message)
233
240
{
234
 
  if (session.getMessageCache().getTableMessage(identifier, table_message))
 
241
  if (session.getTableMessage(identifier, table_message))
235
242
    return EEXIST;
236
243
 
237
244
  return ENOENT;
252
259
 
253
260
 
254
261
 
255
 
TinaShare::TinaShare(const std::string &table_name_arg) : 
256
 
  table_name(table_name_arg),
257
 
  data_file_name(table_name_arg),
258
 
  use_count(0),
259
 
  saved_data_file_length(0),
260
 
  update_file_opened(false),
261
 
  tina_write_opened(false),
262
 
  crashed(false),
263
 
  rows_recorded(0),
264
 
  data_file_version(0)
 
262
TinaShare::TinaShare(const char *table_name_arg)
 
263
  : table_name(table_name_arg), use_count(0), saved_data_file_length(0),
 
264
    update_file_opened(false), tina_write_opened(false),
 
265
    crashed(false), rows_recorded(0), data_file_version(0)
265
266
{
266
 
  data_file_name.append(CSV_EXT);
 
267
  thr_lock_init(&lock);
 
268
  internal::fn_format(data_file_name, table_name_arg, "", CSV_EXT,
 
269
            MY_REPLACE_EXT|MY_UNPACK_FILENAME);
267
270
}
268
271
 
269
272
TinaShare::~TinaShare()
270
273
{
 
274
  thr_lock_delete(&lock);
271
275
  pthread_mutex_destroy(&mutex);
272
276
}
273
277
 
274
278
/*
275
279
  Simple lock controls.
276
280
*/
277
 
TinaShare *ha_tina::get_share(const std::string &table_name)
 
281
TinaShare *ha_tina::get_share(const char *table_name)
278
282
{
279
283
  pthread_mutex_lock(&tina_mutex);
280
284
 
281
 
  Tina *a_tina= static_cast<Tina *>(getEngine());
 
285
  Tina *a_tina= static_cast<Tina *>(engine);
282
286
  share= a_tina->findOpenTable(table_name);
283
287
 
284
 
  std::string meta_file_name;
 
288
  char meta_file_name[FN_REFLEN];
285
289
  struct stat file_stat;
286
290
 
287
291
  /*
298
302
      return NULL;
299
303
    }
300
304
 
301
 
    meta_file_name.assign(table_name);
302
 
    meta_file_name.append(CSM_EXT);
 
305
    internal::fn_format(meta_file_name, table_name, "", CSM_EXT,
 
306
              MY_REPLACE_EXT|MY_UNPACK_FILENAME);
303
307
 
304
 
    if (stat(share->data_file_name.c_str(), &file_stat))
 
308
    if (stat(share->data_file_name, &file_stat))
305
309
    {
306
310
      pthread_mutex_unlock(&tina_mutex);
307
311
      delete share;
320
324
      Usually this will result in auto-repair, and we will get a good
321
325
      meta-file in the end.
322
326
    */
323
 
    if ((share->meta_file= internal::my_open(meta_file_name.c_str(),
 
327
    if ((share->meta_file= internal::my_open(meta_file_name,
324
328
                                             O_RDWR|O_CREAT, MYF(0))) == -1)
325
329
      share->crashed= true;
326
330
 
449
453
  (void)write_meta_file(share->meta_file, share->rows_recorded, true);
450
454
 
451
455
  if ((share->tina_write_filedes=
452
 
        internal::my_open(share->data_file_name.c_str(), O_RDWR|O_APPEND, MYF(0))) == -1)
 
456
        internal::my_open(share->data_file_name, O_RDWR|O_APPEND, MYF(0))) == -1)
453
457
  {
454
458
    share->crashed= true;
455
459
    return(1);
480
484
      share->tina_write_opened= false;
481
485
    }
482
486
 
483
 
    Tina *a_tina= static_cast<Tina *>(getEngine());
 
487
    Tina *a_tina= static_cast<Tina *>(engine);
484
488
    a_tina->deleteOpenTable(share->table_name);
485
489
    delete share;
486
490
  }
529
533
 
530
534
 
531
535
 
532
 
ha_tina::ha_tina(drizzled::plugin::StorageEngine &engine_arg, Table &table_arg)
 
536
ha_tina::ha_tina(drizzled::plugin::StorageEngine &engine_arg, TableShare &table_arg)
533
537
  :Cursor(engine_arg, table_arg),
534
538
  /*
535
539
    These definitions are found in Cursor.h
556
560
 
557
561
  buffer.length(0);
558
562
 
559
 
  for (Field **field= getTable()->getFields() ; *field ; field++)
 
563
  for (Field **field= table->getFields() ; *field ; field++)
560
564
  {
561
565
    const char *ptr;
562
566
    const char *end_ptr;
596
600
        {
597
601
          buffer.append('\\');
598
602
          buffer.append('"');
599
 
          (void) *ptr++;
 
603
          *ptr++;
600
604
        }
601
605
        else if (*ptr == '\r')
602
606
        {
603
607
          buffer.append('\\');
604
608
          buffer.append('r');
605
 
          (void) *ptr++;
 
609
          *ptr++;
606
610
        }
607
611
        else if (*ptr == '\\')
608
612
        {
609
613
          buffer.append('\\');
610
614
          buffer.append('\\');
611
 
          (void) *ptr++;
 
615
          *ptr++;
612
616
        }
613
617
        else if (*ptr == '\n')
614
618
        {
615
619
          buffer.append('\\');
616
620
          buffer.append('n');
617
 
          (void) *ptr++;
 
621
          *ptr++;
618
622
        }
619
623
        else
620
624
          buffer.append(*ptr++);
674
678
 
675
679
  error= HA_ERR_CRASHED_ON_USAGE;
676
680
 
677
 
  memset(buf, 0, getTable()->getShare()->null_bytes);
 
681
  memset(buf, 0, table->getShare()->null_bytes);
678
682
 
679
 
  for (Field **field= getTable()->getFields() ; *field ; field++)
 
683
  for (Field **field=table->getFields() ; *field ; field++)
680
684
  {
681
685
    char curr_char;
682
686
 
745
749
    {
746
750
      /* This masks a bug in the logic for a SELECT * */
747
751
      (*field)->setWriteSet();
748
 
      if ((*field)->store_and_check(CHECK_FIELD_WARN, buffer.c_ptr(), buffer.length(), buffer.charset()))
749
 
      {
 
752
      if ((*field)->store(buffer.ptr(), buffer.length(), buffer.charset(),
 
753
                          CHECK_FIELD_WARN))
750
754
        goto err;
751
 
      }
752
755
 
753
756
      if ((*field)->flags & BLOB_FLAG)
754
757
      {
777
780
}
778
781
 
779
782
/*
 
783
  Three functions below are needed to enable concurrent insert functionality
 
784
  for CSV engine. For more details see mysys/thr_lock.c
 
785
*/
 
786
 
 
787
void tina_get_status(void* param, int)
 
788
{
 
789
  ha_tina *tina= (ha_tina*) param;
 
790
  tina->get_status();
 
791
}
 
792
 
 
793
void tina_update_status(void* param)
 
794
{
 
795
  ha_tina *tina= (ha_tina*) param;
 
796
  tina->update_status();
 
797
}
 
798
 
 
799
/* this should exist and return 0 for concurrent insert to work */
 
800
bool tina_check_status(void *)
 
801
{
 
802
  return 0;
 
803
}
 
804
 
 
805
/*
 
806
  Save the state of the table
 
807
 
 
808
  SYNOPSIS
 
809
    get_status()
 
810
 
 
811
  DESCRIPTION
 
812
    This function is used to retrieve the file length. During the lock
 
813
    phase of concurrent insert. For more details see comment to
 
814
    ha_tina::update_status below.
 
815
*/
 
816
 
 
817
void ha_tina::get_status()
 
818
{
 
819
  local_saved_data_file_length= share->saved_data_file_length;
 
820
}
 
821
 
 
822
 
 
823
/*
 
824
  Correct the state of the table. Called by unlock routines
 
825
  before the write lock is released.
 
826
 
 
827
  SYNOPSIS
 
828
    update_status()
 
829
 
 
830
  DESCRIPTION
 
831
    When we employ concurrent insert lock, we save current length of the file
 
832
    during the lock phase. We do not read further saved value, as we don't
 
833
    want to interfere with undergoing concurrent insert. Writers update file
 
834
    length info during unlock with update_status().
 
835
 
 
836
  NOTE
 
837
    For log tables concurrent insert works different. The reason is that
 
838
    log tables are always opened and locked. And as they do not unlock
 
839
    tables, the file length after writes should be updated in a different
 
840
    way.
 
841
*/
 
842
 
 
843
void ha_tina::update_status()
 
844
{
 
845
  /* correct local_saved_data_file_length for writers */
 
846
  share->saved_data_file_length= local_saved_data_file_length;
 
847
}
 
848
 
 
849
 
 
850
/*
780
851
  Open a database file. Keep in mind that tables are caches, so
781
852
  this will not be called for every request. Any sort of positions
782
853
  that need to be reset should be kept in the ::extra() call.
783
854
*/
784
 
int ha_tina::doOpen(const identifier::Table &identifier, int , uint32_t )
 
855
int ha_tina::doOpen(const TableIdentifier &identifier, int , uint32_t )
785
856
{
786
 
  if (not (share= get_share(identifier.getPath().c_str())))
 
857
  if (!(share= get_share(identifier.getPath().c_str())))
787
858
    return(ENOENT);
788
859
 
789
860
  if (share->crashed)
793
864
  }
794
865
 
795
866
  local_data_file_version= share->data_file_version;
796
 
  if ((data_file= internal::my_open(share->data_file_name.c_str(), O_RDONLY, MYF(0))) == -1)
 
867
  if ((data_file= internal::my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1)
797
868
    return(0);
798
869
 
799
870
  /*
801
872
    so that they could save/update local_saved_data_file_length value
802
873
    during locking. This is needed to enable concurrent inserts.
803
874
  */
 
875
  thr_lock_data_init(&share->lock, &lock, (void*) this);
804
876
  ref_length=sizeof(off_t);
805
877
 
 
878
  share->lock.get_status= tina_get_status;
 
879
  share->lock.update_status= tina_update_status;
 
880
  share->lock.check_status= tina_check_status;
 
881
 
806
882
  return(0);
807
883
}
808
884
 
956
1032
  {
957
1033
    local_data_file_version= share->data_file_version;
958
1034
    if (internal::my_close(data_file, MYF(0)) ||
959
 
        (data_file= internal::my_open(share->data_file_name.c_str(), O_RDONLY, MYF(0))) == -1)
 
1035
        (data_file= internal::my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1)
960
1036
      return 1;
961
1037
  }
962
1038
  file_buff->init_buff(data_file);
1109
1185
*/
1110
1186
int ha_tina::doEndTableScan()
1111
1187
{
 
1188
  char updated_fname[FN_REFLEN];
1112
1189
  off_t file_buffer_start= 0;
1113
1190
 
1114
1191
  blobroot.free_root(MYF(0));
1193
1270
      Close opened fildes's. Then move updated file in place
1194
1271
      of the old datafile.
1195
1272
    */
1196
 
    std::string rename_file= share->table_name;
1197
 
    rename_file.append(CSN_EXT);
1198
1273
    if (internal::my_close(data_file, MYF(0)) ||
1199
 
        internal::my_rename(rename_file.c_str(),
1200
 
                            share->data_file_name.c_str(), MYF(0)))
 
1274
        internal::my_rename(internal::fn_format(updated_fname,
 
1275
                                                share->table_name.c_str(),
 
1276
                                                "", CSN_EXT,
 
1277
                                                MY_REPLACE_EXT | MY_UNPACK_FILENAME),
 
1278
                            share->data_file_name, MYF(0)))
1201
1279
      return(-1);
1202
1280
 
1203
1281
    /* Open the file again */
1204
 
    if (((data_file= internal::my_open(share->data_file_name.c_str(), O_RDONLY, MYF(0))) == -1))
 
1282
    if (((data_file= internal::my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1))
1205
1283
      return(-1);
1206
1284
    /*
1207
1285
      As we reopened the data file, increase share->data_file_version
1268
1346
 
1269
1347
int Tina::doCreateTable(Session &session,
1270
1348
                        Table& table_arg,
1271
 
                        const drizzled::identifier::Table &identifier,
 
1349
                        const drizzled::TableIdentifier &identifier,
1272
1350
                        drizzled::message::Table &create_proto)
1273
1351
{
1274
1352
  char name_buff[FN_REFLEN];
1308
1386
 
1309
1387
  internal::my_close(create_file, MYF(0));
1310
1388
 
1311
 
  session.getMessageCache().storeTableMessage(identifier, create_proto);
 
1389
  session.storeTableMessage(identifier, create_proto);
1312
1390
 
1313
1391
  return 0;
1314
1392
}
1323
1401
  "CSV storage engine",
1324
1402
  PLUGIN_LICENSE_GPL,
1325
1403
  tina_init_func, /* Plugin Init */
1326
 
  NULL,                       /* depends */
 
1404
  NULL,                       /* system variables                */
1327
1405
  NULL                        /* config options                  */
1328
1406
}
1329
1407
DRIZZLE_DECLARE_PLUGIN_END;