~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/schema_engine/schema.cc

  • Committer: pawel
  • Date: 2010-03-29 20:16:08 UTC
  • mto: This revision was merged to the branch mainline in revision 1428.
  • Revision ID: pawel@paw-20100329201608-ndqnc736k47uvy3s
changed function-like defines into functions in some files

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