98
120
class Tina : public drizzled::plugin::StorageEngine
100
typedef std::map<string, TinaShare*> TinaMap;
101
TinaMap tina_open_tables;
103
123
Tina(const string& name_arg)
104
: drizzled::plugin::StorageEngine(name_arg,
105
HTON_TEMPORARY_ONLY |
106
HTON_NO_AUTO_INCREMENT |
107
HTON_SKIP_STORE_LOCK),
124
: drizzled::plugin::StorageEngine(name_arg, HTON_TEMPORARY_ONLY |
125
HTON_HAS_DATA_DICTIONARY | HTON_FILE_BASED) {}
126
virtual Cursor *create(TableShare &table,
112
pthread_mutex_destroy(&tina_mutex);
129
return new (mem_root) ha_tina(*this, table);
115
virtual Cursor *create(Table &table)
132
uint64_t table_flags() const
117
return new ha_tina(*this, table);
134
return (HA_NO_TRANSACTIONS | HA_NO_AUTO_INCREMENT);
120
137
const char **bas_ext() const {
121
138
return ha_tina_exts;
124
int doCreateTable(Session &,
126
const drizzled::TableIdentifier &identifier,
141
int doCreateTable(Session *,
142
const char *table_name,
127
144
drizzled::message::Table&);
129
146
int doGetTableDefinition(Session& session,
130
const drizzled::TableIdentifier &identifier,
131
drizzled::message::Table &table_message);
133
int doDropTable(Session&, const drizzled::TableIdentifier &identifier);
134
TinaShare *findOpenTable(const string table_name);
135
void addOpenTable(const string &table_name, TinaShare *);
136
void deleteOpenTable(const string &table_name);
139
uint32_t max_keys() const { return 0; }
140
uint32_t max_key_parts() const { return 0; }
141
uint32_t max_key_length() const { return 0; }
142
bool doDoesTableExist(Session& session, const drizzled::TableIdentifier &identifier);
143
int doRenameTable(Session&, const drizzled::TableIdentifier &from, const drizzled::TableIdentifier &to);
145
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
146
const drizzled::SchemaIdentifier &schema_identifier,
147
drizzled::TableIdentifier::vector &set_of_identifiers);
149
const char *table_name,
151
drizzled::message::Table *table_proto);
153
/* Temp only engine, so do not return values. */
154
void doGetTableNames(CachedDirectory &, string& , set<string>&) { };
156
int doDropTable(Session&, const string table_path);
150
void Tina::doGetTableIdentifiers(drizzled::CachedDirectory&,
151
const drizzled::SchemaIdentifier&,
152
drizzled::TableIdentifier::vector&)
156
int Tina::doRenameTable(Session &session,
157
const drizzled::TableIdentifier &from, const drizzled::TableIdentifier &to)
160
for (const char **ext= bas_ext(); *ext ; ext++)
162
if (rename_file_ext(from.getPath().c_str(), to.getPath().c_str(), *ext))
164
if ((error=errno) != ENOENT)
170
session.getMessageCache().renameTableMessage(from, to);
175
bool Tina::doDoesTableExist(Session &session, const drizzled::TableIdentifier &identifier)
177
return session.getMessageCache().doesTableMessageExist(identifier);
181
int Tina::doDropTable(Session &session,
182
const drizzled::TableIdentifier &identifier)
159
int Tina::doDropTable(Session&,
160
const string table_path)
185
163
int enoent_or_zero= ENOENT; // Error if no file was deleted
164
char buff[FN_REFLEN];
165
ProtoCache::iterator iter;
187
167
for (const char **ext= bas_ext(); *ext ; ext++)
189
std::string full_name= identifier.getPath();
190
full_name.append(*ext);
192
if (internal::my_delete_with_symlink(full_name.c_str(), MYF(0)))
169
fn_format(buff, table_path.c_str(), "", *ext,
170
MY_UNPACK_FILENAME|MY_APPEND_EXT);
171
if (my_delete_with_symlink(buff, MYF(0)))
194
if ((error= errno) != ENOENT)
173
if ((error= my_errno) != ENOENT)
199
177
enoent_or_zero= 0; // No error for ENOENT
201
178
error= enoent_or_zero;
204
session.getMessageCache().removeTableMessage(identifier);
209
TinaShare *Tina::findOpenTable(const string table_name)
211
TinaMap::iterator find_iter=
212
tina_open_tables.find(table_name);
214
if (find_iter != tina_open_tables.end())
215
return (*find_iter).second;
220
void Tina::addOpenTable(const string &table_name, TinaShare *share)
222
tina_open_tables[table_name]= share;
225
void Tina::deleteOpenTable(const string &table_name)
227
tina_open_tables.erase(table_name);
231
int Tina::doGetTableDefinition(Session &session,
232
const drizzled::TableIdentifier &identifier,
233
drizzled::message::Table &table_message)
235
if (session.getMessageCache().getTableMessage(identifier, table_message))
181
pthread_mutex_lock(&proto_cache_mutex);
182
iter= proto_cache.find(table_path.c_str());
184
if (iter!= proto_cache.end())
185
proto_cache.erase(iter);
186
pthread_mutex_unlock(&proto_cache_mutex);
191
int Tina::doGetTableDefinition(Session&,
196
drizzled::message::Table *table_proto)
199
ProtoCache::iterator iter;
201
pthread_mutex_lock(&proto_cache_mutex);
202
iter= proto_cache.find(path);
204
if (iter!= proto_cache.end())
207
table_proto->CopyFrom(((*iter).second));
210
pthread_mutex_unlock(&proto_cache_mutex);
242
216
static Tina *tina_engine= NULL;
244
static int tina_init_func(drizzled::module::Context &context)
218
static int tina_init_func(drizzled::plugin::Registry ®istry)
247
tina_engine= new Tina("CSV");
248
context.add(tina_engine);
221
tina_engine= new Tina(engine_name);
222
registry.add(tina_engine);
250
224
pthread_mutex_init(&tina_mutex,MY_MUTEX_INIT_FAST);
256
TinaShare::TinaShare(const std::string &table_name_arg) :
257
table_name(table_name_arg),
258
data_file_name(table_name_arg),
260
saved_data_file_length(0),
261
update_file_opened(false),
262
tina_write_opened(false),
267
data_file_name.append(CSV_EXT);
270
TinaShare::~TinaShare()
272
pthread_mutex_destroy(&mutex);
225
(void) hash_init(&tina_open_tables,system_charset_info,32,0,0,
226
(hash_get_key) tina_get_key,0,0);
230
static int tina_done_func(drizzled::plugin::Registry ®istry)
232
registry.remove(tina_engine);
235
hash_free(&tina_open_tables);
236
pthread_mutex_destroy(&tina_mutex);
276
243
Simple lock controls.
278
TinaShare *ha_tina::get_share(const std::string &table_name)
245
static TINA_SHARE *get_share(const char *table_name, Table *)
280
pthread_mutex_lock(&tina_mutex);
282
Tina *a_tina= static_cast<Tina *>(getEngine());
283
share= a_tina->findOpenTable(table_name);
285
std::string meta_file_name;
248
char meta_file_name[FN_REFLEN];
286
249
struct stat file_stat;
253
pthread_mutex_lock(&tina_mutex);
254
length=(uint) strlen(table_name);
289
257
If share is not present in the hash, create a new share and
290
258
initialize its members.
260
if (!(share=(TINA_SHARE*) hash_search(&tina_open_tables,
261
(unsigned char*) table_name,
294
share= new TinaShare(table_name);
298
pthread_mutex_unlock(&tina_mutex);
302
meta_file_name.assign(table_name);
303
meta_file_name.append(CSM_EXT);
305
if (stat(share->data_file_name.c_str(), &file_stat))
307
pthread_mutex_unlock(&tina_mutex);
264
if (!drizzled::memory::multi_malloc(true,
265
&share, sizeof(*share),
269
pthread_mutex_unlock(&tina_mutex);
274
share->table_name_length= length;
275
share->table_name= tmp_name;
276
share->crashed= false;
277
share->rows_recorded= 0;
278
share->update_file_opened= false;
279
share->tina_write_opened= false;
280
share->data_file_version= 0;
281
strcpy(share->table_name, table_name);
282
fn_format(share->data_file_name, table_name, "", CSV_EXT,
283
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
284
fn_format(meta_file_name, table_name, "", CSM_EXT,
285
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
287
if (stat(share->data_file_name, &file_stat))
312
289
share->saved_data_file_length= file_stat.st_size;
314
a_tina->addOpenTable(share->table_name, share);
291
if (my_hash_insert(&tina_open_tables, (unsigned char*) share))
293
thr_lock_init(&share->lock);
316
294
pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
793
Three functions below are needed to enable concurrent insert functionality
794
for CSV engine. For more details see mysys/thr_lock.c
797
void tina_get_status(void* param, int)
799
ha_tina *tina= (ha_tina*) param;
803
void tina_update_status(void* param)
805
ha_tina *tina= (ha_tina*) param;
806
tina->update_status();
809
/* this should exist and return 0 for concurrent insert to work */
810
bool tina_check_status(void *)
816
Save the state of the table
822
This function is used to retrieve the file length. During the lock
823
phase of concurrent insert. For more details see comment to
824
ha_tina::update_status below.
827
void ha_tina::get_status()
829
local_saved_data_file_length= share->saved_data_file_length;
834
Correct the state of the table. Called by unlock routines
835
before the write lock is released.
841
When we employ concurrent insert lock, we save current length of the file
842
during the lock phase. We do not read further saved value, as we don't
843
want to interfere with undergoing concurrent insert. Writers update file
844
length info during unlock with update_status().
847
For log tables concurrent insert works different. The reason is that
848
log tables are always opened and locked. And as they do not unlock
849
tables, the file length after writes should be updated in a different
853
void ha_tina::update_status()
855
/* correct local_saved_data_file_length for writers */
856
share->saved_data_file_length= local_saved_data_file_length;
781
861
Open a database file. Keep in mind that tables are caches, so
782
862
this will not be called for every request. Any sort of positions
783
863
that need to be reset should be kept in the ::extra() call.
785
int ha_tina::doOpen(const TableIdentifier &identifier, int , uint32_t )
865
int ha_tina::open(const char *name, int, uint32_t open_options)
787
if (not (share= get_share(identifier.getPath().c_str())))
867
if (!(share= get_share(name, table)))
870
if (share->crashed && !(open_options & HA_OPEN_FOR_REPAIR))
793
873
return(HA_ERR_CRASHED_ON_USAGE);
796
876
local_data_file_version= share->data_file_version;
797
if ((data_file= internal::my_open(share->data_file_name.c_str(), O_RDONLY, MYF(0))) == -1)
877
if ((data_file= my_open(share->data_file_name, O_RDONLY, MYF(0))) == -1)
1297
if ((create_file= internal::my_create(internal::fn_format(name_buff, identifier.getPath().c_str(), "", CSM_EXT,
1298
MY_REPLACE_EXT|MY_UNPACK_FILENAME), 0,
1299
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1385
if ((create_file= my_create(fn_format(name_buff, table_name, "", CSM_EXT,
1386
MY_REPLACE_EXT|MY_UNPACK_FILENAME), 0,
1387
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1302
1390
write_meta_file(create_file, 0, false);
1303
internal::my_close(create_file, MYF(0));
1391
my_close(create_file, MYF(0));
1305
if ((create_file= internal::my_create(internal::fn_format(name_buff, identifier.getPath().c_str(), "", CSV_EXT,
1306
MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
1307
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1393
if ((create_file= my_create(fn_format(name_buff, table_name, "", CSV_EXT,
1394
MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
1395
O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
1310
internal::my_close(create_file, MYF(0));
1398
my_close(create_file, MYF(0));
1312
session.getMessageCache().storeTableMessage(identifier, create_proto);
1400
pthread_mutex_lock(&proto_cache_mutex);
1401
proto_cache.insert(make_pair(table_name, create_proto));
1402
pthread_mutex_unlock(&proto_cache_mutex);
1318
DRIZZLE_DECLARE_PLUGIN
1408
drizzle_declare_plugin
1323
1412
"Brian Aker, MySQL AB",
1324
1413
"CSV storage engine",
1325
1414
PLUGIN_LICENSE_GPL,
1326
1415
tina_init_func, /* Plugin Init */
1416
tina_done_func, /* Plugin Deinit */
1417
NULL, /* status variables */
1327
1418
NULL, /* system variables */
1328
1419
NULL /* config options */
1330
DRIZZLE_DECLARE_PLUGIN_END;
1421
drizzle_declare_plugin_end;