113
class Tina : public drizzled::plugin::StorageEngine
119
class Tina : public StorageEngine
115
typedef std::map<string, TinaShare*> TinaMap;
116
TinaMap tina_open_tables;
118
122
Tina(const string& name_arg)
119
: drizzled::plugin::StorageEngine(name_arg,
120
HTON_TEMPORARY_ONLY |
121
HTON_NO_AUTO_INCREMENT |
122
HTON_SKIP_STORE_LOCK |
128
pthread_mutex_destroy(&tina_mutex);
131
virtual Cursor *create(TableShare &table,
132
drizzled::memory::Root *mem_root)
134
return new (mem_root) ha_tina(*this, table);
123
: StorageEngine(name_arg, HTON_CAN_RECREATE | HTON_TEMPORARY_ONLY | HTON_FILE_BASED) {}
124
virtual handler *create(TableShare *table,
127
return new (mem_root) ha_tina(this, table);
137
130
const char **bas_ext() const {
138
131
return ha_tina_exts;
141
int doCreateTable(Session &,
143
drizzled::TableIdentifier &identifier,
144
drizzled::message::Table&);
146
int doGetTableDefinition(Session& session,
147
TableIdentifier &identifier,
148
drizzled::message::Table &table_message);
150
/* Temp only engine, so do not return values. */
151
void doGetTableNames(drizzled::CachedDirectory &, SchemaIdentifier&, set<string>&) { };
153
int doDropTable(Session&, TableIdentifier &identifier);
154
TinaShare *findOpenTable(const string table_name);
155
void addOpenTable(const string &table_name, TinaShare *);
156
void deleteOpenTable(const string &table_name);
159
uint32_t max_keys() const { return 0; }
160
uint32_t max_key_parts() const { return 0; }
161
uint32_t max_key_length() const { return 0; }
162
bool doDoesTableExist(Session& session, TableIdentifier &identifier);
163
int doRenameTable(Session&, TableIdentifier &from, TableIdentifier &to);
165
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
166
drizzled::SchemaIdentifier &schema_identifier,
167
drizzled::TableIdentifiers &set_of_identifiers);
134
int createTableImplementation(Session *, const char *table_name,
136
HA_CREATE_INFO *, drizzled::message::Table*);
170
void Tina::doGetTableIdentifiers(drizzled::CachedDirectory&,
171
drizzled::SchemaIdentifier&,
172
drizzled::TableIdentifiers&)
176
int Tina::doRenameTable(Session &session,
177
TableIdentifier &from, TableIdentifier &to)
180
for (const char **ext= bas_ext(); *ext ; ext++)
182
if (rename_file_ext(from.getPath().c_str(), to.getPath().c_str(), *ext))
184
if ((error=errno) != ENOENT)
190
session.renameTableMessage(from, to);
195
bool Tina::doDoesTableExist(Session &session, TableIdentifier &identifier)
197
return session.doesTableMessageExist(identifier);
201
int Tina::doDropTable(Session &session,
202
TableIdentifier &identifier)
205
int enoent_or_zero= ENOENT; // Error if no file was deleted
206
char buff[FN_REFLEN];
208
for (const char **ext= bas_ext(); *ext ; ext++)
210
internal::fn_format(buff, identifier.getPath().c_str(), "", *ext,
211
MY_UNPACK_FILENAME|MY_APPEND_EXT);
212
if (internal::my_delete_with_symlink(buff, MYF(0)))
214
if ((error= errno) != ENOENT)
218
enoent_or_zero= 0; // No error for ENOENT
219
error= enoent_or_zero;
222
session.removeTableMessage(identifier);
227
TinaShare *Tina::findOpenTable(const string table_name)
229
TinaMap::iterator find_iter=
230
tina_open_tables.find(table_name);
232
if (find_iter != tina_open_tables.end())
233
return (*find_iter).second;
238
void Tina::addOpenTable(const string &table_name, TinaShare *share)
240
tina_open_tables[table_name]= share;
243
void Tina::deleteOpenTable(const string &table_name)
245
tina_open_tables.erase(table_name);
249
int Tina::doGetTableDefinition(Session &session,
250
drizzled::TableIdentifier &identifier,
251
drizzled::message::Table &table_message)
253
if (session.getTableMessage(identifier, table_message))
260
140
static Tina *tina_engine= NULL;
262
static int tina_init_func(drizzled::plugin::Context &context)
142
static int tina_init_func(PluginRegistry ®istry)
265
tina_engine= new Tina("CSV");
266
context.add(tina_engine);
145
tina_engine= new Tina(engine_name);
146
registry.add(tina_engine);
268
148
pthread_mutex_init(&tina_mutex,MY_MUTEX_INIT_FAST);
274
TinaShare::TinaShare(const char *table_name_arg)
275
: table_name(table_name_arg), use_count(0), saved_data_file_length(0),
276
update_file_opened(false), tina_write_opened(false),
277
crashed(false), rows_recorded(0), data_file_version(0)
279
thr_lock_init(&lock);
280
internal::fn_format(data_file_name, table_name_arg, "", CSV_EXT,
281
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
284
TinaShare::~TinaShare()
286
thr_lock_delete(&lock);
287
pthread_mutex_destroy(&mutex);
149
(void) hash_init(&tina_open_tables,system_charset_info,32,0,0,
150
(hash_get_key) tina_get_key,0,0);
154
static int tina_done_func(PluginRegistry ®istry)
156
registry.remove(tina_engine);
159
hash_free(&tina_open_tables);
160
pthread_mutex_destroy(&tina_mutex);
291
167
Simple lock controls.
293
TinaShare *ha_tina::get_share(const char *table_name)
169
static TINA_SHARE *get_share(const char *table_name, Table *)
295
pthread_mutex_lock(&tina_mutex);
297
Tina *a_tina= static_cast<Tina *>(engine);
298
share= a_tina->findOpenTable(table_name);
300
172
char meta_file_name[FN_REFLEN];
301
173
struct stat file_stat;
177
pthread_mutex_lock(&tina_mutex);
178
length=(uint) strlen(table_name);
304
181
If share is not present in the hash, create a new share and
305
182
initialize its members.
184
if (!(share=(TINA_SHARE*) hash_search(&tina_open_tables,
185
(unsigned char*) table_name,
309
share= new TinaShare(table_name);
188
if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
189
&share, sizeof(*share),
313
193
pthread_mutex_unlock(&tina_mutex);
317
internal::fn_format(meta_file_name, table_name, "", CSM_EXT,
198
share->table_name_length= length;
199
share->table_name= tmp_name;
200
share->crashed= false;
201
share->rows_recorded= 0;
202
share->update_file_opened= false;
203
share->tina_write_opened= false;
204
share->data_file_version= 0;
205
strcpy(share->table_name, table_name);
206
fn_format(share->data_file_name, table_name, "", CSV_EXT,
207
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
208
fn_format(meta_file_name, table_name, "", CSM_EXT,
318
209
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
320
211
if (stat(share->data_file_name, &file_stat))
322
pthread_mutex_unlock(&tina_mutex);
327
213
share->saved_data_file_length= file_stat.st_size;
329
a_tina->addOpenTable(share->table_name, share);
215
if (my_hash_insert(&tina_open_tables, (unsigned char*) share))
217
thr_lock_init(&share->lock);
331
218
pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
1359
internal::my_close(update_temp_file, MYF(0));
1269
my_close(update_temp_file, MYF(0));
1360
1270
share->update_file_opened= false;
1276
Repair CSV table in the case, it is crashed.
1280
session The thread, performing repair
1281
check_opt The options for repair. We do not use it currently.
1284
If the file is empty, change # of rows in the file and complete recovery.
1285
Otherwise, scan the table looking for bad rows. If none were found,
1286
we mark file as a good one and return. If a bad row was encountered,
1287
we truncate the datafile up to the last good row.
1289
TODO: Make repair more clever - it should try to recover subsequent
1290
rows (after the first bad one) as well.
1293
int ha_tina::repair(Session* session, HA_CHECK_OPT *)
1295
char repaired_fname[FN_REFLEN];
1299
ha_rows rows_repaired= 0;
1300
off_t write_begin= 0, write_end;
1303
if (!share->saved_data_file_length)
1305
share->rows_recorded= 0;
1309
/* Don't assert in field::val() functions */
1310
table->use_all_columns();
1311
if (!(buf= (unsigned char*) malloc(table->s->reclength)))
1312
return(HA_ERR_OUT_OF_MEM);
1314
/* position buffer to the start of the file */
1315
if (init_data_file())
1316
return(HA_ERR_CRASHED_ON_REPAIR);
1319
Local_saved_data_file_length is initialized during the lock phase.
1320
Sometimes this is not getting executed before ::repair (e.g. for
1321
the log tables). We set it manually here.
1323
local_saved_data_file_length= share->saved_data_file_length;
1324
/* set current position to the beginning of the file */
1325
current_position= next_position= 0;
1327
init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
1329
/* Read the file row-by-row. If everything is ok, repair is not needed. */
1330
while (!(rc= find_current_row(buf)))
1332
session_inc_row_count(session);
1334
current_position= next_position;
1337
free_root(&blobroot, MYF(0));
1341
if (rc == HA_ERR_END_OF_FILE)
1344
All rows were read ok until end of file, the file does not need repair.
1345
If rows_recorded != rows_repaired, we should update rows_recorded value
1346
to the current amount of rows.
1348
share->rows_recorded= rows_repaired;
1353
Otherwise we've encountered a bad row => repair is needed.
1354
Let us create a temporary file.
1356
if ((repair_file= my_create(fn_format(repaired_fname, share->table_name,
1358
MY_REPLACE_EXT|MY_UNPACK_FILENAME),
1359
0, O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1360
return(HA_ERR_CRASHED_ON_REPAIR);
1362
file_buff->init_buff(data_file);
1365
/* we just truncated the file up to the first bad row. update rows count. */
1366
share->rows_recorded= rows_repaired;
1368
/* write repaired file */
1371
write_end= std::min(file_buff->end(), current_position);
1373
off_t write_length= write_end - write_begin;
1374
if ((uint64_t)write_length > SIZE_MAX)
1378
if ((write_length) &&
1379
(my_write(repair_file, (unsigned char*)file_buff->ptr(),
1380
(size_t)write_length, MYF_RW)))
1383
write_begin= write_end;
1384
if (write_end== current_position)
1387
file_buff->read_next(); /* shift the buffer */
1391
Close the files and rename repaired file to the datafile.
1392
We have to close the files, as on Windows one cannot rename
1393
a file, which descriptor is still open. EACCES will be returned
1394
when trying to delete the "to"-file in my_rename().
1396
if (my_close(data_file,MYF(0)) || my_close(repair_file, MYF(0)) ||
1397
my_rename(repaired_fname, share->data_file_name, MYF(0)))
1400
/* Open the file again, it should now be repaired */
1401
if ((data_file= my_open(share->data_file_name, O_RDWR|O_APPEND,
1405
/* Set new file size. The file size will be updated by ::update_status() */
1406
local_saved_data_file_length= (size_t) current_position;
1409
share->crashed= false;
1410
return(HA_ADMIN_OK);
1366
1414
DELETE without WHERE calls this
1418
if ((create_file= internal::my_create(internal::fn_format(name_buff, identifier.getPath().c_str(), "", CSM_EXT,
1419
MY_REPLACE_EXT|MY_UNPACK_FILENAME), 0,
1420
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1479
if ((create_file= my_create(fn_format(name_buff, table_name, "", CSM_EXT,
1480
MY_REPLACE_EXT|MY_UNPACK_FILENAME), 0,
1481
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1423
1484
write_meta_file(create_file, 0, false);
1424
internal::my_close(create_file, MYF(0));
1485
my_close(create_file, MYF(0));
1426
if ((create_file= internal::my_create(internal::fn_format(name_buff, identifier.getPath().c_str(), "", CSV_EXT,
1427
MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
1428
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1487
if ((create_file= my_create(fn_format(name_buff, table_name, "", CSV_EXT,
1488
MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
1489
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1431
internal::my_close(create_file, MYF(0));
1433
session.storeTableMessage(identifier, create_proto);
1439
DRIZZLE_DECLARE_PLUGIN
1492
my_close(create_file, MYF(0));
1497
int ha_tina::check(Session* session, HA_CHECK_OPT *)
1501
const char *old_proc_info;
1502
ha_rows count= share->rows_recorded;
1504
old_proc_info= get_session_proc_info(session);
1505
set_session_proc_info(session, "Checking table");
1506
if (!(buf= (unsigned char*) malloc(table->s->reclength)))
1507
return(HA_ERR_OUT_OF_MEM);
1509
/* position buffer to the start of the file */
1510
if (init_data_file())
1511
return(HA_ERR_CRASHED);
1514
Local_saved_data_file_length is initialized during the lock phase.
1515
Check does not use store_lock in certain cases. So, we set it
1518
local_saved_data_file_length= share->saved_data_file_length;
1519
/* set current position to the beginning of the file */
1520
current_position= next_position= 0;
1522
init_alloc_root(&blobroot, BLOB_MEMROOT_ALLOC_SIZE, 0);
1524
/* Read the file row-by-row. If everything is ok, repair is not needed. */
1525
while (!(rc= find_current_row(buf)))
1527
session_inc_row_count(session);
1529
current_position= next_position;
1532
free_root(&blobroot, MYF(0));
1535
set_session_proc_info(session, old_proc_info);
1537
if ((rc != HA_ERR_END_OF_FILE) || count)
1539
share->crashed= true;
1540
return(HA_ADMIN_CORRUPT);
1543
return(HA_ADMIN_OK);
1547
drizzle_declare_plugin(csv)
1444
1551
"Brian Aker, MySQL AB",
1445
1552
"CSV storage engine",
1446
1553
PLUGIN_LICENSE_GPL,
1447
1554
tina_init_func, /* Plugin Init */
1555
tina_done_func, /* Plugin Deinit */
1556
NULL, /* status variables */
1448
1557
NULL, /* system variables */
1449
1558
NULL /* config options */
1451
DRIZZLE_DECLARE_PLUGIN_END;
1560
drizzle_declare_plugin_end;