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 */
17
17
Make sure to look at ha_tina.h for more details.
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"
51
52
#include "ha_tina.h"
64
65
unsigned char + unsigned char + uint64_t + uint64_t + uint64_t + uint64_t + unsigned char
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
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
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);
81
void tina_get_status(void* param, int concurrent_insert);
82
void tina_update_status(void* param);
83
bool tina_check_status(void* param);
80
85
/* Stuff for shares */
81
86
pthread_mutex_t tina_mutex;
111
116
pthread_mutex_destroy(&tina_mutex);
114
virtual Cursor *create(Table &table)
119
virtual Cursor *create(TableShare &table,
120
drizzled::memory::Root *mem_root)
116
return new ha_tina(*this, table);
122
return new (mem_root) ha_tina(*this, table);
119
125
const char **bas_ext() const {
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&);
128
134
int doGetTableDefinition(Session& session,
129
const drizzled::identifier::Table &identifier,
135
const drizzled::TableIdentifier &identifier,
130
136
drizzled::message::Table &table_message);
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>&) { };
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);
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);
149
158
void Tina::doGetTableIdentifiers(drizzled::CachedDirectory&,
150
const drizzled::identifier::Schema&,
151
drizzled::identifier::Table::vector&)
159
const drizzled::SchemaIdentifier&,
160
drizzled::TableIdentifiers&)
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)
159
168
for (const char **ext= bas_ext(); *ext ; ext++)
169
session.getMessageCache().renameTableMessage(from, to);
178
session.renameTableMessage(from, to);
174
bool Tina::doDoesTableExist(Session &session, const drizzled::identifier::Table &identifier)
183
bool Tina::doDoesTableExist(Session &session, const drizzled::TableIdentifier &identifier)
176
return session.getMessageCache().doesTableMessageExist(identifier);
185
return session.doesTableMessageExist(identifier);
180
189
int Tina::doDropTable(Session &session,
181
const drizzled::identifier::Table &identifier)
190
const drizzled::TableIdentifier &identifier)
184
193
int enoent_or_zero= ENOENT; // Error if no file was deleted
194
char buff[FN_REFLEN];
186
196
for (const char **ext= bas_ext(); *ext ; ext++)
188
std::string full_name= identifier.getPath();
189
full_name.append(*ext);
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)))
193
202
if ((error= errno) != ENOENT)
198
206
enoent_or_zero= 0; // No error for ENOENT
200
207
error= enoent_or_zero;
203
session.getMessageCache().removeTableMessage(identifier);
210
session.removeTableMessage(identifier);
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)
234
if (session.getMessageCache().getTableMessage(identifier, table_message))
241
if (session.getTableMessage(identifier, table_message))
255
TinaShare::TinaShare(const std::string &table_name_arg) :
256
table_name(table_name_arg),
257
data_file_name(table_name_arg),
259
saved_data_file_length(0),
260
update_file_opened(false),
261
tina_write_opened(false),
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)
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);
269
272
TinaShare::~TinaShare()
274
thr_lock_delete(&lock);
271
275
pthread_mutex_destroy(&mutex);
275
279
Simple lock controls.
277
TinaShare *ha_tina::get_share(const std::string &table_name)
281
TinaShare *ha_tina::get_share(const char *table_name)
279
283
pthread_mutex_lock(&tina_mutex);
281
Tina *a_tina= static_cast<Tina *>(getEngine());
285
Tina *a_tina= static_cast<Tina *>(engine);
282
286
share= a_tina->findOpenTable(table_name);
284
std::string meta_file_name;
288
char meta_file_name[FN_REFLEN];
285
289
struct stat file_stat;
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);
304
if (stat(share->data_file_name.c_str(), &file_stat))
308
if (stat(share->data_file_name, &file_stat))
306
310
pthread_mutex_unlock(&tina_mutex);
320
324
Usually this will result in auto-repair, and we will get a good
321
325
meta-file in the end.
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;
449
453
(void)write_meta_file(share->meta_file, share->rows_recorded, true);
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)
454
458
share->crashed= true;
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),
535
539
These definitions are found in Cursor.h
675
679
error= HA_ERR_CRASHED_ON_USAGE;
677
memset(buf, 0, getTable()->getShare()->null_bytes);
681
memset(buf, 0, table->getShare()->null_bytes);
679
for (Field **field= getTable()->getFields() ; *field ; field++)
683
for (Field **field=table->getFields() ; *field ; field++)
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()))
752
if ((*field)->store(buffer.ptr(), buffer.length(), buffer.charset(),
753
756
if ((*field)->flags & BLOB_FLAG)
783
Three functions below are needed to enable concurrent insert functionality
784
for CSV engine. For more details see mysys/thr_lock.c
787
void tina_get_status(void* param, int)
789
ha_tina *tina= (ha_tina*) param;
793
void tina_update_status(void* param)
795
ha_tina *tina= (ha_tina*) param;
796
tina->update_status();
799
/* this should exist and return 0 for concurrent insert to work */
800
bool tina_check_status(void *)
806
Save the state of the table
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.
817
void ha_tina::get_status()
819
local_saved_data_file_length= share->saved_data_file_length;
824
Correct the state of the table. Called by unlock routines
825
before the write lock is released.
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().
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
843
void ha_tina::update_status()
845
/* correct local_saved_data_file_length for writers */
846
share->saved_data_file_length= local_saved_data_file_length;
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.
784
int ha_tina::doOpen(const identifier::Table &identifier, int , uint32_t )
855
int ha_tina::doOpen(const TableIdentifier &identifier, int , uint32_t )
786
if (not (share= get_share(identifier.getPath().c_str())))
857
if (!(share= get_share(identifier.getPath().c_str())))
789
860
if (share->crashed)
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)
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.
875
thr_lock_data_init(&share->lock, &lock, (void*) this);
804
876
ref_length=sizeof(off_t);
878
share->lock.get_status= tina_get_status;
879
share->lock.update_status= tina_update_status;
880
share->lock.check_status= tina_check_status;
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)
962
1038
file_buff->init_buff(data_file);
1193
1270
Close opened fildes's. Then move updated file in place
1194
1271
of the old datafile.
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(),
1277
MY_REPLACE_EXT | MY_UNPACK_FILENAME),
1278
share->data_file_name, MYF(0)))
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))
1207
1285
As we reopened the data file, increase share->data_file_version
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)
1274
1352
char name_buff[FN_REFLEN];
1309
1387
internal::my_close(create_file, MYF(0));
1311
session.getMessageCache().storeTableMessage(identifier, create_proto);
1389
session.storeTableMessage(identifier, create_proto);
1323
1401
"CSV storage engine",
1324
1402
PLUGIN_LICENSE_GPL,
1325
1403
tina_init_func, /* Plugin Init */
1404
NULL, /* system variables */
1327
1405
NULL /* config options */
1329
1407
DRIZZLE_DECLARE_PLUGIN_END;