1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2010 Brian Aker
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
#include "plugin/schema_engine/schema.h"
24
#include "drizzled/db.h"
25
#include "drizzled/sql_table.h"
26
#include "drizzled/global_charset_info.h"
27
#include "drizzled/charset.h"
28
#include "drizzled/charset_info.h"
29
#include "drizzled/cursor.h"
31
#include "drizzled/internal/my_sys.h"
35
#include <sys/types.h>
37
#include <google/protobuf/io/zero_copy_stream.h>
38
#include <google/protobuf/io/zero_copy_stream_impl.h>
45
using namespace drizzled;
47
static SchemaIdentifier TEMPORARY_IDENTIFIER("TEMPORARY");
49
#define MY_DB_OPT_FILE "db.opt"
50
#define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
53
drizzled::plugin::StorageEngine("schema",
54
HTON_ALTER_NOT_SUPPORTED |
55
HTON_HAS_SCHEMA_DICTIONARY |
56
HTON_SKIP_STORE_LOCK |
57
HTON_TEMPORARY_NOT_SUPPORTED),
58
schema_cache_filled(false)
60
table_definition_ext= DEFAULT_FILE_EXTENSION;
61
pthread_rwlock_init(&schema_lock, NULL);
67
pthread_rwlock_destroy(&schema_lock);
72
CachedDirectory directory(drizzle_data_home, CachedDirectory::DIRECTORY);
73
CachedDirectory::Entries files= directory.getEntries();
75
pthread_rwlock_wrlock(&schema_lock);
77
for (CachedDirectory::Entries::iterator fileIter= files.begin();
78
fileIter != files.end(); fileIter++)
80
CachedDirectory::Entry *entry= *fileIter;
81
message::Schema schema_message;
83
if (readSchemaFile(entry->filename, schema_message))
85
SchemaIdentifier schema_identifier(schema_message.name());
87
pair<SchemaCache::iterator, bool> ret=
88
schema_cache.insert(make_pair(schema_identifier.getPath(), schema_message));
90
if (ret.second == false)
92
abort(); // If this has happened, something really bad is going down.
96
pthread_rwlock_unlock(&schema_lock);
99
void Schema::doGetSchemaIdentifiers(SchemaIdentifierList &set_of_names)
101
if (not pthread_rwlock_rdlock(&schema_lock))
103
for (SchemaCache::iterator iter= schema_cache.begin();
104
iter != schema_cache.end();
107
set_of_names.push_back(SchemaIdentifier((*iter).second.name()));
109
pthread_rwlock_unlock(&schema_lock);
114
// If for some reason getting a lock should fail, we resort to disk
116
CachedDirectory directory(drizzle_data_home, CachedDirectory::DIRECTORY);
118
CachedDirectory::Entries files= directory.getEntries();
120
for (CachedDirectory::Entries::iterator fileIter= files.begin();
121
fileIter != files.end(); fileIter++)
123
CachedDirectory::Entry *entry= *fileIter;
124
set_of_names.push_back(entry->filename);
128
bool Schema::doGetSchemaDefinition(SchemaIdentifier &schema_identifier, message::Schema &schema_message)
130
if (not pthread_rwlock_rdlock(&schema_lock))
132
SchemaCache::iterator iter= schema_cache.find(schema_identifier.getPath());
134
if (iter != schema_cache.end())
136
schema_message.CopyFrom(((*iter).second));
137
pthread_rwlock_unlock(&schema_lock);
140
pthread_rwlock_unlock(&schema_lock);
145
// Fail to disk based means
146
return readSchemaFile(schema_identifier.getPath(), schema_message);
149
bool Schema::doCreateSchema(const drizzled::message::Schema &schema_message)
151
SchemaIdentifier schema_identifier(schema_message.name());
153
if (mkdir(schema_identifier.getPath().c_str(), 0777) == -1)
156
if (not writeSchemaFile(schema_identifier, schema_message))
158
rmdir(schema_identifier.getPath().c_str());
163
if (not pthread_rwlock_wrlock(&schema_lock))
165
pair<SchemaCache::iterator, bool> ret=
166
schema_cache.insert(make_pair(schema_identifier.getPath(), schema_message));
169
if (ret.second == false)
171
abort(); // If this has happened, something really bad is going down.
173
pthread_rwlock_unlock(&schema_lock);
179
bool Schema::doDropSchema(SchemaIdentifier &schema_identifier)
181
message::Schema schema_message;
183
string schema_file(schema_identifier.getPath());
184
schema_file.append(1, FN_LIBCHAR);
185
schema_file.append(MY_DB_OPT_FILE);
187
if (not doGetSchemaDefinition(schema_identifier, schema_message))
190
// No db.opt file, no love from us.
191
if (access(schema_file.c_str(), F_OK))
193
perror(schema_file.c_str());
197
if (unlink(schema_file.c_str()))
199
perror(schema_file.c_str());
203
if (rmdir(schema_identifier.getPath().c_str()))
205
perror(schema_identifier.getPath().c_str());
206
//@todo If this happens, we want a report of it. For the moment I dump
207
//to stderr so I can catch it in Hudson.
208
CachedDirectory dir(schema_identifier.getPath());
212
if (not pthread_rwlock_wrlock(&schema_lock))
214
schema_cache.erase(schema_identifier.getPath());
215
pthread_rwlock_unlock(&schema_lock);
221
bool Schema::doAlterSchema(const drizzled::message::Schema &schema_message)
223
SchemaIdentifier schema_identifier(schema_message.name());
225
if (access(schema_identifier.getPath().c_str(), F_OK))
228
if (writeSchemaFile(schema_identifier, schema_message))
230
if (not pthread_rwlock_wrlock(&schema_lock))
232
schema_cache.erase(schema_identifier.getPath());
234
pair<SchemaCache::iterator, bool> ret=
235
schema_cache.insert(make_pair(schema_identifier.getPath(), schema_message));
237
if (ret.second == false)
239
abort(); // If this has happened, something really bad is going down.
242
pthread_rwlock_unlock(&schema_lock);
246
abort(); // This would leave us out of sync, suck.
254
path is path to database, not schema file
256
@note we do the rename to make it crash safe.
258
bool Schema::writeSchemaFile(SchemaIdentifier &schema_identifier, const message::Schema &db)
260
char schema_file_tmp[FN_REFLEN];
261
string schema_file(schema_identifier.getPath());
264
schema_file.append(1, FN_LIBCHAR);
265
schema_file.append(MY_DB_OPT_FILE);
267
snprintf(schema_file_tmp, FN_REFLEN, "%sXXXXXX", schema_file.c_str());
269
int fd= mkstemp(schema_file_tmp);
273
perror(schema_file_tmp);
278
if (not db.SerializeToFileDescriptor(fd))
280
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
281
db.InitializationErrorString().c_str());
284
perror(schema_file_tmp);
286
if (unlink(schema_file_tmp))
287
perror(schema_file_tmp);
294
perror(schema_file_tmp);
296
if (unlink(schema_file_tmp))
297
perror(schema_file_tmp);
302
if (rename(schema_file_tmp, schema_file.c_str()) == -1)
304
if (unlink(schema_file_tmp))
305
perror(schema_file_tmp);
314
bool Schema::readSchemaFile(const std::string &schema_file_name, drizzled::message::Schema &schema_message)
316
string db_opt_path(schema_file_name);
319
Pass an empty file name, and the database options file name as extension
320
to avoid table name to file name encoding.
322
db_opt_path.append(1, FN_LIBCHAR);
323
db_opt_path.append(MY_DB_OPT_FILE);
325
fstream input(db_opt_path.c_str(), ios::in | ios::binary);
328
@note If parsing fails, either someone has done a "mkdir" or has deleted their opt file.
329
So what do we do? We muddle through the adventure by generating
330
one with a name in it, and the charset set to the default.
334
if (schema_message.ParseFromIstream(&input))
339
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
340
schema_message.InitializationErrorString().c_str());
344
perror(db_opt_path.c_str());
350
bool Schema::doCanCreateTable(drizzled::TableIdentifier &identifier)
352
if (static_cast<SchemaIdentifier&>(identifier) == TEMPORARY_IDENTIFIER)
360
void Schema::doGetTableIdentifiers(drizzled::CachedDirectory&,
361
drizzled::SchemaIdentifier&,
362
drizzled::TableIdentifiers&)