~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/schema_engine/schema.cc

Merged trunk and use-std-unordred.

Show diffs side-by-side

added added

removed removed

Lines of Context:
44
44
using namespace std;
45
45
using namespace drizzled;
46
46
 
 
47
static SchemaIdentifier TEMPORARY_IDENTIFIER("TEMPORARY");
 
48
 
47
49
#define MY_DB_OPT_FILE "db.opt"
48
50
#define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
49
51
 
50
52
Schema::Schema():
51
53
  drizzled::plugin::StorageEngine("schema",
52
54
                                  HTON_ALTER_NOT_SUPPORTED |
53
 
                                  HTON_HAS_DATA_DICTIONARY |
54
55
                                  HTON_HAS_SCHEMA_DICTIONARY |
55
56
                                  HTON_SKIP_STORE_LOCK |
56
57
                                  HTON_TEMPORARY_NOT_SUPPORTED),
59
60
  table_definition_ext= DEFAULT_FILE_EXTENSION;
60
61
  pthread_rwlock_init(&schema_lock, NULL);
61
62
  prime();
62
 
#if 0
63
 
  message::Schema schema_message;
64
 
 
65
 
  schema_message.set_name("temporary_tables");
66
 
 
67
 
  doCreateSchema(schema_message);
68
 
#endif
69
63
}
70
64
 
71
65
Schema::~Schema()
73
67
  pthread_rwlock_destroy(&schema_lock);
74
68
}
75
69
 
76
 
int Schema::doGetTableDefinition(Session &,
77
 
                                 drizzled::TableIdentifier &identifier,
78
 
                                 message::Table &table_proto)
79
 
{
80
 
  string proto_path(identifier.getPath());
81
 
  proto_path.append(DEFAULT_FILE_EXTENSION);
82
 
 
83
 
  if (access(proto_path.c_str(), F_OK))
84
 
  {
85
 
    return errno;
86
 
  }
87
 
 
88
 
  if (readTableFile(proto_path, table_proto))
89
 
    return EEXIST;
90
 
 
91
 
  return -1;
92
 
}
93
 
 
94
 
void Schema::doGetTableNames(CachedDirectory &directory, string&, set<string>& set_of_names)
95
 
{
96
 
  CachedDirectory::Entries entries= directory.getEntries();
97
 
 
98
 
  for (CachedDirectory::Entries::iterator entry_iter= entries.begin(); 
99
 
       entry_iter != entries.end(); ++entry_iter)
100
 
  {
101
 
    CachedDirectory::Entry *entry= *entry_iter;
102
 
    const string *filename= &entry->filename;
103
 
 
104
 
    assert(filename->size());
105
 
 
106
 
    const char *ext= strchr(filename->c_str(), '.');
107
 
 
108
 
    if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_FILE_EXTENSION) ||
109
 
        (filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
110
 
    { }
111
 
    else
112
 
    {
113
 
      char uname[NAME_LEN + 1];
114
 
      uint32_t file_name_len;
115
 
 
116
 
      file_name_len= filename_to_tablename(filename->c_str(), uname, sizeof(uname));
117
 
      // TODO: Remove need for memory copy here
118
 
      uname[file_name_len - sizeof(DEFAULT_FILE_EXTENSION) + 1]= '\0'; // Subtract ending, place NULL 
119
 
      set_of_names.insert(uname);
120
 
    }
121
 
  }
122
 
}
123
 
 
124
70
void Schema::prime()
125
71
{
126
72
  CachedDirectory directory(data_home, CachedDirectory::DIRECTORY);
136
82
 
137
83
    if (readSchemaFile(entry->filename, schema_message))
138
84
    {
 
85
      SchemaIdentifier schema_identifier(schema_message.name());
 
86
 
139
87
      pair<SchemaCache::iterator, bool> ret=
140
 
        schema_cache.insert(make_pair(schema_message.name(), schema_message));
 
88
        schema_cache.insert(make_pair(schema_identifier.getPath(), schema_message));
141
89
 
142
90
      if (ret.second == false)
143
 
      {
 
91
     {
144
92
        abort(); // If this has happened, something really bad is going down.
145
93
      }
146
94
    }
148
96
  pthread_rwlock_unlock(&schema_lock);
149
97
}
150
98
 
151
 
void Schema::doGetSchemaNames(std::set<std::string>& set_of_names)
 
99
void Schema::doGetSchemaIdentifiers(SchemaIdentifierList &set_of_names)
152
100
{
153
101
  if (not pthread_rwlock_rdlock(&schema_lock))
154
102
  {
156
104
         iter != schema_cache.end();
157
105
         iter++)
158
106
    {
159
 
      set_of_names.insert((*iter).first);
 
107
      set_of_names.push_back(SchemaIdentifier((*iter).second.name()));
160
108
    }
161
109
    pthread_rwlock_unlock(&schema_lock);
162
110
 
173
121
       fileIter != files.end(); fileIter++)
174
122
  {
175
123
    CachedDirectory::Entry *entry= *fileIter;
176
 
    set_of_names.insert(entry->filename);
 
124
    set_of_names.push_back(entry->filename);
177
125
  }
178
126
}
179
127
 
180
 
bool Schema::doGetSchemaDefinition(const std::string &schema_name, message::Schema &schema_message)
 
128
bool Schema::doGetSchemaDefinition(SchemaIdentifier &schema_identifier, message::Schema &schema_message)
181
129
{
182
130
  if (not pthread_rwlock_rdlock(&schema_lock))
183
131
  {
184
 
    SchemaCache::iterator iter= schema_cache.find(schema_name);
 
132
    SchemaCache::iterator iter= schema_cache.find(schema_identifier.getPath());
 
133
 
185
134
    if (iter != schema_cache.end())
186
135
    {
187
136
      schema_message.CopyFrom(((*iter).second));
194
143
  }
195
144
 
196
145
  // Fail to disk based means
197
 
  return readSchemaFile(schema_name, schema_message);
 
146
  return readSchemaFile(schema_identifier.getPath(), schema_message);
198
147
}
199
148
 
200
149
bool Schema::doCreateSchema(const drizzled::message::Schema &schema_message)
201
150
{
202
 
  std::string path;
203
 
  drizzled::build_table_filename(path, schema_message.name().c_str(), "", false);
204
 
 
205
 
  path.erase(path.length()-1);
206
 
 
207
 
  if (mkdir(path.c_str(), 0777) == -1)
 
151
  SchemaIdentifier schema_identifier(schema_message.name());
 
152
 
 
153
  if (mkdir(schema_identifier.getPath().c_str(), 0777) == -1)
208
154
    return false;
209
155
 
210
 
  if (not writeSchemaFile(path.c_str(), schema_message))
 
156
  if (not writeSchemaFile(schema_identifier, schema_message))
211
157
  {
212
 
    rmdir(path.c_str());
 
158
    rmdir(schema_identifier.getPath().c_str());
213
159
 
214
160
    return false;
215
161
  }
217
163
  if (not pthread_rwlock_wrlock(&schema_lock))
218
164
  {
219
165
      pair<SchemaCache::iterator, bool> ret=
220
 
        schema_cache.insert(make_pair(schema_message.name(), schema_message));
 
166
        schema_cache.insert(make_pair(schema_identifier.getPath(), schema_message));
221
167
 
222
168
 
223
169
      if (ret.second == false)
230
176
  return true;
231
177
}
232
178
 
233
 
bool Schema::doDropSchema(const std::string &schema_name)
 
179
bool Schema::doDropSchema(SchemaIdentifier &schema_identifier)
234
180
{
235
 
  string path;
236
181
  message::Schema schema_message;
237
182
 
238
 
  drizzled::build_table_filename(path, schema_name.c_str(), "", false);
239
 
  path.erase(path.length()-1);
240
 
 
241
 
  string schema_file(path);
 
183
  string schema_file(schema_identifier.getPath());
242
184
  schema_file.append(1, FN_LIBCHAR);
243
185
  schema_file.append(MY_DB_OPT_FILE);
244
186
 
245
 
  if (not doGetSchemaDefinition(schema_name, schema_message))
 
187
  if (not doGetSchemaDefinition(schema_identifier, schema_message))
246
188
    return false;
247
189
 
248
190
  // No db.opt file, no love from us.
258
200
    return false;
259
201
  }
260
202
 
261
 
  if (rmdir(path.c_str()))
 
203
  if (rmdir(schema_identifier.getPath().c_str()))
262
204
  {
263
 
    perror(path.c_str());
264
 
    CachedDirectory dir(path);
 
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());
265
209
    cerr << dir;
266
210
  }
267
211
 
268
212
  if (not pthread_rwlock_wrlock(&schema_lock))
269
213
  {
270
 
    schema_cache.erase(schema_message.name());
 
214
    schema_cache.erase(schema_identifier.getPath());
271
215
    pthread_rwlock_unlock(&schema_lock);
272
216
  }
273
217
 
274
218
  return true;
275
219
}
276
220
 
277
 
int Schema::doDropTable(Session&, TableIdentifier &identifier)
278
 
{
279
 
  string path(identifier.getPath());
280
 
 
281
 
  path.append(DEFAULT_FILE_EXTENSION);
282
 
 
283
 
  return internal::my_delete(path.c_str(), MYF(0));
284
 
}
285
 
 
286
221
bool Schema::doAlterSchema(const drizzled::message::Schema &schema_message)
287
222
{
288
 
  string path;
289
 
  drizzled::build_table_filename(path, schema_message.name().c_str(), "", false);
290
 
  path.erase(path.length()-1);
 
223
  SchemaIdentifier schema_identifier(schema_message.name());
291
224
 
292
 
  if (access(path.c_str(), F_OK))
 
225
  if (access(schema_identifier.getPath().c_str(), F_OK))
293
226
    return false;
294
227
 
295
 
  if (writeSchemaFile(path.c_str(), schema_message))
 
228
  if (writeSchemaFile(schema_identifier, schema_message))
296
229
  {
297
230
    if (not pthread_rwlock_wrlock(&schema_lock))
298
231
    {
299
 
      schema_cache.erase(schema_message.name());
 
232
      schema_cache.erase(schema_identifier.getPath());
300
233
 
301
234
      pair<SchemaCache::iterator, bool> ret=
302
 
        schema_cache.insert(make_pair(schema_message.name(), schema_message));
 
235
        schema_cache.insert(make_pair(schema_identifier.getPath(), schema_message));
303
236
 
304
237
      if (ret.second == false)
305
238
      {
322
255
 
323
256
  @note we do the rename to make it crash safe.
324
257
*/
325
 
bool Schema::writeSchemaFile(const char *path, const message::Schema &db)
 
258
bool Schema::writeSchemaFile(SchemaIdentifier &schema_identifier, const message::Schema &db)
326
259
{
327
260
  char schema_file_tmp[FN_REFLEN];
328
 
  string schema_file(path);
 
261
  string schema_file(schema_identifier.getPath());
329
262
 
330
 
  snprintf(schema_file_tmp, FN_REFLEN, "%s%c%s.tmpXXXXXX", path, FN_LIBCHAR, MY_DB_OPT_FILE);
331
263
 
332
264
  schema_file.append(1, FN_LIBCHAR);
333
265
  schema_file.append(MY_DB_OPT_FILE);
334
266
 
 
267
  snprintf(schema_file_tmp, FN_REFLEN, "%sXXXXXX", schema_file.c_str());
 
268
 
335
269
  int fd= mkstemp(schema_file_tmp);
336
270
 
337
271
  if (fd == -1)
338
272
  {
339
273
    perror(schema_file_tmp);
 
274
 
340
275
    return false;
341
276
  }
342
277
 
343
278
  if (not db.SerializeToFileDescriptor(fd))
344
279
  {
345
 
    cerr << "Couldn't write " << path << "\n";
346
 
    close(fd);
 
280
    my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
 
281
             db.InitializationErrorString().c_str());
 
282
 
 
283
    if (close(fd) == -1)
 
284
      perror(schema_file_tmp);
 
285
 
 
286
    if (unlink(schema_file_tmp))
 
287
      perror(schema_file_tmp);
 
288
 
 
289
    return false;
 
290
  }
 
291
 
 
292
  if (close(fd) == -1)
 
293
  {
 
294
    perror(schema_file_tmp);
 
295
 
 
296
    if (unlink(schema_file_tmp))
 
297
      perror(schema_file_tmp);
347
298
 
348
299
    return false;
349
300
  }
350
301
 
351
302
  if (rename(schema_file_tmp, schema_file.c_str()) == -1)
352
303
  {
353
 
    close(fd);
 
304
    if (unlink(schema_file_tmp))
 
305
      perror(schema_file_tmp);
354
306
 
355
307
    return false;
356
308
  }
357
 
  close(fd);
358
309
 
359
310
  return true;
360
311
}
361
312
 
362
313
 
363
 
bool Schema::readTableFile(const std::string &path, message::Table &table_message)
364
 
{
365
 
  fstream input(path.c_str(), ios::in | ios::binary);
366
 
 
367
 
  if (input.good())
368
 
  {
369
 
    if (table_message.ParseFromIstream(&input))
370
 
    {
371
 
      return true;
372
 
    }
373
 
  }
374
 
  else
375
 
  {
376
 
    perror(path.c_str());
377
 
  }
378
 
 
379
 
  return false;
380
 
}
381
 
 
382
 
 
383
 
bool Schema::readSchemaFile(const std::string &schema_name, drizzled::message::Schema &schema_message)
384
 
{
385
 
  string db_opt_path;
 
314
bool Schema::readSchemaFile(const std::string &schema_file_name, drizzled::message::Schema &schema_message)
 
315
{
 
316
  string db_opt_path(schema_file_name);
386
317
 
387
318
  /*
388
319
    Pass an empty file name, and the database options file name as extension
389
320
    to avoid table name to file name encoding.
390
321
  */
391
 
  build_table_filename(db_opt_path, schema_name.c_str(), "", false);
 
322
  db_opt_path.append(1, FN_LIBCHAR);
392
323
  db_opt_path.append(MY_DB_OPT_FILE);
393
324
 
394
325
  fstream input(db_opt_path.c_str(), ios::in | ios::binary);
404
335
    {
405
336
      return true;
406
337
    }
 
338
 
 
339
    my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
 
340
             schema_message.InitializationErrorString().c_str());
407
341
  }
408
342
  else
409
343
  {
413
347
  return false;
414
348
}
415
349
 
416
 
bool Schema::doCanCreateTable(const drizzled::TableIdentifier &identifier)
417
 
{
418
 
  if (not strcasecmp(identifier.getSchemaName().c_str(), "temporary"))
419
 
  {
420
 
    return false;
421
 
  }
422
 
 
423
 
  return true;
424
 
}
425
 
 
426
 
bool Schema::doDoesTableExist(Session&, TableIdentifier &identifier)
427
 
{
428
 
  string proto_path(identifier.getPath());
429
 
  proto_path.append(DEFAULT_FILE_EXTENSION);
430
 
 
431
 
  if (access(proto_path.c_str(), F_OK))
 
350
bool Schema::doCanCreateTable(drizzled::TableIdentifier &identifier)
 
351
{
 
352
  if (static_cast<SchemaIdentifier&>(identifier) == TEMPORARY_IDENTIFIER)
432
353
  {
433
354
    return false;
434
355
  }